Skip to content

[BREAKING] Python: Refactor workflow events to unified discriminated union pattern - #3690

Merged
Evan Mattson (moonbox3) merged 15 commits into
microsoft:mainfrom
moonbox3:refactor-events-generic
Feb 6, 2026
Merged

[BREAKING] Python: Refactor workflow events to unified discriminated union pattern #3690
Evan Mattson (moonbox3) merged 15 commits into
microsoft:mainfrom
moonbox3:refactor-events-generic

Conversation

@moonbox3

Copy link
Copy Markdown
Contributor

Motivation and Context

  • Replace individual event subclasses (ExecutorCompletedEvent, WorkflowOutputEvent, RequestInfoEvent, etc.) with a single generic WorkflowEvent[DataT] class using a type literal discriminator
  • Use event.type == "output" pattern instead of isinstance(event, WorkflowOutputEvent) checks
  • Align with [BREAKING] Python: Fix workflow as agent streaming output #3649 which removed AgentRunEvent/AgentRunUpdateEvent
  • Removed exported event subclasses: ExecutorCompletedEvent, ExecutorFailedEvent, ExecutorInvokedEvent, RequestInfoEvent, SuperStepCompletedEvent, SuperStepStartedEvent, WorkflowFailedEvent, WorkflowLifecycleEvent, WorkflowOutputEvent, WorkflowStartedEvent, WorkflowStatusEvent
  • Event type checking now uses event.type == "..." instead of isinstance()

Migration

# Before
if isinstance(event, WorkflowOutputEvent):
    process(event.data)

# After
if event.type == "output":
    process(event.data)

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 Evan Mattson (moonbox3) added the python Usage: [Issues, PRs], Target: Python label Feb 5, 2026
Copilot AI review requested due to automatic review settings February 5, 2026 07:40
@moonbox3 Evan Mattson (moonbox3) added workflows Usage: [Issues, PRs], Target: Workflows breaking change Usage: [PRs], Target: all PRs that introduce changes that are not backward compatible labels Feb 5, 2026
@markwallace-microsoft Mark Wallace (markwallace-microsoft) added documentation Usage: [Issues, PRs], Target: documentation in the code base and learn docs lab labels Feb 5, 2026
@markwallace-microsoft

Mark Wallace (markwallace-microsoft) commented Feb 5, 2026

Copy link
Copy Markdown
Contributor

Python Test Coverage

Python Test Coverage Report •
FileStmtsMissCoverMissing
packages/core/agent_framework
   _tools.py7898589%232, 278, 329, 331, 359, 529, 564–565, 667, 669, 689, 707, 721, 733, 738, 740, 747, 780, 851–853, 894, 916–944, 979, 987, 1228, 1433, 1490, 1494, 1573–1577, 1595, 1597–1598, 1703, 1707, 1757, 1759, 1775, 1777, 1841, 1868, 1921, 1989, 2168–2169, 2196, 2204, 2217, 2227–2228, 2263, 2319, 2351
packages/core/agent_framework/_workflows
   _agent.py3496681%59, 67–73, 107–108, 349–350, 359–360, 367, 369, 375–376, 462–463, 472, 479, 505, 538–540, 542, 544, 546, 551, 556, 603, 633, 650, 689–692, 698, 704, 708–709, 712–718, 722–723, 729, 790, 797, 803–804, 815, 847, 854, 875, 884, 888, 890–892, 899
   _agent_executor.py1662286%98, 146, 164–165, 216–217, 219–220, 252–254, 262–264, 274–276, 278, 282, 286, 290–291
   _checkpoint.py122298%186–187
   _checkpoint_summary.py27485%36–39
   _edge.py2282887%46, 68–69, 71, 166, 196, 445–446, 451, 455–460, 462–464, 580, 694, 701–703, 750, 778, 804, 858, 872
   _events.py1501292%91–92, 225, 229, 231, 263, 338, 353, 368, 383, 396, 411
   _executor.py1761293%210, 334, 336, 345, 365, 368, 475, 480, 490, 649, 730–731
   _runner.py2183285%132–133, 176–179, 183, 224–226, 251–252, 254, 289–291, 315–319, 323, 358, 362, 364, 370, 378–381, 394, 430
   _runner_context.py172795%86, 89, 385, 405, 482, 495, 499
   _workflow.py2731993%86, 264–266, 268–269, 287, 291, 319, 421, 639, 681, 686, 689, 708–710, 723, 791
   _workflow_context.py157994%57–58, 66, 70, 84, 160, 185, 296, 415
   _workflow_executor.py1823083%94, 444, 468, 470, 478–479, 484, 486, 491, 493, 546, 574–580, 584–586, 594, 599, 610, 620, 624, 630, 634, 644, 648
packages/orchestrations/agent_framework_orchestrations
   _base_group_chat_orchestrator.py1661292%109, 277, 292, 326–328, 332, 351, 412, 458–460
   _concurrent.py1933084%52, 61–62, 70–71, 90–91, 96, 123, 128, 133–134, 140, 162, 172, 179, 347, 350, 378, 434, 446, 485, 487–488, 490, 502–503, 508, 530, 534
   _group_chat.py2943986%173, 336, 343, 372, 383–384, 390, 395, 411, 438–443, 445, 478–481, 483, 488–492, 656, 661, 675, 756, 762, 808, 828, 903–904, 938, 957, 976, 986
   _handoff.py3825785%104–105, 107, 136–137, 159–169, 171, 173, 175, 180, 280, 334, 359, 387, 395–396, 410, 461–462, 494, 541–543, 730, 737, 742, 829, 832, 841–844, 854, 859, 866, 872–875, 910, 915, 1112, 1115, 1123, 1141, 1148, 1223
   _magentic.py6179085%67–76, 81, 85–96, 261, 272, 276, 296, 357, 366, 368, 410, 427, 436–437, 439–441, 443, 454, 596, 598, 638, 686, 722–724, 726, 734–737, 741–744, 805–808, 899, 905, 911, 953, 991, 1023, 1040, 1051, 1108–1109, 1113–1115, 1139, 1163–1164, 1177, 1193, 1215, 1263–1264, 1302–1303, 1462, 1471, 1474, 1479, 1875, 1930, 1945, 1974
   _orchestration_state.py29582%22, 30, 70, 87–88
   _sequential.py1141487%74, 167, 185, 196, 202, 239, 241–242, 244, 256–257, 262, 284, 288
