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