[BREAKING] Python: Foundry hosting: Responses agent history, options, and background - #8794
Conversation
There was a problem hiding this comment.
Copilot review overview
🟡 Changes recommended
Provider-background polling currently loses caller options, mishandles shutdown, and can expose private continuation tokens in logs.
Review effort: Balanced
Findings: 1
What changed in this PR
Implements the Responses-agent slice of the Foundry hosting redesign, separating outer storage from inner history and provider behavior.
Changes:
- Adds explicit history, option-hook, storage, background, and steering policies.
- Adds provider-background recovery and scoped conversation persistence.
- Expands samples, documentation, and tests.
| File | Description |
|---|---|
steerable_long_running_agent/verify_steering.py |
Isolates state and strengthens steering verification. |
steerable_long_running_agent/README.md |
Documents conversation-based steering. |
steerable_long_running_agent/main.py |
Selects host-managed history explicitly. |
basic/service_history.py |
Demonstrates service-managed history. |
basic/README.md |
Documents new history, storage, and options semantics. |
basic/provider_background.py |
Demonstrates provider-native background processing. |
basic/options.py |
Demonstrates the developer options hook. |
basic/main.py |
Updates the basic host configuration. |
basic/client.py |
Adds stored, unstored, and background client examples. |
basic/agent_history.py |
Demonstrates agent-managed history. |
basic/.env.example |
Adds the deployed agent name setting. |
tests/test_responses.py |
Adds lifecycle, storage, recovery, and steering tests. |
tests/test_request.py |
Tests request-option translation and validation. |
foundry_hosting/README.md |
Documents redesigned hosting behavior. |
_responses.py |
Implements history, background, persistence, and option policies. |
_request.py |
Adds request views and option processing. |
__init__.py |
Exports HostedResponseRequest. |
💡 Add a code-review agent skill for context-aware, tailored reviews. Learn more in the docs.
There was a problem hiding this comment.
MAF Automated Review — Iteration 1
Result: Findings reported
Scope: full PR (2 commit(s)): e2c88e6280b1, be003ffc9414
Model: gpt-5.6-sol-fast
Overview
The change cleanly separates outer persistence from inner history/background behavior and adds substantial validation, fail-closed store=False handling, recovery checks, and two-turn coverage. Those guardrails do not cover a nested transport-options escape hatch, and enabling the current TaskManager steering path exposes a process-wide future leak when its bounded durable queue is full. Provider-background calls also fail to observe cancellation and shutdown while awaiting the provider, leaving a bounded but meaningful lifecycle risk.
Reviewed the supplied pull-request change set across correctness, security/reliability, architecture, and failure behavior.
3 verified findings remained after source verification (2 high, 1 medium) across 2 files. Details are attached to the affected lines below.
Affected areas: python/packages/foundry_hosting/agent_framework_foundry_hosting/_request.py, python/packages/foundry_hosting/agent_framework_foundry_hosting/_responses.py
Jose Alvarez (jpalvarezl)
left a comment
There was a problem hiding this comment.
I see two remaining issues on 8857366e6. These are separate from the resolved option-preservation and concurrent-dispatch comments. Both were reproduced during the earlier review, and the relevant paths are unchanged in the latest commits.
-
P2: Preserve completed tool output when polling returns another continuation token. In
python/packages/foundry_hosting/agent_framework_foundry_hosting/_responses.py:1675-1682, this branch saves the next token but does not pass the response's messages or usage to the tracker. A poll can complete a function-call response, execute the local tool, and return its call/result messages alongside the next background token. Using the realOpenAIChatClientwith mocked transport and the PR'ssend_emailscenario, the tool executes once, but the outer response contains only the final "Email sent." message; the function call and result are missing. Could we preserve the completed output and usage across polling and recovery? Please extend the existing polling test to assert the outer response's full tool transcript, not just provider options and execution count. -
P2: Allow recovery after this response has committed the conversation head. The recovery check at
_responses.py:1292-1297requires the head's in-flight claim to still belong to this response. However, finalization at1504-1517saves the response snapshot and clears that claim before publishing the outer completion. A crash immediately after the successful head write leaves a valid completed provider token in the snapshot and no outer completion event, but recovery fails with "claim is no longer held by this response" even though no other turn took ownership. Could we persist enough completion/ownership information to distinguish this response's already-committed head from a competing turn? Please cover recovery from a crash immediately after that head write, while preserving the concurrent-dispatch protection.
|
Addressed both findings from this review in
The previously documented crash window between a local tool side effect and saving the next token/output remains; side-effecting tools must still be idempotent. Full hosting, core, OpenAI and AG-UI unit suites, strict source/test typing, lint and sample checks pass locally. Fresh CI on |

