switchroom 0.19.34 → 0.19.35

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.
@@ -45183,8 +45183,37 @@ function registerStartInfoCommands(bot, deps) {
45183
45183
  init_rich_send();
45184
45184
  init_format();
45185
45185
 
45186
+ // ../src/config/thinking-effort-risk.ts
45187
+ var CLAUDE_CLI_THINKING_MERGE_FIX_VERSION = "2.1.156";
45188
+ var RISKY_EFFORTS = new Set(["medium", "high", "xhigh", "max"]);
45189
+ function isRiskyThinkingEffort(effort) {
45190
+ if (!effort)
45191
+ return false;
45192
+ return RISKY_EFFORTS.has(effort.trim().toLowerCase());
45193
+ }
45194
+ function isAdaptiveThinkingOpus(model) {
45195
+ if (!model)
45196
+ return false;
45197
+ const m = model.trim().toLowerCase();
45198
+ return m.startsWith("claude-opus-4");
45199
+ }
45200
+ function assessThinkingEffortRisk(model, effort) {
45201
+ if (!isRiskyThinkingEffort(effort))
45202
+ return { risky: false };
45203
+ if (!isAdaptiveThinkingOpus(model))
45204
+ return { risky: false };
45205
+ return {
45206
+ risky: true,
45207
+ reason: `thinking_effort '${effort}' on pinned Opus 4.x model '${model}' could trigger ` + `'400 thinking/redacted_thinking blocks cannot be modified' errors when work runs ` + `through concurrent sub-agents (issue #1978). The upstream claude-CLI fix shipped in ` + `${CLAUDE_CLI_THINKING_MERGE_FIX_VERSION}, but the Opus 4.x reproduction has not been ` + `re-tested since, so pin 'thinking_effort: low' or move the agent to a current Opus model.`
45208
+ };
45209
+ }
45210
+
45186
45211
  // gateway/model-command.ts
45187
45212
  var MODEL_ALIASES = ["opus", "sonnet", "haiku", "fable", "default"];
45213
+ var CLAUDE_MODEL_ALIASES = {
45214
+ opus48: "claude-opus-4-8",
45215
+ "opus-4-8": "claude-opus-4-8"
45216
+ };
45188
45217
  var MODEL_ARG_RE = /^[A-Za-z0-9][A-Za-z0-9._/\[\]-]{0,99}$/;
45189
45218
  function isValidModelArg(arg) {
45190
45219
  return MODEL_ARG_RE.test(arg);
@@ -45218,7 +45247,7 @@ function planModelCommand(parsed, ctx) {
45218
45247
  if (parsed.kind === "show" && ctx.menuEnabled)
45219
45248
  return { kind: "menu" };
45220
45249
  if (parsed.kind === "set" && isModelCommandBusy(ctx)) {
45221
- return { kind: "queue", target: expandSrAlias(parsed.model) };
45250
+ return { kind: "queue", target: expandModelAlias(parsed.model) };
45222
45251
  }
45223
45252
  return { kind: "apply", parsed };
45224
45253
  }
@@ -45227,12 +45256,22 @@ function modelCommandReceiptLine(agent, parsed, busy) {
45227
45256
  return `telegram gateway: gw /model received agent=${agent} kind=${parsed.kind} arg=${arg} busy=${busy}`;
45228
45257
  }
45229
45258
  var PERSIST_NOTE = "_A `/model` switch relaunches the session (~30s) on the chosen model. Session-only \u2014 reverts to the configured `model:` on the next restart. `/model default` reverts now. Live scrollback is replaced by a fresh session; memory and the handoff briefing carry the context. To change the default permanently, set `model:` in switchroom.yaml._";
45259
+ function claudeAliasHints(prefix) {
45260
+ const byTarget = new Map;
45261
+ for (const [alias, target] of Object.entries(CLAUDE_MODEL_ALIASES)) {
45262
+ const spellings = byTarget.get(target) ?? [];
45263
+ spellings.push(alias);
45264
+ byTarget.set(target, spellings);
45265
+ }
45266
+ return [...byTarget].map(([target, spellings]) => `${spellings.map((a) => `\`${prefix}${a}\``).join(" \u00b7 ")} \u2192 \`${target}\``).join("; ");
45267
+ }
45230
45268
  function helpText2(deps, reason) {
45231
45269
  const srAliasExamples = Object.keys(SR_MODEL_ALIASES).map((a) => `\`${a}\``).join(" \u00b7 ");
45270
+ const claudeAliasExamples = claudeAliasHints("");
45232
45271
  const lines = [];
45233
45272
  if (reason)
45234
45273
  lines.push(`\u26a0\ufe0f ${deps.escapeHtml(reason)}`);
45235
- lines.push("**/model** \u2014 show or switch the Claude model", "`/model` \u2014 show the configured model", `\`/model <name>\` \u2014 switch the live session (${MODEL_ALIASES.map((a) => `\`${a}\``).join(" \u00b7 ")} or a full model id)`, `_OpenRouter shortcuts:_ ${srAliasExamples}`, "_Every switch relaunches the session (~30s) on the chosen model \u2014 Claude and OpenRouter (sr-\\*) alike._", PERSIST_NOTE);
45274
+ lines.push("**/model** \u2014 show or switch the Claude model", "`/model` \u2014 show the configured model", `\`/model <name>\` \u2014 switch the live session (${MODEL_ALIASES.map((a) => `\`${a}\``).join(" \u00b7 ")} or a full model id)`, `_Pinned Claude shortcuts:_ ${claudeAliasExamples}`, `_OpenRouter shortcuts:_ ${srAliasExamples}`, "_Every switch relaunches the session (~30s) on the chosen model \u2014 Claude and OpenRouter (sr-\\*) alike._", PERSIST_NOTE);
45236
45275
  return { text: lines.join(`
45237
45276
  `), html: true };
45238
45277
  }
@@ -45248,6 +45287,7 @@ async function handleModelCommand(parsed, deps) {
45248
45287
  `**Model \u2014 ${deps.escapeHtml(deps.getAgentName())}**`,
45249
45288
  `Configured: \`${deps.escapeHtml(shown)}\``,
45250
45289
  `Switch the live session: ${MODEL_ALIASES.map((a) => `\`/model ${a}\``).join(" \u00b7 ")}`,
45290
+ `Pinned Claude shortcuts: ${claudeAliasHints("/model ")}`,
45251
45291
  `OpenRouter shortcuts: ${srAliasExamples}`,
45252
45292
  "or `/model <full-model-id>`",
45253
45293
  PERSIST_NOTE
@@ -45259,7 +45299,7 @@ async function handleModelCommand(parsed, deps) {
45259
45299
  if (!isValidModelArg(parsed.model)) {
45260
45300
  return helpText2(deps, `not a valid model name: ${parsed.model}`);
45261
45301
  }
45262
- const model = expandSrAlias(parsed.model);
45302
+ const model = expandModelAlias(parsed.model);
45263
45303
  if (deps.isBusy()) {
45264
45304
  return {
45265
45305
  text: "\u23f3 The agent is mid-turn \u2014 a model switch needs an idle session. The switch was not applied.",
@@ -45286,10 +45326,25 @@ function relaunchErrorReply(deps, model, err) {
45286
45326
  return { text: `\u274c Could not schedule model switch: ${deps.escapeHtml(msg)}`, html: true };
45287
45327
  }
45288
45328
  function unvalidatedIdCaveat(deps, model) {
45289
- if (!model.trim().toLowerCase().startsWith("claude-"))
45329
+ const lower = canonicalModelToken(model).toLowerCase();
45330
+ if (!lower.startsWith("claude-"))
45331
+ return null;
45332
+ if (Object.values(CLAUDE_MODEL_ALIASES).includes(lower))
45290
45333
  return null;
45291
45334
  return `_\`${deps.escapeHtml(model)}\` can't be validated before launch \u2014 if it isn't a real Claude model id, claude will silently serve the configured fallback model instead. I check the first reply and will warn if that happens._`;
45292
45335
  }
