(
&self,
base_url: &str,
api_key: &Option<String>,
model: &str,
messages: &[ConversationMessage],
agent_run_id: &str,
token_sink: &S,
)
| 1107 | } |
| 1108 | |
| 1109 | async fn send_openai_compatible_with_tools<S: TokenSink + Sync>( |
| 1110 | &self, |
| 1111 | base_url: &str, |
| 1112 | api_key: &Option<String>, |
| 1113 | model: &str, |
| 1114 | messages: &[ConversationMessage], |
| 1115 | agent_run_id: &str, |
| 1116 | token_sink: &S, |
| 1117 | ) -> AppResult<LLMTurn> { |
| 1118 | let endpoint = format!("{}/chat/completions", base_url.trim_end_matches('/')); |
| 1119 | |
| 1120 | let payload = json!({ |
| 1121 | "model": model, |
| 1122 | "messages": to_openai_messages(messages), |
| 1123 | "tools": openai_tool_definitions(), |
| 1124 | "stream": true, |
| 1125 | }); |
| 1126 | |
| 1127 | let client = crate::services::http_client::streaming_client()?; |
| 1128 | let mut request = client |
| 1129 | .post(endpoint) |
| 1130 | .header(CONTENT_TYPE, "application/json") |
| 1131 | .json(&payload); |
| 1132 | |
| 1133 | if let Some(key) = api_key.as_deref().filter(|k| !k.trim().is_empty()) { |
| 1134 | request = request.header(AUTHORIZATION, format!("Bearer {key}")); |
| 1135 | } |
| 1136 | |
| 1137 | let response = request.send().await?; |
| 1138 | if !response.status().is_success() { |
| 1139 | let status = response.status(); |
| 1140 | let body = response.text().await.unwrap_or_default(); |
| 1141 | return Err(AppError::Http(format!("{status}: {body}"))); |
| 1142 | } |
| 1143 | |
| 1144 | self.stream_openai_tool_sse(response, agent_run_id, token_sink) |
| 1145 | .await |
| 1146 | } |
| 1147 | |
| 1148 | #[allow(clippy::too_many_arguments)] |
| 1149 | async fn send_anthropic_with_tools<S: TokenSink + Sync>( |
no test coverage detected