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