45336
+ function thinkingEffortCaveat(deps, model) {
45337
+ let effort;
45338
+ try {
45339
+ effort = deps.getConfiguredEffort();
45340
+ } catch {
45341
+ return null;
45342
+ }
45343
+ const risk = assessThinkingEffortRisk(model, effort ?? undefined);
45344
+ if (!risk.risky || !risk.reason)
45345
+ return null;
45346
+ return `\u26a0\ufe0f _${deps.escapeHtml(risk.reason)}_`;
45347
+ }
45293
45348
  async function scheduleRelaunchReply(deps, model, reason) {
45294
45349
  try {
45295
45350
  await deps.scheduleModelRelaunch(model, reason);
@@ -45297,8 +45352,14 @@ async function scheduleRelaunchReply(deps, model, reason) {
45297
45352
  return relaunchErrorReply(deps, model, err);
45298
45353
  }
45299
45354
  const caveat = unvalidatedIdCaveat(deps, model);
45355
+ const effortRisk = thinkingEffortCaveat(deps, model);
45300
45356
  return {
45301
- text: [switchingLine(deps, model), ...caveat ? [caveat] : [], PERSIST_NOTE].join(`
45357
+ text: [
45358
+ switchingLine(deps, model),
45359
+ ...caveat ? [caveat] : [],
45360
+ ...effortRisk ? [effortRisk] : [],
45361
+ PERSIST_NOTE
45362
+ ].join(`
45302
45363
  `),
45303
45364
  html: true
45304
45365
  };
@@ -45325,8 +45386,9 @@ var MODEL_CALLBACK_HEADER = "mdl:h";
45325
45386
  var MODEL_CALLBACK_ALIAS = "mdl:alias:";
45326
45387
  var MODEL_CALLBACK_PAGE_EXTERNAL = "mdl:page:ext";
45327
45388
  var MODEL_CALLBACK_PAGE_MAIN = "mdl:page:main";
45328
- var EXTRA_CLAUDE_ALIASES = [
45329
- { alias: "fable", label: "Fable" }
45389
+ var EXTRA_CLAUDE_MENU_TOKENS = [
45390
+ { token: "fable", label: "Fable" },
45391
+ { token: "claude-opus-4-8", label: "Opus 4.8" }
45330
45392
  ];
45331
45393
  var SR_MODEL_LABELS = {
45332
45394
  "sr-gemini-2.5-pro": "Gemini 2.5 Pro",
@@ -45368,6 +45430,17 @@ var SR_MODEL_ALIASES = {
45368
45430
  function expandSrAlias(arg) {
45369
45431
  return SR_MODEL_ALIASES[arg.toLowerCase()] ?? arg;
45370
45432
  }
45433
+ function canonicalModelToken(arg) {
45434
+ const trimmed = arg.trim();
45435
+ const lower = trimmed.toLowerCase();
45436
+ return lower.startsWith("claude-") ? lower : trimmed;
45437
+ }
45438
+ function expandClaudeAlias(arg) {
45439
+ return CLAUDE_MODEL_ALIASES[arg.trim().toLowerCase()] ?? arg;
45440
+ }
45441
+ function expandModelAlias(arg) {
45442
+ return canonicalModelToken(expandSrAlias(expandClaudeAlias(arg)));
45443
+ }
45371
45444
  function srFriendlyLabel(srName) {
45372
45445
  return SR_MODEL_LABELS[srName] ?? srName.replace(/^sr-/, "").replace(/-/g, " ");
45373
45446
  }
@@ -45409,6 +45482,11 @@ function busyStaticMenu(deps, page) {
45409
45482
  callback_data: `${MODEL_CALLBACK_ALIAS}${alias}`
45410
45483
  }]);
45411
45484
  }
45485
+ for (const { token, label } of EXTRA_CLAUDE_MENU_TOKENS) {
45486
+ if (MODEL_ALIASES.includes(token.toLowerCase()))
45487
+ continue;
45488
+ rows.push([{ text: label, callback_data: `${MODEL_CALLBACK_ALIAS}${token}` }]);
45489
+ }
45412
45490
  rows.push([{ text: "Default (configured)", callback_data: `${MODEL_CALLBACK_ALIAS}default` }]);
45413
45491
  if (externalNames.length > 0) {
45414
45492
  rows.push([{ text: "\uD83C\uDF10 External models \u25b8", callback_data: MODEL_CALLBACK_PAGE_EXTERNAL }]);
@@ -45445,11 +45523,11 @@ function mainPageKeyboard(claudeOptions, hasExternal) {
45445
45523
  callback_data: modelSelectCallbackData(o.label)
45446
45524
  }]);
45447
45525
  }
45448
- for (const { alias, label } of EXTRA_CLAUDE_ALIASES) {
45449
- const already = claudeOptions.some((o) => o.label.toLowerCase() === label.toLowerCase() || o.label.toLowerCase() === alias.toLowerCase());
45526
+ for (const { token, label } of EXTRA_CLAUDE_MENU_TOKENS) {
45527
+ const already = claudeOptions.some((o) => o.label.toLowerCase() === label.toLowerCase() || o.label.toLowerCase() === token.toLowerCase());
45450
45528
  if (already)
45451
45529
  continue;
45452
- rows.push([{ text: label, callback_data: `${MODEL_CALLBACK_ALIAS}${alias}` }]);
45530
+ rows.push([{ text: label, callback_data: `${MODEL_CALLBACK_ALIAS}${token}` }]);
45453
45531
  }
45454
45532
  if (hasExternal) {
45455
45533
  rows.push([{ text: "\uD83C\uDF10 External models \u25b8", callback_data: MODEL_CALLBACK_PAGE_EXTERNAL }]);
@@ -83497,6 +83575,10 @@ Allowed: \`${deps.escapeHtml(allow)}\``, { html: true });
83497
83575
 
83498
83576
  // gateway/model-command.ts
83499
83577
  var MODEL_ALIASES2 = ["opus", "sonnet", "haiku", "fable", "default"];
83578
+ var CLAUDE_MODEL_ALIASES2 = {
83579
+ opus48: "claude-opus-4-8",
83580
+ "opus-4-8": "claude-opus-4-8"
83581
+ };
83500
83582
  var MODEL_ARG_RE2 = /^[A-Za-z0-9][A-Za-z0-9._/\[\]-]{0,99}$/;
83501
83583
  function isValidModelArg2(arg) {
83502
83584
  return MODEL_ARG_RE2.test(arg);
@@ -83632,12 +83714,22 @@ function resolveStaleAwareBusy(input) {
83632
83714
  };
83633
83715
  }
83634
83716
  var PERSIST_NOTE3 = "_A `/model` switch relaunches the session (~30s) on the chosen model. Session-only \u2014 reverts to the configured `model:` on the next restart. `/model default` reverts now. Live scrollback is replaced by a fresh session; memory and the handoff briefing carry the context. To change the default permanently, set `model:` in switchroom.yaml._";
83717
+ function claudeAliasHints2(prefix) {
83718
+ const byTarget = new Map;
83719
+ for (const [alias, target] of Object.entries(CLAUDE_MODEL_ALIASES2)) {
83720
+ const spellings = byTarget.get(target) ?? [];
83721
+ spellings.push(alias);
83722
+ byTarget.set(target, spellings);
83723
+ }
83724
+ return [...byTarget].map(([target, spellings]) => `${spellings.map((a) => `\`${prefix}${a}\``).join(" \u00b7 ")} \u2192 \`${target}\``).join("; ");
83725
+ }
83635
83726
  function helpText4(deps, reason) {
83636
83727
  const srAliasExamples = Object.keys(SR_MODEL_ALIASES2).map((a) => `\`${a}\``).join(" \u00b7 ");
83728
+ const claudeAliasExamples = claudeAliasHints2("");
83637
83729
  const lines = [];
83638
83730
  if (reason)
83639
83731
  lines.push(`\u26a0\ufe0f ${deps.escapeHtml(reason)}`);
83640
- lines.push("**/model** \u2014 show or switch the Claude model", "`/model` \u2014 show the configured model", `\`/model <name>\` \u2014 switch the live session (${MODEL_ALIASES2.map((a) => `\`${a}\``).join(" \u00b7 ")} or a full model id)`, `_OpenRouter shortcuts:_ ${srAliasExamples}`, "_Every switch relaunches the session (~30s) on the chosen model \u2014 Claude and OpenRouter (sr-\\*) alike._", PERSIST_NOTE3);
83732
+ lines.push("**/model** \u2014 show or switch the Claude model", "`/model` \u2014 show the configured model", `\`/model <name>\` \u2014 switch the live session (${MODEL_ALIASES2.map((a) => `\`${a}\``).join(" \u00b7 ")} or a full model id)`, `_Pinned Claude shortcuts:_ ${claudeAliasExamples}`, `_OpenRouter shortcuts:_ ${srAliasExamples}`, "_Every switch relaunches the session (~30s) on the chosen model \u2014 Claude and OpenRouter (sr-\\*) alike._", PERSIST_NOTE3);
83641
83733
  return { text: lines.join(`
