switchroom 0.19.23 → 0.19.24

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.
@@ -4377,17 +4377,19 @@ var init_schema = __esm(() => {
4377
4377
  model: exports_external.string().min(1).optional().describe("Per-op model (upstream `HINDSIGHT_API_<OP>_LLM_MODEL`). Absent → " + "inherit the global `hindsight.llm.model`."),
4378
4378
  provider: exports_external.string().min(1).optional().describe("Per-op provider (upstream `HINDSIGHT_API_<OP>_LLM_PROVIDER`). " + "Absent → inherit the global `hindsight.llm.provider`."),
4379
4379
  base_url: exports_external.string().min(1).optional().describe("Per-op base URL (upstream `HINDSIGHT_API_<OP>_LLM_BASE_URL`). " + "Optional passthrough; absent → inherit the global."),
4380
- api_key: exports_external.string().min(1).optional().describe("Per-op API key (upstream `HINDSIGHT_API_<OP>_LLM_API_KEY`). Literal " + "or `vault:` reference. Optional passthrough; absent → inherit global.")
4380
+ api_key: exports_external.string().min(1).optional().describe("Per-op API key (upstream `HINDSIGHT_API_<OP>_LLM_API_KEY`). Literal " + "or `vault:` reference. Optional passthrough; absent → inherit global."),
4381
+ context_window: exports_external.number().int().positive().optional().describe("Context window (tokens) of the backend serving THIS op. NOT an " + "upstream env var — switchroom derives the op's token budget " + "(consolidation batch size / max-completion caps / reflect " + "max-context cap) from it so a single call can never overflow the " + "window. Absent → inherit " + "`hindsight.llm.context_window`, else a per-provider default " + "(conservative for non-`claude-code` providers, which usually mean " + "a local llama.cpp/Ollama slot; a self-hosted `base_url` — loopback, " + "RFC1918, `.local`/`.internal` — forces the conservative default too, " + "regardless of the provider NAME, since the endpoint is where the " + "traffic actually terminates). All three lanes (`retain`, " + "`reflect`, `consolidation`) are budgeted independently.")
4381
4382
  }).describe("Per-operation LLM override. Every field optional; an unset field (or " + "an omitted op block) inherits the global `hindsight.llm.*`, which is " + "already the engine's fallback — switchroom emits only the vars set.");
4382
4383
  HindsightConfigSchema = exports_external.object({
4383
4384
  llm: exports_external.object({
4384
4385
  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."),
4385
4386
  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."),
4387
+ 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."),
4386
4388
  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."),
4387
4389
  reflect: HindsightPerOpLlmSchema.optional().describe("Per-op override for the `reflect` LLM op (synthesis / mental-model " + "refresh). Emits `HINDSIGHT_API_REFLECT_LLM_*`. Absent → uses global."),
4388
4390
  consolidation: HindsightPerOpLlmSchema.optional().describe("Per-op override for the `consolidation` LLM op (background memory " + "merge). Emits `HINDSIGHT_API_CONSOLIDATION_LLM_*`. Absent → global.")
4389
4391
  }).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."),
4390
- 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, " + "LLM_MAX_CONCURRENT, RETAIN/CONSOLIDATION_LLM_MAX_CONCURRENT, " + "RECALL_MAX_CANDIDATES_PER_SOURCE, LINK_EXPANSION_PER_ENTITY_LIMIT, " + "LINK_EXPANSION_TIMEOUT, LLM_REASONING_EFFORT), 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 — 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 — a blanket " + "passthrough would collide with the vars startHindsight() derives " + "itself (HINDSIGHT_API_PORT, the retain token/deadline budget).")
4392
+ 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, " + "RECALL_MAX_CANDIDATES_PER_SOURCE, LINK_EXPANSION_PER_ENTITY_LIMIT, " + "LINK_EXPANSION_TIMEOUT, LLM_REASONING_EFFORT), the override-only keys " + "switchroom manages but ships NO default for " + "(`HINDSIGHT_PERF_OVERRIDE_ONLY_KEYS`: " + "HINDSIGHT_API_WORKER_CONSOLIDATION_BANK_PRIORITY — a per-deployment " + "`bank-pattern:priority,...` map; unset means upstream's flat " + "created_at FIFO across banks), 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 — 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 — a blanket " + "passthrough would collide with the vars startHindsight() derives " + "itself (HINDSIGHT_API_PORT, the retain token/deadline budget).")
4391
4393
  });
