Python: Pass client thread_id as session_id when constructing AgentSession in AG-UI (#5384)

* Pass thread_id as session_id when constructing AgentSession in AG-UI

run_agent_stream() was constructing AgentSession without passing the
client's thread_id as session_id, causing every request to receive a
random UUID. This broke session continuity for HistoryProvider
implementations that rely on session_id matching the client's thread_id.

Pass session_id=thread_id in both the service-session and non-service
code paths so the session identity is consistent with the AG-UI client.

Fixes #5357

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Add test for service_session with no thread_id edge case (#5357)

When use_service_session=True but no thread_id/threadId is in the payload,
verify session_id is a generated UUID and service_session_id is None.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

---------

Co-authored-by: Copilot <copilot@github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
Evan Mattson
2026-04-22 17:45:25 +00:00
committed by GitHub
co-authored by Copilot Copilot
parent 3ae86f098e
commit 0b50455e75
3 changed files with 116 additions and 2 deletions
@@ -183,6 +183,7 @@ class StubAgent(SupportsAgentRun):
self.client = client or SimpleNamespace(function_invocation_configuration=None)
self.messages_received: list[Any] = []
self.tools_received: list[Any] | None = None
self.last_session: AgentSession | None = None
@overload
def run(
@@ -216,6 +217,7 @@ class StubAgent(SupportsAgentRun):
async def _stream() -> AsyncIterator[AgentResponseUpdate]:
self.messages_received = [] if messages is None else list(messages) # type: ignore[arg-type]
self.last_session = session
self.tools_received = kwargs.get("tools")
for update in self.updates:
yield update