use super::*;
#[must_use]
pub fn resolve_auto_embed(cli_rag: bool, config: &CartogConfig) -> Option<bool> {
resolve_auto_embed_with(
std::env::var("CARTOG_WATCH_RAG").ok().as_deref(),
config.embedding.as_ref().and_then(|e| e.auto_embed),
cli_rag,
)
}
pub(crate) fn resolve_auto_embed_with(
env: Option<&str>,
cfg: Option<bool>,
cli_rag: bool,
) -> Option<bool> {
if let Some(v) = env.and_then(parse_bool_flag) {
return Some(v);
}
cfg.or_else(|| cli_rag.then_some(true))
}
fn parse_bool_flag(s: &str) -> Option<bool> {
match s.trim().to_ascii_lowercase().as_str() {
"1" | "true" | "yes" | "on" => Some(true),
"0" | "false" | "no" | "off" => Some(false),
_ => None,
}
}
pub fn to_redaction_config(config: &CartogConfig) -> cartog_indexer::RedactionConfig {
let enabled = config
.security
.as_ref()
.map_or(true, SecurityConfig::redact_secrets);
cartog_indexer::RedactionConfig { enabled }
}
pub fn to_walk_filter(config: &CartogConfig) -> Result<cartog_indexer::WalkFilter, String> {
let index = config.index.as_ref();
let globs = index.and_then(|i| i.exclude.as_deref()).unwrap_or(&[]);
let exclude = cartog_indexer::ExcludeGlobs::from_globs(globs)
.map_err(|e| format!("[index] exclude: {e:#}"))?;
let respect_gitignore = index.and_then(|i| i.respect_gitignore).unwrap_or(true);
let jobs = resolve_jobs(parse_env_usize("CARTOG_JOBS"), index.and_then(|i| i.jobs));
let lsp_max_servers = resolve_lsp_max_servers(
parse_env_usize("CARTOG_LSP_MAX_SERVERS"),
config.lsp.as_ref().and_then(|l| l.max_concurrent_servers),
);
Ok(cartog_indexer::WalkFilter {
exclude,
respect_gitignore,
jobs,
lsp_max_servers,
})
}
pub(crate) fn resolve_jobs(env: Option<usize>, toml: Option<usize>) -> usize {
env.or(toml).unwrap_or(0)
}
pub(crate) fn resolve_lsp_max_servers(env: Option<usize>, toml: Option<usize>) -> usize {
env.or(toml).unwrap_or(0)
}
pub(crate) fn resolve_embed_concurrency(env: Option<usize>, toml: Option<usize>) -> usize {
env.or(toml)
.unwrap_or(cartog_rag::providers::DEFAULT_EMBED_CONCURRENCY)
.clamp(1, 16)
}
fn parse_env_usize(var: &str) -> Option<usize> {
parse_usize_or_warn(var, std::env::var(var).ok()?.as_str())
}
pub(crate) fn parse_usize_or_warn(var: &str, raw: &str) -> Option<usize> {
match raw.trim().parse::<usize>() {
Ok(n) => Some(n),
Err(_) => {
if config_diagnostics_visible() {
eprintln!("cartog: {var}={raw:?} is not a non-negative integer; ignoring");
}
None
}
}
}
pub fn to_provider_config(config: &CartogConfig) -> cartog_rag::EmbeddingProviderConfig {
let reranker_provider = config
.reranker
.as_ref()
.map(|r| r.provider().to_string())
.unwrap_or_else(|| DEFAULT_RERANKER_PROVIDER.to_string());
let reranker_model = config.reranker.as_ref().and_then(|r| r.model.clone());
match &config.embedding {
Some(embed) => {
let (query_prefix, document_prefix, intra_threads) = match &embed.local {
Some(local) => (
local.query_prefix.clone(),
local.document_prefix.clone(),
local.intra_threads,
),
None => (None, None, None),
};
let (sub_base_url, sub_model, api_key_env) = match embed.provider() {
"ollama" => (
embed.ollama.as_ref().map(|o| o.base_url().to_string()),
embed.ollama.as_ref().map(|o| o.model().to_string()),
None,
),
"openai" => (
embed.openai.as_ref().map(|o| o.base_url().to_string()),
embed.openai.as_ref().map(|o| o.model().to_string()),
embed.openai.as_ref().map(|o| o.api_key_env().to_string()),
),
_ => (None, None, None),
};
cartog_rag::EmbeddingProviderConfig {
provider: embed.provider().to_string(),
model: embed.model.clone().or(sub_model),
dimension: embed.dimension,
query_prefix,
document_prefix,
base_url: sub_base_url,
api_key_env,
reranker_provider,
reranker_model,
intra_threads,
max_concurrent_requests: Some(resolve_embed_concurrency(
parse_env_usize("CARTOG_EMBED_CONCURRENCY"),
embed.max_concurrent_requests,
)),
}
}
None => cartog_rag::EmbeddingProviderConfig {
reranker_provider,
reranker_model,
..Default::default()
},
}
}