{"id":5202,"date":"2026-03-18T09:37:00","date_gmt":"2026-03-18T16:37:00","guid":{"rendered":"https:\/\/devblogs.microsoft.com\/agent-framework\/?p=5202"},"modified":"2026-03-18T09:37:00","modified_gmt":"2026-03-18T16:37:00","slug":"handling-long-running-operations-with-background-responses","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/agent-framework\/handling-long-running-operations-with-background-responses\/","title":{"rendered":"Handling Long-Running Operations with Background Responses"},"content":{"rendered":"<h1>Handling Long-Running Operations with Background Responses<\/h1>\n<p>AI agents powered by reasoning models can take minutes to work through complex problems \u2014 deep research, multi-step analysis, lengthy content generation. In a traditional request-response pattern, that means your client sits idle waiting for a connection that may time out, or worse, fails silently and loses all progress. Background responses in Microsoft Agent Framework let you offload these long-running operations so your application stays responsive and resilient, regardless of how long the agent takes to think.<\/p>\n<p>With background responses, you start an agent task and get back a <strong>continuation token<\/strong> instead of blocking until completion. Your application can poll for results on its own schedule, resume interrupted streams from exactly where they left off, and handle network hiccups without restarting work from scratch. This matters whether you&#8217;re building internal tools for enterprise workflows or customer-facing products where reliability is non-negotiable. Background responses are available in both .NET and Python.<\/p>\n<h2>How It Works<\/h2>\n<p>When you enable background responses and send a request to an agent, what happens depends on whether the underlying agent and model support background processing:<\/p>\n<ol>\n<li><strong>Immediate completion<\/strong> \u2014 if the agent does not support background processing, it completes the task inline and returns the final response directly, with no continuation token.<\/li>\n<li><strong>Background processing<\/strong> \u2014 if the agent supports background processing, it starts working in the background and returns a continuation token that you use to check progress or resume streaming.<\/li>\n<\/ol>\n<p>The continuation token captures the current state of the operation. When it&#8217;s <code>null<\/code> (.NET) or <code>None<\/code> (Python), the operation is complete \u2014 either the response is ready, the operation failed, or further input is required.<\/p>\n<h2>When to Use Background Responses<\/h2>\n<p>Background responses are a good fit when your agent tasks involve:<\/p>\n<ul>\n<li><strong>Complex reasoning<\/strong> \u2014 models like o3 or GPT-5.2 that take time to reason through multi-step problems<\/li>\n<li><strong>Long content generation<\/strong> \u2014 producing detailed reports, extensive analysis, or multi-part documents<\/li>\n<li><strong>Unreliable network conditions<\/strong> \u2014 mobile clients, edge deployments, or any environment where connections may drop<\/li>\n<li><strong>Async user experiences<\/strong> \u2014 &#8220;fire and forget&#8221; patterns where users submit a task and come back later for results<\/li>\n<\/ul>\n<h2>Non-Streaming: Poll for Completion<\/h2>\n<p>The simplest approach is to start a background run, then poll until the result is ready.<\/p>\n<h3>.NET<\/h3>\n<pre><code class=\"language-csharp\">AIAgent agent = new AzureOpenAIClient(\r\n    new Uri(\"https:\/\/&lt;myresource&gt;.openai.azure.com\"),\r\n    new DefaultAzureCredential())\r\n    .GetResponsesClient(\"&lt;deployment-name&gt;\")\r\n    .AsAIAgent();\r\n\r\nAgentRunOptions options = new()\r\n{\r\n    AllowBackgroundResponses = true \/\/ Enable background responses\r\n};\r\n\r\nAgentSession session = await agent.CreateSessionAsync();\r\n\r\n\/\/ Start the run\u2014 may complete immediately or return a continuation token\r\nAgentResponse response = await agent.RunAsync(\r\n    \"Write a detailed market analysis for the Q4 product launch.\", session, options);\r\n\r\n\/\/ Poll until complete\r\nwhile (response.ContinuationToken is not null)\r\n{\r\n    await Task.Delay(TimeSpan.FromSeconds(2));\r\n\r\n    options.ContinuationToken = response.ContinuationToken;\r\n    response = await agent.RunAsync(session, options);\r\n}\r\n\r\nConsole.WriteLine(response.Text);\r\n<\/code><\/pre>\n<h3>Python<\/h3>\n<pre><code class=\"language-python\">import asyncio\r\nfrom agent_framework.openai import OpenAIResponsesClient\r\n\r\nagent = OpenAIResponsesClient(model_id=\"o3\").as_agent(\r\n    name=\"researcher\",\r\n    instructions=\"You are a helpful research assistant.\",\r\n)\r\n\r\nsession = await agent.create_session()\r\n\r\n# Start a background run\r\nresponse = await agent.run(\r\n    messages=\"Write a detailed market analysis for the Q4 product launch.\",\r\n    session=session,\r\n    options={\"background\": True},\r\n)\r\n\r\n# Poll until the operation completes\r\nwhile response.continuation_token is not None:\r\n    await asyncio.sleep(2)\r\n    response = await agent.run(\r\n        session=session,\r\n        options={\"continuation_token\": response.continuation_token},\r\n    )\r\n\r\nprint(response.text)\r\n<\/code><\/pre>\n<p><strong>Key points:<\/strong><\/p>\n<ul>\n<li>If no continuation token is returned, the operation completed immediately \u2014 no polling needed.<\/li>\n<li>Pass the continuation token from each response into the next polling call.<\/li>\n<li>When the token is <code>null<\/code>\/<code>None<\/code>, you have the final result.<\/li>\n<\/ul>\n<h2>Streaming with Resumption<\/h2>\n<p>For a more responsive experience, you can stream results in real time while still benefiting from background processing. Each streamed update carries a continuation token, so if the connection drops, you can pick up right where you left off.<\/p>\n<h3>.NET<\/h3>\n<pre><code class=\"language-csharp\">AgentRunOptions options = new()\r\n{\r\n    AllowBackgroundResponses = true \/\/ Enable background responses\r\n};\r\n\r\nAgentSession session = await agent.CreateSessionAsync();\r\n\r\nAgentResponseUpdate?latestUpdate = null;\r\n\r\nawait foreach (var update in agent.RunStreamingAsync(\r\n    \"Write a detailed market analysis for the Q4 product launch.\", session, options))\r\n{\r\n    Console.Write(update.Text);\r\n    latestUpdate = update;\r\n\r\n    \/\/ Simulate a network interruption\r\n    break;\r\n}\r\n\r\n\/\/ Resume from exactly where we left off\r\noptions.ContinuationToken = latestUpdate?.ContinuationToken;\r\nawait foreach (var update in agent.RunStreamingAsync(session, options))\r\n{\r\n    Console.Write(update.Text);\r\n}\r\n<\/code><\/pre>\n<h3>Python<\/h3>\n<pre><code class=\"language-python\">session = await agent.create_session()\r\n\r\nlast_token = None\r\n\r\n# Start streaming with background enabled\r\nasync for update in agent.run(\r\n    messages=\"Write a detailed market analysis for the Q4 product launch.\",\r\n    stream=True,\r\n    session=session,\r\n    options={\"background\": True},\r\n):\r\n    last_token = update.continuation_token\r\n    if update.text:\r\n        print(update.text, end=\"\", flush=True)\r\n\r\n    # Simulate a network interruption\r\n    break\r\n\r\n# Resume the stream using the last continuation token\r\nif last_token is not None:\r\n    async for update in agent.run(\r\n        stream=True,\r\n        session=session,\r\n        options={\"continuation_token\": last_token},\r\n    ):\r\n        if update.text:\r\n            print(update.text, end=\"\", flush=True)\r\n<\/code><\/pre>\n<p><strong>Key points:<\/strong><\/p>\n<ul>\n<li>Each update includes a continuation token \u2014 save the most recent one.<\/li>\n<li>If the stream breaks, pass the saved token to resume from that exact point.<\/li>\n<li>The agent continues processing on the server even if the client disconnects.<\/li>\n<\/ul>\n<h2>Built-In Fault Tolerance<\/h2>\n<p>One of the practical benefits of background responses is resilience to connectivity issues. Because the agent continues processing server-side regardless of what happens to the client connection, you get fault tolerance without building it yourself:<\/p>\n<ul>\n<li><strong>Network interruptions<\/strong> \u2014 the client can reconnect and resume using the last continuation token.<\/li>\n<li><strong>Client restarts<\/strong> \u2014 persist the continuation token to storage and pick up the operation from a new process.<\/li>\n<li><strong>Timeout protection<\/strong> \u2014 long-running tasks won&#8217;t fail because a connection was held open too long.<\/li>\n<\/ul>\n<p>For production applications, consider storing continuation tokens persistently (in a database or cache) so operations can survive not just network blips but full application restarts. This is especially valuable for enterprise scenarios where agent tasks may run for several minutes.<\/p>\n<h2>Use Cases<\/h2>\n<h3>Document Generation and Review<\/h3>\n<p>An enterprise compliance team uses an agent to generate regulatory filings. These documents require the model to reason through complex guidelines and can take several minutes. With background responses, the application submits the request, shows the user a progress indicator, and polls for the result \u2014 no risk of the request timing out mid-generation.<\/p>\n<h3>Research and Analysis<\/h3>\n<p>A financial services agent performs deep analysis across market data, SEC filings, and news. The reasoning model needs time to synthesize information from multiple sources. Background responses let the application kick off the analysis, free up the UI, and notify the user when results are ready.<\/p>\n<h3>Batch Processing Pipelines<\/h3>\n<p>A data engineering team runs agents over large datasets to extract insights. Each item may require extended reasoning. Background responses allow the pipeline to submit tasks in parallel, poll for completions, and handle individual failures without losing progress on the rest.<\/p>\n<h2>Best Practices<\/h2>\n<ul>\n<li><strong>Use reasonable polling intervals<\/strong> \u2014 start with 2-second intervals and consider exponential backoff for longer-running tasks.<\/li>\n<li><strong>Always check for null continuation tokens<\/strong> \u2014 this is your signal that processing is complete.<\/li>\n<li><strong>Persist continuation tokens<\/strong> for operations that may span user sessions or survive application restarts.<\/li>\n<\/ul>\n<h2>Supported Agents<\/h2>\n<p>Background responses are fully supported when used with the Responses API for <strong><a href=\"https:\/\/learn.microsoft.com\/en-us\/agent-framework\/agents\/providers\/openai\">OpenAI<\/a><\/strong> and <strong><a href=\"https:\/\/learn.microsoft.com\/en-us\/agent-framework\/agents\/providers\/azure-openai\">Azure OpenAI<\/a><\/strong> providers \u2014 via <code>ChatClientAgent<\/code> in .NET and <code>Agent<\/code> in Python. The <code>A2AAgent<\/code> has limited support for background responses, with improvements planned for an upcoming release.<\/p>\n<p>The amount of time you can access response data is subject to the data retention policy of the underlying service.<\/p>\n<h2>Learn More<\/h2>\n<p>Background responses are available in both the .NET and Python SDKs. To get started:<\/p>\n<ul>\n<li>\ud83d\udcd6 <a href=\"https:\/\/learn.microsoft.com\/en-us\/agent-framework\/agents\/background-responses\">Background responses documentation on Microsoft Learn<\/a><\/li>\n<li>\ud83d\udcbb <a href=\"https:\/\/github.com\/microsoft\/agent-framework\">Microsoft Agent Framework on GitHub<\/a><\/li>\n<li>\ud83d\udde3\ufe0f <a href=\"https:\/\/github.com\/microsoft\/agent-framework\/discussions\">Discussion boards<\/a> \u2014 share feedback, ask questions, and connect with the community<\/li>\n<\/ul>\n<p>We&#8217;re always interested in hearing from you. If you have feedback or questions, reach out to us on the <a href=\"https:\/\/github.com\/microsoft\/agent-framework\/discussions\">GitHub discussion boards<\/a>. And if you&#8217;ve been enjoying Agent Framework, give us a \u2b50 on <a href=\"https:\/\/github.com\/microsoft\/agent-framework\">GitHub<\/a>.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Handling Long-Running Operations with Background Responses AI agents powered by reasoning models can take minutes to work through complex problems \u2014 deep research, multi-step analysis, lengthy content generation. In a traditional request-response pattern, that means your client sits idle waiting for a connection that may time out, or worse, fails silently and loses all progress. [&hellip;]<\/p>\n","protected":false},"author":157200,"featured_media":5207,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[78,143,34],"tags":[],"class_list":["post-5202","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-net","category-agent-framework","category-python-2"],"acf":[],"blog_post_summary":"<p>Handling Long-Running Operations with Background Responses AI agents powered by reasoning models can take minutes to work through complex problems \u2014 deep research, multi-step analysis, lengthy content generation. In a traditional request-response pattern, that means your client sits idle waiting for a connection that may time out, or worse, fails silently and loses all progress. [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/agent-framework\/wp-json\/wp\/v2\/posts\/5202","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/agent-framework\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/agent-framework\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/agent-framework\/wp-json\/wp\/v2\/users\/157200"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/agent-framework\/wp-json\/wp\/v2\/comments?post=5202"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/agent-framework\/wp-json\/wp\/v2\/posts\/5202\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/agent-framework\/wp-json\/wp\/v2\/media\/5207"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/agent-framework\/wp-json\/wp\/v2\/media?parent=5202"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/agent-framework\/wp-json\/wp\/v2\/categories?post=5202"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/agent-framework\/wp-json\/wp\/v2\/tags?post=5202"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}