Skip to content

[superseded] [fix]: Preserve document blocks in Bedrock tool results - #5662

Closed
michaeldunn9 wants to merge 1 commit into
maximhq:devfrom
michaeldunn9:codex/fix-document-tool-results
Closed

michaeldunn9 wants to merge 1 commit into
maximhq:devfrom
michaeldunn9:codex/fix-document-tool-results

Conversation

@michaeldunn9

Copy link
Copy Markdown
Contributor

Summary

Preserves valid Anthropic document blocks nested inside tool_result content when routing to Bedrock Converse.

Previously the document was discarded twice: first by both Anthropic-to-Bifrost tool-result converters, then by the Bedrock structured function-output converter. The model received adjacent text but not the generated document.

The existing Responses input_file block remains the canonical internal representation; no public schema, transport, config, or UI change is required.

Before

flowchart LR
    P["Pydantic DocumentUrl"] --> A["Anthropic tool_result.document"]
    A --> X["Grouped or non-grouped converter"]
    X --> B["Bifrost function_call_output"]
    B --> Y["Bedrock tool-result converter"]
    Y --> C["Bedrock toolResult"]

    X -. "document case missing" .-> D1["Document discarded"]
    Y -. "file case missing" .-> D2["Document discarded"]
Loading

After

flowchart LR
    P["Pydantic DocumentUrl"] --> A["Anthropic tool_result.document"]
    A --> H1["Shared Anthropic tool-result mapper"]
    H1 --> B["Canonical Bifrost file block"]
    B --> H2["Shared Bedrock document materializer"]
    H2 --> C["Bedrock toolResult.content.document"]

    H2 --> U["Fetch URL when necessary"]
    H2 --> I["Decode inline base64 when supplied"]
    H2 --> F["Normalize name and document format"]
Loading

Changes

  • Added one private Anthropic mapper for nested tool-result text, image, and document blocks, used by both grouped and non-grouped conversion.
  • Preserved document title, URL, inline data, and MIME type in the canonical Responses file block.
  • Added one private Bedrock document materializer for filename normalization, MIME-to-format mapping, data-URL stripping, plain-text handling, and bounded URL fetching.
  • Reused that materializer from chat file content, regular Responses file content, and structured function-call output.
  • Added the missing file case to Bedrock toolResult.content conversion and return document conversion/fetch errors instead of silently emitting an empty successful result.
  • Updated the prior test that described documents as unsupported.
  • Added focused grouped, non-grouped, inline, URL, SSRF, ordering, empty-content, and cross-provider regression coverage.
  • Added the required core changelog entry.

Using shared private mappers keeps all public schemas unchanged and prevents the grouped/non-grouped Anthropic paths or the three Bedrock document paths from drifting again.

Type of change

  • Bug fix
  • Feature
  • Refactor
  • Documentation
  • Chore/CI

Affected areas

  • Core (Go)
  • Transports (HTTP)
  • Providers/Integrations
  • Plugins
  • UI (React)
  • Docs

How to test

cd core

go test ./providers/anthropic -run ToolResultDocument -count=1
go test ./providers/bedrock -run ToolResultDocument -count=1
go test ./providers/anthropic ./providers/bedrock -count=1
go test -race ./providers/anthropic ./providers/bedrock \
  -run 'ToolResultDocument|ConvertToolResultWithDocumentBlock|ConvertToolResultWithEmptyContent' -count=1
go test -tags pooldebug ./providers/anthropic ./providers/bedrock \
  -run 'ToolResultDocument|ConvertToolResultWithDocumentBlock|ConvertToolResultWithEmptyContent' -count=1
go vet ./providers/anthropic ./providers/bedrock
golangci-lint run --new-from-rev=upstream/dev ./...

cd ..
make test-core

Results:

  • Focused Anthropic and Bedrock regressions: pass.
  • Complete Anthropic and Bedrock provider packages: pass.
  • Race and pooldebug focused runs: pass.
  • Provider go vet: pass.
  • Diff-only lint against upstream/dev: 0 issues.
  • Canonical all-provider harness: 2,974 passed, 0 failed, 33 skipped.
  • Live Anthropic and Bedrock scenarios were among the credential-gated skips because ANTHROPIC_API_KEY and AWS credentials are not configured locally; all local provider regression/unit tests executed.

