@wolfx/opencode-magic-context 0.25.0 → 0.26.0-patch.1

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 (82) 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 +24 -17
  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-identity.d.ts.map +1 -1
  10. package/dist/features/magic-context/memory/embedding-openai.d.ts +8 -4
  11. package/dist/features/magic-context/memory/embedding-openai.d.ts.map +1 -1
  12. package/dist/features/magic-context/memory/embedding-provider.d.ts +8 -4
  13. package/dist/features/magic-context/memory/embedding-provider.d.ts.map +1 -1
  14. package/dist/features/magic-context/memory/embedding.d.ts.map +1 -1
  15. package/dist/features/magic-context/memory/relocate-memory.d.ts +58 -0
  16. package/dist/features/magic-context/memory/relocate-memory.d.ts.map +1 -0
  17. package/dist/features/magic-context/migrations.d.ts.map +1 -1
  18. package/dist/features/magic-context/project-embedding-registry.d.ts +3 -3
  19. package/dist/features/magic-context/project-embedding-registry.d.ts.map +1 -1
  20. package/dist/features/magic-context/storage-db.d.ts +2 -1
  21. package/dist/features/magic-context/storage-db.d.ts.map +1 -1
  22. package/dist/features/magic-context/storage-meta-persisted.d.ts +37 -0
  23. package/dist/features/magic-context/storage-meta-persisted.d.ts.map +1 -1
  24. package/dist/features/magic-context/storage-meta-session.d.ts.map +1 -1
  25. package/dist/features/magic-context/storage-meta-shared.d.ts +3 -1
  26. package/dist/features/magic-context/storage-meta-shared.d.ts.map +1 -1
  27. package/dist/features/magic-context/storage-meta.d.ts +1 -1
  28. package/dist/features/magic-context/storage-meta.d.ts.map +1 -1
  29. package/dist/features/magic-context/storage-tags.d.ts +48 -2
  30. package/dist/features/magic-context/storage-tags.d.ts.map +1 -1
  31. package/dist/features/magic-context/storage.d.ts +3 -3
  32. package/dist/features/magic-context/storage.d.ts.map +1 -1
  33. package/dist/features/magic-context/tagger.d.ts +1 -1
  34. package/dist/features/magic-context/tagger.d.ts.map +1 -1
  35. package/dist/features/magic-context/transform-decision-log.d.ts +49 -0
  36. package/dist/features/magic-context/transform-decision-log.d.ts.map +1 -0
  37. package/dist/features/magic-context/v22-deferred-backfill.d.ts.map +1 -1
  38. package/dist/hooks/magic-context/auto-search-runner.d.ts.map +1 -1
  39. package/dist/hooks/magic-context/compartment-runner-incremental.d.ts.map +1 -1
  40. package/dist/hooks/magic-context/compartment-trigger.d.ts +1 -1
  41. package/dist/hooks/magic-context/compartment-trigger.d.ts.map +1 -1
  42. package/dist/hooks/magic-context/derive-budgets.d.ts +5 -9
  43. package/dist/hooks/magic-context/derive-budgets.d.ts.map +1 -1
  44. package/dist/hooks/magic-context/event-handler.d.ts.map +1 -1
  45. package/dist/hooks/magic-context/event-payloads.d.ts +1 -0
  46. package/dist/hooks/magic-context/event-payloads.d.ts.map +1 -1
  47. package/dist/hooks/magic-context/heuristic-cleanup.d.ts +1 -0
  48. package/dist/hooks/magic-context/heuristic-cleanup.d.ts.map +1 -1
  49. package/dist/hooks/magic-context/hook.d.ts.map +1 -1
  50. package/dist/hooks/magic-context/protected-tail-boundary.d.ts +10 -0
  51. package/dist/hooks/magic-context/protected-tail-boundary.d.ts.map +1 -1
  52. package/dist/hooks/magic-context/read-session-chunk.d.ts.map +1 -1
  53. package/dist/hooks/magic-context/tag-id-fallback.d.ts.map +1 -1
  54. package/dist/hooks/magic-context/tag-messages.d.ts +10 -0
  55. package/dist/hooks/magic-context/tag-messages.d.ts.map +1 -1
  56. package/dist/hooks/magic-context/transform-compartment-phase.d.ts +32 -1
  57. package/dist/hooks/magic-context/transform-compartment-phase.d.ts.map +1 -1
  58. package/dist/hooks/magic-context/transform-postprocess-phase.d.ts +6 -0
  59. package/dist/hooks/magic-context/transform-postprocess-phase.d.ts.map +1 -1
  60. package/dist/hooks/magic-context/transform.d.ts.map +1 -1
  61. package/dist/index.d.ts.map +1 -1
  62. package/dist/index.js +721 -651
  63. package/dist/plugin/dream-timer.d.ts.map +1 -1
  64. package/dist/plugin/hooks/create-session-hooks.d.ts.map +1 -1
  65. package/dist/plugin/rpc-handlers.d.ts.map +1 -1
  66. package/dist/shared/announcement.d.ts +1 -1
  67. package/dist/shared/index.d.ts +0 -1
  68. package/dist/shared/index.d.ts.map +1 -1
  69. package/dist/shared/resolve-fallbacks.d.ts +16 -16
  70. package/dist/shared/resolve-fallbacks.d.ts.map +1 -1
  71. package/dist/tools/ctx-search/tools.d.ts.map +1 -1
  72. package/package.json +5 -12
  73. package/src/shared/announcement.ts +6 -6
  74. package/src/shared/index.ts +0 -1
  75. package/src/shared/resolve-fallbacks.test.ts +37 -71
  76. package/src/shared/resolve-fallbacks.ts +16 -26
  77. package/src/tui/slots/sidebar-content.tsx +11 -7
  78. package/dist/features/magic-context/memory/embedding-local.d.ts +0 -25
  79. package/dist/features/magic-context/memory/embedding-local.d.ts.map +0 -1
  80. package/dist/shared/model-requirements.d.ts +0 -26
  81. package/dist/shared/model-requirements.d.ts.map +0 -1
  82. 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) {
@@ -14836,7 +14825,7 @@ var init_agent_overrides = __esm(() => {
14836
14825
  });
14837
14826
 
14838
14827
  // src/config/schema/magic-context.ts
14839
- var DEFAULT_EXECUTE_THRESHOLD_PERCENTAGE = 65, EXECUTE_THRESHOLD_CAP_MESSAGE = "execute_threshold is capped at 80% for cache safety: a single large agent step can overflow the context window before Magic Context can compact between turns, forcing OpenCode's native compaction (hard to recover from). 80% also leaves headroom below the 85%/95% emergency bands. Use a value between 20 and 80.", DEFAULT_HISTORIAN_TIMEOUT_MS = 300000, DEFAULT_HISTORY_BUDGET_PERCENTAGE = 0.15, DEFAULT_LOCAL_EMBEDDING_MODEL = "Xenova/all-MiniLM-L6-v2", DREAMER_TASKS, DreamingTaskSchema, DEFAULT_DREAMER_TASKS, PiThinkingLevelSchema, DreamerConfigSchema, SidekickConfigSchema, HistorianConfigSchema, BaseEmbeddingConfigSchema, EmbeddingConfigSchema, MagicContextConfigSchema;
14828
+ var DEFAULT_EXECUTE_THRESHOLD_PERCENTAGE = 65, EXECUTE_THRESHOLD_CAP_MESSAGE = "execute_threshold is capped at 80% for cache safety: a single large agent step can overflow the context window before Magic Context can compact between turns, forcing OpenCode's native compaction (hard to recover from). 80% also leaves headroom below the 85%/95% emergency bands. Use a value between 20 and 80.", DEFAULT_HISTORIAN_TIMEOUT_MS = 300000, DEFAULT_HISTORY_BUDGET_PERCENTAGE = 0.15, DREAMER_TASKS, DreamingTaskSchema, DEFAULT_DREAMER_TASKS, PiThinkingLevelSchema, DreamerConfigSchema, SidekickConfigSchema, HistorianConfigSchema, BaseEmbeddingConfigSchema, EmbeddingConfigSchema, MagicContextConfigSchema;
14840
14829
  var init_magic_context = __esm(() => {
14841
14830
  init_zod();
14842
14831
  init_agent_overrides();
@@ -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
- 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
- model: exports_external.string().optional().describe("Embedding model name. Required for openai-compatible, ignored for local."),
14875
+ provider: exports_external.enum(["openai-compatible", "off"]).default("off").describe("Embedding provider. 'openai-compatible' requires endpoint and model, 'off' disables embeddings (default)."),
14876
+ model: exports_external.string().optional().describe("Embedding model name. Required for openai-compatible."),
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) => {
@@ -14906,16 +14897,10 @@ var init_magic_context = __esm(() => {
14906
14897
  }
14907
14898
  });
14908
14899
  EmbeddingConfigSchema = BaseEmbeddingConfigSchema.transform((data) => {
14909
- if (data.provider === "local") {
14910
- return {
14911
- provider: "local",
14912
- model: data.model?.trim() || DEFAULT_LOCAL_EMBEDDING_MODEL,
14913
- ...data.max_input_tokens ? { max_input_tokens: data.max_input_tokens } : {}
14914
- };
14915
- }
14916
14900
  if (data.provider === "openai-compatible") {
14917
14901
  const apiKey = data.api_key?.trim();
14918
14902
  const inputType = data.input_type?.trim();
14903
+ const queryInputType = data.query_input_type?.trim();
14919
14904
  const truncate = data.truncate?.trim();
14920
14905
  return {
14921
14906
  provider: "openai-compatible",
@@ -14923,6 +14908,7 @@ var init_magic_context = __esm(() => {
14923
14908
  endpoint: data.endpoint?.trim() ?? "",
14924
14909
  ...apiKey ? { api_key: apiKey } : {},
14925
14910
  ...inputType ? { input_type: inputType } : {},
14911
+ ...queryInputType ? { query_input_type: queryInputType } : {},
14926
14912
  ...truncate ? { truncate } : {},
14927
14913
  ...data.max_input_tokens ? { max_input_tokens: data.max_input_tokens } : {}
14928
14914
  };
@@ -14962,8 +14948,7 @@ var init_magic_context = __esm(() => {
14962
14948
  mmap_size_mb: exports_external.number().min(0).max(8192).default(0).describe("Memory-mapped I/O size in MiB (PRAGMA mmap_size). 0 disables mmap (SQLite default). Raising it can cut read overhead on large DBs at the cost of address space. (min 0, max 8192, default 0)")
14963
14949
  }).default({ cache_size_mb: 64, mmap_size_mb: 0 }).describe("SQLite connection tuning for Magic Context's own context.db. These are per-connection PRAGMAs applied at open; they do not change the schema or what is stored."),
14964
14950
  embedding: EmbeddingConfigSchema.default({
14965
- provider: "local",
14966
- model: DEFAULT_LOCAL_EMBEDDING_MODEL
14951
+ provider: "off"
14967
14952
  }).describe("Embedding provider configuration"),
14968
14953
  temporal_awareness: exports_external.boolean().default(true).describe('Inject wall-clock gap markers (<!-- +Xm -->) between user messages where > 5 min elapsed since the previous message, and add start/end date attributes on compartments. Gives the agent a sense of session pacing and "how long ago" across multi-day sessions. Graduated from experimental.temporal_awareness; default: true (set false to opt out).'),
14969
14954
  keep_subagents: exports_external.boolean().default(false).describe("Debug: keep the child sessions Magic Context spawns for its own subagents (historian, dreamer, sidekick, memory-migration) instead of deleting them on success. Useful for short-term inspection/data collection — their full transcript (prompt, tool calls, token usage, output) stays in the host session store. Kept sessions accumulate until manually cleared; leave false for normal use. Requires a restart to take effect."),
@@ -15284,58 +15269,6 @@ var init_logger = __esm(() => {
15284
15269
  }
15285
15270
  });
15286
15271
 
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
15272
  // src/features/magic-context/overflow-detection.ts
15340
15273
  function extractErrorMessage(error51) {
15341
15274
  if (!error51)
@@ -15449,15 +15382,9 @@ __export(exports_resolve_fallbacks, {
15449
15382
  resolveFallbackChain: () => resolveFallbackChain,
15450
15383
  parseProviderModel: () => parseProviderModel
15451
15384
  });
15452
- function resolveFallbackChain(agentName, userFallbacks) {
15385
+ function resolveFallbackChain(userFallbacks) {
15453
15386
  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));
15387
+ return dedupe(userList.filter(isValidModelSpec));
15461
15388
  }
15462
15389
  function normalizeUserFallbacks(userFallbacks) {
15463
15390
  if (!userFallbacks)
@@ -15492,9 +15419,6 @@ function parseProviderModel(spec) {
15492
15419
  modelID: spec.slice(slash + 1).trim()
15493
15420
  };
15494
15421
  }
15495
- var init_resolve_fallbacks = __esm(() => {
15496
- init_model_requirements();
15497
- });
15498
15422
 
15499
15423
  // src/shared/model-suggestion-retry.ts
15500
15424
  function extractMessage(error51) {
@@ -15682,7 +15606,6 @@ async function promptSyncWithModelSuggestionRetry(client, args, options = {}) {
15682
15606
  var init_model_suggestion_retry = __esm(() => {
15683
15607
  init_overflow_detection();
15684
15608
  init_logger();
15685
- init_resolve_fallbacks();
15686
15609
  });
15687
15610
 
15688
15611
  // src/shared/normalize-sdk-response.ts
@@ -15712,9 +15635,7 @@ function normalizeSDKResponse(response, fallback, options) {
15712
15635
  // src/shared/index.ts
15713
15636
  var init_shared = __esm(() => {
15714
15637
  init_logger();
15715
- init_model_requirements();
15716
15638
  init_model_suggestion_retry();
15717
- init_resolve_fallbacks();
15718
15639
  });
15719
15640
 
15720
15641
  // src/shared/record-type-guard.ts
@@ -16080,6 +16001,8 @@ var init_storage_meta_shared = __esm(() => {
16080
16001
  "recovery_no_eligible_head_count",
16081
16002
  "force_emergency_bypass_window_start",
16082
16003
  "force_emergency_bypass_used",
16004
+ "emergency_drain_active",
16005
+ "historian_drain_failure_at",
16083
16006
  "upgrade_reminded_at",
16084
16007
  "pi_stable_id_scheme"
16085
16008
  ];
@@ -16129,6 +16052,8 @@ var init_storage_meta_shared = __esm(() => {
16129
16052
  recoveryNoEligibleHeadCount: "recovery_no_eligible_head_count",
16130
16053
  forceEmergencyBypassWindowStart: "force_emergency_bypass_window_start",
16131
16054
  forceEmergencyBypassUsed: "force_emergency_bypass_used",
16055
+ emergencyDrainActive: "emergency_drain_active",
16056
+ historianDrainFailureAt: "historian_drain_failure_at",
16132
16057
  upgradeRemindedAt: "upgrade_reminded_at",
16133
16058
  piStableIdScheme: "pi_stable_id_scheme"
16134
16059
  };
@@ -149680,6 +149605,22 @@ var init_tool_drop_target = __esm(() => {
149680
149605
  });
149681
149606
 
149682
149607
  // src/hooks/magic-context/read-session-chunk.ts
149608
+ function estimateBlockTokens(blockText) {
149609
+ const cached2 = blockTokenMemo.get(blockText);
149610
+ if (cached2 !== undefined) {
149611
+ blockTokenMemo.delete(blockText);
149612
+ blockTokenMemo.set(blockText, cached2);
149613
+ return cached2;
149614
+ }
149615
+ const count = estimateTokens(blockText);
149616
+ if (blockTokenMemo.size >= BLOCK_TOKEN_MEMO_MAX) {
149617
+ const oldest = blockTokenMemo.keys().next().value;
149618
+ if (oldest !== undefined)
149619
+ blockTokenMemo.delete(oldest);
149620
+ }
149621
+ blockTokenMemo.set(blockText, count);
149622
+ return count;
149623
+ }
149683
149624
  function cleanUserText(text) {
149684
149625
  return removeSystemReminders(text).replace(OMO_INTERNAL_INITIATOR_MARKER, "").trim();
149685
149626
  }
@@ -149847,7 +149788,7 @@ function readSessionChunk(sessionId, tokenBudget, offset = 1, eligibleEndOrdinal
149847
149788
  if (!currentBlock)
149848
149789
  return true;
149849
149790
  const blockText = formatBlock(currentBlock);
149850
- const blockTokens = estimateTokens(blockText);
149791
+ const blockTokens = estimateBlockTokens(blockText);
149851
149792
  if (totalTokens + blockTokens > tokenBudget && totalTokens > 0) {
149852
149793
  return false;
149853
149794
  }
@@ -149965,13 +149906,14 @@ function readSessionChunk(sessionId, tokenBudget, offset = 1, eligibleEndOrdinal
149965
149906
  toolOnlyRanges
149966
149907
  };
149967
149908
  }
149968
- var activeRawMessageCache = null, activeAbsoluteCountCache = null, sessionProviders, PROTECTED_TAIL_USER_TURNS = 5;
149909
+ var BLOCK_TOKEN_MEMO_MAX = 2048, blockTokenMemo, activeRawMessageCache = null, activeAbsoluteCountCache = null, sessionProviders, PROTECTED_TAIL_USER_TURNS = 5;
149969
149910
  var init_read_session_chunk = __esm(async () => {
149970
149911
  init_read_session_formatting();
149971
149912
  init_tag_part_guards();
149972
149913
  init_tool_drop_target();
149973
149914
  init_read_session_formatting();
149974
149915
  await init_read_session_db();
149916
+ blockTokenMemo = new Map;
149975
149917
  sessionProviders = new Map;
149976
149918
  });
149977
149919
 
@@ -150716,6 +150658,9 @@ function resolveDatabasePath(dbPathOverride) {
150716
150658
  const dbDir = getMagicContextStorageDir();
150717
150659
  return { dbDir, dbPath: join6(dbDir, "context.db") };
150718
150660
  }
150661
+ function getDatabasePath(db) {
150662
+ return pathByDatabase.get(db) ?? null;
150663
+ }
150719
150664
  function migrateLegacyStorageIfNeeded(targetDbPath, targetDbDir) {
150720
150665
  if (existsSync7(targetDbPath))
150721
150666
  return;
@@ -151226,6 +151171,8 @@ CREATE INDEX IF NOT EXISTS idx_dream_queue_pending ON dream_queue(started_at, en
151226
151171
  recovery_no_eligible_head_count INTEGER NOT NULL DEFAULT 0,
151227
151172
  force_emergency_bypass_window_start INTEGER NOT NULL DEFAULT 0,
151228
151173
  force_emergency_bypass_used INTEGER NOT NULL DEFAULT 0,
151174
+ emergency_drain_active INTEGER NOT NULL DEFAULT 0,
151175
+ historian_drain_failure_at INTEGER NOT NULL DEFAULT 0,
151229
151176
  cached_m0_materialized_at INTEGER,
151230
151177
  cached_m0_session_facts_version INTEGER,
151231
151178
  cached_m0_upgrade_state TEXT,
@@ -151289,6 +151236,23 @@ CREATE INDEX IF NOT EXISTS idx_dream_queue_pending ON dream_queue(started_at, en
151289
151236
  CREATE INDEX IF NOT EXISTS idx_historian_runs_status
151290
151237
  ON historian_runs(status, created_at DESC);
151291
151238
 
151239
+ CREATE TABLE IF NOT EXISTS transform_decisions (
151240
+ session_id TEXT NOT NULL,
151241
+ harness TEXT NOT NULL DEFAULT 'opencode',
151242
+ message_id TEXT NOT NULL,
151243
+ ts_ms INTEGER NOT NULL,
151244
+ decision TEXT NOT NULL,
151245
+ materialized INTEGER NOT NULL DEFAULT 0,
151246
+ materialize_reason TEXT,
151247
+ emergency INTEGER NOT NULL DEFAULT 0,
151248
+ dropped_tokens INTEGER NOT NULL DEFAULT 0,
151249
+ dropped_count INTEGER NOT NULL DEFAULT 0,
151250
+ input_tokens INTEGER NOT NULL DEFAULT 0,
151251
+ PRIMARY KEY (session_id, harness, message_id)
151252
+ );
151253
+ CREATE INDEX IF NOT EXISTS idx_transform_decisions_session_harness
151254
+ ON transform_decisions(session_id, harness);
151255
+
151292
151256
  CREATE INDEX IF NOT EXISTS idx_tags_session_tag_number ON tags(session_id, tag_number);
151293
151257
  CREATE INDEX IF NOT EXISTS idx_tags_session_message_id ON tags(session_id, message_id);
151294
151258
  CREATE INDEX IF NOT EXISTS idx_pending_ops_session ON pending_ops(session_id);
@@ -151440,6 +151404,8 @@ CREATE INDEX IF NOT EXISTS idx_dream_queue_pending ON dream_queue(started_at, en
151440
151404
  ensureColumn(db, "session_meta", "recovery_no_eligible_head_count", "INTEGER NOT NULL DEFAULT 0");
151441
151405
  ensureColumn(db, "session_meta", "force_emergency_bypass_window_start", "INTEGER NOT NULL DEFAULT 0");
151442
151406
  ensureColumn(db, "session_meta", "force_emergency_bypass_used", "INTEGER NOT NULL DEFAULT 0");
151407
+ ensureColumn(db, "session_meta", "emergency_drain_active", "INTEGER NOT NULL DEFAULT 0");
151408
+ ensureColumn(db, "session_meta", "historian_drain_failure_at", "INTEGER NOT NULL DEFAULT 0");
151443
151409
  ensureColumn(db, "session_meta", "cached_m0_materialized_at", "INTEGER");
151444
151410
  ensureColumn(db, "session_meta", "cached_m0_session_facts_version", "INTEGER");
151445
151411
  ensureColumn(db, "session_meta", "cached_m0_upgrade_state", "TEXT");
@@ -151518,6 +151484,22 @@ CREATE INDEX IF NOT EXISTS idx_dream_queue_pending ON dream_queue(started_at, en
151518
151484
  failed_at INTEGER NOT NULL,
151519
151485
  UNIQUE(table_name, row_id)
151520
151486
  );
151487
+ CREATE TABLE IF NOT EXISTS transform_decisions (
151488
+ session_id TEXT NOT NULL,
151489
+ harness TEXT NOT NULL DEFAULT 'opencode',
151490
+ message_id TEXT NOT NULL,
151491
+ ts_ms INTEGER NOT NULL,
151492
+ decision TEXT NOT NULL,
151493
+ materialized INTEGER NOT NULL DEFAULT 0,
151494
+ materialize_reason TEXT,
151495
+ emergency INTEGER NOT NULL DEFAULT 0,
151496
+ dropped_tokens INTEGER NOT NULL DEFAULT 0,
151497
+ dropped_count INTEGER NOT NULL DEFAULT 0,
151498
+ input_tokens INTEGER NOT NULL DEFAULT 0,
151499
+ PRIMARY KEY (session_id, harness, message_id)
151500
+ );
151501
+ CREATE INDEX IF NOT EXISTS idx_transform_decisions_session_harness
151502
+ ON transform_decisions(session_id, harness);
151521
151503
  `);
151522
151504
  ensureColumn(db, "tags", "harness", "TEXT NOT NULL DEFAULT 'opencode'");
151523
151505
  ensureColumn(db, "pending_ops", "harness", "TEXT NOT NULL DEFAULT 'opencode'");
@@ -151603,7 +151585,9 @@ function healNullIntegerColumns(db) {
151603
151585
  ["protected_tail_drain_tokens", 0],
151604
151586
  ["recovery_no_eligible_head_count", 0],
151605
151587
  ["force_emergency_bypass_window_start", 0],
151606
- ["force_emergency_bypass_used", 0]
151588
+ ["force_emergency_bypass_used", 0],
151589
+ ["emergency_drain_active", 0],
151590
+ ["historian_drain_failure_at", 0]
151607
151591
  ];
151608
151592
  for (const [column, fallback] of columns) {
151609
151593
  try {
@@ -151679,6 +151663,7 @@ function openDatabase(dbPathOrOptions) {
151679
151663
  setDatabase(db);
151680
151664
  loadToolDefinitionMeasurements(db);
151681
151665
  databases.set(dbPath, db);
151666
+ pathByDatabase.set(db, dbPath);
151682
151667
  persistenceByDatabase.set(db, true);
151683
151668
  persistenceErrorByDatabase.delete(db);
151684
151669
  return db;
@@ -151698,7 +151683,7 @@ function getDatabasePersistenceError(db) {
151698
151683
  return null;
151699
151684
  return persistenceErrorByDatabase.get(db) ?? null;
151700
151685
  }
151701
- var databases, persistenceByDatabase, persistenceErrorByDatabase, lastSchemaFenceRejection = null, LATEST_SUPPORTED_VERSION = 36, sqlitePragmaConfig, CHANNEL2_CLAIM_TTL_MS = 120000;
151686
+ var databases, persistenceByDatabase, persistenceErrorByDatabase, pathByDatabase, lastSchemaFenceRejection = null, LATEST_SUPPORTED_VERSION = 38, sqlitePragmaConfig, CHANNEL2_CLAIM_TTL_MS = 120000;
151702
151687
  var init_storage_db = __esm(async () => {
151703
151688
  init_data_path();
151704
151689
  init_logger();
@@ -151712,6 +151697,7 @@ var init_storage_db = __esm(async () => {
151712
151697
  databases = new Map;
151713
151698
  persistenceByDatabase = new WeakMap;
151714
151699
  persistenceErrorByDatabase = new WeakMap;
151700
+ pathByDatabase = new WeakMap;
151715
151701
  sqlitePragmaConfig = {
151716
151702
  cacheSizeMb: 64,
151717
151703
  mmapSizeMb: 0
@@ -153030,6 +153016,41 @@ var init_migrations = __esm(async () => {
153030
153016
  `);
153031
153017
  }
153032
153018
  }
153019
+ },
153020
+ {
153021
+ version: 37,
153022
+ description: "emergency drain catch-up latch + historian drain failure backoff",
153023
+ up: (db) => {
153024
+ const hasSessionMeta = db.prepare("SELECT 1 FROM sqlite_master WHERE type='table' AND name='session_meta'").get();
153025
+ if (!hasSessionMeta)
153026
+ return;
153027
+ ensureColumn(db, "session_meta", "emergency_drain_active", "INTEGER NOT NULL DEFAULT 0");
153028
+ ensureColumn(db, "session_meta", "historian_drain_failure_at", "INTEGER NOT NULL DEFAULT 0");
153029
+ }
153030
+ },
153031
+ {
153032
+ version: 38,
153033
+ description: "durable transform decisions for cache-event cause attribution",
153034
+ up: (db) => {
153035
+ db.exec(`
153036
+ CREATE TABLE IF NOT EXISTS transform_decisions (
153037
+ session_id TEXT NOT NULL,
153038
+ harness TEXT NOT NULL DEFAULT 'opencode',
153039
+ message_id TEXT NOT NULL,
153040
+ ts_ms INTEGER NOT NULL,
153041
+ decision TEXT NOT NULL,
153042
+ materialized INTEGER NOT NULL DEFAULT 0,
153043
+ materialize_reason TEXT,
153044
+ emergency INTEGER NOT NULL DEFAULT 0,
153045
+ dropped_tokens INTEGER NOT NULL DEFAULT 0,
153046
+ dropped_count INTEGER NOT NULL DEFAULT 0,
153047
+ input_tokens INTEGER NOT NULL DEFAULT 0,
153048
+ PRIMARY KEY (session_id, harness, message_id)
153049
+ );
153050
+ CREATE INDEX IF NOT EXISTS idx_transform_decisions_session_harness
153051
+ ON transform_decisions(session_id, harness);
153052
+ `);
153053
+ }
153033
153054
  }
153034
153055
  ];
153035
153056
  LATEST_MIGRATION_VERSION = MIGRATIONS.reduce((max, m) => Math.max(max, m.version), 0);
@@ -153434,7 +153455,9 @@ function toProtectedTailMeta(row) {
153434
153455
  protectedTailDrainTokens: numberOr(r.protected_tail_drain_tokens, 0),
153435
153456
  recoveryNoEligibleHeadCount: numberOr(r.recovery_no_eligible_head_count, 0),
153436
153457
  forceEmergencyBypassWindowStart: numberOr(r.force_emergency_bypass_window_start, 0),
153437
- forceEmergencyBypassUsed: numberOr(r.force_emergency_bypass_used, 0)
153458
+ forceEmergencyBypassUsed: numberOr(r.force_emergency_bypass_used, 0),
153459
+ emergencyDrainActive: numberOr(r.emergency_drain_active, 0),
153460
+ historianDrainFailureAt: numberOr(r.historian_drain_failure_at, 0)
153438
153461
  };
153439
153462
  }
153440
153463
  function loadProtectedTailMeta(db, sessionId) {
@@ -153442,7 +153465,7 @@ function loadProtectedTailMeta(db, sessionId) {
153442
153465
  const row = db.prepare(`SELECT prior_boundary_ordinal, protected_tail_policy_version,
153443
153466
  protected_tail_drain_window_started_at, protected_tail_drain_tokens,
153444
153467
  recovery_no_eligible_head_count, force_emergency_bypass_window_start,
153445
- force_emergency_bypass_used
153468
+ force_emergency_bypass_used, emergency_drain_active, historian_drain_failure_at
153446
153469
  FROM session_meta WHERE session_id = ?`).get(sessionId);
153447
153470
  return toProtectedTailMeta(row);
153448
153471
  }
@@ -153491,6 +153514,12 @@ function protectedTailWindowBudget(usagePercentage, usable, perRunCap) {
153491
153514
  return Math.min(750000, Math.max(3 * perRunCap, Math.round(0.35 * usable)));
153492
153515
  return Math.min(500000, Math.max(perRunCap, Math.round(0.2 * usable)));
153493
153516
  }
153517
+ function emergencyDrainExitThreshold(executeThresholdPercentage) {
153518
+ if (!Number.isFinite(executeThresholdPercentage) || executeThresholdPercentage <= 0) {
153519
+ return EMERGENCY_DRAIN_FALLBACK_EXIT_PERCENTAGE;
153520
+ }
153521
+ return Math.max(0, executeThresholdPercentage - EMERGENCY_DRAIN_EXIT_MARGIN);
153522
+ }
153494
153523
  function reserveProtectedTailDrainTokens(args) {
153495
153524
  const now = args.now ?? Date.now();
153496
153525
  const requested = Math.max(0, Math.floor(args.trueRawTokens));
@@ -153509,18 +153538,30 @@ function reserveProtectedTailDrainTokens(args) {
153509
153538
  let meta3 = loadProtectedTailMeta(args.db, args.sessionId);
153510
153539
  if (now - meta3.protectedTailDrainWindowStartedAt > DRAIN_WINDOW_MS) {
153511
153540
  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);
153541
+ SET protected_tail_drain_window_started_at = ?, protected_tail_drain_tokens = 0
153542
+ WHERE session_id = ?`).run(now, args.sessionId);
153515
153543
  meta3 = loadProtectedTailMeta(args.db, args.sessionId);
153516
153544
  }
153545
+ const exitThreshold = emergencyDrainExitThreshold(args.executeThresholdPercentage);
153546
+ let latchActiveSince = meta3.emergencyDrainActive;
153547
+ if (args.usagePercentage >= EMERGENCY_DRAIN_ENTER_PERCENTAGE) {
153548
+ if (latchActiveSince <= 0)
153549
+ latchActiveSince = now;
153550
+ } else if (latchActiveSince > 0) {
153551
+ const expired = now - latchActiveSince > EMERGENCY_DRAIN_MAX_LATCH_MS;
153552
+ if (args.usagePercentage < exitThreshold || expired)
153553
+ latchActiveSince = 0;
153554
+ }
153555
+ if (latchActiveSince !== meta3.emergencyDrainActive) {
153556
+ args.db.prepare("UPDATE session_meta SET emergency_drain_active = ? WHERE session_id = ?").run(latchActiveSince, args.sessionId);
153557
+ }
153558
+ const latchActive = latchActiveSince > 0;
153517
153559
  const budget = protectedTailWindowBudget(args.usagePercentage, args.usable, args.perRunCap);
153518
153560
  const remaining = Math.max(0, budget - meta3.protectedTailDrainTokens);
153519
153561
  let reserved = Math.min(requested, args.perRunCap, remaining);
153520
153562
  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) {
153563
+ const inFailureBackoff = meta3.historianDrainFailureAt > 0 && now - meta3.historianDrainFailureAt < EMERGENCY_DRAIN_FAILURE_BACKOFF_MS;
153564
+ if (reserved <= 0 && latchActive && !inFailureBackoff) {
153524
153565
  reserved = Math.min(requested, args.perRunCap);
153525
153566
  bypass = true;
153526
153567
  }
@@ -153528,10 +153569,8 @@ function reserveProtectedTailDrainTokens(args) {
153528
153569
  return;
153529
153570
  args.db.prepare(`UPDATE session_meta
153530
153571
  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);
153572
+ protected_tail_drain_tokens = COALESCE(protected_tail_drain_tokens, 0) + ?
153573
+ WHERE session_id = ?`).run(now, reserved, args.sessionId);
153535
153574
  result = {
153536
153575
  ok: true,
153537
153576
  reservedTokens: reserved,
@@ -153541,6 +153580,25 @@ function reserveProtectedTailDrainTokens(args) {
153541
153580
  })();
153542
153581
  return result;
153543
153582
  }
153583
+ function clearEmergencyDrainLatch(db, sessionId) {
153584
+ db.transaction(() => {
153585
+ ensureSessionMetaRow(db, sessionId);
153586
+ db.prepare("UPDATE session_meta SET emergency_drain_active = 0 WHERE session_id = ?").run(sessionId);
153587
+ })();
153588
+ }
153589
+ function recordHistorianDrainFailure(db, sessionId, now) {
153590
+ const ts = now ?? Date.now();
153591
+ db.transaction(() => {
153592
+ ensureSessionMetaRow(db, sessionId);
153593
+ db.prepare("UPDATE session_meta SET historian_drain_failure_at = ? WHERE session_id = ?").run(ts, sessionId);
153594
+ })();
153595
+ }
153596
+ function clearHistorianDrainFailure(db, sessionId) {
153597
+ db.transaction(() => {
153598
+ ensureSessionMetaRow(db, sessionId);
153599
+ db.prepare("UPDATE session_meta SET historian_drain_failure_at = 0 WHERE session_id = ?").run(sessionId);
153600
+ })();
153601
+ }
153544
153602
  function rollbackProtectedTailDrainReservation(db, reservation) {
153545
153603
  if (!reservation || reservation.tokens <= 0)
153546
153604
  return;
@@ -154108,7 +154166,7 @@ function setSessionWorkMetrics(db, sessionId, newWorkTokens, totalInputTokens) {
154108
154166
  SET new_work_tokens = ?, total_input_tokens = ?
154109
154167
  WHERE session_id = ?`).run(Math.max(0, Math.floor(newWorkTokens)), Math.max(0, Math.floor(totalInputTokens)), sessionId);
154110
154168
  }
154111
- var CAS_RETRY_LIMIT = 5, AUTO_SEARCH_NO_HINT_REASONS, DEFAULT_PROTECTED_TAIL_META, DRAIN_WINDOW_MS;
154169
+ 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
154170
  var init_storage_meta_persisted = __esm(() => {
154113
154171
  init_logger();
154114
154172
  init_storage_meta_shared();
@@ -154127,9 +154185,12 @@ var init_storage_meta_persisted = __esm(() => {
154127
154185
  protectedTailDrainTokens: 0,
154128
154186
  recoveryNoEligibleHeadCount: 0,
154129
154187
  forceEmergencyBypassWindowStart: 0,
154130
- forceEmergencyBypassUsed: 0
154188
+ forceEmergencyBypassUsed: 0,
154189
+ emergencyDrainActive: 0,
154190
+ historianDrainFailureAt: 0
154131
154191
  };
154132
154192
  DRAIN_WINDOW_MS = 10 * 60 * 1000;
154193
+ EMERGENCY_DRAIN_MAX_LATCH_MS = 30 * 60 * 1000;
154133
154194
  });
154134
154195
 
154135
154196
  // src/features/magic-context/resolve-subagent-fallback.ts
@@ -154247,6 +154308,7 @@ function clearSession(db, sessionId) {
154247
154308
  db.prepare("DELETE FROM subagent_invocations WHERE session_id = ?").run(sessionId);
154248
154309
  db.prepare("DELETE FROM historian_runs WHERE session_id = ?").run(sessionId);
154249
154310
  db.prepare("DELETE FROM plugin_messages WHERE session_id = ?").run(sessionId);
154311
+ db.prepare("DELETE FROM transform_decisions WHERE session_id = ?").run(sessionId);
154250
154312
  clearIndexedMessages(db, sessionId);
154251
154313
  })();
154252
154314
  }
@@ -154692,12 +154754,17 @@ function getOldestActiveUnprotectedToolTags(db, sessionId, protectedTags = 0, li
154692
154754
  toolName: typeof row.tool_name === "string" ? row.tool_name : null
154693
154755
  }));
154694
154756
  }
154695
- function getTriggerTagTokenUpperBound(db, sessionId) {
154696
- const row = db.prepare(`SELECT
154757
+ function getTriggerTagTokenUpperBound(db, sessionId, floor = 0) {
154758
+ const sql = floor > 0 ? `SELECT
154697
154759
  COALESCE(SUM(COALESCE(token_count, 0) + COALESCE(input_token_count, 0) + COALESCE(reasoning_token_count, 0)), 0) AS bound,
154698
154760
  COALESCE(SUM(CASE WHEN token_count IS NULL THEN 1 ELSE 0 END), 0) AS null_count
154699
154761
  FROM tags
154700
- WHERE session_id = ? AND status IN ('active', 'dropped')`).get(sessionId);
154762
+ WHERE session_id = ? AND status IN ('active', 'dropped') AND tag_number >= ?` : `SELECT
154763
+ COALESCE(SUM(COALESCE(token_count, 0) + COALESCE(input_token_count, 0) + COALESCE(reasoning_token_count, 0)), 0) AS bound,
154764
+ COALESCE(SUM(CASE WHEN token_count IS NULL THEN 1 ELSE 0 END), 0) AS null_count
154765
+ FROM tags
154766
+ WHERE session_id = ? AND status IN ('active', 'dropped')`;
154767
+ const row = floor > 0 ? db.prepare(sql).get(sessionId, floor) : db.prepare(sql).get(sessionId);
154701
154768
  return { bound: row?.bound ?? 0, nullCount: row?.null_count ?? 0 };
154702
154769
  }
154703
154770
  function getActiveTagTokenTotalsByMessage(db, sessionId) {
@@ -154726,10 +154793,12 @@ function getActiveTagTokenTotalsByMessage(db, sessionId) {
154726
154793
  }
154727
154794
  return out;
154728
154795
  }
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);
154796
+ function getAllStatusTagTokenTotalsFlat(db, sessionId, floor = 0) {
154797
+ const rows = floor > 0 ? db.prepare(`SELECT type, message_id, tool_owner_message_id, token_count, input_token_count, reasoning_token_count
154798
+ FROM tags
154799
+ 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
154800
+ FROM tags
154801
+ WHERE session_id = ?`).all(sessionId);
154733
154802
  const totals = new Map;
154734
154803
  const nullMessageIds = new Set;
154735
154804
  for (const row of rows) {
@@ -154888,6 +154957,47 @@ function getTagNumberByMessageId(db, sessionId, messageId) {
154888
154957
  const row = getTagNumberByMessageIdStatement(db).get(sessionId, messageId);
154889
154958
  return isTagNumberRow(row) ? row.tag_number : null;
154890
154959
  }
154960
+ function isMinTagNumberRow(row) {
154961
+ return row !== null && typeof row === "object" && "m" in row;
154962
+ }
154963
+ function getMinMessageTagNumberForRawId(db, sessionId, rawId) {
154964
+ if (rawId.includes(":"))
154965
+ return null;
154966
+ let stmt = getMinMessageTagNumberForRawIdStatements.get(db);
154967
+ if (!stmt) {
154968
+ stmt = db.prepare("SELECT MIN(tag_number) AS m FROM tags WHERE session_id = ? AND message_id >= ? AND message_id < ?");
154969
+ getMinMessageTagNumberForRawIdStatements.set(db, stmt);
154970
+ }
154971
+ const row = stmt.get(sessionId, `${rawId}:`, `${rawId};`);
154972
+ return isMinTagNumberRow(row) && typeof row.m === "number" ? row.m : null;
154973
+ }
154974
+ function deriveTagLoadFloor(db, sessionId, rawIds) {
154975
+ let min = Number.POSITIVE_INFINITY;
154976
+ let probes = 0;
154977
+ let hits = 0;
154978
+ let skippedBeforeFirstHit = 0;
154979
+ for (const rawId of rawIds) {
154980
+ if (typeof rawId !== "string" || rawId.length === 0)
154981
+ continue;
154982
+ if (probes >= TAGGER_FLOOR_MAX_PROBES)
154983
+ break;
154984
+ probes++;
154985
+ const m = getMinMessageTagNumberForRawId(db, sessionId, rawId);
154986
+ if (m === null) {
154987
+ if (hits === 0)
154988
+ skippedBeforeFirstHit++;
154989
+ continue;
154990
+ }
154991
+ if (m < min)
154992
+ min = m;
154993
+ if (++hits >= TAGGER_FLOOR_SCAN_MESSAGES)
154994
+ break;
154995
+ }
154996
+ if (!Number.isFinite(min))
154997
+ return 0;
154998
+ const margin = TAGGER_FLOOR_SAFETY_MARGIN + skippedBeforeFirstHit * TAGGER_FLOOR_PER_SKIP_MARGIN;
154999
+ return Math.max(0, min - margin);
155000
+ }
154891
155001
  function getTagsBySession(db, sessionId) {
154892
155002
  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
155003
  return rows.map(toTagEntry);
@@ -155026,7 +155136,7 @@ function deleteToolTagsByOwner(db, sessionId, ownerMsgId) {
155026
155136
  const result = getDeleteToolTagsByOwnerStatement(db).run(sessionId, ownerMsgId);
155027
155137
  return result.changes ?? 0;
155028
155138
  }
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;
155139
+ 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
155140
  var init_storage_tags = __esm(() => {
155031
155141
  insertTagStatements = new WeakMap;
155032
155142
  updateTagStatusStatements = new WeakMap;
@@ -155042,6 +155152,7 @@ var init_storage_tags = __esm(() => {
155042
155152
  updateTagTokenCountStatements = new WeakMap;
155043
155153
  updateTagInputTokenCountStatements = new WeakMap;
155044
155154
  getOwnerScopedToolTagNumbersStatements = new WeakMap;
155155
+ getMinMessageTagNumberForRawIdStatements = new WeakMap;
155045
155156
  getActiveTagsBySessionStatements = new WeakMap;
155046
155157
  getMaxDroppedTagNumberStatements = new WeakMap;
155047
155158
  getToolTagNumberByOwnerStatements = new WeakMap;
@@ -165462,6 +165573,16 @@ function buildCanonicalChunkTextFromFts(db, sessionId, startOrdinal, endOrdinal)
165462
165573
  return lines.join(`
165463
165574
  `);
165464
165575
  }
165576
+ function buildCompartmentSummaryFallbackText(db, compartmentId) {
165577
+ const row = db.prepare("SELECT title, p1, content FROM compartments WHERE id = ?").get(compartmentId);
165578
+ if (!row)
165579
+ return "";
165580
+ const title = typeof row.title === "string" ? row.title.trim() : "";
165581
+ const p1 = typeof row.p1 === "string" ? row.p1.trim() : "";
165582
+ const body = p1.length > 0 ? p1 : typeof row.content === "string" ? row.content.trim() : "";
165583
+ return [title, body].filter((s) => s.length > 0).join(`
165584
+ `);
165585
+ }
165465
165586
  function canonicalizeInMemoryChunkTextForEmbedding(chunkText, startOrdinal, endOrdinal) {
165466
165587
  const lines = [];
165467
165588
  for (const rawLine of chunkText.split(/\r?\n/)) {
@@ -165774,386 +165895,16 @@ function getEmbeddingProviderIdentity(config2) {
165774
165895
  endpoint: normalizeEndpoint2(config2.endpoint),
165775
165896
  apiKeyPresent: Boolean(config2.api_key?.trim()),
165776
165897
  inputType: config2.input_type?.trim() || ""
165777
- } : {
165778
- provider: "local",
165779
- model: config2.model?.trim() || DEFAULT_LOCAL_EMBEDDING_MODEL,
165780
- endpoint: "",
165781
- apiKeyPresent: false
165782
- };
165898
+ } : null;
165899
+ if (!identityInput) {
165900
+ return "embedding-provider:off";
165901
+ }
165783
165902
  return `embedding-provider:${computeNormalizedHash(JSON.stringify(identityInput))}`;
165784
165903
  }
165785
165904
  var init_embedding_identity = __esm(() => {
165786
- init_magic_context();
165787
165905
  init_normalize_hash();
165788
165906
  });
165789
165907
 
165790
- // src/features/magic-context/memory/embedding-local.ts
165791
- import { mkdirSync as mkdirSync3 } from "node:fs";
165792
- import { open, stat, unlink, writeFile } from "node:fs/promises";
165793
- import { dirname as dirname4, join as join13 } from "node:path";
165794
- import { pathToFileURL } from "node:url";
165795
- async function acquireModelLoadLock(lockPath) {
165796
- const waitStart = Date.now();
165797
- while (true) {
165798
- try {
165799
- const handle = await open(lockPath, "wx");
165800
- try {
165801
- await handle.writeFile(`pid=${process.pid} started=${Date.now()}
165802
- `);
165803
- } catch {}
165804
- await handle.close();
165805
- return async () => {
165806
- try {
165807
- await unlink(lockPath);
165808
- } catch {}
165809
- };
165810
- } catch (error51) {
165811
- const code = error51.code;
165812
- if (code !== "EEXIST" && code !== "EPERM") {
165813
- throw error51;
165814
- }
165815
- try {
165816
- const info = await stat(lockPath);
165817
- if (Date.now() - info.mtimeMs > STALE_LOCK_MS) {
165818
- log(`[magic-context] embedding-load lock stale (>${STALE_LOCK_MS}ms), taking over`);
165819
- try {
165820
- await unlink(lockPath);
165821
- } catch {}
165822
- continue;
165823
- }
165824
- } catch {
165825
- continue;
165826
- }
165827
- if (Date.now() - waitStart > MAX_LOCK_WAIT_MS) {
165828
- throw new Error(`[magic-context] embedding-load lock wait exceeded ${MAX_LOCK_WAIT_MS}ms; another process is still loading the model. Skipping this init attempt to avoid an unsynchronized native load.`);
165829
- }
165830
- await new Promise((resolve6) => setTimeout(resolve6, LOCK_POLL_MS));
165831
- }
165832
- }
165833
- }
165834
- function startLockHeartbeat(lockPath) {
165835
- const HEARTBEAT_MS = Math.floor(STALE_LOCK_MS / 3);
165836
- const timer = setInterval(() => {
165837
- writeFile(lockPath, `pid=${process.pid} alive=${Date.now()}
165838
- `).catch(() => {});
165839
- }, HEARTBEAT_MS);
165840
- timer.unref?.();
165841
- return () => clearInterval(timer);
165842
- }
165843
- async function injectWasmOrtForElectron() {
165844
- if (typeof process === "undefined" || !process.versions?.electron) {
165845
- return false;
165846
- }
165847
- try {
165848
- const ortWebSpec = `onnxruntime-${"web"}`;
165849
- const ortWeb = await import(ortWebSpec);
165850
- try {
165851
- const { createRequire: createRequireFn } = await import("node:module");
165852
- const requireFn = createRequireFn(import.meta.url);
165853
- const pkgPath = requireFn.resolve("onnxruntime-web/package.json");
165854
- const distDir = join13(dirname4(pkgPath), "dist");
165855
- const wasmPathsPrefix = `${pathToFileURL(distDir).href}/`;
165856
- if (ortWeb.env?.wasm) {
165857
- ortWeb.env.wasm.wasmPaths = wasmPathsPrefix;
165858
- }
165859
- } catch (pathError) {
165860
- log("[magic-context] could not resolve local onnxruntime-web/dist, falling back to default WASM paths:", pathError instanceof Error ? pathError.message : String(pathError));
165861
- }
165862
- globalThis[Symbol.for("onnxruntime")] = ortWeb;
165863
- log("[magic-context] Electron detected — using onnxruntime-web (WASM) for embeddings (bypasses onnxruntime-node native load)");
165864
- return true;
165865
- } catch (error51) {
165866
- log("[magic-context] failed to inject onnxruntime-web for Electron — letting transformers fall back to native:", error51 instanceof Error ? error51.message : String(error51));
165867
- return false;
165868
- }
165869
- }
165870
- async function withQuietConsole(fn) {
165871
- const origWarn = console.warn;
165872
- const origError = console.error;
165873
- const redirect = (...args) => {
165874
- const message = args.map((a) => typeof a === "string" ? a : String(a)).join(" ");
165875
- log(`[transformers] ${message}`);
165876
- };
165877
- console.warn = redirect;
165878
- console.error = redirect;
165879
- try {
165880
- return await fn();
165881
- } finally {
165882
- console.warn = origWarn;
165883
- console.error = origError;
165884
- }
165885
- }
165886
- function isNativeRuntimeMissingError(error51) {
165887
- const message = error51 instanceof Error ? error51.message : String(error51 ?? "");
165888
- const lower = message.toLowerCase();
165889
- const code = error51?.code;
165890
- const name2 = error51?.name;
165891
- if (code === "ERR_DLOPEN_FAILED" && lower.includes("onnxruntime")) {
165892
- return true;
165893
- }
165894
- if (!lower.includes("onnxruntime-node"))
165895
- return false;
165896
- return code === "ERR_MODULE_NOT_FOUND" || name2 === "ResolveMessage" || lower.includes("cannot find package") || lower.includes("cannot find module") || lower.includes("err_module_not_found");
165897
- }
165898
- function isTransientLoadError(error51) {
165899
- const message = error51 instanceof Error ? error51.message : String(error51 ?? "");
165900
- if (!message)
165901
- return false;
165902
- const lower = message.toLowerCase();
165903
- return lower.includes("protobuf parsing failed") || lower.includes("unable to get model file path or buffer") || lower.includes("ebusy") || lower.includes("resource busy") || lower.includes("resource temporarily unavailable");
165904
- }
165905
- function isArrayLikeNumber(value) {
165906
- if (typeof value !== "object" || value === null || !("length" in value)) {
165907
- return false;
165908
- }
165909
- const arr = value;
165910
- if (typeof arr.length !== "number") {
165911
- return false;
165912
- }
165913
- return arr.length === 0 || typeof arr[0] === "number";
165914
- }
165915
- function toFloat32Array3(values) {
165916
- return values instanceof Float32Array ? new Float32Array(values) : Float32Array.from(Array.from(values));
165917
- }
165918
- function extractBatchEmbeddings(result, expectedCount) {
165919
- const { data } = result;
165920
- if (Array.isArray(data) && data.length === expectedCount && data.every((entry) => typeof entry !== "number" && isArrayLikeNumber(entry))) {
165921
- return data.map((entry) => toFloat32Array3(entry));
165922
- }
165923
- if (!isArrayLikeNumber(data)) {
165924
- log("[magic-context] embedding batch returned unexpected data shape");
165925
- return Array.from({ length: expectedCount }, () => null);
165926
- }
165927
- const flatData = toFloat32Array3(data);
165928
- const dimension = result.dims?.at(-1) ?? flatData.length / expectedCount;
165929
- if (!Number.isInteger(dimension) || dimension <= 0 || flatData.length !== expectedCount * dimension) {
165930
- log("[magic-context] embedding batch returned invalid dimensions");
165931
- return Array.from({ length: expectedCount }, () => null);
165932
- }
165933
- const embeddings = [];
165934
- for (let index = 0;index < expectedCount; index++) {
165935
- embeddings.push(flatData.slice(index * dimension, (index + 1) * dimension));
165936
- }
165937
- return embeddings;
165938
- }
165939
-
165940
- class LocalEmbeddingProvider {
165941
- modelId;
165942
- maxInputTokens;
165943
- model;
165944
- pipeline = null;
165945
- initPromise = null;
165946
- inFlight = 0;
165947
- disposing = false;
165948
- disposePromise = null;
165949
- inFlightWaiters = [];
165950
- constructor(model = DEFAULT_LOCAL_EMBEDDING_MODEL, maxInputTokens = 512) {
165951
- this.model = model;
165952
- this.maxInputTokens = maxInputTokens;
165953
- this.modelId = getEmbeddingProviderIdentity({ provider: "local", model });
165954
- }
165955
- async initialize() {
165956
- if (this.disposing) {
165957
- return false;
165958
- }
165959
- if (this.pipeline) {
165960
- return true;
165961
- }
165962
- if (nativeRuntimeMissing) {
165963
- return false;
165964
- }
165965
- if (this.initPromise) {
165966
- await this.initPromise;
165967
- return this.pipeline !== null;
165968
- }
165969
- this.initPromise = (async () => {
165970
- try {
165971
- if (this.disposing) {
165972
- return;
165973
- }
165974
- await injectWasmOrtForElectron();
165975
- const transformersSpec = "@huggingface/transformers";
165976
- const transformersModule = await import(transformersSpec);
165977
- const env = transformersModule.env;
165978
- const LogLevel = transformersModule.LogLevel;
165979
- if (LogLevel && "ERROR" in LogLevel) {
165980
- env.logLevel = LogLevel.ERROR;
165981
- }
165982
- const modelCacheDir = join13(getMagicContextStorageDir(), "models");
165983
- try {
165984
- mkdirSync3(modelCacheDir, { recursive: true });
165985
- env.cacheDir = modelCacheDir;
165986
- } catch {
165987
- log("[magic-context] could not create model cache dir, using library default");
165988
- }
165989
- const createPipeline = transformersModule.pipeline;
165990
- const lockPath = join13(modelCacheDir, ".load.lock");
165991
- const releaseLock = await acquireModelLoadLock(lockPath);
165992
- const stopHeartbeat = startLockHeartbeat(lockPath);
165993
- try {
165994
- const MAX_ATTEMPTS = 3;
165995
- let lastError;
165996
- for (let attempt = 1;attempt <= MAX_ATTEMPTS; attempt++) {
165997
- try {
165998
- const pipeline = await withQuietConsole(() => createPipeline("feature-extraction", this.model, {
165999
- dtype: "fp32"
166000
- }));
166001
- if (this.disposing) {
166002
- await pipeline.dispose?.();
166003
- this.pipeline = null;
166004
- } else {
166005
- this.pipeline = pipeline;
166006
- }
166007
- lastError = undefined;
166008
- break;
166009
- } catch (error51) {
166010
- lastError = error51;
166011
- if (!isTransientLoadError(error51) || attempt === MAX_ATTEMPTS) {
166012
- break;
166013
- }
166014
- const delayMs = 300 * attempt + Math.floor(Math.random() * 200);
166015
- log(`[magic-context] embedding model load attempt ${attempt}/${MAX_ATTEMPTS} failed transiently, retrying in ${delayMs}ms`);
166016
- await new Promise((resolve6) => setTimeout(resolve6, delayMs));
166017
- }
166018
- }
166019
- if (this.pipeline) {
166020
- log(`[magic-context] embedding model loaded: ${this.model}`);
166021
- } else if (this.disposing) {
166022
- return;
166023
- } else {
166024
- throw lastError ?? new Error("unknown embedding load failure");
166025
- }
166026
- } finally {
166027
- stopHeartbeat();
166028
- await releaseLock();
166029
- }
166030
- } catch (error51) {
166031
- if (isNativeRuntimeMissingError(error51)) {
166032
- nativeRuntimeMissing = true;
166033
- log("[magic-context] local embedding runtime is not installed (onnxruntime-node missing from this install). Local embeddings are disabled. Fix: reinstall the plugin (run `npx @wolfx/magic-context@latest doctor --force`), or configure an `openai-compatible`/`ollama` embedding endpoint instead. Existing memories are unaffected.");
166034
- } else {
166035
- log("[magic-context] embedding model failed to load:", error51);
166036
- }
166037
- this.pipeline = null;
166038
- } finally {
166039
- this.initPromise = null;
166040
- }
166041
- })();
166042
- await this.initPromise;
166043
- return this.pipeline !== null;
166044
- }
166045
- waitForInFlightToDrain() {
166046
- if (this.inFlight === 0) {
166047
- return Promise.resolve();
166048
- }
166049
- return new Promise((resolve6) => {
166050
- this.inFlightWaiters.push(resolve6);
166051
- });
166052
- }
166053
- finishInFlight() {
166054
- this.inFlight = Math.max(0, this.inFlight - 1);
166055
- if (this.inFlight !== 0)
166056
- return;
166057
- const waiters = this.inFlightWaiters.splice(0);
166058
- for (const waiter of waiters) {
166059
- waiter();
166060
- }
166061
- }
166062
- async embed(text, signal) {
166063
- if (signal?.aborted)
166064
- return null;
166065
- if (this.disposing)
166066
- return null;
166067
- this.inFlight += 1;
166068
- try {
166069
- if (!await this.initialize()) {
166070
- return null;
166071
- }
166072
- const pipeline = this.pipeline;
166073
- if (!pipeline) {
166074
- return null;
166075
- }
166076
- const result = await withQuietConsole(() => pipeline(text, {
166077
- pooling: "mean",
166078
- normalize: true
166079
- }));
166080
- return extractBatchEmbeddings(result, 1)[0] ?? null;
166081
- } catch (error51) {
166082
- log("[magic-context] embedding failed:", error51);
166083
- return null;
166084
- } finally {
166085
- this.finishInFlight();
166086
- }
166087
- }
166088
- async embedBatch(texts, signal) {
166089
- if (texts.length === 0) {
166090
- return [];
166091
- }
166092
- if (signal?.aborted) {
166093
- return Array.from({ length: texts.length }, () => null);
166094
- }
166095
- if (this.disposing) {
166096
- return Array.from({ length: texts.length }, () => null);
166097
- }
166098
- this.inFlight += 1;
166099
- try {
166100
- if (!await this.initialize()) {
166101
- return Array.from({ length: texts.length }, () => null);
166102
- }
166103
- const pipeline = this.pipeline;
166104
- if (!pipeline) {
166105
- return Array.from({ length: texts.length }, () => null);
166106
- }
166107
- const result = await withQuietConsole(() => pipeline(texts, {
166108
- pooling: "mean",
166109
- normalize: true
166110
- }));
166111
- return extractBatchEmbeddings(result, texts.length);
166112
- } catch (error51) {
166113
- log("[magic-context] embedding batch failed:", error51);
166114
- return Array.from({ length: texts.length }, () => null);
166115
- } finally {
166116
- this.finishInFlight();
166117
- }
166118
- }
166119
- async dispose() {
166120
- if (this.disposePromise) {
166121
- return this.disposePromise;
166122
- }
166123
- this.disposing = true;
166124
- this.disposePromise = (async () => {
166125
- if (this.initPromise) {
166126
- await this.initPromise;
166127
- }
166128
- await this.waitForInFlightToDrain();
166129
- const pipelineToDispose = this.pipeline;
166130
- this.pipeline = null;
166131
- this.initPromise = null;
166132
- if (!pipelineToDispose) {
166133
- return;
166134
- }
166135
- try {
166136
- await pipelineToDispose.dispose?.();
166137
- } catch (error51) {
166138
- log("[magic-context] embedding model dispose failed:", error51);
166139
- }
166140
- })();
166141
- return this.disposePromise;
166142
- }
166143
- isLoaded() {
166144
- return this.pipeline !== null;
166145
- }
166146
- }
166147
- var LOCK_POLL_MS = 150, STALE_LOCK_MS, MAX_LOCK_WAIT_MS, nativeRuntimeMissing = false;
166148
- var init_embedding_local = __esm(() => {
166149
- init_magic_context();
166150
- init_data_path();
166151
- init_logger();
166152
- init_embedding_identity();
166153
- STALE_LOCK_MS = 3 * 60000;
166154
- MAX_LOCK_WAIT_MS = 5 * 60000;
166155
- });
166156
-
166157
165908
  // src/features/magic-context/memory/embedding-ssrf.ts
166158
165909
  function isLinkLocalIpv4(host) {
166159
165910
  return /^169\.254\.\d{1,3}\.\d{1,3}$/.test(host);
@@ -166229,6 +165980,7 @@ class OpenAICompatibleEmbeddingProvider {
166229
165980
  model;
166230
165981
  apiKey;
166231
165982
  inputType;
165983
+ queryInputType;
166232
165984
  truncate;
166233
165985
  initialized = false;
166234
165986
  failureTimes = [];
@@ -166241,6 +165993,7 @@ class OpenAICompatibleEmbeddingProvider {
166241
165993
  this.model = options.model?.trim() ?? "";
166242
165994
  this.apiKey = options.apiKey?.trim() ?? "";
166243
165995
  this.inputType = options.inputType?.trim() ?? "";
165996
+ this.queryInputType = options.queryInputType?.trim() ?? "";
166244
165997
  this.truncate = options.truncate?.trim() ?? "";
166245
165998
  this.maxInputTokens = typeof options.maxInputTokens === "number" && Number.isFinite(options.maxInputTokens) ? Math.max(1, Math.floor(options.maxInputTokens)) : 512;
166246
165999
  this.modelId = getEmbeddingProviderIdentity({
@@ -166268,11 +166021,17 @@ class OpenAICompatibleEmbeddingProvider {
166268
166021
  this.initialized = true;
166269
166022
  return true;
166270
166023
  }
166271
- async embed(text, signal) {
166272
- const [embedding] = await this.embedBatch([text], signal);
166024
+ resolveInputTypeForPurpose(purpose = "passage") {
166025
+ if (purpose === "query") {
166026
+ return this.queryInputType || this.inputType;
166027
+ }
166028
+ return this.inputType;
166029
+ }
166030
+ async embed(text, signal, purpose) {
166031
+ const [embedding] = await this.embedBatch([text], signal, purpose);
166273
166032
  return embedding ?? null;
166274
166033
  }
166275
- async embedBatch(texts, signal) {
166034
+ async embedBatch(texts, signal, purpose) {
166276
166035
  if (texts.length === 0) {
166277
166036
  return [];
166278
166037
  }
@@ -166298,6 +166057,7 @@ class OpenAICompatibleEmbeddingProvider {
166298
166057
  if (signal) {
166299
166058
  signal.addEventListener("abort", onOuterAbort, { once: true });
166300
166059
  }
166060
+ const inputTypeForRequest = this.resolveInputTypeForPurpose(purpose);
166301
166061
  const response = await fetch(`${this.endpoint}/embeddings`, {
166302
166062
  method: "POST",
166303
166063
  headers: {
@@ -166307,7 +166067,7 @@ class OpenAICompatibleEmbeddingProvider {
166307
166067
  body: JSON.stringify({
166308
166068
  model: this.model,
166309
166069
  input: texts,
166310
- ...this.inputType ? { input_type: this.inputType } : {},
166070
+ ...inputTypeForRequest ? { input_type: inputTypeForRequest } : {},
166311
166071
  ...this.truncate ? { truncate: this.truncate } : {}
166312
166072
  }),
166313
166073
  redirect: "error",
@@ -166872,18 +166632,13 @@ var init_session_project_storage = __esm(() => {
166872
166632
  // src/features/magic-context/project-embedding-registry.ts
166873
166633
  import { createHash as createHash9, randomUUID } from "node:crypto";
166874
166634
  function resolveEmbeddingConfig(config2) {
166875
- if (!config2 || config2.provider === "local") {
166876
- return {
166877
- provider: "local",
166878
- model: config2?.model?.trim() || DEFAULT_LOCAL_EMBEDDING_MODEL,
166879
- ...config2?.max_input_tokens ? {
166880
- max_input_tokens: normalizeCompartmentChunkMaxInputTokens(config2.max_input_tokens)
166881
- } : {}
166882
- };
166635
+ if (!config2 || config2.provider === "off") {
166636
+ return { provider: "off" };
166883
166637
  }
166884
166638
  if (config2.provider === "openai-compatible") {
166885
166639
  const apiKey = config2.api_key?.trim();
166886
166640
  const inputType = config2.input_type?.trim();
166641
+ const queryInputType = config2.query_input_type?.trim();
166887
166642
  const truncate = config2.truncate?.trim();
166888
166643
  return {
166889
166644
  provider: "openai-compatible",
@@ -166891,6 +166646,7 @@ function resolveEmbeddingConfig(config2) {
166891
166646
  endpoint: config2.endpoint.trim(),
166892
166647
  ...apiKey ? { api_key: apiKey } : {},
166893
166648
  ...inputType ? { input_type: inputType } : {},
166649
+ ...queryInputType ? { query_input_type: queryInputType } : {},
166894
166650
  ...truncate ? { truncate } : {},
166895
166651
  ...config2.max_input_tokens ? {
166896
166652
  max_input_tokens: normalizeCompartmentChunkMaxInputTokens(config2.max_input_tokens)
@@ -166912,11 +166668,12 @@ function createProvider(config2) {
166912
166668
  model: config2.model,
166913
166669
  apiKey: config2.api_key,
166914
166670
  inputType: config2.input_type,
166671
+ queryInputType: config2.query_input_type,
166915
166672
  truncate: config2.truncate,
166916
166673
  maxInputTokens: config2.max_input_tokens
166917
166674
  });
166918
166675
  }
166919
- return new LocalEmbeddingProvider(config2.model, config2.max_input_tokens);
166676
+ return null;
166920
166677
  }
166921
166678
  function stableStringify2(value) {
166922
166679
  if (Array.isArray(value)) {
@@ -166968,7 +166725,7 @@ function snapshotFor(registration) {
166968
166725
  modelId: registration.observationMode || !providerIsOn ? "off" : registration.modelId,
166969
166726
  chunkModelId: registration.observationMode || !providerIsOn ? "off" : registration.chunkModelId,
166970
166727
  model: registration.observationMode || !providerIsOn ? "off" : ("model" in registration.config) && registration.config.model.trim() ? registration.config.model.trim() : registration.modelId,
166971
- provider: registration.observationMode || !providerIsOn ? "off" : registration.config.provider ?? "local"
166728
+ provider: registration.observationMode || !providerIsOn ? "off" : registration.config.provider ?? "off"
166972
166729
  };
166973
166730
  }
166974
166731
  function disposeProvider(provider) {
@@ -167094,7 +166851,7 @@ function getOrCreateProjectProvider(registration) {
167094
166851
  registration.provider = provider;
167095
166852
  return provider;
167096
166853
  }
167097
- async function embedTextForProject(projectIdentity, text, signal) {
166854
+ async function embedTextForProject(projectIdentity, text, signal, purpose = "passage") {
167098
166855
  const registration = projectRegistrations.get(projectIdentity);
167099
166856
  if (!registration)
167100
166857
  return null;
@@ -167103,7 +166860,7 @@ async function embedTextForProject(projectIdentity, text, signal) {
167103
166860
  const provider = getOrCreateProjectProvider(registration);
167104
166861
  if (!provider)
167105
166862
  return null;
167106
- const vector = await provider.embed(text, signal);
166863
+ const vector = await provider.embed(text, signal, purpose);
167107
166864
  if (!vector)
167108
166865
  return null;
167109
166866
  const current = projectRegistrations.get(projectIdentity);
@@ -167112,7 +166869,7 @@ async function embedTextForProject(projectIdentity, text, signal) {
167112
166869
  }
167113
166870
  return { vector, modelId, generation };
167114
166871
  }
167115
- async function embedBatchForProject(projectIdentity, texts, signal) {
166872
+ async function embedBatchForProject(projectIdentity, texts, signal, purpose = "passage") {
167116
166873
  if (texts.length === 0) {
167117
166874
  const registration2 = projectRegistrations.get(projectIdentity);
167118
166875
  if (!registration2 || registration2.observationMode)
@@ -167128,7 +166885,7 @@ async function embedBatchForProject(projectIdentity, texts, signal) {
167128
166885
  const provider = getOrCreateProjectProvider(registration);
167129
166886
  if (!provider)
167130
166887
  return null;
167131
- const vectors = await provider.embedBatch(texts, signal);
166888
+ const vectors = await provider.embedBatch(texts, signal, purpose);
167132
166889
  const current = projectRegistrations.get(projectIdentity);
167133
166890
  if (!current || current.generation !== generation || current.runtimeFingerprint !== runtimeFingerprint) {
167134
166891
  return null;
@@ -167185,7 +166942,7 @@ async function embedCandidateChunkBatch(db, projectIdentity, modelId, candidates
167185
166942
  const maxInputTokens = getProjectEmbeddingMaxInputTokens(projectIdentity);
167186
166943
  const prepared = [];
167187
166944
  for (const candidate of candidates) {
167188
- const canonicalText = buildCanonicalChunkTextFromFts(db, candidate.sessionId, candidate.startMessage, candidate.endMessage);
166945
+ const canonicalText = buildCanonicalChunkTextFromFts(db, candidate.sessionId, candidate.startMessage, candidate.endMessage) || buildCompartmentSummaryFallbackText(db, candidate.id);
167189
166946
  if (canonicalText.length === 0) {
167190
166947
  noWork.push(candidate.id);
167191
166948
  continue;
@@ -167377,7 +167134,6 @@ function getEmbeddingCoverageStatus(db, projectIdentity, sessionId) {
167377
167134
  }
167378
167135
  var OFF_PROVIDER_IDENTITY = "embedding-provider:off", SWEEP_MAX_WALL_CLOCK_MS, CHUNK_DRAIN_BATCH_SIZE = 8, MAX_WINDOWS_PER_EMBED_CALL = 2, SESSION_EMBED_LEASE_RENEWAL_MS, EMBED_SLICE_RETRY_ATTEMPTS = 3, EMBED_SLICE_RETRY_BASE_MS = 250, EMBED_SLOW_FAILURE_NO_RETRY_MS = 1e4, MAX_CONSECUTIVE_FAILED_BATCHES = 3, projectRegistrations, loadUnembeddedMemoriesStatements, globalRegistrationGeneration = 0, testProviderFactory = null;
167379
167136
  var init_project_embedding_registry = __esm(() => {
167380
- init_magic_context();
167381
167137
  init_logger();
167382
167138
  init_compartment_chunk_embedding();
167383
167139
  init_storage_git_commit_embeddings();
@@ -167385,7 +167141,6 @@ var init_project_embedding_registry = __esm(() => {
167385
167141
  init_sweep_coordinator();
167386
167142
  init_embedding_cache();
167387
167143
  init_embedding_identity();
167388
- init_embedding_local();
167389
167144
  init_embedding_openai();
167390
167145
  init_storage_memory_embeddings();
167391
167146
  init_session_project_storage();
@@ -167406,11 +167161,12 @@ function createProvider2(config2) {
167406
167161
  model: config2.model,
167407
167162
  apiKey: config2.api_key,
167408
167163
  inputType: config2.input_type,
167164
+ queryInputType: config2.query_input_type,
167409
167165
  truncate: config2.truncate,
167410
167166
  maxInputTokens: config2.max_input_tokens
167411
167167
  });
167412
167168
  }
167413
- return new LocalEmbeddingProvider(config2.model, config2.max_input_tokens);
167169
+ return null;
167414
167170
  }
167415
167171
  function getOrCreateProvider() {
167416
167172
  if (provider) {
@@ -167434,17 +167190,14 @@ async function embedText(text, signal) {
167434
167190
  }
167435
167191
  var DEFAULT_EMBEDDING_CONFIG, embeddingConfig, provider = null, loadUnembeddedMemoriesStatements2, SWEEP_MAX_WALL_CLOCK_MS2;
167436
167192
  var init_embedding = __esm(() => {
167437
- init_magic_context();
167438
167193
  init_logger();
167439
167194
  init_compartment_chunk_embedding();
167440
167195
  init_embedding_identity();
167441
- init_embedding_local();
167442
167196
  init_embedding_openai();
167443
167197
  init_storage_memory_embeddings();
167444
167198
  init_project_embedding_registry();
167445
167199
  DEFAULT_EMBEDDING_CONFIG = {
167446
- provider: "local",
167447
- model: DEFAULT_LOCAL_EMBEDDING_MODEL
167200
+ provider: "off"
167448
167201
  };
167449
167202
  embeddingConfig = DEFAULT_EMBEDDING_CONFIG;
167450
167203
  loadUnembeddedMemoriesStatements2 = new WeakMap;
@@ -167525,13 +167278,13 @@ var init_storage_memory_fts = __esm(() => {
167525
167278
  });
167526
167279
 
167527
167280
  // src/shared/models-dev-cache.ts
167528
- import { mkdirSync as mkdirSync4, readFileSync as readFileSync9, renameSync, writeFileSync } from "node:fs";
167529
- import { join as join14 } from "node:path";
167281
+ import { mkdirSync as mkdirSync3, readFileSync as readFileSync9, renameSync, writeFileSync } from "node:fs";
167282
+ import { join as join13 } from "node:path";
167530
167283
  function isSaneLimit(limit) {
167531
167284
  return typeof limit === "number" && limit >= MIN_SANE_LIMIT && limit <= MAX_SANE_LIMIT;
167532
167285
  }
167533
167286
  function persistFilePath() {
167534
- return join14(getMagicContextStorageDir(), `model-context-limits-${getHarness()}.json`);
167287
+ return join13(getMagicContextStorageDir(), `model-context-limits-${getHarness()}.json`);
167535
167288
  }
167536
167289
  function loadPersistedApiCacheOnce() {
167537
167290
  if (persistSeedLoaded || apiCache !== null)
@@ -167561,7 +167314,7 @@ function persistApiCache() {
167561
167314
  }
167562
167315
  try {
167563
167316
  const dir = getMagicContextStorageDir();
167564
- mkdirSync4(dir, { recursive: true });
167317
+ mkdirSync3(dir, { recursive: true });
167565
167318
  const target = persistFilePath();
167566
167319
  const tmp = `${target}.${process.pid}.tmp`;
167567
167320
  writeFileSync(tmp, JSON.stringify(obj), { encoding: "utf-8", mode: 384 });
@@ -167670,7 +167423,7 @@ async function embedAndStoreCompartmentChunks(db, sessionId, projectPath, compar
167670
167423
  for (const compartment of compartments) {
167671
167424
  try {
167672
167425
  const fromMemory = compartment.sourceChunkText ? canonicalizeInMemoryChunkTextForEmbedding(compartment.sourceChunkText, compartment.startMessage, compartment.endMessage) : "";
167673
- const canonicalText = fromMemory || buildCanonicalChunkTextFromFts(db, sessionId, compartment.startMessage, compartment.endMessage);
167426
+ const canonicalText = fromMemory || buildCanonicalChunkTextFromFts(db, sessionId, compartment.startMessage, compartment.endMessage) || buildCompartmentSummaryFallbackText(db, compartment.id);
167674
167427
  if (canonicalText.length === 0)
167675
167428
  continue;
167676
167429
  const windows = chunkCanonicalText(canonicalText, compartment.startMessage, compartment.endMessage, maxInputTokens);
@@ -167715,7 +167468,7 @@ var init_compartment_embedding = __esm(() => {
167715
167468
  });
167716
167469
 
167717
167470
  // src/features/magic-context/compaction-marker.ts
167718
- import { join as join15 } from "node:path";
167471
+ import { join as join14 } from "node:path";
167719
167472
  function randomBase62(length) {
167720
167473
  const chars = [];
167721
167474
  for (let i = 0;i < length; i++) {
@@ -167735,7 +167488,7 @@ function generatePartId(timestampMs, counter = 0n) {
167735
167488
  return generateId("prt", timestampMs, counter);
167736
167489
  }
167737
167490
  function getOpenCodeDbPath3() {
167738
- return join15(getDataDir(), "opencode", "opencode.db");
167491
+ return join14(getDataDir(), "opencode", "opencode.db");
167739
167492
  }
167740
167493
  function isOpenCodeSchemaCompatible(db, dbPath) {
167741
167494
  if (cachedSchemaCompatible?.path === dbPath) {
@@ -167877,7 +167630,7 @@ var init_compaction_marker = __esm(async () => {
167877
167630
  });
167878
167631
 
167879
167632
  // src/hooks/magic-context/compaction-marker-manager.ts
167880
- import { join as join16 } from "node:path";
167633
+ import { join as join15 } from "node:path";
167881
167634
  function validatePendingTarget(db, sessionId, pending) {
167882
167635
  const ocMessage = getOpenCodeMessageById(sessionId, pending.endMessageId);
167883
167636
  if (!ocMessage) {
@@ -167986,7 +167739,7 @@ function removeCompactionMarkerForSession(db, sessionId) {
167986
167739
  }
167987
167740
  }
167988
167741
  function checkCompactionMarkerConsistency(db) {
167989
- const opencodeDbPath = join16(getDataDir(), "opencode", "opencode.db");
167742
+ const opencodeDbPath = join15(getDataDir(), "opencode", "opencode.db");
167990
167743
  let opencodeDb;
167991
167744
  try {
167992
167745
  opencodeDb = new Database(opencodeDbPath, { readonly: true });
@@ -168383,8 +168136,8 @@ var init_compartment_runner_validation = __esm(async () => {
168383
168136
  });
168384
168137
 
168385
168138
  // src/hooks/magic-context/compartment-runner-historian.ts
168386
- import { mkdirSync as mkdirSync5, unlinkSync, writeFileSync as writeFileSync2 } from "node:fs";
168387
- import { join as join17 } from "node:path";
168139
+ import { mkdirSync as mkdirSync4, unlinkSync, writeFileSync as writeFileSync2 } from "node:fs";
168140
+ import { join as join16 } from "node:path";
168388
168141
  function historianResponseDumpDir(directory) {
168389
168142
  return getProjectMagicContextHistorianDir(directory);
168390
168143
  }
@@ -168686,10 +168439,10 @@ function cleanupHistorianDump(sessionId, dumpPath) {
168686
168439
  function dumpHistorianResponse(sessionId, directory, label, text) {
168687
168440
  try {
168688
168441
  const dumpDir = historianResponseDumpDir(directory);
168689
- mkdirSync5(dumpDir, { recursive: true });
168442
+ mkdirSync4(dumpDir, { recursive: true });
168690
168443
  const safeSessionId = sanitizeDumpName(sessionId);
168691
168444
  const safeLabel = sanitizeDumpName(label);
168692
- const dumpPath = join17(dumpDir, `${safeSessionId}-${safeLabel}-${Date.now()}.xml`);
168445
+ const dumpPath = join16(dumpDir, `${safeSessionId}-${safeLabel}-${Date.now()}.xml`);
168693
168446
  writeFileSync2(dumpPath, text, "utf8");
168694
168447
  sessionLog(sessionId, "compartment agent: historian response dumped", {
168695
168448
  label,
@@ -168812,7 +168565,7 @@ function insertCompartmentEvents(db, sessionId, events, compartmentIds) {
168812
168565
  var init_compartment_events = () => {};
168813
168566
 
168814
168567
  // src/hooks/magic-context/historian-state-file.ts
168815
- import { mkdirSync as mkdirSync6, unlinkSync as unlinkSync2, writeFileSync as writeFileSync3 } from "node:fs";
168568
+ import { mkdirSync as mkdirSync5, unlinkSync as unlinkSync2, writeFileSync as writeFileSync3 } from "node:fs";
168816
168569
  function cleanupHistorianStateFile(path6) {
168817
168570
  if (!path6)
168818
168571
  return;
@@ -169150,7 +168903,7 @@ var init_decay_render = __esm(() => {
169150
168903
 
169151
168904
  // src/hooks/magic-context/key-files-block.ts
169152
168905
  import { readFileSync as readFileSync10, realpathSync as realpathSync4 } from "node:fs";
169153
- import { join as join18, sep as sep2 } from "node:path";
168906
+ import { join as join17, sep as sep2 } from "node:path";
169154
168907
  function staleKey(update) {
169155
168908
  return `${update.projectPath}\x00${update.path}\x00${update.generatedAtWitness}\x00${update.staleReason}`;
169156
168909
  }
@@ -169205,7 +168958,7 @@ function buildKeyFilesBlock(db, projectPath, config2 = { enabled: true, tokenBud
169205
168958
  let nextStale = null;
169206
168959
  let observed = false;
169207
168960
  try {
169208
- const absPath = join18(projectPath, row.path);
168961
+ const absPath = join17(projectPath, row.path);
169209
168962
  const real = realpathSync4(absPath);
169210
168963
  if (!isUnderResolvedRoot(projectRoot, real)) {
169211
168964
  nextStale = "missing";
@@ -170870,29 +170623,12 @@ function resolveHistorianContextLimit(historianModelOverride) {
170870
170623
  return DEFAULT_HISTORIAN_CONTEXT_FALLBACK;
170871
170624
  }
170872
170625
  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;
170626
+ console.warn(`[magic-context] historian.model "${historianModelOverride}" lacks provider prefix ("provider/model-id"); using the default context limit for chunk-budget derivation.`);
170890
170627
  }
170891
- return minLimit ?? DEFAULT_HISTORIAN_CONTEXT_FALLBACK;
170628
+ return DEFAULT_HISTORIAN_CONTEXT_FALLBACK;
170892
170629
  }
170893
170630
  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
170631
  var init_derive_budgets = __esm(() => {
170895
- init_model_requirements();
170896
170632
  init_models_dev_cache();
170897
170633
  });
170898
170634
 
@@ -171692,7 +171428,7 @@ function resolveBoundaryContext(args) {
171692
171428
  }
171693
171429
  let storedTokenTotals;
171694
171430
  try {
171695
- storedTokenTotals = getAllStatusTagTokenTotalsFlat(args.db, args.sessionId).totals;
171431
+ storedTokenTotals = getAllStatusTagTokenTotalsFlat(args.db, args.sessionId, args.taggerFloor ?? 0).totals;
171696
171432
  } catch (error51) {
171697
171433
  sessionLog(args.sessionId, "protected-tail stored-token map unavailable (live fallback):", error51);
171698
171434
  }
@@ -173896,6 +173632,7 @@ async function runCompartmentAgent(deps) {
173896
173632
  const count = recordHighPressureNoEligibleHead(db, boundarySnapshot);
173897
173633
  sessionLog(sessionId, `historian high-pressure no-op: recovery remains armed (noEligibleHeadCount=${count})`);
173898
173634
  }
173635
+ clearEmergencyDrainLatch(db, sessionId);
173899
173636
  telemetry.status = "noop";
173900
173637
  telemetry.failureReason = "nothing to compact before protected tail";
173901
173638
  rollbackDrainReservation();
@@ -173910,7 +173647,8 @@ async function runCompartmentAgent(deps) {
173910
173647
  trueRawTokens: boundarySnapshot.trueRawEligibleTokens,
173911
173648
  usagePercentage: boundarySnapshot.usagePercentage,
173912
173649
  usable,
173913
- perRunCap
173650
+ perRunCap,
173651
+ executeThresholdPercentage: boundarySnapshot.executeThresholdPercentage
173914
173652
  });
173915
173653
  if (!reserve.ok) {
173916
173654
  sessionLog(sessionId, `historian rate-limit skip: ${reserve.skippedReason ?? "quota exhausted"}`);
@@ -173929,6 +173667,7 @@ async function runCompartmentAgent(deps) {
173929
173667
  } else {
173930
173668
  recordHighPressureNoEligibleHead(db, boundarySnapshot);
173931
173669
  }
173670
+ clearEmergencyDrainLatch(db, sessionId);
173932
173671
  telemetry.status = "noop";
173933
173672
  telemetry.failureReason = "chunk empty after filtering";
173934
173673
  rollbackDrainReservation();
@@ -174036,6 +173775,7 @@ ${chunkText}`,
174036
173775
  }
174037
173776
  appendCompartments(db, sessionId, persistedCompartments);
174038
173777
  clearHistorianFailureState(db, sessionId);
173778
+ clearHistorianDrainFailure(db, sessionId);
174039
173779
  recordProtectedTailPublicationFloor(db, sessionId, lastCompartmentEnd + 1);
174040
173780
  clearEmergencyRecovery(db, sessionId);
174041
173781
  drainReservation = null;
@@ -174139,8 +173879,11 @@ ${chunkText}`,
174139
173879
  }
174140
173880
  } finally {
174141
173881
  if (!completedSuccessfully) {
174142
- if (!retainDrainReservationForRetryThrottle)
173882
+ if (!retainDrainReservationForRetryThrottle) {
174143
173883
  rollbackDrainReservation();
173884
+ } else {
173885
+ recordHistorianDrainFailure(db, sessionId);
173886
+ }
174144
173887
  updateSessionMeta(db, sessionId, { compartmentInProgress: false });
174145
173888
  }
174146
173889
  recordTelemetry();
@@ -176354,15 +176097,15 @@ var require_windows = __commonJS((exports, module) => {
176354
176097
  }
176355
176098
  return false;
176356
176099
  }
176357
- function checkStat(stat2, path6, options) {
176358
- if (!stat2.isSymbolicLink() && !stat2.isFile()) {
176100
+ function checkStat(stat, path6, options) {
176101
+ if (!stat.isSymbolicLink() && !stat.isFile()) {
176359
176102
  return false;
176360
176103
  }
176361
176104
  return checkPathExt(path6, options);
176362
176105
  }
176363
176106
  function isexe(path6, options, cb) {
176364
- fs2.stat(path6, function(er, stat2) {
176365
- cb(er, er ? false : checkStat(stat2, path6, options));
176107
+ fs2.stat(path6, function(er, stat) {
176108
+ cb(er, er ? false : checkStat(stat, path6, options));
176366
176109
  });
176367
176110
  }
176368
176111
  function sync(path6, options) {
@@ -176376,20 +176119,20 @@ var require_mode = __commonJS((exports, module) => {
176376
176119
  isexe.sync = sync;
176377
176120
  var fs2 = __require("fs");
176378
176121
  function isexe(path6, options, cb) {
176379
- fs2.stat(path6, function(er, stat2) {
176380
- cb(er, er ? false : checkStat(stat2, options));
176122
+ fs2.stat(path6, function(er, stat) {
176123
+ cb(er, er ? false : checkStat(stat, options));
176381
176124
  });
176382
176125
  }
176383
176126
  function sync(path6, options) {
176384
176127
  return checkStat(fs2.statSync(path6), options);
176385
176128
  }
176386
- function checkStat(stat2, options) {
176387
- return stat2.isFile() && checkMode(stat2, options);
176129
+ function checkStat(stat, options) {
176130
+ return stat.isFile() && checkMode(stat, options);
176388
176131
  }
176389
- function checkMode(stat2, options) {
176390
- var mod = stat2.mode;
176391
- var uid = stat2.uid;
176392
- var gid = stat2.gid;
176132
+ function checkMode(stat, options) {
176133
+ var mod = stat.mode;
176134
+ var uid = stat.uid;
176135
+ var gid = stat.gid;
176393
176136
  var myUid = options.uid !== undefined ? options.uid : process.getuid && process.getuid();
176394
176137
  var myGid = options.gid !== undefined ? options.gid : process.getgid && process.getgid();
176395
176138
  var u = parseInt("100", 8);
@@ -177254,7 +176997,6 @@ var init_memory_migration = __esm(async () => {
177254
176997
  init_shared();
177255
176998
  init_assistant_message_extractor();
177256
176999
  init_logger();
177257
- init_resolve_fallbacks();
177258
177000
  init_project_identity();
177259
177001
  init_storage_memory();
177260
177002
  await init_storage();
@@ -177570,17 +177312,20 @@ function shouldShowAnnouncement() {
177570
177312
  }
177571
177313
  return state.version !== ANNOUNCEMENT_VERSION;
177572
177314
  }
177573
- var ANNOUNCEMENT_VERSION = "0.25.0", ANNOUNCEMENT_FEATURES, ANNOUNCEMENT_FOOTER = "Join us on Discord: https://discord.gg/F2uWxjGnU", STATE_FILENAME = "last_announced_version";
177315
+ var ANNOUNCEMENT_VERSION = "0.26.0", ANNOUNCEMENT_FEATURES, ANNOUNCEMENT_FOOTER = "Join us on Discord: https://discord.gg/F2uWxjGnU", STATE_FILENAME = "last_announced_version";
177574
177316
  var init_announcement = __esm(() => {
177575
177317
  init_data_path();
177576
177318
  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."
177319
+ "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).",
177320
+ "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.",
177321
+ "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.",
177322
+ "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).",
177323
+ "New: doctor migrate-session re-homes a session (and optionally its memories) to another project, with a dry-run preview."
177582
177324
  ];
177583
177325
  });
177326
+
177327
+ // src/agents/dreamer.ts
177328
+ var DREAMER_AGENT = "dreamer";
177584
177329
  // src/agents/permissions.ts
177585
177330
  function buildAllowOnlyPermission(allowedTools) {
177586
177331
  const permission = { "*": "deny" };
@@ -177590,6 +177335,11 @@ function buildAllowOnlyPermission(allowedTools) {
177590
177335
  return permission;
177591
177336
  }
177592
177337
  var HISTORIAN_ALLOWED_TOOLS = ["read", "aft_outline", "aft_zoom", "aft_search"];
177338
+ function applyDisallowedTools(defaults, disallowed) {
177339
+ if (disallowed.includes("*"))
177340
+ return [];
177341
+ return defaults.filter((t) => !disallowed.includes(t));
177342
+ }
177593
177343
  var DREAMER_ALLOWED_TOOLS = [
177594
177344
  "read",
177595
177345
  "grep",
@@ -177605,6 +177355,10 @@ var DREAMER_ALLOWED_TOOLS = [
177605
177355
  "ctx_note"
177606
177356
  ];
177607
177357
  var SIDEKICK_ALLOWED_TOOLS = ["ctx_search", "aft_outline", "aft_zoom"];
177358
+
177359
+ // src/agents/sidekick.ts
177360
+ var SIDEKICK_AGENT = "sidekick";
177361
+
177608
177362
  // src/config/index.ts
177609
177363
  init_jsonc_parser();
177610
177364
  import { existsSync as existsSync3, readFileSync as readFileSync3 } from "node:fs";
@@ -178558,6 +178312,7 @@ ${modeIntro}
178558
178312
  4. **Write or update** using the Write tool. Always write to project root, NOT to .planning/.
178559
178313
 
178560
178314
  ### Rules
178315
+ - **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
178316
  - **Be prescriptive**: "Use X pattern" not "X pattern is used"
178562
178317
  - **Always include file paths** in backticks
178563
178318
  - **Write current state only**: no temporal language, no history
@@ -178694,7 +178449,6 @@ init_project_identity();
178694
178449
  init_shared();
178695
178450
  init_assistant_message_extractor();
178696
178451
  init_logger();
178697
- init_resolve_fallbacks();
178698
178452
  init_subagent_token_capture();
178699
178453
  await init_storage();
178700
178454
 
@@ -178716,7 +178470,7 @@ function stripThinkingBlocks(text) {
178716
178470
 
178717
178471
  // src/features/magic-context/sidekick/agent.ts
178718
178472
  async function runSidekick(deps) {
178719
- const fallbackModels = resolveFallbackChain(SIDEKICK_AGENT, deps.config.fallback_models);
178473
+ const fallbackModels = resolveFallbackChain(deps.config.fallback_models);
178720
178474
  let agentSessionId = null;
178721
178475
  const startedAt = Date.now();
178722
178476
  let invocationRecorded = false;
@@ -178806,6 +178560,11 @@ init_project_identity();
178806
178560
  import { createHash as createHash6 } from "node:crypto";
178807
178561
  import { realpathSync as realpathSync2 } from "node:fs";
178808
178562
  import path5 from "node:path";
178563
+
178564
+ // src/features/magic-context/memory/relocate-memory.ts
178565
+ var memoryCopyColumnsCache = new WeakMap;
178566
+
178567
+ // src/features/magic-context/v22-deferred-backfill.ts
178809
178568
  var BATCH_SIZE = 25;
178810
178569
  var YIELD_EVERY_N_ROWS = 5;
178811
178570
  var BACKFILL_META_KEY = "v22_legacy_memory_backfill";
@@ -179043,6 +178802,7 @@ function createLiveSessionState() {
179043
178802
 
179044
178803
  // src/index.ts
179045
178804
  init_conflict_warning_hook();
178805
+
179046
178806
  // src/features/magic-context/dreamer/storage-dream-state.ts
179047
178807
  var getDreamStateStatements = new WeakMap;
179048
178808
  var setDreamStateStatements = new WeakMap;
@@ -179236,21 +178996,21 @@ function clearStaleEntries(db, maxAgeMs, projectIdentity) {
179236
178996
  return result.changes;
179237
178997
  }
179238
178998
  // src/features/magic-context/dreamer/runner.ts
178999
+ import { existsSync as existsSync10 } from "node:fs";
179000
+ import { join as join12 } from "node:path";
179239
179001
  init_shared();
179240
179002
  init_assistant_message_extractor();
179241
179003
  init_data_path();
179242
179004
  init_logger();
179243
179005
  await init_sqlite();
179244
- import { existsSync as existsSync10 } from "node:fs";
179245
- import { join as join12 } from "node:path";
179246
179006
 
179247
179007
  // src/features/magic-context/key-files/identify-key-files.ts
179008
+ import { readFileSync as readFileSync8 } from "node:fs";
179009
+ import { isAbsolute as isAbsolute3, join as join11, relative as relative2 } from "node:path";
179248
179010
  init_read_session_formatting();
179249
179011
  init_shared();
179250
179012
  init_assistant_message_extractor();
179251
179013
  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
179014
  init_subagent_token_capture();
179255
179015
  init_aft_availability();
179256
179016
  init_project_key_files();
@@ -181119,7 +180879,6 @@ init_sweep_coordinator();
181119
180879
  // src/plugin/dream-timer.ts
181120
180880
  init_embedding();
181121
180881
  init_logger();
181122
- init_resolve_fallbacks();
181123
180882
  await init_storage();
181124
180883
  var DREAM_TIMER_INTERVAL_MS = 15 * 60 * 1000;
181125
180884
  var activeTimer = null;
@@ -181222,7 +180981,7 @@ async function sweepProject(reg, origin, db, gitCommitEnabled = getProjectEmbedd
181222
180981
  experimentalPinKeyFiles: reg.experimentalPinKeyFiles,
181223
180982
  projectIdentity: reg.projectIdentity,
181224
180983
  sessionDirectoryOverride: reg.directory,
181225
- fallbackModels: resolveFallbackChain(DREAMER_AGENT, reg.dreamerConfig.fallback_models)
180984
+ fallbackModels: resolveFallbackChain(reg.dreamerConfig.fallback_models)
181226
180985
  });
181227
180986
  } catch (error51) {
181228
180987
  log(`[dreamer] timer-triggered queue processing failed for ${reg.projectIdentity}:`, error51);
@@ -181671,10 +181430,9 @@ function makeToolCompositeKey(ownerMsgId, callId) {
181671
181430
  }
181672
181431
  var GET_COUNTER_SQL = `SELECT counter FROM session_meta WHERE session_id = ?`;
181673
181432
  var GET_ASSIGNMENTS_SQL = "SELECT message_id, tag_number, type, tool_owner_message_id FROM tags WHERE session_id = ? ORDER BY tag_number ASC";
181433
+ 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
181434
  var PROBE_DATA_VERSION_SQL = "PRAGMA main.data_version";
181675
- var PROBE_TOTAL_CHANGES_SQL = "SELECT total_changes() AS tc";
181676
181435
  var probeDataVersionStatements = new WeakMap;
181677
- var probeTotalChangesStatements = new WeakMap;
181678
181436
  function getProbeDataVersionStatement(db) {
181679
181437
  let stmt = probeDataVersionStatements.get(db);
181680
181438
  if (!stmt) {
@@ -181683,14 +181441,6 @@ function getProbeDataVersionStatement(db) {
181683
181441
  }
181684
181442
  return stmt;
181685
181443
  }
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
181444
  function isAssignmentRow(row) {
181695
181445
  if (row === null || typeof row !== "object") {
181696
181446
  return false;
@@ -181883,20 +181633,18 @@ function createTagger() {
181883
181633
  }
181884
181634
  function probeSignature(db) {
181885
181635
  const dvRow = getProbeDataVersionStatement(db).get();
181886
- const tcRow = getProbeTotalChangesStatement(db).get();
181887
181636
  return {
181888
- dataVersion: dvRow?.data_version ?? 0,
181889
- totalChanges: tcRow?.tc ?? 0
181637
+ dataVersion: dvRow?.data_version ?? 0
181890
181638
  };
181891
181639
  }
181892
- function initFromDb(sessionId, db) {
181640
+ function initFromDb(sessionId, db, floor = 0) {
181893
181641
  const probe = probeSignature(db);
181894
181642
  const cached2 = loadSignatures.get(sessionId);
181895
- if (cached2 !== undefined && cached2.db === db && cached2.dataVersion === probe.dataVersion && cached2.totalChanges === probe.totalChanges) {
181643
+ if (cached2 !== undefined && cached2.db === db && cached2.dataVersion === probe.dataVersion && cached2.floor === floor) {
181896
181644
  return;
181897
181645
  }
181898
181646
  const row = db.prepare(GET_COUNTER_SQL).get(sessionId);
181899
- const assignmentRows = db.prepare(GET_ASSIGNMENTS_SQL).all(sessionId).filter(isAssignmentRow);
181647
+ const assignmentRows = (floor > 0 ? db.prepare(GET_ASSIGNMENTS_SCOPED_SQL).all(sessionId, floor) : db.prepare(GET_ASSIGNMENTS_SQL).all(sessionId)).filter(isAssignmentRow);
181900
181648
  const sessionAssignments = getSessionAssignments(sessionId);
181901
181649
  sessionAssignments.clear();
181902
181650
  let maxTagNumber = 0;
@@ -181917,7 +181665,7 @@ function createTagger() {
181917
181665
  loadSignatures.set(sessionId, {
181918
181666
  db,
181919
181667
  dataVersion: probe.dataVersion,
181920
- totalChanges: probe.totalChanges
181668
+ floor
181921
181669
  });
181922
181670
  }
181923
181671
  function cleanup(sessionId) {
@@ -181940,13 +181688,13 @@ function createTagger() {
181940
181688
  cleanup
181941
181689
  };
181942
181690
  }
181691
+
181943
181692
  // src/hooks/magic-context/hook.ts
181944
181693
  init_magic_context();
181945
181694
  init_project_identity();
181946
181695
  init_project_embedding_registry();
181947
181696
  await init_storage();
181948
181697
  init_logger();
181949
- init_resolve_fallbacks();
181950
181698
  init_rpc_notifications();
181951
181699
 
181952
181700
  // src/hooks/magic-context/command-handler.ts
@@ -181997,6 +181745,7 @@ await __promiseAll([
181997
181745
  // src/hooks/magic-context/compartment-trigger.ts
181998
181746
  init_compartment_storage();
181999
181747
  init_logger();
181748
+ init_read_session_true_raw_tokens();
182000
181749
  await __promiseAll([
182001
181750
  init_storage(),
182002
181751
  init_protected_tail_boundary(),
@@ -182011,6 +181760,38 @@ var TAIL_SIZE_TRIGGER_MULTIPLIER = 3;
182011
181760
  var FORCE_COMPARTMENT_PERCENTAGE = 80;
182012
181761
  var BLOCK_UNTIL_DONE_PERCENTAGE = 95;
182013
181762
  var FORCE_MATERIALIZE_PERCENTAGE = 85;
181763
+ var CONTENT_TAG_OWNER_SUFFIX = /:(?:p|file)\d+$/;
181764
+ function tagOwnerMessageId(row) {
181765
+ if (row.type === "tool")
181766
+ return row.tool_owner_message_id ?? row.message_id;
181767
+ return row.message_id.replace(CONTENT_TAG_OWNER_SUFFIX, "");
181768
+ }
181769
+ function getActiveOrDroppedTagOwnerMessageIds(db, sessionId, floor = 0) {
181770
+ const rows = floor > 0 ? db.prepare(`SELECT type, message_id, tool_owner_message_id
181771
+ FROM tags
181772
+ WHERE session_id = ? AND status IN ('active', 'dropped') AND tag_number >= ?`).all(sessionId, floor) : db.prepare(`SELECT type, message_id, tool_owner_message_id
181773
+ FROM tags
181774
+ WHERE session_id = ? AND status IN ('active', 'dropped')`).all(sessionId);
181775
+ const owners = new Set;
181776
+ for (const row of rows)
181777
+ owners.add(tagOwnerMessageId(row));
181778
+ return owners;
181779
+ }
181780
+ function estimateUntaggedInMemoryTailUpperBound(db, sessionId, inMemoryTail, taggerFloor = 0) {
181781
+ const lastCompartmentEnd = getLastCompartmentEndMessage(db, sessionId);
181782
+ const coveredOwnerMessageIds = getActiveOrDroppedTagOwnerMessageIds(db, sessionId, taggerFloor);
181783
+ let total = 0;
181784
+ for (const message of inMemoryTail.messages) {
181785
+ if (message.ordinal <= lastCompartmentEnd)
181786
+ continue;
181787
+ if (coveredOwnerMessageIds.has(message.id))
181788
+ continue;
181789
+ total += estimateTrueRawMessageTokens(message, {
181790
+ providerShapeVersion: "opencode-v1"
181791
+ }).total;
181792
+ }
181793
+ return total;
181794
+ }
182014
181795
  function buildTriggerInMemoryTail(db, sessionId, messages) {
182015
181796
  if (messages.length === 0)
182016
181797
  return;
@@ -182082,7 +181863,7 @@ function resolveBoundaryContextLimit(usage, fallbackContextLimit) {
182082
181863
  }
182083
181864
  return 128000;
182084
181865
  }
182085
- function getUnsummarizedTailInfo(db, sessionId, triggerBudget, usage, executeThresholdPercentage, contextLimit, inMemoryTail) {
181866
+ function getUnsummarizedTailInfo(db, sessionId, triggerBudget, usage, executeThresholdPercentage, contextLimit, inMemoryTail, taggerFloor = 0) {
182086
181867
  return withRawSessionMessageCache(() => {
182087
181868
  try {
182088
181869
  const memoryPrimed = inMemoryTail ? primeInMemoryTailRawMessageCache({
@@ -182111,7 +181892,8 @@ function getUnsummarizedTailInfo(db, sessionId, triggerBudget, usage, executeThr
182111
181892
  contextLimit: resolveBoundaryContextLimit(usage, contextLimit),
182112
181893
  executeThresholdPercentage,
182113
181894
  usage,
182114
- usageSource: "live"
181895
+ usageSource: "live",
181896
+ taggerFloor
182115
181897
  });
182116
181898
  const hasProtectedEligibleHead = boundary.offset < boundary.protectedTailStart;
182117
181899
  if (!hasProtectedEligibleHead) {
@@ -182142,7 +181924,7 @@ function getUnsummarizedTailInfo(db, sessionId, triggerBudget, usage, executeThr
182142
181924
  }
182143
181925
  });
182144
181926
  }
182145
- function checkCompartmentTrigger(db, sessionId, sessionMeta, usage, _previousPercentage, executeThresholdPercentage, triggerBudget, clearReasoningAge, commitClusterTrigger, preloadedActiveTags, contextLimit, inMemoryTail) {
181927
+ function checkCompartmentTrigger(db, sessionId, sessionMeta, usage, _previousPercentage, executeThresholdPercentage, triggerBudget, clearReasoningAge, commitClusterTrigger, preloadedActiveTags, contextLimit, inMemoryTail, taggerFloorOverride) {
182146
181928
  if (sessionMeta.compartmentInProgress) {
182147
181929
  sessionLog(sessionId, `compartment trigger: skipped — historian already in progress (usage=${usage.percentage.toFixed(1)}%)`);
182148
181930
  return { shouldFire: false };
@@ -182156,14 +181938,17 @@ function checkCompartmentTrigger(db, sessionId, sessionMeta, usage, _previousPer
182156
181938
  inMemoryTail = undefined;
182157
181939
  }
182158
181940
  }
181941
+ const taggerFloor = taggerFloorOverride !== undefined && taggerFloorOverride > 0 ? taggerFloorOverride : inMemoryTail ? deriveTagLoadFloor(db, sessionId, inMemoryTail.messages.map((m) => m.id)) : 0;
182159
181942
  const proactiveFloorForGate = getProactiveCompartmentTriggerPercentage(executeThresholdPercentage);
182160
- if (!inMemoryTail && usage.percentage < proactiveFloorForGate) {
181943
+ if (usage.percentage < proactiveFloorForGate) {
182161
181944
  try {
182162
- const { bound, nullCount } = getTriggerTagTokenUpperBound(db, sessionId);
181945
+ const { bound: persistedBound, nullCount } = getTriggerTagTokenUpperBound(db, sessionId, taggerFloor);
182163
181946
  if (nullCount === 0) {
182164
- const eligibleUpperBound = bound;
181947
+ const untaggedUpperBound = inMemoryTail ? estimateUntaggedInMemoryTailUpperBound(db, sessionId, inMemoryTail, taggerFloor) : 0;
181948
+ const eligibleUpperBound = persistedBound + untaggedUpperBound;
182165
181949
  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`);
181950
+ const memorySuffix = inMemoryTail ? ` (persisted=${persistedBound}, untagged-memory≤${untaggedUpperBound})` : "";
181951
+ 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
181952
  return { shouldFire: false };
182168
181953
  }
182169
181954
  }
@@ -182171,7 +181956,7 @@ function checkCompartmentTrigger(db, sessionId, sessionMeta, usage, _previousPer
182171
181956
  sessionLog(sessionId, `compartment trigger: cheap-gate skipped (falling through to full read): ${error51 instanceof Error ? error51.message : String(error51)}`);
182172
181957
  }
182173
181958
  }
182174
- const tailInfo = getUnsummarizedTailInfo(db, sessionId, triggerBudget, usage, executeThresholdPercentage, contextLimit, inMemoryTail);
181959
+ const tailInfo = getUnsummarizedTailInfo(db, sessionId, triggerBudget, usage, executeThresholdPercentage, contextLimit, inMemoryTail, taggerFloor);
182175
181960
  if (!tailInfo.hasNewRawHistory) {
182176
181961
  try {
182177
181962
  const lastCompartmentEnd = getLastCompartmentEndMessage(db, sessionId);
@@ -182906,9 +182691,142 @@ function clearSessionTracking(sessionId) {
182906
182691
  // src/hooks/magic-context/event-handler.ts
182907
182692
  init_overflow_detection();
182908
182693
  init_storage_meta_persisted();
182694
+ await init_storage();
182695
+
182696
+ // src/features/magic-context/transform-decision-log.ts
182697
+ await __promiseAll([
182698
+ init_sqlite(),
182699
+ init_storage_db()
182700
+ ]);
182701
+ var canonicalReasons = new Set([
182702
+ "system_hash",
182703
+ "model_change",
182704
+ "project_memory_epoch",
182705
+ "ttl_idle",
182706
+ "explicit_flush",
182707
+ "max_mutation_id",
182708
+ "first_render",
182709
+ "pressure_refold",
182710
+ "upgrade_state",
182711
+ "cached_m1_missing"
182712
+ ]);
182713
+ var piReasonAliases = {
182714
+ project_memory_change: "project_memory_epoch",
182715
+ pending_mutations: "max_mutation_id",
182716
+ renderer_upgrade: "upgrade_state",
182717
+ cache_invalid: "cached_m1_missing",
182718
+ drift: "pressure_refold"
182719
+ };
182720
+ var sharedReasonAliases = {
182721
+ model_key: "model_change",
182722
+ pressure: "pressure_refold"
182723
+ };
182724
+ var pendingDecisionBySession = new Map;
182725
+ var pendingPiDecisionBySession = new Map;
182726
+ var lastBoundMessageIdBySession = new Map;
182727
+ var scheduledWriteTokensBySession = new Map;
182728
+ var writerOverrideForTests = null;
182729
+ function normalizeMaterializeReason(harness, reason, rematerialized) {
182730
+ const raw = typeof reason === "string" ? reason.trim() : "";
182731
+ if (raw.length > 0) {
182732
+ const alias = sharedReasonAliases[raw] ?? (harness === "pi" ? piReasonAliases[raw] : undefined) ?? undefined;
182733
+ if (alias)
182734
+ return alias;
182735
+ if (canonicalReasons.has(raw))
182736
+ return raw;
182737
+ return null;
182738
+ }
182739
+ return rematerialized ? "pressure_refold" : null;
182740
+ }
182741
+ function clearOpenCodePendingTransformDecision(sessionId) {
182742
+ pendingDecisionBySession.delete(sessionId);
182743
+ }
182744
+ function clearTransformDecisionSession(sessionId) {
182745
+ pendingDecisionBySession.delete(sessionId);
182746
+ pendingPiDecisionBySession.delete(sessionId);
182747
+ lastBoundMessageIdBySession.delete(sessionId);
182748
+ scheduledWriteTokensBySession.delete(sessionId);
182749
+ }
182750
+ function recordPendingTransformDecision(sessionId, decision) {
182751
+ if (!decision.bustedThisPass) {
182752
+ pendingDecisionBySession.delete(sessionId);
182753
+ return;
182754
+ }
182755
+ pendingDecisionBySession.set(sessionId, decision);
182756
+ }
182757
+ function scheduleOpenCodeTransformDecisionWrite(args) {
182758
+ const pending = pendingDecisionBySession.get(args.sessionId);
182759
+ if (!pending)
182760
+ return false;
182761
+ if (lastBoundMessageIdBySession.get(args.sessionId) === args.messageId) {
182762
+ return false;
182763
+ }
182764
+ const dbPath = getDatabasePath(args.db);
182765
+ if (!dbPath)
182766
+ return false;
182767
+ lastBoundMessageIdBySession.set(args.sessionId, args.messageId);
182768
+ pendingDecisionBySession.delete(args.sessionId);
182769
+ const token = addScheduledWriteToken(args.sessionId);
182770
+ setTimeout(() => {
182771
+ try {
182772
+ if (!hasScheduledWriteToken(args.sessionId, token))
182773
+ return;
182774
+ writeTransformDecisionBestEffort(dbPath, {
182775
+ ...pending,
182776
+ sessionId: args.sessionId,
182777
+ harness: "opencode",
182778
+ messageId: args.messageId,
182779
+ inputTokens: args.inputTokens
182780
+ });
182781
+ } finally {
182782
+ deleteScheduledWriteToken(args.sessionId, token);
182783
+ }
182784
+ }, 0);
182785
+ return true;
182786
+ }
182787
+ function addScheduledWriteToken(sessionId) {
182788
+ const token = Symbol(sessionId);
182789
+ let tokens = scheduledWriteTokensBySession.get(sessionId);
182790
+ if (!tokens) {
182791
+ tokens = new Set;
182792
+ scheduledWriteTokensBySession.set(sessionId, tokens);
182793
+ }
182794
+ tokens.add(token);
182795
+ return token;
182796
+ }
182797
+ function hasScheduledWriteToken(sessionId, token) {
182798
+ return scheduledWriteTokensBySession.get(sessionId)?.has(token) === true;
182799
+ }
182800
+ function deleteScheduledWriteToken(sessionId, token) {
182801
+ const tokens = scheduledWriteTokensBySession.get(sessionId);
182802
+ if (!tokens)
182803
+ return;
182804
+ tokens.delete(token);
182805
+ if (tokens.size === 0)
182806
+ scheduledWriteTokensBySession.delete(sessionId);
182807
+ }
182808
+ function writeTransformDecisionBestEffort(dbPath, row) {
182809
+ try {
182810
+ const writer = writerOverrideForTests ?? writeTransformDecisionRow;
182811
+ writer(dbPath, row);
182812
+ } catch {}
182813
+ }
182814
+ function writeTransformDecisionRow(dbPath, row) {
182815
+ const db = new Database(dbPath);
182816
+ try {
182817
+ db.exec("PRAGMA busy_timeout=0");
182818
+ db.prepare(`INSERT OR REPLACE INTO transform_decisions (
182819
+ session_id, harness, message_id, ts_ms, decision, materialized,
182820
+ materialize_reason, emergency, dropped_tokens, dropped_count, input_tokens
182821
+ ) 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)));
182822
+ } finally {
182823
+ closeQuietly(db);
182824
+ }
182825
+ }
182826
+
182827
+ // src/hooks/magic-context/event-handler.ts
182909
182828
  init_logger();
182910
182829
  init_models_dev_cache();
182911
- await init_storage();
182912
182830
 
182913
182831
  // src/hooks/magic-context/channel2-delivery.ts
182914
182832
  init_storage_meta_persisted();
@@ -183312,11 +183230,13 @@ function getMessageUpdatedAssistantInfo(properties) {
183312
183230
  }
183313
183231
  const tokens = isRecord(info.tokens) ? info.tokens : undefined;
183314
183232
  const cache = tokens && isRecord(tokens.cache) ? tokens.cache : undefined;
183233
+ const time3 = isRecord(info.time) ? info.time : undefined;
183315
183234
  return {
183316
183235
  role: "assistant",
183317
183236
  finish: typeof info.finish === "string" ? info.finish : undefined,
183318
183237
  sessionID: info.sessionID,
183319
183238
  messageID: typeof info.id === "string" ? info.id : undefined,
183239
+ completedAt: typeof time3?.completed === "number" ? time3.completed : undefined,
183320
183240
  providerID: typeof info.providerID === "string" ? info.providerID : undefined,
183321
183241
  modelID: typeof info.modelID === "string" ? info.modelID : undefined,
183322
183242
  tokens: {
@@ -183379,8 +183299,8 @@ init_project_identity();
183379
183299
  import * as crypto2 from "node:crypto";
183380
183300
  init_session_project_storage();
183381
183301
  init_storage_meta_persisted();
183382
- init_logger();
183383
183302
  await init_storage();
183303
+ init_logger();
183384
183304
 
183385
183305
  // src/hooks/magic-context/boundary-execution.ts
183386
183306
  var FORCE_MATERIALIZE_PERCENTAGE2 = 85;
@@ -184416,6 +184336,7 @@ function stripProcessedImages(messages, frozenIds, options) {
184416
184336
  init_temporal_awareness();
184417
184337
 
184418
184338
  // src/hooks/magic-context/transform-compartment-phase.ts
184339
+ init_compartment_storage();
184419
184340
  init_logger();
184420
184341
  await __promiseAll([
184421
184342
  init_storage(),
@@ -184424,9 +184345,29 @@ await __promiseAll([
184424
184345
  init_send_session_notification();
184425
184346
  await __promiseAll([
184426
184347
  init_inject_compartments(),
184427
- init_protected_tail_boundary()
184348
+ init_protected_tail_boundary(),
184349
+ init_read_session_chunk()
184428
184350
  ]);
184429
- async function runCompartmentPhase(args) {
184351
+ function runCompartmentPhase(args) {
184352
+ const historianRunnable = args.historianRunnable !== false;
184353
+ const willReadRawHistory = historianRunnable && args.canRunCompartments && getActiveCompartmentRun(args.sessionId) === undefined && (args.sessionMeta.compartmentInProgress || !args.skipAwaitForThisPass && args.contextUsage.percentage >= BLOCK_UNTIL_DONE_PERCENTAGE);
184354
+ if (!willReadRawHistory) {
184355
+ return runCompartmentPhaseImpl(args);
184356
+ }
184357
+ return withRawSessionMessageCache(() => {
184358
+ try {
184359
+ primeTailRawMessageCache({
184360
+ sessionId: args.resolvedSessionId,
184361
+ lastCompartmentEnd: getLastCompartmentEndMessage(args.db, args.resolvedSessionId),
184362
+ anchorMessageId: getLastCompartmentEndMessageId(args.db, args.resolvedSessionId)
184363
+ });
184364
+ } catch (error51) {
184365
+ sessionLog(args.sessionId, "compartment phase: tail prime failed (non-fatal):", error51);
184366
+ }
184367
+ return runCompartmentPhaseImpl(args);
184368
+ });
184369
+ }
184370
+ async function runCompartmentPhaseImpl(args) {
184430
184371
  let pendingCompartmentInjection = args.pendingCompartmentInjection;
184431
184372
  let compartmentInProgress = args.sessionMeta.compartmentInProgress;
184432
184373
  let published = false;
@@ -184992,6 +184933,7 @@ function createExistingTagResolver(sessionId, tagger, db) {
184992
184933
  return;
184993
184934
  }
184994
184935
  updateTagMessageId(db, sessionId, fallback.tagNumber, currentContentId);
184936
+ tagger.unbindTag(sessionId, fallback.contentId);
184995
184937
  tagger.bindTag(sessionId, currentContentId, fallback.tagNumber);
184996
184938
  usedTagNumbers.add(fallback.tagNumber);
184997
184939
  return fallback.tagNumber;
@@ -185012,7 +184954,45 @@ function logTransformTiming(sessionId, stage, startMs, extra) {
185012
184954
  }
185013
184955
 
185014
184956
  // src/hooks/magic-context/tag-messages.ts
185015
- function deriveToolOwnerMessageId(sessionId, db, message, obs, unpaired) {
184957
+ var TOOL_OWNER_CACHE_KEY_SEP = "\x00";
184958
+ function makeToolOwnerCacheKey(sessionId, callId) {
184959
+ return `${sessionId}${TOOL_OWNER_CACHE_KEY_SEP}${callId}`;
184960
+ }
184961
+ function getCachedCandidateToolOwners(db, sessionId, callId, cache, onLookup) {
184962
+ const key = makeToolOwnerCacheKey(sessionId, callId);
184963
+ const cached2 = cache.candidateOwnersByCallId.get(key);
184964
+ if (cached2 !== undefined)
184965
+ return cached2;
184966
+ onLookup?.({ kind: "candidates", callId });
184967
+ const candidates = getCandidateToolOwners(db, sessionId, callId);
184968
+ cache.candidateOwnersByCallId.set(key, candidates);
184969
+ return candidates;
184970
+ }
184971
+ function getCachedMessageTimesFromOpenCodeDb(sessionId, messageIds, cache, onLookup) {
184972
+ const uncached = [...new Set(messageIds)].filter((id) => !cache.messageTimesById.has(id));
184973
+ if (uncached.length > 0) {
184974
+ onLookup?.({ kind: "messageTimes", messageIds: uncached });
184975
+ const resolved = getMessageTimesFromOpenCodeDb(sessionId, uncached);
184976
+ for (const id of uncached) {
184977
+ cache.messageTimesById.set(id, resolved.get(id) ?? null);
184978
+ }
184979
+ }
184980
+ const times = new Map;
184981
+ for (const id of messageIds) {
184982
+ const time3 = cache.messageTimesById.get(id);
184983
+ if (typeof time3 === "number")
184984
+ times.set(id, time3);
184985
+ }
184986
+ return times;
184987
+ }
184988
+ function invalidateCachedCandidateToolOwnersIfNewOwner(cache, sessionId, callId, ownerMsgId) {
184989
+ const key = makeToolOwnerCacheKey(sessionId, callId);
184990
+ const cached2 = cache.candidateOwnersByCallId.get(key);
184991
+ if (cached2 !== undefined && !cached2.includes(ownerMsgId)) {
184992
+ cache.candidateOwnersByCallId.delete(key);
184993
+ }
184994
+ }
184995
+ function deriveToolOwnerMessageId(sessionId, db, message, obs, unpaired, cache, onFallbackLookup) {
185016
184996
  const messageId = typeof message.info.id === "string" ? message.info.id : "";
185017
184997
  if (obs.kind === "invocation") {
185018
184998
  if (messageId) {
@@ -185032,10 +185012,10 @@ function deriveToolOwnerMessageId(sessionId, db, message, obs, unpaired) {
185032
185012
  return popped;
185033
185013
  }
185034
185014
  if (messageId) {
185035
- const candidates = getCandidateToolOwners(db, sessionId, obs.callId);
185015
+ const candidates = getCachedCandidateToolOwners(db, sessionId, obs.callId, cache, onFallbackLookup);
185036
185016
  if (candidates.length > 0) {
185037
185017
  const ids = [...candidates, messageId];
185038
- const times = getMessageTimesFromOpenCodeDb(sessionId, ids);
185018
+ const times = getCachedMessageTimesFromOpenCodeDb(sessionId, ids, cache, onFallbackLookup);
185039
185019
  const persisted = pickNearestPriorOwner(candidates, messageId, times);
185040
185020
  if (persisted !== null)
185041
185021
  return persisted;
@@ -185116,6 +185096,7 @@ function extractToolTagMetadata(part) {
185116
185096
  }
185117
185097
  function tagMessages(sessionId, messages, tagger, db, options = {}) {
185118
185098
  const skipPrefixInjection = options.skipPrefixInjection === true;
185099
+ const onToolOwnerFallbackLookup = options.onToolOwnerFallbackLookup;
185119
185100
  const targets = new Map;
185120
185101
  const reasoningByMessage = new Map;
185121
185102
  const messageTagNumbers = new Map;
@@ -185123,6 +185104,10 @@ function tagMessages(sessionId, messages, tagger, db, options = {}) {
185123
185104
  const toolThinkingByCallId = new Map;
185124
185105
  const toolCallIndex = new Map;
185125
185106
  const unpairedInvocations = new Map;
185107
+ const ownerDerivationCache = {
185108
+ candidateOwnersByCallId: new Map,
185109
+ messageTimesById: new Map
185110
+ };
185126
185111
  const ownerByPartKey = new Map;
185127
185112
  const batch = new ToolMutationBatch(messages);
185128
185113
  const assignments = tagger.getAssignments(sessionId);
@@ -185163,7 +185148,7 @@ function tagMessages(sessionId, messages, tagger, db, options = {}) {
185163
185148
  const toolObservation = extractToolCallObservation(part);
185164
185149
  if (toolObservation) {
185165
185150
  const _tDerive = performance.now();
185166
- const ownerMsgId = deriveToolOwnerMessageId(sessionId, db, message, toolObservation, unpairedInvocations);
185151
+ const ownerMsgId = deriveToolOwnerMessageId(sessionId, db, message, toolObservation, unpairedInvocations, ownerDerivationCache, onToolOwnerFallbackLookup);
185167
185152
  accDerive += performance.now() - _tDerive;
185168
185153
  const compositeKey = makeToolCompositeKey(ownerMsgId, toolObservation.callId);
185169
185154
  const entry = toolCallIndex.get(compositeKey) ?? {
@@ -185182,6 +185167,7 @@ function tagMessages(sessionId, messages, tagger, db, options = {}) {
185182
185167
  if (orphan !== null) {
185183
185168
  const claimed = adoptNullOwnerToolTag(db, orphan.id, ownerMsgId);
185184
185169
  if (claimed) {
185170
+ invalidateCachedCandidateToolOwnersIfNewOwner(ownerDerivationCache, sessionId, toolObservation.callId, ownerMsgId);
185185
185171
  tagger.bindToolTag(sessionId, toolObservation.callId, ownerMsgId, orphan.tagNumber);
185186
185172
  existingTagId = orphan.tagNumber;
185187
185173
  } else {
@@ -185189,6 +185175,13 @@ function tagMessages(sessionId, messages, tagger, db, options = {}) {
185189
185175
  }
185190
185176
  }
185191
185177
  }
185178
+ if (existingTagId === undefined) {
185179
+ const persisted = getToolTagNumberByOwner(db, sessionId, toolObservation.callId, ownerMsgId);
185180
+ if (persisted !== null) {
185181
+ tagger.bindToolTag(sessionId, toolObservation.callId, ownerMsgId, persisted);
185182
+ existingTagId = persisted;
185183
+ }
185184
+ }
185192
185185
  if (existingTagId !== undefined) {
185193
185186
  toolTagByCallId.set(compositeKey, existingTagId);
185194
185187
  messageTagNumbers.set(message, Math.max(messageTagNumbers.get(message) ?? 0, existingTagId));
@@ -185261,6 +185254,7 @@ function tagMessages(sessionId, messages, tagger, db, options = {}) {
185261
185254
  inputTokenCount,
185262
185255
  reasoningTokenCount: reasoningTokens
185263
185256
  }));
185257
+ invalidateCachedCandidateToolOwnersIfNewOwner(ownerDerivationCache, sessionId, toolPart.callID, ownerMsgId);
185264
185258
  accAssignToolTag += performance.now() - _tAssignTool;
185265
185259
  messageTagNumbers.set(message, Math.max(messageTagNumbers.get(message) ?? 0, tagId));
185266
185260
  if (!skipPrefixInjection) {
@@ -186259,7 +186253,7 @@ async function runAutoSearchHint(args) {
186259
186253
  embeddingEnabled,
186260
186254
  gitCommitsEnabled,
186261
186255
  embedQuery: async (text, signal) => {
186262
- const result = await embedTextForProject(options.projectPath, text, signal);
186256
+ const result = await embedTextForProject(options.projectPath, text, signal, "query");
186263
186257
  return result?.vector ?? null;
186264
186258
  },
186265
186259
  isEmbeddingRuntimeEnabled: () => embeddingEnabled === true,
@@ -186503,6 +186497,7 @@ function applyHeuristicCleanup(sessionId, db, targets, messageTagNumbers, config
186503
186497
  const maxTag = getMaxTagNumberBySession(db, sessionId);
186504
186498
  const protectedCutoff = maxTag - config2.protectedTags;
186505
186499
  let droppedTools = 0;
186500
+ let emergencyDroppedTools = 0;
186506
186501
  let deduplicatedTools = 0;
186507
186502
  let droppedInjections = 0;
186508
186503
  if (config2.emergency) {
@@ -186534,6 +186529,7 @@ function applyHeuristicCleanup(sessionId, db, targets, messageTagNumbers, config
186534
186529
  updateTagStatus(db, sessionId, tag.tagNumber, "dropped");
186535
186530
  updateTagDropMode(db, sessionId, tag.tagNumber, "full");
186536
186531
  droppedTools++;
186532
+ emergencyDroppedTools++;
186537
186533
  }
186538
186534
  }
186539
186535
  setEmergencyDropSample(db, sessionId, emergency.currentTotalInputTokens);
@@ -186637,6 +186633,7 @@ function applyHeuristicCleanup(sessionId, db, targets, messageTagNumbers, config
186637
186633
  droppedTools,
186638
186634
  deduplicatedTools,
186639
186635
  droppedInjections,
186636
+ emergencyDroppedTools,
186640
186637
  compressedTextTags,
186641
186638
  mutatedTextTags
186642
186639
  };
@@ -186865,7 +186862,6 @@ async function runPostTransformPhase(args) {
186865
186862
  const emergencyDropEligible = args.contextUsage.percentage >= args.forceMaterializationPercentage;
186866
186863
  const activeCompartmentRun = args.canRunCompartments ? getActiveCompartmentRun(args.sessionId) : undefined;
186867
186864
  const compartmentRunning = args.canRunCompartments && !args.awaitedCompartmentRun && activeCompartmentRun !== undefined;
186868
- const emergencyBypassCompartmentGate = forceMaterialization;
186869
186865
  const deferredMaterialize = args.canConsumeDeferredLate && deferredMaterializationWasPending;
186870
186866
  const materializationRequested = isExplicitFlush || deferredMaterialize;
186871
186867
  const m0M1EnabledForFold = args.fullFeatureMode && args.m0M1 !== undefined && (!!args.m0M1.projectPath || !!args.m0M1.projectDirectory);
@@ -186877,11 +186873,12 @@ async function runPostTransformPhase(args) {
186877
186873
  projectDirectory: args.m0M1.projectDirectory,
186878
186874
  hardSignals: args.m0M1.hardSignals
186879
186875
  }).value : false;
186876
+ const bypassCompartmentGate = forceMaterialization || m0HardFoldThisPass;
186880
186877
  const shouldReadPendingOps = materializationRequested || args.schedulerDecision === "execute" || forceMaterialization || m0HardFoldThisPass || compartmentRunning;
186881
186878
  const pendingOps = shouldReadPendingOps ? getPendingOps(args.db, args.sessionId) : [];
186882
186879
  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));
186880
+ const shouldApplyPendingOps = (args.schedulerDecision === "execute" || materializationRequested || forceMaterialization || m0HardFoldThisPass) && (!compartmentRunning || bypassCompartmentGate);
186881
+ const shouldRunHeuristics = (!compartmentRunning || bypassCompartmentGate) && (materializationRequested || forceMaterialization || m0HardFoldThisPass || emergencyDropEligible || args.schedulerDecision === "execute" && (!alreadyRanThisTurn || !args.fullFeatureMode));
186885
186882
  const isCacheBustingPass = shouldApplyPendingOps || shouldRunHeuristics;
186886
186883
  const canUseEmptySentinels = modelAcceptsEmptyContent(args.resolvedProviderID);
186887
186884
  if (shouldRunHeuristics) {
@@ -186893,8 +186890,9 @@ async function runPostTransformPhase(args) {
186893
186890
  sessionLog(args.sessionId, `transform: skipping heuristics (already ran for turn ${args.currentTurnId})`);
186894
186891
  }
186895
186892
  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)}%)`);
186893
+ if (bypassCompartmentGate) {
186894
+ const bypassReason = forceMaterialization ? "emergency >=85%" : "m0 hard fold";
186895
+ sessionLog(args.sessionId, `transform: compartment-gate bypass (${bypassReason}) — applying ${pendingOps.length} pending ops while compartment agent runs (${args.contextUsage.percentage.toFixed(1)}%)`);
186898
186896
  } else {
186899
186897
  sessionLog(args.sessionId, "transform: deferring pending ops — compartment agent in progress");
186900
186898
  }
@@ -186905,12 +186903,22 @@ async function runPostTransformPhase(args) {
186905
186903
  let pendingOpsRanSuccessfully = false;
186906
186904
  let pendingOpsDidMutate = false;
186907
186905
  let heuristicOrReasoningDidMutate = false;
186906
+ let droppedCount = 0;
186907
+ const droppedTokens = 0;
186908
+ let emergency = false;
186909
+ let m0RematerializedThisPass = false;
186910
+ let m0MaterializeReason = null;
186911
+ let m0M1InjectedThisPass = false;
186912
+ let autoReclaimDidMutateThisPass = false;
186908
186913
  try {
186909
186914
  if (shouldApplyPendingOps) {
186910
186915
  const applyReason = isExplicitFlush ? "explicit_flush" : deferredMaterialize ? "deferred_materialization" : `scheduler_execute (scheduler=${args.schedulerDecision})`;
186911
186916
  sessionLog(args.sessionId, `pending ops WILL APPLY — reason=${applyReason}, pendingOps=${pendingOps.length}, context=${args.contextUsage.percentage.toFixed(1)}%`);
186912
186917
  const tApply = performance.now();
186913
186918
  pendingOpsDidMutate = applyPendingOperations(args.sessionId, args.db, args.targets, args.protectedTags, undefined, pendingOps);
186919
+ if (pendingOpsDidMutate) {
186920
+ droppedCount += pendingOps.length;
186921
+ }
186914
186922
  logTransformTiming(args.sessionId, "applyPendingOperations", tApply);
186915
186923
  }
186916
186924
  if (shouldRunHeuristics) {
@@ -186930,8 +186938,10 @@ async function runPostTransformPhase(args) {
186930
186938
  }, heuristicTags);
186931
186939
  logTransformTiming(args.sessionId, "applyHeuristicCleanup", t5, `droppedTools=${cleanup.droppedTools} deduplicatedTools=${cleanup.deduplicatedTools} droppedInjections=${cleanup.droppedInjections} compressedTextTags=${cleanup.compressedTextTags} mutatedTextTags=${cleanup.mutatedTextTags}`);
186932
186940
  const heuristicMutationCount = cleanup.droppedTools + cleanup.deduplicatedTools + cleanup.droppedInjections + cleanup.mutatedTextTags;
186941
+ droppedCount += cleanup.droppedTools + cleanup.deduplicatedTools + cleanup.droppedInjections + cleanup.mutatedTextTags;
186942
+ emergency ||= cleanup.emergencyDroppedTools > 0;
186933
186943
  const t7 = performance.now();
186934
- const clearedReasoning = clearOldReasoning(args.messages, args.reasoningByMessage, args.messageTagNumbers, args.clearReasoningAge);
186944
+ const clearedReasoning = canUseEmptySentinels ? clearOldReasoning(args.messages, args.reasoningByMessage, args.messageTagNumbers, args.clearReasoningAge) : 0;
186935
186945
  if (canUseEmptySentinels) {
186936
186946
  stripClearedReasoning(args.messages);
186937
186947
  }
@@ -186956,6 +186966,7 @@ async function runPostTransformPhase(args) {
186956
186966
  }
186957
186967
  logTransformTiming(args.sessionId, "clearOldReasoning", t7);
186958
186968
  heuristicOrReasoningDidMutate = heuristicMutationCount + clearedReasoning + strippedInline > 0;
186969
+ droppedCount += clearedReasoning + strippedInline;
186959
186970
  if (pendingMaterializationAtPassStart) {
186960
186971
  args.pendingMaterializationSessions.delete(args.sessionId);
186961
186972
  }
@@ -186981,6 +186992,10 @@ async function runPostTransformPhase(args) {
186981
186992
  autoReclaimTargetCount = syntheticPendingOps.length;
186982
186993
  if (syntheticPendingOps.length > 0) {
186983
186994
  autoReclaimDidMutate = applyPendingOperations(args.sessionId, args.db, args.targets, args.protectedTags, undefined, [], syntheticPendingOps);
186995
+ if (autoReclaimDidMutate) {
186996
+ droppedCount += syntheticPendingOps.length;
186997
+ autoReclaimDidMutateThisPass = true;
186998
+ }
186984
186999
  }
186985
187000
  }
186986
187001
  args.batch?.finalize();
@@ -187060,6 +187075,9 @@ async function runPostTransformPhase(args) {
187060
187075
  hardSignals: args.m0M1.hardSignals
187061
187076
  });
187062
187077
  if (result.injected) {
187078
+ m0M1InjectedThisPass = true;
187079
+ m0RematerializedThisPass ||= result.m0RematerializedThisPass;
187080
+ m0MaterializeReason = result.decision.reason ?? m0MaterializeReason;
187063
187081
  sessionLog(args.sessionId, `transform: injected m[0]/m[1] (rematerialized=${result.m0RematerializedThisPass}, reason=${result.decision.reason ?? "cache_hit"})`);
187064
187082
  }
187065
187083
  } catch (error51) {
@@ -187268,7 +187286,19 @@ async function runPostTransformPhase(args) {
187268
187286
  sessionLog(args.sessionId, `sticky-injection GC: pruned ${prunedAnchors} note-nudge anchor(s), ${prunedDecisions} auto-search decision(s)`);
187269
187287
  }
187270
187288
  }
187271
- return { explicitMaterializedSuccessfully, deferredMaterializedSuccessfully };
187289
+ const materializeReason = m0MaterializeReason ?? (explicitMaterializedSuccessfully ? "explicit_flush" : null);
187290
+ const materialized = m0RematerializedThisPass || explicitMaterializedSuccessfully || deferredMaterializedSuccessfully;
187291
+ const bustedThisPass = args.didMutateFromFlushedStatuses || pendingOpsDidMutate || heuristicOrReasoningDidMutate || autoReclaimDidMutateThisPass || m0RematerializedThisPass || m0M1InjectedThisPass && historyWasConsumedThisPass || historyWasConsumedThisPass;
187292
+ return {
187293
+ explicitMaterializedSuccessfully,
187294
+ deferredMaterializedSuccessfully,
187295
+ materialized,
187296
+ materializeReason,
187297
+ droppedTokens,
187298
+ droppedCount,
187299
+ emergency,
187300
+ bustedThisPass
187301
+ };
187272
187302
  }
187273
187303
  function checkM0MutationDriftAndSignal(args) {
187274
187304
  const currentMaxMutationId = getMaxM0MutationId(args.db, args.sessionId) ?? 0;
@@ -187303,6 +187333,12 @@ function clearMessageTokensCache(sessionId, messageId) {
187303
187333
  cache.delete(messageId);
187304
187334
  }
187305
187335
  var recordedSessionProjectIdentity = new BoundedSessionMap(MESSAGE_TOKENS_CACHE_MAX);
187336
+ function deriveTaggerLoadFloor(messages, sessionId, db) {
187337
+ return deriveTagLoadFloor(db, sessionId, function* () {
187338
+ for (const message of messages)
187339
+ yield message.info?.id;
187340
+ }());
187341
+ }
187306
187342
  function findLastAssistantModel2(messages) {
187307
187343
  for (let i = messages.length - 1;i >= 0; i--) {
187308
187344
  const info = messages[i].info;
@@ -187325,6 +187361,7 @@ function createTransform(deps) {
187325
187361
  return;
187326
187362
  }
187327
187363
  const resolvedSessionId = sessionId;
187364
+ clearOpenCodePendingTransformDecision(sessionId);
187328
187365
  logTransformTiming(sessionId, "findSessionId", startTime, `messages=${messages.length}`);
187329
187366
  const db = deps.db;
187330
187367
  if (deps.client !== undefined) {
@@ -187627,12 +187664,16 @@ Historian previously failed ${historianFailureState.failureCount} time(s), so Ma
187627
187664
  recordSessionProjectIdentity(db, sessionId, sessionProjectIdentity);
187628
187665
  recordedSessionProjectIdentity.set(sessionId, sessionProjectIdentity);
187629
187666
  }
187667
+ const taggerFloor = deriveTaggerLoadFloor(messages, sessionId, db);
187668
+ if (taggerFloor === 0 && messages.length > 0) {
187669
+ sessionLog(sessionId, `tag floor: 0 (full-scan fallback) — no leading wire message resolved a tag across ${messages.length} msgs`);
187670
+ }
187630
187671
  let triggerBoundarySnapshot;
187631
187672
  if (fullFeatureMode && historianRunnable && !sessionMeta.compartmentInProgress) {
187632
187673
  const tTrigger = performance.now();
187633
187674
  try {
187634
187675
  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);
187676
+ const triggerResult = checkCompartmentTrigger(db, sessionId, sessionMeta, boundaryUsageForProtectedTail, sessionMeta.lastContextPercentage, boundaryExecuteThreshold, deriveTriggerBudget(boundaryContextLimit, boundaryExecuteThreshold), deps.clearReasoningAge, deps.commitClusterTrigger, undefined, boundaryContextLimit, inMemoryTail, taggerFloor);
187636
187677
  if (triggerResult.shouldFire) {
187637
187678
  sessionLog(sessionId, `compartment trigger: firing (reason=${triggerResult.reason})`);
187638
187679
  updateSessionMeta(db, sessionId, { compartmentInProgress: true });
@@ -187674,7 +187715,7 @@ Historian previously failed ${historianFailureState.failureCount} time(s), so Ma
187674
187715
  try {
187675
187716
  const t0 = performance.now();
187676
187717
  const tInitFromDb = performance.now();
187677
- deps.tagger.initFromDb(sessionId, db);
187718
+ deps.tagger.initFromDb(sessionId, db, taggerFloor);
187678
187719
  logTransformTiming(sessionId, "tag.initFromDb", tInitFromDb);
187679
187720
  const skipPrefixInjection = !ctxReduceEnabledEffective;
187680
187721
  const result = tagMessages(sessionId, messages, deps.tagger, db, {
@@ -187726,7 +187767,7 @@ Historian previously failed ${historianFailureState.failureCount} time(s), so Ma
187726
187767
  const persistedReasoningWatermark = sessionMeta?.clearedReasoningThroughTag ?? 0;
187727
187768
  if (persistedReasoningWatermark > 0) {
187728
187769
  const tReplay = performance.now();
187729
- const replayed = replayClearedReasoning(messages, reasoningByMessage, messageTagNumbers, persistedReasoningWatermark);
187770
+ const replayed = canUseEmptySentinels ? replayClearedReasoning(messages, reasoningByMessage, messageTagNumbers, persistedReasoningWatermark) : 0;
187730
187771
  const replayedInline = replayStrippedInlineThinking(messages, messageTagNumbers, persistedReasoningWatermark);
187731
187772
  if (replayed > 0 || replayedInline > 0) {
187732
187773
  sessionLog(sessionId, `reasoning replay: cleared=${replayed} inlineStripped=${replayedInline} (watermark=${persistedReasoningWatermark})`);
@@ -187824,7 +187865,7 @@ Historian previously failed ${historianFailureState.failureCount} time(s), so Ma
187824
187865
  const wasEmergencyBlock = contextUsageEarly.percentage >= FORCE_MATERIALIZE_PERCENTAGE && compartmentPhase.justAwaitedPublication;
187825
187866
  const historyRebuiltThisPass = wasEmergencyBlock ? compartmentPhase.rebuiltHistoryThisPass : rebuiltHistoryFromInitialPrepare || compartmentPhase.rebuiltHistoryThisPass;
187826
187867
  const tPostProcess = performance.now();
187827
- await runPostTransformPhase({
187868
+ const postTransformResult = await runPostTransformPhase({
187828
187869
  sessionId,
187829
187870
  db,
187830
187871
  messages,
@@ -187878,6 +187919,19 @@ Historian previously failed ${historianFailureState.failureCount} time(s), so Ma
187878
187919
  hardSignals: m0HardSignals
187879
187920
  }
187880
187921
  });
187922
+ if (postTransformResult.bustedThisPass) {
187923
+ recordPendingTransformDecision(sessionId, {
187924
+ tsMs: Date.now(),
187925
+ decision: schedulerDecision,
187926
+ materialized: postTransformResult.materialized,
187927
+ materializeReason: normalizeMaterializeReason("opencode", postTransformResult.materializeReason, postTransformResult.materialized),
187928
+ emergency: postTransformResult.emergency,
187929
+ droppedTokens: postTransformResult.droppedTokens,
187930
+ droppedCount: postTransformResult.droppedCount,
187931
+ inputTokens: contextUsage.inputTokens,
187932
+ bustedThisPass: true
187933
+ });
187934
+ }
187881
187935
  logTransformTiming(sessionId, "postTransformPhase", tPostProcess);
187882
187936
  const msgTokens = getMessageTokensCache(sessionId);
187883
187937
  let storedByMessage;
@@ -188259,6 +188313,15 @@ function createEventHandler2(deps) {
188259
188313
  info.tokens?.cache?.write
188260
188314
  ];
188261
188315
  const hasUsageTokens = usageTokens.some((value) => typeof value === "number" && value > 0);
188316
+ const terminalAssistantUpdate = info.messageID !== undefined && hasUsageTokens && (typeof info.finish === "string" || typeof info.completedAt === "number");
188317
+ if (terminalAssistantUpdate && info.messageID) {
188318
+ scheduleOpenCodeTransformDecisionWrite({
188319
+ db: deps.db,
188320
+ sessionId: info.sessionID,
188321
+ messageId: info.messageID,
188322
+ inputTokens: (info.tokens?.input ?? 0) + (info.tokens?.cache?.read ?? 0) + (info.tokens?.cache?.write ?? 0)
188323
+ });
188324
+ }
188262
188325
  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
188326
  const hasKnownUsage = hasUsageTokens || deps.contextUsageMap.has(info.sessionID);
188264
188327
  if (!hasKnownUsage) {
@@ -188416,6 +188479,7 @@ function createEventHandler2(deps) {
188416
188479
  deps.onSessionDeleted?.(sessionId);
188417
188480
  deps.contextUsageMap.delete(sessionId);
188418
188481
  deps.tagger.cleanup(sessionId);
188482
+ clearTransformDecisionSession(sessionId);
188419
188483
  clearMessageTokensCache(sessionId);
188420
188484
  invalidateTrueRawTokenCache({ sessionId, reason: "session.deleted" });
188421
188485
  return;
@@ -189143,7 +189207,7 @@ function createMagicContextHook(deps) {
189143
189207
  }
189144
189208
  let lastScheduleCheckMs = 0;
189145
189209
  const getHistorianChunkTokens = () => deriveHistorianChunkTokens(resolveHistorianContextLimit(deps.config.historian?.model));
189146
- const historianFallbackModels = resolveFallbackChain(HISTORIAN_AGENT, deps.config.historian?.fallback_models);
189210
+ const historianFallbackModels = resolveFallbackChain(deps.config.historian?.fallback_models);
189147
189211
  const historyRefreshSessions = deps.liveSessionState?.historyRefreshSessions ?? new Set;
189148
189212
  const deferredHistoryRefreshSessions = deps.liveSessionState?.deferredHistoryRefreshSessions ?? new Set;
189149
189213
  try {
@@ -189471,7 +189535,7 @@ function createMagicContextHook(deps) {
189471
189535
  token_budget: dreaming.pin_key_files.token_budget,
189472
189536
  min_reads: dreaming.pin_key_files.min_reads
189473
189537
  } : undefined,
189474
- fallbackModels: resolveFallbackChain(DREAMER_AGENT, dreaming.fallback_models),
189538
+ fallbackModels: resolveFallbackChain(dreaming.fallback_models),
189475
189539
  projectIdentity: projectPath
189476
189540
  }).catch((error51) => {
189477
189541
  log("[dreamer] scheduled queue processing failed:", error51);
@@ -189530,7 +189594,7 @@ function createMagicContextHook(deps) {
189530
189594
  token_budget: dreamerConfig.pin_key_files.token_budget,
189531
189595
  min_reads: dreamerConfig.pin_key_files.min_reads
189532
189596
  } : undefined,
189533
- fallbackModels: resolveFallbackChain(DREAMER_AGENT, dreamerConfig.fallback_models)
189597
+ fallbackModels: resolveFallbackChain(dreamerConfig.fallback_models)
189534
189598
  } : undefined
189535
189599
  });
189536
189600
  const systemPromptHash = createSystemPromptHashHandler({
@@ -190506,8 +190570,7 @@ function registerRpcHandlers(rpcServer, args) {
190506
190570
  });
190507
190571
  const buildManagedCtx = async (db) => {
190508
190572
  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);
190573
+ const { resolveFallbackChain: resolveFallbackChain2 } = await Promise.resolve().then(() => exports_resolve_fallbacks);
190511
190574
  const DEFAULT_HISTORIAN_TIMEOUT_MS2 = 600000;
190512
190575
  return {
190513
190576
  client: args.client,
@@ -190518,7 +190581,7 @@ function registerRpcHandlers(rpcServer, args) {
190518
190581
  historianTimeoutMs: config2.historian_timeout_ms ?? DEFAULT_HISTORIAN_TIMEOUT_MS2,
190519
190582
  memoryEnabled: config2.memory?.enabled ?? true,
190520
190583
  autoPromote: config2.memory?.auto_promote ?? true,
190521
- fallbackModels: resolveFallbackChain2(HISTORIAN_AGENT2, config2.historian?.fallback_models),
190584
+ fallbackModels: resolveFallbackChain2(config2.historian?.fallback_models),
190522
190585
  runMigration: config2.memory?.enabled !== false && !!config2.historian?.model,
190523
190586
  userMemoriesEnabled: config2.dreamer?.user_memories?.enabled === true,
190524
190587
  historianTwoPass: config2.historian?.two_pass === true,
@@ -190870,6 +190933,7 @@ Actions:
190870
190933
  Example: ctx_memory(action="write", category="CONSTRAINTS", content="Pi stores sessions as JSONL under ~/.pi/agent/sessions/, not SQLite")`;
190871
190934
  var DEFAULT_SEARCH_LIMIT2 = 10;
190872
190935
  // src/tools/ctx-memory/tools.ts
190936
+ import { tool as tool2 } from "@opencode-ai/plugin";
190873
190937
  init_memory();
190874
190938
  init_embedding();
190875
190939
  init_embedding_cache();
@@ -190877,7 +190941,6 @@ init_normalize_hash();
190877
190941
  init_workspaces();
190878
190942
  init_logger();
190879
190943
  await init_storage();
190880
- import { tool as tool2 } from "@opencode-ai/plugin";
190881
190944
 
190882
190945
  // src/tools/ctx-memory/types.ts
190883
190946
  var CTX_MEMORY_ACTIONS = ["write", "archive", "update", "merge"];
@@ -191802,7 +191865,7 @@ function createCtxSearchTool(deps) {
191802
191865
  memoryEnabled,
191803
191866
  embeddingEnabled,
191804
191867
  embedQuery: async (text, signal) => {
191805
- const result = await embedTextForProject(projectPath, text, signal);
191868
+ const result = await embedTextForProject(projectPath, text, signal, "query");
191806
191869
  return result?.vector ?? null;
191807
191870
  },
191808
191871
  isEmbeddingRuntimeEnabled: () => embeddingEnabled === true,
@@ -191905,14 +191968,13 @@ function createToolRegistry(args) {
191905
191968
  init_conflict_detector();
191906
191969
  init_data_path();
191907
191970
  init_logger();
191908
- init_model_requirements();
191909
191971
  init_models_dev_cache();
191910
191972
 
191911
191973
  // src/shared/rpc-server.ts
191912
191974
  init_logger();
191913
191975
  import { randomBytes, timingSafeEqual } from "node:crypto";
191914
191976
  import {
191915
- mkdirSync as mkdirSync8,
191977
+ mkdirSync as mkdirSync7,
191916
191978
  readdirSync,
191917
191979
  readFileSync as readFileSync12,
191918
191980
  renameSync as renameSync2,
@@ -191920,20 +191982,20 @@ import {
191920
191982
  writeFileSync as writeFileSync5
191921
191983
  } from "node:fs";
191922
191984
  import { createServer } from "node:http";
191923
- import { dirname as dirname5 } from "node:path";
191985
+ import { dirname as dirname4 } from "node:path";
191924
191986
 
191925
191987
  // src/shared/rpc-utils.ts
191926
191988
  import { createHash as createHash13 } from "node:crypto";
191927
- import { join as join20 } from "node:path";
191989
+ import { join as join19 } from "node:path";
191928
191990
  function projectHash(directory) {
191929
191991
  const normalized = directory.replace(/\/+$/, "");
191930
191992
  return createHash13("sha256").update(normalized).digest("hex").slice(0, 16);
191931
191993
  }
191932
191994
  function rpcPortDir(storageDir, directory) {
191933
- return join20(storageDir, "rpc", projectHash(directory));
191995
+ return join19(storageDir, "rpc", projectHash(directory));
191934
191996
  }
191935
191997
  function rpcPortFilePath(storageDir, directory, pid = process.pid) {
191936
- return join20(rpcPortDir(storageDir, directory), `port-${pid}.json`);
191998
+ return join19(rpcPortDir(storageDir, directory), `port-${pid}.json`);
191937
191999
  }
191938
192000
  function isPidAlive(pid) {
191939
192001
  if (!Number.isInteger(pid) || pid <= 0)
@@ -192017,8 +192079,8 @@ class MagicContextRpcServer {
192017
192079
  this.server = server2;
192018
192080
  try {
192019
192081
  this.warnIfOtherLiveInstance();
192020
- const dir = dirname5(this.portFilePath);
192021
- mkdirSync8(dir, { recursive: true, mode: 448 });
192082
+ const dir = dirname4(this.portFilePath);
192083
+ mkdirSync7(dir, { recursive: true, mode: 448 });
192022
192084
  const tmpPath = `${this.portFilePath}.tmp`;
192023
192085
  writeFileSync5(tmpPath, JSON.stringify({
192024
192086
  port: this.port,
@@ -192313,14 +192375,13 @@ var plugin = async (ctx) => {
192313
192375
  await hooks.magicContext?.["experimental.text.complete"]?.(input, output);
192314
192376
  },
192315
192377
  config: async (config2) => {
192316
- const buildHiddenAgentConfig = (agentId, prompt, allowedTools, maxSteps, overrides) => {
192378
+ const buildHiddenAgentConfig = (prompt, allowedTools, maxSteps, overrides) => {
192317
192379
  const { permission: overridePermission, ...restOverrides } = overrides ?? {};
192318
192380
  const basePermission = buildAllowOnlyPermission(allowedTools);
192319
192381
  return {
192320
192382
  prompt,
192321
192383
  steps: maxSteps,
192322
192384
  maxSteps,
192323
- ...getAgentFallbackModels(agentId) ? { fallback_models: getAgentFallbackModels(agentId) } : {},
192324
192385
  ...restOverrides,
192325
192386
  permission: {
192326
192387
  ...basePermission,
@@ -192342,6 +192403,7 @@ var plugin = async (ctx) => {
192342
192403
  max_runtime_minutes: _max,
192343
192404
  tasks: _tasks,
192344
192405
  task_timeout_minutes: _tto,
192406
+ thinking_level: _thinkingLevel,
192345
192407
  ...agentOverrides
192346
192408
  } = pluginConfig.dreamer;
192347
192409
  return agentOverrides;
@@ -192350,20 +192412,28 @@ var plugin = async (ctx) => {
192350
192412
  const {
192351
192413
  timeout_ms: _timeoutMs,
192352
192414
  system_prompt: _systemPrompt,
192415
+ thinking_level: _thinkingLevel,
192353
192416
  ...agentOverrides
192354
192417
  } = pluginConfig.sidekick;
192355
192418
  return agentOverrides;
192356
192419
  })() : undefined;
192357
192420
  const historianAgentOverrides = pluginConfig.historian ? (() => {
192358
- const { two_pass: _twoPass, ...agentOverrides } = pluginConfig.historian;
192421
+ const {
192422
+ two_pass: _twoPass,
192423
+ disallowed_tools: _disallowedTools,
192424
+ thinking_level: _thinkingLevel,
192425
+ ...agentOverrides
192426
+ } = pluginConfig.historian;
192359
192427
  return agentOverrides;
192360
192428
  })() : undefined;
192429
+ const historianDisallowed = pluginConfig.historian?.disallowed_tools ?? [];
192430
+ const historianAllowedTools = applyDisallowedTools(HISTORIAN_ALLOWED_TOOLS, historianDisallowed);
192361
192431
  config2.agent = {
192362
192432
  ...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)
192433
+ [DREAMER_AGENT]: buildHiddenAgentConfig(DREAMER_SYSTEM_PROMPT, DREAMER_ALLOWED_TOOLS, DREAMER_MAX_STEPS, dreamerAgentOverrides),
192434
+ [HISTORIAN_AGENT]: buildHiddenAgentConfig(COMPARTMENT_AGENT_SYSTEM_PROMPT, historianAllowedTools, HISTORIAN_MAX_STEPS, historianAgentOverrides),
192435
+ [HISTORIAN_EDITOR_AGENT]: buildHiddenAgentConfig(HISTORIAN_EDITOR_SYSTEM_PROMPT, historianAllowedTools, HISTORIAN_MAX_STEPS, historianAgentOverrides),
192436
+ [SIDEKICK_AGENT]: buildHiddenAgentConfig(SIDEKICK_SYSTEM_PROMPT, SIDEKICK_ALLOWED_TOOLS, SIDEKICK_MAX_STEPS, sidekickAgentOverrides)
192367
192437
  };
192368
192438
  }
192369
192439
  };