switchroom 0.19.40 → 0.19.42

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.
Files changed (37) hide show
  1. package/dist/agent-scheduler/index.js +22 -2
  2. package/dist/auth-broker/index.js +22 -2
  3. package/dist/cli/notion-write-pretool.mjs +22 -2
  4. package/dist/cli/switchroom.js +810 -241
  5. package/dist/host-control/main.js +94 -19
  6. package/dist/vault/approvals/kernel-server.js +22 -2
  7. package/dist/vault/broker/server.js +22 -2
  8. package/package.json +1 -1
  9. package/telegram-plugin/bridge/bridge.ts +2 -2
  10. package/telegram-plugin/dist/bridge/bridge.js +2 -2
  11. package/telegram-plugin/dist/gateway/gateway.js +332 -124
  12. package/telegram-plugin/dist/server.js +2 -2
  13. package/telegram-plugin/gateway/approval-callback-consume-record.test.ts +132 -0
  14. package/telegram-plugin/gateway/checklist-fallback.ts +370 -0
  15. package/telegram-plugin/gateway/gateway.ts +76 -76
  16. package/telegram-plugin/gateway/liveness-wiring.ts +12 -0
  17. package/telegram-plugin/gateway/model-command.ts +21 -109
  18. package/telegram-plugin/gateway/stream-render.ts +57 -0
  19. package/telegram-plugin/gateway/turn-record-status.ts +80 -0
  20. package/telegram-plugin/tests/checklist-fallback.test.ts +317 -0
  21. package/telegram-plugin/tests/framework-fallback-drains-parked.test.ts +134 -0
  22. package/telegram-plugin/tests/gateway-outbound-redact.test.ts +10 -6
  23. package/telegram-plugin/tests/helpers/liveness-wiring-fixture.ts +3 -0
  24. package/telegram-plugin/tests/turn-record-status.test.ts +62 -0
  25. package/vendor/hindsight-memory/CHANGELOG.md +28 -0
  26. package/vendor/hindsight-memory/docs/measurements/subagent-volume-gate-3994.md +84 -0
  27. package/vendor/hindsight-memory/scripts/backfill_transcripts.py +254 -40
  28. package/vendor/hindsight-memory/scripts/lib/content.py +11 -2
  29. package/vendor/hindsight-memory/scripts/recall.py +18 -3
  30. package/vendor/hindsight-memory/scripts/subagent_retain.py +59 -38
  31. package/vendor/hindsight-memory/scripts/tests/data/replay_volume_gate_3994.py +295 -0
  32. package/vendor/hindsight-memory/scripts/tests/test_backfill_from_logs.py +109 -0
  33. package/vendor/hindsight-memory/scripts/tests/test_overlap_tokens.py +135 -0
  34. package/vendor/hindsight-memory/scripts/tests/test_recall_no_lexical_gate.py +20 -23
  35. package/vendor/hindsight-memory/scripts/tests/test_recall_query_shaping.py +48 -0
  36. package/vendor/hindsight-memory/scripts/tests/test_subagent_retain.py +94 -1
  37. package/vendor/hindsight-memory/scripts/tests/test_subagent_retain_learnings.py +98 -42
