refactor(agents): migrate console.warn/error/info to subsystem logger (#22906)

Merged via /review-pr -> /prepare-pr -> /merge-pr.

Prepared head SHA: a806c4cb2700564096ce8980a8d7f839f8a0d388
Co-authored-by: Kepler2024 <166882517+Kepler2024@users.noreply.github.com>
Co-authored-by: gumadeiras <5599352+gumadeiras@users.noreply.github.com>
Reviewed-by: @gumadeiras
This commit is contained in:
Harry Cui Kepler
2026-02-21 23:11:47 +01:00
committed by GitHub
parent 1257aee6e1
commit ffa63173e0
16 changed files with 79 additions and 50 deletions

View File

@@ -1,6 +1,7 @@
import path from "node:path";
import type { OpenClawConfig } from "../config/config.js";
import { resolveStateDir } from "../config/paths.js";
import { createSubsystemLogger } from "../logging/subsystem.js";
import {
DEFAULT_AGENT_ID,
normalizeAgentId,
@@ -9,6 +10,7 @@ import {
import { resolveUserPath } from "../utils.js";
import { normalizeSkillFilter } from "./skills/filter.js";
import { resolveDefaultAgentWorkspaceDir } from "./workspace.js";
const log = createSubsystemLogger("agent-scope");
export { resolveAgentIdFromSessionKey } from "../routing/session-key.js";
@@ -66,7 +68,7 @@ export function resolveDefaultAgentId(cfg: OpenClawConfig): string {
const defaults = agents.filter((agent) => agent?.default);
if (defaults.length > 1 && !defaultAgentWarned) {
defaultAgentWarned = true;
console.warn("Multiple agents marked default=true; using the first entry as default.");
log.warn("Multiple agents marked default=true; using the first entry as default.");
}
const chosen = (defaults[0] ?? agents[0])?.id?.trim();
return normalizeAgentId(chosen || DEFAULT_AGENT_ID);

View File

@@ -4,6 +4,9 @@ import {
type ListFoundationModelsCommandOutput,
} from "@aws-sdk/client-bedrock";
import type { BedrockDiscoveryConfig, ModelDefinitionConfig } from "../config/types.js";
import { createSubsystemLogger } from "../logging/subsystem.js";
const log = createSubsystemLogger("bedrock-discovery");
const DEFAULT_REFRESH_INTERVAL_SECONDS = 3600;
const DEFAULT_CONTEXT_WINDOW = 32000;
@@ -216,7 +219,7 @@ export async function discoverBedrockModels(params: {
}
if (!hasLoggedBedrockError) {
hasLoggedBedrockError = true;
console.warn(`[bedrock-discovery] Failed to list models: ${String(error)}`);
log.warn(`Failed to list models: ${String(error)}`);
}
return [];
}

View File

@@ -2,9 +2,12 @@ import type { AgentMessage } from "@mariozechner/pi-agent-core";
import type { ExtensionContext } from "@mariozechner/pi-coding-agent";
import { estimateTokens, generateSummary } from "@mariozechner/pi-coding-agent";
import { retryAsync } from "../infra/retry.js";
import { createSubsystemLogger } from "../logging/subsystem.js";
import { DEFAULT_CONTEXT_TOKENS } from "./defaults.js";
import { repairToolUseResultPairing, stripToolResultDetails } from "./session-transcript-repair.js";
const log = createSubsystemLogger("compaction");
export const BASE_CHUNK_RATIO = 0.4;
export const MIN_CHUNK_RATIO = 0.15;
export const SAFETY_MARGIN = 1.2; // 20% buffer for estimateTokens() inaccuracy
@@ -219,7 +222,7 @@ export async function summarizeWithFallback(params: {
try {
return await summarizeChunks(params);
} catch (fullError) {
console.warn(
log.warn(
`Full summarization failed, trying partial: ${
fullError instanceof Error ? fullError.message : String(fullError)
}`,
@@ -251,7 +254,7 @@ export async function summarizeWithFallback(params: {
const notes = oversizedNotes.length > 0 ? `\n\n${oversizedNotes.join("\n")}` : "";
return partialSummary + notes;
} catch (partialError) {
console.warn(
log.warn(
`Partial summarization also failed: ${
partialError instanceof Error ? partialError.message : String(partialError)
}`,

View File

@@ -1,4 +1,7 @@
import type { ModelDefinitionConfig } from "../config/types.models.js";
import { createSubsystemLogger } from "../logging/subsystem.js";
const log = createSubsystemLogger("huggingface-models");
/** Hugging Face Inference Providers (router) — OpenAI-compatible chat completions. */
export const HUGGINGFACE_BASE_URL = "https://router.huggingface.co/v1";
@@ -168,16 +171,14 @@ export async function discoverHuggingfaceModels(apiKey: string): Promise<ModelDe
});
if (!response.ok) {
console.warn(
`[huggingface-models] GET /v1/models failed: HTTP ${response.status}, using static catalog`,
);
log.warn(`GET /v1/models failed: HTTP ${response.status}, using static catalog`);
return HUGGINGFACE_MODEL_CATALOG.map(buildHuggingfaceModelDefinition);
}
const body = (await response.json()) as OpenAIListModelsResponse;
const data = body?.data;
if (!Array.isArray(data) || data.length === 0) {
console.warn("[huggingface-models] No models in response, using static catalog");
log.warn("No models in response, using static catalog");
return HUGGINGFACE_MODEL_CATALOG.map(buildHuggingfaceModelDefinition);
}
@@ -223,7 +224,7 @@ export async function discoverHuggingfaceModels(apiKey: string): Promise<ModelDe
? models
: HUGGINGFACE_MODEL_CATALOG.map(buildHuggingfaceModelDefinition);
} catch (error) {
console.warn(`[huggingface-models] Discovery failed: ${String(error)}, using static catalog`);
log.warn(`Discovery failed: ${String(error)}, using static catalog`);
return HUGGINGFACE_MODEL_CATALOG.map(buildHuggingfaceModelDefinition);
}
}

View File

@@ -1,7 +1,10 @@
import { type OpenClawConfig, loadConfig } from "../config/config.js";
import { createSubsystemLogger } from "../logging/subsystem.js";
import { resolveOpenClawAgentDir } from "./agent-paths.js";
import { ensureOpenClawModelsJson } from "./models-config.js";
const log = createSubsystemLogger("model-catalog");
export type ModelCatalogEntry = {
id: string;
name: string;
@@ -150,7 +153,7 @@ export async function loadModelCatalog(params?: {
} catch (error) {
if (!hasLoggedModelCatalogError) {
hasLoggedModelCatalogError = true;
console.warn(`[model-catalog] Failed to load model catalog: ${String(error)}`);
log.warn(`Failed to load model catalog: ${String(error)}`);
}
// Don't poison the cache on transient dependency/filesystem issues.
modelCatalogPromise = null;

View File

@@ -1,9 +1,12 @@
import type { OpenClawConfig } from "../config/config.js";
import { createSubsystemLogger } from "../logging/subsystem.js";
import { resolveAgentConfig, resolveAgentModelPrimary } from "./agent-scope.js";
import { DEFAULT_MODEL, DEFAULT_PROVIDER } from "./defaults.js";
import type { ModelCatalogEntry } from "./model-catalog.js";
import { normalizeGoogleModelId } from "./models-config.providers.js";
const log = createSubsystemLogger("model-selection");
export type ModelRef = {
provider: string;
model: string;
@@ -270,8 +273,8 @@ export function resolveConfiguredModelRef(params: {
}
// Default to anthropic if no provider is specified, but warn as this is deprecated.
console.warn(
`[openclaw] Model "${trimmed}" specified without provider. Falling back to "anthropic/${trimmed}". Please use "anthropic/${trimmed}" in your config.`,
log.warn(
`Model "${trimmed}" specified without provider. Falling back to "anthropic/${trimmed}". Please use "anthropic/${trimmed}" in your config.`,
);
return { provider: "anthropic", model: trimmed };
}

View File

@@ -1,5 +1,6 @@
import type { OpenClawConfig } from "../config/config.js";
import type { ModelDefinitionConfig } from "../config/types.models.js";
import { createSubsystemLogger } from "../logging/subsystem.js";
import {
DEFAULT_COPILOT_API_BASE_URL,
resolveCopilotApiToken,
@@ -175,6 +176,8 @@ const NVIDIA_DEFAULT_COST = {
cacheWrite: 0,
};
const log = createSubsystemLogger("agents/model-providers");
interface OllamaModel {
name: string;
modified_at: string;
@@ -224,12 +227,12 @@ async function discoverOllamaModels(baseUrl?: string): Promise<ModelDefinitionCo
signal: AbortSignal.timeout(5000),
});
if (!response.ok) {
console.warn(`Failed to discover Ollama models: ${response.status}`);
log.warn(`Failed to discover Ollama models: ${response.status}`);
return [];
}
const data = (await response.json()) as OllamaTagsResponse;
if (!data.models || data.models.length === 0) {
console.warn("No Ollama models found on local instance");
log.warn("No Ollama models found on local instance");
return [];
}
return data.models.map((model) => {
@@ -247,7 +250,7 @@ async function discoverOllamaModels(baseUrl?: string): Promise<ModelDefinitionCo
};
});
} catch (error) {
console.warn(`Failed to discover Ollama models: ${String(error)}`);
log.warn(`Failed to discover Ollama models: ${String(error)}`);
return [];
}
}
@@ -271,13 +274,13 @@ async function discoverVllmModels(
signal: AbortSignal.timeout(5000),
});
if (!response.ok) {
console.warn(`Failed to discover vLLM models: ${response.status}`);
log.warn(`Failed to discover vLLM models: ${response.status}`);
return [];
}
const data = (await response.json()) as VllmModelsResponse;
const models = data.data ?? [];
if (models.length === 0) {
console.warn("No vLLM models found on local instance");
log.warn("No vLLM models found on local instance");
return [];
}
@@ -300,7 +303,7 @@ async function discoverVllmModels(
} satisfies ModelDefinitionConfig;
});
} catch (error) {
console.warn(`Failed to discover vLLM models: ${String(error)}`);
log.warn(`Failed to discover vLLM models: ${String(error)}`);
return [];
}
}

View File

@@ -9,6 +9,9 @@ import type {
Usage,
} from "@mariozechner/pi-ai";
import { createAssistantMessageEventStream } from "@mariozechner/pi-ai";
import { createSubsystemLogger } from "../logging/subsystem.js";
const log = createSubsystemLogger("ollama-stream");
export const OLLAMA_NATIVE_BASE_URL = "http://127.0.0.1:11434";
@@ -261,7 +264,7 @@ export async function* parseNdjsonStream(
try {
yield JSON.parse(trimmed) as OllamaChatResponse;
} catch {
console.warn("[ollama-stream] Skipping malformed NDJSON line:", trimmed.slice(0, 120));
log.warn(`Skipping malformed NDJSON line: ${trimmed.slice(0, 120)}`);
}
}
}
@@ -270,10 +273,7 @@ export async function* parseNdjsonStream(
try {
yield JSON.parse(buffer.trim()) as OllamaChatResponse;
} catch {
console.warn(
"[ollama-stream] Skipping malformed trailing data:",
buffer.trim().slice(0, 120),
);
log.warn(`Skipping malformed trailing data: ${buffer.trim().slice(0, 120)}`);
}
}
}

View File

@@ -12,6 +12,9 @@
*/
import type { ModelApi, ModelDefinitionConfig } from "../config/types.js";
import { createSubsystemLogger } from "../logging/subsystem.js";
const log = createSubsystemLogger("opencode-zen-models");
export const OPENCODE_ZEN_API_BASE_URL = "https://opencode.ai/zen/v1";
export const OPENCODE_ZEN_DEFAULT_MODEL = "claude-opus-4-6";
@@ -302,7 +305,7 @@ export async function fetchOpencodeZenModels(apiKey?: string): Promise<ModelDefi
return models;
} catch (error) {
console.warn(`[opencode-zen] Failed to fetch models, using static fallback: ${String(error)}`);
log.warn(`Failed to fetch models, using static fallback: ${String(error)}`);
return getOpencodeZenStaticFallbackModels();
}
}

View File

@@ -1,9 +1,12 @@
import type { AssistantMessage } from "@mariozechner/pi-ai";
import type { OpenClawConfig } from "../../config/config.js";
import { createSubsystemLogger } from "../../logging/subsystem.js";
import { formatSandboxToolPolicyBlockedMessage } from "../sandbox.js";
import { stableStringify } from "../stable-stringify.js";
import type { FailoverReason } from "./types.js";
const log = createSubsystemLogger("errors");
export function formatBillingErrorMessage(provider?: string, model?: string): string {
const providerName = provider?.trim();
const modelName = model?.trim();
@@ -487,7 +490,7 @@ export function formatAssistantErrorText(
// Never return raw unhandled errors - log for debugging but return safe message
if (raw.length > 600) {
console.warn("[formatAssistantErrorText] Long error truncated:", raw.slice(0, 200));
log.warn(`Long error truncated: ${raw.slice(0, 200)}`);
}
return raw.length > 600 ? `${raw.slice(0, 600)}` : raw;
}

View File

@@ -3,6 +3,7 @@ import path from "node:path";
import type { AgentMessage } from "@mariozechner/pi-agent-core";
import type { ExtensionAPI, FileOperations } from "@mariozechner/pi-coding-agent";
import { extractSections } from "../../auto-reply/reply/post-compaction-context.js";
import { createSubsystemLogger } from "../../logging/subsystem.js";
import {
BASE_CHUNK_RATIO,
MIN_CHUNK_RATIO,
@@ -17,6 +18,8 @@ import {
} from "../compaction.js";
import { collectTextContentBlocks } from "../content-blocks.js";
import { getCompactionSafeguardRuntime } from "./compaction-safeguard-runtime.js";
const log = createSubsystemLogger("compaction-safeguard");
const FALLBACK_SUMMARY =
"Summary unavailable due to context limits. Older messages were truncated.";
const TURN_PREFIX_INSTRUCTIONS =
@@ -252,7 +255,7 @@ export default function compactionSafeguardExtension(api: ExtensionAPI): void {
});
if (pruned.droppedChunks > 0) {
const newContentRatio = (newContentTokens / contextWindowTokens) * 100;
console.warn(
log.warn(
`Compaction safeguard: new content uses ${newContentRatio.toFixed(
1,
)}% of context; dropped ${pruned.droppedChunks} older chunk(s) ` +
@@ -284,7 +287,7 @@ export default function compactionSafeguardExtension(api: ExtensionAPI): void {
previousSummary: preparation.previousSummary,
});
} catch (droppedError) {
console.warn(
log.warn(
`Compaction safeguard: failed to summarize dropped messages, continuing without: ${
droppedError instanceof Error ? droppedError.message : String(droppedError)
}`,
@@ -356,7 +359,7 @@ export default function compactionSafeguardExtension(api: ExtensionAPI): void {
},
};
} catch (error) {
console.warn(
log.warn(
`Compaction summarization failed; truncating history: ${
error instanceof Error ? error.message : String(error)
}`,

View File

@@ -1,4 +1,5 @@
import { spawn } from "node:child_process";
import { createSubsystemLogger } from "../../logging/subsystem.js";
import { sanitizeEnvVars } from "./sanitize-env-vars.js";
type ExecDockerRawOptions = {
@@ -114,6 +115,8 @@ import { resolveSandboxAgentId, resolveSandboxScopeKey, slugifySessionKey } from
import type { SandboxConfig, SandboxDockerConfig, SandboxWorkspaceAccess } from "./types.js";
import { validateSandboxSecurity } from "./validate-sandbox-security.js";
const log = createSubsystemLogger("docker");
const HOT_CONTAINER_WINDOW_MS = 5 * 60 * 1000;
export type ExecDockerOptions = ExecDockerRawOptions;
@@ -291,13 +294,10 @@ export function buildSandboxCreateArgs(params: {
}
const envSanitization = sanitizeEnvVars(params.cfg.env ?? {});
if (envSanitization.blocked.length > 0) {
console.warn(
"[Security] Blocked sensitive environment variables:",
envSanitization.blocked.join(", "),
);
log.warn(`Blocked sensitive environment variables: ${envSanitization.blocked.join(", ")}`);
}
if (envSanitization.warnings.length > 0) {
console.warn("[Security] Suspicious environment variables:", envSanitization.warnings);
log.warn(`Suspicious environment variables: ${envSanitization.warnings.join(", ")}`);
}
for (const [key, value] of Object.entries(envSanitization.allowed)) {
args.push("--env", `${key}=${value}`);

View File

@@ -1,10 +1,13 @@
import type { OpenClawConfig } from "../../config/config.js";
import { isDangerousHostEnvVarName } from "../../infra/host-env-security.js";
import { createSubsystemLogger } from "../../logging/subsystem.js";
import { sanitizeEnvVars, validateEnvVarValue } from "../sandbox/sanitize-env-vars.js";
import { resolveSkillConfig } from "./config.js";
import { resolveSkillKey } from "./frontmatter.js";
import type { SkillEntry, SkillSnapshot } from "./types.js";
const log = createSubsystemLogger("env-overrides");
type EnvUpdate = { key: string; prev: string | undefined };
type SkillConfig = NonNullable<ReturnType<typeof resolveSkillConfig>>;
@@ -114,13 +117,10 @@ function applySkillConfigEnvOverrides(params: {
});
if (sanitized.blocked.length > 0) {
console.warn(
`[Security] Blocked skill env overrides for ${skillKey}:`,
sanitized.blocked.join(", "),
);
log.warn(`Blocked skill env overrides for ${skillKey}: ${sanitized.blocked.join(", ")}`);
}
if (sanitized.warnings.length > 0) {
console.warn(`[Security] Suspicious skill env overrides for ${skillKey}:`, sanitized.warnings);
log.warn(`Suspicious skill env overrides for ${skillKey}: ${sanitized.warnings.join(", ")}`);
}
for (const [envKey, envValue] of Object.entries(sanitized.allowed)) {

View File

@@ -640,14 +640,12 @@ export async function syncSkillsToWorkspace(params: {
});
} catch (error) {
const message = error instanceof Error ? error.message : JSON.stringify(error);
console.warn(
`[skills] Failed to resolve safe destination for ${entry.skill.name}: ${message}`,
);
skillsLogger.warn(`Failed to resolve safe destination for ${entry.skill.name}: ${message}`);
continue;
}
if (!dest) {
console.warn(
`[skills] Failed to resolve safe destination for ${entry.skill.name}: invalid source directory name`,
skillsLogger.warn(
`Failed to resolve safe destination for ${entry.skill.name}: invalid source directory name`,
);
continue;
}
@@ -658,7 +656,7 @@ export async function syncSkillsToWorkspace(params: {
});
} catch (error) {
const message = error instanceof Error ? error.message : JSON.stringify(error);
console.warn(`[skills] Failed to copy ${entry.skill.name} to sandbox: ${message}`);
skillsLogger.warn(`Failed to copy ${entry.skill.name} to sandbox: ${message}`);
}
}
});

View File

@@ -9,10 +9,13 @@ import {
writeRestartSentinel,
} from "../../infra/restart-sentinel.js";
import { scheduleGatewaySigusr1Restart } from "../../infra/restart.js";
import { createSubsystemLogger } from "../../logging/subsystem.js";
import { stringEnum } from "../schema/typebox.js";
import { type AnyAgentTool, jsonResult, readStringParam } from "./common.js";
import { callGatewayTool, readGatewayCallOptions } from "./gateway.js";
const log = createSubsystemLogger("gateway-tool");
const DEFAULT_UPDATE_TIMEOUT_MS = 20 * 60_000;
function resolveBaseHashFromSnapshot(snapshot: unknown): string | undefined {
@@ -116,7 +119,7 @@ export function createGatewayTool(opts?: {
} catch {
// ignore: sentinel is best-effort
}
console.info(
log.info(
`gateway tool: restart requested (delayMs=${delayMs ?? "default"}, reason=${reason ?? "none"})`,
);
const scheduled = scheduleGatewaySigusr1Restart({

View File

@@ -1,4 +1,7 @@
import type { ModelDefinitionConfig } from "../config/types.js";
import { createSubsystemLogger } from "../logging/subsystem.js";
const log = createSubsystemLogger("venice-models");
export const VENICE_BASE_URL = "https://api.venice.ai/api/v1";
export const VENICE_DEFAULT_MODEL_ID = "llama-3.3-70b";
@@ -345,15 +348,13 @@ export async function discoverVeniceModels(): Promise<ModelDefinitionConfig[]> {
});
if (!response.ok) {
console.warn(
`[venice-models] Failed to discover models: HTTP ${response.status}, using static catalog`,
);
log.warn(`Failed to discover models: HTTP ${response.status}, using static catalog`);
return VENICE_MODEL_CATALOG.map(buildVeniceModelDefinition);
}
const data = (await response.json()) as VeniceModelsResponse;
if (!Array.isArray(data.data) || data.data.length === 0) {
console.warn("[venice-models] No models found from API, using static catalog");
log.warn("No models found from API, using static catalog");
return VENICE_MODEL_CATALOG.map(buildVeniceModelDefinition);
}
@@ -396,7 +397,7 @@ export async function discoverVeniceModels(): Promise<ModelDefinitionConfig[]> {
return models.length > 0 ? models : VENICE_MODEL_CATALOG.map(buildVeniceModelDefinition);
} catch (error) {
console.warn(`[venice-models] Discovery failed: ${String(error)}, using static catalog`);
log.warn(`Discovery failed: ${String(error)}, using static catalog`);
return VENICE_MODEL_CATALOG.map(buildVeniceModelDefinition);
}
}