feat: add CitationsContentBlock for document citation support#568
Open
dbschmigelski wants to merge 13 commits intostrands-agents:mainfrom
Open
feat: add CitationsContentBlock for document citation support#568dbschmigelski wants to merge 13 commits intostrands-agents:mainfrom
dbschmigelski wants to merge 13 commits intostrands-agents:mainfrom
Conversation
…s-agents#487) Add CitationsBlock content type to support document citations returned by models (particularly Bedrock) when citations are enabled. This aligns the TypeScript SDK with the Python SDK's citation support.
Bedrock's _formatContentBlock now filters CitationsBlock fields and sends them back in conversation history, matching the Python SDK behavior. Also adds citations feature flag to ProviderFeatures for integration test coverage.
3af7f72 to
8803976
Compare
- Fix searchResult → searchResultLocation to match Bedrock API wire format - Add missing domain field to WebLocation - Add missing source field to Citation - Pass through source field in Bedrock citation filter - Test both streaming and non-streaming Bedrock paths for citations - Test documentChar (text) and documentPage (PDF) location variants - Verify citationsContentDelta events in streaming
…n types Use type aliases instead of interfaces to follow the established pattern for Bedrock API union types (like DocumentSourceData). This allows non-breaking expansion when new variants are added in the future.
… tests Add comprehensive tests for all 5 CitationLocation union variants (documentChar, documentPage, documentChunk, searchResultLocation, web) to verify round-trip serialization, Bedrock formatting pipeline, and multi-turn conversation history preservation.
Replace object-key discrimination with a `type` field on CitationLocation to match the ContentBlockDelta pattern and provide better ergonomics for consumers (switch/case instead of `in` checks). Bedrock's wire format mapping is now handled in bedrock.ts via _mapBedrockCitationLocation and _mapCitationLocationToBedrock, decoupling the SDK types from the provider.
Make source and title required on Citation — integration tests will verify Bedrock always returns them. Consolidate duplicated citation unit tests into a single all-variants round-trip test.
Import BedrockCitationLocation, BedrockCitation, and BedrockCitationsContentBlock from the Bedrock SDK to type the mapping functions at the boundary instead of using Record<string, unknown> and as-unknown-as casts. Simplify _formatContentBlock citationsBlock case by delegating to _mapCitationToBedrock.
…is from AGENTS.md - Strip Bedrock-rejected `domain` field from web citation locations in _mapCitationLocationToBedrock - Refactor citation integ tests: use non-streaming (Bedrock streaming lacks citation support), content source format, object-level assertions, and remove seeded multi-turn test - Remove all emojis from AGENTS.md
| return { searchResultLocation: fields } | ||
| } | ||
| case 'web': | ||
| return { web: { url: location.url } } |
There was a problem hiding this comment.
Issue: Web citation domain field is lost in round-trip
The incoming mapping at line 1117 preserves the optional domain field, but this outgoing mapping drops it. This means web citations won't survive a multi-turn conversation with their domain intact.
Suggestion:
case 'web':
return { web: { url: location.url, ...(location.domain && { domain: location.domain }) } }|
Assessment: Comment (Request Changes on single issue) Well-designed implementation of CitationsBlock with provider-agnostic types and comprehensive test coverage. One issue to address with web citation domain handling. Review Summary
Nice addition achieving Python SDK parity with clean provider-agnostic design. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description
Resolves #487
Adds
CitationsBlockfor document citation support, achieving parity with the Python SDK (strands-agents/sdk-python#631). Citations are returned by models when document citations are enabled viacitations: { enabled: true }onDocumentBlockinputs. They are output-only blocks that appear in conversation history and must be serializable.Provider-agnostic type design
Rather than mirroring Bedrock's wire format directly, citation types use SDK-native patterns.
CitationLocationis a discriminated union with atypefield — matching howContentBlockDeltaalready works — so consumers can useswitch(location.type)instead of'key' in objchecks. The Bedrock-specific object-key format ({ documentChar: { ... } }) is mapped bidirectionally inbedrock.ts, keeping the public types provider-agnostic. This means other providers can add citation support by implementing their own mapping without changing the shared types.We also renamed Bedrock's
searchResultLocationtosearchResultin the SDK type since the "Location" suffix is redundant insideCitationLocation.Union type convention for extensibility
CitationSourceContentandCitationGeneratedContentare modeled astypealiases rather than interfaces. This follows the same pattern asDocumentSourceDatainmedia.ts— when a type maps to a Bedrock API UNION, we use atypealias so additional variants (e.g.,{ image: ... }) can be added as a union expansion rather than requiring interface changes. This convention is now documented inAGENTS.md.Required fields over optional
Bedrock's API docs mark most citation fields as "Not Required", but we kept them required in the SDK types. Integration tests confirm Bedrock always returns
documentIndex,start, andendfor document locations. Starting with required fields is the safer choice — relaxing to optional is non-breaking, but tightening later would break consumers.Multi-turn citation support
Citations are filtered and sent back to Bedrock in conversation history, matching the Python SDK behavior. This enables multi-turn conversations where the model can reference previous citations. The formatting pipeline in
_formatContentBlockstrips to Bedrock-supported fields only (location,sourceContent.text,title) and handles the SDK-to-Bedrock type mapping on the way out.Python SDK alignment
Related Issues
strands-agents/sdk-python#631
Documentation PR
Type of Change
Bug fix
New feature
Breaking change
Documentation update
Other (please describe):
Testing
How have you tested the change?
npm run checkChecklist
By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice.