(&self, request: LlmRequest)
| 192 | } |
| 193 | |
| 194 | async fn complete(&self, request: LlmRequest) -> GraphBitResult<LlmResponse> { |
| 195 | let url = format!("{}/chat/completions", self.base_url); |
| 196 | |
| 197 | let messages: Vec<Ai21Message> = |
| 198 | request.messages.iter().map(Self::convert_message).collect(); |
| 199 | |
| 200 | let tools: Option<Vec<Ai21Tool>> = if request.tools.is_empty() { |
| 201 | None |
| 202 | } else { |
| 203 | Some(request.tools.iter().map(Self::convert_tool).collect()) |
| 204 | }; |
| 205 | |
| 206 | let body = Ai21Request { |
| 207 | model: self.model.clone(), |
| 208 | messages, |
| 209 | max_tokens: request.max_tokens, |
| 210 | temperature: request.temperature, |
| 211 | top_p: request.top_p, |
| 212 | tools: tools.clone(), |
| 213 | tool_choice: if tools.is_some() { |
| 214 | Some("auto".to_string()) |
| 215 | } else { |
| 216 | None |
| 217 | }, |
| 218 | }; |
| 219 | |
| 220 | // Merge extra_params into request JSON |
| 221 | let mut req_json = serde_json::to_value(&body)?; |
| 222 | if let serde_json::Value::Object(ref mut map) = req_json { |
| 223 | for (k, v) in request.extra_params { |
| 224 | map.insert(k, v); |
| 225 | } |
| 226 | } |
| 227 | |
| 228 | let mut builder = self |
| 229 | .client |
| 230 | .post(&url) |
| 231 | .header("Authorization", format!("Bearer {}", self.api_key)) |
| 232 | .header("Content-Type", "application/json") |
| 233 | .json(&req_json); |
| 234 | |
| 235 | if let Some(org) = &self.organization { |
| 236 | builder = builder.header("Ai21-Organization", org); |
| 237 | } |
| 238 | |
| 239 | let resp = builder |
| 240 | .send() |
| 241 | .await |
| 242 | .map_err(|e| GraphBitError::llm_provider("ai21", format!("Request failed: {e}")))?; |
| 243 | |
| 244 | if !resp.status().is_success() { |
| 245 | let text = resp |
| 246 | .text() |
| 247 | .await |
| 248 | .unwrap_or_else(|_| "Unknown error".to_string()); |
| 249 | return Err(GraphBitError::llm_provider( |
| 250 | "ai21", |
| 251 | format!("API error: {text}"), |
nothing calls this directly
no test coverage detected