ADR 0014 Graph as transitions - agbossjs/agboss GitHub Wiki
- Status: Accepted (supersedes the hub graph of Architecture before #116)
- Issue: #116 (branches: engine #137, job-scout #139; spikes #113, #114, #115)
Until #116 every workflow ran one fixed graph: input guards → router ⇄ agent → finalize → output guards, with routers: { main: { maxHops } } and budget in @Workflow. Other shapes (a review
cycle, several entries, two routers) could not be expressed, the graph was not visible in the code, and
runaway loops ended quietly ("max hops reached", "budget exhausted") with a best-effort answer.
-
The workflow file is the graph:
@Workflow({ flow })lists transitions between classes —from(A).next(B),from(Router).routes(),chain(A, B, C),node(Class, "name"),Self. Nodes are@WorkflowStart,@Router,@Agent,@WorkflowFinishclasses. (Names as of today: at #116 the steps were calledto/chooseand the nodes@Entry/@Conclusion; a router's targets later moved into its ownroutes, so the flow says onlyroutes().) -
Checked at assembly, all at once: 15 rules (
graph.*,router.*) before any model call; every violation is reported in oneGraphRuleErrornaming the classes. Relations "by class" are a startup check, never compile time (component classes are empty to the compiler). -
Run as a real LangGraph graph: one node per flow node (
<kind>.<name>), conditional edges for a router's choice, workflow starts fromSTART, workflow finishes toEND. An agent node runs its loop as a compiled subgraph, so the approvalinterrupt()pauses the whole run and nothing before it repeats. -
Routers are nodes with routes:
@Router({ prompt, model, maxVisits?, routes })— the prompt says how to choose, each route what the choice means; texts normalised, routes sent sorted by name. No built-infinish: returning to the user is a route to a workflow finish. A failed decision fails the run. -
Limits fail, never stop quietly:
settings().limits({ perRun: { steps, cost }, perDay: { cost } })andmaxVisits; steps count agent and router visits;LimitExceededErrorcarries the key, path and spend, and the run is a failed Tern. -
Removed: the hub builder (
graph.ts,routing.ts, the hub router node),routersandbudgetin@Workflow,AgentsConfigand profiles;@Workflow({ agents }). - The existing guard, approval, compaction, knowledge and agent nodes run inside the new graph until #119 / #120 replace them; #100 (after a human decision the turn ends) is kept by the router node.
- A workflow's shape is code review-able and testable;
describelists it as transitions (a drawing comes with #127). - Hitting a limit or a router failure (e.g. a Jev timeout) now fails the turn instead of answering with what is there — visible in the Tern and the CLI, at the price of an error message where the hub answered.
- Route texts matter: Jev picks by them, so "send the answer" must say when (see Routers).
- Eval keeps its own account (
<workflow>:eval), now capped bylimits.perDay.cost. - Profiles cannot change the flow, routers or limits (they are code, versioned with the workflow).