Skip to main content

agentsight_protocol/
lib.rs

1// SPDX-License-Identifier: MIT
2// Copyright (c) 2026 eunomia-bpf org.
3//! Transport-independent AgentSight Node API contract.
4use serde::{Deserialize, Serialize};
5
6pub const PROTOCOL_VERSION: u32 = 1;
7pub const PRODUCT: &str = "agentsight";
8const SESSION_PREFIX: &str = "/api/v1/sessions/";
9
10#[derive(Debug, Serialize, Deserialize)]
11pub struct SessionMessageRequest { pub message: String }
12
13impl SessionMessageRequest {
14    pub fn validate(&self) -> Result<&str, &'static str> {
15        let message = self.message.trim();
16        (!message.is_empty() && message.len() <= 65_536)
17            .then_some(message).ok_or("message must contain 1-65536 bytes")
18    }
19}
20
21#[cfg_attr(target_arch = "wasm32", wasm_bindgen::prelude::wasm_bindgen)]
22pub fn info_path() -> String { "/api/v1/info".into() }
23#[cfg_attr(target_arch = "wasm32", wasm_bindgen::prelude::wasm_bindgen)]
24pub fn snapshot_path(limit: usize) -> String { format!("/api/v1/snapshot?audit_limit={limit}") }
25#[cfg_attr(target_arch = "wasm32", wasm_bindgen::prelude::wasm_bindgen)]
26pub fn overview_path() -> String { "/api/v1/overview".into() }
27#[cfg_attr(target_arch = "wasm32", wasm_bindgen::prelude::wasm_bindgen)]
28pub fn session_path(id: &str) -> String { format!("{SESSION_PREFIX}{id}") }
29#[cfg_attr(target_arch = "wasm32", wasm_bindgen::prelude::wasm_bindgen)]
30pub fn session_messages_path(id: &str) -> String { format!("{SESSION_PREFIX}{id}/messages") }
31#[cfg_attr(target_arch = "wasm32", wasm_bindgen::prelude::wasm_bindgen)]
32pub fn session_message_body(message: &str) -> String {
33    serde_json::to_string(&SessionMessageRequest { message: message.into() }).unwrap()
34}
35
36pub fn session_detail_id(path: &str) -> Option<&str> {
37    let id = path.strip_prefix(SESSION_PREFIX)?;
38    (!id.is_empty() && !id.contains('/')).then_some(id)
39}
40pub fn session_message_id(path: &str) -> Option<&str> {
41    let id = path.strip_prefix(SESSION_PREFIX)?.strip_suffix("/messages")?;
42    (!id.is_empty() && !id.contains('/')).then_some(id)
43}