harn-cli 0.10.148

CLI for the Harn programming language — run, test, REPL, format, and lint
//! `harn try "<prompt>"` dispatches to the embedded `cli/try.harn`
//! script. The shim stays intentionally tiny because agent-loop option
//! wiring belongs in the script.

use crate::cli::TryArgs;
use crate::dispatch;
use crate::env_guard::ScopedEnvVar;

pub(crate) async fn run(args: TryArgs) {
    if !mock_provider_active() && harn_vm::llm::available_provider_names().is_empty() {
        eprintln!("{}", crate::commands::doctor::no_credentials_hint());
        std::process::exit(1);
    }

    let resolved = match resolve_try_model() {
        Ok(resolved) => resolved,
        Err(error) => {
            eprintln!("{error}");
            std::process::exit(1);
        }
    };

    let _max = ScopedEnvVar::set("HARN_TRY_MAX_ITERS", &args.max_iterations.to_string());
    let _provider = ScopedEnvVar::set("HARN_TRY_PROVIDER", &resolved.provider);
    let _model = ScopedEnvVar::set("HARN_TRY_MODEL", &resolved.model);
    let _tool_format = args
        .tool_format
        .as_deref()
        .map(|value| ScopedEnvVar::set("HARN_TRY_TOOL_FORMAT", value));
    let _override_reason = args
        .override_reason
        .as_deref()
        .map(|value| ScopedEnvVar::set("HARN_TRY_OVERRIDE_REASON", value));
    let exit =
        dispatch::dispatch_to_embedded_script("try", vec![args.prompt], /* json_mode */ false)
            .await;
    if exit != 0 {
        std::process::exit(exit);
    }
}

fn mock_provider_active() -> bool {
    std::env::var("HARN_LLM_PROVIDER")
        .map(|v| v == "mock")
        .unwrap_or(false)
}

struct ResolvedTryModel {
    provider: String,
    model: String,
}

fn resolve_try_model() -> Result<ResolvedTryModel, String> {
    if let Ok(provider) = std::env::var("HARN_LLM_PROVIDER") {
        let provider = provider.trim().to_string();
        if !provider.is_empty() && !provider.eq_ignore_ascii_case("auto") {
            let model = if let Ok(raw) = std::env::var("HARN_LLM_MODEL") {
                harn_vm::llm_config::resolve_model(&raw).0
            } else {
                harn_vm::llm_config::default_model_for_provider(&provider)
                    .map_err(|error| error.to_string())?
            };
            return Ok(ResolvedTryModel { provider, model });
        }
    }

    if let Ok(raw_model) = std::env::var("HARN_LLM_MODEL") {
        let resolved = harn_vm::llm_config::resolve_model_info(&raw_model);
        return Ok(ResolvedTryModel {
            provider: resolved.provider,
            model: resolved.id,
        });
    }

    let provider = harn_vm::llm_config::default_provider();
    let model = harn_vm::llm_config::default_model_for_provider(&provider)
        .map_err(|error| error.to_string())?;
    Ok(ResolvedTryModel { provider, model })
}