switchroom 0.20.0 → 0.20.2
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/bin/handoff-briefing.sh +213 -74
- package/dist/agent-scheduler/index.js +2 -2
- package/dist/auth-broker/index.js +4 -3
- package/dist/buzz-gateway/index.js +166 -6
- package/dist/cli/notion-write-pretool.mjs +2 -2
- package/dist/cli/switchroom.js +24704 -16399
- package/dist/host-control/main.js +44 -10
- package/dist/vault/approvals/kernel-server.js +4 -3
- package/dist/vault/broker/server.js +4 -3
- package/package.json +3 -2
- package/profiles/_base/start.sh.hbs +79 -10
- package/telegram-plugin/dist/gateway/gateway.js +1400 -964
- package/telegram-plugin/gateway/access-store.test.ts +234 -0
- package/telegram-plugin/gateway/access-store.ts +194 -0
- package/telegram-plugin/gateway/boot-briefing-builder.ts +135 -7
- package/telegram-plugin/gateway/boot-briefing-capability.ts +31 -0
- package/telegram-plugin/gateway/boot-briefing-wiring.ts +166 -4
- package/telegram-plugin/gateway/buzz-mirror-correlation-store.ts +285 -0
- package/telegram-plugin/gateway/buzz-mirror.ts +177 -12
- package/telegram-plugin/gateway/gateway.ts +43 -123
- package/telegram-plugin/gateway/inbound-router.ts +93 -3
- package/telegram-plugin/gateway/outbound-send-path.ts +48 -1
- package/telegram-plugin/gateway/pending-turn-env.ts +10 -1
- package/telegram-plugin/tests/boot-briefing-builder.test.ts +422 -31
- package/telegram-plugin/tests/buzz-mirror-correlation-store.test.ts +173 -0
- package/telegram-plugin/tests/buzz-mirror.test.ts +297 -1
- package/telegram-plugin/tests/outbound-send-path.test.ts +24 -0
- package/telegram-plugin/tests/reply-to-buffer-fallback.test.ts +273 -0
- package/telegram-plugin/tests/reply-to-buffer-history.test.ts +134 -0
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// src/buzz-gateway/index.ts
|
|
2
|
-
import { join as
|
|
2
|
+
import { join as join3 } from "node:path";
|
|
3
3
|
|
|
4
4
|
// node_modules/.bun/@noble+hashes@2.0.1/node_modules/@noble/hashes/utils.js
|
|
5
5
|
/*! noble-hashes - MIT License (c) 2022 Paul Miller (paulmillr.com) */
|
|
@@ -8874,6 +8874,20 @@ async function publishOutbound(req, secretKey, transport, nowSec) {
|
|
|
8874
8874
|
}
|
|
8875
8875
|
return { ok: true, eventId: signed.eventId };
|
|
8876
8876
|
}
|
|
8877
|
+
async function publishOutboundTallied(req, secretKey, transport, tally, nowSec) {
|
|
8878
|
+
let result;
|
|
8879
|
+
try {
|
|
8880
|
+
result = await publishOutbound(req, secretKey, transport, nowSec);
|
|
8881
|
+
} catch {
|
|
8882
|
+
tally.failed += 1;
|
|
8883
|
+
return { ok: false, error: "publish failed: transport threw" };
|
|
8884
|
+
}
|
|
8885
|
+
if (result.ok)
|
|
8886
|
+
tally.ok += 1;
|
|
8887
|
+
else
|
|
8888
|
+
tally.failed += 1;
|
|
8889
|
+
return result;
|
|
8890
|
+
}
|
|
8877
8891
|
|
|
8878
8892
|
// src/buzz-gateway/inbound-map.ts
|
|
8879
8893
|
var BUZZ_MESSAGE_KIND = 9;
|
|
@@ -8898,6 +8912,22 @@ function resolveThreadRoot(ev) {
|
|
|
8898
8912
|
return eTags[0][1];
|
|
8899
8913
|
return ev.id;
|
|
8900
8914
|
}
|
|
8915
|
+
function resolveReplyParent(ev) {
|
|
8916
|
+
const eTags = ev.tags.filter((t) => t[0] === "e" && typeof t[1] === "string");
|
|
8917
|
+
if (eTags.length === 0)
|
|
8918
|
+
return;
|
|
8919
|
+
const hasMarkers = eTags.some((t) => t[3] === "root" || t[3] === "reply" || t[3] === "mention");
|
|
8920
|
+
if (hasMarkers) {
|
|
8921
|
+
const reply = eTags.find((t) => t[3] === "reply");
|
|
8922
|
+
if (reply)
|
|
8923
|
+
return reply[1];
|
|
8924
|
+
const root = eTags.find((t) => t[3] === "root");
|
|
8925
|
+
if (root)
|
|
8926
|
+
return root[1];
|
|
8927
|
+
return;
|
|
8928
|
+
}
|
|
8929
|
+
return eTags[eTags.length - 1][1];
|
|
8930
|
+
}
|
|
8901
8931
|
function resolveChannelId(ev, fallback) {
|
|
8902
8932
|
const h = ev.tags.find((t) => t[0] === "h" && typeof t[1] === "string");
|
|
8903
8933
|
return h ? h[1] : fallback;
|
|
@@ -8907,14 +8937,16 @@ function mapBuzzEvent(ev, ctx) {
|
|
|
8907
8937
|
return null;
|
|
8908
8938
|
const channelId = resolveChannelId(ev, ctx.groupId);
|
|
8909
8939
|
const threadRoot = resolveThreadRoot(ev);
|
|
8940
|
+
const replyTo = resolveReplyParent(ev);
|
|
8910
8941
|
const user = senderLabel(ev.pubkey, ctx.pubkeyNames);
|
|
8911
|
-
const text = `<channel source="buzz" ` + `buzz_channel_id="${escapeAttr(channelId)}" ` + `buzz_event_id="${escapeAttr(ev.id)}" ` + `buzz_pubkey="${escapeAttr(ev.pubkey)}" ` + `buzz_thread_root="${escapeAttr(threadRoot)}" ` + `user="${escapeAttr(user)}">` + escapeBody(ev.content) + `</channel>`;
|
|
8942
|
+
const text = `<channel source="buzz" ` + `buzz_channel_id="${escapeAttr(channelId)}" ` + `buzz_event_id="${escapeAttr(ev.id)}" ` + `buzz_pubkey="${escapeAttr(ev.pubkey)}" ` + `buzz_thread_root="${escapeAttr(threadRoot)}" ` + (replyTo !== undefined ? `buzz_reply_to="${escapeAttr(replyTo)}" ` : "") + `user="${escapeAttr(user)}">` + escapeBody(ev.content) + `</channel>`;
|
|
8912
8943
|
const meta = {
|
|
8913
8944
|
source: "buzz",
|
|
8914
8945
|
buzz_channel_id: channelId,
|
|
8915
8946
|
buzz_event_id: ev.id,
|
|
8916
8947
|
buzz_pubkey: ev.pubkey,
|
|
8917
8948
|
buzz_thread_root: threadRoot,
|
|
8949
|
+
...replyTo !== undefined ? { buzz_reply_to: replyTo } : {},
|
|
8918
8950
|
user
|
|
8919
8951
|
};
|
|
8920
8952
|
return {
|
|
@@ -9052,6 +9084,110 @@ function createRetryQueue(deps) {
|
|
|
9052
9084
|
};
|
|
9053
9085
|
}
|
|
9054
9086
|
|
|
9087
|
+
// src/buzz-gateway/heartbeat.ts
|
|
9088
|
+
import {
|
|
9089
|
+
mkdirSync as realMkdirSync,
|
|
9090
|
+
writeFileSync as realWriteFileSync
|
|
9091
|
+
} from "node:fs";
|
|
9092
|
+
import { dirname as dirname2, join as join2 } from "node:path";
|
|
9093
|
+
var BUZZ_HEARTBEAT_SUBDIR = "buzz";
|
|
9094
|
+
var BUZZ_HEARTBEAT_FILE = "buzz-sidecar.heartbeat.json";
|
|
9095
|
+
var BUZZ_HEARTBEAT_INTERVAL_MS = 60 * 1000;
|
|
9096
|
+
var BUZZ_HEARTBEAT_STALE_MULTIPLIER = 3;
|
|
9097
|
+
var BUZZ_HEARTBEAT_STALE_MS = BUZZ_HEARTBEAT_INTERVAL_MS * BUZZ_HEARTBEAT_STALE_MULTIPLIER;
|
|
9098
|
+
var BUZZ_HEARTBEAT_MAX_INTERVAL_MS = BUZZ_HEARTBEAT_STALE_MS / BUZZ_HEARTBEAT_STALE_MULTIPLIER;
|
|
9099
|
+
function resolveStatsIntervalMs(raw) {
|
|
9100
|
+
const requested = Number(raw);
|
|
9101
|
+
if (!Number.isFinite(requested) || requested <= 0) {
|
|
9102
|
+
return BUZZ_HEARTBEAT_INTERVAL_MS;
|
|
9103
|
+
}
|
|
9104
|
+
return Math.min(requested, BUZZ_HEARTBEAT_MAX_INTERVAL_MS);
|
|
9105
|
+
}
|
|
9106
|
+
function buzzHeartbeatStatePath(stateDir) {
|
|
9107
|
+
return join2(stateDir, BUZZ_HEARTBEAT_SUBDIR, BUZZ_HEARTBEAT_FILE);
|
|
9108
|
+
}
|
|
9109
|
+
function writeBuzzHeartbeat(path, hb, io = {}) {
|
|
9110
|
+
const mkdir = io.mkdirSync ?? realMkdirSync;
|
|
9111
|
+
const write = io.writeFileSync ?? realWriteFileSync;
|
|
9112
|
+
mkdir(dirname2(path), { recursive: true });
|
|
9113
|
+
write(path, JSON.stringify(hb));
|
|
9114
|
+
}
|
|
9115
|
+
|
|
9116
|
+
// src/buzz-gateway/stats.ts
|
|
9117
|
+
var REJECT_PREFIX = "rejected:";
|
|
9118
|
+
function summarizePipeline(pumpStats, mirror) {
|
|
9119
|
+
let received = 0;
|
|
9120
|
+
let authFailures = 0;
|
|
9121
|
+
for (const [key, count] of Object.entries(pumpStats)) {
|
|
9122
|
+
received += count;
|
|
9123
|
+
if (key.startsWith(REJECT_PREFIX))
|
|
9124
|
+
authFailures += count;
|
|
9125
|
+
}
|
|
9126
|
+
return {
|
|
9127
|
+
received,
|
|
9128
|
+
injected: pumpStats.injected ?? 0,
|
|
9129
|
+
duplicate: pumpStats.duplicate ?? 0,
|
|
9130
|
+
queued: pumpStats.queued ?? 0,
|
|
9131
|
+
injectFailed: pumpStats.inject_failed ?? 0,
|
|
9132
|
+
droppedByKind: pumpStats.unmapped ?? 0,
|
|
9133
|
+
channelOff: pumpStats.channel_off ?? 0,
|
|
9134
|
+
authFailures,
|
|
9135
|
+
mirrorOk: mirror.ok,
|
|
9136
|
+
mirrorFailed: mirror.failed
|
|
9137
|
+
};
|
|
9138
|
+
}
|
|
9139
|
+
function formatStatsLine(s) {
|
|
9140
|
+
return `buzz stats: received=${s.received} injected=${s.injected} ` + `duplicate=${s.duplicate} queued=${s.queued} inject_failed=${s.injectFailed} ` + `dropped_by_kind=${s.droppedByKind} channel_off=${s.channelOff} ` + `auth_failures=${s.authFailures} mirror_ok=${s.mirrorOk} mirror_failed=${s.mirrorFailed}`;
|
|
9141
|
+
}
|
|
9142
|
+
function createStatsReporter(deps) {
|
|
9143
|
+
const intervalMs = deps.intervalMs && deps.intervalMs > 0 ? deps.intervalMs : 60000;
|
|
9144
|
+
const setTimer = deps.setTimer ?? ((fn, ms) => setTimeout(fn, ms));
|
|
9145
|
+
const clearTimer = deps.clearTimer ?? ((t) => clearTimeout(t));
|
|
9146
|
+
let timer = null;
|
|
9147
|
+
let stopped = false;
|
|
9148
|
+
let lastLine = null;
|
|
9149
|
+
function tick() {
|
|
9150
|
+
const sample = deps.sample();
|
|
9151
|
+
const line = formatStatsLine(sample.summary);
|
|
9152
|
+
if (line !== lastLine) {
|
|
9153
|
+
deps.emit(line);
|
|
9154
|
+
lastLine = line;
|
|
9155
|
+
}
|
|
9156
|
+
try {
|
|
9157
|
+
deps.persist?.(sample);
|
|
9158
|
+
} catch {}
|
|
9159
|
+
}
|
|
9160
|
+
function schedule() {
|
|
9161
|
+
if (stopped)
|
|
9162
|
+
return;
|
|
9163
|
+
timer = setTimer(() => {
|
|
9164
|
+
timer = null;
|
|
9165
|
+
if (stopped)
|
|
9166
|
+
return;
|
|
9167
|
+
tick();
|
|
9168
|
+
schedule();
|
|
9169
|
+
}, intervalMs);
|
|
9170
|
+
if (timer && typeof timer.unref === "function") {
|
|
9171
|
+
timer.unref();
|
|
9172
|
+
}
|
|
9173
|
+
}
|
|
9174
|
+
return {
|
|
9175
|
+
start() {
|
|
9176
|
+
stopped = false;
|
|
9177
|
+
tick();
|
|
9178
|
+
schedule();
|
|
9179
|
+
},
|
|
9180
|
+
stop() {
|
|
9181
|
+
stopped = true;
|
|
9182
|
+
if (timer !== null) {
|
|
9183
|
+
clearTimer(timer);
|
|
9184
|
+
timer = null;
|
|
9185
|
+
}
|
|
9186
|
+
},
|
|
9187
|
+
tick
|
|
9188
|
+
};
|
|
9189
|
+
}
|
|
9190
|
+
|
|
9055
9191
|
// src/buzz-gateway/index.ts
|
|
9056
9192
|
function log(msg) {
|
|
9057
9193
|
process.stderr.write(`buzz-gateway: ${msg}
|
|
@@ -9123,8 +9259,8 @@ async function main() {
|
|
|
9123
9259
|
const agentPubkey = getPublicKey(secretKey).toLowerCase();
|
|
9124
9260
|
log(`booted agent=${config.agentName} relay=${config.relayUrl} group=${config.groupId} allowlist=${config.authorized.size}`);
|
|
9125
9261
|
const stateDir = process.env.TELEGRAM_STATE_DIR ?? "/state/agent/telegram";
|
|
9126
|
-
const socketPath = process.env.SWITCHROOM_GATEWAY_SOCKET ??
|
|
9127
|
-
const journalPath = process.env.BUZZ_JOURNAL_PATH ??
|
|
9262
|
+
const socketPath = process.env.SWITCHROOM_GATEWAY_SOCKET ?? join3(stateDir, "gateway.sock");
|
|
9263
|
+
const journalPath = process.env.BUZZ_JOURNAL_PATH ?? join3(stateDir, "buzz", "journal.jsonl");
|
|
9128
9264
|
const dedup = createDedupStore({ journalPath, log });
|
|
9129
9265
|
const ipcClient = createInjectIpcClient({ socketPath, log });
|
|
9130
9266
|
const inject = makeInject(ipcClient, config.agentName);
|
|
@@ -9158,16 +9294,17 @@ async function main() {
|
|
|
9158
9294
|
log
|
|
9159
9295
|
});
|
|
9160
9296
|
const publishTransport = (event, timeoutMs) => nostr.publish(event, timeoutMs);
|
|
9297
|
+
const mirror = { ok: 0, failed: 0 };
|
|
9161
9298
|
const buzzPeer = createBuzzPeerClient({
|
|
9162
9299
|
socketPath,
|
|
9163
9300
|
agentName: config.agentName,
|
|
9164
9301
|
onOutbound: async (req) => {
|
|
9165
|
-
const result = await
|
|
9302
|
+
const result = await publishOutboundTallied({
|
|
9166
9303
|
channelId: req.channelId,
|
|
9167
9304
|
replyToEventId: req.replyToEventId,
|
|
9168
9305
|
threadRootId: req.threadRootId,
|
|
9169
9306
|
payload: req.payload
|
|
9170
|
-
}, secretKey, publishTransport);
|
|
9307
|
+
}, secretKey, publishTransport, mirror);
|
|
9171
9308
|
return {
|
|
9172
9309
|
type: "buzz_publish_result",
|
|
9173
9310
|
correlationId: req.correlationId,
|
|
@@ -9178,8 +9315,30 @@ async function main() {
|
|
|
9178
9315
|
},
|
|
9179
9316
|
log
|
|
9180
9317
|
});
|
|
9318
|
+
const bootTs = Date.now();
|
|
9319
|
+
const heartbeatPath = buzzHeartbeatStatePath(stateDir);
|
|
9320
|
+
const statsIntervalMs = resolveStatsIntervalMs(process.env.BUZZ_STATS_INTERVAL_MS);
|
|
9321
|
+
const statsReporter = createStatsReporter({
|
|
9322
|
+
intervalMs: statsIntervalMs,
|
|
9323
|
+
sample: () => ({
|
|
9324
|
+
summary: summarizePipeline(pump.stats, mirror),
|
|
9325
|
+
subscribed: nostr.isSubscribed()
|
|
9326
|
+
}),
|
|
9327
|
+
emit: (line) => log(line),
|
|
9328
|
+
persist: (sample) => writeBuzzHeartbeat(heartbeatPath, {
|
|
9329
|
+
v: 1,
|
|
9330
|
+
agent: config.agentName,
|
|
9331
|
+
ts: Date.now(),
|
|
9332
|
+
bootTs,
|
|
9333
|
+
subscribed: sample.subscribed,
|
|
9334
|
+
stats: sample.summary
|
|
9335
|
+
})
|
|
9336
|
+
});
|
|
9181
9337
|
const shutdown = () => {
|
|
9182
9338
|
log("shutting down");
|
|
9339
|
+
try {
|
|
9340
|
+
statsReporter.stop();
|
|
9341
|
+
} catch {}
|
|
9183
9342
|
try {
|
|
9184
9343
|
nostr.stop();
|
|
9185
9344
|
} catch {}
|
|
@@ -9200,6 +9359,7 @@ async function main() {
|
|
|
9200
9359
|
process.on("SIGTERM", shutdown);
|
|
9201
9360
|
process.on("SIGINT", shutdown);
|
|
9202
9361
|
nostr.start();
|
|
9362
|
+
statsReporter.start();
|
|
9203
9363
|
}
|
|
9204
9364
|
main().catch((err) => {
|
|
9205
9365
|
log(`FATAL: ${err.message}`);
|
|
@@ -12123,7 +12123,7 @@ var BuzzChannelSchema = exports_external.object({
|
|
|
12123
12123
|
default_channel_id: exports_external.string().describe("Relay-minted group UUID (the NIP-29 `h` tag) the sidecar subscribes " + "to and stamps on injected turns."),
|
|
12124
12124
|
channel_map: exports_external.record(exports_external.string(), exports_external.string()).default({}).describe("Optional map of extra group UUIDs \u2192 friendly labels."),
|
|
12125
12125
|
pubkey_names: exports_external.record(exports_external.string(), exports_external.string()).default({}).describe("Optional petnames: hex/npub pubkey \u2192 display name, used to label " + "the sender on injected turns."),
|
|
12126
|
-
pinned_relay_digest: exports_external.string().optional().describe("Pinned relay image digest (M4).
|
|
12126
|
+
pinned_relay_digest: exports_external.string().optional().describe("Pinned relay image digest (M4). RESERVED \u2014 no consumer of this field " + "exists; the existing compat-check (compat-check.ts) validates only " + "the wire contract (AUTH kind, message kind, tag names) and does not " + "read this field. Kept in the schema so the intended digest-pin can " + "be wired without a config shape change.")
|
|
12127
12127
|
}).strict();
|
|
12128
12128
|
var ChannelsSchema = exports_external.object({
|
|
12129
12129
|
telegram: TelegramChannelSchema,
|
|
@@ -12180,7 +12180,7 @@ var HindsightConfigSchema = exports_external.object({
|
|
|
12180
12180
|
reflect: HindsightPerOpLlmSchema.optional().describe("Per-op override for the `reflect` LLM op (synthesis / mental-model " + "refresh). Emits `HINDSIGHT_API_REFLECT_LLM_*`. Absent \u2192 uses global."),
|
|
12181
12181
|
consolidation: HindsightPerOpLlmSchema.optional().describe("Per-op override for the `consolidation` LLM op (background memory " + "merge). Emits `HINDSIGHT_API_CONSOLIDATION_LLM_*`. Absent \u2192 global.")
|
|
12182
12182
|
}).optional().describe("LLM knob for the hindsight container. The flat `provider`/`model` set " + "the global default (backward-compatible); optional `retain`/`reflect`/" + "`consolidation` blocks override individual ops. All fields optional; " + "unset fields fall back to the hard-coded defaults."),
|
|
12183
|
-
env: exports_external.record(exports_external.union([exports_external.string(), exports_external.number(), exports_external.boolean()])).optional().describe("Operator overrides for switchroom's capability-gated Hindsight " + "performance defaults. Only the keys switchroom actually manages are " + "honoured (`HINDSIGHT_PERF_ENV_KEYS` in " + "src/setup/hindsight-perf-defaults.ts: RERANKER_LOCAL_FP16, " + "RERANKER_LOCAL_BATCH_SIZE, LLM_MAX_CONCURRENT, " + "RETAIN/CONSOLIDATION_LLM_MAX_CONCURRENT, LLM_STRICT_SCHEMA, " + "LLM_MAX_RETRIES, CONSOLIDATION_LLM_PARALLELISM, " + "MAX_OBSERVATIONS_PER_SCOPE, " + "RECALL_MAX_CANDIDATES_PER_SOURCE, LINK_EXPANSION_PER_ENTITY_LIMIT, " + "LINK_EXPANSION_TIMEOUT, LLM_REASONING_EFFORT, " + "RERANKER_LOCAL_BUCKET_BATCHING, RERANKER_MAX_CANDIDATES, " + "RERANKER_LOCAL_MAX_CONCURRENT, RECALL_MAX_CONCURRENT, " + "REFLECT_WALL_TIMEOUT, WORKER_CONSOLIDATION_RESERVED_SLOTS, " + "WORKER_CONSOLIDATION_SLOT_LIMIT, " + "CONSOLIDATION_MAX_MEMORIES_PER_ROUND, GRAPH_SEED_MIN_SIMILARITY, " + "LLM_SUPPORTS_MAX_ITEMS, RECENCY_DECAY_FUNCTION, " + "RECENCY_DECAY_HALFLIFE_DAYS \u2014 switchroom defaults recall's recency " + "curve to `exponential` with a 30-day half-life so a fact retained " + "today outranks a stale one, instead of upstream's near-flat " + "linear/365-day window), the override-only keys " + "switchroom manages but ships NO default for " + "(`HINDSIGHT_PERF_OVERRIDE_ONLY_KEYS`: " + "HINDSIGHT_API_WORKER_CONSOLIDATION_BANK_PRIORITY \u2014 a per-deployment " + "`bank-pattern:priority,...` map; unset means upstream's flat " + "created_at FIFO across banks; and " + "HINDSIGHT_CE_DECISIVE_RELATIVE_GAP \u2014 the rollback knob for " + "switchroom's CE-saturation damping patch, a float; >= ~0.65 backs the " + "damping out entirely, unset means the patch's own derived gap; and " + "HINDSIGHT_API_RECENCY_DECAY_LINEAR_WINDOW_DAYS \u2014 only read when the " + "decay function is `linear`, so switchroom ships no default for it but " + "still honours an operator who flips the function back; and " + "HINDSIGHT_API_WORKER_MAX_SLOTS \u2014 the worker poller's TOTAL in-flight " + "task budget, the pool WORKER_CONSOLIDATION_RESERVED_SLOTS reserves out of; " + "unset means upstream's own default; and " + "HINDSIGHT_API_WORKER_RETAIN_RESERVED_SLOTS \u2014 the reserved slot FLOOR for the " + "retain (memory write) lane, carved from that same total; unset means " + "upstream's own 0, i.e. no floor and retain competes for the shared " + "pool; and " + "the pre-0.8.6 name HINDSIGHT_API_WORKER_<TYPE>_MAX_SLOTS is still " + "accepted for every operation type and normalised to " + "..._RESERVED_SLOTS on the way in, because setting both names for " + "one type is a hard boot failure in the engine and switchroom " + "therefore emits only the canonical name; and " + "HINDSIGHT_API_SEMANTIC_MIN_SIMILARITY \u2014 the cosine-similarity floor a " + "candidate must reach to be returned by the semantic retrieval arm at " + "all (0..1); unset means upstream's own 0.3, and where it should sit " + "depends on the bank's embedding model and phrasing diversity, so " + "switchroom ships no opinion; and " + "HINDSIGHT_MCP_RECALL_BUDGET_MODE \u2014 the rollback knob for switchroom's " + "mcp-recall-token-budget image patch; `legacy` restores upstream's " + "exact pre-patch recall returns, anything else or unset is the " + "honest-envelope mode; and " + "HINDSIGHT_API_LLM_TEMPERATURE_REFLECT \u2014 upstream's own per-op reflect " + "temperature knob, made live by switchroom's reflect-temperature image " + "patch; a float, or `none` to omit the kwarg (provider default, " + "upstream's accidental pre-patch behaviour); unset means the image's " + "baked default 0.1; and " + "HINDSIGHT_API_CONSOLIDATION_RECALL_MAX_CONCURRENT \u2014 the background " + "half of switchroom's recall-admission split (#3660): of the " + "RECALL_MAX_CONCURRENT admission slots, at most this many may be held " + "by background consolidation recalls at once, so foreground per-turn " + "recall always keeps the remainder; must be >= 1 and strictly less " + "than RECALL_MAX_CONCURRENT or the engine refuses to boot; unset " + "means the image's derived default min(2, RECALL_MAX_CONCURRENT - 1); " + "1 biases hard toward the interactive lane while a consolidation " + "backlog drains; and " + "HINDSIGHT_MM_REFRESH_MIN_INTERVAL_S \u2014 the rollback/tuning knob for " + "switchroom's MM-refresh-debounce image patch: the minimum seconds " + "between consolidation-triggered refreshes of one mental model; unset " + "means the image's baked 3600, 0 restores upstream's " + "refresh-every-round behaviour; explicit and cron-scheduled refreshes " + "are never debounced), plus the " + "embedded-PostgreSQL (pg0) sizing keys switchroom manages in " + "src/setup/hindsight-pg-defaults.ts (`HINDSIGHT_PG_ENV_KEYS`: " + "SWITCHROOM_HINDSIGHT_PG_EFFECTIVE_CACHE_SIZE, " + "SWITCHROOM_HINDSIGHT_PG_SHARED_BUFFERS \u2014 a postgres size string such " + "as `4GB`, or the sentinel `off` to leave pg0's own default for that " + "one knob). A value set here " + "REPLACES switchroom's default and is emitted even when the gating " + "capability is absent, so an operator can always force a knob. Other " + "`HINDSIGHT_API_*` keys are deliberately IGNORED \u2014 a blanket " + "passthrough would collide with the vars startHindsight() derives " + "itself (HINDSIGHT_API_PORT, the retain token/deadline budget).")
|
|
12183
|
+
env: exports_external.record(exports_external.union([exports_external.string(), exports_external.number(), exports_external.boolean()])).optional().describe("Operator overrides for switchroom's capability-gated Hindsight " + "performance defaults. Only the keys switchroom actually manages are " + "honoured (`HINDSIGHT_PERF_ENV_KEYS` in " + "src/setup/hindsight-perf-defaults.ts: RERANKER_LOCAL_FP16, " + "RERANKER_LOCAL_BATCH_SIZE, LLM_MAX_CONCURRENT, " + "RETAIN/CONSOLIDATION_LLM_MAX_CONCURRENT, LLM_STRICT_SCHEMA, " + "LLM_MAX_RETRIES, CONSOLIDATION_LLM_PARALLELISM, " + "MAX_OBSERVATIONS_PER_SCOPE, " + "RECALL_MAX_CANDIDATES_PER_SOURCE, LINK_EXPANSION_PER_ENTITY_LIMIT, " + "LINK_EXPANSION_TIMEOUT, LLM_REASONING_EFFORT, " + "RERANKER_LOCAL_BUCKET_BATCHING, RERANKER_MAX_CANDIDATES, " + "RERANKER_LOCAL_MAX_CONCURRENT, RECALL_MAX_CONCURRENT, " + "REFLECT_WALL_TIMEOUT, WORKER_CONSOLIDATION_RESERVED_SLOTS, " + "WORKER_CONSOLIDATION_SLOT_LIMIT, " + "CONSOLIDATION_MAX_MEMORIES_PER_ROUND, GRAPH_SEED_MIN_SIMILARITY, " + "LLM_SUPPORTS_MAX_ITEMS, RECENCY_DECAY_FUNCTION, " + "RECENCY_DECAY_HALFLIFE_DAYS \u2014 switchroom defaults recall's recency " + "curve to `exponential` with a 30-day half-life so a fact retained " + "today outranks a stale one, instead of upstream's near-flat " + "linear/365-day window), the override-only keys " + "switchroom manages but ships NO default for " + "(`HINDSIGHT_PERF_OVERRIDE_ONLY_KEYS`: " + "HINDSIGHT_API_WORKER_CONSOLIDATION_BANK_PRIORITY \u2014 a per-deployment " + "`bank-pattern:priority,...` map; unset means upstream's flat " + "created_at FIFO across banks; and " + "HINDSIGHT_CE_DECISIVE_RELATIVE_GAP \u2014 the rollback knob for " + "switchroom's CE-saturation damping patch, a float; >= ~0.65 backs the " + "damping out entirely, unset means the patch's own derived gap; and " + "HINDSIGHT_API_RECENCY_DECAY_LINEAR_WINDOW_DAYS \u2014 only read when the " + "decay function is `linear`, so switchroom ships no default for it but " + "still honours an operator who flips the function back; and " + "HINDSIGHT_API_WORKER_MAX_SLOTS \u2014 the worker poller's TOTAL in-flight " + "task budget, the pool WORKER_CONSOLIDATION_RESERVED_SLOTS reserves out of; " + "unset means upstream's own default; and " + "HINDSIGHT_API_WORKER_RETAIN_RESERVED_SLOTS \u2014 the reserved slot FLOOR for the " + "retain (memory write) lane, carved from that same total; unset means " + "upstream's own 0, i.e. no floor and retain competes for the shared " + "pool; and " + "the pre-0.8.6 name HINDSIGHT_API_WORKER_<TYPE>_MAX_SLOTS is still " + "accepted for every operation type and normalised to " + "..._RESERVED_SLOTS on the way in, because setting both names for " + "one type is a hard boot failure in the engine and switchroom " + "therefore emits only the canonical name; and " + "HINDSIGHT_API_SEMANTIC_MIN_SIMILARITY \u2014 the cosine-similarity floor a " + "candidate must reach to be returned by the semantic retrieval arm at " + "all (0..1); unset means upstream's own 0.3, and where it should sit " + "depends on the bank's embedding model and phrasing diversity, so " + "switchroom ships no opinion; and " + "HINDSIGHT_MCP_RECALL_BUDGET_MODE \u2014 the rollback knob for switchroom's " + "mcp-recall-token-budget image patch; `legacy` restores upstream's " + "exact pre-patch recall returns, anything else or unset is the " + "honest-envelope mode; and " + "HINDSIGHT_API_LLM_TEMPERATURE_REFLECT \u2014 upstream's own per-op reflect " + "temperature knob, made live by switchroom's reflect-temperature image " + "patch; a float, or `none` to omit the kwarg (provider default, " + "upstream's accidental pre-patch behaviour); unset means the image's " + "baked default 0.1; and " + "HINDSIGHT_API_CONSOLIDATION_RECALL_MAX_CONCURRENT \u2014 the background " + "half of switchroom's recall-admission split (#3660): of the " + "RECALL_MAX_CONCURRENT admission slots, at most this many may be held " + "by background consolidation recalls at once, so foreground per-turn " + "recall always keeps the remainder; must be >= 1 and strictly less " + "than RECALL_MAX_CONCURRENT or the engine refuses to boot; unset " + "means the image's derived default min(2, RECALL_MAX_CONCURRENT - 1); " + "1 biases hard toward the interactive lane while a consolidation " + "backlog drains; and " + "HINDSIGHT_MM_REFRESH_MIN_INTERVAL_S \u2014 the rollback/tuning knob for " + "switchroom's MM-refresh-debounce image patch: the minimum seconds " + "between consolidation-triggered refreshes of one mental model; unset " + "means the image's baked 3600, 0 restores upstream's " + "refresh-every-round behaviour; explicit and cron-scheduled refreshes " + "are never debounced; and " + "HINDSIGHT_API_TEMPORAL_LANGUAGES \u2014 the language set dateparser is " + "restricted to during temporal query analysis, made live by switchroom's " + "temporal-language image patch (which ended a 200+-locale auto-detection " + "pass that blocked the shared asyncio loop on every recall); " + "comma-separated, unset means the image's baked `en`, set e.g. `en,es` to " + "restore i18n parsing), plus the " + "embedded-PostgreSQL (pg0) sizing keys switchroom manages in " + "src/setup/hindsight-pg-defaults.ts (`HINDSIGHT_PG_ENV_KEYS`: " + "SWITCHROOM_HINDSIGHT_PG_EFFECTIVE_CACHE_SIZE, " + "SWITCHROOM_HINDSIGHT_PG_SHARED_BUFFERS \u2014 a postgres size string such " + "as `4GB`, or the sentinel `off` to leave pg0's own default for that " + "one knob). A value set here " + "REPLACES switchroom's default and is emitted even when the gating " + "capability is absent, so an operator can always force a knob. Other " + "`HINDSIGHT_API_*` keys are deliberately IGNORED \u2014 a blanket " + "passthrough would collide with the vars startHindsight() derives " + "itself (HINDSIGHT_API_PORT, the retain token/deadline budget).")
|
|
12184
12184
|
});
|
|
12185
12185
|
var MicrosoftWorkspaceConfigSchema = exports_external.object({
|
|
12186
12186
|
microsoft_client_id: exports_external.string().min(1).optional().describe("Microsoft OAuth application (client) ID from Entra portal " + "(literal string or vault reference e.g. " + "'vault:microsoft-oauth-client-id'). OPTIONAL \u2014 omit it to use " + "switchroom's shipped default Microsoft app (zero-config). " + "Set it only to bring your own Entra app (BYO)."),
|