























1+import type { AgentMessage } from "@mariozechner/pi-agent-core";
2+import { describe, expect, it } from "vitest";
3+import { sanitizeReplayToolCallIdsForStream } from "./attempt.tool-call-normalization.js";
4+5+describe("sanitizeReplayToolCallIdsForStream", () => {
6+it("drops orphaned tool results after strict id sanitization", () => {
7+const messages: AgentMessage[] = [
8+{
9+role: "toolResult",
10+toolCallId: "call_function_av7cbkigmk7x1",
11+toolUseId: "call_function_av7cbkigmk7x1",
12+toolName: "read",
13+content: [{ type: "text", text: "stale" }],
14+isError: false,
15+} as never,
16+];
17+18+expect(
19+sanitizeReplayToolCallIdsForStream({
20+ messages,
21+mode: "strict",
22+repairToolUseResultPairing: true,
23+}),
24+).toEqual([]);
25+});
26+27+it("keeps matched assistant and tool-result ids aligned", () => {
28+const rawId = "call_function_av7cbkigmk7x1";
29+const messages: AgentMessage[] = [
30+{
31+role: "assistant",
32+content: [{ type: "toolUse", id: rawId, name: "read", input: { path: "." } }],
33+} as never,
34+{
35+role: "toolResult",
36+toolCallId: rawId,
37+toolUseId: rawId,
38+toolName: "read",
39+content: [{ type: "text", text: "ok" }],
40+isError: false,
41+} as never,
42+];
43+44+const out = sanitizeReplayToolCallIdsForStream({
45+ messages,
46+mode: "strict",
47+repairToolUseResultPairing: true,
48+});
49+50+expect(out).toMatchObject([
51+{
52+role: "assistant",
53+content: [{ type: "toolUse", id: "callfunctionav7cbkigmk7x1", name: "read" }],
54+},
55+{
56+role: "toolResult",
57+toolCallId: "callfunctionav7cbkigmk7x1",
58+toolUseId: "callfunctionav7cbkigmk7x1",
59+toolName: "read",
60+},
61+]);
62+});
63+64+it("keeps real tool results for aborted assistant spans", () => {
65+const rawId = "call_function_av7cbkigmk7x1";
66+const out = sanitizeReplayToolCallIdsForStream({
67+messages: [
68+{
69+role: "assistant",
70+stopReason: "aborted",
71+content: [{ type: "toolUse", id: rawId, name: "read", input: { path: "." } }],
72+} as never,
73+{
74+role: "toolResult",
75+toolCallId: rawId,
76+toolUseId: rawId,
77+toolName: "read",
78+content: [{ type: "text", text: "partial" }],
79+isError: false,
80+} as never,
81+{
82+role: "user",
83+content: [{ type: "text", text: "retry" }],
84+} as never,
85+],
86+mode: "strict",
87+repairToolUseResultPairing: true,
88+});
89+90+expect(out).toMatchObject([
91+{
92+role: "assistant",
93+stopReason: "aborted",
94+content: [{ type: "toolUse", id: "callfunctionav7cbkigmk7x1", name: "read" }],
95+},
96+{
97+role: "toolResult",
98+toolCallId: "callfunctionav7cbkigmk7x1",
99+toolUseId: "callfunctionav7cbkigmk7x1",
100+toolName: "read",
101+},
102+{
103+role: "user",
104+},
105+]);
106+});
107+});
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。