From 22ba1a8da072846947ddd5d0ea5b4c9a3f606720 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 17 Mar 2026 21:19:20 +0000 Subject: [PATCH 1/3] Initial plan From 3247cc44faa29ffe9ad117108bb9c466e06002c7 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 17 Mar 2026 21:24:23 +0000 Subject: [PATCH 2/3] update agent-background-responses reference: new API, new sample paths, tools+persistence section Co-authored-by: KSemenenko <4385716+KSemenenko@users.noreply.github.com> --- .../dotnet-microsoft-agent-framework/SKILL.md | 2 +- .../agents/agent-background-responses.md | 114 +++++++++++++----- 2 files changed, 82 insertions(+), 34 deletions(-) diff --git a/skills/dotnet-microsoft-agent-framework/SKILL.md b/skills/dotnet-microsoft-agent-framework/SKILL.md index 36dc8f9..1a85735 100644 --- a/skills/dotnet-microsoft-agent-framework/SKILL.md +++ b/skills/dotnet-microsoft-agent-framework/SKILL.md @@ -1,6 +1,6 @@ --- name: dotnet-microsoft-agent-framework -version: "1.4.0" +version: "1.4.1" category: "AI" description: "Build .NET AI agents and multi-agent workflows with Microsoft Agent Framework using the right agent type, threads, tools, workflows, hosting protocols, and enterprise guardrails." compatibility: "Requires preview-era Microsoft Agent Framework packages and a .NET application that truly needs agentic or workflow orchestration." diff --git a/skills/dotnet-microsoft-agent-framework/references/official-docs/user-guide/agents/agent-background-responses.md b/skills/dotnet-microsoft-agent-framework/references/official-docs/user-guide/agents/agent-background-responses.md index f54dc10..d4f2ca6 100644 --- a/skills/dotnet-microsoft-agent-framework/references/official-docs/user-guide/agents/agent-background-responses.md +++ b/skills/dotnet-microsoft-agent-framework/references/official-docs/user-guide/agents/agent-background-responses.md @@ -5,7 +5,7 @@ zone_pivot_groups: programming-languages author: sergeymenshykh ms.topic: reference ms.author: semenshi -ms.date: 10/16/2025 +ms.date: 03/17/2026 ms.service: agent-framework --- @@ -14,7 +14,7 @@ ms.service: agent-framework The Microsoft Agent Framework supports background responses for handling long-running operations that may take time to complete. This feature enables agents to start processing a request and return a continuation token that can be used to poll for results or resume interrupted streams. > [!TIP] -> For a complete working example, see the [Background Responses sample](https://github.com/microsoft/agent-framework/blob/main/dotnet/samples/GettingStarted/Agents/Agent_Step17_BackgroundResponses/Program.cs). +> For a complete working example, see the [Background Responses sample](https://github.com/microsoft/agent-framework/blob/main/dotnet/samples/02-agents/Agents/Agent_Step14_BackgroundResponses/Program.cs). ## When to Use Background Responses @@ -22,6 +22,7 @@ Background responses are particularly useful for: - Complex reasoning tasks that require significant processing time - Operations that may be interrupted by network issues or client timeouts - Scenarios where you want to start a long-running task and check back later for results +- Long-running tasks that also invoke function tools during background processing ## How Background Responses Work @@ -56,29 +57,26 @@ For non-streaming scenarios, when you initially run an agent, it may or may not ```csharp AIAgent agent = new AzureOpenAIClient( - new Uri("https://.openai.azure.com"), - new AzureCliCredential()) - .GetOpenAIResponseClient("") + new Uri(endpoint), + new DefaultAzureCredential()) + .GetResponsesClient(deploymentName) .AsAIAgent(); -AgentRunOptions options = new() -{ - AllowBackgroundResponses = true -}; +AgentRunOptions options = new() { AllowBackgroundResponses = true }; -AgentThread thread = await agent.GetNewThreadAsync(); +AgentSession session = await agent.CreateSessionAsync(); // Get initial response - may return with or without a continuation token -AgentResponse response = await agent.RunAsync("Write a very long novel about otters in space.", thread, options); +AgentResponse response = await agent.RunAsync("Write a very long novel about otters in space.", session, options); // Continue to poll until the final response is received -while (response.ContinuationToken is not null) +while (response.ContinuationToken is { } token) { // Wait before polling again. await Task.Delay(TimeSpan.FromSeconds(2)); - options.ContinuationToken = response.ContinuationToken; - response = await agent.RunAsync(thread, options); + options.ContinuationToken = token; + response = await agent.RunAsync(session, options); } Console.WriteLine(response.Text); @@ -91,6 +89,7 @@ Console.WriteLine(response.Text); - If a continuation token is returned, the agent has started a background process that requires polling - Use the continuation token from the previous response in subsequent polling calls - When `ContinuationToken` is `null`, the operation is complete +- Use `AgentSession` (via `CreateSessionAsync()`) to hold conversation context instead of `AgentThread` ## Streaming Background Responses @@ -98,33 +97,33 @@ In streaming scenarios, background responses work much like regular streaming re ```csharp AIAgent agent = new AzureOpenAIClient( - new Uri("https://.openai.azure.com"), - new AzureCliCredential()) - .GetOpenAIResponseClient("") + new Uri(endpoint), + new DefaultAzureCredential()) + .GetResponsesClient(deploymentName) .AsAIAgent(); -AgentRunOptions options = new() -{ - AllowBackgroundResponses = true -}; +AgentRunOptions options = new() { AllowBackgroundResponses = true }; -AgentThread thread = await agent.GetNewThreadAsync(); +AgentSession session = await agent.CreateSessionAsync(); -AgentResponseUpdate? latestReceivedUpdate = null; +AgentResponseUpdate? lastReceivedUpdate = null; -await foreach (var update in agent.RunStreamingAsync("Write a very long novel about otters in space.", thread, options)) +await foreach (AgentResponseUpdate update in agent.RunStreamingAsync("Write a very long novel about otters in space.", session, options)) { Console.Write(update.Text); - - latestReceivedUpdate = update; - - // Simulate an interruption - break; + + lastReceivedUpdate = update; + + // Simulate connection loss after first piece of content received + if (update.Text.Length > 0) + { + break; + } } // Resume from interruption point captured by the continuation token -options.ContinuationToken = latestReceivedUpdate?.ContinuationToken; -await foreach (var update in agent.RunStreamingAsync(thread, options)) +options.ContinuationToken = lastReceivedUpdate?.ContinuationToken; +await foreach (AgentResponseUpdate update in agent.RunStreamingAsync(session, options)) { Console.Write(update.Text); } @@ -136,6 +135,53 @@ await foreach (var update in agent.RunStreamingAsync(thread, options)) - Store the continuation token from the last received update before interruption - Use the stored continuation token to resume the stream from the interruption point +## Background Responses with Tools and State Persistence + +Background responses also support function calling during background operations. Functions can be invoked by the agent while it processes in the background. Combined with session serialization, you can persist the agent state between polling cycles and restore it in a new process or after a restart. + +> [!TIP] +> For a complete working example, see the [Background Responses with Tools and Persistence sample](https://github.com/microsoft/agent-framework/blob/main/dotnet/samples/02-agents/Agents/Agent_Step10_BackgroundResponsesWithToolsAndPersistence/Program.cs). + +```csharp +AIAgent agent = new AzureOpenAIClient( + new Uri(endpoint), + new DefaultAzureCredential()) + .GetResponsesClient(deploymentName) + .AsAIAgent( + name: "SpaceNovelWriter", + instructions: "You are a space novel writer. Always research relevant facts before writing.", + tools: [AIFunctionFactory.Create(ResearchSpaceFactsAsync), AIFunctionFactory.Create(GenerateCharacterProfilesAsync)]); + +AgentRunOptions options = new() { AllowBackgroundResponses = true }; +AgentSession session = await agent.CreateSessionAsync(); + +AgentResponse response = await agent.RunAsync("Write a very long novel about astronauts exploring an uncharted galaxy.", session, options); + +while (response.ContinuationToken is not null) +{ + // Persist session and continuation token to durable storage + await PersistAgentState(agent, session, response.ContinuationToken); + + await Task.Delay(TimeSpan.FromSeconds(10)); + + // Restore state (e.g. after process restart) + var (restoredSession, continuationToken) = await RestoreAgentState(agent); + + options.ContinuationToken = continuationToken; + response = await agent.RunAsync(restoredSession, options); +} + +Console.WriteLine(response.Text); +``` + +### Key Points for Tools and Persistence: + +- Tools registered via `AIFunctionFactory.Create(...)` are called normally during background operations +- Use `agent.SerializeSessionAsync(session)` to persist the session to a `JsonElement` +- Use `agent.DeserializeSessionAsync(serializedSession)` to restore a session from storage +- Use `AgentAbstractionsJsonUtilities.DefaultOptions` when serializing `ResponseContinuationToken` directly +- Persisting state enables recovery from process restarts and server-side recycling between polling cycles + ::: zone-end ::: zone pivot="programming-language-python" @@ -152,13 +198,15 @@ When working with background responses, consider the following best practices: - **Implement appropriate polling intervals** to avoid overwhelming the service - **Use exponential backoff** for polling intervals if the operation is taking longer than expected - **Always check for `null` continuation tokens** to determine when processing is complete -- **Consider storing continuation tokens persistently** for operations that may span user sessions +- **Consider storing continuation tokens and session state persistently** for operations that may span user sessions or process restarts +- **Use `DefaultAzureCredential` carefully in production**: it is convenient for development but uses credential fallback chains; prefer `ManagedIdentityCredential` or a specific credential in production to avoid latency and security risks ## Limitations and Considerations - Background responses are dependent on the underlying AI service supporting long-running operations -- Not all agent types may support background responses +- Currently only agents using the OpenAI Responses API (`GetResponsesClient`) support background responses - Network interruptions or client restarts may require special handling to persist continuation tokens +- Function tools registered with `AIFunctionFactory` are supported during background operations ## Next steps From ba9cbeae0cdf26722d0706b3f915f6a9d6effef5 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 17 Mar 2026 21:47:24 +0000 Subject: [PATCH 3/3] resolve conflict: merge AgentWorkflowBuilder additions from main, bump SKILL.md to 1.5.1 Co-authored-by: KSemenenko <4385716+KSemenenko@users.noreply.github.com> --- skills/dotnet-microsoft-agent-framework/SKILL.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/skills/dotnet-microsoft-agent-framework/SKILL.md b/skills/dotnet-microsoft-agent-framework/SKILL.md index 1a85735..e855c61 100644 --- a/skills/dotnet-microsoft-agent-framework/SKILL.md +++ b/skills/dotnet-microsoft-agent-framework/SKILL.md @@ -1,6 +1,6 @@ --- name: dotnet-microsoft-agent-framework -version: "1.4.1" +version: "1.5.1" category: "AI" description: "Build .NET AI agents and multi-agent workflows with Microsoft Agent Framework using the right agent type, threads, tools, workflows, hosting protocols, and enterprise guardrails." compatibility: "Requires preview-era Microsoft Agent Framework packages and a .NET application that truly needs agentic or workflow orchestration." @@ -54,6 +54,7 @@ flowchart LR - `AgentResponse` and `AgentResponseUpdate` are not just text containers. They can include tool calls, tool results, structured output, reasoning-like updates, and response metadata. - `ChatClientAgent` is the safest default when you already have an `IChatClient` and do not need a hosted-agent service. - `Workflow` is an explicit graph of executors and edges. Use it when the control flow must stay inspectable, typed, resumable, or human-steerable. +- `AgentWorkflowBuilder` provides high-level factory methods such as `BuildConcurrent` for common agent orchestration patterns. Use it when you need concurrent or sequential agent pipelines without writing custom executor classes. - Hosting layers such as OpenAI-compatible HTTP, A2A, and AG-UI are adapters over your in-process agent or workflow. They do not replace the core architecture choice. - Durable agents are a hosting and persistence decision for Azure Functions. They are not the default answer for ordinary app-level orchestration. @@ -65,7 +66,7 @@ flowchart LR | OpenAI-style future-facing APIs, background responses, or richer response state | Responses-based agent | Better fit for new OpenAI-compatible integrations | | Simple client-managed chat history | Chat Completions agent | Keeps request/response simple | | Service-hosted agents and service-owned threads/tools | Azure AI Foundry Agent or other hosted agent | Managed runtime is the requirement | -| Typed multi-step orchestration | `Workflow` | Control flow stays explicit and testable | +| Typed multi-step orchestration | `Workflow` or `AgentWorkflowBuilder` helpers | Control flow stays explicit and testable; use `BuildConcurrent` for agent fan-out/fan-in | | Week-long or failure-resilient Azure execution | Durable agent on Azure Functions | Durable Task gives replay and persisted state | | Agent-to-agent interoperability | A2A hosting or A2A proxy agent | This is protocol-level delegation, not local inference | | Browser or web UI protocol integration | AG-UI | Designed for remote UI sync and approval flows |