@jacobbd/relay-ai 0.10.1 → 0.11.1

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.
@@ -50,7 +50,7 @@ import { join as join2 } from "path";
50
50
  // package.json
51
51
  var package_default = {
52
52
  name: "@jacobbd/relay-ai",
53
- version: "0.10.1",
53
+ version: "0.11.1",
54
54
  publishConfig: {
55
55
  access: "public"
56
56
  },
@@ -82,7 +82,7 @@ var package_default = {
82
82
  "README.md"
83
83
  ],
84
84
  engines: {
85
- node: ">=18"
85
+ node: ">=22"
86
86
  },
87
87
  scripts: {
88
88
  build: "tsup && tsup --config tsup.core.config.ts && node scripts/copy-ui-assets.mjs",
@@ -96,35 +96,34 @@ var package_default = {
96
96
  prepublishOnly: "npm run release:check && npm run build"
97
97
  },
98
98
  dependencies: {
99
- "@ai-sdk/alibaba": "^1.0.26",
100
- "@ai-sdk/amazon-bedrock": "^4.0.113",
101
- "@ai-sdk/azure": "^3.0.70",
102
- "@ai-sdk/cerebras": "^2.0.54",
103
- "@ai-sdk/cohere": "^3.0.36",
104
- "@ai-sdk/deepinfra": "^2.0.52",
105
- "@ai-sdk/gateway": "^3.0.125",
106
- "@ai-sdk/google": "^3.0.80",
107
- "@ai-sdk/google-vertex": "^4.0.142",
108
- "@ai-sdk/groq": "^3.0.39",
109
- "@ai-sdk/mistral": "^3.0.37",
110
- "@ai-sdk/openai": "^3.0.68",
111
- "@ai-sdk/openai-compatible": "^2.0.48",
112
- "@ai-sdk/perplexity": "^3.0.33",
113
- "@ai-sdk/togetherai": "^2.0.53",
114
- "@ai-sdk/vercel": "^2.0.50",
115
- "@ai-sdk/xai": "^3.0.93",
99
+ "@ai-sdk/alibaba": "^2.0.41",
100
+ "@ai-sdk/amazon-bedrock": "^5.0.76",
101
+ "@ai-sdk/azure": "^4.0.63",
102
+ "@ai-sdk/cerebras": "^3.0.44",
103
+ "@ai-sdk/cohere": "^4.0.37",
104
+ "@ai-sdk/deepinfra": "^3.0.44",
105
+ "@ai-sdk/gateway": "^4.0.75",
106
+ "@ai-sdk/google": "^4.0.64",
107
+ "@ai-sdk/google-vertex": "^5.0.76",
108
+ "@ai-sdk/groq": "^4.0.37",
109
+ "@ai-sdk/mistral": "^4.0.39",
110
+ "@ai-sdk/openai": "^4.0.60",
111
+ "@ai-sdk/openai-compatible": "^3.0.44",
112
+ "@ai-sdk/perplexity": "^4.0.39",
113
+ "@ai-sdk/togetherai": "^3.0.45",
114
+ "@ai-sdk/vercel": "^3.0.30",
115
+ "@ai-sdk/xai": "^4.0.54",
116
116
  "@clack/prompts": "^0.9.1",
117
- "@openrouter/ai-sdk-provider": "^2.9.0",
118
- ai: "^6.0.197",
117
+ "@openrouter/ai-sdk-provider": "^3.0.0",
118
+ ai: "^7.0.93",
119
119
  "cross-spawn": "^7.0.6",
120
- "gitlab-ai-provider": "^6.8.0",
120
+ "gitlab-ai-provider": "^6.15.0",
121
121
  graphql: "^16.14.2",
122
122
  "ipaddr.js": "^2.4.0",
123
123
  "node-forge": "^1.4.0",
124
124
  open: "^11.0.0",
125
125
  picocolors: "^1.1.1",
126
126
  "smol-toml": "^1.6.1",
127
- "venice-ai-sdk-provider": "^2.0.2",
128
127
  ws: "^8.21.0",
129
128
  zod: "^3.25.76"
130
129
  },
@@ -157,7 +156,7 @@ var package_default = {
157
156
 
158
157
  // src/constants.ts
159
158
  var CODEX_RESPONSES_LITE_WS_URL = "wss://chatgpt.com/backend-api/codex/responses";
160
- var CODEX_RESPONSES_LITE_VERSION = "0.144.1";
159
+ var CODEX_RESPONSES_LITE_VERSION = "0.153.4";
161
160
  var CODEX_RESPONSES_WEBSOCKETS_BETA = "responses_websockets=2026-02-06";
162
161
  var OPENCODE_CACHE_PATH = join2(homedir2(), ".cache", "opencode", "models.json");
163
162
  var CODEX_SUBAGENT_MODEL_CAP = 1;
@@ -874,6 +873,9 @@ var OPENAI_CHAT_COMPLETIONS_ONLY = [
874
873
  function shouldUseOpenAiResponsesEndpoint(modelId) {
875
874
  return !OPENAI_CHAT_COMPLETIONS_ONLY.includes(modelId.toLowerCase());
876
875
  }
876
+ function resolveProviderNpm(npm) {
877
+ return npm === "venice-ai-sdk-provider" ? "@ai-sdk/openai-compatible" : npm;
878
+ }
877
879
  function findCreateFactory(mod) {
878
880
  for (const value of Object.values(mod)) {
879
881
  if (typeof value === "function" && value.name.startsWith("create")) {
@@ -903,7 +905,8 @@ async function loadSdkProviderFactory(npm) {
903
905
  return cached;
904
906
  }
905
907
  async function createLanguageModel(spec) {
906
- const { npm, modelId, apiKey, baseURL } = spec;
908
+ const npm = resolveProviderNpm(spec.npm);
909
+ const { modelId, apiKey, baseURL } = spec;
907
910
  if (npm === VERTEX_ANTHROPIC_NPM) {
908
911
  if (!spec.vertex?.project) {
909
912
  throw new Error("Vertex project is required for @ai-sdk/google-vertex/anthropic");
@@ -1620,6 +1623,51 @@ function isValidProviderId(id) {
1620
1623
  return PROVIDER_ID_PATTERN.test(id);
1621
1624
  }
1622
1625
 
1626
+ // src/registry/provider-models.ts
1627
+ var MANUAL_MODEL_PACKAGES = /* @__PURE__ */ new Set([
1628
+ "@ai-sdk/openai-compatible",
1629
+ "@ai-sdk/openai",
1630
+ "@ai-sdk/anthropic",
1631
+ "@openrouter/ai-sdk-provider"
1632
+ ]);
1633
+ function supportsManualModels(provider) {
1634
+ return provider.authType !== "oauth" && !["zen", "go", "antigravity"].includes(provider.templateId) && MANUAL_MODEL_PACKAGES.has(provider.api.npm ?? "");
1635
+ }
1636
+ function getProviderModels(provider) {
1637
+ const models = new Map((provider.modelsCache?.models ?? []).map((model) => [model.id, model]));
1638
+ if (supportsManualModels(provider)) {
1639
+ for (const model of provider.manualModels ?? []) {
1640
+ models.set(model.id, { ...model, modelFormat: provider.api.npm === "@ai-sdk/anthropic" ? "anthropic" : "openai" });
1641
+ }
1642
+ }
1643
+ return [...models.values()];
1644
+ }
1645
+ function modelIdError(value) {
1646
+ if (typeof value !== "string" || !value.trim()) return "Model ID is required.";
1647
+ if (value.trim().length > 512 || /[\s\u0000-\u001f\u007f]/u.test(value.trim())) {
1648
+ return "Model ID must be at most 512 characters with no whitespace or control characters.";
1649
+ }
1650
+ }
1651
+ function contextWindowError(value) {
1652
+ if (value !== void 0 && (!Number.isSafeInteger(value) || Number(value) <= 0)) {
1653
+ return "Context size must be a positive whole number of tokens, or left blank.";
1654
+ }
1655
+ }
1656
+ function parseManualModel(raw) {
1657
+ if (!raw || typeof raw !== "object") return void 0;
1658
+ const m = raw;
1659
+ if (modelIdError(m.id) || typeof m.name !== "string" || !m.name.trim() || m.name.length > 200 || m.source !== "manual" || typeof m.validatedAt !== "string" || !Number.isFinite(Date.parse(m.validatedAt)) || contextWindowError(m.contextWindow) || m.modelFormat !== "openai" && m.modelFormat !== "anthropic") return void 0;
1660
+ return {
1661
+ id: m.id.trim(),
1662
+ name: m.name.trim(),
1663
+ upstreamModelId: m.id.trim(),
1664
+ modelFormat: m.modelFormat,
1665
+ source: "manual",
1666
+ validatedAt: m.validatedAt,
1667
+ ...m.contextWindow === void 0 ? {} : { contextWindow: m.contextWindow, contextWindowSource: "user" }
1668
+ };
1669
+ }
1670
+
1623
1671
  // src/registry/io.ts
1624
1672
  var DIR_MODE = 448;
1625
1673
  var FILE_MODE = 384;
@@ -1672,6 +1720,12 @@ function parseProvider(raw) {
1672
1720
  provider.authType = p.authType;
1673
1721
  }
1674
1722
  if (typeof p.refreshedAt === "string") provider.refreshedAt = p.refreshedAt;
1723
+ if (Array.isArray(p.manualModels)) {
1724
+ provider.manualModels = p.manualModels.flatMap((raw2) => {
1725
+ const model = parseManualModel(raw2);
1726
+ return model ? [model] : [];
1727
+ });
1728
+ }
1675
1729
  if (p.modelsCache && typeof p.modelsCache === "object") {
1676
1730
  const cache = p.modelsCache;
1677
1731
  if (typeof cache.fetchedAt === "string" && Array.isArray(cache.models)) {
@@ -1997,7 +2051,7 @@ var PROVIDER_TEMPLATES = [
1997
2051
  id: "venice",
1998
2052
  name: "Venice AI",
1999
2053
  authType: "api",
2000
- npm: "venice-ai-sdk-provider",
2054
+ npm: "@ai-sdk/openai-compatible",
2001
2055
  defaultBaseUrl: "https://api.venice.ai/api/v1",
2002
2056
  signupUrl: "https://venice.ai/settings/api",
2003
2057
  modelSource: "api-list",
@@ -2317,7 +2371,7 @@ async function withReasoningProviderOptions(model, providerOptions) {
2317
2371
  // interface; everything Core builds is a concrete current-spec model.
2318
2372
  model,
2319
2373
  middleware: {
2320
- specificationVersion: "v3",
2374
+ specificationVersion: "v4",
2321
2375
  transformParams: async ({ params }) => ({
2322
2376
  ...params,
2323
2377
  providerOptions: deepMergeProviderOptions(
@@ -2333,7 +2387,7 @@ async function withRequestHeaders(model, headers) {
2333
2387
  return wrapLanguageModel2({
2334
2388
  model,
2335
2389
  middleware: {
2336
- specificationVersion: "v3",
2390
+ specificationVersion: "v4",
2337
2391
  transformParams: async ({ params }) => ({
2338
2392
  ...params,
2339
2393
  headers: mergeHeaders(
@@ -2451,7 +2505,7 @@ function listRelayModels(registryPath) {
2451
2505
  const descriptors = [];
2452
2506
  for (const provider of registry.providers) {
2453
2507
  if (!provider.enabled) continue;
2454
- for (const model of provider.modelsCache?.models ?? []) {
2508
+ for (const model of getProviderModels(provider)) {
2455
2509
  descriptors.push(toDescriptor(provider, model, favorites));
2456
2510
  }
2457
2511
  }
@@ -3821,7 +3875,7 @@ function findRoute(registry, providerId, modelId, routeId) {
3821
3875
  if (!provider.enabled) {
3822
3876
  throw new RelayCoreError("PROVIDER_DISABLED", `Provider "${provider.name}" is disabled \u2014 enable it in relay-ai ui.`, { providerId, routeId });
3823
3877
  }
3824
- const model = provider.modelsCache?.models.find((m) => m.id === modelId);
3878
+ const model = getProviderModels(provider).find((m) => m.id === modelId);
3825
3879
  if (!model) {
3826
3880
  throw new RelayCoreError("UNSUPPORTED_MODEL", `Provider "${provider.name}" has no cached model "${modelId}" \u2014 refresh its models in relay-ai ui.`, { providerId, routeId });
3827
3881
  }