@askdkc/dsh-cli 0.12.2 → 0.12.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +6 -1
- package/node_modules/@askdkc/dsh-auth/README.ja.md +6 -0
- package/node_modules/@askdkc/dsh-auth/README.md +5 -0
- package/node_modules/@askdkc/dsh-auth/lib/fresh-models.d.ts +59 -0
- package/node_modules/@askdkc/dsh-auth/lib/fresh-models.js +246 -0
- package/node_modules/@askdkc/dsh-auth/lib/index.d.ts +1 -0
- package/node_modules/@askdkc/dsh-auth/lib/index.js +1 -0
- package/node_modules/@askdkc/dsh-auth/lib/opencode-snapshot.generated.d.ts +321 -0
- package/node_modules/@askdkc/dsh-auth/lib/opencode-snapshot.generated.js +528 -0
- package/node_modules/@askdkc/dsh-auth/lib/pi-ai.d.ts +2 -1
- package/node_modules/@askdkc/dsh-auth/lib/pi-ai.js +2 -1
- package/node_modules/@askdkc/dsh-auth/lib/profiles.js +7 -1
- package/node_modules/@askdkc/dsh-auth/package.json +1 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -57,7 +57,7 @@ node scripts/with-publish-manifest.mjs npm pack --ignore-scripts
|
|
|
57
57
|
TARBALL="$PWD/askdkc-dsh-cli-$(node -p "require('./package.json').version").tgz"
|
|
58
58
|
|
|
59
59
|
cd ~/DIR/TO/deepseek-harness
|
|
60
|
-
pnpm dsh plugin --profile dsh-cli add "
|
|
60
|
+
pnpm dsh plugin --profile dsh-cli add "@askdkc/dsh-cli@file:${TARBALL}"
|
|
61
61
|
pnpm dsh --profile dsh-cli
|
|
62
62
|
```
|
|
63
63
|
|
|
@@ -65,6 +65,11 @@ Replace `~/DIR/TO/deepseek-harness` with your checkout path. The first interacti
|
|
|
65
65
|
launch registers `dsh-cli`; open a new shell, then run it from your project directory.
|
|
66
66
|
To update this fork, rebuild and reinstall the tarball. `/update` uses the registry.
|
|
67
67
|
|
|
68
|
+
Use the named `@askdkc/dsh-cli@file:...` form for local tarball updates. A bare
|
|
69
|
+
tarball path can fail with `ENOENT` when pnpm resolves a previous `file:` dependency
|
|
70
|
+
whose archive has been deleted. `TARBALL` holds the archive's absolute path; pass
|
|
71
|
+
it to the install command instead of executing it.
|
|
72
|
+
|
|
68
73
|
For PATH setup and install issues, see [Getting started](docs/getting-started.en.md).
|
|
69
74
|
|
|
70
75
|
## Use
|
|
@@ -119,6 +119,12 @@ dsh plugin --profile <name> add @askdkc/dsh-auth
|
|
|
119
119
|
(`llm-pi-ai` の設定プロファイルなど)、レジストリはそのルートの登録を拒否します。
|
|
120
120
|
プラグインは拒否をログに記録し、残りのルートを登録します。
|
|
121
121
|
1 つのプロバイダーには 1 つのアダプターを割り当ててください。
|
|
122
|
+
- `opencode` / `opencode-go` は、インストール済み pi-ai カタログの上に
|
|
123
|
+
Zen の最新モデル一覧を提供します(モデルごとの通信プロトコルは最も近い
|
|
124
|
+
カタログの兄弟モデルから解決し、既存モデルは常に優先されるため、追加のみで
|
|
125
|
+
削除は起きません)。`pnpm --dir dsh-auth sync:models` でスナップショットを
|
|
126
|
+
更新できます(`models.dev` と Zen の `/v1/models` を参照)。
|
|
127
|
+
実行時にネットワークは使いません。
|
|
122
128
|
|
|
123
129
|
## セキュリティ上の注意
|
|
124
130
|
|
|
@@ -118,6 +118,11 @@ the `/auth login <provider>` hint — never silently.
|
|
|
118
118
|
profile naming the same provider — is refused by the registry; the plugin
|
|
119
119
|
logs the refusal and mounts the remaining routes. Keep one provider on one
|
|
120
120
|
adapter.
|
|
121
|
+
- `opencode` / `opencode-go` serve the live Zen roster on top of the installed
|
|
122
|
+
pi-ai catalog (per-model wire protocols resolve from the nearest catalog
|
|
123
|
+
sibling; installed models always win). Refresh the checked-in snapshot with
|
|
124
|
+
`pnpm --dir dsh-auth sync:models` (reads `models.dev` plus the live Zen
|
|
125
|
+
`/v1/models` rosters); runtime stays offline-safe.
|
|
121
126
|
|
|
122
127
|
## Security notes
|
|
123
128
|
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Fresh OpenCode rosters on top of the installed pi-ai catalog.
|
|
3
|
+
*
|
|
4
|
+
* The installed catalog is the wire authority (per-model `api` protocol,
|
|
5
|
+
* base URLs, compat): overlapping ids are served untouched. The checked-in
|
|
6
|
+
* snapshot (`opencode-snapshot.generated.ts`, refreshed from models.dev plus
|
|
7
|
+
* the live Zen `/v1/models` rosters) contributes only roster ids the
|
|
8
|
+
* installed catalog lacks — each synthesized with per-model protocol
|
|
9
|
+
* resolution, never a route-level default:
|
|
10
|
+
*
|
|
11
|
+
* - models.dev metadata (name, reasoning, modalities, limits, cost) plus the
|
|
12
|
+
* wire envelope (`api`, `baseUrl`, `compat`, thinking levels, image
|
|
13
|
+
* budgets) inherited from the nearest same-route catalog sibling;
|
|
14
|
+
* - ids neither source describes are cloned wholesale from that sibling and
|
|
15
|
+
* keep working wherever the sibling does (provenance lives in the
|
|
16
|
+
* snapshot, not on the model object).
|
|
17
|
+
*
|
|
18
|
+
* The merge only ever adds: the result always covers the installed catalog,
|
|
19
|
+
* so a stale snapshot delays additions but can never remove working models.
|
|
20
|
+
*
|
|
21
|
+
* @module dsh-auth/fresh-models
|
|
22
|
+
*/
|
|
23
|
+
import type { PiAiProvider } from './pi-ai.js';
|
|
24
|
+
/** One allowlisted models.dev entry (see scripts/sync-opencode-models.mjs). */
|
|
25
|
+
export interface FreshModelEntry {
|
|
26
|
+
readonly id: string;
|
|
27
|
+
readonly name: string;
|
|
28
|
+
readonly reasoning?: boolean;
|
|
29
|
+
readonly attachment?: boolean;
|
|
30
|
+
readonly modalities: {
|
|
31
|
+
readonly input: readonly string[];
|
|
32
|
+
};
|
|
33
|
+
readonly limit: {
|
|
34
|
+
readonly context: number;
|
|
35
|
+
readonly output?: number;
|
|
36
|
+
};
|
|
37
|
+
readonly cost: {
|
|
38
|
+
readonly input: number;
|
|
39
|
+
readonly output: number;
|
|
40
|
+
readonly cache_read?: number;
|
|
41
|
+
};
|
|
42
|
+
readonly temperature?: boolean;
|
|
43
|
+
readonly reasoning_options?: {
|
|
44
|
+
readonly effort: readonly string[];
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
export type FreshRouteId = 'opencode' | 'opencode-go';
|
|
48
|
+
/**
|
|
49
|
+
* Union the snapshot roster onto one catalog provider. Installed models win
|
|
50
|
+
* on conflict and classifier-roster ids stay on pi-ai's classifier path, so
|
|
51
|
+
* the merged list always covers the installed catalog — a stale snapshot
|
|
52
|
+
* delays additions but never removes a working model.
|
|
53
|
+
* @param catalog - the installed pi-ai catalog provider for one route.
|
|
54
|
+
* @param route - the route the snapshot section is keyed under.
|
|
55
|
+
* @returns the catalog provider, or a shallow clone serving the union.
|
|
56
|
+
*/
|
|
57
|
+
export declare function withFreshModels(catalog: PiAiProvider, route: FreshRouteId): PiAiProvider;
|
|
58
|
+
/** Snapshot roster ids for one route, for smoke coverage. */
|
|
59
|
+
export declare function freshRosterIds(route: FreshRouteId): readonly string[];
|
|
@@ -0,0 +1,246 @@
|
|
|
1
|
+
import { OPENCODE_SNAPSHOT } from './opencode-snapshot.generated.js';
|
|
2
|
+
function record(value, what) {
|
|
3
|
+
if (typeof value !== 'object' || value === null || Array.isArray(value)) {
|
|
4
|
+
throw new Error(`dsh-auth: snapshot ${what} is not an object`);
|
|
5
|
+
}
|
|
6
|
+
return value;
|
|
7
|
+
}
|
|
8
|
+
function nonEmptyString(value) {
|
|
9
|
+
return typeof value === 'string' && value.length > 0 ? value : undefined;
|
|
10
|
+
}
|
|
11
|
+
function boundedStringList(value, what, max) {
|
|
12
|
+
if (!Array.isArray(value) || value.length > max || !value.every(item => typeof item === 'string')) {
|
|
13
|
+
throw new Error(`dsh-auth: snapshot ${what} is not a string list`);
|
|
14
|
+
}
|
|
15
|
+
const list = value;
|
|
16
|
+
if (new Set(list).size !== list.length)
|
|
17
|
+
throw new Error(`dsh-auth: snapshot ${what} has duplicates`);
|
|
18
|
+
return list;
|
|
19
|
+
}
|
|
20
|
+
function positiveInt(value) {
|
|
21
|
+
return typeof value === 'number' && Number.isInteger(value) && value > 0 ? value : undefined;
|
|
22
|
+
}
|
|
23
|
+
function nonnegativeNumber(value) {
|
|
24
|
+
return typeof value === 'number' && Number.isFinite(value) && value >= 0 ? value : undefined;
|
|
25
|
+
}
|
|
26
|
+
function parseEntry(route, key, value) {
|
|
27
|
+
const row = record(value, `${route}/${key}`);
|
|
28
|
+
if (row.id !== key)
|
|
29
|
+
throw new Error(`dsh-auth: snapshot ${route}/${key} names "${String(row.id)}"`);
|
|
30
|
+
const name = nonEmptyString(row.name);
|
|
31
|
+
if (name === undefined)
|
|
32
|
+
throw new Error(`dsh-auth: snapshot ${route}/${key} has no name`);
|
|
33
|
+
const modalities = record(row.modalities ?? fail(route, key, 'modalities'), `${route}/${key} modalities`).input;
|
|
34
|
+
if (!Array.isArray(modalities) || modalities.length === 0 || !modalities.every(m => typeof m === 'string')) {
|
|
35
|
+
throw new Error(`dsh-auth: snapshot ${route}/${key} has no input modalities`);
|
|
36
|
+
}
|
|
37
|
+
const limit = record(row.limit ?? fail(route, key, 'limit'), `${route}/${key} limit`);
|
|
38
|
+
const context = positiveInt(limit.context);
|
|
39
|
+
if (context === undefined)
|
|
40
|
+
throw new Error(`dsh-auth: snapshot ${route}/${key} has no context limit`);
|
|
41
|
+
const output = limit.output === undefined ? undefined : positiveInt(limit.output);
|
|
42
|
+
if (limit.output !== undefined && output === undefined) {
|
|
43
|
+
throw new Error(`dsh-auth: snapshot ${route}/${key} has a malformed output limit`);
|
|
44
|
+
}
|
|
45
|
+
const cost = record(row.cost ?? fail(route, key, 'cost'), `${route}/${key} cost`);
|
|
46
|
+
const input = nonnegativeNumber(cost.input);
|
|
47
|
+
const outputCost = nonnegativeNumber(cost.output);
|
|
48
|
+
if (input === undefined || outputCost === undefined) {
|
|
49
|
+
throw new Error(`dsh-auth: snapshot ${route}/${key} has no pricing`);
|
|
50
|
+
}
|
|
51
|
+
const cacheRead = cost.cache_read === undefined ? undefined : nonnegativeNumber(cost.cache_read);
|
|
52
|
+
if (cost.cache_read !== undefined && cacheRead === undefined) {
|
|
53
|
+
throw new Error(`dsh-auth: snapshot ${route}/${key} has malformed cache pricing`);
|
|
54
|
+
}
|
|
55
|
+
const entry = {
|
|
56
|
+
id: key,
|
|
57
|
+
name,
|
|
58
|
+
reasoning: typeof row.reasoning === 'boolean' ? row.reasoning : undefined,
|
|
59
|
+
attachment: typeof row.attachment === 'boolean' ? row.attachment : undefined,
|
|
60
|
+
temperature: typeof row.temperature === 'boolean' ? row.temperature : undefined,
|
|
61
|
+
reasoning_options: parseEffort(route, key, row.reasoning_options),
|
|
62
|
+
modalities: { input: modalities.slice() },
|
|
63
|
+
limit: output === undefined ? { context } : { context, output },
|
|
64
|
+
cost: cacheRead === undefined ? { input, output: outputCost } : { input, output: outputCost, cache_read: cacheRead },
|
|
65
|
+
};
|
|
66
|
+
return entry;
|
|
67
|
+
}
|
|
68
|
+
function parseEffort(route, key, value) {
|
|
69
|
+
if (value === undefined)
|
|
70
|
+
return undefined;
|
|
71
|
+
const options = record(value, `${route}/${key} reasoning options`).effort;
|
|
72
|
+
if (options === undefined)
|
|
73
|
+
return undefined;
|
|
74
|
+
if (!Array.isArray(options) || !options.every(v => typeof v === 'string')) {
|
|
75
|
+
throw new Error(`dsh-auth: snapshot ${route}/${key} has malformed effort values`);
|
|
76
|
+
}
|
|
77
|
+
return { effort: options.slice() };
|
|
78
|
+
}
|
|
79
|
+
function fail(route, key, what) {
|
|
80
|
+
throw new Error(`dsh-auth: snapshot ${route}/${key} has no ${what}`);
|
|
81
|
+
}
|
|
82
|
+
function parseRoute(route, value) {
|
|
83
|
+
const row = record(value, route);
|
|
84
|
+
const roster = boundedStringList(row.roster, `${route} roster`, 500);
|
|
85
|
+
if (roster.some(id => id.length === 0))
|
|
86
|
+
throw new Error(`dsh-auth: snapshot ${route} roster has an empty id`);
|
|
87
|
+
const entriesRaw = record(row.entries ?? {}, `${route} entries`);
|
|
88
|
+
const entries = {};
|
|
89
|
+
for (const key of Object.keys(entriesRaw))
|
|
90
|
+
entries[key] = parseEntry(route, key, entriesRaw[key]);
|
|
91
|
+
const fallback = boundedStringList(row.fallback ?? [], `${route} fallback`, 500);
|
|
92
|
+
return { roster, entries, fallback };
|
|
93
|
+
}
|
|
94
|
+
/** Validate the checked-in snapshot once; a malformed file is a boot error. */
|
|
95
|
+
function parseSnapshotData(input) {
|
|
96
|
+
const root = record(input, 'root');
|
|
97
|
+
if (root.version !== 1)
|
|
98
|
+
throw new Error('dsh-auth: snapshot has an unsupported version');
|
|
99
|
+
if (nonEmptyString(root.generatedAt) === undefined)
|
|
100
|
+
throw new Error('dsh-auth: snapshot has no timestamp');
|
|
101
|
+
return {
|
|
102
|
+
version: 1,
|
|
103
|
+
generatedAt: root.generatedAt,
|
|
104
|
+
piAiVersion: nonEmptyString(root.piAiVersion) ?? 'unknown',
|
|
105
|
+
classifiers: boundedStringList(root.classifiers ?? [], 'classifiers', 500),
|
|
106
|
+
opencode: parseRoute('opencode', root.opencode),
|
|
107
|
+
'opencode-go': parseRoute('opencode-go', root['opencode-go']),
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
const SNAPSHOT = parseSnapshotData(OPENCODE_SNAPSHOT);
|
|
111
|
+
/** Length of the id prefix two models share (`a-b` vs `a-c` share 2). */
|
|
112
|
+
function sharedPrefixLength(a, b) {
|
|
113
|
+
const end = Math.min(a.length, b.length);
|
|
114
|
+
let length = 0;
|
|
115
|
+
while (length < end && a[length] === b[length])
|
|
116
|
+
length += 1;
|
|
117
|
+
return length;
|
|
118
|
+
}
|
|
119
|
+
/** Wire protocols, most universal first, for deterministic sibling choice. */
|
|
120
|
+
function apiRank(api) {
|
|
121
|
+
if (api === 'openai-completions')
|
|
122
|
+
return 0;
|
|
123
|
+
if (api === 'openai-responses')
|
|
124
|
+
return 1;
|
|
125
|
+
if (api === 'anthropic-messages')
|
|
126
|
+
return 2;
|
|
127
|
+
if (api === 'google-generative-ai')
|
|
128
|
+
return 3;
|
|
129
|
+
return 4;
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* Nearest same-route catalog sibling: longest shared id prefix wins, then
|
|
133
|
+
* the most universal wire protocol, then alphabetical order. Documented
|
|
134
|
+
* approximation, fully deterministic — the same snapshot and catalog always
|
|
135
|
+
* resolve the same wire envelope.
|
|
136
|
+
*/
|
|
137
|
+
function nearestSibling(catalog, id) {
|
|
138
|
+
let best = catalog[0];
|
|
139
|
+
if (best === undefined)
|
|
140
|
+
throw new Error('dsh-auth: installed catalog is empty');
|
|
141
|
+
for (const candidate of catalog) {
|
|
142
|
+
const prefix = sharedPrefixLength(candidate.id, id);
|
|
143
|
+
const bestPrefix = sharedPrefixLength(best.id, id);
|
|
144
|
+
if (prefix > bestPrefix
|
|
145
|
+
|| (prefix === bestPrefix && apiRank(candidate.api) < apiRank(best.api))
|
|
146
|
+
|| (prefix === bestPrefix && apiRank(candidate.api) === apiRank(best.api) && candidate.id < best.id)) {
|
|
147
|
+
best = candidate;
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
return best;
|
|
151
|
+
}
|
|
152
|
+
/** pi-ai thinking levels; `off` is always unsupported, the rest map to themselves. */
|
|
153
|
+
const THINKING_LEVELS = ['minimal', 'low', 'medium', 'high', 'xhigh', 'max'];
|
|
154
|
+
function thinkingLevels(effort, sibling) {
|
|
155
|
+
const siblingMap = (sibling.thinkingLevelMap ?? {});
|
|
156
|
+
const levels = new Set(effort);
|
|
157
|
+
// Only narrow the sibling envelope when every effort value it names fits
|
|
158
|
+
// inside it; otherwise the sibling map stands (documented approximation).
|
|
159
|
+
if (![...levels].every(level => Object.hasOwn(siblingMap, level)))
|
|
160
|
+
return sibling.thinkingLevelMap;
|
|
161
|
+
const map = { off: null };
|
|
162
|
+
for (const level of THINKING_LEVELS) {
|
|
163
|
+
if (!Object.hasOwn(siblingMap, level))
|
|
164
|
+
continue;
|
|
165
|
+
map[level] = levels.has(level) ? level : null;
|
|
166
|
+
}
|
|
167
|
+
return map;
|
|
168
|
+
}
|
|
169
|
+
/**
|
|
170
|
+
* Resolve one snapshot roster id to a pi-shaped model: wire envelope from
|
|
171
|
+
* the sibling, display metadata and capacity from models.dev. pi-ai drops
|
|
172
|
+
* video/pdf/audio modalities (text/image only) and never discloses
|
|
173
|
+
* cache-write pricing, so both are inherited or omitted — see field notes.
|
|
174
|
+
*/
|
|
175
|
+
function synthesize(catalog, route, id, entry) {
|
|
176
|
+
const sibling = nearestSibling(catalog, id);
|
|
177
|
+
// Same-route sibling, so its provider id is already the route's own.
|
|
178
|
+
if (entry === undefined)
|
|
179
|
+
return { ...sibling, id, name: id };
|
|
180
|
+
const modalities = new Set(entry.modalities.input);
|
|
181
|
+
if (!modalities.has('text')) {
|
|
182
|
+
throw new Error(`dsh-auth: snapshot ${route}/${id} has no text modality`);
|
|
183
|
+
}
|
|
184
|
+
const compat = entry.temperature === false
|
|
185
|
+
? { ...sibling.compat, supportsTemperature: false }
|
|
186
|
+
: sibling.compat;
|
|
187
|
+
const input = modalities.has('image') ? ['text', 'image'] : ['text'];
|
|
188
|
+
return {
|
|
189
|
+
...sibling,
|
|
190
|
+
id,
|
|
191
|
+
name: entry.name,
|
|
192
|
+
reasoning: entry.reasoning ?? sibling.reasoning,
|
|
193
|
+
input: [...input],
|
|
194
|
+
cost: {
|
|
195
|
+
input: entry.cost.input,
|
|
196
|
+
output: entry.cost.output,
|
|
197
|
+
cacheRead: entry.cost.cache_read ?? sibling.cost.cacheRead ?? 0,
|
|
198
|
+
cacheWrite: sibling.cost.cacheWrite ?? 0,
|
|
199
|
+
},
|
|
200
|
+
contextWindow: entry.limit.context,
|
|
201
|
+
maxTokens: entry.limit.output ?? sibling.maxTokens,
|
|
202
|
+
compat,
|
|
203
|
+
thinkingLevelMap: entry.reasoning === false
|
|
204
|
+
? undefined
|
|
205
|
+
: entry.reasoning_options === undefined
|
|
206
|
+
? sibling.thinkingLevelMap
|
|
207
|
+
: thinkingLevels(entry.reasoning_options.effort, sibling),
|
|
208
|
+
type: 'chat',
|
|
209
|
+
};
|
|
210
|
+
}
|
|
211
|
+
/**
|
|
212
|
+
* Union the snapshot roster onto one catalog provider. Installed models win
|
|
213
|
+
* on conflict and classifier-roster ids stay on pi-ai's classifier path, so
|
|
214
|
+
* the merged list always covers the installed catalog — a stale snapshot
|
|
215
|
+
* delays additions but never removes a working model.
|
|
216
|
+
* @param catalog - the installed pi-ai catalog provider for one route.
|
|
217
|
+
* @param route - the route the snapshot section is keyed under.
|
|
218
|
+
* @returns the catalog provider, or a shallow clone serving the union.
|
|
219
|
+
*/
|
|
220
|
+
export function withFreshModels(catalog, route) {
|
|
221
|
+
const section = SNAPSHOT[route];
|
|
222
|
+
const installed = new Map(catalog.getModels().map(model => [model.id, model]));
|
|
223
|
+
const classifiers = new Set(SNAPSHOT.classifiers);
|
|
224
|
+
const catalogModels = catalog.getModels();
|
|
225
|
+
const extras = [];
|
|
226
|
+
for (const id of section.roster) {
|
|
227
|
+
if (installed.has(id) || classifiers.has(id))
|
|
228
|
+
continue;
|
|
229
|
+
const marker = section.fallback.includes(id);
|
|
230
|
+
const key = marker ? undefined : section.entries[id];
|
|
231
|
+
if (!marker && key === undefined) {
|
|
232
|
+
throw new Error(`dsh-auth: snapshot ${route}/${id} is on the roster but has neither metadata nor a fallback marker`);
|
|
233
|
+
}
|
|
234
|
+
extras.push(synthesize(catalogModels, route, id, key));
|
|
235
|
+
}
|
|
236
|
+
if (extras.length === 0)
|
|
237
|
+
return catalog;
|
|
238
|
+
return {
|
|
239
|
+
...catalog,
|
|
240
|
+
getModels: () => [...catalog.getModels(), ...extras],
|
|
241
|
+
};
|
|
242
|
+
}
|
|
243
|
+
/** Snapshot roster ids for one route, for smoke coverage. */
|
|
244
|
+
export function freshRosterIds(route) {
|
|
245
|
+
return SNAPSHOT[route].roster.slice();
|
|
246
|
+
}
|
|
@@ -73,6 +73,7 @@ export type { AskFn, QuestionBridgeHelpers } from './interaction.js';
|
|
|
73
73
|
export { copyToClipboard, openInBrowser, openerFor } from './opener.js';
|
|
74
74
|
export { CredentialFile, defaultCredentialsFile } from './credentials.js';
|
|
75
75
|
export { OAUTH_PROVIDER_IDS, CATALOG_PROVIDER_IDS, AUTH_PROVIDER_IDS, canonicalProvider, buildOAuthProfile, type ModelOverride } from './profiles.js';
|
|
76
|
+
export { freshRosterIds, type FreshRouteId } from './fresh-models.js';
|
|
76
77
|
/**
|
|
77
78
|
* The adapter the plugin registers: a {@link PiAiAdapter} whose *advisory
|
|
78
79
|
* catalog* is credential-gated. A provider with no stored credential
|
|
@@ -68,6 +68,7 @@ export { QuestionBridge, describeEvent } from './interaction.js';
|
|
|
68
68
|
export { copyToClipboard, openInBrowser, openerFor } from './opener.js';
|
|
69
69
|
export { CredentialFile, defaultCredentialsFile } from './credentials.js';
|
|
70
70
|
export { OAUTH_PROVIDER_IDS, CATALOG_PROVIDER_IDS, AUTH_PROVIDER_IDS, canonicalProvider, buildOAuthProfile } from './profiles.js';
|
|
71
|
+
export { freshRosterIds } from './fresh-models.js';
|
|
71
72
|
/**
|
|
72
73
|
* The ambient auth context providers may consult while resolving their own
|
|
73
74
|
* auth. `env()` answers from the process environment; `fileExists()` answers
|
|
@@ -0,0 +1,321 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Generated by scripts/sync-opencode-models.mjs — do not edit by hand.
|
|
3
|
+
* Refresh: `pnpm --dir dsh-auth sync:models`.
|
|
4
|
+
*
|
|
5
|
+
* generatedAt: 2026-09-30T15:19:42.378Z
|
|
6
|
+
* pi-ai: 0.99.1
|
|
7
|
+
* live roster: zen=82 go=43
|
|
8
|
+
* beyond installed catalog: zen=+5 go=+14
|
|
9
|
+
*
|
|
10
|
+
* Shape contract (see src/fresh-models.ts parseSnapshotData):
|
|
11
|
+
* version=1, per route { roster (live chat ids, sorted), entries
|
|
12
|
+
* (allowlisted models.dev metadata for roster ids the installed catalog
|
|
13
|
+
* lacks), fallback (roster ids neither source describes — runtime clones
|
|
14
|
+
* the nearest catalog sibling and flags nothing on the model object;
|
|
15
|
+
* provenance lives here) }, classifiers (live ids pi-ai serves on its
|
|
16
|
+
* classifier path, excluded from the chat merge).
|
|
17
|
+
*/
|
|
18
|
+
export declare const OPENCODE_SNAPSHOT: {
|
|
19
|
+
readonly version: 1;
|
|
20
|
+
readonly generatedAt: "2026-09-30T15:19:42.378Z";
|
|
21
|
+
readonly piAiVersion: "0.99.1";
|
|
22
|
+
readonly sources: {
|
|
23
|
+
readonly modelsDev: "https://models.dev/api.json";
|
|
24
|
+
readonly zen: "https://opencode.ai/zen/v1/models";
|
|
25
|
+
readonly go: "https://opencode.ai/zen/go/v1/models";
|
|
26
|
+
};
|
|
27
|
+
readonly classifiers: readonly ["jev-1.13", "jev-1.13-free"];
|
|
28
|
+
readonly opencode: {
|
|
29
|
+
readonly roster: readonly ["big-pickle", "claude-fable-5", "claude-fable-5-1", "claude-haiku-4-5", "claude-opus-4-5", "claude-opus-4-6", "claude-opus-4-7", "claude-opus-4-8", "claude-opus-5", "claude-opus-5-5", "claude-sonnet-4", "claude-sonnet-4-5", "claude-sonnet-4-6", "claude-sonnet-5", "claude-sonnet-5-5", "deepseek-v4-flash", "deepseek-v4-flash-free", "deepseek-v4-flash-vision-exp", "deepseek-v4-pro", "deepseek-v4.1-flash", "gemini-3-flash", "gemini-3.1-pro", "gemini-3.5-flash", "gemini-3.5-flash-lite", "gemini-3.6-flash", "gemini-3.7-flash", "gemini-3.8-flash", "glm-5", "glm-5.1", "glm-5.2", "glm-5.3", "glm-5.3-flash", "gpt-5", "gpt-5-codex", "gpt-5-nano", "gpt-5.1", "gpt-5.1-codex", "gpt-5.1-codex-max", "gpt-5.1-codex-mini", "gpt-5.2", "gpt-5.2-codex", "gpt-5.3-codex", "gpt-5.3-codex-spark", "gpt-5.4", "gpt-5.4-mini", "gpt-5.4-nano", "gpt-5.4-pro", "gpt-5.5", "gpt-5.5-pro", "gpt-5.6-luna", "gpt-5.6-sol", "gpt-5.6-terra", "gpt-6-astra", "gpt-6-luna", "gpt-6-sol", "gpt-6.1-sol", "grok-4.5", "grok-4.6", "grok-4.7", "grok-build-0.1", "kimi-k2.5", "kimi-k2.6", "kimi-k2.7-code", "kimi-k3", "ling-3.0-flash-fin-free", "longcat-2.5-preview-free", "mimo-v2.5-free", "mimo-v2.6-flash-free", "minimax-m2.5", "minimax-m2.7", "minimax-m3", "muse-spark-1.2", "muse-spark-1.2-contributor-free", "muse-spark-1.3", "muse-spark-1.3-contributor-free", "nemotron-3-ultra-free", "nemotron-3.5-lightning-free", "qwen3.5-plus", "qwen3.6-plus", "qwen3.8-flash", "qwen3.8-max", "space-bunny-free"];
|
|
30
|
+
readonly entries: {
|
|
31
|
+
readonly "deepseek-v4-flash-free": {
|
|
32
|
+
readonly id: "deepseek-v4-flash-free";
|
|
33
|
+
readonly name: "DeepSeek V4 Flash Free";
|
|
34
|
+
readonly reasoning: true;
|
|
35
|
+
readonly attachment: false;
|
|
36
|
+
readonly modalities: {
|
|
37
|
+
readonly input: readonly ["text"];
|
|
38
|
+
};
|
|
39
|
+
readonly limit: {
|
|
40
|
+
readonly context: 200000;
|
|
41
|
+
readonly output: 128000;
|
|
42
|
+
};
|
|
43
|
+
readonly cost: {
|
|
44
|
+
readonly input: 0;
|
|
45
|
+
readonly output: 0;
|
|
46
|
+
readonly cache_read: 0;
|
|
47
|
+
};
|
|
48
|
+
readonly temperature: true;
|
|
49
|
+
readonly reasoning_options: {
|
|
50
|
+
readonly effort: readonly ["low", "high", "max"];
|
|
51
|
+
};
|
|
52
|
+
};
|
|
53
|
+
readonly "gpt-5.3-codex-spark": {
|
|
54
|
+
readonly id: "gpt-5.3-codex-spark";
|
|
55
|
+
readonly name: "GPT-5.3 Codex Spark";
|
|
56
|
+
readonly reasoning: true;
|
|
57
|
+
readonly attachment: false;
|
|
58
|
+
readonly modalities: {
|
|
59
|
+
readonly input: readonly ["text"];
|
|
60
|
+
};
|
|
61
|
+
readonly limit: {
|
|
62
|
+
readonly context: 128000;
|
|
63
|
+
readonly output: 128000;
|
|
64
|
+
};
|
|
65
|
+
readonly cost: {
|
|
66
|
+
readonly input: 1.75;
|
|
67
|
+
readonly output: 14;
|
|
68
|
+
readonly cache_read: 0.175;
|
|
69
|
+
};
|
|
70
|
+
readonly temperature: false;
|
|
71
|
+
readonly reasoning_options: {
|
|
72
|
+
readonly effort: readonly ["low", "medium", "high", "xhigh"];
|
|
73
|
+
};
|
|
74
|
+
};
|
|
75
|
+
readonly "gpt-6.1-sol": {
|
|
76
|
+
readonly id: "gpt-6.1-sol";
|
|
77
|
+
readonly name: "GPT-6.1 Sol";
|
|
78
|
+
readonly reasoning: true;
|
|
79
|
+
readonly attachment: true;
|
|
80
|
+
readonly modalities: {
|
|
81
|
+
readonly input: readonly ["text", "image", "pdf"];
|
|
82
|
+
};
|
|
83
|
+
readonly limit: {
|
|
84
|
+
readonly context: 1050000;
|
|
85
|
+
readonly output: 128000;
|
|
86
|
+
};
|
|
87
|
+
readonly cost: {
|
|
88
|
+
readonly input: 2;
|
|
89
|
+
readonly output: 10;
|
|
90
|
+
readonly cache_read: 0.1;
|
|
91
|
+
};
|
|
92
|
+
readonly temperature: false;
|
|
93
|
+
readonly reasoning_options: {
|
|
94
|
+
readonly effort: readonly ["low", "medium", "high", "xhigh", "max"];
|
|
95
|
+
};
|
|
96
|
+
};
|
|
97
|
+
readonly "mimo-v2.5-free": {
|
|
98
|
+
readonly id: "mimo-v2.5-free";
|
|
99
|
+
readonly name: "MiMo V2.5 Free";
|
|
100
|
+
readonly reasoning: true;
|
|
101
|
+
readonly attachment: true;
|
|
102
|
+
readonly modalities: {
|
|
103
|
+
readonly input: readonly ["text", "image", "audio", "video"];
|
|
104
|
+
};
|
|
105
|
+
readonly limit: {
|
|
106
|
+
readonly context: 200000;
|
|
107
|
+
readonly output: 32000;
|
|
108
|
+
};
|
|
109
|
+
readonly cost: {
|
|
110
|
+
readonly input: 0;
|
|
111
|
+
readonly output: 0;
|
|
112
|
+
readonly cache_read: 0;
|
|
113
|
+
};
|
|
114
|
+
readonly temperature: true;
|
|
115
|
+
};
|
|
116
|
+
readonly "muse-spark-1.2-contributor-free": {
|
|
117
|
+
readonly id: "muse-spark-1.2-contributor-free";
|
|
118
|
+
readonly name: "Muse Spark 1.2 Free";
|
|
119
|
+
readonly reasoning: true;
|
|
120
|
+
readonly attachment: true;
|
|
121
|
+
readonly modalities: {
|
|
122
|
+
readonly input: readonly ["text", "image", "video", "pdf", "audio"];
|
|
123
|
+
};
|
|
124
|
+
readonly limit: {
|
|
125
|
+
readonly context: 1048576;
|
|
126
|
+
readonly output: 131072;
|
|
127
|
+
};
|
|
128
|
+
readonly cost: {
|
|
129
|
+
readonly input: 0;
|
|
130
|
+
readonly output: 0;
|
|
131
|
+
readonly cache_read: 0;
|
|
132
|
+
};
|
|
133
|
+
readonly temperature: true;
|
|
134
|
+
readonly reasoning_options: {
|
|
135
|
+
readonly effort: readonly ["minimal", "low", "medium", "high", "xhigh"];
|
|
136
|
+
};
|
|
137
|
+
};
|
|
138
|
+
};
|
|
139
|
+
readonly fallback: readonly [];
|
|
140
|
+
};
|
|
141
|
+
readonly "opencode-go": {
|
|
142
|
+
readonly roster: readonly ["deepseek-flash", "deepseek-v4-flash", "deepseek-v4-flash-vision-exp", "deepseek-v4-pro", "deepseek-v4.1-flash", "glm-5", "glm-5.1", "glm-5.2", "glm-5.3", "glm-5.3-flash", "gpt-5.6-luna", "gpt-6-luna", "grok-4.5", "grok-4.6", "grok-4.7", "hy3", "hy3-preview", "hy4-preview", "kimi-k2.5", "kimi-k2.6", "kimi-k2.7-code", "kimi-k3", "longcat-2.0", "longcat-2.5-preview-free", "mimo-v2-omni", "mimo-v2-pro", "mimo-v2.5", "mimo-v2.5-pro", "mimo-v2.6-flash", "mimo-v2.6-pro", "minimax-m2.5", "minimax-m2.7", "minimax-m3", "muse-spark-1.2-contributor", "muse-spark-1.3-contributor", "omen-alpha", "qwen3.5-plus", "qwen3.6-plus", "qwen3.7-max", "qwen3.7-plus", "qwen3.8-flash", "qwen3.8-max", "space-bunny-free"];
|
|
143
|
+
readonly entries: {
|
|
144
|
+
readonly "glm-5": {
|
|
145
|
+
readonly id: "glm-5";
|
|
146
|
+
readonly name: "GLM-5";
|
|
147
|
+
readonly reasoning: true;
|
|
148
|
+
readonly attachment: false;
|
|
149
|
+
readonly modalities: {
|
|
150
|
+
readonly input: readonly ["text"];
|
|
151
|
+
};
|
|
152
|
+
readonly limit: {
|
|
153
|
+
readonly context: 204800;
|
|
154
|
+
readonly output: 131072;
|
|
155
|
+
};
|
|
156
|
+
readonly cost: {
|
|
157
|
+
readonly input: 1;
|
|
158
|
+
readonly output: 3.2;
|
|
159
|
+
readonly cache_read: 0.2;
|
|
160
|
+
};
|
|
161
|
+
readonly temperature: true;
|
|
162
|
+
};
|
|
163
|
+
readonly "glm-5.1": {
|
|
164
|
+
readonly id: "glm-5.1";
|
|
165
|
+
readonly name: "GLM-5.1";
|
|
166
|
+
readonly reasoning: true;
|
|
167
|
+
readonly attachment: false;
|
|
168
|
+
readonly modalities: {
|
|
169
|
+
readonly input: readonly ["text"];
|
|
170
|
+
};
|
|
171
|
+
readonly limit: {
|
|
172
|
+
readonly context: 204800;
|
|
173
|
+
readonly output: 131072;
|
|
174
|
+
};
|
|
175
|
+
readonly cost: {
|
|
176
|
+
readonly input: 1.4;
|
|
177
|
+
readonly output: 4.4;
|
|
178
|
+
readonly cache_read: 0.26;
|
|
179
|
+
};
|
|
180
|
+
readonly temperature: true;
|
|
181
|
+
};
|
|
182
|
+
readonly "grok-4.5": {
|
|
183
|
+
readonly id: "grok-4.5";
|
|
184
|
+
readonly name: "Grok 4.5";
|
|
185
|
+
readonly reasoning: true;
|
|
186
|
+
readonly attachment: true;
|
|
187
|
+
readonly modalities: {
|
|
188
|
+
readonly input: readonly ["text", "image"];
|
|
189
|
+
};
|
|
190
|
+
readonly limit: {
|
|
191
|
+
readonly context: 500000;
|
|
192
|
+
readonly output: 500000;
|
|
193
|
+
};
|
|
194
|
+
readonly cost: {
|
|
195
|
+
readonly input: 2;
|
|
196
|
+
readonly output: 6;
|
|
197
|
+
readonly cache_read: 0.3;
|
|
198
|
+
};
|
|
199
|
+
readonly temperature: true;
|
|
200
|
+
readonly reasoning_options: {
|
|
201
|
+
readonly effort: readonly ["low", "medium", "high"];
|
|
202
|
+
};
|
|
203
|
+
};
|
|
204
|
+
readonly "kimi-k2.5": {
|
|
205
|
+
readonly id: "kimi-k2.5";
|
|
206
|
+
readonly name: "Kimi K2.5";
|
|
207
|
+
readonly reasoning: true;
|
|
208
|
+
readonly attachment: true;
|
|
209
|
+
readonly modalities: {
|
|
210
|
+
readonly input: readonly ["text", "image", "video"];
|
|
211
|
+
};
|
|
212
|
+
readonly limit: {
|
|
213
|
+
readonly context: 262144;
|
|
214
|
+
readonly output: 65536;
|
|
215
|
+
};
|
|
216
|
+
readonly cost: {
|
|
217
|
+
readonly input: 0.6;
|
|
218
|
+
readonly output: 3;
|
|
219
|
+
readonly cache_read: 0.08;
|
|
220
|
+
};
|
|
221
|
+
readonly temperature: true;
|
|
222
|
+
};
|
|
223
|
+
readonly "kimi-k2.6": {
|
|
224
|
+
readonly id: "kimi-k2.6";
|
|
225
|
+
readonly name: "Kimi K2.6";
|
|
226
|
+
readonly reasoning: true;
|
|
227
|
+
readonly attachment: true;
|
|
228
|
+
readonly modalities: {
|
|
229
|
+
readonly input: readonly ["text", "image", "video"];
|
|
230
|
+
};
|
|
231
|
+
readonly limit: {
|
|
232
|
+
readonly context: 262144;
|
|
233
|
+
readonly output: 65536;
|
|
234
|
+
};
|
|
235
|
+
readonly cost: {
|
|
236
|
+
readonly input: 0.95;
|
|
237
|
+
readonly output: 4;
|
|
238
|
+
readonly cache_read: 0.16;
|
|
239
|
+
};
|
|
240
|
+
readonly temperature: true;
|
|
241
|
+
};
|
|
242
|
+
readonly "minimax-m2.5": {
|
|
243
|
+
readonly id: "minimax-m2.5";
|
|
244
|
+
readonly name: "MiniMax-M2.5";
|
|
245
|
+
readonly reasoning: true;
|
|
246
|
+
readonly attachment: false;
|
|
247
|
+
readonly modalities: {
|
|
248
|
+
readonly input: readonly ["text"];
|
|
249
|
+
};
|
|
250
|
+
readonly limit: {
|
|
251
|
+
readonly context: 204800;
|
|
252
|
+
readonly output: 131072;
|
|
253
|
+
};
|
|
254
|
+
readonly cost: {
|
|
255
|
+
readonly input: 0.3;
|
|
256
|
+
readonly output: 1.2;
|
|
257
|
+
readonly cache_read: 0.06;
|
|
258
|
+
};
|
|
259
|
+
readonly temperature: true;
|
|
260
|
+
};
|
|
261
|
+
readonly "qwen3.5-plus": {
|
|
262
|
+
readonly id: "qwen3.5-plus";
|
|
263
|
+
readonly name: "Qwen3.5 Plus";
|
|
264
|
+
readonly reasoning: true;
|
|
265
|
+
readonly attachment: true;
|
|
266
|
+
readonly modalities: {
|
|
267
|
+
readonly input: readonly ["text", "image", "video"];
|
|
268
|
+
};
|
|
269
|
+
readonly limit: {
|
|
270
|
+
readonly context: 262144;
|
|
271
|
+
readonly output: 65536;
|
|
272
|
+
};
|
|
273
|
+
readonly cost: {
|
|
274
|
+
readonly input: 0.2;
|
|
275
|
+
readonly output: 1.2;
|
|
276
|
+
readonly cache_read: 0.02;
|
|
277
|
+
};
|
|
278
|
+
readonly temperature: true;
|
|
279
|
+
};
|
|
280
|
+
readonly "qwen3.6-plus": {
|
|
281
|
+
readonly id: "qwen3.6-plus";
|
|
282
|
+
readonly name: "Qwen3.6 Plus";
|
|
283
|
+
readonly reasoning: true;
|
|
284
|
+
readonly attachment: true;
|
|
285
|
+
readonly modalities: {
|
|
286
|
+
readonly input: readonly ["text", "image", "video"];
|
|
287
|
+
};
|
|
288
|
+
readonly limit: {
|
|
289
|
+
readonly context: 1000000;
|
|
290
|
+
readonly output: 65536;
|
|
291
|
+
};
|
|
292
|
+
readonly cost: {
|
|
293
|
+
readonly input: 0.5;
|
|
294
|
+
readonly output: 3;
|
|
295
|
+
readonly cache_read: 0.05;
|
|
296
|
+
};
|
|
297
|
+
readonly temperature: true;
|
|
298
|
+
};
|
|
299
|
+
readonly "qwen3.7-max": {
|
|
300
|
+
readonly id: "qwen3.7-max";
|
|
301
|
+
readonly name: "Qwen3.7 Max";
|
|
302
|
+
readonly reasoning: true;
|
|
303
|
+
readonly attachment: false;
|
|
304
|
+
readonly modalities: {
|
|
305
|
+
readonly input: readonly ["text"];
|
|
306
|
+
};
|
|
307
|
+
readonly limit: {
|
|
308
|
+
readonly context: 1000000;
|
|
309
|
+
readonly output: 65536;
|
|
310
|
+
};
|
|
311
|
+
readonly cost: {
|
|
312
|
+
readonly input: 2.5;
|
|
313
|
+
readonly output: 7.5;
|
|
314
|
+
readonly cache_read: 0.5;
|
|
315
|
+
};
|
|
316
|
+
readonly temperature: true;
|
|
317
|
+
};
|
|
318
|
+
};
|
|
319
|
+
readonly fallback: readonly ["deepseek-flash", "hy3-preview", "mimo-v2-omni", "mimo-v2-pro", "omen-alpha"];
|
|
320
|
+
};
|
|
321
|
+
};
|
|
@@ -0,0 +1,528 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Generated by scripts/sync-opencode-models.mjs — do not edit by hand.
|
|
3
|
+
* Refresh: `pnpm --dir dsh-auth sync:models`.
|
|
4
|
+
*
|
|
5
|
+
* generatedAt: 2026-09-30T15:19:42.378Z
|
|
6
|
+
* pi-ai: 0.99.1
|
|
7
|
+
* live roster: zen=82 go=43
|
|
8
|
+
* beyond installed catalog: zen=+5 go=+14
|
|
9
|
+
*
|
|
10
|
+
* Shape contract (see src/fresh-models.ts parseSnapshotData):
|
|
11
|
+
* version=1, per route { roster (live chat ids, sorted), entries
|
|
12
|
+
* (allowlisted models.dev metadata for roster ids the installed catalog
|
|
13
|
+
* lacks), fallback (roster ids neither source describes — runtime clones
|
|
14
|
+
* the nearest catalog sibling and flags nothing on the model object;
|
|
15
|
+
* provenance lives here) }, classifiers (live ids pi-ai serves on its
|
|
16
|
+
* classifier path, excluded from the chat merge).
|
|
17
|
+
*/
|
|
18
|
+
export const OPENCODE_SNAPSHOT = {
|
|
19
|
+
"version": 1,
|
|
20
|
+
"generatedAt": "2026-09-30T15:19:42.378Z",
|
|
21
|
+
"piAiVersion": "0.99.1",
|
|
22
|
+
"sources": {
|
|
23
|
+
"modelsDev": "https://models.dev/api.json",
|
|
24
|
+
"zen": "https://opencode.ai/zen/v1/models",
|
|
25
|
+
"go": "https://opencode.ai/zen/go/v1/models"
|
|
26
|
+
},
|
|
27
|
+
"classifiers": [
|
|
28
|
+
"jev-1.13",
|
|
29
|
+
"jev-1.13-free"
|
|
30
|
+
],
|
|
31
|
+
"opencode": {
|
|
32
|
+
"roster": [
|
|
33
|
+
"big-pickle",
|
|
34
|
+
"claude-fable-5",
|
|
35
|
+
"claude-fable-5-1",
|
|
36
|
+
"claude-haiku-4-5",
|
|
37
|
+
"claude-opus-4-5",
|
|
38
|
+
"claude-opus-4-6",
|
|
39
|
+
"claude-opus-4-7",
|
|
40
|
+
"claude-opus-4-8",
|
|
41
|
+
"claude-opus-5",
|
|
42
|
+
"claude-opus-5-5",
|
|
43
|
+
"claude-sonnet-4",
|
|
44
|
+
"claude-sonnet-4-5",
|
|
45
|
+
"claude-sonnet-4-6",
|
|
46
|
+
"claude-sonnet-5",
|
|
47
|
+
"claude-sonnet-5-5",
|
|
48
|
+
"deepseek-v4-flash",
|
|
49
|
+
"deepseek-v4-flash-free",
|
|
50
|
+
"deepseek-v4-flash-vision-exp",
|
|
51
|
+
"deepseek-v4-pro",
|
|
52
|
+
"deepseek-v4.1-flash",
|
|
53
|
+
"gemini-3-flash",
|
|
54
|
+
"gemini-3.1-pro",
|
|
55
|
+
"gemini-3.5-flash",
|
|
56
|
+
"gemini-3.5-flash-lite",
|
|
57
|
+
"gemini-3.6-flash",
|
|
58
|
+
"gemini-3.7-flash",
|
|
59
|
+
"gemini-3.8-flash",
|
|
60
|
+
"glm-5",
|
|
61
|
+
"glm-5.1",
|
|
62
|
+
"glm-5.2",
|
|
63
|
+
"glm-5.3",
|
|
64
|
+
"glm-5.3-flash",
|
|
65
|
+
"gpt-5",
|
|
66
|
+
"gpt-5-codex",
|
|
67
|
+
"gpt-5-nano",
|
|
68
|
+
"gpt-5.1",
|
|
69
|
+
"gpt-5.1-codex",
|
|
70
|
+
"gpt-5.1-codex-max",
|
|
71
|
+
"gpt-5.1-codex-mini",
|
|
72
|
+
"gpt-5.2",
|
|
73
|
+
"gpt-5.2-codex",
|
|
74
|
+
"gpt-5.3-codex",
|
|
75
|
+
"gpt-5.3-codex-spark",
|
|
76
|
+
"gpt-5.4",
|
|
77
|
+
"gpt-5.4-mini",
|
|
78
|
+
"gpt-5.4-nano",
|
|
79
|
+
"gpt-5.4-pro",
|
|
80
|
+
"gpt-5.5",
|
|
81
|
+
"gpt-5.5-pro",
|
|
82
|
+
"gpt-5.6-luna",
|
|
83
|
+
"gpt-5.6-sol",
|
|
84
|
+
"gpt-5.6-terra",
|
|
85
|
+
"gpt-6-astra",
|
|
86
|
+
"gpt-6-luna",
|
|
87
|
+
"gpt-6-sol",
|
|
88
|
+
"gpt-6.1-sol",
|
|
89
|
+
"grok-4.5",
|
|
90
|
+
"grok-4.6",
|
|
91
|
+
"grok-4.7",
|
|
92
|
+
"grok-build-0.1",
|
|
93
|
+
"kimi-k2.5",
|
|
94
|
+
"kimi-k2.6",
|
|
95
|
+
"kimi-k2.7-code",
|
|
96
|
+
"kimi-k3",
|
|
97
|
+
"ling-3.0-flash-fin-free",
|
|
98
|
+
"longcat-2.5-preview-free",
|
|
99
|
+
"mimo-v2.5-free",
|
|
100
|
+
"mimo-v2.6-flash-free",
|
|
101
|
+
"minimax-m2.5",
|
|
102
|
+
"minimax-m2.7",
|
|
103
|
+
"minimax-m3",
|
|
104
|
+
"muse-spark-1.2",
|
|
105
|
+
"muse-spark-1.2-contributor-free",
|
|
106
|
+
"muse-spark-1.3",
|
|
107
|
+
"muse-spark-1.3-contributor-free",
|
|
108
|
+
"nemotron-3-ultra-free",
|
|
109
|
+
"nemotron-3.5-lightning-free",
|
|
110
|
+
"qwen3.5-plus",
|
|
111
|
+
"qwen3.6-plus",
|
|
112
|
+
"qwen3.8-flash",
|
|
113
|
+
"qwen3.8-max",
|
|
114
|
+
"space-bunny-free"
|
|
115
|
+
],
|
|
116
|
+
"entries": {
|
|
117
|
+
"deepseek-v4-flash-free": {
|
|
118
|
+
"id": "deepseek-v4-flash-free",
|
|
119
|
+
"name": "DeepSeek V4 Flash Free",
|
|
120
|
+
"reasoning": true,
|
|
121
|
+
"attachment": false,
|
|
122
|
+
"modalities": {
|
|
123
|
+
"input": [
|
|
124
|
+
"text"
|
|
125
|
+
]
|
|
126
|
+
},
|
|
127
|
+
"limit": {
|
|
128
|
+
"context": 200000,
|
|
129
|
+
"output": 128000
|
|
130
|
+
},
|
|
131
|
+
"cost": {
|
|
132
|
+
"input": 0,
|
|
133
|
+
"output": 0,
|
|
134
|
+
"cache_read": 0
|
|
135
|
+
},
|
|
136
|
+
"temperature": true,
|
|
137
|
+
"reasoning_options": {
|
|
138
|
+
"effort": [
|
|
139
|
+
"low",
|
|
140
|
+
"high",
|
|
141
|
+
"max"
|
|
142
|
+
]
|
|
143
|
+
}
|
|
144
|
+
},
|
|
145
|
+
"gpt-5.3-codex-spark": {
|
|
146
|
+
"id": "gpt-5.3-codex-spark",
|
|
147
|
+
"name": "GPT-5.3 Codex Spark",
|
|
148
|
+
"reasoning": true,
|
|
149
|
+
"attachment": false,
|
|
150
|
+
"modalities": {
|
|
151
|
+
"input": [
|
|
152
|
+
"text"
|
|
153
|
+
]
|
|
154
|
+
},
|
|
155
|
+
"limit": {
|
|
156
|
+
"context": 128000,
|
|
157
|
+
"output": 128000
|
|
158
|
+
},
|
|
159
|
+
"cost": {
|
|
160
|
+
"input": 1.75,
|
|
161
|
+
"output": 14,
|
|
162
|
+
"cache_read": 0.175
|
|
163
|
+
},
|
|
164
|
+
"temperature": false,
|
|
165
|
+
"reasoning_options": {
|
|
166
|
+
"effort": [
|
|
167
|
+
"low",
|
|
168
|
+
"medium",
|
|
169
|
+
"high",
|
|
170
|
+
"xhigh"
|
|
171
|
+
]
|
|
172
|
+
}
|
|
173
|
+
},
|
|
174
|
+
"gpt-6.1-sol": {
|
|
175
|
+
"id": "gpt-6.1-sol",
|
|
176
|
+
"name": "GPT-6.1 Sol",
|
|
177
|
+
"reasoning": true,
|
|
178
|
+
"attachment": true,
|
|
179
|
+
"modalities": {
|
|
180
|
+
"input": [
|
|
181
|
+
"text",
|
|
182
|
+
"image",
|
|
183
|
+
"pdf"
|
|
184
|
+
]
|
|
185
|
+
},
|
|
186
|
+
"limit": {
|
|
187
|
+
"context": 1050000,
|
|
188
|
+
"output": 128000
|
|
189
|
+
},
|
|
190
|
+
"cost": {
|
|
191
|
+
"input": 2,
|
|
192
|
+
"output": 10,
|
|
193
|
+
"cache_read": 0.1
|
|
194
|
+
},
|
|
195
|
+
"temperature": false,
|
|
196
|
+
"reasoning_options": {
|
|
197
|
+
"effort": [
|
|
198
|
+
"low",
|
|
199
|
+
"medium",
|
|
200
|
+
"high",
|
|
201
|
+
"xhigh",
|
|
202
|
+
"max"
|
|
203
|
+
]
|
|
204
|
+
}
|
|
205
|
+
},
|
|
206
|
+
"mimo-v2.5-free": {
|
|
207
|
+
"id": "mimo-v2.5-free",
|
|
208
|
+
"name": "MiMo V2.5 Free",
|
|
209
|
+
"reasoning": true,
|
|
210
|
+
"attachment": true,
|
|
211
|
+
"modalities": {
|
|
212
|
+
"input": [
|
|
213
|
+
"text",
|
|
214
|
+
"image",
|
|
215
|
+
"audio",
|
|
216
|
+
"video"
|
|
217
|
+
]
|
|
218
|
+
},
|
|
219
|
+
"limit": {
|
|
220
|
+
"context": 200000,
|
|
221
|
+
"output": 32000
|
|
222
|
+
},
|
|
223
|
+
"cost": {
|
|
224
|
+
"input": 0,
|
|
225
|
+
"output": 0,
|
|
226
|
+
"cache_read": 0
|
|
227
|
+
},
|
|
228
|
+
"temperature": true
|
|
229
|
+
},
|
|
230
|
+
"muse-spark-1.2-contributor-free": {
|
|
231
|
+
"id": "muse-spark-1.2-contributor-free",
|
|
232
|
+
"name": "Muse Spark 1.2 Free",
|
|
233
|
+
"reasoning": true,
|
|
234
|
+
"attachment": true,
|
|
235
|
+
"modalities": {
|
|
236
|
+
"input": [
|
|
237
|
+
"text",
|
|
238
|
+
"image",
|
|
239
|
+
"video",
|
|
240
|
+
"pdf",
|
|
241
|
+
"audio"
|
|
242
|
+
]
|
|
243
|
+
},
|
|
244
|
+
"limit": {
|
|
245
|
+
"context": 1048576,
|
|
246
|
+
"output": 131072
|
|
247
|
+
},
|
|
248
|
+
"cost": {
|
|
249
|
+
"input": 0,
|
|
250
|
+
"output": 0,
|
|
251
|
+
"cache_read": 0
|
|
252
|
+
},
|
|
253
|
+
"temperature": true,
|
|
254
|
+
"reasoning_options": {
|
|
255
|
+
"effort": [
|
|
256
|
+
"minimal",
|
|
257
|
+
"low",
|
|
258
|
+
"medium",
|
|
259
|
+
"high",
|
|
260
|
+
"xhigh"
|
|
261
|
+
]
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
},
|
|
265
|
+
"fallback": []
|
|
266
|
+
},
|
|
267
|
+
"opencode-go": {
|
|
268
|
+
"roster": [
|
|
269
|
+
"deepseek-flash",
|
|
270
|
+
"deepseek-v4-flash",
|
|
271
|
+
"deepseek-v4-flash-vision-exp",
|
|
272
|
+
"deepseek-v4-pro",
|
|
273
|
+
"deepseek-v4.1-flash",
|
|
274
|
+
"glm-5",
|
|
275
|
+
"glm-5.1",
|
|
276
|
+
"glm-5.2",
|
|
277
|
+
"glm-5.3",
|
|
278
|
+
"glm-5.3-flash",
|
|
279
|
+
"gpt-5.6-luna",
|
|
280
|
+
"gpt-6-luna",
|
|
281
|
+
"grok-4.5",
|
|
282
|
+
"grok-4.6",
|
|
283
|
+
"grok-4.7",
|
|
284
|
+
"hy3",
|
|
285
|
+
"hy3-preview",
|
|
286
|
+
"hy4-preview",
|
|
287
|
+
"kimi-k2.5",
|
|
288
|
+
"kimi-k2.6",
|
|
289
|
+
"kimi-k2.7-code",
|
|
290
|
+
"kimi-k3",
|
|
291
|
+
"longcat-2.0",
|
|
292
|
+
"longcat-2.5-preview-free",
|
|
293
|
+
"mimo-v2-omni",
|
|
294
|
+
"mimo-v2-pro",
|
|
295
|
+
"mimo-v2.5",
|
|
296
|
+
"mimo-v2.5-pro",
|
|
297
|
+
"mimo-v2.6-flash",
|
|
298
|
+
"mimo-v2.6-pro",
|
|
299
|
+
"minimax-m2.5",
|
|
300
|
+
"minimax-m2.7",
|
|
301
|
+
"minimax-m3",
|
|
302
|
+
"muse-spark-1.2-contributor",
|
|
303
|
+
"muse-spark-1.3-contributor",
|
|
304
|
+
"omen-alpha",
|
|
305
|
+
"qwen3.5-plus",
|
|
306
|
+
"qwen3.6-plus",
|
|
307
|
+
"qwen3.7-max",
|
|
308
|
+
"qwen3.7-plus",
|
|
309
|
+
"qwen3.8-flash",
|
|
310
|
+
"qwen3.8-max",
|
|
311
|
+
"space-bunny-free"
|
|
312
|
+
],
|
|
313
|
+
"entries": {
|
|
314
|
+
"glm-5": {
|
|
315
|
+
"id": "glm-5",
|
|
316
|
+
"name": "GLM-5",
|
|
317
|
+
"reasoning": true,
|
|
318
|
+
"attachment": false,
|
|
319
|
+
"modalities": {
|
|
320
|
+
"input": [
|
|
321
|
+
"text"
|
|
322
|
+
]
|
|
323
|
+
},
|
|
324
|
+
"limit": {
|
|
325
|
+
"context": 204800,
|
|
326
|
+
"output": 131072
|
|
327
|
+
},
|
|
328
|
+
"cost": {
|
|
329
|
+
"input": 1,
|
|
330
|
+
"output": 3.2,
|
|
331
|
+
"cache_read": 0.2
|
|
332
|
+
},
|
|
333
|
+
"temperature": true
|
|
334
|
+
},
|
|
335
|
+
"glm-5.1": {
|
|
336
|
+
"id": "glm-5.1",
|
|
337
|
+
"name": "GLM-5.1",
|
|
338
|
+
"reasoning": true,
|
|
339
|
+
"attachment": false,
|
|
340
|
+
"modalities": {
|
|
341
|
+
"input": [
|
|
342
|
+
"text"
|
|
343
|
+
]
|
|
344
|
+
},
|
|
345
|
+
"limit": {
|
|
346
|
+
"context": 204800,
|
|
347
|
+
"output": 131072
|
|
348
|
+
},
|
|
349
|
+
"cost": {
|
|
350
|
+
"input": 1.4,
|
|
351
|
+
"output": 4.4,
|
|
352
|
+
"cache_read": 0.26
|
|
353
|
+
},
|
|
354
|
+
"temperature": true
|
|
355
|
+
},
|
|
356
|
+
"grok-4.5": {
|
|
357
|
+
"id": "grok-4.5",
|
|
358
|
+
"name": "Grok 4.5",
|
|
359
|
+
"reasoning": true,
|
|
360
|
+
"attachment": true,
|
|
361
|
+
"modalities": {
|
|
362
|
+
"input": [
|
|
363
|
+
"text",
|
|
364
|
+
"image"
|
|
365
|
+
]
|
|
366
|
+
},
|
|
367
|
+
"limit": {
|
|
368
|
+
"context": 500000,
|
|
369
|
+
"output": 500000
|
|
370
|
+
},
|
|
371
|
+
"cost": {
|
|
372
|
+
"input": 2,
|
|
373
|
+
"output": 6,
|
|
374
|
+
"cache_read": 0.3
|
|
375
|
+
},
|
|
376
|
+
"temperature": true,
|
|
377
|
+
"reasoning_options": {
|
|
378
|
+
"effort": [
|
|
379
|
+
"low",
|
|
380
|
+
"medium",
|
|
381
|
+
"high"
|
|
382
|
+
]
|
|
383
|
+
}
|
|
384
|
+
},
|
|
385
|
+
"kimi-k2.5": {
|
|
386
|
+
"id": "kimi-k2.5",
|
|
387
|
+
"name": "Kimi K2.5",
|
|
388
|
+
"reasoning": true,
|
|
389
|
+
"attachment": true,
|
|
390
|
+
"modalities": {
|
|
391
|
+
"input": [
|
|
392
|
+
"text",
|
|
393
|
+
"image",
|
|
394
|
+
"video"
|
|
395
|
+
]
|
|
396
|
+
},
|
|
397
|
+
"limit": {
|
|
398
|
+
"context": 262144,
|
|
399
|
+
"output": 65536
|
|
400
|
+
},
|
|
401
|
+
"cost": {
|
|
402
|
+
"input": 0.6,
|
|
403
|
+
"output": 3,
|
|
404
|
+
"cache_read": 0.08
|
|
405
|
+
},
|
|
406
|
+
"temperature": true
|
|
407
|
+
},
|
|
408
|
+
"kimi-k2.6": {
|
|
409
|
+
"id": "kimi-k2.6",
|
|
410
|
+
"name": "Kimi K2.6",
|
|
411
|
+
"reasoning": true,
|
|
412
|
+
"attachment": true,
|
|
413
|
+
"modalities": {
|
|
414
|
+
"input": [
|
|
415
|
+
"text",
|
|
416
|
+
"image",
|
|
417
|
+
"video"
|
|
418
|
+
]
|
|
419
|
+
},
|
|
420
|
+
"limit": {
|
|
421
|
+
"context": 262144,
|
|
422
|
+
"output": 65536
|
|
423
|
+
},
|
|
424
|
+
"cost": {
|
|
425
|
+
"input": 0.95,
|
|
426
|
+
"output": 4,
|
|
427
|
+
"cache_read": 0.16
|
|
428
|
+
},
|
|
429
|
+
"temperature": true
|
|
430
|
+
},
|
|
431
|
+
"minimax-m2.5": {
|
|
432
|
+
"id": "minimax-m2.5",
|
|
433
|
+
"name": "MiniMax-M2.5",
|
|
434
|
+
"reasoning": true,
|
|
435
|
+
"attachment": false,
|
|
436
|
+
"modalities": {
|
|
437
|
+
"input": [
|
|
438
|
+
"text"
|
|
439
|
+
]
|
|
440
|
+
},
|
|
441
|
+
"limit": {
|
|
442
|
+
"context": 204800,
|
|
443
|
+
"output": 131072
|
|
444
|
+
},
|
|
445
|
+
"cost": {
|
|
446
|
+
"input": 0.3,
|
|
447
|
+
"output": 1.2,
|
|
448
|
+
"cache_read": 0.06
|
|
449
|
+
},
|
|
450
|
+
"temperature": true
|
|
451
|
+
},
|
|
452
|
+
"qwen3.5-plus": {
|
|
453
|
+
"id": "qwen3.5-plus",
|
|
454
|
+
"name": "Qwen3.5 Plus",
|
|
455
|
+
"reasoning": true,
|
|
456
|
+
"attachment": true,
|
|
457
|
+
"modalities": {
|
|
458
|
+
"input": [
|
|
459
|
+
"text",
|
|
460
|
+
"image",
|
|
461
|
+
"video"
|
|
462
|
+
]
|
|
463
|
+
},
|
|
464
|
+
"limit": {
|
|
465
|
+
"context": 262144,
|
|
466
|
+
"output": 65536
|
|
467
|
+
},
|
|
468
|
+
"cost": {
|
|
469
|
+
"input": 0.2,
|
|
470
|
+
"output": 1.2,
|
|
471
|
+
"cache_read": 0.02
|
|
472
|
+
},
|
|
473
|
+
"temperature": true
|
|
474
|
+
},
|
|
475
|
+
"qwen3.6-plus": {
|
|
476
|
+
"id": "qwen3.6-plus",
|
|
477
|
+
"name": "Qwen3.6 Plus",
|
|
478
|
+
"reasoning": true,
|
|
479
|
+
"attachment": true,
|
|
480
|
+
"modalities": {
|
|
481
|
+
"input": [
|
|
482
|
+
"text",
|
|
483
|
+
"image",
|
|
484
|
+
"video"
|
|
485
|
+
]
|
|
486
|
+
},
|
|
487
|
+
"limit": {
|
|
488
|
+
"context": 1000000,
|
|
489
|
+
"output": 65536
|
|
490
|
+
},
|
|
491
|
+
"cost": {
|
|
492
|
+
"input": 0.5,
|
|
493
|
+
"output": 3,
|
|
494
|
+
"cache_read": 0.05
|
|
495
|
+
},
|
|
496
|
+
"temperature": true
|
|
497
|
+
},
|
|
498
|
+
"qwen3.7-max": {
|
|
499
|
+
"id": "qwen3.7-max",
|
|
500
|
+
"name": "Qwen3.7 Max",
|
|
501
|
+
"reasoning": true,
|
|
502
|
+
"attachment": false,
|
|
503
|
+
"modalities": {
|
|
504
|
+
"input": [
|
|
505
|
+
"text"
|
|
506
|
+
]
|
|
507
|
+
},
|
|
508
|
+
"limit": {
|
|
509
|
+
"context": 1000000,
|
|
510
|
+
"output": 65536
|
|
511
|
+
},
|
|
512
|
+
"cost": {
|
|
513
|
+
"input": 2.5,
|
|
514
|
+
"output": 7.5,
|
|
515
|
+
"cache_read": 0.5
|
|
516
|
+
},
|
|
517
|
+
"temperature": true
|
|
518
|
+
}
|
|
519
|
+
},
|
|
520
|
+
"fallback": [
|
|
521
|
+
"deepseek-flash",
|
|
522
|
+
"hy3-preview",
|
|
523
|
+
"mimo-v2-omni",
|
|
524
|
+
"mimo-v2-pro",
|
|
525
|
+
"omen-alpha"
|
|
526
|
+
]
|
|
527
|
+
}
|
|
528
|
+
};
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* The pi-ai instance owned by the installed dsh-llm-pi-ai adapter.
|
|
3
3
|
*
|
|
4
|
-
* dsh-llm-pi-ai rc.2
|
|
4
|
+
* dsh-llm-pi-ai 0.2.0-rc.2 declares pi-ai ^0.87.1; the workspace override
|
|
5
|
+
* pins @earendil-works/pi-ai to the latest verified catalog (0.99.1).
|
|
5
6
|
* Loading a second catalog from dsh-auth and handing its Provider objects to
|
|
6
7
|
* the adapter crosses package instances and is neither type- nor runtime-safe.
|
|
7
8
|
* Resolve the adapter's own dependency instead, and derive every public type
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* The pi-ai instance owned by the installed dsh-llm-pi-ai adapter.
|
|
3
3
|
*
|
|
4
|
-
* dsh-llm-pi-ai rc.2
|
|
4
|
+
* dsh-llm-pi-ai 0.2.0-rc.2 declares pi-ai ^0.87.1; the workspace override
|
|
5
|
+
* pins @earendil-works/pi-ai to the latest verified catalog (0.99.1).
|
|
5
6
|
* Loading a second catalog from dsh-auth and handing its Provider objects to
|
|
6
7
|
* the adapter crosses package instances and is neither type- nor runtime-safe.
|
|
7
8
|
* Resolve the adapter's own dependency instead, and derive every public type
|
|
@@ -12,6 +12,7 @@
|
|
|
12
12
|
import { randomUUID } from 'node:crypto';
|
|
13
13
|
import { resolveRetryPolicy } from '@deepseek-ai/dsh-llm';
|
|
14
14
|
import { adapterBuiltinProviders } from './pi-ai.js';
|
|
15
|
+
import { withFreshModels } from './fresh-models.js';
|
|
15
16
|
/** Provider routes this build mounts, in picker order. */
|
|
16
17
|
export const OAUTH_PROVIDER_IDS = ['openai-codex', 'anthropic', 'xai'];
|
|
17
18
|
export const CATALOG_PROVIDER_IDS = [...OAUTH_PROVIDER_IDS, 'opencode', 'opencode-go', 'openrouter'];
|
|
@@ -110,7 +111,12 @@ export function buildOAuthProfile(id, modelOverrides) {
|
|
|
110
111
|
throw new Error(`dsh-auth: "${id}" is not a catalog provider this build mounts (${CATALOG_PROVIDER_IDS.join(', ')})`);
|
|
111
112
|
}
|
|
112
113
|
const provider = catalogProviderOf(id);
|
|
113
|
-
const
|
|
114
|
+
const routed = id === 'opencode' || id === 'opencode-go' ? withOpenCodeSessionHeader(provider) : provider;
|
|
115
|
+
// OpenCode routes serve the live roster on top of the installed catalog:
|
|
116
|
+
// per-model wire protocols resolve from the nearest catalog sibling and
|
|
117
|
+
// installed models always win, so this only ever adds (see fresh-models).
|
|
118
|
+
const fresh = id === 'opencode' || id === 'opencode-go' ? withFreshModels(routed, id) : routed;
|
|
119
|
+
const catalog = withModelOverrides(fresh, modelOverrides);
|
|
114
120
|
return {
|
|
115
121
|
provider: id,
|
|
116
122
|
displayName: catalog.name,
|
|
@@ -45,6 +45,7 @@
|
|
|
45
45
|
"build": "tsc -p tsconfig.json",
|
|
46
46
|
"clean": "node -e \"require('node:fs').rmSync('lib', { recursive: true, force: true })\"",
|
|
47
47
|
"smoke": "node scripts/smoke.mjs",
|
|
48
|
+
"sync:models": "node scripts/sync-opencode-models.mjs",
|
|
48
49
|
"verify": "npm run build && npm run smoke"
|
|
49
50
|
},
|
|
50
51
|
"peerDependencies": {
|