Skip to content

Python: fix: clear service_session_id in _agent_wrapper when propagate_session=True - #5875

Merged
Evan Mattson (moonbox3) merged 8 commits into
microsoft:mainfrom
benke520:fix/propagate-session-service-id-conflict
Jul 12, 2026
Merged

Python: fix: clear service_session_id in _agent_wrapper when propagate_session=True#5875
Evan Mattson (moonbox3) merged 8 commits into
microsoft:mainfrom
benke520:fix/propagate-session-service-id-conflict

Conversation

@benke520

Copy link
Copy Markdown
Member

Summary

When propagate_session=True, the child agent inherits the parent's session.service_session_id. After the parent's first LLM call, MAF auto-populates this from the Responses API's conversation_id. The child sends it as previous_response_id, which the server rejects because the parent's ool_call is still pending — resulting in a 400 error.

Changes

  • _agents.py: In _agent_wrapper (inside Agent.as_tool()), save and clear service_session_id before calling the child agent, restore it in a inally block. This preserves session.state sharing while isolating the server-side conversation pointer.

Tests

Added 3 new tests:

  • est_chat_agent_as_tool_propagate_session_clears_service_session_id — verifies child sees service_session_id=None and parent gets it restored
  • est_chat_agent_as_tool_propagate_session_restores_service_session_id_on_error — verifies restore happens even if child raises
  • est_chat_agent_as_tool_propagate_session_no_service_session_id — verifies no-op when service_session_id is already None

All 106 tests in est_agents.py pass.

Fixes #5874

Copilot AI review requested due to automatic review settings May 15, 2026 00:18
@moonbox3 Evan Mattson (moonbox3) added the python Usage: [Issues, PRs], Target: Python label May 15, 2026
@github-actions github-actions Bot changed the title fix: clear service_session_id in _agent_wrapper when propagate_session=True Python: fix: clear service_session_id in _agent_wrapper when propagate_session=True May 15, 2026
@moonbox3

Evan Mattson (moonbox3) commented May 15, 2026

Copy link
Copy Markdown
Contributor

Python Test Coverage

Python Test Coverage Report •
FileStmtsMissCoverMissing
packages/core/agent_framework
   _agents.py4474989%540, 552, 607, 1124, 1173, 1244–1248, 1347, 1377, 1414, 1447–1448, 1453, 1460, 1512, 1540, 1553, 1605, 1607, 1616–1621, 1626, 1628, 1634–1635, 1642, 1644–1645, 1653–1654, 1657–1659, 1669–1674, 1678, 1683, 1685
TOTAL44124527088% 

Python Unit Test Overview

Tests Skipped Failures Errors Time
8842 33 💤 0 ❌ 0 🔥 2m 16s ⏱️

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 a Python agent-as-tool session propagation issue where a child agent can inherit the parent’s session.service_session_id, causing invalid previous_response_id usage and 400 errors with Responses-style APIs.

Changes:

  • Update Agent.as_tool(... propagate_session=True) wrapper to temporarily clear session.service_session_id during the child agent run and restore it afterward.
  • Add tests covering save/clear/restore behavior (including restore on child error).

Reviewed changes

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

File Description
python/packages/core/agent_framework/_agents.py Clears and restores service_session_id around delegated run() when propagate_session=True.
python/packages/core/tests/core/test_agents.py Adds tests validating service_session_id isolation/restoration behavior for agent-as-tool.
Comments suppressed due to low confidence (1)

python/packages/core/agent_framework/_agents.py:577

  • The finally block only restores service_session_id when the original value was non-None. If the parent session starts with service_session_id=None, the child run can still set session.service_session_id (e.g., from streaming conversation_id propagation) and it will leak back to the parent. Consider always restoring the original value (including None), using a sentinel to distinguish “no session” vs “saved None”.
            finally:
                if session is not None and saved_service_session_id is not None:
                    session.service_session_id = saved_service_session_id

