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, MessageAttachment, ModelSelection, SessionActiveClient,
19    SessionConfigSchema, SessionSummary, Snapshot, SnapshotState, TelemetryCapabilities,
20    TerminalClaim, 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 UserMessage} 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    /// URIs to subscribe to during handshake
113    #[serde(default, skip_serializing_if = "Option::is_none")]
114    pub initial_subscriptions: Option<Vec<Uri>>,
115    /// IETF BCP 47 language tag indicating the client's preferred locale
116    /// (e.g. `"en-US"`, `"ja"`). The server SHOULD use this to localise
117    /// user-facing strings such as confirmation option labels.
118    #[serde(default, skip_serializing_if = "Option::is_none")]
119    pub locale: Option<String>,
120}
121
122/// Result of the `initialize` command.
123///
124/// `protocolVersion` is the version the server has selected from the client's
125/// `protocolVersions` list. The client and server MUST use this version for
126/// the rest of the connection. If the server cannot speak any of the offered
127/// versions it MUST return error code `-32005` (`UnsupportedProtocolVersion`)
128/// instead of a result.
129#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
130#[serde(rename_all = "camelCase")]
131pub struct InitializeResult {
132    /// Protocol version selected by the server. MUST be one of the entries in
133    /// `InitializeParams.protocolVersions`. Formatted as a [SemVer](https://semver.org)
134    /// `MAJOR.MINOR.PATCH` string (e.g. `"0.1.0"`).
135    pub protocol_version: String,
136    /// Current server sequence number
137    pub server_seq: i64,
138    /// Snapshots for each `initialSubscriptions` URI
139    pub snapshots: Vec<Snapshot>,
140    /// Suggested default directory for remote filesystem browsing
141    #[serde(default, skip_serializing_if = "Option::is_none")]
142    pub default_directory: Option<Uri>,
143    /// Characters that, when typed in a {@link UserMessage} input, SHOULD cause
144    /// the client to issue a `completions` request with
145    /// {@link CompletionItemKind.UserMessage}. Typically includes characters like
146    /// `'@'` or `'/'`.
147    #[serde(default, skip_serializing_if = "Option::is_none")]
148    pub completion_trigger_characters: Option<Vec<String>>,
149    /// OTLP telemetry channels the host emits, if any. Each populated field is
150    /// either a literal `ahp-otlp:` channel URI or an RFC 6570 URI template a
151    /// client expands before subscribing (currently only the `logs` channel
152    /// defines a template variable, `{level}`, for subscriber-side severity
153    /// filtering). Clients MAY ignore signals they cannot process.
154    #[serde(default, skip_serializing_if = "Option::is_none")]
155    pub telemetry: Option<TelemetryCapabilities>,
156}
157
158/// Re-establishes a dropped connection. The server replays missed actions or
159/// provides fresh snapshots.
160#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
161#[serde(rename_all = "camelCase")]
162pub struct ReconnectParams {
163    /// Channel URI this command targets.
164    pub channel: Uri,
165    /// Client identifier from the original connection
166    pub client_id: String,
167    /// Last `serverSeq` the client received
168    pub last_seen_server_seq: i64,
169    /// URIs the client was subscribed to
170    pub subscriptions: Vec<Uri>,
171}
172
173/// Reconnect result when the server can replay from the requested sequence.
174///
175/// The server MUST include all replayed data in the response.
176#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
177#[serde(rename_all = "camelCase")]
178pub struct ReconnectReplayResult {
179    /// Missed action envelopes since `lastSeenServerSeq`
180    pub actions: Vec<ActionEnvelope>,
181    /// URIs from `ReconnectParams.subscriptions` that the server cannot resume.
182    /// This includes resources that no longer exist (e.g. disposed sessions or
183    /// terminals) as well as resources the client is no longer permitted to
184    /// observe. Clients SHOULD drop these from their local subscription set.
185    pub missing: Vec<Uri>,
186}
187
188/// Reconnect result when the gap exceeds the replay buffer.
189#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
190#[serde(rename_all = "camelCase")]
191pub struct ReconnectSnapshotResult {
192    /// Fresh snapshots for each subscription
193    pub snapshots: Vec<Snapshot>,
194}
195
196/// Subscribe to a URI-identified channel.
197///
198/// A channel MAY have state associated with it (e.g. root, sessions,
199/// terminals) or be stateless (pure pub/sub for streaming data). For
200/// state-bearing channels the result includes a snapshot; for stateless
201/// channels `snapshot` is omitted.
202#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
203#[serde(rename_all = "camelCase")]
204pub struct SubscribeParams {
205    /// Channel URI this command targets.
206    pub channel: Uri,
207}
208
209/// Result of the `subscribe` command.
210///
211/// `snapshot` is present when the subscribed channel has associated state, and
212/// absent for stateless channels.
213#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Default)]
214#[serde(rename_all = "camelCase")]
215pub struct SubscribeResult {
216    /// Snapshot of the subscribed channel's state (omitted for stateless channels)
217    #[serde(default, skip_serializing_if = "Option::is_none")]
218    pub snapshot: Option<Snapshot>,
219}
220
221/// Creates a new session with the specified agent provider.
222///
223/// If the session URI already exists, the server MUST return an error with code
224/// `-32003` (`SessionAlreadyExists`).
225///
226/// After creation, the client should subscribe to the session URI to receive state
227/// updates. The server also broadcasts a `root/sessionAdded` notification to all
228/// clients.
229#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
230#[serde(rename_all = "camelCase")]
231pub struct SessionForkSource {
232    /// URI of the existing session to fork from
233    pub session: Uri,
234    /// Turn ID in the source session; content up to and including this turn's response is copied
235    pub turn_id: String,
236}
237
238#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
239#[serde(rename_all = "camelCase")]
240pub struct CreateSessionParams {
241    /// Channel URI this command targets.
242    pub channel: Uri,
243    /// Agent provider ID
244    #[serde(default, skip_serializing_if = "Option::is_none")]
245    pub provider: Option<String>,
246    /// Model selection (ID and optional model-specific configuration)
247    #[serde(default, skip_serializing_if = "Option::is_none")]
248    pub model: Option<ModelSelection>,
249    /// Initial custom agent selection for the new session.
250    ///
251    /// Omit to start the session with no custom agent selected (provider default).
252    #[serde(default, skip_serializing_if = "Option::is_none")]
253    pub agent: Option<AgentSelection>,
254    /// Working directory for the session
255    #[serde(default, skip_serializing_if = "Option::is_none")]
256    pub working_directory: Option<Uri>,
257    /// Fork from an existing session. The new session is populated with content
258    /// from the source session up to and including the specified turn's response.
259    #[serde(default, skip_serializing_if = "Option::is_none")]
260    pub fork: Option<SessionForkSource>,
261    /// Agent-specific configuration values collected via `resolveSessionConfig`.
262    /// Keys and values correspond to the schema returned by the server.
263    #[serde(default, skip_serializing_if = "Option::is_none")]
264    pub config: Option<JsonObject>,
265    /// Eagerly claim the active client role for the new session.
266    ///
267    /// When provided, the server initializes the session with this client as the
268    /// active client, equivalent to dispatching a `session/activeClientChanged`
269    /// action immediately after creation. The `clientId` MUST match the
270    /// `clientId` the creating client supplied in `initialize`.
271    #[serde(default, skip_serializing_if = "Option::is_none")]
272    pub active_client: Option<SessionActiveClient>,
273}
274
275/// Disposes a session and cleans up server-side resources.
276///
277/// The server broadcasts a `root/sessionRemoved` notification to all clients.
278#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
279#[serde(rename_all = "camelCase")]
280pub struct DisposeSessionParams {
281    /// Channel URI this command targets.
282    pub channel: Uri,
283}
284
285/// Returns a list of session summaries. Used to populate session lists and sidebars.
286///
287/// The session list is **not** part of the state tree because it can be arbitrarily
288/// large. Clients fetch it imperatively and maintain a local cache updated by
289/// `root/sessionAdded` and `root/sessionRemoved` notifications.
290#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
291#[serde(rename_all = "camelCase")]
292pub struct ListSessionsParams {
293    /// Channel URI this command targets.
294    pub channel: Uri,
295    /// Optional filter criteria
296    #[serde(default, skip_serializing_if = "Option::is_none")]
297    pub filter: Option<AnyValue>,
298}
299
300/// Result of the `listSessions` command.
301#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
302#[serde(rename_all = "camelCase")]
303pub struct ListSessionsResult {
304    /// The list of session summaries.
305    pub items: Vec<SessionSummary>,
306}
307
308/// Reads the content of a resource by URI.
309///
310/// Content references keep the state tree small by storing large data (images,
311/// long tool outputs) by reference rather than inline.
312///
313/// Binary content (images, etc.) MUST use `base64` encoding. Text content MAY
314/// use `utf-8` encoding.
315///
316/// Like all `resource*` methods, `resourceRead` is symmetrical and MAY be
317/// sent in either direction. Hosts use it to fetch content from a
318/// client-published URI (e.g. `virtual://my-client/...` plugins); clients
319/// use it to read host-side files. The receiver enforces access via the
320/// same permission/`resourceRequest` flow regardless of which peer initiated.
321#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
322#[serde(rename_all = "camelCase")]
323pub struct ResourceReadParams {
324    /// Channel URI this command targets.
325    pub channel: Uri,
326    /// Content URI from a `ContentRef`
327    pub uri: String,
328    /// Preferred encoding for the returned data (default: server-chosen)
329    #[serde(default, skip_serializing_if = "Option::is_none")]
330    pub encoding: Option<ContentEncoding>,
331}
332
333/// Result of the `resourceRead` command.
334///
335/// The server SHOULD honor the `encoding` requested in the params. If the
336/// server cannot provide the requested encoding, it MUST fall back to either
337/// `base64` or `utf-8`.
338#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
339#[serde(rename_all = "camelCase")]
340pub struct ResourceReadResult {
341    /// Content encoded as a string
342    pub data: String,
343    /// How `data` is encoded
344    pub encoding: ContentEncoding,
345    /// Content type (e.g. `"image/png"`, `"text/plain"`)
346    #[serde(default, skip_serializing_if = "Option::is_none")]
347    pub content_type: Option<String>,
348}
349
350/// Writes content to a file on the server's filesystem.
351///
352/// Binary content (images, etc.) MUST use `base64` encoding. Text content MAY
353/// use `utf-8` encoding.
354///
355/// If the file does not exist, it is created. If the file already exists, the
356/// effect on existing bytes depends on {@link ResourceWriteParams.mode}:
357/// `truncate` (default) overwrites from the chosen offset onward, `append`
358/// preserves all existing bytes and adds `data` at a position rooted at EOF,
359/// and `insert` preserves all existing bytes and splices `data` in at an
360/// offset rooted at the start of the file.
361///
362/// Like all `resource*` methods, `resourceWrite` is symmetrical and MAY be
363/// sent in either direction.
364#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
365#[serde(rename_all = "camelCase")]
366pub struct ResourceWriteParams {
367    /// Channel URI this command targets.
368    pub channel: Uri,
369    /// Target file URI on the server filesystem
370    pub uri: Uri,
371    /// Content encoded as a string
372    pub data: String,
373    /// How `data` is encoded
374    pub encoding: ContentEncoding,
375    /// Content type (e.g. `"text/plain"`, `"image/png"`)
376    #[serde(default, skip_serializing_if = "Option::is_none")]
377    pub content_type: Option<String>,
378    /// If `true`, the server MUST fail if the file already exists instead of
379    /// overwriting it. Useful for safe creation of new files.
380    #[serde(default, skip_serializing_if = "Option::is_none")]
381    pub create_only: Option<bool>,
382    /// How `data` is placed within the target file. Defaults to `'truncate'`
383    /// (full overwrite) when omitted. See {@link ResourceWriteMode} for the
384    /// meaning of each mode and how it interprets {@link position}.
385    #[serde(default, skip_serializing_if = "Option::is_none")]
386    pub mode: Option<ResourceWriteMode>,
387    /// Byte offset interpreted according to {@link mode}. Defaults to `0`.
388    /// - `truncate`: offset from the start of the file at which to truncate
389    ///   before writing.
390    /// - `append`: bytes back from EOF at which to insert `data`.
391    /// - `insert`: offset from the start of the file at which to splice in
392    ///   `data`.
393    #[serde(default, skip_serializing_if = "Option::is_none")]
394    pub position: Option<i64>,
395    /// Optimistic-concurrency token previously returned by
396    /// {@link ResourceResolveResult.etag}. When set, the server MUST fail with
397    /// `Conflict` if the current `etag` does not match — preventing lost
398    /// updates between a `resourceResolve` and a subsequent `resourceWrite`.
399    #[serde(default, skip_serializing_if = "Option::is_none")]
400    pub if_match: Option<String>,
401}
402
403/// Result of the `resourceWrite` command.
404///
405/// An empty object on success.
406#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
407#[serde(rename_all = "camelCase")]
408pub struct ResourceWriteResult {}
409
410/// Lists directory entries at a file URI on the server's filesystem.
411///
412/// This is intended for remote folder pickers and similar UI that needs to let
413/// users navigate the server's local filesystem.
414///
415/// The server MUST return success only if the target exists and is a directory.
416/// If the target does not exist, is not a directory, or cannot be accessed, the
417/// server MUST return a JSON-RPC error.
418///
419/// Like all `resource*` methods, `resourceList` is symmetrical and MAY be
420/// sent in either direction.
421#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
422#[serde(rename_all = "camelCase")]
423pub struct ResourceListParams {
424    /// Channel URI this command targets.
425    pub channel: Uri,
426    /// Directory URI on the server filesystem
427    pub uri: Uri,
428}
429
430/// Result of the `resourceList` command.
431#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
432#[serde(rename_all = "camelCase")]
433pub struct ResourceListResult {
434    /// Entries directly contained in the requested directory
435    pub entries: Vec<DirectoryEntry>,
436}
437
438/// Directory entry returned by `resourceList`.
439#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
440#[serde(rename_all = "camelCase")]
441pub struct DirectoryEntry {
442    /// Base name of the entry
443    pub name: String,
444    /// Whether the entry is a file or directory
445    pub r#type: String,
446}
447
448/// Copies a resource from one URI to another on the server's filesystem.
449///
450/// If the destination already exists, it is overwritten unless `failIfExists`
451/// is set.
452///
453/// Like all `resource*` methods, `resourceCopy` is symmetrical and MAY be
454/// sent in either direction.
455#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
456#[serde(rename_all = "camelCase")]
457pub struct ResourceCopyParams {
458    /// Channel URI this command targets.
459    pub channel: Uri,
460    /// Source URI to copy from
461    pub source: Uri,
462    /// Destination URI to copy to
463    pub destination: Uri,
464    /// If `true`, the server MUST fail if the destination already exists instead
465    /// of overwriting it.
466    #[serde(default, skip_serializing_if = "Option::is_none")]
467    pub fail_if_exists: Option<bool>,
468}
469
470/// Result of the `resourceCopy` command.
471///
472/// An empty object on success.
473#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
474#[serde(rename_all = "camelCase")]
475pub struct ResourceCopyResult {}
476
477/// Deletes a resource at a URI on the server's filesystem.
478///
479/// Like all `resource*` methods, `resourceDelete` is symmetrical and MAY be
480/// sent in either direction.
481#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
482#[serde(rename_all = "camelCase")]
483pub struct ResourceDeleteParams {
484    /// Channel URI this command targets.
485    pub channel: Uri,
486    /// URI of the resource to delete
487    pub uri: Uri,
488    /// If `true` and the target is a directory, delete it and all its contents
489    /// recursively. If `false` (default), deleting a non-empty directory MUST fail.
490    #[serde(default, skip_serializing_if = "Option::is_none")]
491    pub recursive: Option<bool>,
492}
493
494/// Result of the `resourceDelete` command.
495///
496/// An empty object on success.
497#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
498#[serde(rename_all = "camelCase")]
499pub struct ResourceDeleteResult {}
500
501/// Moves (renames) a resource from one URI to another on the server's filesystem.
502///
503/// If the destination already exists, it is overwritten unless `failIfExists`
504/// is set.
505///
506/// Like all `resource*` methods, `resourceMove` is symmetrical and MAY be
507/// sent in either direction.
508#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
509#[serde(rename_all = "camelCase")]
510pub struct ResourceMoveParams {
511    /// Channel URI this command targets.
512    pub channel: Uri,
513    /// Source URI to move from
514    pub source: Uri,
515    /// Destination URI to move to
516    pub destination: Uri,
517    /// If `true`, the server MUST fail if the destination already exists instead
518    /// of overwriting it.
519    #[serde(default, skip_serializing_if = "Option::is_none")]
520    pub fail_if_exists: Option<bool>,
521}
522
523/// Result of the `resourceMove` command.
524///
525/// An empty object on success.
526#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
527#[serde(rename_all = "camelCase")]
528pub struct ResourceMoveResult {}
529
530/// Resolves a resource — the combination of POSIX `stat` and `realpath`.
531///
532/// `resourceResolve` returns metadata about the resource together with its
533/// canonical URI after symlink resolution. Use this in place of any
534/// `resourceExists` shim: a missing resource MUST surface as a `NotFound`
535/// JSON-RPC error rather than a success with a sentinel value. Callers that
536/// truly need a boolean check should attempt `resourceResolve` and treat
537/// `NotFound` as "does not exist".
538///
539/// Like all `resource*` methods, `resourceResolve` is symmetrical and MAY be
540/// sent in either direction.
541#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
542#[serde(rename_all = "camelCase")]
543pub struct ResourceResolveParams {
544    /// Channel URI this command targets.
545    pub channel: Uri,
546    /// URI to resolve
547    pub uri: Uri,
548    /// When `true` (default), follow symlinks and report the metadata of the
549    /// link target — and set `uri` in the result to the canonical (realpath)
550    /// URI. When `false`, stat the link itself (lstat semantics) and report
551    /// `type: 'symlink'`.
552    #[serde(default, skip_serializing_if = "Option::is_none")]
553    pub follow_symlinks: Option<bool>,
554}
555
556/// Result of the `resourceResolve` command.
557#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
558#[serde(rename_all = "camelCase")]
559pub struct ResourceResolveResult {
560    /// Canonical URI after symlink resolution. Equal to the requested URI when
561    /// `followSymlinks` is `false` or the URI does not traverse a symlink.
562    pub uri: Uri,
563    /// Resource kind.
564    pub r#type: ResourceType,
565    /// Size in bytes. Omitted for directories when the provider cannot
566    /// cheaply compute it.
567    #[serde(default, skip_serializing_if = "Option::is_none")]
568    pub size: Option<i64>,
569    /// Last-modified time in ISO 8601 format, when known.
570    #[serde(default, skip_serializing_if = "Option::is_none")]
571    pub mtime: Option<String>,
572    /// Creation time in ISO 8601 format, when known.
573    #[serde(default, skip_serializing_if = "Option::is_none")]
574    pub ctime: Option<String>,
575    /// Sniffed MIME type, when known (e.g. `"text/plain"`, `"image/png"`).
576    #[serde(default, skip_serializing_if = "Option::is_none")]
577    pub content_type: Option<String>,
578    /// Opaque per-provider version token. When present, pass it as
579    /// {@link ResourceWriteParams.ifMatch} on a subsequent `resourceWrite` to
580    /// detect concurrent modifications.
581    #[serde(default, skip_serializing_if = "Option::is_none")]
582    pub etag: Option<String>,
583}
584
585/// Creates a directory on the server's filesystem with `mkdir -p` semantics.
586///
587/// The server MUST create any missing parent directories. Creating a
588/// directory that already exists is a no-op success. If `uri` already
589/// exists but is **not** a directory, the server MUST fail with
590/// `AlreadyExists`.
591///
592/// Like all `resource*` methods, `resourceMkdir` is symmetrical and MAY be
593/// sent in either direction.
594#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
595#[serde(rename_all = "camelCase")]
596pub struct ResourceMkdirParams {
597    /// Channel URI this command targets.
598    pub channel: Uri,
599    /// Directory URI to create (parents created as needed).
600    pub uri: Uri,
601}
602
603/// Result of the `resourceMkdir` command.
604///
605/// An empty object on success.
606#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
607#[serde(rename_all = "camelCase")]
608pub struct ResourceMkdirResult {}
609
610/// Requests permission to access a resource on the receiver's filesystem.
611///
612/// `resourceRequest` is symmetrical and MAY be sent in either direction: a
613/// client asks the server to grant access to a server-side resource, or a
614/// server asks the client to grant access to a client-side resource. The
615/// receiver decides whether to allow, deny, or prompt the user for the
616/// requested access.
617///
618/// If the receiver denies access, it MUST respond with `PermissionDenied`
619/// (-32009). The error data MAY include a `ResourceRequestParams` value
620/// describing the access the caller would need to be granted for the
621/// operation to succeed; see `PermissionDeniedErrorData` in
622/// `types/errors.ts`.
623///
624/// After a successful `resourceRequest`, the caller MAY use the corresponding
625/// `resource*` commands (e.g. `resourceRead`, `resourceWrite`) to perform the
626/// operation. Receivers MAY rescind access at any time by returning
627/// `PermissionDenied` on subsequent operations.
628///
629/// Either `read`, `write`, or both SHOULD be set to `true`. A request with
630/// neither flag set is treated as `read: true` by receivers.
631#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
632#[serde(rename_all = "camelCase")]
633pub struct ResourceRequestParams {
634    /// Channel URI this command targets.
635    pub channel: Uri,
636    /// Resource URI being requested. Typically a `file:` URI on the receiver's
637    /// filesystem, but any URI scheme that the receiver mediates access to is
638    /// allowed.
639    pub uri: Uri,
640    /// Whether the caller needs read access to the resource.
641    #[serde(default, skip_serializing_if = "Option::is_none")]
642    pub read: Option<bool>,
643    /// Whether the caller needs write access to the resource.
644    #[serde(default, skip_serializing_if = "Option::is_none")]
645    pub write: Option<bool>,
646}
647
648/// Result of the `resourceRequest` command.
649///
650/// An empty object on success.
651#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
652#[serde(rename_all = "camelCase")]
653pub struct ResourceRequestResult {}
654
655/// Creates a resource watcher on the receiver's filesystem.
656///
657/// The receiver allocates an `ahp-resource-watch:/<id>` channel URI and
658/// returns it on {@link CreateResourceWatchResult.channel}. The caller then
659/// [`subscribe`](./subscriptions)s to that channel to receive
660/// `resourceWatch/changed` actions over the standard action envelope.
661///
662/// The watch lifecycle is tied to subscription: when every subscriber has
663/// unsubscribed (or the underlying connection drops), the receiver MUST
664/// release the watcher. There is no explicit dispose command — `unsubscribe`
665/// is the only handle the caller needs.
666///
667/// Like the rest of the `resource*` family, `createResourceWatch` is
668/// symmetrical and MAY be sent in either direction. Access is gated through
669/// the same permission flow as `resourceRead`/`resourceWrite`.
670#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
671#[serde(rename_all = "camelCase")]
672pub struct CreateResourceWatchParams {
673    /// Channel URI this command targets.
674    pub channel: Uri,
675    /// URI to watch.
676    pub uri: Uri,
677    /// If `true`, the receiver MUST report changes for descendants of `uri`.
678    /// If `false` (default), only changes to `uri` itself — and, when `uri`
679    /// is a directory, its direct children — are reported.
680    #[serde(default, skip_serializing_if = "Option::is_none")]
681    pub recursive: Option<bool>,
682    /// Glob patterns or paths relative to `uri` to exclude from reporting.
683    /// Wrapped in `{ items }` for forward compatibility.
684    #[serde(default, skip_serializing_if = "Option::is_none")]
685    pub excludes: Option<AnyValue>,
686    /// Glob patterns or paths relative to `uri` to restrict reporting to.
687    /// Omit to report every change under `uri` subject to `excludes`.
688    /// Wrapped in `{ items }` for forward compatibility.
689    #[serde(default, skip_serializing_if = "Option::is_none")]
690    pub includes: Option<AnyValue>,
691}
692
693/// Result of the `createResourceWatch` command.
694#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
695#[serde(rename_all = "camelCase")]
696pub struct CreateResourceWatchResult {
697    /// Receiver-assigned watch channel URI (`ahp-resource-watch:/<id>`). The
698    /// caller subscribes to this URI to start receiving change events and
699    /// unsubscribes to release the watcher.
700    pub channel: Uri,
701}
702
703/// Fetches historical turns for a session. Used for lazy loading of conversation
704/// history.
705#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
706#[serde(rename_all = "camelCase")]
707pub struct FetchTurnsParams {
708    /// Channel URI this command targets.
709    pub channel: Uri,
710    /// Turn ID to fetch before (exclusive). Omit to fetch from the most recent turn.
711    #[serde(default, skip_serializing_if = "Option::is_none")]
712    pub before: Option<String>,
713    /// Maximum number of turns to return. Server MAY impose its own upper bound.
714    #[serde(default, skip_serializing_if = "Option::is_none")]
715    pub limit: Option<i64>,
716}
717
718/// Result of the `fetchTurns` command.
719#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
720#[serde(rename_all = "camelCase")]
721pub struct FetchTurnsResult {
722    /// The requested turns, ordered oldest-first
723    pub turns: Vec<Turn>,
724    /// Whether more turns exist before the returned range
725    pub has_more: bool,
726}
727
728/// Stop receiving updates for a channel.
729#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
730#[serde(rename_all = "camelCase")]
731pub struct UnsubscribeParams {
732    /// Channel URI to unsubscribe from
733    pub channel: Uri,
734}
735
736/// Fire-and-forget action dispatch (write-ahead). The client applies actions
737/// optimistically to local state and the server echoes them back as an
738/// {@link ActionEnvelope} once accepted.
739///
740/// The client → server method is named `dispatchAction`; the server's reply
741/// arrives on the server → client `action` notification (params:
742/// {@link ActionEnvelope}).
743#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
744#[serde(rename_all = "camelCase")]
745pub struct DispatchActionParams {
746    /// Channel URI this action targets
747    pub channel: Uri,
748    /// Client sequence number
749    pub client_seq: i64,
750    /// The action to dispatch
751    pub action: StateAction,
752}
753
754/// Pushes a Bearer token for a protected resource. The `resource` field MUST
755/// match a `ProtectedResourceMetadata.resource` value declared by an agent
756/// in `AgentInfo.protectedResources`.
757///
758/// Tokens are delivered using [RFC 6750](https://datatracker.ietf.org/doc/html/rfc6750)
759/// (Bearer Token Usage) semantics. The client obtains the token from the
760/// authorization server(s) listed in the resource's metadata and pushes it
761/// to the server via this command.
762#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
763#[serde(rename_all = "camelCase")]
764pub struct AuthenticateParams {
765    /// Channel URI this command targets.
766    pub channel: Uri,
767    /// The protected resource identifier. MUST match a `resource` value from
768    /// `ProtectedResourceMetadata` declared in `AgentInfo.protectedResources`.
769    pub resource: String,
770    /// Bearer token obtained from the resource's authorization server
771    pub token: String,
772}
773
774/// Result of the `authenticate` command.
775///
776/// An empty object on success. If the token is invalid or the resource is
777/// unrecognized, the server MUST return a JSON-RPC error (e.g. `AuthRequired`
778/// `-32007` or `InvalidParams` `-32602`).
779#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
780#[serde(rename_all = "camelCase")]
781pub struct AuthenticateResult {}
782
783/// Creates a new terminal on the server.
784///
785/// After creation, the client should subscribe to the terminal URI to receive
786/// state updates. The server dispatches `root/terminalsChanged` to update the
787/// root terminal list.
788#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
789#[serde(rename_all = "camelCase")]
790pub struct CreateTerminalParams {
791    /// Channel URI this command targets.
792    pub channel: Uri,
793    /// Initial owner of the terminal
794    pub claim: TerminalClaim,
795    /// Human-readable terminal name
796    #[serde(default, skip_serializing_if = "Option::is_none")]
797    pub name: Option<String>,
798    /// Initial working directory URI
799    #[serde(default, skip_serializing_if = "Option::is_none")]
800    pub cwd: Option<Uri>,
801    /// Initial terminal width in columns
802    #[serde(default, skip_serializing_if = "Option::is_none")]
803    pub cols: Option<i64>,
804    /// Initial terminal height in rows
805    #[serde(default, skip_serializing_if = "Option::is_none")]
806    pub rows: Option<i64>,
807}
808
809/// Disposes a terminal and kills its process if still running.
810///
811/// The server dispatches `root/terminalsChanged` to remove the terminal from
812/// the root terminal list.
813#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
814#[serde(rename_all = "camelCase")]
815pub struct DisposeTerminalParams {
816    /// Channel URI this command targets.
817    pub channel: Uri,
818}
819
820/// Iteratively resolves the session configuration schema. The client sends the
821/// current partial session config and any user-filled metadata values. The server
822/// returns a property schema describing what additional metadata is needed,
823/// contextual to the current selections.
824///
825/// The client calls this command whenever the user changes a significant input
826/// (e.g. picks a working directory, toggles a property). Each response returns
827/// the full current property set (not a delta). The returned `values` contain
828/// server-resolved defaults to pass to `createSession`.
829#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
830#[serde(rename_all = "camelCase")]
831pub struct ResolveSessionConfigParams {
832    /// Channel URI this command targets.
833    pub channel: Uri,
834    /// Agent provider ID
835    #[serde(default, skip_serializing_if = "Option::is_none")]
836    pub provider: Option<String>,
837    /// Working directory for the session
838    #[serde(default, skip_serializing_if = "Option::is_none")]
839    pub working_directory: Option<Uri>,
840    /// Current user-filled configuration values
841    #[serde(default, skip_serializing_if = "Option::is_none")]
842    pub config: Option<JsonObject>,
843}
844
845/// Result of the `resolveSessionConfig` command.
846#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
847#[serde(rename_all = "camelCase")]
848pub struct ResolveSessionConfigResult {
849    /// JSON Schema describing available configuration properties given the current context
850    pub schema: SessionConfigSchema,
851    /// Current configuration values (echoed back with server-resolved defaults applied)
852    pub values: JsonObject,
853}
854
855/// Queries the server for allowed values of a dynamic session config property.
856///
857/// Used when a property in the schema returned by `resolveSessionConfig` has
858/// `enumDynamic: true`. The client sends a search query and receives matching
859/// values with display metadata.
860#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
861#[serde(rename_all = "camelCase")]
862pub struct SessionConfigCompletionsParams {
863    /// Channel URI this command targets.
864    pub channel: Uri,
865    /// Agent provider ID
866    #[serde(default, skip_serializing_if = "Option::is_none")]
867    pub provider: Option<String>,
868    /// Working directory for the session
869    #[serde(default, skip_serializing_if = "Option::is_none")]
870    pub working_directory: Option<Uri>,
871    /// Current user-filled configuration values (provides context for the query)
872    #[serde(default, skip_serializing_if = "Option::is_none")]
873    pub config: Option<JsonObject>,
874    /// Property id from the schema to query values for
875    pub property: String,
876    /// Search filter text (empty or omitted returns default/recent values)
877    #[serde(default, skip_serializing_if = "Option::is_none")]
878    pub query: Option<String>,
879}
880
881/// Result of the `sessionConfigCompletions` command.
882#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
883#[serde(rename_all = "camelCase")]
884pub struct SessionConfigCompletionsResult {
885    /// Matching value items
886    pub items: Vec<SessionConfigValueItem>,
887}
888
889/// A single value item returned by `sessionConfigCompletions`.
890#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
891#[serde(rename_all = "camelCase")]
892pub struct SessionConfigValueItem {
893    /// The value to store in config
894    pub value: String,
895    /// Human-readable display label
896    pub label: String,
897    /// Optional secondary description
898    #[serde(default, skip_serializing_if = "Option::is_none")]
899    pub description: Option<String>,
900}
901
902/// Requests completion items for a partially-typed input (e.g. a user message
903/// the user is currently composing). Used to power `@`-mention pickers,
904/// file/symbol references, and similar inline-completion experiences.
905///
906/// Servers SHOULD treat this command as best-effort and return promptly. The
907/// client SHOULD debounce calls to avoid flooding the server with requests on
908/// every keystroke.
909#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
910#[serde(rename_all = "camelCase")]
911pub struct CompletionsParams {
912    /// Channel URI this command targets.
913    pub channel: Uri,
914    /// What kind of completion is being requested.
915    pub kind: CompletionItemKind,
916    /// The complete text of the input being completed (e.g. the full user
917    /// message text typed so far).
918    pub text: String,
919    /// The character offset within `text` at which the completion is requested,
920    /// measured in UTF-16 code units. MUST satisfy `0 <= offset <= text.length`.
921    pub offset: i64,
922}
923
924/// A single completion item returned by the `completions` command.
925///
926/// When the user accepts an item, the client SHOULD:
927/// 1. Replace the range `[rangeStart, rangeEnd)` in the input with `insertText`
928///    (or insert `insertText` at the cursor when the range is omitted).
929/// 2. Associate the item's `attachment` with the resulting {@link UserMessage}.
930#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
931#[serde(rename_all = "camelCase")]
932pub struct CompletionItem {
933    /// The text inserted into the input when this item is accepted.
934    pub insert_text: String,
935    /// If defined, the start of the range in the input's `text` that is replaced
936    /// by `insertText`. The range is the half-open interval
937    /// `[rangeStart, rangeEnd)` of character offsets, measured in UTF-16 code
938    /// units.
939    ///
940    /// When omitted, the client SHOULD insert `insertText` at the cursor.
941    ///
942    /// Note: this range refers to positions in the *current* input. The
943    /// attachment's own `rangeStart`/`rangeEnd` (when present) refer to
944    /// positions in the final {@link UserMessage.text} after the item is
945    /// accepted.
946    #[serde(default, skip_serializing_if = "Option::is_none")]
947    pub range_start: Option<i64>,
948    /// The end of the range in the input's `text` that is replaced by
949    /// `insertText`. See {@link rangeStart}.
950    #[serde(default, skip_serializing_if = "Option::is_none")]
951    pub range_end: Option<i64>,
952    /// The attachment associated with this completion item.
953    pub attachment: MessageAttachment,
954}
955
956/// Result of the `completions` command.
957#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
958#[serde(rename_all = "camelCase")]
959pub struct CompletionsResult {
960    /// The completion items, in the order the server suggests displaying them.
961    pub items: Vec<CompletionItem>,
962}
963
964/// Invokes a server-defined {@link ChangesetOperation} against a changeset,
965/// a single file, or a line range.
966///
967/// The server validates that `operationId` exists in the changeset's
968/// current `operations` list and that the requested `target.kind` is
969/// contained in the operation's `scopes`. Invalid combinations result in a
970/// JSON-RPC error.
971///
972/// State changes resulting from invocation flow back through the normal
973/// `changeset/*` action stream on the relevant changeset URIs. Clients
974/// SHOULD NOT synthesise local optimistic changes for invocations unless
975/// the server explicitly opts in via a future capability.
976#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
977#[serde(rename_all = "camelCase")]
978pub struct InvokeChangesetOperationParams {
979    /// Channel URI this command targets.
980    pub channel: Uri,
981    /// Matches {@link ChangesetOperation.id} from the changeset's `operations` list.
982    pub operation_id: String,
983    /// Target of the operation. Required iff the chosen scope is
984    /// `'resource'` or `'range'`. Omit for changeset-scoped operations.
985    #[serde(default, skip_serializing_if = "Option::is_none")]
986    pub target: Option<ChangesetOperationTarget>,
987}
988
989/// Result of the {@link InvokeChangesetOperationParams | `invokeChangesetOperation`}
990/// command.
991///
992/// Success is implicit: the server returns this result when it accepted
993/// the operation. Failure is signalled by rejecting the JSON-RPC request
994/// with an appropriate error code, not by any field on this result. The
995/// operation MAY still produce subsequent failure feedback through the
996/// {@link ChangesetStatusChangedAction | `changeset/statusChanged`} stream.
997#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Default)]
998#[serde(rename_all = "camelCase")]
999pub struct InvokeChangesetOperationResult {
1000    /// Optional human-readable message describing the result.
1001    #[serde(default, skip_serializing_if = "Option::is_none")]
1002    pub message: Option<StringOrMarkdown>,
1003    /// Optional follow-up: a URI to open (e.g. a PR), a content ref, etc.
1004    #[serde(default, skip_serializing_if = "Option::is_none")]
1005    pub follow_up: Option<ChangesetOperationFollowUp>,
1006}
1007
1008/// Optional follow-up surfaced by the server after an operation completes —
1009/// a {@link ContentRef} the client can fetch and display.
1010///
1011/// Set `external` to `true` to open the content in the user's preferred
1012/// external handler (e.g. browser); otherwise the client is expected to
1013/// surface it inline.
1014#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1015#[serde(rename_all = "camelCase")]
1016pub struct ChangesetOperationFollowUp {
1017    pub content: ContentRef,
1018    /// When `true`, open in an external handler rather than inline.
1019    #[serde(default, skip_serializing_if = "Option::is_none")]
1020    pub external: Option<bool>,
1021}
1022
1023// ─── ReconnectResult Union ────────────────────────────────────────────
1024
1025/// Result of the `reconnect` command.
1026#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1027#[serde(tag = "type")]
1028pub enum ReconnectResult {
1029    #[serde(rename = "replay")]
1030    Replay(ReconnectReplayResult),
1031    #[serde(rename = "snapshot")]
1032    Snapshot(ReconnectSnapshotResult),
1033}
1034
1035// ─── Changeset Operation Unions ───────────────────────────────────────
1036
1037/// Identifies the file or range a `ChangesetOperation` should act on.
1038#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1039#[serde(tag = "kind")]
1040pub enum ChangesetOperationTarget {
1041    #[serde(rename = "resource")]
1042    Resource {
1043        resource: Uri,
1044        #[serde(default, skip_serializing_if = "Option::is_none")]
1045        side: Option<String>,
1046    },
1047    #[serde(rename = "range")]
1048    Range {
1049        resource: Uri,
1050        #[serde(default, skip_serializing_if = "Option::is_none")]
1051        side: Option<String>,
1052        range: ChangesetOperationTargetRange,
1053    },
1054}
1055
1056#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1057pub struct ChangesetOperationTargetRange {
1058    pub start: i64,
1059    pub end: i64,
1060}