Python: Add declarative workflow runtime (#2815)

* Further support for declarative python workflows

* Add tests. Clean up for typing and formatting

* Improvements and cleanup

* Typing cleanup. Improve docstrings

* Proper code in docstrings

* Fix malformed code-block directive in docstring

* Remove dead links

* PR feedback

* Address PR feedback

* Address PR feedback

* Remove sl

* Update devui frontend

* More cleanup

* Fix uv lock

* Skip Py 3.14 tests as powerfx doesn't support it

* Fix mypy error

* Fix for tool calls

* Removed stale docstring

* Fix lint

* Standardize on .NET namespaces. Revert DevUI changes (bring in later)

* Implement remaining items for Python declarative support to match dotnet
This commit is contained in:
Evan Mattson
2026-01-13 16:11:21 +09:00
committed by GitHub
Unverified
parent b2893fbc00
commit 9c094573e8
79 changed files with 18310 additions and 111 deletions
@@ -62,9 +62,10 @@ agent_name/
| Sample | Description | Features | Required Environment Variables |
| -------------------------------------------- | ----------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------- |
| [**workflow_agents/**](workflow_agents/) | Content review workflow with agents as executors | Agents as workflow nodes, conditional routing based on structured outputs, quality-based paths (Writer → Reviewer → Editor/Publisher) | `AZURE_OPENAI_API_KEY`, `AZURE_OPENAI_CHAT_DEPLOYMENT_NAME`, `AZURE_OPENAI_ENDPOINT` |
| [**declarative/**](declarative/) | Declarative YAML workflow with conditional branching | YAML-based workflow definition, conditional logic, no Python code required | None - uses mock data |
| [**workflow_agents/**](workflow_agents/) | Content review workflow with agents as executors | Agents as workflow nodes, conditional routing based on structured outputs, quality-based paths (Writer -> Reviewer -> Editor/Publisher) | `AZURE_OPENAI_API_KEY`, `AZURE_OPENAI_CHAT_DEPLOYMENT_NAME`, `AZURE_OPENAI_ENDPOINT` |
| [**spam_workflow/**](spam_workflow/) | 5-step email spam detection workflow with branching logic | Sequential execution, conditional branching (spam vs. legitimate), multiple executors, mock spam detection | None - uses mock data |
| [**fanout_workflow/**](fanout_workflow/) | Advanced data processing workflow with parallel execution | Fan-out/fan-in patterns, complex state management, multi-stage processing (validation transformation quality assurance) | None - uses mock data |
| [**fanout_workflow/**](fanout_workflow/) | Advanced data processing workflow with parallel execution | Fan-out/fan-in patterns, complex state management, multi-stage processing (validation -> transformation -> quality assurance) | None - uses mock data |
### Standalone Examples
@@ -0,0 +1,3 @@
# Copyright (c) Microsoft. All rights reserved.
"""Declarative workflow sample for DevUI."""
@@ -0,0 +1,25 @@
# Copyright (c) Microsoft. All rights reserved.
"""
Run the declarative workflow sample with DevUI.
Demonstrates conditional branching based on age input using YAML-defined workflow.
"""
from pathlib import Path
from agent_framework.declarative import WorkflowFactory
from agent_framework.devui import serve
factory = WorkflowFactory()
workflow_path = Path(__file__).parent / "workflow.yaml"
workflow = factory.create_workflow_from_yaml_path(workflow_path)
def main():
"""Run the declarative workflow with DevUI."""
serve(entities=[workflow], auto_open=True)
if __name__ == "__main__":
main()
@@ -0,0 +1,64 @@
name: conditional-workflow
description: Demonstrates conditional branching based on user input
inputs:
age:
type: integer
description: The user's age in years
actions:
- kind: SetValue
id: get_age
displayName: Get user age
path: turn.age
value: =inputs.age
- kind: If
id: check_age
displayName: Check age category
condition: =turn.age < 13
then:
- kind: SetValue
path: turn.category
value: child
- kind: SendActivity
activity:
text: "Welcome, young one! Here are some fun activities for kids."
else:
- kind: If
condition: =turn.age < 20
then:
- kind: SetValue
path: turn.category
value: teenager
- kind: SendActivity
activity:
text: "Hey there! Check out these cool things for teens."
else:
- kind: If
condition: =turn.age < 65
then:
- kind: SetValue
path: turn.category
value: adult
- kind: SendActivity
activity:
text: "Welcome! Here are our professional services."
else:
- kind: SetValue
path: turn.category
value: senior
- kind: SendActivity
activity:
text: "Welcome! Enjoy our senior member benefits."
- kind: SendActivity
id: summary
displayName: Send category summary
activity:
text: '=Concat("You have been categorized as: ", turn.category)'
- kind: SetValue
id: set_output
path: workflow.outputs.category
value: =turn.category