@@ -11116,6 +11116,7 @@ var init_schema = __esm(() => {
11116
11116
  auto_recall: exports_external.boolean().default(true).describe("Auto-search memories before each response"),
11117
11117
  file: exports_external.boolean().default(true).describe("Maintain a curated workspace MEMORY.md file (seeded once, " + "auto-loaded every turn). Set false for hindsight-only memory: " + "the file is not seeded or re-created, so once migrated into " + "Hindsight and deleted it stays gone. Recall + directives carry " + "the memory instead. Cascade: override (per-agent wins over default)."),
11118
11118
  isolation: exports_external.enum(["default", "strict"]).default("default").describe("strict = never shared cross-agent, default = eligible for reflect"),
11119
+ profile: exports_external.string().optional().describe("Memory profile bank this agent's curated memory defaults key off — " + "the built-in disposition + observations_mission in PROFILE_MEMORY_DEFAULTS. " + "Decouples the memory profile from `extends` (the filesystem persona " + "profile), so an agent on `extends: default` can opt into the `coding` " + "memory bundle via `memory.profile: coding` without inheriting the coding " + "persona. Resolution: memory.profile → extends → DEFAULT_PROFILE (see " + "resolveMemoryProfile). Unset ⇒ byte-identical to keying off `extends`."),
11119
11120
  bank_mission: exports_external.string().optional().describe("Bank-level mission statement used during recall to contextualize " + "results. NOTE: this is an alias for the Hindsight engine's " + "`reflect_mission` field (verified live: switchroom's bank_mission " + "lands in `config.reflect_mission`). Prefer `reflect_mission` going " + "forward; `bank_mission` is retained for back-compat. If both are " + "set, `reflect_mission` wins. Cascade: override."),
11120
11121
  reflect_mission: exports_external.string().optional().describe("Mission/context steering Hindsight Reflect operations (the bank's " + "'who am I / what matters' framing applied during recall). The " + "engine-accurate name for what `bank_mission` sets. Cascade: override."),
11121
11122
  retain_mission: exports_external.string().optional().describe("Instructions for the fact extraction LLM during retain. Cascade: override."),
@@ -11409,6 +11410,8 @@ var init_schema = __esm(() => {
11409
11410
  provider: exports_external.string().min(1).optional().describe("Hindsight LLM provider (upstream `HINDSIGHT_API_LLM_PROVIDER`). " + "Defaults to `claude-code` (subscription-honest, broker-fed OAuth). " + "Any litellm-routable provider the upstream image supports is valid. " + "Serves as the GLOBAL default for every op absent a per-op override."),
11410
11411
  model: exports_external.string().min(1).optional().describe("Hindsight LLM model (upstream `HINDSIGHT_API_LLM_MODEL`). Defaults " + "to HINDSIGHT_DEFAULT_MODEL. Any model your LiteLLM proxy can route " + "is valid, e.g. `openrouter/z-ai/glm-5.2` when routing through the " + "fleet proxy. With provider=claude-code this value is ALSO exported " + "as `ANTHROPIC_MODEL` to the claude subprocess. Serves as the GLOBAL " + "default for every op absent a per-op override."),
11411
11412
  context_window: exports_external.number().int().positive().optional().describe("GLOBAL context window (tokens) of the backend serving hindsight's " + "LLM ops — the declared size switchroom derives every token budget " + "from. Set this to the real window of whatever you point " + "`hindsight.llm` at (e.g. 32768 for a llama.cpp slot launched with " + "`-c 65536 -np 2`, 131072 for a large-window OpenRouter model). " + "Absent → a per-provider default: 200000 for `claude-code`, a " + "conservative 32768 for everything else. Overflowing a local " + "backend's window does NOT error — llama.cpp context-shift silently " + "drops the system prompt and the model answers conversationally " + "with HTTP 200 — so this value is what makes the failure " + "detectable at setup time instead of never."),
11413
+ base_url: exports_external.string().min(1).optional().describe("GLOBAL LLM base URL (upstream `HINDSIGHT_API_LLM_BASE_URL`). The " + "default endpoint every op inherits absent a per-op " + "`hindsight.llm.<op>.base_url`. Optional passthrough; unset → the " + "engine's provider default. When this points at host loopback the " + "hindsight container is forced onto host networking, same as a " + "per-op base URL, so the endpoint stays reachable (#3687)."),
11414
+ api_key: exports_external.string().min(1).optional().describe("GLOBAL LLM API key (upstream `HINDSIGHT_API_LLM_API_KEY`). Literal " + "or `vault:` reference. The default credential every op inherits " + "absent a per-op `hindsight.llm.<op>.api_key`; the engine reads it as " + "a plain env fallback. Optional passthrough (#3687)."),
11412
11415
  retain: HindsightPerOpLlmSchema.optional().describe("Per-op override for the `retain` LLM op (memory ingestion). Emits " + "`HINDSIGHT_API_RETAIN_LLM_*`. Absent → uses the global model/provider."),
11413
11416
  reflect: HindsightPerOpLlmSchema.optional().describe("Per-op override for the `reflect` LLM op (synthesis / mental-model " + "refresh). Emits `HINDSIGHT_API_REFLECT_LLM_*`. Absent → uses global."),
11414
11417
  consolidation: HindsightPerOpLlmSchema.optional().describe("Per-op override for the `consolidation` LLM op (background memory " + "merge). Emits `HINDSIGHT_API_CONSOLIDATION_LLM_*`. Absent → global.")
@@ -11545,6 +11548,7 @@ var init_schema = __esm(() => {
11545
11548
  auto_recall: exports_external.boolean().optional(),
11546
11549
  file: exports_external.boolean().optional(),
11547
11550
  isolation: exports_external.enum(["default", "strict"]).optional(),
11551
+ profile: exports_external.string().optional(),
11548
11552
  directive_capture_nudge: exports_external.boolean().optional(),
11549
11553
  observation_scopes: ObservationScopesSchema,
11550
11554
  observation_scope_strategy: ObservationScopeStrategySchema,
@@ -11586,7 +11590,23 @@ var init_schema = __esm(() => {
11586
11590
  max_query_chars: exports_external.number().int().min(1).optional(),
11587
11591
  parallel: exports_external.boolean().optional(),
11588
11592
  additional_banks: exports_external.array(exports_external.string()).optional(),
11589
- sender_banks: exports_external.record(exports_external.string(), exports_external.string()).optional()
11593
+ sender_banks: exports_external.record(exports_external.string(), exports_external.string()).optional(),
11594
+ types: exports_external.array(exports_external.string()).optional(),
11595
+ skip_trivial: exports_external.boolean().optional(),
11596
+ topic_filter_mode: exports_external.enum(["soft-preamble", "hard-filter"]).optional()
11597
+ }).optional(),
11598
+ retain: exports_external.object({
11599
+ every_n_turns: exports_external.number().int().min(1).optional(),
11600
+ overlap_turns: exports_external.number().int().min(0).optional()
11601
+ }).optional(),
11602
+ bank_mission: exports_external.string().optional(),
11603
+ reflect_mission: exports_external.string().optional(),
11604
+ retain_mission: exports_external.string().optional(),
11605
+ observations_mission: exports_external.string().optional(),
11606
+ disposition: exports_external.object({
11607
+ skepticism: exports_external.number().int().min(1).max(5).optional(),
11608
+ literalism: exports_external.number().int().min(1).max(5).optional(),
11609
+ empathy: exports_external.number().int().min(1).max(5).optional()
11590
11610
  }).optional()
11591
11611
  }).optional(),
11592
11612
  schedule: exports_external.array(ScheduleEntrySchema).optional(),
@@ -18753,11 +18773,11 @@ var init_protocol = __esm(() => {
18753
18773
  OkRevokeGrantResponseSchema,
18754
18774
  OkApprovalRequestResponseSchema,
18755
18775
  OkApprovalLookupResponseSchema,
18776
+ OkApprovalConsumeRecordResponseSchema,
18756
18777
  OkApprovalConsumeResponseSchema,
18757
18778
  OkApprovalRevokeResponseSchema,
18758
18779
  OkApprovalListResponseSchema,
18759
18780
  OkApprovalRecordResponseSchema,
18760
- OkApprovalConsumeRecordResponseSchema,
18761
18781
  ErrorResponseSchema
18762
18782
  ]);
18763
18783
  });
@@ -21010,6 +21030,7 @@ function parsePendingRolloutMarker(raw) {
21010
21030
  if (o.allow_downgrade !== undefined && typeof o.allow_downgrade !== "boolean") {
21011
21031
  return null;
21012
21032
  }
21033
+ const narrationIdValid = typeof o.narration_message_id === "number" && Number.isInteger(o.narration_message_id) && o.narration_message_id > 0;
21013
21034
  return {
21014
21035
  v: 1,
21015
21036
  request_id: o.request_id,
@@ -21017,6 +21038,7 @@ function parsePendingRolloutMarker(raw) {
21017
21038
  ...o.agents !== undefined ? { agents: o.agents } : {},
21018
21039
  ...o.skip_web !== undefined ? { skip_web: o.skip_web } : {},
21019
21040
  ...o.allow_downgrade !== undefined ? { allow_downgrade: o.allow_downgrade } : {},
21041
+ ...narrationIdValid ? { narration_message_id: o.narration_message_id } : {},
21020
21042
  caller: caller.kind === "agent" ? { kind: "agent", name: caller.name } : { kind: "operator" },
21021
21043
  created_at: o.created_at,
21022
21044
  prior_hostd_version: o.prior_hostd_version
@@ -21320,7 +21342,7 @@ function allocateAgentUid(name) {
21320
21342
  }
21321
21343
 
21322
21344
  // src/build-info.ts
21323
- var VERSION = "0.19.40";
21345
+ var VERSION = "0.19.42";
21324
21346
 
21325
21347
  // src/setup/hindsight-recall-tunables.ts
21326
21348
  var RECALL_DEADLINE_HEADROOM_SECONDS = 2;
@@ -30786,6 +30808,27 @@ class HostdServer {
30786
30808
  })
30787
30809
  };
30788
30810
  }
30811
+ persistNarrationMessageId(requestId, messageId) {
30812
+ try {
30813
+ if (!Number.isInteger(messageId) || messageId <= 0)
30814
+ return;
30815
+ const markerPath = join13(this.hostdDirPath(), SELF_BUMP_MARKER_FILENAME);
30816
+ if (!existsSync15(markerPath))
30817
+ return;
30818
+ const marker = parsePendingRolloutMarker(readFileSync11(markerPath, "utf8"));
30819
+ if (!marker)
30820
+ return;
30821
+ if (marker.request_id !== requestId)
30822
+ return;
30823
+ const updated = {
30824
+ ...marker,
30825
+ narration_message_id: messageId
30826
+ };
30827
+ const tmp = `${markerPath}.tmp`;
30828
+ writeFileSync6(tmp, encodePendingRolloutMarker(updated), { mode: 384 });
30829
+ renameSync5(tmp, markerPath);
30830
+ } catch {}
30831
+ }
30789
30832
  async resumePendingSelfBumpRollout() {
30790
30833
  const markerPath = join13(this.hostdDirPath(), SELF_BUMP_MARKER_FILENAME);
30791
30834
  if (!existsSync15(markerPath))
@@ -30854,6 +30897,9 @@ class HostdServer {
30854
30897
  ...marker.skip_web ? { skip_web: true } : {},
30855
30898
  ...marker.allow_downgrade ? { allow_downgrade: true } : {}
30856
30899
  }, marker.request_id, caller, Date.now());
30900
+ if (marker.narration_message_id !== undefined && caller.kind === "agent") {
30901
+ this.rolloutNarrator?.seedPostedMessage?.(marker.request_id, caller.name, marker.narration_message_id);
30902
+ }
30857
30903
  this.onRolloutPhase(entry, { phase: "self-bump-done", target: marker.pin });
30858
30904
  }
30859
30905
  async handleAgentStart(req, started) {
@@ -32672,28 +32718,49 @@ class LogTailRolloutNarrator {
32672
32718
  }
32673
32719
  }
32674
32720
  }
