@jacobbd/relay-ai 0.11.0 → 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.11.0",
53
+ version: "0.11.1",
54
54
  publishConfig: {
55
55
  access: "public"
56
56
  },
@@ -156,7 +156,7 @@ var package_default = {
156
156
 
157
157
  // src/constants.ts
158
158
  var CODEX_RESPONSES_LITE_WS_URL = "wss://chatgpt.com/backend-api/codex/responses";
159
- var CODEX_RESPONSES_LITE_VERSION = "0.144.1";
159
+ var CODEX_RESPONSES_LITE_VERSION = "0.153.4";
160
160
  var CODEX_RESPONSES_WEBSOCKETS_BETA = "responses_websockets=2026-02-06";
161
161
  var OPENCODE_CACHE_PATH = join2(homedir2(), ".cache", "opencode", "models.json");
162
162
  var CODEX_SUBAGENT_MODEL_CAP = 1;
@@ -1623,6 +1623,51 @@ function isValidProviderId(id) {
1623
1623
  return PROVIDER_ID_PATTERN.test(id);
1624
1624
  }
1625
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
+
1626
1671
  // src/registry/io.ts
1627
1672
  var DIR_MODE = 448;
1628
1673
  var FILE_MODE = 384;
@@ -1675,6 +1720,12 @@ function parseProvider(raw) {
1675
1720
  provider.authType = p.authType;
1676
1721
  }
1677
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
+ }
1678
1729
  if (p.modelsCache && typeof p.modelsCache === "object") {
1679
1730
  const cache = p.modelsCache;
1680
1731
  if (typeof cache.fetchedAt === "string" && Array.isArray(cache.models)) {
@@ -2454,7 +2505,7 @@ function listRelayModels(registryPath) {
2454
2505
  const descriptors = [];
2455
2506
  for (const provider of registry.providers) {
2456
2507
  if (!provider.enabled) continue;
2457
- for (const model of provider.modelsCache?.models ?? []) {
2508
+ for (const model of getProviderModels(provider)) {
2458
2509
  descriptors.push(toDescriptor(provider, model, favorites));
2459
2510
  }
2460
2511
  }
@@ -3824,7 +3875,7 @@ function findRoute(registry, providerId, modelId, routeId) {
3824
3875
  if (!provider.enabled) {
3825
3876
  throw new RelayCoreError("PROVIDER_DISABLED", `Provider "${provider.name}" is disabled \u2014 enable it in relay-ai ui.`, { providerId, routeId });
3826
3877
  }
3827
- const model = provider.modelsCache?.models.find((m) => m.id === modelId);
3878
+ const model = getProviderModels(provider).find((m) => m.id === modelId);
3828
3879
  if (!model) {
3829
3880
  throw new RelayCoreError("UNSUPPORTED_MODEL", `Provider "${provider.name}" has no cached model "${modelId}" \u2014 refresh its models in relay-ai ui.`, { providerId, routeId });
3830
3881
  }