Skip to main content

ahp_types/
state.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// ─── Enums ────────────────────────────────────────────────────────────
15
16/// Policy configuration state for a model.
17#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
18pub enum PolicyState {
19    #[serde(rename = "enabled")]
20    Enabled,
21    #[serde(rename = "disabled")]
22    Disabled,
23    #[serde(rename = "unconfigured")]
24    Unconfigured,
25}
26
27/// Discriminant for pending message kinds.
28#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
29pub enum PendingMessageKind {
30    /// Injected into the current turn at a convenient point
31    #[serde(rename = "steering")]
32    Steering,
33    /// Sent automatically as a new turn after the current turn finishes
34    #[serde(rename = "queued")]
35    Queued,
36}
37
38/// Session initialization state.
39#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
40pub enum SessionLifecycle {
41    #[serde(rename = "creating")]
42    Creating,
43    #[serde(rename = "ready")]
44    Ready,
45    #[serde(rename = "creationFailed")]
46    CreationFailed,
47}
48
49/// Bitset of summary-level session status flags.
50///
51/// Use bitwise checks instead of equality for non-terminal activity. For example,
52/// `status & SessionStatus.InProgress` matches both ordinary in-progress turns
53/// and turns that are paused waiting for input.
54///
55/// Wire form: a bare `u32` bitset. Unknown/forward-compat bits are
56/// preserved across a decode→encode round-trip.
57#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize, Default)]
58#[serde(transparent)]
59pub struct SessionStatus(pub u32);
60
61#[allow(non_upper_case_globals)]
62impl SessionStatus {
63    /// Session is idle — no turn is active.
64    pub const Idle: SessionStatus = SessionStatus(1);
65    /// Session ended with an error.
66    pub const Error: SessionStatus = SessionStatus(2);
67    /// A turn is actively streaming.
68    pub const InProgress: SessionStatus = SessionStatus(8);
69    /// A turn is in progress but blocked waiting for user input or tool confirmation.
70    pub const InputNeeded: SessionStatus = SessionStatus(24);
71    /// The client has viewed this session since its last modification.
72    pub const IsRead: SessionStatus = SessionStatus(32);
73    /// The session has been archived by the client.
74    pub const IsArchived: SessionStatus = SessionStatus(64);
75
76    /// The raw `u32` bitset value (every set bit, known or not).
77    #[inline]
78    pub const fn bits(self) -> u32 {
79        self.0
80    }
81
82    /// Wrap a raw `u32` bitset value, preserving every bit verbatim.
83    #[inline]
84    pub const fn from_bits(bits: u32) -> Self {
85        SessionStatus(bits)
86    }
87
88    /// True when every bit set in `other` is also set in `self`.
89    #[inline]
90    pub const fn contains(self, other: SessionStatus) -> bool {
91        (self.0 & other.0) == other.0
92    }
93}
94
95impl From<u32> for SessionStatus {
96    #[inline]
97    fn from(value: u32) -> Self {
98        SessionStatus(value)
99    }
100}
101
102impl From<SessionStatus> for u32 {
103    #[inline]
104    fn from(value: SessionStatus) -> Self {
105        value.0
106    }
107}
108
109impl std::ops::BitOr for SessionStatus {
110    type Output = SessionStatus;
111    #[inline]
112    fn bitor(self, rhs: SessionStatus) -> SessionStatus {
113        SessionStatus(self.0 | rhs.0)
114    }
115}
116
117impl std::ops::BitOrAssign for SessionStatus {
118    #[inline]
119    fn bitor_assign(&mut self, rhs: SessionStatus) {
120        self.0 |= rhs.0;
121    }
122}
123
124impl std::ops::BitAnd for SessionStatus {
125    type Output = SessionStatus;
126    #[inline]
127    fn bitand(self, rhs: SessionStatus) -> SessionStatus {
128        SessionStatus(self.0 & rhs.0)
129    }
130}
131
132impl std::ops::Not for SessionStatus {
133    type Output = SessionStatus;
134    #[inline]
135    fn not(self) -> SessionStatus {
136        SessionStatus(!self.0)
137    }
138}
139
140/// Discriminant for {@link ChatOrigin} — how a chat came into existence.
141#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
142pub enum ChatOriginKind {
143    /// User created the chat explicitly (e.g. via the host UI).
144    #[serde(rename = "user")]
145    User,
146    /// Forked from an existing chat at a specific turn.
147    #[serde(rename = "fork")]
148    Fork,
149    /// Created as an independent side conversation from a specific turn.
150    #[serde(rename = "sideChat")]
151    SideChat,
152    /// Spawned by a tool call running in another chat (e.g. a sub-agent delegation).
153    #[serde(rename = "tool")]
154    Tool,
155}
156
157/// How a user can interact with a chat.
158///
159/// - `Full` — user can send messages and watch (default when absent)
160/// - `ReadOnly` — user can watch but not send messages (e.g. agent team workers)
161/// - `Hidden` — internal worker not shown in UI at all
162///
163/// Supports the agent-team pattern where a lead chat is fully interactive and
164/// worker chats are read-only (visible for observability) or hidden (internal
165/// implementation detail). The harness sets this based on the chat's role;
166/// the UI uses it to show appropriate controls.
167#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
168pub enum ChatInteractivity {
169    /// User can send messages and watch (default when absent)
170    #[serde(rename = "full")]
171    Full,
172    /// User can watch but not send messages
173    #[serde(rename = "read-only")]
174    ReadOnly,
175    /// Internal worker not shown in UI at all
176    #[serde(rename = "hidden")]
177    Hidden,
178}
179
180/// Answer lifecycle state.
181#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
182pub enum ChatInputAnswerState {
183    #[serde(rename = "draft")]
184    Draft,
185    #[serde(rename = "submitted")]
186    Submitted,
187    #[serde(rename = "skipped")]
188    Skipped,
189}
190
191/// Answer value kind.
192#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
193pub enum ChatInputAnswerValueKind {
194    #[serde(rename = "text")]
195    Text,
196    #[serde(rename = "number")]
197    Number,
198    #[serde(rename = "boolean")]
199    Boolean,
200    #[serde(rename = "selected")]
201    Selected,
202    #[serde(rename = "selected-many")]
203    SelectedMany,
204}
205
206/// Question/input control kind.
207#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
208pub enum ChatInputQuestionKind {
209    #[serde(rename = "text")]
210    Text,
211    #[serde(rename = "number")]
212    Number,
213    #[serde(rename = "integer")]
214    Integer,
215    #[serde(rename = "boolean")]
216    Boolean,
217    #[serde(rename = "single-select")]
218    SingleSelect,
219    #[serde(rename = "multi-select")]
220    MultiSelect,
221}
222
223/// How a client completed an input request.
224#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
225pub enum ChatInputResponseKind {
226    #[serde(rename = "accept")]
227    Accept,
228    #[serde(rename = "decline")]
229    Decline,
230    #[serde(rename = "cancel")]
231    Cancel,
232}
233
234/// Discriminant for the kinds of outstanding input a session can surface in
235/// {@link SessionState.inputNeeded}.
236///
237/// This is a general/typological union (not a lifecycle), so the discriminant is
238/// a `*Kind`.
239#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
240pub enum SessionInputRequestKind {
241    /// A user-facing elicitation mirrored from an unresolved chat response part.
242    #[serde(rename = "chatInput")]
243    ChatInput,
244    /// A tool call awaiting parameter- or result-confirmation.
245    #[serde(rename = "toolConfirmation")]
246    ToolConfirmation,
247    /// A running tool the session wants an active client to execute.
248    #[serde(rename = "toolClientExecution")]
249    ToolClientExecution,
250    /// A tool call blocked on MCP authentication mid-execution.
251    #[serde(rename = "toolAuthentication")]
252    ToolAuthentication,
253}
254
255/// How a turn ended.
256#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
257pub enum TurnState {
258    #[serde(rename = "complete")]
259    Complete,
260    #[serde(rename = "cancelled")]
261    Cancelled,
262    #[serde(rename = "error")]
263    Error,
264}
265
266/// Discriminant for {@link MessageOrigin} — identifies who produced a message.
267#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
268pub enum MessageKind {
269    /// Sent directly by the user.
270    #[serde(rename = "user")]
271    User,
272    /// Produced by the agent itself rather than the user — for example, an agent
273    /// that seeds the first message of a chat it spawned.
274    #[serde(rename = "agent")]
275    Agent,
276    /// Produced by a tool rather than the user — for example, a tool that spawns a
277    /// worker chat whose first message carries a seed prompt.
278    #[serde(rename = "tool")]
279    Tool,
280    /// A system-generated notification rather than a direct user message.
281    #[serde(rename = "systemNotification")]
282    SystemNotification,
283}
284
285/// Discriminant for {@link MessageAttachment} variants.
286#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
287pub enum MessageAttachmentKind {
288    /// A simple, opaque attachment whose representation is described by the producer.
289    #[serde(rename = "simple")]
290    Simple,
291    /// An attachment whose data is embedded inline as a base64 string.
292    #[serde(rename = "embeddedResource")]
293    EmbeddedResource,
294    /// An attachment that references a resource by URI.
295    #[serde(rename = "resource")]
296    Resource,
297    /// An attachment that references annotations on an annotations channel.
298    #[serde(rename = "annotations")]
299    Annotations,
300    /// An attachment that references a bounded transcript from another chat.
301    #[serde(rename = "chat")]
302    Chat,
303}
304
305/// Discriminant for response part types.
306#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
307pub enum ResponsePartKind {
308    #[serde(rename = "markdown")]
309    Markdown,
310    #[serde(rename = "contentRef")]
311    ContentRef,
312    #[serde(rename = "toolCall")]
313    ToolCall,
314    #[serde(rename = "reasoning")]
315    Reasoning,
316    #[serde(rename = "systemNotification")]
317    SystemNotification,
318    #[serde(rename = "inputRequest")]
319    InputRequest,
320}
321
322/// Status of a tool call in the lifecycle state machine.
323#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
324pub enum ToolCallStatus {
325    #[serde(rename = "streaming")]
326    Streaming,
327    #[serde(rename = "pending-confirmation")]
328    PendingConfirmation,
329    #[serde(rename = "running")]
330    Running,
331    /// Running paused because the MCP server backing this call needs
332    /// authentication (typically step-up auth for insufficient scope,
333    /// surfacing mid-execution). See {@link ToolCallAuthRequiredState}.
334    #[serde(rename = "auth-required")]
335    AuthRequired,
336    #[serde(rename = "pending-result-confirmation")]
337    PendingResultConfirmation,
338    #[serde(rename = "completed")]
339    Completed,
340    #[serde(rename = "cancelled")]
341    Cancelled,
342}
343
344/// How a tool call was confirmed for execution.
345///
346/// - `NotNeeded` — No confirmation required (auto-approved)
347/// - `UserAction` — User explicitly approved
348/// - `Setting` — Approved by a persistent user setting
349#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
350pub enum ToolCallConfirmationReason {
351    #[serde(rename = "not-needed")]
352    NotNeeded,
353    #[serde(rename = "user-action")]
354    UserAction,
355    #[serde(rename = "setting")]
356    Setting,
357}
358
359/// Identifies a model judge as the source of a confirmation requirement.
360#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
361pub enum ToolCallRiskAssessmentKind {
362    #[serde(rename = "judge")]
363    Judge,
364}
365
366/// Lifecycle status of an asynchronous model-judge confirmation decision.
367#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
368pub enum ToolCallRiskAssessmentStatus {
369    #[serde(rename = "loading")]
370    Loading,
371    #[serde(rename = "complete")]
372    Complete,
373}
374
375/// Why a tool call was cancelled.
376#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
377pub enum ToolCallCancellationReason {
378    #[serde(rename = "denied")]
379    Denied,
380    #[serde(rename = "skipped")]
381    Skipped,
382    #[serde(rename = "result-denied")]
383    ResultDenied,
384}
385
386/// Whether a confirmation option represents an approval or denial action.
387#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
388pub enum ConfirmationOptionKind {
389    #[serde(rename = "approve")]
390    Approve,
391    #[serde(rename = "deny")]
392    Deny,
393}
394
395#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
396pub enum ToolCallContributorKind {
397    #[serde(rename = "client")]
398    Client,
399    #[serde(rename = "mcp")]
400    MCP,
401}
402
403/// Discriminant for tool result content types.
404#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
405pub enum ToolResultContentType {
406    #[serde(rename = "text")]
407    Text,
408    #[serde(rename = "embeddedResource")]
409    EmbeddedResource,
410    #[serde(rename = "resource")]
411    Resource,
412    #[serde(rename = "fileEdit")]
413    FileEdit,
414    #[serde(rename = "terminal")]
415    Terminal,
416    #[serde(rename = "subagent")]
417    Subagent,
418}
419
420/// Discriminant for the kind of customization.
421///
422/// Top-level entries in {@link SessionState.customizations} and
423/// {@link AgentInfo.customizations} are either container customizations
424/// ({@link CustomizationType.Plugin | `Plugin`} or
425/// {@link CustomizationType.Directory | `Directory`}) or
426/// {@link CustomizationType.McpServer | `McpServer`} entries surfaced
427/// directly by the host. The remaining types appear only as children of
428/// a container.
429#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
430pub enum CustomizationType {
431    #[serde(rename = "plugin")]
432    Plugin,
433    #[serde(rename = "directory")]
434    Directory,
435    #[serde(rename = "agent")]
436    Agent,
437    #[serde(rename = "skill")]
438    Skill,
439    #[serde(rename = "prompt")]
440    Prompt,
441    #[serde(rename = "rule")]
442    Rule,
443    #[serde(rename = "hook")]
444    Hook,
445    #[serde(rename = "mcpServer")]
446    McpServer,
447}
448
449/// Scope at which customization enablement is decided.
450#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
451pub enum CustomizationEnablementKind {
452    #[serde(rename = "global")]
453    Global,
454    #[serde(rename = "workspace")]
455    Workspace,
456    #[serde(rename = "session")]
457    Session,
458}
459
460/// Discriminant values for {@link CustomizationLoadState}.
461#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
462pub enum CustomizationLoadStatus {
463    #[serde(rename = "loading")]
464    Loading,
465    #[serde(rename = "loaded")]
466    Loaded,
467    #[serde(rename = "degraded")]
468    Degraded,
469    #[serde(rename = "error")]
470    Error,
471}
472
473/// Discriminant for terminal claim kinds.
474#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
475pub enum TerminalClaimKind {
476    #[serde(rename = "client")]
477    Client,
478    #[serde(rename = "session")]
479    Session,
480}
481
482/// Discriminant for the {@link McpServerState} union.
483#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
484pub enum McpServerStatus {
485    /// Server has been registered but is not yet running.
486    #[serde(rename = "starting")]
487    Starting,
488    /// Server is running and serving requests.
489    #[serde(rename = "ready")]
490    Ready,
491    /// Server is reachable but requires additional authentication before it
492    /// can start, or before it can serve a particular request. Carries the
493    /// RFC 9728 Protected Resource Metadata the client needs to obtain a
494    /// token; the client then pushes the token via the existing
495    /// `authenticate` command.
496    #[serde(rename = "authRequired")]
497    AuthRequired,
498    /// Server failed to start, crashed, or otherwise transitioned to a fatal error.
499    #[serde(rename = "error")]
500    Error,
501    /// Server has been shut down.
502    #[serde(rename = "stopped")]
503    Stopped,
504}
505
506/// Why an MCP server is currently in the {@link McpServerStatus.AuthRequired}
507/// state. Mirrors the three failure modes defined by the
508/// [MCP authorization spec](https://modelcontextprotocol.io/specification/2025-11-25/basic/authorization.md).
509#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
510pub enum McpAuthRequiredReason {
511    /// No token has been provided yet (HTTP 401, no prior token).
512    #[serde(rename = "required")]
513    Required,
514    /// A previously valid token expired or was revoked (HTTP 401).
515    #[serde(rename = "expired")]
516    Expired,
517    /// Step-up auth: a token is present but its scopes are insufficient for
518    /// the requested operation (HTTP 403 with
519    /// `WWW-Authenticate: Bearer error="insufficient_scope"`).
520    ///
521    /// Unlike {@link Required} and {@link Expired} — which typically surface
522    /// before any tool work is in flight — `InsufficientScope` is almost
523    /// always triggered by an MCP request issued mid-turn (a `tools/call`,
524    /// `resources/read`, etc.). The host SHOULD pair the
525    /// {@link McpServerAuthRequiredState} transition with
526    /// {@link SessionStatus.InputNeeded} on
527    /// {@link SessionSummary.status | the session} so the activity becomes
528    /// visible at the session-summary level, and clients SHOULD watch for
529    /// this kind on any
530    /// {@link McpServerCustomization | MCP server} backing a running tool
531    /// call so they can present an explicit "grant more access" affordance
532    /// tied to the blocked tool call.
533    #[serde(rename = "insufficientScope")]
534    InsufficientScope,
535}
536
537/// Computation lifecycle of a {@link ChangesetState}.
538#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
539pub enum ChangesetStatus {
540    /// The server is still computing the contents of this changeset.
541    #[serde(rename = "computing")]
542    Computing,
543    /// The changeset has been fully computed and is up-to-date.
544    #[serde(rename = "ready")]
545    Ready,
546    /// Computation failed. The cause is described by
547    /// {@link ChangesetState.error}.
548    #[serde(rename = "error")]
549    Error,
550}
551
552/// Execution lifecycle of a {@link ChangesetOperation}.
553///
554/// An operation is invoked imperatively via `invokeChangesetOperation`, but
555/// its progress and outcome are reflected back into changeset state so that
556/// every subscriber observes a consistent view (e.g. a spinner on a "Create
557/// Pull Request" button, or an inline error after a failed "revert").
558#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
559pub enum ChangesetOperationStatus {
560    /// The operation is ready to be invoked. This is the default when
561    /// {@link ChangesetOperation.status} is omitted.
562    #[serde(rename = "idle")]
563    Idle,
564    /// An invocation of this operation is currently in flight.
565    #[serde(rename = "running")]
566    Running,
567    /// The most recent invocation failed. The cause is described by
568    /// {@link ChangesetOperation.error}.
569    #[serde(rename = "error")]
570    Error,
571    /// The operation is currently disabled and cannot be invoked.
572    #[serde(rename = "disabled")]
573    Disabled,
574}
575
576/// Where a {@link ChangesetOperation} can be invoked.
577#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
578pub enum ChangesetOperationScope {
579    /// Applies to the whole changeset.
580    #[serde(rename = "changeset")]
581    Changeset,
582    /// Applies to a single file within the changeset.
583    #[serde(rename = "resource")]
584    Resource,
585    /// Applies to a line range within a single file.
586    #[serde(rename = "range")]
587    Range,
588}
589
590/// Discriminant for {@link ResourceChange.type}.
591#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
592pub enum ResourceChangeType {
593    #[serde(rename = "added")]
594    Added,
595    #[serde(rename = "updated")]
596    Updated,
597    #[serde(rename = "deleted")]
598    Deleted,
599}
600
601// ─── Structs ──────────────────────────────────────────────────────────
602
603/// An optionally-sized icon that can be displayed in a user interface.
604#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
605#[serde(rename_all = "camelCase")]
606pub struct Icon {
607    /// A standard URI pointing to an icon resource. May be an HTTP/HTTPS URL or a
608    /// `data:` URI with Base64-encoded image data.
609    ///
610    /// Consumers SHOULD take steps to ensure URLs serving icons are from the
611    /// same domain as the client/server or a trusted domain.
612    ///
613    /// Consumers SHOULD take appropriate precautions when consuming SVGs as they can contain
614    /// executable JavaScript.
615    pub src: Uri,
616    /// Optional MIME type override if the source MIME type is missing or generic.
617    /// For example: `"image/png"`, `"image/jpeg"`, or `"image/svg+xml"`.
618    #[serde(default, skip_serializing_if = "Option::is_none")]
619    pub content_type: Option<String>,
620    /// Optional array of strings that specify sizes at which the icon can be used.
621    /// Each string should be in WxH format (e.g., `"48x48"`, `"96x96"`) or `"any"` for scalable formats like SVG.
622    ///
623    /// If not provided, the client should assume that the icon can be used at any size.
624    #[serde(default, skip_serializing_if = "Option::is_none")]
625    pub sizes: Option<Vec<String>>,
626    /// Optional specifier for the theme this icon is designed for. `"light"` indicates
627    /// the icon is designed to be used with a light background, and `"dark"` indicates
628    /// the icon is designed to be used with a dark background.
629    ///
630    /// If not provided, the client should assume the icon can be used with any theme.
631    #[serde(default, skip_serializing_if = "Option::is_none")]
632    pub theme: Option<String>,
633}
634
635/// Describes a protected resource's authentication requirements using
636/// [RFC 9728](https://datatracker.ietf.org/doc/html/rfc9728) (OAuth 2.0
637/// Protected Resource Metadata) semantics.
638///
639/// Field names use snake_case to match the RFC 9728 JSON format.
640#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
641#[serde(rename_all = "camelCase")]
642pub struct ProtectedResourceMetadata {
643    /// REQUIRED. The protected resource's resource identifier, a URL using the
644    /// `https` scheme with no fragment component (e.g. `"https://api.github.com"`).
645    pub resource: String,
646    /// OPTIONAL. Human-readable name of the protected resource.
647    #[serde(
648        rename = "resource_name",
649        default,
650        skip_serializing_if = "Option::is_none"
651    )]
652    pub resource_name: Option<String>,
653    /// OPTIONAL. JSON array of OAuth authorization server identifier URLs.
654    #[serde(
655        rename = "authorization_servers",
656        default,
657        skip_serializing_if = "Option::is_none"
658    )]
659    pub authorization_servers: Option<Vec<String>>,
660    /// OPTIONAL. URL of the protected resource's JWK Set document.
661    #[serde(rename = "jwks_uri", default, skip_serializing_if = "Option::is_none")]
662    pub jwks_uri: Option<String>,
663    /// RECOMMENDED. JSON array of OAuth 2.0 scope values used in authorization requests.
664    #[serde(
665        rename = "scopes_supported",
666        default,
667        skip_serializing_if = "Option::is_none"
668    )]
669    pub scopes_supported: Option<Vec<String>>,
670    /// OPTIONAL. JSON array of Bearer Token presentation methods supported.
671    #[serde(
672        rename = "bearer_methods_supported",
673        default,
674        skip_serializing_if = "Option::is_none"
675    )]
676    pub bearer_methods_supported: Option<Vec<String>>,
677    /// OPTIONAL. JSON array of JWS signing algorithms supported.
678    #[serde(
679        rename = "resource_signing_alg_values_supported",
680        default,
681        skip_serializing_if = "Option::is_none"
682    )]
683    pub resource_signing_alg_values_supported: Option<Vec<String>>,
684    /// OPTIONAL. URL of human-readable documentation for the resource.
685    #[serde(
686        rename = "resource_documentation",
687        default,
688        skip_serializing_if = "Option::is_none"
689    )]
690    pub resource_documentation: Option<String>,
691    /// OPTIONAL. URL of the resource's data-usage policy.
692    #[serde(
693        rename = "resource_policy_uri",
694        default,
695        skip_serializing_if = "Option::is_none"
696    )]
697    pub resource_policy_uri: Option<String>,
698    /// OPTIONAL. URL of the resource's terms of service.
699    #[serde(
700        rename = "resource_tos_uri",
701        default,
702        skip_serializing_if = "Option::is_none"
703    )]
704    pub resource_tos_uri: Option<String>,
705    /// AHP extension. Whether authentication is required for this resource.
706    ///
707    /// - `true` (default) — the agent cannot be used without a valid token.
708    ///   The server SHOULD return `AuthRequired` (`-32007`) if the client
709    ///   attempts to use the agent without authenticating.
710    /// - `false` — the agent works without authentication but MAY offer
711    ///   enhanced capabilities when a token is provided.
712    ///
713    /// Clients SHOULD treat an absent field the same as `true`.
714    #[serde(default, skip_serializing_if = "Option::is_none")]
715    pub required: Option<bool>,
716}
717
718/// Global state shared with every client subscribed to `ahp-root://`.
719#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
720#[serde(rename_all = "camelCase")]
721pub struct RootState {
722    /// Available agent backends and their models
723    pub agents: Vec<AgentInfo>,
724    /// Number of active (non-disposed) sessions on the server
725    #[serde(default, skip_serializing_if = "Option::is_none")]
726    pub active_sessions: Option<i64>,
727    /// Known terminals on the server. Subscribe to individual terminal URIs for full state.
728    #[serde(default, skip_serializing_if = "Option::is_none")]
729    pub terminals: Option<Vec<TerminalInfo>>,
730    /// Agent host configuration schema and current values
731    #[serde(default, skip_serializing_if = "Option::is_none")]
732    pub config: Option<RootConfigState>,
733    /// Additional implementation-defined metadata about the agent host itself.
734    ///
735    /// Clients MAY look for well-known keys here to provide enhanced UI.
736    #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
737    pub meta: Option<JsonObject>,
738}
739
740/// Live agent-host configuration metadata.
741///
742/// The schema describes the available configuration properties and the values
743/// contain the current value for each resolved property.
744#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
745#[serde(rename_all = "camelCase")]
746pub struct RootConfigState {
747    /// JSON Schema describing available configuration properties
748    pub schema: ConfigSchema,
749    /// Current configuration values
750    pub values: JsonObject,
751}
752
753#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
754#[serde(rename_all = "camelCase")]
755pub struct AgentInfo {
756    /// Agent provider ID (e.g. `'copilot'`)
757    pub provider: String,
758    /// Human-readable name
759    pub display_name: String,
760    /// Description string
761    pub description: String,
762    /// Available models for this agent
763    pub models: Vec<SessionModelInfo>,
764    /// Protected resources this agent requires authentication for.
765    ///
766    /// Each entry describes an OAuth 2.0 protected resource using
767    /// [RFC 9728](https://datatracker.ietf.org/doc/html/rfc9728) semantics.
768    /// Clients should obtain tokens from the declared `authorization_servers`
769    /// and push them via the `authenticate` command before creating sessions
770    /// with this agent.
771    #[serde(default, skip_serializing_if = "Option::is_none")]
772    pub protected_resources: Option<Vec<ProtectedResourceMetadata>>,
773    /// Customizations associated with this agent.
774    ///
775    /// Either container customizations —
776    /// {@link PluginCustomization | `PluginCustomization`} entries the agent
777    /// bundles, plus {@link DirectoryCustomization | `DirectoryCustomization`}
778    /// entries it watches in any workspace it's used with — or top-level
779    /// {@link McpServerCustomization | `McpServerCustomization`} entries
780    /// the agent host declares directly. When a session is created with
781    /// this agent, these entries are augmented (e.g. directory URIs are
782    /// resolved against the workspace, children are parsed) and propagated
783    /// into the session's `customizations` list.
784    #[serde(default, skip_serializing_if = "Option::is_none")]
785    pub customizations: Option<Vec<Customization>>,
786    /// Static capabilities the agent advertises about itself. Clients use these
787    /// to gate features (multi-chat, fork) instead of switching on the provider
788    /// id.
789    #[serde(default, skip_serializing_if = "Option::is_none")]
790    pub capabilities: Option<AgentCapabilities>,
791}
792
793/// Static capabilities an {@link AgentInfo} advertises. Modelled after MCP
794/// capabilities: each field is opt-in and its presence (an empty object `{}`)
795/// signals support, while absence means the feature is unsupported and the
796/// corresponding client commands MUST NOT be used. Sub-fields carry
797/// per-capability options.
798#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Default)]
799#[serde(rename_all = "camelCase")]
800pub struct AgentCapabilities {
801    /// The agent can host more than one concurrent chat per session. When absent,
802    /// clients MUST NOT call `createChat` to open chats beyond the default one the
803    /// session starts with. An empty object `{}` advertises multi-chat without
804    /// source-based creation; set {@link MultipleChatsCapability.fork} or
805    /// {@link MultipleChatsCapability.sideChat} to allow the corresponding mode.
806    #[serde(default, skip_serializing_if = "Option::is_none")]
807    pub multiple_chats: Option<MultipleChatsCapability>,
808    /// The session's agent can be granted tool access to more than one working
809    /// directory. The directories are treated as equal peers except where the
810    /// agent advertises a protected primary-slot option (some backends pin or
811    /// replace their first directory as a process root).
812    ///
813    /// When absent, clients MUST NOT mutate a session's or chat's working-directory
814    /// set and MUST NOT set more than one entry in
815    /// {@link CreateSessionParams.workingDirectories}.
816    #[serde(default, skip_serializing_if = "Option::is_none")]
817    pub multiple_working_directories: Option<MultipleWorkingDirectoriesCapability>,
818}
819
820/// Options for the {@link AgentCapabilities.multipleChats} capability.
821#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Default)]
822#[serde(rename_all = "camelCase")]
823pub struct MultipleChatsCapability {
824    /// The agent can fork a chat from a specific turn. When absent or `false`,
825    /// clients MUST NOT pass a {@link ChatSource} with `kind: "fork"` to
826    /// `createChat`.
827    /// Forking always implies multi-chat support.
828    #[serde(default, skip_serializing_if = "Option::is_none")]
829    pub fork: Option<bool>,
830    /// The agent can create a side chat from a specific turn. When absent or
831    /// `false`, clients MUST NOT pass a {@link ChatSource} with
832    /// `kind: "sideChat"` to `createChat`.
833    ///
834    /// A side chat receives the source turn as context without copying the source
835    /// transcript into its own visible history. The source is identified by a
836    /// stable `turnId`, which the host resolves against the source chat's current
837    /// `activeTurn` or retained history. When it names the current active turn,
838    /// the host snapshots the available partial assistant response at creation
839    /// time. Side-chat support always implies multi-chat support.
840    #[serde(default, skip_serializing_if = "Option::is_none")]
841    pub side_chat: Option<bool>,
842}
843
844/// Options for the {@link AgentCapabilities.multipleWorkingDirectories} capability.
845#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Default)]
846#[serde(rename_all = "camelCase")]
847pub struct MultipleWorkingDirectoriesCapability {
848    /// The agent's **first** working directory (index `0` of
849    /// {@link CreateSessionParams.workingDirectories}) is an immutable primary:
850    /// its URI is fixed for the lifetime of the session — clients MUST NOT remove,
851    /// reorder, or replace it. Additional directories after it remain equal peers
852    /// that can be added and removed freely. When
853    /// {@link primaryReplacement} is also `true`, clients that recognize that
854    /// capability MUST instead treat the primary as protected and replaceable.
855    ///
856    /// Advertised by backends whose agent process is rooted at a single directory
857    /// that cannot change once the session has started. A backend MAY also
858    /// advertise this with {@link primaryReplacement} for compatibility with
859    /// clients that do not recognize the newer capability: those clients retain
860    /// the safe immutable-primary behavior, while newer clients allow only the
861    /// targeted replacement action. When both are absent or `false`, all
862    /// directories are equal peers.
863    #[serde(default, skip_serializing_if = "Option::is_none")]
864    pub immutable_primary: Option<bool>,
865    /// The agent's first working-directory slot (index `0`) is a protected primary
866    /// whose URI can be atomically replaced with
867    /// `session/workingDirectoryReplaced`. Clients MUST NOT remove that slot with
868    /// generic membership actions; additional directories remain equal peers.
869    ///
870    /// Backends use this when their cwd-bearing directory can move during a
871    /// session. It MAY be `true` together with {@link immutablePrimary}; this
872    /// preserves the immutable-primary guarantee for older clients that do not
873    /// recognize this capability. Clients that recognize this capability MUST
874    /// allow a targeted replacement even when `immutablePrimary` is also `true`.
875    #[serde(default, skip_serializing_if = "Option::is_none")]
876    pub primary_replacement: Option<bool>,
877}
878
879#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
880#[serde(rename_all = "camelCase")]
881pub struct SessionModelInfo {
882    /// Model identifier
883    pub id: String,
884    /// Provider this model belongs to
885    pub provider: String,
886    /// Human-readable model name
887    pub name: String,
888    /// Maximum context window size
889    #[serde(default, skip_serializing_if = "Option::is_none")]
890    pub max_context_window: Option<i64>,
891    /// Maximum number of output tokens the model can generate
892    #[serde(default, skip_serializing_if = "Option::is_none")]
893    pub max_output_tokens: Option<i64>,
894    /// Maximum number of prompt (input) tokens the model accepts
895    #[serde(default, skip_serializing_if = "Option::is_none")]
896    pub max_prompt_tokens: Option<i64>,
897    /// Whether the model supports vision
898    #[serde(default, skip_serializing_if = "Option::is_none")]
899    pub supports_vision: Option<bool>,
900    /// Policy configuration state
901    #[serde(default, skip_serializing_if = "Option::is_none")]
902    pub policy_state: Option<PolicyState>,
903    /// Configuration schema describing model-specific options (e.g. thinking
904    /// level). Clients present this as a form and pass the resolved values in
905    /// {@link ModelSelection.config} when creating or changing sessions.
906    #[serde(default, skip_serializing_if = "Option::is_none")]
907    pub config_schema: Option<ConfigSchema>,
908    /// Additional provider-specific metadata for this model.
909    ///
910    /// Clients MAY look for well-known keys here to provide enhanced UI.
911    /// For example, a `pricing` key may carry model pricing metadata.
912    #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
913    pub meta: Option<JsonObject>,
914}
915
916/// A model selection: the chosen model ID together with any model-specific
917/// configuration values whose keys correspond to the model's
918/// {@link SessionModelInfo.configSchema}.
919#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
920#[serde(rename_all = "camelCase")]
921pub struct ModelSelection {
922    /// Model identifier
923    pub id: String,
924    /// Model-specific configuration values. Values are JSON primitives: most
925    /// pickers produce strings, but some (e.g. a numeric context-size picker)
926    /// produce numbers or booleans, which are carried through as-is.
927    #[serde(default, skip_serializing_if = "Option::is_none")]
928    pub config: Option<std::collections::HashMap<String, AnyValue>>,
929}
930
931/// A selected custom agent for a session.
932///
933/// The `uri` identifies a specific custom agent (matching an
934/// {@link AgentCustomization.uri | `AgentCustomization.uri`} exposed via
935/// the session's effective customizations). Consumers resolve the agent's
936/// display name by looking up `uri` in the session's customization tree.
937///
938/// A message with no `agent` selected uses the provider's default behavior.
939#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
940#[serde(rename_all = "camelCase")]
941pub struct AgentSelection {
942    /// Stable agent URI (matches an {@link AgentCustomization.uri}).
943    pub uri: Uri,
944}
945
946/// A JSON Schema-compatible property descriptor with display extensions.
947///
948/// Standard JSON Schema fields (`type`, `title`, `description`, `default`,
949/// `enum`) allow validators to process the schema. Display extensions
950/// (`enumLabels`, `enumDescriptions`) are parallel arrays that provide UI
951/// metadata for each `enum` value.
952///
953/// This is the generic base type. See {@link SessionConfigPropertySchema} for
954/// session-specific extensions.
955#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
956#[serde(rename_all = "camelCase")]
957pub struct ConfigPropertySchema {
958    /// JSON Schema: property type
959    pub r#type: String,
960    /// JSON Schema: human-readable label for the property
961    pub title: String,
962    /// JSON Schema: description / tooltip
963    #[serde(default, skip_serializing_if = "Option::is_none")]
964    pub description: Option<String>,
965    /// JSON Schema: default value
966    #[serde(default, skip_serializing_if = "Option::is_none")]
967    pub default: Option<AnyValue>,
968    /// JSON Schema: allowed values. May be primitives of any JSON type.
969    #[serde(default, skip_serializing_if = "Option::is_none")]
970    pub r#enum: Option<Vec<AnyValue>>,
971    /// Display extension: human-readable label per enum value (parallel array)
972    #[serde(default, skip_serializing_if = "Option::is_none")]
973    pub enum_labels: Option<Vec<String>>,
974    /// Display extension: description per enum value (parallel array)
975    #[serde(default, skip_serializing_if = "Option::is_none")]
976    pub enum_descriptions: Option<Vec<String>>,
977    /// JSON Schema: when `true`, the property is displayed but cannot be modified by the user
978    #[serde(default, skip_serializing_if = "Option::is_none")]
979    pub read_only: Option<bool>,
980    /// JSON Schema: schema for array items (used when `type` is `'array'`)
981    #[serde(default, skip_serializing_if = "Option::is_none")]
982    pub items: Option<Box<ConfigPropertySchema>>,
983    /// JSON Schema: property descriptors for object properties (used when `type` is `'object'`)
984    #[serde(default, skip_serializing_if = "Option::is_none")]
985    pub properties: Option<std::collections::HashMap<String, Box<ConfigPropertySchema>>>,
986    /// JSON Schema: list of required property ids (used when `type` is `'object'`)
987    #[serde(default, skip_serializing_if = "Option::is_none")]
988    pub required: Option<Vec<String>>,
989    /// JSON Schema: schema for additional properties not listed in `properties` (used when `type` is `'object'`).
990    #[serde(default, skip_serializing_if = "Option::is_none")]
991    pub additional_properties: Option<Box<ConfigPropertySchema>>,
992}
993
994/// A JSON Schema object describing available configuration properties.
995///
996/// This is the generic base type. See {@link SessionConfigSchema} for
997/// session-specific usage.
998#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
999#[serde(rename_all = "camelCase")]
1000pub struct ConfigSchema {
1001    /// JSON Schema: always `'object'`
1002    pub r#type: String,
1003    /// JSON Schema: property descriptors keyed by property id
1004    pub properties: std::collections::HashMap<String, ConfigPropertySchema>,
1005    /// JSON Schema: list of required property ids
1006    #[serde(default, skip_serializing_if = "Option::is_none")]
1007    pub required: Option<Vec<String>>,
1008}
1009
1010/// A message queued for future delivery to the agent.
1011///
1012/// Steering messages are injected into the current turn mid-flight.
1013/// Queued messages are automatically started as new turns after the
1014/// current turn naturally finishes.
1015#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1016#[serde(rename_all = "camelCase")]
1017pub struct PendingMessage {
1018    /// Unique identifier for this pending message
1019    pub id: String,
1020    /// The message that will start the next turn
1021    pub message: Message,
1022}
1023
1024/// Full state for a single chat, loaded when a client subscribes to the chat's
1025/// URI.
1026///
1027/// The lightweight catalog representation of a chat is {@link ChatSummary},
1028/// carried in {@link SessionState.chats | `SessionState.chats`}. `ChatState`
1029/// **denormalizes** every {@link ChatSummary} field directly onto itself so
1030/// subscribers receive one flat object instead of having to merge a nested
1031/// `summary` sub-object. Producers MUST keep the two representations
1032/// consistent: any change to the inlined fields below SHOULD also be
1033/// announced on the parent session via the matching
1034/// {@link SessionChatUpdatedAction | `session/chatUpdated`} action.
1035#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1036#[serde(rename_all = "camelCase")]
1037pub struct ChatState {
1038    /// Chat URI
1039    pub resource: Uri,
1040    /// Chat title
1041    pub title: String,
1042    /// Current chat status (reuses SessionStatus shape)
1043    pub status: u32,
1044    /// Human-readable description of what the chat is currently doing
1045    #[serde(default, skip_serializing_if = "Option::is_none")]
1046    pub activity: Option<String>,
1047    /// Last modification timestamp (ISO 8601, e.g. `"2025-03-10T18:42:03.123Z"`)
1048    pub modified_at: String,
1049    /// How this chat came into existence
1050    #[serde(default, skip_serializing_if = "Option::is_none")]
1051    pub origin: Option<ChatOrigin>,
1052    /// How the user can interact with this chat. See {@link ChatInteractivity}.
1053    ///
1054    /// Supports agent-team patterns where worker chats are read-only or hidden.
1055    /// Absence defaults to {@link ChatInteractivity.Full} for backward
1056    /// compatibility.
1057    #[serde(default, skip_serializing_if = "Option::is_none")]
1058    pub interactivity: Option<ChatInteractivity>,
1059    /// The subset of the session's
1060    /// {@link SessionState.workingDirectories | `workingDirectories`} that this
1061    /// chat's agent has tool access to. Every entry MUST be present in the owning
1062    /// session's `workingDirectories`; servers MUST reject a
1063    /// `chat/workingDirectorySet` action that violates this constraint.
1064    ///
1065    /// When absent, the chat inherits the full session set. When present but empty
1066    /// (not recommended), the chat has no working-directory tool access at all.
1067    ///
1068    /// Dispatch `chat/workingDirectorySet` / `chat/workingDirectoryRemoved` to
1069    /// update the subset on a running chat.
1070    #[serde(default, skip_serializing_if = "Option::is_none")]
1071    pub working_directories: Option<Vec<Uri>>,
1072    /// Completed turns
1073    pub turns: Vec<Turn>,
1074    /// Cursor for loading older completed turns into this chat state.
1075    ///
1076    /// Presence means `turns` is a tail window and more historical turns are
1077    /// available. Pass this opaque cursor to `fetchTurns`; the host MUST insert
1078    /// the loaded turns into state and update or clear this cursor before
1079    /// responding. Absence means the state contains all retained turns.
1080    #[serde(default, skip_serializing_if = "Option::is_none")]
1081    pub turns_next_cursor: Option<String>,
1082    /// Currently in-progress turn
1083    #[serde(default, skip_serializing_if = "Option::is_none")]
1084    pub active_turn: Option<ActiveTurn>,
1085    /// Message to inject into the current turn at a convenient point
1086    #[serde(default, skip_serializing_if = "Option::is_none")]
1087    pub steering_message: Option<PendingMessage>,
1088    /// Messages to send automatically as new turns after the current turn finishes
1089    #[serde(default, skip_serializing_if = "Option::is_none")]
1090    pub queued_messages: Option<Vec<PendingMessage>>,
1091    /// The user's in-progress draft input for this chat — the message they are
1092    /// composing but have not sent yet, including its
1093    /// {@link Message.model | model} / {@link Message.agent | agent} selection
1094    /// and attachments.
1095    ///
1096    /// Clients MAY periodically sync their local input state into this field so
1097    /// a draft survives reloads and is visible to other clients viewing the same
1098    /// chat. Eager syncing is **not** required — clients SHOULD debounce and MAY
1099    /// sync only at convenient points. When presenting input UI for an existing
1100    /// chat, clients SHOULD use any `draft` to initialize their input state.
1101    /// Cleared (set to `undefined`) once the message is sent.
1102    #[serde(default, skip_serializing_if = "Option::is_none")]
1103    pub draft: Option<Message>,
1104    /// Additional provider-specific metadata for this chat.
1105    #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
1106    pub meta: Option<JsonObject>,
1107}
1108
1109/// Lightweight catalog entry for a chat, carried in
1110/// {@link SessionState.chats | `SessionState.chats`}. The full conversation
1111/// lives in {@link ChatState}, which inlines (denormalizes) every field below.
1112#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1113#[serde(rename_all = "camelCase")]
1114pub struct ChatSummary {
1115    /// Chat URI
1116    pub resource: Uri,
1117    /// Chat title
1118    pub title: String,
1119    /// Current chat status (reuses SessionStatus shape)
1120    pub status: u32,
1121    /// Human-readable description of what the chat is currently doing
1122    #[serde(default, skip_serializing_if = "Option::is_none")]
1123    pub activity: Option<String>,
1124    /// Last modification timestamp (ISO 8601, e.g. `"2025-03-10T18:42:03.123Z"`)
1125    pub modified_at: String,
1126    /// How this chat came into existence
1127    #[serde(default, skip_serializing_if = "Option::is_none")]
1128    pub origin: Option<ChatOrigin>,
1129    /// How the user can interact with this chat. See {@link ChatInteractivity}.
1130    ///
1131    /// Supports agent-team patterns where worker chats are read-only or hidden.
1132    /// Absence defaults to {@link ChatInteractivity.Full} for backward
1133    /// compatibility.
1134    #[serde(default, skip_serializing_if = "Option::is_none")]
1135    pub interactivity: Option<ChatInteractivity>,
1136    /// The subset of the session's working directories this chat uses.
1137    /// See {@link ChatState.workingDirectories} for the full semantics.
1138    #[serde(default, skip_serializing_if = "Option::is_none")]
1139    pub working_directories: Option<Vec<Uri>>,
1140}
1141
1142/// Immutable selected-text snapshot captured when a side chat is created.
1143///
1144/// The host records this exact text when it accepts `createChat`; later changes
1145/// to the source chat do not alter it.
1146#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1147#[serde(rename_all = "camelCase")]
1148pub struct SideChatSelection {
1149    /// Exact selected-text snapshot captured at `createChat` acceptance.
1150    ///
1151    /// MUST be non-empty.
1152    pub text: String,
1153    /// Optional provenance for the response part that contained {@link text} when
1154    /// the host took the snapshot.
1155    ///
1156    /// Advisory only: this is not a live range or offset and MUST NOT be used to
1157    /// recompute `text`.
1158    #[serde(default, skip_serializing_if = "Option::is_none")]
1159    pub response_part_id: Option<String>,
1160}
1161
1162/// Full state for a single session, loaded when a client subscribes to the session's URI.
1163///
1164/// Inlines (denormalizes) every {@link SessionMetadata} field directly onto
1165/// itself so subscribers receive one flat object instead of a nested summary.
1166/// The lightweight catalog representation is {@link SessionSummary}, surfaced on
1167/// the root channel; the host keeps the two in sync via
1168/// `root/sessionSummaryChanged`.
1169#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1170#[serde(rename_all = "camelCase")]
1171pub struct SessionState {
1172    /// Agent provider ID
1173    pub provider: String,
1174    /// Session title
1175    pub title: String,
1176    /// Current session status
1177    pub status: u32,
1178    /// Human-readable description of what the session is currently doing
1179    #[serde(default, skip_serializing_if = "Option::is_none")]
1180    pub activity: Option<String>,
1181    /// Server-owned project for this session
1182    #[serde(default, skip_serializing_if = "Option::is_none")]
1183    pub project: Option<ProjectInfo>,
1184    /// The working directories the session's agent has tool access to, as
1185    /// maintained by working-directory actions. Directories are equal peers except
1186    /// when the agent advertises
1187    /// {@link MultipleWorkingDirectoriesCapability.immutablePrimary} without
1188    /// {@link MultipleWorkingDirectoriesCapability.primaryReplacement} (the first
1189    /// entry is then a fixed process root), or advertises `primaryReplacement`
1190    /// (the first entry is a protected, replaceable primary slot). Individual chats
1191    /// MAY restrict to a subset via
1192    /// {@link ChatSummary.workingDirectories | their own `workingDirectories`}; a
1193    /// chat that sets none operates against this full set.
1194    #[serde(default, skip_serializing_if = "Option::is_none")]
1195    pub working_directories: Option<Vec<Uri>>,
1196    /// Lightweight summary of this session's inline annotations channel
1197    /// (`ahp-session:/<uuid>/annotations`). Surfaced so badge UI can render
1198    /// annotation / entry counts without subscribing. Absent when the session
1199    /// does not expose an annotations channel.
1200    #[serde(default, skip_serializing_if = "Option::is_none")]
1201    pub annotations: Option<AnnotationsSummary>,
1202    /// Session initialization state
1203    pub lifecycle: SessionLifecycle,
1204    /// Error details if creation failed
1205    #[serde(default, skip_serializing_if = "Option::is_none")]
1206    pub creation_error: Option<ErrorInfo>,
1207    /// Tools provided by the server (agent host) for this session
1208    #[serde(default, skip_serializing_if = "Option::is_none")]
1209    pub server_tools: Option<Vec<ToolDefinition>>,
1210    /// The clients currently providing tools and interactive capabilities to this
1211    /// session. If multiple tools or customizations are provided by the same
1212    /// active client, an agent host MAY deduplicate them when exposed to a model,
1213    /// with a preference given to the client that started the turn.
1214    ///
1215    /// Membership is host-managed: clients add (or refresh) themselves with
1216    /// `session/activeClientSet`, and the host removes them with
1217    /// `session/activeClientRemoved` when they unsubscribe, disconnect without
1218    /// reconnecting in time, or reconnect without resubscribing to the session.
1219    pub active_clients: Vec<SessionActiveClient>,
1220    /// Catalog of chats in this session.
1221    pub chats: Vec<ChatSummary>,
1222    /// The chat that receives input when the user addresses the session without
1223    /// selecting a specific chat. This is a UI routing hint, not a hierarchy
1224    /// marker — chats remain equal peers at the protocol level. Hosts MAY change
1225    /// this over the session's lifetime.
1226    #[serde(default, skip_serializing_if = "Option::is_none")]
1227    pub default_chat: Option<Uri>,
1228    /// Session configuration schema and current values
1229    #[serde(default, skip_serializing_if = "Option::is_none")]
1230    pub config: Option<SessionConfigState>,
1231    /// Top-level customizations active in this session.
1232    ///
1233    /// Always one of the {@link Customization} variants:
1234    ///
1235    /// - Container customizations ({@link PluginCustomization},
1236    ///   {@link DirectoryCustomization}) whose children — agents, skills,
1237    ///   prompts, rules, hooks, MCP servers — live in each container's
1238    ///   {@link ContainerCustomizationBase.children | `children`} array.
1239    /// - Top-level {@link McpServerCustomization} entries the host
1240    ///   surfaces directly (for example a globally-configured MCP server
1241    ///   that isn't bundled in a plugin or directory). MCP servers may
1242    ///   also appear as children of a container.
1243    ///
1244    /// Client-published plugins arrive via
1245    /// {@link SessionActiveClient.customizations | `activeClients[].customizations`}
1246    /// and the host propagates them into this list (typically with the
1247    /// container's `clientId` set and `children` populated). Clients
1248    /// publish in container shape only; bare MCP servers at the top level
1249    /// are server-originated.
1250    #[serde(default, skip_serializing_if = "Option::is_none")]
1251    pub customizations: Option<Vec<Customization>>,
1252    /// Catalogue of changesets the server can produce for this session. Each
1253    /// entry advertises a subscribable view of file changes (uncommitted,
1254    /// session-wide, per-turn, etc.) and the URI template the client expands
1255    /// before subscribing. See {@link Changeset} for the full shape and
1256    /// {@link /guide/changesets | Changesets} for an overview of the model.
1257    #[serde(default, skip_serializing_if = "Option::is_none")]
1258    pub changesets: Option<Vec<Changeset>>,
1259    /// Outstanding input the session is blocked on, aggregated across every chat
1260    /// so a client can discover and answer it from the session channel alone,
1261    /// without subscribing to individual chats.
1262    ///
1263    /// Each entry is self-sufficient: it carries the owning chat's URI plus every
1264    /// identifier the client needs to respond. A client answers by dispatching the
1265    /// ordinary `chat/*` action to that chat's channel — see
1266    /// {@link SessionInputRequest} for the per-variant response path. A list
1267    /// holding any entry other than
1268    /// {@link SessionInputRequestKind.ToolClientExecution} implies
1269    /// {@link SessionStatus.InputNeeded} on {@link SessionSummary.status};
1270    /// client-execution entries are work delegated to a client rather than a
1271    /// prompt, so they leave the session's activity unchanged.
1272    ///
1273    /// Host-managed: the host upserts entries with `session/inputNeededSet` as
1274    /// chats raise requests and removes them with `session/inputNeededRemoved`
1275    /// once the underlying request resolves.
1276    #[serde(default, skip_serializing_if = "Option::is_none")]
1277    pub input_needed: Option<Vec<SessionInputRequest>>,
1278    /// Additional provider-specific metadata for this session.
1279    ///
1280    /// Clients MAY look for well-known keys here to provide enhanced UI.
1281    /// For example, a `git` key may provide extra git metadata about the session's
1282    /// working directories.
1283    #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
1284    pub meta: Option<JsonObject>,
1285}
1286
1287/// A client currently providing tools and interactive capabilities to a session.
1288///
1289/// A session MAY have several active clients at once; entries in
1290/// {@link SessionState.activeClients} are keyed by `clientId`. The server SHOULD
1291/// automatically remove an active client when that client disconnects.
1292#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1293#[serde(rename_all = "camelCase")]
1294pub struct SessionActiveClient {
1295    /// Client identifier (matches `clientId` from `initialize`)
1296    pub client_id: String,
1297    /// Human-readable client name (e.g. `"VS Code"`)
1298    #[serde(default, skip_serializing_if = "Option::is_none")]
1299    pub display_name: Option<String>,
1300    /// Tools this client provides to the session
1301    pub tools: Vec<ToolDefinition>,
1302    /// Plugin customizations this client contributes to the session.
1303    ///
1304    /// Clients publish in [Open Plugins](https://open-plugins.com/) format
1305    /// — i.e. always container-shaped plugins. They MAY synthesize virtual
1306    /// plugins in memory and rely on the host to expand them into concrete
1307    /// children inside {@link SessionState.customizations}.
1308    #[serde(default, skip_serializing_if = "Option::is_none")]
1309    pub customizations: Option<Vec<ClientPluginCustomization>>,
1310}
1311
1312/// A user-input elicitation surfaced at the session level, mirroring the request
1313/// from an unresolved {@link InputRequestResponsePart} in the owning chat.
1314///
1315/// Respond by dispatching `chat/inputCompleted` (or syncing drafts with
1316/// `chat/inputAnswerChanged`) to {@link SessionInputRequestBase.chat | `chat`},
1317/// keyed by {@link ChatInputRequest.id | `request.id`}.
1318#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1319#[serde(rename_all = "camelCase")]
1320pub struct SessionChatInputRequest {
1321    /// Stable key for this entry, unique within the session's
1322    /// {@link SessionState.inputNeeded} list. The host derives it however it likes
1323    /// (for example from the chat URI plus the underlying request or tool-call
1324    /// id); consumers MUST treat it as opaque. It is the key for the
1325    /// `session/inputNeededSet` / `session/inputNeededRemoved` upsert convention.
1326    pub id: String,
1327    /// The chat the underlying request lives in. This is the channel a client
1328    /// dispatches its response to — it does not need to have subscribed to that
1329    /// chat first.
1330    pub chat: Uri,
1331    /// The mirrored chat input request.
1332    pub request: ChatInputRequest,
1333}
1334
1335/// A tool call blocked on confirmation — either parameter confirmation before
1336/// execution or result confirmation after — surfaced at the session level.
1337///
1338/// Respond by dispatching `chat/toolCallConfirmed` (for
1339/// {@link ToolCallPendingConfirmationState}) or `chat/toolCallResultConfirmed`
1340/// (for {@link ToolCallPendingResultConfirmationState}) to
1341/// {@link SessionInputRequestBase.chat | `chat`}, keyed by `turnId` and
1342/// `toolCall.toolCallId`.
1343#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1344#[serde(rename_all = "camelCase")]
1345pub struct SessionToolConfirmationRequest {
1346    /// Stable key for this entry, unique within the session's
1347    /// {@link SessionState.inputNeeded} list. The host derives it however it likes
1348    /// (for example from the chat URI plus the underlying request or tool-call
1349    /// id); consumers MUST treat it as opaque. It is the key for the
1350    /// `session/inputNeededSet` / `session/inputNeededRemoved` upsert convention.
1351    pub id: String,
1352    /// The chat the underlying request lives in. This is the channel a client
1353    /// dispatches its response to — it does not need to have subscribed to that
1354    /// chat first.
1355    pub chat: Uri,
1356    /// The turn the tool call belongs to.
1357    pub turn_id: String,
1358    /// The tool call awaiting confirmation.
1359    pub tool_call: ToolCallConfirmationState,
1360}
1361
1362/// A running tool whose execution is delegated to an active client. Surfaced so
1363/// a client that provides the tool can pick up the work without subscribing to
1364/// the owning chat.
1365///
1366/// The {@link toolCall} is always a {@link ToolCallRunningState} (a
1367/// {@link ToolCallState} in `running` status) whose
1368/// {@link ToolCallRunningState.contributor | `contributor`} is a client
1369/// {@link ToolCallClientContributor} whose `clientId` matches the denormalized
1370/// {@link clientId} here. Execute and report the result by dispatching
1371/// `chat/toolCallComplete` (and optionally streaming with
1372/// `chat/toolCallContentChanged`) to {@link SessionInputRequestBase.chat |
1373/// `chat`}, keyed by `turnId` and `toolCall.toolCallId`.
1374///
1375/// Unlike the other variants this does **not** raise
1376/// {@link SessionStatus.InputNeeded}: the call has already cleared its
1377/// confirmation gate and is merely executing elsewhere, so the session stays
1378/// {@link SessionStatus.InProgress} while it runs.
1379#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1380#[serde(rename_all = "camelCase")]
1381pub struct SessionToolClientExecutionRequest {
1382    /// Stable key for this entry, unique within the session's
1383    /// {@link SessionState.inputNeeded} list. The host derives it however it likes
1384    /// (for example from the chat URI plus the underlying request or tool-call
1385    /// id); consumers MUST treat it as opaque. It is the key for the
1386    /// `session/inputNeededSet` / `session/inputNeededRemoved` upsert convention.
1387    pub id: String,
1388    /// The chat the underlying request lives in. This is the channel a client
1389    /// dispatches its response to — it does not need to have subscribed to that
1390    /// chat first.
1391    pub chat: Uri,
1392    /// The turn the tool call belongs to.
1393    pub turn_id: String,
1394    /// The `clientId` expected to execute the tool. Matches the `clientId` of the
1395    /// tool call's client {@link ToolCallContributor}.
1396    pub client_id: String,
1397    /// The running tool call the session wants the owning client to execute. The
1398    /// host only ever populates this with a {@link ToolCallRunningState} (i.e. a
1399    /// {@link ToolCallState} in `running` status).
1400    pub tool_call: ToolCallState,
1401}
1402
1403/// A tool call blocked on MCP authentication mid-execution, surfaced at the
1404/// session level.
1405///
1406/// The {@link toolCall} is always a {@link ToolCallAuthRequiredState} (a
1407/// {@link ToolCallState} in `auth-required` status). Unlike
1408/// {@link SessionToolConfirmationRequest}, this is **not** answered by
1409/// dispatching a `chat/*` action directly: the client obtains a token for
1410/// {@link ToolCallAuthRequiredState.auth | `toolCall.auth`}`.resource` and
1411/// pushes it via the existing `authenticate` command (see
1412/// {@link /specification/authentication | Authentication}). The host resumes
1413/// the tool call and dispatches `chat/toolCallAuthResolved` once the token is
1414/// accepted, at which point it also removes this entry with
1415/// `session/inputNeededRemoved`.
1416#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1417#[serde(rename_all = "camelCase")]
1418pub struct SessionToolAuthenticationRequest {
1419    /// Stable key for this entry, unique within the session's
1420    /// {@link SessionState.inputNeeded} list. The host derives it however it likes
1421    /// (for example from the chat URI plus the underlying request or tool-call
1422    /// id); consumers MUST treat it as opaque. It is the key for the
1423    /// `session/inputNeededSet` / `session/inputNeededRemoved` upsert convention.
1424    pub id: String,
1425    /// The chat the underlying request lives in. This is the channel a client
1426    /// dispatches its response to — it does not need to have subscribed to that
1427    /// chat first.
1428    pub chat: Uri,
1429    /// The turn the tool call belongs to.
1430    pub turn_id: String,
1431    /// The tool call awaiting authentication.
1432    pub tool_call: ToolCallAuthRequiredState,
1433}
1434
1435/// Lightweight catalog entry summarizing one session. Surfaced via
1436/// {@link RootChannelCommands.listSessions | `root/listSessions`} and
1437/// `root/sessionAdded`/`root/sessionSummaryChanged` notifications.
1438///
1439/// **Aggregation across chats.** Once a session contains more than one chat,
1440/// several `SessionSummary` fields are derived from the underlying
1441/// {@link SessionState.chats | chat catalog}. Producers SHOULD follow these
1442/// rules so clients that only consume the session summary (e.g. a session
1443/// list) still see meaningful state:
1444///
1445/// - `status`: take the activity bits (`Idle` / `InProgress` / `InputNeeded` /
1446///   `Error` — bits 0–4) from the
1447///   {@link SessionState.defaultChat | default chat} when present, else from
1448///   the most recently modified chat. **Promote** `InputNeeded` whenever any
1449///   chat in the session needs input, and **promote** `Error` whenever any
1450///   chat is in an error state — both override the default-chat bits. The
1451///   orthogonal flag bits (`IsRead`, `IsArchived`) remain session-scoped.
1452/// - `activity`: mirror the activity string of the default chat, or of the
1453///   chat currently driving the promoted status bits when a non-default chat
1454///   wins (e.g. the chat that raised `InputNeeded`).
1455/// - `modifiedAt`: the max of all chats' `modifiedAt`.
1456/// - `workingDirectories`: the session-level set. Individual chats MAY restrict
1457///   to a subset via {@link ChatSummary.workingDirectories}; aggregating these
1458///   up is meaningless and SHOULD NOT be attempted.
1459/// - `changes`: optional roll-up across all chats. Producers MAY sum the
1460///   per-chat changeset stats or report the most expensive chat's stats —
1461///   whichever is cheaper for the host to compute.
1462///
1463/// Sessions with a single chat trivially satisfy all of the above (the chat's
1464/// values pass through unchanged). The rules only matter once a session
1465/// carries multiple chats.
1466#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1467#[serde(rename_all = "camelCase")]
1468pub struct SessionSummary {
1469    /// Agent provider ID
1470    pub provider: String,
1471    /// Session title
1472    pub title: String,
1473    /// Current session status
1474    pub status: u32,
1475    /// Human-readable description of what the session is currently doing
1476    #[serde(default, skip_serializing_if = "Option::is_none")]
1477    pub activity: Option<String>,
1478    /// Server-owned project for this session
1479    #[serde(default, skip_serializing_if = "Option::is_none")]
1480    pub project: Option<ProjectInfo>,
1481    /// The working directories the session's agent has tool access to, as
1482    /// maintained by working-directory actions. Directories are equal peers except
1483    /// when the agent advertises
1484    /// {@link MultipleWorkingDirectoriesCapability.immutablePrimary} without
1485    /// {@link MultipleWorkingDirectoriesCapability.primaryReplacement} (the first
1486    /// entry is then a fixed process root), or advertises `primaryReplacement`
1487    /// (the first entry is a protected, replaceable primary slot). Individual chats
1488    /// MAY restrict to a subset via
1489    /// {@link ChatSummary.workingDirectories | their own `workingDirectories`}; a
1490    /// chat that sets none operates against this full set.
1491    #[serde(default, skip_serializing_if = "Option::is_none")]
1492    pub working_directories: Option<Vec<Uri>>,
1493    /// Lightweight summary of this session's inline annotations channel
1494    /// (`ahp-session:/<uuid>/annotations`). Surfaced so badge UI can render
1495    /// annotation / entry counts without subscribing. Absent when the session
1496    /// does not expose an annotations channel.
1497    #[serde(default, skip_serializing_if = "Option::is_none")]
1498    pub annotations: Option<AnnotationsSummary>,
1499    /// Session URI
1500    pub resource: Uri,
1501    /// Creation timestamp (ISO 8601, e.g. `"2025-03-10T18:42:03.123Z"`)
1502    pub created_at: String,
1503    /// Last modification timestamp (ISO 8601, e.g. `"2025-03-10T18:42:03.123Z"`)
1504    pub modified_at: String,
1505    /// Aggregate summary of file changes associated with this session. Servers
1506    /// may populate this to give clients a quick at-a-glance view of the
1507    /// session's footprint (e.g., for list rendering) without requiring the
1508    /// client to subscribe to a changeset.
1509    #[serde(default, skip_serializing_if = "Option::is_none")]
1510    pub changes: Option<ChangesSummary>,
1511    /// Lightweight server-defined metadata clients may use for the session
1512    /// presentation. The protocol does not interpret these values; producers
1513    /// SHOULD keep the payload small because summaries appear in session lists
1514    /// and session notifications.
1515    #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
1516    pub meta: Option<JsonObject>,
1517}
1518
1519/// Aggregate counts describing the file changes associated with a session.
1520///
1521/// All fields are optional so servers can populate only the metrics they
1522/// cheaply have available.
1523#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Default)]
1524#[serde(rename_all = "camelCase")]
1525pub struct ChangesSummary {
1526    /// Total number of inserted lines across all changed files.
1527    #[serde(default, skip_serializing_if = "Option::is_none")]
1528    pub additions: Option<i64>,
1529    /// Total number of deleted lines across all changed files.
1530    #[serde(default, skip_serializing_if = "Option::is_none")]
1531    pub deletions: Option<i64>,
1532    /// Number of files that have changes.
1533    #[serde(default, skip_serializing_if = "Option::is_none")]
1534    pub files: Option<i64>,
1535}
1536
1537/// Server-owned project metadata for a session.
1538#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1539#[serde(rename_all = "camelCase")]
1540pub struct ProjectInfo {
1541    /// Project URI
1542    pub uri: Uri,
1543    /// Human-readable project name
1544    pub display_name: String,
1545}
1546
1547/// A session configuration property descriptor.
1548///
1549/// Extends the generic {@link ConfigPropertySchema} with session-specific
1550/// display extensions.
1551#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1552#[serde(rename_all = "camelCase")]
1553pub struct SessionConfigPropertySchema {
1554    /// JSON Schema: property type
1555    pub r#type: String,
1556    /// JSON Schema: human-readable label for the property
1557    pub title: String,
1558    /// JSON Schema: description / tooltip
1559    #[serde(default, skip_serializing_if = "Option::is_none")]
1560    pub description: Option<String>,
1561    /// JSON Schema: default value
1562    #[serde(default, skip_serializing_if = "Option::is_none")]
1563    pub default: Option<AnyValue>,
1564    /// JSON Schema: allowed values. May be primitives of any JSON type.
1565    #[serde(default, skip_serializing_if = "Option::is_none")]
1566    pub r#enum: Option<Vec<AnyValue>>,
1567    /// Display extension: human-readable label per enum value (parallel array)
1568    #[serde(default, skip_serializing_if = "Option::is_none")]
1569    pub enum_labels: Option<Vec<String>>,
1570    /// Display extension: description per enum value (parallel array)
1571    #[serde(default, skip_serializing_if = "Option::is_none")]
1572    pub enum_descriptions: Option<Vec<String>>,
1573    /// JSON Schema: when `true`, the property is displayed but cannot be modified by the user
1574    #[serde(default, skip_serializing_if = "Option::is_none")]
1575    pub read_only: Option<bool>,
1576    /// JSON Schema: schema for array items (used when `type` is `'array'`)
1577    #[serde(default, skip_serializing_if = "Option::is_none")]
1578    pub items: Option<ConfigPropertySchema>,
1579    /// JSON Schema: property descriptors for object properties (used when `type` is `'object'`)
1580    #[serde(default, skip_serializing_if = "Option::is_none")]
1581    pub properties: Option<std::collections::HashMap<String, ConfigPropertySchema>>,
1582    /// JSON Schema: list of required property ids (used when `type` is `'object'`)
1583    #[serde(default, skip_serializing_if = "Option::is_none")]
1584    pub required: Option<Vec<String>>,
1585    /// JSON Schema: schema for additional properties not listed in `properties` (used when `type` is `'object'`).
1586    #[serde(default, skip_serializing_if = "Option::is_none")]
1587    pub additional_properties: Option<ConfigPropertySchema>,
1588    /// Display extension: when `true`, the full set of allowed values is too large
1589    /// to enumerate statically. The client SHOULD use `sessionConfigCompletions`
1590    /// to fetch matching values based on user input. Any values in `enum` are
1591    /// seed/recent values for initial display.
1592    #[serde(default, skip_serializing_if = "Option::is_none")]
1593    pub enum_dynamic: Option<bool>,
1594    /// When `true`, the user may change this property after session creation
1595    #[serde(default, skip_serializing_if = "Option::is_none")]
1596    pub session_mutable: Option<bool>,
1597}
1598
1599/// A JSON Schema object describing available session configuration metadata.
1600#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1601#[serde(rename_all = "camelCase")]
1602pub struct SessionConfigSchema {
1603    /// JSON Schema: always `'object'`
1604    pub r#type: String,
1605    /// JSON Schema: property descriptors keyed by property id
1606    pub properties: std::collections::HashMap<String, SessionConfigPropertySchema>,
1607    /// JSON Schema: list of required property ids
1608    #[serde(default, skip_serializing_if = "Option::is_none")]
1609    pub required: Option<Vec<String>>,
1610}
1611
1612/// Live session configuration metadata.
1613///
1614/// The schema describes the available configuration properties and the values
1615/// contain the current value for each resolved property.
1616#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1617#[serde(rename_all = "camelCase")]
1618pub struct SessionConfigState {
1619    /// JSON Schema describing available configuration properties
1620    pub schema: SessionConfigSchema,
1621    /// Current configuration values
1622    pub values: JsonObject,
1623}
1624
1625/// A completed request/response cycle.
1626#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1627#[serde(rename_all = "camelCase")]
1628pub struct Turn {
1629    /// Turn identifier
1630    pub id: String,
1631    /// ISO 8601 timestamp when this turn started.
1632    #[serde(default, skip_serializing_if = "Option::is_none")]
1633    pub started_at: Option<String>,
1634    /// Turn duration in milliseconds.
1635    #[serde(default, skip_serializing_if = "Option::is_none")]
1636    pub duration: Option<i64>,
1637    /// The message that initiated the turn
1638    pub message: Message,
1639    /// All response content in stream order: text, tool calls, reasoning, and content refs.
1640    ///
1641    /// Consumers should derive display text by concatenating markdown parts,
1642    /// and find tool calls by filtering for `ToolCall` parts.
1643    pub response_parts: Vec<ResponsePart>,
1644    /// Token usage info
1645    #[serde(default, skip_serializing_if = "Option::is_none")]
1646    pub usage: Option<UsageInfo>,
1647    /// How the turn ended
1648    pub state: TurnState,
1649    /// Error details if state is `'error'`
1650    #[serde(default, skip_serializing_if = "Option::is_none")]
1651    pub error: Option<ErrorInfo>,
1652}
1653
1654/// An in-progress turn — the assistant is actively streaming.
1655#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1656#[serde(rename_all = "camelCase")]
1657pub struct ActiveTurn {
1658    /// Turn identifier
1659    pub id: String,
1660    /// ISO 8601 timestamp when this turn started.
1661    pub started_at: String,
1662    /// The message that initiated the turn
1663    pub message: Message,
1664    /// All response content in stream order: text, tool calls, reasoning, and content refs.
1665    ///
1666    /// Tool call parts include `pendingPermissions` when permissions are awaiting user approval.
1667    pub response_parts: Vec<ResponsePart>,
1668    /// Token usage info
1669    #[serde(default, skip_serializing_if = "Option::is_none")]
1670    pub usage: Option<UsageInfo>,
1671}
1672
1673/// A message that initiates or steers a turn. Messages can originate from the
1674/// user, the agent, a tool, or be system-generated (see {@link MessageOrigin}).
1675///
1676/// Attachments MAY be referenced inside {@link Message.text} via their
1677/// {@link MessageAttachmentBase.range} field. Attachments without a range are
1678/// still associated with the message but do not correspond to a specific span
1679/// in the text.
1680#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1681#[serde(rename_all = "camelCase")]
1682pub struct Message {
1683    /// Message text
1684    pub text: String,
1685    /// The origin of the message
1686    pub origin: MessageOrigin,
1687    /// File/selection attachments
1688    #[serde(default, skip_serializing_if = "Option::is_none")]
1689    pub attachments: Option<Vec<MessageAttachment>>,
1690    /// The model this message was, or will be, sent with.
1691    ///
1692    /// For historic user/agent messages this records the model actually used, so
1693    /// a client editing or resending the message can retain that selection. For a
1694    /// {@link ChatState.draft | draft} it carries the model the user picked for
1695    /// the message they are composing. Absent means the agent host's default
1696    /// model applies.
1697    #[serde(default, skip_serializing_if = "Option::is_none")]
1698    pub model: Option<ModelSelection>,
1699    /// The custom agent this message was, or will be, sent with.
1700    ///
1701    /// For historic messages this records the agent actually used; for a
1702    /// {@link ChatState.draft | draft} it carries the agent the user picked.
1703    /// Absent means no custom agent — the provider's default behavior applies.
1704    #[serde(default, skip_serializing_if = "Option::is_none")]
1705    pub agent: Option<AgentSelection>,
1706    /// Additional provider-specific metadata for this message.
1707    ///
1708    /// Clients MAY look for well-known keys here to provide enhanced UI, and
1709    /// agent hosts MAY use it to carry context that does not fit any other
1710    /// field. Mirrors the MCP `_meta` convention.
1711    #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
1712    pub meta: Option<JsonObject>,
1713}
1714
1715/// Identifies the origin of a {@link Message} — who produced it. For the message
1716/// that initiates a turn ({@link Turn.message}), this is also the origin of the
1717/// turn; for steering or queued messages it is just the origin of that message.
1718#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1719#[serde(rename_all = "camelCase")]
1720pub struct MessageOrigin {
1721    /// The kind of actor that produced the message.
1722    pub kind: MessageKind,
1723}
1724
1725/// A choice in a select-style question.
1726#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1727#[serde(rename_all = "camelCase")]
1728pub struct ChatInputOption {
1729    /// Stable option identifier; for MCP enum values this is the enum string
1730    pub id: String,
1731    /// Display label
1732    pub label: String,
1733    /// Optional secondary text
1734    #[serde(default, skip_serializing_if = "Option::is_none")]
1735    pub description: Option<String>,
1736    /// Whether this option is the recommended/default choice
1737    #[serde(default, skip_serializing_if = "Option::is_none")]
1738    pub recommended: Option<bool>,
1739}
1740
1741/// Value captured for one answer.
1742#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1743#[serde(rename_all = "camelCase")]
1744pub struct ChatInputTextAnswerValue {
1745    pub value: String,
1746}
1747
1748#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1749#[serde(rename_all = "camelCase")]
1750pub struct ChatInputNumberAnswerValue {
1751    pub value: f64,
1752}
1753
1754#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1755#[serde(rename_all = "camelCase")]
1756pub struct ChatInputBooleanAnswerValue {
1757    pub value: bool,
1758}
1759
1760#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1761#[serde(rename_all = "camelCase")]
1762pub struct ChatInputSelectedAnswerValue {
1763    pub value: String,
1764    /// Free-form text entered instead of selecting an option
1765    #[serde(default, skip_serializing_if = "Option::is_none")]
1766    pub freeform_values: Option<Vec<String>>,
1767}
1768
1769#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1770#[serde(rename_all = "camelCase")]
1771pub struct ChatInputSelectedManyAnswerValue {
1772    pub value: Vec<String>,
1773    /// Free-form text entered in addition to selected options
1774    #[serde(default, skip_serializing_if = "Option::is_none")]
1775    pub freeform_values: Option<Vec<String>>,
1776}
1777
1778#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1779#[serde(rename_all = "camelCase")]
1780pub struct ChatInputAnswered {
1781    /// Answer value
1782    pub value: ChatInputAnswerValue,
1783}
1784
1785#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Default)]
1786#[serde(rename_all = "camelCase")]
1787pub struct ChatInputSkipped {
1788    /// Free-form reason or value captured while skipping, if any
1789    #[serde(default, skip_serializing_if = "Option::is_none")]
1790    pub freeform_values: Option<Vec<String>>,
1791}
1792
1793/// Text question within a chat input request.
1794#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1795#[serde(rename_all = "camelCase")]
1796pub struct ChatInputTextQuestion {
1797    /// Stable question identifier used as the key in `answers`
1798    pub id: String,
1799    /// Short display title
1800    #[serde(default, skip_serializing_if = "Option::is_none")]
1801    pub title: Option<String>,
1802    /// Prompt shown to the user
1803    pub message: String,
1804    /// Whether the user must answer this question to accept the request
1805    #[serde(default, skip_serializing_if = "Option::is_none")]
1806    pub required: Option<bool>,
1807    /// Format hint for text questions, such as `email`, `uri`, `date`, or `date-time`
1808    #[serde(default, skip_serializing_if = "Option::is_none")]
1809    pub format: Option<String>,
1810    /// Minimum string length
1811    #[serde(default, skip_serializing_if = "Option::is_none")]
1812    pub min: Option<i64>,
1813    /// Maximum string length
1814    #[serde(default, skip_serializing_if = "Option::is_none")]
1815    pub max: Option<i64>,
1816    /// Default text
1817    #[serde(default, skip_serializing_if = "Option::is_none")]
1818    pub default_value: Option<String>,
1819}
1820
1821/// Numeric question within a chat input request.
1822#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1823#[serde(rename_all = "camelCase")]
1824pub struct ChatInputNumberQuestion {
1825    /// Stable question identifier used as the key in `answers`
1826    pub id: String,
1827    /// Short display title
1828    #[serde(default, skip_serializing_if = "Option::is_none")]
1829    pub title: Option<String>,
1830    /// Prompt shown to the user
1831    pub message: String,
1832    /// Whether the user must answer this question to accept the request
1833    #[serde(default, skip_serializing_if = "Option::is_none")]
1834    pub required: Option<bool>,
1835    /// Minimum value
1836    #[serde(default, skip_serializing_if = "Option::is_none")]
1837    pub min: Option<f64>,
1838    /// Maximum value
1839    #[serde(default, skip_serializing_if = "Option::is_none")]
1840    pub max: Option<f64>,
1841    /// Default numeric value
1842    #[serde(default, skip_serializing_if = "Option::is_none")]
1843    pub default_value: Option<f64>,
1844}
1845
1846/// Boolean question within a chat input request.
1847#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1848#[serde(rename_all = "camelCase")]
1849pub struct ChatInputBooleanQuestion {
1850    /// Stable question identifier used as the key in `answers`
1851    pub id: String,
1852    /// Short display title
1853    #[serde(default, skip_serializing_if = "Option::is_none")]
1854    pub title: Option<String>,
1855    /// Prompt shown to the user
1856    pub message: String,
1857    /// Whether the user must answer this question to accept the request
1858    #[serde(default, skip_serializing_if = "Option::is_none")]
1859    pub required: Option<bool>,
1860    /// Default boolean value
1861    #[serde(default, skip_serializing_if = "Option::is_none")]
1862    pub default_value: Option<bool>,
1863}
1864
1865/// Single-select question within a chat input request.
1866#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1867#[serde(rename_all = "camelCase")]
1868pub struct ChatInputSingleSelectQuestion {
1869    /// Stable question identifier used as the key in `answers`
1870    pub id: String,
1871    /// Short display title
1872    #[serde(default, skip_serializing_if = "Option::is_none")]
1873    pub title: Option<String>,
1874    /// Prompt shown to the user
1875    pub message: String,
1876    /// Whether the user must answer this question to accept the request
1877    #[serde(default, skip_serializing_if = "Option::is_none")]
1878    pub required: Option<bool>,
1879    /// Options the user may select from
1880    pub options: Vec<ChatInputOption>,
1881    /// Whether the user may enter text instead of selecting an option
1882    #[serde(default, skip_serializing_if = "Option::is_none")]
1883    pub allow_freeform_input: Option<bool>,
1884}
1885
1886/// Multi-select question within a chat input request.
1887#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1888#[serde(rename_all = "camelCase")]
1889pub struct ChatInputMultiSelectQuestion {
1890    /// Stable question identifier used as the key in `answers`
1891    pub id: String,
1892    /// Short display title
1893    #[serde(default, skip_serializing_if = "Option::is_none")]
1894    pub title: Option<String>,
1895    /// Prompt shown to the user
1896    pub message: String,
1897    /// Whether the user must answer this question to accept the request
1898    #[serde(default, skip_serializing_if = "Option::is_none")]
1899    pub required: Option<bool>,
1900    /// Options the user may select from
1901    pub options: Vec<ChatInputOption>,
1902    /// Whether the user may enter text in addition to selecting options
1903    #[serde(default, skip_serializing_if = "Option::is_none")]
1904    pub allow_freeform_input: Option<bool>,
1905    /// Minimum selected item count
1906    #[serde(default, skip_serializing_if = "Option::is_none")]
1907    pub min: Option<i64>,
1908    /// Maximum selected item count
1909    #[serde(default, skip_serializing_if = "Option::is_none")]
1910    pub max: Option<i64>,
1911}
1912
1913/// The request payload carried by an {@link InputRequestResponsePart}.
1914///
1915/// The server creates or replaces the containing response part with
1916/// `chat/inputRequested`. Clients sync drafts with `chat/inputAnswerChanged`
1917/// and submit responses with `chat/inputCompleted`.
1918#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1919#[serde(rename_all = "camelCase")]
1920pub struct ChatInputRequest {
1921    /// Stable request identifier
1922    pub id: String,
1923    /// Display message for the request as a whole
1924    #[serde(default, skip_serializing_if = "Option::is_none")]
1925    pub message: Option<String>,
1926    /// URL the user should review or open, for URL-style elicitations
1927    #[serde(default, skip_serializing_if = "Option::is_none")]
1928    pub url: Option<Uri>,
1929    /// Ordered questions to ask the user
1930    #[serde(default, skip_serializing_if = "Option::is_none")]
1931    pub questions: Option<Vec<ChatInputQuestion>>,
1932    /// Current draft or submitted answers, keyed by question ID
1933    #[serde(default, skip_serializing_if = "Option::is_none")]
1934    pub answers: Option<std::collections::HashMap<String, ChatInputAnswer>>,
1935}
1936
1937/// A zero-based position within a textual document.
1938#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1939#[serde(rename_all = "camelCase")]
1940pub struct TextPosition {
1941    /// Zero-based line number.
1942    pub line: i64,
1943    /// Zero-based character offset within the line.
1944    pub character: i64,
1945}
1946
1947/// A range within a textual document.
1948#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1949#[serde(rename_all = "camelCase")]
1950pub struct TextRange {
1951    /// Start position of the range.
1952    pub start: TextPosition,
1953    /// End position of the range.
1954    pub end: TextPosition,
1955}
1956
1957/// A selection within a textual resource.
1958///
1959/// This is only meaningful for textual resources. Binary resources may still
1960/// use resource or embedded resource attachments, but they should not use this
1961/// text selection field.
1962#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1963#[serde(rename_all = "camelCase")]
1964pub struct TextSelection {
1965    /// The range covered by the selection.
1966    pub range: TextRange,
1967}
1968
1969/// A simple, opaque attachment whose model representation is described by
1970/// the producer.
1971#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1972#[serde(rename_all = "camelCase")]
1973pub struct SimpleMessageAttachment {
1974    /// A human-readable label for the attachment (e.g. the filename of a file
1975    /// attachment). Used for display in UI.
1976    pub label: String,
1977    /// If defined, the range in {@link Message.text} that references this
1978    /// attachment. This is a text range, not a byte range.
1979    #[serde(default, skip_serializing_if = "Option::is_none")]
1980    pub range: Option<TextRange>,
1981    /// Advisory display hint for clients rendering this attachment. Recognized
1982    /// values include:
1983    ///
1984    /// - `'image'`: the attachment is an image
1985    /// - `'document'`: the attachment is a textual document
1986    /// - `'symbol'`: the attachment is a code symbol (e.g. a function or class)
1987    /// - `'directory'`: the attachment is a folder
1988    /// - `'selection'`: the attachment is a selection within a document
1989    ///
1990    /// Implementations MAY provide additional values; clients SHOULD fall back
1991    /// to a reasonable default when an unknown value is encountered.
1992    #[serde(default, skip_serializing_if = "Option::is_none")]
1993    pub display_kind: Option<String>,
1994    /// Additional implementation-defined metadata for the attachment.
1995    ///
1996    /// If the attachment was produced by the `completions` command, the client
1997    /// MUST preserve every property of `_meta` originally returned by the agent
1998    /// host when sending the user message containing the accepted completion.
1999    #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
2000    pub meta: Option<JsonObject>,
2001    /// Representation of the attachment as it should be shown to the model.
2002    ///
2003    /// If the attachment was produced by the client, this property MUST be
2004    /// defined so the agent host can correctly interpret the attachment. This
2005    /// property MAY be omitted when the attachment originated from a
2006    /// `completions` response.
2007    #[serde(default, skip_serializing_if = "Option::is_none")]
2008    pub model_representation: Option<String>,
2009}
2010
2011/// An attachment whose data is embedded inline as a base64 string.
2012///
2013/// Use this for small binary payloads (e.g. a pasted image) that should be
2014/// delivered with the user message itself rather than fetched separately.
2015#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
2016#[serde(rename_all = "camelCase")]
2017pub struct MessageEmbeddedResourceAttachment {
2018    /// A human-readable label for the attachment (e.g. the filename of a file
2019    /// attachment). Used for display in UI.
2020    pub label: String,
2021    /// If defined, the range in {@link Message.text} that references this
2022    /// attachment. This is a text range, not a byte range.
2023    #[serde(default, skip_serializing_if = "Option::is_none")]
2024    pub range: Option<TextRange>,
2025    /// Advisory display hint for clients rendering this attachment. Recognized
2026    /// values include:
2027    ///
2028    /// - `'image'`: the attachment is an image
2029    /// - `'document'`: the attachment is a textual document
2030    /// - `'symbol'`: the attachment is a code symbol (e.g. a function or class)
2031    /// - `'directory'`: the attachment is a folder
2032    /// - `'selection'`: the attachment is a selection within a document
2033    ///
2034    /// Implementations MAY provide additional values; clients SHOULD fall back
2035    /// to a reasonable default when an unknown value is encountered.
2036    #[serde(default, skip_serializing_if = "Option::is_none")]
2037    pub display_kind: Option<String>,
2038    /// Additional implementation-defined metadata for the attachment.
2039    ///
2040    /// If the attachment was produced by the `completions` command, the client
2041    /// MUST preserve every property of `_meta` originally returned by the agent
2042    /// host when sending the user message containing the accepted completion.
2043    #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
2044    pub meta: Option<JsonObject>,
2045    /// Base64-encoded binary data
2046    pub data: String,
2047    /// Content MIME type (e.g. `"image/png"`, `"application/pdf"`)
2048    pub content_type: String,
2049    /// Optional selection within the attached textual resource.
2050    ///
2051    /// Only meaningful for textual resources.
2052    #[serde(default, skip_serializing_if = "Option::is_none")]
2053    pub selection: Option<TextSelection>,
2054}
2055
2056/// An attachment that references a resource by URI. The content is not
2057/// delivered inline; consumers can fetch it via `resourceRead` when needed.
2058#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
2059#[serde(rename_all = "camelCase")]
2060pub struct MessageResourceAttachment {
2061    /// A human-readable label for the attachment (e.g. the filename of a file
2062    /// attachment). Used for display in UI.
2063    pub label: String,
2064    /// If defined, the range in {@link Message.text} that references this
2065    /// attachment. This is a text range, not a byte range.
2066    #[serde(default, skip_serializing_if = "Option::is_none")]
2067    pub range: Option<TextRange>,
2068    /// Advisory display hint for clients rendering this attachment. Recognized
2069    /// values include:
2070    ///
2071    /// - `'image'`: the attachment is an image
2072    /// - `'document'`: the attachment is a textual document
2073    /// - `'symbol'`: the attachment is a code symbol (e.g. a function or class)
2074    /// - `'directory'`: the attachment is a folder
2075    /// - `'selection'`: the attachment is a selection within a document
2076    ///
2077    /// Implementations MAY provide additional values; clients SHOULD fall back
2078    /// to a reasonable default when an unknown value is encountered.
2079    #[serde(default, skip_serializing_if = "Option::is_none")]
2080    pub display_kind: Option<String>,
2081    /// Additional implementation-defined metadata for the attachment.
2082    ///
2083    /// If the attachment was produced by the `completions` command, the client
2084    /// MUST preserve every property of `_meta` originally returned by the agent
2085    /// host when sending the user message containing the accepted completion.
2086    #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
2087    pub meta: Option<JsonObject>,
2088    /// Content URI
2089    pub uri: Uri,
2090    /// Approximate size in bytes
2091    #[serde(default, skip_serializing_if = "Option::is_none")]
2092    pub size_hint: Option<i64>,
2093    /// Content MIME type
2094    #[serde(default, skip_serializing_if = "Option::is_none")]
2095    pub content_type: Option<String>,
2096    /// Content nonce
2097    #[serde(default, skip_serializing_if = "Option::is_none")]
2098    pub nonce: Option<String>,
2099    /// Optional selection within the referenced textual resource.
2100    ///
2101    /// Only meaningful for textual resources.
2102    #[serde(default, skip_serializing_if = "Option::is_none")]
2103    pub selection: Option<TextSelection>,
2104}
2105
2106/// An attachment that references annotations on a session's annotations
2107/// channel (see {@link AnnotationsState}).
2108///
2109/// When {@link annotationIds} is omitted the attachment references every
2110/// annotation on the channel; when present it references only the listed
2111/// {@link Annotation.id | annotation ids}.
2112#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
2113#[serde(rename_all = "camelCase")]
2114pub struct MessageAnnotationsAttachment {
2115    /// A human-readable label for the attachment (e.g. the filename of a file
2116    /// attachment). Used for display in UI.
2117    pub label: String,
2118    /// If defined, the range in {@link Message.text} that references this
2119    /// attachment. This is a text range, not a byte range.
2120    #[serde(default, skip_serializing_if = "Option::is_none")]
2121    pub range: Option<TextRange>,
2122    /// Advisory display hint for clients rendering this attachment. Recognized
2123    /// values include:
2124    ///
2125    /// - `'image'`: the attachment is an image
2126    /// - `'document'`: the attachment is a textual document
2127    /// - `'symbol'`: the attachment is a code symbol (e.g. a function or class)
2128    /// - `'directory'`: the attachment is a folder
2129    /// - `'selection'`: the attachment is a selection within a document
2130    ///
2131    /// Implementations MAY provide additional values; clients SHOULD fall back
2132    /// to a reasonable default when an unknown value is encountered.
2133    #[serde(default, skip_serializing_if = "Option::is_none")]
2134    pub display_kind: Option<String>,
2135    /// Additional implementation-defined metadata for the attachment.
2136    ///
2137    /// If the attachment was produced by the `completions` command, the client
2138    /// MUST preserve every property of `_meta` originally returned by the agent
2139    /// host when sending the user message containing the accepted completion.
2140    #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
2141    pub meta: Option<JsonObject>,
2142    /// The annotations channel URI (typically `ahp-session:/<uuid>/annotations`).
2143    /// Matches {@link AnnotationsSummary.resource}.
2144    pub resource: Uri,
2145    /// Specific {@link Annotation.id | annotation ids} to reference. When
2146    /// omitted, the attachment references all annotations on the channel.
2147    #[serde(default, skip_serializing_if = "Option::is_none")]
2148    pub annotation_ids: Option<Vec<String>>,
2149}
2150
2151/// An attachment that references a chat transcript through a fixed completed
2152/// turn.
2153///
2154/// The referenced chat MAY belong to a different session than the message's
2155/// chat. The attachment's model representation identifies the chat in a way
2156/// that hosts can resolve regardless of the session that owns it.
2157///
2158/// When `endTurn` is omitted, the host MUST resolve and pin the referenced
2159/// chat's latest completed turn when accepting the message. This lets clients
2160/// attach a chat without knowing its turn identifiers. When provided, `endTurn`
2161/// MUST reference a completed, retained turn. The host resolves the transcript
2162/// from its first retained turn through the pinned turn, inclusive. Later turns
2163/// do not change the context represented by an already-sent attachment.
2164///
2165/// When the referenced chat has no completed retained turns, the resolved
2166/// transcript is empty and hosts MUST NOT reject the attachment on that basis.
2167///
2168/// Hosts MUST NOT recursively expand chat attachments found inside the
2169/// referenced transcript. Clients SHOULD keep rendering `label` if the
2170/// referenced chat is later pruned, and treat opening `resource` as best-effort.
2171#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
2172#[serde(rename_all = "camelCase")]
2173pub struct MessageChatAttachment {
2174    /// A human-readable label for the attachment (e.g. the filename of a file
2175    /// attachment). Used for display in UI.
2176    pub label: String,
2177    /// If defined, the range in {@link Message.text} that references this
2178    /// attachment. This is a text range, not a byte range.
2179    #[serde(default, skip_serializing_if = "Option::is_none")]
2180    pub range: Option<TextRange>,
2181    /// Advisory display hint for clients rendering this attachment. Recognized
2182    /// values include:
2183    ///
2184    /// - `'image'`: the attachment is an image
2185    /// - `'document'`: the attachment is a textual document
2186    /// - `'symbol'`: the attachment is a code symbol (e.g. a function or class)
2187    /// - `'directory'`: the attachment is a folder
2188    /// - `'selection'`: the attachment is a selection within a document
2189    ///
2190    /// Implementations MAY provide additional values; clients SHOULD fall back
2191    /// to a reasonable default when an unknown value is encountered.
2192    #[serde(default, skip_serializing_if = "Option::is_none")]
2193    pub display_kind: Option<String>,
2194    /// Additional implementation-defined metadata for the attachment.
2195    ///
2196    /// If the attachment was produced by the `completions` command, the client
2197    /// MUST preserve every property of `_meta` originally returned by the agent
2198    /// host when sending the user message containing the accepted completion.
2199    #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
2200    pub meta: Option<JsonObject>,
2201    /// URI of the referenced chat.
2202    pub resource: Uri,
2203    /// Last completed turn included in the referenced transcript. When omitted,
2204    /// the host pins the latest completed turn when accepting the message.
2205    #[serde(default, skip_serializing_if = "Option::is_none")]
2206    pub end_turn: Option<String>,
2207}
2208
2209#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
2210#[serde(rename_all = "camelCase")]
2211pub struct MarkdownResponsePart {
2212    /// Part identifier, used by `chat/delta` to target this part for content appends
2213    pub id: String,
2214    /// Markdown content
2215    pub content: String,
2216}
2217
2218/// A reference to large content stored outside the state tree.
2219#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
2220#[serde(rename_all = "camelCase")]
2221pub struct ContentRef {
2222    /// Content URI
2223    pub uri: Uri,
2224    /// Approximate size in bytes
2225    #[serde(default, skip_serializing_if = "Option::is_none")]
2226    pub size_hint: Option<i64>,
2227    /// Content MIME type
2228    #[serde(default, skip_serializing_if = "Option::is_none")]
2229    pub content_type: Option<String>,
2230    /// Content nonce
2231    #[serde(default, skip_serializing_if = "Option::is_none")]
2232    pub nonce: Option<String>,
2233}
2234
2235/// A content part that's a reference to large content stored outside the state tree.
2236#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
2237#[serde(rename_all = "camelCase")]
2238pub struct ResourceResponsePart {
2239    /// Content URI
2240    pub uri: Uri,
2241    /// Approximate size in bytes
2242    #[serde(default, skip_serializing_if = "Option::is_none")]
2243    pub size_hint: Option<i64>,
2244    /// Content MIME type
2245    #[serde(default, skip_serializing_if = "Option::is_none")]
2246    pub content_type: Option<String>,
2247    /// Content nonce
2248    #[serde(default, skip_serializing_if = "Option::is_none")]
2249    pub nonce: Option<String>,
2250}
2251
2252/// A tool call represented as a response part.
2253///
2254/// Tool calls are part of the response stream, interleaved with text and
2255/// reasoning. The `toolCall.toolCallId` serves as the part identifier for
2256/// actions that target this part.
2257#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
2258#[serde(rename_all = "camelCase")]
2259pub struct ToolCallResponsePart {
2260    /// Full tool call lifecycle state
2261    pub tool_call: ToolCallState,
2262}
2263
2264/// Reasoning/thinking content from the model.
2265#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
2266#[serde(rename_all = "camelCase")]
2267pub struct ReasoningResponsePart {
2268    /// Part identifier, used by `chat/reasoning` to target this part for content appends
2269    pub id: String,
2270    /// Accumulated reasoning text
2271    pub content: String,
2272}
2273
2274/// A system notification surfaced as part of the response stream.
2275///
2276/// System notifications are messages authored by the agent harness
2277/// that need to be visible to both the agent (for situational awareness) and
2278/// the user (for transcript continuity). Examples include "background subagent
2279/// X completed" or "task Y was cancelled".
2280#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
2281#[serde(rename_all = "camelCase")]
2282pub struct SystemNotificationResponsePart {
2283    /// The text of the system notification
2284    pub content: StringOrMarkdown,
2285    /// Additional provider-specific metadata for this notification.
2286    ///
2287    /// A host MAY attach a machine-readable descriptor of what triggered the
2288    /// notification so clients can categorize, icon, group, filter, or localize
2289    /// it without parsing `content`. Clients MAY look for well-known keys here to
2290    /// provide enhanced UI, and MUST render coherently from `content` alone when
2291    /// `_meta` is absent or unrecognized.
2292    #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
2293    pub meta: Option<JsonObject>,
2294}
2295
2296/// A live or resolved input request (elicitation) in the turn response stream.
2297///
2298/// The server inserts the part with `chat/inputRequested`. While
2299/// {@link response} is absent, clients can update answer drafts with
2300/// `chat/inputAnswerChanged` and submit a response with `chat/inputCompleted`.
2301/// Completion updates this part in place so its stream position is stable and
2302/// the full interaction remains durable and backfillable via `fetchTurns`.
2303///
2304/// If the turn ends without a submitted response, the unresolved part remains
2305/// in the completed turn transcript with {@link response} absent.
2306#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
2307#[serde(rename_all = "camelCase")]
2308pub struct InputRequestResponsePart {
2309    /// The request, carrying its `id`, `message`, `url`, `questions`, and current
2310    /// draft or submitted `answers`.
2311    pub request: ChatInputRequest,
2312    /// How the request was resolved. Absent until a client submits `accept`,
2313    /// `decline`, or `cancel` with `chat/inputCompleted`.
2314    #[serde(default, skip_serializing_if = "Option::is_none")]
2315    pub response: Option<ChatInputResponseKind>,
2316}
2317
2318/// Tool execution result details, available after execution completes.
2319#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
2320#[serde(rename_all = "camelCase")]
2321pub struct ToolCallResult {
2322    /// Whether the tool succeeded
2323    pub success: bool,
2324    /// Past-tense description of what the tool did
2325    pub past_tense_message: StringOrMarkdown,
2326    /// Unstructured result content blocks.
2327    ///
2328    /// This mirrors the `content` field of MCP `CallToolResult`.
2329    #[serde(default, skip_serializing_if = "Option::is_none")]
2330    pub content: Option<Vec<ToolResultContent>>,
2331    /// Optional structured result object.
2332    ///
2333    /// This mirrors the `structuredContent` field of MCP `CallToolResult`.
2334    #[serde(default, skip_serializing_if = "Option::is_none")]
2335    pub structured_content: Option<JsonObject>,
2336    /// Error details if the tool failed
2337    #[serde(default, skip_serializing_if = "Option::is_none")]
2338    pub error: Option<AnyValue>,
2339}
2340
2341/// The model judge is still evaluating the tool call.
2342#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
2343#[serde(rename_all = "camelCase")]
2344pub struct ToolCallRiskAssessmentLoadingState {
2345    pub kind: ToolCallRiskAssessmentKind,
2346}
2347
2348/// The model judge has completed its evaluation.
2349#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
2350#[serde(rename_all = "camelCase")]
2351pub struct ToolCallRiskAssessmentCompleteState {
2352    pub kind: ToolCallRiskAssessmentKind,
2353    pub reason: StringOrMarkdown,
2354    /// The judge's normalized safety score, where `0` is unsafe and `1` is safe.
2355    pub safety: f64,
2356}
2357
2358/// A confirmation option that the server offers for a tool call awaiting
2359/// approval. Allows richer choices beyond simple approve/deny — for example,
2360/// "Approve in this Session" or "Deny with reason."
2361#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
2362#[serde(rename_all = "camelCase")]
2363pub struct ConfirmationOption {
2364    /// Unique identifier for the option, returned in the confirmed action
2365    pub id: String,
2366    /// Human-readable label displayed to the user
2367    pub label: String,
2368    /// Whether this option represents an approval or denial
2369    pub kind: ConfirmationOptionKind,
2370    /// Logical group number for visual categorisation.
2371    ///
2372    /// Clients SHOULD display options in the order they are defined and MAY
2373    /// use differing group numbers to insert dividers between logical clusters
2374    /// of options.
2375    #[serde(default, skip_serializing_if = "Option::is_none")]
2376    pub group: Option<i64>,
2377}
2378
2379/// LM is streaming the tool call parameters.
2380#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
2381#[serde(rename_all = "camelCase")]
2382pub struct ToolCallStreamingState {
2383    /// Unique tool call identifier
2384    pub tool_call_id: String,
2385    /// Internal tool name (for debugging/logging)
2386    pub tool_name: String,
2387    /// Human-readable tool name
2388    pub display_name: String,
2389    /// Human-readable description of what the tool invocation intends to do
2390    #[serde(default, skip_serializing_if = "Option::is_none")]
2391    pub intention: Option<String>,
2392    /// Reference to the contributor of the tool being called.
2393    #[serde(default, skip_serializing_if = "Option::is_none")]
2394    pub contributor: Option<ToolCallContributor>,
2395    /// Additional provider-specific metadata for this tool call.
2396    ///
2397    /// This MAY include a `ui` field corresponding to the MCP Apps (SEP-1865)
2398    /// `McpUiToolMeta` found in MCP tool calls, which may be used in combination
2399    /// with the {@link contributor} to serve MCP Apps.
2400    #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
2401    pub meta: Option<JsonObject>,
2402    /// Partial parameters accumulated from tool-call deltas.
2403    #[serde(default, skip_serializing_if = "Option::is_none")]
2404    pub partial_input: Option<String>,
2405    /// Progress message shown while parameters are streaming
2406    #[serde(default, skip_serializing_if = "Option::is_none")]
2407    pub invocation_message: Option<StringOrMarkdown>,
2408}
2409
2410/// Parameters are complete, or a running tool requires re-confirmation
2411/// (e.g. a mid-execution permission check).
2412#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
2413#[serde(rename_all = "camelCase")]
2414pub struct ToolCallPendingConfirmationState {
2415    /// Unique tool call identifier
2416    pub tool_call_id: String,
2417    /// Internal tool name (for debugging/logging)
2418    pub tool_name: String,
2419    /// Human-readable tool name
2420    pub display_name: String,
2421    /// Human-readable description of what the tool invocation intends to do
2422    #[serde(default, skip_serializing_if = "Option::is_none")]
2423    pub intention: Option<String>,
2424    /// Reference to the contributor of the tool being called.
2425    #[serde(default, skip_serializing_if = "Option::is_none")]
2426    pub contributor: Option<ToolCallContributor>,
2427    /// Additional provider-specific metadata for this tool call.
2428    ///
2429    /// This MAY include a `ui` field corresponding to the MCP Apps (SEP-1865)
2430    /// `McpUiToolMeta` found in MCP tool calls, which may be used in combination
2431    /// with the {@link contributor} to serve MCP Apps.
2432    #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
2433    pub meta: Option<JsonObject>,
2434    /// Message describing what the tool will do
2435    pub invocation_message: StringOrMarkdown,
2436    /// Final tool input.
2437    ///
2438    /// Referenced input is mutable until the tool call leaves
2439    /// `pending-confirmation`. When the client confirms with `editedToolInput`,
2440    /// the host MUST replace the resource contents before echoing the accepted
2441    /// confirmation action. Clients MUST NOT cache tool input across confirmation.
2442    #[serde(default, skip_serializing_if = "Option::is_none")]
2443    pub tool_input: Option<ToolInput>,
2444    /// Short title for the confirmation prompt (e.g. `"Run in terminal"`, `"Write file"`)
2445    #[serde(default, skip_serializing_if = "Option::is_none")]
2446    pub confirmation_title: Option<StringOrMarkdown>,
2447    /// Risk assessment that informed the confirmation requirement.
2448    #[serde(default, skip_serializing_if = "Option::is_none")]
2449    pub risk_assessment: Option<ToolCallRiskAssessment>,
2450    /// File edits that this tool call will perform, for preview before confirmation
2451    #[serde(default, skip_serializing_if = "Option::is_none")]
2452    pub edits: Option<AnyValue>,
2453    /// Whether the agent host allows the client to edit the tool's input parameters before confirming
2454    #[serde(default, skip_serializing_if = "Option::is_none")]
2455    pub editable: Option<bool>,
2456    /// Options the server offers for this confirmation. When present, the client
2457    /// SHOULD render these instead of a plain approve/deny UI. Each option
2458    /// belongs to a {@link ConfirmationOptionGroup} so the client can still
2459    /// categorise the choices.
2460    #[serde(default, skip_serializing_if = "Option::is_none")]
2461    pub options: Option<Vec<ConfirmationOption>>,
2462}
2463
2464/// Tool is actively executing.
2465#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
2466#[serde(rename_all = "camelCase")]
2467pub struct ToolCallRunningState {
2468    /// Unique tool call identifier
2469    pub tool_call_id: String,
2470    /// Internal tool name (for debugging/logging)
2471    pub tool_name: String,
2472    /// Human-readable tool name
2473    pub display_name: String,
2474    /// Human-readable description of what the tool invocation intends to do
2475    #[serde(default, skip_serializing_if = "Option::is_none")]
2476    pub intention: Option<String>,
2477    /// Reference to the contributor of the tool being called.
2478    #[serde(default, skip_serializing_if = "Option::is_none")]
2479    pub contributor: Option<ToolCallContributor>,
2480    /// Additional provider-specific metadata for this tool call.
2481    ///
2482    /// This MAY include a `ui` field corresponding to the MCP Apps (SEP-1865)
2483    /// `McpUiToolMeta` found in MCP tool calls, which may be used in combination
2484    /// with the {@link contributor} to serve MCP Apps.
2485    #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
2486    pub meta: Option<JsonObject>,
2487    /// Message describing what the tool will do
2488    pub invocation_message: StringOrMarkdown,
2489    /// Final tool input.
2490    ///
2491    /// Referenced input is mutable until the tool call leaves
2492    /// `pending-confirmation`. When the client confirms with `editedToolInput`,
2493    /// the host MUST replace the resource contents before echoing the accepted
2494    /// confirmation action. Clients MUST NOT cache tool input across confirmation.
2495    #[serde(default, skip_serializing_if = "Option::is_none")]
2496    pub tool_input: Option<ToolInput>,
2497    /// How the tool was confirmed for execution
2498    pub confirmed: ToolCallConfirmationReason,
2499    /// The confirmation option the user selected, if confirmation options were provided
2500    #[serde(default, skip_serializing_if = "Option::is_none")]
2501    pub selected_option: Option<ConfirmationOption>,
2502    /// Partial content produced while the tool is still executing.
2503    ///
2504    /// For example, a terminal content block lets clients subscribe to live
2505    /// output before the tool completes.
2506    #[serde(default, skip_serializing_if = "Option::is_none")]
2507    pub content: Option<Vec<ToolResultContent>>,
2508}
2509
2510/// A running tool call is paused because the MCP server backing it needs
2511/// authentication — most commonly {@link McpAuthRequirement.reason |
2512/// `insufficientScope`} step-up auth triggered by the `tools/call` request
2513/// itself. Only ever reached from {@link ToolCallRunningState}, and normally
2514/// returns there once authenticated: `running` → `auth-required` → `running`
2515/// → …. A client MAY instead cancel the invocation without authenticating by
2516/// dispatching a `chat/toolCallComplete` with a **failed** result, always
2517/// moving straight to {@link ToolCallCompletedState} —
2518/// `requiresResultConfirmation` is ignored on this path, so it can never
2519/// enter {@link ToolCallPendingResultConfirmationState}. A **successful**
2520/// result dispatched from this state is invalid and MUST be rejected/ignored
2521/// as a no-op by the reducer, since execution never resumed after the
2522/// challenge.
2523///
2524/// This is the tool-call-level counterpart to
2525/// {@link McpServerAuthRequiredState} — that state means the MCP *server*
2526/// cannot serve any request; this one means *this specific invocation* is
2527/// waiting on the same kind of challenge. The two are dispatched
2528/// independently and MAY be true at the same time, or not: an
2529/// `insufficientScope` challenge triggered by a single tool call, for
2530/// example, need not block the whole server.
2531///
2532/// Because the challenge is always resolved by pushing a token via the
2533/// existing `authenticate` command, this state can only originate from a
2534/// tool call {@link ToolCallContributorKind.MCP | contributed by an MCP
2535/// server} — `contributor` is narrowed accordingly (unlike the optional,
2536/// multi-kind `contributor` on other tool call states).
2537#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
2538#[serde(rename_all = "camelCase")]
2539pub struct ToolCallAuthRequiredState {
2540    /// Unique tool call identifier
2541    pub tool_call_id: String,
2542    /// Internal tool name (for debugging/logging)
2543    pub tool_name: String,
2544    /// Human-readable tool name
2545    pub display_name: String,
2546    /// Human-readable description of what the tool invocation intends to do
2547    #[serde(default, skip_serializing_if = "Option::is_none")]
2548    pub intention: Option<String>,
2549    /// Reference to the contributor of the tool being called.
2550    #[serde(default, skip_serializing_if = "Option::is_none")]
2551    pub contributor: Option<ToolCallContributor>,
2552    /// Additional provider-specific metadata for this tool call.
2553    ///
2554    /// This MAY include a `ui` field corresponding to the MCP Apps (SEP-1865)
2555    /// `McpUiToolMeta` found in MCP tool calls, which may be used in combination
2556    /// with the {@link contributor} to serve MCP Apps.
2557    #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
2558    pub meta: Option<JsonObject>,
2559    /// Message describing what the tool will do
2560    pub invocation_message: StringOrMarkdown,
2561    /// Final tool input.
2562    ///
2563    /// Referenced input is mutable until the tool call leaves
2564    /// `pending-confirmation`. When the client confirms with `editedToolInput`,
2565    /// the host MUST replace the resource contents before echoing the accepted
2566    /// confirmation action. Clients MUST NOT cache tool input across confirmation.
2567    #[serde(default, skip_serializing_if = "Option::is_none")]
2568    pub tool_input: Option<ToolInput>,
2569    /// How the tool was confirmed for execution
2570    pub confirmed: ToolCallConfirmationReason,
2571    /// The confirmation option the user selected, if confirmation options were provided
2572    #[serde(default, skip_serializing_if = "Option::is_none")]
2573    pub selected_option: Option<ConfirmationOption>,
2574    pub status: ToolCallStatus,
2575    /// The authentication challenge blocking this invocation.
2576    pub auth: McpAuthRequirement,
2577    /// Partial content produced before the call paused for authentication.
2578    #[serde(default, skip_serializing_if = "Option::is_none")]
2579    pub content: Option<Vec<ToolResultContent>>,
2580}
2581
2582/// Tool finished executing, waiting for client to approve the result.
2583#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
2584#[serde(rename_all = "camelCase")]
2585pub struct ToolCallPendingResultConfirmationState {
2586    /// Unique tool call identifier
2587    pub tool_call_id: String,
2588    /// Internal tool name (for debugging/logging)
2589    pub tool_name: String,
2590    /// Human-readable tool name
2591    pub display_name: String,
2592    /// Human-readable description of what the tool invocation intends to do
2593    #[serde(default, skip_serializing_if = "Option::is_none")]
2594    pub intention: Option<String>,
2595    /// Reference to the contributor of the tool being called.
2596    #[serde(default, skip_serializing_if = "Option::is_none")]
2597    pub contributor: Option<ToolCallContributor>,
2598    /// Additional provider-specific metadata for this tool call.
2599    ///
2600    /// This MAY include a `ui` field corresponding to the MCP Apps (SEP-1865)
2601    /// `McpUiToolMeta` found in MCP tool calls, which may be used in combination
2602    /// with the {@link contributor} to serve MCP Apps.
2603    #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
2604    pub meta: Option<JsonObject>,
2605    /// Message describing what the tool will do
2606    pub invocation_message: StringOrMarkdown,
2607    /// Final tool input.
2608    ///
2609    /// Referenced input is mutable until the tool call leaves
2610    /// `pending-confirmation`. When the client confirms with `editedToolInput`,
2611    /// the host MUST replace the resource contents before echoing the accepted
2612    /// confirmation action. Clients MUST NOT cache tool input across confirmation.
2613    #[serde(default, skip_serializing_if = "Option::is_none")]
2614    pub tool_input: Option<ToolInput>,
2615    /// Whether the tool succeeded
2616    pub success: bool,
2617    /// Past-tense description of what the tool did
2618    pub past_tense_message: StringOrMarkdown,
2619    /// Unstructured result content blocks.
2620    ///
2621    /// This mirrors the `content` field of MCP `CallToolResult`.
2622    #[serde(default, skip_serializing_if = "Option::is_none")]
2623    pub content: Option<Vec<ToolResultContent>>,
2624    /// Optional structured result object.
2625    ///
2626    /// This mirrors the `structuredContent` field of MCP `CallToolResult`.
2627    #[serde(default, skip_serializing_if = "Option::is_none")]
2628    pub structured_content: Option<JsonObject>,
2629    /// Error details if the tool failed
2630    #[serde(default, skip_serializing_if = "Option::is_none")]
2631    pub error: Option<AnyValue>,
2632    /// How the tool was confirmed for execution
2633    pub confirmed: ToolCallConfirmationReason,
2634    /// The confirmation option the user selected, if confirmation options were provided
2635    #[serde(default, skip_serializing_if = "Option::is_none")]
2636    pub selected_option: Option<ConfirmationOption>,
2637}
2638
2639/// Tool completed successfully or with an error.
2640#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
2641#[serde(rename_all = "camelCase")]
2642pub struct ToolCallCompletedState {
2643    /// Unique tool call identifier
2644    pub tool_call_id: String,
2645    /// Internal tool name (for debugging/logging)
2646    pub tool_name: String,
2647    /// Human-readable tool name
2648    pub display_name: String,
2649    /// Human-readable description of what the tool invocation intends to do
2650    #[serde(default, skip_serializing_if = "Option::is_none")]
2651    pub intention: Option<String>,
2652    /// Reference to the contributor of the tool being called.
2653    #[serde(default, skip_serializing_if = "Option::is_none")]
2654    pub contributor: Option<ToolCallContributor>,
2655    /// Additional provider-specific metadata for this tool call.
2656    ///
2657    /// This MAY include a `ui` field corresponding to the MCP Apps (SEP-1865)
2658    /// `McpUiToolMeta` found in MCP tool calls, which may be used in combination
2659    /// with the {@link contributor} to serve MCP Apps.
2660    #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
2661    pub meta: Option<JsonObject>,
2662    /// Message describing what the tool will do
2663    pub invocation_message: StringOrMarkdown,
2664    /// Final tool input.
2665    ///
2666    /// Referenced input is mutable until the tool call leaves
2667    /// `pending-confirmation`. When the client confirms with `editedToolInput`,
2668    /// the host MUST replace the resource contents before echoing the accepted
2669    /// confirmation action. Clients MUST NOT cache tool input across confirmation.
2670    #[serde(default, skip_serializing_if = "Option::is_none")]
2671    pub tool_input: Option<ToolInput>,
2672    /// Whether the tool succeeded
2673    pub success: bool,
2674    /// Past-tense description of what the tool did
2675    pub past_tense_message: StringOrMarkdown,
2676    /// Unstructured result content blocks.
2677    ///
2678    /// This mirrors the `content` field of MCP `CallToolResult`.
2679    #[serde(default, skip_serializing_if = "Option::is_none")]
2680    pub content: Option<Vec<ToolResultContent>>,
2681    /// Optional structured result object.
2682    ///
2683    /// This mirrors the `structuredContent` field of MCP `CallToolResult`.
2684    #[serde(default, skip_serializing_if = "Option::is_none")]
2685    pub structured_content: Option<JsonObject>,
2686    /// Error details if the tool failed
2687    #[serde(default, skip_serializing_if = "Option::is_none")]
2688    pub error: Option<AnyValue>,
2689    /// How the tool was confirmed for execution
2690    pub confirmed: ToolCallConfirmationReason,
2691    /// The confirmation option the user selected, if confirmation options were provided
2692    #[serde(default, skip_serializing_if = "Option::is_none")]
2693    pub selected_option: Option<ConfirmationOption>,
2694}
2695
2696/// Tool call was cancelled before execution.
2697#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
2698#[serde(rename_all = "camelCase")]
2699pub struct ToolCallCancelledState {
2700    /// Unique tool call identifier
2701    pub tool_call_id: String,
2702    /// Internal tool name (for debugging/logging)
2703    pub tool_name: String,
2704    /// Human-readable tool name
2705    pub display_name: String,
2706    /// Human-readable description of what the tool invocation intends to do
2707    #[serde(default, skip_serializing_if = "Option::is_none")]
2708    pub intention: Option<String>,
2709    /// Reference to the contributor of the tool being called.
2710    #[serde(default, skip_serializing_if = "Option::is_none")]
2711    pub contributor: Option<ToolCallContributor>,
2712    /// Additional provider-specific metadata for this tool call.
2713    ///
2714    /// This MAY include a `ui` field corresponding to the MCP Apps (SEP-1865)
2715    /// `McpUiToolMeta` found in MCP tool calls, which may be used in combination
2716    /// with the {@link contributor} to serve MCP Apps.
2717    #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
2718    pub meta: Option<JsonObject>,
2719    /// Message describing what the tool will do
2720    pub invocation_message: StringOrMarkdown,
2721    /// Final tool input.
2722    ///
2723    /// Referenced input is mutable until the tool call leaves
2724    /// `pending-confirmation`. When the client confirms with `editedToolInput`,
2725    /// the host MUST replace the resource contents before echoing the accepted
2726    /// confirmation action. Clients MUST NOT cache tool input across confirmation.
2727    #[serde(default, skip_serializing_if = "Option::is_none")]
2728    pub tool_input: Option<ToolInput>,
2729    /// Why the tool was cancelled
2730    pub reason: ToolCallCancellationReason,
2731    /// Optional message explaining the cancellation
2732    #[serde(default, skip_serializing_if = "Option::is_none")]
2733    pub reason_message: Option<StringOrMarkdown>,
2734    /// What the user suggested doing instead
2735    #[serde(default, skip_serializing_if = "Option::is_none")]
2736    pub user_suggestion: Option<Message>,
2737    /// The confirmation option the user selected, if confirmation options were provided
2738    #[serde(default, skip_serializing_if = "Option::is_none")]
2739    pub selected_option: Option<ConfirmationOption>,
2740}
2741
2742/// Describes a tool available in a session, provided by either the server or the active client.
2743#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
2744#[serde(rename_all = "camelCase")]
2745pub struct ToolDefinition {
2746    /// Unique tool identifier
2747    pub name: String,
2748    /// Human-readable display name
2749    #[serde(default, skip_serializing_if = "Option::is_none")]
2750    pub title: Option<String>,
2751    /// Description of what the tool does
2752    #[serde(default, skip_serializing_if = "Option::is_none")]
2753    pub description: Option<String>,
2754    /// JSON Schema defining the expected input parameters.
2755    ///
2756    /// Optional because client-provided tools may not have formal schemas.
2757    /// Mirrors MCP `Tool.inputSchema`.
2758    #[serde(default, skip_serializing_if = "Option::is_none")]
2759    pub input_schema: Option<AnyValue>,
2760    /// JSON Schema defining the structure of the tool's output.
2761    ///
2762    /// Mirrors MCP `Tool.outputSchema`.
2763    #[serde(default, skip_serializing_if = "Option::is_none")]
2764    pub output_schema: Option<AnyValue>,
2765    /// Behavioral hints about the tool. All properties are advisory.
2766    #[serde(default, skip_serializing_if = "Option::is_none")]
2767    pub annotations: Option<ToolAnnotations>,
2768    /// Additional provider-specific metadata.
2769    ///
2770    /// Mirrors the MCP `_meta` convention.
2771    #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
2772    pub meta: Option<JsonObject>,
2773}
2774
2775/// Behavioral hints about a tool. All properties are advisory and not
2776/// guaranteed to faithfully describe tool behavior.
2777///
2778/// Mirrors MCP `ToolAnnotations` from the Model Context Protocol specification.
2779#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Default)]
2780#[serde(rename_all = "camelCase")]
2781pub struct ToolAnnotations {
2782    /// Alternate human-readable title
2783    #[serde(default, skip_serializing_if = "Option::is_none")]
2784    pub title: Option<String>,
2785    /// Tool does not modify its environment (default: false)
2786    #[serde(default, skip_serializing_if = "Option::is_none")]
2787    pub read_only_hint: Option<bool>,
2788    /// Tool may perform destructive updates (default: true)
2789    #[serde(default, skip_serializing_if = "Option::is_none")]
2790    pub destructive_hint: Option<bool>,
2791    /// Repeated calls with the same arguments have no additional effect (default: false)
2792    #[serde(default, skip_serializing_if = "Option::is_none")]
2793    pub idempotent_hint: Option<bool>,
2794    /// Tool may interact with external entities (default: true)
2795    #[serde(default, skip_serializing_if = "Option::is_none")]
2796    pub open_world_hint: Option<bool>,
2797}
2798
2799/// Text content in a tool result.
2800///
2801/// Mirrors MCP `TextContent`.
2802#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
2803#[serde(rename_all = "camelCase")]
2804pub struct ToolResultTextContent {
2805    /// The text content
2806    pub text: String,
2807}
2808
2809/// Base64-encoded binary content embedded in a tool result.
2810///
2811/// Mirrors MCP `EmbeddedResource` for inline binary data.
2812#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
2813#[serde(rename_all = "camelCase")]
2814pub struct ToolResultEmbeddedResourceContent {
2815    /// Base64-encoded data
2816    pub data: String,
2817    /// Content type (e.g. `"image/png"`, `"application/pdf"`)
2818    pub content_type: String,
2819}
2820
2821/// A reference to a resource stored outside the tool result.
2822///
2823/// Wraps {@link ContentRef} for lazy-loading large results.
2824#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
2825#[serde(rename_all = "camelCase")]
2826pub struct ToolResultResourceContent {
2827    /// Content URI
2828    pub uri: Uri,
2829    /// Approximate size in bytes
2830    #[serde(default, skip_serializing_if = "Option::is_none")]
2831    pub size_hint: Option<i64>,
2832    /// Content MIME type
2833    #[serde(default, skip_serializing_if = "Option::is_none")]
2834    pub content_type: Option<String>,
2835    /// Content nonce
2836    #[serde(default, skip_serializing_if = "Option::is_none")]
2837    pub nonce: Option<String>,
2838}
2839
2840/// Describes a file modification performed by a tool.
2841#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Default)]
2842#[serde(rename_all = "camelCase")]
2843pub struct ToolResultFileEditContent {
2844    /// The file state before the edit. Absent for file creations or for in-place file edits.
2845    #[serde(default, skip_serializing_if = "Option::is_none")]
2846    pub before: Option<AnyValue>,
2847    /// The file state after the edit. Absent for file deletions.
2848    #[serde(default, skip_serializing_if = "Option::is_none")]
2849    pub after: Option<AnyValue>,
2850    /// Optional diff display metadata
2851    #[serde(default, skip_serializing_if = "Option::is_none")]
2852    pub diff: Option<AnyValue>,
2853}
2854
2855/// A reference to a terminal whose output is relevant to this tool result.
2856///
2857/// Clients can subscribe to the terminal's URI to stream its output in real
2858/// time, providing live feedback while a tool is executing.
2859///
2860/// When the command exits, {@link result} is filled in on the completed
2861/// result, retaining the outcome for clients that did not subscribe. This
2862/// records the command's exit, not the terminal's — the terminal may keep
2863/// running afterwards.
2864#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
2865#[serde(rename_all = "camelCase")]
2866pub struct ToolResultTerminalContent {
2867    /// Terminal URI (subscribable for full terminal state)
2868    pub resource: Uri,
2869    /// Display title for the terminal content
2870    pub title: String,
2871    /// Whether this terminal-style resource is backed by a pseudoterminal.
2872    /// When `false`, output is plain text and clients do not need to parse
2873    /// VT sequences.
2874    #[serde(default, skip_serializing_if = "Option::is_none")]
2875    pub is_pty: Option<bool>,
2876    /// Outcome of the command, present once it has exited.
2877    #[serde(default, skip_serializing_if = "Option::is_none")]
2878    pub result: Option<TerminalCommandResult>,
2879}
2880
2881/// A reference, embedded in a tool result, to a worker chat spawned by the tool
2882/// call (a sub-agent delegation), referenced by a chat URI (`ahp-chat:/...`).
2883///
2884/// This is the spawning tool call's forward view of the worker. The worker chat
2885/// records the same edge in reverse via its {@link ChatOrigin} (`kind: 'tool'`),
2886/// whose `toolCallId` identifies the tool call that emitted this content.
2887#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
2888#[serde(rename_all = "camelCase")]
2889pub struct ToolResultSubagentContent {
2890    /// Worker chat URI (subscribable for full chat state)
2891    pub resource: Uri,
2892    /// Display title for the subagent
2893    pub title: String,
2894    /// Internal agent name
2895    #[serde(default, skip_serializing_if = "Option::is_none")]
2896    pub agent_name: Option<String>,
2897    /// Human-readable description of the subagent's task
2898    #[serde(default, skip_serializing_if = "Option::is_none")]
2899    pub description: Option<String>,
2900}
2901
2902/// Container is being loaded by the host.
2903#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
2904#[serde(rename_all = "camelCase")]
2905pub struct CustomizationLoadingState {}
2906
2907/// Container loaded successfully.
2908#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
2909#[serde(rename_all = "camelCase")]
2910pub struct CustomizationLoadedState {}
2911
2912/// Container partially loaded but has warnings.
2913#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
2914#[serde(rename_all = "camelCase")]
2915pub struct CustomizationDegradedState {
2916    /// Human-readable description of the warning.
2917    pub message: String,
2918}
2919
2920/// Container failed to load.
2921#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
2922#[serde(rename_all = "camelCase")]
2923pub struct CustomizationErrorState {
2924    /// Human-readable error message.
2925    pub message: String,
2926}
2927
2928/// An [Open Plugins](https://open-plugins.com/) plugin.
2929#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
2930#[serde(rename_all = "camelCase")]
2931pub struct PluginCustomization {
2932    /// Session-unique opaque identifier. Used by every action that targets a
2933    /// specific customization. Minted by whoever publishes the customization
2934    /// (typically the agent host).
2935    pub id: String,
2936    /// Source URI for this customization. A plugin URL, a file URI, or a
2937    /// directory URI.
2938    ///
2939    /// For declarations that live inside a larger file — e.g. an MCP
2940    /// server declared inline in a `plugins.json` manifest — `uri` points
2941    /// to the containing file and {@link CustomizationBase.range | `range`}
2942    /// narrows it to the declaration's span.
2943    pub uri: Uri,
2944    /// Human-readable name.
2945    pub name: String,
2946    /// Icons for UI display.
2947    #[serde(default, skip_serializing_if = "Option::is_none")]
2948    pub icons: Option<Vec<Icon>>,
2949    /// Optional span within {@link CustomizationBase.uri | `uri`} when this
2950    /// customization is a subset of a larger file (for example, one entry
2951    /// in an inline `mcpServers` block of a `plugins.json` manifest).
2952    /// Absent when the customization covers the whole resource.
2953    #[serde(default, skip_serializing_if = "Option::is_none")]
2954    pub range: Option<TextRange>,
2955    /// Additional provider-specific metadata for this customization.
2956    ///
2957    /// Mirrors the MCP `_meta` convention. Optional and opaque to the
2958    /// protocol; producers and consumers agree on its contents
2959    /// out-of-band.
2960    #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
2961    pub meta: Option<JsonObject>,
2962    /// `clientId` of the client that contributed this container. Absent for
2963    /// server-originated entries.
2964    #[serde(default, skip_serializing_if = "Option::is_none")]
2965    pub client_id: Option<String>,
2966    /// Host-reported load state. Absent means the host has not yet reported
2967    /// a load state for this container.
2968    #[serde(default, skip_serializing_if = "Option::is_none")]
2969    pub load: Option<CustomizationLoadState>,
2970    /// Children discovered inside this container.
2971    ///
2972    /// Absent means the host has not parsed this container yet. An empty
2973    /// array means the host parsed the container and it contributes
2974    /// nothing.
2975    #[serde(default, skip_serializing_if = "Option::is_none")]
2976    pub children: Option<Vec<ChildCustomization>>,
2977    /// Explicit enablement decisions. See {@link McpServerCustomization.enablement}.
2978    #[serde(default, skip_serializing_if = "Option::is_none")]
2979    pub enablement: Option<Vec<CustomizationEnablement>>,
2980    /// Version of the plugin, sourced from the
2981    /// [Open Plugins](https://open-plugins.com/) manifest's optional
2982    /// `version` field (semver, e.g. `"1.2.0"`). Absent when the manifest
2983    /// declares no version — the field is optional there — or the source
2984    /// has no version concept. Provenance / display only: the host neither
2985    /// parses nor enforces it.
2986    #[serde(default, skip_serializing_if = "Option::is_none")]
2987    pub version: Option<String>,
2988}
2989
2990/// A {@link PluginCustomization} as published by a client. Extends the
2991/// server-facing shape with an opaque `nonce` so the host can detect when
2992/// the client's view of a plugin has changed and re-parse only as needed.
2993///
2994/// Clients SHOULD include a `nonce`. Server-side fields like
2995/// {@link ContainerCustomizationBase.children | `children`} and
2996/// {@link ContainerCustomizationBase.load | `load`} are typically left
2997/// absent on publication and populated by the host when the resolved
2998/// plugin appears in {@link SessionState.customizations}.
2999#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
3000#[serde(rename_all = "camelCase")]
3001pub struct ClientPluginCustomization {
3002    /// Session-unique opaque identifier. Used by every action that targets a
3003    /// specific customization. Minted by whoever publishes the customization
3004    /// (typically the agent host).
3005    pub id: String,
3006    /// Source URI for this customization. A plugin URL, a file URI, or a
3007    /// directory URI.
3008    ///
3009    /// For declarations that live inside a larger file — e.g. an MCP
3010    /// server declared inline in a `plugins.json` manifest — `uri` points
3011    /// to the containing file and {@link CustomizationBase.range | `range`}
3012    /// narrows it to the declaration's span.
3013    pub uri: Uri,
3014    /// Human-readable name.
3015    pub name: String,
3016    /// Icons for UI display.
3017    #[serde(default, skip_serializing_if = "Option::is_none")]
3018    pub icons: Option<Vec<Icon>>,
3019    /// Optional span within {@link CustomizationBase.uri | `uri`} when this
3020    /// customization is a subset of a larger file (for example, one entry
3021    /// in an inline `mcpServers` block of a `plugins.json` manifest).
3022    /// Absent when the customization covers the whole resource.
3023    #[serde(default, skip_serializing_if = "Option::is_none")]
3024    pub range: Option<TextRange>,
3025    /// Additional provider-specific metadata for this customization.
3026    ///
3027    /// Mirrors the MCP `_meta` convention. Optional and opaque to the
3028    /// protocol; producers and consumers agree on its contents
3029    /// out-of-band.
3030    #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
3031    pub meta: Option<JsonObject>,
3032    /// `clientId` of the client that contributed this container. Absent for
3033    /// server-originated entries.
3034    #[serde(default, skip_serializing_if = "Option::is_none")]
3035    pub client_id: Option<String>,
3036    /// Host-reported load state. Absent means the host has not yet reported
3037    /// a load state for this container.
3038    #[serde(default, skip_serializing_if = "Option::is_none")]
3039    pub load: Option<CustomizationLoadState>,
3040    /// Children discovered inside this container.
3041    ///
3042    /// Absent means the host has not parsed this container yet. An empty
3043    /// array means the host parsed the container and it contributes
3044    /// nothing.
3045    #[serde(default, skip_serializing_if = "Option::is_none")]
3046    pub children: Option<Vec<ChildCustomization>>,
3047    /// Explicit enablement decisions. See {@link McpServerCustomization.enablement}.
3048    #[serde(default, skip_serializing_if = "Option::is_none")]
3049    pub enablement: Option<Vec<CustomizationEnablement>>,
3050    /// Version of the plugin, sourced from the
3051    /// [Open Plugins](https://open-plugins.com/) manifest's optional
3052    /// `version` field (semver, e.g. `"1.2.0"`). Absent when the manifest
3053    /// declares no version — the field is optional there — or the source
3054    /// has no version concept. Provenance / display only: the host neither
3055    /// parses nor enforces it.
3056    #[serde(default, skip_serializing_if = "Option::is_none")]
3057    pub version: Option<String>,
3058    /// Opaque version token used by the host to detect changes.
3059    #[serde(default, skip_serializing_if = "Option::is_none")]
3060    pub nonce: Option<String>,
3061    /// Explicit enablement decisions for children this plugin contributes,
3062    /// keyed by child name (for MCP servers, the server name as it appears in
3063    /// the bundled `.mcp.json`).
3064    ///
3065    /// Bundled children are discovered by the host rather than published by the
3066    /// client, so the client cannot attach `enablement` to them directly. This
3067    /// carries the client's global decision for each one; the host applies it
3068    /// under the child's durable key.
3069    #[serde(default, skip_serializing_if = "Option::is_none")]
3070    pub child_enablement: Option<std::collections::HashMap<String, Vec<CustomizationEnablement>>>,
3071}
3072
3073/// A directory the host watches for this session.
3074///
3075/// Presence in the customization list signals that the host may discover
3076/// customizations from this directory. When `writable` is `true`, clients
3077/// MAY persist new customizations into the directory using
3078/// [`resourceWrite`](/reference/common#resourcewrite); the host will
3079/// then surface the resulting child via the customization actions.
3080///
3081/// The directory may not yet exist on disk.
3082#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
3083#[serde(rename_all = "camelCase")]
3084pub struct DirectoryCustomization {
3085    /// Session-unique opaque identifier. Used by every action that targets a
3086    /// specific customization. Minted by whoever publishes the customization
3087    /// (typically the agent host).
3088    pub id: String,
3089    /// Source URI for this customization. A plugin URL, a file URI, or a
3090    /// directory URI.
3091    ///
3092    /// For declarations that live inside a larger file — e.g. an MCP
3093    /// server declared inline in a `plugins.json` manifest — `uri` points
3094    /// to the containing file and {@link CustomizationBase.range | `range`}
3095    /// narrows it to the declaration's span.
3096    pub uri: Uri,
3097    /// Human-readable name.
3098    pub name: String,
3099    /// Icons for UI display.
3100    #[serde(default, skip_serializing_if = "Option::is_none")]
3101    pub icons: Option<Vec<Icon>>,
3102    /// Optional span within {@link CustomizationBase.uri | `uri`} when this
3103    /// customization is a subset of a larger file (for example, one entry
3104    /// in an inline `mcpServers` block of a `plugins.json` manifest).
3105    /// Absent when the customization covers the whole resource.
3106    #[serde(default, skip_serializing_if = "Option::is_none")]
3107    pub range: Option<TextRange>,
3108    /// Additional provider-specific metadata for this customization.
3109    ///
3110    /// Mirrors the MCP `_meta` convention. Optional and opaque to the
3111    /// protocol; producers and consumers agree on its contents
3112    /// out-of-band.
3113    #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
3114    pub meta: Option<JsonObject>,
3115    /// `clientId` of the client that contributed this container. Absent for
3116    /// server-originated entries.
3117    #[serde(default, skip_serializing_if = "Option::is_none")]
3118    pub client_id: Option<String>,
3119    /// Host-reported load state. Absent means the host has not yet reported
3120    /// a load state for this container.
3121    #[serde(default, skip_serializing_if = "Option::is_none")]
3122    pub load: Option<CustomizationLoadState>,
3123    /// Children discovered inside this container.
3124    ///
3125    /// Absent means the host has not parsed this container yet. An empty
3126    /// array means the host parsed the container and it contributes
3127    /// nothing.
3128    #[serde(default, skip_serializing_if = "Option::is_none")]
3129    pub children: Option<Vec<ChildCustomization>>,
3130    /// Whether this container is currently enabled.
3131    pub enabled: bool,
3132    /// Which child customization type this directory holds.
3133    pub contents: CustomizationType,
3134    /// Whether clients may write into this directory.
3135    pub writable: bool,
3136}
3137
3138/// A custom agent contributed by a plugin or directory.
3139///
3140/// Mirrors the [Open Plugins agent](https://open-plugins.com/agent-builders/components/agents)
3141/// format: a markdown file with YAML frontmatter, where the body is the
3142/// agent's system prompt.
3143#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
3144#[serde(rename_all = "camelCase")]
3145pub struct AgentCustomization {
3146    /// Session-unique opaque identifier. Used by every action that targets a
3147    /// specific customization. Minted by whoever publishes the customization
3148    /// (typically the agent host).
3149    pub id: String,
3150    /// Source URI for this customization. A plugin URL, a file URI, or a
3151    /// directory URI.
3152    ///
3153    /// For declarations that live inside a larger file — e.g. an MCP
3154    /// server declared inline in a `plugins.json` manifest — `uri` points
3155    /// to the containing file and {@link CustomizationBase.range | `range`}
3156    /// narrows it to the declaration's span.
3157    pub uri: Uri,
3158    /// Human-readable name.
3159    pub name: String,
3160    /// Icons for UI display.
3161    #[serde(default, skip_serializing_if = "Option::is_none")]
3162    pub icons: Option<Vec<Icon>>,
3163    /// Optional span within {@link CustomizationBase.uri | `uri`} when this
3164    /// customization is a subset of a larger file (for example, one entry
3165    /// in an inline `mcpServers` block of a `plugins.json` manifest).
3166    /// Absent when the customization covers the whole resource.
3167    #[serde(default, skip_serializing_if = "Option::is_none")]
3168    pub range: Option<TextRange>,
3169    /// Additional provider-specific metadata for this customization.
3170    ///
3171    /// Mirrors the MCP `_meta` convention. Optional and opaque to the
3172    /// protocol; producers and consumers agree on its contents
3173    /// out-of-band.
3174    #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
3175    pub meta: Option<JsonObject>,
3176    /// Whether this child is individually enabled. Absent means enabled, so a
3177    /// producer only needs to set it to surface a child that exists but is
3178    /// turned off on its own.
3179    ///
3180    /// This flag is independent of the parent container's: the **effective**
3181    /// enabled state of a plugin child is the plugin's derived enabled value and
3182    /// `(child.enabled ?? true)`, so a disabled plugin disables every child
3183    /// regardless of each child's own flag. A directory child instead uses the
3184    /// directory's `enabled` value and its own flag.
3185    ///
3186    /// A child is turned on or off by id with
3187    /// {@link SessionCustomizationToggledAction | `session/customizationToggled`}.
3188    #[serde(default, skip_serializing_if = "Option::is_none")]
3189    pub enabled: Option<bool>,
3190    /// Short description of what the agent specializes in and when to
3191    /// invoke it. Sourced from the agent file's frontmatter `description`.
3192    #[serde(default, skip_serializing_if = "Option::is_none")]
3193    pub description: Option<String>,
3194    /// Model the agent is pinned to, sourced from the agent file's
3195    /// frontmatter `model`. Absent means the agent inherits the session's
3196    /// default model.
3197    #[serde(default, skip_serializing_if = "Option::is_none")]
3198    pub model: Option<String>,
3199    /// Allowlist of tool names the agent is scoped to, sourced from the
3200    /// agent file's frontmatter `tools`. A non-empty list restricts the
3201    /// agent to exactly those tools. Absent — or an empty list — imposes no
3202    /// restriction beyond the session default: the agent may use any
3203    /// available tool. Producers express "no restriction" by omitting the
3204    /// field rather than sending an empty array, so an empty list carries no
3205    /// meaning distinct from absence.
3206    #[serde(default, skip_serializing_if = "Option::is_none")]
3207    pub tools: Option<Vec<String>>,
3208    /// When `true`, the agent will not auto-delegate to this custom agent
3209    /// as a sub-agent; it can only be selected by the user. Absent or
3210    /// `false` means the agent may delegate to it.
3211    #[serde(default, skip_serializing_if = "Option::is_none")]
3212    pub disable_model_invocation: Option<bool>,
3213    /// When `true`, the user cannot select this custom agent (for example,
3214    /// in a picker); it remains available for the agent to auto-delegate
3215    /// to. Absent or `false` means the user may select it.
3216    #[serde(default, skip_serializing_if = "Option::is_none")]
3217    pub disable_user_invocation: Option<bool>,
3218}
3219
3220/// A skill contributed by a plugin or directory.
3221///
3222/// Covers both [Open Plugins skill formats](https://open-plugins.com/agent-builders/components/skills)
3223/// — the `skills/` directory layout (one subdirectory per skill, each with
3224/// a `SKILL.md`) and the flatter `commands/` directory of slash-command
3225/// skills.
3226#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
3227#[serde(rename_all = "camelCase")]
3228pub struct SkillCustomization {
3229    /// Session-unique opaque identifier. Used by every action that targets a
3230    /// specific customization. Minted by whoever publishes the customization
3231    /// (typically the agent host).
3232    pub id: String,
3233    /// Source URI for this customization. A plugin URL, a file URI, or a
3234    /// directory URI.
3235    ///
3236    /// For declarations that live inside a larger file — e.g. an MCP
3237    /// server declared inline in a `plugins.json` manifest — `uri` points
3238    /// to the containing file and {@link CustomizationBase.range | `range`}
3239    /// narrows it to the declaration's span.
3240    pub uri: Uri,
3241    /// Human-readable name.
3242    pub name: String,
3243    /// Icons for UI display.
3244    #[serde(default, skip_serializing_if = "Option::is_none")]
3245    pub icons: Option<Vec<Icon>>,
3246    /// Optional span within {@link CustomizationBase.uri | `uri`} when this
3247    /// customization is a subset of a larger file (for example, one entry
3248    /// in an inline `mcpServers` block of a `plugins.json` manifest).
3249    /// Absent when the customization covers the whole resource.
3250    #[serde(default, skip_serializing_if = "Option::is_none")]
3251    pub range: Option<TextRange>,
3252    /// Additional provider-specific metadata for this customization.
3253    ///
3254    /// Mirrors the MCP `_meta` convention. Optional and opaque to the
3255    /// protocol; producers and consumers agree on its contents
3256    /// out-of-band.
3257    #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
3258    pub meta: Option<JsonObject>,
3259    /// Whether this child is individually enabled. Absent means enabled, so a
3260    /// producer only needs to set it to surface a child that exists but is
3261    /// turned off on its own.
3262    ///
3263    /// This flag is independent of the parent container's: the **effective**
3264    /// enabled state of a plugin child is the plugin's derived enabled value and
3265    /// `(child.enabled ?? true)`, so a disabled plugin disables every child
3266    /// regardless of each child's own flag. A directory child instead uses the
3267    /// directory's `enabled` value and its own flag.
3268    ///
3269    /// A child is turned on or off by id with
3270    /// {@link SessionCustomizationToggledAction | `session/customizationToggled`}.
3271    #[serde(default, skip_serializing_if = "Option::is_none")]
3272    pub enabled: Option<bool>,
3273    /// Short description used for help text and auto-invocation matching.
3274    /// Sourced from the skill's frontmatter `description`.
3275    #[serde(default, skip_serializing_if = "Option::is_none")]
3276    pub description: Option<String>,
3277    /// When `true`, only the user can invoke this skill — the agent will not
3278    /// auto-invoke it. Sourced from the command skill's frontmatter
3279    /// `disable-model-invocation` flag.
3280    #[serde(default, skip_serializing_if = "Option::is_none")]
3281    pub disable_model_invocation: Option<bool>,
3282    /// When `true`, the user cannot directly invoke this skill (for example,
3283    /// as a slash command); it remains available for the agent to
3284    /// auto-invoke. Absent or `false` means the user may invoke it.
3285    #[serde(default, skip_serializing_if = "Option::is_none")]
3286    pub disable_user_invocation: Option<bool>,
3287}
3288
3289/// A prompt contributed by a plugin or directory.
3290#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
3291#[serde(rename_all = "camelCase")]
3292pub struct PromptCustomization {
3293    /// Session-unique opaque identifier. Used by every action that targets a
3294    /// specific customization. Minted by whoever publishes the customization
3295    /// (typically the agent host).
3296    pub id: String,
3297    /// Source URI for this customization. A plugin URL, a file URI, or a
3298    /// directory URI.
3299    ///
3300    /// For declarations that live inside a larger file — e.g. an MCP
3301    /// server declared inline in a `plugins.json` manifest — `uri` points
3302    /// to the containing file and {@link CustomizationBase.range | `range`}
3303    /// narrows it to the declaration's span.
3304    pub uri: Uri,
3305    /// Human-readable name.
3306    pub name: String,
3307    /// Icons for UI display.
3308    #[serde(default, skip_serializing_if = "Option::is_none")]
3309    pub icons: Option<Vec<Icon>>,
3310    /// Optional span within {@link CustomizationBase.uri | `uri`} when this
3311    /// customization is a subset of a larger file (for example, one entry
3312    /// in an inline `mcpServers` block of a `plugins.json` manifest).
3313    /// Absent when the customization covers the whole resource.
3314    #[serde(default, skip_serializing_if = "Option::is_none")]
3315    pub range: Option<TextRange>,
3316    /// Additional provider-specific metadata for this customization.
3317    ///
3318    /// Mirrors the MCP `_meta` convention. Optional and opaque to the
3319    /// protocol; producers and consumers agree on its contents
3320    /// out-of-band.
3321    #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
3322    pub meta: Option<JsonObject>,
3323    /// Whether this child is individually enabled. Absent means enabled, so a
3324    /// producer only needs to set it to surface a child that exists but is
3325    /// turned off on its own.
3326    ///
3327    /// This flag is independent of the parent container's: the **effective**
3328    /// enabled state of a plugin child is the plugin's derived enabled value and
3329    /// `(child.enabled ?? true)`, so a disabled plugin disables every child
3330    /// regardless of each child's own flag. A directory child instead uses the
3331    /// directory's `enabled` value and its own flag.
3332    ///
3333    /// A child is turned on or off by id with
3334    /// {@link SessionCustomizationToggledAction | `session/customizationToggled`}.
3335    #[serde(default, skip_serializing_if = "Option::is_none")]
3336    pub enabled: Option<bool>,
3337    /// Short description of what the prompt does.
3338    #[serde(default, skip_serializing_if = "Option::is_none")]
3339    pub description: Option<String>,
3340}
3341
3342/// A rule contributed by a plugin or directory.
3343///
3344/// Mirrors the [Open Plugins rule](https://open-plugins.com/agent-builders/components/rules)
3345/// format: a markdown file (e.g. `.mdc`) whose body is injected into
3346/// context while the rule is active. This type also covers tool-specific
3347/// "instruction" formats (e.g. VS Code Copilot's
3348/// `.github/instructions/*.md`), which differ only in naming — they
3349/// share the same semantics of `description`, optional always-on
3350/// activation, and optional glob scoping.
3351#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
3352#[serde(rename_all = "camelCase")]
3353pub struct RuleCustomization {
3354    /// Session-unique opaque identifier. Used by every action that targets a
3355    /// specific customization. Minted by whoever publishes the customization
3356    /// (typically the agent host).
3357    pub id: String,
3358    /// Source URI for this customization. A plugin URL, a file URI, or a
3359    /// directory URI.
3360    ///
3361    /// For declarations that live inside a larger file — e.g. an MCP
3362    /// server declared inline in a `plugins.json` manifest — `uri` points
3363    /// to the containing file and {@link CustomizationBase.range | `range`}
3364    /// narrows it to the declaration's span.
3365    pub uri: Uri,
3366    /// Human-readable name.
3367    pub name: String,
3368    /// Icons for UI display.
3369    #[serde(default, skip_serializing_if = "Option::is_none")]
3370    pub icons: Option<Vec<Icon>>,
3371    /// Optional span within {@link CustomizationBase.uri | `uri`} when this
3372    /// customization is a subset of a larger file (for example, one entry
3373    /// in an inline `mcpServers` block of a `plugins.json` manifest).
3374    /// Absent when the customization covers the whole resource.
3375    #[serde(default, skip_serializing_if = "Option::is_none")]
3376    pub range: Option<TextRange>,
3377    /// Additional provider-specific metadata for this customization.
3378    ///
3379    /// Mirrors the MCP `_meta` convention. Optional and opaque to the
3380    /// protocol; producers and consumers agree on its contents
3381    /// out-of-band.
3382    #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
3383    pub meta: Option<JsonObject>,
3384    /// Whether this child is individually enabled. Absent means enabled, so a
3385    /// producer only needs to set it to surface a child that exists but is
3386    /// turned off on its own.
3387    ///
3388    /// This flag is independent of the parent container's: the **effective**
3389    /// enabled state of a plugin child is the plugin's derived enabled value and
3390    /// `(child.enabled ?? true)`, so a disabled plugin disables every child
3391    /// regardless of each child's own flag. A directory child instead uses the
3392    /// directory's `enabled` value and its own flag.
3393    ///
3394    /// A child is turned on or off by id with
3395    /// {@link SessionCustomizationToggledAction | `session/customizationToggled`}.
3396    #[serde(default, skip_serializing_if = "Option::is_none")]
3397    pub enabled: Option<bool>,
3398    /// Description of what the rule enforces.
3399    #[serde(default, skip_serializing_if = "Option::is_none")]
3400    pub description: Option<String>,
3401    /// When `true`, the rule is always active (subject to `globs` if any).
3402    /// When `false` or absent, the agent or user decides whether to apply
3403    /// the rule.
3404    #[serde(default, skip_serializing_if = "Option::is_none")]
3405    pub always_apply: Option<bool>,
3406    /// Glob patterns the rule applies to. When present, the rule is only
3407    /// active for matching files.
3408    #[serde(default, skip_serializing_if = "Option::is_none")]
3409    pub globs: Option<Vec<String>>,
3410}
3411
3412/// A hook manifest contributed by a plugin or directory.
3413#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
3414#[serde(rename_all = "camelCase")]
3415pub struct HookCustomization {
3416    /// Session-unique opaque identifier. Used by every action that targets a
3417    /// specific customization. Minted by whoever publishes the customization
3418    /// (typically the agent host).
3419    pub id: String,
3420    /// Source URI for this customization. A plugin URL, a file URI, or a
3421    /// directory URI.
3422    ///
3423    /// For declarations that live inside a larger file — e.g. an MCP
3424    /// server declared inline in a `plugins.json` manifest — `uri` points
3425    /// to the containing file and {@link CustomizationBase.range | `range`}
3426    /// narrows it to the declaration's span.
3427    pub uri: Uri,
3428    /// Human-readable name.
3429    pub name: String,
3430    /// Icons for UI display.
3431    #[serde(default, skip_serializing_if = "Option::is_none")]
3432    pub icons: Option<Vec<Icon>>,
3433    /// Optional span within {@link CustomizationBase.uri | `uri`} when this
3434    /// customization is a subset of a larger file (for example, one entry
3435    /// in an inline `mcpServers` block of a `plugins.json` manifest).
3436    /// Absent when the customization covers the whole resource.
3437    #[serde(default, skip_serializing_if = "Option::is_none")]
3438    pub range: Option<TextRange>,
3439    /// Additional provider-specific metadata for this customization.
3440    ///
3441    /// Mirrors the MCP `_meta` convention. Optional and opaque to the
3442    /// protocol; producers and consumers agree on its contents
3443    /// out-of-band.
3444    #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
3445    pub meta: Option<JsonObject>,
3446    /// Whether this child is individually enabled. Absent means enabled, so a
3447    /// producer only needs to set it to surface a child that exists but is
3448    /// turned off on its own.
3449    ///
3450    /// This flag is independent of the parent container's: the **effective**
3451    /// enabled state of a plugin child is the plugin's derived enabled value and
3452    /// `(child.enabled ?? true)`, so a disabled plugin disables every child
3453    /// regardless of each child's own flag. A directory child instead uses the
3454    /// directory's `enabled` value and its own flag.
3455    ///
3456    /// A child is turned on or off by id with
3457    /// {@link SessionCustomizationToggledAction | `session/customizationToggled`}.
3458    #[serde(default, skip_serializing_if = "Option::is_none")]
3459    pub enabled: Option<bool>,
3460}
3461
3462/// An MCP server contributed by a plugin or directory.
3463///
3464/// When the server is declared inline in the containing plugin manifest,
3465/// `uri` points at the manifest file and
3466/// {@link CustomizationBase.range | `range`} narrows it to the
3467/// declaration's span.
3468///
3469/// The MCP server customization also reflects its current status.
3470#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
3471#[serde(rename_all = "camelCase")]
3472pub struct McpServerCustomization {
3473    /// Session-unique opaque identifier. Used by every action that targets a
3474    /// specific customization. Minted by whoever publishes the customization
3475    /// (typically the agent host).
3476    pub id: String,
3477    /// Source URI for this customization. A plugin URL, a file URI, or a
3478    /// directory URI.
3479    ///
3480    /// For declarations that live inside a larger file — e.g. an MCP
3481    /// server declared inline in a `plugins.json` manifest — `uri` points
3482    /// to the containing file and {@link CustomizationBase.range | `range`}
3483    /// narrows it to the declaration's span.
3484    pub uri: Uri,
3485    /// Human-readable name.
3486    pub name: String,
3487    /// Icons for UI display.
3488    #[serde(default, skip_serializing_if = "Option::is_none")]
3489    pub icons: Option<Vec<Icon>>,
3490    /// Optional span within {@link CustomizationBase.uri | `uri`} when this
3491    /// customization is a subset of a larger file (for example, one entry
3492    /// in an inline `mcpServers` block of a `plugins.json` manifest).
3493    /// Absent when the customization covers the whole resource.
3494    #[serde(default, skip_serializing_if = "Option::is_none")]
3495    pub range: Option<TextRange>,
3496    /// Additional provider-specific metadata for this customization.
3497    ///
3498    /// Mirrors the MCP `_meta` convention. Optional and opaque to the
3499    /// protocol; producers and consumers agree on its contents
3500    /// out-of-band.
3501    #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
3502    pub meta: Option<JsonObject>,
3503    /// Explicit enablement decisions for this customization, one entry per scope
3504    /// that has one. This is a wire contract: producers MUST publish entries
3505    /// sorted by descending specificity (Session, Workspace, then Global).
3506    /// The agent host emits at most one Workspace entry, for the session's primary
3507    /// working directory. Consumers MAY treat
3508    /// `enablement[0]` as the decisive decision and
3509    /// `enablement?.[0]?.enabled ?? true` as the effective enabled value. An
3510    /// absent or empty array means no explicit decision exists, so the
3511    /// customization is enabled by default.
3512    ///
3513    /// Flows in both directions. A client publishes this alongside a customization
3514    /// to assert its global decision, which is authoritative for the Global scope;
3515    /// a client always includes its global entry, even when enabled. The host
3516    /// publishes the fully resolved set across all scopes, and consumers derive
3517    /// the effective enabled value from that set.
3518    #[serde(default, skip_serializing_if = "Option::is_none")]
3519    pub enablement: Option<Vec<CustomizationEnablement>>,
3520    /// Current lifecycle state of the MCP server.
3521    pub state: McpServerState,
3522    /// An `mcp://`-protocol channel the client uses to side-channel traffic
3523    /// into the upstream MCP server itself. The channel is NOT a fresh raw MCP
3524    /// connection: it piggybacks on the AHP transport
3525    /// and skips the MCP `initialize` sequence.
3526    ///
3527    /// The agent host MAY only serve a subset of MCP on this
3528    /// channel; the served subset is described by domain-specific
3529    /// capabilities such as those in
3530    /// {@link McpServerCustomizationApps.capabilities}.
3531    ///
3532    /// The channel URI SHOULD be stable across the server's lifetime, but
3533    /// the agent host MAY change it (for example across a restart) and
3534    /// MAY only expose it while the server is in
3535    /// {@link McpServerStatus.Ready | `Ready`}. Absence means no
3536    /// side-channel is currently available.
3537    #[serde(default, skip_serializing_if = "Option::is_none")]
3538    pub channel: Option<Uri>,
3539    /// MCP App support. This property SHOULD be advertised for MCP servers
3540    /// which support apps.
3541    #[serde(default, skip_serializing_if = "Option::is_none")]
3542    pub mcp_app: Option<McpServerCustomizationApps>,
3543}
3544
3545/// Information from the agent host needed to render MCP Apps served
3546/// by this MCP server.
3547#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
3548#[serde(rename_all = "camelCase")]
3549pub struct McpServerCustomizationApps {
3550    /// The subset of MCP App
3551    /// [`HostCapabilities`](https://github.com/modelcontextprotocol/ext-apps/blob/main/specification/draft/apps.mdx)
3552    /// the AHP host can satisfy for Views backed by this server. The
3553    /// client feeds these straight through into the `hostCapabilities` of
3554    /// the `ui/initialize` response delivered to the View.
3555    pub capabilities: AhpMcpUiHostCapabilities,
3556}
3557
3558/// The subset of MCP App
3559/// [`HostCapabilities`](https://github.com/modelcontextprotocol/ext-apps/blob/main/specification/draft/apps.mdx)
3560/// an AHP host can derive from the upstream MCP server (and from AHP's own
3561/// forwarding plumbing). Advertised on
3562/// {@link McpServerCustomizationApps.capabilities} so clients can pass it
3563/// through into the `hostCapabilities` of the `ui/initialize` response
3564/// delivered to an MCP App View.
3565///
3566/// Field names mirror the MCP Apps spec exactly, so the AHP-side producer
3567/// can pass them straight through into the `hostCapabilities` of the
3568/// `ui/initialize` response delivered to the View.
3569///
3570/// Capabilities outside this set (`openLinks`, `downloadFile`, `sandbox`,
3571/// `experimental`) are decided locally by whichever AHP client renders the
3572/// View and are NOT part of this AHP-level advertisement — only the
3573/// server-derived subset is.
3574///
3575/// An agent host MUST only advertise a capability when it actually accepts the
3576/// corresponding methods/notifications on the `mcp://` channel:
3577///
3578/// - {@link serverTools}: host proxies `tools/list` and `tools/call` to
3579///   the MCP server. When `listChanged` is `true`, the host also forwards
3580///   `notifications/tools/list_changed`.
3581/// - {@link serverResources}: host proxies `resources/read`,
3582///   `resources/list`, and `resources/templates/list` to the MCP server.
3583///   When `listChanged` is `true`, the host also forwards
3584///   `notifications/resources/list_changed`.
3585/// - {@link logging}: host accepts `notifications/message` log entries
3586///   from the App and forwards them via `mcpNotification` (and forwards
3587///   `logging/setLevel` calls to the server).
3588/// - {@link sampling}: host serves `sampling/createMessage` via
3589///   `mcpMethodCall`. When `sampling.tools` is present, the host also
3590///   accepts SEP-1577 `tools` / `toolChoice` / `tool_use` content blocks
3591///   inside `CreateMessageRequest`.
3592#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Default)]
3593#[serde(rename_all = "camelCase")]
3594pub struct AhpMcpUiHostCapabilities {
3595    /// Producer proxies the MCP `tools/*` methods to the upstream server.
3596    #[serde(default, skip_serializing_if = "Option::is_none")]
3597    pub server_tools: Option<AnyValue>,
3598    /// Producer proxies the MCP `resources/*` methods to the upstream server.
3599    #[serde(default, skip_serializing_if = "Option::is_none")]
3600    pub server_resources: Option<AnyValue>,
3601    /// Producer accepts `notifications/message` log entries from the App via `mcpNotification`.
3602    #[serde(default, skip_serializing_if = "Option::is_none")]
3603    pub logging: Option<JsonObject>,
3604    /// Producer serves `sampling/createMessage` via `mcpMethodCall`.
3605    #[serde(default, skip_serializing_if = "Option::is_none")]
3606    pub sampling: Option<AnyValue>,
3607}
3608
3609/// Server is registered with the host but has not yet started.
3610#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
3611#[serde(rename_all = "camelCase")]
3612pub struct McpServerStartingState {}
3613
3614/// Server is running and serving requests.
3615#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
3616#[serde(rename_all = "camelCase")]
3617pub struct McpServerReadyState {}
3618
3619/// Server is reachable but cannot serve requests until the client
3620/// authenticates. Mirrors the discovery flow defined by
3621/// [RFC 9728](https://datatracker.ietf.org/doc/html/rfc9728)
3622/// (Protected Resource Metadata) and the OAuth 2.1 / RFC 6750 challenge
3623/// semantics required by the MCP authorization spec.
3624///
3625/// Clients react to this state by calling the existing `authenticate`
3626/// command with the {@link ProtectedResourceMetadata.resource | resource}
3627/// carried here. There is **no** `notify/authRequired` notification for
3628/// MCP servers — the action stream is the single source of truth.
3629///
3630/// When the transition is triggered by a request issued during a turn
3631/// — most commonly
3632/// {@link McpAuthRequiredReason.InsufficientScope | `InsufficientScope`}
3633/// surfacing mid-tool-call — the host SHOULD also raise
3634/// {@link SessionStatus.InputNeeded} on the session so the block is
3635/// visible at the summary level. Clients SHOULD watch this status on
3636/// any MCP server backing a running tool call and surface an explicit
3637/// affordance (e.g. a "grant additional access" prompt) tied to that
3638/// tool call, rather than relying on the user to notice the
3639/// customization’s status badge.
3640#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
3641#[serde(rename_all = "camelCase")]
3642pub struct McpServerAuthRequiredState {
3643    /// Why authentication is required.
3644    pub reason: McpAuthRequiredReason,
3645    /// Pre-registered OAuth client to use for authorization. When present, clients
3646    /// MUST use these credentials instead of dynamic client registration.
3647    #[serde(default, skip_serializing_if = "Option::is_none")]
3648    pub oauth_client: Option<McpOAuthClient>,
3649    /// RFC 9728 Protected Resource Metadata. The `resource` field is the
3650    /// canonical MCP server URI per RFC 8707, used as the OAuth `resource`
3651    /// indicator. `authorization_servers` is REQUIRED by the MCP
3652    /// authorization spec.
3653    pub resource: ProtectedResourceMetadata,
3654    /// Scopes required for the current challenge, parsed from the
3655    /// `WWW-Authenticate: Bearer scope="…"` header (or `scopes_supported`
3656    /// fallback). Authoritative for the next authorization request — clients
3657    /// MUST NOT assume any subset/superset relationship to
3658    /// `resource.scopes_supported`.
3659    #[serde(default, skip_serializing_if = "Option::is_none")]
3660    pub required_scopes: Option<Vec<String>>,
3661    /// Human-readable hint, typically from the OAuth `error_description`.
3662    #[serde(default, skip_serializing_if = "Option::is_none")]
3663    pub description: Option<String>,
3664}
3665
3666/// Server failed to start, crashed, or otherwise transitioned to a
3667/// non-recoverable error. Use {@link McpServerStatus.AuthRequired}
3668/// for authentication failures.
3669#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
3670#[serde(rename_all = "camelCase")]
3671pub struct McpServerErrorState {
3672    /// Error details.
3673    pub error: ErrorInfo,
3674}
3675
3676/// Server has been shut down. The host MAY remove the server from the
3677/// session entirely shortly after this state.
3678#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
3679#[serde(rename_all = "camelCase")]
3680pub struct McpServerStoppedState {}
3681
3682/// A pre-registered OAuth client that clients use instead of dynamic client
3683/// registration when resolving an MCP authentication challenge.
3684#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
3685#[serde(rename_all = "camelCase")]
3686pub struct McpOAuthClient {
3687    /// OAuth client identifier registered with the authorization server.
3688    pub client_id: String,
3689    /// OAuth client secret for a confidential client. Absence means the client is
3690    /// public and uses a secretless flow such as authorization code with PKCE.
3691    #[serde(default, skip_serializing_if = "Option::is_none")]
3692    pub client_secret: Option<String>,
3693}
3694
3695/// Reusable MCP authentication challenge — the RFC 9728 discovery info a
3696/// client needs to obtain a token and push it via the `authenticate` command.
3697/// Deliberately carries **no token**: this describes what is being asked for,
3698/// never the bearer token itself.
3699///
3700/// Shared by two independent state machines that describe the same OAuth
3701/// challenge from different vantage points:
3702///
3703/// - {@link McpServerAuthRequiredState} — the MCP server itself cannot serve
3704///   *any* request until the client authenticates.
3705/// - {@link ToolCallAuthRequiredState} — a specific in-flight tool call is
3706///   paused pending authentication (typically
3707///   {@link McpAuthRequiredReason.InsufficientScope} step-up auth
3708///   mid-execution). The server state and the tool-call state remain
3709///   separate on purpose: the server saying "I need auth" and a tool
3710///   invocation saying "I am waiting on that auth" are different facts that
3711///   can be true independently.
3712#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
3713#[serde(rename_all = "camelCase")]
3714pub struct McpAuthRequirement {
3715    /// Why authentication is required.
3716    pub reason: McpAuthRequiredReason,
3717    /// Pre-registered OAuth client to use for authorization. When present, clients
3718    /// MUST use these credentials instead of dynamic client registration.
3719    #[serde(default, skip_serializing_if = "Option::is_none")]
3720    pub oauth_client: Option<McpOAuthClient>,
3721    /// RFC 9728 Protected Resource Metadata. The `resource` field is the
3722    /// canonical MCP server URI per RFC 8707, used as the OAuth `resource`
3723    /// indicator. `authorization_servers` is REQUIRED by the MCP
3724    /// authorization spec.
3725    pub resource: ProtectedResourceMetadata,
3726    /// Scopes required for the current challenge, parsed from the
3727    /// `WWW-Authenticate: Bearer scope="…"` header (or `scopes_supported`
3728    /// fallback). Authoritative for the next authorization request — clients
3729    /// MUST NOT assume any subset/superset relationship to
3730    /// `resource.scopes_supported`.
3731    #[serde(default, skip_serializing_if = "Option::is_none")]
3732    pub required_scopes: Option<Vec<String>>,
3733    /// Human-readable hint, typically from the OAuth `error_description`.
3734    #[serde(default, skip_serializing_if = "Option::is_none")]
3735    pub description: Option<String>,
3736}
3737
3738#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
3739#[serde(rename_all = "camelCase")]
3740pub struct ToolCallClientContributor {
3741    /// If this tool is provided by a client, the `clientId` of the owning client.
3742    /// Absent for server-side tools.
3743    ///
3744    /// When set, the identified client is responsible for executing the tool and
3745    /// dispatching `chat/toolCallComplete` with the result.
3746    pub client_id: String,
3747}
3748
3749#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
3750#[serde(rename_all = "camelCase")]
3751pub struct ToolCallMcpContributor {
3752    /// Customization ID of the corresponding MCP server in {@link SessionState.customizations}.
3753    pub customization_id: String,
3754}
3755
3756/// Describes a file modification with before/after state and diff metadata.
3757///
3758/// Supports creates (only `after`), deletes (only `before`), renames/moves
3759/// (different `uri` in `before` and `after`), and edits (same `uri`, different content).
3760#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Default)]
3761#[serde(rename_all = "camelCase")]
3762pub struct FileEdit {
3763    /// The file state before the edit. Absent for file creations or for in-place file edits.
3764    #[serde(default, skip_serializing_if = "Option::is_none")]
3765    pub before: Option<AnyValue>,
3766    /// The file state after the edit. Absent for file deletions.
3767    #[serde(default, skip_serializing_if = "Option::is_none")]
3768    pub after: Option<AnyValue>,
3769    /// Optional diff display metadata
3770    #[serde(default, skip_serializing_if = "Option::is_none")]
3771    pub diff: Option<AnyValue>,
3772}
3773
3774/// Outcome of a command run in a terminal-style tool, filled in on
3775/// {@link ToolResultTerminalContent.result} once the command exits.
3776#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Default)]
3777#[serde(rename_all = "camelCase")]
3778pub struct TerminalCommandResult {
3779    /// Exit code from the completed command, if reported by the runtime
3780    #[serde(default, skip_serializing_if = "Option::is_none")]
3781    pub exit_code: Option<i64>,
3782    /// Preview of the command's output, for clients that are not subscribed
3783    /// to the terminal or that arrive after it is disposed. When `isPty` is
3784    /// `true` the preview may contain VT sequences; when `false` it is plain
3785    /// text.
3786    #[serde(default, skip_serializing_if = "Option::is_none")]
3787    pub preview: Option<String>,
3788    /// Whether `preview` is known to be incomplete or truncated
3789    #[serde(default, skip_serializing_if = "Option::is_none")]
3790    pub truncated: Option<bool>,
3791}
3792
3793/// Lightweight terminal metadata exposed on the root state.
3794#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
3795#[serde(rename_all = "camelCase")]
3796pub struct TerminalInfo {
3797    /// Terminal URI (subscribable for full terminal state)
3798    pub resource: Uri,
3799    /// Human-readable terminal title
3800    pub title: String,
3801    /// Who currently holds this terminal
3802    pub claim: TerminalClaim,
3803    /// Process exit code, if the terminal process has exited
3804    #[serde(default, skip_serializing_if = "Option::is_none")]
3805    pub exit_code: Option<i64>,
3806}
3807
3808/// A terminal claimed by a connected client.
3809#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
3810#[serde(rename_all = "camelCase")]
3811pub struct TerminalClientClaim {
3812    /// The `clientId` of the claiming client
3813    pub client_id: String,
3814}
3815
3816/// A terminal claimed by a session, optionally scoped to a specific turn or tool call.
3817#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
3818#[serde(rename_all = "camelCase")]
3819pub struct TerminalSessionClaim {
3820    /// Session URI that claimed the terminal
3821    pub session: Uri,
3822    /// Optional turn identifier within the session
3823    #[serde(default, skip_serializing_if = "Option::is_none")]
3824    pub turn_id: Option<String>,
3825    /// Optional tool call identifier within the turn
3826    #[serde(default, skip_serializing_if = "Option::is_none")]
3827    pub tool_call_id: Option<String>,
3828}
3829
3830/// Full state for a single terminal, loaded when a client subscribes to the terminal's URI.
3831#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
3832#[serde(rename_all = "camelCase")]
3833pub struct TerminalState {
3834    /// Human-readable terminal title
3835    pub title: String,
3836    /// Current working directory of the terminal process
3837    #[serde(default, skip_serializing_if = "Option::is_none")]
3838    pub cwd: Option<Uri>,
3839    /// Terminal width in columns
3840    #[serde(default, skip_serializing_if = "Option::is_none")]
3841    pub cols: Option<i64>,
3842    /// Terminal height in rows
3843    #[serde(default, skip_serializing_if = "Option::is_none")]
3844    pub rows: Option<i64>,
3845    /// Typed content parts, replacing the flat `content: string`.
3846    ///
3847    /// Naive consumers that only need the raw VT stream can reconstruct it with:
3848    ///   `content.map(p => p.type === 'command' ? p.output : p.value).join('')`
3849    ///
3850    /// Consumers that need command boundaries can filter by part type.
3851    pub content: Vec<TerminalContentPart>,
3852    /// Process exit code, set when the terminal process exits
3853    #[serde(default, skip_serializing_if = "Option::is_none")]
3854    pub exit_code: Option<i64>,
3855    /// Who currently holds this terminal
3856    pub claim: TerminalClaim,
3857    /// Whether this terminal emits `terminal/commandExecuted` and
3858    /// `terminal/commandFinished` actions and populates `command`-typed parts.
3859    ///
3860    /// Clients MUST check this flag before relying on command detection.
3861    /// Do NOT use the presence of a `command` part as a feature flag — parts
3862    /// are absent in the normal idle state.
3863    #[serde(default, skip_serializing_if = "Option::is_none")]
3864    pub supports_command_detection: Option<bool>,
3865    /// Whether this terminal-style resource is backed by a pseudoterminal.
3866    /// When `false`, output is plain text and clients do not need to parse
3867    /// VT sequences.
3868    #[serde(default, skip_serializing_if = "Option::is_none")]
3869    pub is_pty: Option<bool>,
3870}
3871
3872/// Unstructured terminal output — content before, between, or after commands,
3873/// or from terminals that do not support command detection.
3874#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
3875#[serde(rename_all = "camelCase")]
3876pub struct TerminalUnclassifiedPart {
3877    /// Accumulated VT output. Appended to by `terminal/data` when no command is executing.
3878    pub value: String,
3879}
3880
3881/// A single command: its command line and the output it produced.
3882///
3883/// While `isComplete` is false the command is still executing; `output` grows
3884/// as `terminal/data` actions arrive. At `terminal/commandFinished` the part
3885/// is mutated in-place with `isComplete: true` and the completion metadata.
3886#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
3887#[serde(rename_all = "camelCase")]
3888pub struct TerminalCommandPart {
3889    /// Stable id matching the `commandId` on the corresponding
3890    /// `terminal/commandExecuted` and `terminal/commandFinished` actions.
3891    pub command_id: String,
3892    /// The command line submitted to the shell.
3893    pub command_line: String,
3894    /// Accumulated VT output. Appended to by `terminal/data` while `isComplete`
3895    /// is false. Shell integration escape sequences are stripped by the server.
3896    pub output: String,
3897    /// Unix timestamp (ms) when execution started, as reported by the server.
3898    pub timestamp: i64,
3899    /// Whether the command has finished.
3900    pub is_complete: bool,
3901    /// Shell exit code. Set at completion. `undefined` if unknown.
3902    #[serde(default, skip_serializing_if = "Option::is_none")]
3903    pub exit_code: Option<i64>,
3904    /// Wall-clock duration in milliseconds. Set at completion.
3905    #[serde(default, skip_serializing_if = "Option::is_none")]
3906    pub duration_ms: Option<i64>,
3907}
3908
3909#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Default)]
3910#[serde(rename_all = "camelCase")]
3911pub struct UsageInfo {
3912    /// Input tokens consumed
3913    #[serde(default, skip_serializing_if = "Option::is_none")]
3914    pub input_tokens: Option<i64>,
3915    /// Output tokens generated
3916    #[serde(default, skip_serializing_if = "Option::is_none")]
3917    pub output_tokens: Option<i64>,
3918    /// Model used
3919    #[serde(default, skip_serializing_if = "Option::is_none")]
3920    pub model: Option<String>,
3921    /// Tokens read from cache
3922    #[serde(default, skip_serializing_if = "Option::is_none")]
3923    pub cache_read_tokens: Option<i64>,
3924    /// Additional provider-specific metadata for this usage report.
3925    /// Clients MAY look for well-known optional keys here to provide enhanced UI.
3926    #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
3927    pub meta: Option<JsonObject>,
3928}
3929
3930#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
3931#[serde(rename_all = "camelCase")]
3932pub struct ErrorInfo {
3933    /// Error type identifier
3934    pub error_type: String,
3935    /// Human-readable error message
3936    pub message: String,
3937    /// Stack trace
3938    #[serde(default, skip_serializing_if = "Option::is_none")]
3939    pub stack: Option<String>,
3940    /// Additional provider-specific metadata for this error.
3941    /// Clients MAY look for well-known optional keys here to provide enhanced UI
3942    /// (e.g. a structured chat fetch error for richer, localized messaging).
3943    #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
3944    pub meta: Option<JsonObject>,
3945}
3946
3947/// A point-in-time snapshot of a subscribed resource's state, returned by
3948/// `initialize`, `reconnect`, and `subscribe`.
3949#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
3950#[serde(rename_all = "camelCase")]
3951pub struct Snapshot {
3952    /// The subscribed channel URI (e.g. `ahp-root://`, `ahp-session:/<uuid>`, or `ahp-chat:/<uuid>`)
3953    pub resource: Uri,
3954    /// The current state of the resource
3955    pub state: SnapshotState,
3956    /// The `serverSeq` at which this snapshot was taken. Subsequent actions will have `serverSeq > fromSeq`.
3957    pub from_seq: i64,
3958}
3959
3960/// Catalogue entry describing one changeset the server can produce for a
3961/// session.
3962///
3963/// Catalogue entries are intentionally lightweight — just enough to render a
3964/// chip or list row without subscribing. Full per-changeset detail
3965/// ({@link ChangesetState}) lives on the subscribable URI obtained by
3966/// expanding {@link uriTemplate}.
3967#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
3968#[serde(rename_all = "camelCase")]
3969pub struct Changeset {
3970    /// Human-readable label, e.g. `"Uncommitted Changes"`.
3971    pub label: String,
3972    /// RFC 6570 URI template. Clients parse the variables directly out of the
3973    /// template using the standard `{name}` syntax — they are not redeclared
3974    /// here.
3975    ///
3976    /// Only the following template shapes are defined by this protocol; any
3977    /// other variable name MUST be ignored by clients (there is no
3978    /// protocol-defined way to obtain values for unknown variables):
3979    ///
3980    /// | Variables in template                       | Meaning                                                                              |
3981    /// | ------------------------------------------- | ------------------------------------------------------------------------------------ |
3982    /// | _(none)_                                    | A static, session-wide changeset. The template is itself a subscribable URI.         |
3983    /// | `{turnId}`                                  | Per-turn slice. Expand with a `Turn.id` from the session.                            |
3984    /// | `{originalTurnId}` and `{modifiedTurnId}`   | Diff between two turns. Both variables MUST be present.                              |
3985    ///
3986    /// Future protocol versions MAY add new well-known variables.
3987    pub uri_template: String,
3988    /// Optional longer description.
3989    #[serde(default, skip_serializing_if = "Option::is_none")]
3990    pub description: Option<String>,
3991    /// Advisory hint describing what kind of changeset this is, so clients can
3992    /// group, sort, or render an appropriate icon without parsing
3993    /// {@link uriTemplate}. Recognized values include:
3994    ///
3995    /// - `'session'`: a static, session-wide changeset covering all changes the
3996    ///   agent has produced in this session.
3997    /// - `'branch'`: changes relative to a base branch (e.g. a feature branch
3998    ///   diffed against `main`).
3999    /// - `'uncommitted'`: the workspace's current uncommitted changes.
4000    /// - `'turn'`: changes produced by a single turn. Typically paired with a
4001    ///   `{turnId}` variable in {@link uriTemplate}.
4002    /// - `'compare-turns'`: a diff between two turns. Typically paired with
4003    ///   `{originalTurnId}` and `{modifiedTurnId}` variables in
4004    ///   {@link uriTemplate}.
4005    ///
4006    /// Implementations MAY provide additional values; clients SHOULD fall back
4007    /// to a reasonable default when an unknown value is encountered.
4008    pub change_kind: String,
4009    /// Optional capability declarations for this changeset. Absent (or an empty
4010    /// object) means the changeset advertises no optional capabilities.
4011    ///
4012    /// Because the catalogue entry is delivered up-front on
4013    /// {@link ChangesetState | the session's changeset list}, clients can decide
4014    /// whether to surface capability-gated UI (such as review checkboxes) without
4015    /// first subscribing to the changeset URI. Mirrors the presence-flag
4016    /// convention of `ClientCapabilities`.
4017    #[serde(default, skip_serializing_if = "Option::is_none")]
4018    pub capabilities: Option<ChangesetCapabilities>,
4019}
4020
4021/// Optional capabilities a changeset advertises on its catalogue
4022/// {@link Changeset} entry.
4023///
4024/// Each field is a presence flag: an empty object `{}` means "supported",
4025/// absence means "not supported". Sub-fields on individual capabilities are
4026/// reserved for future per-capability options.
4027#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Default)]
4028#[serde(rename_all = "camelCase")]
4029pub struct ChangesetCapabilities {
4030    /// The changeset supports the per-file **review** workflow. When declared,
4031    /// clients MAY surface a GitHub-style "Viewed" toggle per file and dispatch
4032    /// {@link ChangesetFilesReviewChangedAction | `changeset/filesReviewChanged`} to
4033    /// set each file's {@link ChangesetFile.reviewed} flag. Clients that omit
4034    /// handling MUST treat the changeset as non-reviewable.
4035    #[serde(default, skip_serializing_if = "Option::is_none")]
4036    pub review: Option<JsonObject>,
4037}
4038
4039/// Full state for a single changeset, returned when a client subscribes to
4040/// an expanded changeset URI.
4041///
4042/// The client already knows the URI it subscribed to, so this state does
4043/// not redundantly carry it (or the catalogue's `id`, `label`, etc.).
4044/// Aggregate counts (`additions`, `deletions`, `files`) are likewise
4045/// omitted: clients trivially compute them from `files[].edit.diff`.
4046#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
4047#[serde(rename_all = "camelCase")]
4048pub struct ChangesetState {
4049    /// Computation lifecycle.
4050    pub status: ChangesetStatus,
4051    /// Present iff `status === ChangesetStatus.Error`.
4052    #[serde(default, skip_serializing_if = "Option::is_none")]
4053    pub error: Option<ErrorInfo>,
4054    /// Files in this changeset, keyed by {@link ChangesetFile.id}.
4055    pub files: Vec<ChangesetFile>,
4056    /// Operations the client may invoke against this changeset. Omit when no
4057    /// operations are available.
4058    #[serde(default, skip_serializing_if = "Option::is_none")]
4059    pub operations: Option<Vec<ChangesetOperation>>,
4060}
4061
4062/// One file entry within a {@link ChangesetState}.
4063#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
4064#[serde(rename_all = "camelCase")]
4065pub struct ChangesetFile {
4066    /// Stable identifier within the changeset. Typically `after.uri`
4067    /// (or `before.uri` for deletions).
4068    pub id: String,
4069    /// Reuses the existing {@link FileEdit} shape. Clients derive line
4070    /// additions, deletions, and rename/create/delete semantics from this.
4071    pub edit: FileEdit,
4072    /// Whether a reviewer has marked this file as reviewed (the GitHub-style
4073    /// "Viewed" checkbox). Absent is equivalent to `false` — clients MUST treat
4074    /// a missing value as not-yet-reviewed.
4075    ///
4076    /// Requires the changeset to advertise {@link ChangesetCapabilities.review}.
4077    /// Clients toggle it by dispatching
4078    /// {@link ChangesetFilesReviewChangedAction | `changeset/filesReviewChanged`};
4079    /// the server MAY also originate it (e.g. an agent self-reviewing its own
4080    /// output).
4081    ///
4082    /// There is no content version in the protocol, so review is **not** reset
4083    /// automatically when a file's contents change under a stable id. The server,
4084    /// which is the authority on what changed, resets review explicitly — either
4085    /// by re-emitting the file (via {@link ChangesetFileSetAction} or
4086    /// {@link ChangesetContentChangedAction}) without `reviewed: true`, or by
4087    /// dispatching `changeset/filesReviewChanged` with `reviewed: false`.
4088    #[serde(default, skip_serializing_if = "Option::is_none")]
4089    pub reviewed: Option<bool>,
4090    /// Server-defined opaque metadata, surfaced to operations and tooling
4091    /// but not interpreted by the protocol.
4092    #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
4093    pub meta: Option<JsonObject>,
4094}
4095
4096/// A server-declared invokable verb the client can run against a
4097/// changeset, a file, or a range — `"stage"`, `"revert"`, `"create-pr"`,
4098/// and so on.
4099///
4100/// The term "operation" is used deliberately to avoid colliding with the
4101/// protocol-level [Actions](/guide/actions) that mutate state.
4102#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
4103#[serde(rename_all = "camelCase")]
4104pub struct ChangesetOperation {
4105    /// Stable identifier, unique within this changeset.
4106    pub id: String,
4107    /// Human-readable button/menu label.
4108    pub label: String,
4109    /// Optional longer description shown on hover or in tooltips.
4110    #[serde(default, skip_serializing_if = "Option::is_none")]
4111    pub description: Option<String>,
4112    /// Where this operation can be invoked.
4113    pub scopes: Vec<ChangesetOperationScope>,
4114    /// Optional confirmation prompt to show before invoking. When present,
4115    /// the client MUST display this message to the user (typically in a
4116    /// confirmation dialog) and only invoke the operation after the user
4117    /// accepts. The presence of this field also signals that the operation
4118    /// is destructive — clients SHOULD style the affirmative button
4119    /// accordingly (e.g. with a warning colour).
4120    #[serde(default, skip_serializing_if = "Option::is_none")]
4121    pub confirmation: Option<StringOrMarkdown>,
4122    /// Optional generic icon hint, e.g. `"check"`, `"trash"`.
4123    #[serde(default, skip_serializing_if = "Option::is_none")]
4124    pub icon: Option<String>,
4125    /// Optional group identifier, used to group related operations together.
4126    #[serde(default, skip_serializing_if = "Option::is_none")]
4127    pub group: Option<String>,
4128    /// Current execution status. The server sets
4129    /// {@link ChangesetOperationStatus.Running | Running} while an invocation
4130    /// is in flight, {@link ChangesetOperationStatus.Error | Error} when the
4131    /// most recent invocation failed, and
4132    /// {@link ChangesetOperationStatus.Idle | Idle} otherwise.
4133    ///
4134    /// Clients SHOULD reflect this state in the UI — e.g. disabling the
4135    /// control or showing a spinner while `Running`, and surfacing
4136    /// {@link error} while `Error`.
4137    pub status: ChangesetOperationStatus,
4138    /// Cause of failure. Present iff
4139    /// `status === ChangesetOperationStatus.Error`; otherwise omitted.
4140    #[serde(default, skip_serializing_if = "Option::is_none")]
4141    pub error: Option<ErrorInfo>,
4142}
4143
4144/// Lightweight per-session summary of the annotations channel, surfaced on
4145/// {@link SessionSummary.annotations} so badge UI can render annotation /
4146/// entry counts without subscribing to the channel itself.
4147#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
4148#[serde(rename_all = "camelCase")]
4149pub struct AnnotationsSummary {
4150    /// The subscribable annotations channel URI for the owning session
4151    /// (typically `ahp-session:/<uuid>/annotations`). Surfaced explicitly even
4152    /// though it is derivable from the session URI so badge UI does not need
4153    /// to know the derivation rule.
4154    pub resource: Uri,
4155    /// Total number of {@link Annotation} entries in the channel.
4156    pub annotation_count: i64,
4157    /// Total number of {@link AnnotationEntry} entries across every annotation.
4158    pub entry_count: i64,
4159}
4160
4161/// Full state for a session's annotations channel, returned when a client
4162/// subscribes to an `ahp-session:/<uuid>/annotations` URI.
4163#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
4164#[serde(rename_all = "camelCase")]
4165pub struct AnnotationsState {
4166    /// Annotations in this channel, keyed by {@link Annotation.id}.
4167    pub annotations: Vec<Annotation>,
4168}
4169
4170/// A conversation anchored to a specific file produced by a specific turn,
4171/// optionally narrowed to a range within that file.
4172///
4173/// {@link turnId} anchors the annotation to the file versions that turn
4174/// produced, so a later turn that rewrites the same file does not silently
4175/// invalidate the annotation's anchor — clients can resolve {@link resource}
4176/// and {@link range} against the turn's changeset. When {@link range} is
4177/// omitted the annotation is anchored to the entire file.
4178///
4179/// Every annotation MUST contain at least one {@link AnnotationEntry}. An
4180/// {@link AnnotationsSetAction} that creates an annotation therefore carries
4181/// its mandatory first entry, and removing the last remaining entry collapses
4182/// the annotation via {@link AnnotationsRemovedAction} rather than leaving an
4183/// empty annotation behind.
4184#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
4185#[serde(rename_all = "camelCase")]
4186pub struct Annotation {
4187    /// Stable identifier within the annotations channel. Assigned by the client
4188    /// that dispatches the creating {@link AnnotationsSetAction}.
4189    pub id: String,
4190    /// Turn that produced the file versions this annotation is anchored to.
4191    /// Matches a {@link Turn.id} on the owning session.
4192    pub turn_id: String,
4193    /// The file the annotation is anchored to.
4194    pub resource: Uri,
4195    /// Range within {@link resource} the annotation is anchored to. When
4196    /// omitted the annotation is anchored to the entire file.
4197    #[serde(default, skip_serializing_if = "Option::is_none")]
4198    pub range: Option<TextRange>,
4199    /// Whether the annotation has been resolved. Newly created annotations are
4200    /// always unresolved (`false`); a client marks an annotation resolved (or
4201    /// re-opens it) by dispatching an {@link AnnotationsUpdatedAction} carrying
4202    /// the updated flag (or an {@link AnnotationsSetAction} when replacing the
4203    /// whole annotation).
4204    pub resolved: bool,
4205    /// Entries in this annotation, in dispatch order (oldest first). MUST
4206    /// contain at least one entry.
4207    pub entries: Vec<AnnotationEntry>,
4208    /// Producer-defined opaque metadata, surfaced to tooling but not
4209    /// interpreted by the protocol.
4210    #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
4211    pub meta: Option<JsonObject>,
4212}
4213
4214/// A single entry within an {@link Annotation}.
4215#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
4216#[serde(rename_all = "camelCase")]
4217pub struct AnnotationEntry {
4218    /// Stable identifier within the enclosing annotation. Assigned by the client
4219    /// that dispatches the {@link AnnotationsEntrySetAction} (or the enclosing
4220    /// {@link AnnotationsSetAction}) introducing the entry.
4221    pub id: String,
4222    /// Entry body. A bare `string` is rendered as plain text; pass
4223    /// `{ markdown: "…" }` to opt into Markdown rendering. See
4224    /// {@link StringOrMarkdown}.
4225    pub text: StringOrMarkdown,
4226    /// Producer-defined opaque metadata, surfaced to tooling but not
4227    /// interpreted by the protocol.
4228    #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
4229    pub meta: Option<JsonObject>,
4230}
4231
4232/// OTLP telemetry channels the agent host emits.
4233///
4234/// Each field, when present, is either a literal channel URI or an
4235/// [RFC 6570](https://datatracker.ietf.org/doc/html/rfc6570) URI template
4236/// a client expands and then subscribes to. Absent fields indicate the host
4237/// does not emit that signal.
4238///
4239/// Channel URIs use the `ahp-otlp:` scheme. The scheme identifies the
4240/// protocol (OpenTelemetry over AHP) so clients can recognise the channel
4241/// type by URI alone; the host is free to choose any authority/path that
4242/// makes sense for its implementation. Clients MUST treat the URI as
4243/// opaque (apart from expanding any well-known template variables defined
4244/// below) and subscribe with the resulting concrete URI.
4245///
4246/// Payloads delivered on these channels are OTLP/JSON values — see
4247/// [opentelemetry-proto](https://github.com/open-telemetry/opentelemetry-proto)
4248/// for the wire shapes (`ExportLogsServiceRequest`,
4249/// `ExportTraceServiceRequest`, `ExportMetricsServiceRequest`).
4250#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Default)]
4251#[serde(rename_all = "camelCase")]
4252pub struct TelemetryCapabilities {
4253    /// Channel URI (or RFC 6570 URI template) for OTLP log records
4254    /// (`otlp/exportLogs` notifications).
4255    ///
4256    /// The following template variables are defined by this protocol; any
4257    /// other variable name MUST be ignored by clients (there is no
4258    /// protocol-defined way to obtain values for unknown variables):
4259    ///
4260    /// | Variables in template | Meaning                                                                                                 |
4261    /// | --------------------- | ------------------------------------------------------------------------------------------------------- |
4262    /// | _(none)_              | The host does not support subscriber-side severity filtering. The template is itself a subscribable URI. |
4263    /// | `{level}`             | Minimum OTLP severity to deliver. Expand to one of the [OTLP `SeverityNumber`](https://opentelemetry.io/docs/specs/otel/logs/data-model/#field-severitynumber) short names (case-insensitive): `trace`, `debug`, `info`, `warn`, `error`, `fatal`. The server delivers log records whose `severityNumber` falls in the corresponding band or above. |
4264    ///
4265    /// Hosts SHOULD honour the expanded `{level}`; clients MUST still filter
4266    /// defensively in case a host ignores the parameter. Hosts that do not
4267    /// advertise `{level}` deliver all severities.
4268    ///
4269    /// Future protocol versions MAY add new well-known variables (e.g. scope
4270    /// or attribute filters).
4271    #[serde(default, skip_serializing_if = "Option::is_none")]
4272    pub logs: Option<Uri>,
4273    /// Channel URI for OTLP spans (`otlp/exportTraces` notifications). No
4274    /// template variables are defined by this protocol version.
4275    #[serde(default, skip_serializing_if = "Option::is_none")]
4276    pub traces: Option<Uri>,
4277    /// Channel URI for OTLP metric data points (`otlp/exportMetrics`
4278    /// notifications). No template variables are defined by this protocol
4279    /// version.
4280    #[serde(default, skip_serializing_if = "Option::is_none")]
4281    pub metrics: Option<Uri>,
4282}
4283
4284/// Full state for a single resource watch, returned when a client subscribes
4285/// to an `ahp-resource-watch:` URI.
4286///
4287/// Watches are otherwise stateless: the watcher exists to deliver
4288/// {@link ResourceWatchChangedAction} events. The state carries only the
4289/// descriptor of what is being watched so a re-subscribing client can
4290/// recover the watch configuration after reconnecting.
4291#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
4292#[serde(rename_all = "camelCase")]
4293pub struct ResourceWatchState {
4294    /// The URI being watched. For recursive watches this is the root of the
4295    /// subtree; for non-recursive watches this is the single file or
4296    /// directory.
4297    pub root: Uri,
4298    /// `true` if the watcher reports changes for descendants of `root`;
4299    /// `false` if it only reports changes to `root` itself (and, when
4300    /// `root` is a directory, its direct children).
4301    pub recursive: bool,
4302    /// Optional glob patterns or paths relative to `root` to exclude from
4303    /// change reporting.
4304    #[serde(default, skip_serializing_if = "Option::is_none")]
4305    pub excludes: Option<AnyValue>,
4306    /// Optional glob patterns or paths relative to `root` to restrict
4307    /// change reporting to. Omit to report every change under `root`
4308    /// subject to `excludes`.
4309    #[serde(default, skip_serializing_if = "Option::is_none")]
4310    pub includes: Option<AnyValue>,
4311}
4312
4313/// A single change observed by a resource watcher.
4314#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
4315#[serde(rename_all = "camelCase")]
4316pub struct ResourceChange {
4317    /// The URI of the resource that changed.
4318    pub uri: Uri,
4319    /// The kind of change observed.
4320    pub r#type: ResourceChangeType,
4321}
4322
4323// ─── Customization Enablement Union ───────────────────────────────────────
4324
4325/// A single explicit customization enablement decision.
4326#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
4327#[serde(tag = "kind")]
4328pub enum CustomizationEnablement {
4329    #[serde(rename = "global")]
4330    Global { enabled: bool },
4331    #[serde(rename = "workspace")]
4332    Workspace { uri: Uri, enabled: bool },
4333    #[serde(rename = "session")]
4334    Session { enabled: bool },
4335}
4336
4337/// Raw tool input represented inline or by content reference.
4338#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
4339#[serde(untagged)]
4340pub enum ToolInput {
4341    Inline(String),
4342    ContentRef(ContentRef),
4343}
4344
4345// ─── Discriminated Unions ─────────────────────────────────────────────
4346
4347/// How a chat came into existence.
4348#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
4349#[serde(tag = "kind")]
4350pub enum ChatOrigin {
4351    /// Created directly by a user.
4352    #[serde(rename = "user")]
4353    User,
4354    /// Forked from a specific turn of another chat.
4355    #[serde(rename = "fork")]
4356    Fork {
4357        /// URI of the chat this one was forked from.
4358        chat: Uri,
4359        /// Completed source-turn identifier the fork was taken from.
4360        #[serde(rename = "turnId")]
4361        turn_id: String,
4362    },
4363    /// Independent side conversation created from a specific turn.
4364    #[serde(rename = "sideChat")]
4365    SideChat {
4366        /// URI of the chat that supplied the side-chat context.
4367        chat: Uri,
4368        /// Stable source-turn identifier through which context was supplied.
4369        #[serde(rename = "turnId")]
4370        turn_id: String,
4371        /// Optional immutable selected-text snapshot captured when the side chat was created.
4372        #[serde(default, skip_serializing_if = "Option::is_none")]
4373        selection: Option<SideChatSelection>,
4374    },
4375    /// Spawned by a tool call in another chat.
4376    #[serde(rename = "tool")]
4377    Tool {
4378        /// URI of the chat whose tool call spawned this one.
4379        chat: Uri,
4380        /// Tool call that spawned this chat.
4381        #[serde(rename = "toolCallId")]
4382        tool_call_id: String,
4383    },
4384    /// Unknown or future variant — preserved as raw JSON for round-trip fidelity.
4385    /// Reducers treat this as a no-op.
4386    #[serde(untagged)]
4387    Unknown(serde_json::Value),
4388}
4389
4390/// A single part of a response stream (text, tool call, reasoning, content reference).
4391#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
4392#[serde(tag = "kind")]
4393pub enum ResponsePart {
4394    #[serde(rename = "markdown")]
4395    Markdown(MarkdownResponsePart),
4396    #[serde(rename = "contentRef")]
4397    ContentRef(ResourceResponsePart),
4398    #[serde(rename = "toolCall")]
4399    ToolCall(Box<ToolCallResponsePart>),
4400    #[serde(rename = "reasoning")]
4401    Reasoning(ReasoningResponsePart),
4402    #[serde(rename = "systemNotification")]
4403    SystemNotification(SystemNotificationResponsePart),
4404    #[serde(rename = "inputRequest")]
4405    InputRequest(InputRequestResponsePart),
4406    /// Unknown or future variant — preserved as raw JSON for round-trip fidelity.
4407    /// Reducers treat this as a no-op.
4408    #[serde(untagged)]
4409    Unknown(serde_json::Value),
4410}
4411
4412/// Full tool call lifecycle state.
4413#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
4414#[serde(tag = "status")]
4415pub enum ToolCallState {
4416    #[serde(rename = "streaming")]
4417    Streaming(ToolCallStreamingState),
4418    #[serde(rename = "pending-confirmation")]
4419    PendingConfirmation(ToolCallPendingConfirmationState),
4420    #[serde(rename = "running")]
4421    Running(ToolCallRunningState),
4422    #[serde(rename = "auth-required")]
4423    AuthRequired(Box<ToolCallAuthRequiredState>),
4424    #[serde(rename = "pending-result-confirmation")]
4425    PendingResultConfirmation(ToolCallPendingResultConfirmationState),
4426    #[serde(rename = "completed")]
4427    Completed(ToolCallCompletedState),
4428    #[serde(rename = "cancelled")]
4429    Cancelled(ToolCallCancelledState),
4430    /// Unknown or future variant — preserved as raw JSON for round-trip fidelity.
4431    /// Reducers treat this as a no-op.
4432    #[serde(untagged)]
4433    Unknown(serde_json::Value),
4434}
4435
4436/// A tool call blocked on parameter- or result-confirmation.
4437#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
4438#[serde(tag = "status")]
4439pub enum ToolCallConfirmationState {
4440    #[serde(rename = "pending-confirmation")]
4441    PendingConfirmation(ToolCallPendingConfirmationState),
4442    #[serde(rename = "pending-result-confirmation")]
4443    PendingResultConfirmation(ToolCallPendingResultConfirmationState),
4444    /// Unknown or future variant — preserved as raw JSON for round-trip fidelity.
4445    /// Reducers treat this as a no-op.
4446    #[serde(untagged)]
4447    Unknown(serde_json::Value),
4448}
4449
4450/// Who currently holds a terminal.
4451#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
4452#[serde(tag = "kind")]
4453pub enum TerminalClaim {
4454    #[serde(rename = "client")]
4455    Client(TerminalClientClaim),
4456    #[serde(rename = "session")]
4457    Session(TerminalSessionClaim),
4458    /// Unknown or future variant — preserved as raw JSON for round-trip fidelity.
4459    /// Reducers treat this as a no-op.
4460    #[serde(untagged)]
4461    Unknown(serde_json::Value),
4462}
4463
4464/// A content part within terminal output.
4465#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
4466#[serde(tag = "type")]
4467pub enum TerminalContentPart {
4468    #[serde(rename = "unclassified")]
4469    Unclassified(TerminalUnclassifiedPart),
4470    #[serde(rename = "command")]
4471    Command(TerminalCommandPart),
4472    /// Unknown or future variant — preserved as raw JSON for round-trip fidelity.
4473    /// Reducers treat this as a no-op.
4474    #[serde(untagged)]
4475    Unknown(serde_json::Value),
4476}
4477
4478/// One question within a chat input request.
4479#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
4480#[serde(tag = "kind")]
4481pub enum ChatInputQuestion {
4482    #[serde(rename = "text")]
4483    Text(ChatInputTextQuestion),
4484    #[serde(rename = "number")]
4485    Number(ChatInputNumberQuestion),
4486    #[serde(rename = "integer")]
4487    Integer(ChatInputNumberQuestion),
4488    #[serde(rename = "boolean")]
4489    Boolean(ChatInputBooleanQuestion),
4490    #[serde(rename = "single-select")]
4491    SingleSelect(ChatInputSingleSelectQuestion),
4492    #[serde(rename = "multi-select")]
4493    MultiSelect(ChatInputMultiSelectQuestion),
4494    /// Unknown or future variant — preserved as raw JSON for round-trip fidelity.
4495    /// Reducers treat this as a no-op.
4496    #[serde(untagged)]
4497    Unknown(serde_json::Value),
4498}
4499
4500/// Value captured for one answer.
4501#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
4502#[serde(tag = "kind")]
4503pub enum ChatInputAnswerValue {
4504    #[serde(rename = "text")]
4505    Text(ChatInputTextAnswerValue),
4506    #[serde(rename = "number")]
4507    Number(ChatInputNumberAnswerValue),
4508    #[serde(rename = "boolean")]
4509    Boolean(ChatInputBooleanAnswerValue),
4510    #[serde(rename = "selected")]
4511    Selected(ChatInputSelectedAnswerValue),
4512    #[serde(rename = "selected-many")]
4513    SelectedMany(ChatInputSelectedManyAnswerValue),
4514    /// Unknown or future variant — preserved as raw JSON for round-trip fidelity.
4515    /// Reducers treat this as a no-op.
4516    #[serde(untagged)]
4517    Unknown(serde_json::Value),
4518}
4519
4520/// Draft, submitted, or skipped answer for one question.
4521#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
4522#[serde(tag = "state")]
4523pub enum ChatInputAnswer {
4524    #[serde(rename = "draft")]
4525    Draft(ChatInputAnswered),
4526    #[serde(rename = "submitted")]
4527    Submitted(ChatInputAnswered),
4528    #[serde(rename = "skipped")]
4529    Skipped(ChatInputSkipped),
4530    /// Unknown or future variant — preserved as raw JSON for round-trip fidelity.
4531    /// Reducers treat this as a no-op.
4532    #[serde(untagged)]
4533    Unknown(serde_json::Value),
4534}
4535
4536/// Content block in a tool result.
4537#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
4538#[serde(tag = "type")]
4539pub enum ToolResultContent {
4540    #[serde(rename = "text")]
4541    Text(ToolResultTextContent),
4542    #[serde(rename = "embeddedResource")]
4543    EmbeddedResource(ToolResultEmbeddedResourceContent),
4544    #[serde(rename = "resource")]
4545    Resource(ToolResultResourceContent),
4546    #[serde(rename = "fileEdit")]
4547    FileEdit(ToolResultFileEditContent),
4548    #[serde(rename = "terminal")]
4549    Terminal(ToolResultTerminalContent),
4550    #[serde(rename = "subagent")]
4551    Subagent(ToolResultSubagentContent),
4552    /// Unknown or future variant — preserved as raw JSON for round-trip fidelity.
4553    /// Reducers treat this as a no-op.
4554    #[serde(untagged)]
4555    Unknown(serde_json::Value),
4556}
4557
4558/// An attachment associated with a `Message`.
4559#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
4560#[serde(tag = "type")]
4561pub enum MessageAttachment {
4562    #[serde(rename = "simple")]
4563    Simple(SimpleMessageAttachment),
4564    #[serde(rename = "embeddedResource")]
4565    EmbeddedResource(MessageEmbeddedResourceAttachment),
4566    #[serde(rename = "resource")]
4567    Resource(MessageResourceAttachment),
4568    #[serde(rename = "annotations")]
4569    Annotations(MessageAnnotationsAttachment),
4570    #[serde(rename = "chat")]
4571    Chat(MessageChatAttachment),
4572    /// Unknown or future variant — preserved as raw JSON for round-trip fidelity.
4573    /// Reducers treat this as a no-op.
4574    #[serde(untagged)]
4575    Unknown(serde_json::Value),
4576}
4577
4578/// A top-level customization (plugin, directory, or bare MCP server).
4579#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
4580#[serde(tag = "type")]
4581pub enum Customization {
4582    #[serde(rename = "plugin")]
4583    Plugin(PluginCustomization),
4584    #[serde(rename = "directory")]
4585    Directory(DirectoryCustomization),
4586    #[serde(rename = "mcpServer")]
4587    McpServer(Box<McpServerCustomization>),
4588    /// Unknown or future variant — preserved as raw JSON for round-trip fidelity.
4589    /// Reducers treat this as a no-op.
4590    #[serde(untagged)]
4591    Unknown(serde_json::Value),
4592}
4593
4594/// A child customization living inside a plugin or directory.
4595#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
4596#[serde(tag = "type")]
4597pub enum ChildCustomization {
4598    #[serde(rename = "agent")]
4599    Agent(AgentCustomization),
4600    #[serde(rename = "skill")]
4601    Skill(SkillCustomization),
4602    #[serde(rename = "prompt")]
4603    Prompt(PromptCustomization),
4604    #[serde(rename = "rule")]
4605    Rule(RuleCustomization),
4606    #[serde(rename = "hook")]
4607    Hook(HookCustomization),
4608    #[serde(rename = "mcpServer")]
4609    McpServer(Box<McpServerCustomization>),
4610    /// Unknown or future variant — preserved as raw JSON for round-trip fidelity.
4611    /// Reducers treat this as a no-op.
4612    #[serde(untagged)]
4613    Unknown(serde_json::Value),
4614}
4615
4616/// Host-reported load state for a container customization.
4617#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
4618#[serde(tag = "kind")]
4619pub enum CustomizationLoadState {
4620    #[serde(rename = "loading")]
4621    Loading(CustomizationLoadingState),
4622    #[serde(rename = "loaded")]
4623    Loaded(CustomizationLoadedState),
4624    #[serde(rename = "degraded")]
4625    Degraded(CustomizationDegradedState),
4626    #[serde(rename = "error")]
4627    Error(CustomizationErrorState),
4628    /// Unknown or future variant — preserved as raw JSON for round-trip fidelity.
4629    /// Reducers treat this as a no-op.
4630    #[serde(untagged)]
4631    Unknown(serde_json::Value),
4632}
4633
4634/// Discriminated lifecycle status of an MCP server customization.
4635#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
4636#[serde(tag = "kind")]
4637pub enum McpServerState {
4638    #[serde(rename = "starting")]
4639    Starting(McpServerStartingState),
4640    #[serde(rename = "ready")]
4641    Ready(McpServerReadyState),
4642    #[serde(rename = "authRequired")]
4643    AuthRequired(Box<McpServerAuthRequiredState>),
4644    #[serde(rename = "error")]
4645    Error(McpServerErrorState),
4646    #[serde(rename = "stopped")]
4647    Stopped(McpServerStoppedState),
4648    /// Unknown or future variant — preserved as raw JSON for round-trip fidelity.
4649    /// Reducers treat this as a no-op.
4650    #[serde(untagged)]
4651    Unknown(serde_json::Value),
4652}
4653
4654/// Reference to the contributor of the tool being called.
4655#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
4656#[serde(tag = "kind")]
4657pub enum ToolCallContributor {
4658    #[serde(rename = "client")]
4659    Client(ToolCallClientContributor),
4660    #[serde(rename = "mcp")]
4661    Mcp(ToolCallMcpContributor),
4662    /// Unknown or future variant — preserved as raw JSON for round-trip fidelity.
4663    /// Reducers treat this as a no-op.
4664    #[serde(untagged)]
4665    Unknown(serde_json::Value),
4666}
4667
4668/// Asynchronous model-judge confirmation rationale.
4669#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
4670#[serde(tag = "status")]
4671pub enum ToolCallRiskAssessment {
4672    #[serde(rename = "loading")]
4673    Loading(ToolCallRiskAssessmentLoadingState),
4674    #[serde(rename = "complete")]
4675    Complete(ToolCallRiskAssessmentCompleteState),
4676    /// Unknown or future variant — preserved as raw JSON for round-trip fidelity.
4677    /// Reducers treat this as a no-op.
4678    #[serde(untagged)]
4679    Unknown(serde_json::Value),
4680}
4681
4682/// One outstanding piece of input a session is blocked on, aggregated across all chats.
4683#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
4684#[serde(tag = "kind")]
4685pub enum SessionInputRequest {
4686    #[serde(rename = "chatInput")]
4687    ChatInput(SessionChatInputRequest),
4688    #[serde(rename = "toolConfirmation")]
4689    ToolConfirmation(SessionToolConfirmationRequest),
4690    #[serde(rename = "toolClientExecution")]
4691    ToolClientExecution(SessionToolClientExecutionRequest),
4692    #[serde(rename = "toolAuthentication")]
4693    ToolAuthentication(SessionToolAuthenticationRequest),
4694    /// Unknown or future variant — preserved as raw JSON for round-trip fidelity.
4695    /// Reducers treat this as a no-op.
4696    #[serde(untagged)]
4697    Unknown(serde_json::Value),
4698}
4699
4700/// The state payload of a snapshot — root, session, chat, terminal,
4701/// changeset, resource-watch, annotations, or content state.
4702///
4703/// Deserialized by trying session first (has required `lifecycle`), then
4704/// chat (has required `turns`), then terminal (has required `content`),
4705/// then changeset (has required `status` and `files`), then resource-watch
4706/// (has required `root` and `recursive`), then annotations (has required
4707/// `annotations`), then root.
4708#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
4709#[serde(untagged)]
4710pub enum SnapshotState {
4711    Session(Box<SessionState>),
4712    Chat(Box<ChatState>),
4713    Terminal(Box<TerminalState>),
4714    Changeset(Box<ChangesetState>),
4715    ResourceWatch(Box<ResourceWatchState>),
4716    Annotations(Box<AnnotationsState>),
4717    Root(Box<RootState>),
4718}