Skip to content

Comments

Python: Fixed declarative deep research sample#4065

Closed
dmytrostruk wants to merge 4 commits intomicrosoft:mainfrom
dmytrostruk:sample-fixes-8
Closed

Python: Fixed declarative deep research sample#4065
dmytrostruk wants to merge 4 commits intomicrosoft:mainfrom
dmytrostruk:sample-fixes-8

Conversation

@dmytrostruk
Copy link
Member

@dmytrostruk dmytrostruk commented Feb 19, 2026

Motivation and Context

  • Created missing workflow.yaml implementing the Magentic orchestration pattern with dynamic agent dispatch
  • Fixed _get_agent_name() in InvokeAzureAgentExecutor to evaluate PowerFx expressions for dynamic agent names
  • Fixed JoinExecutor to initialize workflow state when used as the entry node, so agents receive the user input
  • Fixed _get_branch_exit() in DeclarativeWorkflowBuilder to skip terminator actions (GotoAction, EndWorkflow, etc.), preventing dual-edge wiring that caused infinite loops
  • Simplified path resolution in main.py
  • Added 8 unit tests covering expression-based agent name resolution and terminator branch exit handling
  • Fix also applies to declarative/marketing sample.

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.

@dmytrostruk dmytrostruk self-assigned this Feb 19, 2026
Copilot AI review requested due to automatic review settings February 19, 2026 03:57
@markwallace-microsoft
Copy link
Member

markwallace-microsoft commented Feb 19, 2026

Python Test Coverage

Python Test Coverage Report •
FileStmtsMissCoverMissing
packages/declarative/agent_framework_declarative/_workflows
   _declarative_builder.py3452493%176, 233, 324, 346, 356, 407, 409, 417, 432, 468, 471, 497–498, 517–518, 594, 599, 643–645, 669–670, 892, 965
   _executors_agents.py4798682%94–95, 112–114, 155–156, 163, 191, 194–195, 203–204, 214, 225–230, 509, 547–549, 552, 568, 584–588, 612, 617, 707, 713–718, 725, 749–750, 759–761, 810–811, 819, 838, 945–948, 955–956, 963–964, 976–981, 985–986, 988, 993, 995, 999–1002, 1005, 1007–1008, 1011, 1019–1021, 1023, 1026–1027, 1029, 1056–1057
   _executors_control_flow.py170696%81, 89, 152, 342–343, 347
TOTAL21259330384% 

Python Unit Test Overview

Tests Skipped Failures Errors Time
4198 239 💤 0 ❌ 0 🔥 1m 13s ⏱️

Copy link
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

This PR fixes and completes the Python declarative “Deep Research” workflow sample and corrects several declarative workflow runtime behaviors to support dynamic agent dispatch and correct control-flow graph wiring.

Changes:

  • Adds a missing workflow.yaml implementing the Magentic orchestration pattern with dynamic agent selection.
  • Fixes declarative runtime behavior for (a) expression-based agent name resolution, (b) initializing workflow state when JoinExecutor is the entry node, and (c) preventing successor wiring for terminator branch exits.
  • Adds unit tests covering expression-based agent name resolution and terminator branch exit handling.

Reviewed changes

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

Show a summary per file
File Description
python/samples/03-workflows/declarative/deep_research/workflow.yaml Introduces the declarative Deep Research workflow definition with manager-driven dynamic agent dispatch.
python/samples/03-workflows/declarative/deep_research/main.py Simplifies workflow YAML path resolution to always use the local workflow.yaml.
python/packages/declarative/tests/test_graph_coverage.py Adds tests for dynamic agent-name expression evaluation and terminator branch exit handling.
python/packages/declarative/agent_framework_declarative/_workflows/_executors_control_flow.py Ensures workflow state initialization when JoinExecutor is used as the entry node.
python/packages/declarative/agent_framework_declarative/_workflows/_executors_agents.py Enables expression evaluation for agent names in InvokeAzureAgentExecutor._get_agent_name().
python/packages/declarative/agent_framework_declarative/_workflows/_declarative_builder.py Skips terminator actions as branch exits to avoid incorrect dual-edge wiring.

if not workflow_path.exists():
# Fall back to local copy if workflow-samples doesn't exist
workflow_path = Path(__file__).parent / "workflow.yaml"
workflow_path = Path(__file__).parent / "workflow.yaml"
Copy link
Contributor

Choose a reason for hiding this comment

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

I think the yaml workflow is supposed to be shared between Python and .Net. But let's wait for @moonbox3 's confirmation.

Copy link
Contributor

Choose a reason for hiding this comment

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

Yes, we should be using the DeepResearch.yaml sample (the same one that Dotnet uses from MAF's root) as configured previously.

assert exit_exec is None

def test_get_branch_exit_returns_none_for_end_workflow_terminator(self):
"""Test that _get_branch_exit returns None when branch ends with EndWorkflow."""
Copy link
Contributor

Choose a reason for hiding this comment

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

This test looks like it's using the incorrect executor type. The true path is: EndWorkflow creates an EndWorkflowExecutor. This test seems to be working right now because both store _action_def, but we aren't validating the actual "prod path." How about:

from agent_framework_declarative._workflows._executors_control_flow import EndWorkflowExecutor

end_executor = EndWorkflowExecutor({"kind": "EndWorkflow", "id": "end"}, id="end")
end_executor._chain_executors = [end_executor]
exit_exec = graph_builder._get_branch_exit(end_executor)
assert exit_exec is None

last_executor = chain[-1]

# Skip terminators — they handle their own control flow
action_def = getattr(last_executor, "_action_def", {})
Copy link
Contributor

Choose a reason for hiding this comment

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

This works, but could be improved, I think, if we add something like an is_terminator property on the base class. Just cause I see us reaching to the "private" _action_def attribute.

if not workflow_path.exists():
# Fall back to local copy if workflow-samples doesn't exist
workflow_path = Path(__file__).parent / "workflow.yaml"
workflow_path = Path(__file__).parent / "workflow.yaml"
Copy link
Contributor

Choose a reason for hiding this comment

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

Yes, we should be using the DeepResearch.yaml sample (the same one that Dotnet uses from MAF's root) as configured previously.

@moonbox3
Copy link
Contributor

Closing in favor of #4159.

@moonbox3 moonbox3 closed this Feb 23, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants