@jacobbd/relay-ai 0.7.6 → 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.
@@ -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.7.6",
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
- ...apiKey.trim() ? { apiKey } : {},
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
- return tokensToStoredCredential(tokens, cred.refresh, cred.accountId, cred.providerData);
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
  };