diff --git a/src/agents/openai-completions-string-content.ts b/src/agents/openai-completions-string-content.ts index 7d8e34d88e6..c43f56d2828 100644 --- a/src/agents/openai-completions-string-content.ts +++ b/src/agents/openai-completions-string-content.ts @@ -1,3 +1,5 @@ +// OpenAI Chat Completions compatibility helpers. Some providers only accept +// role/content messages with plain string content instead of text block arrays. function flattenStringOnlyCompletionContent(content: unknown): unknown { if (!Array.isArray(content)) { return content; @@ -17,6 +19,7 @@ function flattenStringOnlyCompletionContent(content: unknown): unknown { return textParts.join("\n"); } +/** Flatten string-only text block content arrays into newline-joined strings. */ export function flattenCompletionMessagesToStringContent(messages: unknown[]): unknown[] { return messages.map((message) => { if (!message || typeof message !== "object") { @@ -34,6 +37,7 @@ export function flattenCompletionMessagesToStringContent(messages: unknown[]): u }); } +/** Strip completion messages to role/content fields for strict providers. */ export function stripCompletionMessagesToRoleContent(messages: unknown[]): unknown[] { return messages.map((message) => { if (!message || typeof message !== "object" || Array.isArray(message)) { diff --git a/src/agents/provider-auth-aliases.ts b/src/agents/provider-auth-aliases.ts index 937e41423aa..bf77564d20d 100644 --- a/src/agents/provider-auth-aliases.ts +++ b/src/agents/provider-auth-aliases.ts @@ -12,6 +12,9 @@ import { loadPluginMetadataSnapshot } from "../plugins/plugin-metadata-snapshot. import type { PluginMetadataSnapshot } from "../plugins/plugin-metadata-snapshot.types.js"; import type { PluginOrigin } from "../plugins/plugin-origin.types.js"; +// Provider auth aliases map deprecated or plugin-defined provider IDs to the +// canonical provider used for credential lookup. Plugin origin priority keeps +// configured aliases ahead of bundled/global/workspace aliases. export type ProviderAuthAliasLookupParams = { config?: OpenClawConfig; workspaceDir?: string; @@ -51,6 +54,7 @@ function buildProviderAuthAliasMapCacheKey( }); } +/** Clear provider auth alias cache for tests that mutate plugin metadata. */ export function resetProviderAuthAliasMapCacheForTest(): void { providerAuthAliasMapCache = new WeakMap>>(); } @@ -108,6 +112,7 @@ function setPreferredAlias(params: { } } +/** Resolve canonical auth provider aliases from plugin metadata. */ export function resolveProviderAuthAliasMap( params?: ProviderAuthAliasLookupParams, ): Record { @@ -116,6 +121,8 @@ export function resolveProviderAuthAliasMap( let cacheKey: string | undefined; let envCache: Map> | undefined; if (!params?.metadataSnapshot) { + // Plugin metadata is process-stable for a control-plane fingerprint, so + // cache per env object without hiding explicit test snapshots. cacheKey = buildProviderAuthAliasMapCacheKey(params, env); envCache = providerAuthAliasMapCache.get(env); if (!envCache) { @@ -195,6 +202,7 @@ export function resolveProviderAuthAliasMap( return aliases; } +/** Resolve the provider ID that should be used for credential lookup. */ export function resolveProviderIdForAuth( provider: string, params?: ProviderAuthAliasLookupParams, diff --git a/src/agents/tool-call-shared.ts b/src/agents/tool-call-shared.ts index efaf8d611c9..cc3b09b93a3 100644 --- a/src/agents/tool-call-shared.ts +++ b/src/agents/tool-call-shared.ts @@ -1,8 +1,11 @@ import { normalizeLowercaseStringOrEmpty } from "@openclaw/normalization-core/string-coerce"; +// Shared validation for model-supplied tool call names. Names are kept compact +// and ASCII-ish before comparing against any allowed-tool set. const TOOL_CALL_NAME_MAX_CHARS = 64; const TOOL_CALL_NAME_RE = /^[A-Za-z0-9_:.-]+$/; +/** Normalize an optional iterable of allowed tool names for lookup. */ export function normalizeAllowedToolNames(allowedToolNames?: Iterable): Set | null { if (!allowedToolNames) { return null; @@ -21,6 +24,7 @@ export function normalizeAllowedToolNames(allowedToolNames?: Iterable): return normalized.size > 0 ? normalized : null; } +/** Return whether a model-supplied tool call name is syntactically and policy allowed. */ export function isAllowedToolCallName( name: unknown, allowedToolNames: Set | null, diff --git a/src/agents/tool-display-common.ts b/src/agents/tool-display-common.ts index 62025335d8d..4242c3c04d6 100644 --- a/src/agents/tool-display-common.ts +++ b/src/agents/tool-display-common.ts @@ -7,6 +7,8 @@ import { redactToolPayloadText } from "../logging/redact.js"; import { resolveExecDetail, type ToolDetailMode } from "./tool-display-exec.js"; import { asRecord } from "./tool-display-record.js"; +// Shared formatting helpers for compact tool-call display labels. Display text +// is redacted and summarized so tool updates stay readable in chat/UI streams. type ToolDisplayActionSpec = { label?: string; detailKeys?: string[]; @@ -35,10 +37,12 @@ type CoerceDisplayValueOptions = { maxArrayEntries?: number; }; +/** Normalize a tool name for fallback display. */ export function normalizeToolName(name?: string): string { return (name ?? "tool").trim(); } +/** Convert a tool identifier into a human-readable title. */ export function defaultTitle(name: string): string { const cleaned = name.replace(/_/g, " ").trim(); if (!cleaned) { @@ -75,6 +79,7 @@ function resolveActionArg(args: unknown): string | undefined { return action || undefined; } +/** Resolve display verb/detail from tool args and optional display metadata. */ export function resolveToolVerbAndDetailForArgs(params: { toolKey: string; args?: unknown; @@ -183,6 +188,7 @@ function lookupValueByPath(args: unknown, path: string): unknown { return current; } +/** Format a detail path/key into a short display label. */ export function formatDetailKey(raw: string, overrides: Record = {}): string { let last = ""; for (const segment of raw.split(".")) { @@ -364,6 +370,8 @@ function collectWebSearchQueries(record: Record): string[] { } function parseToolSearchCall(code: string): { target: string; args?: string } | undefined { + // This is a bounded summary parser for display only; execution still uses the + // real tool-search bridge and schema validation. const prefixMatch = code.match(/openclaw\.tools\.call\s*\(\s*/s); if (!prefixMatch || prefixMatch.index === undefined) { return undefined; @@ -565,6 +573,7 @@ function summarizeToolSearchCallInput(raw: string | undefined): string | undefin return undefined; } +/** Infer the bridged tool target displayed for tool_search_code snippets. */ export function resolveToolSearchCodeDisplayTarget( args: unknown, ): ToolSearchCodeDisplayTarget | undefined { @@ -771,6 +780,7 @@ function resolveToolVerbAndDetail(params: { return { verb, detail }; } +/** Normalize final detail text before attaching it to a tool display line. */ export function formatToolDetailText( detail: string | undefined, opts: { prefixWithWith?: boolean } = {},