Skip to content

fix(core): keep tool result errors when importing threads - #176

Open
kevin9327 wants to merge 1 commit into
deer-flow:mainfrom
kevin9327:fix/import-tool-result-errors
Open

kevin9327 wants to merge 1 commit into
deer-flow:mainfrom
kevin9327:fix/import-tool-result-errors

Conversation

@kevin9327

Copy link
Copy Markdown

Summary

When a conversation is imported (file import or drag-and-drop), failed tool calls come in as successful:

  • Anthropic Messages JSON: a tool_result block with is_error: true loses the flag.
  • DeerFlow run-event JSONL: DeerFlow persists tool results as ToolMessage.model_dump(), so a failed call carries LangChain's status: "error". That field is ignored too.

The imported tool call then shows as completed rather than errored (getToolCallStatus() reads output.isError). Re-running the thread also replays that result to the model with isError: false (convertToPiContext()), so the model is told a failed call succeeded. For a workbench used to debug agents, that hides exactly the failure being investigated.

normalizeToThread() already resolves both shapes. The flag was simply not carried to _attachToolResult(). It now sets output.isError: true for failed results. Successful results keep the exact { content } output they had before, so already-imported or saved threads do not change shape.

Validation

bun test packages/core/tests/parsers/json-thread-parser.test.ts packages/core/tests/parsers/deerflow-jsonl-thread-parser.test.ts

Before the fix (new tests added, source unchanged):

json-thread-parser.test.ts: 4 pass, 1 fail

packages\core\tests\parsers\json-thread-parser.test.ts:
 96 |       expect(assistant?.role).toBe("assistant");
 97 |       if (assistant?.role === "assistant") {
 98 |         expect(assistant.toolCalls?.[0]?.output).toEqual({
 99 |           content: [{ type: "text", text: "hello" }],
100 |         });
101 |         expect(assistant.toolCalls?.[1]?.output).toEqual({
                                                       ^
error: expect(received).toEqual(expected)

@@ -7,3 +7,3 @@
    ],
-   "isError": true,
  }

- Expected  - 1
+ Received  + 0

      at <anonymous> (packages\core\tests\parsers\json-thread-parser.test.ts:101:50)
(fail) JsonThreadParser > keeps the error flag of imported Anthropic tool results [3.33ms]

 4 pass
 1 fail

deerflow-jsonl-thread-parser.test.ts: 5 pass, 1 fail

packages\core\tests\parsers\deerflow-jsonl-thread-parser.test.ts:
142 |       expect(assistant?.role).toBe("assistant");
143 |       if (assistant?.role === "assistant") {
144 |         expect(assistant.toolCalls?.[0]?.output).toEqual({
145 |           content: [{ type: "text", text: "alpha" }],
146 |         });
147 |         expect(assistant.toolCalls?.[1]?.output).toEqual({
                                                       ^
error: expect(received).toEqual(expected)

@@ -7,3 +7,3 @@
    ],
-   "isError": true,
  }

- Expected  - 1
+ Received  + 0

      at <anonymous> (packages\core\tests\parsers\deerflow-jsonl-thread-parser.test.ts:147:50)
(fail) DeerFlowJsonlThreadParser > keeps the error status of tool results [1.09ms]

 5 pass
 1 fail

After the fix: 11 pass, 0 fail across both files.

  • In each new test, the successful result's assertion (toEqual({ content: [...] }), with no isError key) passes both before and after. The existing DeerFlow import test, which pins a successful tool output exactly, is also unchanged. This shows successful results are not rewritten.
  • bun test packages/core/tests/parsers packages/core/tests/thread packages/core/tests/client: 138 pass, 0 fail.
  • ESLint (--max-warnings 0) on the three touched files: clean on main and on this branch.
  • tsc --noEmit -p tsconfig.json: clean.
  • Prettier: normalize-thread.ts already has 11 unformatted lines on main; this change adds none, and both test files stay clean.

🤖 Generated with Claude Code

Importing an Anthropic Messages dump dropped `is_error` from
`tool_result` blocks, and importing a DeerFlow run-event file dropped
`status: "error"` from LangChain tool messages. Failed tool calls then
showed as successful and were replayed to the model as successful
results. Carry the flag through as `output.isError`; successful results
are unchanged.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant