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