github Azure/azure-sdk-for-net Azure.AI.AgentServer.Core_1.0.0-beta.28

1.0.0-beta.28 (2026-08-12)

Features Added

  • FoundryStateStore item operations now accept an explicit callId and forward
    the ambient FoundryAgentRequestContext.Current.CallId by default. Resilient
    task handlers restore a top-level persisted call_id for every execution attempt.
  • Added resilient task and streaming primitives for building durable, long-running agents (Azure.AI.AgentServer.Core.Tasks and Azure.AI.AgentServer.Core.Streaming):
    • Register one-shot and multi-turn tasks with IServiceCollection.AddResilientTasks() and the ResilientTaskBuilder (AddTask / AddMultiTurnTask), including overloads that accept a source-generated JsonTypeInfo<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 the JsonTypeInfo<TInput> overloads.
    • Run and resume tasks through ITaskInvoker (RunAsync, StartAsync, GetActiveRunAsync) with the TaskRun<TOutput> handle (await its Completion task, or Completion.WaitAsync(token) to cancel only your wait) and the TaskContext<TInput> handler surface (entry mode, retry attempt, cooperative cancellation, shutdown, and steering signals).
    • Configure per-task durability with TaskRegistrationOptions (title, timeout, retry) and TaskRetryPolicy (attempt count + an Azure.Core.DelayStrategy for the backoff).
    • Resumable event streaming with AgentEventStreamRegistry / AgentEventStream and AddAgentEventStreams(), supporting in-memory live, in-memory replay, and file-backed replay backings via AgentEventStreamOptions. The event representation is System.Net.ServerSentEvents.SseItem<string>: the caller places the serialized event text in SseItem<string>.Data and an opaque SseItem<string>.EventId is the resume/reconnect token (Subscribe(afterEventId), GetLastEventIdAsync()). Because the data is already a string, there is no payload codec — SseFormatter can frame a Subscribe(...) stream directly onto an HTTP response.
    • A single ResilientTaskException carrying an extensible ResilientTaskErrorCode (HandlerError, ExhaustedRetries, Conflict, PreconditionFailed, QueueFull) with code-specific data exposed as nullable properties (CurrentStatus, ActualLastInputId, Failure). Argument validation surfaces as ArgumentException and cancellation as OperationCanceledException; recovery deferral (ExitForRecoveryAsync) is an internal lifecycle handoff and never surfaces as an exception. The streaming layer keeps its AgentEventStreamException hierarchy.

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> (previously byte[]), 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 ObjectDisposedException on 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 ObjectDisposedException from the cancel path.
  • AddResilientTasks and AddAgentEventStreams are now safe against repeated registration: AddResilientTasks no longer registers the durability hosted service more than once (and rejects a conflicting second credential), and AddAgentEventStreams rejects 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_inputs queue is rehydrated into the in-process steering FIFO, so a recovered chain drains them instead of silently dropping them. Each queued input's per-turn InputId is 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.

Don't miss a new azure-sdk-for-net release

NewReleases is sending notifications on new releases.