ADR 0019 Flow as paths with path scope - agbossjs/agboss GitHub Wiki
- Status: Accepted (supersedes the transition DSL of ADR-0014 and the parallel forms of ADR-0017)
- Issue: #272 (with #270, #271; parent #260; design #258)
The transition DSL — from(A).next(B), from(Router).routes(), chain(…), node(Class, "name"),
catchError, batchParallel — did not read at a glance: a workflow was a bag of edges, the data an
agent read was the whole state (task, contributions, {{item}}), and nothing said which values a
node could rely on. Relations "by class" were checked only at startup; the compiler saw empty
classes. Rollback was a saga engine that could not know how to undo a tool call.
-
A flow line is a path that reads as a sentence:
start(S).returns(InputDto).toRouter(R) .chooseOne(route(A).returns(XDto).toFinish(F), …). Transitions name the target's kind (toAgent,toRouter,toAction,toFinish);.returns(…)writes on the edge what the step gave (one value per.returns, #299);.returns(oneOf(…)).switch(caseOf(…))branches by the class of aoneOfresult;.onError(E, <side path>)stands right after the step that throws. A node reached from two places has its own path (agent(X)…); one class is one node. Position never carries meaning (Workflow). -
Components declare types only:
inputby field ({ draft: OfferDraftDto }) andoutput(XDto,oneOf(…),listOf(…)). The path's scope fills each field by type (Path scope); one analyser to a fixed point proves the data rules ([input.missing-on-path], …) at assembly. -
Generated types:
agboss checkloads the workflows (tsx, transpile-only), runs the same analyser and writes.agboss/types.d.ts— tables keyed by each component'snamethat type.returns(…),InputOf<X>(path-sensitive, the exact union up to 32 shapes) andapp.execute(Start, input). Without the file the compiler names the fix instead ofany. -
Names end with their kind (
main-router,draft-agent,chat-workflow-start), explicit and unique in the application — they key records, checkpoints, traces and the generated types. DTO classes end withDto. -
Agents read an input message (
### field (from producer)+ JSON) after static instructions, and answer a structuredoutputthrough answer tools (answer-<dto>), retried twice when invalid. -
Rollback is explicit:
.onError(Err, toAction(UndoAction)…)— no automatic compensation (Rollback). Replaced by ADR-0020 (#339): an action declares its undo (compensateWith), side paths are checked to run it, and the framework undoes only where no path can say it.maxVisitson routers and agents; a visit past it fails before the model call withVisitsLimitExceededError, which.onErrorcan take. -
One
StateGraphper workflow, node ids are the components' names; the scope is its own channel, error records are plain data, so.onErrorholds after a resume.
- Easier: a workflow is read top to bottom; what a node reads is visible and proven; most mistakes are compile errors, the rest assembly errors with the path that breaks them; prompts stay static and cache across runs.
- Harder: a project needs
agboss checkbeforetsc(generated projects run it on install, the gate before typecheck); every class the types mention must be exported; names are longer. - Not yet: parallel launches and joins (#273), child workflows (#263), code routers (#280) — they
build on the paths. The old DSL,
@WorkflowAction, sagas andagboss/concurrencyare removed.