Motivation & Context
Important
Steering is temporarily gated, not enabled by this PR. On the affected
azure-ai-agentserver-corereleases (including 2.1.0 and 2.2.0),ResponsesHostServer(options=ResponsesServerOptions(steerable_conversations=True))fails at construction before enabling the process-wide TaskManager. This prevents
its rejected-queue future leak while leaving ordinary Responses/background work
available. Azure/azure-sdk-for-python#49233 fixes the SDK bug upstream; removing
this gate requires an official patched wheel, a verified minimum dependency and
uv.lockupdate, and a concurrent queue-overflow test with no retained futures.This PR does not change the SDK dependency or claim steering is currently safe.
This is the Responses agent-only slice of the coordinated Foundry-hosting redesign, building on the
merged trusted-scope foundation in #8741 and landing before one beta release. The earlier
history_source="agent"allowed an agent to use either its ownHistoryProvideror downstream service storage.The redesign must not silently disable the latter.
Description & Review Guide
storeand outer background polling fromhistory_source="agent_server" | "agent" | "service"andbackground_source="agent_server" | "provider". The existinghistory_source="agent"keepsits developer-controlled HistoryProvider or downstream service storage behavior on stored requests;
"service"explicitly chooses the downstream service.history_sourceis not deprecated.Constructor
store=remains a deprecated alias for the outerresponse_store=backend.Map native Responses generation fields and flattened
extra_bodyto MAF options, with extrafields winning collisions and a developer-owned
prepare_optionshook.Save each agent response under its outer ID, advance named conversation state with PR1's CAS protection, and
fail fast if steering is requested before the SDK fix can be safely consumed. Ship
basic history/options/background/client and a runnable non-steerable long-running
agent sample alongside deterministic, credential-free HTTP and unit coverage.
store=Falserequest no longer writes host session/approval state or asksa storing inner client to persist; unsafe legacy/custom configurations fail explicitly instead of persisting
silently. Rejecting conflicting developer
store=Truedefaults on a non-storing client rather than mutatingthem, and the stricter
store=Falseboundary, are intentional beta API behavior changes; the title flags theseas breaking instead of hiding them. Provider tokens and platform identity remain private.
WorkflowAgent legacy dispatch remains intact; native Responses workflows, Invocations, and agent integrations
are separate slices. This branch also retains the merged Python: Fix Foundry hosting test teardown across pytest retries #8791 retry-fixture fix.
history_source="agent"behaviorwith
default_options={"store": True}versus a HistoryProvider anddefault_options={"store": False};fail-closed unstored requests, the private service-session/fork boundary, the response-snapshot-first
conversation CAS path, provider-background recovery, and the guard that prevents any new
steering TaskManager/SDK queue work. The earlier non-streamed steering poll caveat is
inapplicable while steering is gated; re-evaluate it when the SDK fix is consumed. Separate open PRs
Python: add opt-in deferred session persistence to foundry_hosting #8440 (deferred session writes) and Python: Foundry Hosting - support conversation branching #8618 (branching) touch
the same Responses files; neither is imported in this slice.
Related Issue
Closes #8744
Part of #8742
Builds on merged #8741
Related: #7389 (per-request agent and WorkflowAgent factories already completed; native workflow= hosting without as_agent() is tracked by #8747).
Contribution Checklist
breaking changelabel (or add "[BREAKING]" to the title prefix, before or after any language prefix) — a workflow keeps the label and title prefix in sync automatically.