diff --git a/packages/server/src/server/agent/providers/claude-agent.redesign.test.ts b/packages/server/src/server/agent/providers/claude-agent.redesign.test.ts index 75d375af4..37fd2a201 100644 --- a/packages/server/src/server/agent/providers/claude-agent.redesign.test.ts +++ b/packages/server/src/server/agent/providers/claude-agent.redesign.test.ts @@ -441,7 +441,7 @@ describe("ClaudeAgentSession redesign invariants", () => { } }); - test("routes input_json_delta through partial parsing before buffered JSON is complete", async () => { + test("waits for complete JSON values before updating tool input from input_json_delta", async () => { const session = await createSession(); const internal = session as unknown as { mapPartialEvent: (event: Record) => AgentTimelineItem[]; @@ -479,7 +479,7 @@ describe("ClaudeAgentSession redesign invariants", () => { partial_json: '{"command":"echo ', }, }, - expectedCommand: "echo ", + expectedCommand: "echo seed", }, { event: { @@ -520,7 +520,7 @@ describe("ClaudeAgentSession redesign invariants", () => { } }); - test("surfaces canonical partial tool input from input_json_delta before JSON is complete", async () => { + test("does not surface incomplete string values from input_json_delta", async () => { const session = await createSession(); const internal = session as unknown as { mapPartialEvent: (event: Record) => AgentTimelineItem[]; @@ -551,7 +551,6 @@ describe("ClaudeAgentSession redesign invariants", () => { expect(internal.toolUseCache.get(toolUseId)?.input).toEqual({ file_path: "src/message.tsx", - old_string: "before", }); } finally { await session.close(); diff --git a/packages/server/src/server/agent/providers/claude/partial-json.test.ts b/packages/server/src/server/agent/providers/claude/partial-json.test.ts index f4dafb13e..3d9694a4d 100644 --- a/packages/server/src/server/agent/providers/claude/partial-json.test.ts +++ b/packages/server/src/server/agent/providers/claude/partial-json.test.ts @@ -13,33 +13,25 @@ describe("parsePartialJsonObject", () => { }); }); - it("keeps partial string values without field-specific logic", () => { + it("does not emit incomplete string values", () => { expect(parsePartialJsonObject('{"command":"echo ')).toEqual({ - value: { - command: "echo ", - }, + value: {}, complete: false, }); }); - it("returns parsed prefix fields from incomplete objects", () => { + it("returns only complete prefix fields from incomplete objects", () => { expect(parsePartialJsonObject('{"file_path":"src/message.tsx","old_string":"before')).toEqual({ value: { file_path: "src/message.tsx", - old_string: "before", }, complete: false, }); }); - it("parses nested partial values generically", () => { + it("does not emit incomplete nested values", () => { expect(parsePartialJsonObject('{"payload":{"path":"src/index.ts","content":"hello')).toEqual({ - value: { - payload: { - path: "src/index.ts", - content: "hello", - }, - }, + value: {}, complete: false, }); }); diff --git a/packages/server/src/server/agent/providers/claude/partial-json.ts b/packages/server/src/server/agent/providers/claude/partial-json.ts index ca6611a4e..8e8ef3451 100644 --- a/packages/server/src/server/agent/providers/claude/partial-json.ts +++ b/packages/server/src/server/agent/providers/claude/partial-json.ts @@ -271,17 +271,17 @@ function parsePartialObject( }; } - value[parsedKey.value] = parsedMemberValue.value; - currentIndex = skipWhitespace(input, parsedMemberValue.nextIndex); - if (!parsedMemberValue.complete) { return { value, - nextIndex: currentIndex, + nextIndex: skipWhitespace(input, parsedMemberValue.nextIndex), complete: false, }; } + value[parsedKey.value] = parsedMemberValue.value; + currentIndex = skipWhitespace(input, parsedMemberValue.nextIndex); + const delimiter = input[currentIndex]; if (delimiter === ",") { currentIndex += 1;