harn-stdlib 0.8.24

Embedded Harn standard library source catalog
Documentation
// @harn-entrypoint-category llm.stdlib
//
// std/llm/catalog — thin Harn wrappers over the runtime model catalog.
//
// The wrapper functions intentionally use shorter, idiomatic names
// (`model_info`, `resolved_options`) instead of the underlying builtin
// names (`llm_model_info`, `llm_resolved_options`) so that wrapping
// does not shadow the builtin and recurse infinitely.
/**
 * Wraps the llm_model_info(selector) Rust builtin. The runtime always
 * returns a dict; when the selector is unknown, the dict's `catalog`
 * field will be nil and the inferred provider will be the default.
 */
pub fn model_info(selector) {
  return llm_model_info(selector)
}

/** Wraps llm_resolved_options(opts). opts.model is required; throws otherwise. */
pub fn resolved_options(opts) {
  if type_of(opts) != "dict" {
    throw "resolved_options: opts must be a dict"
  }
  if opts?.model == nil || opts.model == "" {
    throw "resolved_options: opts.model is required"
  }
  return llm_resolved_options(opts)
}

fn __capability_field(caps, capability) {
  if capability == "thinking" {
    let direct = caps?.thinking ?? false
    let modes = caps?.thinking_modes ?? []
    return direct || len(modes) > 0
  }
  if capability == "tool_search" {
    return len(caps?.tool_search ?? []) > 0
  }
  if capability == "vision" {
    return caps?.vision_supported ?? false
  }
  if capability == "files_api" {
    return caps?.files_api_supported ?? false
  }
  if capability == "reasoning_effort" {
    return caps?.reasoning_effort_supported ?? false
  }
  if capability == "interleaved_thinking" {
    return caps?.interleaved_thinking_supported ?? false
  }
  if capability == "prompt_caching" {
    return caps?.prompt_caching ?? false
  }
  if capability == "native_tools" {
    return caps?.native_tools ?? false
  }
  if capability == "audio" {
    return caps?.audio ?? false
  }
  if capability == "pdf" {
    return caps?.pdf ?? false
  }
  return false
}

/**
 * True if (model, capability) is supported per the runtime catalog.
 * capability is one of: "thinking", "tool_search", "interleaved_thinking",
 * "prompt_caching", "vision", "audio", "pdf", "files_api",
 * "reasoning_effort", "native_tools". Returns false on unknown model.
 */
pub fn has_capability(model, capability) {
  let info = llm_model_info(model)
  if type_of(info) != "dict" {
    return false
  }
  let caps = info?.capabilities
  if type_of(caps) != "dict" {
    return false
  }
  return __capability_field(caps, capability)
}

fn __family_for_anthropic(id) {
  if contains(id, "haiku") {
    return "anthropic_haiku"
  }
  if contains(id, "opus-4-7") || contains(id, "opus-mythos") {
    return "anthropic_opus_adaptive"
  }
  return "anthropic_sonnet_opus"
}

fn __family_for_openai(id) {
  if starts_with(id, "gpt-5") {
    return "openai_gpt5_family"
  }
  return "openai_legacy"
}

fn __family_for_gemini(id) {
  if contains(id, "flash") {
    return "gemini_flash"
  }
  return "gemini_pro"
}

fn __family_for_ollama(id) {
  if contains(id, "qwen") {
    return "ollama_qwen3"
  }
  return "ollama_generic"
}

/**
 * Best-effort family classifier. Returns one of:
 * "anthropic_haiku", "anthropic_opus_adaptive", "anthropic_sonnet_opus",
 * "openai_gpt5_family", "openai_legacy", "gemini_flash", "gemini_pro",
 * "ollama_qwen3", "ollama_generic", or "generic".
 */
pub fn family_of(model_id) {
  let info = llm_model_info(model_id)
  if type_of(info) != "dict" {
    return "generic"
  }
  let provider = lowercase(to_string(info?.provider ?? ""))
  let id = lowercase(to_string(model_id))
  if provider == "anthropic" {
    return __family_for_anthropic(id)
  }
  if provider == "openai" {
    return __family_for_openai(id)
  }
  if provider == "gemini" {
    return __family_for_gemini(id)
  }
  if provider == "ollama" {
    return __family_for_ollama(id)
  }
  return "generic"
}