switchroom 0.15.44 → 0.15.45
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/cli/switchroom.js
CHANGED
|
@@ -15016,6 +15016,40 @@ var init_loader = __esm(() => {
|
|
|
15016
15016
|
};
|
|
15017
15017
|
});
|
|
15018
15018
|
|
|
15019
|
+
// src/config/users.ts
|
|
15020
|
+
function resolveUsers(config, agentName) {
|
|
15021
|
+
const users = config.users ?? {};
|
|
15022
|
+
const agentRaw = config.agents?.[agentName];
|
|
15023
|
+
const agentConfig = agentRaw ? resolveAgentConfig(config.defaults, config.profiles, agentRaw) : undefined;
|
|
15024
|
+
const uniq = (xs) => [...new Set(xs)];
|
|
15025
|
+
const serves = uniq([
|
|
15026
|
+
...config.defaults?.serves ?? [],
|
|
15027
|
+
...agentConfig?.serves ?? []
|
|
15028
|
+
]);
|
|
15029
|
+
const knows = uniq([
|
|
15030
|
+
...config.defaults?.knows ?? [],
|
|
15031
|
+
...agentConfig?.knows ?? []
|
|
15032
|
+
]);
|
|
15033
|
+
const senderBanks = {};
|
|
15034
|
+
for (const userName of serves) {
|
|
15035
|
+
const u = users[userName];
|
|
15036
|
+
if (!u)
|
|
15037
|
+
continue;
|
|
15038
|
+
for (const id of u.telegram_ids) {
|
|
15039
|
+
senderBanks[id] = u.profile_bank;
|
|
15040
|
+
}
|
|
15041
|
+
}
|
|
15042
|
+
Object.assign(senderBanks, agentConfig?.memory?.recall?.sender_banks ?? {});
|
|
15043
|
+
const additionalBanks = uniq([
|
|
15044
|
+
...knows.map((entry) => users[entry]?.profile_bank ?? entry),
|
|
15045
|
+
...agentConfig?.memory?.recall?.additional_banks ?? []
|
|
15046
|
+
]);
|
|
15047
|
+
return { senderBanks, additionalBanks };
|
|
15048
|
+
}
|
|
15049
|
+
var init_users = __esm(() => {
|
|
15050
|
+
init_merge();
|
|
15051
|
+
});
|
|
15052
|
+
|
|
15019
15053
|
// src/memory/hindsight.ts
|
|
15020
15054
|
function generateHindsightMcpConfig(collection, memoryConfig) {
|
|
15021
15055
|
const url = memoryConfig.config?.url ?? "http://localhost:8888/mcp/";
|
|
@@ -15031,6 +15065,27 @@ function getCollectionForAgent(agentName, config) {
|
|
|
15031
15065
|
const agentConfig = config.agents[agentName];
|
|
15032
15066
|
return agentConfig?.memory?.collection ?? agentName;
|
|
15033
15067
|
}
|
|
15068
|
+
function collectProfileBanks(config, opts = {}) {
|
|
15069
|
+
const { excludeAgentCollections = true } = opts;
|
|
15070
|
+
const banks = new Set;
|
|
15071
|
+
for (const user of Object.values(config.users ?? {})) {
|
|
15072
|
+
if (user.profile_bank)
|
|
15073
|
+
banks.add(user.profile_bank);
|
|
15074
|
+
}
|
|
15075
|
+
for (const agentName of Object.keys(config.agents)) {
|
|
15076
|
+
const { senderBanks, additionalBanks } = resolveUsers(config, agentName);
|
|
15077
|
+
for (const b of Object.values(senderBanks))
|
|
15078
|
+
banks.add(b);
|
|
15079
|
+
for (const b of additionalBanks)
|
|
15080
|
+
banks.add(b);
|
|
15081
|
+
}
|
|
15082
|
+
if (excludeAgentCollections) {
|
|
15083
|
+
for (const agentName of Object.keys(config.agents)) {
|
|
15084
|
+
banks.delete(getCollectionForAgent(agentName, config));
|
|
15085
|
+
}
|
|
15086
|
+
}
|
|
15087
|
+
return banks;
|
|
15088
|
+
}
|
|
15034
15089
|
function isStrictIsolation(agentName, config) {
|
|
15035
15090
|
const agentConfig = config.agents[agentName];
|
|
15036
15091
|
return agentConfig?.memory?.isolation === "strict";
|
|
@@ -15460,6 +15515,7 @@ async function addMemoryTag(apiUrl, bankId, memoryId, tag, opts) {
|
|
|
15460
15515
|
}
|
|
15461
15516
|
var DEFAULT_RETAIN_MISSION, DEMOTE_FROM_RECALL_TAG = "[demote-from-recall]";
|
|
15462
15517
|
var init_hindsight = __esm(() => {
|
|
15518
|
+
init_users();
|
|
15463
15519
|
DEFAULT_RETAIN_MISSION = "Extract user preferences, ongoing projects, recurring commitments, " + "important context, and durable facts that should help across future " + "conversations. Skip one-off chatter and temporary task noise.";
|
|
15464
15520
|
});
|
|
15465
15521
|
|
|
@@ -32964,9 +33020,14 @@ async function checkBankIngestHealth(config, url, opts) {
|
|
|
32964
33020
|
const bankId = agentConfig.memory?.collection ?? agentName;
|
|
32965
33021
|
banks.set(bankId, [...banks.get(bankId) ?? [], agentName]);
|
|
32966
33022
|
}
|
|
33023
|
+
const profileBanks = collectProfileBanks(config);
|
|
33024
|
+
for (const bank of profileBanks) {
|
|
33025
|
+
if (!banks.has(bank))
|
|
33026
|
+
banks.set(bank, []);
|
|
33027
|
+
}
|
|
32967
33028
|
const inspected = await Promise.all([...banks].map(async ([bankId, agents]) => [bankId, agents, await inspectBankHealth(url, bankId, { fetchImpl: opts?.fetchImpl })]));
|
|
32968
33029
|
for (const [bankId, agents, h] of inspected) {
|
|
32969
|
-
const label = `bank ${bankId}` + (agents[0] !== bankId ? ` (${agents.join(", ")})` : "");
|
|
33030
|
+
const label = `bank ${bankId}` + (profileBanks.has(bankId) ? " (profile)" : agents[0] !== bankId ? ` (${agents.join(", ")})` : "");
|
|
32970
33031
|
if (!h.ok) {
|
|
32971
33032
|
results.push({
|
|
32972
33033
|
name: label,
|
|
@@ -50803,8 +50864,8 @@ import { existsSync, readFileSync } from "node:fs";
|
|
|
50803
50864
|
import { dirname, join } from "node:path";
|
|
50804
50865
|
|
|
50805
50866
|
// src/build-info.ts
|
|
50806
|
-
var VERSION = "0.15.
|
|
50807
|
-
var COMMIT_SHA = "
|
|
50867
|
+
var VERSION = "0.15.45";
|
|
50868
|
+
var COMMIT_SHA = "41082e8b";
|
|
50808
50869
|
|
|
50809
50870
|
// src/cli/resolve-version.ts
|
|
50810
50871
|
function readPackageVersion() {
|
|
@@ -50935,40 +50996,7 @@ var LEGACY_CRON_SCRIPT_BASENAME_RE = /^cron-(\d+)\.sh$/;
|
|
|
50935
50996
|
init_schema();
|
|
50936
50997
|
init_cron_routing();
|
|
50937
50998
|
init_tier_selector();
|
|
50938
|
-
|
|
50939
|
-
// src/config/users.ts
|
|
50940
|
-
init_merge();
|
|
50941
|
-
function resolveUsers(config, agentName) {
|
|
50942
|
-
const users = config.users ?? {};
|
|
50943
|
-
const agentRaw = config.agents?.[agentName];
|
|
50944
|
-
const agentConfig = agentRaw ? resolveAgentConfig(config.defaults, config.profiles, agentRaw) : undefined;
|
|
50945
|
-
const uniq = (xs) => [...new Set(xs)];
|
|
50946
|
-
const serves = uniq([
|
|
50947
|
-
...config.defaults?.serves ?? [],
|
|
50948
|
-
...agentConfig?.serves ?? []
|
|
50949
|
-
]);
|
|
50950
|
-
const knows = uniq([
|
|
50951
|
-
...config.defaults?.knows ?? [],
|
|
50952
|
-
...agentConfig?.knows ?? []
|
|
50953
|
-
]);
|
|
50954
|
-
const senderBanks = {};
|
|
50955
|
-
for (const userName of serves) {
|
|
50956
|
-
const u = users[userName];
|
|
50957
|
-
if (!u)
|
|
50958
|
-
continue;
|
|
50959
|
-
for (const id of u.telegram_ids) {
|
|
50960
|
-
senderBanks[id] = u.profile_bank;
|
|
50961
|
-
}
|
|
50962
|
-
}
|
|
50963
|
-
Object.assign(senderBanks, agentConfig?.memory?.recall?.sender_banks ?? {});
|
|
50964
|
-
const additionalBanks = uniq([
|
|
50965
|
-
...knows.map((entry) => users[entry]?.profile_bank ?? entry),
|
|
50966
|
-
...agentConfig?.memory?.recall?.additional_banks ?? []
|
|
50967
|
-
]);
|
|
50968
|
-
return { senderBanks, additionalBanks };
|
|
50969
|
-
}
|
|
50970
|
-
|
|
50971
|
-
// src/agents/scaffold.ts
|
|
50999
|
+
init_users();
|
|
50972
51000
|
init_merge();
|
|
50973
51001
|
init_timezone();
|
|
50974
51002
|
|
|
@@ -53738,15 +53766,6 @@ ${body}
|
|
|
53738
53766
|
}).catch((err) => {
|
|
53739
53767
|
console.warn(` ${source_default.yellow("\u26a0")} Bank mission update error for ${formatAgentBankLabel(name, hindsightBankId)}: ${err}`);
|
|
53740
53768
|
});
|
|
53741
|
-
ensureUserProfileMentalModel(apiUrl, hindsightBankId, { timeoutMs: 5000 }).then((result) => {
|
|
53742
|
-
if (result.ok) {
|
|
53743
|
-
console.log(` ${source_default.green("\u2713")} User-profile Mental Model ready for ${formatAgentBankLabel(name, hindsightBankId)}`);
|
|
53744
|
-
} else {
|
|
53745
|
-
console.warn(` ${source_default.yellow("\u26a0")} Failed to create user-profile MM for ${formatAgentBankLabel(name, hindsightBankId)}: ${result.reason}`);
|
|
53746
|
-
}
|
|
53747
|
-
}).catch((err) => {
|
|
53748
|
-
console.warn(` ${source_default.yellow("\u26a0")} User-profile MM error for ${formatAgentBankLabel(name, hindsightBankId)}: ${err}`);
|
|
53749
|
-
});
|
|
53750
53769
|
});
|
|
53751
53770
|
}
|
|
53752
53771
|
for (const f of rewrittenWithBackup) {
|
|
@@ -53802,14 +53821,6 @@ function buildSettingsHooksBlock(p) {
|
|
|
53802
53821
|
async: true
|
|
53803
53822
|
});
|
|
53804
53823
|
}
|
|
53805
|
-
if (hindsightEnabled) {
|
|
53806
|
-
stopHooks.push({
|
|
53807
|
-
type: "command",
|
|
53808
|
-
command: wrap("hook:user-profile-refresh", `bash "${join10(DOCKER_BIN_PATH, "user-profile-refresh-hook.sh")}"`),
|
|
53809
|
-
timeout: 10,
|
|
53810
|
-
async: true
|
|
53811
|
-
});
|
|
53812
|
-
}
|
|
53813
53824
|
if (useSwitchroomPlugin) {
|
|
53814
53825
|
stopHooks.push({
|
|
53815
53826
|
type: "command",
|
|
@@ -54682,15 +54693,6 @@ ${body}
|
|
|
54682
54693
|
console.warn(` ${source_default.yellow("\u26a0")} Bank mission update error for ${formatAgentBankLabel(name, hindsightBankId)}: ${err}`);
|
|
54683
54694
|
});
|
|
54684
54695
|
}
|
|
54685
|
-
ensureUserProfileMentalModel(apiUrl, hindsightBankId, { timeoutMs: 5000 }).then((result) => {
|
|
54686
|
-
if (result.ok) {
|
|
54687
|
-
console.log(` ${source_default.green("\u2713")} User-profile Mental Model ready for ${formatAgentBankLabel(name, hindsightBankId)}`);
|
|
54688
|
-
} else {
|
|
54689
|
-
console.warn(` ${source_default.yellow("\u26a0")} Failed to create user-profile MM for ${formatAgentBankLabel(name, hindsightBankId)}: ${result.reason}`);
|
|
54690
|
-
}
|
|
54691
|
-
}).catch((err) => {
|
|
54692
|
-
console.warn(` ${source_default.yellow("\u26a0")} User-profile MM error for ${formatAgentBankLabel(name, hindsightBankId)}: ${err}`);
|
|
54693
|
-
});
|
|
54694
54696
|
});
|
|
54695
54697
|
}
|
|
54696
54698
|
return {
|
|
@@ -69340,6 +69342,26 @@ Searching all eligible collections:
|
|
|
69340
69342
|
console.log(` ${row}`);
|
|
69341
69343
|
}
|
|
69342
69344
|
console.log();
|
|
69345
|
+
const profileBanks = collectProfileBanks(config);
|
|
69346
|
+
if (profileBanks.size > 0) {
|
|
69347
|
+
const owners = new Map;
|
|
69348
|
+
for (const [uname, u] of Object.entries(config.users ?? {})) {
|
|
69349
|
+
if (u.profile_bank) {
|
|
69350
|
+
owners.set(u.profile_bank, [
|
|
69351
|
+
...owners.get(u.profile_bank) ?? [],
|
|
69352
|
+
uname
|
|
69353
|
+
]);
|
|
69354
|
+
}
|
|
69355
|
+
}
|
|
69356
|
+
console.log(source_default.bold(` Profile banks (per-user / shared):
|
|
69357
|
+
`));
|
|
69358
|
+
for (const bank of [...profileBanks].sort()) {
|
|
69359
|
+
const who = owners.get(bank);
|
|
69360
|
+
const label = who ? `user: ${who.join(", ")}` : "shared";
|
|
69361
|
+
console.log(` ${bank.padEnd(widths[1])} ${source_default.gray(label)}`);
|
|
69362
|
+
}
|
|
69363
|
+
console.log();
|
|
69364
|
+
}
|
|
69343
69365
|
console.log(source_default.bold(` Hindsight CLI commands:
|
|
69344
69366
|
`));
|
|
69345
69367
|
for (const name of agentNames) {
|
|
@@ -75702,6 +75724,11 @@ async function handleGetMemoryHealth(config, opts) {
|
|
|
75702
75724
|
const bank = getCollectionForAgent(agentName, config);
|
|
75703
75725
|
banks.set(bank, [...banks.get(bank) ?? [], agentName]);
|
|
75704
75726
|
}
|
|
75727
|
+
const profileBankSet = collectProfileBanks(config);
|
|
75728
|
+
for (const bank of profileBankSet) {
|
|
75729
|
+
if (!banks.has(bank))
|
|
75730
|
+
banks.set(bank, []);
|
|
75731
|
+
}
|
|
75705
75732
|
const rows = await Promise.all([...banks].map(async ([bank, agents]) => {
|
|
75706
75733
|
const h = await inspectBankHealth(url, bank, { fetchImpl: opts?.fetchImpl });
|
|
75707
75734
|
const gaps = recentUnextracted(h.unextractedDocuments, 30, now);
|
|
@@ -75746,7 +75773,8 @@ async function handleGetMemoryHealth(config, opts) {
|
|
|
75746
75773
|
staleMentalModelCount: stale.length,
|
|
75747
75774
|
corruptedMentalModelNames: corrupted.map((m) => m.name),
|
|
75748
75775
|
status,
|
|
75749
|
-
statusDetail
|
|
75776
|
+
statusDetail,
|
|
75777
|
+
kind: profileBankSet.has(bank) ? "profile" : "agent"
|
|
75750
75778
|
};
|
|
75751
75779
|
}));
|
|
75752
75780
|
rows.sort((a, b) => a.bank.localeCompare(b.bank));
|
|
@@ -75760,7 +75788,7 @@ function isKnownBank(config, bank) {
|
|
|
75760
75788
|
if (getCollectionForAgent(agentName, config) === bank)
|
|
75761
75789
|
return true;
|
|
75762
75790
|
}
|
|
75763
|
-
return
|
|
75791
|
+
return collectProfileBanks(config).has(bank);
|
|
75764
75792
|
}
|
|
75765
75793
|
async function handleMemoryReprocess(config, body, deps) {
|
|
75766
75794
|
const bank = typeof body.bank === "string" ? body.bank : "";
|
package/dist/cli/ui/index.html
CHANGED
|
@@ -898,7 +898,7 @@
|
|
|
898
898
|
return `<div class="agent-card">
|
|
899
899
|
<div class="card-header" style="cursor:default">
|
|
900
900
|
${statusDot(b.status)}<span class="agent-name">${escapeHtml(b.bank)}</span>
|
|
901
|
-
<span style="color:var(--text-dim);font-size:.85em;margin-left:.5rem">${escapeHtml((b.agents || []).join(', '))}</span>
|
|
901
|
+
<span style="color:var(--text-dim);font-size:.85em;margin-left:.5rem">${b.kind === 'profile' ? '<em>profile bank</em>' : escapeHtml((b.agents || []).join(', '))}</span>
|
|
902
902
|
</div>
|
|
903
903
|
<div style="padding:0 1.25rem 1rem">
|
|
904
904
|
<div style="color:var(--text-dim);margin:.1rem 0 .3rem">${escapeHtml(b.statusDetail || '')}</div>
|
|
@@ -13133,6 +13133,9 @@ function getNonce(db, request_id) {
|
|
|
13133
13133
|
import { createHash } from "node:crypto";
|
|
13134
13134
|
init_merge();
|
|
13135
13135
|
|
|
13136
|
+
// src/config/users.ts
|
|
13137
|
+
init_merge();
|
|
13138
|
+
|
|
13136
13139
|
// src/memory/hindsight.ts
|
|
13137
13140
|
var DEFAULT_RETAIN_MISSION = "Extract user preferences, ongoing projects, recurring commitments, " + "important context, and durable facts that should help across future " + "conversations. Skip one-off chatter and temporary task noise.";
|
|
13138
13141
|
|
|
@@ -12677,6 +12677,9 @@ function identify(socketPath, socket, execFileSyncOverride) {
|
|
|
12677
12677
|
return { uid, pid, exe, systemdUnit };
|
|
12678
12678
|
}
|
|
12679
12679
|
|
|
12680
|
+
// src/config/users.ts
|
|
12681
|
+
init_merge();
|
|
12682
|
+
|
|
12680
12683
|
// src/memory/hindsight.ts
|
|
12681
12684
|
var DEFAULT_RETAIN_MISSION = "Extract user preferences, ongoing projects, recurring commitments, " + "important context, and durable facts that should help across future " + "conversations. Skip one-off chatter and temporary task noise.";
|
|
12682
12685
|
|
package/package.json
CHANGED
|
@@ -61,10 +61,10 @@ Hindsight is a memory bank with semantic search, knowledge graph, entity resolut
|
|
|
61
61
|
- `mcp__hindsight__retain` — store a new memory. The plugin automatically retains the conversation transcript every ~10 turns via the Stop hook, so you usually don't need this. Call manually for significant decisions, corrections, or facts you want immediately searchable.
|
|
62
62
|
- `mcp__hindsight__reflect` — Hindsight's LLM-powered "answer this query using the bank's content + directives". Use when the user asks a question that requires synthesis across multiple past memories.
|
|
63
63
|
|
|
64
|
-
### Mental Models
|
|
65
|
-
A mental model is a pre-computed semantic summary backed by reflection over the bank
|
|
64
|
+
### Mental Models
|
|
65
|
+
A mental model is a pre-computed semantic summary backed by reflection over the bank — a way to maintain a standing answer to a recurring question, semantically populated and refreshed.
|
|
66
66
|
|
|
67
|
-
- `mcp__hindsight__create_mental_model(name, source_query)` — create one. When the user shares a fact about themselves (preferences, background, goals), don't write a file —
|
|
67
|
+
- `mcp__hindsight__create_mental_model(name, source_query)` — create one for a recurring synthesis you need. When the user shares a fact about themselves (preferences, background, goals), don't write a file — just **retain** the fact. You do NOT need to build or maintain a per-agent "user profile": who the user is lives in dedicated per-user profile banks that the operator curates out-of-band, and recall surfaces it automatically.
|
|
68
68
|
|
|
69
69
|
### Directives (replaces feedback rules)
|
|
70
70
|
Hard rules the agent must follow during reflect — guardrails that are always applied.
|
|
@@ -54631,10 +54631,10 @@ function readTurnActiveMarkerAgeMs(stateDir, now) {
|
|
|
54631
54631
|
}
|
|
54632
54632
|
|
|
54633
54633
|
// ../src/build-info.ts
|
|
54634
|
-
var VERSION = "0.15.
|
|
54635
|
-
var COMMIT_SHA = "
|
|
54636
|
-
var COMMIT_DATE = "2026-06-
|
|
54637
|
-
var LATEST_PR =
|
|
54634
|
+
var VERSION = "0.15.45";
|
|
54635
|
+
var COMMIT_SHA = "41082e8b";
|
|
54636
|
+
var COMMIT_DATE = "2026-06-19T09:03:39Z";
|
|
54637
|
+
var LATEST_PR = 2448;
|
|
54638
54638
|
var COMMITS_AHEAD_OF_TAG = 0;
|
|
54639
54639
|
|
|
54640
54640
|
// gateway/boot-version.ts
|