83642
83734
  `), html: true };
83643
83735
  }
@@ -83653,6 +83745,7 @@ async function handleModelCommand2(parsed, deps) {
83653
83745
  `**Model \u2014 ${deps.escapeHtml(deps.getAgentName())}**`,
83654
83746
  `Configured: \`${deps.escapeHtml(shown)}\``,
83655
83747
  `Switch the live session: ${MODEL_ALIASES2.map((a) => `\`/model ${a}\``).join(" \u00b7 ")}`,
83748
+ `Pinned Claude shortcuts: ${claudeAliasHints2("/model ")}`,
83656
83749
  `OpenRouter shortcuts: ${srAliasExamples}`,
83657
83750
  "or `/model <full-model-id>`",
83658
83751
  PERSIST_NOTE3
@@ -83664,7 +83757,7 @@ async function handleModelCommand2(parsed, deps) {
83664
83757
  if (!isValidModelArg2(parsed.model)) {
83665
83758
  return helpText4(deps, `not a valid model name: ${parsed.model}`);
83666
83759
  }
83667
- const model = expandSrAlias2(parsed.model);
83760
+ const model = expandModelAlias2(parsed.model);
83668
83761
  if (deps.isBusy()) {
83669
83762
  return {
83670
83763
  text: "\u23f3 The agent is mid-turn \u2014 a model switch needs an idle session. The switch was not applied.",
@@ -83691,10 +83784,25 @@ function relaunchErrorReply2(deps, model, err) {
83691
83784
  return { text: `\u274c Could not schedule model switch: ${deps.escapeHtml(msg)}`, html: true };
83692
83785
  }
83693
83786
  function unvalidatedIdCaveat2(deps, model) {
83694
- if (!model.trim().toLowerCase().startsWith("claude-"))
83787
+ const lower = canonicalModelToken2(model).toLowerCase();
83788
+ if (!lower.startsWith("claude-"))
83789
+ return null;
83790
+ if (Object.values(CLAUDE_MODEL_ALIASES2).includes(lower))
83695
83791
  return null;
83696
83792
  return `_\`${deps.escapeHtml(model)}\` can't be validated before launch \u2014 if it isn't a real Claude model id, claude will silently serve the configured fallback model instead. I check the first reply and will warn if that happens._`;
