@cortexkit/opencode-magic-context 0.17.2 → 0.18.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.
- package/dist/features/magic-context/dreamer/runner.d.ts +15 -0
- package/dist/features/magic-context/dreamer/runner.d.ts.map +1 -1
- package/dist/features/magic-context/migrations.d.ts.map +1 -1
- package/dist/features/magic-context/sidekick/agent.d.ts.map +1 -1
- package/dist/features/magic-context/storage-db.d.ts.map +1 -1
- package/dist/features/magic-context/storage-meta-persisted.d.ts +14 -0
- package/dist/features/magic-context/storage-meta-persisted.d.ts.map +1 -1
- package/dist/features/magic-context/storage-meta-shared.d.ts +1 -0
- package/dist/features/magic-context/storage-meta-shared.d.ts.map +1 -1
- package/dist/features/magic-context/storage-meta.d.ts +1 -1
- package/dist/features/magic-context/storage-meta.d.ts.map +1 -1
- package/dist/features/magic-context/storage.d.ts +1 -1
- package/dist/features/magic-context/storage.d.ts.map +1 -1
- package/dist/features/magic-context/types.d.ts +1 -0
- package/dist/features/magic-context/types.d.ts.map +1 -1
- package/dist/features/magic-context/user-memory/review-user-memories.d.ts +2 -0
- package/dist/features/magic-context/user-memory/review-user-memories.d.ts.map +1 -1
- package/dist/hooks/magic-context/command-handler.d.ts +2 -0
- package/dist/hooks/magic-context/command-handler.d.ts.map +1 -1
- package/dist/hooks/magic-context/compartment-runner-compressor.d.ts +1 -0
- package/dist/hooks/magic-context/compartment-runner-compressor.d.ts.map +1 -1
- package/dist/hooks/magic-context/compartment-runner-historian.d.ts +7 -0
- package/dist/hooks/magic-context/compartment-runner-historian.d.ts.map +1 -1
- package/dist/hooks/magic-context/compartment-runner-incremental.d.ts.map +1 -1
- package/dist/hooks/magic-context/compartment-runner-partial-recomp.d.ts.map +1 -1
- package/dist/hooks/magic-context/compartment-runner-recomp.d.ts.map +1 -1
- package/dist/hooks/magic-context/compartment-runner-types.d.ts +2 -0
- package/dist/hooks/magic-context/compartment-runner-types.d.ts.map +1 -1
- package/dist/hooks/magic-context/hook-handlers.d.ts.map +1 -1
- package/dist/hooks/magic-context/hook.d.ts.map +1 -1
- package/dist/hooks/magic-context/system-prompt-hash.d.ts.map +1 -1
- package/dist/hooks/magic-context/todo-view.d.ts +102 -0
- package/dist/hooks/magic-context/todo-view.d.ts.map +1 -0
- package/dist/hooks/magic-context/transform-compartment-phase.d.ts +1 -0
- package/dist/hooks/magic-context/transform-compartment-phase.d.ts.map +1 -1
- package/dist/hooks/magic-context/transform-message-helpers.d.ts +22 -0
- package/dist/hooks/magic-context/transform-message-helpers.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 +2 -0
- package/dist/hooks/magic-context/transform.d.ts.map +1 -1
- package/dist/index.js +626 -178
- package/dist/plugin/dream-timer.d.ts.map +1 -1
- package/dist/plugin/hooks/create-session-hooks.d.ts.map +1 -1
- package/dist/plugin/rpc-handlers.d.ts +2 -1
- package/dist/plugin/rpc-handlers.d.ts.map +1 -1
- package/dist/shared/index.d.ts +1 -0
- package/dist/shared/index.d.ts.map +1 -1
- package/dist/shared/model-suggestion-retry.d.ts +37 -0
- package/dist/shared/model-suggestion-retry.d.ts.map +1 -1
- package/dist/shared/models-dev-cache.d.ts.map +1 -1
- package/dist/shared/resolve-fallbacks.d.ts +32 -0
- package/dist/shared/resolve-fallbacks.d.ts.map +1 -0
- package/dist/shared/tag-transcript.d.ts.map +1 -1
- package/dist/tools/ctx-memory/tools.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/shared/index.ts +1 -0
- package/src/shared/model-suggestion-retry.test.ts +251 -0
- package/src/shared/model-suggestion-retry.ts +194 -6
- package/src/shared/models-dev-cache.ts +7 -7
- package/src/shared/resolve-fallbacks.test.ts +136 -0
- package/src/shared/resolve-fallbacks.ts +76 -0
- package/src/shared/tag-transcript.ts +3 -2
- package/src/tui/index.tsx +114 -18
package/dist/index.js
CHANGED
|
@@ -15122,6 +15122,161 @@ var init_model_requirements = __esm(() => {
|
|
|
15122
15122
|
};
|
|
15123
15123
|
});
|
|
15124
15124
|
|
|
15125
|
+
// src/features/magic-context/overflow-detection.ts
|
|
15126
|
+
function extractErrorMessage(error51) {
|
|
15127
|
+
if (!error51)
|
|
15128
|
+
return "";
|
|
15129
|
+
if (typeof error51 === "string")
|
|
15130
|
+
return error51;
|
|
15131
|
+
if (typeof error51 === "object") {
|
|
15132
|
+
const obj = error51;
|
|
15133
|
+
const nested = obj.error;
|
|
15134
|
+
if (nested && typeof nested.message === "string" && nested.message.length > 0) {
|
|
15135
|
+
return nested.message;
|
|
15136
|
+
}
|
|
15137
|
+
}
|
|
15138
|
+
if (error51 instanceof Error)
|
|
15139
|
+
return error51.message;
|
|
15140
|
+
if (typeof error51 === "object") {
|
|
15141
|
+
const obj = error51;
|
|
15142
|
+
if (typeof obj.message === "string")
|
|
15143
|
+
return obj.message;
|
|
15144
|
+
if (typeof obj.responseBody === "string")
|
|
15145
|
+
return obj.responseBody;
|
|
15146
|
+
try {
|
|
15147
|
+
return JSON.stringify(error51);
|
|
15148
|
+
} catch {
|
|
15149
|
+
return String(error51);
|
|
15150
|
+
}
|
|
15151
|
+
}
|
|
15152
|
+
return String(error51);
|
|
15153
|
+
}
|
|
15154
|
+
function detectOverflow(error51) {
|
|
15155
|
+
const message = extractErrorMessage(error51);
|
|
15156
|
+
if (!message) {
|
|
15157
|
+
return { isOverflow: false };
|
|
15158
|
+
}
|
|
15159
|
+
const hasStatus413 = /\b413\b/.test(message) && /(entity|payload|context|prompt)/i.test(message);
|
|
15160
|
+
let matched;
|
|
15161
|
+
for (const pattern of OVERFLOW_PATTERNS) {
|
|
15162
|
+
if (pattern.test(message)) {
|
|
15163
|
+
matched = pattern;
|
|
15164
|
+
break;
|
|
15165
|
+
}
|
|
15166
|
+
}
|
|
15167
|
+
if (!matched && !hasStatus413) {
|
|
15168
|
+
return { isOverflow: false };
|
|
15169
|
+
}
|
|
15170
|
+
const reportedLimit = parseReportedLimit(message);
|
|
15171
|
+
return {
|
|
15172
|
+
isOverflow: true,
|
|
15173
|
+
reportedLimit,
|
|
15174
|
+
matchedPattern: matched?.source
|
|
15175
|
+
};
|
|
15176
|
+
}
|
|
15177
|
+
function parseReportedLimit(message) {
|
|
15178
|
+
if (!message)
|
|
15179
|
+
return;
|
|
15180
|
+
for (const pattern of LIMIT_EXTRACTION_PATTERNS) {
|
|
15181
|
+
const match = message.match(pattern);
|
|
15182
|
+
if (!match)
|
|
15183
|
+
continue;
|
|
15184
|
+
const raw = match[1];
|
|
15185
|
+
if (!raw)
|
|
15186
|
+
continue;
|
|
15187
|
+
const value = Number.parseInt(raw, 10);
|
|
15188
|
+
if (!Number.isFinite(value))
|
|
15189
|
+
continue;
|
|
15190
|
+
if (value < MIN_PLAUSIBLE_LIMIT || value > MAX_PLAUSIBLE_LIMIT)
|
|
15191
|
+
continue;
|
|
15192
|
+
return value;
|
|
15193
|
+
}
|
|
15194
|
+
return;
|
|
15195
|
+
}
|
|
15196
|
+
var OVERFLOW_PATTERNS, LIMIT_EXTRACTION_PATTERNS, MIN_PLAUSIBLE_LIMIT = 1024, MAX_PLAUSIBLE_LIMIT = 1e7;
|
|
15197
|
+
var init_overflow_detection = __esm(() => {
|
|
15198
|
+
OVERFLOW_PATTERNS = [
|
|
15199
|
+
/prompt is too long/i,
|
|
15200
|
+
/input is too long for requested model/i,
|
|
15201
|
+
/exceeds the context window/i,
|
|
15202
|
+
/input token count.*exceeds the maximum/i,
|
|
15203
|
+
/maximum prompt length is \d+/i,
|
|
15204
|
+
/reduce the length of the messages/i,
|
|
15205
|
+
/maximum context length is \d+ tokens/i,
|
|
15206
|
+
/exceeds the limit of \d+/i,
|
|
15207
|
+
/exceeds the available context size/i,
|
|
15208
|
+
/greater than the context length/i,
|
|
15209
|
+
/context window exceeds limit/i,
|
|
15210
|
+
/exceeded model token limit/i,
|
|
15211
|
+
/context[_ ]length[_ ]exceeded/i,
|
|
15212
|
+
/request entity too large/i,
|
|
15213
|
+
/context length is only \d+ tokens/i,
|
|
15214
|
+
/input length.*exceeds.*context length/i,
|
|
15215
|
+
/prompt too long; exceeded (?:max )?context length/i,
|
|
15216
|
+
/too large for model with \d+ maximum context length/i,
|
|
15217
|
+
/model_context_window_exceeded/i,
|
|
15218
|
+
/context size has been exceeded/i
|
|
15219
|
+
];
|
|
15220
|
+
LIMIT_EXTRACTION_PATTERNS = [
|
|
15221
|
+
/maximum prompt length is (\d+)/i,
|
|
15222
|
+
/maximum context length is (\d+) tokens?/i,
|
|
15223
|
+
/context length is only (\d+) tokens?/i,
|
|
15224
|
+
/exceeds the limit of (\d+)/i,
|
|
15225
|
+
/too large for model with (\d+) maximum context length/i,
|
|
15226
|
+
/context size.*(\d+) tokens?/i,
|
|
15227
|
+
/exceeds? the context length of (\d+)/i,
|
|
15228
|
+
/max(?:imum)?.*context.*?(\d+)/i
|
|
15229
|
+
];
|
|
15230
|
+
});
|
|
15231
|
+
|
|
15232
|
+
// src/shared/resolve-fallbacks.ts
|
|
15233
|
+
function resolveFallbackChain(agentName, userFallbacks) {
|
|
15234
|
+
const userList = normalizeUserFallbacks(userFallbacks);
|
|
15235
|
+
if (userList.length > 0) {
|
|
15236
|
+
return dedupe(userList.filter(isValidModelSpec));
|
|
15237
|
+
}
|
|
15238
|
+
const builtin = getAgentFallbackModels(agentName);
|
|
15239
|
+
if (!builtin || builtin.length === 0)
|
|
15240
|
+
return [];
|
|
15241
|
+
return dedupe(builtin.filter(isValidModelSpec));
|
|
15242
|
+
}
|
|
15243
|
+
function normalizeUserFallbacks(userFallbacks) {
|
|
15244
|
+
if (!userFallbacks)
|
|
15245
|
+
return [];
|
|
15246
|
+
if (typeof userFallbacks === "string") {
|
|
15247
|
+
const trimmed = userFallbacks.trim();
|
|
15248
|
+
return trimmed ? [trimmed] : [];
|
|
15249
|
+
}
|
|
15250
|
+
return userFallbacks.map((s) => s.trim()).filter((s) => s.length > 0);
|
|
15251
|
+
}
|
|
15252
|
+
function isValidModelSpec(spec) {
|
|
15253
|
+
const slash = spec.indexOf("/");
|
|
15254
|
+
return slash > 0 && slash < spec.length - 1;
|
|
15255
|
+
}
|
|
15256
|
+
function dedupe(list) {
|
|
15257
|
+
const seen = new Set;
|
|
15258
|
+
const out = [];
|
|
15259
|
+
for (const item of list) {
|
|
15260
|
+
if (seen.has(item))
|
|
15261
|
+
continue;
|
|
15262
|
+
seen.add(item);
|
|
15263
|
+
out.push(item);
|
|
15264
|
+
}
|
|
15265
|
+
return out;
|
|
15266
|
+
}
|
|
15267
|
+
function parseProviderModel(spec) {
|
|
15268
|
+
const slash = spec.indexOf("/");
|
|
15269
|
+
if (slash < 1 || slash >= spec.length - 1)
|
|
15270
|
+
return null;
|
|
15271
|
+
return {
|
|
15272
|
+
providerID: spec.slice(0, slash).trim(),
|
|
15273
|
+
modelID: spec.slice(slash + 1).trim()
|
|
15274
|
+
};
|
|
15275
|
+
}
|
|
15276
|
+
var init_resolve_fallbacks = __esm(() => {
|
|
15277
|
+
init_model_requirements();
|
|
15278
|
+
});
|
|
15279
|
+
|
|
15125
15280
|
// src/shared/model-suggestion-retry.ts
|
|
15126
15281
|
function extractMessage(error51) {
|
|
15127
15282
|
if (typeof error51 === "string")
|
|
@@ -15177,6 +15332,9 @@ function parseModelSuggestion(error51) {
|
|
|
15177
15332
|
};
|
|
15178
15333
|
}
|
|
15179
15334
|
async function promptWithTimeout(client, args, timeoutMs, signal) {
|
|
15335
|
+
if (signal?.aborted) {
|
|
15336
|
+
throw new Error("prompt aborted by external signal");
|
|
15337
|
+
}
|
|
15180
15338
|
const controller = new AbortController;
|
|
15181
15339
|
const timeout = setTimeout(() => controller.abort(), timeoutMs);
|
|
15182
15340
|
const onExternalAbort = () => controller.abort();
|
|
@@ -15199,16 +15357,39 @@ async function promptWithTimeout(client, args, timeoutMs, signal) {
|
|
|
15199
15357
|
signal?.removeEventListener("abort", onExternalAbort);
|
|
15200
15358
|
}
|
|
15201
15359
|
}
|
|
15202
|
-
|
|
15203
|
-
|
|
15360
|
+
function isNonRetryable(error51, externalSignal) {
|
|
15361
|
+
if (externalSignal?.aborted)
|
|
15362
|
+
return true;
|
|
15363
|
+
if (error51 instanceof Error) {
|
|
15364
|
+
if (error51.name === "AbortError")
|
|
15365
|
+
return true;
|
|
15366
|
+
if (error51.message === "prompt aborted by external signal")
|
|
15367
|
+
return true;
|
|
15368
|
+
if (/^prompt timed out after \d+ms$/.test(error51.message))
|
|
15369
|
+
return true;
|
|
15370
|
+
}
|
|
15371
|
+
if (detectOverflow(error51).isOverflow)
|
|
15372
|
+
return true;
|
|
15373
|
+
return false;
|
|
15374
|
+
}
|
|
15375
|
+
function shortErr(error51) {
|
|
15376
|
+
if (error51 instanceof Error) {
|
|
15377
|
+
return error51.name && error51.name !== "Error" ? `${error51.name}: ${error51.message}` : error51.message;
|
|
15378
|
+
}
|
|
15379
|
+
return extractMessage(error51);
|
|
15380
|
+
}
|
|
15381
|
+
async function attemptOnce(client, args, timeoutMs, signal, callContext, label) {
|
|
15204
15382
|
try {
|
|
15205
|
-
await promptWithTimeout(client, args, timeoutMs,
|
|
15383
|
+
await promptWithTimeout(client, args, timeoutMs, signal);
|
|
15384
|
+
return;
|
|
15206
15385
|
} catch (error51) {
|
|
15386
|
+
if (isNonRetryable(error51, signal))
|
|
15387
|
+
throw error51;
|
|
15207
15388
|
const suggestion = parseModelSuggestion(error51);
|
|
15208
15389
|
if (!suggestion || !args.body.model) {
|
|
15209
15390
|
throw error51;
|
|
15210
15391
|
}
|
|
15211
|
-
log(
|
|
15392
|
+
log(`[${callContext}] ${label}: model not found, retrying with suggestion`, {
|
|
15212
15393
|
original: `${suggestion.providerID}/${suggestion.modelID}`,
|
|
15213
15394
|
suggested: suggestion.suggestion
|
|
15214
15395
|
});
|
|
@@ -15221,11 +15402,59 @@ async function promptSyncWithModelSuggestionRetry(client, args, options = {}) {
|
|
|
15221
15402
|
modelID: suggestion.suggestion
|
|
15222
15403
|
}
|
|
15223
15404
|
}
|
|
15224
|
-
}, timeoutMs,
|
|
15405
|
+
}, timeoutMs, signal);
|
|
15225
15406
|
}
|
|
15226
15407
|
}
|
|
15408
|
+
async function promptSyncWithModelSuggestionRetry(client, args, options = {}) {
|
|
15409
|
+
const timeoutMs = options.timeoutMs ?? 300000;
|
|
15410
|
+
const callContext = options.callContext ?? "subagent";
|
|
15411
|
+
const fallbacks = options.fallbackModels ?? [];
|
|
15412
|
+
const explicitPrimaryLabel = args.body.model?.providerID && args.body.model.modelID ? `${args.body.model.providerID}/${args.body.model.modelID}` : "primary";
|
|
15413
|
+
let lastError = null;
|
|
15414
|
+
try {
|
|
15415
|
+
await attemptOnce(client, args, timeoutMs, options.signal, callContext, explicitPrimaryLabel);
|
|
15416
|
+
return;
|
|
15417
|
+
} catch (error51) {
|
|
15418
|
+
lastError = error51;
|
|
15419
|
+
if (isNonRetryable(error51, options.signal))
|
|
15420
|
+
throw error51;
|
|
15421
|
+
if (fallbacks.length === 0) {
|
|
15422
|
+
throw error51;
|
|
15423
|
+
}
|
|
15424
|
+
log(`[${callContext}] primary (${explicitPrimaryLabel}) failed: ${shortErr(error51)}; trying ${fallbacks.length} fallback(s)`);
|
|
15425
|
+
}
|
|
15426
|
+
for (let i = 0;i < fallbacks.length; i += 1) {
|
|
15427
|
+
const parsed = parseProviderModel(fallbacks[i]);
|
|
15428
|
+
if (!parsed) {
|
|
15429
|
+
log(`[${callContext}] skipping invalid fallback spec: ${fallbacks[i]}`);
|
|
15430
|
+
continue;
|
|
15431
|
+
}
|
|
15432
|
+
const label = `${parsed.providerID}/${parsed.modelID}`;
|
|
15433
|
+
const attemptArgs = {
|
|
15434
|
+
...args,
|
|
15435
|
+
body: { ...args.body, model: parsed }
|
|
15436
|
+
};
|
|
15437
|
+
try {
|
|
15438
|
+
await attemptOnce(client, attemptArgs, timeoutMs, options.signal, callContext, label);
|
|
15439
|
+
log(`[${callContext}] fallback succeeded with ${label} (attempt ${i + 2}/${fallbacks.length + 1})`);
|
|
15440
|
+
return;
|
|
15441
|
+
} catch (error51) {
|
|
15442
|
+
lastError = error51;
|
|
15443
|
+
if (isNonRetryable(error51, options.signal))
|
|
15444
|
+
throw error51;
|
|
15445
|
+
const remaining = fallbacks.length - i - 1;
|
|
15446
|
+
if (remaining > 0) {
|
|
15447
|
+
log(`[${callContext}] ${label} failed: ${shortErr(error51)}; ${remaining} fallback(s) left`);
|
|
15448
|
+
}
|
|
15449
|
+
}
|
|
15450
|
+
}
|
|
15451
|
+
log(`[${callContext}] all models exhausted; tried: ${[explicitPrimaryLabel, ...fallbacks].join(", ")}; last error: ${shortErr(lastError)}`);
|
|
15452
|
+
throw lastError ?? new Error("All fallback models failed");
|
|
15453
|
+
}
|
|
15227
15454
|
var init_model_suggestion_retry = __esm(() => {
|
|
15455
|
+
init_overflow_detection();
|
|
15228
15456
|
init_logger();
|
|
15457
|
+
init_resolve_fallbacks();
|
|
15229
15458
|
});
|
|
15230
15459
|
|
|
15231
15460
|
// src/shared/normalize-sdk-response.ts
|
|
@@ -15257,6 +15486,7 @@ var init_shared = __esm(() => {
|
|
|
15257
15486
|
init_logger();
|
|
15258
15487
|
init_model_requirements();
|
|
15259
15488
|
init_model_suggestion_retry();
|
|
15489
|
+
init_resolve_fallbacks();
|
|
15260
15490
|
});
|
|
15261
15491
|
|
|
15262
15492
|
// src/shared/record-type-guard.ts
|
|
@@ -160034,6 +160264,25 @@ var init_migrations = __esm(async () => {
|
|
|
160034
160264
|
WHERE type = 'tool' AND tool_owner_message_id IS NULL;
|
|
160035
160265
|
`);
|
|
160036
160266
|
}
|
|
160267
|
+
},
|
|
160268
|
+
{
|
|
160269
|
+
version: 11,
|
|
160270
|
+
description: "Add todo state synthesis columns to session_meta",
|
|
160271
|
+
up: (db) => {
|
|
160272
|
+
const cols = db.prepare("PRAGMA table_info(session_meta)").all();
|
|
160273
|
+
if (!cols.some((c) => c.name === "last_todo_state")) {
|
|
160274
|
+
db.exec("ALTER TABLE session_meta ADD COLUMN last_todo_state TEXT DEFAULT ''");
|
|
160275
|
+
}
|
|
160276
|
+
if (!cols.some((c) => c.name === "todo_synthetic_call_id")) {
|
|
160277
|
+
db.exec("ALTER TABLE session_meta ADD COLUMN todo_synthetic_call_id TEXT DEFAULT ''");
|
|
160278
|
+
}
|
|
160279
|
+
if (!cols.some((c) => c.name === "todo_synthetic_anchor_message_id")) {
|
|
160280
|
+
db.exec("ALTER TABLE session_meta ADD COLUMN todo_synthetic_anchor_message_id TEXT DEFAULT ''");
|
|
160281
|
+
}
|
|
160282
|
+
if (!cols.some((c) => c.name === "todo_synthetic_state_json")) {
|
|
160283
|
+
db.exec("ALTER TABLE session_meta ADD COLUMN todo_synthetic_state_json TEXT DEFAULT ''");
|
|
160284
|
+
}
|
|
160285
|
+
}
|
|
160037
160286
|
}
|
|
160038
160287
|
];
|
|
160039
160288
|
});
|
|
@@ -160516,6 +160765,10 @@ CREATE INDEX IF NOT EXISTS idx_dream_queue_pending ON dream_queue(started_at, en
|
|
|
160516
160765
|
note_nudge_trigger_message_id TEXT DEFAULT '',
|
|
160517
160766
|
note_nudge_sticky_text TEXT DEFAULT '',
|
|
160518
160767
|
note_nudge_sticky_message_id TEXT DEFAULT '',
|
|
160768
|
+
last_todo_state TEXT DEFAULT '',
|
|
160769
|
+
todo_synthetic_call_id TEXT DEFAULT '',
|
|
160770
|
+
todo_synthetic_anchor_message_id TEXT DEFAULT '',
|
|
160771
|
+
todo_synthetic_state_json TEXT DEFAULT '',
|
|
160519
160772
|
is_subagent INTEGER DEFAULT 0,
|
|
160520
160773
|
last_context_percentage REAL DEFAULT 0,
|
|
160521
160774
|
last_input_tokens INTEGER DEFAULT 0,
|
|
@@ -160580,6 +160833,10 @@ CREATE INDEX IF NOT EXISTS idx_dream_queue_pending ON dream_queue(started_at, en
|
|
|
160580
160833
|
ensureColumn(db, "session_meta", "note_nudge_trigger_message_id", "TEXT DEFAULT ''");
|
|
160581
160834
|
ensureColumn(db, "session_meta", "note_nudge_sticky_text", "TEXT DEFAULT ''");
|
|
160582
160835
|
ensureColumn(db, "session_meta", "note_nudge_sticky_message_id", "TEXT DEFAULT ''");
|
|
160836
|
+
ensureColumn(db, "session_meta", "last_todo_state", "TEXT DEFAULT ''");
|
|
160837
|
+
ensureColumn(db, "session_meta", "todo_synthetic_call_id", "TEXT DEFAULT ''");
|
|
160838
|
+
ensureColumn(db, "session_meta", "todo_synthetic_anchor_message_id", "TEXT DEFAULT ''");
|
|
160839
|
+
ensureColumn(db, "session_meta", "todo_synthetic_state_json", "TEXT DEFAULT ''");
|
|
160583
160840
|
ensureColumn(db, "session_meta", "note_last_read_at", "INTEGER DEFAULT 0");
|
|
160584
160841
|
ensureColumn(db, "session_meta", "times_execute_threshold_reached", "INTEGER DEFAULT 0");
|
|
160585
160842
|
ensureColumn(db, "session_meta", "compartment_in_progress", "INTEGER DEFAULT 0");
|
|
@@ -160644,6 +160901,10 @@ function healNullTextColumns(db) {
|
|
|
160644
160901
|
["note_nudge_trigger_message_id", ""],
|
|
160645
160902
|
["note_nudge_sticky_text", ""],
|
|
160646
160903
|
["note_nudge_sticky_message_id", ""],
|
|
160904
|
+
["last_todo_state", ""],
|
|
160905
|
+
["todo_synthetic_call_id", ""],
|
|
160906
|
+
["todo_synthetic_anchor_message_id", ""],
|
|
160907
|
+
["todo_synthetic_state_json", ""],
|
|
160647
160908
|
["system_prompt_hash", ""],
|
|
160648
160909
|
["stripped_placeholder_ids", ""],
|
|
160649
160910
|
["memory_block_cache", ""],
|
|
@@ -160749,7 +161010,7 @@ function isSessionMetaRow(row) {
|
|
|
160749
161010
|
if (row === null || typeof row !== "object")
|
|
160750
161011
|
return false;
|
|
160751
161012
|
const r = row;
|
|
160752
|
-
return typeof r.session_id === "string" && typeof r.last_response_time === "number" && isStringOrNull(r.cache_ttl) && typeof r.counter === "number" && typeof r.last_nudge_tokens === "number" && isStringOrNull(r.last_nudge_band) && isStringOrNull(r.last_transform_error) && typeof r.is_subagent === "number" && typeof r.last_context_percentage === "number" && typeof r.last_input_tokens === "number" && isNumberOrNull(r.times_execute_threshold_reached) && isNumberOrNull(r.compartment_in_progress) && (r.system_prompt_hash === null || typeof r.system_prompt_hash === "string" || typeof r.system_prompt_hash === "number") && isNumberOrNull(r.system_prompt_tokens) && isNumberOrNull(r.conversation_tokens) && isNumberOrNull(r.tool_call_tokens) && isNumberOrNull(r.cleared_reasoning_through_tag);
|
|
161013
|
+
return typeof r.session_id === "string" && typeof r.last_response_time === "number" && isStringOrNull(r.cache_ttl) && typeof r.counter === "number" && typeof r.last_nudge_tokens === "number" && isStringOrNull(r.last_nudge_band) && isStringOrNull(r.last_transform_error) && typeof r.is_subagent === "number" && typeof r.last_context_percentage === "number" && typeof r.last_input_tokens === "number" && isNumberOrNull(r.times_execute_threshold_reached) && isNumberOrNull(r.compartment_in_progress) && (r.system_prompt_hash === null || typeof r.system_prompt_hash === "string" || typeof r.system_prompt_hash === "number") && isNumberOrNull(r.system_prompt_tokens) && isNumberOrNull(r.conversation_tokens) && isNumberOrNull(r.tool_call_tokens) && isNumberOrNull(r.cleared_reasoning_through_tag) && isStringOrNull(r.last_todo_state);
|
|
160753
161014
|
}
|
|
160754
161015
|
function getDefaultSessionMeta(sessionId) {
|
|
160755
161016
|
return {
|
|
@@ -160769,7 +161030,8 @@ function getDefaultSessionMeta(sessionId) {
|
|
|
160769
161030
|
systemPromptTokens: 0,
|
|
160770
161031
|
conversationTokens: 0,
|
|
160771
161032
|
toolCallTokens: 0,
|
|
160772
|
-
clearedReasoningThroughTag: 0
|
|
161033
|
+
clearedReasoningThroughTag: 0,
|
|
161034
|
+
lastTodoState: ""
|
|
160773
161035
|
};
|
|
160774
161036
|
}
|
|
160775
161037
|
function ensureSessionMetaRow(db, sessionId) {
|
|
@@ -160781,6 +161043,7 @@ function toSessionMeta(row) {
|
|
|
160781
161043
|
const transformErrorRaw = typeof row.last_transform_error === "string" ? row.last_transform_error : "";
|
|
160782
161044
|
const cacheTtlRaw = typeof row.cache_ttl === "string" && row.cache_ttl.length > 0 ? row.cache_ttl : "5m";
|
|
160783
161045
|
const systemPromptHashRaw = row.system_prompt_hash == null ? "" : row.system_prompt_hash;
|
|
161046
|
+
const lastTodoStateRaw = typeof row.last_todo_state === "string" ? row.last_todo_state : "";
|
|
160784
161047
|
const numOrZero = (value) => typeof value === "number" ? value : 0;
|
|
160785
161048
|
return {
|
|
160786
161049
|
sessionId: row.session_id,
|
|
@@ -160799,7 +161062,8 @@ function toSessionMeta(row) {
|
|
|
160799
161062
|
systemPromptTokens: numOrZero(row.system_prompt_tokens),
|
|
160800
161063
|
conversationTokens: numOrZero(row.conversation_tokens),
|
|
160801
161064
|
toolCallTokens: numOrZero(row.tool_call_tokens),
|
|
160802
|
-
clearedReasoningThroughTag: numOrZero(row.cleared_reasoning_through_tag)
|
|
161065
|
+
clearedReasoningThroughTag: numOrZero(row.cleared_reasoning_through_tag),
|
|
161066
|
+
lastTodoState: lastTodoStateRaw
|
|
160803
161067
|
};
|
|
160804
161068
|
}
|
|
160805
161069
|
var META_COLUMNS, BOOLEAN_META_KEYS;
|
|
@@ -160820,7 +161084,8 @@ var init_storage_meta_shared = __esm(() => {
|
|
|
160820
161084
|
systemPromptTokens: "system_prompt_tokens",
|
|
160821
161085
|
conversationTokens: "conversation_tokens",
|
|
160822
161086
|
toolCallTokens: "tool_call_tokens",
|
|
160823
|
-
clearedReasoningThroughTag: "cleared_reasoning_through_tag"
|
|
161087
|
+
clearedReasoningThroughTag: "cleared_reasoning_through_tag",
|
|
161088
|
+
lastTodoState: "last_todo_state"
|
|
160824
161089
|
};
|
|
160825
161090
|
BOOLEAN_META_KEYS = new Set(["isSubagent", "compartmentInProgress"]);
|
|
160826
161091
|
});
|
|
@@ -160856,6 +161121,12 @@ function isPersistedNoteNudgeRow(row) {
|
|
|
160856
161121
|
const r = row;
|
|
160857
161122
|
return typeof r.note_nudge_trigger_pending === "number" && typeof r.note_nudge_trigger_message_id === "string" && typeof r.note_nudge_sticky_text === "string" && typeof r.note_nudge_sticky_message_id === "string";
|
|
160858
161123
|
}
|
|
161124
|
+
function isPersistedTodoSyntheticAnchorRow(row) {
|
|
161125
|
+
if (row === null || typeof row !== "object")
|
|
161126
|
+
return false;
|
|
161127
|
+
const r = row;
|
|
161128
|
+
return typeof r.todo_synthetic_call_id === "string" && typeof r.todo_synthetic_anchor_message_id === "string" && typeof r.todo_synthetic_state_json === "string";
|
|
161129
|
+
}
|
|
160859
161130
|
function isPersistedHistorianFailureRow(row) {
|
|
160860
161131
|
if (row === null || typeof row !== "object")
|
|
160861
161132
|
return false;
|
|
@@ -160978,6 +161249,29 @@ function setPersistedDeliveredNoteNudge(db, sessionId, text, messageId = "") {
|
|
|
160978
161249
|
function clearPersistedNoteNudge(db, sessionId) {
|
|
160979
161250
|
db.prepare("UPDATE session_meta SET note_nudge_trigger_pending = 0, note_nudge_trigger_message_id = '', note_nudge_sticky_text = '', note_nudge_sticky_message_id = '' WHERE session_id = ?").run(sessionId);
|
|
160980
161251
|
}
|
|
161252
|
+
function getPersistedTodoSyntheticAnchor(db, sessionId) {
|
|
161253
|
+
const result = db.prepare("SELECT todo_synthetic_call_id, todo_synthetic_anchor_message_id, todo_synthetic_state_json FROM session_meta WHERE session_id = ?").get(sessionId);
|
|
161254
|
+
if (!isPersistedTodoSyntheticAnchorRow(result)) {
|
|
161255
|
+
return null;
|
|
161256
|
+
}
|
|
161257
|
+
if (result.todo_synthetic_call_id.length === 0 || result.todo_synthetic_anchor_message_id.length === 0) {
|
|
161258
|
+
return null;
|
|
161259
|
+
}
|
|
161260
|
+
return {
|
|
161261
|
+
callId: result.todo_synthetic_call_id,
|
|
161262
|
+
messageId: result.todo_synthetic_anchor_message_id,
|
|
161263
|
+
stateJson: result.todo_synthetic_state_json
|
|
161264
|
+
};
|
|
161265
|
+
}
|
|
161266
|
+
function setPersistedTodoSyntheticAnchor(db, sessionId, callId, messageId, stateJson) {
|
|
161267
|
+
db.transaction(() => {
|
|
161268
|
+
ensureSessionMetaRow(db, sessionId);
|
|
161269
|
+
db.prepare("UPDATE session_meta SET todo_synthetic_call_id = ?, todo_synthetic_anchor_message_id = ?, todo_synthetic_state_json = ? WHERE session_id = ?").run(callId, messageId, stateJson, sessionId);
|
|
161270
|
+
})();
|
|
161271
|
+
}
|
|
161272
|
+
function clearPersistedTodoSyntheticAnchor(db, sessionId) {
|
|
161273
|
+
db.prepare("UPDATE session_meta SET todo_synthetic_call_id = '', todo_synthetic_anchor_message_id = '', todo_synthetic_state_json = '' WHERE session_id = ?").run(sessionId);
|
|
161274
|
+
}
|
|
160981
161275
|
function getNoteLastReadAt(db, sessionId) {
|
|
160982
161276
|
try {
|
|
160983
161277
|
const result = db.prepare("SELECT note_last_read_at FROM session_meta WHERE session_id = ?").get(sessionId);
|
|
@@ -161130,7 +161424,7 @@ var init_resolve_subagent_fallback = __esm(async () => {
|
|
|
161130
161424
|
|
|
161131
161425
|
// src/features/magic-context/storage-meta-session.ts
|
|
161132
161426
|
function getOrCreateSessionMeta(db, sessionId) {
|
|
161133
|
-
const result = db.prepare("SELECT session_id, last_response_time, cache_ttl, counter, last_nudge_tokens, last_nudge_band, last_transform_error, is_subagent, last_context_percentage, last_input_tokens, times_execute_threshold_reached, compartment_in_progress, system_prompt_hash, system_prompt_tokens, conversation_tokens, tool_call_tokens, cleared_reasoning_through_tag FROM session_meta WHERE session_id = ?").get(sessionId);
|
|
161427
|
+
const result = db.prepare("SELECT session_id, last_response_time, cache_ttl, counter, last_nudge_tokens, last_nudge_band, last_transform_error, is_subagent, last_context_percentage, last_input_tokens, times_execute_threshold_reached, compartment_in_progress, system_prompt_hash, system_prompt_tokens, conversation_tokens, tool_call_tokens, cleared_reasoning_through_tag, last_todo_state FROM session_meta WHERE session_id = ?").get(sessionId);
|
|
161134
161428
|
if (isSessionMetaRow(result)) {
|
|
161135
161429
|
return toSessionMeta(result);
|
|
161136
161430
|
}
|
|
@@ -161704,9 +161998,7 @@ function loadModelsDevMetadataFromFile() {
|
|
|
161704
161998
|
try {
|
|
161705
161999
|
const configPath = getOpencodeConfigPath();
|
|
161706
162000
|
if (configPath && existsSync12(configPath)) {
|
|
161707
|
-
|
|
161708
|
-
raw = raw.replace(/"(?:[^"\\]|\\.)*"|\/\/.*$/gm, (match) => match.startsWith('"') ? match : "");
|
|
161709
|
-
const config2 = JSON.parse(raw);
|
|
162001
|
+
const config2 = parseJsonc(readFileSync8(configPath, "utf-8"));
|
|
161710
162002
|
if (config2.provider && typeof config2.provider === "object") {
|
|
161711
162003
|
for (const [providerId, provider2] of Object.entries(config2.provider)) {
|
|
161712
162004
|
if (!provider2?.models || typeof provider2.models !== "object")
|
|
@@ -161778,6 +162070,7 @@ function getModelsDevContextLimit(providerID, modelID) {
|
|
|
161778
162070
|
var RELOAD_INTERVAL_MS, apiCache = null, apiLoadedAt = 0, recentlySeenApiSizes, oscillationLogged = false, fileCache = null, fileLastAttempt = 0;
|
|
161779
162071
|
var init_models_dev_cache = __esm(() => {
|
|
161780
162072
|
init_data_path();
|
|
162073
|
+
init_jsonc_parser();
|
|
161781
162074
|
init_logger();
|
|
161782
162075
|
RELOAD_INTERVAL_MS = 5 * 60 * 1000;
|
|
161783
162076
|
recentlySeenApiSizes = new Set;
|
|
@@ -162125,7 +162418,8 @@ async function runHistorianPrompt(args) {
|
|
|
162125
162418
|
timeoutMs,
|
|
162126
162419
|
dumpLabel,
|
|
162127
162420
|
modelOverride,
|
|
162128
|
-
agentId = HISTORIAN_AGENT
|
|
162421
|
+
agentId = HISTORIAN_AGENT,
|
|
162422
|
+
fallbackModels
|
|
162129
162423
|
} = args;
|
|
162130
162424
|
let agentSessionId = null;
|
|
162131
162425
|
try {
|
|
@@ -162152,7 +162446,11 @@ async function runHistorianPrompt(args) {
|
|
|
162152
162446
|
...modelOverride ? { model: modelOverride } : {},
|
|
162153
162447
|
parts: [{ type: "text", text: prompt, synthetic: true }]
|
|
162154
162448
|
}
|
|
162155
|
-
}, {
|
|
162449
|
+
}, {
|
|
162450
|
+
timeoutMs: timeoutMs ?? DEFAULT_HISTORIAN_TIMEOUT_MS,
|
|
162451
|
+
fallbackModels: modelOverride ? undefined : fallbackModels,
|
|
162452
|
+
callContext: agentId === HISTORIAN_EDITOR_AGENT ? "historian:editor" : "historian"
|
|
162453
|
+
});
|
|
162156
162454
|
sessionLog(parentSessionId, `historian: prompt completed (attempt ${retryIndex + 1}/${MAX_HISTORIAN_RETRIES + 1})`);
|
|
162157
162455
|
break;
|
|
162158
162456
|
} catch (error51) {
|
|
@@ -163117,6 +163415,7 @@ Historian pass ${passCount + 1}, attempt ${passAttempt} started for messages ${c
|
|
|
163117
163415
|
dumpLabelBase: `partial-recomp-${sessionId}-${chunk.startIndex}-${chunk.endIndex}-pass-${passCount + 1}`,
|
|
163118
163416
|
timeoutMs: historianTimeoutMs,
|
|
163119
163417
|
fallbackModelId: deps.fallbackModelId,
|
|
163418
|
+
fallbackModels: deps.fallbackModels,
|
|
163120
163419
|
twoPass: deps.historianTwoPass,
|
|
163121
163420
|
callbacks: {
|
|
163122
163421
|
onRepairRetry: async (error51) => {
|
|
@@ -164318,7 +164617,8 @@ async function runCompressorPass(args) {
|
|
|
164318
164617
|
targetTokens,
|
|
164319
164618
|
outputCount,
|
|
164320
164619
|
outputDepth,
|
|
164321
|
-
historianTimeoutMs
|
|
164620
|
+
historianTimeoutMs,
|
|
164621
|
+
fallbackModels
|
|
164322
164622
|
} = args;
|
|
164323
164623
|
const prompt = buildCompressorPrompt(compartments, currentTokens, targetTokens, outputDepth, outputCount);
|
|
164324
164624
|
let agentSessionId = null;
|
|
@@ -164340,7 +164640,11 @@ async function runCompressorPass(args) {
|
|
|
164340
164640
|
agent: HISTORIAN_AGENT2,
|
|
164341
164641
|
parts: [{ type: "text", text: prompt, synthetic: true }]
|
|
164342
164642
|
}
|
|
164343
|
-
}, {
|
|
164643
|
+
}, {
|
|
164644
|
+
timeoutMs: historianTimeoutMs ?? DEFAULT_HISTORIAN_TIMEOUT_MS,
|
|
164645
|
+
fallbackModels,
|
|
164646
|
+
callContext: "compressor"
|
|
164647
|
+
});
|
|
164344
164648
|
const messagesResponse = await client.session.messages({
|
|
164345
164649
|
path: { id: agentSessionId },
|
|
164346
164650
|
query: { directory }
|
|
@@ -164520,6 +164824,7 @@ ${chunk.text}`, { stateFilePath });
|
|
|
164520
164824
|
dumpLabelBase: `incremental-${sessionId}-${chunk.startIndex}-${chunk.endIndex}`,
|
|
164521
164825
|
timeoutMs: historianTimeoutMs,
|
|
164522
164826
|
fallbackModelId: deps.fallbackModelId,
|
|
164827
|
+
fallbackModels: deps.fallbackModels,
|
|
164523
164828
|
twoPass: deps.historianTwoPass
|
|
164524
164829
|
});
|
|
164525
164830
|
if (!validatedPass.ok) {
|
|
@@ -164568,6 +164873,7 @@ No new compartments or facts were written. Check the historian model/output and
|
|
|
164568
164873
|
directory: sessionDirectory,
|
|
164569
164874
|
historyBudgetTokens: deps.historyBudgetTokens,
|
|
164570
164875
|
historianTimeoutMs,
|
|
164876
|
+
fallbackModels: deps.fallbackModels,
|
|
164571
164877
|
minCompartmentRatio: deps.compressorMinCompartmentRatio,
|
|
164572
164878
|
maxMergeDepth: deps.compressorMaxMergeDepth
|
|
164573
164879
|
});
|
|
@@ -164756,6 +165062,7 @@ Historian pass ${passCount + 1}, attempt ${passAttempt} started for messages ${c
|
|
|
164756
165062
|
dumpLabelBase: `recomp-${sessionId}-${chunk.startIndex}-${chunk.endIndex}-pass-${passCount + 1}`,
|
|
164757
165063
|
timeoutMs: historianTimeoutMs,
|
|
164758
165064
|
fallbackModelId: deps.fallbackModelId,
|
|
165065
|
+
fallbackModels: deps.fallbackModels,
|
|
164759
165066
|
twoPass: deps.historianTwoPass,
|
|
164760
165067
|
callbacks: {
|
|
164761
165068
|
onRepairRetry: async (error51) => {
|
|
@@ -164853,6 +165160,7 @@ Nothing was written.`;
|
|
|
164853
165160
|
directory: sessionDirectory,
|
|
164854
165161
|
historyBudgetTokens: deps.historyBudgetTokens,
|
|
164855
165162
|
historianTimeoutMs,
|
|
165163
|
+
fallbackModels: deps.fallbackModels,
|
|
164856
165164
|
minCompartmentRatio: deps.compressorMinCompartmentRatio,
|
|
164857
165165
|
maxMergeDepth: deps.compressorMaxMergeDepth
|
|
164858
165166
|
});
|
|
@@ -165722,6 +166030,7 @@ function buildDreamTaskPrompt(task, args) {
|
|
|
165722
166030
|
init_shared();
|
|
165723
166031
|
init_assistant_message_extractor();
|
|
165724
166032
|
init_logger();
|
|
166033
|
+
init_resolve_fallbacks();
|
|
165725
166034
|
|
|
165726
166035
|
// src/features/magic-context/sidekick/core.ts
|
|
165727
166036
|
var SIDEKICK_SYSTEM_PROMPT = `You are Sidekick, a focused memory-retrieval subagent for an AI coding assistant.
|
|
@@ -165741,6 +166050,7 @@ function stripThinkingBlocks(text) {
|
|
|
165741
166050
|
|
|
165742
166051
|
// src/features/magic-context/sidekick/agent.ts
|
|
165743
166052
|
async function runSidekick(deps) {
|
|
166053
|
+
const fallbackModels = resolveFallbackChain(SIDEKICK_AGENT, deps.config.fallback_models);
|
|
165744
166054
|
let agentSessionId = null;
|
|
165745
166055
|
try {
|
|
165746
166056
|
const createResponse = await deps.client.session.create({
|
|
@@ -165763,7 +166073,7 @@ async function runSidekick(deps) {
|
|
|
165763
166073
|
system: deps.config.system_prompt?.trim() || deps.config.prompt?.trim() || SIDEKICK_SYSTEM_PROMPT,
|
|
165764
166074
|
parts: [{ type: "text", text: deps.userMessage, synthetic: true }]
|
|
165765
166075
|
}
|
|
165766
|
-
}, { timeoutMs: deps.config.timeout_ms });
|
|
166076
|
+
}, { timeoutMs: deps.config.timeout_ms, fallbackModels, callContext: "sidekick" });
|
|
165767
166077
|
const messagesResponse = await deps.client.session.messages({
|
|
165768
166078
|
path: { id: agentSessionId },
|
|
165769
166079
|
query: { directory: deps.sessionDirectory ?? deps.projectPath }
|
|
@@ -166387,7 +166697,6 @@ function createLiveSessionState() {
|
|
|
166387
166697
|
|
|
166388
166698
|
// src/index.ts
|
|
166389
166699
|
init_conflict_warning_hook();
|
|
166390
|
-
|
|
166391
166700
|
// src/features/magic-context/dreamer/storage-dream-state.ts
|
|
166392
166701
|
var getDreamStateStatements = new WeakMap;
|
|
166393
166702
|
var setDreamStateStatements = new WeakMap;
|
|
@@ -166833,7 +167142,12 @@ If no promotions are warranted, return empty arrays. Always consume reviewed can
|
|
|
166833
167142
|
system: DREAMER_SYSTEM_PROMPT,
|
|
166834
167143
|
parts: [{ type: "text", text: prompt, synthetic: true }]
|
|
166835
167144
|
}
|
|
166836
|
-
}, {
|
|
167145
|
+
}, {
|
|
167146
|
+
timeoutMs: Math.min(remainingMs, 5 * 60 * 1000),
|
|
167147
|
+
signal: abortController.signal,
|
|
167148
|
+
fallbackModels: args.fallbackModels,
|
|
167149
|
+
callContext: "dreamer:user-memories"
|
|
167150
|
+
});
|
|
166837
167151
|
const messagesResponse = await args.client.session.messages({
|
|
166838
167152
|
path: { id: agentSessionId },
|
|
166839
167153
|
query: { directory: args.sessionDirectory }
|
|
@@ -166892,7 +167206,8 @@ If no promotions are warranted, return empty arrays. Always consume reviewed can
|
|
|
166892
167206
|
}
|
|
166893
167207
|
return result;
|
|
166894
167208
|
} catch (error51) {
|
|
166895
|
-
|
|
167209
|
+
const errorDescription = describeError(error51);
|
|
167210
|
+
log(`[dreamer] user-memories: review failed: ${errorDescription.brief}`, errorDescription.stackHead ? { stackHead: errorDescription.stackHead } : undefined);
|
|
166896
167211
|
return result;
|
|
166897
167212
|
} finally {
|
|
166898
167213
|
clearInterval(leaseInterval);
|
|
@@ -166923,6 +167238,7 @@ function insertDreamRun(db, run) {
|
|
|
166923
167238
|
|
|
166924
167239
|
// src/features/magic-context/dreamer/runner.ts
|
|
166925
167240
|
var dreamProjectDirectories = new Map;
|
|
167241
|
+
var CIRCUIT_BREAKER_THRESHOLD = 3;
|
|
166926
167242
|
function registerDreamProjectDirectory(projectIdentity, directory) {
|
|
166927
167243
|
dreamProjectDirectories.set(projectIdentity, directory);
|
|
166928
167244
|
}
|
|
@@ -166939,6 +167255,25 @@ function countNewIds(beforeIds, afterIds) {
|
|
|
166939
167255
|
}
|
|
166940
167256
|
return count;
|
|
166941
167257
|
}
|
|
167258
|
+
function getCircuitBreakerSignature(error51, brief) {
|
|
167259
|
+
if (error51 instanceof Error && error51.name && error51.name !== "Error") {
|
|
167260
|
+
return error51.name;
|
|
167261
|
+
}
|
|
167262
|
+
const namedError = error51;
|
|
167263
|
+
if (namedError && typeof namedError === "object" && typeof namedError.name === "string" && namedError.name.length > 0 && namedError.name !== "Error") {
|
|
167264
|
+
return namedError.name;
|
|
167265
|
+
}
|
|
167266
|
+
return brief.split(":")[0]?.trim().split(/\s+/)[0] || brief || "unknown";
|
|
167267
|
+
}
|
|
167268
|
+
function shouldSkipCircuitBreaker(error51, brief) {
|
|
167269
|
+
const namedError = error51;
|
|
167270
|
+
const name2 = error51 instanceof Error ? error51.name : namedError && typeof namedError === "object" && typeof namedError.name === "string" ? namedError.name : "";
|
|
167271
|
+
const combined = `${name2} ${brief}`.toLowerCase();
|
|
167272
|
+
return name2 === "AbortError" || combined.includes("lease");
|
|
167273
|
+
}
|
|
167274
|
+
function logWithStackHead(message, stackHead) {
|
|
167275
|
+
log(message, stackHead ? { stackHead } : undefined);
|
|
167276
|
+
}
|
|
166942
167277
|
function getOpenCodeDbPath2() {
|
|
166943
167278
|
return join13(getDataDir(), "opencode", "opencode.db");
|
|
166944
167279
|
}
|
|
@@ -167044,7 +167379,12 @@ async function identifyKeyFilesForSession(args) {
|
|
|
167044
167379
|
system: KEY_FILES_SYSTEM_PROMPT,
|
|
167045
167380
|
parts: [{ type: "text", text: prompt, synthetic: true }]
|
|
167046
167381
|
}
|
|
167047
|
-
}, {
|
|
167382
|
+
}, {
|
|
167383
|
+
timeoutMs: Math.min(remainingMs, 300000),
|
|
167384
|
+
signal: abortController.signal,
|
|
167385
|
+
fallbackModels: args.fallbackModels,
|
|
167386
|
+
callContext: `dreamer:key-files:${args.sessionId.slice(0, 12)}`
|
|
167387
|
+
});
|
|
167048
167388
|
const messagesResponse = await args.client.session.messages({
|
|
167049
167389
|
path: { id: agentSessionId },
|
|
167050
167390
|
query: { directory: args.sessionDirectory }
|
|
@@ -167117,6 +167457,7 @@ async function identifyKeyFiles(args) {
|
|
|
167117
167457
|
parentSessionId: args.parentSessionId,
|
|
167118
167458
|
sessionDirectory: args.sessionDirectory,
|
|
167119
167459
|
holderId: args.holderId,
|
|
167460
|
+
fallbackModels: args.fallbackModels,
|
|
167120
167461
|
deadline: args.deadline,
|
|
167121
167462
|
sessionId,
|
|
167122
167463
|
config: args.config
|
|
@@ -167170,6 +167511,9 @@ async function runDream(args) {
|
|
|
167170
167511
|
const deadline = startedAt + args.maxRuntimeMinutes * 60 * 1000;
|
|
167171
167512
|
const lastDreamAt = getDreamState(args.db, `last_dream_at:${args.projectIdentity}`) ?? getDreamState(args.db, "last_dream_at");
|
|
167172
167513
|
log(`[dreamer] last dream at: ${lastDreamAt ?? "never"} (project=${args.projectIdentity})`);
|
|
167514
|
+
let lastErrorSignature = null;
|
|
167515
|
+
let consecutiveSameErrorFailures = 0;
|
|
167516
|
+
let circuitBreakerTripped = false;
|
|
167173
167517
|
try {
|
|
167174
167518
|
for (const taskName of args.tasks) {
|
|
167175
167519
|
if (Date.now() > deadline) {
|
|
@@ -167230,7 +167574,9 @@ async function runDream(args) {
|
|
|
167230
167574
|
}
|
|
167231
167575
|
}, {
|
|
167232
167576
|
timeoutMs: args.taskTimeoutMinutes * 60 * 1000,
|
|
167233
|
-
signal: taskAbortController.signal
|
|
167577
|
+
signal: taskAbortController.signal,
|
|
167578
|
+
fallbackModels: args.fallbackModels,
|
|
167579
|
+
callContext: `dreamer:${taskName}`
|
|
167234
167580
|
});
|
|
167235
167581
|
const messagesResponse = await args.client.session.messages({
|
|
167236
167582
|
path: { id: agentSessionId },
|
|
@@ -167250,16 +167596,40 @@ async function runDream(args) {
|
|
|
167250
167596
|
durationMs,
|
|
167251
167597
|
result: taskResult
|
|
167252
167598
|
});
|
|
167599
|
+
lastErrorSignature = null;
|
|
167600
|
+
consecutiveSameErrorFailures = 0;
|
|
167253
167601
|
} catch (error51) {
|
|
167254
167602
|
const durationMs = Date.now() - taskStartedAt;
|
|
167255
|
-
const
|
|
167256
|
-
|
|
167603
|
+
const errorDescription = describeError(error51);
|
|
167604
|
+
logWithStackHead(`[dreamer] task ${taskName}: failed after ${(durationMs / 1000).toFixed(1)}s — ${errorDescription.brief}`, errorDescription.stackHead);
|
|
167257
167605
|
result.tasks.push({
|
|
167258
167606
|
name: taskName,
|
|
167259
167607
|
durationMs,
|
|
167260
167608
|
result: null,
|
|
167261
|
-
error:
|
|
167609
|
+
error: errorDescription.brief
|
|
167262
167610
|
});
|
|
167611
|
+
if (shouldSkipCircuitBreaker(error51, errorDescription.brief)) {
|
|
167612
|
+
lastErrorSignature = null;
|
|
167613
|
+
consecutiveSameErrorFailures = 0;
|
|
167614
|
+
} else {
|
|
167615
|
+
const signature = getCircuitBreakerSignature(error51, errorDescription.brief);
|
|
167616
|
+
if (signature === lastErrorSignature) {
|
|
167617
|
+
consecutiveSameErrorFailures += 1;
|
|
167618
|
+
} else {
|
|
167619
|
+
lastErrorSignature = signature;
|
|
167620
|
+
consecutiveSameErrorFailures = 1;
|
|
167621
|
+
}
|
|
167622
|
+
if (consecutiveSameErrorFailures >= CIRCUIT_BREAKER_THRESHOLD) {
|
|
167623
|
+
circuitBreakerTripped = true;
|
|
167624
|
+
log(`[dreamer] circuit breaker: ${consecutiveSameErrorFailures} consecutive ${signature} failures — aborting remaining tasks`);
|
|
167625
|
+
result.tasks.push({
|
|
167626
|
+
name: "circuit-breaker",
|
|
167627
|
+
durationMs: 0,
|
|
167628
|
+
result: "",
|
|
167629
|
+
error: `Aborted remaining tasks: ${consecutiveSameErrorFailures} consecutive ${signature} failures. Configure dreamer model/fallback_models in magic-context.jsonc.`
|
|
167630
|
+
});
|
|
167631
|
+
}
|
|
167632
|
+
}
|
|
167263
167633
|
} finally {
|
|
167264
167634
|
clearInterval(leaseRenewalInterval);
|
|
167265
167635
|
if (agentSessionId) {
|
|
@@ -167271,8 +167641,20 @@ async function runDream(args) {
|
|
|
167271
167641
|
});
|
|
167272
167642
|
}
|
|
167273
167643
|
}
|
|
167644
|
+
if (circuitBreakerTripped) {
|
|
167645
|
+
break;
|
|
167646
|
+
}
|
|
167647
|
+
}
|
|
167648
|
+
if (circuitBreakerTripped) {
|
|
167649
|
+
log("[dreamer] circuit breaker: skipping post-task phases");
|
|
167650
|
+
result.tasks.push({
|
|
167651
|
+
name: "post-task-phases",
|
|
167652
|
+
durationMs: 0,
|
|
167653
|
+
result: "",
|
|
167654
|
+
error: "Skipped post-task phases after circuit breaker tripped; configure dreamer model/fallback_models in magic-context.jsonc."
|
|
167655
|
+
});
|
|
167274
167656
|
}
|
|
167275
|
-
if (args.experimentalUserMemories?.enabled && Date.now() <= deadline) {
|
|
167657
|
+
if (!circuitBreakerTripped && args.experimentalUserMemories?.enabled && Date.now() <= deadline) {
|
|
167276
167658
|
const umStart = Date.now();
|
|
167277
167659
|
try {
|
|
167278
167660
|
const reviewResult = await reviewUserMemories({
|
|
@@ -167282,7 +167664,8 @@ async function runDream(args) {
|
|
|
167282
167664
|
sessionDirectory: args.sessionDirectory,
|
|
167283
167665
|
holderId,
|
|
167284
167666
|
deadline,
|
|
167285
|
-
promotionThreshold: args.experimentalUserMemories.promotionThreshold
|
|
167667
|
+
promotionThreshold: args.experimentalUserMemories.promotionThreshold,
|
|
167668
|
+
fallbackModels: args.fallbackModels
|
|
167286
167669
|
});
|
|
167287
167670
|
const umOutput = `promoted=${reviewResult.promoted} merged=${reviewResult.merged} dismissed=${reviewResult.dismissed} consumed=${reviewResult.candidatesConsumed}`;
|
|
167288
167671
|
if (reviewResult.promoted > 0 || reviewResult.merged > 0 || reviewResult.dismissed > 0) {
|
|
@@ -167294,16 +167677,17 @@ async function runDream(args) {
|
|
|
167294
167677
|
result: umOutput
|
|
167295
167678
|
});
|
|
167296
167679
|
} catch (error51) {
|
|
167297
|
-
|
|
167680
|
+
const errorDescription = describeError(error51);
|
|
167681
|
+
logWithStackHead(`[dreamer] user-memory review failed: ${errorDescription.brief}`, errorDescription.stackHead);
|
|
167298
167682
|
result.tasks.push({
|
|
167299
167683
|
name: "user memories",
|
|
167300
167684
|
durationMs: Date.now() - umStart,
|
|
167301
167685
|
result: "",
|
|
167302
|
-
error:
|
|
167686
|
+
error: errorDescription.brief
|
|
167303
167687
|
});
|
|
167304
167688
|
}
|
|
167305
167689
|
}
|
|
167306
|
-
if (Date.now() <= deadline) {
|
|
167690
|
+
if (!circuitBreakerTripped && Date.now() <= deadline) {
|
|
167307
167691
|
try {
|
|
167308
167692
|
await evaluateSmartNotes({
|
|
167309
167693
|
db: args.db,
|
|
@@ -167313,13 +167697,15 @@ async function runDream(args) {
|
|
|
167313
167697
|
sessionDirectory: args.sessionDirectory,
|
|
167314
167698
|
holderId,
|
|
167315
167699
|
deadline,
|
|
167316
|
-
result
|
|
167700
|
+
result,
|
|
167701
|
+
fallbackModels: args.fallbackModels
|
|
167317
167702
|
});
|
|
167318
167703
|
} catch (error51) {
|
|
167319
|
-
|
|
167704
|
+
const errorDescription = describeError(error51);
|
|
167705
|
+
logWithStackHead(`[dreamer] smart note evaluation failed: ${errorDescription.brief}`, errorDescription.stackHead);
|
|
167320
167706
|
}
|
|
167321
167707
|
}
|
|
167322
|
-
if (args.experimentalPinKeyFiles?.enabled && Date.now() <= deadline) {
|
|
167708
|
+
if (!circuitBreakerTripped && args.experimentalPinKeyFiles?.enabled && Date.now() <= deadline) {
|
|
167323
167709
|
const kfStart = Date.now();
|
|
167324
167710
|
try {
|
|
167325
167711
|
await identifyKeyFiles({
|
|
@@ -167330,7 +167716,8 @@ async function runDream(args) {
|
|
|
167330
167716
|
sessionDirectory: args.sessionDirectory ?? args.projectIdentity,
|
|
167331
167717
|
holderId,
|
|
167332
167718
|
deadline,
|
|
167333
|
-
config: args.experimentalPinKeyFiles
|
|
167719
|
+
config: args.experimentalPinKeyFiles,
|
|
167720
|
+
fallbackModels: args.fallbackModels
|
|
167334
167721
|
});
|
|
167335
167722
|
result.tasks.push({
|
|
167336
167723
|
name: "key files",
|
|
@@ -167338,12 +167725,13 @@ async function runDream(args) {
|
|
|
167338
167725
|
result: "completed"
|
|
167339
167726
|
});
|
|
167340
167727
|
} catch (error51) {
|
|
167341
|
-
|
|
167728
|
+
const errorDescription = describeError(error51);
|
|
167729
|
+
logWithStackHead(`[key-files] identification phase failed: ${errorDescription.brief}`, errorDescription.stackHead);
|
|
167342
167730
|
result.tasks.push({
|
|
167343
167731
|
name: "key files",
|
|
167344
167732
|
durationMs: Date.now() - kfStart,
|
|
167345
167733
|
result: "",
|
|
167346
|
-
error:
|
|
167734
|
+
error: errorDescription.brief
|
|
167347
167735
|
});
|
|
167348
167736
|
}
|
|
167349
167737
|
}
|
|
@@ -167378,7 +167766,13 @@ async function runDream(args) {
|
|
|
167378
167766
|
smartNotesPending: result.smartNotesPending,
|
|
167379
167767
|
memoryChanges: persistedMemoryChanges
|
|
167380
167768
|
});
|
|
167381
|
-
const POST_TASK_NAMES = new Set([
|
|
167769
|
+
const POST_TASK_NAMES = new Set([
|
|
167770
|
+
"smart-notes",
|
|
167771
|
+
"user memories",
|
|
167772
|
+
"key files",
|
|
167773
|
+
"post-task-phases",
|
|
167774
|
+
"circuit-breaker"
|
|
167775
|
+
]);
|
|
167382
167776
|
const hasSuccessfulTask = result.tasks.some((t) => !t.error && !POST_TASK_NAMES.has(t.name));
|
|
167383
167777
|
if (hasSuccessfulTask) {
|
|
167384
167778
|
setDreamState(args.db, `last_dream_at:${args.projectIdentity}`, String(result.finishedAt));
|
|
@@ -167457,7 +167851,12 @@ Only include notes whose conditions you could definitively evaluate. Skip notes
|
|
|
167457
167851
|
system: DREAMER_SYSTEM_PROMPT,
|
|
167458
167852
|
parts: [{ type: "text", text: evaluationPrompt, synthetic: true }]
|
|
167459
167853
|
}
|
|
167460
|
-
}, {
|
|
167854
|
+
}, {
|
|
167855
|
+
timeoutMs: Math.min(remainingMs, 300000),
|
|
167856
|
+
signal: abortController.signal,
|
|
167857
|
+
fallbackModels: args.fallbackModels,
|
|
167858
|
+
callContext: "dreamer:smart-notes"
|
|
167859
|
+
});
|
|
167461
167860
|
const messagesResponse = await args.client.session.messages({
|
|
167462
167861
|
path: { id: agentSessionId },
|
|
167463
167862
|
query: { directory: args.sessionDirectory ?? args.projectIdentity }
|
|
@@ -167516,15 +167915,15 @@ Only include notes whose conditions you could definitively evaluate. Skip notes
|
|
|
167516
167915
|
});
|
|
167517
167916
|
} catch (error51) {
|
|
167518
167917
|
const durationMs = Date.now() - taskStartedAt;
|
|
167519
|
-
const
|
|
167918
|
+
const errorDescription = describeError(error51);
|
|
167520
167919
|
args.result.smartNotesSurfaced = 0;
|
|
167521
167920
|
args.result.smartNotesPending = pendingNotes.length;
|
|
167522
|
-
|
|
167921
|
+
logWithStackHead(`[dreamer] smart notes: failed after ${(durationMs / 1000).toFixed(1)}s — ${errorDescription.brief}`, errorDescription.stackHead);
|
|
167523
167922
|
args.result.tasks.push({
|
|
167524
167923
|
name: "smart-notes",
|
|
167525
167924
|
durationMs,
|
|
167526
167925
|
result: null,
|
|
167527
|
-
error:
|
|
167926
|
+
error: errorDescription.brief
|
|
167528
167927
|
});
|
|
167529
167928
|
} finally {
|
|
167530
167929
|
clearInterval(leaseInterval);
|
|
@@ -167557,7 +167956,8 @@ async function processDreamQueue(args) {
|
|
|
167557
167956
|
maxRuntimeMinutes: args.maxRuntimeMinutes,
|
|
167558
167957
|
sessionDirectory: projectDirectory,
|
|
167559
167958
|
experimentalUserMemories: args.experimentalUserMemories,
|
|
167560
|
-
experimentalPinKeyFiles: args.experimentalPinKeyFiles
|
|
167959
|
+
experimentalPinKeyFiles: args.experimentalPinKeyFiles,
|
|
167960
|
+
fallbackModels: args.fallbackModels
|
|
167561
167961
|
});
|
|
167562
167962
|
} catch (error51) {
|
|
167563
167963
|
log(`[dreamer] runDream threw for ${entry.projectIdentity}: ${getErrorMessage(error51)}`);
|
|
@@ -168165,6 +168565,7 @@ function searchGitCommitsSync(db, projectPath, query, options) {
|
|
|
168165
168565
|
init_embedding();
|
|
168166
168566
|
init_project_identity();
|
|
168167
168567
|
init_logger();
|
|
168568
|
+
init_resolve_fallbacks();
|
|
168168
168569
|
await init_storage();
|
|
168169
168570
|
var DREAM_TIMER_INTERVAL_MS = 15 * 60 * 1000;
|
|
168170
168571
|
var activeTimer = null;
|
|
@@ -168251,7 +168652,8 @@ async function sweepProject(reg, origin) {
|
|
|
168251
168652
|
maxRuntimeMinutes: reg.dreamerConfig.max_runtime_minutes,
|
|
168252
168653
|
experimentalUserMemories: reg.experimentalUserMemories,
|
|
168253
168654
|
experimentalPinKeyFiles: reg.experimentalPinKeyFiles,
|
|
168254
|
-
projectIdentity: registrationIdentity
|
|
168655
|
+
projectIdentity: registrationIdentity,
|
|
168656
|
+
fallbackModels: resolveFallbackChain(DREAMER_AGENT, reg.dreamerConfig.fallback_models)
|
|
168255
168657
|
});
|
|
168256
168658
|
} catch (error51) {
|
|
168257
168659
|
log(`[dreamer] timer-triggered queue processing failed for ${reg.directory}:`, error51);
|
|
@@ -168779,6 +169181,7 @@ function createTagger() {
|
|
|
168779
169181
|
init_magic_context();
|
|
168780
169182
|
init_project_identity();
|
|
168781
169183
|
init_logger();
|
|
169184
|
+
init_resolve_fallbacks();
|
|
168782
169185
|
await init_storage();
|
|
168783
169186
|
|
|
168784
169187
|
// src/hooks/magic-context/command-handler.ts
|
|
@@ -169259,7 +169662,8 @@ Dreaming is not configured for this project.`, {});
|
|
|
169259
169662
|
maxRuntimeMinutes: deps.dreamer.config.max_runtime_minutes,
|
|
169260
169663
|
experimentalUserMemories: deps.dreamer.experimentalUserMemories,
|
|
169261
169664
|
experimentalPinKeyFiles: deps.dreamer.experimentalPinKeyFiles,
|
|
169262
|
-
projectIdentity: deps.dreamer.projectPath
|
|
169665
|
+
projectIdentity: deps.dreamer.projectPath,
|
|
169666
|
+
fallbackModels: deps.dreamer.fallbackModels
|
|
169263
169667
|
});
|
|
169264
169668
|
await deps.sendNotification(sessionId, result ? summarizeDreamResult(result) : "Dream queued, but another worker is already processing the queue.", {});
|
|
169265
169669
|
throwSentinel("CTX-DREAM");
|
|
@@ -169555,113 +169959,8 @@ function clearSessionTracking(sessionId) {
|
|
|
169555
169959
|
}
|
|
169556
169960
|
}
|
|
169557
169961
|
|
|
169558
|
-
// src/features/magic-context/overflow-detection.ts
|
|
169559
|
-
var OVERFLOW_PATTERNS = [
|
|
169560
|
-
/prompt is too long/i,
|
|
169561
|
-
/input is too long for requested model/i,
|
|
169562
|
-
/exceeds the context window/i,
|
|
169563
|
-
/input token count.*exceeds the maximum/i,
|
|
169564
|
-
/maximum prompt length is \d+/i,
|
|
169565
|
-
/reduce the length of the messages/i,
|
|
169566
|
-
/maximum context length is \d+ tokens/i,
|
|
169567
|
-
/exceeds the limit of \d+/i,
|
|
169568
|
-
/exceeds the available context size/i,
|
|
169569
|
-
/greater than the context length/i,
|
|
169570
|
-
/context window exceeds limit/i,
|
|
169571
|
-
/exceeded model token limit/i,
|
|
169572
|
-
/context[_ ]length[_ ]exceeded/i,
|
|
169573
|
-
/request entity too large/i,
|
|
169574
|
-
/context length is only \d+ tokens/i,
|
|
169575
|
-
/input length.*exceeds.*context length/i,
|
|
169576
|
-
/prompt too long; exceeded (?:max )?context length/i,
|
|
169577
|
-
/too large for model with \d+ maximum context length/i,
|
|
169578
|
-
/model_context_window_exceeded/i,
|
|
169579
|
-
/context size has been exceeded/i
|
|
169580
|
-
];
|
|
169581
|
-
var LIMIT_EXTRACTION_PATTERNS = [
|
|
169582
|
-
/maximum prompt length is (\d+)/i,
|
|
169583
|
-
/maximum context length is (\d+) tokens?/i,
|
|
169584
|
-
/context length is only (\d+) tokens?/i,
|
|
169585
|
-
/exceeds the limit of (\d+)/i,
|
|
169586
|
-
/too large for model with (\d+) maximum context length/i,
|
|
169587
|
-
/context size.*(\d+) tokens?/i,
|
|
169588
|
-
/exceeds? the context length of (\d+)/i,
|
|
169589
|
-
/max(?:imum)?.*context.*?(\d+)/i
|
|
169590
|
-
];
|
|
169591
|
-
var MIN_PLAUSIBLE_LIMIT = 1024;
|
|
169592
|
-
var MAX_PLAUSIBLE_LIMIT = 1e7;
|
|
169593
|
-
function extractErrorMessage(error51) {
|
|
169594
|
-
if (!error51)
|
|
169595
|
-
return "";
|
|
169596
|
-
if (typeof error51 === "string")
|
|
169597
|
-
return error51;
|
|
169598
|
-
if (typeof error51 === "object") {
|
|
169599
|
-
const obj = error51;
|
|
169600
|
-
const nested = obj.error;
|
|
169601
|
-
if (nested && typeof nested.message === "string" && nested.message.length > 0) {
|
|
169602
|
-
return nested.message;
|
|
169603
|
-
}
|
|
169604
|
-
}
|
|
169605
|
-
if (error51 instanceof Error)
|
|
169606
|
-
return error51.message;
|
|
169607
|
-
if (typeof error51 === "object") {
|
|
169608
|
-
const obj = error51;
|
|
169609
|
-
if (typeof obj.message === "string")
|
|
169610
|
-
return obj.message;
|
|
169611
|
-
if (typeof obj.responseBody === "string")
|
|
169612
|
-
return obj.responseBody;
|
|
169613
|
-
try {
|
|
169614
|
-
return JSON.stringify(error51);
|
|
169615
|
-
} catch {
|
|
169616
|
-
return String(error51);
|
|
169617
|
-
}
|
|
169618
|
-
}
|
|
169619
|
-
return String(error51);
|
|
169620
|
-
}
|
|
169621
|
-
function detectOverflow(error51) {
|
|
169622
|
-
const message = extractErrorMessage(error51);
|
|
169623
|
-
if (!message) {
|
|
169624
|
-
return { isOverflow: false };
|
|
169625
|
-
}
|
|
169626
|
-
const hasStatus413 = /\b413\b/.test(message) && /(entity|payload|context|prompt)/i.test(message);
|
|
169627
|
-
let matched;
|
|
169628
|
-
for (const pattern of OVERFLOW_PATTERNS) {
|
|
169629
|
-
if (pattern.test(message)) {
|
|
169630
|
-
matched = pattern;
|
|
169631
|
-
break;
|
|
169632
|
-
}
|
|
169633
|
-
}
|
|
169634
|
-
if (!matched && !hasStatus413) {
|
|
169635
|
-
return { isOverflow: false };
|
|
169636
|
-
}
|
|
169637
|
-
const reportedLimit = parseReportedLimit(message);
|
|
169638
|
-
return {
|
|
169639
|
-
isOverflow: true,
|
|
169640
|
-
reportedLimit,
|
|
169641
|
-
matchedPattern: matched?.source
|
|
169642
|
-
};
|
|
169643
|
-
}
|
|
169644
|
-
function parseReportedLimit(message) {
|
|
169645
|
-
if (!message)
|
|
169646
|
-
return;
|
|
169647
|
-
for (const pattern of LIMIT_EXTRACTION_PATTERNS) {
|
|
169648
|
-
const match = message.match(pattern);
|
|
169649
|
-
if (!match)
|
|
169650
|
-
continue;
|
|
169651
|
-
const raw = match[1];
|
|
169652
|
-
if (!raw)
|
|
169653
|
-
continue;
|
|
169654
|
-
const value = Number.parseInt(raw, 10);
|
|
169655
|
-
if (!Number.isFinite(value))
|
|
169656
|
-
continue;
|
|
169657
|
-
if (value < MIN_PLAUSIBLE_LIMIT || value > MAX_PLAUSIBLE_LIMIT)
|
|
169658
|
-
continue;
|
|
169659
|
-
return value;
|
|
169660
|
-
}
|
|
169661
|
-
return;
|
|
169662
|
-
}
|
|
169663
|
-
|
|
169664
169962
|
// src/hooks/magic-context/event-handler.ts
|
|
169963
|
+
init_overflow_detection();
|
|
169665
169964
|
init_storage_meta_persisted();
|
|
169666
169965
|
init_logger();
|
|
169667
169966
|
await __promiseAll([
|
|
@@ -170575,6 +170874,7 @@ async function runCompartmentPhase(args) {
|
|
|
170575
170874
|
historianChunkTokens: args.historianChunkTokens,
|
|
170576
170875
|
historyBudgetTokens: args.historyBudgetTokens,
|
|
170577
170876
|
historianTimeoutMs: args.historianTimeoutMs,
|
|
170877
|
+
fallbackModels: args.fallbackModels,
|
|
170578
170878
|
directory: args.compartmentDirectory,
|
|
170579
170879
|
fallbackModelId: args.fallbackModelId,
|
|
170580
170880
|
getNotificationParams: args.getNotificationParams,
|
|
@@ -170602,6 +170902,7 @@ async function runCompartmentPhase(args) {
|
|
|
170602
170902
|
historianChunkTokens: args.historianChunkTokens,
|
|
170603
170903
|
historyBudgetTokens: args.historyBudgetTokens,
|
|
170604
170904
|
historianTimeoutMs: args.historianTimeoutMs,
|
|
170905
|
+
fallbackModels: args.fallbackModels,
|
|
170605
170906
|
directory: args.compartmentDirectory,
|
|
170606
170907
|
fallbackModelId: args.fallbackModelId,
|
|
170607
170908
|
getNotificationParams: args.getNotificationParams,
|
|
@@ -170641,6 +170942,7 @@ async function runCompartmentPhase(args) {
|
|
|
170641
170942
|
directory: args.compartmentDirectory,
|
|
170642
170943
|
historyBudgetTokens: args.historyBudgetTokens,
|
|
170643
170944
|
historianTimeoutMs: args.historianTimeoutMs,
|
|
170945
|
+
fallbackModels: args.fallbackModels,
|
|
170644
170946
|
minCompartmentRatio: args.compressorMinCompartmentRatio,
|
|
170645
170947
|
maxMergeDepth: args.compressorMaxMergeDepth
|
|
170646
170948
|
}).then((compressed) => {
|
|
@@ -170738,6 +171040,46 @@ function countMessagesSinceLastUser(messages) {
|
|
|
170738
171040
|
}
|
|
170739
171041
|
return messagesSinceLastUser;
|
|
170740
171042
|
}
|
|
171043
|
+
function injectToolPartIntoLatestAssistant(messages, part) {
|
|
171044
|
+
for (let index = messages.length - 1;index >= 0; index -= 1) {
|
|
171045
|
+
const message = messages[index];
|
|
171046
|
+
if (message.info.role !== "assistant")
|
|
171047
|
+
continue;
|
|
171048
|
+
if (typeof message.info.id !== "string")
|
|
171049
|
+
continue;
|
|
171050
|
+
if (hasToolPartWithCallId(message, part.callID)) {
|
|
171051
|
+
return message.info.id;
|
|
171052
|
+
}
|
|
171053
|
+
message.parts.push(part);
|
|
171054
|
+
return message.info.id;
|
|
171055
|
+
}
|
|
171056
|
+
return null;
|
|
171057
|
+
}
|
|
171058
|
+
function injectToolPartIntoAssistantById(messages, messageId, part) {
|
|
171059
|
+
for (const message of messages) {
|
|
171060
|
+
if (message.info.id !== messageId)
|
|
171061
|
+
continue;
|
|
171062
|
+
if (message.info.role !== "assistant")
|
|
171063
|
+
continue;
|
|
171064
|
+
if (hasToolPartWithCallId(message, part.callID))
|
|
171065
|
+
return true;
|
|
171066
|
+
message.parts.push(part);
|
|
171067
|
+
return true;
|
|
171068
|
+
}
|
|
171069
|
+
return false;
|
|
171070
|
+
}
|
|
171071
|
+
function hasToolPartWithCallId(message, callId) {
|
|
171072
|
+
for (const part of message.parts) {
|
|
171073
|
+
if (part === null || typeof part !== "object")
|
|
171074
|
+
continue;
|
|
171075
|
+
const p = part;
|
|
171076
|
+
if (p.type !== "tool")
|
|
171077
|
+
continue;
|
|
171078
|
+
if (p.callID === callId)
|
|
171079
|
+
return true;
|
|
171080
|
+
}
|
|
171081
|
+
return false;
|
|
171082
|
+
}
|
|
170741
171083
|
function appendReminderToUserMessage(message, reminder) {
|
|
170742
171084
|
for (const part of message.parts) {
|
|
170743
171085
|
if (!isTextPart(part)) {
|
|
@@ -172247,6 +172589,84 @@ function isVisibleNoteReadPart(part) {
|
|
|
172247
172589
|
return false;
|
|
172248
172590
|
}
|
|
172249
172591
|
|
|
172592
|
+
// src/hooks/magic-context/todo-view.ts
|
|
172593
|
+
import { createHash as createHash4 } from "node:crypto";
|
|
172594
|
+
var TERMINAL_STATUSES = new Set(["completed", "cancelled"]);
|
|
172595
|
+
var TITLE_DONE_STATUSES = new Set(["completed"]);
|
|
172596
|
+
var SYNTHETIC_CALL_ID_PREFIX = "mc_synthetic_todo_";
|
|
172597
|
+
function normalizeTodoStateJson(todos) {
|
|
172598
|
+
if (!Array.isArray(todos))
|
|
172599
|
+
return null;
|
|
172600
|
+
const normalized = [];
|
|
172601
|
+
for (const todo of todos) {
|
|
172602
|
+
if (!isTodoItem(todo))
|
|
172603
|
+
return null;
|
|
172604
|
+
normalized.push({
|
|
172605
|
+
content: todo.content,
|
|
172606
|
+
status: todo.status,
|
|
172607
|
+
priority: todo.priority
|
|
172608
|
+
});
|
|
172609
|
+
}
|
|
172610
|
+
return JSON.stringify(normalized);
|
|
172611
|
+
}
|
|
172612
|
+
function buildSyntheticTodoPart(stateJson) {
|
|
172613
|
+
const todos = parseTodoState(stateJson);
|
|
172614
|
+
if (todos === null || todos.length === 0)
|
|
172615
|
+
return null;
|
|
172616
|
+
if (todos.every((t) => TERMINAL_STATUSES.has(t.status)))
|
|
172617
|
+
return null;
|
|
172618
|
+
const callID = computeSyntheticCallId(stateJson);
|
|
172619
|
+
const activeCount = todos.filter((t) => !TITLE_DONE_STATUSES.has(t.status)).length;
|
|
172620
|
+
const output = JSON.stringify(todos, null, 2);
|
|
172621
|
+
const ts = 0;
|
|
172622
|
+
return {
|
|
172623
|
+
type: "tool",
|
|
172624
|
+
callID,
|
|
172625
|
+
tool: "todowrite",
|
|
172626
|
+
state: {
|
|
172627
|
+
status: "completed",
|
|
172628
|
+
input: { todos },
|
|
172629
|
+
output,
|
|
172630
|
+
title: `${activeCount} todos`,
|
|
172631
|
+
metadata: { todos, truncated: false },
|
|
172632
|
+
time: { start: ts, end: ts }
|
|
172633
|
+
},
|
|
172634
|
+
syntheticTodoMarker: true
|
|
172635
|
+
};
|
|
172636
|
+
}
|
|
172637
|
+
function computeSyntheticCallId(stateJson) {
|
|
172638
|
+
const hash2 = createHash4("sha256").update(stateJson).digest("hex").slice(0, 16);
|
|
172639
|
+
return `${SYNTHETIC_CALL_ID_PREFIX}${hash2}`;
|
|
172640
|
+
}
|
|
172641
|
+
function parseTodoState(stateJson) {
|
|
172642
|
+
if (stateJson.length === 0)
|
|
172643
|
+
return null;
|
|
172644
|
+
try {
|
|
172645
|
+
const parsed = JSON.parse(stateJson);
|
|
172646
|
+
if (!Array.isArray(parsed))
|
|
172647
|
+
return null;
|
|
172648
|
+
const result = [];
|
|
172649
|
+
for (const item of parsed) {
|
|
172650
|
+
if (!isTodoItem(item))
|
|
172651
|
+
continue;
|
|
172652
|
+
result.push({
|
|
172653
|
+
content: item.content,
|
|
172654
|
+
status: item.status,
|
|
172655
|
+
priority: item.priority
|
|
172656
|
+
});
|
|
172657
|
+
}
|
|
172658
|
+
return result;
|
|
172659
|
+
} catch {
|
|
172660
|
+
return null;
|
|
172661
|
+
}
|
|
172662
|
+
}
|
|
172663
|
+
function isTodoItem(value) {
|
|
172664
|
+
if (value === null || typeof value !== "object")
|
|
172665
|
+
return false;
|
|
172666
|
+
const todo = value;
|
|
172667
|
+
return typeof todo.content === "string" && typeof todo.status === "string" && typeof todo.priority === "string";
|
|
172668
|
+
}
|
|
172669
|
+
|
|
172250
172670
|
// src/hooks/magic-context/transform-stage-logger.ts
|
|
172251
172671
|
init_logger();
|
|
172252
172672
|
function logTransformTiming(sessionId, stage, startMs, extra) {
|
|
@@ -172488,6 +172908,33 @@ async function runPostTransformPhase(args) {
|
|
|
172488
172908
|
const anchoredMessageId = appendReminderToLatestUserMessage(args.messages, noteInstruction);
|
|
172489
172909
|
markNoteNudgeDelivered(args.db, args.sessionId, noteInstruction, anchoredMessageId);
|
|
172490
172910
|
}
|
|
172911
|
+
if (args.fullFeatureMode) {
|
|
172912
|
+
const persistedAnchor = getPersistedTodoSyntheticAnchor(args.db, args.sessionId);
|
|
172913
|
+
if (isCacheBustingPass) {
|
|
172914
|
+
const part = buildSyntheticTodoPart(args.sessionMeta.lastTodoState);
|
|
172915
|
+
if (part === null) {
|
|
172916
|
+
if (persistedAnchor) {
|
|
172917
|
+
clearPersistedTodoSyntheticAnchor(args.db, args.sessionId);
|
|
172918
|
+
}
|
|
172919
|
+
} else if (persistedAnchor && persistedAnchor.callId === part.callID && injectToolPartIntoAssistantById(args.messages, persistedAnchor.messageId, part)) {
|
|
172920
|
+
if (persistedAnchor.stateJson.length === 0) {
|
|
172921
|
+
setPersistedTodoSyntheticAnchor(args.db, args.sessionId, persistedAnchor.callId, persistedAnchor.messageId, args.sessionMeta.lastTodoState);
|
|
172922
|
+
}
|
|
172923
|
+
} else {
|
|
172924
|
+
const anchoredMessageId = injectToolPartIntoLatestAssistant(args.messages, part);
|
|
172925
|
+
if (anchoredMessageId) {
|
|
172926
|
+
setPersistedTodoSyntheticAnchor(args.db, args.sessionId, part.callID, anchoredMessageId, args.sessionMeta.lastTodoState);
|
|
172927
|
+
} else if (persistedAnchor) {
|
|
172928
|
+
clearPersistedTodoSyntheticAnchor(args.db, args.sessionId);
|
|
172929
|
+
}
|
|
172930
|
+
}
|
|
172931
|
+
} else if (persistedAnchor && persistedAnchor.stateJson.length > 0) {
|
|
172932
|
+
const part = buildSyntheticTodoPart(persistedAnchor.stateJson);
|
|
172933
|
+
if (part !== null && part.callID === persistedAnchor.callId) {
|
|
172934
|
+
injectToolPartIntoAssistantById(args.messages, persistedAnchor.messageId, part);
|
|
172935
|
+
}
|
|
172936
|
+
}
|
|
172937
|
+
}
|
|
172491
172938
|
if (args.fullFeatureMode && args.autoSearch?.enabled && args.projectPath) {
|
|
172492
172939
|
const visibleMemoryIds = getVisibleMemoryIds(args.db, args.sessionId) ?? undefined;
|
|
172493
172940
|
try {
|
|
@@ -172719,6 +173166,7 @@ function createTransform(deps) {
|
|
|
172719
173166
|
historianChunkTokens: deps.getHistorianChunkTokens?.() ?? 20000,
|
|
172720
173167
|
historyBudgetTokens,
|
|
172721
173168
|
historianTimeoutMs: deps.historianTimeoutMs,
|
|
173169
|
+
fallbackModels: deps.fallbackModels,
|
|
172722
173170
|
directory: compartmentDirectory,
|
|
172723
173171
|
fallbackModelId,
|
|
172724
173172
|
getNotificationParams: () => notificationParams,
|
|
@@ -172888,6 +173336,7 @@ Historian previously failed ${historianFailureState.failureCount} time(s), so ma
|
|
|
172888
173336
|
historianChunkTokens: deps.getHistorianChunkTokens?.() ?? 20000,
|
|
172889
173337
|
historyBudgetTokens,
|
|
172890
173338
|
historianTimeoutMs: deps.historianTimeoutMs,
|
|
173339
|
+
fallbackModels: deps.fallbackModels,
|
|
172891
173340
|
compartmentDirectory,
|
|
172892
173341
|
messages,
|
|
172893
173342
|
pendingCompartmentInjection,
|
|
@@ -173728,9 +174177,17 @@ function createToolExecuteAfterHook(args) {
|
|
|
173728
174177
|
if (typedInput.tool === "todowrite") {
|
|
173729
174178
|
const todoArgs = typedInput.args;
|
|
173730
174179
|
const todos = todoArgs?.todos;
|
|
173731
|
-
|
|
173732
|
-
|
|
173733
|
-
|
|
174180
|
+
const sessionMeta = Array.isArray(todos) ? getOrCreateSessionMeta(args.db, typedInput.sessionID) : null;
|
|
174181
|
+
if (sessionMeta && !sessionMeta.isSubagent) {
|
|
174182
|
+
const normalizedTodos = normalizeTodoStateJson(todos);
|
|
174183
|
+
if (normalizedTodos !== null) {
|
|
174184
|
+
updateSessionMeta(args.db, typedInput.sessionID, {
|
|
174185
|
+
lastTodoState: normalizedTodos
|
|
174186
|
+
});
|
|
174187
|
+
}
|
|
174188
|
+
}
|
|
174189
|
+
if (Array.isArray(todos) && todos.length > 0 && todos.every((t) => typeof t === "object" && t !== null && (t.status === "completed" || t.status === "cancelled"))) {
|
|
174190
|
+
if (sessionMeta && !sessionMeta.isSubagent) {
|
|
173734
174191
|
onNoteTrigger(args.db, typedInput.sessionID, "todos_complete");
|
|
173735
174192
|
}
|
|
173736
174193
|
}
|
|
@@ -173746,7 +174203,7 @@ function createToolExecuteAfterHook(args) {
|
|
|
173746
174203
|
init_send_session_notification();
|
|
173747
174204
|
|
|
173748
174205
|
// src/hooks/magic-context/system-prompt-hash.ts
|
|
173749
|
-
import { createHash as
|
|
174206
|
+
import { createHash as createHash5 } from "node:crypto";
|
|
173750
174207
|
import { existsSync as existsSync13, readFileSync as readFileSync9, realpathSync } from "node:fs";
|
|
173751
174208
|
import { join as join22, resolve as resolve4, sep } from "node:path";
|
|
173752
174209
|
|
|
@@ -174051,7 +174508,7 @@ ${sections.join(`
|
|
|
174051
174508
|
`);
|
|
174052
174509
|
if (systemContent.length === 0)
|
|
174053
174510
|
return;
|
|
174054
|
-
const currentHash =
|
|
174511
|
+
const currentHash = createHash5("md5").update(systemContent).digest("hex");
|
|
174055
174512
|
if (!sessionMetaEarly) {
|
|
174056
174513
|
return;
|
|
174057
174514
|
}
|
|
@@ -174066,14 +174523,12 @@ ${sections.join(`
|
|
|
174066
174523
|
} else if (previousHash === "" || previousHash === "0") {
|
|
174067
174524
|
sessionLog(sessionId, `system prompt hash initialized: ${currentHash} (len=${systemContent.length})`);
|
|
174068
174525
|
}
|
|
174069
|
-
const systemPromptTokens = estimateTokens(systemContent);
|
|
174070
174526
|
if (currentHash !== previousHash) {
|
|
174527
|
+
const systemPromptTokens = estimateTokens(systemContent);
|
|
174071
174528
|
updateSessionMeta(deps.db, sessionId, {
|
|
174072
174529
|
systemPromptHash: currentHash,
|
|
174073
174530
|
systemPromptTokens
|
|
174074
174531
|
});
|
|
174075
|
-
} else if (Math.abs(sessionMeta.systemPromptTokens - systemPromptTokens) > 50) {
|
|
174076
|
-
updateSessionMeta(deps.db, sessionId, { systemPromptTokens });
|
|
174077
174532
|
}
|
|
174078
174533
|
if (isCacheBusting) {
|
|
174079
174534
|
deps.systemPromptRefreshSessions.delete(sessionId);
|
|
@@ -174135,6 +174590,7 @@ function createMagicContextHook(deps) {
|
|
|
174135
174590
|
}
|
|
174136
174591
|
let lastScheduleCheckMs = 0;
|
|
174137
174592
|
const getHistorianChunkTokens = () => deriveHistorianChunkTokens(resolveHistorianContextLimit(deps.config.historian?.model));
|
|
174593
|
+
const historianFallbackModels = resolveFallbackChain(HISTORIAN_AGENT, deps.config.historian?.fallback_models);
|
|
174138
174594
|
const nudgePlacements = createNudgePlacementStore(db);
|
|
174139
174595
|
const historyRefreshSessions = deps.liveSessionState?.historyRefreshSessions ?? new Set;
|
|
174140
174596
|
const systemPromptRefreshSessions = deps.liveSessionState?.systemPromptRefreshSessions ?? new Set;
|
|
@@ -174194,6 +174650,7 @@ function createMagicContextHook(deps) {
|
|
|
174194
174650
|
executeThresholdPercentage: deps.config.execute_threshold_percentage,
|
|
174195
174651
|
executeThresholdTokens: deps.config.execute_threshold_tokens,
|
|
174196
174652
|
historianTimeoutMs: deps.config.historian_timeout_ms ?? DEFAULT_HISTORIAN_TIMEOUT_MS,
|
|
174653
|
+
fallbackModels: historianFallbackModels,
|
|
174197
174654
|
getNotificationParams: (sessionId) => getLiveNotificationParams(sessionId, liveModelBySession, variantBySession, agentBySession),
|
|
174198
174655
|
getModelKey: (sessionId) => {
|
|
174199
174656
|
const model = liveModelBySession.get(sessionId);
|
|
@@ -174271,7 +174728,8 @@ function createMagicContextHook(deps) {
|
|
|
174271
174728
|
enabled: true,
|
|
174272
174729
|
token_budget: deps.config.dreamer.pin_key_files.token_budget,
|
|
174273
174730
|
min_reads: deps.config.dreamer.pin_key_files.min_reads
|
|
174274
|
-
} : undefined
|
|
174731
|
+
} : undefined,
|
|
174732
|
+
fallbackModels: resolveFallbackChain(DREAMER_AGENT, deps.config.dreamer?.fallback_models)
|
|
174275
174733
|
}).catch((error51) => {
|
|
174276
174734
|
log("[dreamer] scheduled queue processing failed:", error51);
|
|
174277
174735
|
});
|
|
@@ -174305,6 +174763,7 @@ function createMagicContextHook(deps) {
|
|
|
174305
174763
|
sessionId,
|
|
174306
174764
|
historianChunkTokens: getHistorianChunkTokens(),
|
|
174307
174765
|
historianTimeoutMs: deps.config.historian_timeout_ms ?? DEFAULT_HISTORIAN_TIMEOUT_MS,
|
|
174766
|
+
fallbackModels: historianFallbackModels,
|
|
174308
174767
|
directory: deps.directory,
|
|
174309
174768
|
fallbackModelId: (() => {
|
|
174310
174769
|
const model = resolveLiveModel(sessionId);
|
|
@@ -174344,7 +174803,8 @@ function createMagicContextHook(deps) {
|
|
|
174344
174803
|
enabled: true,
|
|
174345
174804
|
token_budget: deps.config.dreamer.pin_key_files.token_budget,
|
|
174346
174805
|
min_reads: deps.config.dreamer.pin_key_files.min_reads
|
|
174347
|
-
} : undefined
|
|
174806
|
+
} : undefined,
|
|
174807
|
+
fallbackModels: resolveFallbackChain(DREAMER_AGENT, deps.config.dreamer.fallback_models)
|
|
174348
174808
|
} : undefined
|
|
174349
174809
|
});
|
|
174350
174810
|
const systemPromptHash = createSystemPromptHashHandler({
|
|
@@ -175006,19 +175466,7 @@ function buildStatusDetail(db, sessionId, directory, modelKey, config2, liveSess
|
|
|
175006
175466
|
}
|
|
175007
175467
|
detail.nextNudgeAfter = detail.lastNudgeTokens + detail.nudgeInterval;
|
|
175008
175468
|
try {
|
|
175009
|
-
const
|
|
175010
|
-
const facts = db.prepare("SELECT content FROM session_facts WHERE session_id = ?").all(sessionId);
|
|
175011
|
-
let histTokens = 0;
|
|
175012
|
-
for (const c of compartments) {
|
|
175013
|
-
histTokens += estimateTokens(`<compartment start="${c.start_message}" end="${c.end_message}" title="${c.title}">
|
|
175014
|
-
${c.content}
|
|
175015
|
-
</compartment>
|
|
175016
|
-
`);
|
|
175017
|
-
}
|
|
175018
|
-
for (const f of facts) {
|
|
175019
|
-
histTokens += estimateTokens(`* ${f.content}
|
|
175020
|
-
`);
|
|
175021
|
-
}
|
|
175469
|
+
const histTokens = base.compartmentTokens + base.factTokens;
|
|
175022
175470
|
detail.historyBlockTokens = histTokens;
|
|
175023
175471
|
if (detail.contextLimit > 0) {
|
|
175024
175472
|
const budget = Math.floor(detail.contextLimit * (Math.min(detail.executeThreshold, 80) / 100) * detail.historyBudgetPercentage);
|
|
@@ -175191,7 +175639,7 @@ function normalizeLimit2(limit) {
|
|
|
175191
175639
|
return Math.max(1, Math.floor(limit));
|
|
175192
175640
|
}
|
|
175193
175641
|
function getAllowedActions(deps) {
|
|
175194
|
-
const allowed = deps.allowedActions?.length ? deps.allowedActions : [
|
|
175642
|
+
const allowed = deps.allowedActions?.length ? deps.allowedActions : ["write", "delete"];
|
|
175195
175643
|
return [...allowed];
|
|
175196
175644
|
}
|
|
175197
175645
|
function normalizeCategory(category) {
|
|
@@ -175297,7 +175745,7 @@ function createCtxMemoryTool(deps) {
|
|
|
175297
175745
|
return tool2({
|
|
175298
175746
|
description: CTX_MEMORY_DESCRIPTION,
|
|
175299
175747
|
args: {
|
|
175300
|
-
action: tool2.schema.enum(
|
|
175748
|
+
action: tool2.schema.enum([...CTX_MEMORY_DREAMER_ACTIONS]).describe("Action to perform on memories"),
|
|
175301
175749
|
content: tool2.schema.string().optional().describe("Memory content (required for write, update, merge)"),
|
|
175302
175750
|
category: tool2.schema.string().optional().describe("Memory category (required for write, optional filter for list, optional override for merge)"),
|
|
175303
175751
|
id: tool2.schema.number().optional().describe("Memory ID (required for delete, update, archive)"),
|
|
@@ -176063,11 +176511,11 @@ import { createServer } from "node:http";
|
|
|
176063
176511
|
import { dirname as dirname6 } from "node:path";
|
|
176064
176512
|
|
|
176065
176513
|
// src/shared/rpc-utils.ts
|
|
176066
|
-
import { createHash as
|
|
176514
|
+
import { createHash as createHash6 } from "node:crypto";
|
|
176067
176515
|
import { join as join23 } from "node:path";
|
|
176068
176516
|
function projectHash(directory) {
|
|
176069
176517
|
const normalized = directory.replace(/\/+$/, "");
|
|
176070
|
-
return
|
|
176518
|
+
return createHash6("sha256").update(normalized).digest("hex").slice(0, 16);
|
|
176071
176519
|
}
|
|
176072
176520
|
function rpcPortFilePath(storageDir, directory) {
|
|
176073
176521
|
return join23(storageDir, "rpc", projectHash(directory), "port");
|