@cortexkit/opencode-magic-context 0.9.0 → 0.10.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (34) hide show
  1. package/README.md +1 -1
  2. package/dist/cli/doctor.d.ts.map +1 -1
  3. package/dist/cli.js +6 -3
  4. package/dist/config/schema/magic-context.d.ts +0 -4
  5. package/dist/config/schema/magic-context.d.ts.map +1 -1
  6. package/dist/hooks/magic-context/compartment-runner-types.d.ts +6 -1
  7. package/dist/hooks/magic-context/compartment-runner-types.d.ts.map +1 -1
  8. package/dist/hooks/magic-context/compartment-trigger.d.ts +1 -1
  9. package/dist/hooks/magic-context/compartment-trigger.d.ts.map +1 -1
  10. package/dist/hooks/magic-context/derive-budgets.d.ts +57 -0
  11. package/dist/hooks/magic-context/derive-budgets.d.ts.map +1 -0
  12. package/dist/hooks/magic-context/event-handler.d.ts +0 -1
  13. package/dist/hooks/magic-context/event-handler.d.ts.map +1 -1
  14. package/dist/hooks/magic-context/event-resolvers.d.ts +1 -3
  15. package/dist/hooks/magic-context/event-resolvers.d.ts.map +1 -1
  16. package/dist/hooks/magic-context/hook.d.ts +3 -2
  17. package/dist/hooks/magic-context/hook.d.ts.map +1 -1
  18. package/dist/hooks/magic-context/inject-compartments.d.ts.map +1 -1
  19. package/dist/hooks/magic-context/nudge-injection.d.ts.map +1 -1
  20. package/dist/hooks/magic-context/transform-compartment-phase.d.ts +1 -1
  21. package/dist/hooks/magic-context/transform-compartment-phase.d.ts.map +1 -1
  22. package/dist/hooks/magic-context/transform-postprocess-phase.d.ts.map +1 -1
  23. package/dist/hooks/magic-context/transform.d.ts +7 -1
  24. package/dist/hooks/magic-context/transform.d.ts.map +1 -1
  25. package/dist/index.d.ts.map +1 -1
  26. package/dist/index.js +293 -142
  27. package/dist/plugin/hooks/create-session-hooks.d.ts.map +1 -1
  28. package/dist/plugin/rpc-handlers.d.ts.map +1 -1
  29. package/dist/plugin/tui-action-consumer.d.ts.map +1 -1
  30. package/dist/shared/models-dev-cache.d.ts +52 -4
  31. package/dist/shared/models-dev-cache.d.ts.map +1 -1
  32. package/package.json +1 -1
  33. package/src/shared/models-dev-cache.test.ts +228 -0
  34. package/src/shared/models-dev-cache.ts +146 -28
package/dist/index.js CHANGED
@@ -14070,7 +14070,7 @@ var init_agent_overrides = __esm(() => {
14070
14070
  });
14071
14071
 
14072
14072
  // src/config/schema/magic-context.ts
