Opt in per connection
New and existing connections default to buffered answers. In the operator UI, open an agent’s connection and enable Stream answers, or use the existing operator session/API-token authorization with:progress_enabled (boolean) and
scope (all, chats, or direct) in the same request. Progress is independent
of answer streaming and preserves existing enabled behavior by default. Scope
applies to both features; final replies are unaffected. Omitted options retain
their saved values, so existing clients remain compatible. These advanced options
are not accepted for other connector types.
The response contains connector.streaming_enabled, connector.progress_enabled,
connector.streaming_scope, and status (active or
saved_restart_required). Only operators with access to the owning agent can
change its Slack, Telegram, or generic installation. Settings survive credential
rotation and connection edits. Disabling applies to new turns after reload;
it does not cancel an in-flight turn. A restart is required when reload fails.
Opt-in enables the public-answer handoff and incremental inference. With it off,
existing model requests and whole-message delivery remain buffered. Generic
snapshot/replay still provides canonical messages and authorized progress;
webhook payloads and whole-response delivery do not change.
Native messaging
Slack useschat.startStream, chat.appendStream, and chat.stopStream with
that installation’s bot credentials (chat:write). The validated final first
part updates the same Slack message; further parts use normal delivery. Drafts
are provisional and may be corrected. Public-channel streams include the
requesting user and installation’s workspace as recipient context.
Telegram uses sendMessageDraft in private chats only. It sends plain-text
previews, then the existing formatted sendMessage path persists the final
answer. Group replies stay buffered. No draft stop/cancellation button is exposed.
Both transports coalesce updates to approximately one every three seconds,
with a final flush. If a draft exceeds the provider’s limit or its API rejects an update,
further previews stop and the canonical reply path remains authoritative.
Failed model attempts remove known Slack previews or clear Telegram drafts
best-effort; retries do not append a different generation onto the old preview.
Native APIs do not provide the SSE journal’s replay guarantees. Formation reserves
creation and append before sending and retains known message IDs across worker
restarts. It never blindly repeats an uncertain Slack creation or append. If
Slack accepts a creation but its response or the local ID commit is lost, a
partial preview can remain alongside the eventual answer; Slack expires the
stream after ten minutes. Telegram drafts expire automatically. Lost ownership
prevents cleanup by the old worker. Operators should test with a dedicated
connection before enabling this on an existing conversation.
The native transport’s saved preview text follows the configured run-ledger
body retention window after its run becomes terminal. Active and recent runs
retain that text; a zero window keeps it. Delivery identity and uncertain-send
reservation metadata remain available for reconciliation until the run is deleted.
Official API contracts: Slack streaming
and Telegram drafts.
Authentication and commands
Use the generic connector’s existingX-Mesh-Install, X-Mesh-Timestamp, and
X-Mesh-Signature headers. Sign the exact POST body with the installation’s
secret using the normal v1:in construction. The body binds the operation,
conversation, actor, and replay cursor. Keep signing secrets in the application’s
backend; never ship them to a browser or mobile app.
The application backend derives actor_id from its authenticated user. It must
not accept a client-supplied actor or installation as authority. Formation checks
that this is a private conversation for that actor, in that installation and
agent’s perspective. Mixed or unverifiable audiences do not expose a feed.
Current source disclosure is rechecked for snapshots and each replay page,
including previously delivered progress. Disabled agents and rotated or removed
connections stop active subscriptions.
Send messages through POST /generic/events with stable message_id values for
idempotency. Subscribing does not submit a command, cancel a run, approve a tool,
or start a model call. This protocol does not add cancellation, attachment, or
approval command APIs; applications must not advertise those capabilities based
on streaming support alone.
Snapshot
POST /generic/conversations/snapshot:
Subscription and replay
POST /generic/conversations/stream:
Content-Type: text/event-stream, Cache-Control: private, no-store, and X-Accel-Buffering: no. Disable buffering in any application proxy.
Use a streaming HTTP client rather than a short JSON-request timeout.
id is the decimal sequence, never the event UUID. Numbers stay within the
JavaScript safe-integer range. If sending Last-Event-ID, it must exactly match
after_sequence in the newly signed request. The server does not trust an
unsigned header to change the read scope or cursor.
The current event types are:
A streaming message carries
status: streaming, a text part with
streaming: true, its runId, and an attemptId. A new model attempt replaces
the draft with an empty message.upsert and a different attempt ID. Never
concatenate text from different attempts. A validated canonical reply replaces
the draft at the same message ID and marks it complete. An interrupted or failed
terminal run marks any remaining draft failed. Draft text is provisional;
replacing it cannot undo what a person has already seen.
Incoming IDs are message:<message_id>, replies are reply:<parent_message_id>,
and approved progress has its own progress:<event_id>. Messages are ordered by
their first appearance; replacing a draft does not move it to the bottom.
Run states are queued, running, waiting_input, completed, failed, and
cancelled. Socket EOF does not mean a run completed. Preserve the last
successfully applied sequence and reconnect with a fresh signature. Replay can
include later messages and runs in the same conversation after a run completes.
Subscriptions last at most two minutes, with comment heartbeats every fifteen
seconds and five-second write deadlines. A process admits at most 128 concurrent
subscriptions, with a default of 16 per installation (configure
MESH_GENERIC_MAX_STREAMS_PER_INSTALL). Slots are released when subscriptions
close. Reconnect with bounded jittered backoff after transport failure or
429/503; authentication and authorization errors require fixing access. An
application backend must tie its proxy subscription to the client’s connection,
while keeping command execution independent of that connection.
The journal retains roughly 4,096 events per conversation, pruning in batches of
256. A cursor below the retained floor or ahead of the current watermark receives
HTTP 410 before streaming starts, without an SSE control frame. On HTTP 410, fetch
a new signed snapshot, replace local state, and reconnect with that snapshot’s
sequence; do not retry the expired cursor. If retention overtakes an open
subscriber, the server emits event: resnapshot with data: {} and closes. This is a transport
control event, not an application event: fetch a new snapshot and replace local
state before resuming. Never advance the cursor across a gap or feed this control
frame into a domain-event reducer.
What streams
The engine offersbegin_answer on eligible application turns. The agent calls
it alone once work and verification are finished. Its normal tool receipt makes
the handoff recoverable; the next inference has no tools and emits public answer
text. This adds an explicit model decision boundary rather than exposing private
assistant commentary that may precede a tool call. If a model answers directly
without the handoff, the validated answer still arrives as a complete upsert.
OpenRouter, OpenAI-compatible Chat Completions, and the Responses adapter decode
incrementally through the existing preparation, routing, audit, retry, and usage
paths. Native reasoning fields and tool arguments never become answer deltas.
Provider truncation is an error even when the transport returns EOF cleanly.
Final usage remains provider-reported, including usage received before failure.
Control-envelope continuations and unsupported text tool protocols retain final
validation. The incremental reply guard holds text from the first brace, angle
bracket, or backtick until final validation, so a split JSON envelope, think tag,
or code fence cannot leak control syntax. Ordinary prose before that boundary
can stream; code and structured answers settle through the canonical upsert.
Approved report_progress notices also appear in the feed. Raw tool execution
logs, reasoning, arguments, and internal activity labels remain private.