Skip to main content

ahp_types/
commands.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#[allow(unused_imports)]
15use crate::actions::{ActionEnvelope, StateAction};
16#[allow(unused_imports)]
17use crate::state::{
18    AgentSelection, ContentRef, Message, MessageAttachment, ModelSelection, SessionActiveClient,
19    SessionConfigSchema, SessionSummary, Snapshot, SnapshotState, TelemetryCapabilities,
20    TerminalClaim, TextRange, Turn,
21};
22
23// ─── Enums ────────────────────────────────────────────────────────────
24
25/// Discriminant for reconnect result types.
26#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
27pub enum ReconnectResultType {
28    #[serde(rename = "replay")]
29    Replay,
30    #[serde(rename = "snapshot")]
31    Snapshot,
32}
33
34/// Encoding of fetched content data.
35#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
36pub enum ContentEncoding {
37    #[serde(rename = "base64")]
38    Base64,
39    #[serde(rename = "utf-8")]
40    Utf8,
41}
42
43/// The kind of completion items being requested.
44#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
45pub enum CompletionItemKind {
46    /// Completions for the text of a {@link Message} the user is composing.
47    /// Each returned item carries an attachment that gets associated with the
48    /// message when accepted.
49    #[serde(rename = "userMessage")]
50    UserMessage,
51}
52
53/// Discriminant for {@link ResourceResolveResult.type}.
54#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
55pub enum ResourceType {
56    #[serde(rename = "file")]
57    File,
58    #[serde(rename = "directory")]
59    Directory,
60    #[serde(rename = "symlink")]
61    Symlink,
62}
63
64/// How {@link ResourceWriteParams.data} is placed within the target file.
65///
66/// Each mode interprets {@link ResourceWriteParams.position} differently:
67///
68/// - `truncate` (default): rooted at the **start** of the file. The file is
69///   truncated at `position` (0 by default) and `data` is written from that
70///   offset, so the resulting file is `existing[0..position] + data`. With
71///   `position` omitted this is a full overwrite.
72/// - `append`: rooted at the **end** of the file. `position` counts bytes
73///   backwards from EOF, so `position: 0` (the default) writes at EOF —
74///   POSIX append — and `position: 5` inserts `data` 5 bytes before the
75///   current EOF, shifting those trailing 5 bytes after the inserted region.
76///   The server MUST evaluate the effective EOF and write atomically with
77///   respect to other appenders so concurrent `append` writes do not
78///   clobber each other.
79/// - `insert`: rooted at the **start** of the file. `position` (0 by default)
80///   is the byte offset at which `data` is spliced in; bytes at or after
81///   `position` are shifted right by `data.length`. `insert` always grows
82///   the file — use `truncate` to overwrite bytes in place.
83#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
84pub enum ResourceWriteMode {
85    #[serde(rename = "truncate")]
86    Truncate,
87    #[serde(rename = "append")]
88    Append,
89    #[serde(rename = "insert")]
90    Insert,
91}
92
93// ─── Command Payloads ─────────────────────────────────────────────────
94
95/// Establishes a new connection and negotiates the protocol version.
96/// This MUST be the first message sent by the client.
97#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
98#[serde(rename_all = "camelCase")]
99pub struct InitializeParams {
100    /// Channel URI this command targets.
101    pub channel: Uri,
102    /// Protocol versions the client is willing to speak, ordered from most
103    /// preferred to least preferred. Each entry is a [SemVer](https://semver.org)
104    /// `MAJOR.MINOR.PATCH` string (e.g. `"0.1.0"`).
105    ///
106    /// The server selects one entry and returns it as `InitializeResult.protocolVersion`.
107    /// If the server cannot speak any of the offered versions, it MUST return
108    /// error code `-32005` (`UnsupportedProtocolVersion`).
109    pub protocol_versions: Vec<String>,
110    /// Unique client identifier
111    pub client_id: String,
112    /// Optional identity of the client implementation (name and version).
113    /// Informational only — see {@link Implementation} for how it may and may not
114    /// be used. Distinct from {@link InitializeParams.clientId | `clientId`},
115    /// which is an opaque per-connection identifier used for reconnection, not a
116    /// human-readable implementation name.
117    #[serde(default, skip_serializing_if = "Option::is_none")]
118    pub client_info: Option<Implementation>,
119    /// URIs to subscribe to during handshake
120    #[serde(default, skip_serializing_if = "Option::is_none")]
121    pub initial_subscriptions: Option<Vec<Uri>>,
122    /// IETF BCP 47 language tag indicating the client's preferred locale
123    /// (e.g. `"en-US"`, `"ja"`). The server SHOULD use this to localise
124    /// user-facing strings such as confirmation option labels.
125    #[serde(default, skip_serializing_if = "Option::is_none")]
126    pub locale: Option<String>,
127    /// Optional client capability declarations.
128    ///
129    /// Servers SHOULD only advertise features whose corresponding client
130    /// capability is set here. Absent means "not declared" — the server
131    /// MUST assume the client does not support the feature.
132    #[serde(default, skip_serializing_if = "Option::is_none")]
133    pub capabilities: Option<ClientCapabilities>,
134}
135
136/// Result of the `initialize` command.
137///
138/// `protocolVersion` is the version the server has selected from the client's
139/// `protocolVersions` list. The client and server MUST use this version for
140/// the rest of the connection. If the server cannot speak any of the offered
141/// versions it MUST return error code `-32005` (`UnsupportedProtocolVersion`)
142/// instead of a result.
143#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
144#[serde(rename_all = "camelCase")]
145pub struct InitializeResult {
146    /// Protocol version selected by the server. MUST be one of the entries in
147    /// `InitializeParams.protocolVersions`. Formatted as a [SemVer](https://semver.org)
148    /// `MAJOR.MINOR.PATCH` string (e.g. `"0.1.0"`).
149    pub protocol_version: String,
150    /// Current server sequence number
151    pub server_seq: i64,
152    /// Optional identity of the server implementation (name and version).
153    /// Informational only — see {@link Implementation} for how it may and may not
154    /// be used. Whereas {@link InitializeResult.protocolVersion | `protocolVersion`}
155    /// identifies the negotiated protocol, `serverInfo` identifies the host
156    /// software behind it.
157    #[serde(default, skip_serializing_if = "Option::is_none")]
158    pub server_info: Option<Implementation>,
159    /// Snapshots for each `initialSubscriptions` URI
160    pub snapshots: Vec<Snapshot>,
161    /// Suggested default directory for remote filesystem browsing
162    #[serde(default, skip_serializing_if = "Option::is_none")]
163    pub default_directory: Option<Uri>,
164    /// Characters that, when typed in a {@link Message} input, SHOULD cause
165    /// the client to issue a `completions` request with
166    /// {@link CompletionItemKind.UserMessage}. Typically includes characters like
167    /// `'@'` or `'/'`.
168    #[serde(default, skip_serializing_if = "Option::is_none")]
169    pub completion_trigger_characters: Option<Vec<String>>,
170    /// Prefix that the host recognizes at the start of a user {@link Message.text}
171    /// as a shorthand for executing the remainder as a terminal command. Currently
172    /// the standardized convention is `"!"`; absence means the host does not
173    /// support command prefixes.
174    #[serde(default, skip_serializing_if = "Option::is_none")]
175    pub terminal_command_prefix: Option<String>,
176    /// OTLP telemetry channels the host emits, if any. Each populated field is
177    /// either a literal `ahp-otlp:` channel URI or an RFC 6570 URI template a
178    /// client expands before subscribing (currently only the `logs` channel
179    /// defines a template variable, `{level}`, for subscriber-side severity
180    /// filtering). Clients MAY ignore signals they cannot process.
181    #[serde(default, skip_serializing_if = "Option::is_none")]
182    pub telemetry: Option<TelemetryCapabilities>,
183}
184
185/// Optional capabilities a client declares during `initialize`.
186///
187/// Each field is a presence flag: an empty object `{}` means "supported",
188/// absence means "not supported". Sub-fields on individual capabilities
189/// are reserved for future per-capability options.
190#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Default)]
191#[serde(rename_all = "camelCase")]
192pub struct ClientCapabilities {
193    /// Client can render
194    /// [MCP Apps](https://github.com/modelcontextprotocol/ext-apps) — i.e.
195    /// it can host the View sandbox, run the `ui/*` protocol against it,
196    /// and forward `mcp://`-channel traffic on the App's behalf.
197    ///
198    /// Hosts SHOULD only populate
199    /// {@link McpServerCustomization.mcpApp | `McpServerCustomization.mcpApp`}
200    /// (and expose the corresponding
201    /// {@link McpServerCustomization.channel | `mcp://` channel}) when this
202    /// capability is declared. Clients that omit it MUST treat
203    /// App-bearing tool calls as ordinary MCP tool calls.
204    #[serde(default, skip_serializing_if = "Option::is_none")]
205    pub mcp_apps: Option<JsonObject>,
206}
207
208/// Identifies a protocol implementation — the software (and build) on one end
209/// of the connection, as distinct from the {@link AgentInfo | agent persona} it
210/// hosts. Carried as {@link InitializeParams.clientInfo | `clientInfo`} on the
211/// client side and {@link InitializeResult.serverInfo | `serverInfo`} on the
212/// server side, mirroring LSP's `clientInfo`/`serverInfo` and MCP's
213/// `Implementation`.
214///
215/// This is **informational only**: it exists for logging, telemetry, an
216/// about/status affordance, and — as a last resort — a known-issue workaround
217/// for a specific buggy build. It is **not** a feature-detection mechanism.
218/// Feature availability stays with the capability model
219/// ({@link ClientCapabilities} and the various `*.capabilities` declarations);
220/// implementations SHOULD NOT gate protocol behaviour on parsing
221/// {@link Implementation.version | `version`}.
222#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
223#[serde(rename_all = "camelCase")]
224pub struct Implementation {
225    /// Implementation name, e.g. a product or package identifier.
226    pub name: String,
227    /// Implementation version. A [SemVer](https://semver.org) string is
228    /// recommended but not required.
229    #[serde(default, skip_serializing_if = "Option::is_none")]
230    pub version: Option<String>,
231    /// Optional human-readable display name.
232    #[serde(default, skip_serializing_if = "Option::is_none")]
233    pub title: Option<String>,
234}
235
236/// Re-establishes a dropped connection. The server replays missed actions or
237/// provides fresh snapshots.
238#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
239#[serde(rename_all = "camelCase")]
240pub struct ReconnectParams {
241    /// Channel URI this command targets.
242    pub channel: Uri,
243    /// Client identifier from the original connection
244    pub client_id: String,
245    /// Last `serverSeq` the client received
246    pub last_seen_server_seq: i64,
247    /// URIs the client was subscribed to
248    pub subscriptions: Vec<Uri>,
249}
250
251/// Reconnect result when the server can replay from the requested sequence.
252///
253/// The server MUST include all replayed data in the response.
254#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
255#[serde(rename_all = "camelCase")]
256pub struct ReconnectReplayResult {
257    /// Missed action envelopes since `lastSeenServerSeq`
258    pub actions: Vec<ActionEnvelope>,
259    /// URIs from `ReconnectParams.subscriptions` that the server cannot resume.
260    /// This includes resources that no longer exist (e.g. disposed sessions or
261    /// terminals) as well as resources the client is no longer permitted to
262    /// observe. Clients SHOULD drop these from their local subscription set.
263    pub missing: Vec<Uri>,
264}
265
266/// Reconnect result when the gap exceeds the replay buffer.
267#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
268#[serde(rename_all = "camelCase")]
269pub struct ReconnectSnapshotResult {
270    /// Fresh snapshots for each subscription
271    pub snapshots: Vec<Snapshot>,
272}
273
274/// Subscribe to a URI-identified channel.
275///
276/// A channel MAY have state associated with it (e.g. root, sessions,
277/// terminals) or be stateless (pure pub/sub for streaming data). For
278/// state-bearing channels the result includes a snapshot; for stateless
279/// channels `snapshot` is omitted.
280#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
281#[serde(rename_all = "camelCase")]
282pub struct SubscribeParams {
283    /// Channel URI this command targets.
284    pub channel: Uri,
285    /// Optional delivery preferences for this subscription.
286    ///
287    /// Servers MAY use these preferences to buffer and coalesce high-frequency
288    /// updates while preserving the same reduced state. Omit this field for the
289    /// server's default delivery behavior.
290    #[serde(default, skip_serializing_if = "Option::is_none")]
291    pub delivery: Option<SubscriptionDeliveryOptions>,
292    /// Optional client-requested shape for the returned snapshot.
293    ///
294    /// Servers that do not understand a requested view ignore it and return their
295    /// default snapshot. Clients MUST tolerate receiving more state than requested.
296    #[serde(default, skip_serializing_if = "Option::is_none")]
297    pub view: Option<SubscribeView>,
298}
299
300impl SubscribeParams {
301    /// Create subscribe params with default delivery behavior.
302    pub fn new(channel: impl Into<Uri>) -> Self {
303        Self {
304            channel: channel.into(),
305            delivery: None,
306            view: None,
307        }
308    }
309
310    /// Create subscribe params with advisory delivery preferences.
311    pub fn with_delivery(channel: impl Into<Uri>, delivery: SubscriptionDeliveryOptions) -> Self {
312        Self {
313            channel: channel.into(),
314            delivery: Some(delivery),
315            view: None,
316        }
317    }
318
319    /// Create subscribe params with snapshot-shaping preferences.
320    pub fn with_view(channel: impl Into<Uri>, view: SubscribeView) -> Self {
321        Self {
322            channel: channel.into(),
323            delivery: None,
324            view: Some(view),
325        }
326    }
327}
328
329/// Optional client-requested shape for a subscription snapshot.
330#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Default)]
331#[serde(rename_all = "camelCase")]
332pub struct SubscribeView {
333    /// Advisory number of most-recent completed turns to expose in a chat
334    /// snapshot.
335    ///
336    /// Servers MAY return more or fewer turns than requested. When omitted, the
337    /// host MUST return all retained turns. When older turns remain available, the
338    /// returned {@link ChatState} carries `turnsNextCursor`; clients pass that
339    /// cursor to `fetchTurns` to ask the host to page more turns into the chat
340    /// state.
341    #[serde(default, skip_serializing_if = "Option::is_none")]
342    pub turns: Option<i64>,
343}
344
345/// Advisory delivery preferences for a single subscription.
346#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Default)]
347#[serde(rename_all = "camelCase")]
348pub struct SubscriptionDeliveryOptions {
349    /// Maximum time, in milliseconds, that the server may intentionally delay
350    /// delivery while buffering/coalescing updates for this subscription.
351    ///
352    /// A value of `0` requests immediate delivery with no intentional coalescing.
353    #[serde(default, skip_serializing_if = "Option::is_none")]
354    pub max_latency_ms: Option<i64>,
355}
356
357/// Result of the `subscribe` command.
358///
359/// `snapshot` is present when the subscribed channel has associated state, and
360/// absent for stateless channels.
361#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Default)]
362#[serde(rename_all = "camelCase")]
363pub struct SubscribeResult {
364    /// Snapshot of the subscribed channel's state (omitted for stateless channels)
365    #[serde(default, skip_serializing_if = "Option::is_none")]
366    pub snapshot: Option<Snapshot>,
367}
368
369/// Creates a new session with the specified agent provider.
370///
371/// If the session URI already exists, the server MUST return an error with code
372/// `-32003` (`SessionAlreadyExists`).
373///
374/// After creation, the client should subscribe to the session URI to receive state
375/// updates. The server also broadcasts a `root/sessionAdded` notification to all
376/// clients.
377#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
378#[serde(rename_all = "camelCase")]
379pub struct SessionForkSource {
380    /// URI of the existing session to fork from
381    pub session: Uri,
382    /// Turn ID in the source session; content up to and including this turn's response is copied
383    pub turn_id: String,
384}
385
386#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
387#[serde(rename_all = "camelCase")]
388pub struct CreateSessionParams {
389    /// Channel URI this command targets.
390    pub channel: Uri,
391    /// Agent provider ID
392    #[serde(default, skip_serializing_if = "Option::is_none")]
393    pub provider: Option<String>,
394    /// Working directory for the session
395    #[serde(default, skip_serializing_if = "Option::is_none")]
396    pub working_directory: Option<Uri>,
397    /// Fork from an existing session. The new session is populated with content
398    /// from the source session up to and including the specified turn's response.
399    #[serde(default, skip_serializing_if = "Option::is_none")]
400    pub fork: Option<SessionForkSource>,
401    /// Agent-specific configuration values collected via `resolveSessionConfig`.
402    /// Keys and values correspond to the schema returned by the server.
403    #[serde(default, skip_serializing_if = "Option::is_none")]
404    pub config: Option<JsonObject>,
405    /// Eagerly claim an active client role for the new session.
406    ///
407    /// When provided, the server initializes the session with this client as an
408    /// active client, equivalent to dispatching a `session/activeClientSet`
409    /// action immediately after creation. The `clientId` MUST match the
410    /// `clientId` the creating client supplied in `initialize`.
411    #[serde(default, skip_serializing_if = "Option::is_none")]
412    pub active_client: Option<SessionActiveClient>,
413    /// Opt-in progress token. When set, the client is offering to receive
414    /// `progress` notifications (see `ProgressParams`) for any long-running work
415    /// the server does to bring this session up — most notably the lazy,
416    /// first-use download of the provider's native SDK. The server echoes this
417    /// exact token on every `progress` frame so the client can correlate it to
418    /// this `createSession` call (and the UI awaiting it).
419    ///
420    /// The token MUST be unique across the client's active requests. The server
421    /// MAY ignore it (e.g. when nothing long-running is needed), in which case no
422    /// `progress` notifications are emitted.
423    #[serde(default, skip_serializing_if = "Option::is_none")]
424    pub progress_token: Option<String>,
425}
426
427/// Disposes a session and cleans up server-side resources.
428///
429/// The server broadcasts a `root/sessionRemoved` notification to all clients.
430#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
431#[serde(rename_all = "camelCase")]
432pub struct DisposeSessionParams {
433    /// Channel URI this command targets.
434    pub channel: Uri,
435}
436
437/// Identifies a source chat and turn to fork from.
438#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
439#[serde(rename_all = "camelCase")]
440pub struct ChatForkSource {
441    /// URI of the existing chat to fork from
442    pub chat: Uri,
443    /// Turn ID in the source chat; content up to and including this turn's response is copied
444    pub turn_id: String,
445}
446
447/// Creates a new chat within a session.
448#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
449#[serde(rename_all = "camelCase")]
450pub struct CreateChatParams {
451    /// Channel URI this command targets.
452    pub channel: Uri,
453    /// Chat URI (client-chosen, e.g. `ahp-chat:/<uuid>`).
454    pub chat: Uri,
455    /// Optional initial message for the new chat.
456    #[serde(default, skip_serializing_if = "Option::is_none")]
457    pub initial_message: Option<Message>,
458    /// Optional source chat and turn to fork from.
459    #[serde(default, skip_serializing_if = "Option::is_none")]
460    pub source: Option<ChatForkSource>,
461}
462
463/// Disposes a chat and cleans up server-side resources.
464#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
465#[serde(rename_all = "camelCase")]
466pub struct DisposeChatParams {
467    /// Channel URI this command targets.
468    pub channel: Uri,
469}
470
471/// Returns a list of session summaries. Used to populate session lists and sidebars.
472///
473/// The session list is **not** part of the state tree because it can be arbitrarily
474/// large. Clients fetch it imperatively and maintain a local cache updated by
475/// `root/sessionAdded` and `root/sessionRemoved` notifications.
476///
477/// A large catalogue can be fetched incrementally via the {@link PaginatedParams}
478/// `limit`/`cursor` inputs (see that type for the full pagination contract). The
479/// server SHOULD return most-recently-modified entries first, so the first page
480/// is the immediately useful one. The `root/session*` notifications keep an
481/// already-fetched page live; pagination governs only the initial and backfill
482/// fetches.
483#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
484#[serde(rename_all = "camelCase")]
485pub struct ListSessionsParams {
486    /// Channel URI this command targets.
487    pub channel: Uri,
488    /// Maximum number of entries to return in this page. The server SHOULD respect
489    /// this bound but MAY return fewer entries and MAY impose its own upper cap.
490    /// Omit to let the server choose the page size.
491    #[serde(default, skip_serializing_if = "Option::is_none")]
492    pub limit: Option<i64>,
493    /// Opaque pagination cursor from a previous {@link PaginatedResult.nextCursor}.
494    /// Omit to fetch the first page. Cursors are server-defined and MUST be treated
495    /// as opaque — do not parse, modify, or persist them across connections. An
496    /// unrecognised cursor SHOULD be rejected with an `InvalidParams` error.
497    #[serde(default, skip_serializing_if = "Option::is_none")]
498    pub cursor: Option<String>,
499}
500
501/// Result of the `listSessions` command.
502#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
503#[serde(rename_all = "camelCase")]
504pub struct ListSessionsResult {
505    /// Opaque cursor for the next page. Present when more entries exist beyond the
506    /// returned page; absent signals the end of the collection. Pass it back as
507    /// {@link PaginatedParams.cursor} to fetch the following page.
508    #[serde(default, skip_serializing_if = "Option::is_none")]
509    pub next_cursor: Option<String>,
510    /// The list of session summaries. The server SHOULD order them
511    /// most-recently-modified first.
512    pub items: Vec<SessionSummary>,
513}
514
515/// Reads the content of a resource by URI.
516///
517/// Content references keep the state tree small by storing large data (images,
518/// long tool outputs) by reference rather than inline.
519///
520/// Binary content (images, etc.) MUST use `base64` encoding. Text content MAY
521/// use `utf-8` encoding.
522///
523/// Like all `resource*` methods, `resourceRead` is symmetrical and MAY be
524/// sent in either direction. Hosts use it to fetch content from a
525/// client-published URI (e.g. `virtual://my-client/...` plugins); clients
526/// use it to read host-side files. The receiver enforces access via the
527/// same permission/`resourceRequest` flow regardless of which peer initiated.
528#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
529#[serde(rename_all = "camelCase")]
530pub struct ResourceReadParams {
531    /// Channel URI this command targets.
532    pub channel: Uri,
533    /// Content URI from a `ContentRef`
534    pub uri: String,
535    /// Preferred encoding for the returned data (default: server-chosen)
536    #[serde(default, skip_serializing_if = "Option::is_none")]
537    pub encoding: Option<ContentEncoding>,
538}
539
540/// Result of the `resourceRead` command.
541///
542/// The server SHOULD honor the `encoding` requested in the params. If the
543/// server cannot provide the requested encoding, it MUST fall back to either
544/// `base64` or `utf-8`.
545#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
546#[serde(rename_all = "camelCase")]
547pub struct ResourceReadResult {
548    /// Content encoded as a string
549    pub data: String,
550    /// How `data` is encoded
551    pub encoding: ContentEncoding,
552    /// Content type (e.g. `"image/png"`, `"text/plain"`)
553    #[serde(default, skip_serializing_if = "Option::is_none")]
554    pub content_type: Option<String>,
555}
556
557/// Writes content to a file on the server's filesystem.
558///
559/// Binary content (images, etc.) MUST use `base64` encoding. Text content MAY
560/// use `utf-8` encoding.
561///
562/// If the file does not exist, it is created. If the file already exists, the
563/// effect on existing bytes depends on {@link ResourceWriteParams.mode}:
564/// `truncate` (default) overwrites from the chosen offset onward, `append`
565/// preserves all existing bytes and adds `data` at a position rooted at EOF,
566/// and `insert` preserves all existing bytes and splices `data` in at an
567/// offset rooted at the start of the file.
568///
569/// Like all `resource*` methods, `resourceWrite` is symmetrical and MAY be
570/// sent in either direction.
571#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
572#[serde(rename_all = "camelCase")]
573pub struct ResourceWriteParams {
574    /// Channel URI this command targets.
575    pub channel: Uri,
576    /// Target file URI on the server filesystem
577    pub uri: Uri,
578    /// Content encoded as a string
579    pub data: String,
580    /// How `data` is encoded
581    pub encoding: ContentEncoding,
582    /// Content type (e.g. `"text/plain"`, `"image/png"`)
583    #[serde(default, skip_serializing_if = "Option::is_none")]
584    pub content_type: Option<String>,
585    /// If `true`, the server MUST fail if the file already exists instead of
586    /// overwriting it. Useful for safe creation of new files.
587    #[serde(default, skip_serializing_if = "Option::is_none")]
588    pub create_only: Option<bool>,
589    /// How `data` is placed within the target file. Defaults to `'truncate'`
590    /// (full overwrite) when omitted. See {@link ResourceWriteMode} for the
591    /// meaning of each mode and how it interprets {@link position}.
592    #[serde(default, skip_serializing_if = "Option::is_none")]
593    pub mode: Option<ResourceWriteMode>,
594    /// Byte offset interpreted according to {@link mode}. Defaults to `0`.
595    /// - `truncate`: offset from the start of the file at which to truncate
596    ///   before writing.
597    /// - `append`: bytes back from EOF at which to insert `data`.
598    /// - `insert`: offset from the start of the file at which to splice in
599    ///   `data`.
600    #[serde(default, skip_serializing_if = "Option::is_none")]
601    pub position: Option<i64>,
602    /// Optimistic-concurrency token previously returned by
603    /// {@link ResourceResolveResult.etag}. When set, the server MUST fail with
604    /// `Conflict` if the current `etag` does not match — preventing lost
605    /// updates between a `resourceResolve` and a subsequent `resourceWrite`.
606    #[serde(default, skip_serializing_if = "Option::is_none")]
607    pub if_match: Option<String>,
608}
609
610/// Result of the `resourceWrite` command.
611///
612/// An empty object on success.
613#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
614#[serde(rename_all = "camelCase")]
615pub struct ResourceWriteResult {}
616
617/// Lists directory entries at a file URI on the server's filesystem.
618///
619/// This is intended for remote folder pickers and similar UI that needs to let
620/// users navigate the server's local filesystem.
621///
622/// The server MUST return success only if the target exists and is a directory.
623/// If the target does not exist, is not a directory, or cannot be accessed, the
624/// server MUST return a JSON-RPC error.
625///
626/// Like all `resource*` methods, `resourceList` is symmetrical and MAY be
627/// sent in either direction.
628#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
629#[serde(rename_all = "camelCase")]
630pub struct ResourceListParams {
631    /// Channel URI this command targets.
632    pub channel: Uri,
633    /// Directory URI on the server filesystem
634    pub uri: Uri,
635}
636
637/// Result of the `resourceList` command.
638#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
639#[serde(rename_all = "camelCase")]
640pub struct ResourceListResult {
641    /// Entries directly contained in the requested directory
642    pub entries: Vec<DirectoryEntry>,
643}
644
645/// Directory entry returned by `resourceList`.
646#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
647#[serde(rename_all = "camelCase")]
648pub struct DirectoryEntry {
649    /// Base name of the entry
650    pub name: String,
651    /// Whether the entry is a file or directory
652    pub r#type: String,
653}
654
655/// Copies a resource from one URI to another on the server's filesystem.
656///
657/// If the destination already exists, it is overwritten unless `failIfExists`
658/// is set.
659///
660/// Like all `resource*` methods, `resourceCopy` is symmetrical and MAY be
661/// sent in either direction.
662#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
663#[serde(rename_all = "camelCase")]
664pub struct ResourceCopyParams {
665    /// Channel URI this command targets.
666    pub channel: Uri,
667    /// Source URI to copy from
668    pub source: Uri,
669    /// Destination URI to copy to
670    pub destination: Uri,
671    /// If `true`, the server MUST fail if the destination already exists instead
672    /// of overwriting it.
673    #[serde(default, skip_serializing_if = "Option::is_none")]
674    pub fail_if_exists: Option<bool>,
675}
676
677/// Result of the `resourceCopy` command.
678///
679/// An empty object on success.
680#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
681#[serde(rename_all = "camelCase")]
682pub struct ResourceCopyResult {}
683
684/// Deletes a resource at a URI on the server's filesystem.
685///
686/// Like all `resource*` methods, `resourceDelete` is symmetrical and MAY be
687/// sent in either direction.
688#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
689#[serde(rename_all = "camelCase")]
690pub struct ResourceDeleteParams {
691    /// Channel URI this command targets.
692    pub channel: Uri,
693    /// URI of the resource to delete
694    pub uri: Uri,
695    /// If `true` and the target is a directory, delete it and all its contents
696    /// recursively. If `false` (default), deleting a non-empty directory MUST fail.
697    #[serde(default, skip_serializing_if = "Option::is_none")]
698    pub recursive: Option<bool>,
699}
700
701/// Result of the `resourceDelete` command.
702///
703/// An empty object on success.
704#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
705#[serde(rename_all = "camelCase")]
706pub struct ResourceDeleteResult {}
707
708/// Moves (renames) a resource from one URI to another on the server's filesystem.
709///
710/// If the destination already exists, it is overwritten unless `failIfExists`
711/// is set.
712///
713/// Like all `resource*` methods, `resourceMove` is symmetrical and MAY be
714/// sent in either direction.
715#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
716#[serde(rename_all = "camelCase")]
717pub struct ResourceMoveParams {
718    /// Channel URI this command targets.
719    pub channel: Uri,
720    /// Source URI to move from
721    pub source: Uri,
722    /// Destination URI to move to
723    pub destination: Uri,
724    /// If `true`, the server MUST fail if the destination already exists instead
725    /// of overwriting it.
726    #[serde(default, skip_serializing_if = "Option::is_none")]
727    pub fail_if_exists: Option<bool>,
728}
729
730/// Result of the `resourceMove` command.
731///
732/// An empty object on success.
733#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
734#[serde(rename_all = "camelCase")]
735pub struct ResourceMoveResult {}
736
737/// Resolves a resource — the combination of POSIX `stat` and `realpath`.
738///
739/// `resourceResolve` returns metadata about the resource together with its
740/// canonical URI after symlink resolution. Use this in place of any
741/// `resourceExists` shim: a missing resource MUST surface as a `NotFound`
742/// JSON-RPC error rather than a success with a sentinel value. Callers that
743/// truly need a boolean check should attempt `resourceResolve` and treat
744/// `NotFound` as "does not exist".
745///
746/// Like all `resource*` methods, `resourceResolve` is symmetrical and MAY be
747/// sent in either direction.
748#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
749#[serde(rename_all = "camelCase")]
750pub struct ResourceResolveParams {
751    /// Channel URI this command targets.
752    pub channel: Uri,
753    /// URI to resolve
754    pub uri: Uri,
755    /// When `true` (default), follow symlinks and report the metadata of the
756    /// link target — and set `uri` in the result to the canonical (realpath)
757    /// URI. When `false`, stat the link itself (lstat semantics) and report
758    /// `type: 'symlink'`.
759    #[serde(default, skip_serializing_if = "Option::is_none")]
760    pub follow_symlinks: Option<bool>,
761}
762
763/// Result of the `resourceResolve` command.
764#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
765#[serde(rename_all = "camelCase")]
766pub struct ResourceResolveResult {
767    /// Canonical URI after symlink resolution. Equal to the requested URI when
768    /// `followSymlinks` is `false` or the URI does not traverse a symlink.
769    pub uri: Uri,
770    /// Resource kind.
771    pub r#type: ResourceType,
772    /// Size in bytes. Omitted for directories when the provider cannot
773    /// cheaply compute it.
774    #[serde(default, skip_serializing_if = "Option::is_none")]
775    pub size: Option<i64>,
776    /// Last-modified time in ISO 8601 format, when known.
777    #[serde(default, skip_serializing_if = "Option::is_none")]
778    pub mtime: Option<String>,
779    /// Creation time in ISO 8601 format, when known.
780    #[serde(default, skip_serializing_if = "Option::is_none")]
781    pub ctime: Option<String>,
782    /// Sniffed MIME type, when known (e.g. `"text/plain"`, `"image/png"`).
783    #[serde(default, skip_serializing_if = "Option::is_none")]
784    pub content_type: Option<String>,
785    /// Opaque per-provider version token. When present, pass it as
786    /// {@link ResourceWriteParams.ifMatch} on a subsequent `resourceWrite` to
787    /// detect concurrent modifications.
788    #[serde(default, skip_serializing_if = "Option::is_none")]
789    pub etag: Option<String>,
790}
791
792/// Creates a directory on the server's filesystem with `mkdir -p` semantics.
793///
794/// The server MUST create any missing parent directories. Creating a
795/// directory that already exists is a no-op success. If `uri` already
796/// exists but is **not** a directory, the server MUST fail with
797/// `AlreadyExists`.
798///
799/// Like all `resource*` methods, `resourceMkdir` is symmetrical and MAY be
800/// sent in either direction.
801#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
802#[serde(rename_all = "camelCase")]
803pub struct ResourceMkdirParams {
804    /// Channel URI this command targets.
805    pub channel: Uri,
806    /// Directory URI to create (parents created as needed).
807    pub uri: Uri,
808}
809
810/// Result of the `resourceMkdir` command.
811///
812/// An empty object on success.
813#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
814#[serde(rename_all = "camelCase")]
815pub struct ResourceMkdirResult {}
816
817/// Requests permission to access a resource on the receiver's filesystem.
818///
819/// `resourceRequest` is symmetrical and MAY be sent in either direction: a
820/// client asks the server to grant access to a server-side resource, or a
821/// server asks the client to grant access to a client-side resource. The
822/// receiver decides whether to allow, deny, or prompt the user for the
823/// requested access.
824///
825/// If the receiver denies access, it MUST respond with `PermissionDenied`
826/// (-32009). The error data MAY include a `ResourceRequestParams` value
827/// describing the access the caller would need to be granted for the
828/// operation to succeed; see `PermissionDeniedErrorData` in
829/// `types/errors.ts`.
830///
831/// After a successful `resourceRequest`, the caller MAY use the corresponding
832/// `resource*` commands (e.g. `resourceRead`, `resourceWrite`) to perform the
833/// operation. Receivers MAY rescind access at any time by returning
834/// `PermissionDenied` on subsequent operations.
835///
836/// Either `read`, `write`, or both SHOULD be set to `true`. A request with
837/// neither flag set is treated as `read: true` by receivers.
838#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
839#[serde(rename_all = "camelCase")]
840pub struct ResourceRequestParams {
841    /// Channel URI this command targets.
842    pub channel: Uri,
843    /// Resource URI being requested. Typically a `file:` URI on the receiver's
844    /// filesystem, but any URI scheme that the receiver mediates access to is
845    /// allowed.
846    pub uri: Uri,
847    /// Whether the caller needs read access to the resource.
848    #[serde(default, skip_serializing_if = "Option::is_none")]
849    pub read: Option<bool>,
850    /// Whether the caller needs write access to the resource.
851    #[serde(default, skip_serializing_if = "Option::is_none")]
852    pub write: Option<bool>,
853}
854
855/// Result of the `resourceRequest` command.
856///
857/// An empty object on success.
858#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
859#[serde(rename_all = "camelCase")]
860pub struct ResourceRequestResult {}
861
862/// Creates a resource watcher on the receiver's filesystem.
863///
864/// The receiver allocates an `ahp-resource-watch:/<id>` channel URI and
865/// returns it on {@link CreateResourceWatchResult.channel}. The caller then
866/// [`subscribe`](./subscriptions)s to that channel to receive
867/// `resourceWatch/changed` actions over the standard action envelope.
868///
869/// The watch lifecycle is tied to subscription: when every subscriber has
870/// unsubscribed (or the underlying connection drops), the receiver MUST
871/// release the watcher. There is no explicit dispose command — `unsubscribe`
872/// is the only handle the caller needs.
873///
874/// Like the rest of the `resource*` family, `createResourceWatch` is
875/// symmetrical and MAY be sent in either direction. Access is gated through
876/// the same permission flow as `resourceRead`/`resourceWrite`.
877#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
878#[serde(rename_all = "camelCase")]
879pub struct CreateResourceWatchParams {
880    /// Channel URI this command targets.
881    pub channel: Uri,
882    /// URI to watch.
883    pub uri: Uri,
884    /// If `true`, the receiver MUST report changes for descendants of `uri`.
885    /// If `false` (default), only changes to `uri` itself — and, when `uri`
886    /// is a directory, its direct children — are reported.
887    #[serde(default, skip_serializing_if = "Option::is_none")]
888    pub recursive: Option<bool>,
889    /// Glob patterns or paths relative to `uri` to exclude from reporting.
890    /// Wrapped in `{ items }` for forward compatibility.
891    #[serde(default, skip_serializing_if = "Option::is_none")]
892    pub excludes: Option<AnyValue>,
893    /// Glob patterns or paths relative to `uri` to restrict reporting to.
894    /// Omit to report every change under `uri` subject to `excludes`.
895    /// Wrapped in `{ items }` for forward compatibility.
896    #[serde(default, skip_serializing_if = "Option::is_none")]
897    pub includes: Option<AnyValue>,
898}
899
900/// Result of the `createResourceWatch` command.
901#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
902#[serde(rename_all = "camelCase")]
903pub struct CreateResourceWatchResult {
904    /// Receiver-assigned watch channel URI (`ahp-resource-watch:/<id>`). The
905    /// caller subscribes to this URI to start receiving change events and
906    /// unsubscribes to release the watcher.
907    pub channel: Uri,
908}
909
910/// Requests that the host load older historical turns into a chat state.
911///
912/// The command result does not carry turns. Instead, before responding, the host
913/// MUST dispatch `chat/turnsLoaded` to insert any loaded turns into the chat
914/// channel's `turns` state, ahead of the already-loaded window, and update or
915/// clear `turnsNextCursor`.
916///
917/// Before applying any operation that references a turn outside the currently
918/// loaded window, the host MUST eagerly load enough older turns into state for
919/// that operation to reduce against valid state.
920#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
921#[serde(rename_all = "camelCase")]
922pub struct FetchTurnsParams {
923    /// Channel URI this command targets.
924    pub channel: Uri,
925    /// Opaque cursor from `ChatState.turnsNextCursor`.
926    ///
927    /// The host MUST reject unrecognised cursors with `InvalidParams`. Omit only
928    /// when asking the host to opportunistically load its next older page for the
929    /// chat, if any.
930    #[serde(default, skip_serializing_if = "Option::is_none")]
931    pub cursor: Option<String>,
932}
933
934/// Result of the `fetchTurns` command.
935#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
936#[serde(rename_all = "camelCase")]
937pub struct FetchTurnsResult {}
938
939/// Stop receiving updates for a channel.
940#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
941#[serde(rename_all = "camelCase")]
942pub struct UnsubscribeParams {
943    /// Channel URI to unsubscribe from
944    pub channel: Uri,
945}
946
947/// Fire-and-forget action dispatch (write-ahead). The client applies actions
948/// optimistically to local state and the server echoes them back as an
949/// {@link ActionEnvelope} once accepted.
950///
951/// The client → server method is named `dispatchAction`; the server's reply
952/// arrives on the server → client `action` notification (params:
953/// {@link ActionEnvelope}).
954#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
955#[serde(rename_all = "camelCase")]
956pub struct DispatchActionParams {
957    /// Channel URI this action targets
958    pub channel: Uri,
959    /// Client sequence number
960    pub client_seq: i64,
961    /// The action to dispatch
962    pub action: StateAction,
963}
964
965/// Pushes a Bearer token for a protected resource. The `resource` field MUST
966/// match a `ProtectedResourceMetadata.resource` value declared by an agent
967/// in `AgentInfo.protectedResources`.
968///
969/// Tokens are delivered using [RFC 6750](https://datatracker.ietf.org/doc/html/rfc6750)
970/// (Bearer Token Usage) semantics. The client obtains the token from the
971/// authorization server(s) listed in the resource's metadata and pushes it
972/// to the server via this command.
973#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
974#[serde(rename_all = "camelCase")]
975pub struct AuthenticateParams {
976    /// Channel URI this command targets.
977    pub channel: Uri,
978    /// The protected resource identifier. MUST match a `resource` value from
979    /// `ProtectedResourceMetadata` declared in `AgentInfo.protectedResources`.
980    pub resource: String,
981    /// Bearer token obtained from the resource's authorization server
982    pub token: String,
983}
984
985/// Result of the `authenticate` command.
986///
987/// An empty object on success. If the token is invalid or the resource is
988/// unrecognized, the server MUST return a JSON-RPC error (e.g. `AuthRequired`
989/// `-32007` or `InvalidParams` `-32602`).
990#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
991#[serde(rename_all = "camelCase")]
992pub struct AuthenticateResult {}
993
994/// Creates a new terminal on the server.
995///
996/// After creation, the client should subscribe to the terminal URI to receive
997/// state updates. The server dispatches `root/terminalsChanged` to update the
998/// root terminal list.
999#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1000#[serde(rename_all = "camelCase")]
1001pub struct CreateTerminalParams {
1002    /// Channel URI this command targets.
1003    pub channel: Uri,
1004    /// Initial owner of the terminal
1005    pub claim: TerminalClaim,
1006    /// Human-readable terminal name
1007    #[serde(default, skip_serializing_if = "Option::is_none")]
1008    pub name: Option<String>,
1009    /// Initial working directory URI
1010    #[serde(default, skip_serializing_if = "Option::is_none")]
1011    pub cwd: Option<Uri>,
1012    /// Initial terminal width in columns
1013    #[serde(default, skip_serializing_if = "Option::is_none")]
1014    pub cols: Option<i64>,
1015    /// Initial terminal height in rows
1016    #[serde(default, skip_serializing_if = "Option::is_none")]
1017    pub rows: Option<i64>,
1018}
1019
1020/// Disposes a terminal and kills its process if still running.
1021///
1022/// The server dispatches `root/terminalsChanged` to remove the terminal from
1023/// the root terminal list.
1024#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1025#[serde(rename_all = "camelCase")]
1026pub struct DisposeTerminalParams {
1027    /// Channel URI this command targets.
1028    pub channel: Uri,
1029}
1030
1031/// Iteratively resolves the session configuration schema. The client sends the
1032/// current partial session config and any user-filled metadata values. The server
1033/// returns a property schema describing what additional metadata is needed,
1034/// contextual to the current selections.
1035///
1036/// The client calls this command whenever the user changes a significant input
1037/// (e.g. picks a working directory, toggles a property). Each response returns
1038/// the full current property set (not a delta). The returned `values` contain
1039/// server-resolved defaults to pass to `createSession`.
1040#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1041#[serde(rename_all = "camelCase")]
1042pub struct ResolveSessionConfigParams {
1043    /// Channel URI this command targets.
1044    pub channel: Uri,
1045    /// Agent provider ID
1046    #[serde(default, skip_serializing_if = "Option::is_none")]
1047    pub provider: Option<String>,
1048    /// Working directory for the session
1049    #[serde(default, skip_serializing_if = "Option::is_none")]
1050    pub working_directory: Option<Uri>,
1051    /// Current user-filled configuration values
1052    #[serde(default, skip_serializing_if = "Option::is_none")]
1053    pub config: Option<JsonObject>,
1054}
1055
1056/// Result of the `resolveSessionConfig` command.
1057#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1058#[serde(rename_all = "camelCase")]
1059pub struct ResolveSessionConfigResult {
1060    /// JSON Schema describing available configuration properties given the current context
1061    pub schema: SessionConfigSchema,
1062    /// Current configuration values (echoed back with server-resolved defaults applied)
1063    pub values: JsonObject,
1064}
1065
1066/// Queries the server for allowed values of a dynamic session config property.
1067///
1068/// Used when a property in the schema returned by `resolveSessionConfig` has
1069/// `enumDynamic: true`. The client sends a search query and receives matching
1070/// values with display metadata.
1071#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1072#[serde(rename_all = "camelCase")]
1073pub struct SessionConfigCompletionsParams {
1074    /// Channel URI this command targets.
1075    pub channel: Uri,
1076    /// Agent provider ID
1077    #[serde(default, skip_serializing_if = "Option::is_none")]
1078    pub provider: Option<String>,
1079    /// Working directory for the session
1080    #[serde(default, skip_serializing_if = "Option::is_none")]
1081    pub working_directory: Option<Uri>,
1082    /// Current user-filled configuration values (provides context for the query)
1083    #[serde(default, skip_serializing_if = "Option::is_none")]
1084    pub config: Option<JsonObject>,
1085    /// Property id from the schema to query values for
1086    pub property: String,
1087    /// Search filter text (empty or omitted returns default/recent values)
1088    #[serde(default, skip_serializing_if = "Option::is_none")]
1089    pub query: Option<String>,
1090}
1091
1092/// Result of the `sessionConfigCompletions` command.
1093#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1094#[serde(rename_all = "camelCase")]
1095pub struct SessionConfigCompletionsResult {
1096    /// Matching value items
1097    pub items: Vec<SessionConfigValueItem>,
1098}
1099
1100/// A single value item returned by `sessionConfigCompletions`.
1101#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1102#[serde(rename_all = "camelCase")]
1103pub struct SessionConfigValueItem {
1104    /// The value to store in config
1105    pub value: String,
1106    /// Human-readable display label
1107    pub label: String,
1108    /// Optional secondary description
1109    #[serde(default, skip_serializing_if = "Option::is_none")]
1110    pub description: Option<String>,
1111}
1112
1113/// Requests completion items for a partially-typed input (e.g. a user message
1114/// the user is currently composing). Used to power `@`-mention pickers,
1115/// file/symbol references, and similar inline-completion experiences.
1116///
1117/// Servers SHOULD treat this command as best-effort and return promptly. The
1118/// client SHOULD debounce calls to avoid flooding the server with requests on
1119/// every keystroke.
1120#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1121#[serde(rename_all = "camelCase")]
1122pub struct CompletionsParams {
1123    /// Channel URI this command targets.
1124    pub channel: Uri,
1125    /// What kind of completion is being requested.
1126    pub kind: CompletionItemKind,
1127    /// The complete text of the input being completed (e.g. the full user
1128    /// message text typed so far).
1129    pub text: String,
1130    /// The character offset within `text` at which the completion is requested,
1131    /// measured in UTF-16 code units. MUST satisfy `0 <= offset <= text.length`.
1132    pub offset: i64,
1133}
1134
1135/// A single completion item returned by the `completions` command.
1136///
1137/// When the user accepts an item, the client SHOULD:
1138/// 1. Replace the range `[rangeStart, rangeEnd)` in the input with `insertText`
1139///    (or insert `insertText` at the cursor when the range is omitted).
1140/// 2. Associate the item's `attachment` with the resulting {@link Message}.
1141#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1142#[serde(rename_all = "camelCase")]
1143pub struct CompletionItem {
1144    /// The text inserted into the input when this item is accepted.
1145    pub insert_text: String,
1146    /// If defined, the start of the range in the input's `text` that is replaced
1147    /// by `insertText`. The range is the half-open interval
1148    /// `[rangeStart, rangeEnd)` of character offsets, measured in UTF-16 code
1149    /// units.
1150    ///
1151    /// When omitted, the client SHOULD insert `insertText` at the cursor.
1152    ///
1153    /// Note: this range refers to positions in the *current* input. The
1154    /// attachment's own `rangeStart`/`rangeEnd` (when present) refer to
1155    /// positions in the final {@link Message.text} after the item is
1156    /// accepted.
1157    #[serde(default, skip_serializing_if = "Option::is_none")]
1158    pub range_start: Option<i64>,
1159    /// The end of the range in the input's `text` that is replaced by
1160    /// `insertText`. See {@link rangeStart}.
1161    #[serde(default, skip_serializing_if = "Option::is_none")]
1162    pub range_end: Option<i64>,
1163    /// The attachment associated with this completion item.
1164    pub attachment: MessageAttachment,
1165}
1166
1167/// Result of the `completions` command.
1168#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1169#[serde(rename_all = "camelCase")]
1170pub struct CompletionsResult {
1171    /// The completion items, in the order the server suggests displaying them.
1172    pub items: Vec<CompletionItem>,
1173}
1174
1175/// Invokes a server-defined {@link ChangesetOperation} against a changeset,
1176/// a single file, or a line range.
1177///
1178/// The server validates that `operationId` exists in the changeset's
1179/// current `operations` list and that the requested `target.kind` is
1180/// contained in the operation's `scopes`. Invalid combinations result in a
1181/// JSON-RPC error.
1182///
1183/// State changes resulting from invocation flow back through the normal
1184/// `changeset/*` action stream on the relevant changeset URIs. Clients
1185/// SHOULD NOT synthesise local optimistic changes for invocations unless
1186/// the server explicitly opts in via a future capability.
1187#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1188#[serde(rename_all = "camelCase")]
1189pub struct InvokeChangesetOperationParams {
1190    /// Channel URI this command targets.
1191    pub channel: Uri,
1192    /// Matches {@link ChangesetOperation.id} from the changeset's `operations` list.
1193    pub operation_id: String,
1194    /// Target of the operation. Required iff the chosen scope is
1195    /// `'resource'` or `'range'`. Omit for changeset-scoped operations.
1196    #[serde(default, skip_serializing_if = "Option::is_none")]
1197    pub target: Option<ChangesetOperationTarget>,
1198}
1199
1200/// Result of the {@link InvokeChangesetOperationParams | `invokeChangesetOperation`}
1201/// command.
1202///
1203/// Success is implicit: the server returns this result when it accepted
1204/// the operation. Failure is signalled by rejecting the JSON-RPC request
1205/// with an appropriate error code, not by any field on this result. The
1206/// operation MAY still produce subsequent failure feedback through the
1207/// {@link ChangesetStatusChangedAction | `changeset/statusChanged`} stream.
1208#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Default)]
1209#[serde(rename_all = "camelCase")]
1210pub struct InvokeChangesetOperationResult {
1211    /// Optional human-readable message describing the result.
1212    #[serde(default, skip_serializing_if = "Option::is_none")]
1213    pub message: Option<StringOrMarkdown>,
1214    /// Optional follow-up: a URI to open (e.g. a PR), a content ref, etc.
1215    #[serde(default, skip_serializing_if = "Option::is_none")]
1216    pub follow_up: Option<ChangesetOperationFollowUp>,
1217}
1218
1219/// Optional follow-up surfaced by the server after an operation completes —
1220/// a {@link ContentRef} the client can fetch and display.
1221///
1222/// Set `external` to `true` to open the content in the user's preferred
1223/// external handler (e.g. browser); otherwise the client is expected to
1224/// surface it inline.
1225#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1226#[serde(rename_all = "camelCase")]
1227pub struct ChangesetOperationFollowUp {
1228    pub content: ContentRef,
1229    /// When `true`, open in an external handler rather than inline.
1230    #[serde(default, skip_serializing_if = "Option::is_none")]
1231    pub external: Option<bool>,
1232}
1233
1234// ─── ReconnectResult Union ────────────────────────────────────────────
1235
1236/// Result of the `reconnect` command.
1237#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1238#[serde(tag = "type")]
1239pub enum ReconnectResult {
1240    #[serde(rename = "replay")]
1241    Replay(ReconnectReplayResult),
1242    #[serde(rename = "snapshot")]
1243    Snapshot(ReconnectSnapshotResult),
1244}
1245
1246// ─── Changeset Operation Unions ───────────────────────────────────────
1247
1248/// Identifies the file or range a `ChangesetOperation` should act on.
1249#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1250#[serde(tag = "kind")]
1251pub enum ChangesetOperationTarget {
1252    #[serde(rename = "resource")]
1253    Resource {
1254        resource: Uri,
1255        #[serde(default, skip_serializing_if = "Option::is_none")]
1256        side: Option<String>,
1257    },
1258    #[serde(rename = "range")]
1259    Range {
1260        resource: Uri,
1261        #[serde(default, skip_serializing_if = "Option::is_none")]
1262        side: Option<String>,
1263        range: TextRange,
1264    },
1265}