Skip to content

Python: Add long-running agents and background responses support - #3808

Merged
eavanvalkenburg merged 4 commits into
microsoft:mainfrom
eavanvalkenburg:support_long_running
Feb 10, 2026
Merged

Python: Add long-running agents and background responses support#3808
eavanvalkenburg merged 4 commits into
microsoft:mainfrom
eavanvalkenburg:support_long_running

Conversation

@eavanvalkenburg

Copy link
Copy Markdown
Member

Summary

Adds support for long-running agent operations and background responses, matching the dotnet implementation pattern adapted to Python conventions.

Fixes #2478

Changes

Core Types (_types.py)

  • Added ContinuationToken TypedDict — a simple JSON-serializable dict with response_id field
  • Added continuation_token: ContinuationToken | None to ChatResponse, ChatResponseUpdate, AgentResponse, and AgentResponseUpdate
  • Updated map_chat_to_agent_update and _process_update to propagate tokens

OpenAI Responses Client (_responses_client.py)

  • Added background: bool and continuation_token: ContinuationToken to OpenAIResponsesOptions
  • Non-streaming: polls via responses.retrieve(response_id) when continuation_token is provided
  • Streaming: resumes via responses.retrieve(response_id, stream=True) when continuation_token is provided
  • Sets continuation_token on responses when OpenAI status is in_progress or queued

Agent Layer (_agents.py)

  • Propagates continuation_token from ChatResponseAgentResponse in non-streaming path

Telemetry Fix (observability.py)

  • Fixed pre-existing Failed to detach context error in both ChatTelemetryLayer and AgentTelemetryLayer streaming paths
  • Root cause: trace.use_span() context was attached synchronously but detached in async cleanup hooks (different async context)
  • Fix: create spans directly with start_span() + span.end() for streaming, avoiding context attachment

Tests

  • 14 new unit tests covering token serialization, response types, background status parsing, streaming events, and options handling

Sample

  • samples/concepts/background_responses.py demonstrating non-streaming polling and streaming resumption patterns

Usage

# Non-streaming polling
response = await agent.run(messages="Task", options={"background": True})
while response.continuation_token is not None:
    await asyncio.sleep(2)
    response = await agent.run(options={"continuation_token": response.continuation_token})

# Streaming with resumption
stream = agent.run(messages="Task", stream=True, options={"background": True})
async for update in stream:
    last_token = update.continuation_token
# Resume: agent.run(stream=True, options={"continuation_token": last_token})

Copilot AI review requested due to automatic review settings February 10, 2026 13:49
@eavanvalkenburg eavanvalkenburg added python Usage: [Issues, PRs], Target: Python v1.0 labels Feb 10, 2026
@markwallace-microsoft markwallace-microsoft added the documentation Usage: [Issues, PRs], Target: documentation in the code base and learn docs label Feb 10, 2026
@markwallace-microsoft

markwallace-microsoft commented Feb 10, 2026

Copy link
Copy Markdown
Contributor

Python Test Coverage

Python Test Coverage Report •
FileStmtsMissCoverMissing
packages/a2a/agent_framework_a2a
   _agent.py167994%357, 378, 451–452, 489–490, 519–521
packages/core/agent_framework
   _agents.py3203589%475, 883, 920, 1019–1021, 1134, 1175, 1177, 1186–1191, 1197, 1199, 1209–1210, 1217, 1219–1220, 1228–1232, 1240–1241, 1243, 1248, 1250, 1284, 1324, 1344
   _types.py10459690%83, 92–93, 147, 152, 171, 173, 177, 181, 183, 185, 187, 205, 209, 235, 257, 262, 267, 271, 297, 301, 647–648, 1019, 1081, 1098, 1116, 1121, 1139, 1149, 1166–1167, 1169, 1187–1188, 1190, 1197–1198, 1200, 1235, 1246–1247, 1249, 1287, 1544, 1597, 1604, 1626, 1632, 1680, 1723–1728, 1750, 1755, 1921, 1933, 2176, 2185, 2206, 2301, 2526, 2733, 2803, 2815, 2822, 2833, 3037–3039, 3042–3044, 3048, 3053, 3057, 3169–3171, 3199, 3253, 3257–3259, 3261, 3272–3273, 3276–3280, 3286
   observability.py6118486%334, 336–338, 341–343, 348–349, 355–356, 362–363, 370, 372–374, 377–379, 384–385, 391–392, 398–399, 406, 662, 665, 673–674, 677–680, 682, 685–687, 690–691, 719, 721, 732–734, 736–739, 743, 751, 852, 854, 1003, 1005, 1009–1014, 1016, 1019–1023, 1025, 1137–1138, 1140, 1197–1198, 1333, 1387–1388, 1504–1506, 1565, 1735, 1889, 1891
