Repository navigation
feat(orchestrator): queue a flow with no planner prompt from its frontmatter - #1553
Conversation
The recorder writes the agent menu and every prompt it lists beside the skill menu, one folder per flow. The graph checks read them. Co-Authored-By: Claude <noreply@anthropic.com>
…tmatter A flow's prompts already declare its graph: each task's dependsOn names the types it runs after, and one task is the sink. With wizard-agent-dag on, a flow that has no seed prompt is queued from that graph and no planner runs. A task the run excludes hands its dependencies to the tasks that waited on it, and the sink also waits for every task its dependencies do not reach, the wizard's own tasks among them. Every enqueue passes the guards enqueue_task passes. Every flow context-mill serves has a seed prompt, so no run takes this path yet. orchestrator seeded says which one queued the run, as source. Co-Authored-By: Claude <noreply@anthropic.com>
🧙 Wizard CIRun the Wizard CI and test your changes against wizard-workbench example apps by replying with a GitHub comment using one of the following commands: Test all apps:
Test all apps in a directory:
Test an individual app:
Show more apps
Test against a Context Mill branch:
Add Results will be posted here when complete. |
|
✅ Security review complete — 1 finding posted as a review (changes requested), in 8 min. Add the |
|
✅ Security review complete — 1 finding posted as a review, in 7 min. Add the |
johncwaters
left a comment
There was a problem hiding this comment.
Note
Automated review. Not written by a human.
Verdict: APPROVE WITH NITS
See inline comments.
| analytics.wizardCapture('orchestrator seeded', { | ||
| task_count: store.list().length, | ||
| types: store.list().map((t) => t.type), | ||
| source: seedPrompt ? 'planner' : 'frontmatter', |
There was a problem hiding this comment.
Note
Automated review. Not written by a human.
[convergent: code + redteam + boundary] MEDIUM
Is source on orchestrator seeded meant to ship to flag-off runs too? It isn't gated on isAgentDagEnabled, so every flag-off run (every served flow today) now sends source: 'planner', where the base branch sent only task_count and types.
Two readings:
- Intended: the PR body announces the property, and flag on and flag off still send the same shape, so this is fine.
- Not intended: the stack promises no change with the flag off, and any insight that expects the old property set sees a change before anyone flips the flag.
If it's the second, gate the property behind the flag.
sarahxsanders
left a comment
There was a problem hiding this comment.
this is the change I'm sold on!! makes no sense to have the model reconstruct the graph every run :)
The recorder took each prompt's flow and id from the downloaded agent menu and joined them into the path it wrote. A flow or id is now one path segment, and every destination is checked before a prompt is fetched or a fixture is replaced. Co-Authored-By: Claude <noreply@anthropic.com>
|
✅ Security review complete — No findings above the confidence threshold, in 5 min. Add the |
gewenyu99
left a comment
There was a problem hiding this comment.
good stuff. some error handling stuff to address
# Conflicts: # scripts/record-context-mill-fixtures.no-jest.ts
… own failure A declared graph that cannot be ordered, or that a queue guard rejects, ends the run with PHW_AGENT_ORCHESTRATOR_TASK_GRAPH and a message for the user, and sends `orchestrator task graph rejected` with the reason. A run queued from its frontmatter that queues nothing says the setup had no steps to run. A `dependsOn` name the flow does not declare is logged once when the graph is queued. A full-run test queues a warehouse task before the frontmatter graph: it runs after the declared tasks, and the report waits for it. Co-Authored-By: Claude <noreply@anthropic.com>
The 49 prompts are the ones 1.64.0 published, byte for byte. The agent menu changes only in the release its download URLs name. Co-Authored-By: Claude <noreply@anthropic.com>
Summary
A flow's prompts already declare its task graph: each task's
dependsOnnames the task types it runs after, and one task is thesink. Withwizard-agent-dagon, a flow that has noseed: trueplanner prompt is queued from that graph, and no planner agent runs.Every flow context-mill serves has a planner prompt, so no run takes this path until PR 4 bundles posthog-integration's prompts without one. PR 4 also narrows the path to flows the wizard bundles.
Stack
The five PRs, in merge order:
wizard-agent-dagflag and the shared skill resolver the orchestrator uses when it is on.main. Every later PR hangs its new path off this flag.The four wizard PRs merge in that order and ship in one release with
wizard-agent-dagoff. A run with the flag off or unset behaves as it does onmain.How a run gets its queue
flowchart TD load["Load the flow's prompts"] --> seed{"A seed: true prompt?"} seed -- yes --> planner["Run the planner agent,<br/>which calls enqueue_task per task"] seed -- "no, flag on" --> graph["Read the graph from frontmatter"] seed -- "no, flag off" --> err["Fail: no seed agent prompt"] graph --> drop["Drop the tasks the run excludes,<br/>and give their dependencies<br/>to the tasks that waited on them"] drop --> guards["Queue each task through<br/>the enqueue_task guards"] planner --> queue["Queue"] guards --> queue queue --> drain["Drain: one agent per task"]src/agent/runner/sequence/orchestrator/task-graph.tshas two functions:planTaskGraph(graph, keep)keepallows, each after every task it waits for and the sinks last. A dropped task hands its dependencies to the tasks that waited on it. Throws aTaskGraphErrorwhen the tasks cannot be ordered.queueTaskGraph(ctx, graph)applyEnqueue, so each task passes the guards an agent'senqueue_taskpasses. A sink also waits for every queued task its dependencies do not reach, such as a task the wizard queued first. Logs eachdependsOnname the flow does not declare, once. Throws aTaskGraphErrorwhen a guard rejects a task.Which tasks a run leaves out stays where it is: the program's
excludedTaskTypesfor flags and CI, andseedTasksfor tasks the wizard queues itself. The registry exposes the declared graph, excluded tasks included, asregistry.graph.orchestrator seededcarries which one queued the run assource,plannerorfrontmatter, on every run with the flag on or off. It is the one thing a flag-off run sends that it did not send before.When the graph cannot be queued
PHW_AGENT_ORCHESTRATOR_TASK_GRAPHorchestrator task graph rejectedwith the reason:unorderable, or the guard's name.PHW_AGENT_ORCHESTRATOR_HOLLOW_RUNposthog-integration's graph
The graph the recorded
integration-v2prompts declare. Edges a longer path already implies are left out.mcp-analytics,ai-observabilityandlogsare optional and leave a run when the program excludes them.warehouseis queued by the wizard from what detection found, and onlyreportwaits for it.Proof: the graph queues what the planner queues
The planner's own choices are which tasks to queue. Thirty days of
orchestrator seededevents show what it chose.warehousemcp-analyticsmcp-analyticsmcp-analyticsandwarehouseai-observabilityandlogswarehouseThe last row is planner slips: a task queued twice, a plan that stopped after
installandinit, or a plan with noreport. The graph cannot produce them.src/agent/runner/sequence/orchestrator/__tests__/recorded-flow-graphs.test.tspins the task sets and the edges, and checks every recorded flow: eachdependsOnnames a task in its folder, the folder has one sink and can be ordered, and eachskillsentry is on the recorded menu.Fixtures
fixtures/context-mill/holds context-mill 1.65.0's agent menu and its 49 prompts, one folder per flow, in their own commit.pnpm record:context-mill-fixturesrecords them. The recorder accepts a flow or id only as one path segment and checks every destination first, so a menu cannot name a file outside the fixtures folder.Test plan
pnpm typecheckpnpm lintpnpm exec vitest run: 286 files passtask-graph.test.ts: the order, dropped tasks, cycles, the sink, a task the wizard queued first, an undeclareddependsOnname logged once, a guard rejectionfrontmatter-queue.test.ts: a full orchestrator run with no planner, with an excluded task, with a warehouse task the wizard queued first, with a graph that cannot be ordered, with every task excluded, with a planner prompt, and with the flag off🤖 Generated with Claude Code