From 3630bf35056b96352aad6dd5aad560bb74d7918d Mon Sep 17 00:00:00 2001 From: Roo Code Date: Sat, 21 Feb 2026 02:48:51 +0000 Subject: [PATCH] fix: use loose null check and fix AttemptCompletionTool empty string rejection - Change !== undefined to != null in NativeToolCallParser.ts (lines 452, 781) to also reject null values from malformed LLM JSON output - Change !result to result == null in AttemptCompletionTool.execute() (line 72) to allow empty strings through instead of rejecting them as missing params - Add test for null result rejection in NativeToolCallParser --- .../assistant-message/NativeToolCallParser.ts | 4 ++-- .../__tests__/NativeToolCallParser.spec.ts | 15 +++++++++++++++ src/core/tools/AttemptCompletionTool.ts | 2 +- 3 files changed, 18 insertions(+), 3 deletions(-) diff --git a/src/core/assistant-message/NativeToolCallParser.ts b/src/core/assistant-message/NativeToolCallParser.ts index ef5824528b..254219bb5d 100644 --- a/src/core/assistant-message/NativeToolCallParser.ts +++ b/src/core/assistant-message/NativeToolCallParser.ts @@ -449,7 +449,7 @@ export class NativeToolCallParser { break case "attempt_completion": - if (partialArgs.result !== undefined) { + if (partialArgs.result != null) { nativeArgs = { result: partialArgs.result } } break @@ -778,7 +778,7 @@ export class NativeToolCallParser { break case "attempt_completion": - if (args.result !== undefined) { + if (args.result != null) { nativeArgs = { result: args.result } as NativeArgsFor } break diff --git a/src/core/assistant-message/__tests__/NativeToolCallParser.spec.ts b/src/core/assistant-message/__tests__/NativeToolCallParser.spec.ts index 20706af5a9..b306bb1595 100644 --- a/src/core/assistant-message/__tests__/NativeToolCallParser.spec.ts +++ b/src/core/assistant-message/__tests__/NativeToolCallParser.spec.ts @@ -386,6 +386,21 @@ describe("NativeToolCallParser", () => { } }) + it("should reject attempt_completion with null result", () => { + const toolCall = { + id: "toolu_completion_null", + name: "attempt_completion" as const, + arguments: JSON.stringify({ + result: null, + }), + } + + const result = NativeToolCallParser.parseToolCall(toolCall) + + // null result should be rejected (no nativeArgs produced, parseToolCall returns null) + expect(result).toBeNull() + }) + it("should handle streaming attempt_completion with empty string result", () => { const id = "toolu_streaming_completion" NativeToolCallParser.startStreamingToolCall(id, "attempt_completion") diff --git a/src/core/tools/AttemptCompletionTool.ts b/src/core/tools/AttemptCompletionTool.ts index a406a15c8b..14f8a5158a 100644 --- a/src/core/tools/AttemptCompletionTool.ts +++ b/src/core/tools/AttemptCompletionTool.ts @@ -69,7 +69,7 @@ export class AttemptCompletionTool extends BaseTool<"attempt_completion"> { } try { - if (!result) { + if (result == null) { task.consecutiveMistakeCount++ task.recordToolError("attempt_completion") pushToolResult(await task.sayAndCreateMissingParamError("attempt_completion", "result"))