fix(anthropic): resolve document_index citations to source URLs - #382
Open
cpsievert wants to merge 14 commits into
Open
fix(anthropic): resolve document_index citations to source URLs#382cpsievert wants to merge 14 commits into
cpsievert wants to merge 14 commits into
Conversation
Anthropic's web_fetch tool results carry a document_index that citations reference, but chatlas surfaced that raw index instead of resolving it to the fetched page's URL, leaving citations from web_fetch un-attributable.
…am_content/stream_turn/value_turn
main's UNRELEASED header was retroactively split into 0.21.0, so this entry needs to live above that split, not inside it.
cpsievert
force-pushed
the
fix/anthropic-web-fetch-citations
branch
from
August 8, 2026 01:07
4aaebae to
9c82c01
Compare
ellmer wraps its price list in an object (schema_version, min_ellmer_version, updated_at, data) instead of a bare array. The bot-updated prices.json on this branch already reflects that, but pricing_list still parsed the whole file as the list, so every price lookup raised "string indices must be integers".
Contributor
There was a problem hiding this comment.
Pull request overview
This PR fixes Anthropic document_index citations by resolving them to concrete WebSource URLs/titles across the full request history (including prior turns) and threads the full request turns through the streaming hooks so providers can resolve cross-turn references during streaming.
Changes:
- Resolve Anthropic
document_indexcitations to source URLs by mappingdocument_indexacross prior-turn attachments and current-turnweb_fetchresults. - Pass full request
turnsintoProvider.stream_content()/stream_turn()/value_turn()and update providers + tests accordingly. - Update token pricing loading to match the current wrapped
prices.jsonschema ({"data": [...]}).
Reviewed changes
Copilot reviewed 17 out of 17 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| tests/test_stream_thinking.py | Updates fake provider streaming hook signatures to accept turns. |
| tests/test_provider_stream_contract.py | Extends stream contract tests to assert turns propagation during streaming. |
| tests/test_provider_anthropic.py | Adds coverage for document_index citation source resolution, including cross-turn cases. |
| tests/test_otel.py | Updates OTEL streaming monkeypatches for new turns hook signature. |
| tests/test_echo_display.py | Updates echo display test providers for new turns hook signature. |
| chatlas/types/anthropic/_submit.py | Updates generated Anthropic submit typed dict model literals. |
| chatlas/_tokens.py | Adjusts pricing loader to read prices.json["data"]. |
| chatlas/_provider.py | Adds turns to streaming/value hook signatures and documents purpose. |
| chatlas/_provider_snowflake.py | Updates streaming/value hook signatures to accept turns. |
| chatlas/_provider_openai.py | Updates streaming/value hook signatures to accept turns. |
| chatlas/_provider_openai_completions.py | Updates streaming/value hook signatures to accept turns. |
| chatlas/_provider_google.py | Updates streaming/value hook signatures to accept turns. |
| chatlas/_provider_bedrock_converse.py | Updates streaming/value hook signatures to accept turns. |
| chatlas/_provider_anthropic.py | Implements document_index→WebSource resolution via request-history document slot mapping. |
| chatlas/_chat.py | Threads request_turns through streaming/value hooks when emitting content/turns. |
| CHANGELOG.md | Documents the document_index citation resolution fix. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
Comment on lines
56
to
61
| "claude-haiku-4-5-20251001", | ||
| "claude-opus-4-5", | ||
| "claude-opus-4-5-20251101", | ||
| "claude-sonnet-4-5", | ||
| "claude-sonnet-4-5-20250929", | ||
| "claude-opus-4-1", | ||
| "claude-opus-4-1-20250805", | ||
| ], |
Comment on lines
+13
to
+16
| ### Bug fixes | ||
|
|
||
| * `ChatAnthropic()` citations backed by `document_index` (from `tool_web_fetch()` results and document/PDF attachments) now resolve to a source URL, instead of always coming back without one. Anthropic counts that index across every document-shaped block in the whole request, including ones from prior turns, which chatlas wasn't accounting for. (#382) | ||
|
|
ellmer's prices.json (see tidyverse/ellmer#968, the same PR that introduced the envelope schema) no longer guarantees an `input` key per row -- output-only models (e.g. Bedrock's TwelveLabs Pegasus video models) omit it. get_token_cost() indexed price["input"] directly, so pricing these models raised KeyError.
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.
Summary
Anthropic's
web_fetch/document citations reference sources viadocument_index, an index into every document-shaped block sent in the request (spanning prior turns), not just the current response. Chatlas wasn't resolving that index to anything, sodocument_index-based citations had no attached source. This PR resolves those citations to theirWebSource(URL/title), including:As a side effect of threading turn history through the streaming path,
stream_content()/stream_turn()/value_turn()now accept the request'sturnsacross all providers (previously only some providers received them), which fixes a related bug where turns supplied at request time weren't reaching provider content/turn resolution during streaming.Known limitation
document_indexaccounting doesn't yet look inside custom tool results that embed raw Anthropic document blocks (an advanced, undocumented usage pattern viaContentToolResult(model_format="as_is")). Filed as a follow-up: #381.Test plan
uv run pytest tests/test_provider_anthropic.py tests/test_provider_stream_contract.py tests/test_stream_thinking.py tests/test_echo_display.py tests/test_otel.py— 242 passed/code-review; verified findings against SDK types and existing patterns