83697
83793
  }
83794
+ function thinkingEffortCaveat2(deps, model) {
83795
+ let effort;
83796
+ try {
83797
+ effort = deps.getConfiguredEffort();
83798
+ } catch {
83799
+ return null;
83800
+ }
83801
+ const risk = assessThinkingEffortRisk(model, effort ?? undefined);
83802
+ if (!risk.risky || !risk.reason)
83803
+ return null;
83804
+ return `\u26a0\ufe0f _${deps.escapeHtml(risk.reason)}_`;
83805
+ }
83698
83806
  async function scheduleRelaunchReply2(deps, model, reason) {
83699
83807
  try {
83700
83808
  await deps.scheduleModelRelaunch(model, reason);
@@ -83702,8 +83810,14 @@ async function scheduleRelaunchReply2(deps, model, reason) {
83702
83810
  return relaunchErrorReply2(deps, model, err);
83703
83811
  }
83704
83812
  const caveat = unvalidatedIdCaveat2(deps, model);
83813
+ const effortRisk = thinkingEffortCaveat2(deps, model);
83705
83814
  return {
83706
- text: [switchingLine2(deps, model), ...caveat ? [caveat] : [], PERSIST_NOTE3].join(`
83815
+ text: [
83816
+ switchingLine2(deps, model),
83817
+ ...caveat ? [caveat] : [],
83818
+ ...effortRisk ? [effortRisk] : [],
83819
+ PERSIST_NOTE3
83820
+ ].join(`
83707
83821
  `),
83708
83822
  html: true
83709
83823
  };
@@ -83731,8 +83845,9 @@ var MODEL_CALLBACK_HEADER2 = "mdl:h";
83731
83845
  var MODEL_CALLBACK_ALIAS2 = "mdl:alias:";
83732
83846
  var MODEL_CALLBACK_PAGE_EXTERNAL2 = "mdl:page:ext";
83733
83847
  var MODEL_CALLBACK_PAGE_MAIN2 = "mdl:page:main";
83734
- var EXTRA_CLAUDE_ALIASES2 = [
83735
- { alias: "fable", label: "Fable" }
83848
+ var EXTRA_CLAUDE_MENU_TOKENS2 = [
83849
+ { token: "fable", label: "Fable" },
83850
+ { token: "claude-opus-4-8", label: "Opus 4.8" }
83736
83851
  ];
83737
83852
  var SR_MODEL_LABELS2 = {
83738
83853
  "sr-gemini-2.5-pro": "Gemini 2.5 Pro",
@@ -83777,11 +83892,26 @@ function isOfflineTrustedModelToken(token) {
83777
83892
  return true;
83778
83893
  if (lower in SR_MODEL_ALIASES2)
83779
83894
  return true;
83780
- return Object.values(SR_MODEL_ALIASES2).includes(lower);
83895
+ if (Object.values(SR_MODEL_ALIASES2).includes(lower))
83896
+ return true;
83897
+ if (lower in CLAUDE_MODEL_ALIASES2)
83898
+ return true;
83899
+ return Object.values(CLAUDE_MODEL_ALIASES2).includes(lower);
83781
83900
  }
83782
83901
  function expandSrAlias2(arg) {
83783
83902
  return SR_MODEL_ALIASES2[arg.toLowerCase()] ?? arg;
83784
83903
  }
83904
+ function canonicalModelToken2(arg) {
83905
+ const trimmed = arg.trim();
83906
+ const lower = trimmed.toLowerCase();
83907
+ return lower.startsWith("claude-") ? lower : trimmed;
83908
+ }
83909
+ function expandClaudeAlias2(arg) {
83910
+ return CLAUDE_MODEL_ALIASES2[arg.trim().toLowerCase()] ?? arg;
83911
+ }
83912
+ function expandModelAlias2(arg) {
83913
+ return canonicalModelToken2(expandSrAlias2(expandClaudeAlias2(arg)));
83914
+ }
83785
83915
  function srFriendlyLabel2(srName) {
83786
83916
  return SR_MODEL_LABELS2[srName] ?? srName.replace(/^sr-/, "").replace(/-/g, " ");
83787
83917
  }
@@ -83834,6 +83964,11 @@ function busyStaticMenu2(deps, page) {
83834
83964
  callback_data: `${MODEL_CALLBACK_ALIAS2}${alias}`
83835
83965
  }]);
83836
83966
  }
83967
+ for (const { token, label } of EXTRA_CLAUDE_MENU_TOKENS2) {
83968
+ if (MODEL_ALIASES2.includes(token.toLowerCase()))
83969
+ continue;
83970
+ rows.push([{ text: label, callback_data: `${MODEL_CALLBACK_ALIAS2}${token}` }]);
83971
+ }
83837
83972
  rows.push([{ text: "Default (configured)", callback_data: `${MODEL_CALLBACK_ALIAS2}default` }]);
83838
83973
  if (externalNames.length > 0) {
83839
83974
  rows.push([{ text: "\uD83C\uDF10 External models \u25b8", callback_data: MODEL_CALLBACK_PAGE_EXTERNAL2 }]);
@@ -83870,11 +84005,11 @@ function mainPageKeyboard2(claudeOptions, hasExternal) {
83870
84005
  callback_data: modelSelectCallbackData2(o.label)
83871
84006
  }]);
83872
84007
  }
83873
- for (const { alias, label } of EXTRA_CLAUDE_ALIASES2) {
83874
- const already = claudeOptions.some((o) => o.label.toLowerCase() === label.toLowerCase() || o.label.toLowerCase() === alias.toLowerCase());
84008
+ for (const { token, label } of EXTRA_CLAUDE_MENU_TOKENS2) {
84009
+ const already = claudeOptions.some((o) => o.label.toLowerCase() === label.toLowerCase() || o.label.toLowerCase() === token.toLowerCase());
83875
84010
  if (already)
83876
84011
  continue;
83877
- rows.push([{ text: label, callback_data: `${MODEL_CALLBACK_ALIAS2}${alias}` }]);
84012
+ rows.push([{ text: label, callback_data: `${MODEL_CALLBACK_ALIAS2}${token}` }]);
83878
84013
  }
83879
84014
  if (hasExternal) {
83880
84015
  rows.push([{ text: "\uD83C\uDF10 External models \u25b8", callback_data: MODEL_CALLBACK_PAGE_EXTERNAL2 }]);
@@ -83973,6 +84108,7 @@ async function handleModelMenuCallback(data, deps) {
83973
84108
  if (!isValidModelArg2(token)) {
83974
84109
  return { answer: "Invalid model name", reply: await buildModelMenu2(deps) };
83975
84110
  }
84111
+ token = expandModelAlias2(token);
83976
84112
  if (!isRecognizedSwitchToken(token)) {
83977
84113
  return { answer: "Model list changed \u2014 menu refreshed", reply: await buildModelMenu2(deps) };
83978
84114
  }
@@ -84010,9 +84146,11 @@ async function menuRelaunchOutcome(deps, token, label) {
84010
84146
  };
84011
84147
  }
84012
84148
  const friendly = isDefault ? "the configured default" : label;
84149
+ const effortRisk = isDefault ? null : thinkingEffortCaveat2(deps, token);
84013
84150
  return {
84014
84151
  answer: `Switching to ${isDefault ? "default" : label} \u2014 relaunching (~30s)`,
84015
- reply: await menuWithBannerStatic(deps, `\uD83D\uDD04 Switching session to **${deps.escapeHtml(friendly)}** \u2014 relaunching (~30s).
84152
+ reply: await menuWithBannerStatic(deps, `\uD83D\uDD04 Switching session to **${deps.escapeHtml(friendly)}** \u2014 relaunching (~30s).${effortRisk ? `
84153
+ ${effortRisk}` : ""}
84016
84154
  ${PERSIST_NOTE3}`)
84017
84155
  };
84018
84156
  }
@@ -84586,12 +84724,15 @@ function pgMib(mib) {
84586
84724
  }
84587
84725
  var HINDSIGHT_PG_EFFECTIVE_CACHE_SIZE_ENV = "SWITCHROOM_HINDSIGHT_PG_EFFECTIVE_CACHE_SIZE";
84588
84726
  var HINDSIGHT_PG_SHARED_BUFFERS_ENV = "SWITCHROOM_HINDSIGHT_PG_SHARED_BUFFERS";
84727
+ var HINDSIGHT_PG_FSYNC_ENV = "SWITCHROOM_HINDSIGHT_PG_FSYNC";
84728
+ var HINDSIGHT_PG_DEFAULT_FSYNC = "on";
84589
84729
  var HINDSIGHT_PG_DEFAULTS = [
84590
84730
  [
84591
84731
  HINDSIGHT_PG_EFFECTIVE_CACHE_SIZE_ENV,
84592
84732
  pgMib(HINDSIGHT_PG_DEFAULT_EFFECTIVE_CACHE_SIZE_MIB)
84593
84733
  ],
84594
- [HINDSIGHT_PG_SHARED_BUFFERS_ENV, pgMib(HINDSIGHT_PG_DEFAULT_SHARED_BUFFERS_MIB)]
84734
+ [HINDSIGHT_PG_SHARED_BUFFERS_ENV, pgMib(HINDSIGHT_PG_DEFAULT_SHARED_BUFFERS_MIB)],
84735
+ [HINDSIGHT_PG_FSYNC_ENV, HINDSIGHT_PG_DEFAULT_FSYNC]
84595
84736
  ];
84596
84737
  var HINDSIGHT_PG_ENV_KEYS = new Set(HINDSIGHT_PG_DEFAULTS.map(([k]) => k));
84597
84738
 
@@ -99320,10 +99461,10 @@ function startOutboxSweep(deps) {
99320
99461
  }
99321
99462
 
99322
99463
  // ../src/build-info.ts
99323
- var VERSION2 = "0.19.34";
99324
- var COMMIT_SHA = "73a1b218";
99325
- var COMMIT_DATE = "2026-07-29T05:33:45Z";
99326
- var LATEST_PR = 3981;
99464
+ var VERSION2 = "0.19.35";
99465
+ var COMMIT_SHA = "76ae22ca";
99466
+ var COMMIT_DATE = "2026-07-30T01:27:21Z";
99467
+ var LATEST_PR = 4011;
99327
99468
  var COMMITS_AHEAD_OF_TAG = 0;
99328
99469
 
99329
99470
  // gateway/boot-version.ts
@@ -108836,6 +108977,7 @@ function buildModelDeps(restartCtx) {
108836
108977
  const data = switchroomExecJson(["agent", "list"]);
108837
108978
  return data?.agents?.find((a) => a.name === getMyAgentName())?.model ?? null;
108838
108979
  },
108980
+ getConfiguredEffort: () => getConfiguredEffortForPersist(),
108839
108981
  escapeHtml: escapeHtmlForTg2,
108840
108982
  preBlock,
108841
108983
  scheduleRestart: async (reason) => {
@@ -108986,7 +109128,7 @@ function persistQueuedCommandForRestart(action) {
108986
109128
  return `\u21A9\uFE0F Couldn\u2019t verify \`${escapeHtmlForTg2(action.cmd.targetLabel || action.arg)}\` as a known model without the live session \u2014 it was NOT saved. Re-issue \`/model ${escapeHtmlForTg2(action.arg)}\` once the agent is back.`;
108987
109129
  }
108988
109130
  const configured = readConfiguredDefaultModel(agentDir) ?? resolveMainModel(undefined);
108989
- writeSessionModelFile(agentDir, expandSrAlias2(action.arg), configured);
109131
+ writeSessionModelFile(agentDir, expandModelAlias2(action.arg), configured);
108990
109132
  break;
108991
109133
  }
108992
109134
  case "clear-model":
@@ -564,7 +564,7 @@ import {
564
564
  MODEL_CALLBACK_PAGE_EXTERNAL,
565
565
  MODEL_CALLBACK_PAGE_MAIN,
566
566
  srFriendlyLabel,
567
- expandSrAlias,
567
+ expandModelAlias,
568
568
  isSrModel,
569
569
  isBusyRefusalText,
570
570
  isOfflineTrustedModelToken,
@@ -16961,6 +16961,9 @@ function buildModelDeps(restartCtx?: ModelDepsRestartContext): ModelMenuDeps & M
16961
16961
  const data = switchroomExecJson<AgentListResp>(['agent', 'list'])
16962
16962
  return data?.agents?.find(a => a.name === getMyAgentName())?.model ?? null
16963
16963
  },
16964
+ // Feeds the switch-time #1978 assessment (thinkingEffortCaveat); see the
16965
+ // ModelCommandDeps.getConfiguredEffort doc for why doctor can't make it.
16966
+ getConfiguredEffort: () => getConfiguredEffortForPersist(),
16964
16967
  escapeHtml: escapeHtmlForTg,
16965
16968
  preBlock,
16966
16969
  /**
@@ -17259,7 +17262,7 @@ function persistQueuedCommandForRestart(action: ShutdownResolutionAction): strin
17259
17262
  const configured =
17260
17263
  readConfiguredDefaultModel(agentDir) ?? resolveMainModel(undefined)
17261
17264
  // Consume-once carrier: applied by the next boot, then reverts.
17262
- writeSessionModelFile(agentDir, expandSrAlias(action.arg), configured)
17265
+ writeSessionModelFile(agentDir, expandModelAlias(action.arg), configured)
17263
17266
  break
17264
17267
  }
17265
17268
  case 'clear-model':