@cortexkit/opencode-magic-context 0.9.1 → 0.10.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.
- package/dist/cli/doctor.d.ts.map +1 -1
- package/dist/cli.js +6 -3
- package/dist/config/schema/magic-context.d.ts +0 -4
- package/dist/config/schema/magic-context.d.ts.map +1 -1
- package/dist/features/magic-context/memory/embedding-local.d.ts.map +1 -1
- package/dist/hooks/magic-context/compartment-runner-types.d.ts +6 -1
- package/dist/hooks/magic-context/compartment-runner-types.d.ts.map +1 -1
- package/dist/hooks/magic-context/compartment-trigger.d.ts +1 -1
- package/dist/hooks/magic-context/compartment-trigger.d.ts.map +1 -1
- package/dist/hooks/magic-context/derive-budgets.d.ts +57 -0
- package/dist/hooks/magic-context/derive-budgets.d.ts.map +1 -0
- package/dist/hooks/magic-context/event-handler.d.ts +0 -1
- package/dist/hooks/magic-context/event-handler.d.ts.map +1 -1
- package/dist/hooks/magic-context/event-resolvers.d.ts +1 -3
- package/dist/hooks/magic-context/event-resolvers.d.ts.map +1 -1
- package/dist/hooks/magic-context/hook.d.ts +3 -2
- package/dist/hooks/magic-context/hook.d.ts.map +1 -1
- package/dist/hooks/magic-context/nudge-injection.d.ts.map +1 -1
- package/dist/hooks/magic-context/transform-compartment-phase.d.ts +1 -1
- package/dist/hooks/magic-context/transform-compartment-phase.d.ts.map +1 -1
- package/dist/hooks/magic-context/transform-postprocess-phase.d.ts.map +1 -1
- package/dist/hooks/magic-context/transform.d.ts +7 -1
- package/dist/hooks/magic-context/transform.d.ts.map +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +347 -157
- package/dist/plugin/hooks/create-session-hooks.d.ts.map +1 -1
- package/dist/plugin/rpc-handlers.d.ts.map +1 -1
- package/dist/plugin/tui-action-consumer.d.ts.map +1 -1
- package/dist/shared/models-dev-cache.d.ts +52 -4
- package/dist/shared/models-dev-cache.d.ts.map +1 -1
- package/package.json +2 -2
- package/src/shared/models-dev-cache.test.ts +228 -0
- 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,
|
|
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({
|
|
@@ -16166,7 +16165,57 @@ function cosineSimilarity(a, b) {
|
|
|
16166
16165
|
|
|
16167
16166
|
// src/features/magic-context/memory/embedding-local.ts
|
|
16168
16167
|
import { mkdirSync } from "fs";
|
|
16168
|
+
import { open, stat, unlink, writeFile } from "fs/promises";
|
|
16169
16169
|
import { join as join9 } from "path";
|
|
16170
|
+
async function acquireModelLoadLock(lockPath) {
|
|
16171
|
+
const waitStart = Date.now();
|
|
16172
|
+
while (true) {
|
|
16173
|
+
try {
|
|
16174
|
+
const handle = await open(lockPath, "wx");
|
|
16175
|
+
try {
|
|
16176
|
+
await handle.writeFile(`pid=${process.pid} started=${Date.now()}
|
|
16177
|
+
`);
|
|
16178
|
+
} catch {}
|
|
16179
|
+
await handle.close();
|
|
16180
|
+
return async () => {
|
|
16181
|
+
try {
|
|
16182
|
+
await unlink(lockPath);
|
|
16183
|
+
} catch {}
|
|
16184
|
+
};
|
|
16185
|
+
} catch (error48) {
|
|
16186
|
+
const code = error48.code;
|
|
16187
|
+
if (code !== "EEXIST" && code !== "EPERM") {
|
|
16188
|
+
throw error48;
|
|
16189
|
+
}
|
|
16190
|
+
try {
|
|
16191
|
+
const info = await stat(lockPath);
|
|
16192
|
+
if (Date.now() - info.mtimeMs > STALE_LOCK_MS) {
|
|
16193
|
+
log(`[magic-context] embedding-load lock stale (>${STALE_LOCK_MS}ms), taking over`);
|
|
16194
|
+
try {
|
|
16195
|
+
await unlink(lockPath);
|
|
16196
|
+
} catch {}
|
|
16197
|
+
continue;
|
|
16198
|
+
}
|
|
16199
|
+
} catch {
|
|
16200
|
+
continue;
|
|
16201
|
+
}
|
|
16202
|
+
if (Date.now() - waitStart > MAX_LOCK_WAIT_MS) {
|
|
16203
|
+
log("[magic-context] embedding-load lock wait exceeded, proceeding without lock");
|
|
16204
|
+
return async () => {};
|
|
16205
|
+
}
|
|
16206
|
+
await new Promise((resolve2) => setTimeout(resolve2, LOCK_POLL_MS));
|
|
16207
|
+
}
|
|
16208
|
+
}
|
|
16209
|
+
}
|
|
16210
|
+
function startLockHeartbeat(lockPath) {
|
|
16211
|
+
const HEARTBEAT_MS = Math.floor(STALE_LOCK_MS / 3);
|
|
16212
|
+
const timer = setInterval(() => {
|
|
16213
|
+
writeFile(lockPath, `pid=${process.pid} alive=${Date.now()}
|
|
16214
|
+
`).catch(() => {});
|
|
16215
|
+
}, HEARTBEAT_MS);
|
|
16216
|
+
timer.unref?.();
|
|
16217
|
+
return () => clearInterval(timer);
|
|
16218
|
+
}
|
|
16170
16219
|
async function withQuietConsole(fn) {
|
|
16171
16220
|
const origWarn = console.warn;
|
|
16172
16221
|
const origError = console.error;
|
|
@@ -16259,30 +16308,37 @@ class LocalEmbeddingProvider {
|
|
|
16259
16308
|
log("[magic-context] could not create model cache dir, using library default");
|
|
16260
16309
|
}
|
|
16261
16310
|
const createPipeline = transformersModule.pipeline;
|
|
16262
|
-
const
|
|
16263
|
-
|
|
16264
|
-
|
|
16265
|
-
|
|
16266
|
-
|
|
16267
|
-
|
|
16268
|
-
|
|
16269
|
-
|
|
16270
|
-
|
|
16271
|
-
|
|
16272
|
-
|
|
16273
|
-
|
|
16274
|
-
if (!isTransientLoadError(error48) || attempt === MAX_ATTEMPTS) {
|
|
16311
|
+
const lockPath = join9(modelCacheDir, ".load.lock");
|
|
16312
|
+
const releaseLock = await acquireModelLoadLock(lockPath);
|
|
16313
|
+
const stopHeartbeat = startLockHeartbeat(lockPath);
|
|
16314
|
+
try {
|
|
16315
|
+
const MAX_ATTEMPTS = 3;
|
|
16316
|
+
let lastError;
|
|
16317
|
+
for (let attempt = 1;attempt <= MAX_ATTEMPTS; attempt++) {
|
|
16318
|
+
try {
|
|
16319
|
+
this.pipeline = await withQuietConsole(() => createPipeline("feature-extraction", this.model, {
|
|
16320
|
+
dtype: "fp32"
|
|
16321
|
+
}));
|
|
16322
|
+
lastError = undefined;
|
|
16275
16323
|
break;
|
|
16324
|
+
} catch (error48) {
|
|
16325
|
+
lastError = error48;
|
|
16326
|
+
if (!isTransientLoadError(error48) || attempt === MAX_ATTEMPTS) {
|
|
16327
|
+
break;
|
|
16328
|
+
}
|
|
16329
|
+
const delayMs = 300 * attempt + Math.floor(Math.random() * 200);
|
|
16330
|
+
log(`[magic-context] embedding model load attempt ${attempt}/${MAX_ATTEMPTS} failed transiently, retrying in ${delayMs}ms`);
|
|
16331
|
+
await new Promise((resolve2) => setTimeout(resolve2, delayMs));
|
|
16276
16332
|
}
|
|
16277
|
-
const delayMs = 300 * attempt + Math.floor(Math.random() * 200);
|
|
16278
|
-
log(`[magic-context] embedding model load attempt ${attempt}/${MAX_ATTEMPTS} failed transiently, retrying in ${delayMs}ms`);
|
|
16279
|
-
await new Promise((resolve2) => setTimeout(resolve2, delayMs));
|
|
16280
16333
|
}
|
|
16281
|
-
|
|
16282
|
-
|
|
16283
|
-
|
|
16284
|
-
|
|
16285
|
-
|
|
16334
|
+
if (this.pipeline) {
|
|
16335
|
+
log(`[magic-context] embedding model loaded: ${this.model}`);
|
|
16336
|
+
} else {
|
|
16337
|
+
throw lastError ?? new Error("unknown embedding load failure");
|
|
16338
|
+
}
|
|
16339
|
+
} finally {
|
|
16340
|
+
stopHeartbeat();
|
|
16341
|
+
await releaseLock();
|
|
16286
16342
|
}
|
|
16287
16343
|
} catch (error48) {
|
|
16288
16344
|
log("[magic-context] embedding model failed to load:", error48);
|
|
@@ -16357,10 +16413,13 @@ class LocalEmbeddingProvider {
|
|
|
16357
16413
|
return this.pipeline !== null;
|
|
16358
16414
|
}
|
|
16359
16415
|
}
|
|
16416
|
+
var LOCK_POLL_MS = 150, STALE_LOCK_MS, MAX_LOCK_WAIT_MS;
|
|
16360
16417
|
var init_embedding_local = __esm(() => {
|
|
16361
16418
|
init_magic_context();
|
|
16362
16419
|
init_data_path();
|
|
16363
16420
|
init_logger();
|
|
16421
|
+
STALE_LOCK_MS = 3 * 60000;
|
|
16422
|
+
MAX_LOCK_WAIT_MS = 5 * 60000;
|
|
16364
16423
|
});
|
|
16365
16424
|
|
|
16366
16425
|
// src/features/magic-context/memory/embedding-openai.ts
|
|
@@ -18374,6 +18433,145 @@ var init_storage = __esm(() => {
|
|
|
18374
18433
|
init_storage_tags();
|
|
18375
18434
|
});
|
|
18376
18435
|
|
|
18436
|
+
// src/shared/models-dev-cache.ts
|
|
18437
|
+
import { createHash } from "crypto";
|
|
18438
|
+
import { existsSync as existsSync5, readFileSync as readFileSync4 } from "fs";
|
|
18439
|
+
import { homedir as homedir5, platform as platform2 } from "os";
|
|
18440
|
+
import { join as join11 } from "path";
|
|
18441
|
+
function hashFast(input) {
|
|
18442
|
+
return createHash("sha1").update(input).digest("hex");
|
|
18443
|
+
}
|
|
18444
|
+
function getModelsJsonPath() {
|
|
18445
|
+
const explicit = process.env.OPENCODE_MODELS_PATH?.trim();
|
|
18446
|
+
if (explicit)
|
|
18447
|
+
return explicit;
|
|
18448
|
+
const xdgCache = process.env.XDG_CACHE_HOME;
|
|
18449
|
+
const os3 = platform2();
|
|
18450
|
+
let cacheBase;
|
|
18451
|
+
if (xdgCache) {
|
|
18452
|
+
cacheBase = xdgCache;
|
|
18453
|
+
} else if (os3 === "win32") {
|
|
18454
|
+
cacheBase = process.env.LOCALAPPDATA ?? join11(homedir5(), "AppData", "Local");
|
|
18455
|
+
} else {
|
|
18456
|
+
cacheBase = join11(homedir5(), ".cache");
|
|
18457
|
+
}
|
|
18458
|
+
const source = process.env.OPENCODE_MODELS_URL?.trim();
|
|
18459
|
+
const filename = source && source !== "https://models.dev" ? `models-${hashFast(source)}.json` : "models.json";
|
|
18460
|
+
return join11(cacheBase, "opencode", filename);
|
|
18461
|
+
}
|
|
18462
|
+
function getOpencodeConfigPath() {
|
|
18463
|
+
const envDir = process.env.OPENCODE_CONFIG_DIR?.trim();
|
|
18464
|
+
const configDir = envDir ? envDir : platform2() === "win32" ? join11(homedir5(), ".config", "opencode") : join11(process.env.XDG_CONFIG_HOME || join11(homedir5(), ".config"), "opencode");
|
|
18465
|
+
const jsonc = join11(configDir, "opencode.jsonc");
|
|
18466
|
+
if (existsSync5(jsonc))
|
|
18467
|
+
return jsonc;
|
|
18468
|
+
const json2 = join11(configDir, "opencode.json");
|
|
18469
|
+
if (existsSync5(json2))
|
|
18470
|
+
return json2;
|
|
18471
|
+
return null;
|
|
18472
|
+
}
|
|
18473
|
+
function loadModelsDevLimitsFromFile() {
|
|
18474
|
+
const limits = new Map;
|
|
18475
|
+
const modelsJsonPath = getModelsJsonPath();
|
|
18476
|
+
let fileFound = false;
|
|
18477
|
+
try {
|
|
18478
|
+
if (existsSync5(modelsJsonPath)) {
|
|
18479
|
+
fileFound = true;
|
|
18480
|
+
const raw = readFileSync4(modelsJsonPath, "utf-8");
|
|
18481
|
+
const data = JSON.parse(raw);
|
|
18482
|
+
for (const [providerId, provider2] of Object.entries(data)) {
|
|
18483
|
+
if (!provider2?.models || typeof provider2.models !== "object")
|
|
18484
|
+
continue;
|
|
18485
|
+
for (const [modelId, model] of Object.entries(provider2.models)) {
|
|
18486
|
+
const context = model?.limit?.context;
|
|
18487
|
+
if (typeof context === "number" && context > 0) {
|
|
18488
|
+
limits.set(`${providerId}/${modelId}`, context);
|
|
18489
|
+
const modes = model?.experimental?.modes;
|
|
18490
|
+
if (modes && typeof modes === "object") {
|
|
18491
|
+
for (const mode of Object.keys(modes)) {
|
|
18492
|
+
limits.set(`${providerId}/${modelId}-${mode}`, context);
|
|
18493
|
+
}
|
|
18494
|
+
}
|
|
18495
|
+
}
|
|
18496
|
+
}
|
|
18497
|
+
}
|
|
18498
|
+
}
|
|
18499
|
+
} catch (error48) {
|
|
18500
|
+
sessionLog("global", `models-dev-cache: failed to read models.json at ${modelsJsonPath}:`, error48 instanceof Error ? error48.message : String(error48));
|
|
18501
|
+
}
|
|
18502
|
+
try {
|
|
18503
|
+
const configPath = getOpencodeConfigPath();
|
|
18504
|
+
if (configPath && existsSync5(configPath)) {
|
|
18505
|
+
let raw = readFileSync4(configPath, "utf-8");
|
|
18506
|
+
raw = raw.replace(/"(?:[^"\\]|\\.)*"|\/\/.*$/gm, (match) => match.startsWith('"') ? match : "");
|
|
18507
|
+
const config2 = JSON.parse(raw);
|
|
18508
|
+
if (config2.provider && typeof config2.provider === "object") {
|
|
18509
|
+
for (const [providerId, provider2] of Object.entries(config2.provider)) {
|
|
18510
|
+
if (!provider2?.models || typeof provider2.models !== "object")
|
|
18511
|
+
continue;
|
|
18512
|
+
for (const [modelId, model] of Object.entries(provider2.models)) {
|
|
18513
|
+
const context = model?.limit?.context;
|
|
18514
|
+
if (typeof context === "number" && context > 0) {
|
|
18515
|
+
limits.set(`${providerId}/${modelId}`, context);
|
|
18516
|
+
}
|
|
18517
|
+
}
|
|
18518
|
+
}
|
|
18519
|
+
}
|
|
18520
|
+
}
|
|
18521
|
+
} catch (error48) {
|
|
18522
|
+
sessionLog("global", "models-dev-cache: failed to read opencode config for custom models:", error48 instanceof Error ? error48.message : String(error48));
|
|
18523
|
+
}
|
|
18524
|
+
sessionLog("global", `models-dev-cache: file-layer loaded ${limits.size} model limits (modelsJsonPath=${modelsJsonPath}, found=${fileFound})`);
|
|
18525
|
+
return limits;
|
|
18526
|
+
}
|
|
18527
|
+
async function refreshModelLimitsFromApi(client) {
|
|
18528
|
+
try {
|
|
18529
|
+
const result = await client.config.providers();
|
|
18530
|
+
const data = result.data;
|
|
18531
|
+
const providers = data?.providers;
|
|
18532
|
+
if (!Array.isArray(providers)) {
|
|
18533
|
+
sessionLog("global", "models-dev-cache: API refresh returned no providers payload");
|
|
18534
|
+
return;
|
|
18535
|
+
}
|
|
18536
|
+
const map2 = new Map;
|
|
18537
|
+
for (const entry of providers) {
|
|
18538
|
+
const p = entry;
|
|
18539
|
+
if (!p?.id || !p.models || typeof p.models !== "object")
|
|
18540
|
+
continue;
|
|
18541
|
+
for (const [modelId, model] of Object.entries(p.models)) {
|
|
18542
|
+
const context = model?.limit?.context;
|
|
18543
|
+
if (typeof context === "number" && context > 0) {
|
|
18544
|
+
map2.set(`${p.id}/${modelId}`, context);
|
|
18545
|
+
}
|
|
18546
|
+
}
|
|
18547
|
+
}
|
|
18548
|
+
apiCache = map2;
|
|
18549
|
+
apiLoadedAt = Date.now();
|
|
18550
|
+
sessionLog("global", `models-dev-cache: API layer loaded ${map2.size} model limits`);
|
|
18551
|
+
} catch (error48) {
|
|
18552
|
+
sessionLog("global", "models-dev-cache: API refresh failed:", error48 instanceof Error ? error48.message : String(error48));
|
|
18553
|
+
}
|
|
18554
|
+
}
|
|
18555
|
+
function getModelsDevContextLimit(providerID, modelID) {
|
|
18556
|
+
const key = `${providerID}/${modelID}`;
|
|
18557
|
+
if (apiCache) {
|
|
18558
|
+
const fromApi = apiCache.get(key);
|
|
18559
|
+
if (typeof fromApi === "number")
|
|
18560
|
+
return fromApi;
|
|
18561
|
+
}
|
|
18562
|
+
const now = Date.now();
|
|
18563
|
+
if (!fileCache || now - fileLastAttempt > RELOAD_INTERVAL_MS) {
|
|
18564
|
+
fileLastAttempt = now;
|
|
18565
|
+
fileCache = loadModelsDevLimitsFromFile();
|
|
18566
|
+
}
|
|
18567
|
+
return fileCache.get(key);
|
|
18568
|
+
}
|
|
18569
|
+
var RELOAD_INTERVAL_MS, apiCache = null, apiLoadedAt = 0, fileCache = null, fileLastAttempt = 0;
|
|
18570
|
+
var init_models_dev_cache = __esm(() => {
|
|
18571
|
+
init_logger();
|
|
18572
|
+
RELOAD_INTERVAL_MS = 5 * 60 * 1000;
|
|
18573
|
+
});
|
|
18574
|
+
|
|
18377
18575
|
// src/features/magic-context/memory/project-identity.ts
|
|
18378
18576
|
import { execSync } from "child_process";
|
|
18379
18577
|
import path3 from "path";
|
|
@@ -18566,6 +18764,67 @@ var init_send_session_notification = __esm(() => {
|
|
|
18566
18764
|
init_logger();
|
|
18567
18765
|
});
|
|
18568
18766
|
|
|
18767
|
+
// src/hooks/magic-context/derive-budgets.ts
|
|
18768
|
+
var exports_derive_budgets = {};
|
|
18769
|
+
__export(exports_derive_budgets, {
|
|
18770
|
+
resolveHistorianContextLimit: () => resolveHistorianContextLimit,
|
|
18771
|
+
deriveTriggerBudget: () => deriveTriggerBudget,
|
|
18772
|
+
deriveHistorianChunkTokens: () => deriveHistorianChunkTokens
|
|
18773
|
+
});
|
|
18774
|
+
function deriveTriggerBudget(mainContextLimit, executeThresholdPercentage) {
|
|
18775
|
+
if (!Number.isFinite(mainContextLimit) || mainContextLimit <= 0) {
|
|
18776
|
+
return TRIGGER_BUDGET_MIN;
|
|
18777
|
+
}
|
|
18778
|
+
const thresholdFraction = Math.max(0, executeThresholdPercentage) / 100;
|
|
18779
|
+
const usable = mainContextLimit * thresholdFraction;
|
|
18780
|
+
const derived = Math.round(usable * TRIGGER_BUDGET_PERCENTAGE);
|
|
18781
|
+
return Math.max(TRIGGER_BUDGET_MIN, Math.min(TRIGGER_BUDGET_MAX, derived));
|
|
18782
|
+
}
|
|
18783
|
+
function deriveHistorianChunkTokens(historianContextLimit) {
|
|
18784
|
+
if (!Number.isFinite(historianContextLimit) || historianContextLimit <= 0) {
|
|
18785
|
+
return HISTORIAN_CHUNK_MIN;
|
|
18786
|
+
}
|
|
18787
|
+
const derived = Math.round(historianContextLimit * HISTORIAN_CHUNK_PERCENTAGE);
|
|
18788
|
+
return Math.max(HISTORIAN_CHUNK_MIN, Math.min(HISTORIAN_CHUNK_MAX, derived));
|
|
18789
|
+
}
|
|
18790
|
+
function resolveHistorianContextLimit(historianModelOverride) {
|
|
18791
|
+
if (typeof historianModelOverride === "string" && historianModelOverride.includes("/")) {
|
|
18792
|
+
const [providerID, ...rest] = historianModelOverride.split("/");
|
|
18793
|
+
const modelID = rest.join("/");
|
|
18794
|
+
if (providerID && modelID) {
|
|
18795
|
+
const limit = getModelsDevContextLimit(providerID, modelID);
|
|
18796
|
+
if (typeof limit === "number" && limit > 0)
|
|
18797
|
+
return limit;
|
|
18798
|
+
}
|
|
18799
|
+
return DEFAULT_HISTORIAN_CONTEXT_FALLBACK;
|
|
18800
|
+
}
|
|
18801
|
+
if (typeof historianModelOverride === "string" && historianModelOverride.trim() !== "") {
|
|
18802
|
+
console.warn(`[magic-context] historian.model "${historianModelOverride}" lacks provider prefix ("provider/model-id"); using fallback chain for chunk-budget derivation.`);
|
|
18803
|
+
}
|
|
18804
|
+
const chain = AGENT_MODEL_REQUIREMENTS[HISTORIAN_AGENT]?.fallbackChain;
|
|
18805
|
+
if (!chain || chain.length === 0)
|
|
18806
|
+
return DEFAULT_HISTORIAN_CONTEXT_FALLBACK;
|
|
18807
|
+
const expanded = expandFallbackChain(chain);
|
|
18808
|
+
let minLimit;
|
|
18809
|
+
for (const key of expanded) {
|
|
18810
|
+
const [providerID, ...rest] = key.split("/");
|
|
18811
|
+
const modelID = rest.join("/");
|
|
18812
|
+
if (!providerID || !modelID)
|
|
18813
|
+
continue;
|
|
18814
|
+
const limit = getModelsDevContextLimit(providerID, modelID);
|
|
18815
|
+
if (typeof limit !== "number" || limit <= 0)
|
|
18816
|
+
continue;
|
|
18817
|
+
if (minLimit === undefined || limit < minLimit)
|
|
18818
|
+
minLimit = limit;
|
|
18819
|
+
}
|
|
18820
|
+
return minLimit ?? DEFAULT_HISTORIAN_CONTEXT_FALLBACK;
|
|
18821
|
+
}
|
|
18822
|
+
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;
|
|
18823
|
+
var init_derive_budgets = __esm(() => {
|
|
18824
|
+
init_model_requirements();
|
|
18825
|
+
init_models_dev_cache();
|
|
18826
|
+
});
|
|
18827
|
+
|
|
18569
18828
|
// src/features/magic-context/compaction-marker.ts
|
|
18570
18829
|
import { Database as Database4 } from "bun:sqlite";
|
|
18571
18830
|
import { join as join12 } from "path";
|
|
@@ -19980,7 +20239,7 @@ async function runCompartmentAgent(deps) {
|
|
|
19980
20239
|
client,
|
|
19981
20240
|
db,
|
|
19982
20241
|
sessionId,
|
|
19983
|
-
|
|
20242
|
+
historianChunkTokens,
|
|
19984
20243
|
directory,
|
|
19985
20244
|
historianTimeoutMs,
|
|
19986
20245
|
getNotificationParams
|
|
@@ -20015,7 +20274,7 @@ No new compartments or facts were written. Rebuild or clear the broken compartme
|
|
|
20015
20274
|
if (protectedTailStart <= offset) {
|
|
20016
20275
|
return;
|
|
20017
20276
|
}
|
|
20018
|
-
const chunk = readSessionChunk(sessionId,
|
|
20277
|
+
const chunk = readSessionChunk(sessionId, historianChunkTokens, offset, protectedTailStart);
|
|
20019
20278
|
if (!chunk.text || chunk.messageCount === 0) {
|
|
20020
20279
|
return;
|
|
20021
20280
|
}
|
|
@@ -20158,7 +20417,7 @@ async function executeContextRecompInternal(deps) {
|
|
|
20158
20417
|
client,
|
|
20159
20418
|
db,
|
|
20160
20419
|
sessionId,
|
|
20161
|
-
|
|
20420
|
+
historianChunkTokens,
|
|
20162
20421
|
directory,
|
|
20163
20422
|
historianTimeoutMs,
|
|
20164
20423
|
getNotificationParams
|
|
@@ -20212,7 +20471,7 @@ No eligible raw history exists before the protected tail, so nothing was rebuilt
|
|
|
20212
20471
|
let candidateFacts = existingStaging?.facts ?? [];
|
|
20213
20472
|
let offset = existingStaging ? existingStaging.lastEndMessage + 1 : 1;
|
|
20214
20473
|
let passCount = existingStaging?.passCount ?? 0;
|
|
20215
|
-
let currentTokenBudget =
|
|
20474
|
+
let currentTokenBudget = historianChunkTokens;
|
|
20216
20475
|
let passAttempt = 1;
|
|
20217
20476
|
const resumed = existingStaging !== null;
|
|
20218
20477
|
if (resumed) {
|
|
@@ -20310,7 +20569,7 @@ Nothing was written.`;
|
|
|
20310
20569
|
];
|
|
20311
20570
|
candidateFacts = validatedPass.facts ?? [];
|
|
20312
20571
|
passCount += 1;
|
|
20313
|
-
currentTokenBudget =
|
|
20572
|
+
currentTokenBudget = historianChunkTokens;
|
|
20314
20573
|
passAttempt = 1;
|
|
20315
20574
|
saveRecompStagingPass(db, sessionId, passCount, candidateCompartments, candidateFacts);
|
|
20316
20575
|
const nextOffset = (validatedPass.compartments?.[validatedPass.compartments.length - 1]?.endMessage ?? chunk.endIndex) + 1;
|
|
@@ -28510,7 +28769,7 @@ Check verifiable memories against actual repository state. Update stale wording,
|
|
|
28510
28769
|
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.
|
|
28511
28770
|
|
|
28512
28771
|
### Verification examples
|
|
28513
|
-
- Memory: "
|
|
28772
|
+
- Memory: "history_budget_percentage defaults to 0.15" \u2192 grep schema for \`history_budget_percentage\`, check \`.default(...)\`
|
|
28514
28773
|
- Memory: "Durable state lives in ~/.local/share/opencode/storage/plugin/magic-context/context.db" \u2192 check storage-db.ts for the path construction
|
|
28515
28774
|
- Memory: "ctx_search searches memories, facts, and history" \u2192 grep for ctx_search tool definition and unified search implementation
|
|
28516
28775
|
|
|
@@ -30239,110 +30498,13 @@ function createCompactionHandler() {
|
|
|
30239
30498
|
}
|
|
30240
30499
|
};
|
|
30241
30500
|
}
|
|
30242
|
-
// src/shared/models-dev-cache.ts
|
|
30243
|
-
init_logger();
|
|
30244
|
-
import { existsSync as existsSync5, readFileSync as readFileSync4 } from "fs";
|
|
30245
|
-
import { homedir as homedir5, platform as platform2 } from "os";
|
|
30246
|
-
import { join as join11 } from "path";
|
|
30247
|
-
var cachedLimits = null;
|
|
30248
|
-
var lastLoadAttempt = 0;
|
|
30249
|
-
var RELOAD_INTERVAL_MS = 5 * 60 * 1000;
|
|
30250
|
-
function getModelsJsonPath() {
|
|
30251
|
-
const xdgCache = process.env.XDG_CACHE_HOME;
|
|
30252
|
-
const os3 = platform2();
|
|
30253
|
-
let cacheBase;
|
|
30254
|
-
if (xdgCache) {
|
|
30255
|
-
cacheBase = xdgCache;
|
|
30256
|
-
} else if (os3 === "win32") {
|
|
30257
|
-
cacheBase = process.env.LOCALAPPDATA ?? join11(homedir5(), "AppData", "Local");
|
|
30258
|
-
} else {
|
|
30259
|
-
cacheBase = join11(homedir5(), ".cache");
|
|
30260
|
-
}
|
|
30261
|
-
return join11(cacheBase, "opencode", "models.json");
|
|
30262
|
-
}
|
|
30263
|
-
function getOpencodeConfigPath() {
|
|
30264
|
-
const envDir = process.env.OPENCODE_CONFIG_DIR?.trim();
|
|
30265
|
-
const configDir = envDir ? envDir : platform2() === "win32" ? join11(homedir5(), ".config", "opencode") : join11(process.env.XDG_CONFIG_HOME || join11(homedir5(), ".config"), "opencode");
|
|
30266
|
-
const jsonc = join11(configDir, "opencode.jsonc");
|
|
30267
|
-
if (existsSync5(jsonc))
|
|
30268
|
-
return jsonc;
|
|
30269
|
-
const json2 = join11(configDir, "opencode.json");
|
|
30270
|
-
if (existsSync5(json2))
|
|
30271
|
-
return json2;
|
|
30272
|
-
return null;
|
|
30273
|
-
}
|
|
30274
|
-
function loadModelsDevLimits() {
|
|
30275
|
-
const limits = new Map;
|
|
30276
|
-
const modelsJsonPath = getModelsJsonPath();
|
|
30277
|
-
try {
|
|
30278
|
-
if (existsSync5(modelsJsonPath)) {
|
|
30279
|
-
const raw = readFileSync4(modelsJsonPath, "utf-8");
|
|
30280
|
-
const data = JSON.parse(raw);
|
|
30281
|
-
for (const [providerId, provider2] of Object.entries(data)) {
|
|
30282
|
-
if (!provider2?.models || typeof provider2.models !== "object")
|
|
30283
|
-
continue;
|
|
30284
|
-
for (const [modelId, model] of Object.entries(provider2.models)) {
|
|
30285
|
-
const context = model?.limit?.context;
|
|
30286
|
-
if (typeof context === "number" && context > 0) {
|
|
30287
|
-
limits.set(`${providerId}/${modelId}`, context);
|
|
30288
|
-
const modes = model?.experimental?.modes;
|
|
30289
|
-
if (modes && typeof modes === "object") {
|
|
30290
|
-
for (const mode of Object.keys(modes)) {
|
|
30291
|
-
limits.set(`${providerId}/${modelId}-${mode}`, context);
|
|
30292
|
-
}
|
|
30293
|
-
}
|
|
30294
|
-
}
|
|
30295
|
-
}
|
|
30296
|
-
}
|
|
30297
|
-
}
|
|
30298
|
-
} catch (error48) {
|
|
30299
|
-
sessionLog("global", "models-dev-cache: failed to read models.json:", error48 instanceof Error ? error48.message : String(error48));
|
|
30300
|
-
}
|
|
30301
|
-
try {
|
|
30302
|
-
const configPath = getOpencodeConfigPath();
|
|
30303
|
-
if (configPath && existsSync5(configPath)) {
|
|
30304
|
-
let raw = readFileSync4(configPath, "utf-8");
|
|
30305
|
-
raw = raw.replace(/"(?:[^"\\]|\\.)*"|\/\/.*$/gm, (match) => match.startsWith('"') ? match : "");
|
|
30306
|
-
const config2 = JSON.parse(raw);
|
|
30307
|
-
if (config2.provider && typeof config2.provider === "object") {
|
|
30308
|
-
for (const [providerId, provider2] of Object.entries(config2.provider)) {
|
|
30309
|
-
if (!provider2?.models || typeof provider2.models !== "object")
|
|
30310
|
-
continue;
|
|
30311
|
-
for (const [modelId, model] of Object.entries(provider2.models)) {
|
|
30312
|
-
const context = model?.limit?.context;
|
|
30313
|
-
if (typeof context === "number" && context > 0) {
|
|
30314
|
-
limits.set(`${providerId}/${modelId}`, context);
|
|
30315
|
-
}
|
|
30316
|
-
}
|
|
30317
|
-
}
|
|
30318
|
-
}
|
|
30319
|
-
}
|
|
30320
|
-
} catch (error48) {
|
|
30321
|
-
sessionLog("global", "models-dev-cache: failed to read opencode config for custom models:", error48 instanceof Error ? error48.message : String(error48));
|
|
30322
|
-
}
|
|
30323
|
-
return limits;
|
|
30324
|
-
}
|
|
30325
|
-
function getModelsDevContextLimit(providerID, modelID) {
|
|
30326
|
-
const now = Date.now();
|
|
30327
|
-
if (!cachedLimits || now - lastLoadAttempt > RELOAD_INTERVAL_MS) {
|
|
30328
|
-
lastLoadAttempt = now;
|
|
30329
|
-
cachedLimits = loadModelsDevLimits();
|
|
30330
|
-
}
|
|
30331
|
-
return cachedLimits.get(`${providerID}/${modelID}`);
|
|
30332
|
-
}
|
|
30333
|
-
|
|
30334
30501
|
// src/hooks/magic-context/event-resolvers.ts
|
|
30502
|
+
init_models_dev_cache();
|
|
30335
30503
|
var DEFAULT_CONTEXT_LIMIT = 128000;
|
|
30336
|
-
function resolveContextLimit(providerID, modelID
|
|
30504
|
+
function resolveContextLimit(providerID, modelID) {
|
|
30337
30505
|
if (!providerID) {
|
|
30338
30506
|
return DEFAULT_CONTEXT_LIMIT;
|
|
30339
30507
|
}
|
|
30340
|
-
if (modelID) {
|
|
30341
|
-
const modelSpecific = config2.modelContextLimitsCache?.get(`${providerID}/${modelID}`);
|
|
30342
|
-
if (typeof modelSpecific === "number" && modelSpecific > 0) {
|
|
30343
|
-
return modelSpecific;
|
|
30344
|
-
}
|
|
30345
|
-
}
|
|
30346
30508
|
if (modelID) {
|
|
30347
30509
|
const modelsDevLimit = getModelsDevContextLimit(providerID, modelID);
|
|
30348
30510
|
if (modelsDevLimit !== undefined) {
|
|
@@ -30625,7 +30787,6 @@ init_storage_tags();
|
|
|
30625
30787
|
init_logger();
|
|
30626
30788
|
|
|
30627
30789
|
// src/hooks/magic-context/compartment-trigger.ts
|
|
30628
|
-
init_magic_context();
|
|
30629
30790
|
init_compartment_storage();
|
|
30630
30791
|
init_storage();
|
|
30631
30792
|
init_logger();
|
|
@@ -30703,7 +30864,7 @@ var TAIL_INFO_DEFAULTS = {
|
|
|
30703
30864
|
tokenEstimate: 0,
|
|
30704
30865
|
commitClusterCount: 0
|
|
30705
30866
|
};
|
|
30706
|
-
function getUnsummarizedTailInfo(db, sessionId,
|
|
30867
|
+
function getUnsummarizedTailInfo(db, sessionId, triggerBudget) {
|
|
30707
30868
|
return withRawSessionMessageCache(() => {
|
|
30708
30869
|
try {
|
|
30709
30870
|
const lastCompartmentEnd = getLastCompartmentEndMessage(db, sessionId);
|
|
@@ -30714,7 +30875,7 @@ function getUnsummarizedTailInfo(db, sessionId, compartmentTokenBudget) {
|
|
|
30714
30875
|
if (!hasEligibleHistory) {
|
|
30715
30876
|
return { ...TAIL_INFO_DEFAULTS, nextStartOrdinal };
|
|
30716
30877
|
}
|
|
30717
|
-
const scanBudget = Math.max(MIN_PROACTIVE_TAIL_TOKEN_ESTIMATE,
|
|
30878
|
+
const scanBudget = Math.max(MIN_PROACTIVE_TAIL_TOKEN_ESTIMATE, triggerBudget * TAIL_SIZE_TRIGGER_MULTIPLIER);
|
|
30718
30879
|
const chunk = readSessionChunk(sessionId, scanBudget, nextStartOrdinal, protectedTailStart);
|
|
30719
30880
|
const isMeaningful = chunk.hasMore || chunk.tokenEstimate >= MIN_PROACTIVE_TAIL_TOKEN_ESTIMATE || chunk.messageCount >= MIN_PROACTIVE_TAIL_MESSAGE_COUNT;
|
|
30720
30881
|
return {
|
|
@@ -30730,11 +30891,11 @@ function getUnsummarizedTailInfo(db, sessionId, compartmentTokenBudget) {
|
|
|
30730
30891
|
}
|
|
30731
30892
|
});
|
|
30732
30893
|
}
|
|
30733
|
-
function checkCompartmentTrigger(db, sessionId, sessionMeta, usage, _previousPercentage, executeThresholdPercentage,
|
|
30894
|
+
function checkCompartmentTrigger(db, sessionId, sessionMeta, usage, _previousPercentage, executeThresholdPercentage, triggerBudget, autoDropToolAge, protectedTagCount, clearReasoningAge, dropToolStructure = true, commitClusterTrigger) {
|
|
30734
30895
|
if (sessionMeta.compartmentInProgress) {
|
|
30735
30896
|
return { shouldFire: false };
|
|
30736
30897
|
}
|
|
30737
|
-
const tailInfo = getUnsummarizedTailInfo(db, sessionId,
|
|
30898
|
+
const tailInfo = getUnsummarizedTailInfo(db, sessionId, triggerBudget);
|
|
30738
30899
|
if (!tailInfo.hasNewRawHistory) {
|
|
30739
30900
|
return { shouldFire: false };
|
|
30740
30901
|
}
|
|
@@ -30750,12 +30911,12 @@ function checkCompartmentTrigger(db, sessionId, sessionMeta, usage, _previousPer
|
|
|
30750
30911
|
}
|
|
30751
30912
|
const clusterEnabled = commitClusterTrigger?.enabled ?? true;
|
|
30752
30913
|
const minClusters = commitClusterTrigger?.min_clusters ?? DEFAULT_MIN_COMMIT_CLUSTERS_FOR_TRIGGER;
|
|
30753
|
-
if (clusterEnabled && tailInfo.commitClusterCount >= minClusters && tailInfo.tokenEstimate >=
|
|
30914
|
+
if (clusterEnabled && tailInfo.commitClusterCount >= minClusters && tailInfo.tokenEstimate >= triggerBudget) {
|
|
30754
30915
|
sessionLog(sessionId, `compartment trigger: commit-cluster fire \u2014 ${tailInfo.commitClusterCount} clusters (min=${minClusters}), ~${tailInfo.tokenEstimate} tokens in eligible prefix`);
|
|
30755
30916
|
return { shouldFire: true, reason: "commit_clusters" };
|
|
30756
30917
|
}
|
|
30757
|
-
if (tailInfo.tokenEstimate >=
|
|
30758
|
-
sessionLog(sessionId, `compartment trigger: tail-size fire \u2014 ~${tailInfo.tokenEstimate} tokens exceeds ${
|
|
30918
|
+
if (tailInfo.tokenEstimate >= triggerBudget * TAIL_SIZE_TRIGGER_MULTIPLIER) {
|
|
30919
|
+
sessionLog(sessionId, `compartment trigger: tail-size fire \u2014 ~${tailInfo.tokenEstimate} tokens exceeds ${triggerBudget * TAIL_SIZE_TRIGGER_MULTIPLIER} budget threshold`);
|
|
30759
30920
|
return { shouldFire: true, reason: "tail_size" };
|
|
30760
30921
|
}
|
|
30761
30922
|
const proactiveTriggerPercentage = getProactiveCompartmentTriggerPercentage(executeThresholdPercentage);
|
|
@@ -31099,11 +31260,15 @@ Historian recomp started. Rebuilding compartments and facts from raw session his
|
|
|
31099
31260
|
};
|
|
31100
31261
|
}
|
|
31101
31262
|
|
|
31263
|
+
// src/hooks/magic-context/hook.ts
|
|
31264
|
+
init_derive_budgets();
|
|
31265
|
+
|
|
31102
31266
|
// src/hooks/magic-context/event-handler.ts
|
|
31103
31267
|
init_storage();
|
|
31104
31268
|
init_storage_meta_persisted();
|
|
31105
31269
|
init_logger();
|
|
31106
31270
|
init_compaction_marker_manager();
|
|
31271
|
+
init_derive_budgets();
|
|
31107
31272
|
|
|
31108
31273
|
// src/hooks/magic-context/event-payloads.ts
|
|
31109
31274
|
function getSessionProperties(properties) {
|
|
@@ -31175,7 +31340,6 @@ function getMessageRemovedInfo(properties) {
|
|
|
31175
31340
|
init_note_nudger();
|
|
31176
31341
|
|
|
31177
31342
|
// src/hooks/magic-context/transform-compartment-phase.ts
|
|
31178
|
-
init_magic_context();
|
|
31179
31343
|
init_compartment_storage();
|
|
31180
31344
|
init_storage();
|
|
31181
31345
|
init_logger();
|
|
@@ -31251,7 +31415,7 @@ async function runCompartmentPhase(args) {
|
|
|
31251
31415
|
client: args.client,
|
|
31252
31416
|
db: args.db,
|
|
31253
31417
|
sessionId: args.sessionId,
|
|
31254
|
-
|
|
31418
|
+
historianChunkTokens: args.historianChunkTokens,
|
|
31255
31419
|
historyBudgetTokens: args.historyBudgetTokens,
|
|
31256
31420
|
historianTimeoutMs: args.historianTimeoutMs,
|
|
31257
31421
|
directory: args.compartmentDirectory,
|
|
@@ -31272,7 +31436,7 @@ async function runCompartmentPhase(args) {
|
|
|
31272
31436
|
client: args.client,
|
|
31273
31437
|
db: args.db,
|
|
31274
31438
|
sessionId: args.sessionId,
|
|
31275
|
-
|
|
31439
|
+
historianChunkTokens: args.historianChunkTokens,
|
|
31276
31440
|
historyBudgetTokens: args.historyBudgetTokens,
|
|
31277
31441
|
historianTimeoutMs: args.historianTimeoutMs,
|
|
31278
31442
|
directory: args.compartmentDirectory,
|
|
@@ -31425,9 +31589,7 @@ function createEventHandler2(deps) {
|
|
|
31425
31589
|
}
|
|
31426
31590
|
if (hasUsageTokens) {
|
|
31427
31591
|
const totalInputTokens = (info.tokens?.input ?? 0) + (info.tokens?.cache?.read ?? 0) + (info.tokens?.cache?.write ?? 0);
|
|
31428
|
-
const contextLimit = resolveContextLimit(info.providerID, info.modelID
|
|
31429
|
-
modelContextLimitsCache: deps.config.modelContextLimitsCache
|
|
31430
|
-
});
|
|
31592
|
+
const contextLimit = resolveContextLimit(info.providerID, info.modelID);
|
|
31431
31593
|
const percentage = contextLimit > 0 ? totalInputTokens / contextLimit * 100 : 0;
|
|
31432
31594
|
sessionLog(info.sessionID, `event message.updated: totalInputTokens=${totalInputTokens} contextLimit=${contextLimit} percentage=${percentage.toFixed(1)}%`);
|
|
31433
31595
|
deps.contextUsageMap.set(info.sessionID, {
|
|
@@ -31447,7 +31609,9 @@ function createEventHandler2(deps) {
|
|
|
31447
31609
|
const sessionMeta = getOrCreateSessionMeta(deps.db, info.sessionID);
|
|
31448
31610
|
const previousPercentage = sessionMeta.lastContextPercentage;
|
|
31449
31611
|
if (!sessionMeta.isSubagent) {
|
|
31450
|
-
const
|
|
31612
|
+
const effectiveExecuteThreshold = resolveExecuteThreshold(deps.config.execute_threshold_percentage ?? 65, modelKey, 65);
|
|
31613
|
+
const triggerBudget = deriveTriggerBudget(contextLimit, effectiveExecuteThreshold);
|
|
31614
|
+
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);
|
|
31451
31615
|
if (triggerResult.shouldFire) {
|
|
31452
31616
|
sessionLog(info.sessionID, `compartment trigger: firing (reason=${triggerResult.reason})`);
|
|
31453
31617
|
updateSessionMeta(deps.db, info.sessionID, {
|
|
@@ -31725,7 +31889,6 @@ function createTextCompleteHandler() {
|
|
|
31725
31889
|
}
|
|
31726
31890
|
|
|
31727
31891
|
// src/hooks/magic-context/transform.ts
|
|
31728
|
-
init_magic_context();
|
|
31729
31892
|
init_compartment_storage();
|
|
31730
31893
|
init_project_identity();
|
|
31731
31894
|
init_storage();
|
|
@@ -32806,6 +32969,14 @@ function isToolProtocolPart(part) {
|
|
|
32806
32969
|
function hasToolProtocolParts(message) {
|
|
32807
32970
|
return message.parts.some(isToolProtocolPart);
|
|
32808
32971
|
}
|
|
32972
|
+
function hasThinkingBearingParts(message) {
|
|
32973
|
+
return message.parts.some((part) => {
|
|
32974
|
+
if (part === null || typeof part !== "object")
|
|
32975
|
+
return false;
|
|
32976
|
+
const p = part;
|
|
32977
|
+
return p.type === "thinking" || p.type === "reasoning" || p.type === "redacted_thinking";
|
|
32978
|
+
});
|
|
32979
|
+
}
|
|
32809
32980
|
function isMessageDropped(message) {
|
|
32810
32981
|
const textParts = message.parts.filter(isTextPart);
|
|
32811
32982
|
if (textParts.length === 0)
|
|
@@ -32840,6 +33011,11 @@ function reinjectNudgeAtAnchor(messages, nudgeText, nudgePlacements, sessionId)
|
|
|
32840
33011
|
nudgePlacements.clear(sessionId);
|
|
32841
33012
|
return false;
|
|
32842
33013
|
}
|
|
33014
|
+
if (hasThinkingBearingParts(message)) {
|
|
33015
|
+
sessionLog(sessionId, `nudge anchor abandoned: message ${message.info.id} now contains thinking/reasoning parts (signed, immutable)`);
|
|
33016
|
+
nudgePlacements.clear(sessionId);
|
|
33017
|
+
return false;
|
|
33018
|
+
}
|
|
32843
33019
|
for (let j = message.parts.length - 1;j >= 0; j--) {
|
|
32844
33020
|
const part = message.parts[j];
|
|
32845
33021
|
if (isTextPart(part)) {
|
|
@@ -32868,6 +33044,8 @@ function appendNudgeToAssistant(messages, nudge, nudgePlacements, sessionId) {
|
|
|
32868
33044
|
continue;
|
|
32869
33045
|
if (isMessageDropped(message))
|
|
32870
33046
|
continue;
|
|
33047
|
+
if (hasThinkingBearingParts(message))
|
|
33048
|
+
continue;
|
|
32871
33049
|
for (let j = message.parts.length - 1;j >= 0; j--) {
|
|
32872
33050
|
const part = message.parts[j];
|
|
32873
33051
|
if (isTextPart(part)) {
|
|
@@ -33151,12 +33329,13 @@ function runPostTransformPhase(args) {
|
|
|
33151
33329
|
const forceMaterialization = args.fullFeatureMode && args.contextUsage.percentage >= args.forceMaterializationPercentage;
|
|
33152
33330
|
const activeCompartmentRun = args.canRunCompartments ? getActiveCompartmentRun(args.sessionId) : undefined;
|
|
33153
33331
|
const compartmentRunning = args.canRunCompartments && !args.awaitedCompartmentRun && activeCompartmentRun !== undefined;
|
|
33154
|
-
const
|
|
33332
|
+
const emergencyBypassCompartmentGate = forceMaterialization;
|
|
33333
|
+
const shouldReadPendingOps = isExplicitFlush || args.schedulerDecision === "execute" || forceMaterialization || compartmentRunning;
|
|
33155
33334
|
const pendingOps = shouldReadPendingOps ? getPendingOps(args.db, args.sessionId) : [];
|
|
33156
33335
|
const hasPendingUserOps = pendingOps.length > 0;
|
|
33157
|
-
const shouldApplyPendingOps = (args.schedulerDecision === "execute" || isExplicitFlush) && !compartmentRunning;
|
|
33336
|
+
const shouldApplyPendingOps = (args.schedulerDecision === "execute" || isExplicitFlush || forceMaterialization) && (!compartmentRunning || emergencyBypassCompartmentGate);
|
|
33158
33337
|
const isCacheBustingPass = isExplicitFlush || shouldApplyPendingOps;
|
|
33159
|
-
const shouldRunHeuristics = args.fullFeatureMode && !compartmentRunning && (isExplicitFlush || forceMaterialization || args.schedulerDecision === "execute" && !alreadyRanThisTurn);
|
|
33338
|
+
const shouldRunHeuristics = args.fullFeatureMode && (!compartmentRunning || emergencyBypassCompartmentGate) && (isExplicitFlush || forceMaterialization || args.schedulerDecision === "execute" && !alreadyRanThisTurn);
|
|
33160
33339
|
if (shouldRunHeuristics) {
|
|
33161
33340
|
const reason = isExplicitFlush ? "explicit_flush" : forceMaterialization ? `force_materialization (${args.contextUsage.percentage.toFixed(1)}% >= ${args.forceMaterializationPercentage}%)` : `scheduler_execute (pendingOps=${pendingOps.length}, scheduler=${args.schedulerDecision})`;
|
|
33162
33341
|
sessionLog(args.sessionId, `heuristics WILL RUN \u2014 reason=${reason}, context=${args.contextUsage.percentage.toFixed(1)}%, turn=${args.currentTurnId}`);
|
|
@@ -33165,7 +33344,11 @@ function runPostTransformPhase(args) {
|
|
|
33165
33344
|
sessionLog(args.sessionId, `transform: skipping heuristics (already ran for turn ${args.currentTurnId})`);
|
|
33166
33345
|
}
|
|
33167
33346
|
if (compartmentRunning && hasPendingUserOps) {
|
|
33168
|
-
|
|
33347
|
+
if (emergencyBypassCompartmentGate) {
|
|
33348
|
+
sessionLog(args.sessionId, `transform: emergency bypass \u2014 applying ${pendingOps.length} pending ops while compartment agent runs (${args.contextUsage.percentage.toFixed(1)}%)`);
|
|
33349
|
+
} else {
|
|
33350
|
+
sessionLog(args.sessionId, "transform: deferring pending ops \u2014 compartment agent in progress");
|
|
33351
|
+
}
|
|
33169
33352
|
}
|
|
33170
33353
|
try {
|
|
33171
33354
|
if (shouldApplyPendingOps) {
|
|
@@ -33524,7 +33707,7 @@ function createTransform(deps) {
|
|
|
33524
33707
|
client: deps.client,
|
|
33525
33708
|
db,
|
|
33526
33709
|
sessionId,
|
|
33527
|
-
|
|
33710
|
+
historianChunkTokens: deps.getHistorianChunkTokens?.() ?? 20000,
|
|
33528
33711
|
historyBudgetTokens,
|
|
33529
33712
|
historianTimeoutMs: deps.historianTimeoutMs,
|
|
33530
33713
|
directory: compartmentDirectory,
|
|
@@ -33645,7 +33828,7 @@ Historian previously failed ${historianFailureState.failureCount} time(s), so ma
|
|
|
33645
33828
|
db,
|
|
33646
33829
|
sessionId,
|
|
33647
33830
|
resolvedSessionId,
|
|
33648
|
-
|
|
33831
|
+
historianChunkTokens: deps.getHistorianChunkTokens?.() ?? 20000,
|
|
33649
33832
|
historyBudgetTokens,
|
|
33650
33833
|
historianTimeoutMs: deps.historianTimeoutMs,
|
|
33651
33834
|
compartmentDirectory,
|
|
@@ -34352,6 +34535,7 @@ function createMagicContextHook(deps) {
|
|
|
34352
34535
|
const projectPath = resolveProjectIdentity(deps.directory);
|
|
34353
34536
|
registerDreamProjectDirectory(projectPath, deps.directory);
|
|
34354
34537
|
let lastScheduleCheckMs = 0;
|
|
34538
|
+
const getHistorianChunkTokens = () => deriveHistorianChunkTokens(resolveHistorianContextLimit(deps.config.historian?.model));
|
|
34355
34539
|
const nudgePlacements = createNudgePlacementStore(db);
|
|
34356
34540
|
const flushedSessions = new Set;
|
|
34357
34541
|
const lastHeuristicsTurnId = new Map;
|
|
@@ -34389,7 +34573,7 @@ function createMagicContextHook(deps) {
|
|
|
34389
34573
|
enabled: deps.config.memory.enabled,
|
|
34390
34574
|
injectionBudgetTokens: deps.config.memory.injection_budget_tokens
|
|
34391
34575
|
} : undefined,
|
|
34392
|
-
|
|
34576
|
+
getHistorianChunkTokens,
|
|
34393
34577
|
historyBudgetPercentage: deps.config.history_budget_percentage,
|
|
34394
34578
|
executeThresholdPercentage: deps.config.execute_threshold_percentage,
|
|
34395
34579
|
historianTimeoutMs: deps.config.historian_timeout_ms ?? DEFAULT_HISTORIAN_TIMEOUT_MS,
|
|
@@ -34470,7 +34654,7 @@ function createMagicContextHook(deps) {
|
|
|
34470
34654
|
client: deps.client,
|
|
34471
34655
|
db,
|
|
34472
34656
|
sessionId,
|
|
34473
|
-
|
|
34657
|
+
historianChunkTokens: getHistorianChunkTokens(),
|
|
34474
34658
|
historianTimeoutMs: deps.config.historian_timeout_ms ?? DEFAULT_HISTORIAN_TIMEOUT_MS,
|
|
34475
34659
|
directory: deps.directory,
|
|
34476
34660
|
fallbackModelId: (() => {
|
|
@@ -34596,7 +34780,7 @@ function createSessionHooks(args) {
|
|
|
34596
34780
|
clear_reasoning_age: pluginConfig.clear_reasoning_age,
|
|
34597
34781
|
iteration_nudge_threshold: pluginConfig.iteration_nudge_threshold,
|
|
34598
34782
|
execute_threshold_percentage: pluginConfig.execute_threshold_percentage ?? DEFAULT_EXECUTE_THRESHOLD_PERCENTAGE,
|
|
34599
|
-
|
|
34783
|
+
historian: pluginConfig.historian,
|
|
34600
34784
|
history_budget_percentage: pluginConfig.history_budget_percentage,
|
|
34601
34785
|
historian_timeout_ms: pluginConfig.historian_timeout_ms,
|
|
34602
34786
|
memory: pluginConfig.memory,
|
|
@@ -34921,17 +35105,18 @@ function registerRpcHandlers(rpcServer, args) {
|
|
|
34921
35105
|
return { ok: false, error: "no session" };
|
|
34922
35106
|
const { executeContextRecomp: executeContextRecomp2 } = await Promise.resolve().then(() => (init_compartment_runner(), exports_compartment_runner));
|
|
34923
35107
|
const { sendIgnoredMessage: sendIgnoredMessage2 } = await Promise.resolve().then(() => (init_send_session_notification(), exports_send_session_notification));
|
|
35108
|
+
const { deriveHistorianChunkTokens: deriveHistorianChunkTokens2, resolveHistorianContextLimit: resolveHistorianContextLimit2 } = await Promise.resolve().then(() => (init_derive_budgets(), exports_derive_budgets));
|
|
34924
35109
|
const db = getDb();
|
|
34925
35110
|
if (!db)
|
|
34926
35111
|
return { ok: false, error: "db unavailable" };
|
|
34927
|
-
const DEFAULT_COMPARTMENT_TOKEN_BUDGET2 = 20000;
|
|
34928
35112
|
const DEFAULT_HISTORIAN_TIMEOUT_MS2 = 600000;
|
|
35113
|
+
const historianChunkTokens = deriveHistorianChunkTokens2(resolveHistorianContextLimit2(config2.historian?.model));
|
|
34929
35114
|
log(`[rpc] recomp requested for session ${sessionId}`);
|
|
34930
35115
|
executeContextRecomp2({
|
|
34931
35116
|
client: args.client,
|
|
34932
35117
|
db,
|
|
34933
35118
|
sessionId,
|
|
34934
|
-
|
|
35119
|
+
historianChunkTokens,
|
|
34935
35120
|
historianTimeoutMs: config2.historian_timeout_ms ?? DEFAULT_HISTORIAN_TIMEOUT_MS2,
|
|
34936
35121
|
directory,
|
|
34937
35122
|
getNotificationParams: () => getNotificationParams(sessionId)
|
|
@@ -36136,6 +36321,7 @@ init_conflict_detector();
|
|
|
36136
36321
|
init_data_path();
|
|
36137
36322
|
init_logger();
|
|
36138
36323
|
init_model_requirements();
|
|
36324
|
+
init_models_dev_cache();
|
|
36139
36325
|
|
|
36140
36326
|
// src/shared/rpc-server.ts
|
|
36141
36327
|
init_logger();
|
|
@@ -36144,11 +36330,11 @@ import { createServer } from "http";
|
|
|
36144
36330
|
import { dirname } from "path";
|
|
36145
36331
|
|
|
36146
36332
|
// src/shared/rpc-utils.ts
|
|
36147
|
-
import { createHash } from "crypto";
|
|
36333
|
+
import { createHash as createHash2 } from "crypto";
|
|
36148
36334
|
import { join as join15 } from "path";
|
|
36149
36335
|
function projectHash(directory) {
|
|
36150
36336
|
const normalized = directory.replace(/\/+$/, "");
|
|
36151
|
-
return
|
|
36337
|
+
return createHash2("sha256").update(normalized).digest("hex").slice(0, 16);
|
|
36152
36338
|
}
|
|
36153
36339
|
function rpcPortFilePath(storageDir, directory) {
|
|
36154
36340
|
return join15(storageDir, "rpc", projectHash(directory), "port");
|
|
@@ -36333,6 +36519,10 @@ var plugin = async (ctx) => {
|
|
|
36333
36519
|
rpcServer.start().catch((err) => {
|
|
36334
36520
|
log(`[magic-context] RPC server failed to start: ${err}`);
|
|
36335
36521
|
});
|
|
36522
|
+
refreshModelLimitsFromApi(ctx.client);
|
|
36523
|
+
setInterval(() => {
|
|
36524
|
+
refreshModelLimitsFromApi(ctx.client);
|
|
36525
|
+
}, 5 * 60 * 1000);
|
|
36336
36526
|
}
|
|
36337
36527
|
if (conflictResult?.hasConflict) {
|
|
36338
36528
|
sendConflictWarning(ctx.client, ctx.directory, conflictResult);
|