4392
4394
  MicrosoftWorkspaceConfigSchema = exports_external.object({
4393
4395
  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 — omit it to use " + "switchroom's shipped default Microsoft app (zero-config). " + "Set it only to bring your own Entra app (BYO)."),
@@ -19202,6 +19204,10 @@ var HINDSIGHT_DEFAULT_LLM_MAX_CONCURRENT = 4;
19202
19204
  var HINDSIGHT_DEFAULT_RETAIN_LLM_MAX_CONCURRENT = 1;
19203
19205
  var HINDSIGHT_DEFAULT_CONSOLIDATION_LLM_MAX_CONCURRENT = 1;
19204
19206
  var HINDSIGHT_DEFAULT_RERANKER_LOCAL_FP16 = "true";
19207
+ var HINDSIGHT_DEFAULT_RERANKER_LOCAL_BATCH_SIZE = 128;
19208
+ var HINDSIGHT_DEFAULT_LLM_STRICT_SCHEMA = "true";
19209
+ var HINDSIGHT_DEFAULT_LLM_MAX_RETRIES = 2;
19210
+ var HINDSIGHT_DEFAULT_CONSOLIDATION_LLM_PARALLELISM = 2;
19205
19211
  var HINDSIGHT_PERF_DEFAULTS_UNGATED = [
19206
19212
  [
19207
19213
  "HINDSIGHT_API_RECALL_MAX_CANDIDATES_PER_SOURCE",
@@ -19215,10 +19221,18 @@ var HINDSIGHT_PERF_DEFAULTS_UNGATED = [
19215
19221
  "HINDSIGHT_API_LINK_EXPANSION_TIMEOUT",
19216
19222
  String(HINDSIGHT_DEFAULT_LINK_EXPANSION_TIMEOUT_S)
19217
19223
  ],
19218
- ["HINDSIGHT_API_LLM_REASONING_EFFORT", HINDSIGHT_DEFAULT_LLM_REASONING_EFFORT]
19224
+ ["HINDSIGHT_API_LLM_REASONING_EFFORT", HINDSIGHT_DEFAULT_LLM_REASONING_EFFORT],
19225
+ [
19226
+ "HINDSIGHT_API_CONSOLIDATION_LLM_PARALLELISM",
19227
+ String(HINDSIGHT_DEFAULT_CONSOLIDATION_LLM_PARALLELISM)
19228
+ ]
19219
19229
  ];
19220
19230
  var HINDSIGHT_PERF_DEFAULTS_GPU = [
19221
- ["HINDSIGHT_API_RERANKER_LOCAL_FP16", HINDSIGHT_DEFAULT_RERANKER_LOCAL_FP16]
19231
+ ["HINDSIGHT_API_RERANKER_LOCAL_FP16", HINDSIGHT_DEFAULT_RERANKER_LOCAL_FP16],
19232
+ [
19233
+ "HINDSIGHT_API_RERANKER_LOCAL_BATCH_SIZE",
19234
+ String(HINDSIGHT_DEFAULT_RERANKER_LOCAL_BATCH_SIZE)
19235
+ ]
19222
19236
  ];
19223
19237
  var HINDSIGHT_PERF_DEFAULTS_LOCAL_LLM = [
19224
19238
  ["HINDSIGHT_API_LLM_MAX_CONCURRENT", String(HINDSIGHT_DEFAULT_LLM_MAX_CONCURRENT)],
@@ -19229,13 +19243,21 @@ var HINDSIGHT_PERF_DEFAULTS_LOCAL_LLM = [
19229
19243
  [
19230
19244
  "HINDSIGHT_API_CONSOLIDATION_LLM_MAX_CONCURRENT",
19231
19245
  String(HINDSIGHT_DEFAULT_CONSOLIDATION_LLM_MAX_CONCURRENT)
19232
- ]
19246
+ ],
19247
+ ["HINDSIGHT_API_LLM_STRICT_SCHEMA", HINDSIGHT_DEFAULT_LLM_STRICT_SCHEMA],
19248
+ ["HINDSIGHT_API_LLM_MAX_RETRIES", String(HINDSIGHT_DEFAULT_LLM_MAX_RETRIES)]
19233
19249
  ];
19250
+ var HINDSIGHT_PERF_OVERRIDE_ONLY_KEYS = new Set([
19251
+ "HINDSIGHT_API_WORKER_CONSOLIDATION_BANK_PRIORITY"
19252
+ ]);
19234
19253
  var HINDSIGHT_PERF_ENV_KEYS = new Set([
19235
- ...HINDSIGHT_PERF_DEFAULTS_UNGATED,
19236
- ...HINDSIGHT_PERF_DEFAULTS_GPU,
19237
- ...HINDSIGHT_PERF_DEFAULTS_LOCAL_LLM
19238
- ].map(([k]) => k));
19254
+ ...[
19255
+ ...HINDSIGHT_PERF_DEFAULTS_UNGATED,
19256
+ ...HINDSIGHT_PERF_DEFAULTS_GPU,
19257
+ ...HINDSIGHT_PERF_DEFAULTS_LOCAL_LLM
19258
+ ].map(([k]) => k),
19259
+ ...HINDSIGHT_PERF_OVERRIDE_ONLY_KEYS
19260
+ ]);
19239
19261
 
19240
19262
  // src/setup/hindsight-pg-defaults.ts
19241
19263
  var HINDSIGHT_PG_MEM_LIMIT_MIB_FOR_DERIVATION = 8 * 1024;
@@ -19258,6 +19280,10 @@ var HINDSIGHT_PG_DEFAULTS = [
19258
19280
  ];
19259
19281
  var HINDSIGHT_PG_ENV_KEYS = new Set(HINDSIGHT_PG_DEFAULTS.map(([k]) => k));
19260
19282
 
19283
+ // src/setup/hindsight-context-budget.ts
19284
+ var HINDSIGHT_UPSTREAM_RETAIN_CHUNK_SIZE = 3000;
19285
+ var HINDSIGHT_RETAIN_MAX_COMPLETION_FLOOR = HINDSIGHT_UPSTREAM_RETAIN_CHUNK_SIZE + 72;
19286
+
19261
19287
  // src/setup/hindsight.ts
19262
19288
  var HINDSIGHT_DEFAULT_API_PORT = 18888;
19263
19289
  var HINDSIGHT_DEFAULT_MCP_URL = `http://127.0.0.1:${HINDSIGHT_DEFAULT_API_PORT}/mcp/`;
@@ -4377,17 +4377,19 @@ var init_schema = __esm(() => {
4377
4377
  model: exports_external.string().min(1).optional().describe("Per-op model (upstream `HINDSIGHT_API_<OP>_LLM_MODEL`). Absent → " + "inherit the global `hindsight.llm.model`."),
4378
4378
  provider: exports_external.string().min(1).optional().describe("Per-op provider (upstream `HINDSIGHT_API_<OP>_LLM_PROVIDER`). " + "Absent → inherit the global `hindsight.llm.provider`."),
4379
4379
  base_url: exports_external.string().min(1).optional().describe("Per-op base URL (upstream `HINDSIGHT_API_<OP>_LLM_BASE_URL`). " + "Optional passthrough; absent → inherit the global."),
4380
- api_key: exports_external.string().min(1).optional().describe("Per-op API key (upstream `HINDSIGHT_API_<OP>_LLM_API_KEY`). Literal " + "or `vault:` reference. Optional passthrough; absent → inherit global.")
4380
+ api_key: exports_external.string().min(1).optional().describe("Per-op API key (upstream `HINDSIGHT_API_<OP>_LLM_API_KEY`). Literal " + "or `vault:` reference. Optional passthrough; absent → inherit global."),
4381
+ context_window: exports_external.number().int().positive().optional().describe("Context window (tokens) of the backend serving THIS op. NOT an " + "upstream env var — switchroom derives the op's token budget " + "(consolidation batch size / max-completion caps / reflect " + "max-context cap) from it so a single call can never overflow the " + "window. Absent → inherit " + "`hindsight.llm.context_window`, else a per-provider default " + "(conservative for non-`claude-code` providers, which usually mean " + "a local llama.cpp/Ollama slot; a self-hosted `base_url` — loopback, " + "RFC1918, `.local`/`.internal` — forces the conservative default too, " + "regardless of the provider NAME, since the endpoint is where the " + "traffic actually terminates). All three lanes (`retain`, " + "`reflect`, `consolidation`) are budgeted independently.")
4381
4382
  }).describe("Per-operation LLM override. Every field optional; an unset field (or " + "an omitted op block) inherits the global `hindsight.llm.*`, which is " + "already the engine's fallback — switchroom emits only the vars set.");
4382
4383
  HindsightConfigSchema = exports_external.object({
4383
4384
  llm: exports_external.object({
4384
4385
  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."),
4385
4386
  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."),
4387
+ 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."),
4386
4388
  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."),
4387
4389
  reflect: HindsightPerOpLlmSchema.optional().describe("Per-op override for the `reflect` LLM op (synthesis / mental-model " + "refresh). Emits `HINDSIGHT_API_REFLECT_LLM_*`. Absent → uses global."),
4388
4390
  consolidation: HindsightPerOpLlmSchema.optional().describe("Per-op override for the `consolidation` LLM op (background memory " + "merge). Emits `HINDSIGHT_API_CONSOLIDATION_LLM_*`. Absent → global.")
4389
4391
  }).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."),
4390
- 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, " + "LLM_MAX_CONCURRENT, RETAIN/CONSOLIDATION_LLM_MAX_CONCURRENT, " + "RECALL_MAX_CANDIDATES_PER_SOURCE, LINK_EXPANSION_PER_ENTITY_LIMIT, " + "LINK_EXPANSION_TIMEOUT, LLM_REASONING_EFFORT), 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 — 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 — a blanket " + "passthrough would collide with the vars startHindsight() derives " + "itself (HINDSIGHT_API_PORT, the retain token/deadline budget).")
4392
+ 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, " + "RECALL_MAX_CANDIDATES_PER_SOURCE, LINK_EXPANSION_PER_ENTITY_LIMIT, " + "LINK_EXPANSION_TIMEOUT, LLM_REASONING_EFFORT), the override-only keys " + "switchroom manages but ships NO default for " + "(`HINDSIGHT_PERF_OVERRIDE_ONLY_KEYS`: " + "HINDSIGHT_API_WORKER_CONSOLIDATION_BANK_PRIORITY — a per-deployment " + "`bank-pattern:priority,...` map; unset means upstream's flat " + "created_at FIFO across banks), 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 — 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 — a blanket " + "passthrough would collide with the vars startHindsight() derives " + "itself (HINDSIGHT_API_PORT, the retain token/deadline budget).")
4391
4393
  });