32721
+ freshState(agentName, target) {
32722
+ return {
32723
+ agentName,
32724
+ lastAppliedSeq: -1,
32725
+ messageId: null,
32726
+ posting: false,
32727
+ postAttempts: 0,
32728
+ postFailed: false,
32729
+ render: { target },
32730
+ agents: [],
32731
+ singletons: initialSingletons(),
32732
+ frozen: false,
32733
+ timer: null,
32734
+ pendingEditAfterPost: false
32735
+ };
32736
+ }
32675
32737
  ensureState(entry) {
32676
32738
  let st = this.states.get(entry.request_id);
32677
32739
  if (!st) {
32678
32740
  const agentName = entry.caller.kind === "agent" ? entry.caller.name : "";
32679
- st = {
32680
- agentName,
32681
- lastAppliedSeq: -1,
32682
- messageId: null,
32683
- posting: false,
32684
- postAttempts: 0,
32685
- postFailed: false,
32686
- render: { target: entry.pin ?? "" },
32687
- agents: [],
32688
- singletons: initialSingletons(),
32689
- frozen: false,
32690
- timer: null,
32691
- pendingEditAfterPost: false
32692
- };
32741
+ st = this.freshState(agentName, entry.pin ?? "");
32693
32742
  this.states.set(entry.request_id, st);
32694
32743
  }
32695
32744
  return st;
32696
32745
  }