TOTAL16583202287% 

Python Unit Test Overview

Tests Skipped Failures Errors Time
3912 225 💤 0 ❌ 0 🔥 1m 9s ⏱️

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

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 refactors Python workflow events from individual event subclasses (like ExecutorCompletedEvent, WorkflowOutputEvent, RequestInfoEvent) to a unified discriminated union pattern using a single generic WorkflowEvent[DataT] class with a type literal discriminator. This aligns with PR #3649 and resolves issues #3528 and #3547.

Changes:

  • Replaced event subclasses with WorkflowEvent[DataT] generic type
  • Changed event type checking from isinstance(event, WorkflowOutputEvent) to event.type == "output"
  • Updated all samples, tests, and documentation to use the new pattern
  • Removed exported event subclasses from public API

Reviewed changes

Copilot reviewed 117 out of 118 changed files in this pull request and generated 15 comments.

Show a summary per file
File Description
python/samples/**/*.py Updated 50+ sample files to use event.type == pattern instead of isinstance()
python/packages/core/tests/**/*.py Updated 20+ test files with new event checking pattern
python/packages/orchestrations/**/*.py Updated orchestration builders and tests
python/packages/devui/**/*.py Updated DevUI mapper to use event.type discriminator
python/packages/core/agent_framework/_workflows/*.py Core workflow implementation updates

Comment thread python/samples/autogen-migration/orchestrations/01_round_robin_group_chat.py Outdated
Comment thread python/samples/autogen-migration/orchestrations/03_swarm.py Outdated
Comment thread python/samples/getting_started/workflows/declarative/marketing/main.py Outdated
Comment thread python/samples/getting_started/workflows/declarative/deep_research/main.py Outdated
Comment thread python/samples/getting_started/workflows/control-flow/sequential_streaming.py Outdated
Comment thread python/packages/lab/lightning/tests/test_lightning.py Outdated
Comment thread python/packages/core/agent_framework/_workflows/_events.py Outdated
Comment thread python/samples/getting_started/orchestrations/group_chat_simple_selector.py Outdated
@moonbox3 Evan Mattson (moonbox3) changed the title Python: Refactor workflow events to unified discriminated union pattern [BREAKING] Python: Refactor workflow events to unified discriminated union pattern Feb 6, 2026
Comment thread python/packages/devui/agent_framework_devui/_executor.py Outdated
Comment thread python/samples/getting_started/orchestrations/magentic_human_plan_review copy.py Outdated
Comment thread python/packages/core/agent_framework/_workflows/_agent.py
@moonbox3

Copy link
Copy Markdown
Contributor Author

Tao Chen (@TaoChenOSU), I need these changes in for some other work I am doing - so I don't get stuck fixing conflicts for a day again. Please note anything and we can fast follow in another PR. Thanks.

@moonbox3
Evan Mattson (moonbox3) added this pull request to the merge queue Feb 6, 2026
Merged via the queue into microsoft:main with commit 0f3f4db Feb 6, 2026
35 checks passed
Comment on lines +126 to +127
"handoff_sent", # Handoff routing events (use .data as HandoffSentEvent)
"magentic_orchestrator", # Magentic orchestrator events (use .data as MagenticOrchestratorEvent)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

These are orchestration related events. We should move them to the orchestration package in a follow up PR

Victor Dibia (victordibia) added a commit that referenced this pull request Feb 26, 2026
…ent type on both objects (.type) and dicts (.get("type")). Replaced all 4 bare event.type accesses in _executor.py (lines 267, 477, 499, 523).

Root cause: PR #3690 changed event.__class__.__name__ == "RequestInfoEvent" (safe) to event.type == "request_info" (crashes on dicts), but _execute_workflow still yields raw dicts on error paths.

Test: test_workflow_error_yields_dict_event_without_crash — mocks a workflow that raises, verifies execute_entity consumes the dict error events without crashing.
github-merge-queue Bot pushed a commit that referenced this pull request Mar 2, 2026
* Fix .NET conversation memory in DevUI (#3484)

* formatting fixes

* fix memory regression in python devui , fix for #4123

* Fix for #3983: Added _get_event_type() helper that safely accesses event type on both objects (.type) and dicts (.get("type")). Replaced all 4 bare event.type accesses in _executor.py (lines 267, 477, 499, 523).

Root cause: PR #3690 changed event.__class__.__name__ == "RequestInfoEvent" (safe) to event.type == "request_info" (crashes on dicts), but _execute_workflow still yields raw dicts on error paths.

Test: test_workflow_error_yields_dict_event_without_crash — mocks a workflow that raises, verifies execute_entity consumes the dict error events without crashing.

* format fixes

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

Labels

breaking change Usage: [PRs], Target: all PRs that introduce changes that are not backward compatible documentation Usage: [Issues, PRs], Target: documentation in the code base and learn docs python Usage: [Issues, PRs], Target: Python workflows Usage: [Issues, PRs], Target: Workflows

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

Python: Standardize __repr__ implementations across event classes Python: Use ExecutorEvent[T] generic to simplify event type hierarchy

6 participants