Skip to main content

Overview

ntrp uses a persistent SSE connection per session. Connect to GET /chat/events/{session_id} to receive all events (agent responses, tool calls, background task results). Messages are sent via POST /chat/message as fire-and-forget — the response arrives on the SSE stream. Each event has a type field indicating what happened.

Event envelope

Every chat stream event includes server-owned ordering metadata:
{
  "type": "TEXT_MESSAGE_CONTENT",
  "session_id": "20260508_120000_000",
  "run_id": "cool-otter",
  "seq": 12,
  "timestamp": 1778241600000
}
The SSE id field is the same value as seq. Clients should reconnect with after_seq=<last seen seq> and ignore events whose sequence is not greater than the last applied sequence for that session. If after_seq is older than the server’s checkpoint watermark (events at or below the watermark are persisted to disk and only available via the history endpoint), or points past the server’s known stream generation, the server emits stream_reset. Desktop responds by reloading session history before applying more events for that session. A checkpoint advances after every agent step (and at run finish) when the chat service persists messages. The replay buffer itself is not cleared at the checkpoint — it grows up to a fixed size and evicts oldest. Cursors at or above the checkpoint can replay from the buffer alone, no history reload needed; this is the fast path for tab-switch / brief disconnects. While idle, the SSE keepalive comment frame carries the bus’s latest emitted sequence: : seq=<latest>\n\n. Clients can use this to confirm they are caught up without waiting for a real event.

Event types

thinking

Agent is processing. Includes a status message.
{"type": "thinking", "status": "Searching memory..."}

TEXT_MESSAGE_START

Assistant text block started.
{"type": "TEXT_MESSAGE_START", "message_id": "msg_abc", "role": "assistant"}

TEXT_MESSAGE_CONTENT

Streamed assistant text delta. Only sent when streaming is enabled with ?stream=true.
{"type": "TEXT_MESSAGE_CONTENT", "message_id": "msg_abc", "delta": "Based"}
Deltas arrive in order by seq. Accumulate them by message_id.

TEXT_MESSAGE_END

Assistant text block ended. Includes the cumulative content as a convenience.
{"type": "TEXT_MESSAGE_END", "message_id": "msg_abc", "content": "Based on your calendar..."}

TOOL_CALL_START

Agent invoked a tool.
{
  "type": "TOOL_CALL_START",
  "tool_call_name": "recall",
  "tool_call_id": "tc_abc123",
  "depth": 0
}

TOOL_CALL_ARGS

Tool arguments. NTRP currently emits arguments atomically as a JSON string.
{"type": "TOOL_CALL_ARGS", "tool_call_id": "tc_abc123", "delta": "{\"query\":\"meeting notes\"}"}

TOOL_CALL_END

Tool call input finished.
{"type": "TOOL_CALL_END", "tool_call_id": "tc_abc123"}

TOOL_CALL_RESULT

Tool execution completed.
{
  "type": "TOOL_CALL_RESULT",
  "tool_call_id": "tc_abc123",
  "content": "Found 3 relevant facts...",
  "preview": "3 facts found",
  "duration_ms": 450
}

approval_needed

Tool requires user approval before executing.
{
  "type": "approval_needed",
  "tool_id": "tc_abc123",
  "name": "send_email",
  "content_preview": "Send email to alice@example.com"
}
Respond with POST /tools/result to approve or reject.

RUN_STARTED

Run started.
{
  "type": "RUN_STARTED",
  "session_id": "abc-123",
  "run_id": "run_abc"
}

RUN_FINISHED

Execution complete. Includes token usage.
{
  "type": "RUN_FINISHED",
  "run_id": "run_abc",
  "usage": {
    "prompt": 1500,
    "completion": 200,
    "cache_read": 800,
    "cost": 0.012
  }
}

RUN_ERROR

An error occurred.
{"type": "RUN_ERROR", "run_id": "run_abc", "message": "Rate limit exceeded", "recoverable": false}

background_task

A background task changed state (started, completed, failed, or cancelled).
{"type": "background_task", "task_id": "bg_abc123", "command": "research(deep): research topic", "status": "completed"}

run_backgrounded

A running agent was moved to background mode.
{"type": "run_backgrounded", "run_id": "run_abc"}

run_cancelled

Worker acknowledged cancellation and reached the terminal cancelled state.
{"type": "run_cancelled", "run_id": "run_abc"}
Cancellation is asynchronous. POST /cancel returns 202 when the run exists and cancellation has been requested. The stream emits run_cancelled when the worker acknowledges cancellation and the run reaches its terminal cancelled state.

task_started, task_progress, task_finished

Sub-agent task lifecycle. These events link child work back to the parent tool row.
{
  "type": "task_started",
  "run_id": "run_abc",
  "task_id": "call_research",
  "parent_tool_call_id": "call_research",
  "status": "running",
  "depth": 1
}

stream_reset

The requested after_seq cursor falls below the server’s checkpoint watermark (or is in the future). The client should reload session history and resume from the latest seq.
{"type": "stream_reset", "reason": "replay_gap"}

Approval flow

When approval_needed is received:
  1. Display the tool call to the user
  2. Collect their decision (approve/reject)
  3. Submit via POST /tools/result:
curl -X POST http://localhost:6877/tools/result \
  -H "Authorization: Bearer $API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "run_id": "run_abc",
    "tool_id": "tc_abc123",
    "result": "Approved",
    "approved": true
  }'
The stream continues after approval.