Comment thread python/packages/core/agent_framework/_agents.py Outdated
Comment thread python/packages/core/tests/core/test_agents.py
@benke520

Benke Qu (benke520) commented Jun 2, 2026

Copy link
Copy Markdown
Member Author

Hi Evan Mattson (@moonbox3) Eduard van Valkenburg (@eavanvalkenburg) — I've addressed both Copilot review comments in eb7bc4e (replaced in-place mutation with an isolated child session copy to avoid races under concurrent asyncio.gather). Could you take a look when you get a chance?

Benke Qu added 2 commits June 2, 2026 11:50
…n=True

When propagate_session=True, the child agent inherits the parent's
service_session_id. After the parent's first LLM call, MAF auto-populates
this from the Responses API conversation_id. The child sends it as
previous_response_id which the server rejects because the parent's
tool_call is still pending (400 error).

This fix saves and clears service_session_id before calling the child
agent and restores it in a finally block, preserving session.state
sharing while isolating the server-side conversation pointer.

Fixes microsoft#5874
Address Copilot review comments:
- Create a child AgentSession with shared state dict but isolated
  service_session_id, avoiding race conditions under concurrent
  asyncio.gather tool invocations.
- Update tests to verify child gets a separate session object and
  that child-set service_session_id does not leak to parent.
@benke520
Benke Qu (benke520) force-pushed the fix/propagate-session-service-id-conflict branch from eb7bc4e to 81c3144 Compare June 2, 2026 18:50
@moonbox3

Copy link
Copy Markdown
Contributor

Benke Qu (@benke520) sorry for the delay. Can you please address the failing CI/CD checks? Thanks.

Comment thread python/packages/core/agent_framework/_agents.py
Benke Qu and others added 5 commits July 8, 2026 08:07
…session isolation

The existing test asserted captured_session is parent_session, but since
we now create a separate child AgentSession (to avoid racing under concurrent
asyncio.gather), the child is a different object. Updated assertions to verify:
- child is NOT the parent object (isolation)
- child shares the same session_id and state dict (by reference)
- child's service_session_id is None (isolated)
Add 'assert captured_session is not None' before attribute access to
satisfy mypy/pyright type checking on Optional values.
@moonbox3

Copy link
Copy Markdown
Contributor

Helping get this past the finish line: I updated the branch with the latest main and fixed the test-typing errors. The refreshed CI is now running.

@moonbox3
Evan Mattson (moonbox3) added this pull request to the merge queue Jul 10, 2026
@github-merge-queue
github-merge-queue Bot removed this pull request from the merge queue due to failed status checks Jul 10, 2026
@moonbox3
Evan Mattson (moonbox3) added this pull request to the merge queue Jul 10, 2026
@github-merge-queue
github-merge-queue Bot removed this pull request from the merge queue due to failed status checks Jul 10, 2026
@moonbox3
Evan Mattson (moonbox3) added this pull request to the merge queue Jul 10, 2026
@github-merge-queue
github-merge-queue Bot removed this pull request from the merge queue due to failed status checks Jul 10, 2026
@benke520

Copy link
Copy Markdown
Member Author

Eduard van Valkenburg (@eavanvalkenburg) Sorry for the accidental re-request — no changes since your approval. The PR keeps getting kicked from the merge queue due to a flaky durabletask integration test (test_multiple_calls_to_same_agent timing out after 90 attempts). This test is unrelated to my changes. Could you advise on next steps — re-run, bypass, or something else? Thanks!

@moonbox3
Evan Mattson (moonbox3) added this pull request to the merge queue Jul 11, 2026
@github-merge-queue
github-merge-queue Bot removed this pull request from the merge queue due to failed status checks Jul 11, 2026
@moonbox3
Evan Mattson (moonbox3) added this pull request to the merge queue Jul 12, 2026
Merged via the queue into microsoft:main with commit f3057ef Jul 12, 2026
37 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

python Usage: [Issues, PRs], Target: Python

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Python: propagate_session=True breaks sub-agent when using Responses API (service_session_id conflict)

4 participants