From 9bd4410854c54c089643122e1913cc86701a47d6 Mon Sep 17 00:00:00 2001 From: PratikDhanave Date: Mon, 20 Jul 2026 12:22:43 +0530 Subject: [PATCH 1/2] Add a background-responses agent example Ports the Python getting-started background-responses sample to Go. It starts a long-running OpenAI Responses run with agent.AllowBackgroundResponses(true), which returns a continuation token instead of the final answer, then polls with agent.WithContinuationToken (sending no messages) until the run completes. Placed next to the existing openai_responses provider example since background responses are an OpenAI Responses capability, and registered in verifyexamples with the same AZURE_OPENAI_ENDPOINT gate so it skips cleanly without credentials. --- cmd/verifyexamples/examples.go | 10 +++ .../azure/openai_responses_background/main.go | 85 +++++++++++++++++++ 2 files changed, 95 insertions(+) create mode 100644 examples/02-agents/providers/azure/openai_responses_background/main.go diff --git a/cmd/verifyexamples/examples.go b/cmd/verifyexamples/examples.go index 01f97b86..ed3c67b9 100644 --- a/cmd/verifyexamples/examples.go +++ b/cmd/verifyexamples/examples.go @@ -273,6 +273,16 @@ var agentsExamples = []ExampleDefinition{ "The output should not contain error messages or stack traces.", }, }, + { + Name: "02_agents_providers_azure_openai_responses_background", + ProjectPath: "examples/02-agents/providers/azure/openai_responses_background", + RequiredEnvironmentVariables: []string{"AZURE_OPENAI_ENDPOINT"}, + OptionalEnvironmentVariables: []string{"AZURE_OPENAI_DEPLOYMENT_NAME"}, + ExpectedOutputDescription: []string{ + "The output should contain a concise explanation of the theory of relativity.", + "The output should not contain error messages or stack traces.", + }, + }, { Name: "02_agents_providers_azure_ai_project", ProjectPath: "examples/02-agents/providers/azure/ai_project", diff --git a/examples/02-agents/providers/azure/openai_responses_background/main.go b/examples/02-agents/providers/azure/openai_responses_background/main.go new file mode 100644 index 00000000..08a82750 --- /dev/null +++ b/examples/02-agents/providers/azure/openai_responses_background/main.go @@ -0,0 +1,85 @@ +// Copyright (c) Microsoft. All rights reserved. + +// This sample demonstrates long-running agent operations using the OpenAI +// Responses API "background" option. A background run returns quickly with a +// continuation token instead of the final answer; the caller then polls with +// that token until the operation completes. +// +// Ported from the Python getting-started "background responses" sample. +package main + +import ( + "context" + "time" + + "github.com/microsoft/agent-framework-go/agent" + "github.com/microsoft/agent-framework-go/examples/internal/demo" + "github.com/microsoft/agent-framework-go/provider/openaiprovider" + "github.com/openai/openai-go/v3" + "github.com/openai/openai-go/v3/azure" + "github.com/openai/openai-go/v3/option" +) + +var logger = demo.NewLogger( + "Background Responses", + "Starts a background Responses run and polls with the continuation token until it completes.", + "Model", demo.Deployment, +) + +func main() { + ctx := context.Background() + token := demo.AzureTokenCredential() + + client := openai.NewClient( + option.WithBaseURL(demo.Endpoint), + azure.WithTokenCredential(token), + ) + + researcher := openaiprovider.NewResponsesAgent( + client, + openaiprovider.AgentConfig{ + Model: demo.Deployment, + Instructions: "You are a helpful research assistant. Be concise.", + Config: agent.Config{ + Name: "Researcher", + Middlewares: []agent.Middleware{logger}, + }, + }, + ) + + // Background runs are tied to a session so that follow-up polls target the + // same operation. + session, err := researcher.CreateSession(ctx) + if err != nil { + demo.Panic(err) + } + + // Start a background run. It returns quickly with a continuation token + // rather than the final answer. (If the model or endpoint does not support + // background execution, the run simply completes inline with no token.) + resp, err := researcher.RunText(ctx, + "Briefly explain the theory of relativity in two sentences.", + agent.WithSession(session), + agent.AllowBackgroundResponses(true), + ).Collect() + if err != nil { + demo.Panic(err) + } + + // Poll until the operation completes — i.e. until a run no longer returns a + // continuation token. Continuation runs must not carry any messages, so use + // Run with a nil message slice. + for resp.ContinuationToken != "" { + time.Sleep(2 * time.Second) + resp, err = researcher.Run(ctx, nil, + agent.WithSession(session), + agent.WithContinuationToken(resp.ContinuationToken), + ).Collect() + if err != nil { + demo.Panic(err) + } + } + + // The final response holds the completed result. + demo.Response(resp, nil) +} From 96259eb69f7732ac7e2c13e9e13c9e434328a4db Mon Sep 17 00:00:00 2001 From: PratikDhanave Date: Wed, 22 Jul 2026 09:42:16 +0530 Subject: [PATCH 2/2] Make the background-responses poll loop context-aware Bound the sample with a timeout and replace the blocking sleep with a select on ctx.Done(), so a run that never completes (stuck queued, bad continuation token) cannot hang the example or verifyexamples. --- .../azure/openai_responses_background/main.go | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/examples/02-agents/providers/azure/openai_responses_background/main.go b/examples/02-agents/providers/azure/openai_responses_background/main.go index 08a82750..560c1ef4 100644 --- a/examples/02-agents/providers/azure/openai_responses_background/main.go +++ b/examples/02-agents/providers/azure/openai_responses_background/main.go @@ -27,7 +27,11 @@ var logger = demo.NewLogger( ) func main() { - ctx := context.Background() + // Bound the whole sample so a run that never completes (stuck queued, a bad + // continuation token, etc.) cannot hang indefinitely. + ctx, cancel := context.WithTimeout(context.Background(), 5*time.Minute) + defer cancel() + token := demo.AzureTokenCredential() client := openai.NewClient( @@ -70,7 +74,13 @@ func main() { // continuation token. Continuation runs must not carry any messages, so use // Run with a nil message slice. for resp.ContinuationToken != "" { - time.Sleep(2 * time.Second) + // Wait between polls, but stop promptly if the context is cancelled or + // its deadline is reached rather than sleeping through it. + select { + case <-ctx.Done(): + demo.Panic(ctx.Err()) + case <-time.After(2 * time.Second): + } resp, err = researcher.Run(ctx, nil, agent.WithSession(session), agent.WithContinuationToken(resp.ContinuationToken),