1.0.0-beta.28 (2026-08-12)
Features Added
FoundryStateStoreitem operations now accept an explicitcallIdand forward
the ambientFoundryAgentRequestContext.Current.CallIdby default. Resilient
task handlers restore a top-level persistedcall_idfor every execution attempt.- Added resilient task and streaming primitives for building durable, long-running agents (
Azure.AI.AgentServer.Core.TasksandAzure.AI.AgentServer.Core.Streaming):- Register one-shot and multi-turn tasks with
IServiceCollection.AddResilientTasks()and theResilientTaskBuilder(AddTask/AddMultiTurnTask), including overloads that accept a source-generatedJsonTypeInfo<TInput>for Native-AOT / trimming-safe input serialization. The reflection-based overloads carry[RequiresUnreferencedCode]/[RequiresDynamicCode]so trimming/AOT builds get a compile-time warning steering them to theJsonTypeInfo<TInput>overloads. - Run and resume tasks through
ITaskInvoker(RunAsync,StartAsync,GetActiveRunAsync) with theTaskRun<TOutput>handle (await itsCompletiontask, orCompletion.WaitAsync(token)to cancel only your wait) and theTaskContext<TInput>handler surface (entry mode, retry attempt, cooperative cancellation, shutdown, and steering signals). - Configure per-task durability with
TaskRegistrationOptions(title, timeout, retry) andTaskRetryPolicy(attempt count + anAzure.Core.DelayStrategyfor the backoff). - Resumable event streaming with
AgentEventStreamRegistry/AgentEventStreamandAddAgentEventStreams(), supporting in-memory live, in-memory replay, and file-backed replay backings viaAgentEventStreamOptions. The event representation isSystem.Net.ServerSentEvents.SseItem<string>: the caller places the serialized event text inSseItem<string>.Dataand an opaqueSseItem<string>.EventIdis the resume/reconnect token (Subscribe(afterEventId),GetLastEventIdAsync()). Because the data is already a string, there is no payload codec —SseFormattercan frame aSubscribe(...)stream directly onto an HTTP response. - A single
ResilientTaskExceptioncarrying an extensibleResilientTaskErrorCode(HandlerError,ExhaustedRetries,Conflict,PreconditionFailed,QueueFull) with code-specific data exposed as nullable properties (CurrentStatus,ActualLastInputId,Failure). Argument validation surfaces asArgumentExceptionand cancellation asOperationCanceledException; recovery deferral (ExitForRecoveryAsync) is an internal lifecycle handoff and never surfaces as an exception. The streaming layer keeps itsAgentEventStreamExceptionhierarchy.
- Register one-shot and multi-turn tasks with
Bugs Fixed
- Kept the task lease renewed across retry backoff delays so a long inter-attempt backoff cannot let the lease lapse and allow a concurrent re-invocation of the same task turn.
- Hardened the resilient-task engine shutdown signalling against a benign race between a completing turn and host disposal.
- A one-shot task whose durable completion write fails, and a multi-turn task whose durable suspend write fails, now surface the failure to the caller instead of reporting success while the record remains
in_progress(which a later recovery scan could re-run). - The local file-backed task store now serializes its existence check and record write under the same lock as patch/delete, so two concurrent creates for the same id can no longer both succeed with the later write silently overwriting the earlier record.
- The file-backed event-stream custom serializer/deserializer are now
Func<object, string>/Func<string, object>(previouslybyte[]), matching the UTF-8 JSON-string on-disk format so a custom codec cannot silently corrupt non-UTF-8 payloads. - The local file-backed task store now writes each record through a temporary file and an atomic replace, so a crash mid-write can no longer leave a truncated record that reads back as a parse error and renders the task id permanently unusable.
- The per-task write gate is no longer disposed when its bookkeeping entry is removed, closing a race where a concurrent write could observe
ObjectDisposedExceptionon a gate that was torn down while still in use. - A turn transition that replaces and disposes a handler's cancellation source concurrently with a cancel/steering signal no longer surfaces
ObjectDisposedExceptionfrom the cancel path. AddResilientTasksandAddAgentEventStreamsare now safe against repeated registration:AddResilientTasksno longer registers the durability hosted service more than once (and rejects a conflicting second credential), andAddAgentEventStreamsrejects a second configuring call instead of silently discarding its configuration.- Steering inputs that were queued but not yet drained when a process crashed are no longer stranded: on recovery the persisted
pending_inputsqueue is rehydrated into the in-process steering FIFO, so a recovered chain drains them instead of silently dropping them. Each queued input's per-turnInputIdis persisted alongside it so a recovered turn keeps its own identity and advances the chain head (last_input_id) exactly as it would without a crash.