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