import type {
AgentTool,
AgentToolResult,
AgentToolUpdateCallback,
} from "@mariozechner/pi-agent-core"; import type { ToolDefinition } from "@mariozechner/pi-coding-agent"; import { logDebug, logError } from "../logger.js"; import { redactToolDetail } from "../logging/redact.js"; import { isPlainObject } from "../utils.js"; import { sanitizeForConsole } from "./console-sanitize.js"; import type { ClientToolDefinition } from "./pi-embedded-runner/run/params.js"; import type { HookContext } from "./pi-tools.before-tool-call.js"; import {
isToolWrappedWithBeforeToolCallHook,
runBeforeToolCallHook,
} from "./pi-tools.before-tool-call.js"; import { normalizeToolName } from "./tool-policy.js"; import { jsonResult, payloadTextResult } from "./tools/common.js";
/** *Coercetool-callparamsintoaplainobject. * *Someproviders(e.g.Gemini)streamtool-callargumentsasincremental *stringdeltas.Bythetimetheframeworkinvokesthetool's`execute` *callbacktheaccumulatedvaluemaystillbeaJSON**string**ratherthan *aparsedobject.`isPlainObject()`returns`false`forstrings,which *causedtheparamstobesilentlyreplacedwith`{}`. * *Thishelpertries`JSON.parse`whenthevalueisastringandfallsback *toanemptyobjectonlywhenparsinggenuinelyfails.
*/ function coerceParamsRecord(value: unknown): Record<string, unknown> { if (isPlainObject(value)) { return value;
} if (typeof value === "string") { const trimmed = value.trim(); if (trimmed.length > 0) { try { const parsed: unknown = JSON.parse(trimmed); if (isPlainObject(parsed)) { return parsed;
}
} catch { // not valid JSON – fall through to empty object
}
}
} return {};
}
// Convert client tools (OpenResponses hosted tools) to ToolDefinition format // These tools are intercepted to return a "pending" result instead of executing
export function toClientToolDefinitions(
tools: ClientToolDefinition[],
onClientToolCall?: (toolName: string, params: Record<string, unknown>) => void,
hookContext?: HookContext,
): ToolDefinition[] { return tools.map((tool) => { const func = tool.function; return {
name: func.name,
label: func.name,
description: func.description ?? "",
parameters: func.parameters as ToolDefinition["parameters"],
execute: async (...args: ToolExecuteArgs): Promise<AgentToolResult<unknown>> => { const { toolCallId, params } = splitToolExecuteArgs(args); const outcome = await runBeforeToolCallHook({
toolName: func.name,
params,
toolCallId,
ctx: hookContext,
}); if (outcome.blocked) { thrownew Error(outcome.reason);
} const adjustedParams = outcome.params; const paramsRecord = coerceParamsRecord(adjustedParams); // Notify handler that a client tool was called if (onClientToolCall) {
onClientToolCall(func.name, paramsRecord);
} // Return a pending result - the client will execute this tool return jsonResult({
status: "pending",
tool: func.name,
message: "Tool execution delegated to client",
});
},
} satisfies ToolDefinition;
});
}
Messung V0.5 in Prozent
¤ Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.0.13Bemerkung:
(vorverarbeitet am 2026-06-09)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.