mirror of
https://github.com/openclaw/openclaw.git
synced 2026-08-24 19:35:28 -06:00
docs: document agent tool adapters
This commit is contained in:
@@ -1,3 +1,8 @@
|
||||
/**
|
||||
* Regression tests for adapter interaction with after_tool_call hooks.
|
||||
* Ensures embedded run subscription handling remains the single after-hook
|
||||
* execution path.
|
||||
*/
|
||||
import type { AgentTool } from "openclaw/plugin-sdk/agent-core";
|
||||
import { Type } from "typebox";
|
||||
import { beforeEach, describe, expect, it, vi } from "vitest";
|
||||
|
||||
@@ -1,3 +1,8 @@
|
||||
/**
|
||||
* Logging tests for tool adapter failures.
|
||||
* Verifies retryable parameter errors expose useful context while intentional
|
||||
* hook blocks and exec secrets stay out of raw logs.
|
||||
*/
|
||||
import type { AgentTool } from "openclaw/plugin-sdk/agent-core";
|
||||
import { Type } from "typebox";
|
||||
import { beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
|
||||
|
||||
@@ -1,3 +1,8 @@
|
||||
/**
|
||||
* Unit coverage for adapting runtime and client-hosted tools.
|
||||
* Exercises result coercion, error wrapping, client delegation, and conflict
|
||||
* detection at the ToolDefinition boundary.
|
||||
*/
|
||||
import type { AgentTool } from "openclaw/plugin-sdk/agent-core";
|
||||
import { Type } from "typebox";
|
||||
import { describe, expect, it } from "vitest";
|
||||
|
||||
@@ -1,3 +1,8 @@
|
||||
/**
|
||||
* Adapts runtime AgentTool objects into session ToolDefinition entries.
|
||||
* Owns hook execution, client-tool delegation, result coercion, and safe
|
||||
* logging for failed tool calls.
|
||||
*/
|
||||
import { createHash } from "node:crypto";
|
||||
import { logDebug, logError } from "../logger.js";
|
||||
import { redactToolDetail } from "../logging/redact.js";
|
||||
@@ -304,6 +309,7 @@ function finalizeToolParamsBeforeExecute(params: {
|
||||
|
||||
export const CLIENT_TOOL_NAME_CONFLICT_PREFIX = "client tool name conflict:";
|
||||
|
||||
/** Find client-hosted tool names that collide with runtime or sibling tools. */
|
||||
export function findClientToolNameConflicts(params: {
|
||||
tools: ClientToolDefinition[];
|
||||
existingToolNames?: Iterable<string>;
|
||||
@@ -338,14 +344,17 @@ export function findClientToolNameConflicts(params: {
|
||||
return Array.from(conflicts);
|
||||
}
|
||||
|
||||
/** Build a recognizable error for rejecting conflicting client tool names. */
|
||||
export function createClientToolNameConflictError(conflicts: string[]): Error {
|
||||
return new Error(`${CLIENT_TOOL_NAME_CONFLICT_PREFIX} ${conflicts.join(", ")}`);
|
||||
}
|
||||
|
||||
/** Detect client tool conflict errors without depending on object identity. */
|
||||
export function isClientToolNameConflictError(err: unknown): err is Error {
|
||||
return err instanceof Error && err.message.startsWith(CLIENT_TOOL_NAME_CONFLICT_PREFIX);
|
||||
}
|
||||
|
||||
/** Convert executable agent tools into session definitions with hook handling. */
|
||||
export function toToolDefinitions(
|
||||
tools: AnyAgentTool[],
|
||||
hookContext?: HookContext,
|
||||
@@ -477,8 +486,7 @@ function coerceParamsRecord(value: unknown): Record<string, unknown> {
|
||||
return {};
|
||||
}
|
||||
|
||||
// Convert client tools (OpenResponses hosted tools) to ToolDefinition format
|
||||
// These tools are intercepted to return a "pending" result instead of executing
|
||||
/** Convert client-hosted tools into pending session definitions. */
|
||||
export function toClientToolDefinitions(
|
||||
tools: ClientToolDefinition[],
|
||||
onClientToolCall?: ClientToolCallRecorder,
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
/**
|
||||
* Fixtures for embedded agent tool-handler state tests.
|
||||
* Keeps large mutable handler state construction centralized so assertions can
|
||||
* focus on the field under test.
|
||||
*/
|
||||
import { createEmbeddedRunReplayState } from "./embedded-agent-runner/replay-state.js";
|
||||
|
||||
// Shared fixture for tests that exercise embedded agent tool handler state.
|
||||
/** Build the minimal mutable state object expected by tool handler tests. */
|
||||
export function createBaseToolHandlerState() {
|
||||
return {
|
||||
|
||||
@@ -1,3 +1,8 @@
|
||||
/**
|
||||
* Normalizes model-facing tool parameter schemas across provider quirks.
|
||||
* Handles local JSON Schema refs, OpenAPI nullable syntax, top-level unions,
|
||||
* and provider-specific unsupported keyword stripping.
|
||||
*/
|
||||
import { isRecord as isSchemaRecord } from "@openclaw/normalization-core/record-coerce";
|
||||
import { normalizeLowercaseStringOrEmpty } from "@openclaw/normalization-core/string-coerce";
|
||||
import { uniqueValues } from "@openclaw/normalization-core/string-normalization";
|
||||
@@ -589,6 +594,7 @@ function inlineLocalSchemaRefsWithDefs(
|
||||
return result;
|
||||
}
|
||||
|
||||
/** Inline local $ref pointers so providers receive self-contained tool schemas. */
|
||||
export function inlineLocalToolSchemaRefs(schema: unknown): TSchema {
|
||||
if (!schema || typeof schema !== "object") {
|
||||
return schema as TSchema;
|
||||
@@ -881,6 +887,7 @@ function normalizeToolParameterSchemaUncached(
|
||||
return applyProviderCleaning(flattenedSchema);
|
||||
}
|
||||
|
||||
/** Return a provider-compatible JSON schema for a model-facing tool. */
|
||||
export function normalizeToolParameterSchema(
|
||||
schema: unknown,
|
||||
options?: ToolParameterSchemaOptions,
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
/**
|
||||
* Tests cron-aware deferred follow-up guidance in exec/process descriptions.
|
||||
* Protects the model-facing text selected after tool filtering.
|
||||
*/
|
||||
import { describe, expect, it } from "vitest";
|
||||
import { applyDeferredFollowupToolDescriptions } from "./agent-tools.deferred-followup.js";
|
||||
import type { AnyAgentTool } from "./agent-tools.types.js";
|
||||
|
||||
@@ -1,8 +1,11 @@
|
||||
/**
|
||||
* Adjusts exec/process tool descriptions for long-running follow-up behavior.
|
||||
* Cron-aware runs can point models at scheduled follow-ups; cronless runs keep
|
||||
* guidance constrained to process polling and wake handling.
|
||||
*/
|
||||
import type { AnyAgentTool } from "./agent-tools.types.js";
|
||||
import { describeExecTool, describeProcessTool } from "./bash-tools.descriptions.js";
|
||||
|
||||
// Updates exec/process tool descriptions with deferred-followup guidance based
|
||||
// on the tools available in the current run.
|
||||
/** Return tools with exec/process descriptions adjusted for cron availability. */
|
||||
export function applyDeferredFollowupToolDescriptions(
|
||||
tools: AnyAgentTool[],
|
||||
|
||||
@@ -1,3 +1,8 @@
|
||||
/**
|
||||
* Tests message-provider tool filtering.
|
||||
* Voice-like transports should not expose text-to-speech when that surface is
|
||||
* unsafe or redundant for the active channel.
|
||||
*/
|
||||
import { describe, expect, it } from "vitest";
|
||||
import { filterToolNamesByMessageProvider } from "./agent-tools.message-provider-policy.js";
|
||||
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
/**
|
||||
* Message-provider tool filtering.
|
||||
* Channels can restrict tool names after runtime assembly when the active
|
||||
* transport cannot safely render or execute a class of tools.
|
||||
*/
|
||||
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"],
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
/**
|
||||
* Tests required parameter validation for model-facing tools.
|
||||
* Covers retry guidance and path-only XML suffix cleanup for file operations.
|
||||
*/
|
||||
import { describe, expect, it, vi } from "vitest";
|
||||
import {
|
||||
assertRequiredParams,
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
/**
|
||||
* Shared validation for model-supplied tool parameters.
|
||||
* Converts malformed file-tool arguments into retryable errors and fixes the
|
||||
* specific XML suffix corruption seen in path arguments.
|
||||
*/
|
||||
import type { AnyAgentTool } from "./agent-tools.types.js";
|
||||
|
||||
// Shared tool parameter validation helpers for file-edit style tools. They turn
|
||||
// model-facing malformed arguments into actionable retry guidance.
|
||||
export type RequiredParamGroup = {
|
||||
keys: readonly string[];
|
||||
allowEmpty?: boolean;
|
||||
@@ -84,6 +87,7 @@ function hasValidEditReplacements(record: Record<string, unknown>): boolean {
|
||||
);
|
||||
}
|
||||
|
||||
/** Required parameter groups for file-style tools that need retry guidance. */
|
||||
export const REQUIRED_PARAM_GROUPS = {
|
||||
read: [{ keys: ["path"], label: "path" }],
|
||||
write: [
|
||||
@@ -140,6 +144,7 @@ function resolveMalformedXmlArgValuePathKeys(
|
||||
return [...keys];
|
||||
}
|
||||
|
||||
/** Throw actionable retry guidance when required tool params are missing. */
|
||||
export function assertRequiredParams(
|
||||
record: Record<string, unknown> | undefined,
|
||||
groups: readonly RequiredParamGroup[],
|
||||
|
||||
@@ -1,3 +1,8 @@
|
||||
/**
|
||||
* Tests layered tool policy resolution.
|
||||
* Covers wildcard matching, sub-agent inheritance, provider overrides, and
|
||||
* trusted group context checks.
|
||||
*/
|
||||
import fs from "node:fs";
|
||||
import os from "node:os";
|
||||
import path from "node:path";
|
||||
|
||||
@@ -1,3 +1,8 @@
|
||||
/**
|
||||
* Resolves sandbox tool policies for agents, providers, sub-agents, and group
|
||||
* sessions. Keeps runtime tool filtering tied to canonical config, session
|
||||
* provenance, and inherited sub-agent capabilities.
|
||||
*/
|
||||
import { normalizeProviderId } from "@openclaw/model-catalog-core/provider-id";
|
||||
import {
|
||||
normalizeLowercaseStringOrEmpty,
|
||||
@@ -97,6 +102,7 @@ function mergeConfiguredSubagentAllow(
|
||||
return allow && alsoAllow ? uniqueStrings([...allow, ...alsoAllow]) : allow;
|
||||
}
|
||||
|
||||
/** Resolve depth-based default deny rules plus configured sub-agent overrides. */
|
||||
export function resolveSubagentToolPolicy(cfg?: OpenClawConfig, depth?: number): SandboxToolPolicy {
|
||||
const configured = cfg?.tools?.subagents?.tools;
|
||||
const maxSpawnDepth =
|
||||
@@ -116,6 +122,7 @@ export function resolveSubagentToolPolicy(cfg?: OpenClawConfig, depth?: number):
|
||||
return { allow: mergedAllow, deny };
|
||||
}
|
||||
|
||||
/** Resolve sub-agent tool policy from stored session capabilities. */
|
||||
export function resolveSubagentToolPolicyForSession(
|
||||
cfg: OpenClawConfig | undefined,
|
||||
sessionKey: string,
|
||||
@@ -147,6 +154,7 @@ export function resolveSubagentToolPolicyForSession(
|
||||
return { allow: mergedAllow, deny };
|
||||
}
|
||||
|
||||
/** Resolve the tool policy inherited from a parent sub-agent session. */
|
||||
export function resolveInheritedToolPolicyForSession(
|
||||
cfg: OpenClawConfig | undefined,
|
||||
sessionKey: string | undefined | null,
|
||||
@@ -171,6 +179,7 @@ export function resolveInheritedToolPolicyForSession(
|
||||
};
|
||||
}
|
||||
|
||||
/** Filter runtime tools by sandbox allow/deny policy. */
|
||||
export function filterToolsByPolicy(tools: AnyAgentTool[], policy?: SandboxToolPolicy) {
|
||||
if (!policy) {
|
||||
return tools;
|
||||
@@ -339,6 +348,7 @@ function resolveTrustedGroupIdFromContexts(params: {
|
||||
return { groupId: null, dropped: true };
|
||||
}
|
||||
|
||||
/** Validate caller-supplied group ids against server-derived session context. */
|
||||
export function resolveTrustedGroupId(params: {
|
||||
groupId?: string | null;
|
||||
sessionKey?: string | null;
|
||||
@@ -354,6 +364,7 @@ export function resolveTrustedGroupId(params: {
|
||||
});
|
||||
}
|
||||
|
||||
/** Resolve model/provider-scoped tool policy from canonical provider keys. */
|
||||
export function resolveProviderToolPolicy(params: {
|
||||
byProvider?: Record<string, ToolPolicyConfig>;
|
||||
modelProvider?: string;
|
||||
@@ -435,6 +446,7 @@ function formatToolListForWarning(toolNames: string[]): string {
|
||||
return toolNames.map((toolName) => `"${toolName}"`).join(", ");
|
||||
}
|
||||
|
||||
/** Resolve the layered global, provider, agent, and profile tool policies. */
|
||||
export function resolveEffectiveToolPolicy(params: {
|
||||
config?: OpenClawConfig;
|
||||
sessionKey?: string;
|
||||
@@ -523,6 +535,7 @@ export function resolveEffectiveToolPolicy(params: {
|
||||
};
|
||||
}
|
||||
|
||||
/** Resolve group-scoped tool policy after validating session provenance. */
|
||||
export function resolveGroupToolPolicy(params: {
|
||||
config?: OpenClawConfig;
|
||||
sessionKey?: string;
|
||||
|
||||
Reference in New Issue
Block a user