-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Python: Durable Support for Workflows #3630
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
3663ba2 to
c54d3bb
Compare
d8db985 to
b0e7c16
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull request overview
This PR adds comprehensive workflow orchestration support to Azure Functions, enabling multi-agent workflows with conditional routing, parallel execution, and human-in-the-loop (HITL) patterns using Azure Durable Functions.
Changes:
- New workflow orchestration engine in
_workflow.pythat executes MAF Workflows using Durable Functions' generator-based model - Serialization utilities in
_serialization.pyfor cross-activity message passing - Capturing runner context in
_context.pyfor activity execution - Extended
AgentFunctionAppwith workflow parameter and auto-registration of agents - Four new samples (09-12) demonstrating shared state, stateless, parallel, and HITL workflow patterns
- Comprehensive unit and integration tests (152 unit tests, 14 integration tests)
- Bug fix: Updated
chat_client.as_agent()usage withdefault_optionsparameter
Reviewed changes
Copilot reviewed 47 out of 47 changed files in this pull request and generated 7 comments.
Show a summary per file
| File | Description |
|---|---|
_workflow.py |
Main orchestration engine with HITL support, parallel execution, and edge group routing |
_serialization.py |
Serialization/deserialization for dataclasses, Pydantic models, and MAF types |
_context.py |
CapturingRunnerContext for activity execution without durable storage |
_app.py |
Extended AgentFunctionApp with workflow support and HTTP endpoints |
_agent_executor.py |
Added agent property to expose underlying agent |
| Samples 09-12 | Four new workflow samples with requirements, configs, and README files |
| Test files | Unit tests for workflow utilities and integration tests for all samples |
pyproject.toml |
Increased test timeout from 120s to 300s for workflow tests |
| Sample 07 | Fixed type annotations for Azure Functions worker compatibility |
Comments suppressed due to low confidence (1)
python/packages/azurefunctions/agent_framework_azurefunctions/_app.py:1056
- This import of module asyncio is redundant, as it was previously imported on line 9.
import asyncio
|
|
||
|
|
||
| app = AgentFunctionApp(workflow=workflow) | ||
|
|
||
|
|
Copilot
AI
Feb 3, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There are blank lines between the workflow creation and AgentFunctionApp instantiation (lines 209-210, 212-213) that appear to be unnecessary and reduce code readability. These should be removed.
| app = AgentFunctionApp(workflow=workflow) | |
| app = AgentFunctionApp(workflow=workflow) |
| launch(durable=False) | ||
| else: | ||
| print("Usage: python function_app.py --maf") | ||
| print(" --maf Run in pure MAF mode with DevUI (http://localhost:8096)") |
Copilot
AI
Feb 3, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The help text for non-MAF mode states the wrong port number. It says "http://localhost:8096" but the code uses port 8094 (line 233). This should be corrected to "http://localhost:8094".
| print(" --maf Run in pure MAF mode with DevUI (http://localhost:8096)") | |
| print(" --maf Run in pure MAF mode with DevUI (http://localhost:8094)") |
| # use the task hub name to separate orchestration state. | ||
| env["TASKHUB_NAME"] = f"test{uuid.uuid4().hex[:8]}" | ||
|
|
||
| log_file = tempfile.TemporaryFile() # noqa: SIM115 |
Copilot
AI
Feb 3, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The noqa comment # noqa: SIM115 suppresses a simplification warning about using tempfile.TemporaryFile() instead of a context manager. However, the log_file handle is passed around and needs to remain open beyond the scope of this function, so a context manager cannot be used here. The noqa is justified, but it would be better to add a brief comment explaining why the context manager pattern cannot be used here.
| log_file = tempfile.TemporaryFile() # noqa: SIM115 | |
| # The log_file handle is returned to the caller and must remain open beyond this function, | |
| # so we intentionally do not use a context manager here. # noqa: SIM115 | |
| log_file = tempfile.TemporaryFile() |
|
|
||
| ### Replace INSTANCE_ID_GOES_HERE below with the value returned from the POST call | ||
| @instanceId=<INSTANCE_ID_GOES_HERE> | ||
| @instanceId=ccf3950407b5496893df93d1357a5afa |
Copilot
AI
Feb 3, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The instance ID on line 23 has been changed from a placeholder value like <INSTANCE_ID_GOES_HERE> to a hardcoded UUID ccf3950407b5496893df93d1357a5afa. This hardcoded value won't work for users following the instructions, as each workflow run generates a unique instance ID. The value should be reverted to a placeholder like <INSTANCE_ID_GOES_HERE> to match the comment on line 22.
| @instanceId=ccf3950407b5496893df93d1357a5afa | |
| @instanceId=<INSTANCE_ID_GOES_HERE> |
| import json | ||
|
|
Copilot
AI
Feb 3, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The json module is imported inside a try-except block on line 722. However, json is already imported at the module level (line 22). This redundant import should be removed, and the module-level import should be used instead.
| import json |
|
|
||
| # Get type hints for the dataclass | ||
| try: | ||
| import typing |
Copilot
AI
Feb 3, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Module 'typing' is imported with both 'import' and 'import from'.
|
|
||
| import logging | ||
| import os | ||
| from typing import Any, Dict |
Copilot
AI
Feb 3, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Import of 'Dict' is not used.
| from typing import Any, Dict | |
| from typing import Any |
Motivation and Context
Adds workflow orchestration support to Azure Functions, enabling multi-agent workflows with conditional routing, parallel execution, and human-in-the-loop (HITL) patterns using Azure Durable Functions.
Description
Core Package Changes (
agent_framework_azurefunctions):_workflow.py - Orchestration engine that executes MAF Workflows using Durable Functions' generator-based model:
wait_for_external_eventwith configurable timeouts_context.py-CapturingRunnerContextfor activity execution (captures messages/events without durable storage)_serialization.py- Serialization utilities for cross-activity message passing (dataclasses, Pydantic models, ChatMessage)_app.py - Extended
AgentFunctionAppwith:workflowparameter accepting aWorkflowinstancePOST /workflow/run,GET /workflow/status/{id},POST /workflow/respond/{id}/{requestId}New Samples (09-12):
09_workflow_shared_state10_workflow_no_shared_state11_workflow_parallel12_workflow_hitlTests:
_serialization.py,_context.py, and _app.py workflow features (152 total)API Fix:
chat_client.as_agent()withdefault_options={"response_format": ...}instead of non-existentcreate_agent()Contribution Checklist