Skip to content

feat(anthropic): support document citations#1778

Merged
gold-silver-copper merged 8 commits into
0xPlaygrounds:mainfrom
temrjan:feat/anthropic-citations
May 20, 2026
Merged

feat(anthropic): support document citations#1778
gold-silver-copper merged 8 commits into
0xPlaygrounds:mainfrom
temrjan:feat/anthropic-citations

Conversation

@temrjan

@temrjan temrjan commented May 16, 2026

Copy link
Copy Markdown

What

Adds Anthropic document citations end-to-end:

  • Request: Content::Document gains optional title, context, and typed citations: CitationsConfig fields. TryFrom<message::Document> forwards additional_params so users going through the generic surface 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. Also added #[serde(other)] Unknown so any future delta type Anthropic adds does not break stream deserialization.
  • New public helper anthropic_citations(&message::Text) -> Result<Vec<Citation>, serde_json::Error> for typed extraction from the generic message::AssistantContent surface.

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::Text gains additional_params: Option<serde_json::Value> mirroring Image/Audio/Video/Document in the same module — Text was the only content type missing this. The change is non-breaking at the JSON wire level (default None, #[serde(flatten, skip_serializing_if = "Option::is_none")]) but downstream code using the struct literal message::Text { text } should migrate to Text::new(text) or add additional_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 --workspace
  • cargo test --workspace — 610 tests pass; added 9 in anthropic/completion.rs (document serialization with citations, three location-type round-trips, helper extraction in both empty and populated paths, AssistantContent round-trip preserving citations, end-to-end additional_params forwarding on a request) and 2 in anthropic/streaming.rs (citations_delta event deserialization, unknown-delta fallback).
  • cargo clippy --workspace --all-targets --all-features -- -Dwarnings
  • cargo +nightly fmt --all --check
  • cargo +nightly doc --workspace --all-features --no-deps --document-private-items with RUSTDOCFLAGS="-D warnings"

Notes

  • Streaming consumer currently drops CitationsDelta (returns None from handle_event); citations are accumulated per-content-block and returned with the assembled final Content::Text. Real-time citation streaming through RawStreamingChoice is out of scope here and would be a follow-up.
  • Citation validation (the API requires all-or-none citations across documents in a request) is left to the server — adding client-side validation is scope creep.

AI assistance disclosure

Implemented with a two-stage AI-assisted process:

  1. Claude Opus 4.7 (Anthropic) wrote the implementation, tests, and documentation, following the project's idiomatic Rust style (Result-based error propagation, #[derive(Default)] on the extended message::Text so downstream struct-literal call-sites stay ergonomic).
  2. Kimi K2.6 (Moonshot) ran two independent reviews:
    • Pre-coding architectural audit of the implementation plan — caught missing impl From<String>/impl Display updates and the real scope of ~22 call-sites that would break with the new additional_params field before any code was written.
    • Final diff review — caught compile failures in rig-bedrock and rig-vertexai not surfaced by cargo 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

@fangkangmi

Copy link
Copy Markdown
Contributor

Thanks @temrjan

Temrjan and others added 5 commits May 20, 2026 00:38
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
@gold-silver-copper gold-silver-copper force-pushed the feat/anthropic-citations branch from a5a9fe2 to 58bab1c Compare May 20, 2026 07:44
@gold-silver-copper gold-silver-copper added this pull request to the merge queue May 20, 2026
Merged via the queue into 0xPlaygrounds:main with commit b82cc36 May 20, 2026
5 checks passed
@github-actions github-actions Bot mentioned this pull request May 20, 2026
@github-actions github-actions Bot mentioned this pull request Jun 9, 2026
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.

feat: support Anthropic document citations

3 participants