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