The picker needs a list, and the three backends disagree about whether they have one. Claude answers `query.supportedModels()` and OpenCode answers `client.config.providers()`, both live and both scoped to what you are actually signed in to. Codex can enumerate nothing, at any layer. So `listModels` probes the two that can and falls back to a seed for the one that cannot, and nothing it does throws: a picker that cannot list models is a degraded menu, and one that takes the session down with it is a bug. Every failure comes back as a group carrying a `note` that says which — "Not signed in" and "Probe timed out" are different problems, and only one of them is the user's to fix. `packages/protocol/src/models.ts` is the seed, generated from models.dev by `scripts/gen-models.mjs` and reached through its own `./models` export subpath so the browser can take the list as a value without pulling zod along. Judgement lives in `scripts/models.curation.json` rather than in the output — the mechanical filter admits things like `gpt-realtime`, which is not a coding model — so the generated module stays purely derived and the taste is what gets reviewed. On the daemon, `resolveTarget` settles which backend and which model a turn runs on: what the turn asked for, else the default resolved for that backend, else the cross-harness one. Per backend rather than one string, because the picker can change harness mid-session and a single default would follow it and hand Codex an id only Claude answers to. `modelRefusal` is the other half. OpenCode drops a model id that does not name its provider, which makes asking for one indistinguishable from asking for nothing — the turn runs on the server's default while the composer goes on showing what was picked. It reads the turn's own model and deliberately not the resolved one: `--opencode-model` is already a hard error at parse time, and `--model` reaches all three backends where a bare id is right for two of them, so that one warns at launch and runs. What is left is the picker's free-text box, which had no guard at either end.
36 lines
889 B
JSON
36 lines
889 B
JSON
{
|
|
"name": "@airship/protocol",
|
|
"version": "0.0.0",
|
|
"private": true,
|
|
"type": "module",
|
|
"exports": {
|
|
".": {
|
|
"types": "./dist/index.d.ts",
|
|
"import": "./dist/index.js"
|
|
},
|
|
"./tokens": {
|
|
"types": "./dist/tokens.d.ts",
|
|
"import": "./dist/tokens.js"
|
|
},
|
|
"./models": {
|
|
"types": "./dist/models.d.ts",
|
|
"import": "./dist/models.js"
|
|
}
|
|
},
|
|
"main": "./dist/index.js",
|
|
"types": "./dist/index.d.ts",
|
|
"scripts": {
|
|
"build": "tsup src/index.ts src/tokens.ts src/models.ts --format esm --dts --sourcemap --clean",
|
|
"clean": "node ../../scripts/clean.mjs dist .turbo",
|
|
"dev": "tsup src/index.ts src/tokens.ts src/models.ts --format esm --dts --sourcemap --watch",
|
|
"test": "vitest run",
|
|
"typecheck": "tsc --noEmit"
|
|
},
|
|
"dependencies": {
|
|
"zod": "^4.0.0"
|
|
},
|
|
"devDependencies": {
|
|
"vitest": "^4.1.10"
|
|
}
|
|
}
|