ahp_types/actions.rs
1// Generated from types/*.ts — do not edit.
2//
3// Regenerate with: npm run generate:rust
4
5#![allow(missing_docs)]
6
7#[allow(unused_imports)]
8use crate::common::{AnyValue, JsonObject, StringOrMarkdown, Uri};
9#[allow(unused_imports)]
10use serde::{Deserialize, Serialize};
11#[allow(unused_imports)]
12use serde_repr::{Deserialize_repr, Serialize_repr};
13
14#[allow(unused_imports)]
15use crate::state::{
16 AgentInfo, AgentSelection, Annotation, AnnotationEntry, Changeset, ChangesetFile,
17 ChangesetOperation, ChangesetOperationStatus, ChangesetStatus, ChatInputAnswer,
18 ChatInputRequest, ChatInputResponseKind, ChatInteractivity, ChatOrigin, ChatSummary,
19 ConfirmationOption, Customization, ErrorInfo, McpAuthRequirement, McpServerState, Message,
20 ModelSelection, PendingMessageKind, ResponsePart, SessionActiveClient, SessionInputRequest,
21 TerminalClaim, TerminalInfo, TextRange, ToolCallCancellationReason, ToolCallConfirmationReason,
22 ToolCallContributor, ToolCallResult, ToolCallRiskAssessment, ToolDefinition, ToolResultContent,
23 Turn, UsageInfo,
24};
25
26// ─── ActionType ──────────────────────────────────────────────────────
27
28/// Discriminant values for all state actions.
29#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
30pub enum ActionType {
31 #[serde(rename = "root/agentsChanged")]
32 RootAgentsChanged,
33 #[serde(rename = "root/activeSessionsChanged")]
34 RootActiveSessionsChanged,
35 #[serde(rename = "session/ready")]
36 SessionReady,
37 #[serde(rename = "session/creationFailed")]
38 SessionCreationFailed,
39 #[serde(rename = "session/chatAdded")]
40 SessionChatAdded,
41 #[serde(rename = "session/chatRemoved")]
42 SessionChatRemoved,
43 #[serde(rename = "session/chatUpdated")]
44 SessionChatUpdated,
45 #[serde(rename = "session/defaultChatChanged")]
46 SessionDefaultChatChanged,
47 #[serde(rename = "chat/turnStarted")]
48 ChatTurnStarted,
49 #[serde(rename = "chat/delta")]
50 ChatDelta,
51 #[serde(rename = "chat/responsePart")]
52 ChatResponsePart,
53 #[serde(rename = "chat/toolCallStart")]
54 ChatToolCallStart,
55 #[serde(rename = "chat/toolCallDelta")]
56 ChatToolCallDelta,
57 #[serde(rename = "chat/toolCallReady")]
58 ChatToolCallReady,
59 #[serde(rename = "chat/toolCallConfirmed")]
60 ChatToolCallConfirmed,
61 #[serde(rename = "chat/toolCallComplete")]
62 ChatToolCallComplete,
63 #[serde(rename = "chat/toolCallResultConfirmed")]
64 ChatToolCallResultConfirmed,
65 #[serde(rename = "chat/toolCallContentChanged")]
66 ChatToolCallContentChanged,
67 #[serde(rename = "chat/toolCallAuthRequired")]
68 ChatToolCallAuthRequired,
69 #[serde(rename = "chat/toolCallAuthResolved")]
70 ChatToolCallAuthResolved,
71 #[serde(rename = "chat/turnComplete")]
72 ChatTurnComplete,
73 #[serde(rename = "chat/turnCancelled")]
74 ChatTurnCancelled,
75 #[serde(rename = "chat/error")]
76 ChatError,
77 #[serde(rename = "chat/activityChanged")]
78 ChatActivityChanged,
79 #[serde(rename = "session/titleChanged")]
80 SessionTitleChanged,
81 #[serde(rename = "chat/usage")]
82 ChatUsage,
83 #[serde(rename = "chat/reasoning")]
84 ChatReasoning,
85 #[serde(rename = "session/serverToolsChanged")]
86 SessionServerToolsChanged,
87 #[serde(rename = "session/activeClientSet")]
88 SessionActiveClientSet,
89 #[serde(rename = "session/activeClientRemoved")]
90 SessionActiveClientRemoved,
91 #[serde(rename = "session/inputNeededSet")]
92 SessionInputNeededSet,
93 #[serde(rename = "session/inputNeededRemoved")]
94 SessionInputNeededRemoved,
95 #[serde(rename = "chat/pendingMessageSet")]
96 ChatPendingMessageSet,
97 #[serde(rename = "chat/pendingMessageRemoved")]
98 ChatPendingMessageRemoved,
99 #[serde(rename = "chat/queuedMessagesReordered")]
100 ChatQueuedMessagesReordered,
101 #[serde(rename = "chat/draftChanged")]
102 ChatDraftChanged,
103 #[serde(rename = "chat/inputRequested")]
104 ChatInputRequested,
105 #[serde(rename = "chat/inputAnswerChanged")]
106 ChatInputAnswerChanged,
107 #[serde(rename = "chat/inputCompleted")]
108 ChatInputCompleted,
109 #[serde(rename = "session/customizationsChanged")]
110 SessionCustomizationsChanged,
111 #[serde(rename = "session/customizationToggled")]
112 SessionCustomizationToggled,
113 #[serde(rename = "session/customizationUpdated")]
114 SessionCustomizationUpdated,
115 #[serde(rename = "session/customizationRemoved")]
116 SessionCustomizationRemoved,
117 #[serde(rename = "session/mcpServerStateChanged")]
118 SessionMcpServerStateChanged,
119 #[serde(rename = "session/mcpServerStartRequested")]
120 SessionMcpServerStartRequested,
121 #[serde(rename = "session/mcpServerStopRequested")]
122 SessionMcpServerStopRequested,
123 #[serde(rename = "chat/truncated")]
124 ChatTruncated,
125 #[serde(rename = "chat/turnsLoaded")]
126 ChatTurnsLoaded,
127 #[serde(rename = "session/isReadChanged")]
128 SessionIsReadChanged,
129 #[serde(rename = "session/isArchivedChanged")]
130 SessionIsArchivedChanged,
131 #[serde(rename = "session/activityChanged")]
132 SessionActivityChanged,
133 #[serde(rename = "session/changesetsChanged")]
134 SessionChangesetsChanged,
135 #[serde(rename = "session/configChanged")]
136 SessionConfigChanged,
137 #[serde(rename = "session/metaChanged")]
138 SessionMetaChanged,
139 #[serde(rename = "changeset/statusChanged")]
140 ChangesetStatusChanged,
141 #[serde(rename = "changeset/fileSet")]
142 ChangesetFileSet,
143 #[serde(rename = "changeset/fileRemoved")]
144 ChangesetFileRemoved,
145 #[serde(rename = "changeset/filesReviewChanged")]
146 ChangesetFilesReviewChanged,
147 #[serde(rename = "changeset/contentChanged")]
148 ChangesetContentChanged,
149 #[serde(rename = "changeset/operationsChanged")]
150 ChangesetOperationsChanged,
151 #[serde(rename = "changeset/operationStatusChanged")]
152 ChangesetOperationStatusChanged,
153 #[serde(rename = "changeset/cleared")]
154 ChangesetCleared,
155 #[serde(rename = "annotations/set")]
156 AnnotationsSet,
157 #[serde(rename = "annotations/updated")]
158 AnnotationsUpdated,
159 #[serde(rename = "annotations/removed")]
160 AnnotationsRemoved,
161 #[serde(rename = "annotations/entrySet")]
162 AnnotationsEntrySet,
163 #[serde(rename = "annotations/entryRemoved")]
164 AnnotationsEntryRemoved,
165 #[serde(rename = "root/terminalsChanged")]
166 RootTerminalsChanged,
167 #[serde(rename = "root/configChanged")]
168 RootConfigChanged,
169 #[serde(rename = "terminal/data")]
170 TerminalData,
171 #[serde(rename = "terminal/input")]
172 TerminalInput,
173 #[serde(rename = "terminal/resized")]
174 TerminalResized,
175 #[serde(rename = "terminal/claimed")]
176 TerminalClaimed,
177 #[serde(rename = "terminal/titleChanged")]
178 TerminalTitleChanged,
179 #[serde(rename = "terminal/cwdChanged")]
180 TerminalCwdChanged,
181 #[serde(rename = "terminal/exited")]
182 TerminalExited,
183 #[serde(rename = "terminal/cleared")]
184 TerminalCleared,
185 #[serde(rename = "terminal/commandDetectionAvailable")]
186 TerminalCommandDetectionAvailable,
187 #[serde(rename = "terminal/commandExecuted")]
188 TerminalCommandExecuted,
189 #[serde(rename = "terminal/commandFinished")]
190 TerminalCommandFinished,
191 #[serde(rename = "resourceWatch/changed")]
192 ResourceWatchChanged,
193}
194
195// ─── Action Envelope ─────────────────────────────────────────────────
196
197/// Identifies the client that originally dispatched an action.
198#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
199#[serde(rename_all = "camelCase")]
200pub struct ActionOrigin {
201 pub client_id: String,
202 pub client_seq: i64,
203}
204
205/// Every action is wrapped in an `ActionEnvelope`.
206///
207/// The envelope identifies the channel the action belongs to (e.g.
208/// `ahp-root://` for root actions, the session URI for session actions, the
209/// terminal URI for terminal actions). Individual action payloads carry only
210/// fields that are intrinsic to the action; the channel comes from the
211/// envelope so that any subscribable resource can route its actions uniformly.
212#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
213#[serde(rename_all = "camelCase")]
214pub struct ActionEnvelope {
215 /// Channel URI this action belongs to.
216 pub channel: Uri,
217 pub action: StateAction,
218 pub server_seq: u64,
219 #[serde(default, skip_serializing_if = "Option::is_none")]
220 pub origin: Option<ActionOrigin>,
221 #[serde(default, skip_serializing_if = "Option::is_none")]
222 pub rejection_reason: Option<String>,
223}
224
225// ─── Action Payloads ─────────────────────────────────────────────────
226
227/// Fired when available agent backends or their models change.
228#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
229#[serde(rename_all = "camelCase")]
230pub struct RootAgentsChangedAction {
231 /// Updated agent list
232 pub agents: Vec<AgentInfo>,
233}
234
235/// Fired when the number of active sessions changes.
236#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
237#[serde(rename_all = "camelCase")]
238pub struct RootActiveSessionsChangedAction {
239 /// Current count of active sessions
240 pub active_sessions: i64,
241}
242
243/// Fired when agent-host configuration values change.
244///
245/// By default, the reducer merges the new values into `state.config.values`.
246/// Set `replace` to `true` to replace all values instead of merging.
247#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
248#[serde(rename_all = "camelCase")]
249pub struct RootConfigChangedAction {
250 /// Updated config values
251 pub config: JsonObject,
252 /// When `true`, replaces all config values instead of merging
253 #[serde(default, skip_serializing_if = "Option::is_none")]
254 pub replace: Option<bool>,
255}
256
257/// Session backend initialized successfully.
258#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
259#[serde(rename_all = "camelCase")]
260pub struct SessionReadyAction {}
261
262/// Session backend failed to initialize.
263#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
264#[serde(rename_all = "camelCase")]
265pub struct SessionCreationFailedAction {
266 /// Error details
267 pub error: ErrorInfo,
268}
269
270/// A chat was added to this session's catalog. Upsert semantics: if a chat
271/// with the same `summary.resource` already exists, the existing entry is
272/// replaced.
273///
274/// Mirrors the root-channel `root/sessionAdded` notification.
275#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
276#[serde(rename_all = "camelCase")]
277pub struct SessionChatAddedAction {
278 /// The full summary of the newly added (or upserted) chat.
279 pub summary: ChatSummary,
280}
281
282/// A chat was removed from this session's catalog. No-op when no entry matches.
283///
284/// Mirrors the root-channel `root/sessionRemoved` notification.
285#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
286#[serde(rename_all = "camelCase")]
287pub struct SessionChatRemovedAction {
288 /// The URI of the chat to remove.
289 pub chat: Uri,
290}
291
292/// One existing chat's summary fields changed.
293///
294/// Partial-update semantics: only fields present in `changes` are written;
295/// omitted fields are preserved. Identity fields (`resource`) MUST NOT be
296/// carried in `changes`. No-op when no entry with `chat` exists — clients
297/// SHOULD then wait for a {@link SessionChatAddedAction | `session/chatAdded`}.
298///
299/// Mirrors the root-channel `root/sessionSummaryChanged` notification.
300#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
301#[serde(rename_all = "camelCase")]
302pub struct SessionChatUpdatedAction {
303 /// The URI of the chat whose summary changed.
304 pub chat: Uri,
305 /// Mutable summary fields that changed; omitted fields are unchanged.
306 ///
307 /// Identity fields (`resource`) never change and MUST be omitted by
308 /// senders; receivers SHOULD ignore them if present.
309 pub changes: PartialChatSummary,
310}
311
312/// The default chat input-routing hint for this session changed.
313#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Default)]
314#[serde(rename_all = "camelCase")]
315pub struct SessionDefaultChatChangedAction {
316 /// New default chat URI, or `undefined` to clear the hint.
317 #[serde(default, skip_serializing_if = "Option::is_none")]
318 pub default_chat: Option<Uri>,
319}
320
321/// A new message has been sent to the agent, and a new turn starts.
322///
323/// A client is only allowed to send {@link MessageKind.User} messages.
324#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
325#[serde(rename_all = "camelCase")]
326pub struct ChatTurnStartedAction {
327 /// Turn identifier
328 pub turn_id: String,
329 /// ISO 8601 timestamp when this turn started.
330 pub started_at: String,
331 /// The new message
332 pub message: Message,
333 /// If this turn was auto-started from a queued message, the ID of that message
334 #[serde(default, skip_serializing_if = "Option::is_none")]
335 pub queued_message_id: Option<String>,
336 /// Additional provider-specific metadata for this action.
337 ///
338 /// Clients MAY look for well-known keys here to provide enhanced UI, and
339 /// agent hosts MAY use it to carry per-event context that does not fit any
340 /// other field — for example, attributing the event to a specific agent
341 /// (such as a sub-agent acting within the turn). Mirrors the MCP `_meta`
342 /// convention.
343 #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
344 pub meta: Option<JsonObject>,
345}
346
347/// Streaming text chunk from the assistant, appended to a specific response part.
348///
349/// The server MUST first emit a `chat/responsePart` to create the target
350/// part (markdown or reasoning), then use this action to append text to it.
351#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
352#[serde(rename_all = "camelCase")]
353pub struct ChatDeltaAction {
354 /// Turn identifier
355 pub turn_id: String,
356 /// Identifier of the response part to append to
357 pub part_id: String,
358 /// Text chunk
359 pub content: String,
360 /// Additional provider-specific metadata for this action.
361 ///
362 /// Clients MAY look for well-known keys here to provide enhanced UI, and
363 /// agent hosts MAY use it to carry per-event context that does not fit any
364 /// other field — for example, attributing the event to a specific agent
365 /// (such as a sub-agent acting within the turn). Mirrors the MCP `_meta`
366 /// convention.
367 #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
368 pub meta: Option<JsonObject>,
369}
370
371/// Structured content appended to the response.
372#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
373#[serde(rename_all = "camelCase")]
374pub struct ChatResponsePartAction {
375 /// Turn identifier
376 pub turn_id: String,
377 /// Response part (markdown or content ref)
378 pub part: ResponsePart,
379 /// Additional provider-specific metadata for this action.
380 ///
381 /// Clients MAY look for well-known keys here to provide enhanced UI, and
382 /// agent hosts MAY use it to carry per-event context that does not fit any
383 /// other field — for example, attributing the event to a specific agent
384 /// (such as a sub-agent acting within the turn). Mirrors the MCP `_meta`
385 /// convention.
386 #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
387 pub meta: Option<JsonObject>,
388}
389
390/// A tool call begins — parameters are streaming from the LM.
391///
392/// The server sets {@link ToolCallContributor | `contributor`} to identify
393/// the origin of the tool. For client-provided tools, the named client is
394/// responsible for executing the tool once it reaches the `running` state
395/// and dispatching `chat/toolCallComplete`. For MCP-served tools, the
396/// server executes the call against the named `McpServerCustomization`.
397#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
398#[serde(rename_all = "camelCase")]
399pub struct ChatToolCallStartAction {
400 /// Turn identifier
401 pub turn_id: String,
402 /// Tool call identifier
403 pub tool_call_id: String,
404 /// Additional provider-specific metadata for this tool call.
405 ///
406 /// Clients MAY look for well-known keys here to provide enhanced UI.
407 /// For example, a `ptyTerminal` key with `{ input: string; output: string }`
408 /// indicates the tool operated on a terminal (both `input` and `output` may
409 /// contain escape sequences).
410 #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
411 pub meta: Option<JsonObject>,
412 /// Internal tool name (for debugging/logging)
413 pub tool_name: String,
414 /// Human-readable tool name
415 pub display_name: String,
416 /// Human-readable description of what the tool invocation intends to do
417 #[serde(default, skip_serializing_if = "Option::is_none")]
418 pub intention: Option<String>,
419 /// Reference to the contributor of the tool being called. Absent for
420 /// server-side tools that are not contributed by a client or MCP server.
421 #[serde(default, skip_serializing_if = "Option::is_none")]
422 pub contributor: Option<ToolCallContributor>,
423}
424
425/// Streaming partial parameters for a tool call.
426#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
427#[serde(rename_all = "camelCase")]
428pub struct ChatToolCallDeltaAction {
429 /// Turn identifier
430 pub turn_id: String,
431 /// Tool call identifier
432 pub tool_call_id: String,
433 /// Additional provider-specific metadata for this tool call.
434 ///
435 /// Clients MAY look for well-known keys here to provide enhanced UI.
436 /// For example, a `ptyTerminal` key with `{ input: string; output: string }`
437 /// indicates the tool operated on a terminal (both `input` and `output` may
438 /// contain escape sequences).
439 #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
440 pub meta: Option<JsonObject>,
441 /// Partial parameter content to append
442 pub content: String,
443 /// Updated progress message
444 #[serde(default, skip_serializing_if = "Option::is_none")]
445 pub invocation_message: Option<StringOrMarkdown>,
446}
447
448/// Tool call parameters are complete, or a running tool requires re-confirmation.
449///
450/// When dispatched for a `streaming` tool call, transitions to `pending-confirmation`
451/// or directly to `running` if `confirmed` is set.
452///
453/// When dispatched for a `running` tool call (e.g. mid-execution permission needed),
454/// transitions back to `pending-confirmation`. The `invocationMessage` and `_meta`
455/// SHOULD be updated to describe the specific confirmation needed. Clients use the
456/// standard `chat/toolCallConfirmed` flow to approve or deny.
457///
458/// For client-provided tools, the server typically sets `confirmed` to
459/// `'not-needed'` so the tool transitions directly to `running`, where the
460/// owning client can begin execution immediately.
461#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
462#[serde(rename_all = "camelCase")]
463pub struct ChatToolCallReadyAction {
464 /// Turn identifier
465 pub turn_id: String,
466 /// Tool call identifier
467 pub tool_call_id: String,
468 /// Additional provider-specific metadata for this tool call.
469 ///
470 /// Clients MAY look for well-known keys here to provide enhanced UI.
471 /// For example, a `ptyTerminal` key with `{ input: string; output: string }`
472 /// indicates the tool operated on a terminal (both `input` and `output` may
473 /// contain escape sequences).
474 #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
475 pub meta: Option<JsonObject>,
476 /// Message describing what the tool will do or what confirmation is needed
477 pub invocation_message: StringOrMarkdown,
478 /// Raw tool input
479 #[serde(default, skip_serializing_if = "Option::is_none")]
480 pub tool_input: Option<String>,
481 /// Short title for the confirmation prompt (e.g. `"Run in terminal"`, `"Write file"`)
482 #[serde(default, skip_serializing_if = "Option::is_none")]
483 pub confirmation_title: Option<StringOrMarkdown>,
484 /// Risk assessment that informed the confirmation requirement.
485 #[serde(default, skip_serializing_if = "Option::is_none")]
486 pub risk_assessment: Option<ToolCallRiskAssessment>,
487 /// File edits that this tool call will perform, for preview before confirmation
488 #[serde(default, skip_serializing_if = "Option::is_none")]
489 pub edits: Option<AnyValue>,
490 /// Whether the agent host allows the client to edit the tool's input parameters before confirming
491 #[serde(default, skip_serializing_if = "Option::is_none")]
492 pub editable: Option<bool>,
493 /// If set, the tool was auto-confirmed and transitions directly to `running`
494 #[serde(default, skip_serializing_if = "Option::is_none")]
495 pub confirmed: Option<ToolCallConfirmationReason>,
496 /// Options the server offers for this confirmation. When present, the client
497 /// SHOULD render these instead of a plain approve/deny UI. Each option
498 /// belongs to a {@link ConfirmationOptionGroup} so the client can still
499 /// categorise the choices.
500 #[serde(default, skip_serializing_if = "Option::is_none")]
501 pub options: Option<Vec<ConfirmationOption>>,
502}
503
504/// Client approves or denies a pending tool call (merged approved + denied variants).
505#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
506#[serde(rename_all = "camelCase")]
507pub struct ChatToolCallConfirmedAction {
508 pub turn_id: String,
509 pub tool_call_id: String,
510 /// Additional provider-specific metadata for this tool call.
511 #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
512 pub meta: Option<JsonObject>,
513 /// Whether the tool call was approved.
514 pub approved: bool,
515 /// How the tool was confirmed (present when approved).
516 #[serde(default, skip_serializing_if = "Option::is_none")]
517 pub confirmed: Option<ToolCallConfirmationReason>,
518 /// Why the tool was cancelled (present when denied).
519 #[serde(default, skip_serializing_if = "Option::is_none")]
520 pub reason: Option<ToolCallCancellationReason>,
521 /// Edited tool input parameters, if the client modified them before confirming.
522 #[serde(default, skip_serializing_if = "Option::is_none")]
523 pub edited_tool_input: Option<String>,
524 /// What the user suggested doing instead (present when denied).
525 #[serde(default, skip_serializing_if = "Option::is_none")]
526 pub user_suggestion: Option<Message>,
527 /// Explanation for the denial.
528 #[serde(default, skip_serializing_if = "Option::is_none")]
529 pub reason_message: Option<StringOrMarkdown>,
530 /// ID of the selected confirmation option, if the server provided options.
531 #[serde(default, skip_serializing_if = "Option::is_none")]
532 pub selected_option_id: Option<String>,
533}
534
535/// Tool execution finished. Transitions to `completed` or `pending-result-confirmation`
536/// if `requiresResultConfirmation` is `true`.
537///
538/// For client-provided tools (whose tool call state carries a client
539/// `ToolCallContributor` with a `clientId`), the owning client dispatches this
540/// action with the execution result. The server SHOULD reject this action if the
541/// dispatching client does not match the contributor's `clientId`.
542///
543/// Servers waiting on a client tool call MAY time out after a reasonable duration
544/// if the implementing client disconnects or becomes unresponsive, and dispatch
545/// this action with `result.success = false` and an appropriate error.
546///
547/// A client MAY also dispatch this action with a **failed** result (
548/// `result.success: false`) for a tool call currently in `auth-required`
549/// status, to cancel that invocation without completing the pending MCP
550/// authentication challenge. This always transitions the tool call straight
551/// to `completed`, preserving the fields it had before pausing for auth;
552/// `requiresResultConfirmation` is ignored for this transition; the
553/// cancellation can never enter `pending-result-confirmation`, since there is
554/// no real result to review.
555///
556/// A **successful** result (`result.success: true`) is invalid for a tool
557/// call in `auth-required` status — execution never resumed after the
558/// challenge, so there's nothing that could have produced it. The reducer
559/// MUST reject/ignore it as a no-op, leaving the tool call in
560/// `auth-required`. The client must resolve the auth challenge
561/// (`chat/toolCallAuthResolved`) before completing successfully.
562#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
563#[serde(rename_all = "camelCase")]
564pub struct ChatToolCallCompleteAction {
565 /// Turn identifier
566 pub turn_id: String,
567 /// Tool call identifier
568 pub tool_call_id: String,
569 /// Additional provider-specific metadata for this tool call.
570 ///
571 /// Clients MAY look for well-known keys here to provide enhanced UI.
572 /// For example, a `ptyTerminal` key with `{ input: string; output: string }`
573 /// indicates the tool operated on a terminal (both `input` and `output` may
574 /// contain escape sequences).
575 #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
576 pub meta: Option<JsonObject>,
577 /// Execution result
578 pub result: ToolCallResult,
579 /// If true, the result requires client approval before finalizing
580 #[serde(default, skip_serializing_if = "Option::is_none")]
581 pub requires_result_confirmation: Option<bool>,
582}
583
584/// Client approves or denies a tool's result.
585///
586/// If `approved` is `false`, the tool transitions to `cancelled` with reason `result-denied`.
587#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
588#[serde(rename_all = "camelCase")]
589pub struct ChatToolCallResultConfirmedAction {
590 /// Turn identifier
591 pub turn_id: String,
592 /// Tool call identifier
593 pub tool_call_id: String,
594 /// Additional provider-specific metadata for this tool call.
595 ///
596 /// Clients MAY look for well-known keys here to provide enhanced UI.
597 /// For example, a `ptyTerminal` key with `{ input: string; output: string }`
598 /// indicates the tool operated on a terminal (both `input` and `output` may
599 /// contain escape sequences).
600 #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
601 pub meta: Option<JsonObject>,
602 /// Whether the result was approved
603 pub approved: bool,
604}
605
606/// Partial content produced while a tool is still executing.
607///
608/// Replaces the `content` array on the running tool call state. Clients can
609/// use this to display live feedback (e.g. a terminal reference) before the
610/// tool completes.
611///
612/// For client-provided tools (whose tool call state carries a client
613/// `ToolCallContributor` with a `clientId`), the owning client dispatches this
614/// action to stream intermediate content while executing. The server SHOULD
615/// reject this action if the dispatching client does not match the contributor's
616/// `clientId`.
617#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
618#[serde(rename_all = "camelCase")]
619pub struct ChatToolCallContentChangedAction {
620 /// Turn identifier
621 pub turn_id: String,
622 /// Tool call identifier
623 pub tool_call_id: String,
624 /// Additional provider-specific metadata for this tool call.
625 ///
626 /// Clients MAY look for well-known keys here to provide enhanced UI.
627 /// For example, a `ptyTerminal` key with `{ input: string; output: string }`
628 /// indicates the tool operated on a terminal (both `input` and `output` may
629 /// contain escape sequences).
630 #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
631 pub meta: Option<JsonObject>,
632 /// The current partial content for the running tool call
633 pub content: Vec<ToolResultContent>,
634}
635
636/// A running tool call is paused pending MCP authentication. Transitions the
637/// tool call from `running` to `auth-required`.
638///
639/// The server dispatches this when the MCP server backing the call responds
640/// with a 401/403 challenge mid-execution (see
641/// {@link McpAuthRequirement.reason | `insufficientScope`}). The host SHOULD
642/// pair this with `session/inputNeededSet` (kind `toolAuthentication`) so the
643/// block is visible at the session-summary level, mirroring
644/// {@link McpServerAuthRequiredState}'s own `InputNeeded` guidance.
645///
646/// Only valid for tool calls contributed by an MCP server — the reducer is a
647/// no-op if the tool call's `contributor` is not
648/// {@link ToolCallContributorKind.MCP | MCP-kind}.
649#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
650#[serde(rename_all = "camelCase")]
651pub struct ChatToolCallAuthRequiredAction {
652 /// Turn identifier
653 pub turn_id: String,
654 /// Tool call identifier
655 pub tool_call_id: String,
656 /// Additional provider-specific metadata for this tool call.
657 ///
658 /// Clients MAY look for well-known keys here to provide enhanced UI.
659 /// For example, a `ptyTerminal` key with `{ input: string; output: string }`
660 /// indicates the tool operated on a terminal (both `input` and `output` may
661 /// contain escape sequences).
662 #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
663 pub meta: Option<JsonObject>,
664 /// The authentication challenge blocking this invocation.
665 pub auth: McpAuthRequirement,
666}
667
668/// The authentication challenge blocking a tool call has been resolved (the
669/// client pushed a token via `authenticate` and the host validated it).
670/// Transitions the tool call from `auth-required` back to `running`,
671/// preserving the fields it had before pausing.
672///
673/// The host SHOULD remove the corresponding `session/inputNeededSet` entry
674/// (kind `toolAuthentication`) once this is dispatched.
675#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
676#[serde(rename_all = "camelCase")]
677pub struct ChatToolCallAuthResolvedAction {
678 /// Turn identifier
679 pub turn_id: String,
680 /// Tool call identifier
681 pub tool_call_id: String,
682 /// Additional provider-specific metadata for this tool call.
683 ///
684 /// Clients MAY look for well-known keys here to provide enhanced UI.
685 /// For example, a `ptyTerminal` key with `{ input: string; output: string }`
686 /// indicates the tool operated on a terminal (both `input` and `output` may
687 /// contain escape sequences).
688 #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
689 pub meta: Option<JsonObject>,
690}
691
692/// Turn finished — the assistant is idle.
693#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
694#[serde(rename_all = "camelCase")]
695pub struct ChatTurnCompleteAction {
696 /// Turn identifier
697 pub turn_id: String,
698 /// Elapsed turn duration in milliseconds, measured by the producer's own
699 /// clock. Clients MUST NOT derive this by subtracting timestamps — cross-
700 /// client clocks may differ — and MUST treat it as opaque, producer-supplied
701 /// data.
702 pub duration: i64,
703 /// Additional provider-specific metadata for this action.
704 ///
705 /// Clients MAY look for well-known keys here to provide enhanced UI, and
706 /// agent hosts MAY use it to carry per-event context that does not fit any
707 /// other field — for example, attributing the event to a specific agent
708 /// (such as a sub-agent acting within the turn). Mirrors the MCP `_meta`
709 /// convention.
710 #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
711 pub meta: Option<JsonObject>,
712}
713
714/// Turn was aborted; server stops processing.
715#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
716#[serde(rename_all = "camelCase")]
717pub struct ChatTurnCancelledAction {
718 /// Turn identifier
719 pub turn_id: String,
720 /// Elapsed turn duration in milliseconds, measured by the producer's own
721 /// clock. Clients MUST NOT derive this by subtracting timestamps — cross-
722 /// client clocks may differ — and MUST treat it as opaque, producer-supplied
723 /// data.
724 pub duration: i64,
725 /// Additional provider-specific metadata for this action.
726 ///
727 /// Clients MAY look for well-known keys here to provide enhanced UI, and
728 /// agent hosts MAY use it to carry per-event context that does not fit any
729 /// other field — for example, attributing the event to a specific agent
730 /// (such as a sub-agent acting within the turn). Mirrors the MCP `_meta`
731 /// convention.
732 #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
733 pub meta: Option<JsonObject>,
734}
735
736/// Error during turn processing.
737#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
738#[serde(rename_all = "camelCase")]
739pub struct ChatErrorAction {
740 /// Turn identifier
741 pub turn_id: String,
742 /// Elapsed turn duration in milliseconds, measured by the producer's own
743 /// clock. Clients MUST NOT derive this by subtracting timestamps — cross-
744 /// client clocks may differ — and MUST treat it as opaque, producer-supplied
745 /// data.
746 pub duration: i64,
747 /// Error details
748 pub error: ErrorInfo,
749 /// Additional provider-specific metadata for this action.
750 ///
751 /// Clients MAY look for well-known keys here to provide enhanced UI, and
752 /// agent hosts MAY use it to carry per-event context that does not fit any
753 /// other field — for example, attributing the event to a specific agent
754 /// (such as a sub-agent acting within the turn). Mirrors the MCP `_meta`
755 /// convention.
756 #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
757 pub meta: Option<JsonObject>,
758}
759
760/// The activity description of this chat changed.
761///
762/// Dispatched by the server to indicate what the chat is currently doing
763/// (e.g. running a tool, thinking). Clear activity by omitting it or setting it
764/// to `undefined`.
765/// Producers SHOULD also update the parent session's chat catalog with
766/// `session/chatUpdated` so `ChatSummary.activity` stays in sync.
767#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Default)]
768#[serde(rename_all = "camelCase")]
769pub struct ChatActivityChangedAction {
770 /// Human-readable description of current activity; omit or set `undefined` to clear
771 #[serde(default, skip_serializing_if = "Option::is_none")]
772 pub activity: Option<String>,
773}
774
775/// Session title updated. Fired by the server when the title is auto-generated
776/// from conversation, or dispatched by a client to rename a session.
777#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
778#[serde(rename_all = "camelCase")]
779pub struct SessionTitleChangedAction {
780 /// New title
781 pub title: String,
782}
783
784/// Token usage report for a turn.
785#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
786#[serde(rename_all = "camelCase")]
787pub struct ChatUsageAction {
788 /// Turn identifier
789 pub turn_id: String,
790 /// Token usage data
791 pub usage: UsageInfo,
792 /// Additional provider-specific metadata for this action.
793 ///
794 /// Clients MAY look for well-known keys here to provide enhanced UI, and
795 /// agent hosts MAY use it to carry per-event context that does not fit any
796 /// other field — for example, attributing the event to a specific agent
797 /// (such as a sub-agent acting within the turn). Mirrors the MCP `_meta`
798 /// convention.
799 #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
800 pub meta: Option<JsonObject>,
801}
802
803/// Reasoning/thinking text from the model, appended to a specific reasoning response part.
804///
805/// The server MUST first emit a `chat/responsePart` to create the target
806/// reasoning part, then use this action to append text to it.
807#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
808#[serde(rename_all = "camelCase")]
809pub struct ChatReasoningAction {
810 /// Turn identifier
811 pub turn_id: String,
812 /// Identifier of the reasoning response part to append to
813 pub part_id: String,
814 /// Reasoning text chunk
815 pub content: String,
816 /// Additional provider-specific metadata for this action.
817 ///
818 /// Clients MAY look for well-known keys here to provide enhanced UI, and
819 /// agent hosts MAY use it to carry per-event context that does not fit any
820 /// other field — for example, attributing the event to a specific agent
821 /// (such as a sub-agent acting within the turn). Mirrors the MCP `_meta`
822 /// convention.
823 #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
824 pub meta: Option<JsonObject>,
825}
826
827/// The read state of the session changed.
828///
829/// Dispatched by a client to mark a session as read (e.g. after viewing it)
830/// or unread (e.g. after new activity since the client last looked at it).
831#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
832#[serde(rename_all = "camelCase")]
833pub struct SessionIsReadChangedAction {
834 /// Whether the session has been read
835 pub is_read: bool,
836}
837
838/// The archived state of the session changed.
839///
840/// Dispatched by a client to archive a session (e.g. the task is
841/// complete) or to unarchive it.
842#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
843#[serde(rename_all = "camelCase")]
844pub struct SessionIsArchivedChangedAction {
845 /// Whether the session is archived
846 pub is_archived: bool,
847}
848
849/// The activity description of the session changed.
850///
851/// Dispatched by the server to indicate what the session is currently doing
852/// (e.g. running a tool, thinking). Clear activity by setting it to `undefined`.
853#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Default)]
854#[serde(rename_all = "camelCase")]
855pub struct SessionActivityChangedAction {
856 /// Human-readable description of current activity, or `undefined` to clear
857 #[serde(default, skip_serializing_if = "Option::is_none")]
858 pub activity: Option<String>,
859}
860
861/// The {@link Changeset | catalogue of changesets} the agent host
862/// advertises for this session changed. Replaces
863/// {@link SessionState.changesets | `state.changesets`} entirely
864/// (full-replacement semantics) — set to `undefined` to clear the
865/// catalogue.
866///
867/// Producers dispatch this whenever entries are added or removed. The
868/// fan-out happens through this action so observers see catalogue
869/// mutations in the same {@link ChangesetAction | per-changeset} action
870/// stream they already follow for file-level updates.
871#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Default)]
872#[serde(rename_all = "camelCase")]
873pub struct SessionChangesetsChangedAction {
874 /// New catalogue, or `undefined` to clear it
875 #[serde(default, skip_serializing_if = "Option::is_none")]
876 pub changesets: Option<Vec<Changeset>>,
877}
878
879/// Server tools for this session have changed.
880///
881/// Full-replacement semantics: the `tools` array replaces the previous `serverTools` entirely.
882#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
883#[serde(rename_all = "camelCase")]
884pub struct SessionServerToolsChangedAction {
885 /// Updated server tools list (full replacement)
886 pub tools: Vec<ToolDefinition>,
887}
888
889/// An active client for this session was added or updated.
890///
891/// Upsert semantics keyed by {@link SessionActiveClient.clientId | `clientId`}:
892/// a client dispatches this action with its own `SessionActiveClient` to join
893/// the session's active clients or refresh its entry, replacing any existing
894/// entry that has the same `clientId`. Multiple clients may be active at once.
895/// This is also how a client updates its published tools or customizations —
896/// re-dispatch with the full, updated entry. Use
897/// {@link SessionActiveClientRemovedAction | `session/activeClientRemoved`} to
898/// leave. The server SHOULD automatically dispatch that removal when an active
899/// client disconnects.
900#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
901#[serde(rename_all = "camelCase")]
902pub struct SessionActiveClientSetAction {
903 /// The active client to add or update, matched by `clientId`.
904 pub active_client: SessionActiveClient,
905}
906
907/// An active client was removed from this session.
908///
909/// Removes the entry for the client identified by `clientId` from
910/// {@link SessionState.activeClients}; a no-op when no entry matches.
911///
912/// The host SHOULD dispatch this automatically when a client stops participating
913/// in the session — for example when it unsubscribes from the session channel,
914/// when it disconnects and does not reconnect within a host-defined grace
915/// period, or when a `reconnect` command's `subscriptions` omit a session the
916/// client was still active in. When removing a client, the host SHOULD also
917/// cancel that client's in-flight tool calls — those whose tool call state
918/// carries a client `ToolCallContributor` with the matching `clientId` — by
919/// dispatching `chat/toolCallComplete` with `result.success = false`. (There is
920/// no per-tool-call server cancel; a failed completion is the cancellation
921/// mechanism, and the call ends in `completed` status with a failed result.)
922#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
923#[serde(rename_all = "camelCase")]
924pub struct SessionActiveClientRemovedAction {
925 /// The `clientId` of the active client to remove.
926 pub client_id: String,
927}
928
929/// A session-level input request was added or updated.
930///
931/// Upsert semantics keyed by {@link SessionInputRequest.id | `request.id`}: the
932/// host dispatches this with the full {@link SessionInputRequest} to append a new
933/// entry to {@link SessionState.inputNeeded} or replace the existing entry with
934/// the same `id`.
935///
936/// Server-originated: the host mirrors chat-level requests (elicitations, tool
937/// confirmations, client-tool executions) into the session aggregate so clients
938/// subscribed only to the session channel can discover them. Clients respond by
939/// dispatching the ordinary `chat/*` action to the entry's `chat` channel — see
940/// {@link SessionInputRequest}.
941#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
942#[serde(rename_all = "camelCase")]
943pub struct SessionInputNeededSetAction {
944 /// The input request to add or update, matched by `id`.
945 pub request: SessionInputRequest,
946}
947
948/// A session-level input request was removed.
949///
950/// Removes the entry identified by `id` from
951/// {@link SessionState.inputNeeded}; a no-op when no entry matches.
952///
953/// Server-originated: the host dispatches this once the underlying request
954/// resolves (the user answers, the tool call is confirmed, or the client
955/// reports its result).
956#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
957#[serde(rename_all = "camelCase")]
958pub struct SessionInputNeededRemovedAction {
959 /// The `id` of the input request to remove.
960 pub id: String,
961}
962
963/// A pending message was set (upsert semantics: creates or replaces).
964///
965/// For steering messages, this always replaces the single steering message.
966/// For queued messages, if a message with the given `id` already exists it is
967/// updated in place; otherwise it is appended to the queue. If the chat is
968/// idle when a queued message is set, the server SHOULD immediately consume it
969/// and start a new turn.
970///
971/// A client is only allowed to send {@link MessageKind.User} messages.
972#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
973#[serde(rename_all = "camelCase")]
974pub struct ChatPendingMessageSetAction {
975 /// Whether this is a steering or queued message
976 pub kind: PendingMessageKind,
977 /// Unique identifier for this pending message
978 pub id: String,
979 /// The message content
980 pub message: Message,
981}
982
983/// A pending message was removed (steering or queued).
984///
985/// Dispatched by clients to cancel a pending message, or by the server when
986/// it consumes a message (e.g. starting a turn from a queued message or
987/// injecting a steering message into the current turn).
988#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
989#[serde(rename_all = "camelCase")]
990pub struct ChatPendingMessageRemovedAction {
991 /// Whether this is a steering or queued message
992 pub kind: PendingMessageKind,
993 /// Identifier of the pending message to remove
994 pub id: String,
995}
996
997/// Reorder the queued messages.
998///
999/// The `order` array contains the IDs of queued messages in their new
1000/// desired order. IDs not present in the current queue are ignored.
1001/// Queued messages whose IDs are absent from `order` are appended at
1002/// the end in their original relative order (so a client with a stale
1003/// view of the queue never silently drops messages).
1004#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1005#[serde(rename_all = "camelCase")]
1006pub struct ChatQueuedMessagesReorderedAction {
1007 /// Queued message IDs in the desired order
1008 pub order: Vec<String>,
1009}
1010
1011/// The chat's draft input changed.
1012///
1013/// Clients MAY periodically sync their local input state — the message the user
1014/// is composing, including its {@link Message.model | model} /
1015/// {@link Message.agent | agent} selection and attachments — into the chat's
1016/// {@link ChatState.draft | `draft`} so it survives reloads and is visible to
1017/// other clients viewing the same chat. Eager syncing is **not** required;
1018/// clients SHOULD debounce and MAY sync only at convenient points. Set `draft`
1019/// to `undefined` to clear it (e.g. once the message is sent).
1020///
1021/// A client is only allowed to draft {@link MessageKind.User} messages.
1022#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Default)]
1023#[serde(rename_all = "camelCase")]
1024pub struct ChatDraftChangedAction {
1025 /// New draft message, or `undefined` to clear it
1026 #[serde(default, skip_serializing_if = "Option::is_none")]
1027 pub draft: Option<Message>,
1028}
1029
1030/// A session requested input from the user.
1031///
1032/// Creates an unresolved {@link InputRequestResponsePart} in the active turn,
1033/// or replaces the unresolved part with the same request `id`. Answer drafts
1034/// are preserved unless `request.answers` is provided.
1035#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1036#[serde(rename_all = "camelCase")]
1037pub struct ChatInputRequestedAction {
1038 /// Input request to create or replace
1039 pub request: ChatInputRequest,
1040}
1041
1042/// A client updated, submitted, skipped, or removed a single in-progress answer.
1043///
1044/// Dispatching with `answer: undefined` removes that question's answer draft.
1045#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1046#[serde(rename_all = "camelCase")]
1047pub struct ChatInputAnswerChangedAction {
1048 /// Input request identifier
1049 pub request_id: String,
1050 /// Question identifier within the input request
1051 pub question_id: String,
1052 /// Updated answer, or `undefined` to clear an answer draft
1053 #[serde(default, skip_serializing_if = "Option::is_none")]
1054 pub answer: Option<ChatInputAnswer>,
1055}
1056
1057/// A client submitted an accept, decline, or cancel response to an input request.
1058///
1059/// If accepted, the server uses `answers` (when provided) plus the request's
1060/// synced answer state to resume the blocked operation. The reducer records the
1061/// response and final answers on the existing {@link InputRequestResponsePart}.
1062#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1063#[serde(rename_all = "camelCase")]
1064pub struct ChatInputCompletedAction {
1065 /// Input request identifier
1066 pub request_id: String,
1067 /// Completion outcome
1068 pub response: ChatInputResponseKind,
1069 /// Optional final answer replacement, keyed by question ID
1070 #[serde(default, skip_serializing_if = "Option::is_none")]
1071 pub answers: Option<std::collections::HashMap<String, ChatInputAnswer>>,
1072}
1073
1074/// The session's customizations have changed.
1075///
1076/// Full-replacement semantics: the `customizations` array replaces the
1077/// previous `customizations` entirely.
1078#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1079#[serde(rename_all = "camelCase")]
1080pub struct SessionCustomizationsChangedAction {
1081 /// Updated customization list (full replacement).
1082 pub customizations: Vec<Customization>,
1083}
1084
1085/// A client toggled a customization on or off.
1086///
1087/// Matches `id` against every top-level customization first — a plugin or
1088/// directory container, or a bare top-level MCP server — then against the
1089/// children inside each container (a skill, agent, or other entry), and
1090/// sets the matched entry's `enabled` flag. Disabling a container still
1091/// disables all of its children — the effective state of a child is
1092/// `container.enabled && (child.enabled ?? true)` — so toggling a child
1093/// only matters while its container is enabled. Is a no-op when no
1094/// customization has the given `id`.
1095#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1096#[serde(rename_all = "camelCase")]
1097pub struct SessionCustomizationToggledAction {
1098 /// The id of the container or child to toggle.
1099 pub id: String,
1100 /// Whether to enable or disable the targeted customization.
1101 pub enabled: bool,
1102}
1103
1104/// Upserts a top-level customization (plugin or directory).
1105///
1106/// The reducer locates the existing entry by `customization.id`:
1107///
1108/// - If found, the entry is replaced entirely with `customization`,
1109/// including its `children` array. To preserve existing children, the
1110/// host must include them on the payload.
1111/// - If not found, the entry is appended.
1112#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1113#[serde(rename_all = "camelCase")]
1114pub struct SessionCustomizationUpdatedAction {
1115 /// The customization to upsert (matched by `customization.id`).
1116 pub customization: Customization,
1117}
1118
1119/// Removes a customization by id.
1120///
1121/// Searches every container and its children for the entry. If the entry
1122/// is a container, its children are removed with it. Is a no-op when no
1123/// matching id is found.
1124#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1125#[serde(rename_all = "camelCase")]
1126pub struct SessionCustomizationRemovedAction {
1127 /// The id of the customization to remove.
1128 pub id: String,
1129}
1130
1131/// Updates the runtime fields of an existing
1132/// {@link McpServerCustomization} — narrow alternative to
1133/// {@link SessionCustomizationUpdatedAction} for the high-frequency
1134/// `starting` ↔ `ready` ↔ `authRequired` transitions.
1135///
1136/// Locates the target entry by `id`, searching both the top-level
1137/// customization list and the `children` array of every container.
1138/// Replaces the entry's {@link McpServerCustomization.state | `state`}
1139/// and {@link McpServerCustomization.channel | `channel`}
1140/// (full-replacement semantics: omit `channel` to clear an existing
1141/// channel URI). Other fields of the customization are preserved.
1142///
1143/// Is a no-op when no matching `McpServerCustomization` is found. To
1144/// update any other field (name, icons, `mcpApp` capabilities, etc.) use
1145/// {@link SessionCustomizationUpdatedAction} instead.
1146///
1147/// When the transition is to {@link McpServerStatus.AuthRequired}
1148/// because of a request issued mid-turn, the host SHOULD also raise
1149/// {@link SessionStatus.InputNeeded} on the session — see
1150/// {@link McpServerAuthRequiredState} for the rationale.
1151#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1152#[serde(rename_all = "camelCase")]
1153pub struct SessionMcpServerStateChangedAction {
1154 /// The id of the {@link McpServerCustomization} to update.
1155 pub id: String,
1156 /// The new lifecycle state.
1157 pub state: McpServerState,
1158 /// Updated `mcp://` side-channel URI. Full-replacement: omit to clear
1159 /// an existing channel (typical when leaving
1160 /// {@link McpServerStatus.Ready | `Ready`}).
1161 #[serde(default, skip_serializing_if = "Option::is_none")]
1162 pub channel: Option<Uri>,
1163}
1164
1165/// Requests that the host start or restart an existing
1166/// {@link McpServerCustomization}.
1167///
1168/// Locates the target entry by `id`, searching both the top-level
1169/// customization list and the `children` array of every container. The
1170/// reducer optimistically moves the server to
1171/// {@link McpServerStatus.Starting | `starting`} and clears any previous
1172/// {@link McpServerCustomization.channel | `channel`}; the host remains
1173/// authoritative and SHOULD follow with
1174/// {@link SessionMcpServerStateChangedAction | `session/mcpServerStateChanged`}
1175/// once the server becomes ready, needs authentication, fails, or is
1176/// rejected. Is a no-op when no matching `McpServerCustomization` is found.
1177#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1178#[serde(rename_all = "camelCase")]
1179pub struct SessionMcpServerStartRequestedAction {
1180 /// The id of the {@link McpServerCustomization} to start.
1181 pub id: String,
1182}
1183
1184/// Requests that the host stop an existing {@link McpServerCustomization}.
1185///
1186/// Locates the target entry by `id`, searching both the top-level
1187/// customization list and the `children` array of every container. The
1188/// reducer optimistically moves the server to
1189/// {@link McpServerStatus.Stopped | `stopped`} and clears any previous
1190/// {@link McpServerCustomization.channel | `channel`}. Replacing an
1191/// {@link McpServerStatus.AuthRequired | `authRequired`} lifecycle state with
1192/// `stopped` unblocks the server from waiting on authentication. If the host
1193/// also raised session-level input-needed state solely for that MCP server, it
1194/// SHOULD remove that input-needed entry when accepting the stop.
1195///
1196/// The host remains authoritative and MAY reject the action or follow with
1197/// {@link SessionMcpServerStateChangedAction | `session/mcpServerStateChanged`}
1198/// if the final lifecycle state differs. Is a no-op when no matching
1199/// `McpServerCustomization` is found.
1200#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1201#[serde(rename_all = "camelCase")]
1202pub struct SessionMcpServerStopRequestedAction {
1203 /// The id of the {@link McpServerCustomization} to stop.
1204 pub id: String,
1205}
1206
1207/// Truncates a session's history. If `turnId` is provided, all turns after that
1208/// turn are removed and the specified turn is kept. If `turnId` is omitted, all
1209/// turns are removed.
1210///
1211/// If there is an active turn it is silently dropped and the chat status
1212/// returns to `idle`.
1213///
1214/// Common use-case: truncate old data then dispatch a new
1215/// `chat/turnStarted` with an edited message.
1216#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Default)]
1217#[serde(rename_all = "camelCase")]
1218pub struct ChatTruncatedAction {
1219 /// Keep turns up to and including this turn. Omit to clear all turns.
1220 #[serde(default, skip_serializing_if = "Option::is_none")]
1221 pub turn_id: Option<String>,
1222}
1223
1224/// Loads older completed turns into this chat's state.
1225///
1226/// Hosts dispatch this before responding to `fetchTurns`, and before applying
1227/// any operation that references a turn older than the currently loaded window.
1228/// `turns` is ordered oldest-first and is prepended to the current `turns`
1229/// window. `turnsNextCursor` replaces the state's cursor; omit it when all
1230/// retained turns are now loaded.
1231#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1232#[serde(rename_all = "camelCase")]
1233pub struct ChatTurnsLoadedAction {
1234 /// Older completed turns loaded into the state, ordered oldest-first.
1235 pub turns: Vec<Turn>,
1236 /// Opaque cursor for loading the next older page, if one remains.
1237 #[serde(default, skip_serializing_if = "Option::is_none")]
1238 pub turns_next_cursor: Option<String>,
1239}
1240
1241/// Client changed a mutable config value mid-session.
1242///
1243/// Only properties with `sessionMutable: true` in the config schema may be
1244/// changed. The server validates and broadcasts the action; the reducer merges
1245/// the new values into `state.config.values`.
1246#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1247#[serde(rename_all = "camelCase")]
1248pub struct SessionConfigChangedAction {
1249 /// Updated config values
1250 pub config: JsonObject,
1251 /// When `true`, replaces all config values instead of merging
1252 #[serde(default, skip_serializing_if = "Option::is_none")]
1253 pub replace: Option<bool>,
1254}
1255
1256/// The session's `_meta` side-channel changed. Replaces `state._meta`
1257/// entirely (full-replacement semantics). Producers SHOULD merge any
1258/// keys they wish to preserve into the new value before dispatching.
1259#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Default)]
1260#[serde(rename_all = "camelCase")]
1261pub struct SessionMetaChangedAction {
1262 /// New `_meta` payload, or `undefined` to clear it
1263 #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
1264 pub meta: Option<JsonObject>,
1265}
1266
1267/// The {@link ChangesetState.status} for this changeset transitioned (e.g.
1268/// `computing → ready`). The error payload is set together with `status`
1269/// whenever it transitions to {@link ChangesetStatus.Error | Error}.
1270#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1271#[serde(rename_all = "camelCase")]
1272pub struct ChangesetStatusChangedAction {
1273 /// New computation lifecycle status.
1274 pub status: ChangesetStatus,
1275 /// Cause when `status === ChangesetStatus.Error`; otherwise omitted.
1276 #[serde(default, skip_serializing_if = "Option::is_none")]
1277 pub error: Option<ErrorInfo>,
1278}
1279
1280/// Upsert a {@link ChangesetFile} in the changeset — adds a new entry, or
1281/// replaces an existing one identified by {@link ChangesetFile.id}.
1282#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1283#[serde(rename_all = "camelCase")]
1284pub struct ChangesetFileSetAction {
1285 /// The new or replacement file entry.
1286 pub file: ChangesetFile,
1287}
1288
1289/// Remove a {@link ChangesetFile} from the changeset by its id.
1290///
1291/// Typically dispatched when a file is reverted, staged out, or otherwise
1292/// no longer in scope (e.g. a renamed file is replaced by a new entry).
1293#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1294#[serde(rename_all = "camelCase")]
1295pub struct ChangesetFileRemovedAction {
1296 /// The {@link ChangesetFile.id} of the file to remove.
1297 pub file_id: String,
1298}
1299
1300/// Set the {@link ChangesetFile.reviewed} flag for one or more files — the
1301/// GitHub-style "Viewed" toggle, applied in a single batch.
1302///
1303/// Targets files by their {@link ChangesetFile.id}. Ids in {@link files} that
1304/// do not match a file currently present in the changeset are ignored; if none
1305/// match, the action is a no-op. Only the {@link ChangesetFile.reviewed} field
1306/// of each matched file is affected; the files' {@link ChangesetFile.edit | edit}
1307/// and {@link ChangesetFile._meta | _meta} are left untouched.
1308///
1309/// Only meaningful on a changeset that advertises
1310/// {@link ChangesetCapabilities.review}. Unlike every other `changeset/*` action
1311/// this one is **client-dispatchable**: a reviewer toggles review state directly,
1312/// applying it optimistically through the write-ahead reducer and letting the
1313/// server echo it back on the normal `action` envelope stream. The server MAY
1314/// also originate it (e.g. an agent marking its own output reviewed).
1315///
1316/// There is no protocol-level content version, so review is not reset
1317/// automatically when a file's contents change under a stable id. The server,
1318/// which is the authority on what changed, resets review explicitly — either by
1319/// re-emitting the file without `reviewed: true`, or by dispatching this action
1320/// with `reviewed: false`.
1321#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1322#[serde(rename_all = "camelCase")]
1323pub struct ChangesetFilesReviewChangedAction {
1324 /// The {@link ChangesetFile.id | ids} of the files whose review state changed.
1325 pub files: Vec<String>,
1326 /// New review state applied to every listed file: `true` once reviewed, `false` to clear it.
1327 pub reviewed: bool,
1328}
1329
1330/// The changeset's full content changed. Full replacement semantics: `files`
1331/// replaces the previous file list, and `operations`, when present, replaces
1332/// the previous operation list.
1333///
1334/// Producers SHOULD use this action for initial snapshots and bulk refreshes;
1335/// use {@link ChangesetFileSetAction}, {@link ChangesetFileRemovedAction}, and
1336/// {@link ChangesetOperationsChangedAction} for incremental updates.
1337#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1338#[serde(rename_all = "camelCase")]
1339pub struct ChangesetContentChangedAction {
1340 /// Full replacement file list.
1341 pub files: Vec<ChangesetFile>,
1342 /// Full replacement operation list. Omit when operations are unchanged.
1343 #[serde(default, skip_serializing_if = "Option::is_none")]
1344 pub operations: Option<Vec<ChangesetOperation>>,
1345 /// Error information, if the changeset content change failed.
1346 #[serde(default, skip_serializing_if = "Option::is_none")]
1347 pub error: Option<ErrorInfo>,
1348}
1349
1350/// The set of operations available on this changeset changed. Full
1351/// replacement semantics: `operations` replaces the previous list (or
1352/// removes it entirely when `operations` is `undefined`).
1353#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Default)]
1354#[serde(rename_all = "camelCase")]
1355pub struct ChangesetOperationsChangedAction {
1356 /// Updated operation list. Pass `undefined` to clear all operations.
1357 #[serde(default, skip_serializing_if = "Option::is_none")]
1358 pub operations: Option<Vec<ChangesetOperation>>,
1359}
1360
1361/// The {@link ChangesetOperation.status} for a single operation transitioned
1362/// (e.g. `idle → running → idle`, or `running → error`). The error payload
1363/// is set together with `status` whenever it transitions to
1364/// {@link ChangesetOperationStatus.Error | Error}, and cleared on any other
1365/// transition.
1366///
1367/// Targets one operation by its {@link ChangesetOperation.id}. If no
1368/// operation with that id is currently present in the changeset, the action
1369/// is a no-op. Use {@link ChangesetOperationsChangedAction} to add, remove,
1370/// or otherwise replace the operation list itself.
1371#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1372#[serde(rename_all = "camelCase")]
1373pub struct ChangesetOperationStatusChangedAction {
1374 /// The {@link ChangesetOperation.id} whose status changed.
1375 pub operation_id: String,
1376 /// New execution status.
1377 pub status: ChangesetOperationStatus,
1378 /// Cause when `status === ChangesetOperationStatus.Error`; otherwise omitted.
1379 #[serde(default, skip_serializing_if = "Option::is_none")]
1380 pub error: Option<ErrorInfo>,
1381}
1382
1383/// Drop every file from the changeset.
1384///
1385/// Two cases use this:
1386/// 1. The underlying source moved (branch switched, fork point invalidated,
1387/// …) and the server is recomputing from scratch — subsequent
1388/// {@link ChangesetFileSetAction} entries will repopulate it.
1389/// 2. The owning session has ended and the URI is becoming
1390/// un-subscribable — the server will unsubscribe all clients shortly
1391/// after dispatching this action.
1392///
1393/// Clients SHOULD release any references on receipt and SHOULD NOT
1394/// distinguish the two cases from the action alone — instead, react to
1395/// the corresponding session-level lifecycle signal (e.g.
1396/// `root/sessionRemoved`) for the "going away" case.
1397#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1398#[serde(rename_all = "camelCase")]
1399pub struct ChangesetClearedAction {}
1400
1401/// Upsert an {@link Annotation} in the annotations channel — adds a new
1402/// annotation, or replaces an existing one identified by
1403/// {@link Annotation.id}.
1404///
1405/// Dispatched by a client to create an annotation (together with its
1406/// mandatory first entry) or to re-anchor / resolve an existing one; the
1407/// dispatching client assigns the {@link Annotation.id} and the id of any
1408/// new entry. When replacing, the full annotation payload (including its
1409/// {@link Annotation.entries | entries} list) is substituted; producers
1410/// SHOULD prefer {@link AnnotationsEntrySetAction} for per-entry edits, and
1411/// {@link AnnotationsUpdatedAction} to resolve / re-anchor an existing
1412/// annotation, to keep wire updates small.
1413#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1414#[serde(rename_all = "camelCase")]
1415pub struct AnnotationsSetAction {
1416 /// The new or replacement annotation. MUST contain at least one entry.
1417 pub annotation: Annotation,
1418}
1419
1420/// Partially update an existing {@link Annotation}'s own properties — a narrow
1421/// alternative to {@link AnnotationsSetAction} for the common case of resolving
1422/// / re-opening or re-anchoring an annotation without resending its
1423/// {@link Annotation.entries | entries}.
1424///
1425/// Targets one annotation by its {@link annotationId}. Only the fields present
1426/// on the action are written; omitted fields leave the corresponding
1427/// {@link Annotation} property unchanged. The annotation's
1428/// {@link Annotation.entries | entries}, {@link Annotation.id | id}, and
1429/// {@link Annotation._meta | _meta} are never touched — dispatch
1430/// {@link AnnotationsSetAction} to replace those, to clear {@link range}
1431/// (re-anchor to the whole file), or {@link AnnotationsEntrySetAction} /
1432/// {@link AnnotationsEntryRemovedAction} to edit individual entries.
1433///
1434/// If {@link annotationId} does not match any current annotation the action is
1435/// a no-op.
1436#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1437#[serde(rename_all = "camelCase")]
1438pub struct AnnotationsUpdatedAction {
1439 /// The {@link Annotation.id} of the annotation to update.
1440 pub annotation_id: String,
1441 /// Re-anchors the annotation to the file versions this turn produced.
1442 /// Matches a {@link Turn.id} on the owning session. Omit to leave the
1443 /// current {@link Annotation.turnId} unchanged.
1444 #[serde(default, skip_serializing_if = "Option::is_none")]
1445 pub turn_id: Option<String>,
1446 /// Re-anchors the annotation to this file. Omit to leave the current
1447 /// {@link Annotation.resource} unchanged.
1448 #[serde(default, skip_serializing_if = "Option::is_none")]
1449 pub resource: Option<Uri>,
1450 /// Narrows the annotation to this range within {@link resource}. Omit to
1451 /// leave the current {@link Annotation.range} unchanged; this action cannot
1452 /// clear an existing range — dispatch {@link AnnotationsSetAction} to
1453 /// re-anchor to the whole file.
1454 #[serde(default, skip_serializing_if = "Option::is_none")]
1455 pub range: Option<TextRange>,
1456 /// Marks the annotation resolved (`true`) or re-opens it (`false`). Omit to
1457 /// leave the current {@link Annotation.resolved} state unchanged.
1458 #[serde(default, skip_serializing_if = "Option::is_none")]
1459 pub resolved: Option<bool>,
1460}
1461
1462/// Remove an {@link Annotation} from the channel by its id.
1463///
1464/// Dispatched to delete an entire annotation and every entry it contains.
1465/// Because the protocol forbids empty annotations, a client that wants to
1466/// remove the last remaining entry dispatches this action — collapsing the
1467/// annotation — rather than {@link AnnotationsEntryRemovedAction}.
1468#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1469#[serde(rename_all = "camelCase")]
1470pub struct AnnotationsRemovedAction {
1471 /// The {@link Annotation.id} of the annotation to remove.
1472 pub annotation_id: String,
1473}
1474
1475/// Upsert an {@link AnnotationEntry} within an existing annotation — adds a
1476/// new entry, or replaces one identified by {@link AnnotationEntry.id}. The
1477/// dispatching client assigns the {@link AnnotationEntry.id} of a new entry.
1478/// If {@link annotationId} does not match any current annotation the action
1479/// is a no-op.
1480#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1481#[serde(rename_all = "camelCase")]
1482pub struct AnnotationsEntrySetAction {
1483 /// The {@link Annotation.id} the entry belongs to.
1484 pub annotation_id: String,
1485 /// The new or replacement entry.
1486 pub entry: AnnotationEntry,
1487}
1488
1489/// Remove a single {@link AnnotationEntry} from an annotation without
1490/// collapsing the annotation itself. Used when more than one entry remains —
1491/// to remove the last entry a client dispatches {@link AnnotationsRemovedAction}
1492/// instead, since the protocol forbids empty annotations.
1493///
1494/// If either {@link annotationId} or {@link entryId} does not match the
1495/// current state the action is a no-op.
1496#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1497#[serde(rename_all = "camelCase")]
1498pub struct AnnotationsEntryRemovedAction {
1499 /// The {@link Annotation.id} the entry belongs to.
1500 pub annotation_id: String,
1501 /// The {@link AnnotationEntry.id} to remove.
1502 pub entry_id: String,
1503}
1504
1505/// Fired when the list of known terminals changes.
1506///
1507/// Full-replacement semantics: the `terminals` array replaces the previous
1508/// `terminals` entirely.
1509#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1510#[serde(rename_all = "camelCase")]
1511pub struct RootTerminalsChangedAction {
1512 /// Updated terminal list (full replacement)
1513 pub terminals: Vec<TerminalInfo>,
1514}
1515
1516/// Terminal output data (pty → client direction).
1517///
1518/// Appends `data` to the terminal's `content` in the reducer.
1519///
1520/// `terminal/data` and `terminal/input` are intentionally separate actions
1521/// because standard write-ahead reconciliation is not safe for terminal I/O.
1522/// A pty is a stateful, mutable process — optimistically applying input or
1523/// predicting output would produce incorrect state. Instead, `terminal/input`
1524/// is a side-effect-only action (client → server → pty), and `terminal/data`
1525/// is server-authoritative output (pty → server → client).
1526#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1527#[serde(rename_all = "camelCase")]
1528pub struct TerminalDataAction {
1529 /// Output data (may contain ANSI escape sequences)
1530 pub data: String,
1531}
1532
1533/// Keyboard input sent to the terminal process (client → pty direction).
1534///
1535/// This is a side-effect-only action: the server forwards the data to the
1536/// terminal's pty. The reducer treats this as a no-op since `terminal/data`
1537/// actions will reflect any resulting output.
1538///
1539/// See `terminal/data` for why these two actions are kept separate.
1540#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1541#[serde(rename_all = "camelCase")]
1542pub struct TerminalInputAction {
1543 /// Input data to send to the pty
1544 pub data: String,
1545}
1546
1547/// Terminal dimensions changed.
1548///
1549/// Dispatchable by clients to request a resize, or by the server to inform
1550/// clients of the actual terminal dimensions.
1551#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1552#[serde(rename_all = "camelCase")]
1553pub struct TerminalResizedAction {
1554 /// Terminal width in columns
1555 pub cols: i64,
1556 /// Terminal height in rows
1557 pub rows: i64,
1558}
1559
1560/// Terminal claim changed. A client or session transfers ownership of the terminal.
1561///
1562/// The server SHOULD reject if the dispatching client does not currently hold
1563/// the claim.
1564#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1565#[serde(rename_all = "camelCase")]
1566pub struct TerminalClaimedAction {
1567 /// The new claim
1568 pub claim: TerminalClaim,
1569}
1570
1571/// Terminal title changed.
1572///
1573/// Fired by the server when the terminal process updates its title (e.g. via
1574/// escape sequences), or dispatched by a client to rename a terminal.
1575#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1576#[serde(rename_all = "camelCase")]
1577pub struct TerminalTitleChangedAction {
1578 /// New terminal title
1579 pub title: String,
1580}
1581
1582/// Terminal working directory changed.
1583#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1584#[serde(rename_all = "camelCase")]
1585pub struct TerminalCwdChangedAction {
1586 /// New working directory
1587 pub cwd: Uri,
1588}
1589
1590/// Terminal process exited.
1591#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Default)]
1592#[serde(rename_all = "camelCase")]
1593pub struct TerminalExitedAction {
1594 /// Process exit code. `undefined` if the process was killed without an exit code.
1595 #[serde(default, skip_serializing_if = "Option::is_none")]
1596 pub exit_code: Option<i64>,
1597}
1598
1599/// Terminal scrollback buffer cleared.
1600#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1601#[serde(rename_all = "camelCase")]
1602pub struct TerminalClearedAction {}
1603
1604/// Shell integration has loaded and the terminal now supports command
1605/// detection. The server dispatches this when shell integration becomes
1606/// available (which may happen asynchronously after the terminal is created).
1607///
1608/// Clients MUST NOT assume command detection is available until this action
1609/// (or `terminal/commandExecuted`) has been received.
1610#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1611#[serde(rename_all = "camelCase")]
1612pub struct TerminalCommandDetectionAvailableAction {}
1613
1614/// A command has been submitted to the shell and is now executing.
1615/// All subsequent `terminal/data` actions (until the matching
1616/// `terminal/commandFinished`) constitute this command's output.
1617#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1618#[serde(rename_all = "camelCase")]
1619pub struct TerminalCommandExecutedAction {
1620 /// Stable identifier for this command, scoped to the terminal URI.
1621 /// Allows correlating `commandExecuted` → `commandFinished` pairs.
1622 pub command_id: String,
1623 /// The command line text that was submitted
1624 pub command_line: String,
1625 /// Unix timestamp (ms) of when the command started executing, as measured
1626 /// on the server.
1627 pub timestamp: i64,
1628}
1629
1630/// A command has finished executing.
1631///
1632/// The sequence of `terminal/data` actions between the preceding
1633/// `terminal/commandExecuted` (same `commandId`) and this action constitutes
1634/// the complete output of the command.
1635#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1636#[serde(rename_all = "camelCase")]
1637pub struct TerminalCommandFinishedAction {
1638 /// Matches the `commandId` from the corresponding `commandExecuted`
1639 pub command_id: String,
1640 /// Shell exit code. `undefined` if the shell did not report one.
1641 #[serde(default, skip_serializing_if = "Option::is_none")]
1642 pub exit_code: Option<i64>,
1643 /// Wall-clock duration of the command in milliseconds, as measured by the
1644 /// shell integration script on the server side.
1645 #[serde(default, skip_serializing_if = "Option::is_none")]
1646 pub duration_ms: Option<i64>,
1647}
1648
1649/// A batch of resource changes observed by the watcher.
1650///
1651/// Watch events are coalesced into batches by the server to keep the
1652/// action stream tractable; an empty `changes.items` list MUST NOT be
1653/// dispatched. The reducer does not retain change history — these
1654/// actions exist purely to deliver events to subscribers, who consume
1655/// them directly off the action stream and apply their own logic.
1656#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1657#[serde(rename_all = "camelCase")]
1658pub struct ResourceWatchChangedAction {
1659 /// The set of changes in this batch, wrapped for forward compatibility.
1660 pub changes: AnyValue,
1661}
1662
1663// ─── Partial Summaries ────────────────────────────────────────────────
1664
1665/// Partial equivalent of ChatSummary — every field is optional for delta updates.
1666#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Default)]
1667#[serde(rename_all = "camelCase")]
1668pub struct PartialChatSummary {
1669 /// Chat URI
1670 #[serde(default, skip_serializing_if = "Option::is_none")]
1671 pub resource: Option<Uri>,
1672 /// Chat title
1673 #[serde(default, skip_serializing_if = "Option::is_none")]
1674 pub title: Option<String>,
1675 /// Current chat status (reuses SessionStatus shape)
1676 #[serde(default, skip_serializing_if = "Option::is_none")]
1677 pub status: Option<u32>,
1678 /// Human-readable description of what the chat is currently doing
1679 #[serde(default, skip_serializing_if = "Option::is_none")]
1680 pub activity: Option<String>,
1681 /// Last modification timestamp (ISO 8601, e.g. `"2025-03-10T18:42:03.123Z"`)
1682 #[serde(default, skip_serializing_if = "Option::is_none")]
1683 pub modified_at: Option<String>,
1684 /// How this chat came into existence
1685 #[serde(default, skip_serializing_if = "Option::is_none")]
1686 pub origin: Option<ChatOrigin>,
1687 /// How the user can interact with this chat. See {@link ChatInteractivity}.
1688 ///
1689 /// Supports agent-team patterns where worker chats are read-only or hidden.
1690 /// Absence defaults to {@link ChatInteractivity.Full} for backward
1691 /// compatibility.
1692 #[serde(default, skip_serializing_if = "Option::is_none")]
1693 pub interactivity: Option<ChatInteractivity>,
1694 /// Optional per-chat working directory.
1695 ///
1696 /// If absent, the chat inherits
1697 /// {@link SessionSummary.workingDirectory | the session's working directory}.
1698 /// See {@link ChatState.workingDirectory} for usage notes.
1699 #[serde(default, skip_serializing_if = "Option::is_none")]
1700 pub working_directory: Option<Uri>,
1701}
1702
1703// ─── StateAction Union ───────────────────────────────────────────────
1704
1705/// Discriminated union of every state action.
1706#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1707#[serde(tag = "type")]
1708pub enum StateAction {
1709 #[serde(rename = "root/agentsChanged")]
1710 RootAgentsChanged(RootAgentsChangedAction),
1711 #[serde(rename = "root/activeSessionsChanged")]
1712 RootActiveSessionsChanged(RootActiveSessionsChangedAction),
1713 #[serde(rename = "root/configChanged")]
1714 RootConfigChanged(RootConfigChangedAction),
1715 #[serde(rename = "session/ready")]
1716 SessionReady(SessionReadyAction),
1717 #[serde(rename = "session/creationFailed")]
1718 SessionCreationFailed(SessionCreationFailedAction),
1719 #[serde(rename = "session/chatAdded")]
1720 SessionChatAdded(SessionChatAddedAction),
1721 #[serde(rename = "session/chatRemoved")]
1722 SessionChatRemoved(SessionChatRemovedAction),
1723 #[serde(rename = "session/chatUpdated")]
1724 SessionChatUpdated(SessionChatUpdatedAction),
1725 #[serde(rename = "session/defaultChatChanged")]
1726 SessionDefaultChatChanged(SessionDefaultChatChangedAction),
1727 #[serde(rename = "chat/turnStarted")]
1728 ChatTurnStarted(ChatTurnStartedAction),
1729 #[serde(rename = "chat/delta")]
1730 ChatDelta(ChatDeltaAction),
1731 #[serde(rename = "chat/responsePart")]
1732 ChatResponsePart(ChatResponsePartAction),
1733 #[serde(rename = "chat/toolCallStart")]
1734 ChatToolCallStart(ChatToolCallStartAction),
1735 #[serde(rename = "chat/toolCallDelta")]
1736 ChatToolCallDelta(ChatToolCallDeltaAction),
1737 #[serde(rename = "chat/toolCallReady")]
1738 ChatToolCallReady(ChatToolCallReadyAction),
1739 #[serde(rename = "chat/toolCallConfirmed")]
1740 ChatToolCallConfirmed(ChatToolCallConfirmedAction),
1741 #[serde(rename = "chat/toolCallComplete")]
1742 ChatToolCallComplete(ChatToolCallCompleteAction),
1743 #[serde(rename = "chat/toolCallResultConfirmed")]
1744 ChatToolCallResultConfirmed(ChatToolCallResultConfirmedAction),
1745 #[serde(rename = "chat/toolCallContentChanged")]
1746 ChatToolCallContentChanged(ChatToolCallContentChangedAction),
1747 #[serde(rename = "chat/toolCallAuthRequired")]
1748 ChatToolCallAuthRequired(ChatToolCallAuthRequiredAction),
1749 #[serde(rename = "chat/toolCallAuthResolved")]
1750 ChatToolCallAuthResolved(ChatToolCallAuthResolvedAction),
1751 #[serde(rename = "chat/turnComplete")]
1752 ChatTurnComplete(ChatTurnCompleteAction),
1753 #[serde(rename = "chat/turnCancelled")]
1754 ChatTurnCancelled(ChatTurnCancelledAction),
1755 #[serde(rename = "chat/error")]
1756 ChatError(ChatErrorAction),
1757 #[serde(rename = "chat/activityChanged")]
1758 ChatActivityChanged(ChatActivityChangedAction),
1759 #[serde(rename = "session/titleChanged")]
1760 SessionTitleChanged(SessionTitleChangedAction),
1761 #[serde(rename = "chat/usage")]
1762 ChatUsage(ChatUsageAction),
1763 #[serde(rename = "chat/reasoning")]
1764 ChatReasoning(ChatReasoningAction),
1765 #[serde(rename = "session/isReadChanged")]
1766 SessionIsReadChanged(SessionIsReadChangedAction),
1767 #[serde(rename = "session/isArchivedChanged")]
1768 SessionIsArchivedChanged(SessionIsArchivedChangedAction),
1769 #[serde(rename = "session/activityChanged")]
1770 SessionActivityChanged(SessionActivityChangedAction),
1771 #[serde(rename = "session/changesetsChanged")]
1772 SessionChangesetsChanged(SessionChangesetsChangedAction),
1773 #[serde(rename = "session/serverToolsChanged")]
1774 SessionServerToolsChanged(SessionServerToolsChangedAction),
1775 #[serde(rename = "session/activeClientSet")]
1776 SessionActiveClientSet(SessionActiveClientSetAction),
1777 #[serde(rename = "session/activeClientRemoved")]
1778 SessionActiveClientRemoved(SessionActiveClientRemovedAction),
1779 #[serde(rename = "session/inputNeededSet")]
1780 SessionInputNeededSet(Box<SessionInputNeededSetAction>),
1781 #[serde(rename = "session/inputNeededRemoved")]
1782 SessionInputNeededRemoved(SessionInputNeededRemovedAction),
1783 #[serde(rename = "chat/pendingMessageSet")]
1784 ChatPendingMessageSet(ChatPendingMessageSetAction),
1785 #[serde(rename = "chat/pendingMessageRemoved")]
1786 ChatPendingMessageRemoved(ChatPendingMessageRemovedAction),
1787 #[serde(rename = "chat/queuedMessagesReordered")]
1788 ChatQueuedMessagesReordered(ChatQueuedMessagesReorderedAction),
1789 #[serde(rename = "chat/draftChanged")]
1790 ChatDraftChanged(ChatDraftChangedAction),
1791 #[serde(rename = "chat/inputRequested")]
1792 ChatInputRequested(ChatInputRequestedAction),
1793 #[serde(rename = "chat/inputAnswerChanged")]
1794 ChatInputAnswerChanged(ChatInputAnswerChangedAction),
1795 #[serde(rename = "chat/inputCompleted")]
1796 ChatInputCompleted(ChatInputCompletedAction),
1797 #[serde(rename = "session/customizationsChanged")]
1798 SessionCustomizationsChanged(SessionCustomizationsChangedAction),
1799 #[serde(rename = "session/customizationToggled")]
1800 SessionCustomizationToggled(SessionCustomizationToggledAction),
1801 #[serde(rename = "session/customizationUpdated")]
1802 SessionCustomizationUpdated(Box<SessionCustomizationUpdatedAction>),
1803 #[serde(rename = "session/customizationRemoved")]
1804 SessionCustomizationRemoved(SessionCustomizationRemovedAction),
1805 #[serde(rename = "session/mcpServerStateChanged")]
1806 SessionMcpServerStateChanged(Box<SessionMcpServerStateChangedAction>),
1807 #[serde(rename = "session/mcpServerStartRequested")]
1808 SessionMcpServerStartRequested(SessionMcpServerStartRequestedAction),
1809 #[serde(rename = "session/mcpServerStopRequested")]
1810 SessionMcpServerStopRequested(SessionMcpServerStopRequestedAction),
1811 #[serde(rename = "chat/truncated")]
1812 ChatTruncated(ChatTruncatedAction),
1813 #[serde(rename = "chat/turnsLoaded")]
1814 ChatTurnsLoaded(ChatTurnsLoadedAction),
1815 #[serde(rename = "session/configChanged")]
1816 SessionConfigChanged(SessionConfigChangedAction),
1817 #[serde(rename = "session/metaChanged")]
1818 SessionMetaChanged(SessionMetaChangedAction),
1819 #[serde(rename = "changeset/statusChanged")]
1820 ChangesetStatusChanged(ChangesetStatusChangedAction),
1821 #[serde(rename = "changeset/fileSet")]
1822 ChangesetFileSet(ChangesetFileSetAction),
1823 #[serde(rename = "changeset/fileRemoved")]
1824 ChangesetFileRemoved(ChangesetFileRemovedAction),
1825 #[serde(rename = "changeset/filesReviewChanged")]
1826 ChangesetFilesReviewChanged(ChangesetFilesReviewChangedAction),
1827 #[serde(rename = "changeset/contentChanged")]
1828 ChangesetContentChanged(Box<ChangesetContentChangedAction>),
1829 #[serde(rename = "changeset/operationsChanged")]
1830 ChangesetOperationsChanged(ChangesetOperationsChangedAction),
1831 #[serde(rename = "changeset/operationStatusChanged")]
1832 ChangesetOperationStatusChanged(ChangesetOperationStatusChangedAction),
1833 #[serde(rename = "changeset/cleared")]
1834 ChangesetCleared(ChangesetClearedAction),
1835 #[serde(rename = "annotations/set")]
1836 AnnotationsSet(AnnotationsSetAction),
1837 #[serde(rename = "annotations/updated")]
1838 AnnotationsUpdated(AnnotationsUpdatedAction),
1839 #[serde(rename = "annotations/removed")]
1840 AnnotationsRemoved(AnnotationsRemovedAction),
1841 #[serde(rename = "annotations/entrySet")]
1842 AnnotationsEntrySet(AnnotationsEntrySetAction),
1843 #[serde(rename = "annotations/entryRemoved")]
1844 AnnotationsEntryRemoved(AnnotationsEntryRemovedAction),
1845 #[serde(rename = "root/terminalsChanged")]
1846 RootTerminalsChanged(RootTerminalsChangedAction),
1847 #[serde(rename = "terminal/data")]
1848 TerminalData(TerminalDataAction),
1849 #[serde(rename = "terminal/input")]
1850 TerminalInput(TerminalInputAction),
1851 #[serde(rename = "terminal/resized")]
1852 TerminalResized(TerminalResizedAction),
1853 #[serde(rename = "terminal/claimed")]
1854 TerminalClaimed(TerminalClaimedAction),
1855 #[serde(rename = "terminal/titleChanged")]
1856 TerminalTitleChanged(TerminalTitleChangedAction),
1857 #[serde(rename = "terminal/cwdChanged")]
1858 TerminalCwdChanged(TerminalCwdChangedAction),
1859 #[serde(rename = "terminal/exited")]
1860 TerminalExited(TerminalExitedAction),
1861 #[serde(rename = "terminal/cleared")]
1862 TerminalCleared(TerminalClearedAction),
1863 #[serde(rename = "terminal/commandDetectionAvailable")]
1864 TerminalCommandDetectionAvailable(TerminalCommandDetectionAvailableAction),
1865 #[serde(rename = "terminal/commandExecuted")]
1866 TerminalCommandExecuted(TerminalCommandExecutedAction),
1867 #[serde(rename = "terminal/commandFinished")]
1868 TerminalCommandFinished(TerminalCommandFinishedAction),
1869 #[serde(rename = "resourceWatch/changed")]
1870 ResourceWatchChanged(ResourceWatchChangedAction),
1871 /// Unknown or future variant — preserved as raw JSON for round-trip fidelity.
1872 /// Reducers treat this as a no-op.
1873 #[serde(untagged)]
1874 Unknown(serde_json::Value),
1875}