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
14use crate::state::{
15    AgentInfo, AgentSelection, ChangesetFile, ChangesetOperation, ChangesetStatus,
16    ChangesetSummary, ConfirmationOption, Customization, ErrorInfo, ModelSelection,
17    PendingMessageKind, ResponsePart, SessionActiveClient, SessionInputAnswer, SessionInputRequest,
18    SessionInputResponseKind, TerminalClaim, TerminalInfo, ToolCallCancellationReason,
19    ToolCallConfirmationReason, ToolCallResult, ToolDefinition, ToolResultContent, UsageInfo,
20    UserMessage,
21};
22
23// ─── ActionType ──────────────────────────────────────────────────────
24
25/// Discriminant values for all state actions.
26#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
27pub enum ActionType {
28    #[serde(rename = "root/agentsChanged")]
29    RootAgentsChanged,
30    #[serde(rename = "root/activeSessionsChanged")]
31    RootActiveSessionsChanged,
32    #[serde(rename = "session/ready")]
33    SessionReady,
34    #[serde(rename = "session/creationFailed")]
35    SessionCreationFailed,
36    #[serde(rename = "session/turnStarted")]
37    SessionTurnStarted,
38    #[serde(rename = "session/delta")]
39    SessionDelta,
40    #[serde(rename = "session/responsePart")]
41    SessionResponsePart,
42    #[serde(rename = "session/toolCallStart")]
43    SessionToolCallStart,
44    #[serde(rename = "session/toolCallDelta")]
45    SessionToolCallDelta,
46    #[serde(rename = "session/toolCallReady")]
47    SessionToolCallReady,
48    #[serde(rename = "session/toolCallConfirmed")]
49    SessionToolCallConfirmed,
50    #[serde(rename = "session/toolCallComplete")]
51    SessionToolCallComplete,
52    #[serde(rename = "session/toolCallResultConfirmed")]
53    SessionToolCallResultConfirmed,
54    #[serde(rename = "session/toolCallContentChanged")]
55    SessionToolCallContentChanged,
56    #[serde(rename = "session/turnComplete")]
57    SessionTurnComplete,
58    #[serde(rename = "session/turnCancelled")]
59    SessionTurnCancelled,
60    #[serde(rename = "session/error")]
61    SessionError,
62    #[serde(rename = "session/titleChanged")]
63    SessionTitleChanged,
64    #[serde(rename = "session/usage")]
65    SessionUsage,
66    #[serde(rename = "session/reasoning")]
67    SessionReasoning,
68    #[serde(rename = "session/modelChanged")]
69    SessionModelChanged,
70    #[serde(rename = "session/agentChanged")]
71    SessionAgentChanged,
72    #[serde(rename = "session/serverToolsChanged")]
73    SessionServerToolsChanged,
74    #[serde(rename = "session/activeClientChanged")]
75    SessionActiveClientChanged,
76    #[serde(rename = "session/activeClientToolsChanged")]
77    SessionActiveClientToolsChanged,
78    #[serde(rename = "session/pendingMessageSet")]
79    SessionPendingMessageSet,
80    #[serde(rename = "session/pendingMessageRemoved")]
81    SessionPendingMessageRemoved,
82    #[serde(rename = "session/queuedMessagesReordered")]
83    SessionQueuedMessagesReordered,
84    #[serde(rename = "session/inputRequested")]
85    SessionInputRequested,
86    #[serde(rename = "session/inputAnswerChanged")]
87    SessionInputAnswerChanged,
88    #[serde(rename = "session/inputCompleted")]
89    SessionInputCompleted,
90    #[serde(rename = "session/customizationsChanged")]
91    SessionCustomizationsChanged,
92    #[serde(rename = "session/customizationToggled")]
93    SessionCustomizationToggled,
94    #[serde(rename = "session/customizationUpdated")]
95    SessionCustomizationUpdated,
96    #[serde(rename = "session/customizationRemoved")]
97    SessionCustomizationRemoved,
98    #[serde(rename = "session/truncated")]
99    SessionTruncated,
100    #[serde(rename = "session/isReadChanged")]
101    SessionIsReadChanged,
102    #[serde(rename = "session/isArchivedChanged")]
103    SessionIsArchivedChanged,
104    #[serde(rename = "session/activityChanged")]
105    SessionActivityChanged,
106    #[serde(rename = "session/changesetsChanged")]
107    SessionChangesetsChanged,
108    #[serde(rename = "session/configChanged")]
109    SessionConfigChanged,
110    #[serde(rename = "session/metaChanged")]
111    SessionMetaChanged,
112    #[serde(rename = "changeset/statusChanged")]
113    ChangesetStatusChanged,
114    #[serde(rename = "changeset/fileSet")]
115    ChangesetFileSet,
116    #[serde(rename = "changeset/fileRemoved")]
117    ChangesetFileRemoved,
118    #[serde(rename = "changeset/operationsChanged")]
119    ChangesetOperationsChanged,
120    #[serde(rename = "changeset/cleared")]
121    ChangesetCleared,
122    #[serde(rename = "root/terminalsChanged")]
123    RootTerminalsChanged,
124    #[serde(rename = "root/configChanged")]
125    RootConfigChanged,
126    #[serde(rename = "terminal/data")]
127    TerminalData,
128    #[serde(rename = "terminal/input")]
129    TerminalInput,
130    #[serde(rename = "terminal/resized")]
131    TerminalResized,
132    #[serde(rename = "terminal/claimed")]
133    TerminalClaimed,
134    #[serde(rename = "terminal/titleChanged")]
135    TerminalTitleChanged,
136    #[serde(rename = "terminal/cwdChanged")]
137    TerminalCwdChanged,
138    #[serde(rename = "terminal/exited")]
139    TerminalExited,
140    #[serde(rename = "terminal/cleared")]
141    TerminalCleared,
142    #[serde(rename = "terminal/commandDetectionAvailable")]
143    TerminalCommandDetectionAvailable,
144    #[serde(rename = "terminal/commandExecuted")]
145    TerminalCommandExecuted,
146    #[serde(rename = "terminal/commandFinished")]
147    TerminalCommandFinished,
148    #[serde(rename = "resourceWatch/changed")]
149    ResourceWatchChanged,
150}
151
152// ─── Action Envelope ─────────────────────────────────────────────────
153
154/// Identifies the client that originally dispatched an action.
155#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
156#[serde(rename_all = "camelCase")]
157pub struct ActionOrigin {
158    pub client_id: String,
159    pub client_seq: i64,
160}
161
162/// Every action is wrapped in an `ActionEnvelope`.
163///
164/// The envelope identifies the channel the action belongs to (e.g.
165/// `ahp-root://` for root actions, the session URI for session actions, the
166/// terminal URI for terminal actions). Individual action payloads carry only
167/// fields that are intrinsic to the action; the channel comes from the
168/// envelope so that any subscribable resource can route its actions uniformly.
169#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
170#[serde(rename_all = "camelCase")]
171pub struct ActionEnvelope {
172    /// Channel URI this action belongs to.
173    pub channel: Uri,
174    pub action: StateAction,
175    pub server_seq: u64,
176    pub origin: Option<ActionOrigin>,
177    #[serde(default, skip_serializing_if = "Option::is_none")]
178    pub rejection_reason: Option<String>,
179}
180
181// ─── Action Payloads ─────────────────────────────────────────────────
182
183/// Fired when available agent backends or their models change.
184#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
185#[serde(rename_all = "camelCase")]
186pub struct RootAgentsChangedAction {
187    /// Updated agent list
188    pub agents: Vec<AgentInfo>,
189}
190
191/// Fired when the number of active sessions changes.
192#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
193#[serde(rename_all = "camelCase")]
194pub struct RootActiveSessionsChangedAction {
195    /// Current count of active sessions
196    pub active_sessions: i64,
197}
198
199/// Fired when agent-host configuration values change.
200///
201/// By default, the reducer merges the new values into `state.config.values`.
202/// Set `replace` to `true` to replace all values instead of merging.
203#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
204#[serde(rename_all = "camelCase")]
205pub struct RootConfigChangedAction {
206    /// Updated config values
207    pub config: JsonObject,
208    /// When `true`, replaces all config values instead of merging
209    #[serde(default, skip_serializing_if = "Option::is_none")]
210    pub replace: Option<bool>,
211}
212
213/// Session backend initialized successfully.
214#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
215#[serde(rename_all = "camelCase")]
216pub struct SessionReadyAction {}
217
218/// Session backend failed to initialize.
219#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
220#[serde(rename_all = "camelCase")]
221pub struct SessionCreationFailedAction {
222    /// Error details
223    pub error: ErrorInfo,
224}
225
226/// User sent a message; server starts agent processing.
227#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
228#[serde(rename_all = "camelCase")]
229pub struct SessionTurnStartedAction {
230    /// Turn identifier
231    pub turn_id: String,
232    /// User's message
233    pub user_message: UserMessage,
234    /// If this turn was auto-started from a queued message, the ID of that message
235    #[serde(default, skip_serializing_if = "Option::is_none")]
236    pub queued_message_id: Option<String>,
237}
238
239/// Streaming text chunk from the assistant, appended to a specific response part.
240///
241/// The server MUST first emit a `session/responsePart` to create the target
242/// part (markdown or reasoning), then use this action to append text to it.
243#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
244#[serde(rename_all = "camelCase")]
245pub struct SessionDeltaAction {
246    /// Turn identifier
247    pub turn_id: String,
248    /// Identifier of the response part to append to
249    pub part_id: String,
250    /// Text chunk
251    pub content: String,
252}
253
254/// Structured content appended to the response.
255#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
256#[serde(rename_all = "camelCase")]
257pub struct SessionResponsePartAction {
258    /// Turn identifier
259    pub turn_id: String,
260    /// Response part (markdown or content ref)
261    pub part: ResponsePart,
262}
263
264/// A tool call begins — parameters are streaming from the LM.
265///
266/// For client-provided tools, the server sets `toolClientId` to identify the
267/// owning client. That client is responsible for executing the tool once it
268/// reaches the `running` state and dispatching `session/toolCallComplete`.
269#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
270#[serde(rename_all = "camelCase")]
271pub struct SessionToolCallStartAction {
272    /// Turn identifier
273    pub turn_id: String,
274    /// Tool call identifier
275    pub tool_call_id: String,
276    /// Additional provider-specific metadata for this tool call.
277    ///
278    /// Clients MAY look for well-known keys here to provide enhanced UI.
279    /// For example, a `ptyTerminal` key with `{ input: string; output: string }`
280    /// indicates the tool operated on a terminal (both `input` and `output` may
281    /// contain escape sequences).
282    #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
283    pub meta: Option<JsonObject>,
284    /// Internal tool name (for debugging/logging)
285    pub tool_name: String,
286    /// Human-readable tool name
287    pub display_name: String,
288    /// If this tool is provided by a client, the `clientId` of the owning client.
289    /// Absent for server-side tools.
290    #[serde(default, skip_serializing_if = "Option::is_none")]
291    pub tool_client_id: Option<String>,
292}
293
294/// Streaming partial parameters for a tool call.
295#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
296#[serde(rename_all = "camelCase")]
297pub struct SessionToolCallDeltaAction {
298    /// Turn identifier
299    pub turn_id: String,
300    /// Tool call identifier
301    pub tool_call_id: String,
302    /// Additional provider-specific metadata for this tool call.
303    ///
304    /// Clients MAY look for well-known keys here to provide enhanced UI.
305    /// For example, a `ptyTerminal` key with `{ input: string; output: string }`
306    /// indicates the tool operated on a terminal (both `input` and `output` may
307    /// contain escape sequences).
308    #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
309    pub meta: Option<JsonObject>,
310    /// Partial parameter content to append
311    pub content: String,
312    /// Updated progress message
313    #[serde(default, skip_serializing_if = "Option::is_none")]
314    pub invocation_message: Option<StringOrMarkdown>,
315}
316
317/// Tool call parameters are complete, or a running tool requires re-confirmation.
318///
319/// When dispatched for a `streaming` tool call, transitions to `pending-confirmation`
320/// or directly to `running` if `confirmed` is set.
321///
322/// When dispatched for a `running` tool call (e.g. mid-execution permission needed),
323/// transitions back to `pending-confirmation`. The `invocationMessage` and `_meta`
324/// SHOULD be updated to describe the specific confirmation needed. Clients use the
325/// standard `session/toolCallConfirmed` flow to approve or deny.
326///
327/// For client-provided tools, the server typically sets `confirmed` to
328/// `'not-needed'` so the tool transitions directly to `running`, where the
329/// owning client can begin execution immediately.
330#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
331#[serde(rename_all = "camelCase")]
332pub struct SessionToolCallReadyAction {
333    /// Turn identifier
334    pub turn_id: String,
335    /// Tool call identifier
336    pub tool_call_id: String,
337    /// Additional provider-specific metadata for this tool call.
338    ///
339    /// Clients MAY look for well-known keys here to provide enhanced UI.
340    /// For example, a `ptyTerminal` key with `{ input: string; output: string }`
341    /// indicates the tool operated on a terminal (both `input` and `output` may
342    /// contain escape sequences).
343    #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
344    pub meta: Option<JsonObject>,
345    /// Message describing what the tool will do or what confirmation is needed
346    pub invocation_message: StringOrMarkdown,
347    /// Raw tool input
348    #[serde(default, skip_serializing_if = "Option::is_none")]
349    pub tool_input: Option<String>,
350    /// Short title for the confirmation prompt (e.g. `"Run in terminal"`, `"Write file"`)
351    #[serde(default, skip_serializing_if = "Option::is_none")]
352    pub confirmation_title: Option<StringOrMarkdown>,
353    /// File edits that this tool call will perform, for preview before confirmation
354    #[serde(default, skip_serializing_if = "Option::is_none")]
355    pub edits: Option<AnyValue>,
356    /// Whether the agent host allows the client to edit the tool's input parameters before confirming
357    #[serde(default, skip_serializing_if = "Option::is_none")]
358    pub editable: Option<bool>,
359    /// If set, the tool was auto-confirmed and transitions directly to `running`
360    #[serde(default, skip_serializing_if = "Option::is_none")]
361    pub confirmed: Option<ToolCallConfirmationReason>,
362    /// Options the server offers for this confirmation. When present, the client
363    /// SHOULD render these instead of a plain approve/deny UI. Each option
364    /// belongs to a {@link ConfirmationOptionGroup} so the client can still
365    /// categorise the choices.
366    #[serde(default, skip_serializing_if = "Option::is_none")]
367    pub options: Option<Vec<ConfirmationOption>>,
368}
369
370/// Client approves or denies a pending tool call (merged approved + denied variants).
371#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
372#[serde(rename_all = "camelCase")]
373pub struct SessionToolCallConfirmedAction {
374    pub turn_id: String,
375    pub tool_call_id: String,
376    /// Additional provider-specific metadata for this tool call.
377    #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
378    pub meta: Option<JsonObject>,
379    /// Whether the tool call was approved.
380    pub approved: bool,
381    /// How the tool was confirmed (present when approved).
382    #[serde(default, skip_serializing_if = "Option::is_none")]
383    pub confirmed: Option<ToolCallConfirmationReason>,
384    /// Why the tool was cancelled (present when denied).
385    #[serde(default, skip_serializing_if = "Option::is_none")]
386    pub reason: Option<ToolCallCancellationReason>,
387    /// Edited tool input parameters, if the client modified them before confirming.
388    #[serde(default, skip_serializing_if = "Option::is_none")]
389    pub edited_tool_input: Option<String>,
390    /// What the user suggested doing instead (present when denied).
391    #[serde(default, skip_serializing_if = "Option::is_none")]
392    pub user_suggestion: Option<UserMessage>,
393    /// Explanation for the denial.
394    #[serde(default, skip_serializing_if = "Option::is_none")]
395    pub reason_message: Option<StringOrMarkdown>,
396    /// ID of the selected confirmation option, if the server provided options.
397    #[serde(default, skip_serializing_if = "Option::is_none")]
398    pub selected_option_id: Option<String>,
399}
400
401/// Tool execution finished. Transitions to `completed` or `pending-result-confirmation`
402/// if `requiresResultConfirmation` is `true`.
403///
404/// For client-provided tools (where `toolClientId` is set on the tool call state),
405/// the owning client dispatches this action with the execution result. The server
406/// SHOULD reject this action if the dispatching client does not match `toolClientId`.
407///
408/// Servers waiting on a client tool call MAY time out after a reasonable duration
409/// if the implementing client disconnects or becomes unresponsive, and dispatch
410/// this action with `result.success = false` and an appropriate error.
411#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
412#[serde(rename_all = "camelCase")]
413pub struct SessionToolCallCompleteAction {
414    /// Turn identifier
415    pub turn_id: String,
416    /// Tool call identifier
417    pub tool_call_id: String,
418    /// Additional provider-specific metadata for this tool call.
419    ///
420    /// Clients MAY look for well-known keys here to provide enhanced UI.
421    /// For example, a `ptyTerminal` key with `{ input: string; output: string }`
422    /// indicates the tool operated on a terminal (both `input` and `output` may
423    /// contain escape sequences).
424    #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
425    pub meta: Option<JsonObject>,
426    /// Execution result
427    pub result: ToolCallResult,
428    /// If true, the result requires client approval before finalizing
429    #[serde(default, skip_serializing_if = "Option::is_none")]
430    pub requires_result_confirmation: Option<bool>,
431}
432
433/// Client approves or denies a tool's result.
434///
435/// If `approved` is `false`, the tool transitions to `cancelled` with reason `result-denied`.
436#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
437#[serde(rename_all = "camelCase")]
438pub struct SessionToolCallResultConfirmedAction {
439    /// Turn identifier
440    pub turn_id: String,
441    /// Tool call identifier
442    pub tool_call_id: String,
443    /// Additional provider-specific metadata for this tool call.
444    ///
445    /// Clients MAY look for well-known keys here to provide enhanced UI.
446    /// For example, a `ptyTerminal` key with `{ input: string; output: string }`
447    /// indicates the tool operated on a terminal (both `input` and `output` may
448    /// contain escape sequences).
449    #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
450    pub meta: Option<JsonObject>,
451    /// Whether the result was approved
452    pub approved: bool,
453}
454
455/// Turn finished — the assistant is idle.
456#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
457#[serde(rename_all = "camelCase")]
458pub struct SessionTurnCompleteAction {
459    /// Turn identifier
460    pub turn_id: String,
461}
462
463/// Turn was aborted; server stops processing.
464#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
465#[serde(rename_all = "camelCase")]
466pub struct SessionTurnCancelledAction {
467    /// Turn identifier
468    pub turn_id: String,
469}
470
471/// Error during turn processing.
472#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
473#[serde(rename_all = "camelCase")]
474pub struct SessionErrorAction {
475    /// Turn identifier
476    pub turn_id: String,
477    /// Error details
478    pub error: ErrorInfo,
479}
480
481/// Session title updated. Fired by the server when the title is auto-generated
482/// from conversation, or dispatched by a client to rename a session.
483#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
484#[serde(rename_all = "camelCase")]
485pub struct SessionTitleChangedAction {
486    /// New title
487    pub title: String,
488}
489
490/// Token usage report for a turn.
491#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
492#[serde(rename_all = "camelCase")]
493pub struct SessionUsageAction {
494    /// Turn identifier
495    pub turn_id: String,
496    /// Token usage data
497    pub usage: UsageInfo,
498}
499
500/// Reasoning/thinking text from the model, appended to a specific reasoning response part.
501///
502/// The server MUST first emit a `session/responsePart` to create the target
503/// reasoning part, then use this action to append text to it.
504#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
505#[serde(rename_all = "camelCase")]
506pub struct SessionReasoningAction {
507    /// Turn identifier
508    pub turn_id: String,
509    /// Identifier of the reasoning response part to append to
510    pub part_id: String,
511    /// Reasoning text chunk
512    pub content: String,
513}
514
515/// Model changed for this session.
516#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
517#[serde(rename_all = "camelCase")]
518pub struct SessionModelChangedAction {
519    /// New model selection
520    pub model: ModelSelection,
521}
522
523/// Custom agent selection changed for this session.
524///
525/// Omitting `agent` (or setting it to `undefined`) clears the selection and
526/// resets the session to no selected custom agent (provider default behavior).
527///
528/// When a turn is currently active, the server MUST defer the change until
529/// the active turn completes, then apply it for the next turn (same rule as
530/// {@link SessionModelChangedAction | `session/modelChanged`}).
531#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Default)]
532#[serde(rename_all = "camelCase")]
533pub struct SessionAgentChangedAction {
534    /// New agent selection, or `undefined` to clear the selection and reset the
535    /// session to no selected custom agent.
536    #[serde(default, skip_serializing_if = "Option::is_none")]
537    pub agent: Option<AgentSelection>,
538}
539
540/// The read state of the session changed.
541///
542/// Dispatched by a client to mark a session as read (e.g. after viewing it)
543/// or unread (e.g. after new activity since the client last looked at it).
544#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
545#[serde(rename_all = "camelCase")]
546pub struct SessionIsReadChangedAction {
547    /// Whether the session has been read
548    pub is_read: bool,
549}
550
551/// The archived state of the session changed.
552///
553/// Dispatched by a client to archive a session (e.g. the task is
554/// complete) or to unarchive it.
555#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
556#[serde(rename_all = "camelCase")]
557pub struct SessionIsArchivedChangedAction {
558    /// Whether the session is archived
559    pub is_archived: bool,
560}
561
562/// The activity description of the session changed.
563///
564/// Dispatched by the server to indicate what the session is currently doing
565/// (e.g. running a tool, thinking). Clear activity by setting it to `undefined`.
566#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Default)]
567#[serde(rename_all = "camelCase")]
568pub struct SessionActivityChangedAction {
569    /// Human-readable description of current activity, or `undefined` to clear
570    #[serde(default, skip_serializing_if = "Option::is_none")]
571    pub activity: Option<String>,
572}
573
574/// The {@link ChangesetSummary | catalogue of changesets} the agent host
575/// advertises for this session changed. Replaces
576/// `state.summary.changesets` entirely (full-replacement semantics) — set
577/// to `undefined` to clear the catalogue.
578///
579/// Producers dispatch this whenever entries are added, removed, or have
580/// their aggregate counts (`additions` / `deletions` / `files`) refreshed.
581/// The fan-out happens through this action so observers see catalogue
582/// mutations in the same {@link ChangesetAction | per-changeset} action
583/// stream they already follow for file-level updates.
584#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Default)]
585#[serde(rename_all = "camelCase")]
586pub struct SessionChangesetsChangedAction {
587    /// New catalogue, or `undefined` to clear it
588    #[serde(default, skip_serializing_if = "Option::is_none")]
589    pub changesets: Option<Vec<ChangesetSummary>>,
590}
591
592/// Server tools for this session have changed.
593///
594/// Full-replacement semantics: the `tools` array replaces the previous `serverTools` entirely.
595#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
596#[serde(rename_all = "camelCase")]
597pub struct SessionServerToolsChangedAction {
598    /// Updated server tools list (full replacement)
599    pub tools: Vec<ToolDefinition>,
600}
601
602/// The active client for this session has changed.
603///
604/// A client dispatches this action with its own `SessionActiveClient` to claim
605/// the active role, or with `null` to release it. The server SHOULD reject if
606/// another client is already active. The server SHOULD automatically dispatch
607/// this action with `activeClient: null` when the active client disconnects.
608#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Default)]
609#[serde(rename_all = "camelCase")]
610pub struct SessionActiveClientChangedAction {
611    /// The new active client, or `null` to unset
612    #[serde(default, skip_serializing_if = "Option::is_none")]
613    pub active_client: Option<SessionActiveClient>,
614}
615
616/// The active client's tool list has changed.
617///
618/// Full-replacement semantics: the `tools` array replaces the active client's
619/// previous tools entirely. The server SHOULD reject if the dispatching client
620/// is not the current active client.
621#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
622#[serde(rename_all = "camelCase")]
623pub struct SessionActiveClientToolsChangedAction {
624    /// Updated client tools list (full replacement)
625    pub tools: Vec<ToolDefinition>,
626}
627
628/// A pending message was set (upsert semantics: creates or replaces).
629///
630/// For steering messages, this always replaces the single steering message.
631/// For queued messages, if a message with the given `id` already exists it is
632/// updated in place; otherwise it is appended to the queue. If the session is
633/// idle when a queued message is set, the server SHOULD immediately consume it
634/// and start a new turn.
635#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
636#[serde(rename_all = "camelCase")]
637pub struct SessionPendingMessageSetAction {
638    /// Whether this is a steering or queued message
639    pub kind: PendingMessageKind,
640    /// Unique identifier for this pending message
641    pub id: String,
642    /// The message content
643    pub user_message: UserMessage,
644}
645
646/// A pending message was removed (steering or queued).
647///
648/// Dispatched by clients to cancel a pending message, or by the server when
649/// it consumes a message (e.g. starting a turn from a queued message or
650/// injecting a steering message into the current turn).
651#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
652#[serde(rename_all = "camelCase")]
653pub struct SessionPendingMessageRemovedAction {
654    /// Whether this is a steering or queued message
655    pub kind: PendingMessageKind,
656    /// Identifier of the pending message to remove
657    pub id: String,
658}
659
660/// Reorder the queued messages.
661///
662/// The `order` array contains the IDs of queued messages in their new
663/// desired order. IDs not present in the current queue are ignored.
664/// Queued messages whose IDs are absent from `order` are appended at
665/// the end in their original relative order (so a client with a stale
666/// view of the queue never silently drops messages).
667#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
668#[serde(rename_all = "camelCase")]
669pub struct SessionQueuedMessagesReorderedAction {
670    /// Queued message IDs in the desired order
671    pub order: Vec<String>,
672}
673
674/// A session requested input from the user.
675///
676/// Full-request upsert semantics: the `request` replaces any existing request
677/// with the same `id`, or is appended if it is new. Answer drafts are preserved
678/// unless `request.answers` is provided.
679#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
680#[serde(rename_all = "camelCase")]
681pub struct SessionInputRequestedAction {
682    /// Input request to create or replace
683    pub request: SessionInputRequest,
684}
685
686/// A client updated, submitted, skipped, or removed a single in-progress answer.
687///
688/// Dispatching with `answer: undefined` removes that question's answer draft.
689#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
690#[serde(rename_all = "camelCase")]
691pub struct SessionInputAnswerChangedAction {
692    /// Input request identifier
693    pub request_id: String,
694    /// Question identifier within the input request
695    pub question_id: String,
696    /// Updated answer, or `undefined` to clear an answer draft
697    #[serde(default, skip_serializing_if = "Option::is_none")]
698    pub answer: Option<SessionInputAnswer>,
699}
700
701/// A client accepted, declined, or cancelled a session input request.
702///
703/// If accepted, the server uses `answers` (when provided) plus the request's
704/// synced answer state to resume the blocked operation.
705#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
706#[serde(rename_all = "camelCase")]
707pub struct SessionInputCompletedAction {
708    /// Input request identifier
709    pub request_id: String,
710    /// Completion outcome
711    pub response: SessionInputResponseKind,
712    /// Optional final answer replacement, keyed by question ID
713    #[serde(default, skip_serializing_if = "Option::is_none")]
714    pub answers: Option<std::collections::HashMap<String, SessionInputAnswer>>,
715}
716
717/// The session's customizations have changed.
718///
719/// Full-replacement semantics: the `customizations` array replaces the
720/// previous `customizations` entirely.
721#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
722#[serde(rename_all = "camelCase")]
723pub struct SessionCustomizationsChangedAction {
724    /// Updated customization list (full replacement).
725    pub customizations: Vec<Customization>,
726}
727
728/// A client toggled a container customization on or off.
729///
730/// Targets a top-level container (plugin or directory) by `id`. Only
731/// containers have an `enabled` flag; children are always active when
732/// their container is enabled. Is a no-op when no matching container is
733/// found.
734#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
735#[serde(rename_all = "camelCase")]
736pub struct SessionCustomizationToggledAction {
737    /// The id of the container to toggle.
738    pub id: String,
739    /// Whether to enable or disable the container.
740    pub enabled: bool,
741}
742
743/// Upserts a top-level customization (plugin or directory).
744///
745/// The reducer locates the existing entry by `customization.id`:
746///
747/// - If found, the entry is replaced entirely with `customization`,
748///   including its `children` array. To preserve existing children, the
749///   host must include them on the payload.
750/// - If not found, the entry is appended.
751#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
752#[serde(rename_all = "camelCase")]
753pub struct SessionCustomizationUpdatedAction {
754    /// The customization to upsert (matched by `customization.id`).
755    pub customization: Customization,
756}
757
758/// Removes a customization by id.
759///
760/// Searches every container and its children for the entry. If the entry
761/// is a container, its children are removed with it. Is a no-op when no
762/// matching id is found.
763#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
764#[serde(rename_all = "camelCase")]
765pub struct SessionCustomizationRemovedAction {
766    /// The id of the customization to remove.
767    pub id: String,
768}
769
770/// Truncates a session's history. If `turnId` is provided, all turns after that
771/// turn are removed and the specified turn is kept. If `turnId` is omitted, all
772/// turns are removed.
773///
774/// If there is an active turn it is silently dropped and the session status
775/// returns to `idle`.
776///
777/// Common use-case: truncate old data then dispatch a new
778/// `session/turnStarted` with an edited message.
779#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Default)]
780#[serde(rename_all = "camelCase")]
781pub struct SessionTruncatedAction {
782    /// Keep turns up to and including this turn. Omit to clear all turns.
783    #[serde(default, skip_serializing_if = "Option::is_none")]
784    pub turn_id: Option<String>,
785}
786
787/// Client changed a mutable config value mid-session.
788///
789/// Only properties with `sessionMutable: true` in the config schema may be
790/// changed. The server validates and broadcasts the action; the reducer merges
791/// the new values into `state.config.values`.
792#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
793#[serde(rename_all = "camelCase")]
794pub struct SessionConfigChangedAction {
795    /// Updated config values
796    pub config: JsonObject,
797    /// When `true`, replaces all config values instead of merging
798    #[serde(default, skip_serializing_if = "Option::is_none")]
799    pub replace: Option<bool>,
800}
801
802/// The session's `_meta` side-channel changed. Replaces `state._meta`
803/// entirely (full-replacement semantics). Producers SHOULD merge any
804/// keys they wish to preserve into the new value before dispatching.
805#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Default)]
806#[serde(rename_all = "camelCase")]
807pub struct SessionMetaChangedAction {
808    /// New `_meta` payload, or `undefined` to clear it
809    #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
810    pub meta: Option<JsonObject>,
811}
812
813/// Partial content produced while a tool is still executing.
814///
815/// Replaces the `content` array on the running tool call state. Clients can
816/// use this to display live feedback (e.g. a terminal reference) before the
817/// tool completes.
818///
819/// For client-provided tools (where `toolClientId` is set on the tool call state),
820/// the owning client dispatches this action to stream intermediate content while
821/// executing. The server SHOULD reject this action if the dispatching client does
822/// not match `toolClientId`.
823#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
824#[serde(rename_all = "camelCase")]
825pub struct SessionToolCallContentChangedAction {
826    /// Turn identifier
827    pub turn_id: String,
828    /// Tool call identifier
829    pub tool_call_id: String,
830    /// Additional provider-specific metadata for this tool call.
831    ///
832    /// Clients MAY look for well-known keys here to provide enhanced UI.
833    /// For example, a `ptyTerminal` key with `{ input: string; output: string }`
834    /// indicates the tool operated on a terminal (both `input` and `output` may
835    /// contain escape sequences).
836    #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
837    pub meta: Option<JsonObject>,
838    /// The current partial content for the running tool call
839    pub content: Vec<ToolResultContent>,
840}
841
842/// The {@link ChangesetState.status} for this changeset transitioned (e.g.
843/// `computing → ready`). The error payload is set together with `status`
844/// whenever it transitions to {@link ChangesetStatus.Error | Error}.
845#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
846#[serde(rename_all = "camelCase")]
847pub struct ChangesetStatusChangedAction {
848    /// New computation lifecycle status.
849    pub status: ChangesetStatus,
850    /// Cause when `status === ChangesetStatus.Error`; otherwise omitted.
851    #[serde(default, skip_serializing_if = "Option::is_none")]
852    pub error: Option<ErrorInfo>,
853}
854
855/// Upsert a {@link ChangesetFile} in the changeset — adds a new entry, or
856/// replaces an existing one identified by {@link ChangesetFile.id}.
857#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
858#[serde(rename_all = "camelCase")]
859pub struct ChangesetFileSetAction {
860    /// The new or replacement file entry.
861    pub file: ChangesetFile,
862}
863
864/// Remove a {@link ChangesetFile} from the changeset by its id.
865///
866/// Typically dispatched when a file is reverted, staged out, or otherwise
867/// no longer in scope (e.g. a renamed file is replaced by a new entry).
868#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
869#[serde(rename_all = "camelCase")]
870pub struct ChangesetFileRemovedAction {
871    /// The {@link ChangesetFile.id} of the file to remove.
872    pub file_id: String,
873}
874
875/// The set of operations available on this changeset changed. Full
876/// replacement semantics: `operations` replaces the previous list (or
877/// removes it entirely when `operations` is `undefined`).
878#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Default)]
879#[serde(rename_all = "camelCase")]
880pub struct ChangesetOperationsChangedAction {
881    /// Updated operation list. Pass `undefined` to clear all operations.
882    #[serde(default, skip_serializing_if = "Option::is_none")]
883    pub operations: Option<Vec<ChangesetOperation>>,
884}
885
886/// Drop every file from the changeset.
887///
888/// Two cases use this:
889/// 1. The underlying source moved (branch switched, fork point invalidated,
890///    …) and the server is recomputing from scratch — subsequent
891///    {@link ChangesetFileSetAction} entries will repopulate it.
892/// 2. The owning session has ended and the URI is becoming
893///    un-subscribable — the server will unsubscribe all clients shortly
894///    after dispatching this action.
895///
896/// Clients SHOULD release any references on receipt and SHOULD NOT
897/// distinguish the two cases from the action alone — instead, react to
898/// the corresponding session-level lifecycle signal (e.g.
899/// `root/sessionRemoved`) for the "going away" case.
900#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
901#[serde(rename_all = "camelCase")]
902pub struct ChangesetClearedAction {}
903
904/// Fired when the list of known terminals changes.
905///
906/// Full-replacement semantics: the `terminals` array replaces the previous
907/// `terminals` entirely.
908#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
909#[serde(rename_all = "camelCase")]
910pub struct RootTerminalsChangedAction {
911    /// Updated terminal list (full replacement)
912    pub terminals: Vec<TerminalInfo>,
913}
914
915/// Terminal output data (pty → client direction).
916///
917/// Appends `data` to the terminal's `content` in the reducer.
918///
919/// `terminal/data` and `terminal/input` are intentionally separate actions
920/// because standard write-ahead reconciliation is not safe for terminal I/O.
921/// A pty is a stateful, mutable process — optimistically applying input or
922/// predicting output would produce incorrect state. Instead, `terminal/input`
923/// is a side-effect-only action (client → server → pty), and `terminal/data`
924/// is server-authoritative output (pty → server → client).
925#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
926#[serde(rename_all = "camelCase")]
927pub struct TerminalDataAction {
928    /// Output data (may contain ANSI escape sequences)
929    pub data: String,
930}
931
932/// Keyboard input sent to the terminal process (client → pty direction).
933///
934/// This is a side-effect-only action: the server forwards the data to the
935/// terminal's pty. The reducer treats this as a no-op since `terminal/data`
936/// actions will reflect any resulting output.
937///
938/// See `terminal/data` for why these two actions are kept separate.
939#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
940#[serde(rename_all = "camelCase")]
941pub struct TerminalInputAction {
942    /// Input data to send to the pty
943    pub data: String,
944}
945
946/// Terminal dimensions changed.
947///
948/// Dispatchable by clients to request a resize, or by the server to inform
949/// clients of the actual terminal dimensions.
950#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
951#[serde(rename_all = "camelCase")]
952pub struct TerminalResizedAction {
953    /// Terminal width in columns
954    pub cols: i64,
955    /// Terminal height in rows
956    pub rows: i64,
957}
958
959/// Terminal claim changed. A client or session transfers ownership of the terminal.
960///
961/// The server SHOULD reject if the dispatching client does not currently hold
962/// the claim.
963#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
964#[serde(rename_all = "camelCase")]
965pub struct TerminalClaimedAction {
966    /// The new claim
967    pub claim: TerminalClaim,
968}
969
970/// Terminal title changed.
971///
972/// Fired by the server when the terminal process updates its title (e.g. via
973/// escape sequences), or dispatched by a client to rename a terminal.
974#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
975#[serde(rename_all = "camelCase")]
976pub struct TerminalTitleChangedAction {
977    /// New terminal title
978    pub title: String,
979}
980
981/// Terminal working directory changed.
982#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
983#[serde(rename_all = "camelCase")]
984pub struct TerminalCwdChangedAction {
985    /// New working directory
986    pub cwd: Uri,
987}
988
989/// Terminal process exited.
990#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Default)]
991#[serde(rename_all = "camelCase")]
992pub struct TerminalExitedAction {
993    /// Process exit code. `undefined` if the process was killed without an exit code.
994    #[serde(default, skip_serializing_if = "Option::is_none")]
995    pub exit_code: Option<i64>,
996}
997
998/// Terminal scrollback buffer cleared.
999#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1000#[serde(rename_all = "camelCase")]
1001pub struct TerminalClearedAction {}
1002
1003/// Shell integration has loaded and the terminal now supports command
1004/// detection. The server dispatches this when shell integration becomes
1005/// available (which may happen asynchronously after the terminal is created).
1006///
1007/// Clients MUST NOT assume command detection is available until this action
1008/// (or `terminal/commandExecuted`) has been received.
1009#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1010#[serde(rename_all = "camelCase")]
1011pub struct TerminalCommandDetectionAvailableAction {}
1012
1013/// A command has been submitted to the shell and is now executing.
1014/// All subsequent `terminal/data` actions (until the matching
1015/// `terminal/commandFinished`) constitute this command's output.
1016#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1017#[serde(rename_all = "camelCase")]
1018pub struct TerminalCommandExecutedAction {
1019    /// Stable identifier for this command, scoped to the terminal URI.
1020    /// Allows correlating `commandExecuted` → `commandFinished` pairs.
1021    pub command_id: String,
1022    /// The command line text that was submitted
1023    pub command_line: String,
1024    /// Unix timestamp (ms) of when the command started executing, as measured
1025    /// on the server.
1026    pub timestamp: i64,
1027}
1028
1029/// A command has finished executing.
1030///
1031/// The sequence of `terminal/data` actions between the preceding
1032/// `terminal/commandExecuted` (same `commandId`) and this action constitutes
1033/// the complete output of the command.
1034#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1035#[serde(rename_all = "camelCase")]
1036pub struct TerminalCommandFinishedAction {
1037    /// Matches the `commandId` from the corresponding `commandExecuted`
1038    pub command_id: String,
1039    /// Shell exit code. `undefined` if the shell did not report one.
1040    #[serde(default, skip_serializing_if = "Option::is_none")]
1041    pub exit_code: Option<i64>,
1042    /// Wall-clock duration of the command in milliseconds, as measured by the
1043    /// shell integration script on the server side.
1044    #[serde(default, skip_serializing_if = "Option::is_none")]
1045    pub duration_ms: Option<i64>,
1046}
1047
1048/// A batch of resource changes observed by the watcher.
1049///
1050/// Watch events are coalesced into batches by the server to keep the
1051/// action stream tractable; an empty `changes.items` list MUST NOT be
1052/// dispatched. The reducer does not retain change history — these
1053/// actions exist purely to deliver events to subscribers, who consume
1054/// them directly off the action stream and apply their own logic.
1055#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1056#[serde(rename_all = "camelCase")]
1057pub struct ResourceWatchChangedAction {
1058    /// The set of changes in this batch, wrapped for forward compatibility.
1059    pub changes: AnyValue,
1060}
1061
1062// ─── StateAction Union ───────────────────────────────────────────────
1063
1064/// Discriminated union of every state action.
1065#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1066#[serde(tag = "type")]
1067pub enum StateAction {
1068    #[serde(rename = "root/agentsChanged")]
1069    RootAgentsChanged(RootAgentsChangedAction),
1070    #[serde(rename = "root/activeSessionsChanged")]
1071    RootActiveSessionsChanged(RootActiveSessionsChangedAction),
1072    #[serde(rename = "root/configChanged")]
1073    RootConfigChanged(RootConfigChangedAction),
1074    #[serde(rename = "session/ready")]
1075    SessionReady(SessionReadyAction),
1076    #[serde(rename = "session/creationFailed")]
1077    SessionCreationFailed(SessionCreationFailedAction),
1078    #[serde(rename = "session/turnStarted")]
1079    SessionTurnStarted(SessionTurnStartedAction),
1080    #[serde(rename = "session/delta")]
1081    SessionDelta(SessionDeltaAction),
1082    #[serde(rename = "session/responsePart")]
1083    SessionResponsePart(SessionResponsePartAction),
1084    #[serde(rename = "session/toolCallStart")]
1085    SessionToolCallStart(SessionToolCallStartAction),
1086    #[serde(rename = "session/toolCallDelta")]
1087    SessionToolCallDelta(SessionToolCallDeltaAction),
1088    #[serde(rename = "session/toolCallReady")]
1089    SessionToolCallReady(SessionToolCallReadyAction),
1090    #[serde(rename = "session/toolCallConfirmed")]
1091    SessionToolCallConfirmed(SessionToolCallConfirmedAction),
1092    #[serde(rename = "session/toolCallComplete")]
1093    SessionToolCallComplete(SessionToolCallCompleteAction),
1094    #[serde(rename = "session/toolCallResultConfirmed")]
1095    SessionToolCallResultConfirmed(SessionToolCallResultConfirmedAction),
1096    #[serde(rename = "session/turnComplete")]
1097    SessionTurnComplete(SessionTurnCompleteAction),
1098    #[serde(rename = "session/turnCancelled")]
1099    SessionTurnCancelled(SessionTurnCancelledAction),
1100    #[serde(rename = "session/error")]
1101    SessionError(SessionErrorAction),
1102    #[serde(rename = "session/titleChanged")]
1103    SessionTitleChanged(SessionTitleChangedAction),
1104    #[serde(rename = "session/usage")]
1105    SessionUsage(SessionUsageAction),
1106    #[serde(rename = "session/reasoning")]
1107    SessionReasoning(SessionReasoningAction),
1108    #[serde(rename = "session/modelChanged")]
1109    SessionModelChanged(SessionModelChangedAction),
1110    #[serde(rename = "session/agentChanged")]
1111    SessionAgentChanged(SessionAgentChangedAction),
1112    #[serde(rename = "session/isReadChanged")]
1113    SessionIsReadChanged(SessionIsReadChangedAction),
1114    #[serde(rename = "session/isArchivedChanged")]
1115    SessionIsArchivedChanged(SessionIsArchivedChangedAction),
1116    #[serde(rename = "session/activityChanged")]
1117    SessionActivityChanged(SessionActivityChangedAction),
1118    #[serde(rename = "session/changesetsChanged")]
1119    SessionChangesetsChanged(SessionChangesetsChangedAction),
1120    #[serde(rename = "session/serverToolsChanged")]
1121    SessionServerToolsChanged(SessionServerToolsChangedAction),
1122    #[serde(rename = "session/activeClientChanged")]
1123    SessionActiveClientChanged(SessionActiveClientChangedAction),
1124    #[serde(rename = "session/activeClientToolsChanged")]
1125    SessionActiveClientToolsChanged(SessionActiveClientToolsChangedAction),
1126    #[serde(rename = "session/pendingMessageSet")]
1127    SessionPendingMessageSet(SessionPendingMessageSetAction),
1128    #[serde(rename = "session/pendingMessageRemoved")]
1129    SessionPendingMessageRemoved(SessionPendingMessageRemovedAction),
1130    #[serde(rename = "session/queuedMessagesReordered")]
1131    SessionQueuedMessagesReordered(SessionQueuedMessagesReorderedAction),
1132    #[serde(rename = "session/inputRequested")]
1133    SessionInputRequested(SessionInputRequestedAction),
1134    #[serde(rename = "session/inputAnswerChanged")]
1135    SessionInputAnswerChanged(SessionInputAnswerChangedAction),
1136    #[serde(rename = "session/inputCompleted")]
1137    SessionInputCompleted(SessionInputCompletedAction),
1138    #[serde(rename = "session/customizationsChanged")]
1139    SessionCustomizationsChanged(SessionCustomizationsChangedAction),
1140    #[serde(rename = "session/customizationToggled")]
1141    SessionCustomizationToggled(SessionCustomizationToggledAction),
1142    #[serde(rename = "session/customizationUpdated")]
1143    SessionCustomizationUpdated(SessionCustomizationUpdatedAction),
1144    #[serde(rename = "session/customizationRemoved")]
1145    SessionCustomizationRemoved(SessionCustomizationRemovedAction),
1146    #[serde(rename = "session/truncated")]
1147    SessionTruncated(SessionTruncatedAction),
1148    #[serde(rename = "session/configChanged")]
1149    SessionConfigChanged(SessionConfigChangedAction),
1150    #[serde(rename = "session/metaChanged")]
1151    SessionMetaChanged(SessionMetaChangedAction),
1152    #[serde(rename = "session/toolCallContentChanged")]
1153    SessionToolCallContentChanged(SessionToolCallContentChangedAction),
1154    #[serde(rename = "changeset/statusChanged")]
1155    ChangesetStatusChanged(ChangesetStatusChangedAction),
1156    #[serde(rename = "changeset/fileSet")]
1157    ChangesetFileSet(ChangesetFileSetAction),
1158    #[serde(rename = "changeset/fileRemoved")]
1159    ChangesetFileRemoved(ChangesetFileRemovedAction),
1160    #[serde(rename = "changeset/operationsChanged")]
1161    ChangesetOperationsChanged(ChangesetOperationsChangedAction),
1162    #[serde(rename = "changeset/cleared")]
1163    ChangesetCleared(ChangesetClearedAction),
1164    #[serde(rename = "root/terminalsChanged")]
1165    RootTerminalsChanged(RootTerminalsChangedAction),
1166    #[serde(rename = "terminal/data")]
1167    TerminalData(TerminalDataAction),
1168    #[serde(rename = "terminal/input")]
1169    TerminalInput(TerminalInputAction),
1170    #[serde(rename = "terminal/resized")]
1171    TerminalResized(TerminalResizedAction),
1172    #[serde(rename = "terminal/claimed")]
1173    TerminalClaimed(TerminalClaimedAction),
1174    #[serde(rename = "terminal/titleChanged")]
1175    TerminalTitleChanged(TerminalTitleChangedAction),
1176    #[serde(rename = "terminal/cwdChanged")]
1177    TerminalCwdChanged(TerminalCwdChangedAction),
1178    #[serde(rename = "terminal/exited")]
1179    TerminalExited(TerminalExitedAction),
1180    #[serde(rename = "terminal/cleared")]
1181    TerminalCleared(TerminalClearedAction),
1182    #[serde(rename = "terminal/commandDetectionAvailable")]
1183    TerminalCommandDetectionAvailable(TerminalCommandDetectionAvailableAction),
1184    #[serde(rename = "terminal/commandExecuted")]
1185    TerminalCommandExecuted(TerminalCommandExecutedAction),
1186    #[serde(rename = "terminal/commandFinished")]
1187    TerminalCommandFinished(TerminalCommandFinishedAction),
1188    #[serde(rename = "resourceWatch/changed")]
1189    ResourceWatchChanged(ResourceWatchChangedAction),
1190    /// Unknown or future variant — preserved as raw JSON for round-trip fidelity.
1191    /// Reducers treat this as a no-op.
1192    #[serde(untagged)]
1193    Unknown(serde_json::Value),
1194}