use crate::agent::adapter_dispatch;
use crate::agent::cmd::log;
use crate::agent::grok_auth::grok_subscription_auth_active;
use crate::agent::types::{AgentLaunchOverrides, Config};
pub fn local_inference_overrides(cfg: &Config) -> AgentLaunchOverrides {
let local = &cfg.local_inference;
if !local.advanced {
return AgentLaunchOverrides::default();
}
let base_url = local.base_url.trim();
if base_url.is_empty() {
return AgentLaunchOverrides::default();
}
let (args, env) = adapter_dispatch::launch_local_inference(
cfg.agent,
base_url,
local.api_key.trim(),
local.model.trim(),
);
AgentLaunchOverrides { args, env }
}
pub fn model_selection_overrides(cfg: &Config) -> AgentLaunchOverrides {
if cfg.local_inference.advanced
&& !cfg.local_inference.base_url.trim().is_empty()
&& !cfg.local_inference.model.trim().is_empty()
{
return AgentLaunchOverrides::default();
}
let model = cfg.model.trim();
if model.is_empty() {
return AgentLaunchOverrides::default();
}
let (args, env) = adapter_dispatch::launch_model_selection(cfg.agent, model);
AgentLaunchOverrides { args, env }
}
pub fn auto_mode_overrides(cfg: &Config) -> AgentLaunchOverrides {
if !cfg.auto_mode {
return AgentLaunchOverrides::default();
}
AgentLaunchOverrides {
args: adapter_dispatch::launch_auto_mode(cfg.agent),
env: Vec::new(),
}
}
pub fn merged_agent_env(cfg: &Config, extra_env: &[(String, String)]) -> Vec<(String, String)> {
let mut env = local_inference_overrides(cfg).env;
env.extend(model_selection_overrides(cfg).env);
env.extend(adapter_dispatch::launch_env(cfg.agent));
env.extend(extra_env.iter().cloned());
env.push(("GH_PAGER".to_string(), "cat".to_string()));
if cfg.use_subscription || grok_subscription_auth_active() {
env.push(("ANTHROPIC_API_KEY".to_string(), "".to_string()));
env.push(("OPENAI_API_KEY".to_string(), "".to_string()));
env.push(("GEMINI_API_KEY".to_string(), "".to_string()));
env.push(("GROK_API_KEY".to_string(), "".to_string()));
env.push(("JUNIE_API_KEY".to_string(), "".to_string()));
env.push(("XAI_API_KEY".to_string(), "".to_string()));
}
env
}
fn redact_launch_env_value(key: &str, value: &str) -> String {
if key.ends_with("API_KEY") && !value.is_empty() && value != "local" {
"<redacted>".to_string()
} else {
value.to_string()
}
}
pub fn log_resolved_agent_launch(cfg: &Config, extra_env: &[(String, String)]) {
let mut overrides = local_inference_overrides(cfg);
let model_ov = model_selection_overrides(cfg);
overrides.args.extend(model_ov.args);
let auto_ov = auto_mode_overrides(cfg);
overrides.args.extend(auto_ov.args);
let env = merged_agent_env(cfg, extra_env);
let args = if overrides.args.is_empty() {
"(none)".to_string()
} else {
overrides.args.join(" ")
};
let env = if env.is_empty() {
"(none)".to_string()
} else {
env.iter()
.map(|(key, value)| format!("{key}={}", redact_launch_env_value(key, value)))
.collect::<Vec<_>>()
.join(", ")
};
log(&format!(
"[dry-run] Agent launch overrides for {} -> args: {args}; env: {env}",
cfg.agent
));
}
#[cfg(test)]
mod tests {
use super::merged_agent_env;
use crate::agent::grok_auth::GROK_AUTH_MANAGED_ENV;
use cli_common::{Agent, Config, PricingConfig, TestCommands};
use std::env;
use std::sync::{Mutex, OnceLock};
fn env_lock() -> &'static Mutex<()> {
static LOCK: OnceLock<Mutex<()>> = OnceLock::new();
LOCK.get_or_init(|| Mutex::new(()))
}
fn test_config(agent: Agent) -> Config {
Config {
agent,
model: String::new(),
auto_mode: false,
dry_run: true,
geodynamo_url: None,
local_inference: Default::default(),
root: env!("CARGO_MANIFEST_DIR").to_string(),
project_name: "caretta-test".to_string(),
scan_targets: Default::default(),
skill_paths: Default::default(),
bootstrap_agent_files: false,
bootstrap_snapshot: false,
workflow_preset: "default".to_string(),
use_subscription: false,
pricing: PricingConfig::default(),
bot_settings: Default::default(),
bot_credentials: None,
test: TestCommands::default(),
visual_regression: Default::default(),
deploy: Default::default(),
workspace: None,
telemetry: cli_common::TelemetryConfig::default(),
}
}
#[test]
fn clears_xai_api_key_when_grok_oauth_is_managed() {
let _guard = env_lock().lock().expect("env lock");
unsafe {
env::set_var(GROK_AUTH_MANAGED_ENV, "1");
env::set_var("XAI_API_KEY", "should-clear");
}
let cfg = test_config(Agent::Xai);
let env = merged_agent_env(&cfg, &[]);
let xai = env
.iter()
.find(|(key, _)| key == "XAI_API_KEY")
.map(|(_, value)| value.as_str());
assert_eq!(xai, Some(""));
unsafe {
env::remove_var(GROK_AUTH_MANAGED_ENV);
env::remove_var("XAI_API_KEY");
}
}
}