Concepts

Executions & Streaming

How agent and flow runs are triggered, tracked, and streamed in real time.

Both agents and flows are run through the same execution resource — the API doesn't distinguish between them at the transport level, only at resource_type.

Creating an execution

POST /api/v1/executions
{
  "resource_type": "agent" | "flow",
  "resource_id": "<agent_or_flow_id>",
  "project_id": "<project_id>",
  "input": { "input": "Hello!" }
}
→ 201: { "exec_id": "...", "status": "pending" }

The flow's Input step reads the user's message from input.input, input.message, or input.user_input — whichever is present.

Streaming over SSE

GET /api/v1/executions/{exec_id}/stream

This opens a text/event-stream connection. Event types:

Event typeEmitted byMeaning
tokenagent + flowAn incremental chunk of the model's response
reasoningagent + flowAn incremental chunk of the model's extended-thinking/reasoning text (opt-in, see below)
stepagent onlyAn inference step (phase: "thinking", etc.) — see below
tool_callagent onlyThe model is invoking a tool (name + input)
observationagent onlyThe result returned from a tool call
summaryagent onlyThe agent's Layer 1 running summary was updated this turn (see below)
flow_stepflow onlyOne flow node started/finished — carries node_id, its status, and the current uo_data envelope
doneagent + flowThe execution finished
erroragent + flowThe execution failed; detail explains why

A flow run traces its progress only through flow_step events: a Tool/MCP Tool node inside a flow is reported as a flow_step, not as a tool_call/observation pair. Those two events belong to agent executions.

The LLM flow node has a stream config toggle (default true) controlling whether its output arrives as incremental token events or as a single chunk once the full response is ready; the Agent flow node always streams incrementally. Nodes whose emit_to_output is turned off are silenced for token/reasoning — their text never reaches the caller — but their flow_step trace is still emitted, so the run stays fully observable.

Multi-turn conversations

Agent conversation state is client-driven, not persisted server-side: each POST /executions call is stateless from the API's perspective, so the caller resends the conversation on every turn via input.history (a flat list of {"role": "human"|"assistant", "content": ...}).

Once a conversation grows past the agent's max_tokens_before_summary (Layer 1 running summary, see Context Management), the backend compacts older messages into a rolling summary and emits it as a summary event ({"type": "summary", "content": {"summary": "...", "token_count": N}}). Callers should capture the latest summary event and resend it as input.summary on the next call, alongside only the most recent few messages in input.history — otherwise the backend has no persisted summary to build on and recomputes one from scratch from the full raw history every time the threshold is crossed again, which works but wastes an extra LLM call per turn.

Inference steps

UnderOcean surfaces the agent's internal thought → action → observation loop directly to the UI as step events, rather than only showing the final answer. This is core to the platform's "visibility into agent reasoning" principle — users can watch an agent decide to call a tool, see the tool's output, and see how that changes its next step, as it happens.

Reasoning / extended thinking (opt-in)

Agents, and the Agent/LLM flow nodes, support an optional reasoning_effort setting (none | low | medium | high, default none). When enabled on a model that supports it (e.g. Anthropic extended thinking, OpenAI/DeepSeek/ Grok reasoning models via LiteLLM), the model's reasoning/thinking text is streamed as reasoning events alongside token events, and persisted to the execution's reasoning field once the run completes. Models that don't support reasoning silently ignore the setting (no error).

Checkpointing

Execution state is checkpointed as it runs, which enables:

  • Resuming long-running flows after a pause (human-in-the-loop steps)
  • Recovering execution state after a transient failure

On this page