@jacobbd/relay-ai 0.7.6 → 0.9.0
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 +26 -10
- package/dist/{chunk-HXGZ4CTV.js → chunk-Q2FTCICO.js} +19 -3
- package/dist/chunk-Q2FTCICO.js.map +1 -0
- package/dist/{chunk-GHSURQOK.js → chunk-R4AWEK7T.js} +922 -216
- package/dist/chunk-R4AWEK7T.js.map +1 -0
- package/dist/cli.js +1818 -434
- package/dist/cli.js.map +1 -1
- package/dist/core/index.js +718 -83
- package/dist/core/index.js.map +1 -1
- package/dist/{provider-templates-4H3C4DRL.js → provider-templates-XKNRKAQU.js} +2 -2
- package/dist/ui/public/app.js +270 -41
- package/dist/ui/public/index.html +32 -0
- package/dist/ui/public/provider-model-browser.js +18 -2
- package/dist/{ui-command-27X4WJKC.js → ui-command-FARF2BF4.js} +96 -15
- package/dist/ui-command-FARF2BF4.js.map +1 -0
- package/package.json +4 -3
- package/dist/chunk-GHSURQOK.js.map +0 -1
- package/dist/chunk-HXGZ4CTV.js.map +0 -1
- package/dist/ui-command-27X4WJKC.js.map +0 -1
- /package/dist/{provider-templates-4H3C4DRL.js.map → provider-templates-XKNRKAQU.js.map} +0 -0
package/dist/core/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// src/config.ts
|
|
2
|
-
import { dirname, join as
|
|
2
|
+
import { dirname, join as join3 } from "path";
|
|
3
3
|
import { copyFileSync, existsSync, mkdirSync, readFileSync, renameSync, writeFileSync } from "fs";
|
|
4
4
|
|
|
5
5
|
// src/paths.ts
|
|
@@ -43,83 +43,14 @@ function getLegacyConfPath(env = process.env, platform = process.platform) {
|
|
|
43
43
|
return join(env.XDG_CONFIG_HOME ?? join(home, ".config"), appName, "config.json");
|
|
44
44
|
}
|
|
45
45
|
|
|
46
|
-
// src/config.ts
|
|
47
|
-
function readJsonFile(path) {
|
|
48
|
-
try {
|
|
49
|
-
const parsed = JSON.parse(readFileSync(path, "utf8"));
|
|
50
|
-
return parsed && typeof parsed === "object" ? parsed : null;
|
|
51
|
-
} catch {
|
|
52
|
-
return null;
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
|
-
function ensureAppHomeMigrated() {
|
|
56
|
-
const configPath = getConfigPath();
|
|
57
|
-
if (existsSync(configPath)) return;
|
|
58
|
-
const legacyConfig = join2(getLegacyAppHome(), "config.json");
|
|
59
|
-
if (!existsSync(legacyConfig)) return;
|
|
60
|
-
mkdirSync(getAppHome(), { recursive: true, mode: 448 });
|
|
61
|
-
copyFileSync(legacyConfig, configPath);
|
|
62
|
-
const legacyVertex = join2(getLegacyAppHome(), "vertex-models.json");
|
|
63
|
-
const vertexPath = join2(getAppHome(), "vertex-models.json");
|
|
64
|
-
if (existsSync(legacyVertex) && !existsSync(vertexPath)) {
|
|
65
|
-
copyFileSync(legacyVertex, vertexPath);
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
function ensureConfigMigrated() {
|
|
69
|
-
ensureAppHomeMigrated();
|
|
70
|
-
const configPath = getConfigPath();
|
|
71
|
-
if (existsSync(configPath)) return;
|
|
72
|
-
const legacyPath = getLegacyConfPath();
|
|
73
|
-
if (!existsSync(legacyPath)) return;
|
|
74
|
-
const legacy = readJsonFile(legacyPath);
|
|
75
|
-
if (!legacy) return;
|
|
76
|
-
mkdirSync(dirname(configPath), { recursive: true, mode: 448 });
|
|
77
|
-
writeFileSync(configPath, `${JSON.stringify(legacy, null, 2)}
|
|
78
|
-
`, { encoding: "utf8", mode: 384 });
|
|
79
|
-
try {
|
|
80
|
-
renameSync(legacyPath, `${legacyPath}.migrated`);
|
|
81
|
-
} catch {
|
|
82
|
-
}
|
|
83
|
-
}
|
|
84
|
-
function readConfig() {
|
|
85
|
-
ensureConfigMigrated();
|
|
86
|
-
return readJsonFile(getConfigPath()) ?? {};
|
|
87
|
-
}
|
|
88
|
-
function loadPreferences() {
|
|
89
|
-
const config = readConfig();
|
|
90
|
-
const lastProvider = config.lastProvider === "opencode" ? "zen" : config.lastProvider;
|
|
91
|
-
return {
|
|
92
|
-
lastBackend: config.lastBackend,
|
|
93
|
-
lastModel: config.lastModel,
|
|
94
|
-
lastProvider,
|
|
95
|
-
lastCodexProvider: config.lastCodexProvider,
|
|
96
|
-
lastCodexModel: config.lastCodexModel,
|
|
97
|
-
lastGeminiProvider: config.lastGeminiProvider,
|
|
98
|
-
lastGeminiModel: config.lastGeminiModel,
|
|
99
|
-
lastAntigravityProvider: config.lastAntigravityProvider,
|
|
100
|
-
lastAntigravityModel: config.lastAntigravityModel,
|
|
101
|
-
lastClaudeTransparentMode: config.lastClaudeTransparentMode,
|
|
102
|
-
recentModelsByProvider: config.recentModelsByProvider,
|
|
103
|
-
favoriteModels: config.favoriteModels,
|
|
104
|
-
antigravityCliFavoriteModels: config.antigravityCliFavoriteModels,
|
|
105
|
-
antigravityCliFavoritesHintShown: config.antigravityCliFavoritesHintShown,
|
|
106
|
-
appPathOverrides: config.appPathOverrides,
|
|
107
|
-
recentLaunchFolders: config.recentLaunchFolders,
|
|
108
|
-
server: config.server
|
|
109
|
-
};
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
// src/provider-factory.ts
|
|
113
|
-
import { wrapLanguageModel, extractReasoningMiddleware } from "ai";
|
|
114
|
-
|
|
115
46
|
// src/constants.ts
|
|
116
47
|
import { homedir as homedir2 } from "os";
|
|
117
|
-
import { join as
|
|
48
|
+
import { join as join2 } from "path";
|
|
118
49
|
|
|
119
50
|
// package.json
|
|
120
51
|
var package_default = {
|
|
121
52
|
name: "@jacobbd/relay-ai",
|
|
122
|
-
version: "0.
|
|
53
|
+
version: "0.9.0",
|
|
123
54
|
publishConfig: {
|
|
124
55
|
access: "public"
|
|
125
56
|
},
|
|
@@ -202,10 +133,11 @@ var package_default = {
|
|
|
202
133
|
"@types/node": "^22.0.0",
|
|
203
134
|
"@types/node-forge": "^1.3.14",
|
|
204
135
|
"@types/ws": "^8.18.1",
|
|
205
|
-
"@vitest/coverage-v8": "^
|
|
136
|
+
"@vitest/coverage-v8": "^4.1.10",
|
|
206
137
|
tsup: "^8.0.0",
|
|
207
138
|
typescript: "^5.5.0",
|
|
208
|
-
|
|
139
|
+
"vite-node": "^6.0.0",
|
|
140
|
+
vitest: "^4.1.10"
|
|
209
141
|
},
|
|
210
142
|
optionalDependencies: {
|
|
211
143
|
"@napi-rs/keyring": "^1.3.0"
|
|
@@ -227,10 +159,81 @@ var package_default = {
|
|
|
227
159
|
var CODEX_RESPONSES_LITE_WS_URL = "wss://chatgpt.com/backend-api/codex/responses";
|
|
228
160
|
var CODEX_RESPONSES_LITE_VERSION = "0.144.1";
|
|
229
161
|
var CODEX_RESPONSES_WEBSOCKETS_BETA = "responses_websockets=2026-02-06";
|
|
230
|
-
var OPENCODE_CACHE_PATH =
|
|
162
|
+
var OPENCODE_CACHE_PATH = join2(homedir2(), ".cache", "opencode", "models.json");
|
|
163
|
+
var CODEX_SUBAGENT_MODEL_CAP = 1;
|
|
231
164
|
var VERTEX_ANTHROPIC_NPM = "@ai-sdk/google-vertex/anthropic";
|
|
232
165
|
var VERSION = package_default.version;
|
|
233
166
|
|
|
167
|
+
// src/config.ts
|
|
168
|
+
function readJsonFile(path) {
|
|
169
|
+
try {
|
|
170
|
+
const parsed = JSON.parse(readFileSync(path, "utf8"));
|
|
171
|
+
return parsed && typeof parsed === "object" ? parsed : null;
|
|
172
|
+
} catch {
|
|
173
|
+
return null;
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
function ensureAppHomeMigrated() {
|
|
177
|
+
const configPath = getConfigPath();
|
|
178
|
+
if (existsSync(configPath)) return;
|
|
179
|
+
const legacyConfig = join3(getLegacyAppHome(), "config.json");
|
|
180
|
+
if (!existsSync(legacyConfig)) return;
|
|
181
|
+
mkdirSync(getAppHome(), { recursive: true, mode: 448 });
|
|
182
|
+
copyFileSync(legacyConfig, configPath);
|
|
183
|
+
const legacyVertex = join3(getLegacyAppHome(), "vertex-models.json");
|
|
184
|
+
const vertexPath = join3(getAppHome(), "vertex-models.json");
|
|
185
|
+
if (existsSync(legacyVertex) && !existsSync(vertexPath)) {
|
|
186
|
+
copyFileSync(legacyVertex, vertexPath);
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
function ensureConfigMigrated() {
|
|
190
|
+
ensureAppHomeMigrated();
|
|
191
|
+
const configPath = getConfigPath();
|
|
192
|
+
if (existsSync(configPath)) return;
|
|
193
|
+
const legacyPath = getLegacyConfPath();
|
|
194
|
+
if (!existsSync(legacyPath)) return;
|
|
195
|
+
const legacy = readJsonFile(legacyPath);
|
|
196
|
+
if (!legacy) return;
|
|
197
|
+
mkdirSync(dirname(configPath), { recursive: true, mode: 448 });
|
|
198
|
+
writeFileSync(configPath, `${JSON.stringify(legacy, null, 2)}
|
|
199
|
+
`, { encoding: "utf8", mode: 384 });
|
|
200
|
+
try {
|
|
201
|
+
renameSync(legacyPath, `${legacyPath}.migrated`);
|
|
202
|
+
} catch {
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
function readConfig() {
|
|
206
|
+
ensureConfigMigrated();
|
|
207
|
+
return readJsonFile(getConfigPath()) ?? {};
|
|
208
|
+
}
|
|
209
|
+
function loadPreferences() {
|
|
210
|
+
const config = readConfig();
|
|
211
|
+
const lastProvider = config.lastProvider === "opencode" ? "zen" : config.lastProvider;
|
|
212
|
+
return {
|
|
213
|
+
lastBackend: config.lastBackend,
|
|
214
|
+
lastModel: config.lastModel,
|
|
215
|
+
lastProvider,
|
|
216
|
+
lastCodexProvider: config.lastCodexProvider,
|
|
217
|
+
lastCodexModel: config.lastCodexModel,
|
|
218
|
+
lastGeminiProvider: config.lastGeminiProvider,
|
|
219
|
+
lastGeminiModel: config.lastGeminiModel,
|
|
220
|
+
lastAntigravityProvider: config.lastAntigravityProvider,
|
|
221
|
+
lastAntigravityModel: config.lastAntigravityModel,
|
|
222
|
+
lastClaudeTransparentMode: config.lastClaudeTransparentMode,
|
|
223
|
+
recentModelsByProvider: config.recentModelsByProvider,
|
|
224
|
+
favoriteModels: config.favoriteModels,
|
|
225
|
+
codexSubagentModels: Array.isArray(config.codexSubagentModels) ? config.codexSubagentModels.slice(0, CODEX_SUBAGENT_MODEL_CAP) : void 0,
|
|
226
|
+
antigravityCliFavoriteModels: config.antigravityCliFavoriteModels,
|
|
227
|
+
antigravityCliFavoritesHintShown: config.antigravityCliFavoritesHintShown,
|
|
228
|
+
appPathOverrides: config.appPathOverrides,
|
|
229
|
+
recentLaunchFolders: config.recentLaunchFolders,
|
|
230
|
+
server: config.server
|
|
231
|
+
};
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
// src/provider-factory.ts
|
|
235
|
+
import { wrapLanguageModel, extractReasoningMiddleware } from "ai";
|
|
236
|
+
|
|
234
237
|
// src/oauth/refresh-http.ts
|
|
235
238
|
async function postOAuthRefresh(url, body, options) {
|
|
236
239
|
const isJson = options.contentType === "json";
|
|
@@ -487,6 +490,43 @@ function injectClaudeIdentity(body, providerData, seed) {
|
|
|
487
490
|
return { sessionId, userId };
|
|
488
491
|
}
|
|
489
492
|
|
|
493
|
+
// src/cline-pass.ts
|
|
494
|
+
var CLINE_PASS_HOST = "https://api.cline.bot";
|
|
495
|
+
var CLINE_PASS_SDK_BASE_URL = `${CLINE_PASS_HOST}/api/v1`;
|
|
496
|
+
var CLINE_PASS_CATALOG_URL = `${CLINE_PASS_HOST}/api/v1/ai/cline/recommended-models`;
|
|
497
|
+
var CLINE_PASS_VALIDATION_URL = `${CLINE_PASS_HOST}/api/v1/users/me`;
|
|
498
|
+
var CLINE_PASS_REGISTER_URL = `${CLINE_PASS_HOST}/api/v1/auth/register`;
|
|
499
|
+
var CLINE_PASS_REFRESH_URL = `${CLINE_PASS_HOST}/api/v1/auth/refresh`;
|
|
500
|
+
var CLINE_PASS_WORKOS_PREFIX = "workos:";
|
|
501
|
+
function isClinePassOAuth(providerId, authType) {
|
|
502
|
+
return providerId === "cline-pass" && authType === "oauth";
|
|
503
|
+
}
|
|
504
|
+
function formatClineRuntimeCredential(providerId, authType, key) {
|
|
505
|
+
if (!isClinePassOAuth(providerId, authType)) return key;
|
|
506
|
+
return key.toLowerCase().startsWith(CLINE_PASS_WORKOS_PREFIX) ? key : `${CLINE_PASS_WORKOS_PREFIX}${key}`;
|
|
507
|
+
}
|
|
508
|
+
function createClinePassOAuthFetch(initialRuntimeCredential, refreshToken, onTokenRefreshed, fetchImpl = globalThis.fetch) {
|
|
509
|
+
let currentRuntimeCredential = initialRuntimeCredential;
|
|
510
|
+
return async (input, init) => {
|
|
511
|
+
const request = new Request(input, init);
|
|
512
|
+
const send = (runtimeCredential) => {
|
|
513
|
+
const headers = new Headers(request.headers);
|
|
514
|
+
headers.set("Authorization", `Bearer ${runtimeCredential}`);
|
|
515
|
+
return fetchImpl(request.clone(), { headers });
|
|
516
|
+
};
|
|
517
|
+
const response = await send(currentRuntimeCredential);
|
|
518
|
+
if (response.status !== 401) return response;
|
|
519
|
+
const refreshedRawToken = await refreshToken().catch(() => null);
|
|
520
|
+
const refreshedRuntimeCredential = refreshedRawToken ? formatClineRuntimeCredential("cline-pass", "oauth", refreshedRawToken) : null;
|
|
521
|
+
if (!refreshedRawToken || !refreshedRuntimeCredential || refreshedRuntimeCredential === currentRuntimeCredential) {
|
|
522
|
+
return response;
|
|
523
|
+
}
|
|
524
|
+
currentRuntimeCredential = refreshedRuntimeCredential;
|
|
525
|
+
onTokenRefreshed?.(refreshedRawToken);
|
|
526
|
+
return send(currentRuntimeCredential);
|
|
527
|
+
};
|
|
528
|
+
}
|
|
529
|
+
|
|
490
530
|
// src/provider-factory.ts
|
|
491
531
|
var RESPONSES_ONLY_PREFIXES = [
|
|
492
532
|
"gpt-5-codex",
|
|
@@ -615,11 +655,19 @@ async function createLanguageModel(spec) {
|
|
|
615
655
|
let model;
|
|
616
656
|
if (npm === "@ai-sdk/openai-compatible") {
|
|
617
657
|
const { createOpenAICompatible } = await import("@ai-sdk/openai-compatible");
|
|
658
|
+
const runtimeApiKey = formatClineRuntimeCredential(spec.providerId, spec.authType, apiKey);
|
|
618
659
|
const options = {
|
|
619
660
|
name: spec.providerId ?? "openai-compatible",
|
|
620
661
|
baseURL: baseURL ?? "",
|
|
621
|
-
...
|
|
622
|
-
...spec.headers ? { headers: spec.headers } : {}
|
|
662
|
+
...runtimeApiKey.trim() ? { apiKey: runtimeApiKey } : {},
|
|
663
|
+
...spec.headers ? { headers: spec.headers } : {},
|
|
664
|
+
...isClinePassOAuth(spec.providerId, spec.authType) && spec.refreshToken ? {
|
|
665
|
+
fetch: createClinePassOAuthFetch(
|
|
666
|
+
runtimeApiKey,
|
|
667
|
+
spec.refreshToken,
|
|
668
|
+
spec.onTokenRefreshed
|
|
669
|
+
)
|
|
670
|
+
} : {}
|
|
623
671
|
};
|
|
624
672
|
model = createOpenAICompatible({
|
|
625
673
|
...options
|
|
@@ -1296,7 +1344,7 @@ function accessTokenIsExpiring(token, skewMs = OAUTH_REFRESH_SKEW_MS) {
|
|
|
1296
1344
|
return false;
|
|
1297
1345
|
}
|
|
1298
1346
|
}
|
|
1299
|
-
var NATIVE_OAUTH_PROVIDER_IDS = ["xai", "xai-oauth", "openai", "openai-oauth", "github-copilot", "claude-code", "antigravity"];
|
|
1347
|
+
var NATIVE_OAUTH_PROVIDER_IDS = ["xai", "xai-oauth", "openai", "openai-oauth", "github-copilot", "claude-code", "antigravity", "cline-pass"];
|
|
1300
1348
|
|
|
1301
1349
|
// src/oauth/github.ts
|
|
1302
1350
|
var COPILOT_TOKEN_URL = "https://api.github.com/copilot_internal/v2/token";
|
|
@@ -1482,6 +1530,66 @@ async function refreshAntigravityToken(refreshToken) {
|
|
|
1482
1530
|
);
|
|
1483
1531
|
}
|
|
1484
1532
|
|
|
1533
|
+
// src/oauth/cline-pass.ts
|
|
1534
|
+
var DEFAULT_EXPIRES_MS = 10 * 60 * 1e3;
|
|
1535
|
+
function jsonHeaders() {
|
|
1536
|
+
return {
|
|
1537
|
+
Accept: "application/json",
|
|
1538
|
+
"Content-Type": "application/json"
|
|
1539
|
+
};
|
|
1540
|
+
}
|
|
1541
|
+
function expiresInFromIso(expiresAt) {
|
|
1542
|
+
if (typeof expiresAt !== "string") throw new Error("ClinePass response is missing a valid expiresAt");
|
|
1543
|
+
const timestamp = Date.parse(expiresAt);
|
|
1544
|
+
if (!Number.isFinite(timestamp)) throw new Error("ClinePass response is missing a valid expiresAt");
|
|
1545
|
+
return Math.max(1, Math.floor((timestamp - Date.now()) / 1e3));
|
|
1546
|
+
}
|
|
1547
|
+
function toOAuthResult(data) {
|
|
1548
|
+
if (typeof data.accessToken !== "string" || !data.accessToken) {
|
|
1549
|
+
throw new Error("ClinePass response is missing accessToken");
|
|
1550
|
+
}
|
|
1551
|
+
const userInfo = data.userInfo && typeof data.userInfo === "object" && !Array.isArray(data.userInfo) ? data.userInfo : void 0;
|
|
1552
|
+
const accountId = typeof userInfo?.clineUserId === "string" ? userInfo.clineUserId : void 0;
|
|
1553
|
+
return {
|
|
1554
|
+
tokens: {
|
|
1555
|
+
access_token: data.accessToken,
|
|
1556
|
+
...typeof data.refreshToken === "string" ? { refresh_token: data.refreshToken } : {},
|
|
1557
|
+
expires_in: expiresInFromIso(data.expiresAt),
|
|
1558
|
+
...userInfo ? { providerData: userInfo } : {}
|
|
1559
|
+
},
|
|
1560
|
+
...accountId ? { accountId } : {},
|
|
1561
|
+
...userInfo ? { providerData: userInfo } : {}
|
|
1562
|
+
};
|
|
1563
|
+
}
|
|
1564
|
+
async function readError(response) {
|
|
1565
|
+
const text = await response.text().catch(() => "");
|
|
1566
|
+
if (!text) return `HTTP ${response.status}`;
|
|
1567
|
+
try {
|
|
1568
|
+
const parsed = JSON.parse(text);
|
|
1569
|
+
const detail = typeof parsed.error === "string" ? parsed.error : typeof parsed.message === "string" ? parsed.message : "";
|
|
1570
|
+
return detail || `HTTP ${response.status}`;
|
|
1571
|
+
} catch {
|
|
1572
|
+
return text.slice(0, 120);
|
|
1573
|
+
}
|
|
1574
|
+
}
|
|
1575
|
+
async function refreshClinePassAccessToken(refreshToken) {
|
|
1576
|
+
const response = await fetch(CLINE_PASS_REFRESH_URL, {
|
|
1577
|
+
method: "POST",
|
|
1578
|
+
headers: jsonHeaders(),
|
|
1579
|
+
body: JSON.stringify({ refreshToken, grantType: "refresh_token" })
|
|
1580
|
+
});
|
|
1581
|
+
if (!response.ok) {
|
|
1582
|
+
const detail = await readError(response);
|
|
1583
|
+
throw new Error(`ClinePass token refresh failed (${response.status}): ${detail}`);
|
|
1584
|
+
}
|
|
1585
|
+
const body = await response.json();
|
|
1586
|
+
if (body.success !== true || !body.data) {
|
|
1587
|
+
const detail = typeof body.error === "string" ? body.error : typeof body.message === "string" ? body.message : "unsuccessful response";
|
|
1588
|
+
throw new Error(`ClinePass token refresh failed: ${detail}`);
|
|
1589
|
+
}
|
|
1590
|
+
return toOAuthResult(body.data).tokens;
|
|
1591
|
+
}
|
|
1592
|
+
|
|
1485
1593
|
// src/oauth/refresh.ts
|
|
1486
1594
|
function oauthCredentialShouldRefresh(cred, providerId) {
|
|
1487
1595
|
if (oauthCredentialNeedsRefresh(cred)) return true;
|
|
@@ -1503,10 +1611,13 @@ async function refreshStoredOAuthCredential(providerId, cred) {
|
|
|
1503
1611
|
tokens = await refreshClaudeCodeToken(cred.refresh);
|
|
1504
1612
|
} else if (providerId === "antigravity") {
|
|
1505
1613
|
tokens = await refreshAntigravityToken(cred.refresh);
|
|
1614
|
+
} else if (providerId === "cline-pass") {
|
|
1615
|
+
tokens = await refreshClinePassAccessToken(cred.refresh);
|
|
1506
1616
|
} else {
|
|
1507
1617
|
throw new Error(`OAuth refresh not implemented for provider "${providerId}"`);
|
|
1508
1618
|
}
|
|
1509
|
-
|
|
1619
|
+
const accountId = providerId === "cline-pass" && typeof tokens.providerData?.clineUserId === "string" ? tokens.providerData.clineUserId : cred.accountId;
|
|
1620
|
+
return tokensToStoredCredential(tokens, cred.refresh, accountId, cred.providerData);
|
|
1510
1621
|
}
|
|
1511
1622
|
|
|
1512
1623
|
// src/secrets-file.ts
|
|
@@ -1602,6 +1713,9 @@ var KEYRING_CHUNK_SIZE = 1200;
|
|
|
1602
1713
|
var LEGACY_KEYRING_SERVICE = "opencode-starter";
|
|
1603
1714
|
var LEGACY_KEYRING_ACCOUNT = "opencode-starter";
|
|
1604
1715
|
var GLOBAL_OPENCODE_KEYRING_ACCOUNT = "global:opencode";
|
|
1716
|
+
function providerKeyringAccount(providerId) {
|
|
1717
|
+
return `provider:${providerId}`;
|
|
1718
|
+
}
|
|
1605
1719
|
function oauthProviderIdFromAccount(account) {
|
|
1606
1720
|
const prefix = "oauth:provider:";
|
|
1607
1721
|
return account.startsWith(prefix) ? account.slice(prefix.length) : null;
|
|
@@ -1693,10 +1807,14 @@ async function readGlobalOpencodeCredential(diag) {
|
|
|
1693
1807
|
}
|
|
1694
1808
|
}
|
|
1695
1809
|
async function resolveProviderCredential(providerId, authRef, diag) {
|
|
1696
|
-
const namespaced = readEnvCredential(relayAiKeyEnvVar(providerId));
|
|
1697
|
-
if (namespaced) return namespaced;
|
|
1698
1810
|
const parsed = parseAuthRef(authRef);
|
|
1699
1811
|
if (!parsed) return null;
|
|
1812
|
+
if (parsed.kind === "keyring" && parsed.account === GLOBAL_OPENCODE_KEYRING_ACCOUNT) {
|
|
1813
|
+
const relayOverride = await readProviderSecret(providerKeyringAccount("opencode"), diag);
|
|
1814
|
+
if (relayOverride) return relayOverride;
|
|
1815
|
+
}
|
|
1816
|
+
const namespaced = readEnvCredential(relayAiKeyEnvVar(providerId));
|
|
1817
|
+
if (namespaced) return namespaced;
|
|
1700
1818
|
if (parsed.kind === "env") {
|
|
1701
1819
|
return readEnvCredential(parsed.varName);
|
|
1702
1820
|
}
|
|
@@ -1705,6 +1823,22 @@ async function resolveProviderCredential(providerId, authRef, diag) {
|
|
|
1705
1823
|
}
|
|
1706
1824
|
return readProviderSecret(parsed.account, diag);
|
|
1707
1825
|
}
|
|
1826
|
+
async function forceRefreshProviderCredential(providerId, authRef, diag) {
|
|
1827
|
+
const parsed = parseAuthRef(authRef);
|
|
1828
|
+
if (!parsed || parsed.kind !== "keyring") {
|
|
1829
|
+
return resolveProviderCredential(providerId, authRef, diag);
|
|
1830
|
+
}
|
|
1831
|
+
if (parsed.account === GLOBAL_OPENCODE_KEYRING_ACCOUNT) {
|
|
1832
|
+
const relayOverride = await readProviderSecret(providerKeyringAccount("opencode"), diag);
|
|
1833
|
+
if (relayOverride) return relayOverride;
|
|
1834
|
+
}
|
|
1835
|
+
const namespaced = readEnvCredential(relayAiKeyEnvVar(providerId));
|
|
1836
|
+
if (namespaced) return namespaced;
|
|
1837
|
+
const oauthProviderId = oauthProviderIdFromAccount(parsed.account);
|
|
1838
|
+
const raw = await readKeyringAccount(parsed.account, diag);
|
|
1839
|
+
if (!raw || !oauthProviderId) return decodeProviderSecret(raw);
|
|
1840
|
+
return refreshOAuthKeyringAccount(parsed.account, oauthProviderId, raw, diag, true);
|
|
1841
|
+
}
|
|
1708
1842
|
async function resolveProviderOAuthAccountId(authRef, diag) {
|
|
1709
1843
|
const parsed = parseAuthRef(authRef);
|
|
1710
1844
|
if (!parsed || parsed.kind !== "keyring" || !oauthProviderIdFromAccount(parsed.account)) return void 0;
|
|
@@ -1731,12 +1865,12 @@ function decodeProviderSecret(raw) {
|
|
|
1731
1865
|
}
|
|
1732
1866
|
return trimmed;
|
|
1733
1867
|
}
|
|
1734
|
-
async function refreshOAuthKeyringAccount(account, providerId, raw, diag) {
|
|
1868
|
+
async function refreshOAuthKeyringAccount(account, providerId, raw, diag, force = false) {
|
|
1735
1869
|
const existing = oauthRefreshInflight.get(account);
|
|
1736
1870
|
if (existing) return existing;
|
|
1737
1871
|
const work = (async () => {
|
|
1738
1872
|
const cred = parseStoredOAuthCredential(raw);
|
|
1739
|
-
if (!cred || !oauthCredentialShouldRefresh(cred, providerId)) {
|
|
1873
|
+
if (!cred || !force && !oauthCredentialShouldRefresh(cred, providerId)) {
|
|
1740
1874
|
return decodeProviderSecret(raw);
|
|
1741
1875
|
}
|
|
1742
1876
|
try {
|
|
@@ -1767,6 +1901,506 @@ async function readProviderSecret(account, diag) {
|
|
|
1767
1901
|
return decodeProviderSecret(raw);
|
|
1768
1902
|
}
|
|
1769
1903
|
|
|
1904
|
+
// src/data/model-incompatible.json
|
|
1905
|
+
var model_incompatible_default = {
|
|
1906
|
+
schema_version: "1",
|
|
1907
|
+
entries: [
|
|
1908
|
+
{
|
|
1909
|
+
provider: "google",
|
|
1910
|
+
modelId: "antigravity-preview-05-2026",
|
|
1911
|
+
category: "managed_agent",
|
|
1912
|
+
reason: "Interactions API only; coding agents send multiturn chat via @ai-sdk/google streamGenerateContent",
|
|
1913
|
+
sources: [
|
|
1914
|
+
"https://ai.google.dev/gemini-api/docs/models",
|
|
1915
|
+
"manual UAT 2026-06-10"
|
|
1916
|
+
],
|
|
1917
|
+
verifiedAt: "2026-06-10"
|
|
1918
|
+
},
|
|
1919
|
+
{
|
|
1920
|
+
provider: "*",
|
|
1921
|
+
modelId: "z-ai/glm4.7",
|
|
1922
|
+
category: "gated_access",
|
|
1923
|
+
reason: "NVIDIA NIM requires separate access approval (HTTP 410)",
|
|
1924
|
+
sources: [
|
|
1925
|
+
"manual probe 2026-06"
|
|
1926
|
+
],
|
|
1927
|
+
verifiedAt: "2026-06-10"
|
|
1928
|
+
},
|
|
1929
|
+
{
|
|
1930
|
+
provider: "*",
|
|
1931
|
+
modelId: "qwen3.6-plus-free",
|
|
1932
|
+
category: "stale_promotion",
|
|
1933
|
+
reason: "Free promotion ended; API returns 401",
|
|
1934
|
+
sources: [
|
|
1935
|
+
"OpenCode Zen catalog"
|
|
1936
|
+
],
|
|
1937
|
+
verifiedAt: "2026-06-10"
|
|
1938
|
+
},
|
|
1939
|
+
{
|
|
1940
|
+
provider: "*",
|
|
1941
|
+
modelId: "mimo-v2-pro",
|
|
1942
|
+
category: "deprecated",
|
|
1943
|
+
reason: "Deprecated; API returns 400 \u2014 use mimo-v2.5-pro",
|
|
1944
|
+
sources: [
|
|
1945
|
+
"OpenCode Zen catalog"
|
|
1946
|
+
],
|
|
1947
|
+
verifiedAt: "2026-06-10"
|
|
1948
|
+
},
|
|
1949
|
+
{
|
|
1950
|
+
provider: "*",
|
|
1951
|
+
modelId: "mimo-v2-omni",
|
|
1952
|
+
category: "deprecated",
|
|
1953
|
+
reason: "Deprecated; API returns 400 \u2014 use mimo-v2.5",
|
|
1954
|
+
sources: [
|
|
1955
|
+
"OpenCode Zen catalog"
|
|
1956
|
+
],
|
|
1957
|
+
verifiedAt: "2026-06-10"
|
|
1958
|
+
},
|
|
1959
|
+
{
|
|
1960
|
+
provider: "google",
|
|
1961
|
+
modelId: "aqa",
|
|
1962
|
+
category: "managed_agent",
|
|
1963
|
+
reason: "Attributed QA model \u2014 not for coding agents",
|
|
1964
|
+
sources: [
|
|
1965
|
+
"https://ai.google.dev/gemini-api/docs/models",
|
|
1966
|
+
"Google GET /v1/models vs models.dev gap \u2014 UAT 2026-06-11"
|
|
1967
|
+
],
|
|
1968
|
+
verifiedAt: "2026-06-11"
|
|
1969
|
+
},
|
|
1970
|
+
{
|
|
1971
|
+
provider: "google",
|
|
1972
|
+
modelId: "deep-research-max-preview-04-2026",
|
|
1973
|
+
category: "managed_agent",
|
|
1974
|
+
reason: "Specialized agent API \u2014 not standard coding chat",
|
|
1975
|
+
sources: [
|
|
1976
|
+
"https://ai.google.dev/gemini-api/docs/models",
|
|
1977
|
+
"Google GET /v1/models vs models.dev gap \u2014 UAT 2026-06-11"
|
|
1978
|
+
],
|
|
1979
|
+
verifiedAt: "2026-06-11"
|
|
1980
|
+
},
|
|
1981
|
+
{
|
|
1982
|
+
provider: "google",
|
|
1983
|
+
modelId: "deep-research-preview-04-2026",
|
|
1984
|
+
category: "managed_agent",
|
|
1985
|
+
reason: "Specialized agent API \u2014 not standard coding chat",
|
|
1986
|
+
sources: [
|
|
1987
|
+
"https://ai.google.dev/gemini-api/docs/models",
|
|
1988
|
+
"Google GET /v1/models vs models.dev gap \u2014 UAT 2026-06-11"
|
|
1989
|
+
],
|
|
1990
|
+
verifiedAt: "2026-06-11"
|
|
1991
|
+
},
|
|
1992
|
+
{
|
|
1993
|
+
provider: "google",
|
|
1994
|
+
modelId: "deep-research-pro-preview-12-2025",
|
|
1995
|
+
category: "managed_agent",
|
|
1996
|
+
reason: "Specialized agent API \u2014 not standard coding chat",
|
|
1997
|
+
sources: [
|
|
1998
|
+
"https://ai.google.dev/gemini-api/docs/models",
|
|
1999
|
+
"Google GET /v1/models vs models.dev gap \u2014 UAT 2026-06-11"
|
|
2000
|
+
],
|
|
2001
|
+
verifiedAt: "2026-06-11"
|
|
2002
|
+
},
|
|
2003
|
+
{
|
|
2004
|
+
provider: "google",
|
|
2005
|
+
modelId: "gemini-2.5-computer-use-preview-10-2025",
|
|
2006
|
+
category: "managed_agent",
|
|
2007
|
+
reason: "Specialized agent API \u2014 not standard coding chat",
|
|
2008
|
+
sources: [
|
|
2009
|
+
"https://ai.google.dev/gemini-api/docs/models",
|
|
2010
|
+
"Google GET /v1/models vs models.dev gap \u2014 UAT 2026-06-11"
|
|
2011
|
+
],
|
|
2012
|
+
verifiedAt: "2026-06-11"
|
|
2013
|
+
},
|
|
2014
|
+
{
|
|
2015
|
+
provider: "google",
|
|
2016
|
+
modelId: "gemini-2.5-flash-image",
|
|
2017
|
+
category: "image_generation",
|
|
2018
|
+
reason: "Image-output model \u2014 not for coding chat",
|
|
2019
|
+
sources: [
|
|
2020
|
+
"https://ai.google.dev/gemini-api/docs/models",
|
|
2021
|
+
"Google GET /v1/models vs models.dev gap \u2014 UAT 2026-06-11"
|
|
2022
|
+
],
|
|
2023
|
+
verifiedAt: "2026-06-11"
|
|
2024
|
+
},
|
|
2025
|
+
{
|
|
2026
|
+
provider: "google",
|
|
2027
|
+
modelId: "gemini-2.5-flash-native-audio-latest",
|
|
2028
|
+
category: "audio_only",
|
|
2029
|
+
reason: "Audio/music output \u2014 not for coding chat",
|
|
2030
|
+
sources: [
|
|
2031
|
+
"https://ai.google.dev/gemini-api/docs/models",
|
|
2032
|
+
"Google GET /v1/models vs models.dev gap \u2014 UAT 2026-06-11"
|
|
2033
|
+
],
|
|
2034
|
+
verifiedAt: "2026-06-11"
|
|
2035
|
+
},
|
|
2036
|
+
{
|
|
2037
|
+
provider: "google",
|
|
2038
|
+
modelId: "gemini-2.5-flash-native-audio-preview-09-2025",
|
|
2039
|
+
category: "audio_only",
|
|
2040
|
+
reason: "Audio/music output \u2014 not for coding chat",
|
|
2041
|
+
sources: [
|
|
2042
|
+
"https://ai.google.dev/gemini-api/docs/models",
|
|
2043
|
+
"Google GET /v1/models vs models.dev gap \u2014 UAT 2026-06-11"
|
|
2044
|
+
],
|
|
2045
|
+
verifiedAt: "2026-06-11"
|
|
2046
|
+
},
|
|
2047
|
+
{
|
|
2048
|
+
provider: "google",
|
|
2049
|
+
modelId: "gemini-2.5-flash-native-audio-preview-12-2025",
|
|
2050
|
+
category: "audio_only",
|
|
2051
|
+
reason: "Audio/music output \u2014 not for coding chat",
|
|
2052
|
+
sources: [
|
|
2053
|
+
"https://ai.google.dev/gemini-api/docs/models",
|
|
2054
|
+
"Google GET /v1/models vs models.dev gap \u2014 UAT 2026-06-11"
|
|
2055
|
+
],
|
|
2056
|
+
verifiedAt: "2026-06-11"
|
|
2057
|
+
},
|
|
2058
|
+
{
|
|
2059
|
+
provider: "google",
|
|
2060
|
+
modelId: "gemini-2.5-flash-preview-tts",
|
|
2061
|
+
category: "audio_only",
|
|
2062
|
+
reason: "Audio/music output \u2014 not for coding chat",
|
|
2063
|
+
sources: [
|
|
2064
|
+
"https://ai.google.dev/gemini-api/docs/models",
|
|
2065
|
+
"Google GET /v1/models vs models.dev gap \u2014 UAT 2026-06-11"
|
|
2066
|
+
],
|
|
2067
|
+
verifiedAt: "2026-06-11"
|
|
2068
|
+
},
|
|
2069
|
+
{
|
|
2070
|
+
provider: "google",
|
|
2071
|
+
modelId: "gemini-2.5-pro-preview-tts",
|
|
2072
|
+
category: "audio_only",
|
|
2073
|
+
reason: "Audio/music output \u2014 not for coding chat",
|
|
2074
|
+
sources: [
|
|
2075
|
+
"https://ai.google.dev/gemini-api/docs/models",
|
|
2076
|
+
"Google GET /v1/models vs models.dev gap \u2014 UAT 2026-06-11"
|
|
2077
|
+
],
|
|
2078
|
+
verifiedAt: "2026-06-11"
|
|
2079
|
+
},
|
|
2080
|
+
{
|
|
2081
|
+
provider: "google",
|
|
2082
|
+
modelId: "gemini-3-pro-preview",
|
|
2083
|
+
category: "deprecated",
|
|
2084
|
+
reason: "Retired preview; API returns 404 \u2014 use gemini-3.1-pro-preview or newer",
|
|
2085
|
+
sources: [
|
|
2086
|
+
"https://generativelanguage.googleapis.com/v1beta/models/gemini-3-pro-preview",
|
|
2087
|
+
"manual UAT 2026-06-11"
|
|
2088
|
+
],
|
|
2089
|
+
verifiedAt: "2026-06-11"
|
|
2090
|
+
},
|
|
2091
|
+
{
|
|
2092
|
+
provider: "google",
|
|
2093
|
+
modelId: "gemini-3-pro-image",
|
|
2094
|
+
category: "image_generation",
|
|
2095
|
+
reason: "Image-output model \u2014 not for coding chat",
|
|
2096
|
+
sources: [
|
|
2097
|
+
"https://ai.google.dev/gemini-api/docs/models",
|
|
2098
|
+
"Google GET /v1/models vs models.dev gap \u2014 UAT 2026-06-11"
|
|
2099
|
+
],
|
|
2100
|
+
verifiedAt: "2026-06-11"
|
|
2101
|
+
},
|
|
2102
|
+
{
|
|
2103
|
+
provider: "google",
|
|
2104
|
+
modelId: "gemini-3-pro-image-preview",
|
|
2105
|
+
category: "image_generation",
|
|
2106
|
+
reason: "Image-output model \u2014 not for coding chat",
|
|
2107
|
+
sources: [
|
|
2108
|
+
"https://ai.google.dev/gemini-api/docs/models",
|
|
2109
|
+
"Google GET /v1/models vs models.dev gap \u2014 UAT 2026-06-11"
|
|
2110
|
+
],
|
|
2111
|
+
verifiedAt: "2026-06-11"
|
|
2112
|
+
},
|
|
2113
|
+
{
|
|
2114
|
+
provider: "google",
|
|
2115
|
+
modelId: "gemini-3.1-flash-image",
|
|
2116
|
+
category: "image_generation",
|
|
2117
|
+
reason: "Image-output model \u2014 not for coding chat",
|
|
2118
|
+
sources: [
|
|
2119
|
+
"https://ai.google.dev/gemini-api/docs/models",
|
|
2120
|
+
"Google GET /v1/models vs models.dev gap \u2014 UAT 2026-06-11"
|
|
2121
|
+
],
|
|
2122
|
+
verifiedAt: "2026-06-11"
|
|
2123
|
+
},
|
|
2124
|
+
{
|
|
2125
|
+
provider: "google",
|
|
2126
|
+
modelId: "gemini-3.1-flash-image-preview",
|
|
2127
|
+
category: "image_generation",
|
|
2128
|
+
reason: "Image-output model \u2014 not for coding chat",
|
|
2129
|
+
sources: [
|
|
2130
|
+
"https://ai.google.dev/gemini-api/docs/models",
|
|
2131
|
+
"Google GET /v1/models vs models.dev gap \u2014 UAT 2026-06-11"
|
|
2132
|
+
],
|
|
2133
|
+
verifiedAt: "2026-06-11"
|
|
2134
|
+
},
|
|
2135
|
+
{
|
|
2136
|
+
provider: "google",
|
|
2137
|
+
modelId: "gemini-3.1-flash-live-preview",
|
|
2138
|
+
category: "managed_agent",
|
|
2139
|
+
reason: "Live/session API \u2014 not for Codex multiturn chat",
|
|
2140
|
+
sources: [
|
|
2141
|
+
"https://ai.google.dev/gemini-api/docs/models",
|
|
2142
|
+
"Google GET /v1/models vs models.dev gap \u2014 UAT 2026-06-11"
|
|
2143
|
+
],
|
|
2144
|
+
verifiedAt: "2026-06-11"
|
|
2145
|
+
},
|
|
2146
|
+
{
|
|
2147
|
+
provider: "google",
|
|
2148
|
+
modelId: "gemini-3.1-flash-tts-preview",
|
|
2149
|
+
category: "audio_only",
|
|
2150
|
+
reason: "Audio/music output \u2014 not for coding chat",
|
|
2151
|
+
sources: [
|
|
2152
|
+
"https://ai.google.dev/gemini-api/docs/models",
|
|
2153
|
+
"Google GET /v1/models vs models.dev gap \u2014 UAT 2026-06-11"
|
|
2154
|
+
],
|
|
2155
|
+
verifiedAt: "2026-06-11"
|
|
2156
|
+
},
|
|
2157
|
+
{
|
|
2158
|
+
provider: "google",
|
|
2159
|
+
modelId: "gemini-3.5-live-translate-preview",
|
|
2160
|
+
category: "managed_agent",
|
|
2161
|
+
reason: "Live/session API \u2014 not for Codex multiturn chat",
|
|
2162
|
+
sources: [
|
|
2163
|
+
"https://ai.google.dev/gemini-api/docs/models",
|
|
2164
|
+
"Google GET /v1/models vs models.dev gap \u2014 UAT 2026-06-11"
|
|
2165
|
+
],
|
|
2166
|
+
verifiedAt: "2026-06-11"
|
|
2167
|
+
},
|
|
2168
|
+
{
|
|
2169
|
+
provider: "google",
|
|
2170
|
+
modelId: "gemini-embedding-001",
|
|
2171
|
+
category: "embedding",
|
|
2172
|
+
reason: "Embedding model \u2014 not for chat or tools",
|
|
2173
|
+
sources: [
|
|
2174
|
+
"https://ai.google.dev/gemini-api/docs/models",
|
|
2175
|
+
"Google GET /v1/models vs models.dev gap \u2014 UAT 2026-06-11"
|
|
2176
|
+
],
|
|
2177
|
+
verifiedAt: "2026-06-11"
|
|
2178
|
+
},
|
|
2179
|
+
{
|
|
2180
|
+
provider: "google",
|
|
2181
|
+
modelId: "gemini-embedding-2",
|
|
2182
|
+
category: "embedding",
|
|
2183
|
+
reason: "Embedding model \u2014 not for chat or tools",
|
|
2184
|
+
sources: [
|
|
2185
|
+
"https://ai.google.dev/gemini-api/docs/models",
|
|
2186
|
+
"Google GET /v1/models vs models.dev gap \u2014 UAT 2026-06-11"
|
|
2187
|
+
],
|
|
2188
|
+
verifiedAt: "2026-06-11"
|
|
2189
|
+
},
|
|
2190
|
+
{
|
|
2191
|
+
provider: "google",
|
|
2192
|
+
modelId: "gemini-embedding-2-preview",
|
|
2193
|
+
category: "embedding",
|
|
2194
|
+
reason: "Embedding model \u2014 not for chat or tools",
|
|
2195
|
+
sources: [
|
|
2196
|
+
"https://ai.google.dev/gemini-api/docs/models",
|
|
2197
|
+
"Google GET /v1/models vs models.dev gap \u2014 UAT 2026-06-11"
|
|
2198
|
+
],
|
|
2199
|
+
verifiedAt: "2026-06-11"
|
|
2200
|
+
},
|
|
2201
|
+
{
|
|
2202
|
+
provider: "google",
|
|
2203
|
+
modelId: "gemini-robotics-er-1.5-preview",
|
|
2204
|
+
category: "managed_agent",
|
|
2205
|
+
reason: "Specialized agent API \u2014 not standard coding chat",
|
|
2206
|
+
sources: [
|
|
2207
|
+
"https://ai.google.dev/gemini-api/docs/models",
|
|
2208
|
+
"Google GET /v1/models vs models.dev gap \u2014 UAT 2026-06-11"
|
|
2209
|
+
],
|
|
2210
|
+
verifiedAt: "2026-06-11"
|
|
2211
|
+
},
|
|
2212
|
+
{
|
|
2213
|
+
provider: "google",
|
|
2214
|
+
modelId: "gemini-robotics-er-1.6-preview",
|
|
2215
|
+
category: "managed_agent",
|
|
2216
|
+
reason: "Specialized agent API \u2014 not standard coding chat",
|
|
2217
|
+
sources: [
|
|
2218
|
+
"https://ai.google.dev/gemini-api/docs/models",
|
|
2219
|
+
"Google GET /v1/models vs models.dev gap \u2014 UAT 2026-06-11"
|
|
2220
|
+
],
|
|
2221
|
+
verifiedAt: "2026-06-11"
|
|
2222
|
+
},
|
|
2223
|
+
{
|
|
2224
|
+
provider: "google",
|
|
2225
|
+
modelId: "imagen-4.0-fast-generate-001",
|
|
2226
|
+
category: "image_generation",
|
|
2227
|
+
reason: "Image generation \u2014 not for coding chat",
|
|
2228
|
+
sources: [
|
|
2229
|
+
"https://ai.google.dev/gemini-api/docs/models",
|
|
2230
|
+
"Google GET /v1/models vs models.dev gap \u2014 UAT 2026-06-11"
|
|
2231
|
+
],
|
|
2232
|
+
verifiedAt: "2026-06-11"
|
|
2233
|
+
},
|
|
2234
|
+
{
|
|
2235
|
+
provider: "google",
|
|
2236
|
+
modelId: "imagen-4.0-generate-001",
|
|
2237
|
+
category: "image_generation",
|
|
2238
|
+
reason: "Image generation \u2014 not for coding chat",
|
|
2239
|
+
sources: [
|
|
2240
|
+
"https://ai.google.dev/gemini-api/docs/models",
|
|
2241
|
+
"Google GET /v1/models vs models.dev gap \u2014 UAT 2026-06-11"
|
|
2242
|
+
],
|
|
2243
|
+
verifiedAt: "2026-06-11"
|
|
2244
|
+
},
|
|
2245
|
+
{
|
|
2246
|
+
provider: "google",
|
|
2247
|
+
modelId: "imagen-4.0-ultra-generate-001",
|
|
2248
|
+
category: "image_generation",
|
|
2249
|
+
reason: "Image generation \u2014 not for coding chat",
|
|
2250
|
+
sources: [
|
|
2251
|
+
"https://ai.google.dev/gemini-api/docs/models",
|
|
2252
|
+
"Google GET /v1/models vs models.dev gap \u2014 UAT 2026-06-11"
|
|
2253
|
+
],
|
|
2254
|
+
verifiedAt: "2026-06-11"
|
|
2255
|
+
},
|
|
2256
|
+
{
|
|
2257
|
+
provider: "google",
|
|
2258
|
+
modelId: "lyria-3-clip-preview",
|
|
2259
|
+
category: "audio_only",
|
|
2260
|
+
reason: "Audio/music output \u2014 not for coding chat",
|
|
2261
|
+
sources: [
|
|
2262
|
+
"https://ai.google.dev/gemini-api/docs/models",
|
|
2263
|
+
"Google GET /v1/models vs models.dev gap \u2014 UAT 2026-06-11"
|
|
2264
|
+
],
|
|
2265
|
+
verifiedAt: "2026-06-11"
|
|
2266
|
+
},
|
|
2267
|
+
{
|
|
2268
|
+
provider: "google",
|
|
2269
|
+
modelId: "lyria-3-pro-preview",
|
|
2270
|
+
category: "audio_only",
|
|
2271
|
+
reason: "Audio/music output \u2014 not for coding chat",
|
|
2272
|
+
sources: [
|
|
2273
|
+
"https://ai.google.dev/gemini-api/docs/models",
|
|
2274
|
+
"Google GET /v1/models vs models.dev gap \u2014 UAT 2026-06-11"
|
|
2275
|
+
],
|
|
2276
|
+
verifiedAt: "2026-06-11"
|
|
2277
|
+
},
|
|
2278
|
+
{
|
|
2279
|
+
provider: "google",
|
|
2280
|
+
modelId: "lyria-realtime-exp",
|
|
2281
|
+
category: "audio_only",
|
|
2282
|
+
reason: "Audio/music output \u2014 not for coding chat",
|
|
2283
|
+
sources: [
|
|
2284
|
+
"https://ai.google.dev/gemini-api/docs/models",
|
|
2285
|
+
"Google GET /v1/models vs models.dev gap \u2014 UAT 2026-06-11"
|
|
2286
|
+
],
|
|
2287
|
+
verifiedAt: "2026-06-11"
|
|
2288
|
+
},
|
|
2289
|
+
{
|
|
2290
|
+
provider: "google",
|
|
2291
|
+
modelId: "nano-banana-pro-preview",
|
|
2292
|
+
category: "image_generation",
|
|
2293
|
+
reason: "Image generation \u2014 not for coding chat",
|
|
2294
|
+
sources: [
|
|
2295
|
+
"https://ai.google.dev/gemini-api/docs/models",
|
|
2296
|
+
"Google GET /v1/models vs models.dev gap \u2014 UAT 2026-06-11"
|
|
2297
|
+
],
|
|
2298
|
+
verifiedAt: "2026-06-11"
|
|
2299
|
+
},
|
|
2300
|
+
{
|
|
2301
|
+
provider: "google",
|
|
2302
|
+
modelId: "veo-2.0-generate-001",
|
|
2303
|
+
category: "video_generation",
|
|
2304
|
+
reason: "Video generation \u2014 not for coding chat",
|
|
2305
|
+
sources: [
|
|
2306
|
+
"https://ai.google.dev/gemini-api/docs/models",
|
|
2307
|
+
"Google GET /v1/models vs models.dev gap \u2014 UAT 2026-06-11"
|
|
2308
|
+
],
|
|
2309
|
+
verifiedAt: "2026-06-11"
|
|
2310
|
+
},
|
|
2311
|
+
{
|
|
2312
|
+
provider: "google",
|
|
2313
|
+
modelId: "veo-3.0-fast-generate-001",
|
|
2314
|
+
category: "video_generation",
|
|
2315
|
+
reason: "Video generation \u2014 not for coding chat",
|
|
2316
|
+
sources: [
|
|
2317
|
+
"https://ai.google.dev/gemini-api/docs/models",
|
|
2318
|
+
"Google GET /v1/models vs models.dev gap \u2014 UAT 2026-06-11"
|
|
2319
|
+
],
|
|
2320
|
+
verifiedAt: "2026-06-11"
|
|
2321
|
+
},
|
|
2322
|
+
{
|
|
2323
|
+
provider: "google",
|
|
2324
|
+
modelId: "veo-3.0-generate-001",
|
|
2325
|
+
category: "video_generation",
|
|
2326
|
+
reason: "Video generation \u2014 not for coding chat",
|
|
2327
|
+
sources: [
|
|
2328
|
+
"https://ai.google.dev/gemini-api/docs/models",
|
|
2329
|
+
"Google GET /v1/models vs models.dev gap \u2014 UAT 2026-06-11"
|
|
2330
|
+
],
|
|
2331
|
+
verifiedAt: "2026-06-11"
|
|
2332
|
+
},
|
|
2333
|
+
{
|
|
2334
|
+
provider: "google",
|
|
2335
|
+
modelId: "veo-3.1-fast-generate-preview",
|
|
2336
|
+
category: "video_generation",
|
|
2337
|
+
reason: "Video generation \u2014 not for coding chat",
|
|
2338
|
+
sources: [
|
|
2339
|
+
"https://ai.google.dev/gemini-api/docs/models",
|
|
2340
|
+
"Google GET /v1/models vs models.dev gap \u2014 UAT 2026-06-11"
|
|
2341
|
+
],
|
|
2342
|
+
verifiedAt: "2026-06-11"
|
|
2343
|
+
},
|
|
2344
|
+
{
|
|
2345
|
+
provider: "google",
|
|
2346
|
+
modelId: "veo-3.1-generate-preview",
|
|
2347
|
+
category: "video_generation",
|
|
2348
|
+
reason: "Video generation \u2014 not for coding chat",
|
|
2349
|
+
sources: [
|
|
2350
|
+
"https://ai.google.dev/gemini-api/docs/models",
|
|
2351
|
+
"Google GET /v1/models vs models.dev gap \u2014 UAT 2026-06-11"
|
|
2352
|
+
],
|
|
2353
|
+
verifiedAt: "2026-06-11"
|
|
2354
|
+
},
|
|
2355
|
+
{
|
|
2356
|
+
provider: "google",
|
|
2357
|
+
modelId: "veo-3.1-lite-generate-preview",
|
|
2358
|
+
category: "video_generation",
|
|
2359
|
+
reason: "Video generation \u2014 not for coding chat",
|
|
2360
|
+
sources: [
|
|
2361
|
+
"https://ai.google.dev/gemini-api/docs/models",
|
|
2362
|
+
"Google GET /v1/models vs models.dev gap \u2014 UAT 2026-06-11"
|
|
2363
|
+
],
|
|
2364
|
+
verifiedAt: "2026-06-11"
|
|
2365
|
+
}
|
|
2366
|
+
]
|
|
2367
|
+
};
|
|
2368
|
+
|
|
2369
|
+
// src/registry/models-dev.ts
|
|
2370
|
+
import {
|
|
2371
|
+
chmodSync as chmodSync4,
|
|
2372
|
+
existsSync as existsSync6,
|
|
2373
|
+
mkdirSync as mkdirSync5,
|
|
2374
|
+
readFileSync as readFileSync8,
|
|
2375
|
+
statSync as statSync2,
|
|
2376
|
+
writeFileSync as writeFileSync4
|
|
2377
|
+
} from "fs";
|
|
2378
|
+
import { dirname as dirname4, join as join6 } from "path";
|
|
2379
|
+
|
|
2380
|
+
// src/registry/pricing.ts
|
|
2381
|
+
import {
|
|
2382
|
+
chmodSync as chmodSync3,
|
|
2383
|
+
existsSync as existsSync5,
|
|
2384
|
+
mkdirSync as mkdirSync4,
|
|
2385
|
+
readFileSync as readFileSync7,
|
|
2386
|
+
writeFileSync as writeFileSync3
|
|
2387
|
+
} from "fs";
|
|
2388
|
+
import { dirname as dirname3, join as join5 } from "path";
|
|
2389
|
+
|
|
2390
|
+
// src/model-compatibility.ts
|
|
2391
|
+
var BLACKLIST_ENTRIES = model_incompatible_default.entries ?? [];
|
|
2392
|
+
|
|
2393
|
+
// src/registry/import-build.ts
|
|
2394
|
+
function oauthAuthRef(providerId) {
|
|
2395
|
+
return `keyring:oauth:provider:${providerId}`;
|
|
2396
|
+
}
|
|
2397
|
+
|
|
2398
|
+
// src/provider-runtime.ts
|
|
2399
|
+
function providerRefreshToken(providerId, authType, authRef) {
|
|
2400
|
+
if (authType !== "oauth" || !providerId) return void 0;
|
|
2401
|
+
return () => forceRefreshProviderCredential(providerId, authRef ?? oauthAuthRef(providerId));
|
|
2402
|
+
}
|
|
2403
|
+
|
|
1770
2404
|
// src/core/model.ts
|
|
1771
2405
|
function findRoute(registry, providerId, modelId, routeId) {
|
|
1772
2406
|
const provider = registry.providers.find((p) => p.id === providerId);
|
|
@@ -1833,6 +2467,7 @@ async function createRelayModel(routeId) {
|
|
|
1833
2467
|
oauthAccountId,
|
|
1834
2468
|
providerData,
|
|
1835
2469
|
headers: provider.api.headers,
|
|
2470
|
+
refreshToken: providerRefreshToken(provider.id, provider.authType, provider.authRef),
|
|
1836
2471
|
useResponsesLite: model.useResponsesLite,
|
|
1837
2472
|
preferWebSockets: model.preferWebSockets
|
|
1838
2473
|
};
|