Skip to main content

ahp_types/
actions.rs

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