AI agents in a process
In Flow a model call is a capability, dispatched through the same registry as a database write or an HTTP request and run by the same host as every other task in the process or case. An agent has no separate runtime, retry logic or audit trail.
Two capabilities, one seam
Section titled “Two capabilities, one seam”Flow registers two AI capabilities:
ai:generateis a synchronous, one-shot completion: one prompt in, one completion out, no tools and no memory across calls. It fits work that is one task: summarise this, classify this, extract this field.agent:runis a durable reason/act loop. The model calls tools, reads their results and decides what to do next, for as many turns as its spec allows. A human approval gate can sit on any tool namespace.
They register under different namespaces, ai for the synchronous one
and agent for the asynchronous one. The host resolves an asynchronous
handler before a synchronous one, so an agent registered under ai
would take every ai:* task.
Both name a stored agent spec by agentRef, and both reach the model
through llm.Provider. It has one method, Generate, which performs
one turn: no streaming, no retry, no clock. Adapters for Anthropic,
OpenAI and Gemini implement it over each provider’s own SDK, and the
spec names the provider explicitly. A spec’s baseURL points an adapter
at a non-default endpoint. Moving an agent to another provider is a
change to its spec.
Tools are connectors
Section titled “Tools are connectors”An agent’s tools are the capability connectors a service task uses. A
tool call to http:request resolves through the same
capability.Registry, and runs the same handler, as a BPMN service task
or a CMMN task of type http:request. The parameter schema the model
sees for that tool is derived from the connector’s input struct, the
same derivation that builds the task’s properties panel in the
modeller.
A connector written once is a process step and an agent tool. There is no second schema to keep in step with the first, and the tools a model can be offered are the connectors registered on that host, narrowed by the spec’s allowlist.
An asynchronous capability is callable as a tool too. agent:run is one,
so an agent can call another agent as a tool when the spec allows the
agent namespace. The nesting depth is bounded by the spec’s maxDepth,
which defaults to one level.
Durable by construction
Section titled “Durable by construction”The loop keeps no state outside what its host records. On the broker the
loop is a reducer like the BPMN and CMMN engines: each model call and
each tool call is a job, and its result comes back as an event that
advances the loop. On DBOS the loop runs each model call
and each tool dispatch as one journaled step, with no goroutine and no
bare time.Now. A structural test holds the loop to that discipline.
A worker crash between a tool result and the next model call resumes from the recorded state. A model call or tool call that completed is not made again. A call that was in flight when the worker died is dispatched again, so a tool that writes to another system should pass on the idempotency key its host gives it.
Every turn can be recorded as an agent.turn event in the case’s
history, carrying the model’s response and the OpenTelemetry GenAI
attributes (gen_ai.system, gen_ai.request.model, gen_ai.usage.*).
The broker records every turn. DBOS records them when the
spec sets auditTurns. A replay feeds the recorded responses back in,
because a model’s answer cannot be recomputed.
Where this splits
Section titled “Where this splits”The seam, the tools and the loop are one mechanism used two ways:
- The static agent has a tool allowlist fixed when the loop starts. It is the agent to reach for first.
- Agents governed by the case read their tools from the live case on every turn, so the case model decides what the agent may do.
Flow and agent frameworks compares this design with graph and conversational agent frameworks.