GreenPT Docs

Stream run events

GET /v1/agents/runs/{agentId}/stream: follow a run as Server-Sent Events.

GET
GET https://api.greenpt.ai/v1/agents/runs/{agentId}/stream

Streams 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"
EventPayloadMeaning
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:

pointoutcomeMeaning
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.

On this page