@jacobbd/relay-ai 0.7.5 → 0.8.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 +8 -4
- package/dist/{chunk-HEMJFOXG.js → chunk-5DDQJSTU.js} +1029 -169
- package/dist/chunk-5DDQJSTU.js.map +1 -0
- package/dist/{chunk-HXGZ4CTV.js → chunk-Q2FTCICO.js} +19 -3
- package/dist/chunk-Q2FTCICO.js.map +1 -0
- package/dist/cli.js +206 -50
- package/dist/cli.js.map +1 -1
- package/dist/core/index.js +628 -7
- 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 +106 -0
- package/dist/{ui-command-26QQUWTQ.js → ui-command-RYWL36VR.js} +44 -7
- package/dist/ui-command-RYWL36VR.js.map +1 -0
- package/package.json +1 -1
- package/dist/chunk-HEMJFOXG.js.map +0 -1
- package/dist/chunk-HXGZ4CTV.js.map +0 -1
- package/dist/ui-command-26QQUWTQ.js.map +0 -1
- /package/dist/{provider-templates-4H3C4DRL.js.map → provider-templates-XKNRKAQU.js.map} +0 -0
package/dist/core/index.js
CHANGED
|
@@ -119,7 +119,7 @@ import { join as join3 } from "path";
|
|
|
119
119
|
// package.json
|
|
120
120
|
var package_default = {
|
|
121
121
|
name: "@jacobbd/relay-ai",
|
|
122
|
-
version: "0.
|
|
122
|
+
version: "0.8.0",
|
|
123
123
|
publishConfig: {
|
|
124
124
|
access: "public"
|
|
125
125
|
},
|
|
@@ -487,6 +487,43 @@ function injectClaudeIdentity(body, providerData, seed) {
|
|
|
487
487
|
return { sessionId, userId };
|
|
488
488
|
}
|
|
489
489
|
|
|
490
|
+
// src/cline-pass.ts
|
|
491
|
+
var CLINE_PASS_HOST = "https://api.cline.bot";
|
|
492
|
+
var CLINE_PASS_SDK_BASE_URL = `${CLINE_PASS_HOST}/api/v1`;
|
|
493
|
+
var CLINE_PASS_CATALOG_URL = `${CLINE_PASS_HOST}/api/v1/ai/cline/recommended-models`;
|
|
494
|
+
var CLINE_PASS_VALIDATION_URL = `${CLINE_PASS_HOST}/api/v1/users/me`;
|
|
495
|
+
var CLINE_PASS_REGISTER_URL = `${CLINE_PASS_HOST}/api/v1/auth/register`;
|
|
496
|
+
var CLINE_PASS_REFRESH_URL = `${CLINE_PASS_HOST}/api/v1/auth/refresh`;
|
|
497
|
+
var CLINE_PASS_WORKOS_PREFIX = "workos:";
|
|
498
|
+
function isClinePassOAuth(providerId, authType) {
|
|
499
|
+
return providerId === "cline-pass" && authType === "oauth";
|
|
500
|
+
}
|
|
501
|
+
function formatClineRuntimeCredential(providerId, authType, key) {
|
|
502
|
+
if (!isClinePassOAuth(providerId, authType)) return key;
|
|
503
|
+
return key.toLowerCase().startsWith(CLINE_PASS_WORKOS_PREFIX) ? key : `${CLINE_PASS_WORKOS_PREFIX}${key}`;
|
|
504
|
+
}
|
|
505
|
+
function createClinePassOAuthFetch(initialRuntimeCredential, refreshToken, onTokenRefreshed, fetchImpl = globalThis.fetch) {
|
|
506
|
+
let currentRuntimeCredential = initialRuntimeCredential;
|
|
507
|
+
return async (input, init) => {
|
|
508
|
+
const request = new Request(input, init);
|
|
509
|
+
const send = (runtimeCredential) => {
|
|
510
|
+
const headers = new Headers(request.headers);
|
|
511
|
+
headers.set("Authorization", `Bearer ${runtimeCredential}`);
|
|
512
|
+
return fetchImpl(request.clone(), { headers });
|
|
513
|
+
};
|
|
514
|
+
const response = await send(currentRuntimeCredential);
|
|
515
|
+
if (response.status !== 401) return response;
|
|
516
|
+
const refreshedRawToken = await refreshToken().catch(() => null);
|
|
517
|
+
const refreshedRuntimeCredential = refreshedRawToken ? formatClineRuntimeCredential("cline-pass", "oauth", refreshedRawToken) : null;
|
|
518
|
+
if (!refreshedRawToken || !refreshedRuntimeCredential || refreshedRuntimeCredential === currentRuntimeCredential) {
|
|
519
|
+
return response;
|
|
520
|
+
}
|
|
521
|
+
currentRuntimeCredential = refreshedRuntimeCredential;
|
|
522
|
+
onTokenRefreshed?.(refreshedRawToken);
|
|
523
|
+
return send(currentRuntimeCredential);
|
|
524
|
+
};
|
|
525
|
+
}
|
|
526
|
+
|
|
490
527
|
// src/provider-factory.ts
|
|
491
528
|
var RESPONSES_ONLY_PREFIXES = [
|
|
492
529
|
"gpt-5-codex",
|
|
@@ -615,11 +652,19 @@ async function createLanguageModel(spec) {
|
|
|
615
652
|
let model;
|
|
616
653
|
if (npm === "@ai-sdk/openai-compatible") {
|
|
617
654
|
const { createOpenAICompatible } = await import("@ai-sdk/openai-compatible");
|
|
655
|
+
const runtimeApiKey = formatClineRuntimeCredential(spec.providerId, spec.authType, apiKey);
|
|
618
656
|
const options = {
|
|
619
657
|
name: spec.providerId ?? "openai-compatible",
|
|
620
658
|
baseURL: baseURL ?? "",
|
|
621
|
-
...
|
|
622
|
-
...spec.headers ? { headers: spec.headers } : {}
|
|
659
|
+
...runtimeApiKey.trim() ? { apiKey: runtimeApiKey } : {},
|
|
660
|
+
...spec.headers ? { headers: spec.headers } : {},
|
|
661
|
+
...isClinePassOAuth(spec.providerId, spec.authType) && spec.refreshToken ? {
|
|
662
|
+
fetch: createClinePassOAuthFetch(
|
|
663
|
+
runtimeApiKey,
|
|
664
|
+
spec.refreshToken,
|
|
665
|
+
spec.onTokenRefreshed
|
|
666
|
+
)
|
|
667
|
+
} : {}
|
|
623
668
|
};
|
|
624
669
|
model = createOpenAICompatible({
|
|
625
670
|
...options
|
|
@@ -1296,7 +1341,7 @@ function accessTokenIsExpiring(token, skewMs = OAUTH_REFRESH_SKEW_MS) {
|
|
|
1296
1341
|
return false;
|
|
1297
1342
|
}
|
|
1298
1343
|
}
|
|
1299
|
-
var NATIVE_OAUTH_PROVIDER_IDS = ["xai", "xai-oauth", "openai", "openai-oauth", "github-copilot", "claude-code", "antigravity"];
|
|
1344
|
+
var NATIVE_OAUTH_PROVIDER_IDS = ["xai", "xai-oauth", "openai", "openai-oauth", "github-copilot", "claude-code", "antigravity", "cline-pass"];
|
|
1300
1345
|
|
|
1301
1346
|
// src/oauth/github.ts
|
|
1302
1347
|
var COPILOT_TOKEN_URL = "https://api.github.com/copilot_internal/v2/token";
|
|
@@ -1482,6 +1527,66 @@ async function refreshAntigravityToken(refreshToken) {
|
|
|
1482
1527
|
);
|
|
1483
1528
|
}
|
|
1484
1529
|
|
|
1530
|
+
// src/oauth/cline-pass.ts
|
|
1531
|
+
var DEFAULT_EXPIRES_MS = 10 * 60 * 1e3;
|
|
1532
|
+
function jsonHeaders() {
|
|
1533
|
+
return {
|
|
1534
|
+
Accept: "application/json",
|
|
1535
|
+
"Content-Type": "application/json"
|
|
1536
|
+
};
|
|
1537
|
+
}
|
|
1538
|
+
function expiresInFromIso(expiresAt) {
|
|
1539
|
+
if (typeof expiresAt !== "string") throw new Error("ClinePass response is missing a valid expiresAt");
|
|
1540
|
+
const timestamp = Date.parse(expiresAt);
|
|
1541
|
+
if (!Number.isFinite(timestamp)) throw new Error("ClinePass response is missing a valid expiresAt");
|
|
1542
|
+
return Math.max(1, Math.floor((timestamp - Date.now()) / 1e3));
|
|
1543
|
+
}
|
|
1544
|
+
function toOAuthResult(data) {
|
|
1545
|
+
if (typeof data.accessToken !== "string" || !data.accessToken) {
|
|
1546
|
+
throw new Error("ClinePass response is missing accessToken");
|
|
1547
|
+
}
|
|
1548
|
+
const userInfo = data.userInfo && typeof data.userInfo === "object" && !Array.isArray(data.userInfo) ? data.userInfo : void 0;
|
|
1549
|
+
const accountId = typeof userInfo?.clineUserId === "string" ? userInfo.clineUserId : void 0;
|
|
1550
|
+
return {
|
|
1551
|
+
tokens: {
|
|
1552
|
+
access_token: data.accessToken,
|
|
1553
|
+
...typeof data.refreshToken === "string" ? { refresh_token: data.refreshToken } : {},
|
|
1554
|
+
expires_in: expiresInFromIso(data.expiresAt),
|
|
1555
|
+
...userInfo ? { providerData: userInfo } : {}
|
|
1556
|
+
},
|
|
1557
|
+
...accountId ? { accountId } : {},
|
|
1558
|
+
...userInfo ? { providerData: userInfo } : {}
|
|
1559
|
+
};
|
|
1560
|
+
}
|
|
1561
|
+
async function readError(response) {
|
|
1562
|
+
const text = await response.text().catch(() => "");
|
|
1563
|
+
if (!text) return `HTTP ${response.status}`;
|
|
1564
|
+
try {
|
|
1565
|
+
const parsed = JSON.parse(text);
|
|
1566
|
+
const detail = typeof parsed.error === "string" ? parsed.error : typeof parsed.message === "string" ? parsed.message : "";
|
|
1567
|
+
return detail || `HTTP ${response.status}`;
|
|
1568
|
+
} catch {
|
|
1569
|
+
return text.slice(0, 120);
|
|
1570
|
+
}
|
|
1571
|
+
}
|
|
1572
|
+
async function refreshClinePassAccessToken(refreshToken) {
|
|
1573
|
+
const response = await fetch(CLINE_PASS_REFRESH_URL, {
|
|
1574
|
+
method: "POST",
|
|
1575
|
+
headers: jsonHeaders(),
|
|
1576
|
+
body: JSON.stringify({ refreshToken, grantType: "refresh_token" })
|
|
1577
|
+
});
|
|
1578
|
+
if (!response.ok) {
|
|
1579
|
+
const detail = await readError(response);
|
|
1580
|
+
throw new Error(`ClinePass token refresh failed (${response.status}): ${detail}`);
|
|
1581
|
+
}
|
|
1582
|
+
const body = await response.json();
|
|
1583
|
+
if (body.success !== true || !body.data) {
|
|
1584
|
+
const detail = typeof body.error === "string" ? body.error : typeof body.message === "string" ? body.message : "unsuccessful response";
|
|
1585
|
+
throw new Error(`ClinePass token refresh failed: ${detail}`);
|
|
1586
|
+
}
|
|
1587
|
+
return toOAuthResult(body.data).tokens;
|
|
1588
|
+
}
|
|
1589
|
+
|
|
1485
1590
|
// src/oauth/refresh.ts
|
|
1486
1591
|
function oauthCredentialShouldRefresh(cred, providerId) {
|
|
1487
1592
|
if (oauthCredentialNeedsRefresh(cred)) return true;
|
|
@@ -1503,10 +1608,13 @@ async function refreshStoredOAuthCredential(providerId, cred) {
|
|
|
1503
1608
|
tokens = await refreshClaudeCodeToken(cred.refresh);
|
|
1504
1609
|
} else if (providerId === "antigravity") {
|
|
1505
1610
|
tokens = await refreshAntigravityToken(cred.refresh);
|
|
1611
|
+
} else if (providerId === "cline-pass") {
|
|
1612
|
+
tokens = await refreshClinePassAccessToken(cred.refresh);
|
|
1506
1613
|
} else {
|
|
1507
1614
|
throw new Error(`OAuth refresh not implemented for provider "${providerId}"`);
|
|
1508
1615
|
}
|
|
1509
|
-
|
|
1616
|
+
const accountId = providerId === "cline-pass" && typeof tokens.providerData?.clineUserId === "string" ? tokens.providerData.clineUserId : cred.accountId;
|
|
1617
|
+
return tokensToStoredCredential(tokens, cred.refresh, accountId, cred.providerData);
|
|
1510
1618
|
}
|
|
1511
1619
|
|
|
1512
1620
|
// src/secrets-file.ts
|
|
@@ -1705,6 +1813,18 @@ async function resolveProviderCredential(providerId, authRef, diag) {
|
|
|
1705
1813
|
}
|
|
1706
1814
|
return readProviderSecret(parsed.account, diag);
|
|
1707
1815
|
}
|
|
1816
|
+
async function forceRefreshProviderCredential(providerId, authRef, diag) {
|
|
1817
|
+
const namespaced = readEnvCredential(relayAiKeyEnvVar(providerId));
|
|
1818
|
+
if (namespaced) return namespaced;
|
|
1819
|
+
const parsed = parseAuthRef(authRef);
|
|
1820
|
+
if (!parsed || parsed.kind !== "keyring") {
|
|
1821
|
+
return resolveProviderCredential(providerId, authRef, diag);
|
|
1822
|
+
}
|
|
1823
|
+
const oauthProviderId = oauthProviderIdFromAccount(parsed.account);
|
|
1824
|
+
const raw = await readKeyringAccount(parsed.account, diag);
|
|
1825
|
+
if (!raw || !oauthProviderId) return decodeProviderSecret(raw);
|
|
1826
|
+
return refreshOAuthKeyringAccount(parsed.account, oauthProviderId, raw, diag, true);
|
|
1827
|
+
}
|
|
1708
1828
|
async function resolveProviderOAuthAccountId(authRef, diag) {
|
|
1709
1829
|
const parsed = parseAuthRef(authRef);
|
|
1710
1830
|
if (!parsed || parsed.kind !== "keyring" || !oauthProviderIdFromAccount(parsed.account)) return void 0;
|
|
@@ -1731,12 +1851,12 @@ function decodeProviderSecret(raw) {
|
|
|
1731
1851
|
}
|
|
1732
1852
|
return trimmed;
|
|
1733
1853
|
}
|
|
1734
|
-
async function refreshOAuthKeyringAccount(account, providerId, raw, diag) {
|
|
1854
|
+
async function refreshOAuthKeyringAccount(account, providerId, raw, diag, force = false) {
|
|
1735
1855
|
const existing = oauthRefreshInflight.get(account);
|
|
1736
1856
|
if (existing) return existing;
|
|
1737
1857
|
const work = (async () => {
|
|
1738
1858
|
const cred = parseStoredOAuthCredential(raw);
|
|
1739
|
-
if (!cred || !oauthCredentialShouldRefresh(cred, providerId)) {
|
|
1859
|
+
if (!cred || !force && !oauthCredentialShouldRefresh(cred, providerId)) {
|
|
1740
1860
|
return decodeProviderSecret(raw);
|
|
1741
1861
|
}
|
|
1742
1862
|
try {
|
|
@@ -1767,6 +1887,506 @@ async function readProviderSecret(account, diag) {
|
|
|
1767
1887
|
return decodeProviderSecret(raw);
|
|
1768
1888
|
}
|
|
1769
1889
|
|
|
1890
|
+
// src/data/model-incompatible.json
|
|
1891
|
+
var model_incompatible_default = {
|
|
1892
|
+
schema_version: "1",
|
|
1893
|
+
entries: [
|
|
1894
|
+
{
|
|
1895
|
+
provider: "google",
|
|
1896
|
+
modelId: "antigravity-preview-05-2026",
|
|
1897
|
+
category: "managed_agent",
|
|
1898
|
+
reason: "Interactions API only; coding agents send multiturn chat via @ai-sdk/google streamGenerateContent",
|
|
1899
|
+
sources: [
|
|
1900
|
+
"https://ai.google.dev/gemini-api/docs/models",
|
|
1901
|
+
"manual UAT 2026-06-10"
|
|
1902
|
+
],
|
|
1903
|
+
verifiedAt: "2026-06-10"
|
|
1904
|
+
},
|
|
1905
|
+
{
|
|
1906
|
+
provider: "*",
|
|
1907
|
+
modelId: "z-ai/glm4.7",
|
|
1908
|
+
category: "gated_access",
|
|
1909
|
+
reason: "NVIDIA NIM requires separate access approval (HTTP 410)",
|
|
1910
|
+
sources: [
|
|
1911
|
+
"manual probe 2026-06"
|
|
1912
|
+
],
|
|
1913
|
+
verifiedAt: "2026-06-10"
|
|
1914
|
+
},
|
|
1915
|
+
{
|
|
1916
|
+
provider: "*",
|
|
1917
|
+
modelId: "qwen3.6-plus-free",
|
|
1918
|
+
category: "stale_promotion",
|
|
1919
|
+
reason: "Free promotion ended; API returns 401",
|
|
1920
|
+
sources: [
|
|
1921
|
+
"OpenCode Zen catalog"
|
|
1922
|
+
],
|
|
1923
|
+
verifiedAt: "2026-06-10"
|
|
1924
|
+
},
|
|
1925
|
+
{
|
|
1926
|
+
provider: "*",
|
|
1927
|
+
modelId: "mimo-v2-pro",
|
|
1928
|
+
category: "deprecated",
|
|
1929
|
+
reason: "Deprecated; API returns 400 \u2014 use mimo-v2.5-pro",
|
|
1930
|
+
sources: [
|
|
1931
|
+
"OpenCode Zen catalog"
|
|
1932
|
+
],
|
|
1933
|
+
verifiedAt: "2026-06-10"
|
|
1934
|
+
},
|
|
1935
|
+
{
|
|
1936
|
+
provider: "*",
|
|
1937
|
+
modelId: "mimo-v2-omni",
|
|
1938
|
+
category: "deprecated",
|
|
1939
|
+
reason: "Deprecated; API returns 400 \u2014 use mimo-v2.5",
|
|
1940
|
+
sources: [
|
|
1941
|
+
"OpenCode Zen catalog"
|
|
1942
|
+
],
|
|
1943
|
+
verifiedAt: "2026-06-10"
|
|
1944
|
+
},
|
|
1945
|
+
{
|
|
1946
|
+
provider: "google",
|
|
1947
|
+
modelId: "aqa",
|
|
1948
|
+
category: "managed_agent",
|
|
1949
|
+
reason: "Attributed QA model \u2014 not for coding agents",
|
|
1950
|
+
sources: [
|
|
1951
|
+
"https://ai.google.dev/gemini-api/docs/models",
|
|
1952
|
+
"Google GET /v1/models vs models.dev gap \u2014 UAT 2026-06-11"
|
|
1953
|
+
],
|
|
1954
|
+
verifiedAt: "2026-06-11"
|
|
1955
|
+
},
|
|
1956
|
+
{
|
|
1957
|
+
provider: "google",
|
|
1958
|
+
modelId: "deep-research-max-preview-04-2026",
|
|
1959
|
+
category: "managed_agent",
|
|
1960
|
+
reason: "Specialized agent API \u2014 not standard coding chat",
|
|
1961
|
+
sources: [
|
|
1962
|
+
"https://ai.google.dev/gemini-api/docs/models",
|
|
1963
|
+
"Google GET /v1/models vs models.dev gap \u2014 UAT 2026-06-11"
|
|
1964
|
+
],
|
|
1965
|
+
verifiedAt: "2026-06-11"
|
|
1966
|
+
},
|
|
1967
|
+
{
|
|
1968
|
+
provider: "google",
|
|
1969
|
+
modelId: "deep-research-preview-04-2026",
|
|
1970
|
+
category: "managed_agent",
|
|
1971
|
+
reason: "Specialized agent API \u2014 not standard coding chat",
|
|
1972
|
+
sources: [
|
|
1973
|
+
"https://ai.google.dev/gemini-api/docs/models",
|
|
1974
|
+
"Google GET /v1/models vs models.dev gap \u2014 UAT 2026-06-11"
|
|
1975
|
+
],
|
|
1976
|
+
verifiedAt: "2026-06-11"
|
|
1977
|
+
},
|
|
1978
|
+
{
|
|
1979
|
+
provider: "google",
|
|
1980
|
+
modelId: "deep-research-pro-preview-12-2025",
|
|
1981
|
+
category: "managed_agent",
|
|
1982
|
+
reason: "Specialized agent API \u2014 not standard coding chat",
|
|
1983
|
+
sources: [
|
|
1984
|
+
"https://ai.google.dev/gemini-api/docs/models",
|
|
1985
|
+
"Google GET /v1/models vs models.dev gap \u2014 UAT 2026-06-11"
|
|
1986
|
+
],
|
|
1987
|
+
verifiedAt: "2026-06-11"
|
|
1988
|
+
},
|
|
1989
|
+
{
|
|
1990
|
+
provider: "google",
|
|
1991
|
+
modelId: "gemini-2.5-computer-use-preview-10-2025",
|
|
1992
|
+
category: "managed_agent",
|
|
1993
|
+
reason: "Specialized agent API \u2014 not standard coding chat",
|
|
1994
|
+
sources: [
|
|
1995
|
+
"https://ai.google.dev/gemini-api/docs/models",
|
|
1996
|
+
"Google GET /v1/models vs models.dev gap \u2014 UAT 2026-06-11"
|
|
1997
|
+
],
|
|
1998
|
+
verifiedAt: "2026-06-11"
|
|
1999
|
+
},
|
|
2000
|
+
{
|
|
2001
|
+
provider: "google",
|
|
2002
|
+
modelId: "gemini-2.5-flash-image",
|
|
2003
|
+
category: "image_generation",
|
|
2004
|
+
reason: "Image-output model \u2014 not for coding chat",
|
|
2005
|
+
sources: [
|
|
2006
|
+
"https://ai.google.dev/gemini-api/docs/models",
|
|
2007
|
+
"Google GET /v1/models vs models.dev gap \u2014 UAT 2026-06-11"
|
|
2008
|
+
],
|
|
2009
|
+
verifiedAt: "2026-06-11"
|
|
2010
|
+
},
|
|
2011
|
+
{
|
|
2012
|
+
provider: "google",
|
|
2013
|
+
modelId: "gemini-2.5-flash-native-audio-latest",
|
|
2014
|
+
category: "audio_only",
|
|
2015
|
+
reason: "Audio/music output \u2014 not for coding chat",
|
|
2016
|
+
sources: [
|
|
2017
|
+
"https://ai.google.dev/gemini-api/docs/models",
|
|
2018
|
+
"Google GET /v1/models vs models.dev gap \u2014 UAT 2026-06-11"
|
|
2019
|
+
],
|
|
2020
|
+
verifiedAt: "2026-06-11"
|
|
2021
|
+
},
|
|
2022
|
+
{
|
|
2023
|
+
provider: "google",
|
|
2024
|
+
modelId: "gemini-2.5-flash-native-audio-preview-09-2025",
|
|
2025
|
+
category: "audio_only",
|
|
2026
|
+
reason: "Audio/music output \u2014 not for coding chat",
|
|
2027
|
+
sources: [
|
|
2028
|
+
"https://ai.google.dev/gemini-api/docs/models",
|
|
2029
|
+
"Google GET /v1/models vs models.dev gap \u2014 UAT 2026-06-11"
|
|
2030
|
+
],
|
|
2031
|
+
verifiedAt: "2026-06-11"
|
|
2032
|
+
},
|
|
2033
|
+
{
|
|
2034
|
+
provider: "google",
|
|
2035
|
+
modelId: "gemini-2.5-flash-native-audio-preview-12-2025",
|
|
2036
|
+
category: "audio_only",
|
|
2037
|
+
reason: "Audio/music output \u2014 not for coding chat",
|
|
2038
|
+
sources: [
|
|
2039
|
+
"https://ai.google.dev/gemini-api/docs/models",
|
|
2040
|
+
"Google GET /v1/models vs models.dev gap \u2014 UAT 2026-06-11"
|
|
2041
|
+
],
|
|
2042
|
+
verifiedAt: "2026-06-11"
|
|
2043
|
+
},
|
|
2044
|
+
{
|
|
2045
|
+
provider: "google",
|
|
2046
|
+
modelId: "gemini-2.5-flash-preview-tts",
|
|
2047
|
+
category: "audio_only",
|
|
2048
|
+
reason: "Audio/music output \u2014 not for coding chat",
|
|
2049
|
+
sources: [
|
|
2050
|
+
"https://ai.google.dev/gemini-api/docs/models",
|
|
2051
|
+
"Google GET /v1/models vs models.dev gap \u2014 UAT 2026-06-11"
|
|
2052
|
+
],
|
|
2053
|
+
verifiedAt: "2026-06-11"
|
|
2054
|
+
},
|
|
2055
|
+
{
|
|
2056
|
+
provider: "google",
|
|
2057
|
+
modelId: "gemini-2.5-pro-preview-tts",
|
|
2058
|
+
category: "audio_only",
|
|
2059
|
+
reason: "Audio/music output \u2014 not for coding chat",
|
|
2060
|
+
sources: [
|
|
2061
|
+
"https://ai.google.dev/gemini-api/docs/models",
|
|
2062
|
+
"Google GET /v1/models vs models.dev gap \u2014 UAT 2026-06-11"
|
|
2063
|
+
],
|
|
2064
|
+
verifiedAt: "2026-06-11"
|
|
2065
|
+
},
|
|
2066
|
+
{
|
|
2067
|
+
provider: "google",
|
|
2068
|
+
modelId: "gemini-3-pro-preview",
|
|
2069
|
+
category: "deprecated",
|
|
2070
|
+
reason: "Retired preview; API returns 404 \u2014 use gemini-3.1-pro-preview or newer",
|
|
2071
|
+
sources: [
|
|
2072
|
+
"https://generativelanguage.googleapis.com/v1beta/models/gemini-3-pro-preview",
|
|
2073
|
+
"manual UAT 2026-06-11"
|
|
2074
|
+
],
|
|
2075
|
+
verifiedAt: "2026-06-11"
|
|
2076
|
+
},
|
|
2077
|
+
{
|
|
2078
|
+
provider: "google",
|
|
2079
|
+
modelId: "gemini-3-pro-image",
|
|
2080
|
+
category: "image_generation",
|
|
2081
|
+
reason: "Image-output model \u2014 not for coding chat",
|
|
2082
|
+
sources: [
|
|
2083
|
+
"https://ai.google.dev/gemini-api/docs/models",
|
|
2084
|
+
"Google GET /v1/models vs models.dev gap \u2014 UAT 2026-06-11"
|
|
2085
|
+
],
|
|
2086
|
+
verifiedAt: "2026-06-11"
|
|
2087
|
+
},
|
|
2088
|
+
{
|
|
2089
|
+
provider: "google",
|
|
2090
|
+
modelId: "gemini-3-pro-image-preview",
|
|
2091
|
+
category: "image_generation",
|
|
2092
|
+
reason: "Image-output model \u2014 not for coding chat",
|
|
2093
|
+
sources: [
|
|
2094
|
+
"https://ai.google.dev/gemini-api/docs/models",
|
|
2095
|
+
"Google GET /v1/models vs models.dev gap \u2014 UAT 2026-06-11"
|
|
2096
|
+
],
|
|
2097
|
+
verifiedAt: "2026-06-11"
|
|
2098
|
+
},
|
|
2099
|
+
{
|
|
2100
|
+
provider: "google",
|
|
2101
|
+
modelId: "gemini-3.1-flash-image",
|
|
2102
|
+
category: "image_generation",
|
|
2103
|
+
reason: "Image-output model \u2014 not for coding chat",
|
|
2104
|
+
sources: [
|
|
2105
|
+
"https://ai.google.dev/gemini-api/docs/models",
|
|
2106
|
+
"Google GET /v1/models vs models.dev gap \u2014 UAT 2026-06-11"
|
|
2107
|
+
],
|
|
2108
|
+
verifiedAt: "2026-06-11"
|
|
2109
|
+
},
|
|
2110
|
+
{
|
|
2111
|
+
provider: "google",
|
|
2112
|
+
modelId: "gemini-3.1-flash-image-preview",
|
|
2113
|
+
category: "image_generation",
|
|
2114
|
+
reason: "Image-output model \u2014 not for coding chat",
|
|
2115
|
+
sources: [
|
|
2116
|
+
"https://ai.google.dev/gemini-api/docs/models",
|
|
2117
|
+
"Google GET /v1/models vs models.dev gap \u2014 UAT 2026-06-11"
|
|
2118
|
+
],
|
|
2119
|
+
verifiedAt: "2026-06-11"
|
|
2120
|
+
},
|
|
2121
|
+
{
|
|
2122
|
+
provider: "google",
|
|
2123
|
+
modelId: "gemini-3.1-flash-live-preview",
|
|
2124
|
+
category: "managed_agent",
|
|
2125
|
+
reason: "Live/session API \u2014 not for Codex multiturn chat",
|
|
2126
|
+
sources: [
|
|
2127
|
+
"https://ai.google.dev/gemini-api/docs/models",
|
|
2128
|
+
"Google GET /v1/models vs models.dev gap \u2014 UAT 2026-06-11"
|
|
2129
|
+
],
|
|
2130
|
+
verifiedAt: "2026-06-11"
|
|
2131
|
+
},
|
|
2132
|
+
{
|
|
2133
|
+
provider: "google",
|
|
2134
|
+
modelId: "gemini-3.1-flash-tts-preview",
|
|
2135
|
+
category: "audio_only",
|
|
2136
|
+
reason: "Audio/music output \u2014 not for coding chat",
|
|
2137
|
+
sources: [
|
|
2138
|
+
"https://ai.google.dev/gemini-api/docs/models",
|
|
2139
|
+
"Google GET /v1/models vs models.dev gap \u2014 UAT 2026-06-11"
|
|
2140
|
+
],
|
|
2141
|
+
verifiedAt: "2026-06-11"
|
|
2142
|
+
},
|
|
2143
|
+
{
|
|
2144
|
+
provider: "google",
|
|
2145
|
+
modelId: "gemini-3.5-live-translate-preview",
|
|
2146
|
+
category: "managed_agent",
|
|
2147
|
+
reason: "Live/session API \u2014 not for Codex multiturn chat",
|
|
2148
|
+
sources: [
|
|
2149
|
+
"https://ai.google.dev/gemini-api/docs/models",
|
|
2150
|
+
"Google GET /v1/models vs models.dev gap \u2014 UAT 2026-06-11"
|
|
2151
|
+
],
|
|
2152
|
+
verifiedAt: "2026-06-11"
|
|
2153
|
+
},
|
|
2154
|
+
{
|
|
2155
|
+
provider: "google",
|
|
2156
|
+
modelId: "gemini-embedding-001",
|
|
2157
|
+
category: "embedding",
|
|
2158
|
+
reason: "Embedding model \u2014 not for chat or tools",
|
|
2159
|
+
sources: [
|
|
2160
|
+
"https://ai.google.dev/gemini-api/docs/models",
|
|
2161
|
+
"Google GET /v1/models vs models.dev gap \u2014 UAT 2026-06-11"
|
|
2162
|
+
],
|
|
2163
|
+
verifiedAt: "2026-06-11"
|
|
2164
|
+
},
|
|
2165
|
+
{
|
|
2166
|
+
provider: "google",
|
|
2167
|
+
modelId: "gemini-embedding-2",
|
|
2168
|
+
category: "embedding",
|
|
2169
|
+
reason: "Embedding model \u2014 not for chat or tools",
|
|
2170
|
+
sources: [
|
|
2171
|
+
"https://ai.google.dev/gemini-api/docs/models",
|
|
2172
|
+
"Google GET /v1/models vs models.dev gap \u2014 UAT 2026-06-11"
|
|
2173
|
+
],
|
|
2174
|
+
verifiedAt: "2026-06-11"
|
|
2175
|
+
},
|
|
2176
|
+
{
|
|
2177
|
+
provider: "google",
|
|
2178
|
+
modelId: "gemini-embedding-2-preview",
|
|
2179
|
+
category: "embedding",
|
|
2180
|
+
reason: "Embedding model \u2014 not for chat or tools",
|
|
2181
|
+
sources: [
|
|
2182
|
+
"https://ai.google.dev/gemini-api/docs/models",
|
|
2183
|
+
"Google GET /v1/models vs models.dev gap \u2014 UAT 2026-06-11"
|
|
2184
|
+
],
|
|
2185
|
+
verifiedAt: "2026-06-11"
|
|
2186
|
+
},
|
|
2187
|
+
{
|
|
2188
|
+
provider: "google",
|
|
2189
|
+
modelId: "gemini-robotics-er-1.5-preview",
|
|
2190
|
+
category: "managed_agent",
|
|
2191
|
+
reason: "Specialized agent API \u2014 not standard coding chat",
|
|
2192
|
+
sources: [
|
|
2193
|
+
"https://ai.google.dev/gemini-api/docs/models",
|
|
2194
|
+
"Google GET /v1/models vs models.dev gap \u2014 UAT 2026-06-11"
|
|
2195
|
+
],
|
|
2196
|
+
verifiedAt: "2026-06-11"
|
|
2197
|
+
},
|
|
2198
|
+
{
|
|
2199
|
+
provider: "google",
|
|
2200
|
+
modelId: "gemini-robotics-er-1.6-preview",
|
|
2201
|
+
category: "managed_agent",
|
|
2202
|
+
reason: "Specialized agent API \u2014 not standard coding chat",
|
|
2203
|
+
sources: [
|
|
2204
|
+
"https://ai.google.dev/gemini-api/docs/models",
|
|
2205
|
+
"Google GET /v1/models vs models.dev gap \u2014 UAT 2026-06-11"
|
|
2206
|
+
],
|
|
2207
|
+
verifiedAt: "2026-06-11"
|
|
2208
|
+
},
|
|
2209
|
+
{
|
|
2210
|
+
provider: "google",
|
|
2211
|
+
modelId: "imagen-4.0-fast-generate-001",
|
|
2212
|
+
category: "image_generation",
|
|
2213
|
+
reason: "Image generation \u2014 not for coding chat",
|
|
2214
|
+
sources: [
|
|
2215
|
+
"https://ai.google.dev/gemini-api/docs/models",
|
|
2216
|
+
"Google GET /v1/models vs models.dev gap \u2014 UAT 2026-06-11"
|
|
2217
|
+
],
|
|
2218
|
+
verifiedAt: "2026-06-11"
|
|
2219
|
+
},
|
|
2220
|
+
{
|
|
2221
|
+
provider: "google",
|
|
2222
|
+
modelId: "imagen-4.0-generate-001",
|
|
2223
|
+
category: "image_generation",
|
|
2224
|
+
reason: "Image generation \u2014 not for coding chat",
|
|
2225
|
+
sources: [
|
|
2226
|
+
"https://ai.google.dev/gemini-api/docs/models",
|
|
2227
|
+
"Google GET /v1/models vs models.dev gap \u2014 UAT 2026-06-11"
|
|
2228
|
+
],
|
|
2229
|
+
verifiedAt: "2026-06-11"
|
|
2230
|
+
},
|
|
2231
|
+
{
|
|
2232
|
+
provider: "google",
|
|
2233
|
+
modelId: "imagen-4.0-ultra-generate-001",
|
|
2234
|
+
category: "image_generation",
|
|
2235
|
+
reason: "Image generation \u2014 not for coding chat",
|
|
2236
|
+
sources: [
|
|
2237
|
+
"https://ai.google.dev/gemini-api/docs/models",
|
|
2238
|
+
"Google GET /v1/models vs models.dev gap \u2014 UAT 2026-06-11"
|
|
2239
|
+
],
|
|
2240
|
+
verifiedAt: "2026-06-11"
|
|
2241
|
+
},
|
|
2242
|
+
{
|
|
2243
|
+
provider: "google",
|
|
2244
|
+
modelId: "lyria-3-clip-preview",
|
|
2245
|
+
category: "audio_only",
|
|
2246
|
+
reason: "Audio/music output \u2014 not for coding chat",
|
|
2247
|
+
sources: [
|
|
2248
|
+
"https://ai.google.dev/gemini-api/docs/models",
|
|
2249
|
+
"Google GET /v1/models vs models.dev gap \u2014 UAT 2026-06-11"
|
|
2250
|
+
],
|
|
2251
|
+
verifiedAt: "2026-06-11"
|
|
2252
|
+
},
|
|
2253
|
+
{
|
|
2254
|
+
provider: "google",
|
|
2255
|
+
modelId: "lyria-3-pro-preview",
|
|
2256
|
+
category: "audio_only",
|
|
2257
|
+
reason: "Audio/music output \u2014 not for coding chat",
|
|
2258
|
+
sources: [
|
|
2259
|
+
"https://ai.google.dev/gemini-api/docs/models",
|
|
2260
|
+
"Google GET /v1/models vs models.dev gap \u2014 UAT 2026-06-11"
|
|
2261
|
+
],
|
|
2262
|
+
verifiedAt: "2026-06-11"
|
|
2263
|
+
},
|
|
2264
|
+
{
|
|
2265
|
+
provider: "google",
|
|
2266
|
+
modelId: "lyria-realtime-exp",
|
|
2267
|
+
category: "audio_only",
|
|
2268
|
+
reason: "Audio/music output \u2014 not for coding chat",
|
|
2269
|
+
sources: [
|
|
2270
|
+
"https://ai.google.dev/gemini-api/docs/models",
|
|
2271
|
+
"Google GET /v1/models vs models.dev gap \u2014 UAT 2026-06-11"
|
|
2272
|
+
],
|
|
2273
|
+
verifiedAt: "2026-06-11"
|
|
2274
|
+
},
|
|
2275
|
+
{
|
|
2276
|
+
provider: "google",
|
|
2277
|
+
modelId: "nano-banana-pro-preview",
|
|
2278
|
+
category: "image_generation",
|
|
2279
|
+
reason: "Image generation \u2014 not for coding chat",
|
|
2280
|
+
sources: [
|
|
2281
|
+
"https://ai.google.dev/gemini-api/docs/models",
|
|
2282
|
+
"Google GET /v1/models vs models.dev gap \u2014 UAT 2026-06-11"
|
|
2283
|
+
],
|
|
2284
|
+
verifiedAt: "2026-06-11"
|
|
2285
|
+
},
|
|
2286
|
+
{
|
|
2287
|
+
provider: "google",
|
|
2288
|
+
modelId: "veo-2.0-generate-001",
|
|
2289
|
+
category: "video_generation",
|
|
2290
|
+
reason: "Video generation \u2014 not for coding chat",
|
|
2291
|
+
sources: [
|
|
2292
|
+
"https://ai.google.dev/gemini-api/docs/models",
|
|
2293
|
+
"Google GET /v1/models vs models.dev gap \u2014 UAT 2026-06-11"
|
|
2294
|
+
],
|
|
2295
|
+
verifiedAt: "2026-06-11"
|
|
2296
|
+
},
|
|
2297
|
+
{
|
|
2298
|
+
provider: "google",
|
|
2299
|
+
modelId: "veo-3.0-fast-generate-001",
|
|
2300
|
+
category: "video_generation",
|
|
2301
|
+
reason: "Video generation \u2014 not for coding chat",
|
|
2302
|
+
sources: [
|
|
2303
|
+
"https://ai.google.dev/gemini-api/docs/models",
|
|
2304
|
+
"Google GET /v1/models vs models.dev gap \u2014 UAT 2026-06-11"
|
|
2305
|
+
],
|
|
2306
|
+
verifiedAt: "2026-06-11"
|
|
2307
|
+
},
|
|
2308
|
+
{
|
|
2309
|
+
provider: "google",
|
|
2310
|
+
modelId: "veo-3.0-generate-001",
|
|
2311
|
+
category: "video_generation",
|
|
2312
|
+
reason: "Video generation \u2014 not for coding chat",
|
|
2313
|
+
sources: [
|
|
2314
|
+
"https://ai.google.dev/gemini-api/docs/models",
|
|
2315
|
+
"Google GET /v1/models vs models.dev gap \u2014 UAT 2026-06-11"
|
|
2316
|
+
],
|
|
2317
|
+
verifiedAt: "2026-06-11"
|
|
2318
|
+
},
|
|
2319
|
+
{
|
|
2320
|
+
provider: "google",
|
|
2321
|
+
modelId: "veo-3.1-fast-generate-preview",
|
|
2322
|
+
category: "video_generation",
|
|
2323
|
+
reason: "Video generation \u2014 not for coding chat",
|
|
2324
|
+
sources: [
|
|
2325
|
+
"https://ai.google.dev/gemini-api/docs/models",
|
|
2326
|
+
"Google GET /v1/models vs models.dev gap \u2014 UAT 2026-06-11"
|
|
2327
|
+
],
|
|
2328
|
+
verifiedAt: "2026-06-11"
|
|
2329
|
+
},
|
|
2330
|
+
{
|
|
2331
|
+
provider: "google",
|
|
2332
|
+
modelId: "veo-3.1-generate-preview",
|
|
2333
|
+
category: "video_generation",
|
|
2334
|
+
reason: "Video generation \u2014 not for coding chat",
|
|
2335
|
+
sources: [
|
|
2336
|
+
"https://ai.google.dev/gemini-api/docs/models",
|
|
2337
|
+
"Google GET /v1/models vs models.dev gap \u2014 UAT 2026-06-11"
|
|
2338
|
+
],
|
|
2339
|
+
verifiedAt: "2026-06-11"
|
|
2340
|
+
},
|
|
2341
|
+
{
|
|
2342
|
+
provider: "google",
|
|
2343
|
+
modelId: "veo-3.1-lite-generate-preview",
|
|
2344
|
+
category: "video_generation",
|
|
2345
|
+
reason: "Video generation \u2014 not for coding chat",
|
|
2346
|
+
sources: [
|
|
2347
|
+
"https://ai.google.dev/gemini-api/docs/models",
|
|
2348
|
+
"Google GET /v1/models vs models.dev gap \u2014 UAT 2026-06-11"
|
|
2349
|
+
],
|
|
2350
|
+
verifiedAt: "2026-06-11"
|
|
2351
|
+
}
|
|
2352
|
+
]
|
|
2353
|
+
};
|
|
2354
|
+
|
|
2355
|
+
// src/registry/models-dev.ts
|
|
2356
|
+
import {
|
|
2357
|
+
chmodSync as chmodSync4,
|
|
2358
|
+
existsSync as existsSync6,
|
|
2359
|
+
mkdirSync as mkdirSync5,
|
|
2360
|
+
readFileSync as readFileSync8,
|
|
2361
|
+
statSync as statSync2,
|
|
2362
|
+
writeFileSync as writeFileSync4
|
|
2363
|
+
} from "fs";
|
|
2364
|
+
import { dirname as dirname4, join as join6 } from "path";
|
|
2365
|
+
|
|
2366
|
+
// src/registry/pricing.ts
|
|
2367
|
+
import {
|
|
2368
|
+
chmodSync as chmodSync3,
|
|
2369
|
+
existsSync as existsSync5,
|
|
2370
|
+
mkdirSync as mkdirSync4,
|
|
2371
|
+
readFileSync as readFileSync7,
|
|
2372
|
+
writeFileSync as writeFileSync3
|
|
2373
|
+
} from "fs";
|
|
2374
|
+
import { dirname as dirname3, join as join5 } from "path";
|
|
2375
|
+
|
|
2376
|
+
// src/model-compatibility.ts
|
|
2377
|
+
var BLACKLIST_ENTRIES = model_incompatible_default.entries ?? [];
|
|
2378
|
+
|
|
2379
|
+
// src/registry/import-build.ts
|
|
2380
|
+
function oauthAuthRef(providerId) {
|
|
2381
|
+
return `keyring:oauth:provider:${providerId}`;
|
|
2382
|
+
}
|
|
2383
|
+
|
|
2384
|
+
// src/provider-runtime.ts
|
|
2385
|
+
function providerRefreshToken(providerId, authType, authRef) {
|
|
2386
|
+
if (authType !== "oauth" || !providerId) return void 0;
|
|
2387
|
+
return () => forceRefreshProviderCredential(providerId, authRef ?? oauthAuthRef(providerId));
|
|
2388
|
+
}
|
|
2389
|
+
|
|
1770
2390
|
// src/core/model.ts
|
|
1771
2391
|
function findRoute(registry, providerId, modelId, routeId) {
|
|
1772
2392
|
const provider = registry.providers.find((p) => p.id === providerId);
|
|
@@ -1833,6 +2453,7 @@ async function createRelayModel(routeId) {
|
|
|
1833
2453
|
oauthAccountId,
|
|
1834
2454
|
providerData,
|
|
1835
2455
|
headers: provider.api.headers,
|
|
2456
|
+
refreshToken: providerRefreshToken(provider.id, provider.authType, provider.authRef),
|
|
1836
2457
|
useResponsesLite: model.useResponsesLite,
|
|
1837
2458
|
preferWebSockets: model.preferWebSockets
|
|
1838
2459
|
};
|