Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: thaolaptrinh/commandcode-api-proxy
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: v0.1.4
Choose a base ref
...
head repository: thaolaptrinh/commandcode-api-proxy
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: v0.2.0
Choose a head ref
  • 2 commits
  • 20 files changed
  • 2 contributors

Commits on Jul 20, 2026

  1. feat(proxy): expand model catalog, per-model reasoning effort, openco…

    …de variants + production hardening (#2)
    
    * fix(proxy): tool_choice object form, streaming input_tokens, production hardening
    
    Found + verified against the live CC /alpha/generate stream (captured real
    events + probed the validation schema). The biggest issue — tool_choice — was
    invisible from code review alone.
    
    Functional fixes
    - tool_choice: was sent as a bare string, which CC rejects with 400
      ("expected object, received string at params.tool_choice"). Map both OpenAI
      and Anthropic tool_choice to CC's object union {type:"auto"|"any"|"tool",
      name?}. CC has no "required" (use "any") and no "none" (omit). Verified all
      three shapes return 200 against live CC.
    - streaming Anthropic input_tokens: CC's `start` event carries no usage, so
      message_start reported input_tokens=0. Emit input_tokens in message_delta
      from finish.totalUsage (the Anthropic SDK merges it over message_start).
    
    Robustness / ops
    - Retry retryable upstream failures (5xx/429/timeout/network) up to 2x with
      backoff, before the stream starts only; client aborts are never retried.
      (isRetryable was previously computed but unused.)
    - Request body size limit (10 MiB → 413) to prevent OOM.
    - Guard all response writes against destroyed/ended sockets (client disconnect
      mid-request no longer throws).
    - Top-level unhandledRejection/uncaughtException handlers + bounded graceful
      shutdown (force-exit after 10s).
    
    Config / packaging
    - Docker: mount ~/.config/commandcode-api-proxy (was ~/.commandcode, so
      auth.json never loaded); bind host port to 127.0.0.1 only.
    - CORS_ORIGIN env (default *; empty disables); document the localhost-only
      security posture.
    - Drop key-prefix logging (length only).
    - Remove dead NDJSONParser class (runtime parses via parseCCLine).
    
    Tests: 127 pass; added tool_choice (object form) + streaming input_tokens
    coverage.
    
    Co-Authored-By: Claude <noreply@anthropic.com>
    
    * feat(models): expand catalog + per-model reasoning effort clipping
    
    Researched the model catalog in the command-code CLI (the authoritative
    source) and the /alpha/generate plan gating by probing each candidate live.
    
    Catalog (src/models.json)
    - Add 12 models reachable on the standard plan (verified 200, not 403):
      GLM-5.2, GLM-5.2-Fast, MiniMax-M3, Kimi-K2.7-Code (+Highspeed), Kimi-K3,
      mimo-v2.5-pro, Step-3.7-Flash, grok-4.5, nemotron-3-ultra, inkling, Hy3.
    - Exclude plan-gated models (gemini-3.5-flash, gemini-3.1-flash-lite,
      fugu-ultra, muse-spark) — they 403 MODEL_NOT_IN_PLAN on standard.
    - Add reasoningEfforts map; fix stale contextWindows (Step-3.5-Flash 1M,
      Kimi K2.5/K2.6 256k); add aliases for all new models.
    
    Reasoning effort (the capability gap)
    - Each CC model accepts a different effort subset (e.g. deepseek-v4-pro is
      {high,max}; grok-4.5 is {low,medium,high}). CC silently coerces unsupported
      values, so the proxy previously could send (or drop) the wrong level and
      could never reach "max"/"xhigh".
    - models.ts: resolveEffortForModel() clips a request to the nearest valid
      level for the model; uncatalogued models pass through unchanged.
    - OpenAI: widen reasoning_effort to low/medium/high/xhigh/max.
    - Anthropic: extend thinking.budget_tokens mapping through xhigh/max, then
      clip per model. Verified live: deepseek-v4-pro+low→high, +max→max;
      grok-4.5+xhigh→high.
    
    Tests: 130 pass; added effort-clipping coverage (per-model clip, xhigh/max,
    grok cap) for both protocols. README aliases + reasoning-effort notes updated.
    
    Co-Authored-By: Claude <noreply@anthropic.com>
    
    * fix(models): resolve bare model names so OpenCode variant keys work
    
    OpenCode's provider config (written by --setup-opencode) keys each model by
    the bare last path segment with original casing (e.g. "GLM-5.2",
    "MiniMax-M3", "Kimi-K3") and sends that key as the model id. The proxy's
    resolveModel only matched lowercase aliases or org-prefixed ids, so mixed-case
    bare names passed through unchanged and CC rejected them (403 — needs org/model).
    Only deepseek/grok worked, by lowercase-alias coincidence.
    
    resolveModel now: (a) matches aliases case-insensitively, and (b) falls back to
    the builtin catalog's last path segment. Verified live: GLM-5.2, MiniMax-M3,
    Kimi-K3, Kimi-K2.7-Code-Highspeed, nemotron-3-ultra-550b-a55b all resolve to
    canonical ids and return 200.
    
    Tests: 131 pass; added bare-name resolution coverage.
    
    Co-Authored-By: Claude <noreply@anthropic.com>
    
    * feat(opencode): emit reasoning-effort variants so /variants is populated
    
    OpenCode's `/variants` picker lists a model's `variants` map. OpenCode only
    auto-generates reasoning variants from models.dev metadata, which does not
    cover our custom commandcode model IDs — so the picker was empty.
    
    The opencode setup now declares `variants` explicitly for effort-capable
    models, driven by models.json's reasoningEfforts map:
      deepseek-v4-pro/flash, GLM-5.2 → {high, max}
      grok-4.5                     → {low, medium, high}
    Each variant maps to `{ reasoningEffort: <level> }`, which OpenCode forwards
    to the proxy (and the proxy clips per model — see resolveEffortForModel).
    
    Source-of-truth for the mechanism: sst/opencode —
    provider/provider.ts (config variants are mergeDeep'd in) and
    provider/transform.ts ({reasoningEffort} variant shape for openai-compatible).
    
    Tests: 133 pass; added setup-opencode coverage (variants emitted for effort
    models, omitted for others).
    
    Co-Authored-By: Claude <noreply@anthropic.com>
    
    * fix(opencode): disable unsupported effort tiers so /variants matches the model
    
    OpenCode auto-adds WIDELY_SUPPORTED_EFFORTS (low/medium/high) to every
    reasoning-capable openai-compatible model and mergeDeep's them with our config,
    so deepseek-v4-pro (which CC only supports at {high, max}) showed 4 variants
    including bogus low/medium (which the proxy would silently clip to high).
    
    Declare the full effort universe per model and mark the unsupported tiers
    `disabled: true`. OpenCode filters disabled variants out of the picker
    (pickBy !disabled), so each model shows exactly what it supports:
      deepseek-v4-pro/flash, GLM-5.2 → high, max
      grok-4.5                         → low, medium, high
    
    Tests updated to assert the disabled tiers. 133 pass.
    
    Co-Authored-By: Claude <noreply@anthropic.com>
    
    * fix(models): guard empty effort set in resolveEffortForModel
    
    An empty reasoningEfforts array ([] is truthy) bypassed the early return and
    reached reduce() on an empty array, which throws. No current model triggers it,
    but adding `reasoningEfforts: []` to models.json would have crashed the request.
    Added a length guard.
    
    Co-Authored-By: Claude <noreply@anthropic.com>
    
    ---------
    
    Co-authored-by: Claude <noreply@anthropic.com>
    thaolaptrinh and claude authored Jul 20, 2026
    Configuration menu
    Copy the full SHA
    665a859 View commit details
    Browse the repository at this point in the history
  2. Configuration menu
    Copy the full SHA
    748704c View commit details
    Browse the repository at this point in the history
Loading