mirror of
https://github.com/openclaw/openclaw.git
synced 2026-08-28 13:26:04 -06:00
docs: document agent runtime tool policies
This commit is contained in:
@@ -1,5 +1,8 @@
|
||||
import { normalizeOptionalLowercaseString } from "@openclaw/normalization-core/string-coerce";
|
||||
|
||||
// Message providers can narrow the tool surface when a channel cannot safely
|
||||
// render or execute a tool class. The policy is name-based because channel
|
||||
// delivery happens after tools are already assembled.
|
||||
const TOOL_DENY_BY_MESSAGE_PROVIDER: Readonly<Record<string, readonly string[]>> = {
|
||||
"discord-voice": ["tts"],
|
||||
voice: ["tts"],
|
||||
@@ -9,6 +12,7 @@ const TOOL_ALLOW_BY_MESSAGE_PROVIDER: Readonly<Record<string, readonly string[]>
|
||||
node: ["canvas", "image", "pdf", "tts", "web_fetch", "web_search"],
|
||||
};
|
||||
|
||||
/** Filters tool names by the active message-provider allow/deny policy. */
|
||||
export function filterToolNamesByMessageProvider(
|
||||
toolNames: readonly string[],
|
||||
messageProvider?: string,
|
||||
@@ -30,6 +34,7 @@ export function filterToolNamesByMessageProvider(
|
||||
return toolNames.filter((toolName) => !deniedSet.has(toolName));
|
||||
}
|
||||
|
||||
/** Applies message-provider filtering while preserving duplicate tool entries. */
|
||||
export function filterToolsByMessageProvider<TTool extends { name: string }>(
|
||||
tools: readonly TTool[],
|
||||
messageProvider?: string,
|
||||
@@ -43,6 +48,8 @@ export function filterToolsByMessageProvider<TTool extends { name: string }>(
|
||||
remainingCounts.set(toolName, (remainingCounts.get(toolName) ?? 0) + 1);
|
||||
}
|
||||
return tools.filter((tool) => {
|
||||
// Counted matching preserves the original order and duplicate instances
|
||||
// after name-level policy filtering.
|
||||
const remaining = remainingCounts.get(tool.name) ?? 0;
|
||||
if (remaining <= 0) {
|
||||
return false;
|
||||
|
||||
@@ -5,10 +5,14 @@ import {
|
||||
import { normalizeUniqueSingleOrTrimmedStringList } from "@openclaw/normalization-core/string-normalization";
|
||||
import type { OpenClawConfig } from "../config/types.openclaw.js";
|
||||
|
||||
// Scope refs feed provider discovery and model catalog lookups. Keep the
|
||||
// ordering deterministic so prompt/cache inputs do not drift across runs.
|
||||
function dedupeCatalogScopeRefs(values: Array<string | undefined>): string[] {
|
||||
return normalizeUniqueSingleOrTrimmedStringList(values);
|
||||
}
|
||||
|
||||
// Accept provider/model refs in addition to separate provider fields so aliases
|
||||
// and user-entered model refs discover the owning provider catalog.
|
||||
function providerFromModelRef(value: string | undefined): string | undefined {
|
||||
const trimmed = value?.trim();
|
||||
if (!trimmed) {
|
||||
@@ -33,6 +37,7 @@ function providerConfigDeclaresModel(
|
||||
);
|
||||
}
|
||||
|
||||
/** Resolves provider/model refs used to scope model catalog discovery. */
|
||||
export function resolveModelCatalogScope(params: {
|
||||
cfg?: OpenClawConfig;
|
||||
provider: string;
|
||||
@@ -50,6 +55,7 @@ export function resolveModelCatalogScope(params: {
|
||||
};
|
||||
}
|
||||
|
||||
/** Extracts provider ids from resolved catalog scope refs for discovery calls. */
|
||||
export function resolveProviderDiscoveryProviderIdsForCatalogScope(params: {
|
||||
providerRefs?: readonly string[];
|
||||
modelRefs?: readonly string[];
|
||||
|
||||
@@ -9,10 +9,14 @@ import {
|
||||
import type { AgentRuntimeAuthPlan } from "./types.js";
|
||||
|
||||
const CODEX_HARNESS_AUTH_PROVIDER = "openai";
|
||||
// Empty metadata disables plugin alias lookups without changing the downstream
|
||||
// resolver contract, matching the "plugins disabled" runtime-plan state.
|
||||
const EMPTY_PROVIDER_AUTH_ALIAS_METADATA = {
|
||||
plugins: [],
|
||||
} satisfies NonNullable<ProviderAuthAliasLookupParams["metadataSnapshot"]>;
|
||||
|
||||
// Harness runtimes that authenticate through a different provider must be
|
||||
// resolved before session auth profiles can be forwarded.
|
||||
function resolveHarnessAuthProvider(params: {
|
||||
harnessId?: string;
|
||||
harnessRuntime?: string;
|
||||
@@ -22,6 +26,7 @@ function resolveHarnessAuthProvider(params: {
|
||||
return harnessId === "codex" || runtime === "codex" ? CODEX_HARNESS_AUTH_PROVIDER : undefined;
|
||||
}
|
||||
|
||||
/** Builds the auth forwarding plan for one resolved agent runtime. */
|
||||
export function buildAgentRuntimeAuthPlan(params: {
|
||||
provider: string;
|
||||
authProfileProvider?: string;
|
||||
@@ -64,6 +69,8 @@ export function buildAgentRuntimeAuthPlan(params: {
|
||||
!harnessProviderForAuth && providerForAuth === authProfileProviderForAuth;
|
||||
const canForwardProfile = providerCanForwardProfile || harnessCanForwardProfile;
|
||||
|
||||
// Forward only when the selected provider/harness resolves to the same auth
|
||||
// owner as the stored session profile; otherwise the runtime must choose auth.
|
||||
return {
|
||||
providerForAuth,
|
||||
authProfileProviderForAuth,
|
||||
|
||||
@@ -15,6 +15,8 @@ import {
|
||||
} from "../tool-schema-projection.js";
|
||||
import type { AgentRuntimePlan } from "./types.js";
|
||||
|
||||
// Shared by normalization and diagnostics so the same provider/model/runtime
|
||||
// context reaches both runtime-plan hooks and provider fallback code.
|
||||
type AgentRuntimeToolPolicyParams<TSchemaType extends TSchema = TSchema, TResult = unknown> = {
|
||||
runtimePlan?: AgentRuntimePlan;
|
||||
tools: AgentTool<TSchemaType, TResult>[];
|
||||
@@ -33,6 +35,7 @@ type AgentRuntimeToolPolicyParams<TSchemaType extends TSchema = TSchema, TResult
|
||||
) => void;
|
||||
};
|
||||
|
||||
/** Builds the provider/runtime context passed into runtime-plan tool hooks. */
|
||||
function runtimePlanToolContext(params: {
|
||||
workspaceDir?: string;
|
||||
modelApi?: string | null;
|
||||
@@ -45,6 +48,8 @@ function runtimePlanToolContext(params: {
|
||||
};
|
||||
}
|
||||
|
||||
// Normalizers may return cloned tool definitions. Copy plugin/channel metadata
|
||||
// so downstream inventory, delivery, and attribution still know the owner.
|
||||
function copyRuntimeToolMetadata(source: AgentTool, target: AgentTool): void {
|
||||
if (source === target) {
|
||||
return;
|
||||
@@ -53,6 +58,8 @@ function copyRuntimeToolMetadata(source: AgentTool, target: AgentTool): void {
|
||||
copyChannelAgentToolMeta(source as never, target as never);
|
||||
}
|
||||
|
||||
// Duplicate names cannot be matched by map lookup alone, so same-index matches
|
||||
// take precedence and unique-name fallback covers cloned arrays.
|
||||
function preserveRuntimeToolMetadata<TSchemaType extends TSchema = TSchema, TResult = unknown>(
|
||||
sourceTools: AgentTool<TSchemaType, TResult>[],
|
||||
normalizedTools: AgentTool<TSchemaType, TResult>[],
|
||||
@@ -81,6 +88,7 @@ function preserveRuntimeToolMetadata<TSchemaType extends TSchema = TSchema, TRes
|
||||
return normalizedTools;
|
||||
}
|
||||
|
||||
/** Normalizes tool schemas through a runtime plan or provider fallback policy. */
|
||||
export function normalizeAgentRuntimeTools<
|
||||
TSchemaType extends TSchema = TSchema,
|
||||
TResult = unknown,
|
||||
@@ -115,6 +123,7 @@ export function normalizeAgentRuntimeTools<
|
||||
return preserveRuntimeToolMetadata(normalizableTools, normalizedTools);
|
||||
}
|
||||
|
||||
/** Emits runtime-plan or provider fallback diagnostics for normalized tools. */
|
||||
export function logAgentRuntimeToolDiagnostics(params: AgentRuntimeToolPolicyParams): void {
|
||||
const planContext = runtimePlanToolContext(params);
|
||||
if (params.runtimePlan) {
|
||||
|
||||
@@ -20,6 +20,8 @@ import type { AnyAgentTool } from "./tools/common.js";
|
||||
|
||||
const BUNDLE_MCP_PLUGIN_ID = "bundle-mcp";
|
||||
|
||||
// MCP tools often expose low-signal labels identical to their names. Prefer the
|
||||
// display resolver in that case so inventory output stays readable.
|
||||
function resolveMcpToolLabel(tool: AnyAgentTool): string {
|
||||
const rawLabel = normalizeOptionalString(tool.label) ?? "";
|
||||
if (
|
||||
@@ -42,6 +44,8 @@ function summarizeToolDescription(tool: AnyAgentTool): string {
|
||||
});
|
||||
}
|
||||
|
||||
// Runtime schema diagnostics become operator-facing notices on the effective
|
||||
// inventory screen instead of silently hiding quarantined MCP tools.
|
||||
function buildMcpUnsupportedToolSchemaNotice(
|
||||
diagnostic: RuntimeToolSchemaDiagnostic,
|
||||
): EffectiveToolInventoryNotice {
|
||||
@@ -52,6 +56,8 @@ function buildMcpUnsupportedToolSchemaNotice(
|
||||
};
|
||||
}
|
||||
|
||||
// Duplicate labels are ambiguous in inventory UIs; add the plugin/id only where
|
||||
// needed so unique entries keep their concise display names.
|
||||
function disambiguateLabels(entries: EffectiveToolInventoryEntry[]): EffectiveToolInventoryEntry[] {
|
||||
const counts = new Map<string, number>();
|
||||
for (const entry of entries) {
|
||||
@@ -85,6 +91,7 @@ function buildMcpToolInventoryEntries(
|
||||
);
|
||||
}
|
||||
|
||||
/** Builds the runtime-compatible MCP tool inventory and quarantine notices. */
|
||||
export function buildRuntimeCompatibleMcpToolInventory(params: {
|
||||
tools: readonly AnyAgentTool[];
|
||||
cfg: OpenClawConfig;
|
||||
|
||||
Reference in New Issue
Block a user