32746
+ seedPostedMessage(requestId, agentName, messageId) {
32747
+ const existing = this.states.get(requestId);
32748
+ if (existing) {
32749
+ if (existing.messageId === null) {
32750
+ existing.messageId = messageId;
32751
+ existing.posting = false;
32752
+ existing.postFailed = false;
32753
+ if (existing.postAttempts < 1)
32754
+ existing.postAttempts = 1;
32755
+ existing.pendingEditAfterPost = false;
32756
+ }
32757
+ return;
32758
+ }
32759
+ const st = this.freshState(agentName, "");
32760
+ st.messageId = messageId;
32761
+ st.postAttempts = 1;
32762
+ this.states.set(requestId, st);
32763
+ }
32697
32764
  scheduleRenderOrPost(requestId) {
32698
32765
  const st = this.states.get(requestId);
32699
32766
  if (!st)
@@ -32734,6 +32801,11 @@ class LogTailRolloutNarrator {
32734
32801
  }
32735
32802
  st.messageId = mid;
32736
32803
  st.postFailed = false;
32804
+ try {
32805
+ this.opts.onMessageId?.(requestId, mid);
32806
+ } catch (e) {
32807
+ this.opts.log?.(`onMessageId sink threw (non-fatal): ${e.message}`);
32808
+ }
32737
32809
  if (st.pendingEditAfterPost) {
32738
32810
  st.pendingEditAfterPost = false;
32739
32811
  this.flush(requestId, false);
@@ -33378,8 +33450,11 @@ async function main() {
33378
33450
  resolveGatewaySocket,
33379
33451
  log: (m) => process.stderr.write(`hostd: rollout-narration — ${m}
33380
33452
  `)
33381
- }), { log: (m) => process.stderr.write(`hostd: rollout-narration — ${m}
33382
- `) });
33453
+ }), {
33454
+ log: (m) => process.stderr.write(`hostd: rollout-narration — ${m}
33455
+ `),
33456
+ onMessageId: (rid, mid) => server?.persistNarrationMessageId(rid, mid)
33457
+ });
33383
33458
  const server = new HostdServer({
33384
33459
  homeDir: homedir8(),
33385
33460
  agentUids,
@@ -4407,11 +4407,11 @@ var init_protocol = __esm(() => {
4407
4407
  OkRevokeGrantResponseSchema,
4408
4408
  OkApprovalRequestResponseSchema,
4409
4409
  OkApprovalLookupResponseSchema,
4410
+ OkApprovalConsumeRecordResponseSchema,
4410
4411
  OkApprovalConsumeResponseSchema,
4411
4412
  OkApprovalRevokeResponseSchema,
4412
4413
  OkApprovalListResponseSchema,
4413
4414
  OkApprovalRecordResponseSchema,
4414
- OkApprovalConsumeRecordResponseSchema,
4415
4415
  ErrorResponseSchema
4416
4416
  ]);
4417
4417
  });
