@jacobbd/relay-ai 0.6.2 → 0.6.3

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 CHANGED
@@ -17,9 +17,9 @@
17
17
 
18
18
  📺 **Watch the Demos**
19
19
 
20
- | **Claude Code / Cowork / Desktop** | **Codex CLI & Desktop App** | **Gemini CLI** | **v0.4.1: UI & Antigravity** |
21
- |:---:|:---:|:---:|:---:|
22
- | [![Claude Demo](https://img.youtube.com/vi/IvsUPHLhX0o/mqdefault.jpg)](https://youtu.be/IvsUPHLhX0o) | [![Codex Demo](https://img.youtube.com/vi/42oiOB8IAu4/mqdefault.jpg)](https://youtu.be/42oiOB8IAu4) | [![Gemini Demo](https://img.youtube.com/vi/g7JKvqOHJl4/mqdefault.jpg)](https://www.youtube.com/watch?v=g7JKvqOHJl4) | [![UI & Antigravity Demo](https://img.youtube.com/vi/8vXJ0LfpdoY/mqdefault.jpg)](https://www.youtube.com/watch?v=8vXJ0LfpdoY) |
20
+ | **Claude Code / Cowork / Desktop** | **Codex CLI & Desktop App** | **Gemini CLI** | **v0.4.1: UI & Antigravity** | **Server Gateway** |
21
+ |:---:|:---:|:---:|:---:|:---:|
22
+ | [![Claude Demo](https://img.youtube.com/vi/IvsUPHLhX0o/mqdefault.jpg)](https://youtu.be/IvsUPHLhX0o) | [![Codex Demo](https://img.youtube.com/vi/42oiOB8IAu4/mqdefault.jpg)](https://youtu.be/42oiOB8IAu4) | [![Gemini Demo](https://img.youtube.com/vi/g7JKvqOHJl4/mqdefault.jpg)](https://www.youtube.com/watch?v=g7JKvqOHJl4) | [![UI & Antigravity Demo](https://img.youtube.com/vi/8vXJ0LfpdoY/mqdefault.jpg)](https://www.youtube.com/watch?v=8vXJ0LfpdoY) | [![Server Gateway Demo](https://img.youtube.com/vi/4CEw0MQUE9I/mqdefault.jpg)](https://www.youtube.com/watch?v=4CEw0MQUE9I) |
23
23
 
24
24
  **relay-ai** is an interactive CLI — and now a **visual launcher** — that connects AI coding tools to any provider and runs local API gateways on your machine. It supports **Claude Code**, **Claude Desktop (Cowork + Code)**, the **OpenAI Codex CLI**, the **ChatGPT desktop app in Codex mode (macOS + Windows)**, **Google Gemini CLI**, and experimental **Antigravity CLI / IDE** support.
25
25
 
@@ -455,8 +455,9 @@ Launch **Claude Desktop** (macOS or Windows) with registry providers:
455
455
  relay-ai claude-app
456
456
  ```
457
457
 
458
- This command automates the "Third-Party Inference" (Developer Mode) setup. It temporarily configures Claude Desktop to point at a local gateway, launches the app, and routes traffic to your chosen provider.
458
+ This command automates the "Third-Party Inference" (Developer Mode) setup. It temporarily configures Claude Desktop to point at a local gateway, launches the app, and exposes the selected model followed by your available saved favorites (up to 20 models total).
459
459
 
460
+ - **Selected + favorites:** The selected model is listed first; duplicates and unavailable favorites are skipped. Claude Desktop ultimately controls which discovered model it activates initially.
460
461
  - **Keep the terminal open:** The proxy runs in the foreground.
461
462
  - **Ctrl+C to restore:** When you're done, press `Ctrl+C` in the terminal to automatically restore Claude Desktop to its normal Anthropic cloud mode.
462
463
  - **Cleanup:** If the terminal crashes, run `relay-ai claude-app --restore`.
@@ -11,7 +11,7 @@ import { join } from "path";
11
11
  // package.json
12
12
  var package_default = {
13
13
  name: "@jacobbd/relay-ai",
14
- version: "0.6.2",
14
+ version: "0.6.3",
15
15
  publishConfig: {
16
16
  access: "public"
17
17
  },
@@ -46,7 +46,7 @@ var package_default = {
46
46
  node: ">=18"
47
47
  },
48
48
  scripts: {
49
- build: "tsup && mkdir -p dist/ui/public && cp -r src/ui/public/. dist/ui/public/",
49
+ build: "tsup && node scripts/copy-ui-assets.mjs",
50
50
  dev: "tsup --watch",
51
51
  test: "vitest run",
52
52
  "test:watch": "vitest",
@@ -139,6 +139,14 @@ var CONFLICTING_ENV_VARS = [
139
139
  "ANTHROPIC_DEFAULT_SONNET_MODEL",
140
140
  "ANTHROPIC_DEFAULT_HAIKU_MODEL"
141
141
  ];
142
+ var PARENT_SESSION_ENV_VARS = [
143
+ "CLAUDECODE",
144
+ "CLAUDE_CODE_CHILD_SESSION",
145
+ "CLAUDE_CODE_SESSION_ID",
146
+ "CLAUDE_CODE_HOST_SESSION_ID",
147
+ "CLAUDE_CODE_ENTRYPOINT",
148
+ "CLAUDE_PID"
149
+ ];
142
150
  var OPENCODE_CACHE_PATH = join(homedir(), ".cache", "opencode", "models.json");
143
151
  var MAX_MODEL_CATALOG = 20;
144
152
  var VERTEX_ANTHROPIC_NPM = "@ai-sdk/google-vertex/anthropic";
@@ -3045,6 +3053,9 @@ function buildChildEnv(baseUrl, model, apiKey, proxyPort, contextWindow, enableG
3045
3053
  for (const name of CONFLICTING_ENV_VARS) {
3046
3054
  delete env[name];
3047
3055
  }
3056
+ for (const name of PARENT_SESSION_ENV_VARS) {
3057
+ delete env[name];
3058
+ }
3048
3059
  env["ANTHROPIC_BASE_URL"] = proxyPort ? `http://127.0.0.1:${proxyPort}` : baseUrl;
3049
3060
  env["ANTHROPIC_API_KEY"] = apiKey;
3050
3061
  const bareModel = stripOneMContextSuffix(model);
@@ -4243,7 +4254,7 @@ function maskGatewayModelId(aliasId) {
4243
4254
  // src/server/models.ts
4244
4255
  var CREATED_AT_ISO = "2025-01-01T00:00:00Z";
4245
4256
  var CREATED_AT_UNIX = 1735689600;
4246
- function formatAnthropicModelEntry(id, displayName, contextWindow) {
4257
+ function formatAnthropicModelEntry(id, displayName, contextWindow, options) {
4247
4258
  const maxInput = resolveContextWindow(id, contextWindow);
4248
4259
  return {
4249
4260
  id,
@@ -4251,12 +4262,18 @@ function formatAnthropicModelEntry(id, displayName, contextWindow) {
4251
4262
  display_name: displayName,
4252
4263
  created_at: CREATED_AT_ISO,
4253
4264
  context_window: maxInput,
4254
- max_input_tokens: maxInput
4265
+ max_input_tokens: maxInput,
4266
+ ...options?.supportsOneM !== void 0 ? { supports_1m: options.supportsOneM } : {}
4255
4267
  };
4256
4268
  }
4257
4269
  function formatAnthropicModelList(entries) {
4258
4270
  return {
4259
- data: entries.map((entry) => formatAnthropicModelEntry(entry.id, entry.name, entry.contextWindow)),
4271
+ data: entries.map((entry) => formatAnthropicModelEntry(
4272
+ entry.id,
4273
+ entry.name,
4274
+ entry.contextWindow,
4275
+ { supportsOneM: entry.supportsOneM }
4276
+ )),
4260
4277
  has_more: false,
4261
4278
  first_id: entries[0]?.id ?? null,
4262
4279
  last_id: entries.at(-1)?.id ?? null
@@ -4282,22 +4299,28 @@ function openAiExposedId(model, collisions) {
4282
4299
  return collisions.has(model.id) ? `${gatewayProviderId(model)}/${model.id}` : model.id;
4283
4300
  }
4284
4301
  function exposedGatewayAliasId(model, opts) {
4285
- const alias = gatewayAliasId(model);
4286
- return opts?.maskGatewayIds ? maskGatewayModelId(alias) : alias;
4302
+ const singleOneM = usesSingleOneMEntry(model, opts);
4303
+ const alias = gatewayAliasId(singleOneM ? { ...model, id: stripOneMContextSuffix(model.id) } : model);
4304
+ const exposed = opts?.maskGatewayIds ? maskGatewayModelId(alias) : alias;
4305
+ return singleOneM ? `${stripOneMContextSuffix(exposed)}[1m]` : exposed;
4287
4306
  }
4288
4307
  function gatewayDisplayName(model, opts) {
4289
- if (!opts?.maskGatewayIds) return model.name;
4290
- return `${model.name} (${gatewayProviderLabel(model)})`;
4308
+ const name = opts?.maskGatewayIds ? `${model.name} (${gatewayProviderLabel(model)})` : model.name;
4309
+ return usesSingleOneMEntry(model, opts) && !/\b1m$/i.test(name) ? `${name} 1M` : name;
4291
4310
  }
4292
4311
  function formatGatewayAnthropicModels(models, opts) {
4293
4312
  return formatAnthropicModelList(
4294
4313
  models.map((model) => ({
4295
4314
  id: exposedGatewayAliasId(model, opts),
4296
4315
  name: gatewayDisplayName(model, opts),
4297
- contextWindow: model.contextWindow
4316
+ contextWindow: model.contextWindow,
4317
+ supportsOneM: usesSingleOneMEntry(model, opts) ? false : void 0
4298
4318
  }))
4299
4319
  );
4300
4320
  }
4321
+ function usesSingleOneMEntry(model, opts) {
4322
+ return opts?.longContextDisplay === "single-1m" && resolveContextWindow(stripOneMContextSuffix(model.id), model.contextWindow) >= 1e6;
4323
+ }
4301
4324
  function createGatewayModelCatalog(models, opts) {
4302
4325
  const byId = /* @__PURE__ */ new Map();
4303
4326
  const collisions = openAiIdCollisions(models);
@@ -4307,8 +4330,23 @@ function createGatewayModelCatalog(models, opts) {
4307
4330
  if (scopedId !== model.id) byId.set(scopedId, model);
4308
4331
  const alias = exposedGatewayAliasId(model, opts);
4309
4332
  if (alias !== model.id) byId.set(alias, model);
4333
+ const singleOneM = usesSingleOneMEntry(model, opts);
4334
+ if (singleOneM) {
4335
+ const bareModel = { ...model, id: stripOneMContextSuffix(model.id) };
4336
+ const rawBareAlias = gatewayAliasId(bareModel);
4337
+ const exposedBareAlias = opts?.maskGatewayIds ? maskGatewayModelId(rawBareAlias) : rawBareAlias;
4338
+ for (const compatibleId of [
4339
+ stripOneMContextSuffix(model.id),
4340
+ rawBareAlias,
4341
+ `${rawBareAlias}[1m]`,
4342
+ exposedBareAlias,
4343
+ `${exposedBareAlias}[1m]`
4344
+ ]) {
4345
+ byId.set(compatibleId, model);
4346
+ }
4347
+ }
4310
4348
  if (opts?.maskGatewayIds) {
4311
- const rawAlias = gatewayAliasId(model);
4349
+ const rawAlias = gatewayAliasId(singleOneM ? { ...model, id: stripOneMContextSuffix(model.id) } : model);
4312
4350
  if (rawAlias !== alias) byId.set(rawAlias, model);
4313
4351
  }
4314
4352
  }
@@ -10679,6 +10717,8 @@ function winLocalAppData2() {
10679
10717
  function winClaudeExeCandidates() {
10680
10718
  const local = winLocalAppData2();
10681
10719
  const bases = [
10720
+ // Squirrel install folder used by the Anthropic Claude desktop installer.
10721
+ join12(local, "AnthropicClaude"),
10682
10722
  join12(local, "Programs", "Claude"),
10683
10723
  join12(local, "Claude")
10684
10724
  ];
@@ -11063,4 +11103,4 @@ export {
11063
11103
  supportsClaudeTransparentMode,
11064
11104
  buildHttpProxyRoutes
11065
11105
  };
11066
- //# sourceMappingURL=chunk-I3I5LKZI.js.map
11106
+ //# sourceMappingURL=chunk-WHEMJ7C3.js.map