Skip to main content

ahp_types/
lib.rs

1//! Wire protocol types for the [Agent Host Protocol (AHP)][spec].
2//!
3//! `ahp-types` is the data-only crate of the AHP family. Every command,
4//! action, notification, and state object defined by the protocol has a
5//! Rust counterpart here — `Serialize` + `Deserialize`, using the exact
6//! same JSON field names as the wire format. There is no I/O, no async
7//! runtime, and no transport code; if you only need to parse or
8//! construct AHP messages, this is the only crate you need.
9//!
10//! These types are generated from the TypeScript source of truth in
11//! `types/*.ts`, so any change to the protocol surfaces here first.
12//!
13//! [spec]: https://microsoft.github.io/agent-host-protocol/
14//!
15//! # Companion crates
16//!
17//! | Crate | What it adds |
18//! |---|---|
19//! | [`ahp`](https://docs.rs/ahp) | Async client, reducers, and pluggable [`Transport`](https://docs.rs/ahp/latest/ahp/transport/trait.Transport.html) trait |
20//! | [`ahp-ws`](https://docs.rs/ahp-ws) | WebSocket transport built on `tokio-tungstenite` |
21//!
22//! # Module map
23//!
24//! | Module | Contents |
25//! |---|---|
26//! | [`state`]         | [`RootState`], [`SessionState`], [`TerminalState`], tool-call lifecycle |
27//! | [`actions`]       | [`StateAction`] discriminated union and [`ActionEnvelope`] |
28//! | [`commands`]      | Request/response parameter and result types (`initialize`, `subscribe`, …) |
29//! | [`notifications`] | Server-pushed protocol notification params ([`SessionAddedParams`], [`AuthRequiredParams`], …) |
30//! | [`messages`]      | JSON-RPC wire envelopes ([`JsonRpcMessage`] and friends) |
31//! | [`errors`]        | AHP and JSON-RPC [error codes][errors::AhpErrorCode] |
32//! | [`version`]       | Negotiation constants ([`PROTOCOL_VERSION`]) |
33//! | [`common`]        | Hand-written primitives ([`Uri`], [`StringOrMarkdown`], …) |
34//!
35//! # Examples
36//!
37//! ## Parse an action envelope
38//!
39//! ```
40//! use ahp_types::actions::{ActionEnvelope, StateAction};
41//!
42//! let json = r#"{
43//!   "channel": "ahp-session:/s1",
44//!   "action": { "type": "session/titleChanged", "title": "Hi" },
45//!   "serverSeq": 7
46//! }"#;
47//! let env: ActionEnvelope = serde_json::from_str(json)?;
48//! assert_eq!(env.server_seq, 7);
49//! assert_eq!(env.channel, "ahp-session:/s1");
50//! match env.action {
51//!     StateAction::SessionTitleChanged(a) => assert_eq!(a.title, "Hi"),
52//!     _ => panic!("unexpected variant"),
53//! }
54//! # Ok::<_, serde_json::Error>(())
55//! ```
56//!
57//! ## Build an `initialize` request
58//!
59//! ```
60//! use ahp_types::commands::InitializeParams;
61//! use ahp_types::messages::{JsonRpcMessage, JsonRpcRequest, JsonRpcVersion};
62//! use ahp_types::common::AnyValue;
63//!
64//! let params = InitializeParams {
65//!     channel: "ahp-root://".into(),
66//!     protocol_versions: vec![ahp_types::PROTOCOL_VERSION.to_string()],
67//!     client_id: "my-host/1.0".into(),
68//!     initial_subscriptions: Some(vec!["ahp-root://".into()]),
69//!     locale: Some("en".into()),
70//!     capabilities: None,
71//! };
72//!
73//! let req = JsonRpcMessage::Request(JsonRpcRequest {
74//!     jsonrpc: JsonRpcVersion::V2,
75//!     id: 1,
76//!     method: "initialize".into(),
77//!     params: Some(AnyValue::from(serde_json::to_value(&params)?)),
78//! });
79//!
80//! let wire = serde_json::to_string(&req)?;
81//! assert!(wire.contains("\"method\":\"initialize\""));
82//! # Ok::<_, serde_json::Error>(())
83//! ```
84//!
85//! ## Inspect a session status bitset
86//!
87//! [`SessionStatus`](state::SessionStatus) packs activity and metadata
88//! flags into a single value — use bitwise checks rather than equality:
89//!
90//! `SessionStatus` is a `u32` bitset newtype: combine flags with `|`, test
91//! membership with [`contains`](state::SessionStatus::contains), and read the
92//! raw value (including unknown/forward-compat bits) with
93//! [`bits`](state::SessionStatus::bits).
94//!
95//! ```
96//! use ahp_types::state::SessionStatus;
97//!
98//! let status = SessionStatus::InProgress | SessionStatus::IsArchived;
99//! assert!(status.contains(SessionStatus::InProgress));
100//! assert!(status.contains(SessionStatus::IsArchived));
101//! assert!(!status.contains(SessionStatus::Idle));
102//! assert_eq!(status.bits(), 8 | 64);
103//! ```
104//!
105//! # Compatibility
106//!
107//! - JSON field names match the protocol exactly (`camelCase`); use the
108//!   provided `Serialize`/`Deserialize` derives rather than manually
109//!   building JSON.
110//! - Unknown enum variants surface as a generic `Unknown` arm where the
111//!   protocol allows forward-compatible extension (see e.g.
112//!   [`state::ToolCallState`]).
113//! - The protocol version this crate speaks is exposed as
114//!   [`PROTOCOL_VERSION`].
115
116#![forbid(unsafe_code)]
117#![warn(missing_docs)]
118#![cfg_attr(docsrs, feature(doc_cfg))]
119
120pub mod actions;
121pub mod commands;
122pub mod common;
123pub mod errors;
124pub mod messages;
125pub mod notifications;
126pub mod state;
127pub mod version;
128
129pub use actions::{ActionEnvelope, ActionOrigin, ActionType, StateAction};
130pub use common::{StringOrMarkdown, Uri, ROOT_RESOURCE_URI};
131pub use errors::{AhpErrorCode, JsonRpcErrorCode};
132pub use messages::{JsonRpcError, JsonRpcErrorResponse, JsonRpcMessage};
133pub use notifications::{
134    AuthRequiredParams, SessionAddedParams, SessionRemovedParams, SessionSummaryChangedParams,
135};
136pub use state::{Icon, ProtectedResourceMetadata, RootState, SessionState, TerminalState};
137pub use version::{PROTOCOL_VERSION, SUPPORTED_PROTOCOL_VERSIONS};