1pub use genai;
2
3pub trait LLMSafe {}
4
5impl<T: LLMSafe> LLMSafe for Vec<T> {}
6impl<T: LLMSafe> LLMSafe for Option<T> {}
7impl<T: LLMSafe> LLMSafe for Box<T> {}
8impl<T: LLMSafe> LLMSafe for &T {}
9impl<T: LLMSafe> LLMSafe for [T] {}
10impl<T: LLMSafe, const N: usize> LLMSafe for [T; N] {}
11use std::collections::HashMap;
12impl<K: LLMSafe, V: LLMSafe> LLMSafe for HashMap<K, V> {}
13
14pub use synapto_derive::LLMSafe;
15
16#[derive(
17 Clone,
18 Copy,
19 Debug,
20 serde::Serialize,
21 serde::Deserialize,
22 schemars::JsonSchema,
23 PartialEq,
24 Eq,
25 Default,
26)]
27pub enum ReasoningEffort {
28 #[default]
29 None,
30 Minimal,
31 Low,
32 Medium,
33 High,
34}
35
36#[derive(
37 Clone, Debug, serde::Serialize, serde::Deserialize, schemars::JsonSchema, PartialEq, Eq,
38)]
39pub struct ModelConfig {
40 pub model: String,
41 #[serde(default)]
42 pub reasoning_effort: ReasoningEffort,
43}
44
45#[derive(Debug, Default, Clone)]
46pub struct RawLlmOptions {
47 pub reasoning_effort: Option<genai::chat::ReasoningEffort>,
48 pub tools: Option<Vec<genai::chat::Tool>>,
49 pub resolved_tools: Option<Vec<(genai::chat::ToolCall, String)>>,
50 pub output_schema: Option<schemars::Schema>,
51 pub messages: Option<Vec<genai::chat::ChatMessage>>,
52}
53
54#[doc(hidden)]
56#[async_trait::async_trait]
57pub trait RawLlmExecutor: Send + Sync + 'static {
58 async fn execute_raw(
59 &self,
60 model: &str,
61 system_prompt: &str,
62 prompt: &str,
63 options: RawLlmOptions,
64 ) -> Result<genai::chat::ChatResponse, String>;
65}
66
67#[doc(hidden)]
68#[async_trait::async_trait]
69impl<T: RawLlmExecutor + ?Sized> RawLlmExecutor for std::sync::Arc<T> {
70 async fn execute_raw(
71 &self,
72 model: &str,
73 system_prompt: &str,
74 prompt: &str,
75 options: RawLlmOptions,
76 ) -> Result<genai::chat::ChatResponse, String> {
77 (**self)
78 .execute_raw(model, system_prompt, prompt, options)
79 .await
80 }
81}
82
83#[derive(Clone)]
88pub struct LlmExecutor {
89 backend: std::sync::Arc<dyn RawLlmExecutor>,
90}
91
92impl std::fmt::Debug for LlmExecutor {
93 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
94 f.debug_struct("LlmExecutor").finish_non_exhaustive()
95 }
96}
97
98impl LlmExecutor {
99 pub fn new<B: RawLlmExecutor + 'static>(backend: B) -> Self {
100 Self {
101 backend: std::sync::Arc::new(backend),
102 }
103 }
104
105 pub fn from_arc(backend: std::sync::Arc<dyn RawLlmExecutor>) -> Self {
106 Self { backend }
107 }
108
109 #[doc(hidden)]
110 pub async fn execute_internal(
111 &self,
112 model: &str,
113 system_prompt: &str,
114 prompt: &str,
115 options: RawLlmOptions,
116 ) -> Result<genai::chat::ChatResponse, String> {
117 self.backend
118 .execute_raw(model, system_prompt, prompt, options)
119 .await
120 }
121}