Cite documents agents find via document search - #1274
Merged
Paul Lizer (paullizer) merged 2 commits intoAug 18, 2026
Merged
Conversation
Documents retrieved through DocumentSearchPlugin were only recorded as agent tool citations, so they never appeared as message sources, were not clickable, and never reached cited references or the used documents drawer. Derive real document citations from search_documents, retrieve_document_chunks, and summarize_document payloads, and merge them into hybrid_citations before cited subsets are built. Applies to the document action path, non-streaming and streaming chat including cancelled and interrupted streams, and workflow runs. Document search payloads now carry copy-ready citation markers so cited agent documents are promoted into cited_hybrid_citations and used_documents. Sources stay uncapped, so the sources panel collapses past 25 entries instead of discarding data. Summaries anchor to a real source chunk rather than a synthesized locator, and a valid page or sequence of 0 is preserved. Fixes #1239
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
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.
Fixes #1239
The problem
Documents an agent retrieved through the document search action never became document citations.
hybrid_search()DocumentSearchPlugin.search_documents()hybrid_citationsagent_citationsonlycited_hybrid_citationsThe retrieved documents were already sitting inside the plugin result payload — nothing ever converted them into the document citation shape.
functions_workflow_runner.pyhad the identical gap.The fix
New
functions_agent_document_citations.pyderives real document citations fromsearch_documents,retrieve_document_chunks, andsummarize_documentpayloads, and merges them intohybrid_citationsbeforebuild_cited_source_subsets()runs — so agent-discovered documents flow through the existing sources → cited references → used documents pipeline unchanged.Wired into every path that writes an assistant message:
functions_workflow_runner._create_assistant_message()Document search payloads now also carry a copy-ready
citationmarker formatted exactly as the tracker matches —(Source: Policy.pdf, Page: 3) [#doc-1_3]— pluscitation_instructions, and the three kernel function descriptions tell the model to reuse it verbatim. When it does, the document is promoted intocited_hybrid_citationsand the conversation'sused_documents.Sources are not cited references
Derived citations are sources and are deliberately uncapped — if an agent sources 500 chunks, all 500 are recorded.
functions_citation_tracking.build_cited_source_subsets()remains solely responsible for narrowing to what the answer actually cited.Because nothing is capped server-side, the per-message Sources disclosure now renders the first 25 entries and collapses the rest behind a Show N more sources control. No stored data is discarded. The Used documents drawer is unaffected — it lists cited documents, not source chunks.
Correctness details
<document_id>_1. Video chunks are keyed by second and start at<document_id>_0.summarize_document_content()now reports acitation_chunkdescribing its real first source chunk, and summaries anchor to it instead of a synthesized locator. A valid page or sequence of0is preserved rather than relabelled as page 1 — this also correctsresolve_citation_location(), which is safe because every pre-existing caller already coerced0to1before calling.citation_id, falling back todocument_id+chunk_id+page_number. Existing route-level records always win, so a chunk retrieved by both the toggle and an agent is listed once with its original metadata.workspace.search_used/result_countnow report document usage for agent-only document turns, which previously under-reported as unused.functions_search_service, which already resolves personal, group, and public scope against the current user.Validation
functional_tests/test_agent_document_search_citations.py— 12/12 passing, covering derivation for all three plugin functions, dedupe without truncation on a 500-result set, provenance tagging, zero-indexed locator handling, raw-invocation support for cancelled streams, marker-to-cited-reference promotion, tabular sheets, JSON-string payloads, and wiring.Test 11 is a branch-aware AST check: for every function that builds cited subsets, a merge must precede tracking and persistence on that branch, so a merge inside one finalization branch cannot vouch for another. It was confirmed to have teeth — removing the interrupted-stream merge makes it fail with the exact branch and line, and it independently caught a missing merge during development.
Regressions clean:
test_chat_cited_source_tracking.py,test_agent_citations_fix.py,test_agent_citations_per_message_fix.py,test_chat_capability_usage_metadata.py,test_markdown_citation_lookup_fallback.py,test_stored_xss_chat_workspace_rendering_fix.py,test_mixed_source_chat_search_consistency.py, and the threeroute_testspolicy suites. Remaining repo test failures are pre-existing and fail identically on the base branch (they require live Azure configuration).Known limitation
PluginInvocationLoggeris process-global and filters only by user and conversation, so a superseding request can clear invocations a prior request has not finished reading. This predates this change and affects existing agent tool citation capture identically. Making it exact requires tagging invocations with a request or run id across shared plugin infrastructure, which is better handled separately.Docs and version
docs/explanation/fixes/AGENT_DOCUMENT_SEARCH_CITATION_FIX.mdv0.250.219VERSIONbumped to0.250.219Development was merged in and this fix renumbered from
0.250.218to0.250.219, since #1270 landed on0.250.218first.