Screenshots/Recordings

N/A — provider conversion fix with no UI changes.

Breaking changes

  • Yes
  • No

No public schema or API contract changes.

Related issues

Closes #5661

Security considerations

URL-backed documents continue to use providerUtils.FetchAndEncodeURL, which enforces HTTP(S)-only URLs, request deadlines, a 25 MiB body limit, redirect limits, non-2xx errors, and dial-time SSRF protection. A regression test verifies a loopback URL is rejected before the test server is reached. No credentials, secrets, or document contents are logged.

Checklist

  • I read the repository contribution, code-convention, and PR guidelines and followed them
  • I added/updated tests where appropriate
  • I evaluated documentation impact (none required: no public API/config behavior changed)
  • I verified the affected Go builds and canonical core test harness succeed
  • Commit and PR title follow the required [type]: description format
  • The commit body lists every affected package
  • The core changelog entry is at the top and includes the contributor link

Affected packages:
- core/providers/anthropic/
- core/providers/bedrock/
- core/changelog.md
@coderabbitai

coderabbitai Bot commented Jul 29, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Summary by CodeRabbit

  • Bug Fixes

    • Preserved documents in Anthropic and Bedrock tool results, including URLs, inline data, filenames, and media types.
    • Improved document conversion consistency across provider and tool-result workflows.
    • Added safe handling for unsupported or restricted document URLs.
    • Preserved text and document ordering during cross-provider conversions.
  • Tests

    • Added coverage for document serialization, URL handling, inline files, media types, and provider round trips.

Walkthrough

Anthropic tool-result conversion now preserves document blocks as canonical file content. Bedrock centralizes document materialization for inline data and URLs, then uses it for tool results and regular file blocks. Tests cover grouped and non-grouped conversion, format normalization, URL handling, SSRF protection, and cross-provider round trips.

Changes

Document tool-result preservation

