cortexai_cloudflare/
http.rs1use crate::error::{CloudflareError, Result};
4use cortexai_llm_client::{HttpRequest, LlmResponse, Provider, ResponseParser};
5use worker::Fetch;
6
7pub struct CloudflareHttpClient;
9
10impl CloudflareHttpClient {
11 pub async fn execute(request: HttpRequest) -> Result<LlmResponse> {
13 let mut headers = worker::Headers::new();
14 for (key, value) in &request.headers {
15 headers
16 .set(key, value)
17 .map_err(|e| CloudflareError::HttpError(e.to_string()))?;
18 }
19
20 let mut init = worker::RequestInit::new();
21 init.with_method(worker::Method::Post);
22 init.with_headers(headers);
23 init.with_body(Some(wasm_bindgen::JsValue::from_str(&request.body)));
24
25 let worker_request = worker::Request::new_with_init(&request.url, &init)
26 .map_err(|e| CloudflareError::HttpError(e.to_string()))?;
27
28 let mut response = Fetch::Request(worker_request)
29 .send()
30 .await
31 .map_err(|e| CloudflareError::HttpError(e.to_string()))?;
32
33 let status = response.status_code();
34 let body = response
35 .text()
36 .await
37 .map_err(|e| CloudflareError::HttpError(e.to_string()))?;
38
39 if status != 200 {
40 return Err(CloudflareError::ProviderError(format!(
41 "HTTP {}: {}",
42 status, body
43 )));
44 }
45
46 let provider = extract_provider_from_url(&request.url);
48 let llm_response = ResponseParser::parse(provider, &body)?;
49
50 Ok(llm_response)
51 }
52
53 pub async fn execute_stream(request: HttpRequest) -> Result<worker::Response> {
55 let mut headers = worker::Headers::new();
56 for (key, value) in &request.headers {
57 headers
58 .set(key, value)
59 .map_err(|e| CloudflareError::HttpError(e.to_string()))?;
60 }
61
62 let mut init = worker::RequestInit::new();
63 init.with_method(worker::Method::Post);
64 init.with_headers(headers);
65 init.with_body(Some(wasm_bindgen::JsValue::from_str(&request.body)));
66
67 let worker_request = worker::Request::new_with_init(&request.url, &init)
68 .map_err(|e| CloudflareError::HttpError(e.to_string()))?;
69
70 let response = Fetch::Request(worker_request)
71 .send()
72 .await
73 .map_err(|e| CloudflareError::HttpError(e.to_string()))?;
74
75 let status = response.status_code();
76 if status != 200 {
77 return Err(CloudflareError::ProviderError(format!(
78 "HTTP {} error",
79 status
80 )));
81 }
82
83 Ok(response)
84 }
85}
86
87fn extract_provider_from_url(url: &str) -> Provider {
89 if url.contains("anthropic") {
90 Provider::Anthropic
91 } else if url.contains("openrouter") {
92 Provider::OpenRouter
93 } else {
94 Provider::OpenAI
95 }
96}
97
98#[cfg(test)]
99mod tests {
100 use super::*;
101
102 #[test]
103 fn test_extract_provider() {
104 assert!(matches!(
105 extract_provider_from_url("https://api.anthropic.com/v1/messages"),
106 Provider::Anthropic
107 ));
108 assert!(matches!(
109 extract_provider_from_url("https://openrouter.ai/api/v1/chat"),
110 Provider::OpenRouter
111 ));
112 assert!(matches!(
113 extract_provider_from_url("https://api.openai.com/v1/chat/completions"),
114 Provider::OpenAI
115 ));
116 }
117}