14073
- var DEFAULT_NUDGE_INTERVAL_TOKENS = 1e4, DEFAULT_EXECUTE_THRESHOLD_PERCENTAGE = 65, DEFAULT_COMPARTMENT_TOKEN_BUDGET = 20000, 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, DreamerConfigSchema, SidekickConfigSchema, BaseEmbeddingConfigSchema, EmbeddingConfigSchema, MagicContextConfigSchema;
14073
+ var DEFAULT_NUDGE_INTERVAL_TOKENS = 1e4, DEFAULT_EXECUTE_THRESHOLD_PERCENTAGE = 65, 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, DreamerConfigSchema, SidekickConfigSchema, BaseEmbeddingConfigSchema, EmbeddingConfigSchema, MagicContextConfigSchema;
14074
14074
  var init_magic_context = __esm(() => {
14075
14075
  init_zod();
14076
14076
  init_agent_overrides();
@@ -14156,7 +14156,6 @@ var init_magic_context = __esm(() => {
14156
14156
  drop_tool_structure: exports_external.boolean().default(true),
14157
14157
  clear_reasoning_age: exports_external.number().min(10).default(50),
14158
14158
  iteration_nudge_threshold: exports_external.number().min(5).default(15),
14159
- compartment_token_budget: exports_external.number().min(1e4).default(DEFAULT_COMPARTMENT_TOKEN_BUDGET),
14160
14159
  history_budget_percentage: exports_external.number().min(0.05).max(0.5).default(DEFAULT_HISTORY_BUDGET_PERCENTAGE),
14161
14160
  historian_timeout_ms: exports_external.number().min(60000).default(DEFAULT_HISTORIAN_TIMEOUT_MS),
14162
14161
  commit_cluster_trigger: exports_external.object({
@@ -18374,6 +18373,145 @@ var init_storage = __esm(() => {
18374
18373
  init_storage_tags();
18375
18374
  });
18376
18375
 
18376
+ // src/shared/models-dev-cache.ts
18377
+ import { createHash } from "crypto";
18378
+ import { existsSync as existsSync5, readFileSync as readFileSync4 } from "fs";
18379
+ import { homedir as homedir5, platform as platform2 } from "os";
18380
+ import { join as join11 } from "path";
18381
+ function hashFast(input) {
18382
+ return createHash("sha1").update(input).digest("hex");
18383
+ }
18384
+ function getModelsJsonPath() {
18385
+ const explicit = process.env.OPENCODE_MODELS_PATH?.trim();
18386
+ if (explicit)
18387
+ return explicit;
18388
+ const xdgCache = process.env.XDG_CACHE_HOME;
18389
+ const os3 = platform2();
18390
+ let cacheBase;
18391
+ if (xdgCache) {
18392
+ cacheBase = xdgCache;
18393
+ } else if (os3 === "win32") {
18394
+ cacheBase = process.env.LOCALAPPDATA ?? join11(homedir5(), "AppData", "Local");
18395
+ } else {
18396
+ cacheBase = join11(homedir5(), ".cache");
18397
+ }
18398
+ const source = process.env.OPENCODE_MODELS_URL?.trim();
18399
+ const filename = source && source !== "https://models.dev" ? `models-${hashFast(source)}.json` : "models.json";
18400
+ return join11(cacheBase, "opencode", filename);
18401
+ }
18402
+ function getOpencodeConfigPath() {
18403
+ const envDir = process.env.OPENCODE_CONFIG_DIR?.trim();
18404
+ const configDir = envDir ? envDir : platform2() === "win32" ? join11(homedir5(), ".config", "opencode") : join11(process.env.XDG_CONFIG_HOME || join11(homedir5(), ".config"), "opencode");
18405
+ const jsonc = join11(configDir, "opencode.jsonc");
18406
+ if (existsSync5(jsonc))
18407
+ return jsonc;
18408
+ const json2 = join11(configDir, "opencode.json");
18409
+ if (existsSync5(json2))
18410
+ return json2;
18411
+ return null;
18412
+ }
18413
+ function loadModelsDevLimitsFromFile() {
18414
+ const limits = new Map;
18415
+ const modelsJsonPath = getModelsJsonPath();
18416
+ let fileFound = false;
18417
+ try {
18418
+ if (existsSync5(modelsJsonPath)) {
18419
+ fileFound = true;
18420
+ const raw = readFileSync4(modelsJsonPath, "utf-8");
18421
+ const data = JSON.parse(raw);
18422
+ for (const [providerId, provider2] of Object.entries(data)) {
18423
+ if (!provider2?.models || typeof provider2.models !== "object")
18424
+ continue;
18425
+ for (const [modelId, model] of Object.entries(provider2.models)) {
18426
+ const context = model?.limit?.context;
18427
+ if (typeof context === "number" && context > 0) {
18428
+ limits.set(`${providerId}/${modelId}`, context);
18429
+ const modes = model?.experimental?.modes;
18430
+ if (modes && typeof modes === "object") {
18431
+ for (const mode of Object.keys(modes)) {
18432
+ limits.set(`${providerId}/${modelId}-${mode}`, context);
18433
+ }
18434
+ }
18435
+ }
18436
+ }
18437
+ }
18438
+ }
18439
+ } catch (error48) {
18440
+ sessionLog("global", `models-dev-cache: failed to read models.json at ${modelsJsonPath}:`, error48 instanceof Error ? error48.message : String(error48));
18441
+ }
18442
+ try {
18443
+ const configPath = getOpencodeConfigPath();
18444
+ if (configPath && existsSync5(configPath)) {
18445
+ let raw = readFileSync4(configPath, "utf-8");
18446
+ raw = raw.replace(/"(?:[^"\\]|\\.)*"|\/\/.*$/gm, (match) => match.startsWith('"') ? match : "");
18447
+ const config2 = JSON.parse(raw);
18448
+ if (config2.provider && typeof config2.provider === "object") {
18449
+ for (const [providerId, provider2] of Object.entries(config2.provider)) {
18450
+ if (!provider2?.models || typeof provider2.models !== "object")
18451
+ continue;
18452
+ for (const [modelId, model] of Object.entries(provider2.models)) {
18453
+ const context = model?.limit?.context;
18454
+ if (typeof context === "number" && context > 0) {
18455
+ limits.set(`${providerId}/${modelId}`, context);
18456
+ }
18457
+ }
18458
+ }
18459
+ }
18460
+ }
18461
+ } catch (error48) {
18462
+ sessionLog("global", "models-dev-cache: failed to read opencode config for custom models:", error48 instanceof Error ? error48.message : String(error48));
18463
+ }
18464
+ sessionLog("global", `models-dev-cache: file-layer loaded ${limits.size} model limits (modelsJsonPath=${modelsJsonPath}, found=${fileFound})`);
18465
+ return limits;
18466
+ }
18467
+ async function refreshModelLimitsFromApi(client) {
18468
+ try {
18469
+ const result = await client.config.providers();
18470
+ const data = result.data;
18471
+ const providers = data?.providers;
18472
+ if (!Array.isArray(providers)) {
18473
+ sessionLog("global", "models-dev-cache: API refresh returned no providers payload");
18474
+ return;
18475
+ }
18476
+ const map2 = new Map;
18477
+ for (const entry of providers) {
18478
+ const p = entry;
18479
+ if (!p?.id || !p.models || typeof p.models !== "object")
18480
+ continue;
18481
+ for (const [modelId, model] of Object.entries(p.models)) {
18482
+ const context = model?.limit?.context;
18483
+ if (typeof context === "number" && context > 0) {
18484
+ map2.set(`${p.id}/${modelId}`, context);
18485
+ }
18486
+ }
18487
+ }
18488
+ apiCache = map2;
18489
+ apiLoadedAt = Date.now();
18490
+ sessionLog("global", `models-dev-cache: API layer loaded ${map2.size} model limits`);
18491
+ } catch (error48) {
18492
+ sessionLog("global", "models-dev-cache: API refresh failed:", error48 instanceof Error ? error48.message : String(error48));
18493
+ }
18494
+ }
18495
+ function getModelsDevContextLimit(providerID, modelID) {
18496
+ const key = `${providerID}/${modelID}`;
18497
+ if (apiCache) {
18498
+ const fromApi = apiCache.get(key);
18499
+ if (typeof fromApi === "number")
18500
+ return fromApi;
18501
+ }
18502
+ const now = Date.now();
18503
+ if (!fileCache || now - fileLastAttempt > RELOAD_INTERVAL_MS) {
18504
+ fileLastAttempt = now;
18505
+ fileCache = loadModelsDevLimitsFromFile();
18506
+ }
18507
+ return fileCache.get(key);
18508
+ }
18509
+ var RELOAD_INTERVAL_MS, apiCache = null, apiLoadedAt = 0, fileCache = null, fileLastAttempt = 0;
18510
+ var init_models_dev_cache = __esm(() => {
18511
+ init_logger();
18512
+ RELOAD_INTERVAL_MS = 5 * 60 * 1000;
18513
+ });
18514
+
18377
18515
  // src/features/magic-context/memory/project-identity.ts
18378
18516
  import { execSync } from "child_process";
18379
18517
  import path3 from "path";
@@ -18566,6 +18704,67 @@ var init_send_session_notification = __esm(() => {
18566
18704
  init_logger();
18567
18705
  });
18568
18706
 
18707
+ // src/hooks/magic-context/derive-budgets.ts
18708
+ var exports_derive_budgets = {};
18709
+ __export(exports_derive_budgets, {
18710
+ resolveHistorianContextLimit: () => resolveHistorianContextLimit,
18711
+ deriveTriggerBudget: () => deriveTriggerBudget,
18712
+ deriveHistorianChunkTokens: () => deriveHistorianChunkTokens
18713
+ });
18714
+ function deriveTriggerBudget(mainContextLimit, executeThresholdPercentage) {
18715
+ if (!Number.isFinite(mainContextLimit) || mainContextLimit <= 0) {
18716
+ return TRIGGER_BUDGET_MIN;
18717
+ }
18718
+ const thresholdFraction = Math.max(0, executeThresholdPercentage) / 100;
18719
+ const usable = mainContextLimit * thresholdFraction;
18720
+ const derived = Math.round(usable * TRIGGER_BUDGET_PERCENTAGE);
18721
+ return Math.max(TRIGGER_BUDGET_MIN, Math.min(TRIGGER_BUDGET_MAX, derived));
18722
+ }
18723
+ function deriveHistorianChunkTokens(historianContextLimit) {
18724
+ if (!Number.isFinite(historianContextLimit) || historianContextLimit <= 0) {
18725
+ return HISTORIAN_CHUNK_MIN;
18726
+ }
18727
+ const derived = Math.round(historianContextLimit * HISTORIAN_CHUNK_PERCENTAGE);
18728
+ return Math.max(HISTORIAN_CHUNK_MIN, Math.min(HISTORIAN_CHUNK_MAX, derived));
18729
+ }
18730
+ function resolveHistorianContextLimit(historianModelOverride) {
18731
+ if (typeof historianModelOverride === "string" && historianModelOverride.includes("/")) {
18732
+ const [providerID, ...rest] = historianModelOverride.split("/");
18733
+ const modelID = rest.join("/");
18734
+ if (providerID && modelID) {
18735
+ const limit = getModelsDevContextLimit(providerID, modelID);
18736
+ if (typeof limit === "number" && limit > 0)
18737
+ return limit;
18738
+ }
18739
+ return DEFAULT_HISTORIAN_CONTEXT_FALLBACK;
18740
+ }
18741
+ if (typeof historianModelOverride === "string" && historianModelOverride.trim() !== "") {
18742
+ console.warn(`[magic-context] historian.model "${historianModelOverride}" lacks provider prefix ("provider/model-id"); using fallback chain for chunk-budget derivation.`);
18743
+ }
18744
+ const chain = AGENT_MODEL_REQUIREMENTS[HISTORIAN_AGENT]?.fallbackChain;
18745
+ if (!chain || chain.length === 0)
18746
+ return DEFAULT_HISTORIAN_CONTEXT_FALLBACK;
18747
+ const expanded = expandFallbackChain(chain);
18748
+ let minLimit;
18749
+ for (const key of expanded) {
18750
+ const [providerID, ...rest] = key.split("/");
18751
+ const modelID = rest.join("/");
18752
+ if (!providerID || !modelID)
18753
+ continue;
18754
+ const limit = getModelsDevContextLimit(providerID, modelID);
18755
+ if (typeof limit !== "number" || limit <= 0)
18756
+ continue;
18757
+ if (minLimit === undefined || limit < minLimit)
18758
+ minLimit = limit;
18759
+ }
18760
+ return minLimit ?? DEFAULT_HISTORIAN_CONTEXT_FALLBACK;
18761
+ }
18762
+ 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;
18763
+ var init_derive_budgets = __esm(() => {
18764
+ init_model_requirements();
18765
+ init_models_dev_cache();
18766
+ });
18767
+
18569
18768
  // src/features/magic-context/compaction-marker.ts
18570
18769
  import { Database as Database4 } from "bun:sqlite";
18571
18770
  import { join as join12 } from "path";
@@ -19838,10 +20037,6 @@ function prepareCompartmentInjection(db, sessionId, messages, isCacheBusting, pr
19838
20037
  return cached2;
19839
20038
  }
19840
20039
  const compartments = getCompartments(db, sessionId);
19841
- if (compartments.length === 0) {
19842
- injectionCache.delete(sessionId);
19843
- return null;
19844
- }
19845
20040
  const facts = getSessionFacts(db, sessionId);
19846
20041
  let memoryBlock;
19847
20042
  let memoryCount = 0;
@@ -19860,7 +20055,24 @@ function prepareCompartmentInjection(db, sessionId, messages, isCacheBusting, pr
19860
20055
  db.prepare("UPDATE session_meta SET memory_block_cache = ?, memory_block_count = ? WHERE session_id = ?").run(memoryBlock ?? "", memoryCount, sessionId);
19861
20056
  }
19862
20057
  }
20058
+ if (compartments.length === 0 && facts.length === 0 && !memoryBlock) {
20059
+ injectionCache.delete(sessionId);
20060
+ return null;
20061
+ }
19863
20062
  const block = buildCompartmentBlock(compartments, facts, memoryBlock);
20063
+ if (compartments.length === 0) {
20064
+ const result2 = {
20065
+ block,
20066
+ compartmentEndMessage: 0,
20067
+ compartmentEndMessageId: "",
20068
+ compartmentCount: 0,
20069
+ skippedVisibleMessages: 0,
20070
+ factCount: facts.length,
20071
+ memoryCount
20072
+ };
20073
+ injectionCache.set(sessionId, result2);
20074
+ return result2;
20075
+ }
19864
20076
  const lastCompartment = compartments[compartments.length - 1];
19865
20077
  const lastEnd = lastCompartment.endMessage;
19866
20078
  const lastEndMessageId = lastCompartment.endMessageId;
@@ -19917,7 +20129,11 @@ ${prepared.block}
19917
20129
  ${textPart.text}`;
19918
20130
  }
19919
20131
  const memoryLabel = prepared.memoryCount > 0 ? ` + ${prepared.memoryCount} memories` : "";
19920
- sessionLog(sessionId, `injected ${prepared.compartmentCount} compartments + ${prepared.factCount} facts${memoryLabel} into message[0]`);
20132
+ if (prepared.compartmentCount > 0) {
20133
+ sessionLog(sessionId, `injected ${prepared.compartmentCount} compartments + ${prepared.factCount} facts${memoryLabel} into message[0]`);
20134
+ } else {
20135
+ sessionLog(sessionId, `injected ${prepared.factCount} facts${memoryLabel} into message[0] (no compartments yet)`);
20136
+ }
19921
20137
  return {
19922
20138
  injected: true,
19923
20139
  compartmentEndMessage: prepared.compartmentEndMessage,
@@ -19963,7 +20179,7 @@ async function runCompartmentAgent(deps) {
19963
20179
  client,
19964
20180
  db,
19965
20181
  sessionId,
19966
- tokenBudget,
20182
+ historianChunkTokens,
19967
20183
  directory,
19968
20184
  historianTimeoutMs,
19969
20185
  getNotificationParams
@@ -19998,7 +20214,7 @@ No new compartments or facts were written. Rebuild or clear the broken compartme
19998
20214
  if (protectedTailStart <= offset) {
19999
20215
  return;
20000
20216
  }
20001
- const chunk = readSessionChunk(sessionId, tokenBudget, offset, protectedTailStart);
20217
+ const chunk = readSessionChunk(sessionId, historianChunkTokens, offset, protectedTailStart);
20002
20218
  if (!chunk.text || chunk.messageCount === 0) {
20003
20219
  return;
20004
20220
  }
@@ -20141,7 +20357,7 @@ async function executeContextRecompInternal(deps) {
20141
20357
  client,
20142
20358
  db,
20143
20359
  sessionId,
20144
- tokenBudget,
20360
+ historianChunkTokens,
20145
20361
  directory,
20146
20362
  historianTimeoutMs,
20147
20363
  getNotificationParams
@@ -20195,7 +20411,7 @@ No eligible raw history exists before the protected tail, so nothing was rebuilt
20195
20411
  let candidateFacts = existingStaging?.facts ?? [];
20196
20412
  let offset = existingStaging ? existingStaging.lastEndMessage + 1 : 1;
20197
20413
  let passCount = existingStaging?.passCount ?? 0;
20198
- let currentTokenBudget = tokenBudget;
20414
+ let currentTokenBudget = historianChunkTokens;
20199
20415
  let passAttempt = 1;
20200
20416
  const resumed = existingStaging !== null;
20201
20417
  if (resumed) {
@@ -20293,7 +20509,7 @@ Nothing was written.`;
20293
20509
  ];
20294
20510
  candidateFacts = validatedPass.facts ?? [];
20295
20511
  passCount += 1;
20296
- currentTokenBudget = tokenBudget;
20512
+ currentTokenBudget = historianChunkTokens;
20297
20513
  passAttempt = 1;
20298
20514
  saveRecompStagingPass(db, sessionId, passCount, candidateCompartments, candidateFacts);
20299
20515
  const nextOffset = (validatedPass.compartments?.[validatedPass.compartments.length - 1]?.endMessage ?? chunk.endIndex) + 1;
@@ -28493,7 +28709,7 @@ Check verifiable memories against actual repository state. Update stale wording,
28493
28709
  4. **Be conservative.** If you cannot find the referenced code but it might be in a location you haven't checked, do NOT archive. Move on.
28494
28710
 
28495
28711
  ### Verification examples
28496
- - Memory: "compartment_token_budget defaults to 20000" \u2192 grep schema for \`compartment_token_budget\`, check \`.default(...)\`
28712
+ - Memory: "history_budget_percentage defaults to 0.15" \u2192 grep schema for \`history_budget_percentage\`, check \`.default(...)\`
28497
28713
  - Memory: "Durable state lives in ~/.local/share/opencode/storage/plugin/magic-context/context.db" \u2192 check storage-db.ts for the path construction
28498
28714
  - Memory: "ctx_search searches memories, facts, and history" \u2192 grep for ctx_search tool definition and unified search implementation
28499
28715
 
@@ -30222,110 +30438,13 @@ function createCompactionHandler() {
30222
30438
  }
30223
30439
  };
30224
30440
  }
30225
- // src/shared/models-dev-cache.ts
30226
- init_logger();
30227
- import { existsSync as existsSync5, readFileSync as readFileSync4 } from "fs";
30228
- import { homedir as homedir5, platform as platform2 } from "os";
30229
- import { join as join11 } from "path";
30230
- var cachedLimits = null;
30231
- var lastLoadAttempt = 0;
30232
- var RELOAD_INTERVAL_MS = 5 * 60 * 1000;
30233
- function getModelsJsonPath() {
30234
- const xdgCache = process.env.XDG_CACHE_HOME;
30235
- const os3 = platform2();
30236
- let cacheBase;
30237
- if (xdgCache) {
30238
- cacheBase = xdgCache;
30239
- } else if (os3 === "win32") {
30240
- cacheBase = process.env.LOCALAPPDATA ?? join11(homedir5(), "AppData", "Local");
30241
- } else {
30242
- cacheBase = join11(homedir5(), ".cache");
30243
- }
30244
- return join11(cacheBase, "opencode", "models.json");
30245
- }
30246
- function getOpencodeConfigPath() {
30247
- const envDir = process.env.OPENCODE_CONFIG_DIR?.trim();
30248
- const configDir = envDir ? envDir : platform2() === "win32" ? join11(homedir5(), ".config", "opencode") : join11(process.env.XDG_CONFIG_HOME || join11(homedir5(), ".config"), "opencode");
30249
- const jsonc = join11(configDir, "opencode.jsonc");
30250
- if (existsSync5(jsonc))
30251
- return jsonc;
30252
- const json2 = join11(configDir, "opencode.json");
30253
- if (existsSync5(json2))
30254
- return json2;
30255
- return null;
30256
- }
30257
- function loadModelsDevLimits() {
30258
- const limits = new Map;
30259
- const modelsJsonPath = getModelsJsonPath();
30260
- try {
30261
- if (existsSync5(modelsJsonPath)) {
30262
- const raw = readFileSync4(modelsJsonPath, "utf-8");
30263
- const data = JSON.parse(raw);
30264
- for (const [providerId, provider2] of Object.entries(data)) {
30265
- if (!provider2?.models || typeof provider2.models !== "object")
30266
- continue;
30267
- for (const [modelId, model] of Object.entries(provider2.models)) {
30268
- const context = model?.limit?.context;
30269
- if (typeof context === "number" && context > 0) {
30270
- limits.set(`${providerId}/${modelId}`, context);
30271
- const modes = model?.experimental?.modes;
30272
- if (modes && typeof modes === "object") {
30273
- for (const mode of Object.keys(modes)) {
30274
- limits.set(`${providerId}/${modelId}-${mode}`, context);
30275
- }
30276
- }
30277
- }
30278
- }
30279
- }
30280
- }
30281
- } catch (error48) {
30282
- sessionLog("global", "models-dev-cache: failed to read models.json:", error48 instanceof Error ? error48.message : String(error48));
30283
- }
30284
- try {
30285
- const configPath = getOpencodeConfigPath();
30286
- if (configPath && existsSync5(configPath)) {
30287
- let raw = readFileSync4(configPath, "utf-8");
30288
- raw = raw.replace(/"(?:[^"\\]|\\.)*"|\/\/.*$/gm, (match) => match.startsWith('"') ? match : "");
30289
- const config2 = JSON.parse(raw);
30290
- if (config2.provider && typeof config2.provider === "object") {
30291
- for (const [providerId, provider2] of Object.entries(config2.provider)) {
30292
- if (!provider2?.models || typeof provider2.models !== "object")
30293
- continue;
30294
- for (const [modelId, model] of Object.entries(provider2.models)) {
30295
- const context = model?.limit?.context;
30296
- if (typeof context === "number" && context > 0) {
30297
- limits.set(`${providerId}/${modelId}`, context);
30298
- }
30299
- }
30300
- }
30301
- }
30302
- }
30303
- } catch (error48) {
30304
- sessionLog("global", "models-dev-cache: failed to read opencode config for custom models:", error48 instanceof Error ? error48.message : String(error48));
30305
- }
30306
- return limits;
30307
- }
30308
- function getModelsDevContextLimit(providerID, modelID) {
30309
- const now = Date.now();
30310
- if (!cachedLimits || now - lastLoadAttempt > RELOAD_INTERVAL_MS) {
30311
- lastLoadAttempt = now;
30312
- cachedLimits = loadModelsDevLimits();
30313
- }
30314
- return cachedLimits.get(`${providerID}/${modelID}`);
30315
- }
30316
-
30317
30441
  // src/hooks/magic-context/event-resolvers.ts
30442
+ init_models_dev_cache();
30318
30443
  var DEFAULT_CONTEXT_LIMIT = 128000;
30319
- function resolveContextLimit(providerID, modelID, config2) {
30444
+ function resolveContextLimit(providerID, modelID) {
30320
30445
  if (!providerID) {
30321
30446
  return DEFAULT_CONTEXT_LIMIT;
30322
30447
  }
30323
- if (modelID) {
30324
- const modelSpecific = config2.modelContextLimitsCache?.get(`${providerID}/${modelID}`);
30325
- if (typeof modelSpecific === "number" && modelSpecific > 0) {
30326
- return modelSpecific;
30327
- }
30328
- }
30329
30448
  if (modelID) {
30330
30449
  const modelsDevLimit = getModelsDevContextLimit(providerID, modelID);
30331
30450
  if (modelsDevLimit !== undefined) {
@@ -30608,7 +30727,6 @@ init_storage_tags();
30608
30727
  init_logger();
30609
30728
 
30610
30729
  // src/hooks/magic-context/compartment-trigger.ts
30611
- init_magic_context();
30612
30730
  init_compartment_storage();
30613
30731
  init_storage();
30614
30732
  init_logger();
@@ -30686,7 +30804,7 @@ var TAIL_INFO_DEFAULTS = {
30686
30804
  tokenEstimate: 0,
30687
30805
  commitClusterCount: 0
30688
30806
  };
30689
- function getUnsummarizedTailInfo(db, sessionId, compartmentTokenBudget) {
30807
+ function getUnsummarizedTailInfo(db, sessionId, triggerBudget) {
30690
30808
  return withRawSessionMessageCache(() => {
30691
30809
  try {
30692
30810
  const lastCompartmentEnd = getLastCompartmentEndMessage(db, sessionId);
@@ -30697,7 +30815,7 @@ function getUnsummarizedTailInfo(db, sessionId, compartmentTokenBudget) {
30697
30815
  if (!hasEligibleHistory) {
30698
30816
  return { ...TAIL_INFO_DEFAULTS, nextStartOrdinal };
30699
30817
  }
30700
- const scanBudget = Math.max(MIN_PROACTIVE_TAIL_TOKEN_ESTIMATE, compartmentTokenBudget * TAIL_SIZE_TRIGGER_MULTIPLIER);
30818
+ const scanBudget = Math.max(MIN_PROACTIVE_TAIL_TOKEN_ESTIMATE, triggerBudget * TAIL_SIZE_TRIGGER_MULTIPLIER);
30701
30819
  const chunk = readSessionChunk(sessionId, scanBudget, nextStartOrdinal, protectedTailStart);
30702
30820
  const isMeaningful = chunk.hasMore || chunk.tokenEstimate >= MIN_PROACTIVE_TAIL_TOKEN_ESTIMATE || chunk.messageCount >= MIN_PROACTIVE_TAIL_MESSAGE_COUNT;
30703
30821
  return {
@@ -30713,11 +30831,11 @@ function getUnsummarizedTailInfo(db, sessionId, compartmentTokenBudget) {
30713
30831
  }
30714
30832
  });
30715
30833
  }
30716
- function checkCompartmentTrigger(db, sessionId, sessionMeta, usage, _previousPercentage, executeThresholdPercentage, compartmentTokenBudget = DEFAULT_COMPARTMENT_TOKEN_BUDGET, autoDropToolAge, protectedTagCount, clearReasoningAge, dropToolStructure = true, commitClusterTrigger) {
30834
+ function checkCompartmentTrigger(db, sessionId, sessionMeta, usage, _previousPercentage, executeThresholdPercentage, triggerBudget, autoDropToolAge, protectedTagCount, clearReasoningAge, dropToolStructure = true, commitClusterTrigger) {
30717
30835
  if (sessionMeta.compartmentInProgress) {
30718
30836
  return { shouldFire: false };
30719
30837
  }
30720
- const tailInfo = getUnsummarizedTailInfo(db, sessionId, compartmentTokenBudget);
30838
+ const tailInfo = getUnsummarizedTailInfo(db, sessionId, triggerBudget);
30721
30839
  if (!tailInfo.hasNewRawHistory) {
30722
30840
  return { shouldFire: false };
30723
30841
  }
@@ -30733,12 +30851,12 @@ function checkCompartmentTrigger(db, sessionId, sessionMeta, usage, _previousPer
30733
30851
  }
30734
30852
  const clusterEnabled = commitClusterTrigger?.enabled ?? true;
30735
30853
  const minClusters = commitClusterTrigger?.min_clusters ?? DEFAULT_MIN_COMMIT_CLUSTERS_FOR_TRIGGER;
30736
- if (clusterEnabled && tailInfo.commitClusterCount >= minClusters && tailInfo.tokenEstimate >= compartmentTokenBudget) {
30854
+ if (clusterEnabled && tailInfo.commitClusterCount >= minClusters && tailInfo.tokenEstimate >= triggerBudget) {
30737
30855
  sessionLog(sessionId, `compartment trigger: commit-cluster fire \u2014 ${tailInfo.commitClusterCount} clusters (min=${minClusters}), ~${tailInfo.tokenEstimate} tokens in eligible prefix`);
30738
30856
  return { shouldFire: true, reason: "commit_clusters" };
30739
30857
  }
30740
- if (tailInfo.tokenEstimate >= compartmentTokenBudget * TAIL_SIZE_TRIGGER_MULTIPLIER) {
30741
- sessionLog(sessionId, `compartment trigger: tail-size fire \u2014 ~${tailInfo.tokenEstimate} tokens exceeds ${compartmentTokenBudget * TAIL_SIZE_TRIGGER_MULTIPLIER} budget threshold`);
30858
+ if (tailInfo.tokenEstimate >= triggerBudget * TAIL_SIZE_TRIGGER_MULTIPLIER) {
30859
+ sessionLog(sessionId, `compartment trigger: tail-size fire \u2014 ~${tailInfo.tokenEstimate} tokens exceeds ${triggerBudget * TAIL_SIZE_TRIGGER_MULTIPLIER} budget threshold`);
30742
30860
  return { shouldFire: true, reason: "tail_size" };
30743
30861
  }
30744
30862
  const proactiveTriggerPercentage = getProactiveCompartmentTriggerPercentage(executeThresholdPercentage);
@@ -31082,11 +31200,15 @@ Historian recomp started. Rebuilding compartments and facts from raw session his
31082
31200
  };
31083
31201
  }
31084
31202
 
31203
+ // src/hooks/magic-context/hook.ts
31204
+ init_derive_budgets();
31205
+
31085
31206
  // src/hooks/magic-context/event-handler.ts
31086
31207
  init_storage();
31087
31208
  init_storage_meta_persisted();
31088
31209
  init_logger();
31089
31210
  init_compaction_marker_manager();
31211
+ init_derive_budgets();
31090
31212
 
31091
31213
  // src/hooks/magic-context/event-payloads.ts
31092
31214
  function getSessionProperties(properties) {
@@ -31158,7 +31280,6 @@ function getMessageRemovedInfo(properties) {
31158
31280
  init_note_nudger();
31159
31281
 
31160
31282
  // src/hooks/magic-context/transform-compartment-phase.ts
31161
- init_magic_context();
31162
31283
  init_compartment_storage();
31163
31284
  init_storage();
31164
31285
  init_logger();
@@ -31234,7 +31355,7 @@ async function runCompartmentPhase(args) {
31234
31355
  client: args.client,
31235
31356
  db: args.db,
31236
31357
  sessionId: args.sessionId,
31237
- tokenBudget: args.compartmentTokenBudget ?? DEFAULT_COMPARTMENT_TOKEN_BUDGET,
31358
+ historianChunkTokens: args.historianChunkTokens,
31238
31359
  historyBudgetTokens: args.historyBudgetTokens,
31239
31360
  historianTimeoutMs: args.historianTimeoutMs,
31240
31361
  directory: args.compartmentDirectory,
@@ -31255,7 +31376,7 @@ async function runCompartmentPhase(args) {
31255
31376
  client: args.client,
31256
31377
  db: args.db,
31257
31378
  sessionId: args.sessionId,
31258
- tokenBudget: args.compartmentTokenBudget ?? DEFAULT_COMPARTMENT_TOKEN_BUDGET,
31379
+ historianChunkTokens: args.historianChunkTokens,
31259
31380
  historyBudgetTokens: args.historyBudgetTokens,
31260
31381
  historianTimeoutMs: args.historianTimeoutMs,
31261
31382
  directory: args.compartmentDirectory,
@@ -31408,9 +31529,7 @@ function createEventHandler2(deps) {
31408
31529
  }
31409
31530
  if (hasUsageTokens) {
31410
31531
  const totalInputTokens = (info.tokens?.input ?? 0) + (info.tokens?.cache?.read ?? 0) + (info.tokens?.cache?.write ?? 0);
31411
- const contextLimit = resolveContextLimit(info.providerID, info.modelID, {
31412
- modelContextLimitsCache: deps.config.modelContextLimitsCache
31413
- });
31532
+ const contextLimit = resolveContextLimit(info.providerID, info.modelID);
31414
31533
  const percentage = contextLimit > 0 ? totalInputTokens / contextLimit * 100 : 0;
31415
31534
  sessionLog(info.sessionID, `event message.updated: totalInputTokens=${totalInputTokens} contextLimit=${contextLimit} percentage=${percentage.toFixed(1)}%`);
31416
31535
  deps.contextUsageMap.set(info.sessionID, {
@@ -31430,7 +31549,9 @@ function createEventHandler2(deps) {
31430
31549
  const sessionMeta = getOrCreateSessionMeta(deps.db, info.sessionID);
31431
31550
  const previousPercentage = sessionMeta.lastContextPercentage;
31432
31551
  if (!sessionMeta.isSubagent) {
31433
- const triggerResult = checkCompartmentTrigger(deps.db, info.sessionID, sessionMeta, { percentage, inputTokens: totalInputTokens }, previousPercentage, resolveExecuteThreshold(deps.config.execute_threshold_percentage ?? 65, modelKey, 65), undefined, deps.config.auto_drop_tool_age ?? 100, deps.config.protected_tags, deps.config.clear_reasoning_age ?? 50, deps.config.drop_tool_structure ?? true, deps.config.commit_cluster_trigger);
31552
+ const effectiveExecuteThreshold = resolveExecuteThreshold(deps.config.execute_threshold_percentage ?? 65, modelKey, 65);
31553
+ const triggerBudget = deriveTriggerBudget(contextLimit, effectiveExecuteThreshold);
31554
+ const triggerResult = checkCompartmentTrigger(deps.db, info.sessionID, sessionMeta, { percentage, inputTokens: totalInputTokens }, previousPercentage, effectiveExecuteThreshold, triggerBudget, deps.config.auto_drop_tool_age ?? 100, deps.config.protected_tags, deps.config.clear_reasoning_age ?? 50, deps.config.drop_tool_structure ?? true, deps.config.commit_cluster_trigger);
31434
31555
  if (triggerResult.shouldFire) {
31435
31556
  sessionLog(info.sessionID, `compartment trigger: firing (reason=${triggerResult.reason})`);
31436
31557
  updateSessionMeta(deps.db, info.sessionID, {
@@ -31708,7 +31829,6 @@ function createTextCompleteHandler() {
31708
31829
  }
31709
31830
 
31710
31831
  // src/hooks/magic-context/transform.ts
31711
- init_magic_context();
31712
31832
  init_compartment_storage();
31713
31833
  init_project_identity();
31714
31834
  init_storage();
@@ -32789,6 +32909,14 @@ function isToolProtocolPart(part) {
32789
32909
  function hasToolProtocolParts(message) {
32790
32910
  return message.parts.some(isToolProtocolPart);
32791
32911
  }
32912
+ function hasThinkingBearingParts(message) {
32913
+ return message.parts.some((part) => {
32914
+ if (part === null || typeof part !== "object")
32915
+ return false;
32916
+ const p = part;
32917
+ return p.type === "thinking" || p.type === "reasoning" || p.type === "redacted_thinking";
32918
+ });
32919
+ }
32792
32920
  function isMessageDropped(message) {
32793
32921
  const textParts = message.parts.filter(isTextPart);
32794
32922
  if (textParts.length === 0)
@@ -32823,6 +32951,11 @@ function reinjectNudgeAtAnchor(messages, nudgeText, nudgePlacements, sessionId)
32823
32951
  nudgePlacements.clear(sessionId);
32824
32952
  return false;
32825
32953
  }
32954
+ if (hasThinkingBearingParts(message)) {
32955
+ sessionLog(sessionId, `nudge anchor abandoned: message ${message.info.id} now contains thinking/reasoning parts (signed, immutable)`);
32956
+ nudgePlacements.clear(sessionId);
32957
+ return false;
32958
+ }
32826
32959
  for (let j = message.parts.length - 1;j >= 0; j--) {
32827
32960
  const part = message.parts[j];
32828
32961
  if (isTextPart(part)) {
@@ -32851,6 +32984,8 @@ function appendNudgeToAssistant(messages, nudge, nudgePlacements, sessionId) {
32851
32984
  continue;
32852
32985
  if (isMessageDropped(message))
32853
32986
  continue;
32987
+ if (hasThinkingBearingParts(message))
32988
+ continue;
32854
32989
  for (let j = message.parts.length - 1;j >= 0; j--) {
32855
32990
  const part = message.parts[j];
32856
32991
  if (isTextPart(part)) {
@@ -33134,12 +33269,13 @@ function runPostTransformPhase(args) {
33134
33269
  const forceMaterialization = args.fullFeatureMode && args.contextUsage.percentage >= args.forceMaterializationPercentage;
33135
33270
  const activeCompartmentRun = args.canRunCompartments ? getActiveCompartmentRun(args.sessionId) : undefined;
33136
33271
  const compartmentRunning = args.canRunCompartments && !args.awaitedCompartmentRun && activeCompartmentRun !== undefined;
33137
- const shouldReadPendingOps = isExplicitFlush || args.schedulerDecision === "execute" || compartmentRunning;
33272
+ const emergencyBypassCompartmentGate = forceMaterialization;
33273
+ const shouldReadPendingOps = isExplicitFlush || args.schedulerDecision === "execute" || forceMaterialization || compartmentRunning;
33138
33274
  const pendingOps = shouldReadPendingOps ? getPendingOps(args.db, args.sessionId) : [];
33139
33275
  const hasPendingUserOps = pendingOps.length > 0;
33140
- const shouldApplyPendingOps = (args.schedulerDecision === "execute" || isExplicitFlush) && !compartmentRunning;
33276
+ const shouldApplyPendingOps = (args.schedulerDecision === "execute" || isExplicitFlush || forceMaterialization) && (!compartmentRunning || emergencyBypassCompartmentGate);
33141
33277
  const isCacheBustingPass = isExplicitFlush || shouldApplyPendingOps;
33142
- const shouldRunHeuristics = args.fullFeatureMode && !compartmentRunning && (isExplicitFlush || forceMaterialization || args.schedulerDecision === "execute" && !alreadyRanThisTurn);
33278
+ const shouldRunHeuristics = args.fullFeatureMode && (!compartmentRunning || emergencyBypassCompartmentGate) && (isExplicitFlush || forceMaterialization || args.schedulerDecision === "execute" && !alreadyRanThisTurn);
33143
33279
  if (shouldRunHeuristics) {
33144
33280
  const reason = isExplicitFlush ? "explicit_flush" : forceMaterialization ? `force_materialization (${args.contextUsage.percentage.toFixed(1)}% >= ${args.forceMaterializationPercentage}%)` : `scheduler_execute (pendingOps=${pendingOps.length}, scheduler=${args.schedulerDecision})`;
33145
33281
  sessionLog(args.sessionId, `heuristics WILL RUN \u2014 reason=${reason}, context=${args.contextUsage.percentage.toFixed(1)}%, turn=${args.currentTurnId}`);
@@ -33148,7 +33284,11 @@ function runPostTransformPhase(args) {
33148
33284
  sessionLog(args.sessionId, `transform: skipping heuristics (already ran for turn ${args.currentTurnId})`);
33149
33285
  }
33150
33286
  if (compartmentRunning && hasPendingUserOps) {
33151
- sessionLog(args.sessionId, "transform: deferring pending ops \u2014 compartment agent in progress");
33287
+ if (emergencyBypassCompartmentGate) {
33288
+ sessionLog(args.sessionId, `transform: emergency bypass \u2014 applying ${pendingOps.length} pending ops while compartment agent runs (${args.contextUsage.percentage.toFixed(1)}%)`);
33289
+ } else {
33290
+ sessionLog(args.sessionId, "transform: deferring pending ops \u2014 compartment agent in progress");
33291
+ }
33152
33292
  }
33153
33293
  try {
33154
33294
  if (shouldApplyPendingOps) {
@@ -33237,7 +33377,11 @@ function runPostTransformPhase(args) {
33237
33377
  if (args.fullFeatureMode && args.pendingCompartmentInjection) {
33238
33378
  const compartmentResult = renderCompartmentInjection(args.sessionId, args.messages, args.pendingCompartmentInjection);
33239
33379
  if (compartmentResult.injected) {
33240
- sessionLog(args.sessionId, `transform: injected ${compartmentResult.compartmentCount} compartments ` + `(covering raw messages 1-${compartmentResult.compartmentEndMessage}, ` + `skipped ${compartmentResult.skippedVisibleMessages} visible messages)`);
33380
+ if (compartmentResult.compartmentCount > 0) {
33381
+ sessionLog(args.sessionId, `transform: injected ${compartmentResult.compartmentCount} compartments ` + `(covering raw messages 1-${compartmentResult.compartmentEndMessage}, ` + `skipped ${compartmentResult.skippedVisibleMessages} visible messages)`);
33382
+ } else {
33383
+ sessionLog(args.sessionId, "transform: injected memories/facts block (no compartments yet)");
33384
+ }
33241
33385
  }
33242
33386
  }
33243
33387
  {
@@ -33503,7 +33647,7 @@ function createTransform(deps) {
33503
33647
  client: deps.client,
33504
33648
  db,
33505
33649
  sessionId,
33506
- tokenBudget: deps.compartmentTokenBudget ?? DEFAULT_COMPARTMENT_TOKEN_BUDGET,
33650
+ historianChunkTokens: deps.getHistorianChunkTokens?.() ?? 20000,
33507
33651
  historyBudgetTokens,
33508
33652
  historianTimeoutMs: deps.historianTimeoutMs,
33509
33653
  directory: compartmentDirectory,
@@ -33624,7 +33768,7 @@ Historian previously failed ${historianFailureState.failureCount} time(s), so ma
33624
33768
  db,
33625
33769
  sessionId,
33626
33770
  resolvedSessionId,
33627
- compartmentTokenBudget: deps.compartmentTokenBudget ?? DEFAULT_COMPARTMENT_TOKEN_BUDGET,
33771
+ historianChunkTokens: deps.getHistorianChunkTokens?.() ?? 20000,
33628
33772
  historyBudgetTokens,
33629
33773
  historianTimeoutMs: deps.historianTimeoutMs,
33630
33774
  compartmentDirectory,
@@ -34331,6 +34475,7 @@ function createMagicContextHook(deps) {
34331
34475
  const projectPath = resolveProjectIdentity(deps.directory);
34332
34476
  registerDreamProjectDirectory(projectPath, deps.directory);
34333
34477
  let lastScheduleCheckMs = 0;
34478
+ const getHistorianChunkTokens = () => deriveHistorianChunkTokens(resolveHistorianContextLimit(deps.config.historian?.model));
34334
34479
  const nudgePlacements = createNudgePlacementStore(db);
34335
34480
  const flushedSessions = new Set;
34336
34481
  const lastHeuristicsTurnId = new Map;
@@ -34368,7 +34513,7 @@ function createMagicContextHook(deps) {
34368
34513
  enabled: deps.config.memory.enabled,
34369
34514
  injectionBudgetTokens: deps.config.memory.injection_budget_tokens
34370
34515
  } : undefined,
34371
- compartmentTokenBudget: deps.config.compartment_token_budget ?? DEFAULT_COMPARTMENT_TOKEN_BUDGET,
34516
+ getHistorianChunkTokens,
34372
34517
  historyBudgetPercentage: deps.config.history_budget_percentage,
34373
34518
  executeThresholdPercentage: deps.config.execute_threshold_percentage,
34374
34519
  historianTimeoutMs: deps.config.historian_timeout_ms ?? DEFAULT_HISTORIAN_TIMEOUT_MS,
@@ -34449,7 +34594,7 @@ function createMagicContextHook(deps) {
34449
34594
  client: deps.client,
34450
34595
  db,
34451
34596
  sessionId,
34452
- tokenBudget: deps.config.compartment_token_budget ?? DEFAULT_COMPARTMENT_TOKEN_BUDGET,
34597
+ historianChunkTokens: getHistorianChunkTokens(),
34453
34598
  historianTimeoutMs: deps.config.historian_timeout_ms ?? DEFAULT_HISTORIAN_TIMEOUT_MS,
34454
34599
  directory: deps.directory,
34455
34600
  fallbackModelId: (() => {
@@ -34575,7 +34720,7 @@ function createSessionHooks(args) {
34575
34720
  clear_reasoning_age: pluginConfig.clear_reasoning_age,
34576
34721
  iteration_nudge_threshold: pluginConfig.iteration_nudge_threshold,
34577
34722
  execute_threshold_percentage: pluginConfig.execute_threshold_percentage ?? DEFAULT_EXECUTE_THRESHOLD_PERCENTAGE,
34578
- compartment_token_budget: pluginConfig.compartment_token_budget,
34723
+ historian: pluginConfig.historian,
34579
34724
  history_budget_percentage: pluginConfig.history_budget_percentage,
34580
34725
  historian_timeout_ms: pluginConfig.historian_timeout_ms,
34581
34726
  memory: pluginConfig.memory,
@@ -34900,17 +35045,18 @@ function registerRpcHandlers(rpcServer, args) {
34900
35045
  return { ok: false, error: "no session" };
34901
35046
  const { executeContextRecomp: executeContextRecomp2 } = await Promise.resolve().then(() => (init_compartment_runner(), exports_compartment_runner));
34902
35047
  const { sendIgnoredMessage: sendIgnoredMessage2 } = await Promise.resolve().then(() => (init_send_session_notification(), exports_send_session_notification));
35048
+ const { deriveHistorianChunkTokens: deriveHistorianChunkTokens2, resolveHistorianContextLimit: resolveHistorianContextLimit2 } = await Promise.resolve().then(() => (init_derive_budgets(), exports_derive_budgets));
34903
35049
  const db = getDb();
34904
35050
  if (!db)
34905
35051
  return { ok: false, error: "db unavailable" };
34906
- const DEFAULT_COMPARTMENT_TOKEN_BUDGET2 = 20000;
34907
35052
  const DEFAULT_HISTORIAN_TIMEOUT_MS2 = 600000;
35053
+ const historianChunkTokens = deriveHistorianChunkTokens2(resolveHistorianContextLimit2(config2.historian?.model));
34908
35054
  log(`[rpc] recomp requested for session ${sessionId}`);
34909
35055
  executeContextRecomp2({
34910
35056
  client: args.client,
34911
35057
  db,
34912
35058
  sessionId,
34913
- tokenBudget: config2.compartment_token_budget ?? DEFAULT_COMPARTMENT_TOKEN_BUDGET2,
35059
+ historianChunkTokens,
34914
35060
  historianTimeoutMs: config2.historian_timeout_ms ?? DEFAULT_HISTORIAN_TIMEOUT_MS2,
34915
35061
  directory,
34916
35062
  getNotificationParams: () => getNotificationParams(sessionId)
@@ -36115,6 +36261,7 @@ init_conflict_detector();
36115
36261
  init_data_path();
36116
36262
  init_logger();
36117
36263
  init_model_requirements();
36264
+ init_models_dev_cache();
36118
36265
 
36119
36266
  // src/shared/rpc-server.ts
36120
36267
  init_logger();
@@ -36123,11 +36270,11 @@ import { createServer } from "http";
36123
36270
  import { dirname } from "path";
36124
36271
 
36125
36272
  // src/shared/rpc-utils.ts
36126
- import { createHash } from "crypto";
36273
+ import { createHash as createHash2 } from "crypto";
36127
36274
  import { join as join15 } from "path";
36128
36275
  function projectHash(directory) {
36129
36276
  const normalized = directory.replace(/\/+$/, "");
36130
- return createHash("sha256").update(normalized).digest("hex").slice(0, 16);
36277
+ return createHash2("sha256").update(normalized).digest("hex").slice(0, 16);
36131
36278
  }
36132
36279
  function rpcPortFilePath(storageDir, directory) {
36133
36280
  return join15(storageDir, "rpc", projectHash(directory), "port");
@@ -36312,6 +36459,10 @@ var plugin = async (ctx) => {
36312
36459
  rpcServer.start().catch((err) => {
36313
36460
  log(`[magic-context] RPC server failed to start: ${err}`);
36314
36461
  });
36462
+ refreshModelLimitsFromApi(ctx.client);
36463
+ setInterval(() => {
36464
+ refreshModelLimitsFromApi(ctx.client);
36465
+ }, 5 * 60 * 1000);
36315
36466
  }
36316
36467
  if (conflictResult?.hasConflict) {
36317
36468
  sendConflictWarning(ctx.client, ctx.directory, conflictResult);