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::{Implementation, 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//! client_info: Some(Implementation {
72//! name: "my-host".into(),
73//! version: Some("1.0.0".into()),
74//! title: Some("My Host".into()),
75//! }),
76//! };
77//!
78//! let req = JsonRpcMessage::Request(JsonRpcRequest {
79//! jsonrpc: JsonRpcVersion::V2,
80//! id: 1,
81//! method: "initialize".into(),
82//! params: Some(AnyValue::from(serde_json::to_value(¶ms)?)),
83//! });
84//!
85//! let wire = serde_json::to_string(&req)?;
86//! assert!(wire.contains("\"method\":\"initialize\""));
87//! # Ok::<_, serde_json::Error>(())
88//! ```
89//!
90//! ## Inspect a session status bitset
91//!
92//! [`SessionStatus`](state::SessionStatus) packs activity and metadata
93//! flags into a single value — use bitwise checks rather than equality:
94//!
95//! `SessionStatus` is a `u32` bitset newtype: combine flags with `|`, test
96//! membership with [`contains`](state::SessionStatus::contains), and read the
97//! raw value (including unknown/forward-compat bits) with
98//! [`bits`](state::SessionStatus::bits).
99//!
100//! ```
101//! use ahp_types::state::SessionStatus;
102//!
103//! let status = SessionStatus::InProgress | SessionStatus::IsArchived;
104//! assert!(status.contains(SessionStatus::InProgress));
105//! assert!(status.contains(SessionStatus::IsArchived));
106//! assert!(!status.contains(SessionStatus::Idle));
107//! assert_eq!(status.bits(), 8 | 64);
108//! ```
109//!
110//! # Compatibility
111//!
112//! - JSON field names match the protocol exactly (`camelCase`); use the
113//! provided `Serialize`/`Deserialize` derives rather than manually
114//! building JSON.
115//! - Unknown enum variants surface as a generic `Unknown` arm where the
116//! protocol allows forward-compatible extension (see e.g.
117//! [`state::ToolCallState`]).
118//! - The protocol version this crate speaks is exposed as
119//! [`PROTOCOL_VERSION`].
120
121#![forbid(unsafe_code)]
122#![warn(missing_docs)]
123#![cfg_attr(docsrs, feature(doc_cfg))]
124
125pub mod actions;
126pub mod commands;
127pub mod common;
128pub mod errors;
129pub mod messages;
130pub mod notifications;
131pub mod state;
132pub mod version;
133
134pub use actions::{ActionEnvelope, ActionOrigin, ActionType, StateAction};
135pub use common::{StringOrMarkdown, Uri, ROOT_RESOURCE_URI};
136pub use errors::{AhpErrorCode, JsonRpcErrorCode};
137pub use messages::{JsonRpcError, JsonRpcErrorResponse, JsonRpcMessage};
138pub use notifications::{
139 AuthRequiredParams, SessionAddedParams, SessionRemovedParams, SessionSummaryChangedParams,
140};
141pub use state::{Icon, ProtectedResourceMetadata, RootState, SessionState, TerminalState};
142pub use version::{PROTOCOL_VERSION, SUPPORTED_PROTOCOL_VERSIONS};