Layer / File(s) Summary
Anthropic tool-result conversion
core/providers/anthropic/responses.go, core/providers/anthropic/*test.go
Shared conversion preserves supported text, image, and document blocks across grouped and non-grouped paths, including document URLs and base64 data.
Bedrock document materialization
core/providers/bedrock/utils.go
Centralized format detection, filename normalization, URL fetching, data-URL parsing, and text or byte source construction.
Bedrock tool-result wiring and validation
core/providers/bedrock/responses.go, core/providers/bedrock/toolresultdocument_test.go, core/changelog.md
Bedrock tool-result and file conversion use the shared materializer; tests cover inline documents, URL failures, SSRF-safe fetching, and Anthropic-to-Bedrock round trips.

Estimated code review effort: 4 (Complex) | ~45 minutes

Sequence Diagram(s)

sequenceDiagram
  participant AnthropicToolResult
  participant AnthropicConverter
  participant BedrockMaterializer
  participant BedrockConverse
  AnthropicToolResult->>AnthropicConverter: convert text and document blocks
  AnthropicConverter->>BedrockMaterializer: pass canonical file content
  BedrockMaterializer->>BedrockConverse: send inline Bedrock document
Loading

Possibly related PRs

  • maximhq/bifrost#5503: Updates related Bedrock file and tool-document format normalization and data-URL handling.

Suggested reviewers: akshaydeo, pratham-mishra04, tejasghatte

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title is concise and accurately describes the main fix: preserving document blocks in Bedrock tool results.
Description check ✅ Passed The description follows the template well and includes summary, changes, testing, related issues, security, and checklist sections.
Linked Issues check ✅ Passed The changes address #5661 by preserving document blocks, handling base64 and URL sources, preserving order, and adding SSRF-safe Bedrock conversion tests.
Out of Scope Changes check ✅ Passed The changes stay focused on Anthropic and Bedrock document conversion plus supporting tests and changelog updates.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 golangci-lint (2.12.2)

level=error msg="[linters_context] typechecking error: pattern ./...: directory prefix . does not contain main module or its selected dependencies"


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (2)
core/providers/bedrock/utils.go (1)

191-219: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

Unrecognized document types silently fall back to "pdf".

Any fileType that doesn't match a known extension/MIME type (e.g. a typo'd type, or a genuinely unsupported format like RTF/ODT) falls through to return "pdf", false. Since Bedrock's format enum is fixed anyway, unsupported types will fail either way, but mislabeling the actual bytes as "pdf" turns a clear "unsupported document type" signal into an opaque downstream parse failure on Bedrock's side instead of a clear error at conversion time.

♻️ Suggested improvement: surface a clear error for genuinely unrecognized types
 func bedrockDocumentFormat(fileType string) (format string, isText bool) {
 	normalized := strings.ToLower(strings.TrimSpace(fileType))
 	if mediaType, _, err := mime.ParseMediaType(normalized); err == nil {
 		normalized = mediaType
 	}
 
 	switch {
 	case normalized == "text/markdown" || normalized == "md":
 		return "md", true
 	...
 	case strings.Contains(normalized, "pdf") || normalized == "pdf":
 		return "pdf", false
 	default:
-		return "pdf", false
+		// Fall back to pdf only for empty/unspecified types; treat other
+		// unrecognized types as an explicit error upstream if strictness is desired.
+		return "pdf", false
 	}
 }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@core/providers/bedrock/utils.go` around lines 191 - 219, Update
bedrockDocumentFormat to distinguish unsupported or unrecognized file types from
recognized formats instead of defaulting them to "pdf". Propagate a clear
unsupported-document-type error to the caller, while preserving the existing
mappings and return behavior for all recognized MIME types and extensions.
core/providers/anthropic/responses.go (1)

7839-7871: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Good centralization; consider reusing for mcp_tool_result too.

convertAnthropicToolResultContentBlocks correctly consolidates text/image/document handling and is now shared by both grouped and non-grouped paths, matching the PR's stated goal. Note that the unrelated AnthropicContentBlockTypeMCPToolResult case (further down, unchanged in this diff) still inlines its own loop that only converts Text blocks — image/document content inside an MCP tool result would still be silently dropped there. Not a regression from this PR, but a good candidate to reuse this new helper for in a follow-up.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@core/providers/anthropic/responses.go` around lines 7839 - 7871, Update the
AnthropicContentBlockTypeMCPToolResult handling to reuse
convertAnthropicToolResultContentBlocks instead of its inline text-only
conversion loop. Pass the MCP tool result content blocks and the appropriate
isOutputMessage value so text, image, and document content are all preserved
consistently.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@core/providers/anthropic/responses.go`:
- Around line 7839-7871: Update the AnthropicContentBlockTypeMCPToolResult
handling to reuse convertAnthropicToolResultContentBlocks instead of its inline
text-only conversion loop. Pass the MCP tool result content blocks and the
appropriate isOutputMessage value so text, image, and document content are all
preserved consistently.

In `@core/providers/bedrock/utils.go`:
- Around line 191-219: Update bedrockDocumentFormat to distinguish unsupported
or unrecognized file types from recognized formats instead of defaulting them to
"pdf". Propagate a clear unsupported-document-type error to the caller, while
preserving the existing mappings and return behavior for all recognized MIME
types and extensions.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 925e73b2-4d84-4782-8ee8-e2e60961dbd1

📥 Commits

Reviewing files that changed from the base of the PR and between 93cca7c and 2b99259.

📒 Files selected for processing (7)
  • core/changelog.md
  • core/providers/anthropic/emptytoolresult_test.go
  • core/providers/anthropic/responses.go
  • core/providers/anthropic/toolresultdocument_test.go
  • core/providers/bedrock/responses.go
  • core/providers/bedrock/toolresultdocument_test.go
  • core/providers/bedrock/utils.go

@CLAassistant

CLAassistant commented Jul 29, 2026

Copy link
Copy Markdown

CLA assistant check
All committers have signed the CLA.

@michaeldunn9
michaeldunn9 deleted the codex/fix-document-tool-results branch July 29, 2026 16:23
@michaeldunn9

Copy link
Copy Markdown
Contributor Author

Superseded by #5663. GitHub closed this PR when the cross-fork head branch was renamed from codex/fix-document-tool-results to feat/fix-document-tool-results. The commit and PR content are unchanged.

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]: Anthropic document blocks are dropped from Bedrock tool results

2 participants