Repository navigation
fix(orchestrator): workflow planning is dead at every caller — un-awaited coroutines plus retired WorkflowTask field names #13730
Description
Activity
- added a commit that references this issue
on Aug 8, 2026 Context: the planner-side half of this landed as #13731 (squash
2dd19bfe9, closing #13699).Orchestrator.plan_workflow_stepsnow constructs canonicalWorkflowTaskfields and returns a real plan.That makes this issue the only thing standing between the planner and working end-to-end workflow planning — every caller listed above is still un-awaited and still reads retired field names, so chat-request planning remains dead until this lands.
- added 5 commits that reference this issue
on Aug 8, 2026 Merged and verified on
Dev_new_gui.PR: #13752 · squash commit:
6a1d769e4Verified in base, not merge state
$ git log --oneline -1 origin/Dev_new_gui 6a1d769e4 fix(orchestration): await the planning API and read canonical WorkflowTask fields (#13730) # awaits on the planning API, per file 2 services/workflow_automation/manager.py 3 orchestration/workflow_planner.py 1 services/advanced_workflow/step_generator.py # retired attribute reads remaining 0 orchestration/workflow_planner.py 0 services/workflow_automation/manager.py $ git ls-tree origin/Dev_new_gui --name-only autobot-backend/tests/orchestration/test_planning_caller_wiring.py autobot-backend/tests/orchestration/test_planning_caller_wiring.py $ python3 -m pytest tests/orchestration/test_planning_caller_wiring.py orchestration/plan_steps_e2e_test.py -q -p no:randomly 6 passed in 1.22sAcceptance criteria
- All four call sites await the planning coroutines. Three were in
async defand needed onlyawait;get_plan_summarywasdefcalling an async API (runningcomplexity.valueandlen(base_steps)against coroutines) and is nowasync def. - All field reads use canonical
WorkflowTasknames.step.id→task_id,step.user_approval_required→requires_approval,base_steps[j].id→.task_id. A grep for retired attribute reads returns nothing outside docstrings. Dict keys inworkflow_planner.pyare deliberately unchanged — they are that module's contract withcreate_plan_summary_for_approval(line 267), which readsstep.get("user_approval_required"); only the attribute sources moved. -
plan_steps_e2e_test.pyasserts a non-empty plan per complexity level and no longer swallows exceptions. Also corrected a false premise in the old file: its four "complexity levels" were really two, becauseRESEARCH/INSTALL/SECURITY_SCANall carry the value"complex"and are therefore Enum aliases ofCOMPLEX— it exercised COMPLEX three times. Now covers SIMPLE and COMPLEX explicitly. - A test covers
create_workflow_from_chat_requestandplan_workflow_steps_with_agentsreturning real steps.tests/orchestration/test_planning_caller_wiring.pydrives all four callers with a realOrchestrator— a stub with invented attributes would have passed against the exact bug being fixed.
Live impact this fixed
Worse than this issue originally described.
create_workflow_from_chat_requestis reached by two HTTP routes (api/workflow.py:290,services/workflow_automation/routes.py:258). It returnedNoneon every call, andapi/workflow.py:292maps a falsy id toHTTPException(500)— so every chat-driven workflow request was answering HTTP 500, not merely failing silently inside the orchestrator.Every fix proven load-bearing
Each of the seven changes was reverted in isolation; all seven make the new tests fail, so none of them can pass against the broken code:
Reverted Result awaitonmanager.pyplan callFAILED step.requires_approval→user_approval_requiredFAILED base_steps[j].task_id→.idFAILED awaitonworkflow_planner.py:113FAILED "id": step.task_id→step.idFAILED async def get_plan_summary→defERROR awaitonstep_generator.py:63FAILED CI
All 10 required contexts green or correctly skipped (
migration-matrix/api-wiring— no migrations, no API surface). All 13python-suiteentries (12 shards + aggregate) SUCCESS, so not a pytest-split empty-shard false green. 995 tests passed locally across every touched area, re-run after a mid-flight rebase onto #13734.Carried forward — #13751
WorkflowPlanner.plan_workflow_steps_with_agentsandget_plan_summaryhave zero callers. Both were corrected and are now directly tested, but neither is reachable from any production path — agent-assigned planning and plan preview remain unwired. Their unreachability is also why two of the four bugs fixed here survived so long: no runtime signal can point at code nothing executes. Per the standing rule they were kept and fixed, not removed.- All four call sites await the planning coroutines. Three were in
Verified the downstream effect of this fix rather than assuming it, and filed #13809: the path is now live, but every chat request yields the same three
echo 'Executing: <action>'steps becauseplan_workflow_stepsis a fixed skeleton and the command fallback cannot match its action names. No injection risk (user text never reaches the command — checked with a hostile request), but the endpoint now fails silently where it previously failed loudly with a 500. Worth closing that gap.- added a commit that references this issue
on Oct 4, 2026
Discovered while fixing #13699. That issue repaired the benchmark that exercises
Orchestrator.plan_workflow_steps; strengthening its assertions surfaced that themethod returned an empty plan for every caller. #13699 fixes the method itself.
Every remaining caller is still broken, in two independent ways.
1. Every production caller invokes the async planning API without
awaitOrchestrator.plan_workflow_stepsandOrchestrator.classify_request_complexityareboth
async def. Four call sites bind the coroutine object and then iterate it:autobot-backend/orchestration/workflow_planner.py:113for step in base_stepsover a coroutineautobot-backend/orchestration/workflow_planner.py:219len(base_steps)over a coroutineautobot-backend/services/workflow_automation/manager.py:75-76autobot-backend/services/advanced_workflow/step_generator.py:63for i, base_step in enumerate(base_steps)over a coroutineThe benchmark repaired in #13699 is the only awaited caller in the tree:
Confirmed at runtime — pytest reports it directly:
2. Callers read field names the canonical task shape dropped in #6951
WorkflowStephas aliasedautobot_shared.workflow.WorkflowTasksince #6951 Phase 2A.WorkflowTaskexposestask_idandrequires_approval. These sites still read theretired names, so they would raise
AttributeErroreven with theawaitadded:orchestration/workflow_planner.py:128—step.idorchestration/workflow_planner.py:133—step.user_approval_requiredorchestration/workflow_planner.py:227,230—step.id,step.user_approval_requiredservices/workflow_automation/manager.py:83,85—step.user_approval_required,base_steps[j].id3. The e2e test for this method cannot fail
autobot-backend/orchestration/plan_steps_e2e_test.pyhas no assertions — it prints astep count inside a
trythat catches every exception and prints the traceback. Itpassed throughout the entire period the method returned nothing. This is the #13162
shape again: a green test file guarding a fully broken method.
Why it matters
Workflow planning from a chat request is dead end-to-end.
create_workflow_from_chat_request(
services/workflow_automation/manager.py) andplan_workflow_steps_with_agents(
orchestration/workflow_planner.py) cannot produce a plan, and nothing in the suitereports it.
Acceptance criteria
awaitthe planning coroutines.WorkflowTasknames (task_id,requires_approval); no read of a name absent from the dataclass.plan_steps_e2e_test.pyasserts a non-empty plan per complexity level and no longer swallows exceptions — verified by a deliberate failure.create_workflow_from_chat_requestandplan_workflow_steps_with_agentsreturning real steps, so a regression to the empty-plan state fails CI.