Commit Graph

6 Commits

Author SHA1 Message Date
Hongming Wang
b9a1fa1b1f feat: per-vendor env routing for third-party providers (task #244)
Some checks failed
CI / validate (push) Failing after 0s
CI / Adapter unit tests (push) Failing after 6s
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
Hongming Wang
9de33057aa feat(config): add MiniMax-M2.7-highspeed model entry
Routes via the existing `minimax` provider entry (model prefix matches
`minimax-` case-insensitively) — no registry change needed.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-30 23:30:24 -07:00
Hongming Wang
c6f4912d09 feat(adapter): data-driven provider registry in config.yaml
Move the model→endpoint→auth-env mapping out of hardcoded constants
in adapter.py + entrypoint.sh into a single `providers:` list at the
top of config.yaml. The adapter loads it at boot via _load_providers;
canvas Config tab will read the same YAML for its Provider dropdown so
UI and adapter never disagree on what's available. Adding a new
provider becomes a one-line YAML edit — no Python or shell changes.

Includes 5 third-party providers ready out of the box (Anthropic-compat
endpoints, Bearer-style ANTHROPIC_AUTH_TOKEN OR ANTHROPIC_API_KEY auth):

  xiaomi-mimo  https://api.xiaomimimo.com/anthropic
  minimax      https://api.minimax.io/anthropic
  zai          https://api.z.ai/api/anthropic           (NEW)
  moonshot     https://api.moonshot.ai/anthropic        (NEW)
  deepseek     https://api.deepseek.com/anthropic       (NEW)

Plus 7 new model entries in runtime_config.models (mimo-v2.5, MiniMax-M2,
MiniMax-M2.7, GLM-4.6, GLM-4.5, kimi-k2.5, kimi-k2, deepseek-v4-pro,
deepseek-v4-flash) so they show up in the Canvas Config dropdown.

Operator override unchanged: ANTHROPIC_BASE_URL set as a workspace
secret still wins over the registry default — the escape hatch for
regional endpoints (Xiaomi token-plan-sgp, MiniMax api.minimaxi.com).

entrypoint.sh: drops the `mimo-*` case mapping (adapter handles routing
now). _BUILTIN_PROVIDERS retained as malformed-YAML fallback so a
bare-bones workspace still boots with oauth + anthropic-api defaults.

Tests: 25 passing. New coverage:
  - YAML parses + normalizes to expected shape
  - Malformed YAML falls back to builtins (warning, not raise)
  - Each new provider routes its model id to the right base_url
  - ANTHROPIC_AUTH_TOKEN alone satisfies third-party auth check
  - Operator-set ANTHROPIC_BASE_URL overrides registry default
  - Case-insensitive prefix match (MiniMax-M2 / minimax-m2.7 / GLM-4.6)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-30 23:29:40 -07:00
Hongming Wang
a21d16d94f feat: add Xiaomi MiMo support via Anthropic-API-compatible routing (testing)
Adds 4 model entries (mimo-v2-flash, mimo-v2-pro, mimo-v2-omni,
mimo-v2.5-pro) selectable from canvas. When MODEL matches mimo-*,
entrypoint.sh exports ANTHROPIC_BASE_URL=https://api.xiaomimimo.com/anthropic
so the claude CLI's native ANTHROPIC_BASE_URL handling routes there.
ANTHROPIC_API_KEY in this case is the Xiaomi key, not Anthropic Console.

Verified live against all 4 model IDs with x-api-key auth — all returned
200 with proper Anthropic-shape Messages responses (id, type=message,
role=assistant, content[].text, usage including cache_read_input_tokens).

Operator-set ANTHROPIC_BASE_URL is never overridden — the case-statement
only fills in the default when unset, so a user-supplied proxy still wins.

Marked as testing because the model→base-URL mapping currently lives in
entrypoint.sh shell. The robust shape is a data-driven `runtime_env`
field in config.yaml read by the platform provisioner; will follow up
with that as a separate cross-repo PR (workspace-server + canvas) so
this template no longer carries provider-specific knowledge in shell.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-29 03:13:01 -07:00
Hongming Wang
2ca6ed7dc0
feat(config): split OAuth vs API-key in models[] registry (plugin-dev-agent)
Claude Code supports two auth paths that use different env vars:
- OAuth (via `claude login`) → CLAUDE_CODE_OAUTH_TOKEN, tied to a
  Claude Code subscription
- Direct API key → ANTHROPIC_API_KEY, pay-as-you-go via the Anthropic
  Console

Previously the template only listed CLAUDE_CODE_OAUTH_TOKEN, hiding the
API-key path and forcing API-key users to override manually. Now
models[] exposes both as distinct dropdown entries — users pick the
one matching the credential they have; canvas auto-suggests the right
env var.

Model IDs differ intentionally:
- OAuth entries use CLI aliases (sonnet/opus/haiku — resolve to latest)
- API-key entries use explicit versioned ids (claude-sonnet-4-6, etc.)

claude CLI accepts either auth style transparently — OAuth wins when
both are set, which preserves existing workspace behaviour.

Paired with Molecule-AI/molecule-core#1526 (platform + canvas).

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-22 05:36:03 +00:00
Hongming Wang
b8859da375 feat: initial template content (extracted from molecule-monorepo) 2026-04-16 03:05:40 -07:00