docs: document provider tool helpers

This commit is contained in:
Peter Steinberger
2026-06-03 23:13:37 -04:00
parent 8c74fd4e23
commit dd555073d0
4 changed files with 26 additions and 0 deletions

View File

@@ -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)) {

View File

@@ -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<NodeJS.ProcessEnv, Map<string, Record<string, string>>>();
}
@@ -108,6 +112,7 @@ function setPreferredAlias(params: {
}
}
/** Resolve canonical auth provider aliases from plugin metadata. */
export function resolveProviderAuthAliasMap(
params?: ProviderAuthAliasLookupParams,
): Record<string, string> {
@@ -116,6 +121,8 @@ export function resolveProviderAuthAliasMap(
let cacheKey: string | undefined;
let envCache: Map<string, Record<string, string>> | 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,

View File

@@ -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<string>): Set<string> | null {
if (!allowedToolNames) {
return null;
@@ -21,6 +24,7 @@ export function normalizeAllowedToolNames(allowedToolNames?: Iterable<string>):
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<string> | null,

View File

@@ -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, string> = {}): string {
let last = "";
for (const segment of raw.split(".")) {
@@ -364,6 +370,8 @@ function collectWebSearchQueries(record: Record<string, unknown>): 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 } = {},