switchroom 0.20.17 → 0.20.19

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.
@@ -22037,7 +22037,13 @@ var init_schema = __esm(() => {
22037
22037
  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."),
22038
22038
  consolidation: HindsightPerOpLlmSchema.optional().describe("Per-op override for the `consolidation` LLM op (background memory " + "merge). Emits `HINDSIGHT_API_CONSOLIDATION_LLM_*`. Absent \u2192 global.")
22039
22039
  }).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."),
22040
- 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; and " + "HINDSIGHT_API_TEMPORAL_MAX_QUERY_CHARS \u2014 the max chars of query text " + "dateparser.search_dates() is handed during temporal analysis (0 = " + "unlimited), made live by switchroom's temporal-offload image patch " + "(which moved the synchronous extraction off the shared asyncio loop onto " + "a single-worker thread and bounds its input, ending multi-second loop " + "stalls on multi-KB consolidation queries); unset means the image's baked " + "2000, set 0 to restore an unbounded full scan); and " + "HINDSIGHT_API_TEXT_SEARCH_EXTENSION_NATIVE_LANGUAGE \u2014 the Postgres " + "text-search regconfig the native BM25 arms and the search_vector index " + "write run to_tsvector/to_tsquery against; unset means upstream's " + "always-safe `english`, set `hindsight_english` to use switchroom's " + "junk-stopping config (dict + stopword file provisioned durably by the " + "image entrypoint, recall degrading to semantic-only if it is ever " + "missing); and " + "HINDSIGHT_API_BM25_MAX_QUERY_TERMS \u2014 the max number of query tokens the " + "keyword (BM25) recall arm searches for; unset means upstream's 0 = " + "unbounded, which makes a multi-KB consolidation query a disjunction " + "over hundreds of terms; set e.g. 64 to cap it, at the cost of " + "silently dropping the tail of a long query; 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).")
22040
+ recall_pool: exports_external.object({
22041
+ enabled: exports_external.boolean().optional().describe("Turn on the recall/background WORKER SPLIT: a second container, " + "`switchroom-hindsight-recall`, serves recall/reflect only with N " + "uvicorn workers, while the existing `switchroom-hindsight` " + "container keeps pg0, the single background WorkerPoller, the " + "healthcheck and all consolidation/retain processing but moves off " + "the public port onto public+1. The public port (memory.config.url) " + "does not change \u2014 the pool binds it instead. Absent/false (the " + "default) \u2192 the single-container topology, unchanged. Opt-in only. " + "Raises recall throughput ~2.2x on the fleet (2.6\u21925.6 rps)."),
22042
+ workers: exports_external.number().int().positive().optional().describe("uvicorn `--workers` for the recall pool (HINDSIGHT_API_WORKERS). " + "Default 4. Each worker holds its own GPU cross-encoder reranker, " + "so past ~4 workers contend for VRAM rather than adding throughput " + "on a single GPU \u2014 raise only on a bigger GPU or a CPU reranker. " + "The per-worker DB pools are auto-sized down from the pg0 " + "connection budget so N*(write+read)+60 background stays under " + "max_connections=250; a worker count that would overflow that " + "budget is rejected at launch."),
22043
+ db_pool_max_size: exports_external.number().int().positive().optional().describe("Override the per-worker WRITE pool cap " + "(HINDSIGHT_API_DB_POOL_MAX_SIZE). Absent \u2192 auto-sized from the " + "worker count. Set this only to override the auto-sizing; the " + "connection-budget check still applies and rejects an overflow."),
22044
+ read_db_pool_max_size: exports_external.number().int().positive().optional().describe("Override the per-worker READ pool cap " + "(HINDSIGHT_API_READ_DB_POOL_MAX_SIZE). Absent \u2192 auto-sized from " + "the worker count. Set this only to override the auto-sizing; the " + "connection-budget check still applies and rejects an overflow.")
22045
+ }).optional().describe("Optional recall/background container split for the hindsight " + "singleton. Off by default; see `enabled`. Provisioned by " + "`switchroom memory setup` (src/setup/hindsight-recall-pool.ts) so it " + "survives `switchroom apply` \u2014 the hand-applied topology it replaces " + "did not."),
22046
+ 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_QUERY_ANALYZER_LANGUAGES \u2014 the language set dateparser is " + "restricted to during temporal query analysis (upstream #3154, which " + "superseded switchroom's own temporal-language image patch at v0.9.0); " + "comma-separated; switchroom EMITS `en` on every host because upstream's " + "unset default auto-detects across 200+ locales inline on the shared " + "asyncio loop (~165x slower per call), set e.g. `en,es` for i18n parsing; " + "and " + "HINDSIGHT_API_TEMPORAL_MAX_QUERY_CHARS \u2014 the max chars of query text " + "dateparser.search_dates() is handed during temporal analysis (0 = " + "unlimited), made live by switchroom's temporal-offload image patch " + "(which moved the synchronous extraction off the shared asyncio loop onto " + "a single-worker thread and bounds its input, ending multi-second loop " + "stalls on multi-KB consolidation queries); unset means the image's baked " + "2000, set 0 to restore an unbounded full scan); and " + "HINDSIGHT_API_TEXT_SEARCH_EXTENSION_NATIVE_LANGUAGE \u2014 the Postgres " + "text-search regconfig the native BM25 arms and the search_vector index " + "write run to_tsvector/to_tsquery against; unset means upstream's " + "always-safe `english`, set `hindsight_english` to use switchroom's " + "junk-stopping config (dict + stopword file provisioned durably by the " + "image entrypoint, recall degrading to semantic-only if it is ever " + "missing); and " + "HINDSIGHT_API_BM25_MAX_QUERY_TERMS \u2014 the max number of query tokens the " + "keyword (BM25) recall arm searches for; unset means upstream's 0 = " + "unbounded, which makes a multi-KB consolidation query a disjunction " + "over hundreds of terms; set e.g. 64 to cap it, at the cost of " + "silently dropping the tail of a long query; and " + "HINDSIGHT_API_EMBEDDINGS_PROVIDER with the four " + "HINDSIGHT_API_EMBEDDINGS_ONNX_{MODEL_ID,POOLING,QUERY_PREFIX," + "PASSAGE_PREFIX} keys \u2014 the ONNX-embeddings cutover: unset keeps " + "upstream's slower `local` (PyTorch) backend, set `onnx` plus the model " + "id/pooling to run the SAME model on ONNX-CPU at a fraction of the " + "latency; the two _PREFIX keys are the query/passage affixes and are " + "set to the empty string for bge parity (vectors are byte-identical " + "between the two backends, so no re-embedding is needed) \u2014 unusually " + "for this block an EMPTY value here is honoured, not dropped, because an " + "affix-free prefix is the intended value; and the v0.9.0 knobs " + "switchroom allowlists for reach but emits no value for \u2014 " + "HINDSIGHT_API_RERANKER_MAX_CANDIDATES_{LOW,MID,HIGH} (per-recall-budget " + "rerank caps; unset/0 falls back to the global " + "HINDSIGHT_API_RERANKER_MAX_CANDIDATES switchroom does pin), " + "HINDSIGHT_API_EMBEDDINGS_MAX_INPUT_TOKENS (embedding-input truncation " + "ceiling; unset means the model's own limit), " + "HINDSIGHT_API_ENTITY_TRGM_SIMILARITY_THRESHOLD (entity-resolution fuzzy " + "match floor; unset means upstream's 0.15) and " + "HINDSIGHT_API_ENABLE_{TEMPORAL_RETRIEVAL,GRAPH_RETRIEVAL,RERANKING} " + "(global per-stage kill switches, all default true \u2014 the emergency lever " + "if one retrieval stage is implicated in a latency incident, at the cost " + "of recall quality); 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).")
22041
22047
  });
