Skip to content

fix: preserve text block structure when externalizing large toolResult content#235

Merged
jalehman merged 2 commits intoMartian-Engineering:mainfrom
tmchow:fix/196-bedrock-externalize-text
Apr 3, 2026
Merged

fix: preserve text block structure when externalizing large toolResult content#235
jalehman merged 2 commits intoMartian-Engineering:mainfrom
tmchow:fix/196-bedrock-externalize-text

Conversation

@tmchow
Copy link
Copy Markdown
Contributor

@tmchow tmchow commented Apr 2, 2026

Summary

When interceptLargeToolResults externalizes a large plain-text content block ({type: "text", text: "..."}) inside a toolResult message, it rewrites it to {type: "tool_result", output: "..."}, dropping the text field. The amazon-bedrock provider crashes on sanitizeSurrogates(c.text) because c.text is undefined.

Changes

src/engine.ts -- interceptLargeToolResults() now branches on isPlainTextToolResult:

  • Plain text blocks ({type: "text", text: "..."}) keep {type: "text", text: ref} after externalization
  • Tool result blocks (tool_result, function_call_output) keep existing {type: normalizedRawType, output: ref} behavior
  • A rawType metadata field carries the original type through storage so the assembler can reconstruct the correct part type during assemble()

src/engine.ts -- assemble() path reads rawType from stored metadata instead of the block's runtime type, so externalized text blocks round-trip correctly through storage and reassembly.

test/engine.test.ts -- Updated the externalization test to check text field for plain-text blocks (was checking output).

Testing

npm test passes (463/464, 1 pre-existing failure in circuit-breaker.test.ts on main).

Fixes #196

This contribution was developed with AI assistance (Codex).

…t content

When a toolResult message contains a plain-text content block
({type: "text", text: "..."}) that exceeds the externalization
threshold, interceptLargeToolResults now keeps {type: "text", text: ref}
instead of rewriting to {type: "tool_result", output: ref}.

This prevents the amazon-bedrock provider from crashing on
sanitizeSurrogates(c.text) when c.text is undefined.

The assembler path also reads rawType from stored metadata so
reassembled blocks reconstruct the correct part type.

Fixes Martian-Engineering#196
Make the assembler reconstruct externalized plain-text tool results as
`{ type: "text", text: ... }` instead of forcing them back through the
`tool_result`/`output` shape. Tighten the regression tests so they assert
the exact assembled block shape, and add assembler coverage for the
externalized-text path.

Regeneration-Prompt: |
  Review feedback on PR 235 showed the previous change only altered how
  large plain-text tool results were stored, not how they were assembled
  back into runtime messages. The bug report was that Bedrock reads
  `c.text` for plain text tool-result content, and the PR still rebuilt
  those externalized blocks as `tool_result` objects with `output`, so the
  provider would still see `undefined`.

  Fix the round-trip at the assembler layer with the smallest additive
  change. Preserve existing behavior for structured tool results and
  function_call_output blocks. Add regression tests that fail unless the
  assembled block is actually `type: "text"` with a `text` field, and add
  focused assembler coverage for the externalized plain-text case.
@jalehman jalehman merged commit ad4b057 into Martian-Engineering:main Apr 3, 2026
1 check passed
@jalehman
Copy link
Copy Markdown
Contributor

jalehman commented Apr 3, 2026

Thank you!

@tmchow
Copy link
Copy Markdown
Contributor Author

tmchow commented Apr 4, 2026

Appreciate the merge, @jalehman.

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.

[Bug] Externalized large toolResult messages crash amazon-bedrock provider — text block rewritten as tool_result with no text field

2 participants