@@ -4556,6 +4556,7 @@ var init_schema = __esm(() => {
4556
4556
  auto_recall: exports_external.boolean().default(true).describe("Auto-search memories before each response"),
4557
4557
  file: exports_external.boolean().default(true).describe("Maintain a curated workspace MEMORY.md file (seeded once, " + "auto-loaded every turn). Set false for hindsight-only memory: " + "the file is not seeded or re-created, so once migrated into " + "Hindsight and deleted it stays gone. Recall + directives carry " + "the memory instead. Cascade: override (per-agent wins over default)."),
4558
4558
  isolation: exports_external.enum(["default", "strict"]).default("default").describe("strict = never shared cross-agent, default = eligible for reflect"),
4559
+ profile: exports_external.string().optional().describe("Memory profile bank this agent's curated memory defaults key off — " + "the built-in disposition + observations_mission in PROFILE_MEMORY_DEFAULTS. " + "Decouples the memory profile from `extends` (the filesystem persona " + "profile), so an agent on `extends: default` can opt into the `coding` " + "memory bundle via `memory.profile: coding` without inheriting the coding " + "persona. Resolution: memory.profile → extends → DEFAULT_PROFILE (see " + "resolveMemoryProfile). Unset ⇒ byte-identical to keying off `extends`."),
4559
4560
  bank_mission: exports_external.string().optional().describe("Bank-level mission statement used during recall to contextualize " + "results. NOTE: this is an alias for the Hindsight engine's " + "`reflect_mission` field (verified live: switchroom's bank_mission " + "lands in `config.reflect_mission`). Prefer `reflect_mission` going " + "forward; `bank_mission` is retained for back-compat. If both are " + "set, `reflect_mission` wins. Cascade: override."),
4560
4561
  reflect_mission: exports_external.string().optional().describe("Mission/context steering Hindsight Reflect operations (the bank's " + "'who am I / what matters' framing applied during recall). The " + "engine-accurate name for what `bank_mission` sets. Cascade: override."),
4561
4562
  retain_mission: exports_external.string().optional().describe("Instructions for the fact extraction LLM during retain. Cascade: override."),
@@ -4849,6 +4850,8 @@ var init_schema = __esm(() => {
4849
4850
  provider: exports_external.string().min(1).optional().describe("Hindsight LLM provider (upstream `HINDSIGHT_API_LLM_PROVIDER`). " + "Defaults to `claude-code` (subscription-honest, broker-fed OAuth). " + "Any litellm-routable provider the upstream image supports is valid. " + "Serves as the GLOBAL default for every op absent a per-op override."),
4850
4851
  model: exports_external.string().min(1).optional().describe("Hindsight LLM model (upstream `HINDSIGHT_API_LLM_MODEL`). Defaults " + "to HINDSIGHT_DEFAULT_MODEL. Any model your LiteLLM proxy can route " + "is valid, e.g. `openrouter/z-ai/glm-5.2` when routing through the " + "fleet proxy. With provider=claude-code this value is ALSO exported " + "as `ANTHROPIC_MODEL` to the claude subprocess. Serves as the GLOBAL " + "default for every op absent a per-op override."),
4851
4852
  context_window: exports_external.number().int().positive().optional().describe("GLOBAL context window (tokens) of the backend serving hindsight's " + "LLM ops — the declared size switchroom derives every token budget " + "from. Set this to the real window of whatever you point " + "`hindsight.llm` at (e.g. 32768 for a llama.cpp slot launched with " + "`-c 65536 -np 2`, 131072 for a large-window OpenRouter model). " + "Absent → a per-provider default: 200000 for `claude-code`, a " + "conservative 32768 for everything else. Overflowing a local " + "backend's window does NOT error — llama.cpp context-shift silently " + "drops the system prompt and the model answers conversationally " + "with HTTP 200 — so this value is what makes the failure " + "detectable at setup time instead of never."),
4853
+ base_url: exports_external.string().min(1).optional().describe("GLOBAL LLM base URL (upstream `HINDSIGHT_API_LLM_BASE_URL`). The " + "default endpoint every op inherits absent a per-op " + "`hindsight.llm.<op>.base_url`. Optional passthrough; unset → the " + "engine's provider default. When this points at host loopback the " + "hindsight container is forced onto host networking, same as a " + "per-op base URL, so the endpoint stays reachable (#3687)."),
4854
+ api_key: exports_external.string().min(1).optional().describe("GLOBAL LLM API key (upstream `HINDSIGHT_API_LLM_API_KEY`). Literal " + "or `vault:` reference. The default credential every op inherits " + "absent a per-op `hindsight.llm.<op>.api_key`; the engine reads it as " + "a plain env fallback. Optional passthrough (#3687)."),
4852
4855
  retain: HindsightPerOpLlmSchema.optional().describe("Per-op override for the `retain` LLM op (memory ingestion). Emits " + "`HINDSIGHT_API_RETAIN_LLM_*`. Absent → uses the global model/provider."),
4853
4856
  reflect: HindsightPerOpLlmSchema.optional().describe("Per-op override for the `reflect` LLM op (synthesis / mental-model " + "refresh). Emits `HINDSIGHT_API_REFLECT_LLM_*`. Absent → uses global."),
4854
4857
  consolidation: HindsightPerOpLlmSchema.optional().describe("Per-op override for the `consolidation` LLM op (background memory " + "merge). Emits `HINDSIGHT_API_CONSOLIDATION_LLM_*`. Absent → global.")
@@ -4985,6 +4988,7 @@ var init_schema = __esm(() => {
4985
4988
  auto_recall: exports_external.boolean().optional(),
4986
4989
  file: exports_external.boolean().optional(),
4987
4990
  isolation: exports_external.enum(["default", "strict"]).optional(),
4991
+ profile: exports_external.string().optional(),
4988
4992
  directive_capture_nudge: exports_external.boolean().optional(),
4989
4993
  observation_scopes: ObservationScopesSchema,
4990
4994
  observation_scope_strategy: ObservationScopeStrategySchema,
@@ -5026,7 +5030,23 @@ var init_schema = __esm(() => {
5026
5030
  max_query_chars: exports_external.number().int().min(1).optional(),
5027
5031
  parallel: exports_external.boolean().optional(),
5028
5032
  additional_banks: exports_external.array(exports_external.string()).optional(),
5029
- sender_banks: exports_external.record(exports_external.string(), exports_external.string()).optional()
5033
+ sender_banks: exports_external.record(exports_external.string(), exports_external.string()).optional(),
5034
+ types: exports_external.array(exports_external.string()).optional(),
5035
+ skip_trivial: exports_external.boolean().optional(),
5036
+ topic_filter_mode: exports_external.enum(["soft-preamble", "hard-filter"]).optional()
5037
+ }).optional(),
5038
+ retain: exports_external.object({
5039
+ every_n_turns: exports_external.number().int().min(1).optional(),
5040
+ overlap_turns: exports_external.number().int().min(0).optional()
5041
+ }).optional(),
5042
+ bank_mission: exports_external.string().optional(),
5043
+ reflect_mission: exports_external.string().optional(),
5044
+ retain_mission: exports_external.string().optional(),
5045
+ observations_mission: exports_external.string().optional(),
5046
+ disposition: exports_external.object({
5047
+ skepticism: exports_external.number().int().min(1).max(5).optional(),
5048
+ literalism: exports_external.number().int().min(1).max(5).optional(),
5049
+ empathy: exports_external.number().int().min(1).max(5).optional()
5030
5050
  }).optional()
5031
5051
  }).optional(),
5032
5052
  schedule: exports_external.array(ScheduleEntrySchema).optional(),
@@ -4152,6 +4152,7 @@ var init_schema = __esm(() => {
4152
4152
  auto_recall: exports_external.boolean().default(true).describe("Auto-search memories before each response"),
4153
4153
  file: exports_external.boolean().default(true).describe("Maintain a curated workspace MEMORY.md file (seeded once, " + "auto-loaded every turn). Set false for hindsight-only memory: " + "the file is not seeded or re-created, so once migrated into " + "Hindsight and deleted it stays gone. Recall + directives carry " + "the memory instead. Cascade: override (per-agent wins over default)."),
4154
4154
  isolation: exports_external.enum(["default", "strict"]).default("default").describe("strict = never shared cross-agent, default = eligible for reflect"),
4155
+ profile: exports_external.string().optional().describe("Memory profile bank this agent's curated memory defaults key off — " + "the built-in disposition + observations_mission in PROFILE_MEMORY_DEFAULTS. " + "Decouples the memory profile from `extends` (the filesystem persona " + "profile), so an agent on `extends: default` can opt into the `coding` " + "memory bundle via `memory.profile: coding` without inheriting the coding " + "persona. Resolution: memory.profile → extends → DEFAULT_PROFILE (see " + "resolveMemoryProfile). Unset ⇒ byte-identical to keying off `extends`."),
4155
4156
  bank_mission: exports_external.string().optional().describe("Bank-level mission statement used during recall to contextualize " + "results. NOTE: this is an alias for the Hindsight engine's " + "`reflect_mission` field (verified live: switchroom's bank_mission " + "lands in `config.reflect_mission`). Prefer `reflect_mission` going " + "forward; `bank_mission` is retained for back-compat. If both are " + "set, `reflect_mission` wins. Cascade: override."),
4156
4157
  reflect_mission: exports_external.string().optional().describe("Mission/context steering Hindsight Reflect operations (the bank's " + "'who am I / what matters' framing applied during recall). The " + "engine-accurate name for what `bank_mission` sets. Cascade: override."),
4157
4158
  retain_mission: exports_external.string().optional().describe("Instructions for the fact extraction LLM during retain. Cascade: override."),
@@ -4445,6 +4446,8 @@ var init_schema = __esm(() => {
4445
4446
  provider: exports_external.string().min(1).optional().describe("Hindsight LLM provider (upstream `HINDSIGHT_API_LLM_PROVIDER`). " + "Defaults to `claude-code` (subscription-honest, broker-fed OAuth). " + "Any litellm-routable provider the upstream image supports is valid. " + "Serves as the GLOBAL default for every op absent a per-op override."),
4446
4447
  model: exports_external.string().min(1).optional().describe("Hindsight LLM model (upstream `HINDSIGHT_API_LLM_MODEL`). Defaults " + "to HINDSIGHT_DEFAULT_MODEL. Any model your LiteLLM proxy can route " + "is valid, e.g. `openrouter/z-ai/glm-5.2` when routing through the " + "fleet proxy. With provider=claude-code this value is ALSO exported " + "as `ANTHROPIC_MODEL` to the claude subprocess. Serves as the GLOBAL " + "default for every op absent a per-op override."),
4447
4448
  context_window: exports_external.number().int().positive().optional().describe("GLOBAL context window (tokens) of the backend serving hindsight's " + "LLM ops — the declared size switchroom derives every token budget " + "from. Set this to the real window of whatever you point " + "`hindsight.llm` at (e.g. 32768 for a llama.cpp slot launched with " + "`-c 65536 -np 2`, 131072 for a large-window OpenRouter model). " + "Absent → a per-provider default: 200000 for `claude-code`, a " + "conservative 32768 for everything else. Overflowing a local " + "backend's window does NOT error — llama.cpp context-shift silently " + "drops the system prompt and the model answers conversationally " + "with HTTP 200 — so this value is what makes the failure " + "detectable at setup time instead of never."),
4449
+ base_url: exports_external.string().min(1).optional().describe("GLOBAL LLM base URL (upstream `HINDSIGHT_API_LLM_BASE_URL`). The " + "default endpoint every op inherits absent a per-op " + "`hindsight.llm.<op>.base_url`. Optional passthrough; unset → the " + "engine's provider default. When this points at host loopback the " + "hindsight container is forced onto host networking, same as a " + "per-op base URL, so the endpoint stays reachable (#3687)."),
4450
+ api_key: exports_external.string().min(1).optional().describe("GLOBAL LLM API key (upstream `HINDSIGHT_API_LLM_API_KEY`). Literal " + "or `vault:` reference. The default credential every op inherits " + "absent a per-op `hindsight.llm.<op>.api_key`; the engine reads it as " + "a plain env fallback. Optional passthrough (#3687)."),
4448
4451
  retain: HindsightPerOpLlmSchema.optional().describe("Per-op override for the `retain` LLM op (memory ingestion). Emits " + "`HINDSIGHT_API_RETAIN_LLM_*`. Absent → uses the global model/provider."),
4449
4452
  reflect: HindsightPerOpLlmSchema.optional().describe("Per-op override for the `reflect` LLM op (synthesis / mental-model " + "refresh). Emits `HINDSIGHT_API_REFLECT_LLM_*`. Absent → uses global."),
4450
4453
  consolidation: HindsightPerOpLlmSchema.optional().describe("Per-op override for the `consolidation` LLM op (background memory " + "merge). Emits `HINDSIGHT_API_CONSOLIDATION_LLM_*`. Absent → global.")
@@ -4581,6 +4584,7 @@ var init_schema = __esm(() => {
4581
4584
  auto_recall: exports_external.boolean().optional(),
4582
4585
  file: exports_external.boolean().optional(),
4583
4586
  isolation: exports_external.enum(["default", "strict"]).optional(),
4587
+ profile: exports_external.string().optional(),
4584
4588
  directive_capture_nudge: exports_external.boolean().optional(),
4585
4589
  observation_scopes: ObservationScopesSchema,
4586
4590
  observation_scope_strategy: ObservationScopeStrategySchema,
@@ -4622,7 +4626,23 @@ var init_schema = __esm(() => {
4622
4626
  max_query_chars: exports_external.number().int().min(1).optional(),
4623
4627
  parallel: exports_external.boolean().optional(),
4624
4628
  additional_banks: exports_external.array(exports_external.string()).optional(),
4625
- sender_banks: exports_external.record(exports_external.string(), exports_external.string()).optional()
4629
+ sender_banks: exports_external.record(exports_external.string(), exports_external.string()).optional(),
4630
+ types: exports_external.array(exports_external.string()).optional(),
4631
+ skip_trivial: exports_external.boolean().optional(),
4632
+ topic_filter_mode: exports_external.enum(["soft-preamble", "hard-filter"]).optional()
4633
+ }).optional(),
4634
+ retain: exports_external.object({
4635
+ every_n_turns: exports_external.number().int().min(1).optional(),
4636
+ overlap_turns: exports_external.number().int().min(0).optional()
4637
+ }).optional(),
4638
+ bank_mission: exports_external.string().optional(),
4639
+ reflect_mission: exports_external.string().optional(),
4640
+ retain_mission: exports_external.string().optional(),
4641
+ observations_mission: exports_external.string().optional(),
4642
+ disposition: exports_external.object({
4643
+ skepticism: exports_external.number().int().min(1).max(5).optional(),
4644
+ literalism: exports_external.number().int().min(1).max(5).optional(),
4645
+ empathy: exports_external.number().int().min(1).max(5).optional()
4626
4646
  }).optional()
4627
4647
  }).optional(),
4628
4648
  schedule: exports_external.array(ScheduleEntrySchema).optional(),
@@ -19406,11 +19426,11 @@ var init_protocol = __esm(() => {
19406
19426
  OkRevokeGrantResponseSchema,
19407
19427
  OkApprovalRequestResponseSchema,
19408
19428
  OkApprovalLookupResponseSchema,
19429
+ OkApprovalConsumeRecordResponseSchema,
19409
19430
  OkApprovalConsumeResponseSchema,
19410
19431
  OkApprovalRevokeResponseSchema,
19411
19432
  OkApprovalListResponseSchema,
19412
19433
  OkApprovalRecordResponseSchema,
19413
- OkApprovalConsumeRecordResponseSchema,
19414
19434
  ErrorResponseSchema
19415
19435
  ]);
19416
19436
  });
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "switchroom",
3
3
  "//version": "NOT the release version — source of truth is the git tag, resolved by scripts/build.mjs:resolveVersion() (see CLAUDE.md > Standard release process). This field is stale by design and only the Layer-4 dev/non-tag fallback for build.mjs + src/cli/resolve-version.ts; do NOT bump it expecting a release to pick it up. npm-pack tarball naming needs a real version — do that as an UNCOMMITTED pack-time bump (see release step 6), never a committed one.",
4
- "version": "0.19.40",
4
+ "version": "0.19.42",
5
5
  "description": "Run Claude Code 24/7 on your Claude Pro/Max subscription over Telegram. Open-source alternative to OpenClaw and NanoClaw — no API keys.",
6
6
  "type": "module",
7
7
  "bin": {
@@ -268,7 +268,7 @@ const TOOL_SCHEMAS = [
268
268
  {
269
269
  name: 'send_checklist',
270
270
  description:
271
- 'Send a native Telegram checklist (interactive task list) to a chat. Users can tick tasks directly in the Telegram app. Returns the message_id of the created checklist. The bot is notified when tasks are ticked these arrive as channel events with kind="checklist_task_changed". Limit: 30 tasks per checklist.',
271
+ 'Send a checklist (task list) to a chat. Native interactive Telegram checklists require a Business-account connection, which most deployments do not have — in that normal case the checklist is sent as a formatted TEXT message (bold title + ✅/⬜ task lines) and the result carries degraded:"text": tasks are NOT tappable, and you tick them yourself via update_checklist (task ids are 1..N in send order). With a Business connection configured, the checklist is sent natively and tick events arrive as channel events with kind="checklist_task_changed". Returns JSON with message_id and mode. Limit: 30 tasks.',
272
272
  inputSchema: {
273
273
  type: 'object',
274
274
  properties: {
@@ -357,7 +357,7 @@ const TOOL_SCHEMAS = [
357
357
  {
358
358
  name: 'update_checklist',
359
359
  description:
360
- 'Patch an existing native Telegram checklist. Supports updating the title, adding new tasks, removing tasks, or marking tasks done/undone. Tasks with an id target existing items; tasks without an id are appended. Preserves existing task ids across edits.',
360
+ 'Patch a checklist previously sent with send_checklist: update the title, append tasks, or mark tasks done/undone. Tasks with an id target existing items (ids are 1..N in send order for text-mode checklists); tasks without an id are appended. Removal is not supported. The edit re-renders in the mode the checklist was sent in (text for most deployments). Returns JSON { ok, ... }; after a gateway restart the stored task state may be gone — then it returns ok:false with reason "unknown_checklist" unless you pass a full replacement (title + every task\'s text).',
361
361
  inputSchema: {
362
362
  type: 'object',
363
363
  properties: {
@@ -25241,7 +25241,7 @@ var TOOL_SCHEMAS = [
25241
25241
  },
25242
25242
  {
25243
25243
  name: "send_checklist",
25244
- description: 'Send a native Telegram checklist (interactive task list) to a chat. Users can tick tasks directly in the Telegram app. Returns the message_id of the created checklist. The bot is notified when tasks are ticked \u2014 these arrive as channel events with kind="checklist_task_changed". Limit: 30 tasks per checklist.',
25244
+ description: 'Send a checklist (task list) to a chat. Native interactive Telegram checklists require a Business-account connection, which most deployments do not have \u2014 in that normal case the checklist is sent as a formatted TEXT message (bold title + \u2705/\u2B1C task lines) and the result carries degraded:"text": tasks are NOT tappable, and you tick them yourself via update_checklist (task ids are 1..N in send order). With a Business connection configured, the checklist is sent natively and tick events arrive as channel events with kind="checklist_task_changed". Returns JSON with message_id and mode. Limit: 30 tasks.',
25245
25245
  inputSchema: {
25246
25246
  type: "object",
25247
25247
  properties: {
@@ -25326,7 +25326,7 @@ var TOOL_SCHEMAS = [
25326
25326
  },
25327
25327
  {
25328
25328
  name: "update_checklist",
25329
- description: "Patch an existing native Telegram checklist. Supports updating the title, adding new tasks, removing tasks, or marking tasks done/undone. Tasks with an id target existing items; tasks without an id are appended. Preserves existing task ids across edits.",
25329
+ description: `Patch a checklist previously sent with send_checklist: update the title, append tasks, or mark tasks done/undone. Tasks with an id target existing items (ids are 1..N in send order for text-mode checklists); tasks without an id are appended. Removal is not supported. The edit re-renders in the mode the checklist was sent in (text for most deployments). Returns JSON { ok, ... }; after a gateway restart the stored task state may be gone \u2014 then it returns ok:false with reason "unknown_checklist" unless you pass a full replacement (title + every task's text).`,
25330
25330
  inputSchema: {
25331
25331
  type: "object",
25332
25332
  properties: {