SessionEvent
Category: Core
Source: session_event.dart
Sealed event hierarchy emitted by a running session.
Status: proposed (PR 2 of harness-layers plan). Not yet wired to consumers — see docs/plans/2026-04-29-harness-layers.md.
Design properties encoded here:
Permission and OAuth are events, not callbacks. The agent emits [PermissionRequestedEvent] and the surface responds via
session.dispatch(ResolvePermissionCommand(...)). Same for device-code OAuth. The agent never imports surface code.Subagents emit forwarded events. [SubagentEventForwardedEvent] carries an inner event. Surfaces decide whether to render inline (CLI does this) or in a separate pane (web could).
Sequence numbers are mandatory. Every event has a monotonic per-session [SessionEvent.sequence]. This is what makes "snapshot + subscribe" work without missing or duplicating events.
Enums
McpDisconnectReason
Why an MCP server disconnected. Drives the surface message and the reconnection state machine.
| Value | Description |
|---|---|
SSE | |
WebSocket | |
dropped | |
shutdown |
McpServerErrorKind
What flavour of error fired for [McpServerErrorEvent].
| Value | Description |
|---|---|
required | |
required | |
required | |
required | |
required | |
required | |
required |
RuntimeOutputStream
| Value | Description |
|---|---|
stdout | |
stderr |
RuntimeCancelReason
RuntimeContainerStopReason
AttachmentKind
| Value | Description |
|---|---|
image | |
pdf | |
text | |
binary |
ChunkKind
| Value | Description |
|---|---|
text | |
thinking | |
toolCallArgs |
ToolKind
| Value | Description |
|---|---|
read | |
write | |
exec | |
network | |
meta |
SessionStatus
| Value | Description |
|---|---|
idle | |
thinking | |
callingTool | |
awaitingPermission | |
completed | |
error |
TurnOutcome
| Value | Description |
|---|---|
completed | |
interrupted | |
errored |
ErrorCategory
| Value | Description |
|---|---|
provider | |
tool | |
runtime | |
internal |
PermissionScope
How long a permission grant applies.
Classes
sealed SessionEvent
Base type for all events emitted by a [Session].
Pattern-match with switch to handle each variant:
switch (event) {
AssistantChunkEvent(:final delta) => render(delta),
PermissionRequestedEvent() => showPermissionUi(event),
_ => null,
}Constructor
const SessionEvent({
required this.turnId,
required this.timestamp,
required this.sequence,
})Properties
| Property | Type | Description |
|---|---|---|
turnId | TurnId | The turn this event belongs to. A turn is one user-message → assistant-response cycle (which may include many tool calls). |
timestamp | DateTime | Wall-clock time the event was produced. |
sequence | int | Monotonic per-session sequence number. Surfaces use this to resume from a known position without missing or duplicating events. |
UserMessageEvent
User-authored input dispatched into a session.
Constructor
const UserMessageEvent({
required super.turnId,
required super.timestamp,
required super.sequence,
required this.text,
this.attachments = const [],
this.fileRefs = const [],
})Properties
| Property | Type | Description |
|---|---|---|
text | String | |
attachments | List<Attachment> | |
fileRefs | List<FileReference> | @file expansions resolved at dispatch time. |
AssistantThinkingStartedEvent
The model has begun producing thinking tokens (if exposed).
Constructor
const AssistantThinkingStartedEvent({
required super.turnId,
required super.timestamp,
required super.sequence,
})AssistantChunkEvent
A streamed delta from the model — text, thinking, or tool-call args.
Constructor
const AssistantChunkEvent({
required super.turnId,
required super.timestamp,
required super.sequence,
required this.delta,
required this.kind,
})Properties
| Property | Type | Description |
|---|---|---|
delta | String | |
kind | ChunkKind |
AssistantMessageEvent
The model finished producing a complete assistant message for this turn.
Constructor
const AssistantMessageEvent({
required super.turnId,
required super.timestamp,
required super.sequence,
required this.text,
required this.usage,
required this.elapsed,
})Properties
| Property | Type | Description |
|---|---|---|
text | String | |
usage | TokenUsage | |
elapsed | Duration |
AssistantThinkingCompletedEvent
The model finished producing thinking tokens.
Constructor
const AssistantThinkingCompletedEvent({
required super.turnId,
required super.timestamp,
required super.sequence,
required this.usage,
this.summary,
})Properties
| Property | Type | Description |
|---|---|---|
summary | String? | Some providers expose a thinking summary; null if not. |
usage | TokenUsage |
ToolCallStartedEvent
A tool call has begun executing (after permission, if applicable).
Constructor
const ToolCallStartedEvent({
required super.turnId,
required super.timestamp,
required super.sequence,
required this.id,
required this.tool,
required this.args,
required this.kind,
})Properties
| Property | Type | Description |
|---|---|---|
id | ToolCallId | |
tool | String | |
args | Map<String, Object?> | |
kind | ToolKind |
ToolCallProgressEvent
Optional progress update emitted while a tool is running.
Constructor
const ToolCallProgressEvent({
required super.turnId,
required super.timestamp,
required super.sequence,
required this.id,
required this.message,
this.percentComplete,
})Properties
| Property | Type | Description |
|---|---|---|
id | ToolCallId | |
message | String | |
percentComplete | double? |
ToolCallCompletedEvent
A tool call finished — either successfully, with an error, or cancelled.
Constructor
const ToolCallCompletedEvent({
required super.turnId,
required super.timestamp,
required super.sequence,
required this.id,
required this.result,
required this.elapsed,
})Properties
| Property | Type | Description |
|---|---|---|
id | ToolCallId | |
result | ToolResultSnapshot | |
elapsed | Duration |
PermissionRequestedEvent
The agent needs the user's permission to proceed with a tool call.
The surface responds by dispatching a ResolvePermissionCommand with the same [requestId].
Constructor
const PermissionRequestedEvent({
required super.turnId,
required super.timestamp,
required super.sequence,
required this.requestId,
required this.toolCallId,
required this.scope,
required this.summary,
required this.dangerLevel,
})Properties
| Property | Type | Description |
|---|---|---|
requestId | PermissionRequestId | |
toolCallId | ToolCallId | |
scope | PermissionScope | |
summary | String | |
dangerLevel | ToolKind |
PermissionResolvedEvent
The user resolved a pending permission request.
Constructor
const PermissionResolvedEvent({
required super.turnId,
required super.timestamp,
required super.sequence,
required this.requestId,
required this.granted,
required this.appliedScope,
})Properties
| Property | Type | Description |
|---|---|---|
requestId | PermissionRequestId | |
granted | bool | |
appliedScope | PermissionScope |
SubagentSpawnedEvent
The agent spawned a subagent. Subsequent events from that subagent arrive wrapped in [SubagentEventForwardedEvent].
Constructor
const SubagentSpawnedEvent({
required super.turnId,
required super.timestamp,
required super.sequence,
required this.childId,
required this.childSessionId,
required this.task,
required this.model,
})Properties
| Property | Type | Description |
|---|---|---|
childId | SubagentId | |
childSessionId | SessionId | |
task | String | |
model | ModelRef |
SubagentEventForwardedEvent
An event emitted by a subagent, forwarded to the parent stream.
Surfaces choose to render [inner] inline (CLI today) or in a separate pane (a future web client could).
Constructor
const SubagentEventForwardedEvent({
required super.turnId,
required super.timestamp,
required super.sequence,
required this.childId,
required this.inner,
})Properties
| Property | Type | Description |
|---|---|---|
childId | SubagentId | |
inner | SessionEvent |
SubagentCompletedEvent
A subagent finished — emitted on the parent stream.
Constructor
const SubagentCompletedEvent({
required super.turnId,
required super.timestamp,
required super.sequence,
required this.childId,
required this.usage,
required this.elapsed,
this.finalMessage,
})Properties
| Property | Type | Description |
|---|---|---|
childId | SubagentId | |
finalMessage | String? | |
usage | TokenUsage | |
elapsed | Duration |
DeviceCodeRequestedEvent
A device-code OAuth flow has produced a code the user must enter.
The surface displays [code] + [verificationUrl], waits for the user to complete the flow in their browser, and dispatches ResolveDeviceCodeCommand.
Constructor
const DeviceCodeRequestedEvent({
required super.turnId,
required super.timestamp,
required super.sequence,
required this.code,
required this.verificationUrl,
required this.expiresIn,
})Properties
| Property | Type | Description |
|---|---|---|
code | String | |
verificationUrl | String | |
expiresIn | Duration |
DeviceCodeResolvedEvent
The OAuth flow completed (success or failure).
Constructor
const DeviceCodeResolvedEvent({
required super.turnId,
required super.timestamp,
required super.sequence,
required this.success,
this.errorMessage,
})Properties
| Property | Type | Description |
|---|---|---|
success | bool | |
errorMessage | String? |
TurnStartedEvent
A new turn started.
Constructor
const TurnStartedEvent({
required super.turnId,
required super.timestamp,
required super.sequence,
required this.model,
})Properties
| Property | Type | Description |
|---|---|---|
id | TurnId get | Equal to [SessionEvent.turnId]; included for ergonomics in switch arms. |
model | ModelRef | |
id | TurnId get | Equal to [SessionEvent.turnId]; included for ergonomics in switch arms. |
TurnCompletedEvent
The current turn finished — completed normally, was interrupted, or errored.
Constructor
const TurnCompletedEvent({
required super.turnId,
required super.timestamp,
required super.sequence,
required this.outcome,
required this.usage,
})Properties
| Property | Type | Description |
|---|---|---|
id | TurnId get | |
outcome | TurnOutcome | |
usage | TokenUsage | |
id | TurnId get |
StatusChangeEvent
The session's high-level status changed.
Constructor
const StatusChangeEvent({
required super.turnId,
required super.timestamp,
required super.sequence,
required this.from,
required this.to,
})Properties
| Property | Type | Description |
|---|---|---|
from | SessionStatus | |
to | SessionStatus |
TitleGeneratedEvent
A title was generated for this session (typically after the first turn).
Constructor
const TitleGeneratedEvent({
required super.turnId,
required super.timestamp,
required super.sequence,
required this.title,
})Properties
| Property | Type | Description |
|---|---|---|
title | String |
MetricsUpdatedEvent
Session metrics were refreshed.
Constructor
const MetricsUpdatedEvent({
required super.turnId,
required super.timestamp,
required super.sequence,
required this.current,
})Properties
| Property | Type | Description |
|---|---|---|
current | SessionMetricsSnapshot |
ErrorEvent
An error occurred. May or may not be recoverable.
Constructor
const ErrorEvent({
required super.turnId,
required super.timestamp,
required super.sequence,
required this.message,
required this.category,
required this.recoverable,
this.stackTrace,
})Properties
| Property | Type | Description |
|---|---|---|
message | String | |
category | ErrorCategory | |
recoverable | bool | |
stackTrace | StackTrace? | Null in production builds. |
McpServerConnectedEvent
An MCP server completed the initialize handshake and its tools are available to the agent.
Constructor
const McpServerConnectedEvent({
required super.turnId,
required super.timestamp,
required super.sequence,
required this.serverId,
required this.serverName,
required this.serverVersion,
required this.toolNames,
})Properties
| Property | Type | Description |
|---|---|---|
serverId | String | Local config id for the server (the user's chosen name). |
serverName | String | Server-reported name (from initialize → serverInfo.name). |
serverVersion | String | Server-reported version. |
toolNames | List<String> | Namespaced tool names registered with the agent (<serverId>.<tool>). |
serverId | String | |
reason | McpDisconnectReason | |
reconnectAttempt | int | 0 when not retrying (e.g. clean shutdown or dead). |
nextAttemptIn | Duration | Duration.zero when not retrying. |
serverId | String | |
kind | McpServerErrorKind | |
message | String | |
serverId | String | |
reauthCommand | String | Shell command the user should run (or that the TUI can trigger via a modal-confirmed action). e.g. glue mcp auth login notion. |
serverId | String | |
added | List<String> | Namespaced tool names that appeared since the last tools/list. |
removed | List<String> | Namespaced tool names that disappeared. |
runtimeId | String | Identifier of the runtime running this command: 'host', 'docker', 'daytona', … |
commandId | String | Per-session-unique id for correlating this event with later progress / completion / cancellation events. Distinct from [SessionEvent.sequence], which is monotonic across the whole session. |
command | String | The command line as dispatched (may be redacted/truncated by the emitter — surfaces should treat it as a display string, not a fully reconstructible value). |
runtimeCwd | String | The directory inside the runtime where the command will execute (e.g. /workspace for Docker / cloud, or the host cwd otherwise). |
sessionScopedId | String? | Cloud-side session id (e.g. a Daytona sandboxId), when relevant. |
commandId | String | |
stream | RuntimeOutputStream | |
text | String | |
commandId | String | |
exitCode | int | |
duration | Duration | |
stdoutBytes | int? | Total bytes emitted on stdout, when known. Useful for surfaces that want to elide huge outputs. |
stderrBytes | int? | |
commandId | String | |
errorType | String | |
message | String | |
commandId | String | |
reason | RuntimeCancelReason | |
runtimeId | String | |
containerId | String | |
image | String? | |
runtimeId | String | |
containerId | String | |
reason | RuntimeContainerStopReason | |
kind | AttachmentKind | |
bytes | List<int> | |
mimeType | String? | |
filename | String? | |
path | String | |
absolutePath | String | |
promptTokens | int | |
completionTokens | int | |
cachedTokens | int | Tokens served from prompt cache (provider-dependent). |
estimatedCostUsd | double | Cost estimate in USD. May be 0.0 when pricing is unavailable. |
turnCount | int | |
usage | TokenUsage | |
totalElapsed | Duration |
Methods
`const McpServerDisconnectedEvent({
required super.turnId,
required super.timestamp,
required super.sequence,
required this.serverId,
required this.reason,
this.reconnectAttempt = 0,
this.nextAttemptIn = Duration.zero,
})`
`const McpServerErrorEvent({
required super.turnId,
required super.timestamp,
required super.sequence,
required this.serverId,
required this.kind,
required this.message,
})`
`const McpServerAuthRequiredEvent({
required super.turnId,
required super.timestamp,
required super.sequence,
required this.serverId,
required this.reauthCommand,
})`
`const McpToolListChangedEvent({
required super.turnId,
required super.timestamp,
required super.sequence,
required this.serverId,
required this.added,
required this.removed,
})`
`const RuntimeCommandStartedEvent({
required super.turnId,
required super.timestamp,
required super.sequence,
required this.runtimeId,
required this.commandId,
required this.command,
required this.runtimeCwd,
this.sessionScopedId,
})`
`const RuntimeCommandOutputEvent({
required super.turnId,
required super.timestamp,
required super.sequence,
required this.commandId,
required this.stream,
required this.text,
})`
`const RuntimeCommandCompletedEvent({
required super.turnId,
required super.timestamp,
required super.sequence,
required this.commandId,
required this.exitCode,
required this.duration,
this.stdoutBytes,
this.stderrBytes,
})`
`const RuntimeCommandFailedEvent({
required super.turnId,
required super.timestamp,
required super.sequence,
required this.commandId,
required this.errorType,
required this.message,
})`
`const RuntimeCommandCancelledEvent({
required super.turnId,
required super.timestamp,
required super.sequence,
required this.commandId,
required this.reason,
})`
`const RuntimeContainerStartedEvent({
required super.turnId,
required super.timestamp,
required super.sequence,
required this.runtimeId,
required this.containerId,
this.image,
})`
`const RuntimeContainerStoppedEvent({
required super.turnId,
required super.timestamp,
required super.sequence,
required this.runtimeId,
required this.containerId,
required this.reason,
})`
`const Attachment({
required this.kind,
required this.bytes,
this.mimeType,
this.filename,
})`
`const FileReference({
required this.path,
required this.absolutePath,
this.lineRange,
})`
`const TokenUsage({
required this.promptTokens,
required this.completionTokens,
this.cachedTokens = 0,
this.estimatedCostUsd = 0.0,
})`
`const SessionMetricsSnapshot({
required this.turnCount,
required this.usage,
required this.totalElapsed,
})`
McpServerDisconnectedEvent
An MCP server's connection has dropped — possibly transiently. If [reconnectAttempt] is > 0 the pool is retrying after [nextAttemptIn]. If [reason] is [McpDisconnectReason.dead], the pool has given up.
Constructor
const McpServerDisconnectedEvent({
required super.turnId,
required super.timestamp,
required super.sequence,
required this.serverId,
required this.reason,
this.reconnectAttempt = 0,
this.nextAttemptIn = Duration.zero,
})Properties
| Property | Type | Description |
|---|---|---|
serverId | String | |
reason | McpDisconnectReason | |
reconnectAttempt | int | 0 when not retrying (e.g. clean shutdown or dead). |
nextAttemptIn | Duration | Duration.zero when not retrying. |
McpServerErrorEvent
An error specific to the MCP server lifecycle (not a tool-call error, which surfaces as [ToolCallCompletedEvent] with an error snapshot).
Constructor
const McpServerErrorEvent({
required super.turnId,
required super.timestamp,
required super.sequence,
required this.serverId,
required this.kind,
required this.message,
})Properties
| Property | Type | Description |
|---|---|---|
serverId | String | |
kind | McpServerErrorKind | |
message | String |
McpServerAuthRequiredEvent
The server needs the user to re-authorise (OAuth refresh failed or bearer was rejected). The surface should display [reauthCommand] and pause the server until [reauthCommand] (or equivalent) completes.
Constructor
const McpServerAuthRequiredEvent({
required super.turnId,
required super.timestamp,
required super.sequence,
required this.serverId,
required this.reauthCommand,
})Properties
| Property | Type | Description |
|---|---|---|
serverId | String | |
reauthCommand | String | Shell command the user should run (or that the TUI can trigger via a modal-confirmed action). e.g. glue mcp auth login notion. |
McpToolListChangedEvent
The server's tool list changed mid-session (via the notifications/tools/list_changed protocol message).
Constructor
const McpToolListChangedEvent({
required super.turnId,
required super.timestamp,
required super.sequence,
required this.serverId,
required this.added,
required this.removed,
})Properties
| Property | Type | Description |
|---|---|---|
serverId | String | |
added | List<String> | Namespaced tool names that appeared since the last tools/list. |
removed | List<String> | Namespaced tool names that disappeared. |
RuntimeCommandStartedEvent
A command has been dispatched to a runtime and is starting.
Constructor
const RuntimeCommandStartedEvent({
required super.turnId,
required super.timestamp,
required super.sequence,
required this.runtimeId,
required this.commandId,
required this.command,
required this.runtimeCwd,
this.sessionScopedId,
})Properties
| Property | Type | Description |
|---|---|---|
runtimeId | String | Identifier of the runtime running this command: 'host', 'docker', 'daytona', … |
commandId | String | Per-session-unique id for correlating this event with later progress / completion / cancellation events. Distinct from [SessionEvent.sequence], which is monotonic across the whole session. |
command | String | The command line as dispatched (may be redacted/truncated by the emitter — surfaces should treat it as a display string, not a fully reconstructible value). |
runtimeCwd | String | The directory inside the runtime where the command will execute (e.g. /workspace for Docker / cloud, or the host cwd otherwise). |
sessionScopedId | String? | Cloud-side session id (e.g. a Daytona sandboxId), when relevant. |
RuntimeCommandOutputEvent
Streamed output bytes from a running runtime command.
Optional/high-volume — emitters may suppress this for short commands or gate it behind a debug flag.
Constructor
const RuntimeCommandOutputEvent({
required super.turnId,
required super.timestamp,
required super.sequence,
required this.commandId,
required this.stream,
required this.text,
})Properties
| Property | Type | Description |
|---|---|---|
commandId | String | |
stream | RuntimeOutputStream | |
text | String |
RuntimeCommandCompletedEvent
A runtime command finished normally with an [exitCode]. Non-zero exit codes are not errors — they're the program's own failure signal. Use [RuntimeCommandFailedEvent] for transport-level errors.
Constructor
const RuntimeCommandCompletedEvent({
required super.turnId,
required super.timestamp,
required super.sequence,
required this.commandId,
required this.exitCode,
required this.duration,
this.stdoutBytes,
this.stderrBytes,
})Properties
| Property | Type | Description |
|---|---|---|
commandId | String | |
exitCode | int | |
duration | Duration | |
stdoutBytes | int? | Total bytes emitted on stdout, when known. Useful for surfaces that want to elide huge outputs. |
stderrBytes | int? |
RuntimeCommandFailedEvent
A runtime command failed at the transport or runtime layer (i.e. the runtime couldn't run it at all, or lost connection). Distinct from a non-zero exit code, which is [RuntimeCommandCompletedEvent].
Constructor
const RuntimeCommandFailedEvent({
required super.turnId,
required super.timestamp,
required super.sequence,
required this.commandId,
required this.errorType,
required this.message,
})Properties
| Property | Type | Description |
|---|---|---|
commandId | String | |
errorType | String | |
message | String |
RuntimeCommandCancelledEvent
A runtime command was cancelled by the harness (timeout, /cancel, shutdown) before it finished.
Constructor
const RuntimeCommandCancelledEvent({
required super.turnId,
required super.timestamp,
required super.sequence,
required this.commandId,
required this.reason,
})Properties
| Property | Type | Description |
|---|---|---|
commandId | String | |
reason | RuntimeCancelReason |
RuntimeContainerStartedEvent
A runtime container (Docker / cloud sandbox) was started for the session. Host runtimes don't emit this — there's no container.
Constructor
const RuntimeContainerStartedEvent({
required super.turnId,
required super.timestamp,
required super.sequence,
required this.runtimeId,
required this.containerId,
this.image,
})Properties
| Property | Type | Description |
|---|---|---|
runtimeId | String | |
containerId | String | |
image | String? |
RuntimeContainerStoppedEvent
A runtime container was stopped (either normally on session end, or because of a failure / cancellation).
Constructor
const RuntimeContainerStoppedEvent({
required super.turnId,
required super.timestamp,
required super.sequence,
required this.runtimeId,
required this.containerId,
required this.reason,
})Properties
| Property | Type | Description |
|---|---|---|
runtimeId | String | |
containerId | String | |
reason | RuntimeContainerStopReason |
Attachment
A non-text input attached to a user message.
Constructor
const Attachment({
required this.kind,
required this.bytes,
this.mimeType,
this.filename,
})Properties
| Property | Type | Description |
|---|---|---|
kind | AttachmentKind | |
bytes | List<int> | |
mimeType | String? | |
filename | String? |
FileReference
A reference to a file in the project (the result of @file expansion).
Constructor
const FileReference({
required this.path,
required this.absolutePath,
this.lineRange,
})Properties
| Property | Type | Description |
|---|---|---|
path | String | |
absolutePath | String |
TokenUsage
Constructor
const TokenUsage({
required this.promptTokens,
required this.completionTokens,
this.cachedTokens = 0,
this.estimatedCostUsd = 0.0,
})Properties
| Property | Type | Description |
|---|---|---|
promptTokens | int | |
completionTokens | int | |
cachedTokens | int | Tokens served from prompt cache (provider-dependent). |
estimatedCostUsd | double | Cost estimate in USD. May be 0.0 when pricing is unavailable. |
SessionMetricsSnapshot
Constructor
const SessionMetricsSnapshot({
required this.turnCount,
required this.usage,
required this.totalElapsed,
})Properties
| Property | Type | Description |
|---|---|---|
turnCount | int | |
usage | TokenUsage | |
totalElapsed | Duration |
sealed ToolResultSnapshot
A serializable snapshot of a [ToolCall]'s outcome. The runtime tool result type lives elsewhere; this is the on-the-wire / on-disk shape.
Constructor
const ToolResultSnapshot({required this.id, required this.elapsed})Properties
| Property | Type | Description |
|---|---|---|
id | ToolCallId | |
elapsed | Duration |
ToolOkSnapshot
Constructor
const ToolOkSnapshot({
required super.id,
required super.elapsed,
required this.contentSummary,
})Properties
| Property | Type | Description |
|---|---|---|
contentSummary | String | Human-readable summary; the full content is the tool's own concern. |
message | String | |
category | ErrorCategory | |
retryable | bool |
Methods
`const ToolErrorSnapshot({
required super.id,
required super.elapsed,
required this.message,
required this.category,
required this.retryable,
})`
const ToolCancelledSnapshot({required super.id, required super.elapsed})
ToolErrorSnapshot
Constructor
const ToolErrorSnapshot({
required super.id,
required super.elapsed,
required this.message,
required this.category,
required this.retryable,
})Properties
| Property | Type | Description |
|---|---|---|
message | String | |
category | ErrorCategory | |
retryable | bool |
ToolCancelledSnapshot
Constructor
const ToolCancelledSnapshot({required super.id, required super.elapsed})