From 50efbe56148f754489df23b9fa111dafdbe6155d Mon Sep 17 00:00:00 2001 From: gnanam1990 Date: Mon, 6 Apr 2026 18:08:01 +0530 Subject: [PATCH] fix: skip streaming normalization on finish_reason length Truncated tool calls (finish_reason: 'length') now preserve the raw buffer instead of normalizing into executable commands, preventing incomplete commands from becoming runnable. Co-Authored-By: Claude Opus 4.6 (1M context) --- src/services/api/openaiShim.test.ts | 2 +- src/services/api/openaiShim.ts | 20 +++++++++++++------- 2 files changed, 14 insertions(+), 8 deletions(-) diff --git a/src/services/api/openaiShim.test.ts b/src/services/api/openaiShim.test.ts index e84ff27c..b47d84f6 100644 --- a/src/services/api/openaiShim.test.ts +++ b/src/services/api/openaiShim.test.ts @@ -1420,7 +1420,7 @@ test('does not normalize incomplete streamed Bash commands when finish_reason is .map(event => (event.delta as Record).partial_json) .join('') - expect(streamedInput).toBe('{"command":"rg --fi"}') + expect(streamedInput).toBe('rg --fi') }) test('does not repair truncated Bash objects that do not contain command', async () => { diff --git a/src/services/api/openaiShim.ts b/src/services/api/openaiShim.ts index c781563c..f1100e0e 100644 --- a/src/services/api/openaiShim.ts +++ b/src/services/api/openaiShim.ts @@ -692,16 +692,22 @@ async function* openaiStreamToAnthropic( // Close active tool calls for (const [, tc] of activeToolCalls) { if (tc.normalizeAtStop) { - const repairedStructuredJson = repairPossiblyTruncatedObjectJson( - tc.jsonBuffer, - ) let partialJson: string - if (repairedStructuredJson) { - partialJson = repairedStructuredJson + if (choice.finish_reason === 'length') { + // Truncated by max tokens — preserve raw buffer to avoid + // turning an incomplete tool call into an executable command + partialJson = tc.jsonBuffer } else { - partialJson = JSON.stringify( - normalizeToolArguments(tc.name, tc.jsonBuffer), + const repairedStructuredJson = repairPossiblyTruncatedObjectJson( + tc.jsonBuffer, ) + if (repairedStructuredJson) { + partialJson = repairedStructuredJson + } else { + partialJson = JSON.stringify( + normalizeToolArguments(tc.name, tc.jsonBuffer), + ) + } } yield {