22042
22048
  MicrosoftWorkspaceConfigSchema = exports_external.object({
22043
22049
  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)."),
@@ -41878,6 +41884,7 @@ async function createTelegraphPage(args) {
41878
41884
  }
41879
41885
  };
41880
41886
  }
41887
+ var TELEGRAPH_QUOTE_LINE = /^(?:\*\*)?>\s?/;
41881
41888
  function markdownToTelegraphNodes(text) {
41882
41889
  const nodes = [];
41883
41890
  const lines = text.split(/\r?\n/);
@@ -41933,10 +41940,10 @@ function markdownToTelegraphNodes(text) {
41933
41940
  nodes.push({ tag: "ol", children: items });
41934
41941
  continue;
41935
41942
  }
41936
- if (/^>\s?/.test(line)) {
41943
+ if (TELEGRAPH_QUOTE_LINE.test(line)) {
41937
41944
  const quoted = [];
41938
- while (i < lines.length && /^>\s?/.test(lines[i])) {
41939
- quoted.push(lines[i].replace(/^>\s?/, ""));
41945
+ while (i < lines.length && TELEGRAPH_QUOTE_LINE.test(lines[i])) {
41946
+ quoted.push(lines[i].replace(TELEGRAPH_QUOTE_LINE, ""));
41940
41947
  i++;
41941
41948
  }
41942
41949
  nodes.push({ tag: "blockquote", children: parseInline(quoted.join(" ")) });
@@ -41953,7 +41960,7 @@ function markdownToTelegraphNodes(text) {
41953
41960
  return nodes;
41954
41961
  }
41955
41962
  function isBlockStart(line) {
41956
- return /^#{1,2}\s/.test(line) || /^[-*]\s+/.test(line) || /^\d+\.\s+/.test(line) || line.trim().startsWith("```") || /^>\s?/.test(line);
41963
+ return /^#{1,2}\s/.test(line) || /^[-*]\s+/.test(line) || /^\d+\.\s+/.test(line) || line.trim().startsWith("```") || TELEGRAPH_QUOTE_LINE.test(line);
41957
41964
  }
41958
41965
  function parseInline(text) {
41959
41966
  const out = [];
@@ -46507,6 +46514,8 @@ var TELEGRAM_MENU_COMMANDS = [
46507
46514
  { command: "new", description: "Fresh session (flush handoff, restart)" },
46508
46515
  { command: "compact", description: "Compact context (summarize, keep the thread)" },
46509
46516
  { command: "clear", description: "Clear context (fresh slate; memory in Hindsight)" },
46517
+ { command: "private", description: "Pause saving this session to memory" },
46518
+ { command: "public", description: "Resume saving this session to memory" },
46510
46519
  { command: "approve", description: "Approve pending tool permission" },
46511
46520
  { command: "deny", description: "Deny pending tool permission" },
46512
46521
  { command: "pending", description: "List pending permission prompts" },
@@ -46533,6 +46542,8 @@ function switchroomHelpText(agentName) {
46533
46542
  `\`/new\` \u2014 fresh session (flush handoff, restart)`,
46534
46543
  `\`/compact\` \u2014 compact context (summarize, keep the thread)`,
46535
46544
  `\`/clear\` \u2014 clear context (fresh slate; memory in Hindsight)`,
46545
+ `\`/private\` \u2014 pause saving this session to memory`,
46546
+ `\`/public\` \u2014 resume saving this session to memory`,
46536
46547
  `\`/approve [id]\` \u2014 approve pending tool permission`,
46537
46548
  `\`/deny [id]\` \u2014 deny pending tool permission`,
46538
46549
  `\`/pending\` \u2014 list pending permission prompts`,
@@ -84760,6 +84771,8 @@ var TELEGRAM_MENU_COMMANDS2 = [
84760
84771
  { command: "new", description: "Fresh session (flush handoff, restart)" },
84761
84772
  { command: "compact", description: "Compact context (summarize, keep the thread)" },
84762
84773
  { command: "clear", description: "Clear context (fresh slate; memory in Hindsight)" },
84774
+ { command: "private", description: "Pause saving this session to memory" },
84775
+ { command: "public", description: "Resume saving this session to memory" },
84763
84776
  { command: "approve", description: "Approve pending tool permission" },
84764
84777
  { command: "deny", description: "Deny pending tool permission" },
84765
84778
  { command: "pending", description: "List pending permission prompts" },
@@ -88030,6 +88043,7 @@ var HINDSIGHT_DEFAULT_LLM_SUPPORTS_MAX_ITEMS = "false";
88030
88043
  var HINDSIGHT_DEFAULT_RECENCY_DECAY_FUNCTION = "exponential";
88031
88044
  var HINDSIGHT_DEFAULT_RECENCY_DECAY_HALFLIFE_DAYS = 30;
88032
88045
  var HINDSIGHT_DEFAULT_TEXT_SEARCH_EXTENSION = "pg_search";
88046
+ var HINDSIGHT_DEFAULT_QUERY_ANALYZER_LANGUAGES = "en";
88033
88047
  var HINDSIGHT_PERF_DEFAULTS_UNGATED = [
88034
88048
  [
88035
88049
  "HINDSIGHT_API_RECALL_MAX_CANDIDATES_PER_SOURCE",
@@ -88096,7 +88110,11 @@ var HINDSIGHT_PERF_DEFAULTS_UNGATED = [
88096
88110
  "HINDSIGHT_API_GRAPH_SEED_MIN_SIMILARITY",
88097
88111
  String(HINDSIGHT_DEFAULT_GRAPH_SEED_MIN_SIMILARITY)
88098
88112
  ],
88099
- ["HINDSIGHT_API_TEXT_SEARCH_EXTENSION", HINDSIGHT_DEFAULT_TEXT_SEARCH_EXTENSION]
88113
+ ["HINDSIGHT_API_TEXT_SEARCH_EXTENSION", HINDSIGHT_DEFAULT_TEXT_SEARCH_EXTENSION],
88114
+ [
88115
+ "HINDSIGHT_API_QUERY_ANALYZER_LANGUAGES",
88116
+ HINDSIGHT_DEFAULT_QUERY_ANALYZER_LANGUAGES
88117
+ ]
88100
88118
  ];
88101
88119
  var HINDSIGHT_PERF_DEFAULTS_GPU = [
88102
88120
  ["HINDSIGHT_API_RERANKER_LOCAL_FP16", HINDSIGHT_DEFAULT_RERANKER_LOCAL_FP16],
@@ -88131,10 +88149,26 @@ var HINDSIGHT_PERF_OVERRIDE_ONLY_KEYS = new Set([
88131
88149
  "HINDSIGHT_API_RETAIN_WALL_TIMEOUT",
88132
88150
  "HINDSIGHT_API_CONSOLIDATION_RECALL_MAX_CONCURRENT",
88133
88151
  "HINDSIGHT_MM_REFRESH_MIN_INTERVAL_S",
88134
- "HINDSIGHT_API_TEMPORAL_LANGUAGES",
88135
88152
  "HINDSIGHT_API_TEMPORAL_MAX_QUERY_CHARS",
88136
88153
  "HINDSIGHT_API_TEXT_SEARCH_EXTENSION_NATIVE_LANGUAGE",
88137
- "HINDSIGHT_API_BM25_MAX_QUERY_TERMS"
88154
+ "HINDSIGHT_API_BM25_MAX_QUERY_TERMS",
88155
+ "HINDSIGHT_API_EMBEDDINGS_PROVIDER",
88156
+ "HINDSIGHT_API_EMBEDDINGS_ONNX_MODEL_ID",
88157
+ "HINDSIGHT_API_EMBEDDINGS_ONNX_POOLING",
88158
+ "HINDSIGHT_API_EMBEDDINGS_ONNX_QUERY_PREFIX",
88159
+ "HINDSIGHT_API_EMBEDDINGS_ONNX_PASSAGE_PREFIX",
88160
+ "HINDSIGHT_API_RERANKER_MAX_CANDIDATES_LOW",
88161
+ "HINDSIGHT_API_RERANKER_MAX_CANDIDATES_MID",
88162
+ "HINDSIGHT_API_RERANKER_MAX_CANDIDATES_HIGH",
88163
+ "HINDSIGHT_API_EMBEDDINGS_MAX_INPUT_TOKENS",
88164
+ "HINDSIGHT_API_ENTITY_TRGM_SIMILARITY_THRESHOLD",
88165
+ "HINDSIGHT_API_ENABLE_TEMPORAL_RETRIEVAL",
88166
+ "HINDSIGHT_API_ENABLE_GRAPH_RETRIEVAL",
88167
+ "HINDSIGHT_API_ENABLE_RERANKING"
88168
+ ]);
88169
+ var HINDSIGHT_PERF_ALLOW_EMPTY_KEYS = new Set([
88170
+ "HINDSIGHT_API_EMBEDDINGS_ONNX_QUERY_PREFIX",
88171
+ "HINDSIGHT_API_EMBEDDINGS_ONNX_PASSAGE_PREFIX"
88138
88172
  ]);
88139
88173
  var HINDSIGHT_WORKER_SLOT_TYPES = [
88140
88174
  "consolidation",
@@ -88148,6 +88182,15 @@ var HINDSIGHT_WORKER_RESERVED_SLOT_ALIASES = new Map(HINDSIGHT_WORKER_SLOT_TYPES
88148
88182
  `HINDSIGHT_API_WORKER_${type.toUpperCase()}_MAX_SLOTS`,
88149
88183
  `HINDSIGHT_API_WORKER_${type.toUpperCase()}_RESERVED_SLOTS`
88150
88184
  ]));
88185
+ var HINDSIGHT_RECALL_POOL_ENV_KEYS = [
88186
+ "HINDSIGHT_API_WORKERS",
88187
+ "HINDSIGHT_API_WORKER_ENABLED",
88188
+ "HINDSIGHT_API_DATABASE_URL",
88189
+ "HINDSIGHT_API_DB_URL",
88190
+ "HINDSIGHT_API_DB_POOL_MAX_SIZE",
88191
+ "HINDSIGHT_API_READ_DB_POOL_MAX_SIZE",
88192
+ "HINDSIGHT_API_RUN_MIGRATIONS_ON_STARTUP"
88193
+ ];
88151
88194
  var HINDSIGHT_PERF_ENV_KEYS = new Set([
88152
88195
  ...[
88153
88196
  ...HINDSIGHT_PERF_DEFAULTS_UNGATED,
@@ -88156,7 +88199,8 @@ var HINDSIGHT_PERF_ENV_KEYS = new Set([
88156
88199
  ].map(([k]) => k),
88157
88200
  ...HINDSIGHT_PERF_OVERRIDE_ONLY_KEYS,
88158
88201
  ...HINDSIGHT_WORKER_RESERVED_SLOT_ALIASES.keys(),
88159
- ...HINDSIGHT_WORKER_RESERVED_SLOT_ALIASES.values()
88202
+ ...HINDSIGHT_WORKER_RESERVED_SLOT_ALIASES.values(),
88203
+ ...HINDSIGHT_RECALL_POOL_ENV_KEYS
88160
88204
  ]);
88161
88205
 
88162
88206
  // ../src/setup/hindsight-context-budget.ts
@@ -103439,10 +103483,10 @@ function startOutboxSweep(deps) {
103439
103483
  }
103440
103484
 
103441
103485
  // ../src/build-info.ts
103442
- var VERSION2 = "0.20.17";
103443
- var COMMIT_SHA = "75253052";
103444
- var COMMIT_DATE = "2026-08-08T01:54:42Z";
103445
- var LATEST_PR = 4522;
103486
+ var VERSION2 = "0.20.19";
103487
+ var COMMIT_SHA = "552a2d21";
103488
+ var COMMIT_DATE = "2026-08-09T02:06:44Z";
103489
+ var LATEST_PR = 4563;
103446
103490
  var COMMITS_AHEAD_OF_TAG = 0;
103447
103491
 
103448
103492
  // gateway/boot-version.ts
@@ -192,6 +192,18 @@ export async function createTelegraphPage(
192
192
  }
193
193
  }
194
194
 
195
+ /**
196
+ * A blockquote line: a plain `> ` marker OR the expandable-blockquote opener
197
+ * `**> ` (Bot API 10.1 syntax the switchroom render path emits on the first
198
+ * line of an expandable quote — see `render/render.ts` and
199
+ * `reference/telegram-formatting-guide.md`). Telegra.ph has no collapsible
200
+ * blockquote tag, so an expandable quote degrades to a normal `<blockquote>`;
201
+ * the `**` prefix must still be recognised and stripped here, else the
202
+ * unterminated `**` renders as literal `**>` text and the `>` continuation
203
+ * lines split off into a second, detached quote.
204
+ */
205
+ const TELEGRAPH_QUOTE_LINE = /^(?:\*\*)?>\s?/
206
+
195
207
  /**
196
208
  * Convert reply text (markdown-ish) into Telegraph node structure.
197
209
  *
@@ -278,11 +290,15 @@ export function markdownToTelegraphNodes(text: string): TelegraphNode[] {
278
290
  continue
279
291
  }
280
292
 
281
- // Blockquote.
282
- if (/^>\s?/.test(line)) {
293
+ // Blockquote — plain `> …` OR an expandable `**> …` opener followed by
294
+ // `> …` continuation lines. Both collapse into one <blockquote> with the
295
+ // markers stripped (Telegra.ph has no expandable-blockquote tag, so the
296
+ // expandable quote degrades faithfully to a normal one; the `**>` marker is
297
+ // stripped so no literal `**>` leaks and the summary stays with its body).
298
+ if (TELEGRAPH_QUOTE_LINE.test(line)) {
283
299
  const quoted: string[] = []
284
- while (i < lines.length && /^>\s?/.test(lines[i])) {
285
- quoted.push(lines[i].replace(/^>\s?/, ''))
300
+ while (i < lines.length && TELEGRAPH_QUOTE_LINE.test(lines[i])) {
301
+ quoted.push(lines[i].replace(TELEGRAPH_QUOTE_LINE, ''))
286
302
  i++
287
303
  }
288
304
  nodes.push({ tag: 'blockquote', children: parseInline(quoted.join(' ')) })
@@ -310,7 +326,9 @@ function isBlockStart(line: string): boolean {
310
326
  /^[-*]\s+/.test(line) ||
311
327
  /^\d+\.\s+/.test(line) ||
312
328
  line.trim().startsWith('```') ||
313
- /^>\s?/.test(line)
329
+ // A `**>` expandable-quote opener is a block start too, so a preceding
330
+ // paragraph does not absorb it (which is what left the `**>` literal).
331
+ TELEGRAPH_QUOTE_LINE.test(line)
314
332
  )
315
333
  }
316
334
 
@@ -164,6 +164,40 @@ describe('markdownToTelegraphNodes — block elements', () => {
164
164
  expect(r[0].tag).toBe('blockquote')
165
165
  })
166
166
 
167
+ it('folds an expandable `**>` quote into one blockquote, marker stripped', () => {
168
+ // The Bot API 10.1 expandable-blockquote syntax: `**>` opener on the first
169
+ // line, `>` continuation lines. Telegra.ph has no collapsible-blockquote
170
+ // tag, so it degrades to a normal blockquote — but the `**>` marker MUST be
171
+ // recognised. Before the fix the `**>` line became a paragraph with literal
172
+ // `**>` text and the `>` lines split into a detached second quote.
173
+ const r = markdownToTelegraphNodes('**> summary of the thing\n> body one\n> body two')
174
+ expect(r).toHaveLength(1)
175
+ expect(r[0].tag).toBe('blockquote')
176
+ // Summary and body are joined in the single quote, no literal `**>` leaks.
177
+ const flat = JSON.stringify(r)
178
+ expect(flat).not.toContain('**>')
179
+ expect(flat).not.toContain('*') // no stray bold delimiter survives
180
+ expect(flat).toContain('summary of the thing')
181
+ expect(flat).toContain('body one')
182
+ expect(flat).toContain('body two')
183
+ })
184
+
185
+ it('does not let a paragraph absorb a following `**>` opener', () => {
186
+ // isBlockStart must treat `**>` as a block start so the preceding line ends
187
+ // the paragraph instead of swallowing the quote (which left the `**>`
188
+ // literal glued into prose).
189
+ const r = markdownToTelegraphNodes('Intro line\n**> quoted summary')
190
+ expect(r.map((n) => n.tag)).toEqual(['p', 'blockquote'])
191
+ expect(r[0].children).toEqual(['Intro line'])
192
+ })
193
+
194
+ it('does not misread a line that merely opens with bold text', () => {
195
+ // `**` is only a quote marker when `>` follows it immediately. A line
196
+ // starting with real bold must stay a paragraph, not become a blockquote.
197
+ const r = markdownToTelegraphNodes('**bold** > x')
198
+ expect(r.map((n) => n.tag)).toEqual(['p'])
199
+ })
200
+
167
201
  it('handles a mixed document end-to-end', () => {
168
202
  const md = '# Title\n\nIntro paragraph.\n\n## Steps\n\n- one\n- two\n\nFinal note.'
169
203
  const r = markdownToTelegraphNodes(md)
@@ -533,11 +533,12 @@ describe("TELEGRAM_MENU_COMMANDS (slash-menu shape)", () => {
533
533
  ).not.toMatch(/`\/reauth\b/);
534
534
  });
535
535
 
536
- it("menu is short enough for a mobile keyboard (<= 21 entries)", () => {
536
+ it("menu is short enough for a mobile keyboard (<= 23 entries)", () => {
537
537
  // Hard cap: Telegram autocomplete on mobile shows ~8-10 commands
538
- // without scrolling. 21 is a generous upper bound (well under
539
- // Telegram's own 100-command limit). /whoami brought it to 21.
540
- expect(TELEGRAM_MENU_COMMANDS.length).toBeLessThanOrEqual(21);
538
+ // without scrolling. 23 is a generous upper bound (well under
539
+ // Telegram's own 100-command limit). /whoami brought it to 21;
540
+ // /private + /public (autocomplete for the shipped handlers) → 23.
541
+ expect(TELEGRAM_MENU_COMMANDS.length).toBeLessThanOrEqual(23);
541
542
  });
542
543
 
543
544
  it("menu includes /whoami (sandbox introspection)", () => {
@@ -356,6 +356,11 @@ export const TELEGRAM_MENU_COMMANDS = [
356
356
  { command: "new", description: "Fresh session (flush handoff, restart)" },
357
357
  { command: "compact", description: "Compact context (summarize, keep the thread)" },
358
358
  { command: "clear", description: "Clear context (fresh slate; memory in Hindsight)" },
359
+ // Privacy — pause/resume Hindsight auto-retain for this session
360
+ // (session-start resets to public). Handlers shipped in #4445;
361
+ // these entries only add them to the autocomplete menu.
362
+ { command: "private", description: "Pause saving this session to memory" },
363
+ { command: "public", description: "Resume saving this session to memory" },
359
364
  // Inline approvals
360
365
  { command: "approve", description: "Approve pending tool permission" },
361
366
  { command: "deny", description: "Deny pending tool permission" },
@@ -418,6 +423,8 @@ export function switchroomHelpText(agentName: string): string {
418
423
  `\`/new\` — fresh session (flush handoff, restart)`,
419
424
  `\`/compact\` — compact context (summarize, keep the thread)`,
420
425
  `\`/clear\` — clear context (fresh slate; memory in Hindsight)`,
426
+ `\`/private\` — pause saving this session to memory`,
427
+ `\`/public\` — resume saving this session to memory`,
421
428
  `\`/approve [id]\` — approve pending tool permission`,
422
429
  `\`/deny [id]\` — deny pending tool permission`,
423
430
  `\`/pending\` — list pending permission prompts`,