@@ -123,15 +123,37 @@ pub struct LlmBridge {
123123 session_manager : Arc < SessionManager > ,
124124 /// Budget trackers per session.
125125 budget_trackers : dashmap:: DashMap < SessionId , Arc < BudgetTracker > > ,
126+ /// Optional real LLM client. When `None`, `query()` returns
127+ /// `LlmNotConfigured` instead of a silent stub.
128+ #[ cfg( feature = "llm" ) ]
129+ llm_client : Option < Arc < dyn terraphim_service:: llm:: LlmClient > > ,
126130}
127131
128132impl LlmBridge {
129- /// Create a new LLM bridge.
133+ /// Create a new LLM bridge without a real LLM client.
134+ /// Queries will return `LlmNotConfigured`.
130135 pub fn new ( config : LlmBridgeConfig , session_manager : Arc < SessionManager > ) -> Self {
131136 Self {
132137 config,
133138 session_manager,
134139 budget_trackers : dashmap:: DashMap :: new ( ) ,
140+ #[ cfg( feature = "llm" ) ]
141+ llm_client : None ,
142+ }
143+ }
144+
145+ /// Create a new LLM bridge with a configured LLM client.
146+ #[ cfg( feature = "llm" ) ]
147+ pub fn with_llm_client (
148+ config : LlmBridgeConfig ,
149+ session_manager : Arc < SessionManager > ,
150+ client : Arc < dyn terraphim_service:: llm:: LlmClient > ,
151+ ) -> Self {
152+ Self {
153+ config,
154+ session_manager,
155+ budget_trackers : dashmap:: DashMap :: new ( ) ,
156+ llm_client : Some ( client) ,
135157 }
136158 }
137159
@@ -189,16 +211,34 @@ impl LlmBridge {
189211
190212 let start = std:: time:: Instant :: now ( ) ;
191213
192- // TODO: Actually call the LLM service
193- // For now, return a stub response
194- let response_text = format ! (
195- "[LLM Bridge stub] Query: {}..." ,
196- if request. prompt. len( ) > 50 {
197- & request. prompt[ ..50 ]
198- } else {
199- & request. prompt
214+ #[ cfg( feature = "llm" ) ]
215+ let response_text = match & self . llm_client {
216+ Some ( client) => {
217+ let chat_opts = terraphim_service:: llm:: ChatOptions {
218+ max_tokens : request. max_tokens . map ( |t| t as u32 ) ,
219+ temperature : request. temperature ,
220+ } ;
221+ let messages = vec ! [ serde_json:: json!( {
222+ "role" : "user" ,
223+ "content" : request. prompt
224+ } ) ] ;
225+ client
226+ . chat_completion ( messages, chat_opts)
227+ . await
228+ . map_err ( |e| RlmError :: LlmCallFailed {
229+ message : e. to_string ( ) ,
230+ } ) ?
231+ }
232+ None => {
233+ return Err ( RlmError :: LlmNotConfigured ) ;
200234 }
201- ) ;
235+ } ;
236+
237+ #[ cfg( not( feature = "llm" ) ) ]
238+ {
239+ let _request = request;
240+ return Err ( RlmError :: LlmNotConfigured ) ;
241+ }
202242
203243 // Estimate tokens (1 token ~= 4 chars for English text)
204244 let estimated_tokens = ( request. prompt . len ( ) / 4 + response_text. len ( ) / 4 ) as u64 ;
0 commit comments