demo(agentserver): TEMPORARY - durable-agent-demo (split out of #46997, never-merged) - #47276
Draft
RaviPidaparthi wants to merge 692 commits into
Draft
demo(agentserver): TEMPORARY - durable-agent-demo (split out of #46997, never-merged)#47276RaviPidaparthi wants to merge 692 commits into
RaviPidaparthi wants to merge 692 commits into
Conversation
RaviPidaparthi
changed the base branch from
main
to
feature/agentserver-durable-tasks
June 2, 2026 03:33
RaviPidaparthi
force-pushed
the
feature/agentserver-durable-agent-demo
branch
from
June 2, 2026 22:50
756e0fe to
2553746
Compare
…te-serialization (spec 031) Behavioral tests through real framework wiring (no mocks): pending_input_count must reflect the live queued-steering count at the cancel boundary (SOT §13 ordering invariant), and a steer+drain must run the steered turn with no blind PATCHes (SOT §25.1). The pending_input_count test lands RED (count==0, the observed defect) ahead of the fix. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…pec 031) Conformance-restoration: the implementation had drifted from the SOT spec (docs/task-and-streaming-spec.md). Fixes: - pending_input_count (FR-001/002, SOT §12/§13): add settable _ActiveTask slot _pending_input_count; record it BEFORE ctx.cancel in the same-process enqueue and both cross-process steering polls (§13 ordering invariant); reset to the remaining backlog on drain. Previously read a never-written attribute -> 0. - No blind writes (FR-005b, SOT §25.1): the queued-steering-cancel path used a bare provider.update with no If-Match (lost-update risk) -> now routes through the lock-held update primitive carrying the tracked etag. - Lock-held update primitive (FR-005a): extract _provider_update_lock_held for callers that already hold the non-reentrant per-task lock; _provider_update_locked delegates to it. - Drain read-inside-lock (FR-005, SOT §25.2): the steering drain now performs its record read + compute + write under one per-task lock hold (read was lock-free before, letting the lease heartbeat invalidate the pinned etag and starve the retry budget). Cross-process conflicts retry outside the lock. - SOT reconciled: §12/§13 (pending_input_count is in-process observed state, failure-tolerant, set-before-cancel), §25.1 (no blind writes), §25.2 (read-inside-lock rationale + two-helper split). Validated: 646 durable + 746 durable+streaming green; responses consumer green (2 pre-existing unrelated failures). Tests from prior commit now GREEN. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…ry, provider parity Completes the remaining spec-031 conformance work: - Drain recovers from cross-process etag conflict (FR-006/SOT §25.3): the drain now also catches EtagConflict (consistent with the terminal-write + metadata paths) so a conflict landing on its write re-reads + retries instead of being abandoned by the caller's bare except. RED test reproduced the exact hosted 'Failed to drain steering queue' failure, then GREEN. - Metadata flush conflict retry (FR-006a/SOT §25.3): re-read + retry (≤5, last-write-wins on the namespace slot) instead of swallow-and-defer. - Local/file-provider hosted-parity assertions (FR-008/009): stale-if_match -> hosted-identical etag_mismatch/412 classification; lease-only update bumps the etag; two providers over one store reproduce a deterministic cross-process conflict + recovery. - Registered the new behavioral tests in the completeness meta-test (FR-016). - FR-005c if_match-site audit recorded; FR-012 streams conformance confirmed already-comprehensive by audit; FR-018 guide already consistent. Validated: 651 durable + 755 durable+streaming green; pylint unchanged (9.59/10). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…rver-responses-spec016
…ntserver-durable-agent-demo
…n bug (spec 031)
Hosted re-test of the invocations steering demo revealed the real drain failure
is NOT an etag race but a lease-renewal-on-suspended rejection: the multi-turn
turn writes status=suspended before the drain runs, and the hosted task store
rejects the drain PATCH's lease-renewal piggyback with 'lease renewal is only
supported for in_progress tasks'. The local provider was too permissive (allowed
renewal on {in_progress, suspended}), masking it. This commit tightens the local
provider to in_progress-only (hosted parity) + adds the drain status-transition
regression test, landing the bug RED.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…red turn runs (spec 031) The drain promotes a queued steering input to a NEW turn, but the record was left 'suspended' by the just-ended turn. The drain's PATCH now sets status='in_progress' (a valid suspended->in_progress claim that the hosted store accepts WITH lease params), instead of a bare lease renewal that the store rejects on a suspended task. Validated on a deployed hosted agent (rapida-0687): the steered turn now runs the new topic end-to-end; logs show 'Steering drain: drained next input' with no 'Failed to drain'. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…rver-responses-spec016
…ntserver-durable-agent-demo
Refresh the checked-in preview wheels so the demo's docker image ships the pending_input_count + steering-drain (suspended->in_progress) fixes validated on hosted (rapida-0687, s4 steering passes end-to-end). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…se renewal requires in_progress (spec 031) Corrects §52 step 14 (drain Phase-1 PATCH MUST set status='in_progress') and adds the §25.4 rule that the lease-extension trio is a renewal only on an already-in_progress record, or a claim when the same PATCH flips to in_progress. This is the doc-level root of the hosted 'Failed to drain steering queue' bug. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…rver-responses-spec016
…ntserver-durable-agent-demo
… (gpt-4o, env-driven) The invocations demo committed its .azure env hardcoding the e2e-tests-westus2 project (broken ACR perms) and gpt-4.1-mini. Align it with the responses demo which targets the working project (rapida-0687): gitignore .azure (env-driven, no committed project pointer) and switch the model to gpt-4o in azure.yaml, agent.yaml, agent.py, and README. Validated by deploying to rapida-0687 and running an invocation end-to-end (clean run, gpt-4o streaming, no errors). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The default ENDPOINT was an unresolved <account>/<project> placeholder and the script never read the azd env (despite the comment), so 'demo-client.sh start' POSTed to a bogus host -> empty invocation_id -> immediate 'Stream disconnected'. Now ensure_endpoint() auto-resolves ENDPOINT from AGENT_DURABLE_RESEARCH_AGENT_INVOCATIONS_ENDPOINT (stripping the /invocations?... tail) when the placeholder is still in place, and errors with clear guidance if it cannot. API_VERSION stays 'v1' (verified working). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…now an offline alternative The hosted task API no longer returns 403; the durable demos are validated end-to-end on a hosted Foundry deployment. Reframe both durable-demo READMEs: the azd-deployed hosted flow is the recommended path; the local file-backed kit is an offline alternative (no longer 'recommended because hosted is broken'). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…depth gaps B1/B6/B7
- FR-001: harden the Principle XI depth gate from soft warnings.warn to a hard
assert; broaden the detector to recognize the failed-row error idiom
(terminal.get('error')/error.get('code')); add response.output content depth to
the status-only completed Path-A per-cell tests (Row 1/2 Path A).
- B1 (FR-005): reset-event CONTENT — real-crash Row 11 test asserts the
post-recovery response.in_progress reset event's response.output carries the
corrected (seeded) items, not just that it exists.
- B6 (FR-009a): Path B graceful-handoff — assert the runtime exits gracefully
(not the Path-C SIGKILL fallback), proving the graceful shutdown path ran.
- B7 (FR-009b): recovery precondition — a transient store error during the
recovery pre-fetch MUST NOT drop; new fault-injecting store handler proves
recovery proceeds (handler re-invoked, completes) and the transient fired.
All RED-first (gate failed on the 2 shape-only Path-A tests before depth added).
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…coverage matrix Spec 032 conformance audit follow-up: - Add test_client_cancel_during_recovery.py (B3): real crash + real cancel endpoint during a recovered invocation settles to terminal cancelled. - Reconcile CONTRACT_COVERAGE.md: correct stale GAP/TO-BE-ADDED markers to the tests that already close them; add a Spec 032 section mapping the new recovery-gap tests (B1 reset-event content, B3 client-cancel-during-recovery, B6 graceful-exit-not-SIGKILL, B7 transient-precondition-must-not-drop) and the closed-by-existing/consequence items (B4 seeding, B5 dedup, B8 created idempotency) to their contract clauses. - black formatting on the Spec 032 test modules. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…ntserver-durable-agent-demo
…urable task input
On hosted, the platform injects `agent_reference` as an AgentReference model
(a Mapping but not json.dumps-serializable). It leaked through
_split_runtime_refs into the persisted durable-task input, so
create_and_start -> _resolve_input_storage raised
`TypeError: Object of type AgentReference is not JSON serializable` and the
durable background start silently fell back to a non-durable
asyncio.create_task — meaning NO durable task was created and crash recovery
never happened on hosted.
_split_runtime_refs now normalizes a model-typed agent_reference to a plain
dict (consumers all accept AgentReference | dict and read it as a mapping; the
dict also survives cross-process recovery). Absent agent_reference stays the
{} sentinel.
This was invisible to the conformance suite because local/conformance requests
carry no agent_reference (-> {} sentinel -> serializable). Adds
TestSplitRuntimeRefsSerializable asserting the persisted durable input is
JSON-serializable when agent_reference is a model.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…ntserver-durable-agent-demo
…de-bloat - responses wheel now carries the agent_reference durable-input serialization fix (durable background responses were silently degrading to non-durable asyncio.create_task on hosted). - All three wheels rebuilt from clean trees: the previously checked-in wheels had bundled stale build/lib/** duplicates (core 612KB->157KB, invocations 722KB->20KB, responses 1.3MB->336KB) with no functional change beyond the responses fix. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Pin both durable demos to the shared rapida-0687 Foundry project so deploys are reproducible: - invocations durable-agent-demo (.azure/demo-dev) - responses durable-responses-agent-demo (.azure/durable-responses-agent-demo) Force-added past the .azure/.gitignore. Contains resource pointers (subscription/resource-group/project/ACR/endpoint) only — no secrets; .env.lock and state/ remain ignored. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…n recover) The demo crash trigger (input='crash' -> os._exit(137)) did not check context.is_recovery, so after a crash the durably re-delivered 'crash' input re-fired the exit on every recovered lifetime — an infinite crash-loop for a demo whose whole point is to crash ONCE and recover. Guard with 'not context.is_recovery' so the recovered run skips the crash and resumes to completion. Also refreshes the azd env agent version pointer. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…ntserver-durable-agent-demo
…t agent_reference
Adds a Path-C real-crash conformance test that carries an agent_reference on the
request (the hosted gateway-injected AgentReference model). It reproduces the
hosted 'AgentReference is not JSON serializable' durable-start failure LOCALLY
(durable start is provider-agnostic): without the _split_runtime_refs
normalization fix the model leaks into the durable-task input, durable start
falls back to a non-durable asyncio.create_task, the SIGKILL'd task is lost and
recovery never reaches completed (verified RED). With the fix it recovers.
Closes the gap that let the bug ship: every other durability test sent no
agent_reference ({} sentinel) or a plain string, so none exercised the model
form through durable-input serialization.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…ding agents
Reviewed all four standalone skills against the actual package surface and fixed
claims that produce broken code:
durable-task-skill:
- Remove the broken 'from ...durable import ... Suspended' (Suspended is an
internal _Suspended sentinel, not exported -> ImportError).
- Fix local-provider env vars: the LocalFileTaskProvider roots at
${AGENTSERVER_DURABLE_ROOT:-~/.durable}/tasks/ and the force-local override is
AGENTSERVER_TASKS_BACKEND=local (the doc's ~/.durable-tasks/ +
AGENTSERVER_DURABLE_TASKS_PATH were wrong/legacy).
responses-skill:
- context.durable_metadata / DurableMetadataNamespace does not exist; the real
handler metadata facade is context.conversation_chain_metadata
(ConversationChainMetadataNamespace, has .flush()). Fixed surface table +
decision shortcut.
- Import CreateResponse and ResponseEventStream from the public top-level
azure.ai.agentserver.responses (not the private models._generated /
streaming._event_stream modules).
streaming-skill:
- use_file_backed_replay takes storage_dir=, not root= (2 spots).
invocations-skill verified correct (invoke_handler/get_invocation_handler/
cancel_invocation_handler/ws_handler/request.state.session_id all real) — no change.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…ec 041 A-docs) Capture the composition learning surfaced while reworking the resilient langgraph samples: on steer/recovery re-run from the last stable graph checkpoint (not the latest tip), seed checkpoint_ns="" when forking through the sqlite checkpointer (else KeyError), and use Command(resume=...) only when parked at an interrupt. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…ec 041 PY-3) The task/streaming identity rule (and tasks-guide.md, and the .NET port) specify that a multi-turn turn gets its OWN unique input_id when the caller omits one — but the source defaulted an omitted multi-turn input_id to the (fixed) chain task_id, identical across turns. Source lagged the spec + its own docs. MultiTurnTask.run/.start now mint a fresh per-turn id (input-<uuid4-hex>) when input_id is omitted (and no If-Match precondition is in play, which requires an explicit advancing id). The id flows through the existing plumbing: persisted as the chain head (payload["last_input_id"], advancing every turn and surviving recovery) and surfaced on TaskContext.input_id. One-shot tasks are unchanged (input_id still defaults to task_id — the 1:1 invariant). Tests: per-turn uniqueness + chain-head advance, surfaced on ctx.input_id, caller-supplied id preserved, one-shot defaults to task_id. Updated the former test_legacy_callers_unaffected (which pinned the old "slot not seeded" behavior) to assert the new auto-generated seeding. Full core tasks suite: 697 passed. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
… terminal (Spec 041 PY-5) verify_crash.py previously proved recovery primarily by scraping continuous `azd ai agent monitor` server logs (worker-instance counts, reclaim/recovered markers) — unreliable across a nanny restart (re-attaches to the pre-crash log buffer, doesn't reliably follow the new container's stdout). Now the verdict is DETERMINISTIC and log-independent: (a) confirmed hard crash (the streaming connection dropped → sandbox died), (b) observed pre-crash checkpointed progress, and (c) the response reaches `completed` AFTER the crash, read via a NON-STREAMING GET snapshot poll (rs.poll_terminal — no stream-TTL constraint, unlike the SSE reconnect which may have expired across the restart). Continuous log capture + marker greps + the stream reconnect are retained as SUPPLEMENTARY evidence only, and the script now exits non-zero when the deterministic proof fails (usable as a battery gate). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…rver-responses-spec016
…ntserver-durable-agent-demo
…hanges Rebuild the checked-in core/invocations/responses preview wheels so the demo container ships the Spec 041 library changes (PY-1/PY-2 file-backed replay, PY-3 per-turn multi-turn input_id). Sample-only changes (A0/A1, checkpoint_ns fixes) are not in the wheels. Built from a clean tree (no stray build/ dir). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…041 PY-6) The responses demo battery never pinned agent_session_id, so each POST landed on a DIFFERENT sandbox — a `crash` request killed an unrelated container, not the one running the in-flight response. The run finished normally and merely *looked* recovered, so the crash cases were not actually testing recovery. (agent_session_id is a top-level create-response body property; one session id == one sandbox.) run_suite.py: - body() gains an agent_session_id param; new_session() mints demo-<uuid>. - fire_crash(session) is now REQUIRED to pin the crash to the run's session; corrected its false "single sandbox" docstring; returns crash_session (echoed x-agent-session-id) + requested_session. - case_crash_recovery / case_steering_crash pin start+steer+crash to one session and add crash_hit_target (crash_session == run session) as a REQUIRED part of the ok/recovery gate. verify_crash.py: - Pins the run + crash to a fresh session; crash_hit_target is now a required fact of recovery_proven (alongside crash_confirmed + pre-crash progress + authoritative completed terminal); surfaced in the verdict + failure message. (The latent session_id->crash_session key bug was already fixed in PY-5.) demo-client.sh: - Persist AGENT_SESSION_ID in .demo-session; mint_session_id() uses uuidgen with a python3 fallback; start mints a fresh session, steer/crash reuse it, all three send agent_session_id in the body so they hit the same sandbox. verify_crash_steer.py + the __ECHO_CRASH__ self-crash proofs were already sound (they route the crash onto the target's own task) and are unchanged. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…ash-confirmation (Spec 041 PY-6 follow-up) The session-affinity fix (PY-6) made crashes actually hit the run's sandbox, which exposed two battery MEASUREMENT bugs (the run recovered, but the battery mis-read it): - case_crash_recovery(stream=True) read the terminal via an SSE reconnect, whose TTL expires across the ~150s restart window -> terminal=None (false FAIL). Now BOTH stream and non-stream crash cases read the authoritative terminal via a non-streaming GET poll (like the poll variant + verify_crash); the SSE reconnect is kept as supplementary stream-continuity evidence. - verify_crash.py required the connection-drop signal (sandbox_dropped) to confirm the crash, but the handler flushes a terminal SSE before os._exit so the client often sees a clean close (drop=False) even though the sandbox genuinely died + restarted. crash_confirmed now accepts EITHER a dropped connection OR restart evidence (new worker instance / reclaim / recovered markers). Verified live: crash recovery PROVEN (crash_hit_target=True, 2 worker instances, reclaim+recovered markers, terminal=completed) for verify_crash + T3/T8; T1/T2/T4/ T6/T7/T16 pass. Known separate finding (pre-existing, newly exposed, NOT a regression): T5 steer x crash leaves the steered turn in_progress after the original recovers to completed — orchestrator steering-queue drain after a real crash needs follow-up. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…covery, timestamps (Spec 041 PY-7/8/9) Responses demo-client.sh fixes for the interactive (cross-terminal) demo flow — invisible to the battery (which posts in-process and reads the session id from the response header directly), which is why PY-6's battery verification passed while the interactive demo still failed for users. PY-7 (cross-terminal crash/steer targeting): - Publish the in-flight response id to a shared .demo-session.active the instant it is captured mid-stream; load_session falls back to it — so a command in another terminal (steer/cancel/stream) can target the run that is currently streaming (the session file only got RESPONSE_ID when the stream ended). - SSE sidecar temp files are now PID-private (.$$) so a concurrent invocation can't rm/clobber a streaming command's id/seq files. - The interactive crash stays a BARE agent_session_id-pinned streaming crash (never a previous_response_id steer, which would only run AFTER the current turn and never interrupt it). PY-8 (endpoint self-discovery + fail-fast): - _azd_responses_endpoint resolves AGENT_*_RESPONSES_ENDPOINT from `azd env get-values` (fallback: ./.azure/<defaultEnvironment>/.env), strips the trailing /responses?api-version=… to the protocol base, and lifts api-version. - An exported ENDPOINT is honored only when it is a real (non-placeholder) URL. - _require_endpoint (invoked from ensure_token, so every network command is guarded) aborts with actionable guidance if the value is still a placeholder, so a mis-run crash can never be silently fired at a bogus host. Fixed the placeholder default path to …/protocols/openai. PY-9 (client/server log correlation): - _now_iso() (UTC ISO-8601, matching the server log clock); a "▶ triggered @" banner and an EXIT-trap "⏹ ended @ (elapsed Ns, exit rc)" banner to stderr (so they never pollute SSE stdout); the crash line is timestamped. Verified: bash -n clean; `status` with ENDPOINT unset auto-resolves the real …/protocols/openai endpoint (api-version=v1) and makes a live call (no placeholder no-op); banners print with UTC timestamps + elapsed. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…client (Spec 041 PY-9 parity) The invocations resilient-agent-demo demo-client already had endpoint self-discovery + placeholder guard (PY-8) and session pinning (PY-7); it only lacked client-side timestamps. Add _now_iso() + the "▶ triggered @" / "⏹ ended @ (elapsed Ns, exit rc)" stderr banners so its timeline can be lined up against the server log, matching the responses demo-client. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…eleased on PyPI) Merged origin/main into the core branch; main had dated+released core 2.0.0b7, invocations 1.0.0b6, responses 1.0.0b8 (all on PyPI 2026-06-28). Bump each to the next beta so the unreleased work ships without colliding with a released version: - core 2.0.0b7 -> 2.0.0b8 - invocations 1.0.0b6 -> 1.0.0b7 - responses 1.0.0b8 -> 1.0.0b9 Changelog hygiene: the merge collapsed our stale "## X (Unreleased)" headers (which reused the now-released version numbers) — restored main's released dated sections (core b7, invocations b6) below the new (Unreleased) sections, and moved the genuinely-new work under the bumped versions (de-duplicated the bullets that had already shipped in the released version). Added a responses b9 (Unreleased) section (samples/docs rework; no library API change). Bumped the invocations + responses minimum core dependency pin to >=2.0.0b8 (the release carrying the PY-1/PY-2 file-backed-replay parity and PY-3 per-turn input_id fixes). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…sion bumps - _orchestrator.py: kept responses resilience version (superset of main's container-protocol/PlatformContext work + resilient-task refactor) - _endpoint_handler.py: union of SSE symbols (encode_sse_any_event, _encode_sse, with_keep_alive) - CHANGELOG.md: b9 (Unreleased) resilience work over main's dated b8/b7/b6 releases - responses -> 1.0.0b9; core-dep pin >=2.0.0b8 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…rface Promotes the shared-state-root subdir resolver to the public `azure.ai.agentserver.core` API (import + __all__ + docstring) so protocol packages (e.g. the responses file store) can locate the AGENTSERVER_STATE_ROOT subdirectories without reaching into the private _config module (Spec 033 FR-007). Note: api.md regeneration is deferred — the agentserver api.md files are pre-existingly stale and core's cannot be regenerated with the pinned apistub 0.3.28 (crashes on TaskMetadata, a collections.abc.MutableMapping subclass). Tracked for the eventual PR-to-main. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…rver-responses-spec016
…(FR-007)
- FileResponseStore.storage_dir is now optional and defaults to the public
core resolve_state_subdir("responses"), mirroring how the core task/stream
layers default their own dirs.
- _routing.py no longer reaches into the private core._config: the stream
registry already defaults storage_dir internally (redundant arg dropped),
and the response-store default now comes from FileResponseStore itself.
Clears the Spec 033 import-lint gate (test_spec033_import_lint) without any
behavior change to the resolved on-disk paths.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…ntserver-durable-agent-demo
… b7, responses b9) Refreshes the checked-in demo wheels after the origin/main merge + version bumps and the resolve_state_subdir public-surface change. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…e old wheels - verify_crash_steer.py: retired. It used steering (previous_response_id) only as a crash-DELIVERY mechanism to land the crash on the lease-holding container — obsolete since PY-6: a bare 'crash' pinned via agent_session_id already lands on the same sandbox (verify_crash.py proves recovery). Steering resilience is now covered by a dedicated deterministic e2e test. - Delete the stale b7/b6/b8 wheels the previous wheel-refresh commit left behind (git add wheels/*.whl staged the new wheels but not the old-file deletions), so the demo image no longer bundles duplicate/conflicting package versions. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Deterministic CI test for steering-feature resilience: a steerable resilient conversation runs turn 1, the client steers turn 2 (previous_response_id), and a SIGKILL lands while the steered turn is mid-flight (core drain_in_progress). Asserts both the superseded turn AND the steered turn recover to 'completed' (steered turn carries the recovered L1 lifetime + the steered input), proving a steered turn is not orphaned in_progress after a crash. Uses the CrashHarness (real SIGKILL + restart) with a new deterministic steerable handler (_steering_handler.py). Replaces the retired hosted battery verify_crash_steer.py; reclassifies finding-t5 as a test-artifact (steering the literal 'crash' sentinel) rather than a framework bug. Registered in CONTRACT_COVERAGE.md. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…ntserver-durable-agent-demo
The apiview-stub-generator (apistub 0.3.28) namespace detector mis-parses a
multi-line module docstring in a package __init__ — a closing triple-quote on
its own line leaves its parser stuck in 'docstring' mode, so the package
namespace resolves to '' and the 'azure-package-only' member filter is defeated
(startswith('') is always true). Effects:
- core: the public TaskMetadata (a collections.abc.MutableMapping subclass)
leaked its inherited __class_getitem__ (= C-level types.GenericAlias) past the
filter, crashing apistub (getsource on a C type) — core api.md was ungenerable
and stale (missing the entire tasks/ + streaming/ public API).
- invocations: no crash, but inherited Starlette framework methods
(add_middleware/add_route/__call__/...) leaked into api.md as if they were the
package's own API (71 lines of bloat).
Fix: collapse both module docstrings to a single line (matches the sibling
responses package + repo convention e.g. azure-appconfiguration). Namespace now
resolves correctly, so:
- core api.md regenerates cleanly with core/streaming/tasks namespaces,
TaskMetadata, and resolve_state_subdir (+418 lines).
- invocations api.md drops the leaked Starlette methods (-71 lines).
Regenerated api.md + api.metadata.yml for both (parserVersion 0.3.28).
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…rver-responses-spec016
) Refresh the responses api.md + api.metadata.yml to the current public surface (namespace detection already worked here — responses uses a single-line module docstring). Captures the resilience work accumulated since the last regen: the new store namespace (FileResponseStore, now with optional storage_dir=None), plus hosting/streaming/models additions. parserVersion 0.3.28. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…ntserver-durable-agent-demo
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: b25bbfa5-424a-4e99-a4b0-0b0154ed699d # Conflicts: # sdk/agentserver/azure-ai-agentserver-core/CHANGELOG.md # sdk/agentserver/azure-ai-agentserver-core/api.md # sdk/agentserver/azure-ai-agentserver-core/api.metadata.yml # sdk/agentserver/azure-ai-agentserver-core/azure/ai/agentserver/core/__init__.py # sdk/agentserver/azure-ai-agentserver-core/pyproject.toml # sdk/agentserver/azure-ai-agentserver-invocations/CHANGELOG.md # sdk/agentserver/azure-ai-agentserver-invocations/api.metadata.yml # sdk/agentserver/azure-ai-agentserver-invocations/pyproject.toml
…ble-agent-demo Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: b25bbfa5-424a-4e99-a4b0-0b0154ed699d # Conflicts: # sdk/agentserver/azure-ai-agentserver-responses/api.metadata.yml # sdk/agentserver/azure-ai-agentserver-responses/tests/conftest.py
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: b25bbfa5-424a-4e99-a4b0-0b0154ed699d
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: b25bbfa5-424a-4e99-a4b0-0b0154ed699d
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary — TEMPORARY / DO NOT MERGE
This is the
durable-agent-demosplit out of the original spec 016durability PR (#46997). It carries the azd-deployable hosted-agent
demo (34 files: bicep infra, .azure azd state,
src/durable-research-agentagent code, build/demo-client scripts).
Status
🚨 This PR is not intended for merge. The demo lives here purely so
it isn't lost from the working set; we use it temporarily as a
reference deployment while the durable-task primitive matures.
Scope
sdk/agentserver/azure-ai-agentserver-invocations/samples/durable-agent-demo/only (34 files). Plus whatever else came from the original split-point
branch — see the next section for cleanup needed.
What this branch needs before any potential reuse
durable-agent-demo/directory(everything else should be discarded by reverting to
origin/mainfor those paths, since the core+invocations work belongs in feat(agentserver): resilient task primitive + event streaming (core 2.0.0b7, invocations 1.0.0b6) #46997
and the responses work belongs in PR feat(agentserver-responses): resilient/durable responses orchestration (1.0.0b10) #47275).
Pointers
samples/durable_research)derived from this demo is shipping in PR feat(agentserver): resilient task primitive + event streaming (core 2.0.0b7, invocations 1.0.0b6) #46997 — the demo here
remains as the fuller azd-deployable reference.