Skip to content

.NET: Fix CopySessionConfig() and CopyResumeSessionConfig() to preserve SessionConfig.Streaming value - #6463

Merged
Giles Odigwe (giles17) merged 3 commits into
microsoft:mainfrom
giles17:agent/fix-4732-1
Jun 11, 2026
Merged

Giles Odigwe (giles17) merged 3 commits into
microsoft:mainfrom
giles17:agent/fix-4732-1

Conversation

@giles17

Copy link
Copy Markdown
Contributor

Motivation and Context

CopySessionConfig() and CopyResumeSessionConfig() in GitHubCopilotAgent hardcoded Streaming = true, making it impossible to disable streaming when using AsAIAgent() with the GitHub Copilot SDK even though SessionConfig.Streaming is a settable property.

Fixes #4732

Description

The root cause was that both copy methods unconditionally set Streaming = true on the output config instead of propagating the caller's value. The fix changes both methods to use source.Streaming ?? true, preserving an explicitly set false value while defaulting to true when unset (maintaining backward compatibility). Unit tests are added to verify that Streaming = false is preserved and that a null value defaults to true for both CopySessionConfig and CopyResumeSessionConfig.

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? If yes, add "[BREAKING]" prefix to the title of the PR.

Note: PR autogenerated by giles17's agent

