Event reference
Generated reference of turn events, session journal kinds, begin and error codes, and feed frames.
Generated by bun run docs:generate (scripts/generate-event-reference.ts) from the event and journal schemas; the full JSON schemas are in docs/event-reference.json. Writers, sensitivity, HTTP statuses and error-code meanings are kept by hand in that script, which fails when they no longer match the code.
There are two kinds of events. The bus carries a turn’s typed events (TurnEvent) live, in process, to the turn’s subscribers. The journal is the session’s durable log: the turn’s writer subscribes to the bus first and stores most bus events, memory stores its entries, and the sessions plugin stores the turn’s start, end and the inbox. Another request or process reads the journal with Sessions.read; only the bus carries token deltas. See the events guide for how to subscribe to them, stream a turn to a client and follow a session.
Bus events
_tag is the event’s name. Subscribe with turn.events.subscribe, onEvent, onTool or a host event’s on.
| Event | Transient | Stored as |
|---|---|---|
turn.started | no | Recorded elsewhere: the session’s own turn.started, written when the turn began |
step.started | no | step.started |
tool.started | no | tool.started |
tool.refused | no | tool.refused, without input |
tool.progress | yes | Not stored (transient) |
tool.completed | no | tool.completed, without input, result, encoded |
step.ended | no | step.ended |
completion.evaluated | no | completion.evaluated |
skills.activated | no | Recorded elsewhere: memory’s memory.skills |
context.built | no | context.built |
decision.recorded | no | decision.recorded |
assistant.message | no | step.usage, without text, reasoning, toolCalls |
assistant.delta | yes | Not stored (transient) |
stream.fallback | no | stream.fallback |
turn.ended | no | Recorded elsewhere: memory’s turn.reply and the session’s own turn.ended |
host | no | Under its name |
turn.started
Published once per turn when memory takes the user’s message as turn turn (TurnMemory.persistMessage; Agent.turn runs it before the host’s use). runId names the run, userMessage is what the user said (as the session stored it: its images, inline as base64, normalised), meta is the host’s metadata the turn was begun with ({} when none was given; never shown to the model), and resumes, present only on a turn that resumes an earlier one, is that turn’s number. Not journaled from the bus: the session stored its own turn.started when the turn began, with meta and resumes only when they were given. A subscription made in use never sees it; one in the host’s per-turn layer or a session plugin does.
| Field | Type |
|---|---|
runId | string |
turn | integer |
userMessage | { text, attachments } |
meta | object |
resumes | integer (optional) |
step.started
Published by the step loop as each step starts. planned is true for step 0 of a host-planned batch, which makes no provider call; activeTools are the tool names the step offers the model. Journaled as step.started.
| Field | Type |
|---|---|
step | integer |
planned | boolean |
activeTools | Array<string> |
tool.started
Published by the tool registry just before a tool’s handler runs. invocationId (<runId>:call:<n>) pairs it with its tool.progress and tool.completed; input is the decoded parameters; labels and stage come from the tool’s annotations. A refused call (inactive, forbidden, denied, over a limit) publishes tool.refused instead, and no other tool.* event; step.ended.results lists every recorded result, refused calls included. Journaled as tool.started, input included.
| Field | Type |
|---|---|
step | integer |
invocationId | string |
tool | string |
input | unknown |
labels | Record<string, string> |
stage | string | null |
tool.refused
Published by the tool registry when it refuses a call before the handler runs, in place of tool.started: the tool is not active (inactive: not loaded, or not available in this conversation), the turn lacks a permission it needs (forbidden), the host’s ActionPolicy denied it (denied), the turn’s call limit is reached (call-limit) or the tool’s own (tool-call-limit). invocationId is minted for the call as for any other (the refused call takes its <runId>:call:<n>); message is what the model receives as the call’s failed result, which step.ended.results lists as not ok. The model is offered only active tools, so inactive comes from a call made through the handlers directly (a host’s, another tool’s); forbidden also from a tool an earlier turn activated whose permission this turn lacks. Journaled as tool.refused without input.
| Field | Type |
|---|---|
step | integer |
invocationId | string |
tool | string |
input | unknown |
reason | "inactive" | "forbidden" | "denied" | "call-limit" | "tool-call-limit" |
message | string |
tool.progress
Published by publishToolProgress from inside a tool handler, between that call’s tool.started and tool.completed (same step, invocationId and tool). channel is stdout or stderr for a command’s output as it arrives, status for anything else the tool reports; text is that output or message. Transient: never journaled; tool.completed carries the result.
| Field | Type |
|---|---|
step | integer |
invocationId | string |
tool | string |
channel | "stdout" | "stderr" | "status" |
text | string |
tool.completed
Published by the tool registry when a handler returned or failed (ok). result is the decoded value, encoded its wire form as the model receives it. durationMs runs from just after tool.started to the handler’s exit, so it includes any wait for the tool’s read or write lane. Journaled as tool.completed without input, result and encoded: memory keeps the call and its result (memory.message, memory.tool-result).
| Field | Type |
|---|---|
step | integer |
invocationId | string |
tool | string |
input | unknown |
ok | boolean |
result | unknown |
encoded | unknown |
durationMs | number |
labels | Record<string, string> |
stage | string | null |
step.ended
Published by the step loop after the step’s tail is recorded. status is completed, failed or cancelled; results are the step’s recorded tool results (memory entry, tool call id, tool, ok), in log order, refused calls included. Journaled as step.ended.
| Field | Type |
|---|---|
step | integer |
status | "completed" | "failed" | "cancelled" |
results | Array<{ entry, toolCallId, tool, ok }> |
completion.evaluated
Published by the step loop after step.ended, with the verdict of the host’s completion policy for that step. A verdict that awaits tasks is evaluated again once they finish, publishing a second event. Journaled as completion.evaluated.
| Field | Type |
|---|---|
step | integer |
verdict | { complete, awaiting, facts } |
skills.activated
Published by the tool registry when skills (and their tools) become active: always-on skills, the intent matcher, the model’s load_skill, or the host. Not journaled from the bus: memory records the activation as memory.skills.
| Field | Type |
|---|---|
skills | Array<string> |
tools | Array<string> |
source | "always" | "matcher" | "load_skill" | "host" |
context.built
Published before each provider call, once the step’s context is built (none for a planned step 0). It carries the memory strategy and its version, the context and system-prompt fingerprints, the token estimate of the messages, the tokens reserved for the system prompt and tool schemas, the run’s budgetTokens (the whole request’s; memory compacted the messages toward budgetTokens - reservedTokens), how many compactions the build applied, and the active tools. Journaled as context.built (records written before 0.14.0 have no budgetTokens); the full request is journaled beside it as request.prepared.
| Field | Type |
|---|---|
step | integer |
turn | integer |
strategy | string |
strategyVersion | string |
fingerprint | string |
systemFingerprint | string |
estimatedTokens | integer |
reservedTokens | integer |
budgetTokens | integer |
compactions | integer |
activeTools | Array<string> |
decision.recorded
Published by recordDecision, for example when turn.tools.select or apply records the skill selection: the decision record holds the candidates, the policy version and what was chosen. Journaled as decision.recorded.
| Field | Type |
|---|---|
record | { version, id, family, contextHash, candidateHash, policyVersion, candidates, attempts, selection, validation, fallback, applied, probabilities } |
assistant.message
Published by the step loop once per provider response, after that step’s tools ran and its tail is recorded: the text, the reasoning, the model, the tool calls and the token usage (input with its cache reads and writes inside, output with its reasoning inside). A host-planned step 0 carries zero usage. Journaled only as step.usage (step, model, usage): the content itself is memory’s memory.message.
| Field | Type |
|---|---|
step | integer |
text | string |
reasoning | string |
model | string | null |
toolCalls | Array<{ id, tool, input }> |
usage | { inputTokens, outputTokens, totalTokens, cacheReadTokens, cacheWriteTokens, reasoningTokens } |
assistant.delta
Published by the step loop for each streamed increment while limits.streaming is on (the default), on channel text, reasoning or tool-params; id groups the increments of one content part. Transient: never journaled, and restated in full by assistant.message. A stream that falls back to a non-streamed call (stream.fallback) publishes none.
| Field | Type |
|---|---|
step | integer |
channel | "text" | "reasoning" | "tool-params" |
id | string |
delta | string |
stream.fallback
Published by the step loop when a streamed provider call fails before its first part: the step is answered by a non-streamed call instead, and so is every later step of the run. Once per run at most. message is the stream’s error as text, cut to 300 characters; it can quote the provider’s error. A stream that fails after its first part fails the step instead (its tools may have run). A refusal over an image (an InvalidRequestError that names one) is no stream failure: it has no fallback; the turn omits the images and sends the step again (StepRequest.onMediaRejected), or the step fails. Journaled as stream.fallback.
| Field | Type |
|---|---|
step | integer |
message | string |
turn.ended
Published once when the turn’s reply is recorded (TurnMemory.persistReply, from guardTurn), also when the turn fails, with outcome failed; usage is the turn’s usage, the usage of its assistant.message events summed (RunContext.usage). Under Agent.turn it is published after use, the host’s per-turn layer and the turn-dependent plugins have closed, and their subscriptions with them: only a subscription whose scope is still open sees it, such as one made with Scope.provide(observerScope) over the caller’s outer scope, or one registered around TurnLive by a host composing the turn itself. Otherwise read the TurnResult Agent.turn returns (its usage is the same total), or the stored turn.reply and turn.ended, and turnUsageOf over the stored events. Not journaled from the bus: memory stores turn.reply and the session its own turn.ended (reason and failure, no usage).
| Field | Type |
|---|---|
runId | string |
turn | integer |
outcome | "completed" | "partial" | "failed" |
reply | string | null |
usage | { inputTokens, outputTokens, totalTokens, cacheReadTokens, cacheWriteTokens, reasoningTokens } |
host
An application’s own event (defineHostEvent), published by the host’s code, tools or tasks. name is the host’s namespace and data the payload as its schema encodes it. Journaled under name as its kind; a name in RESERVED_KINDS fails the publish with events.reserved.
| Field | Type |
|---|---|
name | string |
data | object |
Journal kinds
Every event of a session’s journal is { session, seq, turn, kind, at, data }; seq is dense from 1 and is the cursor for Sessions.read({ after }). These are the kinds the framework writes. journalSchemaOf(kind) (from @xandreed/core) gives the schema of each kind’s data. A host that exports, streams or redacts session events must treat the sensitive kinds like the conversation itself: request.prepared, memory.system, memory.section and memory.step hold the system prompt and the host’s context.
| Kind | Written by | Sensitive content | Fields |
|---|---|---|---|
turn.started | plugin-sessions, when Sessions.begin opens the turn | The user’s message (its images, inline as base64, included), the host’s command and the host’s metadata (meta), when given. | runId, key, origin, userMessage, command, claimed, entry, at, meta, resumes |
memory.system | Memory, when the turn’s system prompt (or a variant) changes | The full system prompt text. | entry, runId, step, at, body |
memory.section | Memory: turn.context(…) and turn-tier prompt sections | Turn sections: the host’s context for this turn, as the model sees it. | entry, runId, step, at, body |
memory.step | Memory: the step policy’s step context | Step context text. | entry, runId, step, at, body |
memory.message | Memory: the step loop’s recorded messages | User and assistant text, reasoning, tool call inputs. | entry, runId, step, at, body |
memory.tool-result | Memory: the step loop’s recorded tool results | Tool output, encoded (a tool’s images, inline as base64, included) and as the model saw it. | entry, runId, step, at, body |
memory.digest | Memory: a digester (plugin-memory-digest) | Tool output, digested. | entry, runId, step, at, body |
memory.skills | Memory: the tool registry’s skill activations | None: skill and tool names. | entry, runId, step, at, body |
memory.compaction | Memory: the memory strategy’s compactions (window, summary); the turn, when a provider refuses an image (OmitMedia) | Conversation text: summaries and compact views; an OmitMedia’s reason quotes the provider’s error (up to 500 characters). | entry, runId, step, at, body |
turn.reply | Memory, when the turn’s reply is recorded (TurnMemory.persistReply) | The assistant’s reply. | entry, runId, step, at, body |
step.started | The turn’s bus (stored from step.started) | None: tool names. | step, planned, activeTools |
step.ended | The turn’s bus (stored from step.ended) | None: entry ids and tool names. | step, status, results |
step.usage | The turn’s bus (stored from assistant.message) | None: model name and token counts. | step, model, usage |
tool.started | The turn’s bus (stored from tool.started) | Tool input. | step, invocationId, tool, input, labels, stage |
tool.refused | The turn’s bus (stored from tool.refused) | The refusal message, which may name missing permissions or quote the host’s denial; the input is left out. | step, invocationId, tool, reason, message |
tool.completed | The turn’s bus (stored from tool.completed) | None: input and result are left out. | step, invocationId, tool, ok, durationMs, labels, stage |
completion.evaluated | The turn’s bus (stored from completion.evaluated) | The host’s facts behind the verdict. | step, verdict |
context.built | The turn’s bus (stored from context.built) | None: fingerprints, counts and tool names. | step, turn, strategy, strategyVersion, fingerprint, systemFingerprint, estimatedTokens, reservedTokens, budgetTokens, compactions, activeTools |
decision.recorded | The turn’s bus (stored from decision.recorded) | Candidate descriptions; the context itself only as a hash. | record |
stream.fallback | The turn’s bus (stored from stream.fallback) | The stream’s error text, which may quote the provider’s error. | step, message |
request.prepared | The turn, before each provider call (TurnMemory.prepareRequest) | The full system prompt text and every active tool declaration (and step context in system mode). | version, runId, step, strategyVersion, system, render, through, contextFingerprint, tools, toolChoice, model, cacheKey, callPolicy |
turn.ended | plugin-sessions: the turn writer’s end (Agent.turn and Sessions.drain end with turnEndingOf the turn’s exit), the writer’s scope, Sessions.cancel, or a reap | Failure messages, which may quote errors. | reason, failure |
inbox.queued | plugin-sessions: Sessions.deliver (a task’s result, a host’s item) | The item’s content and source. | id, source, content |
inbox.dropped | plugin-sessions: the end of the last turn that took the item and failed | None: the item id. | id, reason |
A memory kind’s data is { entry, runId, step, at, body }: the memory entry’s id, run, step and time, and its body without the _tag (the kind names it). Memory is rebuilt from these events by entriesOfEvents.
| Kind | Body fields |
|---|---|
memory.system | fingerprint: string, text: string, sections: Array<{ id, version, fingerprint }> |
memory.section | sectionId: string, version: string, text: string |
memory.step | step: integer, text: string |
memory.message | message: { role, content, providerOptions } |
memory.tool-result | toolCallId: string, toolName: string, isError: boolean, encoded: unknown, view: string, viewVersion: string, subjects: Array<{ kind, id, label, data }>, artifacts: Array<{ id, kind, mediaType, url, alt }>, pinned: boolean, media: Array<{ path, fingerprint, mediaType, bytes }>, mediaNotes: Array<string> |
memory.digest | entry: string, version: string, mode: "select" | "summarize", keep: Array<string>, text: string, digester: string, trigger: "write" | "compaction" |
memory.skills | skills: Array<string>, tools: Array<string>, source: "always" | "matcher" | "load_skill" | "host", decision: string | null |
memory.compaction | strategy: string, version: string, action: { _tag, entries, texts } | { _tag, entry, preview } | { _tag, throughTurn, ledger } | { _tag, keepFromTurn, summary } | { _tag, entries, reason } |
turn.reply | outcome: "completed" | "partial" | "failed", reply: string | null |
Any other kind is a host’s or a plugin’s own record (defineHostEvent, Sessions.transact, the tasks plugin’s task.*).
Reserved kinds
A host event, or a Sessions.transact draft, may not use these names: the publish fails with events.reserved, the transact with ReservedKind. They are the journal kinds above and every bus event’s name (TURN_EVENT_NAMES), the ones the journal never stores under their own name included (assistant.message, assistant.delta, tool.progress, skills.activated, host). The list is matched exactly, not by prefix: other names in these namespaces are accepted, but a host should use its own namespace.
turn.started
memory.system
memory.section
memory.step
memory.message
memory.tool-result
memory.digest
memory.skills
memory.compaction
turn.reply
step.started
step.ended
step.usage
tool.started
tool.refused
tool.completed
completion.evaluated
context.built
decision.recorded
stream.fallback
request.prepared
turn.ended
inbox.queued
inbox.dropped
tool.progress
skills.activated
assistant.message
assistant.delta
host
Begin codes
When Agent.turn begins the turn itself and the turn cannot begin (Sessions.begin refuses it, or, for AttachmentRejected, Agent.turn’s own check of the attachments before it), the turn fails with a HarnessError whose code is one of these (turnBeginCodes from @xandreed/sdk). The HTTP status is a suggestion for a host serving turns over HTTP.
| Begin error | Code | Suggested HTTP status | Meaning |
|---|---|---|---|
AttachmentRejected | turn.attachment-rejected | 400 | An attachment of the user’s message is not an image the framework takes (not base64, not a PNG, JPEG, GIF or WebP, over the size or pixel limits, too large together; see MEDIA_LIMITS). Agent.turn checks before it calls Sessions.begin: nothing was opened. The HarnessError carries the reason only in its message; a host that wants it typed (to answer 413 for TooLarge and TooLargeTogether, or name the attachment by its index) runs normalizeUserMessage from @xandreed/core on the message first and branches on AttachmentRejected.reason. |
SessionBusy | session.busy | 409 | Another turn is open in the session. Retry after it ends, or queue the message. |
TurnDuplicate | turn.duplicate | 200 once that turn ended, 409 while it is open | The key was begun before with the same message, command and resumes: that turn is the answer, so serve its result instead of running again (Sessions.lookup(address, key) finds it). |
KeyConflict | turn.key-conflict | 409 | The key was begun before with another message, command or resumes (the key resume:<n> begun again without resumes conflicts). |
NothingPending | session.nothing-pending | 204 | An inbox turn found nothing to take (inbox turns only). |
NotResumable | turn.not-resumable | 409 | The turn named in resumes cannot be resumed: missing (no such turn in the session, or resumes is not a whole number of at least 1), inbox (an inbox turn), superseded (a user’s turn began after it, other than a resume of it that failed, was cancelled or was interrupted) or finished (it ended completed, partial or failed). Only the last user’s turn, ended cancelled or interrupted, can be; a resume that failed is tried again with a new key. |
TurnRefused | turn.refused | 429 for a quota or rate, 403 when not allowed, 503 while draining before a shutdown | The host’s TurnAdmission refused the turn; nothing was opened or counted. |
SessionMissing | session.missing | 404 | No such session for this owner. |
SessionLogError | session.log | 503 | The session store failed. Retry later. |
Common turn error codes
Besides the begin codes, these are common HarnessError codes a turn fails with, or that a stored turn.ended carries in failure.code. A failed turn’s turn.ended carries the code of the error it failed with (one of these, a plugin’s, or a host’s own), else turn.failed, turn.defect or turn.interrupted (turnEndingOf from @xandreed/core), with the error’s message cut to 500 characters; a closer that ends its writer itself stores its own code (plugin-tasks: task.turn, task.deadline). The list is not exhaustive: it has every code the packages raise under turn.*, events.*, request.*, loop.*, tools.* (the generator checks), but other plugins raise codes of their own (a memory strategy’s, a store’s), and a host’s own errors keep their own codes.
| Code | Where | Meaning |
|---|---|---|
turn.closed | Agent.turn, the turn writer | Someone else closed the turn (cancelled, reaped, the session removed); its later writes are refused. |
turn.failed | stored turn.ended failure (turnEndingOf) | The turn failed with a typed error that has no code of its own; the message is <_tag>: <message>, or the error as text (reason failed). |
turn.defect | stored turn.ended failure (turnEndingOf) | The turn died with a defect, an unexpected error; the message is the defect as text (reason failed). Agent.turn and Sessions.drain first turn a HarnessError carried as a defect back into a failure, so it keeps its own code; a runner calling turnEndingOf itself does the same with harnessDefectsAsFailures. |
turn.interrupted | stored turn.ended failure | The turn was interrupted before it ended: its body (turnEndingOf), the scope its writer lived in, or its begin after the opening commit (reason interrupted). |
turn.unended | stored turn.ended failure | The turn’s scope closed, without an interruption, before anyone tried to end the turn (reason failed). An end that was tried but could not be stored is tried again by the scope with that same ending, not this code. |
turn.lease | stored turn.ended failure | The turn’s holder stopped writing and another instance reaped it (reason interrupted). |
turn.budget | a run of the step loop (turn.run, runTurnLoop) | The run’s budgetTokens (the policy’s, else the agent’s) is not an integer of at least 1. |
config.budget | Agent.define | The agent’s budgetTokens is not an integer of at least 1. |
turn.unstarted | the turn’s memory | Memory was asked to record, or for the turn’s number, before the user’s message was taken. |
turn.persisted | TurnMemory.persistMessage | The user’s message was taken twice in one turn. |
turn.numbering | the turn’s memory | Memory numbered the user’s message differently from the turn the session stored. |
events.reserved | publishing a host event | The host event’s name is one of the reserved kinds. |
events.depth | publishing an event | Reactions nested deeper than maxEventDepth (8 by default). |
events.background | a background subscription | A background handler died with a defect; the turn fails when the bus drains. |
events.encode | a host event’s make / publish | The payload did not encode with the host event’s schema. |
service.missing | Agent.turn | A service the turn needs is not provided by the agent’s plugins or the turn’s services. |
config.graph | Agent.define | The plugin graph cannot be built (a missing provider, a cycle, a misplaced turn-dependent plugin). |
config.options | Agent.define, activating a plugin | A plugin’s options did not decode with its schema. |
plugin.activation | activating a plugin (a session plugin’s, every turn) | The plugin’s layer failed to build with an error that is not a HarnessError (one that is keeps its own code: skills.duplicate, skills.root, …). |
plugin.defect | activating a plugin (a session plugin’s, every turn) | The plugin’s layer died with a defect while it was built. |
tools.duplicate | building the tool registry | Two capabilities define a tool of the same name. |
skills.duplicate | building the tool registry | Two capabilities define a skill with the same id (a host’s and a skills directory’s: set the directory’s idPrefix). |
skills.tools | building the tool registry | A skill names a tool no capability registers. |
skills.files | skillsFromFiles; @xandreed/plugin-workspace skills directory (strict) | A skills tree has an issue: a SKILL.md without frontmatter or description, an id already used, a reference over the size limit. The message names each file. |
skills.root | @xandreed/plugin-workspace skills directory | A required skills root does not exist, or a root or a file in it cannot be read. |
skills.limit | collectSkillFiles; @xandreed/plugin-workspace skills directory | A skills root holds more files (maxFiles) or text (maxBytes) than allowed, or the roots more skills than maxSkills. |
tools.opened | openTurnTools | The turn’s tools were opened twice. |
tools.unavailable | the turn’s tools | The tools were used before openTurnTools opened them. |
loop.model | the step loop | The turn’s services carry no LanguageModel. |
loop.failed | the step loop | The loop failed with an error that is not a HarnessError (the model call’s own error, for example); the message is that error’s text. |
request.encode | the turn, before each provider call | The request header did not encode. |
request.missing | before each provider call | No stored request.prepared header for the step. |
request.decode | before each provider call | The step’s stored request.prepared header did not decode. |
request.descriptor | before each provider call | The model’s descriptor (provider, model and settings) did not decode. |
request.diverged | before each provider call | The request about to be sent differs from the one rebuilt from its stored header and memory. |
request.model | @xandreed/plugin-models | The selected model could not be resolved or described. |
request.memory | replayModelRequest | The memory events before a stored request did not decode. |
memory.log | the turn | Stored memory events did not decode, or memory could not be stored. |
context.budget | each step of a run; @xandreed/plugin-memory-window | At a step, the system prompt and the active tools’ schemas leave nothing of the context budget (budgetTokens); with the window strategy, also when the current turn alone does not fit the budget memory is given: the whole budget at the turn’s start, what they leave at each step. |
session.log | the turn writer | The session store failed during the turn. |
session.contended | the turn writer, plugin-sessions | Too many conflicting writes to the session in a row. |
session.state | the turn writer | The session’s state, kept in its head, did not decode. |
session.encode | the turn writer | The turn’s closing turn.ended did not encode. |
Feed and socket frames
@xandreed/plugin-render turns a journal into client frames (RenderFeed); the host’s projection names each record’s event and data, and its cursor is the journal’s seq. Over SSE, each connection starts with the preamble; a record carries its sequence as the event id, so a reconnecting EventSource resumes with Last-Event-ID. One ready frame follows the backlog (the first poll that finds nothing new), then a heartbeat comment while the feed is idle. The feed ends after maxDurationMs, and the client reconnects with its cursor.
| Frame | SSE | WebSocket |
|---|---|---|
| preamble | "retry: 1000\n\n" | none |
| record | "id: 42\nevent: turn.reply\ndata: {\"outcome\":\"completed\",\"reply\":\"Done.\"}\n\n" | {"type":"record","sequence":42,"event":"turn.reply","data":{"outcome":"completed","reply":"Done."}} |
| ready | "event: ready\ndata: {}\n\n" | {"type":"ready"} |
| heartbeat | ": heartbeat\n\n" | {"type":"heartbeat"} |
| resume | the Last-Event-ID request header | the client’s first message, {"after":41} |
SSE response headers (sseHeaders):
{
"content-type": "text/event-stream; charset=utf-8",
"cache-control": "no-store",
"connection": "keep-alive",
"x-accel-buffering": "no"
}
Feed defaults (renderFeedDefaults, in milliseconds):
{
"pollMs": 200,
"maxPollMs": 1000,
"heartbeatMs": 15000,
"maxDurationMs": 240000
}
Task records
@xandreed/plugin-tasks records its own kinds (not reserved). A finished task is delivered to the parent’s inbox once, as inbox.queued with the id task:<taskId> and the source { kind: "task", taskId, child, status }.
| Kind | Recorded in | When |
|---|---|---|
task.started | the parent session | Tasks.start: the task’s instructions, mode and the starter’s facts; its child session is created with it. |
task.result | the child session | Before the child’s turn ends (or outside a turn when the host refused it): the outcome, reply and failure. |
task.cancelled | the child, then the parent | Tasks.cancel, while the task is pending or running; the first of a result and a cancellation ends the task. |
task.started
| Field | Type |
|---|---|
taskId | string |
instructions | string |
mode | "fork" | "spawn" |
meta | object |
task.result
| Field | Type |
|---|---|
taskId | string |
outcome | "completed" | "partial" | "failed" | "interrupted" |
reply | string | null |
failure | { code, message } | null |
task.cancelled
| Field | Type |
|---|---|
taskId | string |
Task failure codes
The code of a task result’s failure, or of a task’s status, besides any HarnessError code the task’s turn failed with.
| Code | Where | Meaning |
|---|---|---|
task.turn | a task’s result failure | The task’s turn failed, or died with an error that is not a HarnessError (a HarnessError keeps its own code). |
task.refused | a task’s result failure | The host would not admit the task’s turn. |
task.deadline | a task’s result or the parent’s reaction | The task runner’s deadline cut the work. |
task.lost | a task’s status | The task’s turn stopped without a result. |
task.removed | a task’s status | The task’s session was removed with its parent. |