Skip to content
Open
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
12 changes: 5 additions & 7 deletions src/providers/model-rename-startup.ts
Original file line number Diff line number Diff line change
@@ -1,26 +1,24 @@
import { mutatePersistedConfig } from "../config";
import { projectModelRenames } from "./model-rename-migration";
import { projectStaleContextWindows } from "./stale-context-window-migration";
import { projectStaleVisionClassifications } from "./stale-vision-classification-migration";
import { projectDevinCliAuthMode } from "./devin-cli-authmode-migration";
import type { OcxConfig } from "../types";

/**
* The startup projection: registry model renames, then the context-window and
* vision-classification repairs. All three fix a saved row the registry can no longer reach on its own —
* The startup projection: registry model renames, then context-window and auth-mode repairs.
* These fix a saved row the registry can no longer reach on its own —
* `enrichProviderFromRegistry` backfills a missing field and never rewrites a
* present one — so they share this pass rather than adding a second boot step
* with its own persistence, adopt, and failure handling.
*/
export function projectStartupConfigRepairs(config: OcxConfig): ReturnType<typeof projectModelRenames> {
const renames = projectModelRenames(config);
const windows = projectStaleContextWindows(renames.config);
const vision = projectStaleVisionClassifications(windows.config);
const devinCli = projectDevinCliAuthMode(vision.config);
const devinCli = projectDevinCliAuthMode(windows.config);
return {
config: devinCli.config,
changed: renames.changed || windows.changed || vision.changed || devinCli.changed,
warnings: [...renames.warnings, ...windows.warnings, ...vision.warnings, ...devinCli.warnings],
changed: renames.changed || windows.changed || devinCli.changed,
warnings: [...renames.warnings, ...windows.warnings, ...devinCli.warnings],
};
}

Expand Down
10 changes: 3 additions & 7 deletions src/providers/registry/entries-core.ts
Original file line number Diff line number Diff line change
Expand Up @@ -718,12 +718,9 @@ export const PROVIDER_REGISTRY_CORE: readonly ProviderRegistryEntry[] = [
// HTTP 400 "Model only supports text input", which is what keeps the two
// distinct here rather than collapsing them.
//
// The declaration is what reaches an EXISTING install: derive.ts fills
// noVisionModels all-or-nothing, so a config persisted while the stale list
// was current keeps it forever, and modelInputModalities is filled per-key
// BENEATH the saved value. Both halves are repaired by
// stale-vision-classification-migration.ts; correcting the registry alone
// would fix new installs and leave existing ones stripping images.
// derive.ts fills missing registry metadata but does not replace saved values.
// That makes this declaration the default for new rows while preserving an
// existing install's operator-editable image-routing restrictions.
"deepseek-v4.1-flash": ["text", "image"],
// Muse Spark Contributor is natively multimodal on Zen Go: it accepts input_image
// parts over /responses (probed 2026-08-26). Without this declaration the catalog
Expand Down Expand Up @@ -1258,4 +1255,3 @@ export const PROVIDER_REGISTRY_CORE: readonly ProviderRegistryEntry[] = [
note: "Serverless Inference subscription API. Live discovery exposes only kimi-k2-instruct because Vultr documents it as the sole tool-calling model.",
},
];

137 changes: 0 additions & 137 deletions src/providers/stale-vision-classification-migration.ts

This file was deleted.

28 changes: 7 additions & 21 deletions structure/providers-and-adapters.md
Original file line number Diff line number Diff line change
Expand Up @@ -78,27 +78,13 @@ answers HTTP 400 "Model only supports text input" and stays sidecar-backed. The
(`opencode-zen`, `opencode-free`) were not measurable (HTTP 402) and keep their existing
classification — an unverified tier is not evidence.

Because `enrichProviderFromRegistry` fills `noVisionModels` all-or-nothing and fills
`modelInputModalities` per-key beneath the saved value, both halves of a stale classification are
frozen into any config saved while it was current. `src/providers/stale-vision-classification-migration.ts`
repairs exactly those two saved values and runs inside the shared startup repair pass in
`src/providers/model-rename-startup.ts`. Correcting the registry alone fixes new installs only.

It covers both states that reach a running process, because the sidecar predicate reads
`noVisionModels` before `modelInputModalities`: the full stale pair (modalities still the stale
declaration and the id listed, both rewritten) and the half-repaired row (modalities already
corrected but the id still listed, where removing the name is what stops the image from being
stripped). The paired modality declaration is the guard in both cases, which is why a name listed
without one is left alone — that row is either a half-finished repair or a deliberate operator
entry, and the projection does not guess which. The row must also still be the registry's own:
identity resolves through `providerMatchesRegistryTransport`, the rule `enrichProviderFromRegistry`
applies before it writes registry metadata, plus the entry's adapter. `opencode-go` is a pinned
key preset without `preserveCustomDestination`, so its id alone claims a row — exactly as it does
for enrichment — and an entry that opts into destination preservation narrows the projection with
it. `modelCapabilities` is never written: it is the
axis that outranks every source here, so it is where a deliberate text-only override belongs
(`ocx provider edit <provider> --model <id> --text-only` writes it) and the one declaration a
restart cannot take back.
Because `enrichProviderFromRegistry` is fill-only, the corrected classification applies to new
rows and missing values. Startup does not rewrite an existing `noVisionModels` entry or
`modelInputModalities` value: those fields are operator-editable request-routing policy, and a
saved registry seed is indistinguishable from an intentional restriction without provenance.
Existing users can opt into the corrected native-vision classification by removing those saved

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Publish the upgrade steps in user docs

After the startup repair is removed, an existing opencode-go row that inherited the old seed continues routing deepseek-v4.1-flash through the vision sidecar until the user removes both saved overrides. This is a user-visible upgrade requirement, but the only new instruction is in this maintainer-facing structure document; add the cleanup steps and the corrected OpenCode Go classification to the relevant English docs-site/ provider or sidecar guide and keep its translations consistent.

AGENTS.md reference: AGENTS.md:L434-L435

Useful? React with 👍 / 👎.

overrides. `modelCapabilities` remains the highest-precedence per-model axis, and
`ocx provider edit <provider> --model <id> --text-only` writes an explicit restriction there.

The BigModel Coding Plan Responses preset uses the separately documented
`https://open.bigmodel.cn/api/v1` transport and a static catalog. Its provider row
Expand Down
Loading
Loading