use crate::ai::Request;
use std::hash::{Hash, Hasher};
pub const BASE_URL: &str = "https://opencode.ai/inference/go/openai/v1";
const GO_MODELS_URL: &str = "https://opencode.ai/inference/go/v1/models";
pub(crate) fn is_opencode(base_url: &str) -> bool {
base_url.starts_with("https://opencode.ai/")
}
pub(crate) fn models_url(base_url: &str) -> Option<String> {
base_url.starts_with("https://opencode.ai/inference/go").then(|| GO_MODELS_URL.to_owned())
}
pub(crate) fn headers(request: &Request) -> [(String, String); 2] {
let mut hasher = std::collections::hash_map::DefaultHasher::new();
if let Some(first) = request.messages.first() {
format!("{:?}", first.blocks).hash(&mut hasher);
}
[
("user-agent".to_owned(), concat!("aura/", env!("CARGO_PKG_VERSION")).to_owned()),
("x-opencode-session".to_owned(), format!("aura-{:016x}", hasher.finish())),
]
}
#[cfg(test)]
mod tests {
use super::*;
use crate::ai::{Message, Provider, ProviderKind};
fn request(messages: Vec<Message>) -> Request {
Request { model: "deepseek-v4.1-flash".into(), system: None, messages, tools: Vec::new(), max_tokens: 1 }
}
#[test]
fn la_sesion_es_estable_en_la_conversacion_y_distinta_entre_conversaciones() {
let first = headers(&request(vec![Message::user("hola")]));
let later = headers(&request(vec![Message::user("hola"), Message::user("sigue")]));
let other = headers(&request(vec![Message::user("otra cosa")]));
assert_eq!(first[1], later[1], "el mismo hilo conserva la sesión");
assert_ne!(first[1], other[1]);
assert!(first[0].1.starts_with("aura/"), "se identifica como Aura y no como la librería HTTP");
}
#[test]
fn go_usa_su_lista_de_modelos_y_zen_la_de_siempre() {
let at = |base_url: &str| {
Provider { kind: ProviderKind::OpenAiCompatible, base_url: base_url.into(), api_key: None, effort: None }
.models_endpoint()
.0
};
assert_eq!(at(BASE_URL), GO_MODELS_URL);
assert_eq!(at("https://opencode.ai/zen/v1"), "https://opencode.ai/zen/v1/models");
assert!(is_opencode(BASE_URL) && !is_opencode("https://api.openai.com/v1"));
}
}