1use thiserror::Error;
12
13#[derive(Debug, Error)]
15pub enum AppError {
16 #[error("Configuration error: {message}")]
18 Config {
19 message: String,
21 },
22
23 #[error("Storage error: {0}")]
25 Storage(#[from] StorageError),
26
27 #[error("Langbase error: {0}")]
29 Langbase(#[from] LangbaseError),
30
31 #[error("MCP protocol error: {0}")]
33 Mcp(#[from] McpError),
34
35 #[error("Internal error: {message}")]
37 Internal {
38 message: String,
40 },
41}
42
43#[derive(Debug, Error)]
45pub enum StorageError {
46 #[error("Database connection failed: {message}")]
48 Connection {
49 message: String,
51 },
52
53 #[error("Query failed: {message}")]
55 Query {
56 message: String,
58 },
59
60 #[error("Session not found: {session_id}")]
62 SessionNotFound {
63 session_id: String,
65 },
66
67 #[error("Thought not found: {thought_id}")]
69 ThoughtNotFound {
70 thought_id: String,
72 },
73
74 #[error("Migration failed: {message}")]
76 Migration {
77 message: String,
79 },
80
81 #[error("SQLx error: {0}")]
83 Sqlx(#[from] sqlx::Error),
84
85 #[error("Serialization failed: {message}")]
87 Serialization {
88 message: String,
90 },
91}
92
93#[derive(Debug, Error)]
95pub enum LangbaseError {
96 #[error("Langbase unavailable: {message} (retries: {retries})")]
98 Unavailable {
99 message: String,
101 retries: u32,
103 },
104
105 #[error("API error: {status} - {message}")]
107 Api {
108 status: u16,
110 message: String,
112 },
113
114 #[error("Invalid response: {message}")]
116 InvalidResponse {
117 message: String,
119 },
120
121 #[error("Request timeout after {timeout_ms}ms")]
123 Timeout {
124 timeout_ms: u64,
126 },
127
128 #[error("HTTP error: {0}")]
130 Http(#[from] reqwest::Error),
131
132 #[error("Response parse failed for pipe '{pipe}': {message}")]
134 ResponseParseFailed {
135 pipe: String,
137 message: String,
139 raw_response: String,
141 },
142
143 #[error("Pipe not found: {pipe} (verify pipe exists on Langbase)")]
145 PipeNotFound {
146 pipe: String,
148 },
149}
150
151#[derive(Debug, Error)]
153pub enum McpError {
154 #[error("Invalid request: {message}")]
156 InvalidRequest {
157 message: String,
159 },
160
161 #[error("Unknown tool: {tool_name}")]
163 UnknownTool {
164 tool_name: String,
166 },
167
168 #[error("Invalid parameters for {tool_name}: {message}")]
170 InvalidParameters {
171 tool_name: String,
173 message: String,
175 },
176
177 #[error("Tool execution failed: {message}")]
179 ExecutionFailed {
180 message: String,
182 },
183
184 #[error("JSON serialization error: {0}")]
186 Json(#[from] serde_json::Error),
187}
188
189#[derive(Debug, Error)]
191pub enum ToolError {
192 #[error("Validation failed: {field} - {reason}")]
194 Validation {
195 field: String,
197 reason: String,
199 },
200
201 #[error("Session error: {0}")]
203 Session(String),
204
205 #[error("Reasoning failed: {message}")]
207 Reasoning {
208 message: String,
210 },
211
212 #[error("Parse error in {mode} mode: {message}")]
214 ParseFailed {
215 mode: String,
217 message: String,
219 },
220
221 #[error("Pipe unavailable: {pipe} - {reason}")]
223 PipeUnavailable {
224 pipe: String,
226 reason: String,
228 },
229}
230
231#[derive(Debug, Error)]
236pub enum ModeError {
237 #[error("Session state corrupted: {message}")]
239 StateCorrupted {
240 message: String,
242 },
243
244 #[error("Required parameter missing: {param}")]
246 MissingParameter {
247 param: String,
249 },
250
251 #[error("Invalid branch state: {branch_id}")]
253 InvalidBranchState {
254 branch_id: String,
256 },
257
258 #[error("Lock acquisition failed: {resource}")]
260 LockPoisoned {
261 resource: String,
263 },
264
265 #[error("Checkpoint not found: {checkpoint_id}")]
267 CheckpointNotFound {
268 checkpoint_id: String,
270 },
271
272 #[error("Graph node not found: {node_id}")]
274 NodeNotFound {
275 node_id: String,
277 },
278
279 #[error("Invalid confidence value: {value} (must be 0.0-1.0)")]
281 InvalidConfidence {
282 value: f64,
284 },
285
286 #[error("Operation timed out after {timeout_ms}ms")]
288 Timeout {
289 timeout_ms: u64,
291 },
292
293 #[error("Parse error in {context}: {message}")]
295 ParseError {
296 context: String,
298 message: String,
300 },
301}
302
303impl From<ModeError> for AppError {
304 fn from(err: ModeError) -> Self {
305 AppError::Internal {
306 message: err.to_string(),
307 }
308 }
309}
310
311impl From<ModeError> for McpError {
312 fn from(err: ModeError) -> Self {
313 McpError::ExecutionFailed {
314 message: err.to_string(),
315 }
316 }
317}
318
319impl From<ToolError> for AppError {
320 fn from(err: ToolError) -> Self {
321 AppError::Internal {
322 message: err.to_string(),
323 }
324 }
325}
326
327impl From<AppError> for McpError {
328 fn from(err: AppError) -> Self {
329 McpError::ExecutionFailed {
330 message: err.to_string(),
331 }
332 }
333}
334
335pub type AppResult<T> = Result<T, AppError>;
337
338pub type StorageResult<T> = Result<T, StorageError>;
340
341pub type LangbaseResult<T> = Result<T, LangbaseError>;
343
344pub type McpResult<T> = Result<T, McpError>;
346
347pub type ModeResult<T> = Result<T, ModeError>;
349
350#[cfg(test)]
351mod tests {
352 use super::*;
353
354 #[test]
355 fn test_app_error_display() {
356 let err = AppError::Config {
357 message: "missing key".to_string(),
358 };
359 assert_eq!(err.to_string(), "Configuration error: missing key");
360
361 let err = AppError::Internal {
362 message: "unexpected".to_string(),
363 };
364 assert_eq!(err.to_string(), "Internal error: unexpected");
365 }
366
367 #[test]
368 fn test_storage_error_display() {
369 let err = StorageError::Connection {
370 message: "failed to connect".to_string(),
371 };
372 assert_eq!(
373 err.to_string(),
374 "Database connection failed: failed to connect"
375 );
376
377 let err = StorageError::SessionNotFound {
378 session_id: "sess-123".to_string(),
379 };
380 assert_eq!(err.to_string(), "Session not found: sess-123");
381
382 let err = StorageError::ThoughtNotFound {
383 thought_id: "thought-456".to_string(),
384 };
385 assert_eq!(err.to_string(), "Thought not found: thought-456");
386
387 let err = StorageError::Query {
388 message: "syntax error".to_string(),
389 };
390 assert_eq!(err.to_string(), "Query failed: syntax error");
391
392 let err = StorageError::Migration {
393 message: "version mismatch".to_string(),
394 };
395 assert_eq!(err.to_string(), "Migration failed: version mismatch");
396
397 let err = StorageError::Serialization {
398 message: "invalid utf-8 in metadata".to_string(),
399 };
400 assert_eq!(
401 err.to_string(),
402 "Serialization failed: invalid utf-8 in metadata"
403 );
404 }
405
406 #[test]
407 fn test_langbase_error_display() {
408 let err = LangbaseError::Unavailable {
409 message: "server down".to_string(),
410 retries: 3,
411 };
412 assert_eq!(
413 err.to_string(),
414 "Langbase unavailable: server down (retries: 3)"
415 );
416
417 let err = LangbaseError::Api {
418 status: 401,
419 message: "unauthorized".to_string(),
420 };
421 assert_eq!(err.to_string(), "API error: 401 - unauthorized");
422
423 let err = LangbaseError::InvalidResponse {
424 message: "malformed JSON".to_string(),
425 };
426 assert_eq!(err.to_string(), "Invalid response: malformed JSON");
427
428 let err = LangbaseError::Timeout { timeout_ms: 5000 };
429 assert_eq!(err.to_string(), "Request timeout after 5000ms");
430 }
431
432 #[test]
433 fn test_mcp_error_display() {
434 let err = McpError::InvalidRequest {
435 message: "bad format".to_string(),
436 };
437 assert_eq!(err.to_string(), "Invalid request: bad format");
438
439 let err = McpError::UnknownTool {
440 tool_name: "nonexistent".to_string(),
441 };
442 assert_eq!(err.to_string(), "Unknown tool: nonexistent");
443
444 let err = McpError::InvalidParameters {
445 tool_name: "reasoning.linear".to_string(),
446 message: "missing content".to_string(),
447 };
448 assert_eq!(
449 err.to_string(),
450 "Invalid parameters for reasoning.linear: missing content"
451 );
452
453 let err = McpError::ExecutionFailed {
454 message: "pipe failed".to_string(),
455 };
456 assert_eq!(err.to_string(), "Tool execution failed: pipe failed");
457 }
458
459 #[test]
460 fn test_tool_error_display() {
461 let err = ToolError::Validation {
462 field: "content".to_string(),
463 reason: "cannot be empty".to_string(),
464 };
465 assert_eq!(
466 err.to_string(),
467 "Validation failed: content - cannot be empty"
468 );
469
470 let err = ToolError::Session("not found".to_string());
471 assert_eq!(err.to_string(), "Session error: not found");
472
473 let err = ToolError::Reasoning {
474 message: "logic error".to_string(),
475 };
476 assert_eq!(err.to_string(), "Reasoning failed: logic error");
477 }
478
479 #[test]
480 fn test_tool_error_conversion_to_app_error() {
481 let tool_err = ToolError::Validation {
482 field: "test".to_string(),
483 reason: "invalid".to_string(),
484 };
485 let app_err: AppError = tool_err.into();
486 assert!(matches!(app_err, AppError::Internal { .. }));
487 assert!(app_err.to_string().contains("Validation failed"));
488 }
489
490 #[test]
491 fn test_app_error_conversion_to_mcp_error() {
492 let app_err = AppError::Config {
493 message: "test error".to_string(),
494 };
495 let mcp_err: McpError = app_err.into();
496 assert!(matches!(mcp_err, McpError::ExecutionFailed { .. }));
497 assert!(mcp_err.to_string().contains("Configuration error"));
498 }
499
500 #[test]
501 fn test_storage_error_conversion_to_app_error() {
502 let storage_err = StorageError::SessionNotFound {
503 session_id: "test-123".to_string(),
504 };
505 let app_err: AppError = storage_err.into();
506 assert!(matches!(app_err, AppError::Storage(_)));
507 }
508
509 #[test]
510 fn test_langbase_error_conversion_to_app_error() {
511 let langbase_err = LangbaseError::Timeout { timeout_ms: 1000 };
512 let app_err: AppError = langbase_err.into();
513 assert!(matches!(app_err, AppError::Langbase(_)));
514 }
515
516 #[test]
517 fn test_mcp_error_conversion_to_app_error() {
518 let mcp_err = McpError::UnknownTool {
519 tool_name: "test".to_string(),
520 };
521 let app_err: AppError = mcp_err.into();
522 assert!(matches!(app_err, AppError::Mcp(_)));
523 }
524
525 #[test]
528 fn test_app_error_storage_variant_display() {
529 let storage_err = StorageError::Query {
530 message: "syntax error".to_string(),
531 };
532 let app_err = AppError::Storage(storage_err);
533 assert!(app_err.to_string().contains("Storage error"));
534 assert!(app_err.to_string().contains("syntax error"));
535 }
536
537 #[test]
538 fn test_app_error_langbase_variant_display() {
539 let langbase_err = LangbaseError::Api {
540 status: 500,
541 message: "internal server error".to_string(),
542 };
543 let app_err = AppError::Langbase(langbase_err);
544 assert!(app_err.to_string().contains("Langbase error"));
545 assert!(app_err.to_string().contains("500"));
546 }
547
548 #[test]
549 fn test_app_error_mcp_variant_display() {
550 let mcp_err = McpError::InvalidParameters {
551 tool_name: "test_tool".to_string(),
552 message: "missing field".to_string(),
553 };
554 let app_err = AppError::Mcp(mcp_err);
555 assert!(app_err.to_string().contains("MCP protocol error"));
556 assert!(app_err.to_string().contains("test_tool"));
557 }
558
559 #[test]
560 fn test_storage_error_conversion_from_sqlx() {
561 let sqlx_err = sqlx::Error::RowNotFound;
562 let storage_err: StorageError = sqlx_err.into();
563 assert!(matches!(storage_err, StorageError::Sqlx(_)));
564 }
565
566 #[test]
567 fn test_langbase_error_http_variant_display() {
568 }
573
574 #[test]
575 fn test_mcp_error_conversion_from_serde_json() {
576 let json_err = serde_json::from_str::<serde_json::Value>("invalid json").unwrap_err();
577 let mcp_err: McpError = json_err.into();
578 assert!(matches!(mcp_err, McpError::Json(_)));
579 }
580
581 #[test]
582 fn test_tool_error_to_app_error_to_mcp_error_chain() {
583 let tool_err = ToolError::Reasoning {
584 message: "inference failed".to_string(),
585 };
586 let app_err: AppError = tool_err.into();
587 let mcp_err: McpError = app_err.into();
588 assert!(matches!(mcp_err, McpError::ExecutionFailed { .. }));
589 assert!(mcp_err.to_string().contains("Reasoning failed"));
590 }
591
592 #[test]
593 fn test_storage_error_to_app_error_to_mcp_error_chain() {
594 let storage_err = StorageError::Connection {
595 message: "db offline".to_string(),
596 };
597 let app_err: AppError = storage_err.into();
598 let mcp_err: McpError = app_err.into();
599 assert!(matches!(mcp_err, McpError::ExecutionFailed { .. }));
600 assert!(mcp_err.to_string().contains("Database connection failed"));
601 }
602
603 #[test]
604 fn test_langbase_error_to_app_error_to_mcp_error_chain() {
605 let langbase_err = LangbaseError::InvalidResponse {
606 message: "malformed response".to_string(),
607 };
608 let app_err: AppError = langbase_err.into();
609 let mcp_err: McpError = app_err.into();
610 assert!(matches!(mcp_err, McpError::ExecutionFailed { .. }));
611 assert!(mcp_err.to_string().contains("Invalid response"));
612 }
613
614 #[test]
615 fn test_storage_error_serialization_variant() {
616 let err = StorageError::Serialization {
617 message: "json parse error".to_string(),
618 };
619 let display = err.to_string();
620 assert!(display.contains("Serialization failed"));
621 assert!(display.contains("json parse error"));
622 }
623
624 #[test]
625 fn test_langbase_error_unavailable_with_zero_retries() {
626 let err = LangbaseError::Unavailable {
627 message: "immediate failure".to_string(),
628 retries: 0,
629 };
630 assert!(err.to_string().contains("retries: 0"));
631 }
632
633 #[test]
634 fn test_langbase_error_unavailable_with_high_retries() {
635 let err = LangbaseError::Unavailable {
636 message: "persistent failure".to_string(),
637 retries: 999,
638 };
639 assert!(err.to_string().contains("retries: 999"));
640 }
641
642 #[test]
643 fn test_langbase_error_api_with_various_status_codes() {
644 let err_400 = LangbaseError::Api {
645 status: 400,
646 message: "bad request".to_string(),
647 };
648 assert!(err_400.to_string().contains("400"));
649
650 let err_403 = LangbaseError::Api {
651 status: 403,
652 message: "forbidden".to_string(),
653 };
654 assert!(err_403.to_string().contains("403"));
655
656 let err_503 = LangbaseError::Api {
657 status: 503,
658 message: "service unavailable".to_string(),
659 };
660 assert!(err_503.to_string().contains("503"));
661 }
662
663 #[test]
664 fn test_langbase_error_timeout_various_durations() {
665 let err_short = LangbaseError::Timeout { timeout_ms: 100 };
666 assert!(err_short.to_string().contains("100ms"));
667
668 let err_long = LangbaseError::Timeout { timeout_ms: 60000 };
669 assert!(err_long.to_string().contains("60000ms"));
670 }
671
672 #[test]
673 fn test_tool_error_session_variant_with_various_messages() {
674 let err1 = ToolError::Session("session expired".to_string());
675 assert!(err1.to_string().contains("session expired"));
676
677 let err2 = ToolError::Session("session locked".to_string());
678 assert!(err2.to_string().contains("session locked"));
679
680 let err3 = ToolError::Session("session corrupt".to_string());
681 assert!(err3.to_string().contains("session corrupt"));
682 }
683
684 #[test]
685 fn test_tool_error_validation_field_names() {
686 let err = ToolError::Validation {
687 field: "max_depth".to_string(),
688 reason: "must be between 1 and 10".to_string(),
689 };
690 assert!(err.to_string().contains("max_depth"));
691 assert!(err.to_string().contains("must be between 1 and 10"));
692 }
693
694 #[test]
695 fn test_app_error_debug_format() {
696 let err = AppError::Config {
697 message: "test".to_string(),
698 };
699 let debug_str = format!("{:?}", err);
700 assert!(debug_str.contains("Config"));
701 assert!(debug_str.contains("test"));
702 }
703
704 #[test]
705 fn test_storage_error_debug_format() {
706 let err = StorageError::Migration {
707 message: "failed migration".to_string(),
708 };
709 let debug_str = format!("{:?}", err);
710 assert!(debug_str.contains("Migration"));
711 assert!(debug_str.contains("failed migration"));
712 }
713
714 #[test]
715 fn test_langbase_error_debug_format() {
716 let err = LangbaseError::Timeout { timeout_ms: 3000 };
717 let debug_str = format!("{:?}", err);
718 assert!(debug_str.contains("Timeout"));
719 assert!(debug_str.contains("3000"));
720 }
721
722 #[test]
723 fn test_mcp_error_debug_format() {
724 let err = McpError::UnknownTool {
725 tool_name: "mystery_tool".to_string(),
726 };
727 let debug_str = format!("{:?}", err);
728 assert!(debug_str.contains("UnknownTool"));
729 assert!(debug_str.contains("mystery_tool"));
730 }
731
732 #[test]
733 fn test_tool_error_debug_format() {
734 let err = ToolError::Reasoning {
735 message: "logic failed".to_string(),
736 };
737 let debug_str = format!("{:?}", err);
738 assert!(debug_str.contains("Reasoning"));
739 assert!(debug_str.contains("logic failed"));
740 }
741
742 #[test]
743 fn test_error_equality_via_string_representation() {
744 let err1 = StorageError::SessionNotFound {
745 session_id: "test-id".to_string(),
746 };
747 let err2 = StorageError::SessionNotFound {
748 session_id: "test-id".to_string(),
749 };
750 assert_eq!(err1.to_string(), err2.to_string());
751 }
752
753 #[test]
754 fn test_nested_error_display_preservation() {
755 let storage_err = StorageError::ThoughtNotFound {
756 thought_id: "thought-999".to_string(),
757 };
758 let original_msg = storage_err.to_string();
759
760 let app_err: AppError = storage_err.into();
761 assert!(app_err.to_string().contains(&original_msg));
762 }
763
764 #[test]
765 fn test_app_result_type_alias() {
766 fn returns_app_result() -> AppResult<String> {
767 Ok("success".to_string())
768 }
769 assert!(returns_app_result().is_ok());
770 }
771
772 #[test]
773 fn test_storage_result_type_alias() {
774 fn returns_storage_result() -> StorageResult<i32> {
775 Err(StorageError::Query {
776 message: "test".to_string(),
777 })
778 }
779 assert!(returns_storage_result().is_err());
780 }
781
782 #[test]
783 fn test_langbase_result_type_alias() {
784 fn returns_langbase_result() -> LangbaseResult<bool> {
785 Ok(true)
786 }
787 assert!(returns_langbase_result().unwrap());
788 }
789
790 #[test]
791 fn test_mcp_result_type_alias() {
792 fn returns_mcp_result() -> McpResult<()> {
793 Err(McpError::InvalidRequest {
794 message: "test".to_string(),
795 })
796 }
797 assert!(returns_mcp_result().is_err());
798 }
799
800 #[test]
801 fn test_multiple_error_conversions_in_sequence() {
802 let tool_err = ToolError::Validation {
803 field: "depth".to_string(),
804 reason: "negative value".to_string(),
805 };
806
807 let app_err: AppError = tool_err.into();
808 assert!(app_err.to_string().contains("Validation failed"));
809 assert!(app_err.to_string().contains("depth"));
810
811 let mcp_err: McpError = app_err.into();
812 assert!(mcp_err.to_string().contains("Tool execution failed"));
813 assert!(mcp_err.to_string().contains("Validation failed"));
814 }
815
816 #[test]
817 fn test_error_messages_with_special_characters() {
818 let err = AppError::Internal {
819 message: "Error: \"quotes\" and 'apostrophes' and \\ backslashes".to_string(),
820 };
821 let display = err.to_string();
822 assert!(display.contains("quotes"));
823 assert!(display.contains("apostrophes"));
824 assert!(display.contains("backslashes"));
825 }
826
827 #[test]
828 fn test_error_messages_with_unicode() {
829 let err = StorageError::Query {
830 message: "Invalid character: \u{1F4A5}".to_string(),
831 };
832 assert!(err.to_string().contains("\u{1F4A5}"));
833 }
834
835 #[test]
836 fn test_empty_error_messages() {
837 let err1 = AppError::Config {
838 message: "".to_string(),
839 };
840 assert_eq!(err1.to_string(), "Configuration error: ");
841
842 let err2 = ToolError::Session("".to_string());
843 assert_eq!(err2.to_string(), "Session error: ");
844 }
845
846 #[test]
847 fn test_very_long_error_messages() {
848 let long_msg = "a".repeat(1000);
849 let err = LangbaseError::InvalidResponse {
850 message: long_msg.clone(),
851 };
852 assert!(err.to_string().contains(&long_msg));
853 }
854
855 #[test]
856 fn test_error_trait_source_method() {
857 use std::error::Error;
858
859 let json_err = serde_json::from_str::<serde_json::Value>("bad").unwrap_err();
860 let mcp_err = McpError::Json(json_err);
861
862 assert!(mcp_err.source().is_some());
863 }
864
865 #[test]
868 fn test_langbase_error_response_parse_failed() {
869 let err = LangbaseError::ResponseParseFailed {
870 pipe: "linear-reasoning-v1".to_string(),
871 message: "expected object, found array".to_string(),
872 raw_response: "[1, 2, 3]".to_string(),
873 };
874 let display = err.to_string();
875 assert!(display.contains("Response parse failed"));
876 assert!(display.contains("linear-reasoning-v1"));
877 assert!(display.contains("expected object, found array"));
878 }
879
880 #[test]
881 fn test_langbase_error_pipe_not_found() {
882 let err = LangbaseError::PipeNotFound {
883 pipe: "nonexistent-pipe-v1".to_string(),
884 };
885 let display = err.to_string();
886 assert!(display.contains("Pipe not found"));
887 assert!(display.contains("nonexistent-pipe-v1"));
888 assert!(display.contains("verify pipe exists on Langbase"));
889 }
890
891 #[test]
892 fn test_tool_error_parse_failed() {
893 let err = ToolError::ParseFailed {
894 mode: "auto".to_string(),
895 message: "JSON syntax error at line 1".to_string(),
896 };
897 let display = err.to_string();
898 assert!(display.contains("Parse error in auto mode"));
899 assert!(display.contains("JSON syntax error"));
900 }
901
902 #[test]
903 fn test_tool_error_pipe_unavailable() {
904 let err = ToolError::PipeUnavailable {
905 pipe: "decision-framework-v1".to_string(),
906 reason: "API returned 503 Service Unavailable".to_string(),
907 };
908 let display = err.to_string();
909 assert!(display.contains("Pipe unavailable"));
910 assert!(display.contains("decision-framework-v1"));
911 assert!(display.contains("503"));
912 }
913
914 #[test]
915 fn test_tool_error_parse_failed_conversion_to_app_error() {
916 let tool_err = ToolError::ParseFailed {
917 mode: "got_generate".to_string(),
918 message: "missing required field 'continuations'".to_string(),
919 };
920 let app_err: AppError = tool_err.into();
921 assert!(matches!(app_err, AppError::Internal { .. }));
922 assert!(app_err.to_string().contains("Parse error"));
923 }
924
925 #[test]
926 fn test_tool_error_pipe_unavailable_conversion_to_app_error() {
927 let tool_err = ToolError::PipeUnavailable {
928 pipe: "test-pipe".to_string(),
929 reason: "connection refused".to_string(),
930 };
931 let app_err: AppError = tool_err.into();
932 assert!(matches!(app_err, AppError::Internal { .. }));
933 assert!(app_err.to_string().contains("Pipe unavailable"));
934 }
935
936 #[test]
937 fn test_langbase_error_response_parse_failed_debug() {
938 let err = LangbaseError::ResponseParseFailed {
939 pipe: "test".to_string(),
940 message: "error".to_string(),
941 raw_response: "raw".to_string(),
942 };
943 let debug_str = format!("{:?}", err);
944 assert!(debug_str.contains("ResponseParseFailed"));
945 assert!(debug_str.contains("test"));
946 }
947
948 #[test]
949 fn test_langbase_error_pipe_not_found_debug() {
950 let err = LangbaseError::PipeNotFound {
951 pipe: "missing-pipe".to_string(),
952 };
953 let debug_str = format!("{:?}", err);
954 assert!(debug_str.contains("PipeNotFound"));
955 assert!(debug_str.contains("missing-pipe"));
956 }
957}