1pub const PROTOCOL_VERSION: u16 = 1;
5
6pub const MAGIC: [u8; 4] = *b"PXB\x01";
8
9pub const HEADER_SIZE: usize = 16;
11
12pub const MAX_PAYLOAD: usize = 16 << 20;
14
15pub const TYPE_HELLO: u16 = 1;
18pub const TYPE_READY: u16 = 2;
19pub const TYPE_REGISTER_COMMAND: u16 = 3;
20pub const TYPE_REGISTER_TOOL: u16 = 4;
21pub const TYPE_SUBSCRIBE: u16 = 5;
22pub const TYPE_COMMAND_RESPONSE: u16 = 6;
23pub const TYPE_TOOL_RESULT: u16 = 7;
24pub const TYPE_INTERCEPT_RESPONSE: u16 = 8;
25pub const TYPE_SHUTDOWN_ACK: u16 = 9;
26pub const TYPE_NOTIFY: u16 = 10;
27pub const TYPE_HOST_REQUEST: u16 = 11;
28
29pub const TYPE_HELLO_ACK: u16 = 100;
30pub const TYPE_COMMAND_INVOKED: u16 = 101;
31pub const TYPE_TOOL_INVOKE: u16 = 102;
32pub const TYPE_EVENT: u16 = 103;
33pub const TYPE_INTERCEPT: u16 = 104;
34pub const TYPE_SHUTDOWN: u16 = 105;
35pub const TYPE_HOST_RESULT: u16 = 106;
36pub const TYPE_SESSION_META: u16 = 107;
37
38pub const FLAG_HAS_ID: u16 = 1 << 0; pub const CAP_COMMANDS: u32 = 1 << 0;
43pub const CAP_TOOLS: u32 = 1 << 1;
44pub const CAP_EVENTS: u32 = 1 << 2;
45pub const CAP_INTERCEPT: u32 = 1 << 3;
46
47#[derive(Debug, Clone, Copy, PartialEq, Eq)]
50pub enum FrameType {
51 Hello,
52 Ready,
53 RegisterCommand,
54 RegisterTool,
55 Subscribe,
56 CommandResponse,
57 ToolResult,
58 InterceptResponse,
59 ShutdownAck,
60 Notify,
61 HostRequest,
62 HelloAck,
63 CommandInvoked,
64 ToolInvoke,
65 Event,
66 Intercept,
67 Shutdown,
68 HostResult,
69 SessionMeta,
70 Unknown(u16),
71}
72
73impl FrameType {
74 pub fn from_u16(v: u16) -> Self {
75 match v {
76 TYPE_HELLO => Self::Hello,
77 TYPE_READY => Self::Ready,
78 TYPE_REGISTER_COMMAND => Self::RegisterCommand,
79 TYPE_REGISTER_TOOL => Self::RegisterTool,
80 TYPE_SUBSCRIBE => Self::Subscribe,
81 TYPE_COMMAND_RESPONSE => Self::CommandResponse,
82 TYPE_TOOL_RESULT => Self::ToolResult,
83 TYPE_INTERCEPT_RESPONSE => Self::InterceptResponse,
84 TYPE_SHUTDOWN_ACK => Self::ShutdownAck,
85 TYPE_NOTIFY => Self::Notify,
86 TYPE_HOST_REQUEST => Self::HostRequest,
87 TYPE_HELLO_ACK => Self::HelloAck,
88 TYPE_COMMAND_INVOKED => Self::CommandInvoked,
89 TYPE_TOOL_INVOKE => Self::ToolInvoke,
90 TYPE_EVENT => Self::Event,
91 TYPE_INTERCEPT => Self::Intercept,
92 TYPE_SHUTDOWN => Self::Shutdown,
93 TYPE_HOST_RESULT => Self::HostResult,
94 TYPE_SESSION_META => Self::SessionMeta,
95 other => Self::Unknown(other),
96 }
97 }
98
99 pub fn code(self) -> u16 {
100 match self {
101 Self::Hello => TYPE_HELLO,
102 Self::Ready => TYPE_READY,
103 Self::RegisterCommand => TYPE_REGISTER_COMMAND,
104 Self::RegisterTool => TYPE_REGISTER_TOOL,
105 Self::Subscribe => TYPE_SUBSCRIBE,
106 Self::CommandResponse => TYPE_COMMAND_RESPONSE,
107 Self::ToolResult => TYPE_TOOL_RESULT,
108 Self::InterceptResponse => TYPE_INTERCEPT_RESPONSE,
109 Self::ShutdownAck => TYPE_SHUTDOWN_ACK,
110 Self::Notify => TYPE_NOTIFY,
111 Self::HostRequest => TYPE_HOST_REQUEST,
112 Self::HelloAck => TYPE_HELLO_ACK,
113 Self::CommandInvoked => TYPE_COMMAND_INVOKED,
114 Self::ToolInvoke => TYPE_TOOL_INVOKE,
115 Self::Event => TYPE_EVENT,
116 Self::Intercept => TYPE_INTERCEPT,
117 Self::Shutdown => TYPE_SHUTDOWN,
118 Self::HostResult => TYPE_HOST_RESULT,
119 Self::SessionMeta => TYPE_SESSION_META,
120 Self::Unknown(v) => v,
121 }
122 }
123}
124
125#[derive(Debug, Clone, Copy, PartialEq, Eq)]
129pub enum Event {
130 ToolCall,
131 ToolResult,
132 ToolExecStart,
133 ToolExecEnd,
134 SessionStart,
135 SessionShutdown,
136 SessionBeforeSwitch,
137 BeforeAgentStart,
138 AgentStart,
139 AgentEnd,
140 TurnStart,
141 TurnEnd,
142 UserInput,
143 TurnStopping,
144 SessionCompact,
145 PaneAction,
146 Unknown(u16),
147}
148
149impl Event {
150 pub fn from_code(code: u16) -> Self {
153 match code {
154 1 => Self::ToolCall,
155 2 => Self::ToolResult,
156 3 => Self::ToolExecStart,
157 4 => Self::ToolExecEnd,
158 5 => Self::SessionStart,
159 6 => Self::SessionShutdown,
160 7 => Self::SessionBeforeSwitch,
161 8 => Self::BeforeAgentStart,
162 9 => Self::AgentStart,
163 10 => Self::AgentEnd,
164 11 => Self::TurnStart,
165 12 => Self::TurnEnd,
166 13 => Self::UserInput,
167 14 => Self::TurnStopping,
168 15 => Self::SessionCompact,
169 16 => Self::PaneAction,
170 other => Self::Unknown(other),
171 }
172 }
173
174 pub fn code(self) -> u16 {
175 match self {
176 Self::ToolCall => 1,
177 Self::ToolResult => 2,
178 Self::ToolExecStart => 3,
179 Self::ToolExecEnd => 4,
180 Self::SessionStart => 5,
181 Self::SessionShutdown => 6,
182 Self::SessionBeforeSwitch => 7,
183 Self::BeforeAgentStart => 8,
184 Self::AgentStart => 9,
185 Self::AgentEnd => 10,
186 Self::TurnStart => 11,
187 Self::TurnEnd => 12,
188 Self::UserInput => 13,
189 Self::TurnStopping => 14,
190 Self::SessionCompact => 15,
191 Self::PaneAction => 16,
192 Self::Unknown(v) => v,
193 }
194 }
195
196 pub fn name(self) -> &'static str {
198 match self {
199 Self::ToolCall => "tool_call",
200 Self::ToolResult => "tool_result",
201 Self::ToolExecStart => "tool_execution_start",
202 Self::ToolExecEnd => "tool_execution_end",
203 Self::SessionStart => "session_start",
204 Self::SessionShutdown => "session_shutdown",
205 Self::SessionBeforeSwitch => "session_before_switch",
206 Self::BeforeAgentStart => "before_agent_start",
207 Self::AgentStart => "agent_start",
208 Self::AgentEnd => "agent_end",
209 Self::TurnStart => "turn_start",
210 Self::TurnEnd => "turn_end",
211 Self::UserInput => "user_input",
212 Self::TurnStopping => "turn_stopping",
213 Self::SessionCompact => "session_compact",
214 Self::PaneAction => "pane_action",
215 Self::Unknown(_) => "",
216 }
217 }
218
219 pub fn from_name(name: &str) -> Self {
222 match name {
223 "tool_call" => Self::ToolCall,
224 "tool_result" => Self::ToolResult,
225 "tool_execution_start" => Self::ToolExecStart,
226 "tool_execution_end" => Self::ToolExecEnd,
227 "session_start" => Self::SessionStart,
228 "session_shutdown" => Self::SessionShutdown,
229 "session_before_switch" => Self::SessionBeforeSwitch,
230 "before_agent_start" => Self::BeforeAgentStart,
231 "agent_start" => Self::AgentStart,
232 "agent_end" => Self::AgentEnd,
233 "turn_start" => Self::TurnStart,
234 "turn_end" => Self::TurnEnd,
235 "user_input" => Self::UserInput,
236 "turn_stopping" => Self::TurnStopping,
237 "session_compact" => Self::SessionCompact,
238 "pane_action" => Self::PaneAction,
239 _ => Self::Unknown(0),
240 }
241 }
242}
243
244#[cfg(test)]
245mod tests {
246 use super::*;
247
248 #[test]
249 fn frame_type_roundtrip() {
250 for v in 1..=19 {
251 assert_eq!(FrameType::from_u16(v).code(), v);
252 }
253 assert_eq!(FrameType::from_u16(999), FrameType::Unknown(999));
254 }
255
256 #[test]
257 fn event_name_and_code_roundtrip() {
258 for code in 1..=16 {
259 let ev = Event::from_code(code);
260 assert_eq!(ev.code(), code);
261 assert_eq!(Event::from_name(ev.name()), ev);
262 }
263 assert_eq!(Event::from_code(0), Event::Unknown(0));
264 assert_eq!(Event::from_name("nope"), Event::Unknown(0));
265 }
266}