4392
4394
  MicrosoftWorkspaceConfigSchema = exports_external.object({
4393
4395
  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 — omit it to use " + "switchroom's shipped default Microsoft app (zero-config). " + "Set it only to bring your own Entra app (BYO)."),
@@ -18875,6 +18877,10 @@ var HINDSIGHT_DEFAULT_LLM_MAX_CONCURRENT = 4;
18875
18877
  var HINDSIGHT_DEFAULT_RETAIN_LLM_MAX_CONCURRENT = 1;
18876
18878
  var HINDSIGHT_DEFAULT_CONSOLIDATION_LLM_MAX_CONCURRENT = 1;
18877
18879
  var HINDSIGHT_DEFAULT_RERANKER_LOCAL_FP16 = "true";
18880
+ var HINDSIGHT_DEFAULT_RERANKER_LOCAL_BATCH_SIZE = 128;
18881
+ var HINDSIGHT_DEFAULT_LLM_STRICT_SCHEMA = "true";
18882
+ var HINDSIGHT_DEFAULT_LLM_MAX_RETRIES = 2;
18883
+ var HINDSIGHT_DEFAULT_CONSOLIDATION_LLM_PARALLELISM = 2;
18878
18884
  var HINDSIGHT_PERF_DEFAULTS_UNGATED = [
18879
18885
  [
18880
18886
  "HINDSIGHT_API_RECALL_MAX_CANDIDATES_PER_SOURCE",
@@ -18888,10 +18894,18 @@ var HINDSIGHT_PERF_DEFAULTS_UNGATED = [
18888
18894
  "HINDSIGHT_API_LINK_EXPANSION_TIMEOUT",
18889
18895
  String(HINDSIGHT_DEFAULT_LINK_EXPANSION_TIMEOUT_S)
18890
18896
  ],
18891
- ["HINDSIGHT_API_LLM_REASONING_EFFORT", HINDSIGHT_DEFAULT_LLM_REASONING_EFFORT]
18897
+ ["HINDSIGHT_API_LLM_REASONING_EFFORT", HINDSIGHT_DEFAULT_LLM_REASONING_EFFORT],
18898
+ [
18899
+ "HINDSIGHT_API_CONSOLIDATION_LLM_PARALLELISM",
18900
+ String(HINDSIGHT_DEFAULT_CONSOLIDATION_LLM_PARALLELISM)
18901
+ ]
18892
18902
  ];
18893
18903
  var HINDSIGHT_PERF_DEFAULTS_GPU = [
18894
- ["HINDSIGHT_API_RERANKER_LOCAL_FP16", HINDSIGHT_DEFAULT_RERANKER_LOCAL_FP16]
18904
+ ["HINDSIGHT_API_RERANKER_LOCAL_FP16", HINDSIGHT_DEFAULT_RERANKER_LOCAL_FP16],
18905
+ [
18906
+ "HINDSIGHT_API_RERANKER_LOCAL_BATCH_SIZE",
18907
+ String(HINDSIGHT_DEFAULT_RERANKER_LOCAL_BATCH_SIZE)
18908
+ ]
18895
18909
  ];
18896
18910
  var HINDSIGHT_PERF_DEFAULTS_LOCAL_LLM = [
18897
18911
  ["HINDSIGHT_API_LLM_MAX_CONCURRENT", String(HINDSIGHT_DEFAULT_LLM_MAX_CONCURRENT)],
@@ -18902,13 +18916,21 @@ var HINDSIGHT_PERF_DEFAULTS_LOCAL_LLM = [
18902
18916
  [
18903
18917
  "HINDSIGHT_API_CONSOLIDATION_LLM_MAX_CONCURRENT",
18904
18918
  String(HINDSIGHT_DEFAULT_CONSOLIDATION_LLM_MAX_CONCURRENT)
18905
- ]
18919
+ ],
18920
+ ["HINDSIGHT_API_LLM_STRICT_SCHEMA", HINDSIGHT_DEFAULT_LLM_STRICT_SCHEMA],
18921
+ ["HINDSIGHT_API_LLM_MAX_RETRIES", String(HINDSIGHT_DEFAULT_LLM_MAX_RETRIES)]
18906
18922
  ];
18923
+ var HINDSIGHT_PERF_OVERRIDE_ONLY_KEYS = new Set([
18924
+ "HINDSIGHT_API_WORKER_CONSOLIDATION_BANK_PRIORITY"
18925
+ ]);
18907
18926
  var HINDSIGHT_PERF_ENV_KEYS = new Set([
18908
- ...HINDSIGHT_PERF_DEFAULTS_UNGATED,
18909
- ...HINDSIGHT_PERF_DEFAULTS_GPU,
18910
- ...HINDSIGHT_PERF_DEFAULTS_LOCAL_LLM
18911
- ].map(([k]) => k));
18927
+ ...[
18928
+ ...HINDSIGHT_PERF_DEFAULTS_UNGATED,
18929
+ ...HINDSIGHT_PERF_DEFAULTS_GPU,
18930
+ ...HINDSIGHT_PERF_DEFAULTS_LOCAL_LLM
18931
+ ].map(([k]) => k),
18932
+ ...HINDSIGHT_PERF_OVERRIDE_ONLY_KEYS
18933
+ ]);
18912
18934
 
18913
18935
  // src/setup/hindsight-pg-defaults.ts
18914
18936
  var HINDSIGHT_PG_MEM_LIMIT_MIB_FOR_DERIVATION = 8 * 1024;
@@ -18931,6 +18953,10 @@ var HINDSIGHT_PG_DEFAULTS = [
18931
18953
  ];
18932
18954
  var HINDSIGHT_PG_ENV_KEYS = new Set(HINDSIGHT_PG_DEFAULTS.map(([k]) => k));
18933
18955
 
18956
+ // src/setup/hindsight-context-budget.ts
18957
+ var HINDSIGHT_UPSTREAM_RETAIN_CHUNK_SIZE = 3000;
18958
+ var HINDSIGHT_RETAIN_MAX_COMPLETION_FLOOR = HINDSIGHT_UPSTREAM_RETAIN_CHUNK_SIZE + 72;
18959
+
18934
18960
  // src/setup/hindsight.ts
18935
18961
  var HINDSIGHT_DEFAULT_API_PORT = 18888;
18936
18962
  var HINDSIGHT_DEFAULT_MCP_URL = `http://127.0.0.1:${HINDSIGHT_DEFAULT_API_PORT}/mcp/`;
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.23",
4
+ "version": "0.19.24",
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": {
@@ -1,15 +1,14 @@
1
1
  ## Development Protocol
2
2
 
3
- Judgement criteria for substantive coding, infra, or debugging work. The long-form playbook — task classification, design-report shape, adversarial-review dispatch, re-review verdict format — is the bundled `dev-protocol` skill; load it before starting.
3
+ Judgement criteria for substantive coding, infra, or debugging work.
4
4
 
5
5
  This governs HOW delegated work is done, and is **not a license to do it inline**: dispatch first (see Delegation), then these bind the worker.
6
6
 
7
7
  - **Orient before you build — validate, don't assume.** Root-cause in real source — the repo's files at HEAD, not `dist/`, caches, or generated output. If the evidence contradicts your theory, the plan, or the task description, report the contradiction rather than force-fitting it. Cite `file:line`, commits, PRs.
8
8
  - **Infer before you ask.** Most questions are answerable from the code and history. If genuinely unsure, ask ONE question at a time, during planning; act autonomously during execution — make the reasonable call and note the assumption.
9
9
  - **Design report before implementation, when the change is large.** Architecturally significant, cross-cutting, or ambiguous-approach work earns an evidence-grounded design report and a red-team pass before code, and ships as focused single-concern PRs.
10
- - **Branch off fresh main. Scoped tests + lint locally; CI is the full-suite authority. Merge only on CI green.**
10
+ - **Run `git fetch origin` first, then branch off `origin/main`.** Never branch off the working copy as-is: you do not start in the repo you are coding in, and the checkout on disk may be many commits stale. Scoped tests + lint locally; CI is the full-suite authority.
11
11
  - **Adversarial review of the diff.** Read every change as an adversary would: what breaks, what's untested, what's inconsistent.
12
- - **Blockers and mediums block the merge; lows don't** — fix a low inline if it's a one-liner, else file a follow-up issue and merge. Filing is mandatory.
13
- - **Re-review only a behavioural fix** — a docs/comment/log/test-only commit doesn't earn one. Prefix a fix commit `review-fix:`; two rounds is the cap, and CI enforces it.
12
+ - **Blockers and majors block the merge; lows don't** — file a low as a follow-up issue rather than fixing it now. Filing is mandatory. Fix what blocks, then merge on CI green. Do not count review rounds and do not run a mandatory re-review pass: verifying your own fix is part of making it, not a separate step.
14
13
  - **Durable fixes over hack patches. Deterministic mechanisms over model-dependent behaviour** — if code can enforce a guarantee, don't leave it to prompt discipline. **Tests assert outcomes, not just code paths:** one that wouldn't fail on the bug it guards is not a test.
15
14
  - **Communicate as you go.** Consolidated messages — one substantive update beats five fragments; never go dark; no foreground watch over 30 seconds (background it); max 15 parallel sub-agents.
@@ -80,29 +80,36 @@ fixing lows produces a new diff, and a new diff earned another re-review. It
80
80
  produced PRs going four rounds where the last round's only finding was an
81
81
  inaccurate doc comment. So:
82
82
 
83
- - **Blockers and mediums block the merge.** Fix them.
84
- - **Lows do NOT block.** Fix a low inline only if it's a genuine one-liner;
85
- otherwise **file a follow-up issue and merge**. Filing is mandatory — an
86
- unfiled low is a dropped bug, and there is no human team to catch it later.
87
- - **A re-review is earned only by a behavioural fix.** A docs-, comment-,
88
- log-, or test-only fix commit does not earn another pass.
89
- - **Two rounds is the cap.** Prefix every commit answering a review round
90
- `review-fix:` — `scripts/check-review-rounds.mjs` counts them and the
91
- `review-rounds` check fails past two, unless a `review-cap-override` label
92
- is on the PR.
83
+ - **Blockers and majors block the merge.** Fix them.
84
+ - **Lows do NOT block.** File a low as a follow-up issue rather than fixing it
85
+ now. Filing is mandatory — an unfiled low is a dropped bug, and there is no
86
+ human team to catch it later.
87
+ - **Fix what blocks, then merge on CI green.**
88
+ - **Do not count review rounds, and do not run a mandatory re-review pass.**
89
+ Verifying your own fix is part of making it, not a separate step. Counting
90
+ rounds was itself a loop driver: it made the review process the subject of
91
+ the work instead of the change.
93
92
 
94
93
  If a finding is genuinely invalid, rebut it with evidence in writing; silence
95
94
  is not a rebuttal.
96
95
 
97
- When you do re-review, the verdict states per original finding: the finding
98
- ID, what changed (`file:line` of the fix), whether it fully resolves the
99
- finding (`RESOLVED` / `PARTIAL` / `REBUTTED` with evidence), and whether the
100
- fix introduced anything new. A bare "fixed" is not a verdict.
101
-
102
96
  ## 5. Non-obvious pipeline rules
103
97
 
104
98
  - **CI is the full-suite authority.** Local scoped tests are a fast filter,
105
99
  never the merge evidence. Never claim done off a local run alone.
100
+ - **`main` is behind a merge queue: `gh pr merge` ENQUEUES, it does not
101
+ merge.** The command exits 0 and the PR stays `OPEN`. The queue then re-runs
102
+ all seven required contexts on its own `gh-readonly-queue/main/pr-<n>-<sha>`
103
+ ref before landing anything, so "green on the PR" is necessary but not
104
+ sufficient. Never report a PR merged off that exit code — poll until its
105
+ state is `MERGED` and the commit is an ancestor of `origin/main`. Two flags
106
+ to know: `--delete-branch` is **rejected outright** while the queue is on
107
+ (delete the branch after it lands), and `--subject` is ignored, since the
108
+ queue composes the merge commit from the PR title plus `(#<pr>)` — so the PR
109
+ title is the commit title, write it accordingly. An entry stuck in
110
+ `AWAITING_CHECKS` means a required workflow is not listening for
111
+ `merge_group`; `.github/MERGE-QUEUE.md` owns that failure mode and the
112
+ invariants that prevent it.
106
113
  - **A test that wouldn't fail on the bug it guards is not a test.** Assert the
107
114
  observable outcome, not that the code path executed.
108
115
  - **Prefer a deterministic mechanism over prompt discipline.** If a check, a
@@ -100,7 +100,8 @@ The tag push triggers `docker-images` and `release`. `release` internally waits
100
100
 
101
101
  ### Gate B — the release pipeline (`release.yml`)
102
102
  - `gh run list --workflow=release.yml --limit 1` — wait for `completed` / `success`. Expect ~25-30 minutes: four native build legs plus the wait on `docker-images`.
103
- - Its jobs, in order: `guard` (release exists + held out of `latest`) → `build` ×4 → `bundle` → `publish` (attach) → `images-gate` (wait on docker-images) → `npm` → `finalize` (un-draft). A red job anywhere leaves the release a **draft** and npm **unpublished** — which is the correct, recoverable state.
103
+ - Its jobs, in order: `guard` (release exists + held out of `latest`) → `build` ×4 → `bundle` → `publish` (attach) → `images-gate` (wait on docker-images) → `npm` → `finalize` (un-draft) → `images-latest` (promote `:vX.Y.Z` → `:latest`). A red job anywhere leaves the release a **draft** and npm **unpublished** — which is the correct, recoverable state.
104
+ - `images-latest` is why a tag push no longer moves the `:latest` image tag by itself (#3685). If that last job is the one that failed, every other leg shipped and only the image tag lags: re-run it with `gh workflow run promote.yml -f from=vX.Y.Z -f to=latest`. Don't roll the fleet off `:latest` until it is green — `docker manifest inspect ghcr.io/switchroom/switchroom-agent:latest` should report the same digest as `:vX.Y.Z`.
104
105
  - Verify the release page actually has assets **and is no longer a draft**:
105
106
  ```bash
106
107
  gh release view vX.Y.Z -R switchroom/switchroom --json isDraft,assets \