Files
agentic-mobile-control/openspec/changes/archive/2026-07-06-workflow-orchestration-runtime/proposal.md
T
2026-07-06 23:52:53 +08:00

6.5 KiB

Why

agent-runtime (apex-agent-mvp, code-complete, unapplied) gives the runtime exactly one shape of work: a single flat goal driven by one Planner/Executor Observe-Think-Act-Observe loop until it succeeds, fails, or exceeds max_steps. Real device-automation usage is rarely one flat goal — it is a sequence of distinct sub-goals with control flow between them: open an app, send a message, wait for a reply to arrive, take a screenshot, then end; or run a locally-learned Skill (skill-learning-runtime, Milestone 7) instead of re-planning from scratch, only re-planning if the skill's assumptions don't hold. Nothing in the current runtime can express "do A, then B, then wait until C is true, then D," track where a multi-stage run is, or resume it if the process restarts mid-way. Workflow Runtime introduces Workflow as a first-class, persisted, resumable object composed of planner-derived steps, skill-invocation steps, wait-for-condition steps, and simple branch steps — sitting one layer above the existing single-goal loop, not replacing it.

What Changes

  • Add a new workflow/ package defining a WorkflowDefinition (an ordered, possibly-branching list of WorkflowSteps) as a discriminated union of four step kinds: a planned-goal step (delegates a sub-goal string to the existing agent-runtime Planner/Executor loop), a skill-invocation step (resolves parameters and executes a locally-synthesized FlowTemplateSkill from skill-learning-runtime, Milestone 7), a wait-for-condition step (polls a named condition — e.g. scene text present, a world variable equals a value, elapsed time — up to a timeout), and a branch step (evaluates a condition and jumps to a named step id instead of falling through sequentially).
  • Add a WorkflowRun — the persisted, mutable execution record for one execution of a WorkflowDefinition: status (pending/running/waiting/completed/failed/cancelled), current_step_id, workflow-scoped variables, and a per-step result log — checkpointed to storage after every completed step so a WorkflowRunner.resume(run_id) can continue from the last checkpoint instead of re-running from step 0, without re-executing already-completed mutating steps.
  • Add a WorkflowRunner orchestration component that composes (imports, never subclasses or edits) runtime/task.py's existing TaskRunner for planned-goal steps, and drives skill-invocation/wait/branch steps itself.
  • Add a first, minimal skill-invocation execution path (workflow/skill_exec.py): resolve a FlowTemplateSkill's declared parameters against a step's supplied argument values, validate against the skill's parameter schema, and drive the resolved tool calls through tools/ — the "some future runner resolves parameters and drives tools/" gap skill-learning-runtime explicitly left open.
  • Add a ConditionEvaluator port + registry (workflow/conditions.py) for wait/branch conditions, mirroring the Driver Registry / PerceptionProvider extension-point pattern already established by device-agent-runtime-foundation, with a small starting set of condition kinds (scene_contains_text, world_variable_equals, elapsed_seconds, step_result_success).
  • Add a new, independently-owned SQLite-backed WorkflowStore (workflow/store.py) for WorkflowDefinition/WorkflowRun persistence, following the same connect-per-call sqlite3 pattern as storage/task_metadata.py but in its own database file — not a schema change to storage/, which remains owned by the pending task-memory capability.
  • No changes to runtime/task.py, runtime/planner.py, runtime/executor.py, runtime/context.py, storage/*, tools/*, or any other existing module's public behavior — this change is purely additive composition on top of them.

Capabilities

New Capabilities

  • workflow-orchestration: A Workflow model (planned-goal / skill-invocation / wait-for-condition / branch step kinds), executed by a WorkflowRunner that composes the existing single-goal Planner/Executor loop and the not-yet-built skill-execution path, persisted via a task-memory-style store, and resumable from its last checkpoint if interrupted mid-workflow.

Modified Capabilities

(none — openspec/specs/ has no applied baseline for agent-runtime, task-memory, skill-authoring, or skill-embedding-retrieval yet, so this change cannot and does not write a MODIFIED Requirements delta against any of them; it composes with their pending, unapplied designs in prose only, and does not alter their specified behavior.)

Impact

  • New package: workflow/models.py (WorkflowDefinition, WorkflowStep variants, WorkflowRun, WorkflowStepResult), runner.py (WorkflowRunner), conditions.py (ConditionEvaluator port + registry), skill_exec.py (parameter resolution + tool dispatch for skill-invocation steps), store.py (WorkflowStore, SQLite-backed), config.py (enable flags, default poll interval, default wait timeout).
  • New storage: a new workflows/workflows.sqlite3 database file (own schema: workflow_definitions, workflow_runs, workflow_step_results tables), independent of storage/task_metadata.py's tasks/tasks.sqlite3.
  • Composed, not modified, dependencies: runtime/task.py's TaskRunner (planned-goal steps construct a Task and call TaskRunner(...).run(task), reading back task.status/task.failure_reason), skill-learning-runtime's FlowTemplateSkill/Skill dataclass shape (imported, not redefined, matching that change's own D6 precedent for composing with skill-catalog-subscription), and optionally world-model-runtime's WorldState.variables (read-only, for world_variable_equals conditions — degrades to "condition never satisfied until timeout" if WorldState is absent, never raises).
  • Config: add workflow* to pyproject.toml's [tool.setuptools.packages.find].include list; no new third-party dependency beyond the standard library sqlite3 already used by storage/task_metadata.py.
  • Out of scope: no visual workflow editor/UI (a future web-console concern, not touched here); no distributed/multi-device workflow execution (Milestone 10, Cloud Runtime); does not replace or remove the existing single-goal Planner/Executor loop, which remains the right tool for simple one-shot tasks; no generic expression/scripting language for branch conditions (a closed, registrable set of condition kinds only); no changes to skill-catalog-subscription, web-console, or any other pending change's files.