Stream run events
GET /v1/agents/runs/{agentId}/stream: follow a run as Server-Sent Events.
GET https://api.greenpt.ai/v1/agents/runs/{agentId}/streamStreams the run as Server-Sent Events instead of polling. Reconnecting with
a Last-Event-ID header replays every event after that ID, then tails new
ones live — useful for recovering from a dropped connection without missing
anything.
curl -N https://api.greenpt.ai/v1/agents/runs/3fa2b1e4-8c5d-4a2e-9f1b-7d6e2c9a91cd/stream \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Accept: text/event-stream"| Event | Payload | Meaning |
|---|---|---|
step_start | { step, description } | A new step began. |
tool_call | { toolName, input } | Mangrove is calling a tool. input is an object on a forced step and a JSON string when the model generated it. |
tool_result | { toolName, result } | The tool's result, fed back to Mangrove. |
text | { text } | A whole message Mangrove produced, not a token-by-token delta. A run emits more than one. |
step_complete | { step } | The step finished. |
decision | { point, outcome } | A choice the run made about itself before or while it works. See Decisions. |
input_required | { message, expected } | Terminal — Mangrove needs input only you can provide. |
done | { finalText } | Terminal — the run succeeded; finalText is the answer. |
error | { message, code? } | Terminal — the run failed. code is task_not_done when Mangrove could not do the task — it said so, or every tool it called failed — and message is then its reason. |
toolName is usually one of the tools GET /v1/agents lists, but not
always: Mangrove also plans its work with write_todos, which emits the
same tool_call and tool_result pair, and ends a task it cannot do with a
report_task_not_done call, which the error event follows. Treat an unrecognized toolName as
something to display rather than an error.
Decisions
A decision event records how the run judged its task and what that changed.
Treat a point you do not recognize as something to display. Two of them say
how much work the run expects:
point | outcome | Meaning |
|---|---|---|
length_classification | { kind: "match", length, confidence? } or { kind: "fallback", reason } | How much work the task is: short (a few steps), medium (tens of lookups or pages) or long (hundreds of items or pages). Graded once, before the run starts. A fallback grades nothing and changes no limit. |
run_limits | { kind: "task_scoped", lanes, llmCallCap?, wallClockSeconds? } | The run narrowed its limits to what its task needs. Only the limits that changed are present. A run never goes above the guardrails it was created with. |
Example transcript for a research run that searches the web before answering:
event: step_start
data: {"type":"step_start","step":1,"description":"LLM agentic loop"}
event: tool_call
data: {"type":"tool_call","toolName":"web_search","input":"{\"query\":\"sustainable data center cooling\"}"}
event: tool_result
data: {"type":"tool_result","toolName":"web_search","result":"[{\"title\":\"Liquid cooling adoption accelerates\",\"url\":\"https://example.com/article\",\"snippet\":\"...\"}]"}
event: text
data: {"type":"text","text":"Data centers are increasingly adopting liquid cooling to cut energy use..."}
event: step_complete
data: {"type":"step_complete","step":1}
event: step_start
data: {"type":"step_start","step":2,"description":"Confirming the answer is complete before stopping"}
event: text
data: {"type":"text","text":"Data centers are increasingly adopting liquid cooling to cut energy use..."}
event: step_complete
data: {"type":"step_complete","step":2}
event: done
data: {"type":"done","finalText":"Data centers are increasingly adopting liquid cooling to cut energy use..."}Two things to handle when reading a stream, covered in How runs work:
reading it without duplicating the answer,
and a run that ends with input_required.