…value (microsoft#4732)

CopySessionConfig() and CopyResumeSessionConfig() hardcoded Streaming = true,
ignoring the caller's explicitly set SessionConfig.Streaming value. This made it
impossible to disable streaming when using AsAIAgent() with the GitHub Copilot SDK.

Changed both methods to use source.Streaming ?? true (and source?.Streaming ?? true
for the nullable overload), preserving the caller's value when set while maintaining
backward compatibility by defaulting to true when unset.

Co-authored-by: Copilot <[email protected]>
Copilot AI review requested due to automatic review settings June 10, 2026 18:22
@moonbox3 Evan Mattson (moonbox3) added the .NET Usage: [Issues, PRs], Target: .Net label Jun 10, 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.

Pull request overview

Fixes GitHubCopilotAgent’s session-config copy helpers so an explicitly configured SessionConfig.Streaming = false is preserved (instead of being overwritten to true), while keeping the historical default behavior of streaming enabled when the caller leaves it unset.

Changes:

  • Update CopySessionConfig() to preserve source.Streaming (defaulting to true when null).
  • Update CopyResumeSessionConfig() to preserve source.Streaming (defaulting to true when null).
  • Add unit tests covering Streaming=false preservation and Streaming=null defaulting behavior for both copy methods.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated no comments.

File Description
dotnet/src/Microsoft.Agents.AI.GitHub.Copilot/GitHubCopilotAgent.cs Preserve SessionConfigBase.Streaming when copying configs, defaulting to true only when unset.
dotnet/tests/Microsoft.Agents.AI.GitHub.Copilot.UnitTests/GitHubCopilotAgentTests.cs Add regression tests ensuring Streaming is preserved when explicitly disabled and defaults to true when unset.

@giles17 Giles Odigwe (giles17) left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Automated Code Review

Reviewers: 5 | Confidence: 95%

✓ Correctness

The PR correctly fixes the bug where CopySessionConfig and CopyResumeSessionConfig were hardcoding Streaming=true, ignoring the caller's explicit value. The fix uses null-coalescing (source.Streaming ?? true / source?.Streaming ?? true) which preserves an explicit false, preserves an explicit true, and defaults to true when unset. The Clone() call in CopySessionConfig already copies all properties, but the subsequent assignment correctly handles the null→true default. Tests cover all meaningful cases. No issues found.

✓ Security Reliability

This PR correctly fixes the streaming configuration preservation bug by replacing hardcoded Streaming = true with null-coalescing logic (source.Streaming ?? true and source?.Streaming ?? true). The change properly preserves an explicitly set false while defaulting to true when unset. No security or reliability concerns: no injection risks, no resource leaks, null handling is correct (CopyResumeSessionConfig uses source?.Streaming for its nullable parameter), and backward compatibility is maintained for calers that don't explicitly set Streaming.

✓ Test Coverage

The test coverage for this change is thorough. The PR adds four new tests covering both CopySessionConfig and CopyResumeSessionConfig for the two key scenarios: Streaming = false (the bug fix) and Streaming = null (backward-compatible default to true). The existing tests (CopySessionConfig_CopiesAllProperties, CopyResumeSessionConfig_CopiesAllProperties, CopyResumeSessionConfig_WithNullSource_ReturnsDefaults) continue to validate backward compatibility. The explicit Streaming = true case is not separately tested, but it's logically equivalent to the null-defaults-to-true path from an output perspective, making it a non-gap. Assertions are meaningful and specific (Assert.True/Assert.False on the boolean property).

✓ Failure Modes

The PR correctly fixes the streaming value preservation bug. Both CopySessionConfig (using Clone + null-coalescing override) and CopyResumeSessionConfig (using manual construction with null-conditional + null-coalescing) properly preserve explicit Streaming=false while defaulting to true when unset. No silent failure modes, lost errors, or operational issues found.

✗ Design Approach

I found one blocking design gap. This PR now preserves Streaming=false, but the agent’s response-conversion path still assumes assistant text was already delivered via delta events. In the non-streaming case enabled by this change, that assumption is false, so final assistant text can be silently dropped instead of surfaced in the response.

Flagged Issues

  • Preserving SessionConfig.Streaming = false is not end-to-end supported: GitHubCopilotAgent.cs:280 and :310 now allow non-streaming sessions, but GitHubCopilotAgent.cs:329-342 converts AssistantMessageEvent into raw AIContent only, and GitHubCopilotAgentTests.cs:291-309 explicitly documents that this is safe only because the text was 'already delivered via delta events'. With streaming disabled, that premise no longer holds, so the assistant's final text can be lost.

Automated review by giles17's agents

@github-actions github-actions Bot 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.

Automated Code Review

Reviewers: 5 | Confidence: 94% | Result: All clear

Reviewed: Correctness, Security Reliability, Test Coverage, Failure Modes, Design Approach


Automated review by giles17's agents

…crosoft#4732)

The config-copy fix (preserving Streaming=false via null-coalescing) was
already in place, but ConvertToAgentResponseUpdate(AssistantMessageEvent)
always emitted raw AIContent without text—assuming delta events had already
delivered it. When streaming is disabled there are no delta events, so the
assistant's final text was silently dropped.

Changes:
- Add isStreaming parameter to ConvertToAgentResponseUpdate for
  AssistantMessageEvent so it emits TextContent in non-streaming mode.
- Capture the resolved streaming flag in RunCoreStreamingAsync and pass
  it through the event subscription closure.
- Add/update unit tests for both streaming and non-streaming paths.

Co-authored-by: Copilot <[email protected]>

@giles17 Giles Odigwe (giles17) left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Automated Code Review

Reviewers: 5 | Confidence: 91%

✓ Correctness

The PR correctly adds conditional text content emission based on streaming mode. When streaming, text was already delivered via delta events so only raw metadata is emitted (avoiding duplicates). When not streaming, the full message text is properly emitted as TextContent. The isStreaming variable is correctly derived from the resolved sessionConfig.Streaming value, captured safely by the event subscription closure, and the null-conditional handling of assistantMessage.Data?.Content is correct. No correctness issues found.

✓ Security Reliability

The PR cleanly adds non-streaming support to ConvertToAgentResponseUpdate by threading an isStreaming boolean derived from the session config. Null handling is defensive (Data?.Content ?? string.Empty), the captured variable in the closure is a value type so there's no race condition, and tests cover both streaming and non-streaming paths including the empty-content edge case. No security or reliability issues found.

✓ Test Coverage

The PR adds good test coverage for the new isStreaming parameter on ConvertToAgentResponseUpdate. The streaming path, non-streaming path, and empty-content edge case are all tested with meaningful assertions (content equality, type checks, reference identity). One minor gap: the production code handles assistantMessage.Data?.Content ?? string.Empty (null-coalescing on Data), but no test exercises the Data = null scenario in non-streaming mode. This is a low-severity gap since the null-coalescing ensures it won't crash, but a test would document the expected behavior.

✓ Failure Modes

The PR correctly handles the streaming/non-streaming distinction for AssistantMessageEvent conversion. The isStreaming flag is derived from the same session config sent to the server, null handling is proper throughout (Data?.Content ?? string.Empty), and the code paths for both modes are well-tested. No concrete failure modes or silent error paths were identified.

✓ Design Approach

I did not find a design-approach issue in this diff. The change is narrowly scoped to the demonstrated bug: AgentResponseUpdate.Text is defined as the concatenation of TextContent items in Contents (dotnet/src/Microsoft.Agents.AI.Abstractions/AgentResponseUpdate.cs:91-97), so emitting TextContent only for non-streaming assistant messages is consistent with the framework contract and with the new tests. I also did not find repo evidence that a better pattern should be used here instead of keying off the session's streaming configuration.


Automated review by giles17's agents

…t#4732)

Add a regression test covering the null-propagation path where
AssistantMessageEvent.Data is null. The production code already handles
this via ?. operators, but no test previously verified the behavior.

Co-authored-by: Copilot <[email protected]>

@giles17 Giles Odigwe (giles17) left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Automated Code Review

Reviewers: 5 | Confidence: 94% | Result: All clear

Reviewed: Correctness, Security Reliability, Test Coverage, Failure Modes, Design Approach


Automated review by giles17's agents

@giles17
Giles Odigwe (giles17) added this pull request to the merge queue Jun 11, 2026
Merged via the queue into microsoft:main with commit 8b0405d Jun 11, 2026
27 checks passed

This branch was previously deployed

1 inactive deployment
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

.NET Usage: [Issues, PRs], Target: .Net

Projects

None yet

Development

Successfully merging this pull request may close these issues.

.NET: [Bug]: CopySessionConfig() hardcodes Streaming = true, ignoring SessionConfig.Streaming value

5 participants