fix: dedupe before_tool_call in embedded runtime (#15635) (thanks @lailoo)

This commit is contained in:
Peter Steinberger
2026-02-14 02:48:51 +01:00
parent 534e4213a1
commit 8c3cc793b7
6 changed files with 108 additions and 31 deletions

View File

@@ -12,6 +12,9 @@ type HookContext = {
type HookOutcome = { blocked: true; reason: string } | { blocked: false; params: unknown };
const log = createSubsystemLogger("agents/tools");
const BEFORE_TOOL_CALL_WRAPPED = Symbol("beforeToolCallWrapped");
const adjustedParamsByToolCallId = new Map<string, unknown>();
const MAX_TRACKED_ADJUSTED_PARAMS = 1024;
export async function runBeforeToolCallHook(args: {
toolName: string;
@@ -71,7 +74,7 @@ export function wrapToolWithBeforeToolCallHook(
return tool;
}
const toolName = tool.name || "tool";
return {
const wrappedTool: AnyAgentTool = {
...tool,
execute: async (toolCallId, params, signal, onUpdate) => {
const outcome = await runBeforeToolCallHook({
@@ -83,12 +86,39 @@ export function wrapToolWithBeforeToolCallHook(
if (outcome.blocked) {
throw new Error(outcome.reason);
}
if (toolCallId) {
adjustedParamsByToolCallId.set(toolCallId, outcome.params);
if (adjustedParamsByToolCallId.size > MAX_TRACKED_ADJUSTED_PARAMS) {
const oldest = adjustedParamsByToolCallId.keys().next().value;
if (oldest) {
adjustedParamsByToolCallId.delete(oldest);
}
}
}
return await execute(toolCallId, outcome.params, signal, onUpdate);
},
};
Object.defineProperty(wrappedTool, BEFORE_TOOL_CALL_WRAPPED, {
value: true,
enumerable: false,
});
return wrappedTool;
}
export function isToolWrappedWithBeforeToolCallHook(tool: AnyAgentTool): boolean {
const taggedTool = tool as unknown as Record<symbol, unknown>;
return taggedTool[BEFORE_TOOL_CALL_WRAPPED] === true;
}
export function consumeAdjustedParamsForToolCall(toolCallId: string): unknown {
const params = adjustedParamsByToolCallId.get(toolCallId);
adjustedParamsByToolCallId.delete(toolCallId);
return params;
}
export const __testing = {
BEFORE_TOOL_CALL_WRAPPED,
adjustedParamsByToolCallId,
runBeforeToolCallHook,
isPlainObject,
};