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.
- package/dist/auth-broker/index.js +7 -1
- package/dist/cli/switchroom.js +334 -42
- package/dist/host-control/main.js +8 -2
- package/dist/vault/approvals/kernel-server.js +7 -1
- package/dist/vault/broker/server.js +7 -1
- package/package.json +1 -1
- package/telegram-plugin/dist/gateway/gateway.js +169 -27
- package/telegram-plugin/gateway/gateway.ts +5 -2
- package/telegram-plugin/gateway/model-command.ts +245 -23
- package/telegram-plugin/tests/model-command.test.ts +415 -4
- package/vendor/hindsight-memory/scripts/subagent_retain.py +103 -7
- package/vendor/hindsight-memory/scripts/tests/test_subagent_retain_learnings.py +377 -0
|
@@ -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:
|
|
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 =
|
|
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
|
-
|
|
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: [
|
|
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
|
|
45329
|
-
{
|
|
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 {
|
|
45449
|
-
const already = claudeOptions.some((o) => o.label.toLowerCase() === label.toLowerCase() || o.label.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}${
|
|
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 =
|
|
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
|
-
|
|
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: [
|
|
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
|
|
83735
|
-
{
|
|
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
|
-
|
|
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 {
|
|
83874
|
-
const already = claudeOptions.some((o) => o.label.toLowerCase() === label.toLowerCase() || o.label.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}${
|
|
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.
|
|
99324
|
-
var COMMIT_SHA = "
|
|
99325
|
-
var COMMIT_DATE = "2026-07-
|
|
99326
|
-
var LATEST_PR =
|
|
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,
|
|
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
|
-
|
|
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,
|
|
17265
|
+
writeSessionModelFile(agentDir, expandModelAlias(action.arg), configured)
|
|
17263
17266
|
break
|
|
17264
17267
|
}
|
|
17265
17268
|
case 'clear-model':
|