1use serde::{Deserialize, Serialize};
7use serde_json::Value;
8
9#[derive(Debug, Clone, Serialize, Deserialize)]
13#[serde(tag = "type", rename_all = "lowercase")]
14pub enum ProtocolMessage {
15 Request(RequestMessage),
16 Response(ResponseMessage),
17 Event(EventMessage),
18}
19
20#[derive(Debug, Clone, Serialize, Deserialize)]
22pub struct RequestMessage {
23 pub seq: i64,
24 #[serde(rename = "type")]
25 pub message_type: String,
26 pub command: String,
27 #[serde(skip_serializing_if = "Option::is_none")]
28 pub arguments: Option<Value>,
29}
30
31#[derive(Debug, Clone, Serialize, Deserialize)]
33pub struct ResponseMessage {
34 pub seq: i64,
35 #[serde(rename = "type")]
36 pub message_type: String,
37 pub request_seq: i64,
38 pub success: bool,
39 pub command: String,
40 #[serde(skip_serializing_if = "Option::is_none")]
41 pub message: Option<String>,
42 #[serde(skip_serializing_if = "Option::is_none")]
43 pub body: Option<Value>,
44}
45
46#[derive(Debug, Clone, Serialize, Deserialize)]
48pub struct EventMessage {
49 pub seq: i64,
50 #[serde(rename = "type")]
51 pub message_type: String,
52 pub event: String,
53 #[serde(skip_serializing_if = "Option::is_none")]
54 pub body: Option<Value>,
55}
56
57#[derive(Debug, Clone, Serialize, Deserialize)]
61#[serde(rename_all = "camelCase")]
62pub struct InitializeArguments {
63 #[serde(skip_serializing_if = "Option::is_none")]
64 pub client_id: Option<String>,
65 #[serde(skip_serializing_if = "Option::is_none")]
66 pub client_name: Option<String>,
67 #[serde(rename = "adapterID")]
68 pub adapter_id: String,
69 #[serde(skip_serializing_if = "Option::is_none")]
70 pub locale: Option<String>,
71 #[serde(default = "default_true")]
72 pub lines_start_at1: bool,
73 #[serde(default = "default_true")]
74 pub columns_start_at1: bool,
75 #[serde(skip_serializing_if = "Option::is_none")]
76 pub path_format: Option<String>,
77 #[serde(default)]
78 pub supports_variable_type: bool,
79 #[serde(default)]
80 pub supports_variable_paging: bool,
81 #[serde(default)]
82 pub supports_run_in_terminal_request: bool,
83 #[serde(default)]
84 pub supports_memory_references: bool,
85 #[serde(default)]
86 pub supports_progress_reporting: bool,
87}
88
89fn default_true() -> bool {
90 true
91}
92
93impl Default for InitializeArguments {
94 fn default() -> Self {
95 Self {
96 client_id: Some("debugger-cli".to_string()),
97 client_name: Some("LLM Debugger CLI".to_string()),
98 adapter_id: "lldb-dap".to_string(),
99 locale: None,
100 lines_start_at1: true,
101 columns_start_at1: true,
102 path_format: Some("path".to_string()),
103 supports_variable_type: true,
104 supports_variable_paging: true,
105 supports_run_in_terminal_request: false,
106 supports_memory_references: true,
107 supports_progress_reporting: false,
108 }
109 }
110}
111
112#[derive(Debug, Clone, Serialize, Deserialize)]
117#[serde(rename_all = "camelCase")]
118pub struct LaunchArguments {
119 pub program: String,
120 #[serde(default, skip_serializing_if = "Vec::is_empty")]
121 pub args: Vec<String>,
122 #[serde(skip_serializing_if = "Option::is_none")]
123 pub cwd: Option<String>,
124 #[serde(skip_serializing_if = "Option::is_none")]
125 pub env: Option<std::collections::HashMap<String, String>>,
126 #[serde(default)]
127 pub stop_on_entry: bool,
128
129 #[serde(skip_serializing_if = "Option::is_none")]
131 pub init_commands: Option<Vec<String>>,
132 #[serde(skip_serializing_if = "Option::is_none")]
133 pub pre_run_commands: Option<Vec<String>>,
134
135 #[serde(skip_serializing_if = "Option::is_none")]
138 pub request: Option<String>,
139 #[serde(skip_serializing_if = "Option::is_none")]
141 pub console: Option<String>,
142 #[serde(skip_serializing_if = "Option::is_none")]
144 pub python: Option<String>,
145 #[serde(skip_serializing_if = "Option::is_none")]
147 pub just_my_code: Option<bool>,
148
149 #[serde(skip_serializing_if = "Option::is_none")]
152 pub mode: Option<String>,
153 #[serde(skip_serializing_if = "Option::is_none")]
155 pub stop_at_entry: Option<bool>,
156
157 #[serde(skip_serializing_if = "Option::is_none")]
160 pub stop_at_beginning_of_main_subprogram: Option<bool>,
161}
162
163#[derive(Debug, Clone, Serialize, Deserialize)]
165#[serde(rename_all = "camelCase")]
166pub struct AttachArguments {
167 pub pid: u32,
168 #[serde(skip_serializing_if = "Option::is_none")]
170 pub wait_for: Option<bool>,
171}
172
173#[derive(Debug, Clone, Serialize, Deserialize)]
175#[serde(rename_all = "camelCase")]
176pub struct SetBreakpointsArguments {
177 pub source: Source,
178 #[serde(default, skip_serializing_if = "Vec::is_empty")]
179 pub breakpoints: Vec<SourceBreakpoint>,
180}
181
182#[derive(Debug, Clone, Serialize, Deserialize)]
184#[serde(rename_all = "camelCase")]
185pub struct SetFunctionBreakpointsArguments {
186 pub breakpoints: Vec<FunctionBreakpoint>,
187}
188
189#[derive(Debug, Clone, Serialize, Deserialize)]
191#[serde(rename_all = "camelCase")]
192pub struct ContinueArguments {
193 pub thread_id: i64,
194 #[serde(default)]
195 pub single_thread: bool,
196}
197
198#[derive(Debug, Clone, Serialize, Deserialize)]
200#[serde(rename_all = "camelCase")]
201pub struct StepArguments {
202 pub thread_id: i64,
203 #[serde(skip_serializing_if = "Option::is_none")]
204 pub granularity: Option<String>,
205}
206
207#[derive(Debug, Clone, Serialize, Deserialize)]
209#[serde(rename_all = "camelCase")]
210pub struct PauseArguments {
211 pub thread_id: i64,
212}
213
214#[derive(Debug, Clone, Serialize, Deserialize)]
216#[serde(rename_all = "camelCase")]
217pub struct StackTraceArguments {
218 pub thread_id: i64,
219 #[serde(skip_serializing_if = "Option::is_none")]
220 pub start_frame: Option<i64>,
221 #[serde(skip_serializing_if = "Option::is_none")]
222 pub levels: Option<i64>,
223}
224
225#[derive(Debug, Clone, Serialize, Deserialize)]
227#[serde(rename_all = "camelCase")]
228pub struct ScopesArguments {
229 pub frame_id: i64,
230}
231
232#[derive(Debug, Clone, Serialize, Deserialize)]
234#[serde(rename_all = "camelCase")]
235pub struct VariablesArguments {
236 pub variables_reference: i64,
237 #[serde(skip_serializing_if = "Option::is_none")]
238 pub start: Option<i64>,
239 #[serde(skip_serializing_if = "Option::is_none")]
240 pub count: Option<i64>,
241}
242
243#[derive(Debug, Clone, Serialize, Deserialize)]
245#[serde(rename_all = "camelCase")]
246pub struct EvaluateArguments {
247 pub expression: String,
248 #[serde(skip_serializing_if = "Option::is_none")]
249 pub frame_id: Option<i64>,
250 #[serde(skip_serializing_if = "Option::is_none")]
251 pub context: Option<String>,
252}
253
254#[derive(Debug, Clone, Serialize, Deserialize)]
256#[serde(rename_all = "camelCase")]
257pub struct DisconnectArguments {
258 #[serde(default)]
259 pub restart: bool,
260 #[serde(skip_serializing_if = "Option::is_none")]
261 pub terminate_debuggee: Option<bool>,
262}
263
264#[derive(Debug, Clone, Default, Serialize, Deserialize)]
268#[serde(rename_all = "camelCase")]
269pub struct Capabilities {
270 #[serde(default)]
271 pub supports_configuration_done_request: bool,
272 #[serde(default)]
273 pub supports_function_breakpoints: bool,
274 #[serde(default)]
275 pub supports_conditional_breakpoints: bool,
276 #[serde(default)]
277 pub supports_hit_conditional_breakpoints: bool,
278 #[serde(default)]
279 pub supports_evaluate_for_hovers: bool,
280 #[serde(default)]
281 pub supports_step_back: bool,
282 #[serde(default)]
283 pub supports_set_variable: bool,
284 #[serde(default)]
285 pub supports_restart_frame: bool,
286 #[serde(default)]
287 pub supports_restart_request: bool,
288 #[serde(default)]
289 pub supports_goto_targets_request: bool,
290 #[serde(default)]
291 pub supports_step_in_targets_request: bool,
292 #[serde(default)]
293 pub supports_completions_request: bool,
294 #[serde(default)]
295 pub supports_modules_request: bool,
296 #[serde(default)]
297 pub supports_data_breakpoints: bool,
298 #[serde(default)]
299 pub supports_read_memory_request: bool,
300 #[serde(default)]
301 pub supports_disassemble_request: bool,
302 #[serde(default)]
303 pub supports_terminate_request: bool,
304}
305
306#[derive(Debug, Clone, Serialize, Deserialize)]
308pub struct SetBreakpointsResponseBody {
309 pub breakpoints: Vec<Breakpoint>,
310}
311
312#[derive(Debug, Clone, Serialize, Deserialize)]
314#[serde(rename_all = "camelCase")]
315pub struct StackTraceResponseBody {
316 pub stack_frames: Vec<StackFrame>,
317 #[serde(skip_serializing_if = "Option::is_none")]
318 pub total_frames: Option<i64>,
319}
320
321#[derive(Debug, Clone, Serialize, Deserialize)]
323pub struct ThreadsResponseBody {
324 pub threads: Vec<Thread>,
325}
326
327#[derive(Debug, Clone, Serialize, Deserialize)]
329pub struct ScopesResponseBody {
330 pub scopes: Vec<Scope>,
331}
332
333#[derive(Debug, Clone, Serialize, Deserialize)]
335pub struct VariablesResponseBody {
336 pub variables: Vec<Variable>,
337}
338
339#[derive(Debug, Clone, Serialize, Deserialize)]
341#[serde(rename_all = "camelCase")]
342pub struct EvaluateResponseBody {
343 pub result: String,
344 #[serde(rename = "type", skip_serializing_if = "Option::is_none")]
345 pub type_name: Option<String>,
346 #[serde(default)]
347 pub variables_reference: i64,
348}
349
350#[derive(Debug, Clone, Serialize, Deserialize)]
352#[serde(rename_all = "camelCase")]
353pub struct ContinueResponseBody {
354 #[serde(default = "default_true")]
355 pub all_threads_continued: bool,
356}
357
358#[derive(Debug, Clone, Default, Serialize, Deserialize)]
362#[serde(rename_all = "camelCase")]
363pub struct Source {
364 #[serde(skip_serializing_if = "Option::is_none")]
365 pub name: Option<String>,
366 #[serde(skip_serializing_if = "Option::is_none")]
367 pub path: Option<String>,
368 #[serde(skip_serializing_if = "Option::is_none")]
369 pub source_reference: Option<i64>,
370}
371
372#[derive(Debug, Clone, Serialize, Deserialize)]
374#[serde(rename_all = "camelCase")]
375pub struct SourceBreakpoint {
376 pub line: u32,
377 #[serde(skip_serializing_if = "Option::is_none")]
378 pub column: Option<u32>,
379 #[serde(skip_serializing_if = "Option::is_none")]
380 pub condition: Option<String>,
381 #[serde(skip_serializing_if = "Option::is_none")]
382 pub hit_condition: Option<String>,
383 #[serde(skip_serializing_if = "Option::is_none")]
384 pub log_message: Option<String>,
385}
386
387#[derive(Debug, Clone, Serialize, Deserialize)]
389#[serde(rename_all = "camelCase")]
390pub struct FunctionBreakpoint {
391 pub name: String,
392 #[serde(skip_serializing_if = "Option::is_none")]
393 pub condition: Option<String>,
394 #[serde(skip_serializing_if = "Option::is_none")]
395 pub hit_condition: Option<String>,
396}
397
398#[derive(Debug, Clone, Serialize, Deserialize)]
400#[serde(rename_all = "camelCase")]
401pub struct Breakpoint {
402 #[serde(skip_serializing_if = "Option::is_none")]
403 pub id: Option<u32>,
404 pub verified: bool,
405 #[serde(skip_serializing_if = "Option::is_none")]
406 pub message: Option<String>,
407 #[serde(skip_serializing_if = "Option::is_none")]
408 pub source: Option<Source>,
409 #[serde(skip_serializing_if = "Option::is_none")]
410 pub line: Option<u32>,
411 #[serde(skip_serializing_if = "Option::is_none")]
412 pub column: Option<u32>,
413}
414
415#[derive(Debug, Clone, Serialize, Deserialize)]
417#[serde(rename_all = "camelCase")]
418pub struct StackFrame {
419 pub id: i64,
420 pub name: String,
421 #[serde(skip_serializing_if = "Option::is_none")]
422 pub source: Option<Source>,
423 pub line: u32,
424 pub column: u32,
425 #[serde(skip_serializing_if = "Option::is_none")]
426 pub module_id: Option<Value>,
427}
428
429#[derive(Debug, Clone, Serialize, Deserialize)]
431pub struct Thread {
432 pub id: i64,
433 pub name: String,
434}
435
436#[derive(Debug, Clone, Serialize, Deserialize)]
438#[serde(rename_all = "camelCase")]
439pub struct Scope {
440 pub name: String,
441 pub variables_reference: i64,
442 #[serde(default)]
443 pub expensive: bool,
444 #[serde(skip_serializing_if = "Option::is_none")]
445 pub source: Option<Source>,
446 #[serde(skip_serializing_if = "Option::is_none")]
447 pub line: Option<u32>,
448}
449
450#[derive(Debug, Clone, Serialize, Deserialize)]
452#[serde(rename_all = "camelCase")]
453pub struct Variable {
454 pub name: String,
455 pub value: String,
456 #[serde(rename = "type", skip_serializing_if = "Option::is_none")]
457 pub type_name: Option<String>,
458 #[serde(default)]
459 pub variables_reference: i64,
460}
461
462#[derive(Debug, Clone, Serialize, Deserialize)]
466#[serde(rename_all = "camelCase")]
467pub struct StoppedEventBody {
468 pub reason: String,
469 #[serde(skip_serializing_if = "Option::is_none")]
470 pub description: Option<String>,
471 #[serde(skip_serializing_if = "Option::is_none")]
472 pub thread_id: Option<i64>,
473 #[serde(default)]
474 pub all_threads_stopped: bool,
475 #[serde(default, skip_serializing_if = "Vec::is_empty")]
476 pub hit_breakpoint_ids: Vec<u32>,
477 #[serde(skip_serializing_if = "Option::is_none")]
478 pub text: Option<String>,
479}
480
481#[derive(Debug, Clone, Serialize, Deserialize)]
483pub struct OutputEventBody {
484 pub category: Option<String>,
485 pub output: String,
486 #[serde(skip_serializing_if = "Option::is_none")]
487 pub source: Option<Source>,
488 #[serde(skip_serializing_if = "Option::is_none")]
489 pub line: Option<u32>,
490}
491
492#[derive(Debug, Clone, Serialize, Deserialize)]
494#[serde(rename_all = "camelCase")]
495pub struct ThreadEventBody {
496 pub reason: String,
497 pub thread_id: i64,
498}
499
500#[derive(Debug, Clone, Serialize, Deserialize)]
502#[serde(rename_all = "camelCase")]
503pub struct ExitedEventBody {
504 pub exit_code: i32,
505}
506
507#[derive(Debug, Clone, Serialize, Deserialize)]
509pub struct TerminatedEventBody {
510 #[serde(default)]
511 pub restart: bool,
512}
513
514#[derive(Debug, Clone)]
518pub enum Event {
519 Initialized,
520 Stopped(StoppedEventBody),
521 Continued { thread_id: i64, all_threads_continued: bool },
522 Exited(ExitedEventBody),
523 Terminated(Option<TerminatedEventBody>),
524 Thread(ThreadEventBody),
525 Output(OutputEventBody),
526 Breakpoint { reason: String, breakpoint: Breakpoint },
527 Unknown { event: String, body: Option<Value> },
528}
529
530impl Event {
531 pub fn from_message(msg: &EventMessage) -> Self {
533 match msg.event.as_str() {
534 "initialized" => Event::Initialized,
535 "stopped" => {
536 if let Some(body) = &msg.body {
537 if let Ok(stopped) = serde_json::from_value(body.clone()) {
538 return Event::Stopped(stopped);
539 }
540 }
541 Event::Unknown {
542 event: msg.event.clone(),
543 body: msg.body.clone(),
544 }
545 }
546 "continued" => {
547 let thread_id = msg.body.as_ref()
548 .and_then(|b| b.get("threadId"))
549 .and_then(|v| v.as_i64())
550 .unwrap_or(0);
551 let all_threads_continued = msg.body.as_ref()
552 .and_then(|b| b.get("allThreadsContinued"))
553 .and_then(|v| v.as_bool())
554 .unwrap_or(true);
555 Event::Continued { thread_id, all_threads_continued }
556 }
557 "exited" => {
558 if let Some(body) = &msg.body {
559 if let Ok(exited) = serde_json::from_value(body.clone()) {
560 return Event::Exited(exited);
561 }
562 }
563 Event::Exited(ExitedEventBody { exit_code: 0 })
564 }
565 "terminated" => {
566 let body = msg.body.as_ref()
567 .and_then(|b| serde_json::from_value(b.clone()).ok());
568 Event::Terminated(body)
569 }
570 "thread" => {
571 if let Some(body) = &msg.body {
572 if let Ok(thread) = serde_json::from_value(body.clone()) {
573 return Event::Thread(thread);
574 }
575 }
576 Event::Unknown {
577 event: msg.event.clone(),
578 body: msg.body.clone(),
579 }
580 }
581 "output" => {
582 if let Some(body) = &msg.body {
583 if let Ok(output) = serde_json::from_value(body.clone()) {
584 return Event::Output(output);
585 }
586 }
587 Event::Unknown {
588 event: msg.event.clone(),
589 body: msg.body.clone(),
590 }
591 }
592 "breakpoint" => {
593 if let Some(body) = &msg.body {
594 let reason = body.get("reason")
595 .and_then(|v| v.as_str())
596 .unwrap_or("unknown")
597 .to_string();
598 if let Some(bp) = body.get("breakpoint") {
599 if let Ok(breakpoint) = serde_json::from_value(bp.clone()) {
600 return Event::Breakpoint { reason, breakpoint };
601 }
602 }
603 }
604 Event::Unknown {
605 event: msg.event.clone(),
606 body: msg.body.clone(),
607 }
608 }
609 _ => Event::Unknown {
610 event: msg.event.clone(),
611 body: msg.body.clone(),
612 },
613 }
614 }
615}