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