packages/core/agent_framework/openai
   _responses_client.py6047787%298–301, 305–306, 309–310, 316–317, 322, 335–341, 362, 370, 393, 455, 487, 512, 518, 536–537, 559, 564, 621, 635, 652, 665, 720, 799, 804, 808–810, 814–815, 838, 907, 929–930, 945–946, 964–965, 1096–1097, 1113, 1115, 1194–1202, 1297, 1352, 1367, 1403–1404, 1406–1408, 1422–1424, 1434–1435, 1441, 1456
TOTAL16695207587% 

Python Unit Test Overview

Tests Skipped Failures Errors Time
3964 225 💤 0 ❌ 0 🔥 1m 10s ⏱️

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

Adds Python support for long-running agent operations via OpenAI Responses “background” runs, including continuation token propagation across core response types, OpenAI client polling/resumption paths, telemetry fixes for streaming spans, plus tests and a sample.

Changes:

  • Introduces a ContinuationToken TypedDict and propagates it through ChatResponse* and AgentResponse* types and mapping/merge logic.
  • Extends OpenAIResponsesClient options with background + continuation_token, enabling non-streaming polling and streaming resumption via retrieve.
  • Fixes OpenTelemetry streaming span lifecycle handling and adds unit tests + a usage sample + changelog entry.

Reviewed changes

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

Show a summary per file
File Description
python/packages/core/agent_framework/_types.py Adds ContinuationToken and plumbs continuation_token through response/update types and update processing.
python/packages/core/agent_framework/openai/_responses_client.py Adds background + continuation token support, including polling and stream resumption behavior.
python/packages/core/agent_framework/_agents.py Propagates continuation_token into AgentResponse (non-streaming path).
python/packages/core/agent_framework/observability.py Fixes streaming span detach errors by avoiding context attachment for spans closed in async cleanup.
python/packages/core/tests/openai/test_openai_responses_client.py Adds unit tests covering token serialization/propagation and background status handling.
python/samples/concepts/background_responses.py Adds a sample demonstrating polling and streaming resumption patterns.
python/CHANGELOG.md Documents the new long-running/background responses feature.

Comment thread python/packages/core/agent_framework/_types.py Outdated
Comment thread python/samples/concepts/background_responses.py
Comment thread python/samples/concepts/background_responses.py
Comment thread python/packages/core/tests/openai/test_openai_responses_client.py Outdated
Comment thread python/packages/core/agent_framework/_types.py Outdated
@eavanvalkenburg
eavanvalkenburg added this pull request to the merge queue Feb 10, 2026
@eavanvalkenburg
eavanvalkenburg removed this pull request from the merge queue due to a manual request Feb 10, 2026
@eavanvalkenburg
eavanvalkenburg added this pull request to the merge queue Feb 10, 2026
@github-merge-queue
github-merge-queue Bot removed this pull request from the merge queue due to a conflict with the base branch Feb 10, 2026
- Add ContinuationToken TypedDict to core types
- Add continuation_token field to ChatResponse, ChatResponseUpdate,
  AgentResponse, and AgentResponseUpdate
- Add background and continuation_token options to OpenAIResponsesOptions
- Implement polling via responses.retrieve() and streaming resumption
  in RawOpenAIResponsesClient
- Propagate continuation tokens through agent run() and
  map_chat_to_agent_update
- Fix streaming telemetry 'Failed to detach context' error in both
  ChatTelemetryLayer and AgentTelemetryLayer by avoiding
  trace.use_span() context attachment for async-managed spans
- Add 14 unit tests for continuation token types and background flows
- Add background_responses sample showing polling and stream resumption

Fixes microsoft#2478
- Make ContinuationToken provider-agnostic (total=False, optional task_id/context_id fields)
- Add background param to A2AAgent.run() controlling token emission
- Add poll_task() for single-request task state retrieval
- Add resubscribe support via continuation_token param on run()
- Extract _updates_from_task() and _map_a2a_stream() for cleaner code
- Streamline run()/streaming by removing intermediate _stream_updates wrapper
- Update A2A sample to show background=False (default) with link to background_responses sample
- Remove stale BareAgent from __all__
- Add 12 new A2A continuation token tests
@eavanvalkenburg
eavanvalkenburg added this pull request to the merge queue Feb 10, 2026
Merged via the queue into microsoft:main with commit 35097d8 Feb 10, 2026
26 checks passed
@moonbox3 moonbox3 removed the v1.0 label Jun 17, 2026
@eavanvalkenburg
eavanvalkenburg deleted the support_long_running branch June 30, 2026 09:02
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Usage: [Issues, PRs], Target: documentation in the code base and learn docs python Usage: [Issues, PRs], Target: Python

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Python: Long running agents support

5 participants