Skip to content

Surface Copilot model citations as CitationAnnotations - #1009

Open
PratikDhanave (PratikDhanave) wants to merge 1 commit into
microsoft:mainfrom
PratikDhanaveFork:copilot-surface-citations
Open

Surface Copilot model citations as CitationAnnotations#1009
PratikDhanave (PratikDhanave) wants to merge 1 commit into
microsoft:mainfrom
PratikDhanaveFork:copilot-surface-citations

Conversation

@PratikDhanave

Copy link
Copy Markdown
Contributor

Problem

The Copilot provider already plumbs AgentConfig.EnableCitations into the session config (copilot.go), so a citation-capable model returns citations on AssistantMessageData.Citations. But assistantMessageUpdate only reads Content and ReasoningText — it never looks at Citations, so every returned citation is silently dropped. This is a one-sided gap: the request opts in, the response data is discarded.

Fix

When data.Citations is present on the non-streaming assistant message, map each CitationSource onto the assistant TextContent's Annotations as a message.CitationAnnotation (title / URL / file path). This mirrors how the OpenAI chat (populateChatAnnotations) and Responses providers surface url_citation annotations onto text content.

Test

TestConvertToAgentResponseUpdate_AssistantMessageSurfacesCitations emits an assistant.message event carrying a citation source and asserts the resulting TextContent has a CitationAnnotation with the source's title and URL. Fails before the fix (no annotations), passes after.

Note: this maps the deduplicated citation sources; span-to-text-region mapping (Citations.SpansAnnotatedRegions) can follow as an enhancement.

The Copilot provider plumbs AgentConfig.EnableCitations into the session
config, so the model returns citations on AssistantMessageData.Citations - but
assistantMessageUpdate never read that field, silently dropping every citation.

Map each citation source onto the assistant TextContent's Annotations as a
message.CitationAnnotation (title/url/file path), mirroring how the OpenAI
chat and Responses providers surface url_citation annotations.
Copilot AI lite review requested due to automatic review settings September 6, 2026 05:16
@github-actions github-actions Bot added area:provider Changes files in the provider area area:provider/copilot Changes files in the provider / copilot area size:medium At most 100 changed lines across at most 5 files labels Sep 6, 2026
@github-actions github-actions Bot added the pending-auto-risk Automatic risk classification is in progress label Sep 6, 2026

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟢 Approval recommended

The change is narrowly scoped, aligns with existing provider behavior, and includes a focused regression test; remaining feedback is minor/defensive maintainability.

Pull request overview

Maps GitHub Copilot model citation sources returned on AssistantMessageData.Citations into message.CitationAnnotations on the assistant’s TextContent, ensuring citations aren’t silently dropped for non-streaming runs.

Changes:

  • In assistantMessageUpdate, append CitationAnnotation entries for each citation source on non-streaming assistant.message events.
  • Add derefString helper for optional *string citation fields.
  • Add a unit test asserting citations are surfaced as TextContent.Annotations.
File summaries
File Description
provider/copilotprovider/copilot.go Surfaces data.Citations.Sources as CitationAnnotations on non-streaming assistant text content.
provider/copilotprovider/copilot_test.go Adds a regression test verifying citation annotations are produced from an assistant.message event.
Review details
  • Files reviewed: 2/2 changed files
  • Comments generated: 2
  • Review effort level: Lite

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment on lines +678 to +685
for _, source := range data.Citations.Sources {
textContent.Annotations = append(textContent.Annotations, &message.CitationAnnotation{
FileID: derefString(source.Path),
Title: derefString(source.Title),
URL: derefString(source.URL),
RawRepresentation: source,
})
}
Comment on lines +853 to +858
func derefString(value *string) string {
if value == nil {
return ""
}
return *value
}
@github-actions

github-actions Bot commented Sep 6, 2026

Copy link
Copy Markdown
Contributor

Scope: user-visible behavior (bug fix), internal-only implementation

Changed Go contract: No new exported API. assistantMessageUpdate in provider/copilotprovider/copilot.go now populates the existing exported message.CitationAnnotation (FileID, Title, URL) on the assistant TextContent.Annotations slice when AssistantMessageData.Citations is present. Previously this data was silently dropped despite AgentConfig.EnableCitations already opting the session into citations.

Upstream evidence reviewed:

  • Go: provider/openaiprovider/chat.go:600 (populateChatAnnotations) and provider/openaiprovider/responses.go:1306-1459 — existing Go providers already map provider-native citation/url_citation data onto message.CitationAnnotation on TextContent, confirming this is the established Go-internal convention this PR now applies consistently to the Copilot provider.
  • message/annotation.go:78-104CitationAnnotation is a pre-existing, unchanged exported type; no new fields, options, or exported API were added.
  • No .NET/Python file changes are implicated: this PR does not add a new capability relative to those SDKs, it fixes a Go-only defect where already-requested (EnableCitations), already-returned response data was discarded before reaching the exported Contents/Annotations model. There is no equivalent Copilot-provider citation-dropping behavior to compare against upstream, since the Go Copilot provider bridges a Go-specific copilot client/event model; no equivalent upstream .NET/Python Copilot provider source was found in this review to map field-for-field, so this is evaluated as an internal consistency fix relative to the Go providers' own established annotation convention rather than a cross-language port.

Result: aligned — this is a defensible bug fix that brings the Copilot provider's citation handling in line with the same-language precedent set by the OpenAI and Anthropic Go providers (map source citations onto message.CitationAnnotation). No new exported symbols, no default/opt-in behavior change (citations were already enabled via AgentConfig.EnableCitations; this PR only stops discarding the resulting data), and no observable divergence from other Go providers' semantics. No public-api-change label needed since no exported API surface was added or changed.

Warning

Firewall blocked 1 domain

The following domain was blocked by the firewall during workflow execution:

  • github.com

To allow these domains, add them to the network.allowed list in your workflow frontmatter:

network:
  allowed:
    - defaults
    - "github.com"

See Network Configuration for more information.

Generated by Go API Consistency Review Agent · copilot · auto · 25.3 AIC · ⌖ 5.36 AIC · ⊞ 9.5K ·

@github-actions github-actions Bot added risk:medium Contained production impact requiring normal review depth and removed pending-auto-risk Automatic risk classification is in progress labels Sep 6, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area:provider/copilot Changes files in the provider / copilot area area:provider Changes files in the provider area risk:medium Contained production impact requiring normal review depth size:medium At most 100 changed lines across at most 5 files

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants