proxitor 0.9.0-beta.6 → 0.9.0-beta.8

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
@@ -258,25 +258,29 @@ By default, OpenRouter doesn't enable prompt caching — every request pays full
258
258
 
259
259
  **`cacheControl`** — injects `cache_control: { "type": "ephemeral" }` into the request body. OpenRouter uses this to set cache breakpoints and advance them as conversations grow.
260
260
 
261
- **`cacheControlTtl`** controls the cache time-to-live. Anthropic's default TTL is 5 minutes (300s). Set to `1h` for a 1-hour cache at higher write cost ( vs 1.25×). Only applies to Anthropic models other providers don't support TTL.
261
+ **`cacheControlTtl`** (`5m` / `1h` / `omit` / `skip`, default absent = passthrough) controls the `ttl` field on injected `cache_control` (Anthropic endpoints only). TTL only has effect when caching is active (`cacheControl` is `auto`/`always`); it is now set independently of the cache mode in the editor.
262
262
 
263
263
  **`sessionId`** — injects `session_id` for provider sticky routing. Without it, OpenRouter only pins to a provider after detecting a cache hit. With it, routing sticks from the **first request** — critical for OpenAI models where delayed caching means 0 cached tokens on the first 1-2 requests.
264
264
 
265
- Both `cacheControl` and `sessionId` support `auto` / `always` / `never` modes:
265
+ Both `cacheControl` and `sessionId` support `auto` / `always` / `skip` modes:
266
266
 
267
267
  | Mode | `cacheControl` | `sessionId` |
268
268
  | --- | --- | --- |
269
269
  | `auto` (default) | Anthropic models on `/v1/chat/completions`; all models on `/v1/messages` and `/v1/responses` | Passthrough client session ID if present; otherwise generate proxy UUID |
270
270
  | `always` | All models, all endpoints | Always generate proxy session ID, ignoring client-provided |
271
- | `never` | Disabled | Don't manage session headers pass through as-is |
271
+ | `skip` | Passthrough: leave the client's `cache_control` untouched and inject nothing | Passthrough: leave client session headers untouched |
272
272
 
273
273
  `cacheControlTtl` values:
274
274
 
275
275
  | Value | TTL | Write cost | Use when |
276
276
  | --- | --- | --- | --- |
277
- | _(not set)_ | 5 min (Anthropic default) | 1.25× | High-frequency requests (>1 per 5 min) |
278
- | `5m` | 5 minutes | 1.25× | Explicit short cache |
277
+ | _(absent)_ | Passthrough: preserve client `ttl`, add nothing; per-model absent inherits the global TTL | — | Default |
278
+ | `5m` | 5 minutes (Anthropic default) | 1.25× | Explicit short cache; high-frequency requests (>1 per 5 min) |
279
279
  | `1h` | 1 hour | 2.0× | Low-frequency or long-running sessions |
280
+ | `omit` | Strip the `ttl` field, guaranteeing no TTL (even one sent by the client) | — | Force-disable TTL |
281
+ | `skip` | Passthrough: preserve the client's `ttl`, add nothing, ignore an inherited value | — | Ignore global TTL without stripping |
282
+
283
+ > **Note:** `null` (previously accepted in model overrides to cancel an inherited TTL) is **removed** — migrate to `skip`. `null` was undocumented and unsettable from the UI.
280
284
 
281
285
  ```yaml
282
286
  cacheControl: auto # safe default — Anthropic and safe endpoints only
@@ -288,13 +292,13 @@ cacheControlTtl: 1h
288
292
  # Force caching for all models (may cause 400 on non-Anthropic /v1/chat/completions)
289
293
  # cacheControl: always
290
294
 
291
- # Per-model overrides — TTL supports '5m', '1h', or null (cancel global TTL)
295
+ # Per-model overrides — TTL supports '5m', '1h', 'omit', or 'skip' (passthrough)
292
296
  modelOverrides:
293
297
  "gpt-*":
294
- cacheControl: never # OpenAI caches automatically, no injection needed
298
+ cacheControl: skip # OpenAI caches automatically, no injection needed
295
299
  sessionId: always # but sticky routing still helps
296
300
  "claude-opus-*":
297
- cacheControlTtl: null # cancel global 1h TTL for Opus — use Anthropic's 5 min default
301
+ cacheControlTtl: skip # passthrough for Opus — ignore the global 1h TTL, use the client ttl
298
302
  ```
299
303
 
300
304
  **Why all three matter:**
@@ -362,7 +366,7 @@ If a config already exists, the wizard shows its location and asks whether to re
362
366
 
363
367
  - **Show current config** — display the resolved configuration
364
368
  - **API key & connection** — change API key, port, listen address, base URL, auth type
365
- - **Session routing** — set global `sessionId` mode (`auto` / `always` / `never`)
369
+ - **Session routing** — set global `sessionId` mode (`auto` / `always` / `skip`)
366
370
  - **Cache control** — set global `cacheControl` mode and TTL
367
371
  - **Model overrides** — add, edit, remove, list, or browse models
368
372
 
@@ -386,6 +390,8 @@ proxitor doctor --offline # skip network checks
386
390
 
387
391
  When adding or editing a model override, you can also configure per-model `sessionId` and `cacheControl` — useful for models that need different caching or routing behavior than the global default.
388
392
 
393
+ In `config edit`, any field (provider, session ID, cache control, cache TTL) can be reset to inherit the global/default value via the **Reset / inherit** prompt option. The global `config cache-control` and `config session-routing` commands support the same reset — it reverts the field to the schema default.
394
+
389
395
  ### Add override walkthrough
390
396
 
391
397
  ```sh
package/dist/cli.mjs CHANGED
@@ -8369,7 +8369,6 @@ const string$2 = (params) => {
8369
8369
  const integer = /^-?\d+$/;
8370
8370
  const number$2 = /^-?\d+(?:\.\d+)?$/;
8371
8371
  const boolean$1 = /^(?:true|false)$/i;
8372
- const _null$2 = /^null$/i;
8373
8372
  const lowercase = /^[^A-Z]*$/;
8374
8373
  const uppercase = /^[^a-z]*$/;
8375
8374
  //#endregion
@@ -9182,22 +9181,6 @@ const $ZodBoolean = /*@__PURE__*/ $constructor("$ZodBoolean", (inst, def) => {
9182
9181
  return payload;
9183
9182
  };
9184
9183
  });
9185
- const $ZodNull = /*@__PURE__*/ $constructor("$ZodNull", (inst, def) => {
9186
- $ZodType.init(inst, def);
9187
- inst._zod.pattern = _null$2;
9188
- inst._zod.values = new Set([null]);
9189
- inst._zod.parse = (payload, _ctx) => {
9190
- const input = payload.value;
9191
- if (input === null) return payload;
9192
- payload.issues.push({
9193
- expected: "null",
9194
- code: "invalid_type",
9195
- input,
9196
- inst
9197
- });
9198
- return payload;
9199
- };
9200
- });
9201
9184
  const $ZodUnknown = /*@__PURE__*/ $constructor("$ZodUnknown", (inst, def) => {
9202
9185
  $ZodType.init(inst, def);
9203
9186
  inst._zod.parse = (payload) => payload;
@@ -10346,13 +10329,6 @@ function _boolean(Class, params) {
10346
10329
  });
10347
10330
  }
10348
10331
  // @__NO_SIDE_EFFECTS__
10349
- function _null$1(Class, params) {
10350
- return new Class({
10351
- type: "null",
10352
- ...normalizeParams(params)
10353
- });
10354
- }
10355
- // @__NO_SIDE_EFFECTS__
10356
10332
  function _unknown(Class) {
10357
10333
  return new Class({ type: "unknown" });
10358
10334
  }
@@ -10901,13 +10877,6 @@ const numberProcessor = (schema, ctx, _json, _params) => {
10901
10877
  const booleanProcessor = (_schema, _ctx, json, _params) => {
10902
10878
  json.type = "boolean";
10903
10879
  };
10904
- const nullProcessor = (_schema, ctx, json, _params) => {
10905
- if (ctx.target === "openapi-3.0") {
10906
- json.type = "string";
10907
- json.nullable = true;
10908
- json.enum = [null];
10909
- } else json.type = "null";
10910
- };
10911
10880
  const neverProcessor = (_schema, _ctx, json, _params) => {
10912
10881
  json.not = {};
10913
10882
  };
@@ -11577,14 +11546,6 @@ const ZodBoolean = /*@__PURE__*/ $constructor("ZodBoolean", (inst, def) => {
11577
11546
  function boolean(params) {
11578
11547
  return /* @__PURE__ */ _boolean(ZodBoolean, params);
11579
11548
  }
11580
- const ZodNull = /*@__PURE__*/ $constructor("ZodNull", (inst, def) => {
11581
- $ZodNull.init(inst, def);
11582
- ZodType.init(inst, def);
11583
- inst._zod.processJSONSchema = (ctx, json, params) => nullProcessor(inst, ctx, json, params);
11584
- });
11585
- function _null(params) {
11586
- return /* @__PURE__ */ _null$1(ZodNull, params);
11587
- }
11588
11549
  const ZodUnknown = /*@__PURE__*/ $constructor("ZodUnknown", (inst, def) => {
11589
11550
  $ZodUnknown.init(inst, def);
11590
11551
  ZodType.init(inst, def);
@@ -11992,13 +11953,19 @@ const providerConfigSchema = object({
11992
11953
  const triStateSchema = _enum([
11993
11954
  "auto",
11994
11955
  "always",
11995
- "never"
11956
+ "skip"
11957
+ ]);
11958
+ const ttlSchema = _enum([
11959
+ "5m",
11960
+ "1h",
11961
+ "omit",
11962
+ "skip"
11996
11963
  ]);
11997
11964
  const modelOverrideSchema = object({
11998
11965
  provider: providerConfigSchema.optional(),
11999
11966
  headers: record(string$1(), string$1()).optional(),
12000
11967
  cacheControl: triStateSchema.optional(),
12001
- cacheControlTtl: union([_enum(["5m", "1h"]), _null()]).optional(),
11968
+ cacheControlTtl: ttlSchema.optional(),
12002
11969
  sessionId: triStateSchema.optional()
12003
11970
  }).strict();
12004
11971
  const proxyConfigSchema = object({
@@ -12015,7 +11982,7 @@ const proxyConfigSchema = object({
12015
11982
  attributionTitle: string$1().min(1).default("proxitor"),
12016
11983
  headers: record(string$1(), string$1()).optional(),
12017
11984
  cacheControl: triStateSchema.default("auto"),
12018
- cacheControlTtl: _enum(["5m", "1h"]).optional(),
11985
+ cacheControlTtl: ttlSchema.optional(),
12019
11986
  sessionId: triStateSchema.default("auto"),
12020
11987
  modelOverrides: record(string$1().min(1), modelOverrideSchema).optional()
12021
11988
  }).strict();
@@ -12171,7 +12138,7 @@ function applyOverride(result, override) {
12171
12138
  ...override.headers
12172
12139
  };
12173
12140
  if (override.cacheControl !== void 0) result.cacheControl = override.cacheControl;
12174
- if (override.cacheControlTtl !== void 0) result.cacheControlTtl = override.cacheControlTtl ?? void 0;
12141
+ if (override.cacheControlTtl !== void 0) result.cacheControlTtl = override.cacheControlTtl;
12175
12142
  if (override.sessionId !== void 0) result.sessionId = override.sessionId;
12176
12143
  }
12177
12144
  /** Reject base URLs ending in /v1 — paths are forwarded as-is, so /v1 suffix causes doubled paths. */
@@ -20259,85 +20226,113 @@ async function askHost(current) {
20259
20226
  const SESSION_HINTS = {
20260
20227
  auto: "Passthrough client ID, generate if missing",
20261
20228
  always: "Always generate proxy session ID",
20262
- never: "Don't manage session headers"
20229
+ skip: "Passthrough leave client session headers as-is"
20263
20230
  };
20264
20231
  /** Shared hint texts for cache control tri-state — used in add, edit, cache-control. */
20265
20232
  const CACHE_HINTS = {
20266
20233
  auto: "Anthropic models only",
20267
20234
  always: "All models",
20268
- never: "Off"
20235
+ skip: "Passthrough — leave client cache_control headers as-is"
20269
20236
  };
20270
- async function askTriState(message, current, hints) {
20271
- const result = await select({
20237
+ async function askTriState(message, current, hints, opts) {
20238
+ const options = [
20239
+ {
20240
+ value: "auto",
20241
+ label: "auto",
20242
+ hint: hints.auto
20243
+ },
20244
+ {
20245
+ value: "always",
20246
+ label: "always",
20247
+ hint: hints.always
20248
+ },
20249
+ {
20250
+ value: "skip",
20251
+ label: "skip",
20252
+ hint: hints.skip
20253
+ }
20254
+ ];
20255
+ if (opts?.removable) options.push({
20256
+ value: "reset",
20257
+ label: "Reset / inherit",
20258
+ hint: "Remove override"
20259
+ });
20260
+ return await select({
20272
20261
  message,
20273
20262
  initialValue: current ?? "auto",
20274
- options: [
20275
- {
20276
- value: "auto",
20277
- label: "auto",
20278
- hint: hints.auto
20279
- },
20280
- {
20281
- value: "always",
20282
- label: "always",
20283
- hint: hints.always
20284
- },
20285
- {
20286
- value: "never",
20287
- label: "never",
20288
- hint: hints.never
20289
- }
20290
- ]
20263
+ options
20291
20264
  });
20292
- if (isCancel(result)) return null;
20293
- return result;
20294
20265
  }
20295
- async function askCacheControlTtl(current) {
20296
- const options = [{
20297
- value: "5m",
20298
- label: "5 minutes",
20299
- hint: "Anthropic default"
20300
- }, {
20301
- value: "1h",
20302
- label: "1 hour",
20303
- hint: "Higher write cost"
20304
- }];
20305
- if (current) options.push({
20266
+ async function askCacheControlTtl(current, opts) {
20267
+ const inherit = opts?.globalTtl === void 0 ? "inherit global (none)" : `inherit global (${opts.globalTtl})`;
20268
+ const overrides = opts?.globalTtl === void 0 ? "overrides inherited" : `overrides global ${opts.globalTtl}`;
20269
+ const options = [
20270
+ {
20271
+ value: "5m",
20272
+ label: "5 minutes",
20273
+ hint: "Anthropic default"
20274
+ },
20275
+ {
20276
+ value: "1h",
20277
+ label: "1 hour",
20278
+ hint: "Higher write cost"
20279
+ },
20280
+ {
20281
+ value: "skip",
20282
+ label: "Passthrough",
20283
+ hint: `Preserve client ttl, ${overrides}`
20284
+ },
20285
+ {
20286
+ value: "omit",
20287
+ label: "Strip",
20288
+ hint: `Guarantee no ttl (${overrides})`
20289
+ }
20290
+ ];
20291
+ if (opts?.removable) options.push({
20306
20292
  value: "reset",
20307
- label: "Reset to default",
20308
- hint: "Remove TTL override"
20293
+ label: "Reset / inherit",
20294
+ hint: inherit
20309
20295
  });
20310
- const result = await select({
20296
+ return await select({
20311
20297
  message: "Cache TTL",
20312
20298
  initialValue: current ?? "5m",
20313
20299
  options
20314
20300
  });
20315
- if (isCancel(result)) return null;
20316
- if (result === "reset") return "reset";
20317
- return result;
20318
20301
  }
20319
20302
  //#endregion
20320
20303
  //#region src/commands/config/tri-state.ts
20321
- async function collectSessionTriState(currentSid) {
20322
- const sid = await askTriState("Session ID mode", currentSid ?? "auto", SESSION_HINTS);
20323
- if (sid === null) return null;
20324
- return { sessionId: sid };
20304
+ /** Apply a resolved field: {value}→assign, {remove}→delete, undefined→keep. */
20305
+ function applyField(obj, key, field) {
20306
+ if (field === void 0) return;
20307
+ if ("remove" in field) delete obj[key];
20308
+ else obj[key] = field.value;
20325
20309
  }
20326
- /**
20327
- * TTL cancel behaviour: pressing Escape on the TTL prompt preserves the
20328
- * existing TTL rather than silently dropping it.
20329
- */
20330
- async function collectCacheTriState(currentCc, currentTtl) {
20331
- const cc = await askTriState("Cache control mode", currentCc ?? "auto", CACHE_HINTS);
20332
- if (cc === null) return null;
20333
- const result = { cacheControl: cc };
20334
- if (cc !== "never") {
20335
- const ttl = await askCacheControlTtl(currentTtl ?? void 0);
20336
- if (ttl === null) {
20337
- if (currentTtl) result.cacheControlTtl = currentTtl;
20338
- } else if (ttl !== "reset") result.cacheControlTtl = ttl;
20339
- }
20340
- return result;
20310
+ async function collectSessionTriState(currentSid) {
20311
+ const sid = await askTriState("Session ID mode", currentSid ?? "auto", SESSION_HINTS, { removable: true });
20312
+ if (typeof sid === "symbol") return null;
20313
+ if (sid === "reset") return { sessionId: { remove: true } };
20314
+ return { sessionId: { value: sid } };
20315
+ }
20316
+ /** TTL is independent of cache mode. Mode-cancel aborts; TTL-cancel keeps existing TTL. */
20317
+ async function collectCacheTriState(currentCc, currentTtl, globalTtl) {
20318
+ const cc = await askTriState("Cache control mode", currentCc ?? "auto", CACHE_HINTS, { removable: true });
20319
+ if (typeof cc === "symbol") return null;
20320
+ let cacheControl;
20321
+ if (cc === "reset") cacheControl = { remove: true };
20322
+ else cacheControl = { value: cc };
20323
+ const ttl = await askCacheControlTtl(currentTtl, {
20324
+ removable: true,
20325
+ globalTtl
20326
+ });
20327
+ if (typeof ttl === "symbol") return { cacheControl };
20328
+ if (ttl === "reset") return {
20329
+ cacheControl,
20330
+ cacheControlTtl: { remove: true }
20331
+ };
20332
+ return {
20333
+ cacheControl,
20334
+ cacheControlTtl: { value: ttl }
20335
+ };
20341
20336
  }
20342
20337
  //#endregion
20343
20338
  //#region src/commands/config/add.ts
@@ -20457,7 +20452,7 @@ async function collectSession(override) {
20457
20452
  });
20458
20453
  if (isCancel(want) || !want) return override;
20459
20454
  const result = await collectSessionTriState();
20460
- if (result) override.sessionId = result.sessionId;
20455
+ if (result && !("remove" in result.sessionId)) override.sessionId = result.sessionId.value;
20461
20456
  return override;
20462
20457
  }
20463
20458
  async function collectCache(override) {
@@ -20468,8 +20463,8 @@ async function collectCache(override) {
20468
20463
  if (isCancel(want) || !want) return override;
20469
20464
  const result = await collectCacheTriState();
20470
20465
  if (result) {
20471
- override.cacheControl = result.cacheControl;
20472
- if (result.cacheControlTtl) override.cacheControlTtl = result.cacheControlTtl;
20466
+ if (!("remove" in result.cacheControl)) override.cacheControl = result.cacheControl.value;
20467
+ if (result.cacheControlTtl && !("remove" in result.cacheControlTtl)) override.cacheControlTtl = result.cacheControlTtl.value;
20473
20468
  }
20474
20469
  return override;
20475
20470
  }
@@ -20610,6 +20605,20 @@ function formatOverrideHint(override) {
20610
20605
  if (override.headers) parts.push(`${Object.keys(override.headers).length} header(s)`);
20611
20606
  return parts.join(", ") || "(empty)";
20612
20607
  }
20608
+ function formatCacheHint(cc, ttl) {
20609
+ let ttlLabel = ttl ?? "";
20610
+ if (ttl === "omit") ttlLabel = "ttl strip";
20611
+ else if (ttl === "skip") ttlLabel = "ttl passthrough";
20612
+ return [cc, ttlLabel].filter(Boolean).join(", ") || "(inherit)";
20613
+ }
20614
+ function readGlobalTtl(configPath) {
20615
+ if (!configPath) return void 0;
20616
+ try {
20617
+ return readConfigFile(configPath).cacheControlTtl;
20618
+ } catch {
20619
+ return;
20620
+ }
20621
+ }
20613
20622
  function showCurrentConfig(modelKey, current) {
20614
20623
  log.info(`Current config for "${modelKey}":`);
20615
20624
  if (current.provider) for (const [field, value] of Object.entries(current.provider)) log.info(` provider.${field}: ${JSON.stringify(value)}`);
@@ -20638,21 +20647,19 @@ async function editProvider(modelKey, current, client) {
20638
20647
  async function editSessionId(current) {
20639
20648
  const result = await collectSessionTriState(current.sessionId);
20640
20649
  if (result === null) return current;
20641
- const { sessionId: _, ...rest } = current;
20642
- return {
20643
- ...rest,
20644
- sessionId: result.sessionId
20645
- };
20650
+ const next = { ...current };
20651
+ applyField(next, "sessionId", result.sessionId);
20652
+ return next;
20646
20653
  }
20647
20654
  /** @internal */
20648
- async function editCacheControl(current) {
20649
- const result = await collectCacheTriState(current.cacheControl, current.cacheControlTtl);
20655
+ async function editCacheControl(current, configPath) {
20656
+ const globalTtl = readGlobalTtl(configPath);
20657
+ const result = await collectCacheTriState(current.cacheControl, current.cacheControlTtl, globalTtl);
20650
20658
  if (result === null) return current;
20651
- const { cacheControl: _cc, cacheControlTtl: _ttl, ...rest } = current;
20652
- return {
20653
- ...rest,
20654
- ...result
20655
- };
20659
+ const next = { ...current };
20660
+ applyField(next, "cacheControl", result.cacheControl);
20661
+ applyField(next, "cacheControlTtl", result.cacheControlTtl);
20662
+ return next;
20656
20663
  }
20657
20664
  /** Run the interactive "Edit model override" flow. */
20658
20665
  async function editOverrideCommand(client, configPath) {
@@ -20694,7 +20701,7 @@ async function editOverrideCommand(client, configPath) {
20694
20701
  {
20695
20702
  value: "cacheControl",
20696
20703
  label: "Cache control",
20697
- hint: [current.cacheControl, current.cacheControlTtl].filter(Boolean).join(", ") || "(inherit)"
20704
+ hint: formatCacheHint(current.cacheControl, current.cacheControlTtl)
20698
20705
  },
20699
20706
  {
20700
20707
  value: "done",
@@ -20711,7 +20718,7 @@ async function editOverrideCommand(client, configPath) {
20711
20718
  current = await editSessionId(current);
20712
20719
  break;
20713
20720
  case "cacheControl":
20714
- current = await editCacheControl(current);
20721
+ current = await editCacheControl(current, resolvedConfigPath);
20715
20722
  break;
20716
20723
  }
20717
20724
  }
@@ -21251,18 +21258,21 @@ async function cacheControlCommand(opts) {
21251
21258
  const currentTtl = cfg.cacheControlTtl;
21252
21259
  log.info(`Current: cacheControl = ${currentCc}`);
21253
21260
  if (currentTtl) log.info(`Current: cacheControlTtl = ${currentTtl}`);
21254
- const cc = await askTriState("Cache control mode", currentCc, CACHE_HINTS);
21255
- if (cc === null) return;
21256
- const fields = { cacheControl: cc };
21257
- if (cc !== "never") {
21258
- const ttlResult = await askCacheControlTtl(currentTtl);
21259
- if (ttlResult === null) return;
21260
- if (ttlResult === "reset") fields.cacheControlTtl = void 0;
21261
- else fields.cacheControlTtl = ttlResult;
21261
+ const cc = await askTriState("Cache control mode", currentCc, CACHE_HINTS, { removable: true });
21262
+ if (typeof cc === "symbol") return;
21263
+ const fields = {};
21264
+ fields.cacheControl = cc === "reset" ? void 0 : cc;
21265
+ const ttlResult = await askCacheControlTtl(currentTtl, { removable: true });
21266
+ if (typeof ttlResult === "symbol") {
21267
+ setGlobalConfigFields(configPath, fields);
21268
+ log.success(`cacheControl set to ${cc === "reset" ? "(default)" : cc}`);
21269
+ return;
21262
21270
  }
21271
+ fields.cacheControlTtl = ttlResult === "reset" ? void 0 : ttlResult;
21263
21272
  setGlobalConfigFields(configPath, fields);
21264
- const ttlPart = fields.cacheControlTtl ? `, TTL = ${fields.cacheControlTtl}` : "";
21265
- log.success(`cacheControl set to ${cc}${ttlPart}`);
21273
+ const ccLabel = cc === "reset" ? "(default)" : cc;
21274
+ const ttlLabel = ttlResult === "reset" ? "(default)" : ttlResult;
21275
+ log.success(`cacheControl set to ${ccLabel}, TTL = ${ttlLabel}`);
21266
21276
  }
21267
21277
  //#endregion
21268
21278
  //#region src/commands/config/connection.ts
@@ -21343,8 +21353,13 @@ async function sessionRoutingCommand(opts) {
21343
21353
  const configPath = requireConfigPath(opts?.configPath);
21344
21354
  const current = readConfigFile(configPath).sessionId ?? DEFAULTS.sessionId;
21345
21355
  log.info(`Current: sessionId = ${current}`);
21346
- const result = await askTriState("Session routing mode", current, SESSION_HINTS);
21347
- if (result === null) return;
21356
+ const result = await askTriState("Session routing mode", current, SESSION_HINTS, { removable: true });
21357
+ if (typeof result === "symbol") return;
21358
+ if (result === "reset") {
21359
+ setGlobalConfigField(configPath, "sessionId", void 0);
21360
+ log.success("sessionId reset to default (auto)");
21361
+ return;
21362
+ }
21348
21363
  setGlobalConfigField(configPath, "sessionId", result);
21349
21364
  log.success(`sessionId set to ${result}`);
21350
21365
  }
@@ -21457,7 +21472,7 @@ async function runConfigMenu(client) {
21457
21472
  }
21458
21473
  //#endregion
21459
21474
  //#region src/version.ts
21460
- const version = "0.9.0-beta.6";
21475
+ const version = "0.9.0-beta.8";
21461
21476
  //#endregion
21462
21477
  //#region src/commands/doctor.ts
21463
21478
  const DEFAULT_TIMEOUT_MS = 3e3;
@@ -24741,14 +24756,17 @@ function isAnthropicEndpoint(modelName, path) {
24741
24756
  return ANTHROPIC_NATIVE_ENDPOINTS.has(endpoint) || isAnthropicModel(modelName ?? "");
24742
24757
  }
24743
24758
  function shouldInjectCacheControl(mode, modelName, path) {
24744
- if (mode === "never") return false;
24759
+ if (mode === "skip") return false;
24745
24760
  if (mode === "always") return true;
24746
24761
  return isAnthropicEndpoint(modelName, path);
24747
24762
  }
24748
24763
  function buildCacheControl(existing, ttl, isAnthropic) {
24749
24764
  const base = existing !== null && typeof existing === "object" && !Array.isArray(existing) ? { ...existing } : {};
24750
24765
  if (!("type" in base)) base.type = "ephemeral";
24751
- if (ttl && isAnthropic) base.ttl = ttl;
24766
+ if (ttl === "omit") delete base.ttl;
24767
+ else if (ttl === "5m" || ttl === "1h") {
24768
+ if (isAnthropic) base.ttl = ttl;
24769
+ }
24752
24770
  return base;
24753
24771
  }
24754
24772
  //#endregion
@@ -24823,7 +24841,7 @@ function extractConversationFingerprint(parsedBody, path) {
24823
24841
  return hash.digest("hex");
24824
24842
  }
24825
24843
  function deriveSessionId(incomingHeaders, parsedBody, path, mode) {
24826
- if (mode === "never") return void 0;
24844
+ if (mode === "skip") return void 0;
24827
24845
  if (mode === "auto") {
24828
24846
  const fromHeader = incomingHeaders.get("x-claude-code-session-id");
24829
24847
  if (fromHeader) return fromHeader.slice(0, 256);