mirror of
https://github.com/openclaw/openclaw.git
synced 2026-08-05 19:31:40 +00:00
* fix(channels): enforce configured read targets * test(channels): align policy checks with boundaries * fix: bind channel reads to trusted turn context * test: satisfy gateway lint * fix: narrow message action channel imports * fix(feishu): authorize message reads before provider access * fix(slack): await reaction clear authorization * fix(channels): align provider action contracts * fix(matrix): read direct-room account data before sync * fix(channels): reject unsupported attachment actions early * fix: restore trusted operator conversation reads * fix(matrix): authorize pin actions before provider reads * fix: preserve trusted channel read workflows * fix(discord): resolve current channel ids consistently * fix(agents): preserve message action turn capability * fix(plugins): enforce host-owned read provenance * fix(channels): harden Teams and Discord read policy * fix(channels): preserve exact-current action compatibility * fix(imessage): authorize trusted current chat aliases * fix(channels): preserve normalized current aliases * fix(channels): preserve external current target aliases * fix: reconcile channel policy with current main * fix(discord): isolate DM read policy * fix(channels): enforce provider read gates * fix(gateway): await serialized message action identity tokens * fix(ci): refresh channel protocol contracts
98 lines
3.0 KiB
TypeScript
98 lines
3.0 KiB
TypeScript
// Tool invocation methods adapt gateway-visible tools to RPC callers with
|
|
// protocol-shaped success, approval-required, validation, and error payloads.
|
|
import { normalizeOptionalString } from "@openclaw/normalization-core/string-coerce";
|
|
import {
|
|
ErrorCodes,
|
|
errorShape,
|
|
formatValidationErrors,
|
|
validateToolsInvokeParams,
|
|
type ToolsInvokeResult,
|
|
} from "../../../packages/gateway-protocol/src/index.js";
|
|
import { resolveGatewayConversationReadOrigin } from "../conversation-read-origin.js";
|
|
import { invokeGatewayTool } from "../tools-invoke-shared.js";
|
|
import type { GatewayRequestHandlers } from "./types.js";
|
|
|
|
/**
|
|
* RPC adapter for invoking gateway-visible tools from connected clients.
|
|
*/
|
|
function resolveRpcErrorCode(params: {
|
|
type: "invalid_request" | "not_found" | "tool_call_blocked" | "tool_error";
|
|
requiresApproval?: boolean;
|
|
}): string {
|
|
if (params.requiresApproval) {
|
|
return "requires_approval";
|
|
}
|
|
switch (params.type) {
|
|
case "invalid_request":
|
|
return "validation_error";
|
|
case "not_found":
|
|
return "not_found";
|
|
case "tool_call_blocked":
|
|
return "forbidden";
|
|
case "tool_error":
|
|
return "internal_error";
|
|
}
|
|
return "internal_error";
|
|
}
|
|
|
|
/** Handles `tools.invoke` with protocol-shaped success and failure payloads. */
|
|
export const toolsInvokeHandlers: GatewayRequestHandlers = {
|
|
"tools.invoke": async ({ params, respond, context, client }) => {
|
|
if (!validateToolsInvokeParams(params)) {
|
|
respond(
|
|
false,
|
|
undefined,
|
|
errorShape(
|
|
ErrorCodes.INVALID_REQUEST,
|
|
`invalid tools.invoke params: ${formatValidationErrors(validateToolsInvokeParams.errors)}`,
|
|
),
|
|
);
|
|
return;
|
|
}
|
|
const requestedToolName = normalizeOptionalString(params.name);
|
|
if (!requestedToolName) {
|
|
respond(
|
|
false,
|
|
undefined,
|
|
errorShape(ErrorCodes.INVALID_REQUEST, "invalid tools.invoke params: name required"),
|
|
);
|
|
return;
|
|
}
|
|
|
|
const outcome = await invokeGatewayTool({
|
|
cfg: context.getRuntimeConfig(),
|
|
input: params,
|
|
senderIsOwner: client?.connect?.scopes?.includes("operator.admin"),
|
|
clientCaps: client?.connect?.caps,
|
|
conversationReadOrigin: resolveGatewayConversationReadOrigin({
|
|
client,
|
|
requestedOrigin: params.conversationReadOrigin,
|
|
}),
|
|
toolCallIdPrefix: "rpc",
|
|
approvalMode: params.confirm === true ? "request" : "report",
|
|
});
|
|
|
|
if (outcome.ok) {
|
|
const payload: ToolsInvokeResult = {
|
|
ok: true,
|
|
toolName: outcome.toolName,
|
|
output: outcome.result,
|
|
source: outcome.source,
|
|
};
|
|
respond(true, payload, undefined);
|
|
return;
|
|
}
|
|
|
|
const payload: ToolsInvokeResult = {
|
|
ok: false,
|
|
toolName: outcome.toolName || requestedToolName,
|
|
...(outcome.error.requiresApproval ? { requiresApproval: true } : {}),
|
|
error: {
|
|
code: resolveRpcErrorCode(outcome.error),
|
|
message: outcome.error.message,
|
|
},
|
|
};
|
|
respond(true, payload, undefined);
|
|
},
|
|
};
|