Skip to content

Comments

.NET: Fix GitHubCopilotAgent producing duplicated text content (#3979)#4145

Open
kallebelins wants to merge 1 commit intomicrosoft:mainfrom
kallebelins:copilot/fix-github-copilot-agent-duplicated-text-3979
Open

.NET: Fix GitHubCopilotAgent producing duplicated text content (#3979)#4145
kallebelins wants to merge 1 commit intomicrosoft:mainfrom
kallebelins:copilot/fix-github-copilot-agent-duplicated-text-3979

Conversation

@kallebelins
Copy link

Motivation and Context

This change fixes a bug where GitHubCopilotAgent produces duplicated text content during streaming responses (issue #3979).

When streaming, the agent emitted TextContent from both AssistantMessageDeltaEvent (incremental chunks) and AssistantMessageEvent (complete assembled message). Any consumer concatenating all TextContent from the streaming updates would see the full response text duplicated — e.g., "Hello world!Hello world!" instead of "Hello world!".

This is a correctness bug that affects all downstream integrations relying on the streaming pipeline, including AG-UI and CopilotKit clients.

Fixes #3979

Description

Root cause: RunCoreStreamingAsync had an explicit case AssistantMessageEvent in its switch statement that called ConvertToAgentResponseUpdate, which created a TextContent containing the full assembled text — the same text already streamed incrementally via AssistantMessageDeltaEvent chunks.

Fix applied:

  1. Removed the dedicated AssistantMessageEvent case from the streaming switch so it falls through to the default handler, which stores the event as RawRepresentation only (no TextContent). A code comment explains the intentional omission.
  2. Changed ConvertToAgentResponseUpdate(AssistantMessageEvent) to return a generic AIContent with RawRepresentation instead of TextContent, so even if called directly it cannot produce duplicate text. This follows the same approach used by the Python SDK.
  3. Changed ConvertToAgentResponseUpdate methods from private to internal to enable direct unit testing of each event type conversion.

Tests added (GitHubCopilotAgentDuplicateTextTests.cs — 8 new tests):

Test Validates
ConvertDeltaEvent_ProducesTextContent Delta events correctly produce TextContent for streaming
ConvertDeltaEvent_PreservesMessageId Delta event metadata (MessageId, AgentId, Role) is preserved
ConvertAssistantMessageEvent_DoesNotProduceTextContent Complete message event does not produce TextContent (the fix)
ConvertAssistantMessageEvent_PreservesIdsAndTimestamp Metadata is preserved even without TextContent
StreamingSimulation_DeltasPlusComplete_NoDuplicatedText End-to-end: 3 deltas + 1 complete → collected text equals expected (no duplication)
ConvertDeltaEvent_EmptyDeltaContent_ProducesEmptyTextContent Defensive handling of empty delta content
ConvertUsageEvent_ProducesUsageContent_NotTextContent Usage events produce UsageContent, not TextContent
ConvertSessionEvent_ProducesRawContent_NotTextContent Session events produce raw content, not TextContent

All 22 existing + 8 new unit tests pass on net8.0, net9.0, and net10.0.

Contribution Checklist

  • The code builds clean without any errors or warnings
  • The PR follows the Contribution Guidelines
  • All unit tests pass, and I have added new tests where possible
  • Is this a breaking change? No. The AssistantMessageEvent data remains accessible via RawRepresentation for any consumer that needs it; only the spurious TextContent duplication is removed.

Copilot AI review requested due to automatic review settings February 21, 2026 15:21
@github-actions github-actions bot changed the title Fix GitHubCopilotAgent producing duplicated text content (#3979) .NET: Fix GitHubCopilotAgent producing duplicated text content (#3979) Feb 21, 2026
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR fixes a bug where GitHubCopilotAgent produced duplicated text content during streaming responses. The bug occurred because both AssistantMessageDeltaEvent (incremental chunks) and AssistantMessageEvent (complete assembled message) were emitting TextContent, causing consumers to see the full response text twice.

Changes:

  • Removed the explicit AssistantMessageEvent case handler in the streaming switch statement, allowing it to fall through to the default handler that stores only raw representation
  • Modified ConvertToAgentResponseUpdate(AssistantMessageEvent) to return generic AIContent instead of TextContent to prevent duplication
  • Changed visibility of conversion methods from private to internal to enable unit testing
  • Added 8 comprehensive unit tests to verify the fix and prevent regression

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.

File Description
GitHubCopilotAgent.cs Fixed streaming event handling to prevent text duplication; removed AssistantMessageEvent case and updated conversion method to not produce TextContent
GitHubCopilotAgentDuplicateTextTests.cs Added comprehensive test suite with 8 tests covering delta events, complete message events, usage events, session events, and end-to-end streaming simulation

)

When streaming responses, GitHubCopilotAgent emitted TextContent from both
AssistantMessageDeltaEvent (incremental chunks) and AssistantMessageEvent
(complete assembled message). Consumers concatenating all streaming updates
would see the full text duplicated.

Root cause: RunCoreStreamingAsync had an explicit case for
AssistantMessageEvent that called ConvertToAgentResponseUpdate, which
created a TextContent with the full assembled text — the same text
already streamed via delta events.

Fix:
- Remove the dedicated AssistantMessageEvent case from the streaming
  switch so it falls through to the default handler, which stores the
  event as RawRepresentation only (no TextContent).
- Change ConvertToAgentResponseUpdate(AssistantMessageEvent) to return
  a generic AIContent with RawRepresentation instead of TextContent,
  matching the Python SDK approach.
- Change ConvertToAgentResponseUpdate methods from private to internal
  to enable direct unit testing.

Tests added (GitHubCopilotAgentDuplicateTextTests.cs — 8 tests):
- ConvertDeltaEvent_ProducesTextContent
- ConvertDeltaEvent_PreservesMessageId
- ConvertAssistantMessageEvent_DoesNotProduceTextContent
- ConvertAssistantMessageEvent_PreservesIdsAndTimestamp
- StreamingSimulation_DeltasPlusComplete_NoDuplicatedText
- ConvertDeltaEvent_EmptyDeltaContent_ProducesEmptyTextContent
- ConvertUsageEvent_ProducesUsageContent_NotTextContent
- ConvertSessionEvent_ProducesRawContent_NotTextContent

All 22 existing + 8 new unit tests pass on net8.0, net9.0 and net10.0.

Fixes microsoft#3979
@kallebelins kallebelins force-pushed the copilot/fix-github-copilot-agent-duplicated-text-3979 branch from 832a912 to 5a19ab3 Compare February 21, 2026 15:32
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

.NET: [Bug]: GitHubCopilotAgent produces duplicated text content from both delta and complete message events

2 participants