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