feat(anthropic): support document citations#1778
Merged
gold-silver-copper merged 8 commits intoMay 20, 2026
Merged
Conversation
Contributor
|
Thanks @temrjan |
Implements Anthropic's citations API end-to-end:
- Request: `Content::Document` gains optional `title`, `context`, and typed
`citations: CitationsConfig` fields. `TryFrom<message::Document>` forwards
`additional_params` so generic users can opt in.
- Response: `Content::Text` carries typed `citations: Vec<Citation>` with all
three Anthropic location types (`char_location`, `page_location`,
`content_block_location`). Conversion to `message::AssistantContent` preserves
them via `message::Text.additional_params`.
- Streaming: new `ContentDelta::CitationsDelta` variant, plus
`#[serde(other)] Unknown` for forward compatibility.
- New public helper `anthropic_citations()` for typed extraction from the
generic surface.
`message::Text` gains `additional_params: Option<serde_json::Value>` mirroring
`Image`/`Audio`/`Video`/`Document` in the same module. Non-breaking
(default `None`, `#[serde(flatten, skip_serializing_if = "Option::is_none")]`)
and enables provider-specific metadata on text blocks generally.
Downstream code using the struct literal `message::Text { text }` should
migrate to `Text::new(text)` or add `additional_params: None`.
Fixes 0xPlaygrounds#1767
a5a9fe2 to
58bab1c
Compare
Merged
This was referenced Jun 2, 2026
Merged
Merged
Merged
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.
What
Adds Anthropic document citations end-to-end:
Content::Documentgains optionaltitle,context, and typedcitations: CitationsConfigfields.TryFrom<message::Document>forwardsadditional_paramsso users going through the generic surface can opt in.Content::Textcarries typedcitations: Vec<Citation>with all three Anthropic location types (char_location,page_location,content_block_location). Conversion tomessage::AssistantContentpreserves them viamessage::Text.additional_params.ContentDelta::CitationsDeltavariant. Also added#[serde(other)] Unknownso any future delta type Anthropic adds does not break stream deserialization.anthropic_citations(&message::Text) -> Result<Vec<Citation>, serde_json::Error>for typed extraction from the genericmessage::AssistantContentsurface.Why
The Messages API exposes citation metadata (RAG, document QA, auditable model output). Rig previously dropped these fields silently both on the request side (when set via
message::Document.additional_params) and on the response side (the citation arrays returned on text blocks). This PR closes the gap without forcing other providers to model fields they don't support.Compatibility note
message::Textgainsadditional_params: Option<serde_json::Value>mirroringImage/Audio/Video/Documentin the same module —Textwas the only content type missing this. The change is non-breaking at the JSON wire level (defaultNone,#[serde(flatten, skip_serializing_if = "Option::is_none")]) but downstream code using the struct literalmessage::Text { text }should migrate toText::new(text)or addadditional_params: None. A constructor is provided. Same generic mechanism would let future providers (logprobs, reasoning notes, ...) attach metadata to text blocks without a new abstraction per provider.Testing
Full workspace baseline green:
cargo build --workspacecargo test --workspace— 610 tests pass; added 9 inanthropic/completion.rs(document serialization with citations, three location-type round-trips, helper extraction in both empty and populated paths,AssistantContentround-trip preserving citations, end-to-endadditional_paramsforwarding on a request) and 2 inanthropic/streaming.rs(citations_delta event deserialization, unknown-delta fallback).cargo clippy --workspace --all-targets --all-features -- -Dwarningscargo +nightly fmt --all --checkcargo +nightly doc --workspace --all-features --no-deps --document-private-itemswithRUSTDOCFLAGS="-D warnings"Notes
CitationsDelta(returnsNonefromhandle_event); citations are accumulated per-content-block and returned with the assembled finalContent::Text. Real-time citation streaming throughRawStreamingChoiceis out of scope here and would be a follow-up.AI assistance disclosure
Implemented with a two-stage AI-assisted process:
Result-based error propagation,#[derive(Default)]on the extendedmessage::Textso downstream struct-literal call-sites stay ergonomic).impl From<String>/impl Displayupdates and the real scope of ~22 call-sites that would break with the newadditional_paramsfield before any code was written.rig-bedrockandrig-vertexainot surfaced bycargo check -p rig-core.I reviewed every line and take responsibility for correctness and maintainability. Full workspace baseline is green:
cargo build,test,clippy --all-targets --all-features -- -Dwarnings,+nightly fmt --check, and+nightly doc -D warnings.Fixes #1767