harn-vm 0.10.153

Async bytecode virtual machine for the Harn programming language
Documentation
//! Provider config, provider status, and the model catalog surfaces.

use super::super::catalog_builtins::llm_config_builtin;
use super::super::model_projection::llm_catalog_value;
use super::super::provider_projection::{llm_provider_status_value, provider_catalog_to_vm_value};
use super::fixtures::credential_status_for;
use crate::llm_config;
use crate::value::VmValue;

#[test]
fn provider_status_reports_deferred_for_platform_managed_providers() {
    // Bedrock and Vertex both declare `credential_resolution =
    // "platform_managed"` in providers.toml. They reach the same
    // "deferred" status through that shared field, not a hardcoded
    // `matches!(name, "bedrock" | "vertex")` arm in this function — a
    // third platform-managed provider would get the same treatment by
    // declaring the field, without touching this code.
    let _guard = crate::llm::env_guard();
    std::env::remove_var("VERTEX_AI_ACCESS_TOKEN");
    std::env::remove_var("GOOGLE_OAUTH_ACCESS_TOKEN");
    std::env::remove_var("GOOGLE_APPLICATION_CREDENTIALS");
    let _region = crate::llm::test_env::ScopedEnvVar::set("AWS_REGION", "us-east-1");
    let _key = crate::llm::test_env::ScopedEnvVar::set("AWS_ACCESS_KEY_ID", "AKIDEXAMPLE");
    let _secret =
        crate::llm::test_env::ScopedEnvVar::set("AWS_SECRET_ACCESS_KEY", "example-secret");
    let status = llm_provider_status_value();
    assert_eq!(credential_status_for(&status, "bedrock"), "deferred");
    assert_eq!(credential_status_for(&status, "vertex"), "deferred");
}

#[test]
fn llm_config_surfaces_bedrock_region_block() {
    let mut out = String::new();
    let args = vec![VmValue::String(arcstr::ArcStr::from("bedrock"))];
    let result = llm_config_builtin(&args, &mut out).expect("bedrock config");
    let cfg = result.as_dict().expect("config dict");

    let region = cfg
        .get("region")
        .and_then(|v| v.as_dict())
        .expect("region block present for bedrock");

    // override_key documents the chain-link field a routing_policy
    // route sets to pin a region.
    assert_eq!(
        region.get("override_key").map(|v| v.display()).as_deref(),
        Some("region")
    );

    // envs lists the resolution precedence chain.
    let envs = match region.get("envs") {
        Some(VmValue::List(items)) => items.iter().map(|v| v.display()).collect::<Vec<_>>(),
        other => panic!("expected envs list, got {other:?}"),
    };
    assert!(envs.contains(&"AWS_REGION".to_string()));
    assert!(envs.contains(&"BEDROCK_REGION".to_string()));

    // resolved is always present (string or nil) so a gateway can
    // branch on "is a region already configured?".
    assert!(region.contains_key("resolved"));
}

#[test]
fn llm_config_omits_region_block_for_single_region_provider() {
    let mut out = String::new();
    let args = vec![VmValue::String(arcstr::ArcStr::from("anthropic"))];
    let result = llm_config_builtin(&args, &mut out).expect("anthropic config");
    let cfg = result.as_dict().expect("config dict");
    assert!(
        !cfg.contains_key("region"),
        "region block should only appear for multi-region providers"
    );
}

#[test]
fn test_llm_catalog_surfaces_batch_and_tool_parity_metadata_for_scripts() {
    crate::llm::capabilities::clear_user_overrides();
    let VmValue::List(entries) = llm_catalog_value() else {
        panic!("expected model catalog list");
    };
    let openai = entries
        .iter()
        .filter_map(VmValue::as_dict)
        .find(|entry| {
            entry.get("provider").map(VmValue::display) == Some("openai".to_string())
                && entry.get("id").map(VmValue::display) == Some("gpt-4o-mini".to_string())
        })
        .expect("openai gpt-4o-mini catalog row");
    assert!(openai.contains_key("tool_mode_parity"));
    assert!(openai.contains_key("tool_mode_parity_notes"));
    assert!(matches!(openai.get("batch_api"), Some(VmValue::Bool(true))));
    match openai.get("batch_wire_format") {
        Some(VmValue::String(value)) => assert_eq!(value.as_str(), "openai"),
        other => panic!("expected openai batch wire format, got {other:?}"),
    }
    match openai.get("batch_input_mode") {
        Some(VmValue::String(value)) => assert_eq!(value.as_str(), "jsonl_file"),
        other => panic!("expected jsonl_file batch input mode, got {other:?}"),
    }
    assert!(matches!(
        openai.get("batch_discount_percent"),
        Some(VmValue::Int(50))
    ));
    assert!(matches!(
        openai.get("batch_turnaround_hours"),
        Some(VmValue::Int(24))
    ));
    assert!(matches!(
        openai.get("batch_max_requests"),
        Some(VmValue::Int(50_000))
    ));
    assert!(matches!(
        openai.get("batch_max_input_bytes"),
        Some(VmValue::Int(209_715_200))
    ));
    match openai.get("batch_result_ordering") {
        Some(VmValue::String(value)) => assert_eq!(value.as_str(), "custom_id_rejoin"),
        other => panic!("expected openai batch result ordering, got {other:?}"),
    }
    match openai.get("batch_partial_failure") {
        Some(VmValue::String(value)) => assert_eq!(value.as_str(), "per_request"),
        other => panic!("expected openai batch partial failure, got {other:?}"),
    }
    match openai.get("batch_cancellation") {
        Some(VmValue::String(value)) => assert_eq!(value.as_str(), "supported"),
        other => panic!("expected openai batch cancellation, got {other:?}"),
    }
    match openai.get("batch_security_notes") {
        Some(VmValue::List(notes)) => assert!(
            !notes.is_empty(),
            "expected batch security notes in llm catalog row"
        ),
        other => panic!("expected batch security notes list, got {other:?}"),
    }
    match openai.get("batch_operational_notes") {
        Some(VmValue::List(notes)) => assert!(
            notes
                .iter()
                .any(|note| note.display().contains("custom_id")),
            "expected batch operational notes in llm catalog row"
        ),
        other => panic!("expected batch operational notes list, got {other:?}"),
    }
    let openai_batch = openai
        .get("batch")
        .and_then(VmValue::as_dict)
        .expect("expected nested batch catalog row");
    match openai_batch.get("result_ordering") {
        Some(VmValue::String(value)) => assert_eq!(value.as_str(), "custom_id_rejoin"),
        other => panic!("expected nested openai batch ordering, got {other:?}"),
    }
    match openai_batch.get("operational_notes") {
        Some(VmValue::List(notes)) => assert!(
            notes
                .iter()
                .any(|note| note.display().contains("one model")),
            "expected nested batch operational notes in llm catalog row"
        ),
        other => panic!("expected nested batch operational notes list, got {other:?}"),
    }
}

