Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/pull_request_template.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

## Safety and compatibility

- [ ] Unknown pricing and unavailable models still fail closed in every cost mode.
- [ ] Free and legacy verified-price Paid still reject unknown pricing; configured Paid still checks connection identity, availability, and capabilities.
- [ ] Paid routing remains an explicit user choice and cannot bypass capability gates.
- [ ] No credentials, private prompts, customer data, absolute user paths, or generated local settings are included.
- [ ] OpenCode config writes are explicit, receipt-owned, recoverable, and preserve unrelated settings.
Expand Down
8 changes: 8 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,14 @@

All notable changes to OpenCode Model Control are recorded here. The project follows [Semantic Versioning](https://semver.org/).

## 0.4.1

- Keep zero token rates on plan-specific provider slots from authorizing Free access, including old saved catalogs and public metadata caches. Configured Paid access remains available without an API estimate.
- Preserve availability for beta and enabled alpha models listed by OpenCode.
- Keep unchanged connection billing and role bindings when incomplete discovery omits models within a provider. Fresh endpoint changes still invalidate bindings.
- Accept nested and regional Usage model IDs containing `@` and `~`.
- Update dependencies within their existing major versions and record the published 0.4.0 release evidence.

## 0.4.0

- Treat empty SDK-default endpoints as unspecified rather than invalid, without letting a missing public URL certify a custom gateway.
Expand Down
16 changes: 9 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ The control panel runs on `127.0.0.1`. OpenCode remains responsible for provider

The running app is authoritative for model names, availability, pricing evidence, and role eligibility.

> This source documents **0.4.0**; `@latest` installs the version currently published on [npm](https://www.npmjs.com/package/opencode-model-control). Check the [release index](https://github.com/BitL8-ByteShort/opencode-model-control/releases) for availability and the [support matrix](docs/support-matrix.md) for verified compatibility.
> This source documents **0.4.1**; `@latest` installs the version currently published on [npm](https://www.npmjs.com/package/opencode-model-control). Check the [release index](https://github.com/BitL8-ByteShort/opencode-model-control/releases) for availability and the [support matrix](docs/support-matrix.md) for verified compatibility.

## What it does

Expand Down Expand Up @@ -55,7 +55,7 @@ npm install --global opencode-model-control@latest
opencode-model-control
```

The first command installs the version tagged `latest` on npm and its runtime dependencies. Check `opencode-model-control --version` against the public release notes; an older published version may not include the 0.3.0 behavior described here. The second command starts the local panel and opens it in the default browser.
The first command installs the version tagged `latest` on npm and its runtime dependencies. Check `opencode-model-control --version` against the public release notes; an older published version may not include the fixes described here. The second command starts the local panel and opens it in the default browser.

Then:

Expand Down Expand Up @@ -108,11 +108,11 @@ The connector writes absolute Node and package CLI paths, so a source checkout d

### Direct GitHub release artifact

The [GitHub release index](https://github.com/BitL8-ByteShort/opencode-model-control/releases) lists published versioned tarballs and checksums. Download the exact release asset, verify its SHA-256 against that release's checksum, then install the local file with `npm install --global /absolute/path/to/downloaded-package.tgz`. Historical package digests are recorded in the [historical package ledger](https://github.com/BitL8-ByteShort/opencode-model-control/blob/v0.2.1/packages/README.md). The [release checklist](docs/releasing.md) contains the maintainer-only 0.4.0 publication and verification procedure.
The [GitHub release index](https://github.com/BitL8-ByteShort/opencode-model-control/releases) lists published versioned tarballs and checksums. Download the exact release asset, verify its SHA-256 against that release's checksum, then install the local file with `npm install --global /absolute/path/to/downloaded-package.tgz`. Package digests and release evidence are recorded in the [package ledger](packages/README.md). The [release checklist](docs/releasing.md) contains the maintainer publication and verification procedure.

## What “Update available models” means (0.4.0)
## What “Update available models” means (0.4.1)

The button asks the installed OpenCode CLI for its effective model list with plugin-aware discovery and `--refresh`. This reflects OpenCode's resolved provider configuration, including its provider and model filters.
The button asks the installed OpenCode CLI for its effective model list with plugin-aware discovery and `--refresh`. This reflects OpenCode's resolved provider configuration, including its provider and model filters. Listed beta and enabled alpha models stay available. An incomplete result preserves omitted model routes and unchanged connection bindings; a freshly observed endpoint change still invalidates saved bindings.

Startup refreshes stale metadata before initialization completes; a live service checks every **15 minutes**, and **Update available models** can request an immediate refresh. A shared refresh lease coalesces panel/MCP processes; a recent persisted attempt prevents duplicate periodic work. OpenCode discovery and the independent public metadata fetch run concurrently. Failed or incomplete discovery retains the last usable model records; complete discovery can mark an absent model unavailable while preserving its identity and saved choices. The panel distinguishes last attempt, last successful discovery, and last successful pricing retrieval. A failed refresh cannot renew pricing freshness. Refresh does not invoke provider inference or rewrite OpenCode config; OpenCode itself may normalize its standard `$schema` field.

Expand All @@ -124,13 +124,15 @@ Catalog state is deliberately split into four concepts:

- **Discovered:** OpenCode reported the model.
- **Saved inclusion intent:** Policy, explicitly enabled, or explicitly disabled. Effective eligibility also requires current pricing, availability, and role capabilities.
- **Available:** the refreshed metadata reports it active.
- **Available:** OpenCode lists an active, beta, or enabled alpha model.
- **Runtime access checked:** a manually confirmed bounded synthetic OpenCode run returned the expected sentinel. OpenCode may have retried a provider failure during that run. Refresh does not make this claim or incur a model charge, and a runtime-access pass is not benchmark evidence.

## Free-first, Paid-first, and pricing evidence

Pricing is matched by the exact provider/full model key and API identity (model ID, npm adapter, and normalized endpoint). A similarly named model, a `-free` suffix, arbitrary CLI zeros, and bundled historical evidence cannot authorize free routing. Model Control fetches the fixed public `https://models.dev/api.json` endpoint without credentials; URLs inside metadata are never fetched. Complete, finite, nonnegative input/output rates are required. Every supported supplied billing dimension counts: reasoning, cache read/write, audio input/output, context tiers, legacy over-200k rates, and experimental modes. With complete valid evidence, any positive rate means paid; all supplied rates must be valid and exactly zero for free. Missing, malformed, unsupported, or conflicting pricing evidence is unknown. It cannot authorize Free or legacy verified-price Paid routing; configured Paid routing instead requires an eligible host connection. Complete positive CLI evidence can establish `reported-paid` when independent evidence does not contradict it; CLI zero cannot establish free.

Zero token rates on identified plan-specific provider slots do not prove free access. These records remain Unknown for Free routing, including when loaded from old saved catalogs or public metadata caches. Provider names do not establish account billing, entitlement, authentication, or quota. Configured Paid access can still use an eligible host connection.

Pricing evidence expires after **24 hours**, checked at route time even without another refresh. Successful HTTP 200 or cached 304 revalidation renews public-source freshness; a failed attempt does not. Cached evidence remains usable only until its existing expiry. Public-source digests and timestamps describe retrieved metadata, not a billing guarantee or model-quality score.

**Automatically include new models** defaults on. A model with `selection: "policy"` (including an absent control) follows that setting and the saved Free/Paid policy. Free permits current verified-free evidence only. Configured Paid permits eligible host connections without requiring a public estimate. Saving that Paid mode with auto-include on authorizes future eligible configured models without a separate click for every new model. Turning auto-include off excludes policy-following models; explicit enables still apply. An explicit disable always wins. An enable or role pin cannot bypass availability, capabilities, connection binding, or the selected policy. Free and legacy verified-price Paid still require current pricing evidence.
Expand Down Expand Up @@ -207,7 +209,7 @@ The isolation guard excludes user/project instructions, external plugins, MCP se

## Easy controls and Advanced tools

The normal 0.3.0 setup path is **Update**, choose a cost preference and inclusion policy, decide whether Omc-Router should become the default agent, **Save**, **Connect**, and restart OpenCode. After setup, saved policy changes apply live within the host-loaded inventory. The default-agent option adds `default_agent: "omc-router"` only when OpenCode has no existing default. A user-owned default is preserved, and disabling the option removes only a value previously added by this installation.
The normal setup path is **Update**, choose a cost preference and inclusion policy, decide whether Omc-Router should become the default agent, **Save**, **Connect**, and restart OpenCode. After setup, saved policy changes apply live within the host-loaded inventory. The default-agent option adds `default_agent: "omc-router"` only when OpenCode has no existing default. A user-owned default is preserved, and disabling the option removes only a value previously added by this installation.

The collapsed **Advanced tools for developers** section is optional. It shows the exact managed config path, lets a developer open or reveal that existing file, and previews or exports generated integration JSON. It does not provide an unrestricted config writer. Manual changes to an owned entry make connection health report **Needs attention**, and Model Control will not overwrite the divergence.

Expand Down
2 changes: 2 additions & 0 deletions docs/opencode-integration.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ For a custom provider that maps models to different endpoints or SDK adapters, a

Pricing is matched by the exact provider/full model key and API identity (model ID, npm adapter, and normalized endpoint). Raw empty, absent, and null URLs are unspecified SDK defaults; they are not invalid and are not a wildcard for custom gateways. A similarly named model, a `-free` suffix, arbitrary CLI zeros, and bundled historical evidence cannot authorize free routing. Model Control fetches the fixed public `https://models.dev/api.json` endpoint without credentials; URLs inside metadata are never fetched. Complete, finite, nonnegative input/output rates are required. Every supported supplied billing dimension counts: reasoning, cache read/write, audio input/output, context tiers, legacy over-200k rates, and experimental modes. With complete valid evidence, any positive rate means paid; all supplied rates must be valid and exactly zero for free. Missing, malformed, unsupported, or conflicting evidence is unknown. Unknown prices cannot authorize **Free** or migrated **verified-pricing Paid**. After the user saves the new Paid control (`configured-connections`), a configured host route may be used when estimates are unavailable. Complete positive CLI evidence can establish `reported-paid` when independent evidence does not contradict it; CLI zero cannot establish free, and CLI cost cannot override a public-price route mismatch.

Zero token rates on identified plan-specific provider slots do not prove free access. These records remain Unknown for Free routing, including old saved catalogs and cached public metadata. This restriction does not infer account billing, entitlement, authentication, or quota. Configured Paid access remains available when the host connection is eligible.

OpenCode owns execution transport. A provider-owned authentication `fetch` may be accepted on Paid routes when the exact selected provider/model and observable connection binding match. Transport visibility is host-managed in that case; Model Control does not claim to have verified the network destination. Task or model route overrides, changed endpoints, and opaque transports under Free policy remain blocked. There is no automatic fallback from a subscription connection to metered API billing.

Pricing evidence expires after **24 hours** for Free and legacy verified-pricing access, checked at route time even without another refresh. Configured-connection Paid can continue with a stale-estimate warning. Successful HTTP 200 or cached 304 revalidation renews public-source freshness; a failed attempt does not. Cached evidence remains usable only until its existing expiry. Public-source digests and timestamps describe retrieved metadata, not a billing guarantee, subscription quota, or model-quality score. Quota is **Not reported** unless a supported host adapter actually exposes it. Historical OpenCode usage is not classified from today's login.
Expand Down
Loading
Loading