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