Skip to content

chat(citations=True): cite answers with the server's cited_answer prompt - #496

Merged
rejojer merged 4 commits into
feat/mcp-bridge-promptsfrom
feat/citation-prompt
Sep 10, 2026
Merged

chat(citations=True): cite answers with the server's cited_answer prompt#496
rejojer merged 4 commits into
feat/mcp-bridge-promptsfrom
feat/citation-prompt

Conversation

@rejojer

@rejojer rejojer commented Sep 9, 2026

Copy link
Copy Markdown
Member

chat(citations=True) makes the answer cite every claim the way PageIndex chat does: <cite doc="…" page="…"/> tags, block="…" added where the cloud document has blocks. Stacks on #494 (bridge prompts/get); this PR's diff is the four files on top of it.

How it works

  • Own-model chat over cloud documents: fetches the MCP server's cited_answer prompt (format=cite, the rules citation-contract.ts also feeds PageIndex chat) over the same bridge session as the tools, and folds it into the system prompt after the managed prompt and before the caller's instructions. All three lanes (answer lane, protocol="responses", protocol="messages") via the existing instructions plumbing; local_chat.py untouched.
  • Managed chat: citations=True passes enable_citations=True to the endpoint.
  • Local documents: a frozen copy of the same prompt (LOCAL_CITATION_PROMPTS, generated from the live text minus the one bullet naming the cloud-only get_document_image() tool). Local page content carries no blocks, so citations resolve to pages.
  • client.citation_prompt(format="cite") exposes the same text for framework-built agents; markdown / footnote are the MCP prompt's variants for hosts that strip tags.

Verified

  • 503 tests green (10 new, red-verified first), without-frameworks leg simulated, pyright clean.
  • Key-gated live tests: the three formats served and distinct; local frozen copies equal the live text minus that bullet.
  • Live with real models: block document → <cite doc="document_5.pdf" page="1" block="p1_text_1"/>; legacy document → <cite doc="1706.03762_24.pdf" page="1"/>; locally indexed PDF → <cite doc="q1-fy25-earnings.pdf" page="3"/>; managed citations=True non-stream and stream.

Not in this PR

  • Docs (agents.mdx, chat.mdx's hand-written <cite> system message becomes citations=) and a release-notes line, with the release.
  • Server-side, for the prompt's owner: the managed API's citation prompt (pageindex-compute) carries a literal example id p1_text_001 that the model echoes on legacy documents (resolved citations then carry a block_id with no bbox); and a granularity argument on cited_answer would let the SDK offer page-only citations on block documents.

https://claude.ai/code/session_01Ex6uKLsDrQjZkqypjSyPwA

…hat's format

chat(citations=True) makes the answer cite every claim the way PageIndex
chat does: <cite doc= page=/> tags, block= added where the cloud document
has blocks. Own-model chat over cloud documents fetches the MCP server's
cited_answer prompt (format=cite) over the tools' bridge session and folds
it into the system prompt after the managed prompt and before the caller's
instructions, on all three lanes; the managed chat gets its own
enable_citations; local documents get a frozen copy of the same prompt
(pages only, local page content carries no blocks), pinned to the live text
by a key-gated parity test. client.citation_prompt(format=) exposes the
same text for framework-built agents: cite by default, markdown / footnote
for hosts that strip tags.

Stacks on #494 (bridge prompts/get). Verified live: block documents cite
block ids, legacy and local documents cite pages, on the answer lane and
both protocol lanes.

Claude-Session: https://claude.ai/code/session_01Ex6uKLsDrQjZkqypjSyPwA
The refusal's only exit was dropping the chat model; own-model chat now
cites through chat(citations=True), so name it. Also drop an unused return
in the citation test helper.

Claude-Session: https://claude.ai/code/session_01Ex6uKLsDrQjZkqypjSyPwA
A format name passed as citations= was truthy and silently meant cite;
it now raises and names citation_prompt(format=) + instructions=.
citation_prompt(format="") returned the server's markdown default while
the getter's own default is cite; "" is unset, so it is cite too. That
left fetch_citation_prompt's unset fallbacks without a caller, so it
now takes the format it is given.

The enable_citations refusal's keyless arm still said local mode could
not cite; both arms now point at chat(citations=True). The docstrings
that route other formats through instructions= say own-model chat only.

Claude-Session: https://claude.ai/code/session_01RWo3vKJs6MVMxrfPxEVaxd
…comment

chat() reached the citation text through a lazy import of the private
fetch_citation_prompt(self, "cite") when the public citation_prompt()
getter beside it is exactly that call, so the "cite" default was spelled
in two places. chat() now uses the getter; the default lives in its
signature only.

The comment above LOCAL_CITATION_PROMPTS named the private chat repo and
its server-side prompt file. That file ships to PyPI with the package and
public code carries only the contract, so the comment keeps what the copy
is and why its block rules stay dormant locally.

Claude-Session: https://claude.ai/code/session_01XGBdRF2qoTcLNpRahj6QHx
@rejojer
rejojer merged commit 8ae62c2 into feat/mcp-bridge-prompts Sep 10, 2026
5 checks passed
@rejojer
rejojer deleted the feat/citation-prompt branch September 10, 2026 05:24
@rejojer

rejojer commented Sep 10, 2026

Copy link
Copy Markdown
Member Author

@codex review

@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Sep 10, 2026

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review Completed 2026-09-10T11:01:09.613469Z 18cc720 Manual request
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. Already looking forward to the next diff.

Reviewed commit: 8ae62c2163

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

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.

1 participant