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