Skip to content

.NET: Support returning durable workflow results from HTTP trigger endpoint#5321

Open
kshyju wants to merge 3 commits intomainfrom
shkr/workflow_return_value
Open

.NET: Support returning durable workflow results from HTTP trigger endpoint#5321
kshyju wants to merge 3 commits intomainfrom
shkr/workflow_return_value

Conversation

@kshyju
Copy link
Copy Markdown
Contributor

@kshyju kshyju commented Apr 17, 2026

Summary

Adds support for synchronously returning workflow execution results from the HTTP trigger endpoint. By default, the workflow HTTP endpoint fires-and-forgets (202 Accepted). With this change, callers can set the x-ms-wait-for-response: true header to wait for the workflow to complete and receive the result directly in the HTTP response (200 OK). Results are returned as plain text by default, or as a structured JSON object when Accept: application/json is specified.

Changes

New feature

  • Parse the x-ms-wait-for-response header in RunWorkflowOrchestrationHttpTriggerAsync
  • New WaitForWorkflowCompletionAsync method that calls WaitForInstanceCompletionAsync and handles failure/completed/unexpected statuses
  • Support Accept: application/json header to return a structured JSON response (runId, status, result)
  • POCO results from executors are properly serialized as nested JSON objects (using JsonElement) rather than double-encoded strings

Code quality improvements

  • Extracted WaitForResponseHeaderName constant (replaces two inline string literals)
  • Extracted ShouldWaitForResponse(req, defaultValue) helper to eliminate duplicated header-parsing logic across workflow and agent triggers
  • Extracted AcceptsJson(req) helper to deduplicate Accept header checks across 4 response methods
  • Added optional acceptsJson parameter to CreateErrorResponseAsync to avoid redundant header reads within WaitForWorkflowCompletionAsync

Docs & samples

  • Updated 01_SequentialWorkflow/README.md with curl/PowerShell examples for the new header
  • Added demo.http entries for wait-for-response scenarios (plain text and JSON)

Tests

  • Added integration test in WorkflowSamplesValidation.cs verifying the header works end-to-end

JSON response examples

Plain text (default):

Cancellation email sent for order 12345 to jerry@example.com.

JSON (with Accept: application/json):

{
  "runId": "abc123def456",
  "status": "Completed",
  "result": "Cancellation email sent for order 12345 to jerry@example.com."
}

JSON with POCO result (executor returns an object):

{
  "runId": "abc123def456",
  "status": "Completed",
  "result": { "orderId": 123, "email": "jerry@example.com" }
}

Description

Contribution Checklist

  • The code builds clean without any errors or warnings
  • The PR follows the Contribution Guidelines
  • All unit tests pass, and I have added new tests where possible
  • Is this a breaking change? If yes, add "[BREAKING]" prefix to the title of the PR.

@moonbox3 moonbox3 added documentation Improvements or additions to documentation .NET labels Apr 17, 2026
@kshyju kshyju marked this pull request as ready for review April 17, 2026 03:46
Copilot AI review requested due to automatic review settings April 17, 2026 03:46
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds an opt-in “wait for completion” mode to the Azure Functions HTTP workflow trigger so callers can synchronously receive workflow results (plain text by default, JSON when Accept: application/json is provided), along with docs, samples, and an integration test update.

Changes:

  • Add x-ms-wait-for-response support for workflow HTTP trigger and refactor shared header parsing helpers.
  • Add synchronous completion wait path that returns 200 OK with either plain text or structured JSON (runId, status, result).
  • Update samples/docs and add an end-to-end integration test for the new header behavior.

Reviewed changes

Copilot reviewed 5 out of 5 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
dotnet/src/Microsoft.Agents.AI.Hosting.AzureFunctions/BuiltInFunctions.cs Implements wait-for-completion HTTP response path and consolidates header parsing helpers.
dotnet/tests/Microsoft.Agents.AI.Hosting.AzureFunctions.IntegrationTests/WorkflowSamplesValidation.cs Adds an integration test covering the wait-for-response header for workflows.
dotnet/src/Microsoft.Agents.AI.Hosting.AzureFunctions/CHANGELOG.md Adds an Unreleased changelog entry for the new HTTP trigger behavior.
dotnet/samples/04-hosting/DurableWorkflows/AzureFunctions/01_SequentialWorkflow/demo.http Adds request examples demonstrating wait-for-response (plain text + JSON).
dotnet/samples/04-hosting/DurableWorkflows/AzureFunctions/01_SequentialWorkflow/README.md Documents how to wait for workflow results and request JSON responses.

Comment thread dotnet/src/Microsoft.Agents.AI.Hosting.AzureFunctions/BuiltInFunctions.cs Outdated
Comment thread dotnet/src/Microsoft.Agents.AI.Hosting.AzureFunctions/BuiltInFunctions.cs Outdated
Comment thread dotnet/src/Microsoft.Agents.AI.Hosting.AzureFunctions/BuiltInFunctions.cs Outdated
@kshyju kshyju requested a review from cgillum April 17, 2026 20:17
if (metadata is null)
{
return await CreateErrorResponseAsync(req, context, HttpStatusCode.InternalServerError,
$"Workflow orchestration '{instanceId}' returned no metadata.", acceptsJson);
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's also possible that no orchestration with this ID exists.

if (metadata.RuntimeStatus is OrchestrationRuntimeStatus.Failed)
{
string errorMessage = metadata.FailureDetails?.ErrorMessage ?? "Unknown error";
return await CreateErrorResponseAsync(req, context, HttpStatusCode.InternalServerError,
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is InternalServerError the right status code for us to use on a failed workflow? I wonder if an HTTP 200 response is actually more appropriate from an HTP protocol perspective. HTTP 500 typically means that we failed to process the request due to some internal failure, but in this case, the operation succeeded, but the state of the workflow happens to be that it failed.

/// <param name="Result">The workflow result as a JSON element so POCOs serialize as nested objects rather than escaped strings.</param>
private sealed record WorkflowRunSuccessResponse(
[property: JsonPropertyName("runId")] string RunId,
[property: JsonPropertyName("status")] string Status,
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's an inconsistency here with AgentRunSuccessResponse, which returns the status as an integer value rather than a string value. The string value probably makes more sense, but to resolve this inconsistency, consider using a different property name, like WorkflowStatus, to avoid confusion.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation .NET

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants