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