use serde::{Deserialize, Serialize}; use crate::gateway::{ApprovalOutcome, ApprovalPosted, ApprovalReply, ApprovalRequest}; use crate::memory::{ MemoryAdmin, MemoryAdminReply, MemoryBlockReply, MemoryCall, Reindexed, SessionUpdated, }; use crate::{CallId, DataClass, DecisionRecord, SessionId, Timestamp, Usage}; pub const PROTOCOL_VERSION: u32 = 1; #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] #[serde(deny_unknown_fields)] pub struct Envelope { pub v: u32, pub id: u64, pub r#final: bool, pub msg: Message, } #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] #[serde( tag = "kind", content = "body", deny_unknown_fields, rename_all = "snake_case" )] pub enum Message { ToolRequest(ToolRequest), ToolResponse(ToolResponse), Error(WireError), Turn(Turn), TurnEvent(TurnEvent), TurnDone(TurnDone), Approvals(Empty), ApprovalList(ApprovalList), Approve(Approve), ApproveResult(ApproveResult), Refuse(Refuse), Ok(Empty), CheckGrants(Empty), GrantsReport(GrantsReport), ApprovalRequest(ApprovalRequest), ApprovalPosted(ApprovalPosted), ApprovalReply(ApprovalReply), ApprovalOutcome(ApprovalOutcome), MemoryBlock(Empty), MemoryBlockReply(MemoryBlockReply), SessionUpdated(SessionUpdated), MemoryCall(MemoryCall), Reindex(Empty), Reindexed(Reindexed), MemoryAdmin(MemoryAdmin), MemoryAdminReply(MemoryAdminReply), } #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] #[serde(deny_unknown_fields)] pub struct WireError { pub code: ErrorCode, pub detail: String, } #[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)] #[serde(rename_all = "snake_case")] pub enum ErrorCode { BadFrame, BadVersion, BadMessage, Internal, SessionFull, TurnLimit, SessionBusy, NoSuchSession, SessionExists, Inference, Forbidden, NoSuchApproval, } #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] #[serde(deny_unknown_fields)] pub struct ToolRequest { pub session: SessionId, pub call: CallId, pub tool: String, pub arguments: String, } #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] #[serde(tag = "status", deny_unknown_fields, rename_all = "snake_case")] pub enum ToolResponse { PendingApproval { approval: u64, expires: Timestamp, }, Result { content: String, class: DataClass, untrusted: bool, truncated: bool, }, Failed { message: String, }, Denied { reason: DenyReason, }, } #[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)] #[serde(rename_all = "snake_case")] pub enum DenyReason { NoGrant, GrantExpired, TaintTooHigh, DeniedByGrant, ApprovalRefused, ApprovalExpired, GrantsInvalid, AuditUnavailable, InvalidArguments, StateUnreadable, } // JSON: {"kind":"turn","body":{"session":"…","content":"…","resume":false}} #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] #[serde(deny_unknown_fields)] pub struct Turn { pub session: SessionId, pub content: String, pub resume: bool, } // JSON: {"event":"content","text":"…"} — the tag sits beside the fields, snake_case #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] #[serde(tag = "event", deny_unknown_fields, rename_all = "snake_case")] pub enum TurnEvent { Queued { ahead: u64, }, Waiting { slot_busy: bool, }, Progress { total: u64, cache: u64, processed: u64, }, Reasoning { text: String, }, Content { text: String, }, ToolCallStarted { name: String, }, ToolResult { name: String, class: DataClass, truncated: bool, }, ThinkingCapped { tokens: u64, }, Retrying { attempt: u32, after_ms: u64, error: String, }, CacheLoss { expected: u64, got: u64, }, ApprovalPending { approval: u64, tool: String, expires: Timestamp, }, ToolDenied { name: String, reason: DenyReason, }, } // JSON: {"kind":"turn_done","body":{"content":"…","usage":{…}}} #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] #[serde(deny_unknown_fields)] pub struct TurnDone { pub content: String, pub usage: Usage, } // The admin messages on admin.sock. JSON: {"kind":"approvals","body":{}} #[derive(Debug, Clone, PartialEq, Eq, Default, Serialize, Deserialize)] #[serde(deny_unknown_fields)] pub struct Empty {} #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] #[serde(deny_unknown_fields)] pub struct PendingApproval { pub approval: u64, pub session: SessionId, pub call: CallId, pub tool: String, pub arguments: String, pub grant: String, pub taint: DataClass, pub created: Timestamp, pub expires: Timestamp, } #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] #[serde(deny_unknown_fields)] pub struct ApprovalList { pub items: Vec, } #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] #[serde(deny_unknown_fields)] pub struct Approve { pub approval: u64, } #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] #[serde(deny_unknown_fields)] pub struct ApproveResult { pub outcome: DecisionRecord, } #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] #[serde(deny_unknown_fields)] pub struct Refuse { pub approval: u64, pub reason: Option, } #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] #[serde(deny_unknown_fields)] pub struct GrantProblem { pub file: String, pub line: Option, pub problem: String, } #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] #[serde(deny_unknown_fields)] pub struct GrantsReport { pub problems: Vec, }