#[test]
fn provider_catalog_builtin_surfaces_presentation_effort_and_lifecycle() {
    llm_config::clear_user_overrides();
    crate::llm::capabilities::clear_user_overrides();
    let catalog = provider_catalog_to_vm_value();
    let catalog = catalog.as_dict().expect("provider catalog dict");

    let providers = match catalog.get("providers") {
        Some(VmValue::List(providers)) => providers,
        other => panic!("expected providers list, got {other:?}"),
    };
    let artifact = crate::provider_catalog::artifact();
    assert!(!artifact.providers.is_empty());
    assert_eq!(providers.len(), artifact.providers.len());
    for expected in artifact.providers {
        let projected = providers
            .iter()
            .filter_map(VmValue::as_dict)
            .find(|provider| provider.get("id").map(VmValue::display) == Some(expected.id.clone()))
            .expect("catalog provider reaches the VM");
        let expected = crate::stdlib::json_to_vm_value(
            &serde_json::to_value(expected).expect("serializable provider"),
        );
        for field in ["classification", "auth", "endpoint"] {
            assert_eq!(
                projected
                    .get(field)
                    .map(crate::llm::helpers::vm_value_to_json),
                expected
                    .as_dict()
                    .unwrap()
                    .get(field)
                    .map(crate::llm::helpers::vm_value_to_json)
            );
        }
    }

    let families = match catalog.get("families") {
        Some(VmValue::List(families)) => families,
        other => panic!("expected families list, got {other:?}"),
    };
    let gpt_family = families
        .iter()
        .filter_map(VmValue::as_dict)
        .find(|family| family.get("id").map(VmValue::display) == Some("openai-gpt-6".to_string()))
        .expect("GPT-6 family");
    assert_eq!(
        gpt_family.get("provider").map(VmValue::display).as_deref(),
        Some("openai")
    );

    let models = match catalog.get("models") {
        Some(VmValue::List(models)) => models,
        other => panic!("expected models list, got {other:?}"),
    };
    let sol = models
        .iter()
        .filter_map(VmValue::as_dict)
        .find(|model| model.get("id").map(VmValue::display) == Some("gpt-6-sol".to_string()))
        .expect("GPT-6 Sol model");
    assert!(sol
        .get("blurb")
        .map(VmValue::display)
        .is_some_and(|blurb| !blurb.is_empty()));
    let levels = match sol.get("reasoning_effort_levels") {
        Some(VmValue::List(levels)) => levels.iter().map(VmValue::display).collect::<Vec<_>>(),
        other => panic!("expected reasoning_effort_levels list, got {other:?}"),
    };
    assert_eq!(levels, ["none", "low", "medium", "high", "xhigh"]);

    // Together retired the DeepSeek V4 Pro preview this fixture used to read,
    // and its row is gone. OpenAI's o1 is the bundled route that now carries a
    // typed retirement date, sourced from the `shutdown_date` on its live
    // model record.
    let retired_route = models
        .iter()
        .filter_map(VmValue::as_dict)
        .find(|model| model.get("id").map(VmValue::display) == Some("o1".to_string()))
        .expect("deprecated OpenAI o1 route");
    assert_eq!(
        retired_route
            .get("sunset_date")
            .map(VmValue::display)
            .as_deref(),
        Some("2026-10-23")
    );
}

#[test]
fn provider_catalog_builtin_preserves_non_chat_operations() {
    let (id, _) = llm_config::model_catalog_entries()
        .into_iter()
        .find(|(_, model)| {
            model.operations.as_ref().is_some_and(|operations| {
                operations.contains(&llm_config::ModelOperation::Decision)
            })
        })
        .expect("a bundled decision route");
    let catalog = provider_catalog_to_vm_value();
    let models = catalog
        .as_dict()
        .and_then(|catalog| catalog.get("models"))
        .and_then(|models| match models {
            VmValue::List(models) => Some(models),
            _ => None,
        })
        .expect("projected model rows");
    let model = models
        .iter()
        .filter_map(VmValue::as_dict)
        .find(|model| model.get("id").map(VmValue::display).as_deref() == Some(id.as_str()))
        .expect("projected decision route");
    let operations = model.get("operations").expect("projected operation type");
    assert!(
        matches!(operations, VmValue::List(values) if values.iter().any(|value| value.display() == "decision"))
    );
}