fix(coding-agent): document mutable tool_call input closes #2611

This commit is contained in:
Mario Zechner
2026-03-27 04:01:20 +01:00
parent f456a7a4db
commit 7fe7081745
3 changed files with 80 additions and 2 deletions

View File

@@ -307,6 +307,68 @@ describe("agentLoop with AgentMessage", () => {
}
});
it("should execute mutated beforeToolCall args without revalidation", async () => {
const toolSchema = Type.Object({ value: Type.String() });
const executed: Array<string | number> = [];
const tool: AgentTool<typeof toolSchema, { value: string | number }> = {
name: "echo",
label: "Echo",
description: "Echo tool",
parameters: toolSchema,
async execute(_toolCallId, params) {
executed.push(params.value as string | number);
return {
content: [{ type: "text", text: `echoed: ${String(params.value)}` }],
details: { value: params.value as string | number },
};
},
};
const context: AgentContext = {
systemPrompt: "",
messages: [],
tools: [tool],
};
const userPrompt: AgentMessage = createUserMessage("echo something");
const config: AgentLoopConfig = {
model: createModel(),
convertToLlm: identityConverter,
beforeToolCall: async ({ args }) => {
const mutableArgs = args as { value: string | number };
mutableArgs.value = 123;
return undefined;
},
};
let callIndex = 0;
const streamFn = () => {
const stream = new MockAssistantStream();
queueMicrotask(() => {
if (callIndex === 0) {
const message = createAssistantMessage(
[{ type: "toolCall", id: "tool-1", name: "echo", arguments: { value: "hello" } }],
"toolUse",
);
stream.push({ type: "done", reason: "toolUse", message });
} else {
const message = createAssistantMessage([{ type: "text", text: "done" }]);
stream.push({ type: "done", reason: "stop", message });
}
callIndex++;
});
return stream;
};
const stream = agentLoop([userPrompt], context, config, undefined, streamFn);
for await (const _event of stream) {
// consume
}
expect(executed).toEqual([123]);
});
it("should execute tool calls in parallel and emit tool results in source order", async () => {
const toolSchema = Type.Object({ value: Type.String() });
let firstResolved = false;