#![allow(clippy::module_name_repetitions)]
use lsp_types::{Range, Url};
use serde::{Deserialize, Serialize};
pub const METHOD: &str = "axon/askAdvisor";
pub const ENV_ENABLED: &str = "AXON_LSP_LLM_ENABLED";
pub const ENV_BACKEND: &str = "AXON_LLM_BACKEND";
pub const ENV_MODEL: &str = "AXON_LLM_MODEL";
pub const ENV_ANTHROPIC_KEY: &str = "ANTHROPIC_API_KEY";
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct CodeContext {
pub uri: Url,
pub range: Range,
#[serde(default)]
pub text: String,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct AskRequest {
pub question: String,
#[serde(default)]
pub context: Option<CodeContext>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Citation {
pub uri: Url,
pub range: Range,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct AskResponse {
pub answer: String,
#[serde(default)]
pub citations: Vec<Citation>,
}
#[must_use]
pub const fn is_compiled_in() -> bool {
cfg!(feature = "llm")
}
#[must_use]
pub fn is_runtime_enabled() -> bool {
std::env::var(ENV_ENABLED).as_deref() == Ok("1")
}
#[must_use]
pub fn is_active() -> bool {
is_compiled_in() && is_runtime_enabled()
}
#[cfg(feature = "llm")]
mod advisor;
#[cfg(feature = "llm")]
pub use advisor::{Advisor, AdvisorError, try_advisor_from_env};
#[cfg(test)]
mod tests {
#[cfg(not(feature = "llm"))]
use super::is_active;
use super::{AskRequest, is_compiled_in};
use serde_json::json;
#[test]
fn flags_match_cfg_default() {
assert_eq!(is_compiled_in(), cfg!(feature = "llm"));
}
#[cfg(not(feature = "llm"))]
#[test]
fn default_build_is_inactive() {
assert!(!is_active());
}
#[test]
fn ask_request_round_trips_json() {
let req: AskRequest = serde_json::from_value(json!({
"question": "What is a Trusted<T>?",
"context": null,
}))
.expect("deserialise");
assert_eq!(req.question, "What is a Trusted<T>?");
assert!(req.context.is_none());
let v = serde_json::to_value(&req).expect("serialise");
assert_eq!(v["question"], "What is a Trusted<T>?");
}
}