mirror of
https://github.com/dtzp555-max/ocp.git
synced 2026-07-21 21:15:09 +00:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4f3355d415 |
@@ -1,11 +1,5 @@
|
||||
# Changelog
|
||||
|
||||
## Unreleased
|
||||
|
||||
### Changed
|
||||
|
||||
- **Default `sonnet` alias → `claude-sonnet-5`.** The `sonnet` alias (the model used for every `/v1/chat/completions` request that omits `model`, and OpenClaw's OCP primary via `ocp-connect`) now resolves to `claude-sonnet-5` instead of `claude-sonnet-4-6`. `claude-sonnet-4-6` remains available by full ID for pinning. This is a behavior change for clients relying on the default — pin `claude-sonnet-4-6` explicitly to retain the previous model. Split out from the additive `claude-sonnet-5` model entry (#152) per Iron Rule 11.
|
||||
|
||||
## v3.22.1 — 2026-07-17
|
||||
|
||||
Minor release: TUI-mode latency and streaming features — **all opt-in and off by default**, so the default request path (`-p` / `--output-format stream-json`) is byte-for-byte unchanged — plus hardening from an independent (Codex) re-review of the streaming work, Windows `claude.exe` startup resolution, and the Claude Sonnet 5 model entry. No new `cli.js` wire behavior and no new endpoint; the new surface is entirely OCP-owned TUI-mode configuration (env vars), startup binary discovery, model metadata, and `/health` observation. Every code PR carried a fresh-context reviewer (Iron Rule 10). (Version note: v3.22.0 was prepared but never tagged; its contents ship here as v3.22.1 together with the additions below.)
|
||||
|
||||
@@ -25,7 +25,7 @@ One proxy. Multiple IDEs. All models. **$0 API cost.**
|
||||
There are several Claude proxy projects. OCP picks a specific lane: **align tightly with what `cli.js` actually does, observe + multiplex what's already there, don't extend the protocol.** What you get:
|
||||
|
||||
- **LAN multi-user keys** (v3.7.0) — reach one Claude Pro/Max subscription from your own devices across the LAN. Each device gets a per-key API token (no OAuth session leak), with independent usage tracking and one-line revocation. Pro/Max are **per-user** accounts — see [Sharing with family / a team — honest limits](#deployment-model--security-read-this) before extending access to other **people**.
|
||||
- **`ocp-connect` one-shot client setup** — one command on the client machine auto-configures OpenClaw, and detects Cursor, Cline, Continue.dev, and opencode to print ready-to-paste setup hints for each. No hunting for where each tool keeps its `OPENAI_BASE_URL`.
|
||||
- **`ocp-connect` one-shot IDE setup** — one command on the client machine detects and configures Claude Code, Cursor, Cline, Continue.dev, OpenCode, and OpenClaw. No pasting `OPENAI_BASE_URL` six times.
|
||||
- **Response cache with per-key isolation + singleflight** (v3.13.0). Optional SHA-256 prompt cache, isolated per API key (cross-user pollution is impossible by hash construction, not by application logic), with stampede protection on concurrent identical prompts. Off by default. ([PR #65](https://github.com/dtzp555-max/ocp/pull/65), [PR #66](https://github.com/dtzp555-max/ocp/pull/66))
|
||||
- **Per-key request quotas** (v3.8.0). Daily / weekly / monthly limits per key — set a kid's iPad to 20/day, a partner's laptop to 100/week. ([PR #18](https://github.com/dtzp555-max/ocp/pull/18))
|
||||
- **SSE heartbeat for long reasoning** ([v3.12.0](https://github.com/dtzp555-max/ocp/releases/tag/v3.12.0), opt-in). If you've ever watched your IDE die at the 60s idle mark during a long Claude tool-use pause — that's nginx/Cloudflare default behavior. OCP emits an SSE comment frame to keep the connection alive without polluting the response. ([PR #49](https://github.com/dtzp555-max/ocp/pull/49))
|
||||
@@ -121,7 +121,7 @@ Please follow https://github.com/dtzp555-max/ocp/blob/main/README.md
|
||||
installed and logged in (`claude auth status`). Install missing pieces
|
||||
using my system's package manager.
|
||||
2. git clone the repo, cd in, and run `node setup.mjs`.
|
||||
3. Verify with `curl http://127.0.0.1:3456/v1/models` (should list 6 models).
|
||||
3. Verify with `curl http://127.0.0.1:3456/v1/models` (should list 5 models).
|
||||
4. Add `export OPENAI_BASE_URL=http://127.0.0.1:3456/v1` to my shell rc.
|
||||
5. Tell me to reload my shell and try a tool like Cline / Continue / Cursor.
|
||||
|
||||
@@ -148,7 +148,7 @@ Please follow https://github.com/dtzp555-max/ocp/blob/main/README.md
|
||||
5. Add OCP_ADMIN_KEY to my shell rc (~/.zshrc or ~/.bashrc).
|
||||
6. Run `ocp lan` to show me the LAN IP and connect command.
|
||||
7. Optionally create example keys: `ocp keys add laptop`, `ocp keys add tablet`.
|
||||
8. Verify: `curl http://127.0.0.1:3456/v1/models` returns 6 models.
|
||||
8. Verify: `curl http://127.0.0.1:3456/v1/models` returns 5 models.
|
||||
|
||||
Tell me each step before running it. On error, diagnose before retrying.
|
||||
```
|
||||
@@ -157,7 +157,8 @@ Tell me each step before running it. On error, diagnose before retrying.
|
||||
|
||||
```text
|
||||
There's an OCP server at <SERVER_IP> on my LAN. Configure this machine to
|
||||
use it for any local IDEs (Cursor, Cline, Continue.dev, OpenCode, OpenClaw).
|
||||
use it for any local IDEs (Cursor, Cline, Continue.dev, OpenCode, Claude
|
||||
Code, OpenClaw).
|
||||
|
||||
Server IP: <SERVER_IP>
|
||||
API key (leave blank if the server has anonymous mode enabled): <OPTIONAL_KEY>
|
||||
@@ -170,7 +171,7 @@ Please follow https://github.com/dtzp555-max/ocp/blob/main/README.md
|
||||
chmod +x ocp-connect
|
||||
2. Run `./ocp-connect <SERVER_IP>` (add `--key <KEY>` if you have one).
|
||||
3. Follow any IDE-specific manual hints it prints.
|
||||
4. Verify: `curl http://<SERVER_IP>:3456/v1/models` returns 6 models.
|
||||
4. Verify: `curl http://<SERVER_IP>:3456/v1/models` returns 5 models.
|
||||
5. Tell me to reload my shell + restart any IDE that was already running.
|
||||
|
||||
Don't auto-retry on error. Tell me the failure mode first.
|
||||
@@ -240,7 +241,7 @@ Run `ocp lan` to see your IP and ready-to-share instructions.
|
||||
**Verify:**
|
||||
```bash
|
||||
curl http://127.0.0.1:3456/v1/models
|
||||
# Returns: claude-opus-4-8, claude-opus-4-7, claude-opus-4-6, claude-sonnet-5, claude-sonnet-4-6, claude-haiku-4-5-20251001
|
||||
# Returns: claude-opus-4-8, claude-opus-4-7, claude-opus-4-6, claude-sonnet-4-6, claude-haiku-4-5-20251001
|
||||
```
|
||||
|
||||
#### Headless install notes
|
||||
@@ -319,7 +320,7 @@ OCP Connect v1.3.0
|
||||
(set by admin via PROXY_ANONYMOUS_KEY; see issue #12 §14 Path A)
|
||||
|
||||
Testing API access...
|
||||
✓ API accessible (6 models available)
|
||||
✓ API accessible (5 models available)
|
||||
|
||||
Shell config:
|
||||
✓ .bashrc
|
||||
@@ -352,7 +353,6 @@ OCP Connect v1.3.0
|
||||
• ocp/claude-opus-4-8
|
||||
• ocp/claude-opus-4-7
|
||||
• ocp/claude-opus-4-6
|
||||
• ocp/claude-sonnet-5
|
||||
• ocp/claude-sonnet-4-6
|
||||
• ocp/claude-haiku-4-5-20251001
|
||||
Priority: PRIMARY (default model)
|
||||
@@ -577,9 +577,9 @@ The simplest path: ask your AI.
|
||||
|
||||
What `ocp update` does:
|
||||
|
||||
- **Patch bump** (e.g. `v3.21.0 → v3.21.1`):
|
||||
- **Patch bump** (e.g. `v3.14.0 → v3.14.1`):
|
||||
light path (git pull + npm install + restart).
|
||||
- **Cross-minor** (e.g. `v3.18 → v3.22`):
|
||||
- **Cross-minor** (e.g. `v3.10 → v3.14`):
|
||||
full path: pre-flight check, snapshot, `setup.mjs` (with plist env-merge),
|
||||
service restart, post-flight `/health` and `/v1/models` verification.
|
||||
- **Old version** (< v3.4.0):
|
||||
@@ -701,8 +701,6 @@ Your IDE → OCP (localhost:3456) → claude --output-format stream-json CLI →
|
||||
|
||||
OCP translates OpenAI-compatible `/v1/chat/completions` requests into `claude --output-format stream-json` CLI calls. Anthropic sees normal Claude Code usage — no API billing, no separate key needed.
|
||||
|
||||
> **Billing-policy status (as of 2026-07).** Anthropic announced (2026-05-14) that from 2026-06-15 the `claude -p` / Agent SDK path would move to a separate metered credit pool — then **paused the change on its effective date**: *"For now, nothing has changed: Claude Agent SDK, `claude -p`, and third-party app usage still draw from your subscription's usage limits"* ([official help article](https://support.claude.com/en/articles/15036540-use-the-claude-agent-sdk-with-your-claude-plan)). So the default path above currently bills your subscription. Anthropic has said it will give notice before any future change; if the split re-lands, OCP's opt-in [subscription-pool (TUI) mode](#subscription-pool-tui-mode) is the ready-made hedge — see the billing table there.
|
||||
|
||||
### Client-tools boundary
|
||||
|
||||
OCP is a **text-prompt bridge** to the official `claude` CLI. It does **not** pass through OpenAI `tools`/`functions` payloads or Anthropic `tool_use` blocks to the client. Clients (Cline, Cursor, OpenClaw, etc.) pointed at OCP receive **assistant TEXT only** — they never get `tool_calls` to execute locally.
|
||||
@@ -711,8 +709,6 @@ Any tool use happens server-side, under the `--allowedTools` set configured on t
|
||||
|
||||
**Client-local tool execution is not supported by design.** Supporting it would require bypassing the `claude` CLI to call the raw Anthropic API directly — that is a different product, and is out of scope per `ALIGNMENT.md` (every OCP endpoint must correspond to something `cli.js` actually does).
|
||||
|
||||
**What this means for choosing OCP (workload fit).** LAN/multi-device OCP is built for **chat-class** workloads — Q&A, translation, scripting against the API, chat frontends, home-automation backends — where text in/text out is the whole job. It is **not** the right tool for a coding agent running on a *client* machine that needs the AI to read and edit *that machine's* files: tools execute on the OCP host, so the model can never touch the client's filesystem. For that workload, run `claude` (or a local OCP) directly on the machine where the code lives.
|
||||
|
||||
## Available Models
|
||||
|
||||
| Model ID | Notes |
|
||||
@@ -720,8 +716,8 @@ Any tool use happens server-side, under the `--allowedTools` set configured on t
|
||||
| `claude-opus-4-8` | Most capable (default for `opus` alias) |
|
||||
| `claude-opus-4-7` | Previous Opus, retained for pinning |
|
||||
| `claude-opus-4-6` | Older Opus, retained for pinning |
|
||||
| `claude-sonnet-5` | Latest Sonnet (default for `sonnet` alias) |
|
||||
| `claude-sonnet-4-6` | Previous Sonnet, retained for pinning |
|
||||
| `claude-sonnet-5` | Latest Sonnet (available by full ID; `sonnet` alias repoint tracked separately) |
|
||||
| `claude-sonnet-4-6` | Good balance of speed/quality (default for `sonnet` alias) |
|
||||
| `claude-haiku-4-5-20251001` | Fastest, lightweight (default for `haiku` alias) |
|
||||
|
||||
The canonical list lives in [`models.json`](./models.json) — the single source of truth as of v3.11.0. Both `server.mjs` (the `/v1/models` endpoint) and `setup.mjs` (the OpenClaw registration) derive from it. Adding a new model is now a one-file edit:
|
||||
@@ -831,12 +827,11 @@ lsof -nP -iTCP:3456 -sTCP:LISTEN
|
||||
If it's an old OCP process, stop it before re-running setup:
|
||||
|
||||
```bash
|
||||
launchctl bootout gui/$(id -u)/dev.ocp.proxy # macOS launchd
|
||||
systemctl --user stop ocp-proxy # Linux systemd (installed as a --user unit)
|
||||
ocp stop # if the CLI is on PATH
|
||||
launchctl bootout gui/$(id -u)/dev.ocp.proxy # macOS launchd fallback
|
||||
sudo systemctl stop ocp-proxy # Linux systemd fallback
|
||||
```
|
||||
|
||||
(There is no `ocp stop` subcommand — the proxy runs as a service, so stopping it goes through the service manager above. `ocp restart` exists for the bounce case.)
|
||||
|
||||
### Setup fails with "node: command not found" or version error
|
||||
|
||||
OCP requires Node.js 22.5+. Install:
|
||||
@@ -953,7 +948,6 @@ See [Subscription-pool (TUI) mode](#subscription-pool-tui-mode) and ADR 0007 PR-
|
||||
| `CLAUDE_CACHE_TTL` | `0` | Response cache TTL (ms, 0 = disabled). Set to e.g. `300000` for 5-min cache |
|
||||
| `CLAUDE_ALLOWED_TOOLS` | `Bash,Read,...,Agent` | Comma-separated tools to pre-approve |
|
||||
| `CLAUDE_SKIP_PERMISSIONS` | `false` | Bypass all permission checks |
|
||||
| `CLAUDE_MCP_CONFIG` | *(unset)* | Path to an MCP server config JSON, passed to the spawned `claude` as `--mcp-config` (both the `-p` path and TUI `OCP_TUI_FULL_TOOLS` panes) |
|
||||
| `CLAUDE_NO_CONTEXT` | `false` | Suppress CLAUDE.md and auto-memory injection (pure API mode) |
|
||||
| `PROXY_API_KEY` | *(unset)* | Bearer token for shared-mode authentication |
|
||||
| `PROXY_ANONYMOUS_KEY` | *(unset)* | Well-known anonymous key allowlist (multi mode). When set, this exact string bypasses `validateKey()` and grants public access. Exposed via `/health.anonymousKey` only to localhost, or to all callers when `PROXY_ADVERTISE_ANON_KEY=1`. See [Anonymous Access](#anonymous-access-optional). |
|
||||
@@ -972,7 +966,7 @@ See [Subscription-pool (TUI) mode](#subscription-pool-tui-mode) and ADR 0007 PR-
|
||||
| `OCP_TUI_STREAM_POLL_MS` | `100` | (TUI-mode, streaming) Interval at which OCP drains the delta sink. The hook fires at block granularity (seconds apart), so a finer poll buys nothing. |
|
||||
| `OCP_TUI_MAX_CONCURRENT` | `2` | (TUI-mode) Max concurrent interactive TUI turns. **Independent** of `CLAUDE_MAX_CONCURRENT` (which bounds the `-p`/stream-json path; TUI never uses it). A TUI turn is heavy (per-request cold-boot of tmux+claude + up to `CLAUDE_TUI_WALLCLOCK_MS` wallclock), so the default is low to keep small hosts (e.g. a Pi 4) alive under a burst. Excess turns **queue** (bounded); a full queue yields a 503. See ADR 0007 PR-B amendment. |
|
||||
| `OCP_TUI_POOL_SIZE` | `0` (off) | (TUI-mode) Number of **pre-booted warm `claude` panes** kept ready, so a request does not pay the cold boot. `0` disables the pool entirely — the request path is then exactly the cold-boot path. Max `4`; an unparseable value disables it rather than guessing. **Measured on a Mac mini (Sonnet 4.6, `--effort low`): end-to-end p50 `10.17s` (n=6, pool off) → `6.00s` (n=12 warm hits) — −4.2 s / −41%** — the pool recovers both the ~1.2 s boot *and* ~2.9 s of post-input-bar init that a pane which has been idle a moment has already finished. **Cost:** each warm pane is a *live idle `claude` process* held whether or not a request ever arrives (peak processes ≈ pool size + `OCP_TUI_MAX_CONCURRENT` + 1 booting replacement) — which is why it is opt-in. Panes are **single-use**: one turn, then killed and replaced in the background. The **first request after start (and after any model switch) is always a cold miss** — the pool warms the most recently requested model, since OCP cannot know which model the next caller wants. See `docs/plans/2026-07-13-tui-latency/`. |
|
||||
| `OCP_SKIP_AUTH_TEST` | *(unset)* | When `=1`, skip the `claude -p` auth probe during `setup.mjs`. Under the announced (currently **paused**) 2026-06-15 billing split this probe would draw from the metered Agent SDK credit pool; set this to avoid burning a probe on re-installs or `ocp update` runs. Auth is validated at the first real request. |
|
||||
| `OCP_SKIP_AUTH_TEST` | *(unset)* | When `=1`, skip the `claude -p` auth probe during `setup.mjs`. After 2026-06-15 this probe draws from the Agent SDK credit pool; set this to avoid burning a metered credit on re-installs or `ocp update` runs. Auth is validated at the first real request. |
|
||||
| `OCP_TUI_FULL_TOOLS` | *(unset)* | (TUI-mode, **single-user only**) When `=1`, grant the interactive session the **same tool surface as the `-p` path** — `--allowedTools` (+ optional `--mcp-config`, read from `CLAUDE_ALLOWED_TOOLS` / `CLAUDE_MCP_CONFIG`) — instead of the default MCP-walled, built-in-tools-only set. Lets a trusted single-operator TUI deployment run a **tool-using / MCP agent** (e.g. an OpenClaw assistant) on the subscription pool. Safe because TUI **refuses to boot under `AUTH_MODE=multi`** (hard exit) — no guest key can ever reach the TUI path, so this gate cannot expose tools to an untrusted caller. (Under `AUTH_MODE=shared` + `OCP_TUI_ALLOW_LAN=1`, anyone holding the single shared key reaches it — that is the existing TUI trust model, unchanged.) Note: `--dangerously-skip-permissions` / `CLAUDE_SKIP_PERMISSIONS` is **not** supported for TUI — claude v2.1.x shows an interactive bypass-acceptance screen in headless tmux that cannot be answered, bricking the pane. Use scratch-home `settings.json` `additionalDirectories` instead. See [Subscription-pool (TUI) mode](#subscription-pool-tui-mode) and ADR 0007. |
|
||||
|
||||
### Streaming heartbeat
|
||||
@@ -992,16 +986,14 @@ OCP also sends `X-Accel-Buffering: no` on SSE responses so nginx-default proxy b
|
||||
|
||||
### What it is and why
|
||||
|
||||
> **⚠️ Status (as of 2026-07): the billing split below is PAUSED.** Anthropic announced it for 2026-06-15, then paused it on the effective date — *"For now, nothing has changed: Claude Agent SDK, `claude -p`, and third-party app usage still draw from your subscription's usage limits"* ([official help article](https://support.claude.com/en/articles/15036540-use-the-claude-agent-sdk-with-your-claude-plan)). While the pause holds, OCP's default `-p` path bills the subscription and **TUI-mode is a hedge, not a necessity**. The table describes the *announced* regime, kept here because Anthropic says a reworked change will return (with advance notice) — everything in this section is ready to flip on that day.
|
||||
From 2026-06-15 Anthropic routes `claude` invocations by `cc_entrypoint`:
|
||||
|
||||
The announced routing keys `claude` invocations by `cc_entrypoint`:
|
||||
|
||||
| Launch method | `cc_entrypoint` | Billing pool (announced regime, currently paused) |
|
||||
| Launch method | `cc_entrypoint` | Billing pool |
|
||||
|---------------|-----------------|-------------|
|
||||
| `claude -p` / `--output-format` (OCP default) | `sdk-cli` | Agent SDK credit pool (~$20/mo on Pro) |
|
||||
| Interactive `claude` (no flags) | `cli` | Pro/Max subscription pool |
|
||||
|
||||
TUI-mode lets OCP serve requests via the interactive path so they bill against the subscription pool under that regime. The response is read from claude's native JSONL session transcript once the turn is complete, then replayed to the caller as a normal OpenAI completion or chunked SSE response.
|
||||
TUI-mode lets OCP serve requests via the interactive path so they bill against the subscription pool. The response is read from claude's native JSONL session transcript once the turn is complete, then replayed to the caller as a normal OpenAI completion or chunked SSE response.
|
||||
|
||||
### Billing-classifier labeling (`OCP_TUI_ENTRYPOINT`)
|
||||
|
||||
@@ -1087,7 +1079,7 @@ a sub-5-second budget. Full measurements and methodology:
|
||||
|
||||
### Monitoring drift via `/health`
|
||||
|
||||
`GET /health` includes a `tui` block so you can poll for a silent billing-pool drift (the top risk under the announced split, if it re-lands — a lost TTY flipping `cc_entrypoint` from `cli` to `sdk-cli` would still return answers but land in the metered pool). The block is **always present** (with `enabled:false` when TUI-mode is off):
|
||||
`GET /health` includes a `tui` block so you can poll for a silent billing-pool drift (the top risk after the 6/15 flip — a lost TTY flipping `cc_entrypoint` from `cli` to the metered `sdk-cli` pool would still return answers but burn metered credits). The block is **always present** (with `enabled:false` when TUI-mode is off):
|
||||
|
||||
```jsonc
|
||||
"tui": {
|
||||
@@ -1126,11 +1118,9 @@ unset CLAUDE_TUI_MODE
|
||||
|
||||
The stream-json path is restored immediately. No other change is needed.
|
||||
|
||||
### Operator checklist for the (paused) billing split
|
||||
### 2026-06-15 operator checklist
|
||||
|
||||
> **Status:** the 2026-06-15 split never took effect — Anthropic paused it on the effective date (see the status note at the top of this section). **Nothing needs flipping while the pause holds.** The checklist is retained verbatim as the runbook for if/when a reworked change lands (Anthropic has promised advance notice).
|
||||
|
||||
Under the announced regime, every host serving traffic must be flipped to TUI-mode **and** canary-verified before the effective date, or it will bill the metered Agent SDK credit pool instead of the subscription.
|
||||
Every host serving traffic must be flipped to TUI-mode **and** canary-verified before 2026-06-15, or it will bill the metered Agent SDK credit pool instead of the subscription.
|
||||
|
||||
- **[Flip/rollback runbook](docs/runbooks/tui-flip-rollback.md)** — how to set `CLAUDE_TUI_MODE=true` on systemd (Linux) and launchd (macOS) hosts. Covers the `daemon-reload` requirement (systemd) and the `bootout`+`bootstrap` cycle requirement (launchd — `launchctl kickstart -k` does not reload plist env).
|
||||
- **[615-canary runbook](docs/runbooks/615-canary.md)** — after each flip, run one quiesced request and compare the Agent SDK credit balance before and after. `entrypoint:cli` in the transcript (the `cc_entrypoint` billing classifier) is necessary but not sufficient — only a stable credit balance confirms the subscription pool is being used. Balance check is a manual step (no known programmatic API for the Agent SDK credit pool balance).
|
||||
|
||||
+1
-1
@@ -53,7 +53,7 @@
|
||||
],
|
||||
"aliases": {
|
||||
"opus": "claude-opus-4-8",
|
||||
"sonnet": "claude-sonnet-5",
|
||||
"sonnet": "claude-sonnet-4-6",
|
||||
"haiku": "claude-haiku-4-5-20251001"
|
||||
},
|
||||
"legacyAliases": {
|
||||
|
||||
+2
-7
@@ -202,13 +202,8 @@ for mid in model_ids:
|
||||
|
||||
# Handle primary/backup
|
||||
if priority == "1":
|
||||
# OCP as primary — pick the best model (prefer the latest Sonnet for daily use,
|
||||
# tracking the `sonnet` alias default in models.json; fall back across versions).
|
||||
_sonnet_pref = ["claude-sonnet-5", "claude-sonnet-4-6"]
|
||||
primary_model = next(
|
||||
(provider_name + "/" + m for m in _sonnet_pref if m in model_ids),
|
||||
provider_name + "/" + model_ids[0],
|
||||
)
|
||||
# OCP as primary — pick the best model (prefer sonnet for daily use)
|
||||
primary_model = provider_name + "/claude-sonnet-4-6" if "claude-sonnet-4-6" in model_ids else provider_name + "/" + model_ids[0]
|
||||
config["agents"]["defaults"].setdefault("model", {})
|
||||
config["agents"]["defaults"]["model"]["primary"] = primary_model
|
||||
# Keep existing fallbacks
|
||||
|
||||
+2
-2
@@ -3322,8 +3322,8 @@ test("models.json aliases.haiku === 'claude-haiku-4-5-20251001' (usage-probe SPO
|
||||
assert.equal(_spotModels.aliases.haiku, "claude-haiku-4-5-20251001");
|
||||
});
|
||||
|
||||
test("models.json aliases.sonnet === 'claude-sonnet-5' (default-request-model SPOT)", () => {
|
||||
assert.equal(_spotModels.aliases.sonnet, "claude-sonnet-5");
|
||||
test("models.json aliases.sonnet === 'claude-sonnet-4-6' (default-request-model SPOT)", () => {
|
||||
assert.equal(_spotModels.aliases.sonnet, "claude-sonnet-4-6");
|
||||
});
|
||||
|
||||
// ── Referential integrity (PR #152 review) ──────────────────────────────────
|
||||
|
||||
Reference in New Issue
Block a user