




















@@ -3,6 +3,7 @@ import { describe, expect, it } from "vitest";
33import { castAgentMessages } from "./test-helpers/agent-message-fixtures.js";
44import {
55isValidCloudCodeAssistToolId,
6+sanitizeToolCallId,
67sanitizeToolCallIdsForCloudCodeAssist,
78} from "./tool-call-id.js";
89@@ -448,6 +449,103 @@ describe("sanitizeToolCallIdsForCloudCodeAssist", () => {
448449expect(aId).not.toMatch(/[_-]/);
449450expect(bId).not.toMatch(/[_-]/);
450451});
452+453+it("preserves native Kimi function ids in direct strict sanitization", () => {
454+expect(sanitizeToolCallId("functions.read:0", "strict")).toBe("functions.read:0");
455+expect(sanitizeToolCallId("functions.bash_tool:12", "strict")).toBe("functions.bash_tool:12");
456+expect(sanitizeToolCallId("functions.edit-file:3", "strict")).toBe("functions.edit-file:3");
457+expect(isValidCloudCodeAssistToolId("functions.read:0", "strict")).toBe(true);
458+expect(isValidCloudCodeAssistToolId("functions.read:0", "strict9")).toBe(false);
459+});
460+461+it("preserves native Kimi function ids across assistant/toolResult pairs", () => {
462+const input = castAgentMessages([
463+{
464+role: "assistant",
465+content: [{ type: "toolCall", id: "functions.read:0", name: "read", arguments: {} }],
466+},
467+{
468+role: "toolResult",
469+toolCallId: "functions.read:0",
470+toolName: "read",
471+content: [{ type: "text", text: "ok" }],
472+},
473+]);
474+475+const out = sanitizeToolCallIdsForCloudCodeAssist(input, "strict");
476+expect(out).toBe(input);
477+});
478+479+it("preserves native Kimi ids while sanitizing non-Kimi siblings", () => {
480+const input = castAgentMessages([
481+{
482+role: "assistant",
483+content: [
484+{ type: "toolCall", id: "functions.read:0", name: "read", arguments: {} },
485+{ type: "toolCall", id: "call_a|b", name: "read", arguments: {} },
486+],
487+},
488+buildToolResult({ toolCallId: "functions.read:0", text: "native" }),
489+buildToolResult({ toolCallId: "call_a|b", text: "sanitized" }),
490+]);
491+492+const out = sanitizeToolCallIdsForCloudCodeAssist(input, "strict");
493+expect(out).not.toBe(input);
494+const assistant = out[0] as Extract<AgentMessage, { role: "assistant" }>;
495+const native = assistant.content?.[0] as { id?: string };
496+const sibling = assistant.content?.[1] as { id?: string };
497+expect(native.id).toBe("functions.read:0");
498+expect(sibling.id).toBe("callab");
499+expect((out[1] as Extract<AgentMessage, { role: "toolResult" }>).toolCallId).toBe(
500+"functions.read:0",
501+);
502+expect((out[2] as Extract<AgentMessage, { role: "toolResult" }>).toolCallId).toBe("callab");
503+});
504+505+it("disambiguates repeated native Kimi ids after preserving the first occurrence", () => {
506+const input = castAgentMessages([
507+{
508+role: "assistant",
509+content: [{ type: "toolCall", id: "functions.read:0", name: "read", arguments: {} }],
510+},
511+buildToolResult({ toolCallId: "functions.read:0", text: "one" }),
512+{
513+role: "assistant",
514+content: [{ type: "toolCall", id: "functions.read:0", name: "read", arguments: {} }],
515+},
516+buildToolResult({ toolCallId: "functions.read:0", text: "two" }),
517+]);
518+519+const out = sanitizeToolCallIdsForCloudCodeAssist(input, "strict");
520+expect(out).not.toBe(input);
521+const first = (out[0] as Extract<AgentMessage, { role: "assistant" }>).content?.[0] as {
522+id?: string;
523+};
524+const second = (out[2] as Extract<AgentMessage, { role: "assistant" }>).content?.[0] as {
525+id?: string;
526+};
527+expect(first.id).toBe("functions.read:0");
528+expect(second.id).not.toBe("functions.read:0");
529+expect(isValidCloudCodeAssistToolId(second.id as string, "strict")).toBe(true);
530+expect((out[1] as Extract<AgentMessage, { role: "toolResult" }>).toolCallId).toBe(
531+"functions.read:0",
532+);
533+expect((out[3] as Extract<AgentMessage, { role: "toolResult" }>).toolCallId).toBe(second.id);
534+});
535+536+it("does not preserve malformed Kimi-like ids", () => {
537+for (const bad of [
538+"functions.read",
539+"functions.:0",
540+"functions.read:",
541+"functions.read:x",
542+"functions.read:0:extra",
543+"xfunctions.read:0",
544+]) {
545+expect(sanitizeToolCallId(bad, "strict")).not.toBe(bad);
546+expect(isValidCloudCodeAssistToolId(bad, "strict")).toBe(false);
547+}
548+});
451549});
452550453551describe("strict9 mode (Mistral tool call IDs)", () => {
@@ -510,5 +608,19 @@ describe("sanitizeToolCallIdsForCloudCodeAssist", () => {
510608expect(out).not.toBe(input);
511609expectStrict9IdLengths(expectToolUseIdsFollowDistinctToolCallIds(out, "strict9"));
512610});
611+612+it("rewrites native Kimi function ids in strict9 mode", () => {
613+const input = castAgentMessages([
614+{
615+role: "assistant",
616+content: [{ type: "toolCall", id: "functions.read:0", name: "read", arguments: {} }],
617+},
618+buildToolResult({ toolCallId: "functions.read:0", text: "ok" }),
619+]);
620+621+const out = sanitizeToolCallIdsForCloudCodeAssist(input, "strict9");
622+expect(out).not.toBe(input);
623+expectSingleToolCallRewrite(out, "functions", "strict9");
624+});
513625});
514626});
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。