molecule-ai-workspace-templ.../config.yaml
Hongming Wang b9a1fa1b1f
Some checks failed
CI / validate (push) Failing after 0s
CI / Adapter unit tests (push) Failing after 6s
feat: per-vendor env routing for third-party providers (task #244)
Third-party Anthropic-compat providers (MiniMax, GLM, Kimi, DeepSeek)
all reuse the Anthropic SDK's wire format, which means the claude CLI
and claude-code-sdk read the bearer token from ANTHROPIC_AUTH_TOKEN no
matter which vendor is being talked to. Pre-#244:

  * Canvas surfaced the vendor-specific name (MINIMAX_API_KEY, etc.)
    to the user — so a user who saved only MINIMAX_API_KEY hit a
    silent 401 on first call.
  * The boot audit said `MINIMAX_API_KEY=set`, making it look like an
    SDK bug rather than a routing gap.
  * A user with multiple vendor keys could only run one workspace at a
    time because they all fought over the shared ANTHROPIC_AUTH_TOKEN
    slot.

Diagnostic-only audit logging shipped earlier (#32) but the actual
routing was never written — task #244 was mismarked complete.

Changes:
  * config.yaml: third-party model `required_env` now references the
    per-vendor name (MINIMAX_API_KEY, GLM_API_KEY, KIMI_API_KEY,
    DEEPSEEK_API_KEY) so canvas asks the user for the right key.
    First-party Anthropic models still use ANTHROPIC_AUTH_TOKEN /
    CLAUDE_CODE_OAUTH_TOKEN.
  * config.yaml: each third-party provider's `auth_env` lists the
    vendor name FIRST (priority order) so projection picks the
    vendor key over a stale ANTHROPIC_AUTH_TOKEN.
  * adapter.py: new `_project_vendor_auth(provider)` helper, called
    from `setup()` right after `_resolve_provider`. Idempotent — only
    projects when ANTHROPIC_AUTH_TOKEN is unset (operator override
    always wins). Logs the projection by NAME, never by VALUE
    (mirrors `_audit_auth_env_presence`).
  * tests/test_provider_routing.py: 6 new tests pin the contract —
    vendor-key-set projects, AUTH_TOKEN-already-set is never
    clobbered, first-party providers skip projection, secret value
    never leaks into a log record, empty-string vendor env doesn't
    trigger projection, and the same routing fires for GLM / Kimi /
    DeepSeek.

Mirrors the parallel hermes-side fix from task #249 / hermes PR #38;
keeps the two runtimes' multi-vendor UX in lockstep.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-02 22:20:03 -07:00

209 lines
9.0 KiB
YAML

name: Claude Code Agent
description: >-
General-purpose Claude Code workspace. Supports three auth paths:
(1) Claude Code subscription via OAuth token (CLAUDE_CODE_OAUTH_TOKEN,
obtained from `claude login`), (2) Anthropic API key
(ANTHROPIC_API_KEY, pay-as-you-go via console.anthropic.com), or
(3) third-party Anthropic-API-compatible providers (e.g. Xiaomi MiMo,
MiniMax) via ANTHROPIC_AUTH_TOKEN/ANTHROPIC_API_KEY + provider-specific
ANTHROPIC_BASE_URL routing. The `claude` CLI picks whichever is set;
OAuth takes precedence when multiple are present.
version: 1.0.0
tier: 2
# Provider registry — single source of truth for model→endpoint→auth
# routing. The adapter reads this list at boot to resolve the picked
# model to a provider, auto-set ANTHROPIC_BASE_URL, and validate the
# right auth env var. The canvas Config tab reads the same list to
# render its Provider dropdown — UI and adapter never disagree on
# what's available.
#
# Adding a new provider = one entry below. No adapter or entrypoint.sh
# code changes needed. Operator override always wins: setting
# ANTHROPIC_BASE_URL as a workspace secret bypasses the auto-routing
# (useful for regional endpoints like Xiaomi's token-plan-sgp.* or
# MiniMax's api.minimaxi.com China endpoint).
#
# Schema per entry:
# name : human-readable label (boot banner + UI dropdown)
# auth_mode : "oauth" | "anthropic_api" | "third_party_anthropic_compat"
# model_prefixes : lowercase model-id prefixes (e.g. ["mimo-", "minimax-"])
# model_aliases : exact lowercase ids (e.g. ["sonnet", "opus"])
# base_url : ANTHROPIC_BASE_URL to set; null = CLI default (anthropic-native)
# auth_env : env vars accepted; any one being set satisfies auth
providers:
- name: anthropic-oauth
auth_mode: oauth
model_prefixes: []
model_aliases: [sonnet, opus, haiku]
base_url: null
auth_env: [CLAUDE_CODE_OAUTH_TOKEN]
- name: anthropic-api
auth_mode: anthropic_api
model_prefixes: [claude-]
model_aliases: []
base_url: null
auth_env: [ANTHROPIC_API_KEY, ANTHROPIC_AUTH_TOKEN]
- name: xiaomi-mimo
auth_mode: third_party_anthropic_compat
model_prefixes: [mimo-]
model_aliases: []
base_url: https://api.xiaomimimo.com/anthropic
auth_env: [ANTHROPIC_AUTH_TOKEN, ANTHROPIC_API_KEY]
- name: minimax
auth_mode: third_party_anthropic_compat
model_prefixes: [minimax-]
model_aliases: []
base_url: https://api.minimax.io/anthropic
# Vendor-specific name FIRST so the boot-time projection helper
# (_project_vendor_auth in adapter.py) picks it over a stale
# ANTHROPIC_AUTH_TOKEN belonging to a sibling vendor.
auth_env: [MINIMAX_API_KEY, ANTHROPIC_AUTH_TOKEN, ANTHROPIC_API_KEY]
# Z.ai — GLM family. docs.z.ai/scenario-example/develop-tools/claude.
# Model ids are uppercase (GLM-4.6) but the registry lowercases for
# matching, so the `glm-` prefix catches both `GLM-4.6` and `glm-4.6`.
- name: zai
auth_mode: third_party_anthropic_compat
model_prefixes: [glm-]
model_aliases: []
base_url: https://api.z.ai/api/anthropic
auth_env: [GLM_API_KEY, ANTHROPIC_AUTH_TOKEN, ANTHROPIC_API_KEY]
# Moonshot AI — Kimi family. platform.kimi.ai/docs/guide/agent-support.
- name: moonshot
auth_mode: third_party_anthropic_compat
model_prefixes: [kimi-]
model_aliases: []
base_url: https://api.moonshot.ai/anthropic
auth_env: [KIMI_API_KEY, ANTHROPIC_AUTH_TOKEN, ANTHROPIC_API_KEY]
# DeepSeek — api-docs.deepseek.com/guides/anthropic_api. Note: their
# endpoint silently maps unknown model ids to deepseek-v4-flash, so a
# typo lands on a working-but-wrong-tier model rather than 400ing.
# Worth flagging in operator-facing docs.
- name: deepseek
auth_mode: third_party_anthropic_compat
model_prefixes: [deepseek-]
model_aliases: []
base_url: https://api.deepseek.com/anthropic
auth_env: [DEEPSEEK_API_KEY, ANTHROPIC_AUTH_TOKEN, ANTHROPIC_API_KEY]
runtime: claude-code
runtime_config:
model: sonnet
# Canvas surfaces this list as a Model dropdown and auto-populates
# Required Env Vars based on the selected entry. OAuth and API-key
# variants of each model appear as separate entries so users pick
# the auth path matching the key they have — the claude CLI accepts
# either and the model id is identical across both.
models:
# --- OAuth (Claude Code subscription) — set CLAUDE_CODE_OAUTH_TOKEN ---
- id: sonnet
name: Claude Sonnet (OAuth / Claude Code subscription)
required_env: [CLAUDE_CODE_OAUTH_TOKEN]
- id: opus
name: Claude Opus (OAuth / Claude Code subscription)
required_env: [CLAUDE_CODE_OAUTH_TOKEN]
- id: haiku
name: Claude Haiku (OAuth / Claude Code subscription)
required_env: [CLAUDE_CODE_OAUTH_TOKEN]
# --- Direct Anthropic API — set ANTHROPIC_API_KEY ---
# Explicit versioned ids so the API call lands on a specific snapshot
# (OAuth aliases above resolve to the latest each model family).
- id: claude-sonnet-4-6
name: Claude Sonnet 4.6 (API key / Anthropic Console)
required_env: [ANTHROPIC_API_KEY]
- id: claude-opus-4-7
name: Claude Opus 4.7 (API key / Anthropic Console)
required_env: [ANTHROPIC_API_KEY]
- id: claude-haiku-4-5
name: Claude Haiku 4.5 (API key / Anthropic Console)
required_env: [ANTHROPIC_API_KEY]
# --- Xiaomi MiMo (third-party, Anthropic-API-compatible) ---
# Routed via the `xiaomi-mimo` provider entry above (base_url and
# auth_env are resolved from the registry — the adapter sets
# ANTHROPIC_BASE_URL automatically based on the model prefix). Either
# ANTHROPIC_AUTH_TOKEN or ANTHROPIC_API_KEY satisfies auth — both work.
- id: mimo-v2-flash
name: Xiaomi MiMo V2 Flash (third-party, Anthropic-API-compatible)
required_env: [ANTHROPIC_API_KEY]
- id: mimo-v2-pro
name: Xiaomi MiMo V2 Pro (third-party, Anthropic-API-compatible)
required_env: [ANTHROPIC_API_KEY]
- id: mimo-v2-omni
name: Xiaomi MiMo V2 Omni (third-party, Anthropic-API-compatible)
required_env: [ANTHROPIC_API_KEY]
- id: mimo-v2.5
name: Xiaomi MiMo V2.5 (third-party, Anthropic-API-compatible)
required_env: [ANTHROPIC_API_KEY]
- id: mimo-v2.5-pro
name: Xiaomi MiMo V2.5 Pro (third-party, Anthropic-API-compatible)
required_env: [ANTHROPIC_API_KEY]
# --- MiniMax (third-party, Anthropic-API-compatible) ---
# Vendor-specific env var so a user with multiple third-party Anthropic-
# compat keys can run multiple workspaces simultaneously without them
# fighting over a shared ANTHROPIC_AUTH_TOKEN slot. The adapter projects
# MINIMAX_API_KEY → ANTHROPIC_AUTH_TOKEN at boot (only when
# ANTHROPIC_AUTH_TOKEN is unset, so an explicit operator override wins).
# Mirrors hermes-side fix from task #249 / hermes PR #38.
- id: MiniMax-M2
name: MiniMax M2 (third-party, Anthropic-API-compatible)
required_env: [MINIMAX_API_KEY]
- id: MiniMax-M2.7
name: MiniMax M2.7 (third-party, Anthropic-API-compatible)
required_env: [MINIMAX_API_KEY]
- id: MiniMax-M2.7-highspeed
name: MiniMax M2.7 High-Speed (third-party, Anthropic-API-compatible)
required_env: [MINIMAX_API_KEY]
# --- Z.ai GLM family (third-party, Anthropic-API-compatible) ---
# GLM_API_KEY → ANTHROPIC_AUTH_TOKEN projection at boot. docs.z.ai for
# the full Anthropic-compat docs. GLM-4.6 is the current-gen flagship;
# 4.5 remains for users on legacy quotas.
- id: GLM-4.6
name: Z.ai GLM-4.6 (third-party, Anthropic-API-compatible)
required_env: [GLM_API_KEY]
- id: GLM-4.5
name: Z.ai GLM-4.5 (third-party, Anthropic-API-compatible)
required_env: [GLM_API_KEY]
# --- Moonshot AI Kimi family (third-party, Anthropic-API-compatible) ---
# KIMI_API_KEY → ANTHROPIC_AUTH_TOKEN projection at boot.
# platform.kimi.ai for docs. K2.5 is the latest agentic-coding tier;
# K2 stays as a cheaper option.
- id: kimi-k2.5
name: Moonshot Kimi K2.5 (third-party, Anthropic-API-compatible)
required_env: [KIMI_API_KEY]
- id: kimi-k2
name: Moonshot Kimi K2 (third-party, Anthropic-API-compatible)
required_env: [KIMI_API_KEY]
# --- DeepSeek (third-party, Anthropic-API-compatible) ---
# DEEPSEEK_API_KEY → ANTHROPIC_AUTH_TOKEN projection at boot.
# api-docs.deepseek.com. Note: unknown deepseek-* ids silently fall
# back to v4-flash on DeepSeek's side — pick the exact tier you mean.
- id: deepseek-v4-pro
name: DeepSeek V4 Pro (third-party, Anthropic-API-compatible)
required_env: [DEEPSEEK_API_KEY]
- id: deepseek-v4-flash
name: DeepSeek V4 Flash (third-party, Anthropic-API-compatible)
required_env: [DEEPSEEK_API_KEY]
# Default required_env — per-model entries above override this once a
# model is picked. Keep CLAUDE_CODE_OAUTH_TOKEN as the default so
# existing workspaces (which all use OAuth) keep working unchanged.
required_env:
- CLAUDE_CODE_OAUTH_TOKEN
timeout: 0
template_schema_version: 1