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