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