Tighten Claude partial tool input parsing
This commit is contained in:
@@ -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<string, unknown>) => 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<string, unknown>) => 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();
|
||||
|
||||
@@ -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,
|
||||
});
|
||||
});
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user