@wolfx/opencode-magic-context 0.25.0 → 0.26.0

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 (81) hide show
  1. package/dist/agents/permissions.d.ts +6 -0
  2. package/dist/agents/permissions.d.ts.map +1 -1
  3. package/dist/config/schema/magic-context.d.ts +22 -0
  4. package/dist/config/schema/magic-context.d.ts.map +1 -1
  5. package/dist/features/magic-context/compartment-chunk-embedding.d.ts +17 -0
  6. package/dist/features/magic-context/compartment-chunk-embedding.d.ts.map +1 -1
  7. package/dist/features/magic-context/compartment-embedding.d.ts.map +1 -1
  8. package/dist/features/magic-context/dreamer/task-prompts.d.ts.map +1 -1
  9. package/dist/features/magic-context/memory/embedding-local.d.ts +3 -3
  10. package/dist/features/magic-context/memory/embedding-local.d.ts.map +1 -1
  11. package/dist/features/magic-context/memory/embedding-openai.d.ts +8 -4
  12. package/dist/features/magic-context/memory/embedding-openai.d.ts.map +1 -1
  13. package/dist/features/magic-context/memory/embedding-provider.d.ts +8 -4
  14. package/dist/features/magic-context/memory/embedding-provider.d.ts.map +1 -1
  15. package/dist/features/magic-context/memory/embedding.d.ts.map +1 -1
  16. package/dist/features/magic-context/memory/relocate-memory.d.ts +58 -0
  17. package/dist/features/magic-context/memory/relocate-memory.d.ts.map +1 -0
  18. package/dist/features/magic-context/migrations.d.ts.map +1 -1
  19. package/dist/features/magic-context/project-embedding-registry.d.ts +3 -3
  20. package/dist/features/magic-context/project-embedding-registry.d.ts.map +1 -1
  21. package/dist/features/magic-context/storage-db.d.ts +2 -1
  22. package/dist/features/magic-context/storage-db.d.ts.map +1 -1
  23. package/dist/features/magic-context/storage-meta-persisted.d.ts +37 -0
  24. package/dist/features/magic-context/storage-meta-persisted.d.ts.map +1 -1
  25. package/dist/features/magic-context/storage-meta-session.d.ts.map +1 -1
  26. package/dist/features/magic-context/storage-meta-shared.d.ts +3 -1
  27. package/dist/features/magic-context/storage-meta-shared.d.ts.map +1 -1
  28. package/dist/features/magic-context/storage-meta.d.ts +1 -1
  29. package/dist/features/magic-context/storage-meta.d.ts.map +1 -1
  30. package/dist/features/magic-context/storage-tags.d.ts +48 -2
  31. package/dist/features/magic-context/storage-tags.d.ts.map +1 -1
  32. package/dist/features/magic-context/storage.d.ts +3 -3
  33. package/dist/features/magic-context/storage.d.ts.map +1 -1
  34. package/dist/features/magic-context/tagger.d.ts +1 -1
  35. package/dist/features/magic-context/tagger.d.ts.map +1 -1
  36. package/dist/features/magic-context/transform-decision-log.d.ts +49 -0
  37. package/dist/features/magic-context/transform-decision-log.d.ts.map +1 -0
  38. package/dist/features/magic-context/v22-deferred-backfill.d.ts.map +1 -1
  39. package/dist/hooks/magic-context/auto-search-runner.d.ts.map +1 -1
  40. package/dist/hooks/magic-context/compartment-runner-incremental.d.ts.map +1 -1
  41. package/dist/hooks/magic-context/compartment-trigger.d.ts +1 -1
  42. package/dist/hooks/magic-context/compartment-trigger.d.ts.map +1 -1
  43. package/dist/hooks/magic-context/derive-budgets.d.ts +5 -9
  44. package/dist/hooks/magic-context/derive-budgets.d.ts.map +1 -1
  45. package/dist/hooks/magic-context/event-handler.d.ts.map +1 -1
  46. package/dist/hooks/magic-context/event-payloads.d.ts +1 -0
  47. package/dist/hooks/magic-context/event-payloads.d.ts.map +1 -1
  48. package/dist/hooks/magic-context/heuristic-cleanup.d.ts +1 -0
  49. package/dist/hooks/magic-context/heuristic-cleanup.d.ts.map +1 -1
  50. package/dist/hooks/magic-context/hook.d.ts.map +1 -1
  51. package/dist/hooks/magic-context/protected-tail-boundary.d.ts +10 -0
  52. package/dist/hooks/magic-context/protected-tail-boundary.d.ts.map +1 -1
  53. package/dist/hooks/magic-context/read-session-chunk.d.ts.map +1 -1
  54. package/dist/hooks/magic-context/tag-id-fallback.d.ts.map +1 -1
  55. package/dist/hooks/magic-context/tag-messages.d.ts +10 -0
  56. package/dist/hooks/magic-context/tag-messages.d.ts.map +1 -1
  57. package/dist/hooks/magic-context/transform-compartment-phase.d.ts +32 -1
  58. package/dist/hooks/magic-context/transform-compartment-phase.d.ts.map +1 -1
  59. package/dist/hooks/magic-context/transform-postprocess-phase.d.ts +6 -0
  60. package/dist/hooks/magic-context/transform-postprocess-phase.d.ts.map +1 -1
  61. package/dist/hooks/magic-context/transform.d.ts.map +1 -1
  62. package/dist/index.d.ts.map +1 -1
  63. package/dist/index.js +675 -216
  64. package/dist/plugin/dream-timer.d.ts.map +1 -1
  65. package/dist/plugin/hooks/create-session-hooks.d.ts.map +1 -1
  66. package/dist/plugin/rpc-handlers.d.ts.map +1 -1
  67. package/dist/shared/announcement.d.ts +1 -1
  68. package/dist/shared/index.d.ts +0 -1
  69. package/dist/shared/index.d.ts.map +1 -1
  70. package/dist/shared/resolve-fallbacks.d.ts +16 -16
  71. package/dist/shared/resolve-fallbacks.d.ts.map +1 -1
  72. package/dist/tools/ctx-search/tools.d.ts.map +1 -1
  73. package/package.json +5 -11
  74. package/src/shared/announcement.ts +6 -6
  75. package/src/shared/index.ts +0 -1
  76. package/src/shared/resolve-fallbacks.test.ts +37 -71
  77. package/src/shared/resolve-fallbacks.ts +16 -26
  78. package/src/tui/slots/sidebar-content.tsx +11 -7
  79. package/dist/shared/model-requirements.d.ts +0 -26
  80. package/dist/shared/model-requirements.d.ts.map +0 -1
  81. package/src/shared/model-requirements.ts +0 -86
package/dist/index.js CHANGED
@@ -47,20 +47,9 @@ var __esm = (fn, res) => () => (fn && (res = fn(fn = 0)), res);
47
47
  var __promiseAll = (args) => Promise.all(args);
48
48
  var __require = /* @__PURE__ */ createRequire(import.meta.url);
49
49
 
50
- // src/agents/dreamer.ts
51
- var DREAMER_AGENT = "dreamer";
52
-
53
50
  // src/agents/historian.ts
54
- var exports_historian = {};
55
- __export(exports_historian, {
56
- HISTORIAN_EDITOR_AGENT: () => HISTORIAN_EDITOR_AGENT,
57
- HISTORIAN_AGENT: () => HISTORIAN_AGENT
58
- });
59
51
  var HISTORIAN_AGENT = "historian", HISTORIAN_EDITOR_AGENT = "historian-editor";
60
52
 
61
- // src/agents/sidekick.ts
62
- var SIDEKICK_AGENT = "sidekick";
63
-
64
53
  // src/shared/jsonc-parser.ts
65
54
  import { existsSync, readFileSync } from "node:fs";
66
55
  function stripJsonComments(content) {
@@ -14879,14 +14868,16 @@ var init_magic_context = __esm(() => {
14879
14868
  }).optional();
14880
14869
  HistorianConfigSchema = AgentOverrideConfigSchema.extend({
14881
14870
  two_pass: exports_external.boolean().default(false).describe("Run a second editor pass over historian output to clean low-signal U: lines and cross-compartment duplicates. Adds ~1 extra API call and ~1.3x cost per historian run. Useful for models without extended thinking support. (default: false)"),
14882
- thinking_level: PiThinkingLevelSchema.describe("Pi only: explicit thinking level passed as --thinking <level> to Pi historian subagent invocations. Required when using reasoning models (e.g. github-copilot/gpt-5.4) because Pi's default thinking-level resolution can pick a value the provider rejects. OpenCode users set variant instead. Valid: off | minimal | low | medium | high | xhigh")
14871
+ thinking_level: PiThinkingLevelSchema.describe("Pi only: explicit thinking level passed as --thinking <level> to Pi historian subagent invocations. Required when using reasoning models (e.g. github-copilot/gpt-5.4) because Pi's default thinking-level resolution can pick a value the provider rejects. OpenCode users set variant instead. Valid: off | minimal | low | medium | high | xhigh"),
14872
+ disallowed_tools: exports_external.array(exports_external.enum(["*", "read", "aft_outline", "aft_zoom", "aft_search"])).default([]).describe(`OpenCode only. Tools to REMOVE from the historian's default allow-list [read, aft_outline, aft_zoom, aft_search]. Applies to both historian and historian-editor agents. Use ["*"] to strip all tool definitions from the model request — this prevents weak instruction-following models (e.g. mistral-small-latest) from entering tool-calling loops. Individual tool names remove just that tool. Note: a user-supplied historian.permission override can re-allow a tool that disallowed_tools removed — disallowed_tools sets the baseline, permission overrides take precedence. (default: [])`)
14883
14873
  }).optional();
14884
14874
  BaseEmbeddingConfigSchema = exports_external.object({
14885
14875
  provider: exports_external.enum(["local", "openai-compatible", "off"]).default("local").describe("Embedding provider. 'local' uses Xenova/all-MiniLM-L6-v2, 'openai-compatible' requires endpoint and model, 'off' disables embeddings."),
14886
14876
  model: exports_external.string().optional().describe("Embedding model name. Required for openai-compatible, ignored for local."),
14887
14877
  endpoint: exports_external.string().optional().describe("API endpoint URL. Required when provider is openai-compatible."),
14888
14878
  api_key: exports_external.string().optional().describe("API key for remote embedding provider (optional)"),
14889
- input_type: exports_external.string().optional().describe("Optional input_type sent in the embedding request body. Required by some openai-compatible providers (e.g. NVIDIA NIM expects 'query' or 'passage'). Omitted from the request when unset."),
14879
+ input_type: exports_external.string().optional().describe("Default input_type for stored/indexed (passage) embeddings in the request body. Required by some openai-compatible providers (e.g. NVIDIA NIM). Omitted from the request when unset."),
14880
+ query_input_type: exports_external.string().optional().describe("Optional input_type for query (search) embeddings on asymmetric models (e.g. NVIDIA NIM 'query'). When unset, query embeddings use embedding.input_type. Passage/stored content always uses embedding.input_type."),
14890
14881
  truncate: exports_external.string().optional().describe("Optional truncate mode sent in the embedding request body (e.g. NVIDIA NIM accepts 'NONE' | 'START' | 'END'). Omitted from the request when unset."),
14891
14882
  max_input_tokens: exports_external.number().int().positive().optional().describe("Optional maximum input tokens for chunk embeddings. Defaults conservatively to 512 when omitted.")
14892
14883
  }).superRefine((data, ctx) => {
@@ -14916,6 +14907,7 @@ var init_magic_context = __esm(() => {
14916
14907
  if (data.provider === "openai-compatible") {
14917
14908
  const apiKey = data.api_key?.trim();
14918
14909
  const inputType = data.input_type?.trim();
14910
+ const queryInputType = data.query_input_type?.trim();
14919
14911
  const truncate = data.truncate?.trim();
14920
14912
  return {
14921
14913
  provider: "openai-compatible",
@@ -14923,6 +14915,7 @@ var init_magic_context = __esm(() => {
14923
14915
  endpoint: data.endpoint?.trim() ?? "",
14924
14916
  ...apiKey ? { api_key: apiKey } : {},
14925
14917
  ...inputType ? { input_type: inputType } : {},
14918
+ ...queryInputType ? { query_input_type: queryInputType } : {},
14926
14919
  ...truncate ? { truncate } : {},
14927
14920
  ...data.max_input_tokens ? { max_input_tokens: data.max_input_tokens } : {}
14928
14921
  };
@@ -15284,58 +15277,6 @@ var init_logger = __esm(() => {
15284
15277
  }
15285
15278
  });
15286
15279
 
15287
- // src/shared/model-requirements.ts
15288
- function expandFallbackChain(chain) {
15289
- const models = [];
15290
- for (const entry of chain) {
15291
- for (const provider of entry.providers) {
15292
- models.push(`${provider}/${entry.model}`);
15293
- }
15294
- }
15295
- return models;
15296
- }
15297
- function getAgentFallbackModels(agent) {
15298
- const requirement = AGENT_MODEL_REQUIREMENTS[agent];
15299
- if (!requirement)
15300
- return;
15301
- return expandFallbackChain(requirement.fallbackChain);
15302
- }
15303
- var HISTORIAN_FALLBACK_CHAIN, DREAMER_FALLBACK_CHAIN, SIDEKICK_FALLBACK_CHAIN, AGENT_MODEL_REQUIREMENTS;
15304
- var init_model_requirements = __esm(() => {
15305
- HISTORIAN_FALLBACK_CHAIN = [
15306
- { providers: ["github-copilot", "anthropic", "opencode"], model: "claude-sonnet-4-6" },
15307
- { providers: ["opencode-go"], model: "minimax-m2.7" },
15308
- {
15309
- providers: ["zai-coding-plan", "bailian-coding-plan", "opencode-go", "opencode"],
15310
- model: "glm-5"
15311
- },
15312
- { providers: ["openai", "github-copilot", "opencode"], model: "gpt-5.4" },
15313
- { providers: ["google", "github-copilot", "opencode"], model: "gemini-3.1-pro" }
15314
- ];
15315
- DREAMER_FALLBACK_CHAIN = [
15316
- { providers: ["github-copilot", "anthropic", "opencode"], model: "claude-sonnet-4-6" },
15317
- { providers: ["google", "github-copilot", "opencode"], model: "gemini-3-flash" },
15318
- {
15319
- providers: ["zai-coding-plan", "bailian-coding-plan", "opencode-go", "opencode"],
15320
- model: "glm-5"
15321
- },
15322
- { providers: ["opencode-go"], model: "minimax-m2.7" },
15323
- { providers: ["github-copilot", "openai", "opencode"], model: "gpt-5.4-mini" }
15324
- ];
15325
- SIDEKICK_FALLBACK_CHAIN = [
15326
- { providers: ["cerebras"], model: "qwen-3-235b-a22b-instruct-2507" },
15327
- { providers: ["google", "github-copilot", "opencode"], model: "gemini-3-flash" },
15328
- { providers: ["openai", "github-copilot", "opencode"], model: "gpt-5.4-mini" },
15329
- { providers: ["opencode"], model: "gpt-5-nano" }
15330
- ];
15331
- AGENT_MODEL_REQUIREMENTS = {
15332
- [HISTORIAN_AGENT]: { fallbackChain: HISTORIAN_FALLBACK_CHAIN },
15333
- [HISTORIAN_EDITOR_AGENT]: { fallbackChain: HISTORIAN_FALLBACK_CHAIN },
15334
- [DREAMER_AGENT]: { fallbackChain: DREAMER_FALLBACK_CHAIN },
15335
- [SIDEKICK_AGENT]: { fallbackChain: SIDEKICK_FALLBACK_CHAIN }
15336
- };
15337
- });
15338
-
15339
15280
  // src/features/magic-context/overflow-detection.ts
15340
15281
  function extractErrorMessage(error51) {
15341
15282
  if (!error51)
@@ -15449,15 +15390,9 @@ __export(exports_resolve_fallbacks, {
15449
15390
  resolveFallbackChain: () => resolveFallbackChain,
15450
15391
  parseProviderModel: () => parseProviderModel
15451
15392
  });
15452
- function resolveFallbackChain(agentName, userFallbacks) {
15393
+ function resolveFallbackChain(userFallbacks) {
15453
15394
  const userList = normalizeUserFallbacks(userFallbacks);
15454
- if (userList.length > 0) {
15455
- return dedupe(userList.filter(isValidModelSpec));
15456
- }
15457
- const builtin = getAgentFallbackModels(agentName);
15458
- if (!builtin || builtin.length === 0)
15459
- return [];
15460
- return dedupe(builtin.filter(isValidModelSpec));
15395
+ return dedupe(userList.filter(isValidModelSpec));
15461
15396
  }
15462
15397
  function normalizeUserFallbacks(userFallbacks) {
15463
15398
  if (!userFallbacks)
@@ -15492,9 +15427,6 @@ function parseProviderModel(spec) {
15492
15427
  modelID: spec.slice(slash + 1).trim()
15493
15428
  };
15494
15429
  }
15495
- var init_resolve_fallbacks = __esm(() => {
15496
- init_model_requirements();
15497
- });
15498
15430
 
15499
15431
  // src/shared/model-suggestion-retry.ts
15500
15432
  function extractMessage(error51) {
@@ -15682,7 +15614,6 @@ async function promptSyncWithModelSuggestionRetry(client, args, options = {}) {
15682
15614
  var init_model_suggestion_retry = __esm(() => {
15683
15615
  init_overflow_detection();
15684
15616
  init_logger();
15685
- init_resolve_fallbacks();
15686
15617
  });
15687
15618
 
15688
15619
  // src/shared/normalize-sdk-response.ts
@@ -15712,9 +15643,7 @@ function normalizeSDKResponse(response, fallback, options) {
15712
15643
  // src/shared/index.ts
15713
15644
  var init_shared = __esm(() => {
15714
15645
  init_logger();
15715
- init_model_requirements();
15716
15646
  init_model_suggestion_retry();
15717
- init_resolve_fallbacks();
15718
15647
  });
15719
15648
 
15720
15649
  // src/shared/record-type-guard.ts
@@ -16080,6 +16009,8 @@ var init_storage_meta_shared = __esm(() => {
16080
16009
  "recovery_no_eligible_head_count",
16081
16010
  "force_emergency_bypass_window_start",
16082
16011
  "force_emergency_bypass_used",
16012
+ "emergency_drain_active",
16013
+ "historian_drain_failure_at",
16083
16014
  "upgrade_reminded_at",
16084
16015
  "pi_stable_id_scheme"
16085
16016
  ];
@@ -16129,6 +16060,8 @@ var init_storage_meta_shared = __esm(() => {
16129
16060
  recoveryNoEligibleHeadCount: "recovery_no_eligible_head_count",
16130
16061
  forceEmergencyBypassWindowStart: "force_emergency_bypass_window_start",
16131
16062
  forceEmergencyBypassUsed: "force_emergency_bypass_used",
16063
+ emergencyDrainActive: "emergency_drain_active",
16064
+ historianDrainFailureAt: "historian_drain_failure_at",
16132
16065
  upgradeRemindedAt: "upgrade_reminded_at",
16133
16066
  piStableIdScheme: "pi_stable_id_scheme"
16134
16067
  };
@@ -149680,6 +149613,22 @@ var init_tool_drop_target = __esm(() => {
149680
149613
  });
149681
149614
 
149682
149615
  // src/hooks/magic-context/read-session-chunk.ts
149616
+ function estimateBlockTokens(blockText) {
149617
+ const cached2 = blockTokenMemo.get(blockText);
149618
+ if (cached2 !== undefined) {
149619
+ blockTokenMemo.delete(blockText);
149620
+ blockTokenMemo.set(blockText, cached2);
149621
+ return cached2;
149622
+ }
149623
+ const count = estimateTokens(blockText);
149624
+ if (blockTokenMemo.size >= BLOCK_TOKEN_MEMO_MAX) {
149625
+ const oldest = blockTokenMemo.keys().next().value;
149626
+ if (oldest !== undefined)
149627
+ blockTokenMemo.delete(oldest);
149628
+ }
149629
+ blockTokenMemo.set(blockText, count);
149630
+ return count;
149631
+ }
149683
149632
  function cleanUserText(text) {
149684
149633
  return removeSystemReminders(text).replace(OMO_INTERNAL_INITIATOR_MARKER, "").trim();
149685
149634
  }
@@ -149847,7 +149796,7 @@ function readSessionChunk(sessionId, tokenBudget, offset = 1, eligibleEndOrdinal
149847
149796
  if (!currentBlock)
149848
149797
  return true;
149849
149798
  const blockText = formatBlock(currentBlock);
149850
- const blockTokens = estimateTokens(blockText);
149799
+ const blockTokens = estimateBlockTokens(blockText);
149851
149800
  if (totalTokens + blockTokens > tokenBudget && totalTokens > 0) {
149852
149801
  return false;
149853
149802
  }
@@ -149965,13 +149914,14 @@ function readSessionChunk(sessionId, tokenBudget, offset = 1, eligibleEndOrdinal
149965
149914
  toolOnlyRanges
149966
149915
  };
149967
149916
  }
149968
- var activeRawMessageCache = null, activeAbsoluteCountCache = null, sessionProviders, PROTECTED_TAIL_USER_TURNS = 5;
149917
+ var BLOCK_TOKEN_MEMO_MAX = 2048, blockTokenMemo, activeRawMessageCache = null, activeAbsoluteCountCache = null, sessionProviders, PROTECTED_TAIL_USER_TURNS = 5;
149969
149918
  var init_read_session_chunk = __esm(async () => {
149970
149919
  init_read_session_formatting();
149971
149920
  init_tag_part_guards();
149972
149921
  init_tool_drop_target();
149973
149922
  init_read_session_formatting();
149974
149923
  await init_read_session_db();
149924
+ blockTokenMemo = new Map;
149975
149925
  sessionProviders = new Map;
149976
149926
  });
149977
149927
 
@@ -150716,6 +150666,9 @@ function resolveDatabasePath(dbPathOverride) {
150716
150666
  const dbDir = getMagicContextStorageDir();
150717
150667
  return { dbDir, dbPath: join6(dbDir, "context.db") };
150718
150668
  }
150669
+ function getDatabasePath(db) {
150670
+ return pathByDatabase.get(db) ?? null;
150671
+ }
150719
150672
  function migrateLegacyStorageIfNeeded(targetDbPath, targetDbDir) {
150720
150673
  if (existsSync7(targetDbPath))
150721
150674
  return;
@@ -151226,6 +151179,8 @@ CREATE INDEX IF NOT EXISTS idx_dream_queue_pending ON dream_queue(started_at, en
151226
151179
  recovery_no_eligible_head_count INTEGER NOT NULL DEFAULT 0,
151227
151180
  force_emergency_bypass_window_start INTEGER NOT NULL DEFAULT 0,
151228
151181
  force_emergency_bypass_used INTEGER NOT NULL DEFAULT 0,
151182
+ emergency_drain_active INTEGER NOT NULL DEFAULT 0,
151183
+ historian_drain_failure_at INTEGER NOT NULL DEFAULT 0,
151229
151184
  cached_m0_materialized_at INTEGER,
151230
151185
  cached_m0_session_facts_version INTEGER,
151231
151186
  cached_m0_upgrade_state TEXT,
@@ -151289,6 +151244,23 @@ CREATE INDEX IF NOT EXISTS idx_dream_queue_pending ON dream_queue(started_at, en
151289
151244
  CREATE INDEX IF NOT EXISTS idx_historian_runs_status
151290
151245
  ON historian_runs(status, created_at DESC);
151291
151246
 
151247
+ CREATE TABLE IF NOT EXISTS transform_decisions (
151248
+ session_id TEXT NOT NULL,
151249
+ harness TEXT NOT NULL DEFAULT 'opencode',
151250
+ message_id TEXT NOT NULL,
151251
+ ts_ms INTEGER NOT NULL,
151252
+ decision TEXT NOT NULL,
151253
+ materialized INTEGER NOT NULL DEFAULT 0,
151254
+ materialize_reason TEXT,
151255
+ emergency INTEGER NOT NULL DEFAULT 0,
151256
+ dropped_tokens INTEGER NOT NULL DEFAULT 0,
151257
+ dropped_count INTEGER NOT NULL DEFAULT 0,
151258
+ input_tokens INTEGER NOT NULL DEFAULT 0,
151259
+ PRIMARY KEY (session_id, harness, message_id)
151260
+ );
151261
+ CREATE INDEX IF NOT EXISTS idx_transform_decisions_session_harness
151262
+ ON transform_decisions(session_id, harness);
151263
+
151292
151264
  CREATE INDEX IF NOT EXISTS idx_tags_session_tag_number ON tags(session_id, tag_number);
151293
151265
  CREATE INDEX IF NOT EXISTS idx_tags_session_message_id ON tags(session_id, message_id);
151294
151266
  CREATE INDEX IF NOT EXISTS idx_pending_ops_session ON pending_ops(session_id);
@@ -151440,6 +151412,8 @@ CREATE INDEX IF NOT EXISTS idx_dream_queue_pending ON dream_queue(started_at, en
151440
151412
  ensureColumn(db, "session_meta", "recovery_no_eligible_head_count", "INTEGER NOT NULL DEFAULT 0");
151441
151413
  ensureColumn(db, "session_meta", "force_emergency_bypass_window_start", "INTEGER NOT NULL DEFAULT 0");
151442
151414
  ensureColumn(db, "session_meta", "force_emergency_bypass_used", "INTEGER NOT NULL DEFAULT 0");
151415
+ ensureColumn(db, "session_meta", "emergency_drain_active", "INTEGER NOT NULL DEFAULT 0");
151416
+ ensureColumn(db, "session_meta", "historian_drain_failure_at", "INTEGER NOT NULL DEFAULT 0");
151443
151417
  ensureColumn(db, "session_meta", "cached_m0_materialized_at", "INTEGER");
151444
151418
  ensureColumn(db, "session_meta", "cached_m0_session_facts_version", "INTEGER");
151445
151419
  ensureColumn(db, "session_meta", "cached_m0_upgrade_state", "TEXT");
@@ -151518,6 +151492,22 @@ CREATE INDEX IF NOT EXISTS idx_dream_queue_pending ON dream_queue(started_at, en
151518
151492
  failed_at INTEGER NOT NULL,
151519
151493
  UNIQUE(table_name, row_id)
151520
151494
  );
151495
+ CREATE TABLE IF NOT EXISTS transform_decisions (
151496
+ session_id TEXT NOT NULL,
151497
+ harness TEXT NOT NULL DEFAULT 'opencode',
151498
+ message_id TEXT NOT NULL,
151499
+ ts_ms INTEGER NOT NULL,
151500
+ decision TEXT NOT NULL,
151501
+ materialized INTEGER NOT NULL DEFAULT 0,
151502
+ materialize_reason TEXT,
151503
+ emergency INTEGER NOT NULL DEFAULT 0,
151504
+ dropped_tokens INTEGER NOT NULL DEFAULT 0,
151505
+ dropped_count INTEGER NOT NULL DEFAULT 0,
151506
+ input_tokens INTEGER NOT NULL DEFAULT 0,
151507
+ PRIMARY KEY (session_id, harness, message_id)
151508
+ );
151509
+ CREATE INDEX IF NOT EXISTS idx_transform_decisions_session_harness
151510
+ ON transform_decisions(session_id, harness);
151521
151511
  `);
151522
151512
  ensureColumn(db, "tags", "harness", "TEXT NOT NULL DEFAULT 'opencode'");
151523
151513
  ensureColumn(db, "pending_ops", "harness", "TEXT NOT NULL DEFAULT 'opencode'");
@@ -151603,7 +151593,9 @@ function healNullIntegerColumns(db) {
151603
151593
  ["protected_tail_drain_tokens", 0],
151604
151594
  ["recovery_no_eligible_head_count", 0],
151605
151595
  ["force_emergency_bypass_window_start", 0],
151606
- ["force_emergency_bypass_used", 0]
151596
+ ["force_emergency_bypass_used", 0],
151597
+ ["emergency_drain_active", 0],
151598
+ ["historian_drain_failure_at", 0]
151607
151599
  ];
151608
151600
  for (const [column, fallback] of columns) {
151609
151601
  try {
@@ -151679,6 +151671,7 @@ function openDatabase(dbPathOrOptions) {
151679
151671
  setDatabase(db);
151680
151672
  loadToolDefinitionMeasurements(db);
151681
151673
  databases.set(dbPath, db);
151674
+ pathByDatabase.set(db, dbPath);
151682
151675
  persistenceByDatabase.set(db, true);
151683
151676
  persistenceErrorByDatabase.delete(db);
151684
151677
  return db;
@@ -151698,7 +151691,7 @@ function getDatabasePersistenceError(db) {
151698
151691
  return null;
151699
151692
  return persistenceErrorByDatabase.get(db) ?? null;
151700
151693
  }
151701
- var databases, persistenceByDatabase, persistenceErrorByDatabase, lastSchemaFenceRejection = null, LATEST_SUPPORTED_VERSION = 36, sqlitePragmaConfig, CHANNEL2_CLAIM_TTL_MS = 120000;
151694
+ var databases, persistenceByDatabase, persistenceErrorByDatabase, pathByDatabase, lastSchemaFenceRejection = null, LATEST_SUPPORTED_VERSION = 38, sqlitePragmaConfig, CHANNEL2_CLAIM_TTL_MS = 120000;
151702
151695
  var init_storage_db = __esm(async () => {
151703
151696
  init_data_path();
151704
151697
  init_logger();
@@ -151712,6 +151705,7 @@ var init_storage_db = __esm(async () => {
151712
151705
  databases = new Map;
151713
151706
  persistenceByDatabase = new WeakMap;
151714
151707
  persistenceErrorByDatabase = new WeakMap;
151708
+ pathByDatabase = new WeakMap;
151715
151709
  sqlitePragmaConfig = {
151716
151710
  cacheSizeMb: 64,
151717
151711
  mmapSizeMb: 0
@@ -153030,6 +153024,41 @@ var init_migrations = __esm(async () => {
153030
153024
  `);
153031
153025
  }
153032
153026
  }
153027
+ },
153028
+ {
153029
+ version: 37,
153030
+ description: "emergency drain catch-up latch + historian drain failure backoff",
153031
+ up: (db) => {
153032
+ const hasSessionMeta = db.prepare("SELECT 1 FROM sqlite_master WHERE type='table' AND name='session_meta'").get();
153033
+ if (!hasSessionMeta)
153034
+ return;
153035
+ ensureColumn(db, "session_meta", "emergency_drain_active", "INTEGER NOT NULL DEFAULT 0");
153036
+ ensureColumn(db, "session_meta", "historian_drain_failure_at", "INTEGER NOT NULL DEFAULT 0");
153037
+ }
153038
+ },
153039
+ {
153040
+ version: 38,
153041
+ description: "durable transform decisions for cache-event cause attribution",
153042
+ up: (db) => {
153043
+ db.exec(`
153044
+ CREATE TABLE IF NOT EXISTS transform_decisions (
153045
+ session_id TEXT NOT NULL,
153046
+ harness TEXT NOT NULL DEFAULT 'opencode',
153047
+ message_id TEXT NOT NULL,
153048
+ ts_ms INTEGER NOT NULL,
153049
+ decision TEXT NOT NULL,
153050
+ materialized INTEGER NOT NULL DEFAULT 0,
153051
+ materialize_reason TEXT,
153052
+ emergency INTEGER NOT NULL DEFAULT 0,
153053
+ dropped_tokens INTEGER NOT NULL DEFAULT 0,
153054
+ dropped_count INTEGER NOT NULL DEFAULT 0,
153055
+ input_tokens INTEGER NOT NULL DEFAULT 0,
153056
+ PRIMARY KEY (session_id, harness, message_id)
153057
+ );
153058
+ CREATE INDEX IF NOT EXISTS idx_transform_decisions_session_harness
153059
+ ON transform_decisions(session_id, harness);
153060
+ `);
153061
+ }
153033
153062
  }
153034
153063
  ];
153035
153064
  LATEST_MIGRATION_VERSION = MIGRATIONS.reduce((max, m) => Math.max(max, m.version), 0);
@@ -153434,7 +153463,9 @@ function toProtectedTailMeta(row) {
153434
153463
  protectedTailDrainTokens: numberOr(r.protected_tail_drain_tokens, 0),
153435
153464
  recoveryNoEligibleHeadCount: numberOr(r.recovery_no_eligible_head_count, 0),
153436
153465
  forceEmergencyBypassWindowStart: numberOr(r.force_emergency_bypass_window_start, 0),
153437
- forceEmergencyBypassUsed: numberOr(r.force_emergency_bypass_used, 0)
153466
+ forceEmergencyBypassUsed: numberOr(r.force_emergency_bypass_used, 0),
153467
+ emergencyDrainActive: numberOr(r.emergency_drain_active, 0),
153468
+ historianDrainFailureAt: numberOr(r.historian_drain_failure_at, 0)
153438
153469
  };
153439
153470
  }
153440
153471
  function loadProtectedTailMeta(db, sessionId) {
@@ -153442,7 +153473,7 @@ function loadProtectedTailMeta(db, sessionId) {
153442
153473
  const row = db.prepare(`SELECT prior_boundary_ordinal, protected_tail_policy_version,
153443
153474
  protected_tail_drain_window_started_at, protected_tail_drain_tokens,
153444
153475
  recovery_no_eligible_head_count, force_emergency_bypass_window_start,
153445
- force_emergency_bypass_used
153476
+ force_emergency_bypass_used, emergency_drain_active, historian_drain_failure_at
153446
153477
  FROM session_meta WHERE session_id = ?`).get(sessionId);
153447
153478
  return toProtectedTailMeta(row);
153448
153479
  }
@@ -153491,6 +153522,12 @@ function protectedTailWindowBudget(usagePercentage, usable, perRunCap) {
153491
153522
  return Math.min(750000, Math.max(3 * perRunCap, Math.round(0.35 * usable)));
153492
153523
  return Math.min(500000, Math.max(perRunCap, Math.round(0.2 * usable)));
153493
153524
  }
153525
+ function emergencyDrainExitThreshold(executeThresholdPercentage) {
153526
+ if (!Number.isFinite(executeThresholdPercentage) || executeThresholdPercentage <= 0) {
153527
+ return EMERGENCY_DRAIN_FALLBACK_EXIT_PERCENTAGE;
153528
+ }
153529
+ return Math.max(0, executeThresholdPercentage - EMERGENCY_DRAIN_EXIT_MARGIN);
153530
+ }
153494
153531
  function reserveProtectedTailDrainTokens(args) {
153495
153532
  const now = args.now ?? Date.now();
153496
153533
  const requested = Math.max(0, Math.floor(args.trueRawTokens));
@@ -153509,18 +153546,30 @@ function reserveProtectedTailDrainTokens(args) {
153509
153546
  let meta3 = loadProtectedTailMeta(args.db, args.sessionId);
153510
153547
  if (now - meta3.protectedTailDrainWindowStartedAt > DRAIN_WINDOW_MS) {
153511
153548
  args.db.prepare(`UPDATE session_meta
153512
- SET protected_tail_drain_window_started_at = ?, protected_tail_drain_tokens = 0,
153513
- force_emergency_bypass_window_start = ?, force_emergency_bypass_used = 0
153514
- WHERE session_id = ?`).run(now, now, args.sessionId);
153549
+ SET protected_tail_drain_window_started_at = ?, protected_tail_drain_tokens = 0
153550
+ WHERE session_id = ?`).run(now, args.sessionId);
153515
153551
  meta3 = loadProtectedTailMeta(args.db, args.sessionId);
153516
153552
  }
153553
+ const exitThreshold = emergencyDrainExitThreshold(args.executeThresholdPercentage);
153554
+ let latchActiveSince = meta3.emergencyDrainActive;
153555
+ if (args.usagePercentage >= EMERGENCY_DRAIN_ENTER_PERCENTAGE) {
153556
+ if (latchActiveSince <= 0)
153557
+ latchActiveSince = now;
153558
+ } else if (latchActiveSince > 0) {
153559
+ const expired = now - latchActiveSince > EMERGENCY_DRAIN_MAX_LATCH_MS;
153560
+ if (args.usagePercentage < exitThreshold || expired)
153561
+ latchActiveSince = 0;
153562
+ }
153563
+ if (latchActiveSince !== meta3.emergencyDrainActive) {
153564
+ args.db.prepare("UPDATE session_meta SET emergency_drain_active = ? WHERE session_id = ?").run(latchActiveSince, args.sessionId);
153565
+ }
153566
+ const latchActive = latchActiveSince > 0;
153517
153567
  const budget = protectedTailWindowBudget(args.usagePercentage, args.usable, args.perRunCap);
153518
153568
  const remaining = Math.max(0, budget - meta3.protectedTailDrainTokens);
153519
153569
  let reserved = Math.min(requested, args.perRunCap, remaining);
153520
153570
  let bypass = false;
153521
- const bypassWindowExpired = now - meta3.forceEmergencyBypassWindowStart > DRAIN_WINDOW_MS;
153522
- const bypassUsed = bypassWindowExpired ? 0 : meta3.forceEmergencyBypassUsed;
153523
- if (reserved <= 0 && args.usagePercentage >= 95 && bypassUsed === 0) {
153571
+ const inFailureBackoff = meta3.historianDrainFailureAt > 0 && now - meta3.historianDrainFailureAt < EMERGENCY_DRAIN_FAILURE_BACKOFF_MS;
153572
+ if (reserved <= 0 && latchActive && !inFailureBackoff) {
153524
153573
  reserved = Math.min(requested, args.perRunCap);
153525
153574
  bypass = true;
153526
153575
  }
@@ -153528,10 +153577,8 @@ function reserveProtectedTailDrainTokens(args) {
153528
153577
  return;
153529
153578
  args.db.prepare(`UPDATE session_meta
153530
153579
  SET protected_tail_drain_window_started_at = CASE WHEN protected_tail_drain_window_started_at = 0 THEN ? ELSE protected_tail_drain_window_started_at END,
153531
- protected_tail_drain_tokens = COALESCE(protected_tail_drain_tokens, 0) + ?,
153532
- force_emergency_bypass_window_start = CASE WHEN ? THEN ? ELSE force_emergency_bypass_window_start END,
153533
- force_emergency_bypass_used = CASE WHEN ? THEN 1 ELSE force_emergency_bypass_used END
153534
- WHERE session_id = ?`).run(now, reserved, bypass ? 1 : 0, now, bypass ? 1 : 0, args.sessionId);
153580
+ protected_tail_drain_tokens = COALESCE(protected_tail_drain_tokens, 0) + ?
153581
+ WHERE session_id = ?`).run(now, reserved, args.sessionId);
153535
153582
  result = {
153536
153583
  ok: true,
153537
153584
  reservedTokens: reserved,
@@ -153541,6 +153588,25 @@ function reserveProtectedTailDrainTokens(args) {
153541
153588
  })();
153542
153589
  return result;
153543
153590
  }
153591
+ function clearEmergencyDrainLatch(db, sessionId) {
153592
+ db.transaction(() => {
153593
+ ensureSessionMetaRow(db, sessionId);
153594
+ db.prepare("UPDATE session_meta SET emergency_drain_active = 0 WHERE session_id = ?").run(sessionId);
153595
+ })();
153596
+ }
153597
+ function recordHistorianDrainFailure(db, sessionId, now) {
153598
+ const ts = now ?? Date.now();
153599
+ db.transaction(() => {
153600
+ ensureSessionMetaRow(db, sessionId);
153601
+ db.prepare("UPDATE session_meta SET historian_drain_failure_at = ? WHERE session_id = ?").run(ts, sessionId);
153602
+ })();
153603
+ }
153604
+ function clearHistorianDrainFailure(db, sessionId) {
153605
+ db.transaction(() => {
153606
+ ensureSessionMetaRow(db, sessionId);
153607
+ db.prepare("UPDATE session_meta SET historian_drain_failure_at = 0 WHERE session_id = ?").run(sessionId);
153608
+ })();
153609
+ }
153544
153610
  function rollbackProtectedTailDrainReservation(db, reservation) {
153545
153611
  if (!reservation || reservation.tokens <= 0)
153546
153612
  return;
@@ -154108,7 +154174,7 @@ function setSessionWorkMetrics(db, sessionId, newWorkTokens, totalInputTokens) {
154108
154174
  SET new_work_tokens = ?, total_input_tokens = ?
154109
154175
  WHERE session_id = ?`).run(Math.max(0, Math.floor(newWorkTokens)), Math.max(0, Math.floor(totalInputTokens)), sessionId);
154110
154176
  }
154111
- var CAS_RETRY_LIMIT = 5, AUTO_SEARCH_NO_HINT_REASONS, DEFAULT_PROTECTED_TAIL_META, DRAIN_WINDOW_MS;
154177
+ var CAS_RETRY_LIMIT = 5, AUTO_SEARCH_NO_HINT_REASONS, DEFAULT_PROTECTED_TAIL_META, DRAIN_WINDOW_MS, EMERGENCY_DRAIN_ENTER_PERCENTAGE = 95, EMERGENCY_DRAIN_EXIT_MARGIN = 10, EMERGENCY_DRAIN_FALLBACK_EXIT_PERCENTAGE = 55, EMERGENCY_DRAIN_FAILURE_BACKOFF_MS = 60000, EMERGENCY_DRAIN_MAX_LATCH_MS;
154112
154178
  var init_storage_meta_persisted = __esm(() => {
154113
154179
  init_logger();
154114
154180
  init_storage_meta_shared();
@@ -154127,9 +154193,12 @@ var init_storage_meta_persisted = __esm(() => {
154127
154193
  protectedTailDrainTokens: 0,
154128
154194
  recoveryNoEligibleHeadCount: 0,
154129
154195
  forceEmergencyBypassWindowStart: 0,
154130
- forceEmergencyBypassUsed: 0
154196
+ forceEmergencyBypassUsed: 0,
154197
+ emergencyDrainActive: 0,
154198
+ historianDrainFailureAt: 0
154131
154199
  };
154132
154200
  DRAIN_WINDOW_MS = 10 * 60 * 1000;
154201
+ EMERGENCY_DRAIN_MAX_LATCH_MS = 30 * 60 * 1000;
154133
154202
  });
154134
154203
 
154135
154204
  // src/features/magic-context/resolve-subagent-fallback.ts
@@ -154247,6 +154316,7 @@ function clearSession(db, sessionId) {
154247
154316
  db.prepare("DELETE FROM subagent_invocations WHERE session_id = ?").run(sessionId);
154248
154317
  db.prepare("DELETE FROM historian_runs WHERE session_id = ?").run(sessionId);
154249
154318
  db.prepare("DELETE FROM plugin_messages WHERE session_id = ?").run(sessionId);
154319
+ db.prepare("DELETE FROM transform_decisions WHERE session_id = ?").run(sessionId);
154250
154320
  clearIndexedMessages(db, sessionId);
154251
154321
  })();
154252
154322
  }
@@ -154692,12 +154762,17 @@ function getOldestActiveUnprotectedToolTags(db, sessionId, protectedTags = 0, li
154692
154762
  toolName: typeof row.tool_name === "string" ? row.tool_name : null
154693
154763
  }));
154694
154764
  }
154695
- function getTriggerTagTokenUpperBound(db, sessionId) {
154696
- const row = db.prepare(`SELECT
154765
+ function getTriggerTagTokenUpperBound(db, sessionId, floor = 0) {
154766
+ const sql = floor > 0 ? `SELECT
154697
154767
  COALESCE(SUM(COALESCE(token_count, 0) + COALESCE(input_token_count, 0) + COALESCE(reasoning_token_count, 0)), 0) AS bound,
154698
154768
  COALESCE(SUM(CASE WHEN token_count IS NULL THEN 1 ELSE 0 END), 0) AS null_count
154699
154769
  FROM tags
154700
- WHERE session_id = ? AND status IN ('active', 'dropped')`).get(sessionId);
154770
+ WHERE session_id = ? AND status IN ('active', 'dropped') AND tag_number >= ?` : `SELECT
154771
+ COALESCE(SUM(COALESCE(token_count, 0) + COALESCE(input_token_count, 0) + COALESCE(reasoning_token_count, 0)), 0) AS bound,
154772
+ COALESCE(SUM(CASE WHEN token_count IS NULL THEN 1 ELSE 0 END), 0) AS null_count
154773
+ FROM tags
154774
+ WHERE session_id = ? AND status IN ('active', 'dropped')`;
154775
+ const row = floor > 0 ? db.prepare(sql).get(sessionId, floor) : db.prepare(sql).get(sessionId);
154701
154776
  return { bound: row?.bound ?? 0, nullCount: row?.null_count ?? 0 };
154702
154777
  }
154703
154778
  function getActiveTagTokenTotalsByMessage(db, sessionId) {
@@ -154726,10 +154801,12 @@ function getActiveTagTokenTotalsByMessage(db, sessionId) {
154726
154801
  }
154727
154802
  return out;
154728
154803
  }
154729
- function getAllStatusTagTokenTotalsFlat(db, sessionId) {
154730
- const rows = db.prepare(`SELECT type, message_id, tool_owner_message_id, token_count, input_token_count, reasoning_token_count
154731
- FROM tags
154732
- WHERE session_id = ?`).all(sessionId);
154804
+ function getAllStatusTagTokenTotalsFlat(db, sessionId, floor = 0) {
154805
+ const rows = floor > 0 ? db.prepare(`SELECT type, message_id, tool_owner_message_id, token_count, input_token_count, reasoning_token_count
154806
+ FROM tags
154807
+ WHERE session_id = ? AND tag_number >= ?`).all(sessionId, floor) : db.prepare(`SELECT type, message_id, tool_owner_message_id, token_count, input_token_count, reasoning_token_count
154808
+ FROM tags
154809
+ WHERE session_id = ?`).all(sessionId);
154733
154810
  const totals = new Map;
154734
154811
  const nullMessageIds = new Set;
154735
154812
  for (const row of rows) {
@@ -154888,6 +154965,47 @@ function getTagNumberByMessageId(db, sessionId, messageId) {
154888
154965
  const row = getTagNumberByMessageIdStatement(db).get(sessionId, messageId);
154889
154966
  return isTagNumberRow(row) ? row.tag_number : null;
154890
154967
  }
154968
+ function isMinTagNumberRow(row) {
154969
+ return row !== null && typeof row === "object" && "m" in row;
154970
+ }
154971
+ function getMinMessageTagNumberForRawId(db, sessionId, rawId) {
154972
+ if (rawId.includes(":"))
154973
+ return null;
154974
+ let stmt = getMinMessageTagNumberForRawIdStatements.get(db);
154975
+ if (!stmt) {
154976
+ stmt = db.prepare("SELECT MIN(tag_number) AS m FROM tags WHERE session_id = ? AND message_id >= ? AND message_id < ?");
154977
+ getMinMessageTagNumberForRawIdStatements.set(db, stmt);
154978
+ }
154979
+ const row = stmt.get(sessionId, `${rawId}:`, `${rawId};`);
154980
+ return isMinTagNumberRow(row) && typeof row.m === "number" ? row.m : null;
154981
+ }
154982
+ function deriveTagLoadFloor(db, sessionId, rawIds) {
154983
+ let min = Number.POSITIVE_INFINITY;
154984
+ let probes = 0;
154985
+ let hits = 0;
154986
+ let skippedBeforeFirstHit = 0;
154987
+ for (const rawId of rawIds) {
154988
+ if (typeof rawId !== "string" || rawId.length === 0)
154989
+ continue;
154990
+ if (probes >= TAGGER_FLOOR_MAX_PROBES)
154991
+ break;
154992
+ probes++;
154993
+ const m = getMinMessageTagNumberForRawId(db, sessionId, rawId);
154994
+ if (m === null) {
154995
+ if (hits === 0)
154996
+ skippedBeforeFirstHit++;
154997
+ continue;
154998
+ }
154999
+ if (m < min)
155000
+ min = m;
155001
+ if (++hits >= TAGGER_FLOOR_SCAN_MESSAGES)
155002
+ break;
155003
+ }
155004
+ if (!Number.isFinite(min))
155005
+ return 0;
155006
+ const margin = TAGGER_FLOOR_SAFETY_MARGIN + skippedBeforeFirstHit * TAGGER_FLOOR_PER_SKIP_MARGIN;
155007
+ return Math.max(0, min - margin);
155008
+ }
154891
155009
  function getTagsBySession(db, sessionId) {
154892
155010
  const rows = db.prepare(`SELECT ${TAG_SELECT_COLUMNS} FROM tags WHERE session_id = ? ORDER BY tag_number ASC, id ASC`).all(sessionId).filter(isTagRow);
154893
155011
  return rows.map(toTagEntry);
@@ -155026,7 +155144,7 @@ function deleteToolTagsByOwner(db, sessionId, ownerMsgId) {
155026
155144
  const result = getDeleteToolTagsByOwnerStatement(db).run(sessionId, ownerMsgId);
155027
155145
  return result.changes ?? 0;
155028
155146
  }
155029
- var insertTagStatements, updateTagStatusStatements, updateTagDropModeStatements, updateTagMessageIdStatements, getTagNumbersByMessageIdStatements, deleteTagsByMessageIdStatements, getMaxTagNumberBySessionStatements, getTagNumberByMessageIdStatements, updateTagByteSizeStatements, updateTagInputByteSizeStatements, CONTENT_ID_SUFFIX, updateTagTokenCountStatements, updateTagInputTokenCountStatements, getOwnerScopedToolTagNumbersStatements, TAG_SELECT_COLUMNS = "id, message_id, type, status, drop_mode, tool_name, input_byte_size, byte_size, reasoning_byte_size, session_id, tag_number, caveman_depth, tool_owner_message_id", getActiveTagsBySessionStatements, getMaxDroppedTagNumberStatements, getToolTagNumberByOwnerStatements, getNullOwnerToolTagStatements, adoptNullOwnerToolTagStatements, deleteToolTagsByOwnerStatements;
155147
+ var insertTagStatements, updateTagStatusStatements, updateTagDropModeStatements, updateTagMessageIdStatements, getTagNumbersByMessageIdStatements, deleteTagsByMessageIdStatements, getMaxTagNumberBySessionStatements, getTagNumberByMessageIdStatements, updateTagByteSizeStatements, updateTagInputByteSizeStatements, CONTENT_ID_SUFFIX, updateTagTokenCountStatements, updateTagInputTokenCountStatements, getOwnerScopedToolTagNumbersStatements, getMinMessageTagNumberForRawIdStatements, TAGGER_FLOOR_SCAN_MESSAGES = 8, TAGGER_FLOOR_MAX_PROBES = 64, TAGGER_FLOOR_SAFETY_MARGIN = 256, TAGGER_FLOOR_PER_SKIP_MARGIN = 64, TAG_SELECT_COLUMNS = "id, message_id, type, status, drop_mode, tool_name, input_byte_size, byte_size, reasoning_byte_size, session_id, tag_number, caveman_depth, tool_owner_message_id", getActiveTagsBySessionStatements, getMaxDroppedTagNumberStatements, getToolTagNumberByOwnerStatements, getNullOwnerToolTagStatements, adoptNullOwnerToolTagStatements, deleteToolTagsByOwnerStatements;
155030
155148
  var init_storage_tags = __esm(() => {
155031
155149
  insertTagStatements = new WeakMap;
155032
155150
  updateTagStatusStatements = new WeakMap;
@@ -155042,6 +155160,7 @@ var init_storage_tags = __esm(() => {
155042
155160
  updateTagTokenCountStatements = new WeakMap;
155043
155161
  updateTagInputTokenCountStatements = new WeakMap;
155044
155162
  getOwnerScopedToolTagNumbersStatements = new WeakMap;
155163
+ getMinMessageTagNumberForRawIdStatements = new WeakMap;
155045
155164
  getActiveTagsBySessionStatements = new WeakMap;
155046
155165
  getMaxDroppedTagNumberStatements = new WeakMap;
155047
155166
  getToolTagNumberByOwnerStatements = new WeakMap;
@@ -165462,6 +165581,16 @@ function buildCanonicalChunkTextFromFts(db, sessionId, startOrdinal, endOrdinal)
165462
165581
  return lines.join(`
165463
165582
  `);
165464
165583
  }
165584
+ function buildCompartmentSummaryFallbackText(db, compartmentId) {
165585
+ const row = db.prepare("SELECT title, p1, content FROM compartments WHERE id = ?").get(compartmentId);
165586
+ if (!row)
165587
+ return "";
165588
+ const title = typeof row.title === "string" ? row.title.trim() : "";
165589
+ const p1 = typeof row.p1 === "string" ? row.p1.trim() : "";
165590
+ const body = p1.length > 0 ? p1 : typeof row.content === "string" ? row.content.trim() : "";
165591
+ return [title, body].filter((s) => s.length > 0).join(`
165592
+ `);
165593
+ }
165465
165594
  function canonicalizeInMemoryChunkTextForEmbedding(chunkText, startOrdinal, endOrdinal) {
165466
165595
  const lines = [];
165467
165596
  for (const rawLine of chunkText.split(/\r?\n/)) {
@@ -166059,7 +166188,7 @@ class LocalEmbeddingProvider {
166059
166188
  waiter();
166060
166189
  }
166061
166190
  }
166062
- async embed(text, signal) {
166191
+ async embed(text, signal, _purpose) {
166063
166192
  if (signal?.aborted)
166064
166193
  return null;
166065
166194
  if (this.disposing)
@@ -166085,7 +166214,7 @@ class LocalEmbeddingProvider {
166085
166214
  this.finishInFlight();
166086
166215
  }
166087
166216
  }
166088
- async embedBatch(texts, signal) {
166217
+ async embedBatch(texts, signal, _purpose) {
166089
166218
  if (texts.length === 0) {
166090
166219
  return [];
166091
166220
  }
@@ -166229,6 +166358,7 @@ class OpenAICompatibleEmbeddingProvider {
166229
166358
  model;
166230
166359
  apiKey;
166231
166360
  inputType;
166361
+ queryInputType;
166232
166362
  truncate;
166233
166363
  initialized = false;
166234
166364
  failureTimes = [];
@@ -166241,6 +166371,7 @@ class OpenAICompatibleEmbeddingProvider {
166241
166371
  this.model = options.model?.trim() ?? "";
166242
166372
  this.apiKey = options.apiKey?.trim() ?? "";
166243
166373
  this.inputType = options.inputType?.trim() ?? "";
166374
+ this.queryInputType = options.queryInputType?.trim() ?? "";
166244
166375
  this.truncate = options.truncate?.trim() ?? "";
166245
166376
  this.maxInputTokens = typeof options.maxInputTokens === "number" && Number.isFinite(options.maxInputTokens) ? Math.max(1, Math.floor(options.maxInputTokens)) : 512;
166246
166377
  this.modelId = getEmbeddingProviderIdentity({
@@ -166268,11 +166399,17 @@ class OpenAICompatibleEmbeddingProvider {
166268
166399
  this.initialized = true;
166269
166400
  return true;
166270
166401
  }
166271
- async embed(text, signal) {
166272
- const [embedding] = await this.embedBatch([text], signal);
166402
+ resolveInputTypeForPurpose(purpose = "passage") {
166403
+ if (purpose === "query") {
166404
+ return this.queryInputType || this.inputType;
166405
+ }
166406
+ return this.inputType;
166407
+ }
166408
+ async embed(text, signal, purpose) {
166409
+ const [embedding] = await this.embedBatch([text], signal, purpose);
166273
166410
  return embedding ?? null;
166274
166411
  }
166275
- async embedBatch(texts, signal) {
166412
+ async embedBatch(texts, signal, purpose) {
166276
166413
  if (texts.length === 0) {
166277
166414
  return [];
166278
166415
  }
@@ -166298,6 +166435,7 @@ class OpenAICompatibleEmbeddingProvider {
166298
166435
  if (signal) {
166299
166436
  signal.addEventListener("abort", onOuterAbort, { once: true });
166300
166437
  }
166438
+ const inputTypeForRequest = this.resolveInputTypeForPurpose(purpose);
166301
166439
  const response = await fetch(`${this.endpoint}/embeddings`, {
166302
166440
  method: "POST",
166303
166441
  headers: {
@@ -166307,7 +166445,7 @@ class OpenAICompatibleEmbeddingProvider {
166307
166445
  body: JSON.stringify({
166308
166446
  model: this.model,
166309
166447
  input: texts,
166310
- ...this.inputType ? { input_type: this.inputType } : {},
166448
+ ...inputTypeForRequest ? { input_type: inputTypeForRequest } : {},
166311
166449
  ...this.truncate ? { truncate: this.truncate } : {}
166312
166450
  }),
166313
166451
  redirect: "error",
@@ -166884,6 +167022,7 @@ function resolveEmbeddingConfig(config2) {
166884
167022
  if (config2.provider === "openai-compatible") {
166885
167023
  const apiKey = config2.api_key?.trim();
166886
167024
  const inputType = config2.input_type?.trim();
167025
+ const queryInputType = config2.query_input_type?.trim();
166887
167026
  const truncate = config2.truncate?.trim();
166888
167027
  return {
166889
167028
  provider: "openai-compatible",
@@ -166891,6 +167030,7 @@ function resolveEmbeddingConfig(config2) {
166891
167030
  endpoint: config2.endpoint.trim(),
166892
167031
  ...apiKey ? { api_key: apiKey } : {},
166893
167032
  ...inputType ? { input_type: inputType } : {},
167033
+ ...queryInputType ? { query_input_type: queryInputType } : {},
166894
167034
  ...truncate ? { truncate } : {},
166895
167035
  ...config2.max_input_tokens ? {
166896
167036
  max_input_tokens: normalizeCompartmentChunkMaxInputTokens(config2.max_input_tokens)
@@ -166912,6 +167052,7 @@ function createProvider(config2) {
166912
167052
  model: config2.model,
166913
167053
  apiKey: config2.api_key,
166914
167054
  inputType: config2.input_type,
167055
+ queryInputType: config2.query_input_type,
166915
167056
  truncate: config2.truncate,
166916
167057
  maxInputTokens: config2.max_input_tokens
166917
167058
  });
@@ -167094,7 +167235,7 @@ function getOrCreateProjectProvider(registration) {
167094
167235
  registration.provider = provider;
167095
167236
  return provider;
167096
167237
  }
167097
- async function embedTextForProject(projectIdentity, text, signal) {
167238
+ async function embedTextForProject(projectIdentity, text, signal, purpose = "passage") {
167098
167239
  const registration = projectRegistrations.get(projectIdentity);
167099
167240
  if (!registration)
167100
167241
  return null;
@@ -167103,7 +167244,7 @@ async function embedTextForProject(projectIdentity, text, signal) {
167103
167244
  const provider = getOrCreateProjectProvider(registration);
167104
167245
  if (!provider)
167105
167246
  return null;
167106
- const vector = await provider.embed(text, signal);
167247
+ const vector = await provider.embed(text, signal, purpose);
167107
167248
  if (!vector)
167108
167249
  return null;
167109
167250
  const current = projectRegistrations.get(projectIdentity);
@@ -167112,7 +167253,7 @@ async function embedTextForProject(projectIdentity, text, signal) {
167112
167253
  }
167113
167254
  return { vector, modelId, generation };
167114
167255
  }
167115
- async function embedBatchForProject(projectIdentity, texts, signal) {
167256
+ async function embedBatchForProject(projectIdentity, texts, signal, purpose = "passage") {
167116
167257
  if (texts.length === 0) {
167117
167258
  const registration2 = projectRegistrations.get(projectIdentity);
167118
167259
  if (!registration2 || registration2.observationMode)
@@ -167128,7 +167269,7 @@ async function embedBatchForProject(projectIdentity, texts, signal) {
167128
167269
  const provider = getOrCreateProjectProvider(registration);
167129
167270
  if (!provider)
167130
167271
  return null;
167131
- const vectors = await provider.embedBatch(texts, signal);
167272
+ const vectors = await provider.embedBatch(texts, signal, purpose);
167132
167273
  const current = projectRegistrations.get(projectIdentity);
167133
167274
  if (!current || current.generation !== generation || current.runtimeFingerprint !== runtimeFingerprint) {
167134
167275
  return null;
@@ -167185,7 +167326,7 @@ async function embedCandidateChunkBatch(db, projectIdentity, modelId, candidates
167185
167326
  const maxInputTokens = getProjectEmbeddingMaxInputTokens(projectIdentity);
167186
167327
  const prepared = [];
167187
167328
  for (const candidate of candidates) {
167188
- const canonicalText = buildCanonicalChunkTextFromFts(db, candidate.sessionId, candidate.startMessage, candidate.endMessage);
167329
+ const canonicalText = buildCanonicalChunkTextFromFts(db, candidate.sessionId, candidate.startMessage, candidate.endMessage) || buildCompartmentSummaryFallbackText(db, candidate.id);
167189
167330
  if (canonicalText.length === 0) {
167190
167331
  noWork.push(candidate.id);
167191
167332
  continue;
@@ -167406,6 +167547,7 @@ function createProvider2(config2) {
167406
167547
  model: config2.model,
167407
167548
  apiKey: config2.api_key,
167408
167549
  inputType: config2.input_type,
167550
+ queryInputType: config2.query_input_type,
167409
167551
  truncate: config2.truncate,
167410
167552
  maxInputTokens: config2.max_input_tokens
167411
167553
  });
@@ -167670,7 +167812,7 @@ async function embedAndStoreCompartmentChunks(db, sessionId, projectPath, compar
167670
167812
  for (const compartment of compartments) {
167671
167813
  try {
167672
167814
  const fromMemory = compartment.sourceChunkText ? canonicalizeInMemoryChunkTextForEmbedding(compartment.sourceChunkText, compartment.startMessage, compartment.endMessage) : "";
167673
- const canonicalText = fromMemory || buildCanonicalChunkTextFromFts(db, sessionId, compartment.startMessage, compartment.endMessage);
167815
+ const canonicalText = fromMemory || buildCanonicalChunkTextFromFts(db, sessionId, compartment.startMessage, compartment.endMessage) || buildCompartmentSummaryFallbackText(db, compartment.id);
167674
167816
  if (canonicalText.length === 0)
167675
167817
  continue;
167676
167818
  const windows = chunkCanonicalText(canonicalText, compartment.startMessage, compartment.endMessage, maxInputTokens);
@@ -170870,29 +171012,12 @@ function resolveHistorianContextLimit(historianModelOverride) {
170870
171012
  return DEFAULT_HISTORIAN_CONTEXT_FALLBACK;
170871
171013
  }
170872
171014
  if (typeof historianModelOverride === "string" && historianModelOverride.trim() !== "") {
170873
- console.warn(`[magic-context] historian.model "${historianModelOverride}" lacks provider prefix ("provider/model-id"); using fallback chain for chunk-budget derivation.`);
170874
- }
170875
- const chain = AGENT_MODEL_REQUIREMENTS[HISTORIAN_AGENT]?.fallbackChain;
170876
- if (!chain || chain.length === 0)
170877
- return DEFAULT_HISTORIAN_CONTEXT_FALLBACK;
170878
- const expanded = expandFallbackChain(chain);
170879
- let minLimit;
170880
- for (const key of expanded) {
170881
- const [providerID, ...rest] = key.split("/");
170882
- const modelID = rest.join("/");
170883
- if (!providerID || !modelID)
170884
- continue;
170885
- const limit = getSdkContextLimit(providerID, modelID);
170886
- if (typeof limit !== "number" || limit <= 0)
170887
- continue;
170888
- if (minLimit === undefined || limit < minLimit)
170889
- minLimit = limit;
171015
+ console.warn(`[magic-context] historian.model "${historianModelOverride}" lacks provider prefix ("provider/model-id"); using the default context limit for chunk-budget derivation.`);
170890
171016
  }
170891
- return minLimit ?? DEFAULT_HISTORIAN_CONTEXT_FALLBACK;
171017
+ return DEFAULT_HISTORIAN_CONTEXT_FALLBACK;
170892
171018
  }
170893
171019
  var TRIGGER_BUDGET_PERCENTAGE = 0.05, TRIGGER_BUDGET_MIN = 5000, TRIGGER_BUDGET_MAX = 50000, HISTORIAN_CHUNK_PERCENTAGE = 0.25, HISTORIAN_CHUNK_MIN = 8000, HISTORIAN_CHUNK_MAX = 50000, DEFAULT_HISTORIAN_CONTEXT_FALLBACK = 128000;
170894
171020
  var init_derive_budgets = __esm(() => {
170895
- init_model_requirements();
170896
171021
  init_models_dev_cache();
170897
171022
  });
170898
171023
 
@@ -171692,7 +171817,7 @@ function resolveBoundaryContext(args) {
171692
171817
  }
171693
171818
  let storedTokenTotals;
171694
171819
  try {
171695
- storedTokenTotals = getAllStatusTagTokenTotalsFlat(args.db, args.sessionId).totals;
171820
+ storedTokenTotals = getAllStatusTagTokenTotalsFlat(args.db, args.sessionId, args.taggerFloor ?? 0).totals;
171696
171821
  } catch (error51) {
171697
171822
  sessionLog(args.sessionId, "protected-tail stored-token map unavailable (live fallback):", error51);
171698
171823
  }
@@ -173896,6 +174021,7 @@ async function runCompartmentAgent(deps) {
173896
174021
  const count = recordHighPressureNoEligibleHead(db, boundarySnapshot);
173897
174022
  sessionLog(sessionId, `historian high-pressure no-op: recovery remains armed (noEligibleHeadCount=${count})`);
173898
174023
  }
174024
+ clearEmergencyDrainLatch(db, sessionId);
173899
174025
  telemetry.status = "noop";
173900
174026
  telemetry.failureReason = "nothing to compact before protected tail";
173901
174027
  rollbackDrainReservation();
@@ -173910,7 +174036,8 @@ async function runCompartmentAgent(deps) {
173910
174036
  trueRawTokens: boundarySnapshot.trueRawEligibleTokens,
173911
174037
  usagePercentage: boundarySnapshot.usagePercentage,
173912
174038
  usable,
173913
- perRunCap
174039
+ perRunCap,
174040
+ executeThresholdPercentage: boundarySnapshot.executeThresholdPercentage
173914
174041
  });
173915
174042
  if (!reserve.ok) {
173916
174043
  sessionLog(sessionId, `historian rate-limit skip: ${reserve.skippedReason ?? "quota exhausted"}`);
@@ -173929,6 +174056,7 @@ async function runCompartmentAgent(deps) {
173929
174056
  } else {
173930
174057
  recordHighPressureNoEligibleHead(db, boundarySnapshot);
173931
174058
  }
174059
+ clearEmergencyDrainLatch(db, sessionId);
173932
174060
  telemetry.status = "noop";
173933
174061
  telemetry.failureReason = "chunk empty after filtering";
173934
174062
  rollbackDrainReservation();
@@ -174036,6 +174164,7 @@ ${chunkText}`,
174036
174164
  }
174037
174165
  appendCompartments(db, sessionId, persistedCompartments);
174038
174166
  clearHistorianFailureState(db, sessionId);
174167
+ clearHistorianDrainFailure(db, sessionId);
174039
174168
  recordProtectedTailPublicationFloor(db, sessionId, lastCompartmentEnd + 1);
174040
174169
  clearEmergencyRecovery(db, sessionId);
174041
174170
  drainReservation = null;
@@ -174139,8 +174268,11 @@ ${chunkText}`,
174139
174268
  }
174140
174269
  } finally {
174141
174270
  if (!completedSuccessfully) {
174142
- if (!retainDrainReservationForRetryThrottle)
174271
+ if (!retainDrainReservationForRetryThrottle) {
174143
174272
  rollbackDrainReservation();
174273
+ } else {
174274
+ recordHistorianDrainFailure(db, sessionId);
174275
+ }
174144
174276
  updateSessionMeta(db, sessionId, { compartmentInProgress: false });
174145
174277
  }
174146
174278
  recordTelemetry();
@@ -177254,7 +177386,6 @@ var init_memory_migration = __esm(async () => {
177254
177386
  init_shared();
177255
177387
  init_assistant_message_extractor();
177256
177388
  init_logger();
177257
- init_resolve_fallbacks();
177258
177389
  init_project_identity();
177259
177390
  init_storage_memory();
177260
177391
  await init_storage();
@@ -177570,17 +177701,20 @@ function shouldShowAnnouncement() {
177570
177701
  }
177571
177702
  return state.version !== ANNOUNCEMENT_VERSION;
177572
177703
  }
177573
- var ANNOUNCEMENT_VERSION = "0.25.0", ANNOUNCEMENT_FEATURES, ANNOUNCEMENT_FOOTER = "Join us on Discord: https://discord.gg/F2uWxjGnU", STATE_FILENAME = "last_announced_version";
177704
+ var ANNOUNCEMENT_VERSION = "0.26.0", ANNOUNCEMENT_FEATURES, ANNOUNCEMENT_FOOTER = "Join us on Discord: https://discord.gg/F2uWxjGnU", STATE_FILENAME = "last_announced_version";
177574
177705
  var init_announcement = __esm(() => {
177575
177706
  init_data_path();
177576
177707
  ANNOUNCEMENT_FEATURES = [
177577
- "Old tool output is now reclaimed automatically: once a file read / search / command output has gone a full execute cycle unused, it's dropped on the next one — no need to call ctx_reduce for stale results.",
177578
- "Recover anything that was dropped: ctx_expand({ message: N }) returns a dropped message's full content (every tool call's input + output) from storage. ctx_expand({ start, end, verbose: true }) lists a range message-by-message to find it.",
177579
- "Searchable history made reliable: /ctx-embed shows embedding coverage and runs a resilient backfill (retries transient failures, no longer bails on the first hiccup); the active session now auto-embeds in the background. ctx_reduce guidance also reframed as deferred + recoverable so models trim spent output earlier.",
177580
- "Pi: fixed /ctx-dream (was failing with 'Unknown named parameter') and local-embedding load failures on Windows/Desktop (#151, #128).",
177581
- "Runaway background agents on weak/local models are now capped and force-stopped (#154, #152). Plus several prompt-cache busts removed."
177708
+ "Faster on large sessions: per-message transform overhead is at least 2x lower on typical passes and up to ~10x lower when history summarization fires (no more multi-second pause on big sessions).",
177709
+ "No more surprise models: the built-in fallback chain is gone. Hidden agents only use the model (and fallback_models) you configure — no confusing 'model not found' for providers you never set up. `doctor` now records every historian run so real failures are visible.",
177710
+ "Anthropic thinking-block fix: clearing old reasoning no longer risks a stale-signature rejection on Claude / Bedrock / proxied-Claude routes. Plus fewer prompt-cache busts.",
177711
+ "Community fixes: TUI crash on the upgrade progress panel (#168), historian.disallowed_tools for weak models that loop on tool calls (#166), and a Pi-only config key leak (#167).",
177712
+ "New: doctor migrate-session re-homes a session (and optionally its memories) to another project, with a dry-run preview."
177582
177713
  ];
177583
177714
  });
177715
+
177716
+ // src/agents/dreamer.ts
177717
+ var DREAMER_AGENT = "dreamer";
177584
177718
  // src/agents/permissions.ts
177585
177719
  function buildAllowOnlyPermission(allowedTools) {
177586
177720
  const permission = { "*": "deny" };
@@ -177590,6 +177724,11 @@ function buildAllowOnlyPermission(allowedTools) {
177590
177724
  return permission;
177591
177725
  }
177592
177726
  var HISTORIAN_ALLOWED_TOOLS = ["read", "aft_outline", "aft_zoom", "aft_search"];
177727
+ function applyDisallowedTools(defaults, disallowed) {
177728
+ if (disallowed.includes("*"))
177729
+ return [];
177730
+ return defaults.filter((t) => !disallowed.includes(t));
177731
+ }
177593
177732
  var DREAMER_ALLOWED_TOOLS = [
177594
177733
  "read",
177595
177734
  "grep",
@@ -177605,6 +177744,10 @@ var DREAMER_ALLOWED_TOOLS = [
177605
177744
  "ctx_note"
177606
177745
  ];
177607
177746
  var SIDEKICK_ALLOWED_TOOLS = ["ctx_search", "aft_outline", "aft_zoom"];
177747
+
177748
+ // src/agents/sidekick.ts
177749
+ var SIDEKICK_AGENT = "sidekick";
177750
+
177608
177751
  // src/config/index.ts
177609
177752
  init_jsonc_parser();
177610
177753
  import { existsSync as existsSync3, readFileSync as readFileSync3 } from "node:fs";
@@ -178558,6 +178701,7 @@ ${modeIntro}
178558
178701
  4. **Write or update** using the Write tool. Always write to project root, NOT to .planning/.
178559
178702
 
178560
178703
  ### Rules
178704
+ - **NEVER touch protected regions**: any content between \`<!-- mc:protected START ... -->\` and \`<!-- mc:protected END -->\` is hand-authored and cache-critical. Reproduce it BYTE-FOR-BYTE in your rewrite — do not edit, reword, reorder, summarize, trim, or drop a single line of it, and keep the marker comments themselves. Only a human edits that region.
178561
178705
  - **Be prescriptive**: "Use X pattern" not "X pattern is used"
178562
178706
  - **Always include file paths** in backticks
178563
178707
  - **Write current state only**: no temporal language, no history
@@ -178694,7 +178838,6 @@ init_project_identity();
178694
178838
  init_shared();
178695
178839
  init_assistant_message_extractor();
178696
178840
  init_logger();
178697
- init_resolve_fallbacks();
178698
178841
  init_subagent_token_capture();
178699
178842
  await init_storage();
178700
178843
 
@@ -178716,7 +178859,7 @@ function stripThinkingBlocks(text) {
178716
178859
 
178717
178860
  // src/features/magic-context/sidekick/agent.ts
178718
178861
  async function runSidekick(deps) {
178719
- const fallbackModels = resolveFallbackChain(SIDEKICK_AGENT, deps.config.fallback_models);
178862
+ const fallbackModels = resolveFallbackChain(deps.config.fallback_models);
178720
178863
  let agentSessionId = null;
178721
178864
  const startedAt = Date.now();
178722
178865
  let invocationRecorded = false;
@@ -178806,6 +178949,11 @@ init_project_identity();
178806
178949
  import { createHash as createHash6 } from "node:crypto";
178807
178950
  import { realpathSync as realpathSync2 } from "node:fs";
178808
178951
  import path5 from "node:path";
178952
+
178953
+ // src/features/magic-context/memory/relocate-memory.ts
178954
+ var memoryCopyColumnsCache = new WeakMap;
178955
+
178956
+ // src/features/magic-context/v22-deferred-backfill.ts
178809
178957
  var BATCH_SIZE = 25;
178810
178958
  var YIELD_EVERY_N_ROWS = 5;
178811
178959
  var BACKFILL_META_KEY = "v22_legacy_memory_backfill";
@@ -179043,6 +179191,7 @@ function createLiveSessionState() {
179043
179191
 
179044
179192
  // src/index.ts
179045
179193
  init_conflict_warning_hook();
179194
+
179046
179195
  // src/features/magic-context/dreamer/storage-dream-state.ts
179047
179196
  var getDreamStateStatements = new WeakMap;
179048
179197
  var setDreamStateStatements = new WeakMap;
@@ -179236,21 +179385,21 @@ function clearStaleEntries(db, maxAgeMs, projectIdentity) {
179236
179385
  return result.changes;
179237
179386
  }
179238
179387
  // src/features/magic-context/dreamer/runner.ts
179388
+ import { existsSync as existsSync10 } from "node:fs";
179389
+ import { join as join12 } from "node:path";
179239
179390
  init_shared();
179240
179391
  init_assistant_message_extractor();
179241
179392
  init_data_path();
179242
179393
  init_logger();
179243
179394
  await init_sqlite();
179244
- import { existsSync as existsSync10 } from "node:fs";
179245
- import { join as join12 } from "node:path";
179246
179395
 
179247
179396
  // src/features/magic-context/key-files/identify-key-files.ts
179397
+ import { readFileSync as readFileSync8 } from "node:fs";
179398
+ import { isAbsolute as isAbsolute3, join as join11, relative as relative2 } from "node:path";
179248
179399
  init_read_session_formatting();
179249
179400
  init_shared();
179250
179401
  init_assistant_message_extractor();
179251
179402
  init_logger();
179252
- import { readFileSync as readFileSync8 } from "node:fs";
179253
- import { isAbsolute as isAbsolute3, join as join11, relative as relative2 } from "node:path";
179254
179403
  init_subagent_token_capture();
179255
179404
  init_aft_availability();
179256
179405
  init_project_key_files();
@@ -181119,7 +181268,6 @@ init_sweep_coordinator();
181119
181268
  // src/plugin/dream-timer.ts
181120
181269
  init_embedding();
181121
181270
  init_logger();
181122
- init_resolve_fallbacks();
181123
181271
  await init_storage();
181124
181272
  var DREAM_TIMER_INTERVAL_MS = 15 * 60 * 1000;
181125
181273
  var activeTimer = null;
@@ -181222,7 +181370,7 @@ async function sweepProject(reg, origin, db, gitCommitEnabled = getProjectEmbedd
181222
181370
  experimentalPinKeyFiles: reg.experimentalPinKeyFiles,
181223
181371
  projectIdentity: reg.projectIdentity,
181224
181372
  sessionDirectoryOverride: reg.directory,
181225
- fallbackModels: resolveFallbackChain(DREAMER_AGENT, reg.dreamerConfig.fallback_models)
181373
+ fallbackModels: resolveFallbackChain(reg.dreamerConfig.fallback_models)
181226
181374
  });
181227
181375
  } catch (error51) {
181228
181376
  log(`[dreamer] timer-triggered queue processing failed for ${reg.projectIdentity}:`, error51);
@@ -181671,10 +181819,9 @@ function makeToolCompositeKey(ownerMsgId, callId) {
181671
181819
  }
181672
181820
  var GET_COUNTER_SQL = `SELECT counter FROM session_meta WHERE session_id = ?`;
181673
181821
  var GET_ASSIGNMENTS_SQL = "SELECT message_id, tag_number, type, tool_owner_message_id FROM tags WHERE session_id = ? ORDER BY tag_number ASC";
181822
+ var GET_ASSIGNMENTS_SCOPED_SQL = "SELECT message_id, tag_number, type, tool_owner_message_id FROM tags WHERE session_id = ? AND tag_number >= ? ORDER BY tag_number ASC";
181674
181823
  var PROBE_DATA_VERSION_SQL = "PRAGMA main.data_version";
181675
- var PROBE_TOTAL_CHANGES_SQL = "SELECT total_changes() AS tc";
181676
181824
  var probeDataVersionStatements = new WeakMap;
181677
- var probeTotalChangesStatements = new WeakMap;
181678
181825
  function getProbeDataVersionStatement(db) {
181679
181826
  let stmt = probeDataVersionStatements.get(db);
181680
181827
  if (!stmt) {
@@ -181683,14 +181830,6 @@ function getProbeDataVersionStatement(db) {
181683
181830
  }
181684
181831
  return stmt;
181685
181832
  }
181686
- function getProbeTotalChangesStatement(db) {
181687
- let stmt = probeTotalChangesStatements.get(db);
181688
- if (!stmt) {
181689
- stmt = db.prepare(PROBE_TOTAL_CHANGES_SQL);
181690
- probeTotalChangesStatements.set(db, stmt);
181691
- }
181692
- return stmt;
181693
- }
181694
181833
  function isAssignmentRow(row) {
181695
181834
  if (row === null || typeof row !== "object") {
181696
181835
  return false;
@@ -181883,20 +182022,18 @@ function createTagger() {
181883
182022
  }
181884
182023
  function probeSignature(db) {
181885
182024
  const dvRow = getProbeDataVersionStatement(db).get();
181886
- const tcRow = getProbeTotalChangesStatement(db).get();
181887
182025
  return {
181888
- dataVersion: dvRow?.data_version ?? 0,
181889
- totalChanges: tcRow?.tc ?? 0
182026
+ dataVersion: dvRow?.data_version ?? 0
181890
182027
  };
181891
182028
  }
181892
- function initFromDb(sessionId, db) {
182029
+ function initFromDb(sessionId, db, floor = 0) {
181893
182030
  const probe = probeSignature(db);
181894
182031
  const cached2 = loadSignatures.get(sessionId);
181895
- if (cached2 !== undefined && cached2.db === db && cached2.dataVersion === probe.dataVersion && cached2.totalChanges === probe.totalChanges) {
182032
+ if (cached2 !== undefined && cached2.db === db && cached2.dataVersion === probe.dataVersion && cached2.floor === floor) {
181896
182033
  return;
181897
182034
  }
181898
182035
  const row = db.prepare(GET_COUNTER_SQL).get(sessionId);
181899
- const assignmentRows = db.prepare(GET_ASSIGNMENTS_SQL).all(sessionId).filter(isAssignmentRow);
182036
+ const assignmentRows = (floor > 0 ? db.prepare(GET_ASSIGNMENTS_SCOPED_SQL).all(sessionId, floor) : db.prepare(GET_ASSIGNMENTS_SQL).all(sessionId)).filter(isAssignmentRow);
181900
182037
  const sessionAssignments = getSessionAssignments(sessionId);
181901
182038
  sessionAssignments.clear();
181902
182039
  let maxTagNumber = 0;
@@ -181917,7 +182054,7 @@ function createTagger() {
181917
182054
  loadSignatures.set(sessionId, {
181918
182055
  db,
181919
182056
  dataVersion: probe.dataVersion,
181920
- totalChanges: probe.totalChanges
182057
+ floor
181921
182058
  });
181922
182059
  }
181923
182060
  function cleanup(sessionId) {
@@ -181940,13 +182077,13 @@ function createTagger() {
181940
182077
  cleanup
181941
182078
  };
181942
182079
  }
182080
+
181943
182081
  // src/hooks/magic-context/hook.ts
181944
182082
  init_magic_context();
181945
182083
  init_project_identity();
181946
182084
  init_project_embedding_registry();
181947
182085
  await init_storage();
181948
182086
  init_logger();
181949
- init_resolve_fallbacks();
181950
182087
  init_rpc_notifications();
181951
182088
 
181952
182089
  // src/hooks/magic-context/command-handler.ts
@@ -181997,6 +182134,7 @@ await __promiseAll([
181997
182134
  // src/hooks/magic-context/compartment-trigger.ts
181998
182135
  init_compartment_storage();
181999
182136
  init_logger();
182137
+ init_read_session_true_raw_tokens();
182000
182138
  await __promiseAll([
182001
182139
  init_storage(),
182002
182140
  init_protected_tail_boundary(),
@@ -182011,6 +182149,38 @@ var TAIL_SIZE_TRIGGER_MULTIPLIER = 3;
182011
182149
  var FORCE_COMPARTMENT_PERCENTAGE = 80;
182012
182150
  var BLOCK_UNTIL_DONE_PERCENTAGE = 95;
182013
182151
  var FORCE_MATERIALIZE_PERCENTAGE = 85;
182152
+ var CONTENT_TAG_OWNER_SUFFIX = /:(?:p|file)\d+$/;
182153
+ function tagOwnerMessageId(row) {
182154
+ if (row.type === "tool")
182155
+ return row.tool_owner_message_id ?? row.message_id;
182156
+ return row.message_id.replace(CONTENT_TAG_OWNER_SUFFIX, "");
182157
+ }
182158
+ function getActiveOrDroppedTagOwnerMessageIds(db, sessionId, floor = 0) {
182159
+ const rows = floor > 0 ? db.prepare(`SELECT type, message_id, tool_owner_message_id
182160
+ FROM tags
182161
+ WHERE session_id = ? AND status IN ('active', 'dropped') AND tag_number >= ?`).all(sessionId, floor) : db.prepare(`SELECT type, message_id, tool_owner_message_id
182162
+ FROM tags
182163
+ WHERE session_id = ? AND status IN ('active', 'dropped')`).all(sessionId);
182164
+ const owners = new Set;
182165
+ for (const row of rows)
182166
+ owners.add(tagOwnerMessageId(row));
182167
+ return owners;
182168
+ }
182169
+ function estimateUntaggedInMemoryTailUpperBound(db, sessionId, inMemoryTail, taggerFloor = 0) {
182170
+ const lastCompartmentEnd = getLastCompartmentEndMessage(db, sessionId);
182171
+ const coveredOwnerMessageIds = getActiveOrDroppedTagOwnerMessageIds(db, sessionId, taggerFloor);
182172
+ let total = 0;
182173
+ for (const message of inMemoryTail.messages) {
182174
+ if (message.ordinal <= lastCompartmentEnd)
182175
+ continue;
182176
+ if (coveredOwnerMessageIds.has(message.id))
182177
+ continue;
182178
+ total += estimateTrueRawMessageTokens(message, {
182179
+ providerShapeVersion: "opencode-v1"
182180
+ }).total;
182181
+ }
182182
+ return total;
182183
+ }
182014
182184
  function buildTriggerInMemoryTail(db, sessionId, messages) {
182015
182185
  if (messages.length === 0)
182016
182186
  return;
@@ -182082,7 +182252,7 @@ function resolveBoundaryContextLimit(usage, fallbackContextLimit) {
182082
182252
  }
182083
182253
  return 128000;
182084
182254
  }
182085
- function getUnsummarizedTailInfo(db, sessionId, triggerBudget, usage, executeThresholdPercentage, contextLimit, inMemoryTail) {
182255
+ function getUnsummarizedTailInfo(db, sessionId, triggerBudget, usage, executeThresholdPercentage, contextLimit, inMemoryTail, taggerFloor = 0) {
182086
182256
  return withRawSessionMessageCache(() => {
182087
182257
  try {
182088
182258
  const memoryPrimed = inMemoryTail ? primeInMemoryTailRawMessageCache({
@@ -182111,7 +182281,8 @@ function getUnsummarizedTailInfo(db, sessionId, triggerBudget, usage, executeThr
182111
182281
  contextLimit: resolveBoundaryContextLimit(usage, contextLimit),
182112
182282
  executeThresholdPercentage,
182113
182283
  usage,
182114
- usageSource: "live"
182284
+ usageSource: "live",
182285
+ taggerFloor
182115
182286
  });
182116
182287
  const hasProtectedEligibleHead = boundary.offset < boundary.protectedTailStart;
182117
182288
  if (!hasProtectedEligibleHead) {
@@ -182142,7 +182313,7 @@ function getUnsummarizedTailInfo(db, sessionId, triggerBudget, usage, executeThr
182142
182313
  }
182143
182314
  });
182144
182315
  }
182145
- function checkCompartmentTrigger(db, sessionId, sessionMeta, usage, _previousPercentage, executeThresholdPercentage, triggerBudget, clearReasoningAge, commitClusterTrigger, preloadedActiveTags, contextLimit, inMemoryTail) {
182316
+ function checkCompartmentTrigger(db, sessionId, sessionMeta, usage, _previousPercentage, executeThresholdPercentage, triggerBudget, clearReasoningAge, commitClusterTrigger, preloadedActiveTags, contextLimit, inMemoryTail, taggerFloorOverride) {
182146
182317
  if (sessionMeta.compartmentInProgress) {
182147
182318
  sessionLog(sessionId, `compartment trigger: skipped — historian already in progress (usage=${usage.percentage.toFixed(1)}%)`);
182148
182319
  return { shouldFire: false };
@@ -182156,14 +182327,17 @@ function checkCompartmentTrigger(db, sessionId, sessionMeta, usage, _previousPer
182156
182327
  inMemoryTail = undefined;
182157
182328
  }
182158
182329
  }
182330
+ const taggerFloor = taggerFloorOverride !== undefined && taggerFloorOverride > 0 ? taggerFloorOverride : inMemoryTail ? deriveTagLoadFloor(db, sessionId, inMemoryTail.messages.map((m) => m.id)) : 0;
182159
182331
  const proactiveFloorForGate = getProactiveCompartmentTriggerPercentage(executeThresholdPercentage);
182160
- if (!inMemoryTail && usage.percentage < proactiveFloorForGate) {
182332
+ if (usage.percentage < proactiveFloorForGate) {
182161
182333
  try {
182162
- const { bound, nullCount } = getTriggerTagTokenUpperBound(db, sessionId);
182334
+ const { bound: persistedBound, nullCount } = getTriggerTagTokenUpperBound(db, sessionId, taggerFloor);
182163
182335
  if (nullCount === 0) {
182164
- const eligibleUpperBound = bound;
182336
+ const untaggedUpperBound = inMemoryTail ? estimateUntaggedInMemoryTailUpperBound(db, sessionId, inMemoryTail, taggerFloor) : 0;
182337
+ const eligibleUpperBound = persistedBound + untaggedUpperBound;
182165
182338
  if (eligibleUpperBound < triggerBudget) {
182166
- sessionLog(sessionId, `compartment trigger: cheap-skip at ${usage.percentage.toFixed(1)}% (below proactive floor ${proactiveFloorForGate}%) — live-tail upper bound ${eligibleUpperBound} < triggerBudget ${triggerBudget}; no size trigger possible, skipped full raw read`);
182339
+ const memorySuffix = inMemoryTail ? ` (persisted=${persistedBound}, untagged-memory≤${untaggedUpperBound})` : "";
182340
+ sessionLog(sessionId, `compartment trigger: cheap-skip at ${usage.percentage.toFixed(1)}% (below proactive floor ${proactiveFloorForGate}%) — live-tail upper bound ${eligibleUpperBound}${memorySuffix} < triggerBudget ${triggerBudget}; no size trigger possible, skipped full raw read`);
182167
182341
  return { shouldFire: false };
182168
182342
  }
182169
182343
  }
@@ -182171,7 +182345,7 @@ function checkCompartmentTrigger(db, sessionId, sessionMeta, usage, _previousPer
182171
182345
  sessionLog(sessionId, `compartment trigger: cheap-gate skipped (falling through to full read): ${error51 instanceof Error ? error51.message : String(error51)}`);
182172
182346
  }
182173
182347
  }
182174
- const tailInfo = getUnsummarizedTailInfo(db, sessionId, triggerBudget, usage, executeThresholdPercentage, contextLimit, inMemoryTail);
182348
+ const tailInfo = getUnsummarizedTailInfo(db, sessionId, triggerBudget, usage, executeThresholdPercentage, contextLimit, inMemoryTail, taggerFloor);
182175
182349
  if (!tailInfo.hasNewRawHistory) {
182176
182350
  try {
182177
182351
  const lastCompartmentEnd = getLastCompartmentEndMessage(db, sessionId);
@@ -182906,9 +183080,142 @@ function clearSessionTracking(sessionId) {
182906
183080
  // src/hooks/magic-context/event-handler.ts
182907
183081
  init_overflow_detection();
182908
183082
  init_storage_meta_persisted();
183083
+ await init_storage();
183084
+
183085
+ // src/features/magic-context/transform-decision-log.ts
183086
+ await __promiseAll([
183087
+ init_sqlite(),
183088
+ init_storage_db()
183089
+ ]);
183090
+ var canonicalReasons = new Set([
183091
+ "system_hash",
183092
+ "model_change",
183093
+ "project_memory_epoch",
183094
+ "ttl_idle",
183095
+ "explicit_flush",
183096
+ "max_mutation_id",
183097
+ "first_render",
183098
+ "pressure_refold",
183099
+ "upgrade_state",
183100
+ "cached_m1_missing"
183101
+ ]);
183102
+ var piReasonAliases = {
183103
+ project_memory_change: "project_memory_epoch",
183104
+ pending_mutations: "max_mutation_id",
183105
+ renderer_upgrade: "upgrade_state",
183106
+ cache_invalid: "cached_m1_missing",
183107
+ drift: "pressure_refold"
183108
+ };
183109
+ var sharedReasonAliases = {
183110
+ model_key: "model_change",
183111
+ pressure: "pressure_refold"
183112
+ };
183113
+ var pendingDecisionBySession = new Map;
183114
+ var pendingPiDecisionBySession = new Map;
183115
+ var lastBoundMessageIdBySession = new Map;
183116
+ var scheduledWriteTokensBySession = new Map;
183117
+ var writerOverrideForTests = null;
183118
+ function normalizeMaterializeReason(harness, reason, rematerialized) {
183119
+ const raw = typeof reason === "string" ? reason.trim() : "";
183120
+ if (raw.length > 0) {
183121
+ const alias = sharedReasonAliases[raw] ?? (harness === "pi" ? piReasonAliases[raw] : undefined) ?? undefined;
183122
+ if (alias)
183123
+ return alias;
183124
+ if (canonicalReasons.has(raw))
183125
+ return raw;
183126
+ return null;
183127
+ }
183128
+ return rematerialized ? "pressure_refold" : null;
183129
+ }
183130
+ function clearOpenCodePendingTransformDecision(sessionId) {
183131
+ pendingDecisionBySession.delete(sessionId);
183132
+ }
183133
+ function clearTransformDecisionSession(sessionId) {
183134
+ pendingDecisionBySession.delete(sessionId);
183135
+ pendingPiDecisionBySession.delete(sessionId);
183136
+ lastBoundMessageIdBySession.delete(sessionId);
183137
+ scheduledWriteTokensBySession.delete(sessionId);
183138
+ }
183139
+ function recordPendingTransformDecision(sessionId, decision) {
183140
+ if (!decision.bustedThisPass) {
183141
+ pendingDecisionBySession.delete(sessionId);
183142
+ return;
183143
+ }
183144
+ pendingDecisionBySession.set(sessionId, decision);
183145
+ }
183146
+ function scheduleOpenCodeTransformDecisionWrite(args) {
183147
+ const pending = pendingDecisionBySession.get(args.sessionId);
183148
+ if (!pending)
183149
+ return false;
183150
+ if (lastBoundMessageIdBySession.get(args.sessionId) === args.messageId) {
183151
+ return false;
183152
+ }
183153
+ const dbPath = getDatabasePath(args.db);
183154
+ if (!dbPath)
183155
+ return false;
183156
+ lastBoundMessageIdBySession.set(args.sessionId, args.messageId);
183157
+ pendingDecisionBySession.delete(args.sessionId);
183158
+ const token = addScheduledWriteToken(args.sessionId);
183159
+ setTimeout(() => {
183160
+ try {
183161
+ if (!hasScheduledWriteToken(args.sessionId, token))
183162
+ return;
183163
+ writeTransformDecisionBestEffort(dbPath, {
183164
+ ...pending,
183165
+ sessionId: args.sessionId,
183166
+ harness: "opencode",
183167
+ messageId: args.messageId,
183168
+ inputTokens: args.inputTokens
183169
+ });
183170
+ } finally {
183171
+ deleteScheduledWriteToken(args.sessionId, token);
183172
+ }
183173
+ }, 0);
183174
+ return true;
183175
+ }
183176
+ function addScheduledWriteToken(sessionId) {
183177
+ const token = Symbol(sessionId);
183178
+ let tokens = scheduledWriteTokensBySession.get(sessionId);
183179
+ if (!tokens) {
183180
+ tokens = new Set;
183181
+ scheduledWriteTokensBySession.set(sessionId, tokens);
183182
+ }
183183
+ tokens.add(token);
183184
+ return token;
183185
+ }
183186
+ function hasScheduledWriteToken(sessionId, token) {
183187
+ return scheduledWriteTokensBySession.get(sessionId)?.has(token) === true;
183188
+ }
183189
+ function deleteScheduledWriteToken(sessionId, token) {
183190
+ const tokens = scheduledWriteTokensBySession.get(sessionId);
183191
+ if (!tokens)
183192
+ return;
183193
+ tokens.delete(token);
183194
+ if (tokens.size === 0)
183195
+ scheduledWriteTokensBySession.delete(sessionId);
183196
+ }
183197
+ function writeTransformDecisionBestEffort(dbPath, row) {
183198
+ try {
183199
+ const writer = writerOverrideForTests ?? writeTransformDecisionRow;
183200
+ writer(dbPath, row);
183201
+ } catch {}
183202
+ }
183203
+ function writeTransformDecisionRow(dbPath, row) {
183204
+ const db = new Database(dbPath);
183205
+ try {
183206
+ db.exec("PRAGMA busy_timeout=0");
183207
+ db.prepare(`INSERT OR REPLACE INTO transform_decisions (
183208
+ session_id, harness, message_id, ts_ms, decision, materialized,
183209
+ materialize_reason, emergency, dropped_tokens, dropped_count, input_tokens
183210
+ ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`).run(row.sessionId, row.harness, row.messageId, row.tsMs, row.decision, row.materialized ? 1 : 0, row.materializeReason, row.emergency ? 1 : 0, Math.max(0, Math.floor(row.droppedTokens)), Math.max(0, Math.floor(row.droppedCount)), Math.max(0, Math.floor(row.inputTokens)));
183211
+ } finally {
183212
+ closeQuietly(db);
183213
+ }
183214
+ }
183215
+
183216
+ // src/hooks/magic-context/event-handler.ts
182909
183217
  init_logger();
182910
183218
  init_models_dev_cache();
182911
- await init_storage();
182912
183219
 
182913
183220
  // src/hooks/magic-context/channel2-delivery.ts
182914
183221
  init_storage_meta_persisted();
@@ -183312,11 +183619,13 @@ function getMessageUpdatedAssistantInfo(properties) {
183312
183619
  }
183313
183620
  const tokens = isRecord(info.tokens) ? info.tokens : undefined;
183314
183621
  const cache = tokens && isRecord(tokens.cache) ? tokens.cache : undefined;
183622
+ const time3 = isRecord(info.time) ? info.time : undefined;
183315
183623
  return {
183316
183624
  role: "assistant",
183317
183625
  finish: typeof info.finish === "string" ? info.finish : undefined,
183318
183626
  sessionID: info.sessionID,
183319
183627
  messageID: typeof info.id === "string" ? info.id : undefined,
183628
+ completedAt: typeof time3?.completed === "number" ? time3.completed : undefined,
183320
183629
  providerID: typeof info.providerID === "string" ? info.providerID : undefined,
183321
183630
  modelID: typeof info.modelID === "string" ? info.modelID : undefined,
183322
183631
  tokens: {
@@ -183379,8 +183688,8 @@ init_project_identity();
183379
183688
  import * as crypto2 from "node:crypto";
183380
183689
  init_session_project_storage();
183381
183690
  init_storage_meta_persisted();
183382
- init_logger();
183383
183691
  await init_storage();
183692
+ init_logger();
183384
183693
 
183385
183694
  // src/hooks/magic-context/boundary-execution.ts
183386
183695
  var FORCE_MATERIALIZE_PERCENTAGE2 = 85;
@@ -184416,6 +184725,7 @@ function stripProcessedImages(messages, frozenIds, options) {
184416
184725
  init_temporal_awareness();
184417
184726
 
184418
184727
  // src/hooks/magic-context/transform-compartment-phase.ts
184728
+ init_compartment_storage();
184419
184729
  init_logger();
184420
184730
  await __promiseAll([
184421
184731
  init_storage(),
@@ -184424,9 +184734,29 @@ await __promiseAll([
184424
184734
  init_send_session_notification();
184425
184735
  await __promiseAll([
184426
184736
  init_inject_compartments(),
184427
- init_protected_tail_boundary()
184737
+ init_protected_tail_boundary(),
184738
+ init_read_session_chunk()
184428
184739
  ]);
184429
- async function runCompartmentPhase(args) {
184740
+ function runCompartmentPhase(args) {
184741
+ const historianRunnable = args.historianRunnable !== false;
184742
+ const willReadRawHistory = historianRunnable && args.canRunCompartments && getActiveCompartmentRun(args.sessionId) === undefined && (args.sessionMeta.compartmentInProgress || !args.skipAwaitForThisPass && args.contextUsage.percentage >= BLOCK_UNTIL_DONE_PERCENTAGE);
184743
+ if (!willReadRawHistory) {
184744
+ return runCompartmentPhaseImpl(args);
184745
+ }
184746
+ return withRawSessionMessageCache(() => {
184747
+ try {
184748
+ primeTailRawMessageCache({
184749
+ sessionId: args.resolvedSessionId,
184750
+ lastCompartmentEnd: getLastCompartmentEndMessage(args.db, args.resolvedSessionId),
184751
+ anchorMessageId: getLastCompartmentEndMessageId(args.db, args.resolvedSessionId)
184752
+ });
184753
+ } catch (error51) {
184754
+ sessionLog(args.sessionId, "compartment phase: tail prime failed (non-fatal):", error51);
184755
+ }
184756
+ return runCompartmentPhaseImpl(args);
184757
+ });
184758
+ }
184759
+ async function runCompartmentPhaseImpl(args) {
184430
184760
  let pendingCompartmentInjection = args.pendingCompartmentInjection;
184431
184761
  let compartmentInProgress = args.sessionMeta.compartmentInProgress;
184432
184762
  let published = false;
@@ -184992,6 +185322,7 @@ function createExistingTagResolver(sessionId, tagger, db) {
184992
185322
  return;
184993
185323
  }
184994
185324
  updateTagMessageId(db, sessionId, fallback.tagNumber, currentContentId);
185325
+ tagger.unbindTag(sessionId, fallback.contentId);
184995
185326
  tagger.bindTag(sessionId, currentContentId, fallback.tagNumber);
184996
185327
  usedTagNumbers.add(fallback.tagNumber);
184997
185328
  return fallback.tagNumber;
@@ -185012,7 +185343,45 @@ function logTransformTiming(sessionId, stage, startMs, extra) {
185012
185343
  }
185013
185344
 
185014
185345
  // src/hooks/magic-context/tag-messages.ts
185015
- function deriveToolOwnerMessageId(sessionId, db, message, obs, unpaired) {
185346
+ var TOOL_OWNER_CACHE_KEY_SEP = "\x00";
185347
+ function makeToolOwnerCacheKey(sessionId, callId) {
185348
+ return `${sessionId}${TOOL_OWNER_CACHE_KEY_SEP}${callId}`;
185349
+ }
185350
+ function getCachedCandidateToolOwners(db, sessionId, callId, cache, onLookup) {
185351
+ const key = makeToolOwnerCacheKey(sessionId, callId);
185352
+ const cached2 = cache.candidateOwnersByCallId.get(key);
185353
+ if (cached2 !== undefined)
185354
+ return cached2;
185355
+ onLookup?.({ kind: "candidates", callId });
185356
+ const candidates = getCandidateToolOwners(db, sessionId, callId);
185357
+ cache.candidateOwnersByCallId.set(key, candidates);
185358
+ return candidates;
185359
+ }
185360
+ function getCachedMessageTimesFromOpenCodeDb(sessionId, messageIds, cache, onLookup) {
185361
+ const uncached = [...new Set(messageIds)].filter((id) => !cache.messageTimesById.has(id));
185362
+ if (uncached.length > 0) {
185363
+ onLookup?.({ kind: "messageTimes", messageIds: uncached });
185364
+ const resolved = getMessageTimesFromOpenCodeDb(sessionId, uncached);
185365
+ for (const id of uncached) {
185366
+ cache.messageTimesById.set(id, resolved.get(id) ?? null);
185367
+ }
185368
+ }
185369
+ const times = new Map;
185370
+ for (const id of messageIds) {
185371
+ const time3 = cache.messageTimesById.get(id);
185372
+ if (typeof time3 === "number")
185373
+ times.set(id, time3);
185374
+ }
185375
+ return times;
185376
+ }
185377
+ function invalidateCachedCandidateToolOwnersIfNewOwner(cache, sessionId, callId, ownerMsgId) {
185378
+ const key = makeToolOwnerCacheKey(sessionId, callId);
185379
+ const cached2 = cache.candidateOwnersByCallId.get(key);
185380
+ if (cached2 !== undefined && !cached2.includes(ownerMsgId)) {
185381
+ cache.candidateOwnersByCallId.delete(key);
185382
+ }
185383
+ }
185384
+ function deriveToolOwnerMessageId(sessionId, db, message, obs, unpaired, cache, onFallbackLookup) {
185016
185385
  const messageId = typeof message.info.id === "string" ? message.info.id : "";
185017
185386
  if (obs.kind === "invocation") {
185018
185387
  if (messageId) {
@@ -185032,10 +185401,10 @@ function deriveToolOwnerMessageId(sessionId, db, message, obs, unpaired) {
185032
185401
  return popped;
185033
185402
  }
185034
185403
  if (messageId) {
185035
- const candidates = getCandidateToolOwners(db, sessionId, obs.callId);
185404
+ const candidates = getCachedCandidateToolOwners(db, sessionId, obs.callId, cache, onFallbackLookup);
185036
185405
  if (candidates.length > 0) {
185037
185406
  const ids = [...candidates, messageId];
185038
- const times = getMessageTimesFromOpenCodeDb(sessionId, ids);
185407
+ const times = getCachedMessageTimesFromOpenCodeDb(sessionId, ids, cache, onFallbackLookup);
185039
185408
  const persisted = pickNearestPriorOwner(candidates, messageId, times);
185040
185409
  if (persisted !== null)
185041
185410
  return persisted;
@@ -185116,6 +185485,7 @@ function extractToolTagMetadata(part) {
185116
185485
  }
185117
185486
  function tagMessages(sessionId, messages, tagger, db, options = {}) {
185118
185487
  const skipPrefixInjection = options.skipPrefixInjection === true;
185488
+ const onToolOwnerFallbackLookup = options.onToolOwnerFallbackLookup;
185119
185489
  const targets = new Map;
185120
185490
  const reasoningByMessage = new Map;
185121
185491
  const messageTagNumbers = new Map;
@@ -185123,6 +185493,10 @@ function tagMessages(sessionId, messages, tagger, db, options = {}) {
185123
185493
  const toolThinkingByCallId = new Map;
185124
185494
  const toolCallIndex = new Map;
185125
185495
  const unpairedInvocations = new Map;
185496
+ const ownerDerivationCache = {
185497
+ candidateOwnersByCallId: new Map,
185498
+ messageTimesById: new Map
185499
+ };
185126
185500
  const ownerByPartKey = new Map;
185127
185501
  const batch = new ToolMutationBatch(messages);
185128
185502
  const assignments = tagger.getAssignments(sessionId);
@@ -185163,7 +185537,7 @@ function tagMessages(sessionId, messages, tagger, db, options = {}) {
185163
185537
  const toolObservation = extractToolCallObservation(part);
185164
185538
  if (toolObservation) {
185165
185539
  const _tDerive = performance.now();
185166
- const ownerMsgId = deriveToolOwnerMessageId(sessionId, db, message, toolObservation, unpairedInvocations);
185540
+ const ownerMsgId = deriveToolOwnerMessageId(sessionId, db, message, toolObservation, unpairedInvocations, ownerDerivationCache, onToolOwnerFallbackLookup);
185167
185541
  accDerive += performance.now() - _tDerive;
185168
185542
  const compositeKey = makeToolCompositeKey(ownerMsgId, toolObservation.callId);
185169
185543
  const entry = toolCallIndex.get(compositeKey) ?? {
@@ -185182,6 +185556,7 @@ function tagMessages(sessionId, messages, tagger, db, options = {}) {
185182
185556
  if (orphan !== null) {
185183
185557
  const claimed = adoptNullOwnerToolTag(db, orphan.id, ownerMsgId);
185184
185558
  if (claimed) {
185559
+ invalidateCachedCandidateToolOwnersIfNewOwner(ownerDerivationCache, sessionId, toolObservation.callId, ownerMsgId);
185185
185560
  tagger.bindToolTag(sessionId, toolObservation.callId, ownerMsgId, orphan.tagNumber);
185186
185561
  existingTagId = orphan.tagNumber;
185187
185562
  } else {
@@ -185189,6 +185564,13 @@ function tagMessages(sessionId, messages, tagger, db, options = {}) {
185189
185564
  }
185190
185565
  }
185191
185566
  }
185567
+ if (existingTagId === undefined) {
185568
+ const persisted = getToolTagNumberByOwner(db, sessionId, toolObservation.callId, ownerMsgId);
185569
+ if (persisted !== null) {
185570
+ tagger.bindToolTag(sessionId, toolObservation.callId, ownerMsgId, persisted);
185571
+ existingTagId = persisted;
185572
+ }
185573
+ }
185192
185574
  if (existingTagId !== undefined) {
185193
185575
  toolTagByCallId.set(compositeKey, existingTagId);
185194
185576
  messageTagNumbers.set(message, Math.max(messageTagNumbers.get(message) ?? 0, existingTagId));
@@ -185261,6 +185643,7 @@ function tagMessages(sessionId, messages, tagger, db, options = {}) {
185261
185643
  inputTokenCount,
185262
185644
  reasoningTokenCount: reasoningTokens
185263
185645
  }));
185646
+ invalidateCachedCandidateToolOwnersIfNewOwner(ownerDerivationCache, sessionId, toolPart.callID, ownerMsgId);
185264
185647
  accAssignToolTag += performance.now() - _tAssignTool;
185265
185648
  messageTagNumbers.set(message, Math.max(messageTagNumbers.get(message) ?? 0, tagId));
185266
185649
  if (!skipPrefixInjection) {
@@ -186259,7 +186642,7 @@ async function runAutoSearchHint(args) {
186259
186642
  embeddingEnabled,
186260
186643
  gitCommitsEnabled,
186261
186644
  embedQuery: async (text, signal) => {
186262
- const result = await embedTextForProject(options.projectPath, text, signal);
186645
+ const result = await embedTextForProject(options.projectPath, text, signal, "query");
186263
186646
  return result?.vector ?? null;
186264
186647
  },
186265
186648
  isEmbeddingRuntimeEnabled: () => embeddingEnabled === true,
@@ -186503,6 +186886,7 @@ function applyHeuristicCleanup(sessionId, db, targets, messageTagNumbers, config
186503
186886
  const maxTag = getMaxTagNumberBySession(db, sessionId);
186504
186887
  const protectedCutoff = maxTag - config2.protectedTags;
186505
186888
  let droppedTools = 0;
186889
+ let emergencyDroppedTools = 0;
186506
186890
  let deduplicatedTools = 0;
186507
186891
  let droppedInjections = 0;
186508
186892
  if (config2.emergency) {
@@ -186534,6 +186918,7 @@ function applyHeuristicCleanup(sessionId, db, targets, messageTagNumbers, config
186534
186918
  updateTagStatus(db, sessionId, tag.tagNumber, "dropped");
186535
186919
  updateTagDropMode(db, sessionId, tag.tagNumber, "full");
186536
186920
  droppedTools++;
186921
+ emergencyDroppedTools++;
186537
186922
  }
186538
186923
  }
186539
186924
  setEmergencyDropSample(db, sessionId, emergency.currentTotalInputTokens);
@@ -186637,6 +187022,7 @@ function applyHeuristicCleanup(sessionId, db, targets, messageTagNumbers, config
186637
187022
  droppedTools,
186638
187023
  deduplicatedTools,
186639
187024
  droppedInjections,
187025
+ emergencyDroppedTools,
186640
187026
  compressedTextTags,
186641
187027
  mutatedTextTags
186642
187028
  };
@@ -186865,7 +187251,6 @@ async function runPostTransformPhase(args) {
186865
187251
  const emergencyDropEligible = args.contextUsage.percentage >= args.forceMaterializationPercentage;
186866
187252
  const activeCompartmentRun = args.canRunCompartments ? getActiveCompartmentRun(args.sessionId) : undefined;
186867
187253
  const compartmentRunning = args.canRunCompartments && !args.awaitedCompartmentRun && activeCompartmentRun !== undefined;
186868
- const emergencyBypassCompartmentGate = forceMaterialization;
186869
187254
  const deferredMaterialize = args.canConsumeDeferredLate && deferredMaterializationWasPending;
186870
187255
  const materializationRequested = isExplicitFlush || deferredMaterialize;
186871
187256
  const m0M1EnabledForFold = args.fullFeatureMode && args.m0M1 !== undefined && (!!args.m0M1.projectPath || !!args.m0M1.projectDirectory);
@@ -186877,11 +187262,12 @@ async function runPostTransformPhase(args) {
186877
187262
  projectDirectory: args.m0M1.projectDirectory,
186878
187263
  hardSignals: args.m0M1.hardSignals
186879
187264
  }).value : false;
187265
+ const bypassCompartmentGate = forceMaterialization || m0HardFoldThisPass;
186880
187266
  const shouldReadPendingOps = materializationRequested || args.schedulerDecision === "execute" || forceMaterialization || m0HardFoldThisPass || compartmentRunning;
186881
187267
  const pendingOps = shouldReadPendingOps ? getPendingOps(args.db, args.sessionId) : [];
186882
187268
  const hasPendingUserOps = pendingOps.length > 0;
186883
- const shouldApplyPendingOps = (args.schedulerDecision === "execute" || materializationRequested || forceMaterialization || m0HardFoldThisPass) && (!compartmentRunning || emergencyBypassCompartmentGate);
186884
- const shouldRunHeuristics = (!compartmentRunning || emergencyBypassCompartmentGate) && (materializationRequested || forceMaterialization || m0HardFoldThisPass || emergencyDropEligible || args.schedulerDecision === "execute" && (!alreadyRanThisTurn || !args.fullFeatureMode));
187269
+ const shouldApplyPendingOps = (args.schedulerDecision === "execute" || materializationRequested || forceMaterialization || m0HardFoldThisPass) && (!compartmentRunning || bypassCompartmentGate);
187270
+ const shouldRunHeuristics = (!compartmentRunning || bypassCompartmentGate) && (materializationRequested || forceMaterialization || m0HardFoldThisPass || emergencyDropEligible || args.schedulerDecision === "execute" && (!alreadyRanThisTurn || !args.fullFeatureMode));
186885
187271
  const isCacheBustingPass = shouldApplyPendingOps || shouldRunHeuristics;
186886
187272
  const canUseEmptySentinels = modelAcceptsEmptyContent(args.resolvedProviderID);
186887
187273
  if (shouldRunHeuristics) {
@@ -186893,8 +187279,9 @@ async function runPostTransformPhase(args) {
186893
187279
  sessionLog(args.sessionId, `transform: skipping heuristics (already ran for turn ${args.currentTurnId})`);
186894
187280
  }
186895
187281
  if (compartmentRunning && hasPendingUserOps) {
186896
- if (emergencyBypassCompartmentGate) {
186897
- sessionLog(args.sessionId, `transform: emergency bypass applying ${pendingOps.length} pending ops while compartment agent runs (${args.contextUsage.percentage.toFixed(1)}%)`);
187282
+ if (bypassCompartmentGate) {
187283
+ const bypassReason = forceMaterialization ? "emergency >=85%" : "m0 hard fold";
187284
+ sessionLog(args.sessionId, `transform: compartment-gate bypass (${bypassReason}) — applying ${pendingOps.length} pending ops while compartment agent runs (${args.contextUsage.percentage.toFixed(1)}%)`);
186898
187285
  } else {
186899
187286
  sessionLog(args.sessionId, "transform: deferring pending ops — compartment agent in progress");
186900
187287
  }
@@ -186905,12 +187292,22 @@ async function runPostTransformPhase(args) {
186905
187292
  let pendingOpsRanSuccessfully = false;
186906
187293
  let pendingOpsDidMutate = false;
186907
187294
  let heuristicOrReasoningDidMutate = false;
187295
+ let droppedCount = 0;
187296
+ const droppedTokens = 0;
187297
+ let emergency = false;
187298
+ let m0RematerializedThisPass = false;
187299
+ let m0MaterializeReason = null;
187300
+ let m0M1InjectedThisPass = false;
187301
+ let autoReclaimDidMutateThisPass = false;
186908
187302
  try {
186909
187303
  if (shouldApplyPendingOps) {
186910
187304
  const applyReason = isExplicitFlush ? "explicit_flush" : deferredMaterialize ? "deferred_materialization" : `scheduler_execute (scheduler=${args.schedulerDecision})`;
186911
187305
  sessionLog(args.sessionId, `pending ops WILL APPLY — reason=${applyReason}, pendingOps=${pendingOps.length}, context=${args.contextUsage.percentage.toFixed(1)}%`);
186912
187306
  const tApply = performance.now();
186913
187307
  pendingOpsDidMutate = applyPendingOperations(args.sessionId, args.db, args.targets, args.protectedTags, undefined, pendingOps);
187308
+ if (pendingOpsDidMutate) {
187309
+ droppedCount += pendingOps.length;
187310
+ }
186914
187311
  logTransformTiming(args.sessionId, "applyPendingOperations", tApply);
186915
187312
  }
186916
187313
  if (shouldRunHeuristics) {
@@ -186930,8 +187327,10 @@ async function runPostTransformPhase(args) {
186930
187327
  }, heuristicTags);
186931
187328
  logTransformTiming(args.sessionId, "applyHeuristicCleanup", t5, `droppedTools=${cleanup.droppedTools} deduplicatedTools=${cleanup.deduplicatedTools} droppedInjections=${cleanup.droppedInjections} compressedTextTags=${cleanup.compressedTextTags} mutatedTextTags=${cleanup.mutatedTextTags}`);
186932
187329
  const heuristicMutationCount = cleanup.droppedTools + cleanup.deduplicatedTools + cleanup.droppedInjections + cleanup.mutatedTextTags;
187330
+ droppedCount += cleanup.droppedTools + cleanup.deduplicatedTools + cleanup.droppedInjections + cleanup.mutatedTextTags;
187331
+ emergency ||= cleanup.emergencyDroppedTools > 0;
186933
187332
  const t7 = performance.now();
186934
- const clearedReasoning = clearOldReasoning(args.messages, args.reasoningByMessage, args.messageTagNumbers, args.clearReasoningAge);
187333
+ const clearedReasoning = canUseEmptySentinels ? clearOldReasoning(args.messages, args.reasoningByMessage, args.messageTagNumbers, args.clearReasoningAge) : 0;
186935
187334
  if (canUseEmptySentinels) {
186936
187335
  stripClearedReasoning(args.messages);
186937
187336
  }
@@ -186956,6 +187355,7 @@ async function runPostTransformPhase(args) {
186956
187355
  }
186957
187356
  logTransformTiming(args.sessionId, "clearOldReasoning", t7);
186958
187357
  heuristicOrReasoningDidMutate = heuristicMutationCount + clearedReasoning + strippedInline > 0;
187358
+ droppedCount += clearedReasoning + strippedInline;
186959
187359
  if (pendingMaterializationAtPassStart) {
186960
187360
  args.pendingMaterializationSessions.delete(args.sessionId);
186961
187361
  }
@@ -186981,6 +187381,10 @@ async function runPostTransformPhase(args) {
186981
187381
  autoReclaimTargetCount = syntheticPendingOps.length;
186982
187382
  if (syntheticPendingOps.length > 0) {
186983
187383
  autoReclaimDidMutate = applyPendingOperations(args.sessionId, args.db, args.targets, args.protectedTags, undefined, [], syntheticPendingOps);
187384
+ if (autoReclaimDidMutate) {
187385
+ droppedCount += syntheticPendingOps.length;
187386
+ autoReclaimDidMutateThisPass = true;
187387
+ }
186984
187388
  }
186985
187389
  }
186986
187390
  args.batch?.finalize();
@@ -187060,6 +187464,9 @@ async function runPostTransformPhase(args) {
187060
187464
  hardSignals: args.m0M1.hardSignals
187061
187465
  });
187062
187466
  if (result.injected) {
187467
+ m0M1InjectedThisPass = true;
187468
+ m0RematerializedThisPass ||= result.m0RematerializedThisPass;
187469
+ m0MaterializeReason = result.decision.reason ?? m0MaterializeReason;
187063
187470
  sessionLog(args.sessionId, `transform: injected m[0]/m[1] (rematerialized=${result.m0RematerializedThisPass}, reason=${result.decision.reason ?? "cache_hit"})`);
187064
187471
  }
187065
187472
  } catch (error51) {
@@ -187268,7 +187675,19 @@ async function runPostTransformPhase(args) {
187268
187675
  sessionLog(args.sessionId, `sticky-injection GC: pruned ${prunedAnchors} note-nudge anchor(s), ${prunedDecisions} auto-search decision(s)`);
187269
187676
  }
187270
187677
  }
187271
- return { explicitMaterializedSuccessfully, deferredMaterializedSuccessfully };
187678
+ const materializeReason = m0MaterializeReason ?? (explicitMaterializedSuccessfully ? "explicit_flush" : null);
187679
+ const materialized = m0RematerializedThisPass || explicitMaterializedSuccessfully || deferredMaterializedSuccessfully;
187680
+ const bustedThisPass = args.didMutateFromFlushedStatuses || pendingOpsDidMutate || heuristicOrReasoningDidMutate || autoReclaimDidMutateThisPass || m0RematerializedThisPass || m0M1InjectedThisPass && historyWasConsumedThisPass || historyWasConsumedThisPass;
187681
+ return {
187682
+ explicitMaterializedSuccessfully,
187683
+ deferredMaterializedSuccessfully,
187684
+ materialized,
187685
+ materializeReason,
187686
+ droppedTokens,
187687
+ droppedCount,
187688
+ emergency,
187689
+ bustedThisPass
187690
+ };
187272
187691
  }
187273
187692
  function checkM0MutationDriftAndSignal(args) {
187274
187693
  const currentMaxMutationId = getMaxM0MutationId(args.db, args.sessionId) ?? 0;
@@ -187303,6 +187722,12 @@ function clearMessageTokensCache(sessionId, messageId) {
187303
187722
  cache.delete(messageId);
187304
187723
  }
187305
187724
  var recordedSessionProjectIdentity = new BoundedSessionMap(MESSAGE_TOKENS_CACHE_MAX);
187725
+ function deriveTaggerLoadFloor(messages, sessionId, db) {
187726
+ return deriveTagLoadFloor(db, sessionId, function* () {
187727
+ for (const message of messages)
187728
+ yield message.info?.id;
187729
+ }());
187730
+ }
187306
187731
  function findLastAssistantModel2(messages) {
187307
187732
  for (let i = messages.length - 1;i >= 0; i--) {
187308
187733
  const info = messages[i].info;
@@ -187325,6 +187750,7 @@ function createTransform(deps) {
187325
187750
  return;
187326
187751
  }
187327
187752
  const resolvedSessionId = sessionId;
187753
+ clearOpenCodePendingTransformDecision(sessionId);
187328
187754
  logTransformTiming(sessionId, "findSessionId", startTime, `messages=${messages.length}`);
187329
187755
  const db = deps.db;
187330
187756
  if (deps.client !== undefined) {
@@ -187627,12 +188053,16 @@ Historian previously failed ${historianFailureState.failureCount} time(s), so Ma
187627
188053
  recordSessionProjectIdentity(db, sessionId, sessionProjectIdentity);
187628
188054
  recordedSessionProjectIdentity.set(sessionId, sessionProjectIdentity);
187629
188055
  }
188056
+ const taggerFloor = deriveTaggerLoadFloor(messages, sessionId, db);
188057
+ if (taggerFloor === 0 && messages.length > 0) {
188058
+ sessionLog(sessionId, `tag floor: 0 (full-scan fallback) — no leading wire message resolved a tag across ${messages.length} msgs`);
188059
+ }
187630
188060
  let triggerBoundarySnapshot;
187631
188061
  if (fullFeatureMode && historianRunnable && !sessionMeta.compartmentInProgress) {
187632
188062
  const tTrigger = performance.now();
187633
188063
  try {
187634
188064
  const inMemoryTail = buildTriggerInMemoryTail(db, sessionId, extractInMemoryMessageViews(messages));
187635
- const triggerResult = checkCompartmentTrigger(db, sessionId, sessionMeta, boundaryUsageForProtectedTail, sessionMeta.lastContextPercentage, boundaryExecuteThreshold, deriveTriggerBudget(boundaryContextLimit, boundaryExecuteThreshold), deps.clearReasoningAge, deps.commitClusterTrigger, undefined, boundaryContextLimit, inMemoryTail);
188065
+ const triggerResult = checkCompartmentTrigger(db, sessionId, sessionMeta, boundaryUsageForProtectedTail, sessionMeta.lastContextPercentage, boundaryExecuteThreshold, deriveTriggerBudget(boundaryContextLimit, boundaryExecuteThreshold), deps.clearReasoningAge, deps.commitClusterTrigger, undefined, boundaryContextLimit, inMemoryTail, taggerFloor);
187636
188066
  if (triggerResult.shouldFire) {
187637
188067
  sessionLog(sessionId, `compartment trigger: firing (reason=${triggerResult.reason})`);
187638
188068
  updateSessionMeta(db, sessionId, { compartmentInProgress: true });
@@ -187674,7 +188104,7 @@ Historian previously failed ${historianFailureState.failureCount} time(s), so Ma
187674
188104
  try {
187675
188105
  const t0 = performance.now();
187676
188106
  const tInitFromDb = performance.now();
187677
- deps.tagger.initFromDb(sessionId, db);
188107
+ deps.tagger.initFromDb(sessionId, db, taggerFloor);
187678
188108
  logTransformTiming(sessionId, "tag.initFromDb", tInitFromDb);
187679
188109
  const skipPrefixInjection = !ctxReduceEnabledEffective;
187680
188110
  const result = tagMessages(sessionId, messages, deps.tagger, db, {
@@ -187726,7 +188156,7 @@ Historian previously failed ${historianFailureState.failureCount} time(s), so Ma
187726
188156
  const persistedReasoningWatermark = sessionMeta?.clearedReasoningThroughTag ?? 0;
187727
188157
  if (persistedReasoningWatermark > 0) {
187728
188158
  const tReplay = performance.now();
187729
- const replayed = replayClearedReasoning(messages, reasoningByMessage, messageTagNumbers, persistedReasoningWatermark);
188159
+ const replayed = canUseEmptySentinels ? replayClearedReasoning(messages, reasoningByMessage, messageTagNumbers, persistedReasoningWatermark) : 0;
187730
188160
  const replayedInline = replayStrippedInlineThinking(messages, messageTagNumbers, persistedReasoningWatermark);
187731
188161
  if (replayed > 0 || replayedInline > 0) {
187732
188162
  sessionLog(sessionId, `reasoning replay: cleared=${replayed} inlineStripped=${replayedInline} (watermark=${persistedReasoningWatermark})`);
@@ -187824,7 +188254,7 @@ Historian previously failed ${historianFailureState.failureCount} time(s), so Ma
187824
188254
  const wasEmergencyBlock = contextUsageEarly.percentage >= FORCE_MATERIALIZE_PERCENTAGE && compartmentPhase.justAwaitedPublication;
187825
188255
  const historyRebuiltThisPass = wasEmergencyBlock ? compartmentPhase.rebuiltHistoryThisPass : rebuiltHistoryFromInitialPrepare || compartmentPhase.rebuiltHistoryThisPass;
187826
188256
  const tPostProcess = performance.now();
187827
- await runPostTransformPhase({
188257
+ const postTransformResult = await runPostTransformPhase({
187828
188258
  sessionId,
187829
188259
  db,
187830
188260
  messages,
@@ -187878,6 +188308,19 @@ Historian previously failed ${historianFailureState.failureCount} time(s), so Ma
187878
188308
  hardSignals: m0HardSignals
187879
188309
  }
187880
188310
  });
188311
+ if (postTransformResult.bustedThisPass) {
188312
+ recordPendingTransformDecision(sessionId, {
188313
+ tsMs: Date.now(),
188314
+ decision: schedulerDecision,
188315
+ materialized: postTransformResult.materialized,
188316
+ materializeReason: normalizeMaterializeReason("opencode", postTransformResult.materializeReason, postTransformResult.materialized),
188317
+ emergency: postTransformResult.emergency,
188318
+ droppedTokens: postTransformResult.droppedTokens,
188319
+ droppedCount: postTransformResult.droppedCount,
188320
+ inputTokens: contextUsage.inputTokens,
188321
+ bustedThisPass: true
188322
+ });
188323
+ }
187881
188324
  logTransformTiming(sessionId, "postTransformPhase", tPostProcess);
187882
188325
  const msgTokens = getMessageTokensCache(sessionId);
187883
188326
  let storedByMessage;
@@ -188259,6 +188702,15 @@ function createEventHandler2(deps) {
188259
188702
  info.tokens?.cache?.write
188260
188703
  ];
188261
188704
  const hasUsageTokens = usageTokens.some((value) => typeof value === "number" && value > 0);
188705
+ const terminalAssistantUpdate = info.messageID !== undefined && hasUsageTokens && (typeof info.finish === "string" || typeof info.completedAt === "number");
188706
+ if (terminalAssistantUpdate && info.messageID) {
188707
+ scheduleOpenCodeTransformDecisionWrite({
188708
+ db: deps.db,
188709
+ sessionId: info.sessionID,
188710
+ messageId: info.messageID,
188711
+ inputTokens: (info.tokens?.input ?? 0) + (info.tokens?.cache?.read ?? 0) + (info.tokens?.cache?.write ?? 0)
188712
+ });
188713
+ }
188262
188714
  sessionLog(info.sessionID, `event message.updated: provider=${info.providerID} model=${info.modelID} hasUsageTokens=${hasUsageTokens} tokens.input=${info.tokens?.input} cache.read=${info.tokens?.cache?.read} cache.write=${info.tokens?.cache?.write}`);
188263
188715
  const hasKnownUsage = hasUsageTokens || deps.contextUsageMap.has(info.sessionID);
188264
188716
  if (!hasKnownUsage) {
@@ -188416,6 +188868,7 @@ function createEventHandler2(deps) {
188416
188868
  deps.onSessionDeleted?.(sessionId);
188417
188869
  deps.contextUsageMap.delete(sessionId);
188418
188870
  deps.tagger.cleanup(sessionId);
188871
+ clearTransformDecisionSession(sessionId);
188419
188872
  clearMessageTokensCache(sessionId);
188420
188873
  invalidateTrueRawTokenCache({ sessionId, reason: "session.deleted" });
188421
188874
  return;
@@ -189143,7 +189596,7 @@ function createMagicContextHook(deps) {
189143
189596
  }
189144
189597
  let lastScheduleCheckMs = 0;
189145
189598
  const getHistorianChunkTokens = () => deriveHistorianChunkTokens(resolveHistorianContextLimit(deps.config.historian?.model));
189146
- const historianFallbackModels = resolveFallbackChain(HISTORIAN_AGENT, deps.config.historian?.fallback_models);
189599
+ const historianFallbackModels = resolveFallbackChain(deps.config.historian?.fallback_models);
189147
189600
  const historyRefreshSessions = deps.liveSessionState?.historyRefreshSessions ?? new Set;
189148
189601
  const deferredHistoryRefreshSessions = deps.liveSessionState?.deferredHistoryRefreshSessions ?? new Set;
189149
189602
  try {
@@ -189471,7 +189924,7 @@ function createMagicContextHook(deps) {
189471
189924
  token_budget: dreaming.pin_key_files.token_budget,
189472
189925
  min_reads: dreaming.pin_key_files.min_reads
189473
189926
  } : undefined,
189474
- fallbackModels: resolveFallbackChain(DREAMER_AGENT, dreaming.fallback_models),
189927
+ fallbackModels: resolveFallbackChain(dreaming.fallback_models),
189475
189928
  projectIdentity: projectPath
189476
189929
  }).catch((error51) => {
189477
189930
  log("[dreamer] scheduled queue processing failed:", error51);
@@ -189530,7 +189983,7 @@ function createMagicContextHook(deps) {
189530
189983
  token_budget: dreamerConfig.pin_key_files.token_budget,
189531
189984
  min_reads: dreamerConfig.pin_key_files.min_reads
189532
189985
  } : undefined,
189533
- fallbackModels: resolveFallbackChain(DREAMER_AGENT, dreamerConfig.fallback_models)
189986
+ fallbackModels: resolveFallbackChain(dreamerConfig.fallback_models)
189534
189987
  } : undefined
189535
189988
  });
189536
189989
  const systemPromptHash = createSystemPromptHashHandler({
@@ -190506,8 +190959,7 @@ function registerRpcHandlers(rpcServer, args) {
190506
190959
  });
190507
190960
  const buildManagedCtx = async (db) => {
190508
190961
  const { deriveHistorianChunkTokens: deriveHistorianChunkTokens2, resolveHistorianContextLimit: resolveHistorianContextLimit2 } = await Promise.resolve().then(() => (init_derive_budgets(), exports_derive_budgets));
190509
- const { resolveFallbackChain: resolveFallbackChain2 } = await Promise.resolve().then(() => (init_resolve_fallbacks(), exports_resolve_fallbacks));
190510
- const { HISTORIAN_AGENT: HISTORIAN_AGENT2 } = await Promise.resolve().then(() => exports_historian);
190962
+ const { resolveFallbackChain: resolveFallbackChain2 } = await Promise.resolve().then(() => exports_resolve_fallbacks);
190511
190963
  const DEFAULT_HISTORIAN_TIMEOUT_MS2 = 600000;
190512
190964
  return {
190513
190965
  client: args.client,
@@ -190518,7 +190970,7 @@ function registerRpcHandlers(rpcServer, args) {
190518
190970
  historianTimeoutMs: config2.historian_timeout_ms ?? DEFAULT_HISTORIAN_TIMEOUT_MS2,
190519
190971
  memoryEnabled: config2.memory?.enabled ?? true,
190520
190972
  autoPromote: config2.memory?.auto_promote ?? true,
190521
- fallbackModels: resolveFallbackChain2(HISTORIAN_AGENT2, config2.historian?.fallback_models),
190973
+ fallbackModels: resolveFallbackChain2(config2.historian?.fallback_models),
190522
190974
  runMigration: config2.memory?.enabled !== false && !!config2.historian?.model,
190523
190975
  userMemoriesEnabled: config2.dreamer?.user_memories?.enabled === true,
190524
190976
  historianTwoPass: config2.historian?.two_pass === true,
@@ -190870,6 +191322,7 @@ Actions:
190870
191322
  Example: ctx_memory(action="write", category="CONSTRAINTS", content="Pi stores sessions as JSONL under ~/.pi/agent/sessions/, not SQLite")`;
190871
191323
  var DEFAULT_SEARCH_LIMIT2 = 10;
190872
191324
  // src/tools/ctx-memory/tools.ts
191325
+ import { tool as tool2 } from "@opencode-ai/plugin";
190873
191326
  init_memory();
190874
191327
  init_embedding();
190875
191328
  init_embedding_cache();
@@ -190877,7 +191330,6 @@ init_normalize_hash();
190877
191330
  init_workspaces();
190878
191331
  init_logger();
190879
191332
  await init_storage();
190880
- import { tool as tool2 } from "@opencode-ai/plugin";
190881
191333
 
190882
191334
  // src/tools/ctx-memory/types.ts
190883
191335
  var CTX_MEMORY_ACTIONS = ["write", "archive", "update", "merge"];
@@ -191802,7 +192254,7 @@ function createCtxSearchTool(deps) {
191802
192254
  memoryEnabled,
191803
192255
  embeddingEnabled,
191804
192256
  embedQuery: async (text, signal) => {
191805
- const result = await embedTextForProject(projectPath, text, signal);
192257
+ const result = await embedTextForProject(projectPath, text, signal, "query");
191806
192258
  return result?.vector ?? null;
191807
192259
  },
191808
192260
  isEmbeddingRuntimeEnabled: () => embeddingEnabled === true,
@@ -191905,7 +192357,6 @@ function createToolRegistry(args) {
191905
192357
  init_conflict_detector();
191906
192358
  init_data_path();
191907
192359
  init_logger();
191908
- init_model_requirements();
191909
192360
  init_models_dev_cache();
191910
192361
 
191911
192362
  // src/shared/rpc-server.ts
@@ -192313,14 +192764,13 @@ var plugin = async (ctx) => {
192313
192764
  await hooks.magicContext?.["experimental.text.complete"]?.(input, output);
192314
192765
  },
192315
192766
  config: async (config2) => {
192316
- const buildHiddenAgentConfig = (agentId, prompt, allowedTools, maxSteps, overrides) => {
192767
+ const buildHiddenAgentConfig = (prompt, allowedTools, maxSteps, overrides) => {
192317
192768
  const { permission: overridePermission, ...restOverrides } = overrides ?? {};
192318
192769
  const basePermission = buildAllowOnlyPermission(allowedTools);
192319
192770
  return {
192320
192771
  prompt,
192321
192772
  steps: maxSteps,
192322
192773
  maxSteps,
192323
- ...getAgentFallbackModels(agentId) ? { fallback_models: getAgentFallbackModels(agentId) } : {},
192324
192774
  ...restOverrides,
192325
192775
  permission: {
192326
192776
  ...basePermission,
@@ -192342,6 +192792,7 @@ var plugin = async (ctx) => {
192342
192792
  max_runtime_minutes: _max,
192343
192793
  tasks: _tasks,
192344
192794
  task_timeout_minutes: _tto,
192795
+ thinking_level: _thinkingLevel,
192345
192796
  ...agentOverrides
192346
192797
  } = pluginConfig.dreamer;
192347
192798
  return agentOverrides;
@@ -192350,20 +192801,28 @@ var plugin = async (ctx) => {
192350
192801
  const {
192351
192802
  timeout_ms: _timeoutMs,
192352
192803
  system_prompt: _systemPrompt,
192804
+ thinking_level: _thinkingLevel,
192353
192805
  ...agentOverrides
192354
192806
  } = pluginConfig.sidekick;
192355
192807
  return agentOverrides;
192356
192808
  })() : undefined;
192357
192809
  const historianAgentOverrides = pluginConfig.historian ? (() => {
192358
- const { two_pass: _twoPass, ...agentOverrides } = pluginConfig.historian;
192810
+ const {
192811
+ two_pass: _twoPass,
192812
+ disallowed_tools: _disallowedTools,
192813
+ thinking_level: _thinkingLevel,
192814
+ ...agentOverrides
192815
+ } = pluginConfig.historian;
192359
192816
  return agentOverrides;
192360
192817
  })() : undefined;
192818
+ const historianDisallowed = pluginConfig.historian?.disallowed_tools ?? [];
192819
+ const historianAllowedTools = applyDisallowedTools(HISTORIAN_ALLOWED_TOOLS, historianDisallowed);
192361
192820
  config2.agent = {
192362
192821
  ...config2.agent ?? {},
192363
- [DREAMER_AGENT]: buildHiddenAgentConfig(DREAMER_AGENT, DREAMER_SYSTEM_PROMPT, DREAMER_ALLOWED_TOOLS, DREAMER_MAX_STEPS, dreamerAgentOverrides),
192364
- [HISTORIAN_AGENT]: buildHiddenAgentConfig(HISTORIAN_AGENT, COMPARTMENT_AGENT_SYSTEM_PROMPT, HISTORIAN_ALLOWED_TOOLS, HISTORIAN_MAX_STEPS, historianAgentOverrides),
192365
- [HISTORIAN_EDITOR_AGENT]: buildHiddenAgentConfig(HISTORIAN_EDITOR_AGENT, HISTORIAN_EDITOR_SYSTEM_PROMPT, HISTORIAN_ALLOWED_TOOLS, HISTORIAN_MAX_STEPS, historianAgentOverrides),
192366
- [SIDEKICK_AGENT]: buildHiddenAgentConfig(SIDEKICK_AGENT, SIDEKICK_SYSTEM_PROMPT, SIDEKICK_ALLOWED_TOOLS, SIDEKICK_MAX_STEPS, sidekickAgentOverrides)
192822
+ [DREAMER_AGENT]: buildHiddenAgentConfig(DREAMER_SYSTEM_PROMPT, DREAMER_ALLOWED_TOOLS, DREAMER_MAX_STEPS, dreamerAgentOverrides),
192823
+ [HISTORIAN_AGENT]: buildHiddenAgentConfig(COMPARTMENT_AGENT_SYSTEM_PROMPT, historianAllowedTools, HISTORIAN_MAX_STEPS, historianAgentOverrides),
192824
+ [HISTORIAN_EDITOR_AGENT]: buildHiddenAgentConfig(HISTORIAN_EDITOR_SYSTEM_PROMPT, historianAllowedTools, HISTORIAN_MAX_STEPS, historianAgentOverrides),
192825
+ [SIDEKICK_AGENT]: buildHiddenAgentConfig(SIDEKICK_SYSTEM_PROMPT, SIDEKICK_ALLOWED_TOOLS, SIDEKICK_MAX_STEPS, sidekickAgentOverrides)
192367
192826
  };
192368
192827
  }
192369
192828
  };