@wolfx/opencode-magic-context 0.24.1 → 0.25.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/agents/magic-context-prompt.d.ts.map +1 -1
- package/dist/features/magic-context/compartment-chunk-embedding.d.ts +8 -0
- package/dist/features/magic-context/compartment-chunk-embedding.d.ts.map +1 -1
- package/dist/features/magic-context/memory/embedding-local.d.ts +4 -0
- package/dist/features/magic-context/memory/embedding-local.d.ts.map +1 -1
- package/dist/features/magic-context/memory/storage-memory-embeddings.d.ts +6 -0
- package/dist/features/magic-context/memory/storage-memory-embeddings.d.ts.map +1 -1
- package/dist/features/magic-context/project-embedding-registry.d.ts +38 -0
- package/dist/features/magic-context/project-embedding-registry.d.ts.map +1 -1
- package/dist/features/magic-context/storage-db.d.ts.map +1 -1
- package/dist/features/magic-context/storage-meta-session.d.ts +1 -0
- package/dist/features/magic-context/storage-meta-session.d.ts.map +1 -1
- package/dist/features/magic-context/storage-meta-shared.d.ts +2 -1
- 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-tags.d.ts +10 -0
- package/dist/features/magic-context/storage-tags.d.ts.map +1 -1
- package/dist/features/magic-context/storage.d.ts +2 -2
- 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/hooks/magic-context/apply-operations.d.ts +3 -25
- package/dist/hooks/magic-context/apply-operations.d.ts.map +1 -1
- package/dist/hooks/magic-context/caveman-cleanup.d.ts +1 -0
- package/dist/hooks/magic-context/caveman-cleanup.d.ts.map +1 -1
- package/dist/hooks/magic-context/channel2-delivery.d.ts +2 -0
- package/dist/hooks/magic-context/channel2-delivery.d.ts.map +1 -1
- package/dist/hooks/magic-context/command-handler.d.ts +7 -5
- package/dist/hooks/magic-context/command-handler.d.ts.map +1 -1
- package/dist/hooks/magic-context/ctx-reduce-nudge.d.ts +7 -2
- package/dist/hooks/magic-context/ctx-reduce-nudge.d.ts.map +1 -1
- package/dist/hooks/magic-context/embed-session-state.d.ts +14 -0
- package/dist/hooks/magic-context/embed-session-state.d.ts.map +1 -0
- package/dist/hooks/magic-context/event-handler.d.ts.map +1 -1
- package/dist/hooks/magic-context/format-embed-status.d.ts +9 -0
- package/dist/hooks/magic-context/format-embed-status.d.ts.map +1 -0
- package/dist/hooks/magic-context/heuristic-cleanup.d.ts +1 -0
- package/dist/hooks/magic-context/heuristic-cleanup.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/protected-tail-boundary.d.ts.map +1 -1
- package/dist/hooks/magic-context/read-session-true-raw-tokens.d.ts +1 -1
- package/dist/hooks/magic-context/read-session-true-raw-tokens.d.ts.map +1 -1
- package/dist/hooks/magic-context/strip-content.d.ts +0 -1
- package/dist/hooks/magic-context/strip-content.d.ts.map +1 -1
- package/dist/hooks/magic-context/tag-content-primitives.d.ts +2 -0
- package/dist/hooks/magic-context/tag-content-primitives.d.ts.map +1 -1
- package/dist/hooks/magic-context/tag-messages.d.ts.map +1 -1
- package/dist/hooks/magic-context/tool-drop-target.d.ts +1 -1
- package/dist/hooks/magic-context/tool-drop-target.d.ts.map +1 -1
- package/dist/hooks/magic-context/tool-reclaim.d.ts +12 -0
- package/dist/hooks/magic-context/tool-reclaim.d.ts.map +1 -0
- package/dist/hooks/magic-context/transform-operations.d.ts +1 -1
- package/dist/hooks/magic-context/transform-operations.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.d.ts.map +1 -1
- package/dist/index.js +1103 -408
- package/dist/plugin/conflict-warning-hook.d.ts.map +1 -1
- package/dist/plugin/hooks/create-session-hooks.d.ts.map +1 -1
- package/dist/plugin/rpc-handlers.d.ts.map +1 -1
- package/dist/shared/announcement.d.ts +1 -1
- package/dist/shared/model-suggestion-retry.d.ts.map +1 -1
- package/dist/shared/rpc-types.d.ts +20 -0
- package/dist/shared/rpc-types.d.ts.map +1 -1
- package/dist/shared/sqlite.d.ts +5 -1
- package/dist/shared/sqlite.d.ts.map +1 -1
- package/dist/tools/ctx-expand/constants.d.ts +1 -1
- package/dist/tools/ctx-expand/constants.d.ts.map +1 -1
- package/dist/tools/ctx-expand/render.d.ts +43 -0
- package/dist/tools/ctx-expand/render.d.ts.map +1 -0
- package/dist/tools/ctx-expand/tools.d.ts.map +1 -1
- package/dist/tools/ctx-expand/types.d.ts +6 -2
- package/dist/tools/ctx-expand/types.d.ts.map +1 -1
- package/dist/tools/ctx-reduce/constants.d.ts +1 -1
- package/dist/tools/ctx-reduce/constants.d.ts.map +1 -1
- package/dist/tui/data/context-db.d.ts +4 -2
- package/dist/tui/data/context-db.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/shared/announcement.ts +6 -6
- package/src/shared/model-suggestion-retry.test.ts +61 -1
- package/src/shared/model-suggestion-retry.ts +22 -0
- package/src/shared/rpc-types.ts +11 -0
- package/src/shared/sqlite-bind-style.test.ts +82 -0
- package/src/shared/sqlite.ts +30 -1
- package/src/shared/tag-transcript.test.ts +3 -1
- package/src/shared/tag-transcript.ts +19 -17
- package/src/tui/data/context-db.ts +34 -2
- package/src/tui/index.tsx +58 -4
- package/src/tui/slots/sidebar-content.tsx +7 -2
package/dist/index.js
CHANGED
|
@@ -15565,9 +15565,11 @@ async function promptWithTimeout(client, args, timeoutMs, signal) {
|
|
|
15565
15565
|
});
|
|
15566
15566
|
} catch (error51) {
|
|
15567
15567
|
if (signal?.aborted) {
|
|
15568
|
+
await abortChildRun(client, args.path.id);
|
|
15568
15569
|
throw new Error("prompt aborted by external signal");
|
|
15569
15570
|
}
|
|
15570
15571
|
if (controller.signal.aborted) {
|
|
15572
|
+
await abortChildRun(client, args.path.id);
|
|
15571
15573
|
throw new Error(`prompt timed out after ${timeoutMs}ms`);
|
|
15572
15574
|
}
|
|
15573
15575
|
throw error51;
|
|
@@ -15576,6 +15578,13 @@ async function promptWithTimeout(client, args, timeoutMs, signal) {
|
|
|
15576
15578
|
signal?.removeEventListener("abort", onExternalAbort);
|
|
15577
15579
|
}
|
|
15578
15580
|
}
|
|
15581
|
+
async function abortChildRun(client, sessionId) {
|
|
15582
|
+
try {
|
|
15583
|
+
await client.session.abort({ path: { id: sessionId } });
|
|
15584
|
+
} catch (error51) {
|
|
15585
|
+
log(`[model-retry] child session abort failed for ${sessionId}: ${String(error51)}`);
|
|
15586
|
+
}
|
|
15587
|
+
}
|
|
15579
15588
|
function isNonRetryable(error51, externalSignal) {
|
|
15580
15589
|
if (externalSignal?.aborted)
|
|
15581
15590
|
return true;
|
|
@@ -15847,7 +15856,7 @@ function isSessionMetaRow(row) {
|
|
|
15847
15856
|
if (row === null || typeof row !== "object")
|
|
15848
15857
|
return false;
|
|
15849
15858
|
const r = row;
|
|
15850
|
-
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.observed_safe_input_tokens) && isNumberOrNull(r.cache_alert_sent) && 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) && isBlobOrNull(r.cached_m0_bytes) && isBlobOrNull(r.cached_m1_bytes) && isNumberOrNull(r.cached_m0_project_memory_epoch) && isStringOrNull(r.cached_m0_workspace_fingerprint) && isNumberOrNull(r.cached_m0_project_user_profile_version) && isNumberOrNull(r.cached_m0_max_compartment_seq) && isNumberOrNull(r.cached_m0_max_memory_id) && isNumberOrNull(r.cached_m0_max_mutation_id) && isNumberOrNull(r.cached_m0_max_memory_mutation_id) && isStringOrNull(r.cached_m0_project_docs_hash) && isNumberOrNull(r.cached_m0_materialized_at) && isNumberOrNull(r.cached_m0_session_facts_version) && isStringOrNull(r.cached_m0_upgrade_state) && isStringOrNull(r.cached_m0_system_hash) && isStringOrNull(r.cached_m0_tool_set_hash) && isStringOrNull(r.cached_m0_model_key) && isStringOrNull(r.last_observed_model_key) && isNumberOrNull(r.last_usage_context_limit) && isNumberOrNull(r.prior_boundary_ordinal) && isNumberOrNull(r.protected_tail_policy_version) && isNumberOrNull(r.protected_tail_drain_window_started_at) && isNumberOrNull(r.protected_tail_drain_tokens) && isNumberOrNull(r.recovery_no_eligible_head_count) && isNumberOrNull(r.force_emergency_bypass_window_start) && isNumberOrNull(r.force_emergency_bypass_used) && isNumberOrNull(r.upgrade_reminded_at) && isNumberOrNull(r.pi_stable_id_scheme);
|
|
15859
|
+
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.observed_safe_input_tokens) && isNumberOrNull(r.cache_alert_sent) && 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) && isBlobOrNull(r.cached_m0_bytes) && isBlobOrNull(r.cached_m1_bytes) && isNumberOrNull(r.cached_m0_project_memory_epoch) && isStringOrNull(r.cached_m0_workspace_fingerprint) && isNumberOrNull(r.cached_m0_project_user_profile_version) && isNumberOrNull(r.cached_m0_max_compartment_seq) && isNumberOrNull(r.cached_m0_max_memory_id) && isNumberOrNull(r.cached_m0_max_mutation_id) && isNumberOrNull(r.cached_m0_max_memory_mutation_id) && isStringOrNull(r.cached_m0_project_docs_hash) && isNumberOrNull(r.cached_m0_materialized_at) && isNumberOrNull(r.cached_m0_session_facts_version) && isStringOrNull(r.cached_m0_upgrade_state) && isStringOrNull(r.cached_m0_system_hash) && isStringOrNull(r.cached_m0_tool_set_hash) && isStringOrNull(r.cached_m0_model_key) && isStringOrNull(r.last_observed_model_key) && isNumberOrNull(r.last_usage_context_limit) && isNumberOrNull(r.prior_boundary_ordinal) && isNumberOrNull(r.protected_tail_policy_version) && isNumberOrNull(r.protected_tail_drain_window_started_at) && isNumberOrNull(r.protected_tail_drain_tokens) && isNumberOrNull(r.recovery_no_eligible_head_count) && isNumberOrNull(r.force_emergency_bypass_window_start) && isNumberOrNull(r.force_emergency_bypass_used) && isNumberOrNull(r.upgrade_reminded_at) && isNumberOrNull(r.pi_stable_id_scheme) && isNumberOrNull(r.tool_reclaim_watermark);
|
|
15851
15860
|
}
|
|
15852
15861
|
function getDefaultSessionMeta(sessionId) {
|
|
15853
15862
|
return {
|
|
@@ -15870,6 +15879,7 @@ function getDefaultSessionMeta(sessionId) {
|
|
|
15870
15879
|
conversationTokens: 0,
|
|
15871
15880
|
toolCallTokens: 0,
|
|
15872
15881
|
clearedReasoningThroughTag: 0,
|
|
15882
|
+
toolReclaimWatermark: 0,
|
|
15873
15883
|
lastTodoState: "",
|
|
15874
15884
|
cachedM0Bytes: null,
|
|
15875
15885
|
cachedM1Bytes: null,
|
|
@@ -15933,6 +15943,7 @@ function toSessionMeta(row) {
|
|
|
15933
15943
|
conversationTokens: numOrZero(row.conversation_tokens),
|
|
15934
15944
|
toolCallTokens: numOrZero(row.tool_call_tokens),
|
|
15935
15945
|
clearedReasoningThroughTag: numOrZero(row.cleared_reasoning_through_tag),
|
|
15946
|
+
toolReclaimWatermark: numOrZero(row.tool_reclaim_watermark),
|
|
15936
15947
|
lastTodoState: lastTodoStateRaw,
|
|
15937
15948
|
cachedM0Bytes: toBufferOrNull(row.cached_m0_bytes),
|
|
15938
15949
|
cachedM1Bytes: toBufferOrNull(row.cached_m1_bytes),
|
|
@@ -16042,6 +16053,7 @@ var init_storage_meta_shared = __esm(() => {
|
|
|
16042
16053
|
"conversation_tokens",
|
|
16043
16054
|
"tool_call_tokens",
|
|
16044
16055
|
"cleared_reasoning_through_tag",
|
|
16056
|
+
"tool_reclaim_watermark",
|
|
16045
16057
|
"last_todo_state",
|
|
16046
16058
|
"cached_m0_bytes",
|
|
16047
16059
|
"cached_m1_bytes",
|
|
@@ -16090,6 +16102,7 @@ var init_storage_meta_shared = __esm(() => {
|
|
|
16090
16102
|
conversationTokens: "conversation_tokens",
|
|
16091
16103
|
toolCallTokens: "tool_call_tokens",
|
|
16092
16104
|
clearedReasoningThroughTag: "cleared_reasoning_through_tag",
|
|
16105
|
+
toolReclaimWatermark: "tool_reclaim_watermark",
|
|
16093
16106
|
lastTodoState: "last_todo_state",
|
|
16094
16107
|
cachedM0Bytes: "cached_m0_bytes",
|
|
16095
16108
|
cachedM1Bytes: "cached_m1_bytes",
|
|
@@ -16366,6 +16379,14 @@ function buildNodeSqliteDatabaseClass(DatabaseSync) {
|
|
|
16366
16379
|
}
|
|
16367
16380
|
super(typeof filename === "string" ? filename : ":memory:", translated);
|
|
16368
16381
|
}
|
|
16382
|
+
prepare(sql) {
|
|
16383
|
+
const stmt = super.prepare(sql);
|
|
16384
|
+
for (const method of ["run", "get", "all"]) {
|
|
16385
|
+
const original = stmt[method].bind(stmt);
|
|
16386
|
+
stmt[method] = (...args) => args.length === 1 && Array.isArray(args[0]) ? original(...args[0]) : original(...args);
|
|
16387
|
+
}
|
|
16388
|
+
return stmt;
|
|
16389
|
+
}
|
|
16369
16390
|
transaction(fn) {
|
|
16370
16391
|
const self = this;
|
|
16371
16392
|
const wrapped = function(...args) {
|
|
@@ -149342,6 +149363,9 @@ function stripCompleteTagPairsGlobally(value) {
|
|
|
149342
149363
|
function stripMalformedTagNotationGlobally(value) {
|
|
149343
149364
|
return value.replace(MALFORMED_TAG_GLOBAL_REGEX, "");
|
|
149344
149365
|
}
|
|
149366
|
+
function stripDanglingTagNotationGlobally(value) {
|
|
149367
|
+
return value.replace(DANGLING_TAG_GLOBAL_REGEX, "");
|
|
149368
|
+
}
|
|
149345
149369
|
function stripTagSectionCharacters(value) {
|
|
149346
149370
|
return value.replace(STRAY_SECTION_CHAR_REGEX, "");
|
|
149347
149371
|
}
|
|
@@ -149349,6 +149373,7 @@ function stripPersistedAssistantText(value) {
|
|
|
149349
149373
|
let text = stripWellFormedLeadingTagPrefix(value);
|
|
149350
149374
|
text = stripCompleteTagPairsGlobally(text);
|
|
149351
149375
|
text = stripMalformedTagNotationGlobally(text);
|
|
149376
|
+
text = stripDanglingTagNotationGlobally(text);
|
|
149352
149377
|
text = stripTagSectionCharacters(text);
|
|
149353
149378
|
return text.trim();
|
|
149354
149379
|
}
|
|
@@ -149361,6 +149386,7 @@ function stripTagPrefix(value) {
|
|
|
149361
149386
|
const prev = stripped;
|
|
149362
149387
|
stripped = stripped.replace(MALFORMED_TAG_PREFIX_REGEX, "");
|
|
149363
149388
|
stripped = stripped.replace(TAG_PREFIX_REGEX, "");
|
|
149389
|
+
stripped = stripped.replace(DANGLING_TAG_PREFIX_REGEX, "");
|
|
149364
149390
|
if (stripped === prev)
|
|
149365
149391
|
break;
|
|
149366
149392
|
}
|
|
@@ -149382,11 +149408,13 @@ function isThinkingPart(part) {
|
|
|
149382
149408
|
const candidate = part;
|
|
149383
149409
|
return candidate.type === "thinking" || candidate.type === "reasoning";
|
|
149384
149410
|
}
|
|
149385
|
-
var encoder, TAG_PREFIX_REGEX, MALFORMED_TAG_PREFIX_REGEX, COMPLETE_TAG_PAIR_GLOBAL_REGEX, MALFORMED_TAG_GLOBAL_REGEX, STRAY_SECTION_CHAR_REGEX;
|
|
149411
|
+
var encoder, TAG_PREFIX_REGEX, MALFORMED_TAG_PREFIX_REGEX, DANGLING_TAG_GLOBAL_REGEX, DANGLING_TAG_PREFIX_REGEX, COMPLETE_TAG_PAIR_GLOBAL_REGEX, MALFORMED_TAG_GLOBAL_REGEX, STRAY_SECTION_CHAR_REGEX;
|
|
149386
149412
|
var init_tag_content_primitives = __esm(() => {
|
|
149387
149413
|
encoder = new TextEncoder;
|
|
149388
149414
|
TAG_PREFIX_REGEX = /^(?:§\d+§\s*)+/;
|
|
149389
149415
|
MALFORMED_TAG_PREFIX_REGEX = /^(?:§\d+">§(?:\d+§)?\s*)+/;
|
|
149416
|
+
DANGLING_TAG_GLOBAL_REGEX = /\u00a7\d+(?!\.\d)[^\s\u00a7\w.]?/g;
|
|
149417
|
+
DANGLING_TAG_PREFIX_REGEX = /^(?:\u00a7\d+(?!\.\d)[^\s\u00a7\w.]?\s*)+/;
|
|
149390
149418
|
COMPLETE_TAG_PAIR_GLOBAL_REGEX = /\u00a7\d+\u00a7/g;
|
|
149391
149419
|
MALFORMED_TAG_GLOBAL_REGEX = /\u00a7\d+">(?:\u00a7(?:\d+\u00a7)?)?/g;
|
|
149392
149420
|
STRAY_SECTION_CHAR_REGEX = /\u00a7/g;
|
|
@@ -149450,12 +149478,13 @@ function setToolContent(part, content) {
|
|
|
149450
149478
|
part.content = content;
|
|
149451
149479
|
}
|
|
149452
149480
|
}
|
|
149453
|
-
function truncateToolPart(part) {
|
|
149481
|
+
function truncateToolPart(part, tagId) {
|
|
149454
149482
|
if (!isRecord(part))
|
|
149455
149483
|
return;
|
|
149484
|
+
const sentinel = `[dropped §${tagId}§]`;
|
|
149456
149485
|
if (part.type === "tool" && isRecord(part.state)) {
|
|
149457
149486
|
const state = part.state;
|
|
149458
|
-
state.output =
|
|
149487
|
+
state.output = sentinel;
|
|
149459
149488
|
if (isRecord(state.input)) {
|
|
149460
149489
|
const inputSize = estimateInputSize(state.input);
|
|
149461
149490
|
if (inputSize > 500) {
|
|
@@ -149465,7 +149494,7 @@ function truncateToolPart(part) {
|
|
|
149465
149494
|
return;
|
|
149466
149495
|
}
|
|
149467
149496
|
if (part.type === "tool_result") {
|
|
149468
|
-
part.content =
|
|
149497
|
+
part.content = sentinel;
|
|
149469
149498
|
return;
|
|
149470
149499
|
}
|
|
149471
149500
|
if (part.type === "tool-invocation" && isRecord(part.args)) {
|
|
@@ -149582,7 +149611,7 @@ class ToolMutationBatch {
|
|
|
149582
149611
|
this.affectedMessages.clear();
|
|
149583
149612
|
}
|
|
149584
149613
|
}
|
|
149585
|
-
function createToolDropTarget(compositeKey, thinkingParts, index, batch) {
|
|
149614
|
+
function createToolDropTarget(compositeKey, thinkingParts, index, batch, tagId) {
|
|
149586
149615
|
const drop = () => {
|
|
149587
149616
|
const entry = index.get(compositeKey);
|
|
149588
149617
|
if (!entry || entry.occurrences.length === 0)
|
|
@@ -149603,7 +149632,7 @@ function createToolDropTarget(compositeKey, thinkingParts, index, batch) {
|
|
|
149603
149632
|
if (!entry.hasResult)
|
|
149604
149633
|
return "incomplete";
|
|
149605
149634
|
for (const occurrence of entry.occurrences) {
|
|
149606
|
-
truncateToolPart(occurrence.part);
|
|
149635
|
+
truncateToolPart(occurrence.part, tagId);
|
|
149607
149636
|
}
|
|
149608
149637
|
clearThinkingParts(thinkingParts);
|
|
149609
149638
|
return "truncated";
|
|
@@ -151337,6 +151366,7 @@ CREATE INDEX IF NOT EXISTS idx_dream_queue_pending ON dream_queue(started_at, en
|
|
|
151337
151366
|
ensureColumn(db, "session_meta", "historian_last_failure_at", "INTEGER DEFAULT NULL");
|
|
151338
151367
|
ensureColumn(db, "session_meta", "system_prompt_hash", "TEXT DEFAULT ''");
|
|
151339
151368
|
ensureColumn(db, "session_meta", "cleared_reasoning_through_tag", "INTEGER DEFAULT 0");
|
|
151369
|
+
ensureColumn(db, "session_meta", "tool_reclaim_watermark", "INTEGER DEFAULT 0");
|
|
151340
151370
|
ensureColumn(db, "session_meta", "stripped_placeholder_ids", "TEXT DEFAULT ''");
|
|
151341
151371
|
ensureColumn(db, "session_meta", "stale_reduce_stripped_ids", "TEXT DEFAULT ''");
|
|
151342
151372
|
ensureColumn(db, "session_meta", "processed_image_stripped_ids", "TEXT DEFAULT ''");
|
|
@@ -154126,7 +154156,8 @@ var exports_storage_meta_session = {};
|
|
|
154126
154156
|
__export(exports_storage_meta_session, {
|
|
154127
154157
|
updateSessionMeta: () => updateSessionMeta,
|
|
154128
154158
|
getOrCreateSessionMeta: () => getOrCreateSessionMeta,
|
|
154129
|
-
clearSession: () => clearSession
|
|
154159
|
+
clearSession: () => clearSession,
|
|
154160
|
+
advanceToolReclaimWatermark: () => advanceToolReclaimWatermark
|
|
154130
154161
|
});
|
|
154131
154162
|
import { Buffer as Buffer3 } from "node:buffer";
|
|
154132
154163
|
function getSessionMetaSelectColumns(db) {
|
|
@@ -154187,6 +154218,14 @@ function updateSessionMeta(db, sessionId, updates) {
|
|
|
154187
154218
|
db.prepare(`UPDATE session_meta SET ${setClauses.join(", ")} WHERE session_id = ?`).run(...values, sessionId);
|
|
154188
154219
|
})();
|
|
154189
154220
|
}
|
|
154221
|
+
function advanceToolReclaimWatermark(db, sessionId, maxTagNumber) {
|
|
154222
|
+
if (maxTagNumber <= 0)
|
|
154223
|
+
return;
|
|
154224
|
+
db.transaction(() => {
|
|
154225
|
+
ensureSessionMetaRow(db, sessionId);
|
|
154226
|
+
db.prepare("UPDATE session_meta SET tool_reclaim_watermark = MAX(COALESCE(tool_reclaim_watermark, 0), ?) WHERE session_id = ?").run(maxTagNumber, sessionId);
|
|
154227
|
+
})();
|
|
154228
|
+
}
|
|
154190
154229
|
function clearSession(db, sessionId) {
|
|
154191
154230
|
db.transaction(() => {
|
|
154192
154231
|
db.prepare("DELETE FROM pending_ops WHERE session_id = ?").run(sessionId);
|
|
@@ -154225,6 +154264,7 @@ var init_storage_meta_session = __esm(async () => {
|
|
|
154225
154264
|
last_transform_error: "'' AS last_transform_error",
|
|
154226
154265
|
system_prompt_hash: "'' AS system_prompt_hash",
|
|
154227
154266
|
last_todo_state: "'' AS last_todo_state",
|
|
154267
|
+
tool_reclaim_watermark: "0 AS tool_reclaim_watermark",
|
|
154228
154268
|
cached_m0_bytes: "NULL AS cached_m0_bytes",
|
|
154229
154269
|
cached_m1_bytes: "NULL AS cached_m1_bytes",
|
|
154230
154270
|
cached_m0_project_memory_epoch: "NULL AS cached_m0_project_memory_epoch",
|
|
@@ -154632,6 +154672,26 @@ function getActiveTagTokenAggregate(db, sessionId, protectedTags = 0) {
|
|
|
154632
154672
|
nullCount: row?.null_count ?? 0
|
|
154633
154673
|
};
|
|
154634
154674
|
}
|
|
154675
|
+
function getOldestActiveUnprotectedToolTags(db, sessionId, protectedTags = 0, limit = 4) {
|
|
154676
|
+
if (limit <= 0)
|
|
154677
|
+
return [];
|
|
154678
|
+
const boundedLimit = Math.max(1, Math.min(10, Math.floor(limit)));
|
|
154679
|
+
const whereProtected = protectedTags > 0 ? `AND tag_number < (
|
|
154680
|
+
SELECT tag_number FROM tags
|
|
154681
|
+
WHERE session_id = ? AND status = 'active'
|
|
154682
|
+
ORDER BY tag_number DESC LIMIT 1 OFFSET ?
|
|
154683
|
+
)` : "";
|
|
154684
|
+
const params = protectedTags > 0 ? [sessionId, sessionId, protectedTags - 1, boundedLimit] : [sessionId, boundedLimit];
|
|
154685
|
+
const rows = db.prepare(`SELECT tag_number, tool_name
|
|
154686
|
+
FROM tags
|
|
154687
|
+
WHERE session_id = ? AND status = 'active' AND type = 'tool' ${whereProtected}
|
|
154688
|
+
ORDER BY tag_number ASC, id ASC
|
|
154689
|
+
LIMIT ?`).all(...params);
|
|
154690
|
+
return rows.filter((row) => typeof row.tag_number === "number").map((row) => ({
|
|
154691
|
+
tagNumber: row.tag_number,
|
|
154692
|
+
toolName: typeof row.tool_name === "string" ? row.tool_name : null
|
|
154693
|
+
}));
|
|
154694
|
+
}
|
|
154635
154695
|
function getTriggerTagTokenUpperBound(db, sessionId) {
|
|
154636
154696
|
const row = db.prepare(`SELECT
|
|
154637
154697
|
COALESCE(SUM(COALESCE(token_count, 0) + COALESCE(input_token_count, 0) + COALESCE(reasoning_token_count, 0)), 0) AS bound,
|
|
@@ -156218,6 +156278,58 @@ var init_safe_notification_target = __esm(() => {
|
|
|
156218
156278
|
DEFAULT_TITLE_RE = /^(New session - |Child session - )\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{3}Z$/;
|
|
156219
156279
|
});
|
|
156220
156280
|
|
|
156281
|
+
// src/shared/rpc-notifications.ts
|
|
156282
|
+
var exports_rpc_notifications = {};
|
|
156283
|
+
__export(exports_rpc_notifications, {
|
|
156284
|
+
pushNotification: () => pushNotification,
|
|
156285
|
+
isTuiConnected: () => isTuiConnected,
|
|
156286
|
+
drainNotifications: () => drainNotifications
|
|
156287
|
+
});
|
|
156288
|
+
function pushNotification(type, payload, sessionId) {
|
|
156289
|
+
queue.push({ id: nextNotificationId++, type, payload, sessionId });
|
|
156290
|
+
if (queue.length > 100) {
|
|
156291
|
+
const newestPerSession = new Map;
|
|
156292
|
+
for (const n of queue) {
|
|
156293
|
+
const prev = newestPerSession.get(n.sessionId);
|
|
156294
|
+
if (prev === undefined || n.id > prev) {
|
|
156295
|
+
newestPerSession.set(n.sessionId, n.id);
|
|
156296
|
+
}
|
|
156297
|
+
}
|
|
156298
|
+
const mustKeep = new Set(newestPerSession.values());
|
|
156299
|
+
const byNewest = [...queue].sort((a, b) => b.id - a.id);
|
|
156300
|
+
const kept = [];
|
|
156301
|
+
for (const n of byNewest) {
|
|
156302
|
+
if (kept.length < 50 || mustKeep.has(n.id))
|
|
156303
|
+
kept.push(n);
|
|
156304
|
+
}
|
|
156305
|
+
queue = kept.sort((a, b) => a.id - b.id);
|
|
156306
|
+
}
|
|
156307
|
+
}
|
|
156308
|
+
function drainNotifications(lastReceivedId = 0, sessionId) {
|
|
156309
|
+
const now = Date.now();
|
|
156310
|
+
lastDrainAtAny = now;
|
|
156311
|
+
if (sessionId !== undefined)
|
|
156312
|
+
lastDrainAtBySession.set(sessionId, now);
|
|
156313
|
+
const matchesClient = (notification) => sessionId === undefined || notification.sessionId === undefined || notification.sessionId === sessionId;
|
|
156314
|
+
if (lastReceivedId > 0) {
|
|
156315
|
+
queue = queue.filter((notification) => !(notification.id <= lastReceivedId && matchesClient(notification)));
|
|
156316
|
+
}
|
|
156317
|
+
return queue.filter((notification) => notification.id > lastReceivedId && matchesClient(notification));
|
|
156318
|
+
}
|
|
156319
|
+
function isTuiConnected(sessionId) {
|
|
156320
|
+
const now = Date.now();
|
|
156321
|
+
if (sessionId !== undefined) {
|
|
156322
|
+
const at = lastDrainAtBySession.get(sessionId) ?? 0;
|
|
156323
|
+
return at > 0 && now - at < TUI_CONNECTED_WINDOW_MS;
|
|
156324
|
+
}
|
|
156325
|
+
return lastDrainAtAny > 0 && now - lastDrainAtAny < TUI_CONNECTED_WINDOW_MS;
|
|
156326
|
+
}
|
|
156327
|
+
var queue, nextNotificationId = 1, lastDrainAtBySession, lastDrainAtAny = 0, TUI_CONNECTED_WINDOW_MS = 3000;
|
|
156328
|
+
var init_rpc_notifications = __esm(() => {
|
|
156329
|
+
queue = [];
|
|
156330
|
+
lastDrainAtBySession = new Map;
|
|
156331
|
+
});
|
|
156332
|
+
|
|
156221
156333
|
// src/plugin/conflict-warning-hook.ts
|
|
156222
156334
|
var exports_conflict_warning_hook = {};
|
|
156223
156335
|
__export(exports_conflict_warning_hook, {
|
|
@@ -156552,6 +156664,9 @@ async function sendStartupAnnouncement(client, directory, version2, features, fo
|
|
|
156552
156664
|
if (!sessionId) {
|
|
156553
156665
|
return;
|
|
156554
156666
|
}
|
|
156667
|
+
const { isTuiConnected: isTuiConnected2 } = await Promise.resolve().then(() => (init_rpc_notifications(), exports_rpc_notifications));
|
|
156668
|
+
if (isTuiConnected2(sessionId) || isTuiConnected2())
|
|
156669
|
+
return;
|
|
156555
156670
|
if (await waitForSafeNotificationTarget(client, sessionId) === "skip")
|
|
156556
156671
|
return;
|
|
156557
156672
|
const bullets = features.map((line) => ` • ${line}`).join(`
|
|
@@ -164531,6 +164646,20 @@ function getDistinctStoredModelIds(db, projectPath) {
|
|
|
164531
164646
|
const rows = getDistinctStoredModelIdsStatement(db).all(projectPath);
|
|
164532
164647
|
return new Set(rows.map((row) => typeof row.modelId === "string" ? row.modelId : null));
|
|
164533
164648
|
}
|
|
164649
|
+
function getMemoryEmbedCoverage(db, projectPath, modelId) {
|
|
164650
|
+
const row = db.prepare(`SELECT
|
|
164651
|
+
COUNT(*) AS total,
|
|
164652
|
+
SUM(CASE WHEN EXISTS (
|
|
164653
|
+
SELECT 1 FROM memory_embeddings e
|
|
164654
|
+
WHERE e.memory_id = m.id AND e.model_id = ?
|
|
164655
|
+
) THEN 1 ELSE 0 END) AS embedded
|
|
164656
|
+
FROM memories m
|
|
164657
|
+
WHERE m.project_path = ? AND m.status = 'active'`).get(modelId, projectPath);
|
|
164658
|
+
return {
|
|
164659
|
+
total: typeof row?.total === "number" ? row.total : 0,
|
|
164660
|
+
embedded: typeof row?.embedded === "number" ? row.embedded : 0
|
|
164661
|
+
};
|
|
164662
|
+
}
|
|
164534
164663
|
var saveEmbeddingStatements, loadAllEmbeddingsStatements, deleteEmbeddingStatements, getStoredModelIdStatements, clearAllEmbeddingsStatements, getDistinctStoredModelIdsStatements;
|
|
164535
164664
|
var init_storage_memory_embeddings = __esm(() => {
|
|
164536
164665
|
saveEmbeddingStatements = new WeakMap;
|
|
@@ -165575,6 +165704,28 @@ function countUnembeddedSessionCompartments(db, projectPath, sessionId, modelId)
|
|
|
165575
165704
|
)`).get(projectPath, sessionId, projectPath, modelId);
|
|
165576
165705
|
return typeof row?.n === "number" ? row.n : 0;
|
|
165577
165706
|
}
|
|
165707
|
+
function countSessionCompartmentEmbedCoverage(db, projectPath, sessionId, modelId) {
|
|
165708
|
+
const row = db.prepare(`SELECT
|
|
165709
|
+
COUNT(*) AS total,
|
|
165710
|
+
SUM(CASE WHEN EXISTS (
|
|
165711
|
+
SELECT 1 FROM compartment_chunk_embeddings e
|
|
165712
|
+
WHERE e.compartment_id = c.id
|
|
165713
|
+
AND e.project_path = ?
|
|
165714
|
+
AND e.model_id = ?
|
|
165715
|
+
) THEN 1 ELSE 0 END) AS embedded
|
|
165716
|
+
FROM compartments c
|
|
165717
|
+
JOIN session_projects sp
|
|
165718
|
+
ON sp.session_id = c.session_id
|
|
165719
|
+
AND sp.harness = c.harness
|
|
165720
|
+
AND sp.project_path = ?
|
|
165721
|
+
WHERE c.session_id = ?
|
|
165722
|
+
AND c.start_message IS NOT NULL
|
|
165723
|
+
AND c.end_message IS NOT NULL`).get(projectPath, modelId, projectPath, sessionId);
|
|
165724
|
+
return {
|
|
165725
|
+
total: typeof row?.total === "number" ? row.total : 0,
|
|
165726
|
+
embedded: typeof row?.embedded === "number" ? row.embedded : 0
|
|
165727
|
+
};
|
|
165728
|
+
}
|
|
165578
165729
|
var DEFAULT_COMPARTMENT_CHUNK_MAX_INPUT_TOKENS = 512, CHUNK_WINDOW_SAFETY_RATIO = 0.9, loadFtsRowsStatements, existingHashStatements, existingHashByProjectStatements, deleteByCompartmentStatements, insertEmbeddingStatements, distinctModelStatements, clearProjectStatements, clearProjectModelStatements, searchRowsStatements, searchRowsByModelStatements, backfillCandidateStatements, sessionBackfillCandidateStatements;
|
|
165579
165730
|
var init_compartment_chunk_embedding = __esm(() => {
|
|
165580
165731
|
init_read_session_formatting();
|
|
@@ -165732,6 +165883,18 @@ async function withQuietConsole(fn) {
|
|
|
165732
165883
|
console.error = origError;
|
|
165733
165884
|
}
|
|
165734
165885
|
}
|
|
165886
|
+
function isNativeRuntimeMissingError(error51) {
|
|
165887
|
+
const message = error51 instanceof Error ? error51.message : String(error51 ?? "");
|
|
165888
|
+
const lower = message.toLowerCase();
|
|
165889
|
+
const code = error51?.code;
|
|
165890
|
+
const name2 = error51?.name;
|
|
165891
|
+
if (code === "ERR_DLOPEN_FAILED" && lower.includes("onnxruntime")) {
|
|
165892
|
+
return true;
|
|
165893
|
+
}
|
|
165894
|
+
if (!lower.includes("onnxruntime-node"))
|
|
165895
|
+
return false;
|
|
165896
|
+
return code === "ERR_MODULE_NOT_FOUND" || name2 === "ResolveMessage" || lower.includes("cannot find package") || lower.includes("cannot find module") || lower.includes("err_module_not_found");
|
|
165897
|
+
}
|
|
165735
165898
|
function isTransientLoadError(error51) {
|
|
165736
165899
|
const message = error51 instanceof Error ? error51.message : String(error51 ?? "");
|
|
165737
165900
|
if (!message)
|
|
@@ -165796,6 +165959,9 @@ class LocalEmbeddingProvider {
|
|
|
165796
165959
|
if (this.pipeline) {
|
|
165797
165960
|
return true;
|
|
165798
165961
|
}
|
|
165962
|
+
if (nativeRuntimeMissing) {
|
|
165963
|
+
return false;
|
|
165964
|
+
}
|
|
165799
165965
|
if (this.initPromise) {
|
|
165800
165966
|
await this.initPromise;
|
|
165801
165967
|
return this.pipeline !== null;
|
|
@@ -165862,7 +166028,12 @@ class LocalEmbeddingProvider {
|
|
|
165862
166028
|
await releaseLock();
|
|
165863
166029
|
}
|
|
165864
166030
|
} catch (error51) {
|
|
165865
|
-
|
|
166031
|
+
if (isNativeRuntimeMissingError(error51)) {
|
|
166032
|
+
nativeRuntimeMissing = true;
|
|
166033
|
+
log("[magic-context] local embedding runtime is not installed (onnxruntime-node missing from this install). Local embeddings are disabled. Fix: reinstall the plugin (run `npx @wolfx/magic-context@latest doctor --force`), or configure an `openai-compatible`/`ollama` embedding endpoint instead. Existing memories are unaffected.");
|
|
166034
|
+
} else {
|
|
166035
|
+
log("[magic-context] embedding model failed to load:", error51);
|
|
166036
|
+
}
|
|
165866
166037
|
this.pipeline = null;
|
|
165867
166038
|
} finally {
|
|
165868
166039
|
this.initPromise = null;
|
|
@@ -165973,7 +166144,7 @@ class LocalEmbeddingProvider {
|
|
|
165973
166144
|
return this.pipeline !== null;
|
|
165974
166145
|
}
|
|
165975
166146
|
}
|
|
165976
|
-
var LOCK_POLL_MS = 150, STALE_LOCK_MS, MAX_LOCK_WAIT_MS;
|
|
166147
|
+
var LOCK_POLL_MS = 150, STALE_LOCK_MS, MAX_LOCK_WAIT_MS, nativeRuntimeMissing = false;
|
|
165977
166148
|
var init_embedding_local = __esm(() => {
|
|
165978
166149
|
init_magic_context();
|
|
165979
166150
|
init_data_path();
|
|
@@ -166387,6 +166558,121 @@ var init_storage_git_commit_embeddings = __esm(() => {
|
|
|
166387
166558
|
distinctModelIdStatements = new WeakMap;
|
|
166388
166559
|
});
|
|
166389
166560
|
|
|
166561
|
+
// src/features/magic-context/git-commits/storage-git-commits.ts
|
|
166562
|
+
function getInsertStatement(db) {
|
|
166563
|
+
let stmt = insertStatements.get(db);
|
|
166564
|
+
if (!stmt) {
|
|
166565
|
+
stmt = db.prepare(`INSERT INTO git_commits (sha, project_path, short_sha, message, author, committed_at, indexed_at)
|
|
166566
|
+
VALUES (?, ?, ?, ?, ?, ?, ?)
|
|
166567
|
+
ON CONFLICT(sha) DO UPDATE SET
|
|
166568
|
+
project_path = excluded.project_path,
|
|
166569
|
+
short_sha = excluded.short_sha,
|
|
166570
|
+
message = excluded.message,
|
|
166571
|
+
author = excluded.author,
|
|
166572
|
+
committed_at = excluded.committed_at,
|
|
166573
|
+
indexed_at = excluded.indexed_at
|
|
166574
|
+
WHERE git_commits.message != excluded.message`);
|
|
166575
|
+
insertStatements.set(db, stmt);
|
|
166576
|
+
}
|
|
166577
|
+
return stmt;
|
|
166578
|
+
}
|
|
166579
|
+
function getExistingShasStatement(db) {
|
|
166580
|
+
let stmt = existingShasStatements.get(db);
|
|
166581
|
+
if (!stmt) {
|
|
166582
|
+
stmt = db.prepare("SELECT sha FROM git_commits WHERE project_path = ?");
|
|
166583
|
+
existingShasStatements.set(db, stmt);
|
|
166584
|
+
}
|
|
166585
|
+
return stmt;
|
|
166586
|
+
}
|
|
166587
|
+
function getProjectCountStatement(db) {
|
|
166588
|
+
let stmt = projectCountStatements.get(db);
|
|
166589
|
+
if (!stmt) {
|
|
166590
|
+
stmt = db.prepare("SELECT COUNT(*) AS count FROM git_commits WHERE project_path = ?");
|
|
166591
|
+
projectCountStatements.set(db, stmt);
|
|
166592
|
+
}
|
|
166593
|
+
return stmt;
|
|
166594
|
+
}
|
|
166595
|
+
function getLatestCommitTimeStatement(db) {
|
|
166596
|
+
let stmt = latestCommitTimeStatements.get(db);
|
|
166597
|
+
if (!stmt) {
|
|
166598
|
+
stmt = db.prepare("SELECT MAX(committed_at) AS latest FROM git_commits WHERE project_path = ?");
|
|
166599
|
+
latestCommitTimeStatements.set(db, stmt);
|
|
166600
|
+
}
|
|
166601
|
+
return stmt;
|
|
166602
|
+
}
|
|
166603
|
+
function getEvictOverflowStatement(db) {
|
|
166604
|
+
let stmt = evictOverflowStatements.get(db);
|
|
166605
|
+
if (!stmt) {
|
|
166606
|
+
stmt = db.prepare(`DELETE FROM git_commits
|
|
166607
|
+
WHERE rowid IN (
|
|
166608
|
+
SELECT rowid FROM git_commits
|
|
166609
|
+
WHERE project_path = ?
|
|
166610
|
+
ORDER BY committed_at DESC, sha DESC
|
|
166611
|
+
LIMIT -1 OFFSET ?
|
|
166612
|
+
)`);
|
|
166613
|
+
evictOverflowStatements.set(db, stmt);
|
|
166614
|
+
}
|
|
166615
|
+
return stmt;
|
|
166616
|
+
}
|
|
166617
|
+
function upsertCommits(db, projectPath, commits) {
|
|
166618
|
+
if (commits.length === 0)
|
|
166619
|
+
return { inserted: 0, updated: 0 };
|
|
166620
|
+
const existing = new Set;
|
|
166621
|
+
for (const row of getExistingShasStatement(db).all(projectPath)) {
|
|
166622
|
+
existing.add(row.sha);
|
|
166623
|
+
}
|
|
166624
|
+
let inserted = 0;
|
|
166625
|
+
let updated = 0;
|
|
166626
|
+
const now = Date.now();
|
|
166627
|
+
const insertStmt = getInsertStatement(db);
|
|
166628
|
+
db.transaction(() => {
|
|
166629
|
+
for (const commit of commits) {
|
|
166630
|
+
const result = insertStmt.run(commit.sha, projectPath, commit.shortSha, commit.message, commit.author, commit.committedAtMs, now);
|
|
166631
|
+
if (result.changes > 0) {
|
|
166632
|
+
if (existing.has(commit.sha)) {
|
|
166633
|
+
updated++;
|
|
166634
|
+
} else {
|
|
166635
|
+
inserted++;
|
|
166636
|
+
existing.add(commit.sha);
|
|
166637
|
+
}
|
|
166638
|
+
}
|
|
166639
|
+
}
|
|
166640
|
+
})();
|
|
166641
|
+
return { inserted, updated };
|
|
166642
|
+
}
|
|
166643
|
+
function getCommitCount(db, projectPath) {
|
|
166644
|
+
const row = getProjectCountStatement(db).get(projectPath);
|
|
166645
|
+
return row?.count ?? 0;
|
|
166646
|
+
}
|
|
166647
|
+
function getLatestIndexedCommitTimeMs(db, projectPath) {
|
|
166648
|
+
const row = getLatestCommitTimeStatement(db).get(projectPath);
|
|
166649
|
+
return row?.latest ?? null;
|
|
166650
|
+
}
|
|
166651
|
+
function enforceProjectCap(db, projectPath, maxCommits) {
|
|
166652
|
+
if (maxCommits <= 0)
|
|
166653
|
+
return 0;
|
|
166654
|
+
const count = getCommitCount(db, projectPath);
|
|
166655
|
+
if (count <= maxCommits)
|
|
166656
|
+
return 0;
|
|
166657
|
+
getEvictOverflowStatement(db).run(projectPath, maxCommits);
|
|
166658
|
+
const after = getCommitCount(db, projectPath);
|
|
166659
|
+
const evicted = Math.max(0, count - after);
|
|
166660
|
+
if (evicted > 0) {
|
|
166661
|
+
log(`[git-commits] evicted ${evicted} oldest commits for project ${projectPath} (cap=${maxCommits}, was=${count})`);
|
|
166662
|
+
}
|
|
166663
|
+
return evicted;
|
|
166664
|
+
}
|
|
166665
|
+
var insertStatements, existingShasStatements, projectCountStatements, evictStatements, evictOverflowStatements, latestCommitTimeStatements;
|
|
166666
|
+
var init_storage_git_commits = __esm(() => {
|
|
166667
|
+
init_logger();
|
|
166668
|
+
insertStatements = new WeakMap;
|
|
166669
|
+
existingShasStatements = new WeakMap;
|
|
166670
|
+
projectCountStatements = new WeakMap;
|
|
166671
|
+
evictStatements = new WeakMap;
|
|
166672
|
+
evictOverflowStatements = new WeakMap;
|
|
166673
|
+
latestCommitTimeStatements = new WeakMap;
|
|
166674
|
+
});
|
|
166675
|
+
|
|
166390
166676
|
// src/features/magic-context/git-commits/sweep-coordinator.ts
|
|
166391
166677
|
function runImmediate2(db, body) {
|
|
166392
166678
|
db.exec("BEGIN IMMEDIATE");
|
|
@@ -166680,7 +166966,9 @@ function snapshotFor(registration) {
|
|
|
166680
166966
|
enabled,
|
|
166681
166967
|
gitCommitEnabled,
|
|
166682
166968
|
modelId: registration.observationMode || !providerIsOn ? "off" : registration.modelId,
|
|
166683
|
-
chunkModelId: registration.observationMode || !providerIsOn ? "off" : registration.chunkModelId
|
|
166969
|
+
chunkModelId: registration.observationMode || !providerIsOn ? "off" : registration.chunkModelId,
|
|
166970
|
+
model: registration.observationMode || !providerIsOn ? "off" : ("model" in registration.config) && registration.config.model.trim() ? registration.config.model.trim() : registration.modelId,
|
|
166971
|
+
provider: registration.observationMode || !providerIsOn ? "off" : registration.config.provider ?? "local"
|
|
166684
166972
|
};
|
|
166685
166973
|
}
|
|
166686
166974
|
function disposeProvider(provider) {
|
|
@@ -166891,8 +167179,9 @@ async function embedUnembeddedMemoriesForProject(db, projectIdentity, batchSize
|
|
|
166891
167179
|
}
|
|
166892
167180
|
async function embedCandidateChunkBatch(db, projectIdentity, modelId, candidates, signal) {
|
|
166893
167181
|
const noWork = [];
|
|
167182
|
+
const failed = [];
|
|
166894
167183
|
if (candidates.length === 0)
|
|
166895
|
-
return { embedded: 0, noWork };
|
|
167184
|
+
return { embedded: 0, noWork, failed };
|
|
166896
167185
|
const maxInputTokens = getProjectEmbeddingMaxInputTokens(projectIdentity);
|
|
166897
167186
|
const prepared = [];
|
|
166898
167187
|
for (const candidate of candidates) {
|
|
@@ -166909,7 +167198,7 @@ async function embedCandidateChunkBatch(db, projectIdentity, modelId, candidates
|
|
|
166909
167198
|
prepared.push({ candidate, windows });
|
|
166910
167199
|
}
|
|
166911
167200
|
if (prepared.length === 0)
|
|
166912
|
-
return { embedded: 0, noWork };
|
|
167201
|
+
return { embedded: 0, noWork, failed };
|
|
166913
167202
|
let embedded = 0;
|
|
166914
167203
|
let i = 0;
|
|
166915
167204
|
while (i < prepared.length) {
|
|
@@ -166926,35 +167215,60 @@ async function embedCandidateChunkBatch(db, projectIdentity, modelId, candidates
|
|
|
166926
167215
|
const texts = [];
|
|
166927
167216
|
for (const item of slice)
|
|
166928
167217
|
texts.push(...item.windows.map((w) => w.text));
|
|
166929
|
-
|
|
166930
|
-
|
|
166931
|
-
if (!result)
|
|
166932
|
-
continue;
|
|
167218
|
+
const persistedIds = new Set;
|
|
167219
|
+
for (let attempt = 0;attempt < EMBED_SLICE_RETRY_ATTEMPTS; attempt++) {
|
|
166933
167220
|
if (signal?.aborted)
|
|
166934
167221
|
break;
|
|
166935
|
-
let
|
|
166936
|
-
|
|
166937
|
-
|
|
166938
|
-
|
|
166939
|
-
|
|
166940
|
-
|
|
167222
|
+
let result = null;
|
|
167223
|
+
const attemptStart = Date.now();
|
|
167224
|
+
try {
|
|
167225
|
+
result = await embedBatchForProject(projectIdentity, texts, signal);
|
|
167226
|
+
} catch (error51) {
|
|
167227
|
+
log("[magic-context] failed to proactively embed compartment chunks:", error51);
|
|
167228
|
+
}
|
|
167229
|
+
if (signal?.aborted)
|
|
167230
|
+
break;
|
|
167231
|
+
if (result) {
|
|
167232
|
+
let offset = 0;
|
|
167233
|
+
for (const item of slice) {
|
|
167234
|
+
const vectors = result.vectors.slice(offset, offset + item.windows.length);
|
|
167235
|
+
offset += item.windows.length;
|
|
167236
|
+
if (persistedIds.has(item.candidate.id))
|
|
167237
|
+
continue;
|
|
167238
|
+
if (vectors.length !== item.windows.length || vectors.some((v) => !v)) {
|
|
167239
|
+
continue;
|
|
167240
|
+
}
|
|
167241
|
+
const rows = item.windows.map((window, index) => ({
|
|
167242
|
+
compartmentId: item.candidate.id,
|
|
167243
|
+
sessionId: item.candidate.sessionId,
|
|
167244
|
+
projectPath: projectIdentity,
|
|
167245
|
+
window,
|
|
167246
|
+
modelId,
|
|
167247
|
+
vector: vectors[index]
|
|
167248
|
+
}));
|
|
167249
|
+
replaceCompartmentChunkEmbeddings(db, rows);
|
|
167250
|
+
persistedIds.add(item.candidate.id);
|
|
166941
167251
|
}
|
|
166942
|
-
const rows = item.windows.map((window, index) => ({
|
|
166943
|
-
compartmentId: item.candidate.id,
|
|
166944
|
-
sessionId: item.candidate.sessionId,
|
|
166945
|
-
projectPath: projectIdentity,
|
|
166946
|
-
window,
|
|
166947
|
-
modelId,
|
|
166948
|
-
vector: vectors[index]
|
|
166949
|
-
}));
|
|
166950
|
-
replaceCompartmentChunkEmbeddings(db, rows);
|
|
166951
|
-
embedded += 1;
|
|
166952
167252
|
}
|
|
166953
|
-
|
|
166954
|
-
|
|
167253
|
+
if (persistedIds.size === slice.length)
|
|
167254
|
+
break;
|
|
167255
|
+
if (persistedIds.size > 0)
|
|
167256
|
+
break;
|
|
167257
|
+
if (Date.now() - attemptStart >= EMBED_SLOW_FAILURE_NO_RETRY_MS)
|
|
167258
|
+
break;
|
|
167259
|
+
if (attempt < EMBED_SLICE_RETRY_ATTEMPTS - 1) {
|
|
167260
|
+
await new Promise((resolve6) => setTimeout(resolve6, EMBED_SLICE_RETRY_BASE_MS * 2 ** attempt));
|
|
167261
|
+
}
|
|
167262
|
+
}
|
|
167263
|
+
embedded += persistedIds.size;
|
|
167264
|
+
if (!signal?.aborted) {
|
|
167265
|
+
for (const item of slice) {
|
|
167266
|
+
if (!persistedIds.has(item.candidate.id))
|
|
167267
|
+
failed.push(item.candidate.id);
|
|
167268
|
+
}
|
|
166955
167269
|
}
|
|
166956
167270
|
}
|
|
166957
|
-
return { embedded, noWork };
|
|
167271
|
+
return { embedded, noWork, failed };
|
|
166958
167272
|
}
|
|
166959
167273
|
async function embedSessionCompartmentChunks(db, projectIdentity, sessionId, options) {
|
|
166960
167274
|
const snapshot = getProjectEmbeddingSnapshot(projectIdentity);
|
|
@@ -166977,9 +167291,11 @@ async function embedSessionCompartmentChunks(db, projectIdentity, sessionId, opt
|
|
|
166977
167291
|
renewal.unref?.();
|
|
166978
167292
|
const batchSize = Math.max(1, options?.batchSize ?? CHUNK_DRAIN_BATCH_SIZE);
|
|
166979
167293
|
const skipIds = [];
|
|
167294
|
+
const failedIds = [];
|
|
166980
167295
|
let embedded = 0;
|
|
166981
167296
|
let aborted2 = false;
|
|
166982
|
-
let
|
|
167297
|
+
let providerDown = false;
|
|
167298
|
+
let consecutiveFailedBatches = 0;
|
|
166983
167299
|
try {
|
|
166984
167300
|
options?.onProgress?.({ embedded, total });
|
|
166985
167301
|
for (;; ) {
|
|
@@ -166987,15 +167303,26 @@ async function embedSessionCompartmentChunks(db, projectIdentity, sessionId, opt
|
|
|
166987
167303
|
aborted2 = true;
|
|
166988
167304
|
break;
|
|
166989
167305
|
}
|
|
166990
|
-
const candidates = loadUnembeddedSessionChunkCandidates(db, projectIdentity, sessionId, snapshot.chunkModelId, batchSize, skipIds);
|
|
167306
|
+
const candidates = loadUnembeddedSessionChunkCandidates(db, projectIdentity, sessionId, snapshot.chunkModelId, batchSize, [...skipIds, ...failedIds]);
|
|
166991
167307
|
if (candidates.length === 0)
|
|
166992
167308
|
break;
|
|
166993
|
-
const {
|
|
167309
|
+
const {
|
|
167310
|
+
embedded: n,
|
|
167311
|
+
noWork,
|
|
167312
|
+
failed
|
|
167313
|
+
} = await embedCandidateChunkBatch(db, projectIdentity, snapshot.chunkModelId, candidates, options?.signal);
|
|
166994
167314
|
for (const id of noWork)
|
|
166995
167315
|
skipIds.push(id);
|
|
167316
|
+
for (const id of failed)
|
|
167317
|
+
failedIds.push(id);
|
|
166996
167318
|
if (n === 0 && noWork.length === 0) {
|
|
166997
|
-
|
|
166998
|
-
|
|
167319
|
+
consecutiveFailedBatches += 1;
|
|
167320
|
+
if (consecutiveFailedBatches >= MAX_CONSECUTIVE_FAILED_BATCHES) {
|
|
167321
|
+
providerDown = true;
|
|
167322
|
+
break;
|
|
167323
|
+
}
|
|
167324
|
+
} else {
|
|
167325
|
+
consecutiveFailedBatches = 0;
|
|
166999
167326
|
}
|
|
167000
167327
|
embedded += n;
|
|
167001
167328
|
options?.onProgress?.({ embedded: Math.min(embedded, total), total });
|
|
@@ -167003,23 +167330,58 @@ async function embedSessionCompartmentChunks(db, projectIdentity, sessionId, opt
|
|
|
167003
167330
|
}
|
|
167004
167331
|
} finally {
|
|
167005
167332
|
clearInterval(renewal);
|
|
167006
|
-
|
|
167333
|
+
try {
|
|
167334
|
+
releaseGitSweepLease(db, projectIdentity, holderId);
|
|
167335
|
+
} catch (error51) {
|
|
167336
|
+
log("[magic-context] embed drain: lease release failed (will TTL-expire):", error51);
|
|
167337
|
+
}
|
|
167007
167338
|
}
|
|
167008
167339
|
if (aborted2)
|
|
167009
|
-
return { status: "aborted", embedded, total };
|
|
167010
|
-
if (
|
|
167340
|
+
return { status: "aborted", embedded, total, failed: failedIds.length };
|
|
167341
|
+
if (providerDown || failedIds.length > 0) {
|
|
167011
167342
|
const remaining = Math.max(0, countUnembeddedSessionCompartments(db, projectIdentity, sessionId, snapshot.chunkModelId) - skipIds.length);
|
|
167012
|
-
if (remaining > 0)
|
|
167013
|
-
return { status: "stalled", embedded, total, remaining };
|
|
167343
|
+
if (remaining > 0) {
|
|
167344
|
+
return { status: "stalled", embedded, total, remaining, failed: failedIds.length };
|
|
167345
|
+
}
|
|
167014
167346
|
}
|
|
167015
|
-
return { status: "done", embedded, total };
|
|
167347
|
+
return { status: "done", embedded, total, failed: failedIds.length };
|
|
167016
167348
|
}
|
|
167017
|
-
|
|
167349
|
+
function getEmbeddingCoverageStatus(db, projectIdentity, sessionId) {
|
|
167350
|
+
const snapshot = getProjectEmbeddingSnapshot(projectIdentity);
|
|
167351
|
+
if (!snapshot?.enabled || snapshot.chunkModelId === "off") {
|
|
167352
|
+
return {
|
|
167353
|
+
enabled: false,
|
|
167354
|
+
model: snapshot?.model ?? "off",
|
|
167355
|
+
provider: snapshot?.provider ?? "off",
|
|
167356
|
+
session: { embedded: 0, total: 0 },
|
|
167357
|
+
memories: { embedded: 0, total: 0 },
|
|
167358
|
+
commits: { embedded: 0, total: 0, gitEnabled: false }
|
|
167359
|
+
};
|
|
167360
|
+
}
|
|
167361
|
+
const session = countSessionCompartmentEmbedCoverage(db, projectIdentity, sessionId, snapshot.chunkModelId);
|
|
167362
|
+
const memories = getMemoryEmbedCoverage(db, projectIdentity, snapshot.modelId);
|
|
167363
|
+
const gitEnabled = snapshot.gitCommitEnabled;
|
|
167364
|
+
const commits = gitEnabled ? {
|
|
167365
|
+
embedded: countEmbeddedCommits(db, projectIdentity),
|
|
167366
|
+
total: getCommitCount(db, projectIdentity),
|
|
167367
|
+
gitEnabled: true
|
|
167368
|
+
} : { embedded: 0, total: 0, gitEnabled: false };
|
|
167369
|
+
return {
|
|
167370
|
+
enabled: true,
|
|
167371
|
+
model: snapshot.model,
|
|
167372
|
+
provider: snapshot.provider,
|
|
167373
|
+
session,
|
|
167374
|
+
memories,
|
|
167375
|
+
commits
|
|
167376
|
+
};
|
|
167377
|
+
}
|
|
167378
|
+
var OFF_PROVIDER_IDENTITY = "embedding-provider:off", SWEEP_MAX_WALL_CLOCK_MS, CHUNK_DRAIN_BATCH_SIZE = 8, MAX_WINDOWS_PER_EMBED_CALL = 2, SESSION_EMBED_LEASE_RENEWAL_MS, EMBED_SLICE_RETRY_ATTEMPTS = 3, EMBED_SLICE_RETRY_BASE_MS = 250, EMBED_SLOW_FAILURE_NO_RETRY_MS = 1e4, MAX_CONSECUTIVE_FAILED_BATCHES = 3, projectRegistrations, loadUnembeddedMemoriesStatements, globalRegistrationGeneration = 0, testProviderFactory = null;
|
|
167018
167379
|
var init_project_embedding_registry = __esm(() => {
|
|
167019
167380
|
init_magic_context();
|
|
167020
167381
|
init_logger();
|
|
167021
167382
|
init_compartment_chunk_embedding();
|
|
167022
167383
|
init_storage_git_commit_embeddings();
|
|
167384
|
+
init_storage_git_commits();
|
|
167023
167385
|
init_sweep_coordinator();
|
|
167024
167386
|
init_embedding_cache();
|
|
167025
167387
|
init_embedding_identity();
|
|
@@ -167300,58 +167662,6 @@ var init_models_dev_cache = __esm(() => {
|
|
|
167300
167662
|
init_logger();
|
|
167301
167663
|
});
|
|
167302
167664
|
|
|
167303
|
-
// src/shared/rpc-notifications.ts
|
|
167304
|
-
var exports_rpc_notifications = {};
|
|
167305
|
-
__export(exports_rpc_notifications, {
|
|
167306
|
-
pushNotification: () => pushNotification,
|
|
167307
|
-
isTuiConnected: () => isTuiConnected,
|
|
167308
|
-
drainNotifications: () => drainNotifications
|
|
167309
|
-
});
|
|
167310
|
-
function pushNotification(type, payload, sessionId) {
|
|
167311
|
-
queue2.push({ id: nextNotificationId++, type, payload, sessionId });
|
|
167312
|
-
if (queue2.length > 100) {
|
|
167313
|
-
const newestPerSession = new Map;
|
|
167314
|
-
for (const n of queue2) {
|
|
167315
|
-
const prev = newestPerSession.get(n.sessionId);
|
|
167316
|
-
if (prev === undefined || n.id > prev) {
|
|
167317
|
-
newestPerSession.set(n.sessionId, n.id);
|
|
167318
|
-
}
|
|
167319
|
-
}
|
|
167320
|
-
const mustKeep = new Set(newestPerSession.values());
|
|
167321
|
-
const byNewest = [...queue2].sort((a, b) => b.id - a.id);
|
|
167322
|
-
const kept = [];
|
|
167323
|
-
for (const n of byNewest) {
|
|
167324
|
-
if (kept.length < 50 || mustKeep.has(n.id))
|
|
167325
|
-
kept.push(n);
|
|
167326
|
-
}
|
|
167327
|
-
queue2 = kept.sort((a, b) => a.id - b.id);
|
|
167328
|
-
}
|
|
167329
|
-
}
|
|
167330
|
-
function drainNotifications(lastReceivedId = 0, sessionId) {
|
|
167331
|
-
const now = Date.now();
|
|
167332
|
-
lastDrainAtAny = now;
|
|
167333
|
-
if (sessionId !== undefined)
|
|
167334
|
-
lastDrainAtBySession.set(sessionId, now);
|
|
167335
|
-
const matchesClient = (notification) => sessionId === undefined || notification.sessionId === undefined || notification.sessionId === sessionId;
|
|
167336
|
-
if (lastReceivedId > 0) {
|
|
167337
|
-
queue2 = queue2.filter((notification) => !(notification.id <= lastReceivedId && matchesClient(notification)));
|
|
167338
|
-
}
|
|
167339
|
-
return queue2.filter((notification) => notification.id > lastReceivedId && matchesClient(notification));
|
|
167340
|
-
}
|
|
167341
|
-
function isTuiConnected(sessionId) {
|
|
167342
|
-
const now = Date.now();
|
|
167343
|
-
if (sessionId !== undefined) {
|
|
167344
|
-
const at = lastDrainAtBySession.get(sessionId) ?? 0;
|
|
167345
|
-
return at > 0 && now - at < TUI_CONNECTED_WINDOW_MS;
|
|
167346
|
-
}
|
|
167347
|
-
return lastDrainAtAny > 0 && now - lastDrainAtAny < TUI_CONNECTED_WINDOW_MS;
|
|
167348
|
-
}
|
|
167349
|
-
var queue2, nextNotificationId = 1, lastDrainAtBySession, lastDrainAtAny = 0, TUI_CONNECTED_WINDOW_MS = 3000;
|
|
167350
|
-
var init_rpc_notifications = __esm(() => {
|
|
167351
|
-
queue2 = [];
|
|
167352
|
-
lastDrainAtBySession = new Map;
|
|
167353
|
-
});
|
|
167354
|
-
|
|
167355
167665
|
// src/features/magic-context/compartment-embedding.ts
|
|
167356
167666
|
async function embedAndStoreCompartmentChunks(db, sessionId, projectPath, compartments) {
|
|
167357
167667
|
if (compartments.length === 0)
|
|
@@ -170903,7 +171213,7 @@ function buildToolArcs(messages) {
|
|
|
170903
171213
|
}
|
|
170904
171214
|
return arcs.sort((a, b) => a.invOrdinal - b.invOrdinal || (a.resOrdinal ?? Number.MAX_SAFE_INTEGER) - (b.resOrdinal ?? Number.MAX_SAFE_INTEGER));
|
|
170905
171215
|
}
|
|
170906
|
-
function fenceBoundaryForToolArcs(candidate, arcs, lastCompartmentEndOrdinal) {
|
|
171216
|
+
function fenceBoundaryForToolArcs(candidate, arcs, lastCompartmentEndOrdinal, recentOpenArcCutoff) {
|
|
170907
171217
|
let boundary = candidate;
|
|
170908
171218
|
for (const arc of arcs) {
|
|
170909
171219
|
if (arc.resOrdinal !== null) {
|
|
@@ -170912,6 +171222,8 @@ function fenceBoundaryForToolArcs(candidate, arcs, lastCompartmentEndOrdinal) {
|
|
|
170912
171222
|
}
|
|
170913
171223
|
continue;
|
|
170914
171224
|
}
|
|
171225
|
+
if (arc.invOrdinal < recentOpenArcCutoff)
|
|
171226
|
+
continue;
|
|
170915
171227
|
if (arc.invOrdinal >= lastCompartmentEndOrdinal + 1 && arc.invOrdinal < boundary) {
|
|
170916
171228
|
return arc.invOrdinal;
|
|
170917
171229
|
}
|
|
@@ -171151,7 +171463,7 @@ function semanticSnapBoundary(args) {
|
|
|
171151
171463
|
return snapped;
|
|
171152
171464
|
}
|
|
171153
171465
|
function applyHeadCap(args) {
|
|
171154
|
-
const { index, protectedTailStart, offset, arcs, capTokens } = args;
|
|
171466
|
+
const { index, protectedTailStart, offset, arcs, capTokens, recentOpenArcCutoff } = args;
|
|
171155
171467
|
if (offset >= protectedTailStart)
|
|
171156
171468
|
return { eligibleEndOrdinal: offset, oversizeAtomicUnit: false };
|
|
171157
171469
|
let end = index.findHeadEndForCap(offset, protectedTailStart, capTokens);
|
|
@@ -171159,7 +171471,7 @@ function applyHeadCap(args) {
|
|
|
171159
171471
|
for (const arc of arcs) {
|
|
171160
171472
|
const resOrdinal = arc.resOrdinal;
|
|
171161
171473
|
if (resOrdinal === null) {
|
|
171162
|
-
if (arc.invOrdinal >= offset && arc.invOrdinal < end) {
|
|
171474
|
+
if (arc.invOrdinal >= recentOpenArcCutoff && arc.invOrdinal >= offset && arc.invOrdinal < end) {
|
|
171163
171475
|
end = Math.min(end, arc.invOrdinal);
|
|
171164
171476
|
}
|
|
171165
171477
|
continue;
|
|
@@ -171226,7 +171538,14 @@ function resolveProtectedTailBoundary(ctx) {
|
|
|
171226
171538
|
}
|
|
171227
171539
|
if (ctx.mode === "manual-full-recomp") {
|
|
171228
171540
|
const arcs2 = buildToolArcs(messages);
|
|
171229
|
-
const
|
|
171541
|
+
const recompTarget = deriveProtectedTailTokenTarget({
|
|
171542
|
+
contextLimit: ctx.contextLimit,
|
|
171543
|
+
executeThresholdPercentage: ctx.executeThresholdPercentage,
|
|
171544
|
+
usagePercentage: 0,
|
|
171545
|
+
triggerBudget: ctx.triggerBudget
|
|
171546
|
+
});
|
|
171547
|
+
const recentOpenArcCutoff2 = index.findSuffixStartForTokens(recompTarget.N);
|
|
171548
|
+
const firstOpenArc = arcs2.find((arc) => arc.resOrdinal === null && arc.invOrdinal >= offset && arc.invOrdinal >= recentOpenArcCutoff2);
|
|
171230
171549
|
const protectedTailStart2 = firstOpenArc?.invOrdinal ?? rawMessageCount + 1;
|
|
171231
171550
|
const rawRangeFingerprint2 = computeRawRangeFingerprint(messages, offset, protectedTailStart2);
|
|
171232
171551
|
return {
|
|
@@ -171268,13 +171587,14 @@ function resolveProtectedTailBoundary(ctx) {
|
|
|
171268
171587
|
const scaledN = ctx.emergencyTailScale ? Math.max(1, Math.floor(target.N * ctx.emergencyTailScale)) : target.N;
|
|
171269
171588
|
const arcs = buildToolArcs(messages);
|
|
171270
171589
|
let boundary = index.findSuffixStartForTokens(scaledN);
|
|
171590
|
+
const recentOpenArcCutoff = boundary;
|
|
171271
171591
|
let boundaryReason = boundary === 1 ? "whole-session-smaller-than-tail" : "size-walk";
|
|
171272
171592
|
const tokenAtBoundary = index.tokenForOrdinal(boundary);
|
|
171273
171593
|
if (boundary <= rawMessageCount && tokenAtBoundary > Math.max(2 * scaledN, 64000) && boundary < rawMessageCount) {
|
|
171274
171594
|
boundary += 1;
|
|
171275
171595
|
boundaryReason = "huge-message-exception";
|
|
171276
171596
|
}
|
|
171277
|
-
boundary = fenceBoundaryForToolArcs(boundary, arcs, ctx.lastCompartmentEndOrdinal);
|
|
171597
|
+
boundary = fenceBoundaryForToolArcs(boundary, arcs, ctx.lastCompartmentEndOrdinal, recentOpenArcCutoff);
|
|
171278
171598
|
const snapped = semanticSnapBoundary({
|
|
171279
171599
|
messages,
|
|
171280
171600
|
index,
|
|
@@ -171284,7 +171604,7 @@ function resolveProtectedTailBoundary(ctx) {
|
|
|
171284
171604
|
});
|
|
171285
171605
|
if (snapped !== boundary)
|
|
171286
171606
|
boundaryReason = "semantic-snap";
|
|
171287
|
-
boundary = fenceBoundaryForToolArcs(snapped, arcs, ctx.lastCompartmentEndOrdinal);
|
|
171607
|
+
boundary = fenceBoundaryForToolArcs(snapped, arcs, ctx.lastCompartmentEndOrdinal, recentOpenArcCutoff);
|
|
171288
171608
|
let runtimeFloor = offset;
|
|
171289
171609
|
if (ctx.migrationFloorActive)
|
|
171290
171610
|
runtimeFloor = Math.max(runtimeFloor, ctx.priorBoundaryOrdinal);
|
|
@@ -171320,7 +171640,8 @@ function resolveProtectedTailBoundary(ctx) {
|
|
|
171320
171640
|
offset,
|
|
171321
171641
|
arcs,
|
|
171322
171642
|
lastCompartmentEndOrdinal: ctx.lastCompartmentEndOrdinal,
|
|
171323
|
-
capTokens: perRunCap
|
|
171643
|
+
capTokens: perRunCap,
|
|
171644
|
+
recentOpenArcCutoff
|
|
171324
171645
|
});
|
|
171325
171646
|
const rawRangeFingerprint = computeRawRangeFingerprint(messages, offset, head.eligibleEndOrdinal);
|
|
171326
171647
|
return {
|
|
@@ -177249,15 +177570,15 @@ function shouldShowAnnouncement() {
|
|
|
177249
177570
|
}
|
|
177250
177571
|
return state.version !== ANNOUNCEMENT_VERSION;
|
|
177251
177572
|
}
|
|
177252
|
-
var ANNOUNCEMENT_VERSION = "0.
|
|
177573
|
+
var ANNOUNCEMENT_VERSION = "0.25.0", ANNOUNCEMENT_FEATURES, ANNOUNCEMENT_FOOTER = "Join us on Discord: https://discord.gg/F2uWxjGnU", STATE_FILENAME = "last_announced_version";
|
|
177253
177574
|
var init_announcement = __esm(() => {
|
|
177254
177575
|
init_data_path();
|
|
177255
177576
|
ANNOUNCEMENT_FEATURES = [
|
|
177256
|
-
"
|
|
177257
|
-
"
|
|
177258
|
-
"
|
|
177259
|
-
"
|
|
177260
|
-
"
|
|
177577
|
+
"Old tool output is now reclaimed automatically: once a file read / search / command output has gone a full execute cycle unused, it's dropped on the next one — no need to call ctx_reduce for stale results.",
|
|
177578
|
+
"Recover anything that was dropped: ctx_expand({ message: N }) returns a dropped message's full content (every tool call's input + output) from storage. ctx_expand({ start, end, verbose: true }) lists a range message-by-message to find it.",
|
|
177579
|
+
"Searchable history made reliable: /ctx-embed shows embedding coverage and runs a resilient backfill (retries transient failures, no longer bails on the first hiccup); the active session now auto-embeds in the background. ctx_reduce guidance also reframed as deferred + recoverable so models trim spent output earlier.",
|
|
177580
|
+
"Pi: fixed /ctx-dream (was failing with 'Unknown named parameter') and local-embedding load failures on Windows/Desktop (#151, #128).",
|
|
177581
|
+
"Runaway background agents on weak/local models are now capped and force-stopped (#154, #152). Plus several prompt-cache busts removed."
|
|
177261
177582
|
];
|
|
177262
177583
|
});
|
|
177263
177584
|
// src/agents/permissions.ts
|
|
@@ -177986,9 +178307,9 @@ function getMagicContextBuiltinCommands() {
|
|
|
177986
178307
|
template: "ctx-dream",
|
|
177987
178308
|
description: "Run the hidden dreamer maintenance pass for this project now"
|
|
177988
178309
|
},
|
|
177989
|
-
"ctx-embed
|
|
177990
|
-
template: "ctx-embed
|
|
177991
|
-
description: "
|
|
178310
|
+
"ctx-embed": {
|
|
178311
|
+
template: "ctx-embed",
|
|
178312
|
+
description: "Embedding status, or start/pause history compartment embedding (start | pause)"
|
|
177992
178313
|
}
|
|
177993
178314
|
};
|
|
177994
178315
|
}
|
|
@@ -178859,7 +179180,7 @@ function enqueueDream(db, projectIdentity, reason, force = false) {
|
|
|
178859
179180
|
return db.transaction(() => {
|
|
178860
179181
|
if (!hasActiveDreamLease(db)) {
|
|
178861
179182
|
const staleThresholdMs = force ? 2 * 60 * 1000 : 120 * 60 * 1000;
|
|
178862
|
-
db.prepare("DELETE FROM dream_queue WHERE project_path = ? AND started_at IS NOT NULL AND started_at < ?").run(
|
|
179183
|
+
db.prepare("DELETE FROM dream_queue WHERE project_path = ? AND started_at IS NOT NULL AND started_at < ?").run(projectIdentity, now - staleThresholdMs);
|
|
178863
179184
|
}
|
|
178864
179185
|
const existing = db.prepare("SELECT id FROM dream_queue WHERE project_path = ?").get(projectIdentity);
|
|
178865
179186
|
if (existing) {
|
|
@@ -180554,120 +180875,7 @@ ${body}` : subject;
|
|
|
180554
180875
|
init_logger();
|
|
180555
180876
|
init_embedding();
|
|
180556
180877
|
init_storage_git_commit_embeddings();
|
|
180557
|
-
|
|
180558
|
-
// src/features/magic-context/git-commits/storage-git-commits.ts
|
|
180559
|
-
init_logger();
|
|
180560
|
-
var insertStatements = new WeakMap;
|
|
180561
|
-
var existingShasStatements = new WeakMap;
|
|
180562
|
-
var projectCountStatements = new WeakMap;
|
|
180563
|
-
var evictStatements = new WeakMap;
|
|
180564
|
-
var evictOverflowStatements = new WeakMap;
|
|
180565
|
-
var latestCommitTimeStatements = new WeakMap;
|
|
180566
|
-
function getInsertStatement(db) {
|
|
180567
|
-
let stmt = insertStatements.get(db);
|
|
180568
|
-
if (!stmt) {
|
|
180569
|
-
stmt = db.prepare(`INSERT INTO git_commits (sha, project_path, short_sha, message, author, committed_at, indexed_at)
|
|
180570
|
-
VALUES (?, ?, ?, ?, ?, ?, ?)
|
|
180571
|
-
ON CONFLICT(sha) DO UPDATE SET
|
|
180572
|
-
project_path = excluded.project_path,
|
|
180573
|
-
short_sha = excluded.short_sha,
|
|
180574
|
-
message = excluded.message,
|
|
180575
|
-
author = excluded.author,
|
|
180576
|
-
committed_at = excluded.committed_at,
|
|
180577
|
-
indexed_at = excluded.indexed_at
|
|
180578
|
-
WHERE git_commits.message != excluded.message`);
|
|
180579
|
-
insertStatements.set(db, stmt);
|
|
180580
|
-
}
|
|
180581
|
-
return stmt;
|
|
180582
|
-
}
|
|
180583
|
-
function getExistingShasStatement(db) {
|
|
180584
|
-
let stmt = existingShasStatements.get(db);
|
|
180585
|
-
if (!stmt) {
|
|
180586
|
-
stmt = db.prepare("SELECT sha FROM git_commits WHERE project_path = ?");
|
|
180587
|
-
existingShasStatements.set(db, stmt);
|
|
180588
|
-
}
|
|
180589
|
-
return stmt;
|
|
180590
|
-
}
|
|
180591
|
-
function getProjectCountStatement(db) {
|
|
180592
|
-
let stmt = projectCountStatements.get(db);
|
|
180593
|
-
if (!stmt) {
|
|
180594
|
-
stmt = db.prepare("SELECT COUNT(*) AS count FROM git_commits WHERE project_path = ?");
|
|
180595
|
-
projectCountStatements.set(db, stmt);
|
|
180596
|
-
}
|
|
180597
|
-
return stmt;
|
|
180598
|
-
}
|
|
180599
|
-
function getLatestCommitTimeStatement(db) {
|
|
180600
|
-
let stmt = latestCommitTimeStatements.get(db);
|
|
180601
|
-
if (!stmt) {
|
|
180602
|
-
stmt = db.prepare("SELECT MAX(committed_at) AS latest FROM git_commits WHERE project_path = ?");
|
|
180603
|
-
latestCommitTimeStatements.set(db, stmt);
|
|
180604
|
-
}
|
|
180605
|
-
return stmt;
|
|
180606
|
-
}
|
|
180607
|
-
function getEvictOverflowStatement(db) {
|
|
180608
|
-
let stmt = evictOverflowStatements.get(db);
|
|
180609
|
-
if (!stmt) {
|
|
180610
|
-
stmt = db.prepare(`DELETE FROM git_commits
|
|
180611
|
-
WHERE rowid IN (
|
|
180612
|
-
SELECT rowid FROM git_commits
|
|
180613
|
-
WHERE project_path = ?
|
|
180614
|
-
ORDER BY committed_at DESC, sha DESC
|
|
180615
|
-
LIMIT -1 OFFSET ?
|
|
180616
|
-
)`);
|
|
180617
|
-
evictOverflowStatements.set(db, stmt);
|
|
180618
|
-
}
|
|
180619
|
-
return stmt;
|
|
180620
|
-
}
|
|
180621
|
-
function upsertCommits(db, projectPath, commits) {
|
|
180622
|
-
if (commits.length === 0)
|
|
180623
|
-
return { inserted: 0, updated: 0 };
|
|
180624
|
-
const existing = new Set;
|
|
180625
|
-
for (const row of getExistingShasStatement(db).all(projectPath)) {
|
|
180626
|
-
existing.add(row.sha);
|
|
180627
|
-
}
|
|
180628
|
-
let inserted = 0;
|
|
180629
|
-
let updated = 0;
|
|
180630
|
-
const now = Date.now();
|
|
180631
|
-
const insertStmt = getInsertStatement(db);
|
|
180632
|
-
db.transaction(() => {
|
|
180633
|
-
for (const commit of commits) {
|
|
180634
|
-
const result = insertStmt.run(commit.sha, projectPath, commit.shortSha, commit.message, commit.author, commit.committedAtMs, now);
|
|
180635
|
-
if (result.changes > 0) {
|
|
180636
|
-
if (existing.has(commit.sha)) {
|
|
180637
|
-
updated++;
|
|
180638
|
-
} else {
|
|
180639
|
-
inserted++;
|
|
180640
|
-
existing.add(commit.sha);
|
|
180641
|
-
}
|
|
180642
|
-
}
|
|
180643
|
-
}
|
|
180644
|
-
})();
|
|
180645
|
-
return { inserted, updated };
|
|
180646
|
-
}
|
|
180647
|
-
function getCommitCount(db, projectPath) {
|
|
180648
|
-
const row = getProjectCountStatement(db).get(projectPath);
|
|
180649
|
-
return row?.count ?? 0;
|
|
180650
|
-
}
|
|
180651
|
-
function getLatestIndexedCommitTimeMs(db, projectPath) {
|
|
180652
|
-
const row = getLatestCommitTimeStatement(db).get(projectPath);
|
|
180653
|
-
return row?.latest ?? null;
|
|
180654
|
-
}
|
|
180655
|
-
function enforceProjectCap(db, projectPath, maxCommits) {
|
|
180656
|
-
if (maxCommits <= 0)
|
|
180657
|
-
return 0;
|
|
180658
|
-
const count = getCommitCount(db, projectPath);
|
|
180659
|
-
if (count <= maxCommits)
|
|
180660
|
-
return 0;
|
|
180661
|
-
getEvictOverflowStatement(db).run(projectPath, maxCommits);
|
|
180662
|
-
const after = getCommitCount(db, projectPath);
|
|
180663
|
-
const evicted = Math.max(0, count - after);
|
|
180664
|
-
if (evicted > 0) {
|
|
180665
|
-
log(`[git-commits] evicted ${evicted} oldest commits for project ${projectPath} (cap=${maxCommits}, was=${count})`);
|
|
180666
|
-
}
|
|
180667
|
-
return evicted;
|
|
180668
|
-
}
|
|
180669
|
-
|
|
180670
|
-
// src/features/magic-context/git-commits/indexer.ts
|
|
180878
|
+
init_storage_git_commits();
|
|
180671
180879
|
var MS_PER_DAY = 24 * 60 * 60 * 1000;
|
|
180672
180880
|
var EMBED_BATCH_SIZE = 16;
|
|
180673
180881
|
var EMBED_MAX_PER_SWEEP = 500;
|
|
@@ -180905,6 +181113,7 @@ function searchGitCommitsSync(db, projectPath, query, options) {
|
|
|
180905
181113
|
|
|
180906
181114
|
// src/features/magic-context/git-commits/index.ts
|
|
180907
181115
|
init_storage_git_commit_embeddings();
|
|
181116
|
+
init_storage_git_commits();
|
|
180908
181117
|
init_sweep_coordinator();
|
|
180909
181118
|
|
|
180910
181119
|
// src/plugin/dream-timer.ts
|
|
@@ -182328,7 +182537,7 @@ function createMagicContextCommandHandler(deps) {
|
|
|
182328
182537
|
const isAugCommand = (command) => command === "ctx-aug";
|
|
182329
182538
|
const isDreamCommand = (command) => command === "ctx-dream";
|
|
182330
182539
|
const isSessionUpgradeCommand = (command) => command === "ctx-session-upgrade";
|
|
182331
|
-
const
|
|
182540
|
+
const isEmbedCommand = (command) => command === "ctx-embed";
|
|
182332
182541
|
return {
|
|
182333
182542
|
"command.execute.before": async (input, _output, _params) => {
|
|
182334
182543
|
const isStatus = isStatusCommand(input.command);
|
|
@@ -182337,8 +182546,8 @@ function createMagicContextCommandHandler(deps) {
|
|
|
182337
182546
|
const isAug = isAugCommand(input.command);
|
|
182338
182547
|
const isDream = isDreamCommand(input.command);
|
|
182339
182548
|
const isSessionUpgrade = isSessionUpgradeCommand(input.command);
|
|
182340
|
-
const
|
|
182341
|
-
if (!isStatus && !isFlush && !isRecomp && !isAug && !isDream && !isSessionUpgrade && !
|
|
182549
|
+
const isEmbed = isEmbedCommand(input.command);
|
|
182550
|
+
if (!isStatus && !isFlush && !isRecomp && !isAug && !isDream && !isSessionUpgrade && !isEmbed) {
|
|
182342
182551
|
return;
|
|
182343
182552
|
}
|
|
182344
182553
|
const sessionId = input.sessionID;
|
|
@@ -182351,15 +182560,50 @@ function createMagicContextCommandHandler(deps) {
|
|
|
182351
182560
|
await executeDreaming(deps, sessionId);
|
|
182352
182561
|
return;
|
|
182353
182562
|
}
|
|
182354
|
-
if (
|
|
182355
|
-
const
|
|
182356
|
-
|
|
182357
|
-
|
|
182563
|
+
if (isEmbed) {
|
|
182564
|
+
const sub = input.arguments.trim().toLowerCase();
|
|
182565
|
+
if (sub === "pause") {
|
|
182566
|
+
const summary = deps.pauseEmbedDrain ? deps.pauseEmbedDrain(sessionId) : "Embedding pause is unavailable.";
|
|
182567
|
+
if (isTuiConnected(sessionId)) {
|
|
182568
|
+
pushNotification("action", { action: "show-result-dialog", title: "Embed", message: summary }, sessionId);
|
|
182569
|
+
} else {
|
|
182570
|
+
await deps.sendNotification(sessionId, summary, {});
|
|
182571
|
+
}
|
|
182572
|
+
throwSentinel(input.command);
|
|
182573
|
+
}
|
|
182574
|
+
if (sub === "start") {
|
|
182575
|
+
const summary = deps.executeEmbedHistory ? await deps.executeEmbedHistory(sessionId) : "Semantic embedding is not configured for this project, so there is nothing to embed.";
|
|
182576
|
+
if (isTuiConnected(sessionId)) {
|
|
182577
|
+
pushNotification("action", { action: "show-result-dialog", title: "Embed", message: summary }, sessionId);
|
|
182578
|
+
} else {
|
|
182579
|
+
await deps.sendNotification(sessionId, summary, {});
|
|
182580
|
+
}
|
|
182581
|
+
throwSentinel(input.command);
|
|
182582
|
+
}
|
|
182583
|
+
if (sub !== "") {
|
|
182584
|
+
await deps.sendNotification(sessionId, "Usage: `/ctx-embed` (status), `/ctx-embed start`, or `/ctx-embed pause`.", {});
|
|
182585
|
+
throwSentinel(input.command);
|
|
182586
|
+
}
|
|
182587
|
+
if (isTuiConnected(sessionId)) {
|
|
182588
|
+
pushNotification("action", { action: "show-embed-dialog" }, sessionId);
|
|
182589
|
+
sessionLog(sessionId, "command ctx-embed: pushed show-embed-dialog to TUI");
|
|
182590
|
+
throwSentinel(input.command);
|
|
182591
|
+
}
|
|
182592
|
+
result = deps.getEmbedStatusText ? `## Embedding Status
|
|
182593
|
+
|
|
182594
|
+
${deps.getEmbedStatusText(sessionId)}` : `## Embedding Status
|
|
182595
|
+
|
|
182596
|
+
Embedding status is unavailable.`;
|
|
182358
182597
|
}
|
|
182359
182598
|
if (isFlush) {
|
|
182360
182599
|
result = executeFlush(deps.db, sessionId);
|
|
182361
182600
|
clearCachedM0M1(deps.db, sessionId);
|
|
182362
182601
|
deps.onFlush?.(sessionId);
|
|
182602
|
+
if (isTuiConnected(sessionId)) {
|
|
182603
|
+
pushNotification("action", { action: "show-flush-dialog", message: result }, sessionId);
|
|
182604
|
+
sessionLog(sessionId, "command ctx-flush: pushed show-flush-dialog to TUI");
|
|
182605
|
+
throwSentinel(input.command);
|
|
182606
|
+
}
|
|
182363
182607
|
}
|
|
182364
182608
|
if (isStatus) {
|
|
182365
182609
|
if (isTuiConnected(sessionId)) {
|
|
@@ -182486,6 +182730,34 @@ ${snap.error}`;
|
|
|
182486
182730
|
// src/hooks/magic-context/hook.ts
|
|
182487
182731
|
init_derive_budgets();
|
|
182488
182732
|
|
|
182733
|
+
// src/hooks/magic-context/embed-session-state.ts
|
|
182734
|
+
var embedPauseBySession = new Set;
|
|
182735
|
+
var embedRunStateBySession = new Map;
|
|
182736
|
+
var autoEmbedAttemptedBySession = new Set;
|
|
182737
|
+
function getEmbedDrainUiStatus(sessionId, progress) {
|
|
182738
|
+
if (embedPauseBySession.has(sessionId)) {
|
|
182739
|
+
return { status: "paused" };
|
|
182740
|
+
}
|
|
182741
|
+
if (progress?.kind === "embed" && progress.phase === "recomp") {
|
|
182742
|
+
return { status: "running" };
|
|
182743
|
+
}
|
|
182744
|
+
if (progress?.kind === "embed" && (progress.phase === "failed" || progress.phase === "skipped") && progress.message) {
|
|
182745
|
+
if (/provider/i.test(progress.message)) {
|
|
182746
|
+
return { status: "stopped", detail: progress.message };
|
|
182747
|
+
}
|
|
182748
|
+
}
|
|
182749
|
+
return { status: "idle" };
|
|
182750
|
+
}
|
|
182751
|
+
function clearEmbedSessionState(sessionId) {
|
|
182752
|
+
embedPauseBySession.delete(sessionId);
|
|
182753
|
+
const ctrl = embedRunStateBySession.get(sessionId);
|
|
182754
|
+
if (ctrl) {
|
|
182755
|
+
ctrl.abort();
|
|
182756
|
+
embedRunStateBySession.delete(sessionId);
|
|
182757
|
+
}
|
|
182758
|
+
autoEmbedAttemptedBySession.delete(sessionId);
|
|
182759
|
+
}
|
|
182760
|
+
|
|
182489
182761
|
// src/features/magic-context/message-index-async.ts
|
|
182490
182762
|
init_logger();
|
|
182491
182763
|
await init_message_index();
|
|
@@ -182846,6 +183118,13 @@ function computePressure(input) {
|
|
|
182846
183118
|
function approxThousands(tokens) {
|
|
182847
183119
|
return `${Math.round(tokens / 1000)}k`;
|
|
182848
183120
|
}
|
|
183121
|
+
function formatOldestReclaimableHint(hint) {
|
|
183122
|
+
if (!hint || hint.length === 0)
|
|
183123
|
+
return "";
|
|
183124
|
+
const rendered = hint.slice(0, 4).map((tag) => `§${tag.tagNumber}§ ${tag.toolName ?? "tool"}`).join(" · ");
|
|
183125
|
+
return rendered.length > 0 ? `
|
|
183126
|
+
oldest reclaimable: ${rendered}.` : "";
|
|
183127
|
+
}
|
|
182849
183128
|
var CHANNEL2_USABLE_FRACTION = 1 / 3;
|
|
182850
183129
|
var CHANNEL2_MIN_RECLAIMABLE = 1e4;
|
|
182851
183130
|
function shouldTriggerChannel2(input) {
|
|
@@ -182855,14 +183134,16 @@ function shouldTriggerChannel2(input) {
|
|
|
182855
183134
|
return true;
|
|
182856
183135
|
return input.reclaimableTokens >= input.usableTokens * CHANNEL2_USABLE_FRACTION;
|
|
182857
183136
|
}
|
|
182858
|
-
function buildChannel2Reminder(undroppedTokens) {
|
|
183137
|
+
function buildChannel2Reminder(undroppedTokens, hint) {
|
|
182859
183138
|
const amount = approxThousands(undroppedTokens);
|
|
183139
|
+
const hintText = formatOldestReclaimableHint(hint);
|
|
182860
183140
|
return `<system-reminder>
|
|
182861
|
-
` + `Routine context housekeeping is near: a large span of this session will be comparted soon, ` + `and ~${amount} tokens of tool output remain unreduced. Drop spent outputs with ctx_reduce ` + `first so the archived span is the part that matters
|
|
183141
|
+
` + `Routine context housekeeping is near: a large span of this session will be comparted soon, ` + `and ~${amount} tokens of tool output remain unreduced. Drop spent outputs with ctx_reduce ` + `first so the archived span is the part that matters.${hintText}
|
|
182862
183142
|
` + `</system-reminder>`;
|
|
182863
183143
|
}
|
|
182864
|
-
function buildChannel1Reminder(level, undroppedTokens) {
|
|
183144
|
+
function buildChannel1Reminder(level, undroppedTokens, hint) {
|
|
182865
183145
|
const amount = approxThousands(undroppedTokens);
|
|
183146
|
+
const hintText = formatOldestReclaimableHint(hint);
|
|
182866
183147
|
let body;
|
|
182867
183148
|
switch (level) {
|
|
182868
183149
|
case "gentle":
|
|
@@ -182878,7 +183159,7 @@ function buildChannel1Reminder(level, undroppedTokens) {
|
|
|
182878
183159
|
return `
|
|
182879
183160
|
|
|
182880
183161
|
<system-reminder>
|
|
182881
|
-
${body}
|
|
183162
|
+
${body}${hintText}
|
|
182882
183163
|
</system-reminder>`;
|
|
182883
183164
|
}
|
|
182884
183165
|
|
|
@@ -182932,10 +183213,10 @@ async function maybeDeliverChannel2(sessionId, deps) {
|
|
|
182932
183213
|
try {
|
|
182933
183214
|
const client3 = getLiveServerClient(serverUrl, deps.directory);
|
|
182934
183215
|
const promptContext = await resolvePromptContext(client3, sessionId);
|
|
182935
|
-
const reminder = buildChannel2Reminder(deps.reclaimableTokens);
|
|
183216
|
+
const reminder = buildChannel2Reminder(deps.reclaimableTokens, deps.oldestReclaimableToolTags);
|
|
182936
183217
|
const body = {
|
|
182937
183218
|
noReply: false,
|
|
182938
|
-
parts: [{ type: "text", text: reminder }]
|
|
183219
|
+
parts: [{ type: "text", text: reminder, synthetic: true }]
|
|
182939
183220
|
};
|
|
182940
183221
|
if (promptContext?.agent)
|
|
182941
183222
|
body.agent = promptContext.agent;
|
|
@@ -183393,7 +183674,8 @@ function applyCavemanCleanup(sessionId, db, targets, tags, config2) {
|
|
|
183393
183674
|
const result = {
|
|
183394
183675
|
compressedToLite: 0,
|
|
183395
183676
|
compressedToFull: 0,
|
|
183396
|
-
compressedToUltra: 0
|
|
183677
|
+
compressedToUltra: 0,
|
|
183678
|
+
mutatedTextTags: 0
|
|
183397
183679
|
};
|
|
183398
183680
|
if (!config2.enabled)
|
|
183399
183681
|
return result;
|
|
@@ -183434,7 +183716,9 @@ function applyCavemanCleanup(sessionId, db, targets, tags, config2) {
|
|
|
183434
183716
|
const target = targets.get(tag.tagNumber);
|
|
183435
183717
|
if (!target)
|
|
183436
183718
|
continue;
|
|
183437
|
-
target.setContent(compressed);
|
|
183719
|
+
const didMutate = target.setContent(compressed);
|
|
183720
|
+
if (didMutate)
|
|
183721
|
+
result.mutatedTextTags += 1;
|
|
183438
183722
|
updateCavemanDepth(db, sessionId, tag.tagNumber, targetDepth);
|
|
183439
183723
|
if (targetDepth === DEPTH_LITE)
|
|
183440
183724
|
result.compressedToLite += 1;
|
|
@@ -184022,28 +184306,6 @@ function stripInlineThinking(messages, messageTagNumbers, clearReasoningAge) {
|
|
|
184022
184306
|
}
|
|
184023
184307
|
return stripped;
|
|
184024
184308
|
}
|
|
184025
|
-
function truncateErroredTools(messages, watermark, messageTagNumbers) {
|
|
184026
|
-
let truncated = 0;
|
|
184027
|
-
for (let i = 0;i < messages.length; i++) {
|
|
184028
|
-
const maxTag = messageTagNumbers.get(messages[i]) ?? 0;
|
|
184029
|
-
if (maxTag > watermark) {
|
|
184030
|
-
continue;
|
|
184031
|
-
}
|
|
184032
|
-
for (const part of messages[i].parts) {
|
|
184033
|
-
if (!isRecord(part) || part.type !== "tool" || !isRecord(part.state)) {
|
|
184034
|
-
continue;
|
|
184035
|
-
}
|
|
184036
|
-
if (part.state.status !== "error") {
|
|
184037
|
-
continue;
|
|
184038
|
-
}
|
|
184039
|
-
if (typeof part.state.error === "string" && part.state.error.length > 100) {
|
|
184040
|
-
part.state.error = `${part.state.error.slice(0, 100)}... [truncated]`;
|
|
184041
|
-
truncated++;
|
|
184042
|
-
}
|
|
184043
|
-
}
|
|
184044
|
-
}
|
|
184045
|
-
return truncated;
|
|
184046
|
-
}
|
|
184047
184309
|
var REASONING_IGNORED_PART_TYPES = new Set([
|
|
184048
184310
|
"step-start",
|
|
184049
184311
|
"step-finish",
|
|
@@ -184461,78 +184723,11 @@ function appendReminderToUserMessage(message, reminder) {
|
|
|
184461
184723
|
|
|
184462
184724
|
// src/hooks/magic-context/apply-operations.ts
|
|
184463
184725
|
await init_storage();
|
|
184464
|
-
|
|
184465
|
-
// src/hooks/magic-context/system-injection-stripper.ts
|
|
184466
|
-
var SYSTEM_INJECTION_MARKERS = [
|
|
184467
|
-
"<!-- OMO_INTERNAL_INITIATOR -->",
|
|
184468
|
-
"[SYSTEM DIRECTIVE: MAGIC-CONTEXT",
|
|
184469
|
-
"[SYSTEM DIRECTIVE: OH-MY-OPENCODE",
|
|
184470
|
-
"[Category+Skill Reminder]",
|
|
184471
|
-
"[EDIT ERROR - IMMEDIATE ACTION REQUIRED]",
|
|
184472
|
-
"[task CALL FAILED - IMMEDIATE RETRY REQUIRED]",
|
|
184473
|
-
"[EMERGENCY CONTEXT WINDOW WARNING]",
|
|
184474
|
-
"Unstable background agent appears idle",
|
|
184475
|
-
"**THE SUBAGENT JUST CLAIMED THIS TASK IS DONE."
|
|
184476
|
-
];
|
|
184477
|
-
var SYSTEM_REMINDER_REGEX = /<system-reminder>[\s\S]*?<\/system-reminder>/gi;
|
|
184478
|
-
var OMO_MARKER_REGEX = /<!-- OMO_INTERNAL_INITIATOR -->/g;
|
|
184479
|
-
function stripSystemInjection(text) {
|
|
184480
|
-
let hasInjection = false;
|
|
184481
|
-
for (const marker of SYSTEM_INJECTION_MARKERS) {
|
|
184482
|
-
if (text.includes(marker)) {
|
|
184483
|
-
hasInjection = true;
|
|
184484
|
-
break;
|
|
184485
|
-
}
|
|
184486
|
-
}
|
|
184487
|
-
if (SYSTEM_REMINDER_REGEX.test(text))
|
|
184488
|
-
hasInjection = true;
|
|
184489
|
-
SYSTEM_REMINDER_REGEX.lastIndex = 0;
|
|
184490
|
-
if (!hasInjection)
|
|
184491
|
-
return null;
|
|
184492
|
-
let cleaned = text;
|
|
184493
|
-
cleaned = cleaned.replace(SYSTEM_REMINDER_REGEX, "");
|
|
184494
|
-
cleaned = cleaned.replace(OMO_MARKER_REGEX, "");
|
|
184495
|
-
cleaned = cleaned.replace(/\[SYSTEM DIRECTIVE: OH-MY-(?:OPENCODE|CLAUDE)[^\]]*\][\s\S]*?(?=\n\n(?!\s*[-*])|$)/g, "");
|
|
184496
|
-
for (const marker of SYSTEM_INJECTION_MARKERS) {
|
|
184497
|
-
if (marker.startsWith("<!-- ") || marker.startsWith("[SYSTEM DIRECTIVE"))
|
|
184498
|
-
continue;
|
|
184499
|
-
const idx = cleaned.indexOf(marker);
|
|
184500
|
-
if (idx === -1)
|
|
184501
|
-
continue;
|
|
184502
|
-
const blockEnd = cleaned.indexOf(`
|
|
184503
|
-
|
|
184504
|
-
`, idx + marker.length);
|
|
184505
|
-
cleaned = blockEnd !== -1 ? cleaned.slice(0, idx) + cleaned.slice(blockEnd) : cleaned.slice(0, idx);
|
|
184506
|
-
}
|
|
184507
|
-
return cleaned.trim();
|
|
184508
|
-
}
|
|
184509
|
-
|
|
184510
|
-
// src/hooks/magic-context/apply-operations.ts
|
|
184511
|
-
init_tag_part_guards();
|
|
184512
|
-
var USER_DROP_PREVIEW_CHARS = 250;
|
|
184513
184726
|
var RECENT_TOOL_SKELETON_WINDOW = 20;
|
|
184514
|
-
function buildReplacementContent(tagId
|
|
184515
|
-
|
|
184516
|
-
|
|
184517
|
-
|
|
184518
|
-
}
|
|
184519
|
-
const currentContent = target.getContent?.() ?? "";
|
|
184520
|
-
const strippedInjection = stripSystemInjection(currentContent);
|
|
184521
|
-
if (strippedInjection !== null && stripTagPrefix(strippedInjection).trim().length === 0) {
|
|
184522
|
-
return `[dropped §${tagId}§]`;
|
|
184523
|
-
}
|
|
184524
|
-
const originalText = stripTagPrefix(currentContent);
|
|
184525
|
-
if (originalText.length <= USER_DROP_PREVIEW_CHARS) {
|
|
184526
|
-
return `[truncated §${tagId}§]
|
|
184527
|
-
${originalText}`;
|
|
184528
|
-
}
|
|
184529
|
-
const hardCut = originalText.slice(0, USER_DROP_PREVIEW_CHARS);
|
|
184530
|
-
const softCutIndex = hardCut.search(/\s\S*$/);
|
|
184531
|
-
const preview = softCutIndex > USER_DROP_PREVIEW_CHARS - 30 ? hardCut.slice(0, softCutIndex) : hardCut;
|
|
184532
|
-
return `[truncated §${tagId}§]
|
|
184533
|
-
${preview}…`;
|
|
184534
|
-
}
|
|
184535
|
-
function applyPendingOperations(sessionId, db, targets, protectedTags = 0, preloadedTags, preloadedPendingOps) {
|
|
184727
|
+
function buildReplacementContent(tagId) {
|
|
184728
|
+
return `[dropped §${tagId}§]`;
|
|
184729
|
+
}
|
|
184730
|
+
function applyPendingOperations(sessionId, db, targets, protectedTags = 0, preloadedTags, preloadedPendingOps, syntheticPendingOps = []) {
|
|
184536
184731
|
let didMutateMessage = false;
|
|
184537
184732
|
db.transaction(() => {
|
|
184538
184733
|
const tags = preloadedTags ?? getTagsBySession(db, sessionId);
|
|
@@ -184540,11 +184735,16 @@ function applyPendingOperations(sessionId, db, targets, protectedTags = 0, prelo
|
|
|
184540
184735
|
const tagTypeById = new Map(tags.map((tag) => [tag.tagNumber, tag.type]));
|
|
184541
184736
|
const protectedTagIds = protectedTags > 0 ? new Set(tags.filter((tag) => tag.status === "active").map((tag) => tag.tagNumber).sort((left, right) => right - left).slice(0, protectedTags)) : new Set;
|
|
184542
184737
|
const pendingOps = preloadedPendingOps ?? getPendingOps(db, sessionId);
|
|
184738
|
+
const opsToApply = [
|
|
184739
|
+
...pendingOps.map((op) => ({ op, synthetic: false })),
|
|
184740
|
+
...syntheticPendingOps.map((op) => ({ op, synthetic: true }))
|
|
184741
|
+
];
|
|
184543
184742
|
const skeletonWindow = new Set(tags.filter((tag) => tag.type === "tool").map((tag) => tag.tagNumber).sort((left, right) => right - left).slice(0, RECENT_TOOL_SKELETON_WINDOW));
|
|
184544
|
-
for (const pendingOp of
|
|
184743
|
+
for (const { op: pendingOp, synthetic } of opsToApply) {
|
|
184545
184744
|
const tagStatus = tagStatusById.get(pendingOp.tagId);
|
|
184546
184745
|
if (tagStatus === "compacted" || tagStatus === "dropped") {
|
|
184547
|
-
|
|
184746
|
+
if (!synthetic)
|
|
184747
|
+
removePendingOp(db, sessionId, pendingOp.tagId);
|
|
184548
184748
|
continue;
|
|
184549
184749
|
}
|
|
184550
184750
|
if (protectedTagIds.has(pendingOp.tagId)) {
|
|
@@ -184552,33 +184752,46 @@ function applyPendingOperations(sessionId, db, targets, protectedTags = 0, prelo
|
|
|
184552
184752
|
}
|
|
184553
184753
|
const target = targets.get(pendingOp.tagId);
|
|
184554
184754
|
const isToolTag = tagTypeById.get(pendingOp.tagId) === "tool";
|
|
184755
|
+
if (synthetic) {
|
|
184756
|
+
if (!isToolTag || target?.canDrop?.() !== true)
|
|
184757
|
+
continue;
|
|
184758
|
+
}
|
|
184759
|
+
let shouldPersistDrop = false;
|
|
184555
184760
|
if (isToolTag) {
|
|
184556
184761
|
if (skeletonWindow.has(pendingOp.tagId)) {
|
|
184557
184762
|
const truncResult = target?.truncate?.() ?? "absent";
|
|
184558
|
-
if (truncResult === "incomplete") {
|
|
184763
|
+
if (truncResult === "incomplete" || synthetic && truncResult !== "truncated") {
|
|
184559
184764
|
continue;
|
|
184560
184765
|
}
|
|
184561
184766
|
if (truncResult === "truncated") {
|
|
184562
184767
|
didMutateMessage = true;
|
|
184563
184768
|
}
|
|
184564
184769
|
updateTagDropMode(db, sessionId, pendingOp.tagId, "truncated");
|
|
184770
|
+
shouldPersistDrop = true;
|
|
184565
184771
|
} else {
|
|
184566
184772
|
const dropResult = target?.drop?.() ?? "absent";
|
|
184567
|
-
if (dropResult === "incomplete") {
|
|
184773
|
+
if (dropResult === "incomplete" || synthetic && dropResult !== "removed") {
|
|
184568
184774
|
continue;
|
|
184569
184775
|
}
|
|
184570
184776
|
if (dropResult === "removed") {
|
|
184571
184777
|
didMutateMessage = true;
|
|
184572
184778
|
}
|
|
184573
184779
|
updateTagDropMode(db, sessionId, pendingOp.tagId, "full");
|
|
184780
|
+
shouldPersistDrop = true;
|
|
184574
184781
|
}
|
|
184575
184782
|
} else if (target) {
|
|
184576
|
-
const changed = target.setContent(buildReplacementContent(pendingOp.tagId
|
|
184783
|
+
const changed = target.setContent(buildReplacementContent(pendingOp.tagId));
|
|
184577
184784
|
if (changed)
|
|
184578
184785
|
didMutateMessage = true;
|
|
184786
|
+
shouldPersistDrop = true;
|
|
184787
|
+
} else if (!synthetic) {
|
|
184788
|
+
shouldPersistDrop = true;
|
|
184579
184789
|
}
|
|
184790
|
+
if (!shouldPersistDrop)
|
|
184791
|
+
continue;
|
|
184580
184792
|
updateTagStatus(db, sessionId, pendingOp.tagId, "dropped");
|
|
184581
|
-
|
|
184793
|
+
if (!synthetic)
|
|
184794
|
+
removePendingOp(db, sessionId, pendingOp.tagId);
|
|
184582
184795
|
}
|
|
184583
184796
|
})();
|
|
184584
184797
|
return didMutateMessage;
|
|
@@ -184602,7 +184815,7 @@ function applyFlushedStatuses(sessionId, db, targets, preloadedTags) {
|
|
|
184602
184815
|
}
|
|
184603
184816
|
}
|
|
184604
184817
|
} else if (target) {
|
|
184605
|
-
const changed = target.setContent(buildReplacementContent(tag.tagNumber
|
|
184818
|
+
const changed = target.setContent(buildReplacementContent(tag.tagNumber));
|
|
184606
184819
|
if (changed)
|
|
184607
184820
|
didMutateMessage = true;
|
|
184608
184821
|
}
|
|
@@ -185119,7 +185332,7 @@ function tagMessages(sessionId, messages, tagger, db, options = {}) {
|
|
|
185119
185332
|
logTransformTiming(sessionId, "tag.saveSource", performance.now() - accSaveSource);
|
|
185120
185333
|
for (const [compositeKey, tagId] of toolTagByCallId) {
|
|
185121
185334
|
const thinkingParts = toolThinkingByCallId.get(compositeKey) ?? [];
|
|
185122
|
-
targets.set(tagId, createToolDropTarget(compositeKey, thinkingParts, toolCallIndex, batch));
|
|
185335
|
+
targets.set(tagId, createToolDropTarget(compositeKey, thinkingParts, toolCallIndex, batch, tagId));
|
|
185123
185336
|
}
|
|
185124
185337
|
const hasRecentReduceCall = lastReduceMessageIndex >= 0 && messages.length - lastReduceMessageIndex <= RECENT_REDUCE_LOOKBACK;
|
|
185125
185338
|
return {
|
|
@@ -186227,6 +186440,51 @@ function planEmergencyDrop(input) {
|
|
|
186227
186440
|
};
|
|
186228
186441
|
}
|
|
186229
186442
|
|
|
186443
|
+
// src/hooks/magic-context/system-injection-stripper.ts
|
|
186444
|
+
var SYSTEM_INJECTION_MARKERS = [
|
|
186445
|
+
"<!-- OMO_INTERNAL_INITIATOR -->",
|
|
186446
|
+
"[SYSTEM DIRECTIVE: MAGIC-CONTEXT",
|
|
186447
|
+
"[SYSTEM DIRECTIVE: OH-MY-OPENCODE",
|
|
186448
|
+
"[Category+Skill Reminder]",
|
|
186449
|
+
"[EDIT ERROR - IMMEDIATE ACTION REQUIRED]",
|
|
186450
|
+
"[task CALL FAILED - IMMEDIATE RETRY REQUIRED]",
|
|
186451
|
+
"[EMERGENCY CONTEXT WINDOW WARNING]",
|
|
186452
|
+
"Unstable background agent appears idle",
|
|
186453
|
+
"**THE SUBAGENT JUST CLAIMED THIS TASK IS DONE."
|
|
186454
|
+
];
|
|
186455
|
+
var SYSTEM_REMINDER_REGEX = /<system-reminder>[\s\S]*?<\/system-reminder>/gi;
|
|
186456
|
+
var OMO_MARKER_REGEX = /<!-- OMO_INTERNAL_INITIATOR -->/g;
|
|
186457
|
+
function stripSystemInjection(text) {
|
|
186458
|
+
let hasInjection = false;
|
|
186459
|
+
for (const marker of SYSTEM_INJECTION_MARKERS) {
|
|
186460
|
+
if (text.includes(marker)) {
|
|
186461
|
+
hasInjection = true;
|
|
186462
|
+
break;
|
|
186463
|
+
}
|
|
186464
|
+
}
|
|
186465
|
+
if (SYSTEM_REMINDER_REGEX.test(text))
|
|
186466
|
+
hasInjection = true;
|
|
186467
|
+
SYSTEM_REMINDER_REGEX.lastIndex = 0;
|
|
186468
|
+
if (!hasInjection)
|
|
186469
|
+
return null;
|
|
186470
|
+
let cleaned = text;
|
|
186471
|
+
cleaned = cleaned.replace(SYSTEM_REMINDER_REGEX, "");
|
|
186472
|
+
cleaned = cleaned.replace(OMO_MARKER_REGEX, "");
|
|
186473
|
+
cleaned = cleaned.replace(/\[SYSTEM DIRECTIVE: OH-MY-(?:OPENCODE|CLAUDE)[^\]]*\][\s\S]*?(?=\n\n(?!\s*[-*])|$)/g, "");
|
|
186474
|
+
for (const marker of SYSTEM_INJECTION_MARKERS) {
|
|
186475
|
+
if (marker.startsWith("<!-- ") || marker.startsWith("[SYSTEM DIRECTIVE"))
|
|
186476
|
+
continue;
|
|
186477
|
+
const idx = cleaned.indexOf(marker);
|
|
186478
|
+
if (idx === -1)
|
|
186479
|
+
continue;
|
|
186480
|
+
const blockEnd = cleaned.indexOf(`
|
|
186481
|
+
|
|
186482
|
+
`, idx + marker.length);
|
|
186483
|
+
cleaned = blockEnd !== -1 ? cleaned.slice(0, idx) + cleaned.slice(blockEnd) : cleaned.slice(0, idx);
|
|
186484
|
+
}
|
|
186485
|
+
return cleaned.trim();
|
|
186486
|
+
}
|
|
186487
|
+
|
|
186230
186488
|
// src/hooks/magic-context/heuristic-cleanup.ts
|
|
186231
186489
|
init_tag_part_guards();
|
|
186232
186490
|
var DEDUP_SAFE_TOOLS = new Set([
|
|
@@ -186354,7 +186612,9 @@ function applyHeuristicCleanup(sessionId, db, targets, messageTagNumbers, config
|
|
|
186354
186612
|
continue;
|
|
186355
186613
|
updateTagDropMode(db, sessionId, tag.tagNumber, "full");
|
|
186356
186614
|
updateTagStatus(db, sessionId, tag.tagNumber, "dropped");
|
|
186357
|
-
|
|
186615
|
+
if (result === "removed" || result === "truncated") {
|
|
186616
|
+
deduplicatedTools++;
|
|
186617
|
+
}
|
|
186358
186618
|
}
|
|
186359
186619
|
}
|
|
186360
186620
|
})();
|
|
@@ -186363,6 +186623,7 @@ function applyHeuristicCleanup(sessionId, db, targets, messageTagNumbers, config
|
|
|
186363
186623
|
sessionLog(sessionId, `heuristic cleanup: dropped ${droppedTools} tool tags, deduplicated ${deduplicatedTools} tool calls, dropped ${droppedInjections} system injections`);
|
|
186364
186624
|
}
|
|
186365
186625
|
let compressedTextTags = 0;
|
|
186626
|
+
let mutatedTextTags = 0;
|
|
186366
186627
|
if (config2.caveman?.enabled) {
|
|
186367
186628
|
const cavemanResult = applyCavemanCleanup(sessionId, db, targets, tags, {
|
|
186368
186629
|
enabled: true,
|
|
@@ -186370,8 +186631,15 @@ function applyHeuristicCleanup(sessionId, db, targets, messageTagNumbers, config
|
|
|
186370
186631
|
protectedTags: config2.protectedTags
|
|
186371
186632
|
});
|
|
186372
186633
|
compressedTextTags = cavemanResult.compressedToLite + cavemanResult.compressedToFull + cavemanResult.compressedToUltra;
|
|
186634
|
+
mutatedTextTags = cavemanResult.mutatedTextTags;
|
|
186373
186635
|
}
|
|
186374
|
-
return {
|
|
186636
|
+
return {
|
|
186637
|
+
droppedTools,
|
|
186638
|
+
deduplicatedTools,
|
|
186639
|
+
droppedInjections,
|
|
186640
|
+
compressedTextTags,
|
|
186641
|
+
mutatedTextTags
|
|
186642
|
+
};
|
|
186375
186643
|
}
|
|
186376
186644
|
function extractToolInfo(part) {
|
|
186377
186645
|
if (part.type === "tool" && typeof part.tool === "string" && DEDUP_SAFE_TOOLS.has(part.tool)) {
|
|
@@ -186545,6 +186813,42 @@ function isTodoItem(value) {
|
|
|
186545
186813
|
return typeof todo.content === "string" && typeof todo.status === "string" && (todo.priority === undefined || typeof todo.priority === "string");
|
|
186546
186814
|
}
|
|
186547
186815
|
|
|
186816
|
+
// src/hooks/magic-context/tool-reclaim.ts
|
|
186817
|
+
await init_storage();
|
|
186818
|
+
function buildSyntheticToolReclaimOps(input) {
|
|
186819
|
+
const watermark = Math.max(0, input.watermark);
|
|
186820
|
+
if (watermark <= 0)
|
|
186821
|
+
return [];
|
|
186822
|
+
const realPendingTagIds = new Set((input.pendingOps ?? []).map((op) => op.tagId));
|
|
186823
|
+
const tags = getActiveTagsBySession(input.db, input.sessionId);
|
|
186824
|
+
const synthetic = [];
|
|
186825
|
+
for (const tag of tags) {
|
|
186826
|
+
if (tag.type !== "tool")
|
|
186827
|
+
continue;
|
|
186828
|
+
if (tag.status !== "active")
|
|
186829
|
+
continue;
|
|
186830
|
+
if (tag.tagNumber > watermark)
|
|
186831
|
+
continue;
|
|
186832
|
+
if (realPendingTagIds.has(tag.tagNumber))
|
|
186833
|
+
continue;
|
|
186834
|
+
if (input.targets.get(tag.tagNumber)?.canDrop?.() !== true)
|
|
186835
|
+
continue;
|
|
186836
|
+
synthetic.push({
|
|
186837
|
+
id: 0,
|
|
186838
|
+
sessionId: input.sessionId,
|
|
186839
|
+
tagId: tag.tagNumber,
|
|
186840
|
+
operation: "drop",
|
|
186841
|
+
queuedAt: 0
|
|
186842
|
+
});
|
|
186843
|
+
}
|
|
186844
|
+
return synthetic;
|
|
186845
|
+
}
|
|
186846
|
+
function advanceToolReclaimWatermarkToCurrentMax(db, sessionId) {
|
|
186847
|
+
const maxTagNumber = getMaxTagNumberBySession(db, sessionId);
|
|
186848
|
+
advanceToolReclaimWatermark(db, sessionId, maxTagNumber);
|
|
186849
|
+
return maxTagNumber;
|
|
186850
|
+
}
|
|
186851
|
+
|
|
186548
186852
|
// src/hooks/magic-context/transform-postprocess-phase.ts
|
|
186549
186853
|
var DEGRADE_CACHE_WARNING_THRESHOLD = 10;
|
|
186550
186854
|
var degradedCacheCountBySession = new BoundedSessionMap(100);
|
|
@@ -186599,12 +186903,14 @@ async function runPostTransformPhase(args) {
|
|
|
186599
186903
|
let deferredMaterializedSuccessfully = false;
|
|
186600
186904
|
let heuristicsRanSuccessfully = false;
|
|
186601
186905
|
let pendingOpsRanSuccessfully = false;
|
|
186906
|
+
let pendingOpsDidMutate = false;
|
|
186907
|
+
let heuristicOrReasoningDidMutate = false;
|
|
186602
186908
|
try {
|
|
186603
186909
|
if (shouldApplyPendingOps) {
|
|
186604
186910
|
const applyReason = isExplicitFlush ? "explicit_flush" : deferredMaterialize ? "deferred_materialization" : `scheduler_execute (scheduler=${args.schedulerDecision})`;
|
|
186605
186911
|
sessionLog(args.sessionId, `pending ops WILL APPLY — reason=${applyReason}, pendingOps=${pendingOps.length}, context=${args.contextUsage.percentage.toFixed(1)}%`);
|
|
186606
186912
|
const tApply = performance.now();
|
|
186607
|
-
applyPendingOperations(args.sessionId, args.db, args.targets, args.protectedTags, undefined, pendingOps);
|
|
186913
|
+
pendingOpsDidMutate = applyPendingOperations(args.sessionId, args.db, args.targets, args.protectedTags, undefined, pendingOps);
|
|
186608
186914
|
logTransformTiming(args.sessionId, "applyPendingOperations", tApply);
|
|
186609
186915
|
}
|
|
186610
186916
|
if (shouldRunHeuristics) {
|
|
@@ -186622,7 +186928,8 @@ async function runPostTransformPhase(args) {
|
|
|
186622
186928
|
} : undefined,
|
|
186623
186929
|
caveman: cavemanConfig
|
|
186624
186930
|
}, heuristicTags);
|
|
186625
|
-
logTransformTiming(args.sessionId, "applyHeuristicCleanup", t5, `droppedTools=${cleanup.droppedTools} deduplicatedTools=${cleanup.deduplicatedTools} droppedInjections=${cleanup.droppedInjections} compressedTextTags=${cleanup.compressedTextTags}`);
|
|
186931
|
+
logTransformTiming(args.sessionId, "applyHeuristicCleanup", t5, `droppedTools=${cleanup.droppedTools} deduplicatedTools=${cleanup.deduplicatedTools} droppedInjections=${cleanup.droppedInjections} compressedTextTags=${cleanup.compressedTextTags} mutatedTextTags=${cleanup.mutatedTextTags}`);
|
|
186932
|
+
const heuristicMutationCount = cleanup.droppedTools + cleanup.deduplicatedTools + cleanup.droppedInjections + cleanup.mutatedTextTags;
|
|
186626
186933
|
const t7 = performance.now();
|
|
186627
186934
|
const clearedReasoning = clearOldReasoning(args.messages, args.reasoningByMessage, args.messageTagNumbers, args.clearReasoningAge);
|
|
186628
186935
|
if (canUseEmptySentinels) {
|
|
@@ -186648,6 +186955,7 @@ async function runPostTransformPhase(args) {
|
|
|
186648
186955
|
}
|
|
186649
186956
|
}
|
|
186650
186957
|
logTransformTiming(args.sessionId, "clearOldReasoning", t7);
|
|
186958
|
+
heuristicOrReasoningDidMutate = heuristicMutationCount + clearedReasoning + strippedInline > 0;
|
|
186651
186959
|
if (pendingMaterializationAtPassStart) {
|
|
186652
186960
|
args.pendingMaterializationSessions.delete(args.sessionId);
|
|
186653
186961
|
}
|
|
@@ -186658,7 +186966,31 @@ async function runPostTransformPhase(args) {
|
|
|
186658
186966
|
if (args.schedulerDecision === "execute" && !materializationRequested) {
|
|
186659
186967
|
updateSessionMeta(args.db, args.sessionId, { lastResponseTime: Date.now() });
|
|
186660
186968
|
}
|
|
186969
|
+
const toolReclaimExecutePass = args.schedulerDecision === "execute";
|
|
186970
|
+
const alreadyMutatingThisPass = pendingOpsDidMutate || heuristicOrReasoningDidMutate;
|
|
186971
|
+
let autoReclaimTargetCount = 0;
|
|
186972
|
+
let autoReclaimDidMutate = false;
|
|
186973
|
+
if (toolReclaimExecutePass && alreadyMutatingThisPass && !emergencyDropEligible) {
|
|
186974
|
+
const syntheticPendingOps = buildSyntheticToolReclaimOps({
|
|
186975
|
+
db: args.db,
|
|
186976
|
+
sessionId: args.sessionId,
|
|
186977
|
+
targets: args.targets,
|
|
186978
|
+
watermark: args.sessionMeta.toolReclaimWatermark ?? 0,
|
|
186979
|
+
pendingOps
|
|
186980
|
+
});
|
|
186981
|
+
autoReclaimTargetCount = syntheticPendingOps.length;
|
|
186982
|
+
if (syntheticPendingOps.length > 0) {
|
|
186983
|
+
autoReclaimDidMutate = applyPendingOperations(args.sessionId, args.db, args.targets, args.protectedTags, undefined, [], syntheticPendingOps);
|
|
186984
|
+
}
|
|
186985
|
+
}
|
|
186661
186986
|
args.batch?.finalize();
|
|
186987
|
+
if (toolReclaimExecutePass) {
|
|
186988
|
+
const maxTagNumber = advanceToolReclaimWatermarkToCurrentMax(args.db, args.sessionId);
|
|
186989
|
+
args.sessionMeta.toolReclaimWatermark = Math.max(args.sessionMeta.toolReclaimWatermark ?? 0, maxTagNumber);
|
|
186990
|
+
}
|
|
186991
|
+
if (autoReclaimTargetCount > 0) {
|
|
186992
|
+
sessionLog(args.sessionId, `tool reclaim auto-drop: targets=${autoReclaimTargetCount} mutated=${autoReclaimDidMutate}`);
|
|
186993
|
+
}
|
|
186662
186994
|
logTransformTiming(args.sessionId, "batchFinalize:heuristics", performance.now());
|
|
186663
186995
|
if (args.sessionMeta.lastTransformError !== null) {
|
|
186664
186996
|
updateSessionMeta(args.db, args.sessionId, { lastTransformError: null });
|
|
@@ -186670,11 +187002,6 @@ async function runPostTransformPhase(args) {
|
|
|
186670
187002
|
deferredMaterializedSuccessfully = true;
|
|
186671
187003
|
heuristicsRanSuccessfully = true;
|
|
186672
187004
|
}
|
|
186673
|
-
if (args.watermark > 0) {
|
|
186674
|
-
const tWatermarkCleanup = performance.now();
|
|
186675
|
-
truncateErroredTools(args.messages, args.watermark, args.messageTagNumbers);
|
|
186676
|
-
logTransformTiming(args.sessionId, "watermarkCleanup", tWatermarkCleanup);
|
|
186677
|
-
}
|
|
186678
187005
|
if (shouldApplyPendingOps) {
|
|
186679
187006
|
pendingOpsRanSuccessfully = true;
|
|
186680
187007
|
}
|
|
@@ -187701,6 +188028,7 @@ Historian previously failed ${historianFailureState.failureCount} time(s), so Ma
|
|
|
187701
188028
|
const executeThresholdTokens = Math.round((resolvedContextLimit ?? 0) * resolvedExecuteThresholdPct / 100);
|
|
187702
188029
|
const usableTokens = Math.max(0, executeThresholdTokens - contextUsage.inputTokens + liveTailTokens);
|
|
187703
188030
|
resetLastNudgeCycleIfTailShrank(db, sessionId, tailToolTokens);
|
|
188031
|
+
const oldestReclaimableToolTags = getOldestActiveUnprotectedToolTags(db, sessionId, deps.protectedTags);
|
|
187704
188032
|
deps.channel1StateBySession.set(sessionId, {
|
|
187705
188033
|
tailToolTokens,
|
|
187706
188034
|
historyBudgetTokens: historyBudgetTokens ?? 0,
|
|
@@ -187709,9 +188037,10 @@ Historian previously failed ${historianFailureState.failureCount} time(s), so Ma
|
|
|
187709
188037
|
lastInputTokens: contextUsage.inputTokens,
|
|
187710
188038
|
turnToolTokens: 0,
|
|
187711
188039
|
usableTokens,
|
|
187712
|
-
reducedSinceRefresh: false
|
|
188040
|
+
reducedSinceRefresh: false,
|
|
188041
|
+
oldestReclaimableToolTags
|
|
187713
188042
|
});
|
|
187714
|
-
const channel2MetricsKnown =
|
|
188043
|
+
const channel2MetricsKnown = resolvedContextLimit !== undefined && resolvedContextLimit > 0 && resolvedExecuteThresholdPct > 0;
|
|
187715
188044
|
if (channel2MetricsKnown) {
|
|
187716
188045
|
const channel2ShouldTrigger = shouldTriggerChannel2({
|
|
187717
188046
|
reclaimableTokens: tailToolTokens,
|
|
@@ -187735,6 +188064,7 @@ Historian previously failed ${historianFailureState.failureCount} time(s), so Ma
|
|
|
187735
188064
|
}
|
|
187736
188065
|
const elapsed = (performance.now() - startTime).toFixed(1);
|
|
187737
188066
|
sessionLog(sessionId, `transform completed in ${elapsed}ms (${messages.length} messages, ${targets.size} targets, watermark: ${watermark})`);
|
|
188067
|
+
deps.maybeAutoEmbedSession?.(sessionId);
|
|
187738
188068
|
};
|
|
187739
188069
|
}
|
|
187740
188070
|
function resolveHistoryBudgetTokens(historyBudgetPercentage, contextUsage, executeThresholdPercentage, modelKey, executeThresholdTokens, resolvedContextLimit) {
|
|
@@ -187780,18 +188110,14 @@ function evictExpiredUsageEntries(contextUsageMap) {
|
|
|
187780
188110
|
}
|
|
187781
188111
|
async function deliverChannel2IfPending(deps, sessionId) {
|
|
187782
188112
|
try {
|
|
187783
|
-
try {
|
|
187784
|
-
const meta3 = getOrCreateSessionMeta(deps.db, sessionId);
|
|
187785
|
-
if (meta3.isSubagent)
|
|
187786
|
-
return;
|
|
187787
|
-
} catch {}
|
|
187788
188113
|
const baseline = deps.channel1StateBySession?.get(sessionId);
|
|
187789
188114
|
await maybeDeliverChannel2(sessionId, {
|
|
187790
188115
|
db: deps.db,
|
|
187791
188116
|
serverUrl: deps.serverUrl,
|
|
187792
188117
|
directory: deps.directory ?? ".",
|
|
187793
188118
|
reclaimableTokens: baseline ? baseline.tailToolTokens + baseline.turnToolTokens : undefined,
|
|
187794
|
-
usableTokens: baseline?.usableTokens
|
|
188119
|
+
usableTokens: baseline?.usableTokens,
|
|
188120
|
+
oldestReclaimableToolTags: baseline?.oldestReclaimableToolTags
|
|
187795
188121
|
});
|
|
187796
188122
|
} catch (error51) {
|
|
187797
188123
|
sessionLog(sessionId, "channel2 delivery wrapper failed (ignored):", error51);
|
|
@@ -188097,6 +188423,46 @@ function createEventHandler2(deps) {
|
|
|
188097
188423
|
};
|
|
188098
188424
|
}
|
|
188099
188425
|
|
|
188426
|
+
// src/hooks/magic-context/format-embed-status.ts
|
|
188427
|
+
function formatEmbedStatusText(coverage, drain) {
|
|
188428
|
+
if (!coverage.enabled) {
|
|
188429
|
+
return "Embedding is off (no provider configured).";
|
|
188430
|
+
}
|
|
188431
|
+
const lines = [];
|
|
188432
|
+
lines.push(`Embedding — model: ${coverage.model} (${coverage.provider})`);
|
|
188433
|
+
lines.push(`This session: ${coverage.session.embedded} / ${coverage.session.total} compartments embedded`);
|
|
188434
|
+
lines.push(`Project memories: ${coverage.memories.embedded} / ${coverage.memories.total} embedded`);
|
|
188435
|
+
if (coverage.commits.gitEnabled) {
|
|
188436
|
+
lines.push(`Git commits: ${coverage.commits.embedded} / ${coverage.commits.total}`);
|
|
188437
|
+
} else {
|
|
188438
|
+
lines.push("Git commits: 0 / 0 (git indexing off)");
|
|
188439
|
+
}
|
|
188440
|
+
let drainLine = "Drain: idle";
|
|
188441
|
+
switch (drain.status) {
|
|
188442
|
+
case "running": {
|
|
188443
|
+
const e = drain.embedded ?? coverage.session.embedded;
|
|
188444
|
+
const t = drain.total ?? coverage.session.total;
|
|
188445
|
+
const failedSuffix = drain.failed && drain.failed > 0 ? ` (${drain.failed} failed)` : "";
|
|
188446
|
+
drainLine = `Drain: running ${e}/${t}${failedSuffix}`;
|
|
188447
|
+
break;
|
|
188448
|
+
}
|
|
188449
|
+
case "paused": {
|
|
188450
|
+
const e = drain.embedded ?? coverage.session.embedded;
|
|
188451
|
+
const t = drain.total ?? coverage.session.total;
|
|
188452
|
+
drainLine = `Drain: paused ${e}/${t}`;
|
|
188453
|
+
break;
|
|
188454
|
+
}
|
|
188455
|
+
case "stopped":
|
|
188456
|
+
drainLine = "Drain: stopped (provider down)";
|
|
188457
|
+
break;
|
|
188458
|
+
default:
|
|
188459
|
+
drainLine = "Drain: idle";
|
|
188460
|
+
}
|
|
188461
|
+
lines.push(drainLine);
|
|
188462
|
+
return lines.join(`
|
|
188463
|
+
`);
|
|
188464
|
+
}
|
|
188465
|
+
|
|
188100
188466
|
// src/hooks/magic-context/hook.ts
|
|
188101
188467
|
await __promiseAll([
|
|
188102
188468
|
init_inject_compartments(),
|
|
@@ -188338,7 +188704,7 @@ function maybeInjectChannel1Nudge(args, sessionId, tool, output) {
|
|
|
188338
188704
|
setLastNudgeLevel(args.db, sessionId, decision.nextLastNudgeLevel);
|
|
188339
188705
|
if (!decision.fire)
|
|
188340
188706
|
return;
|
|
188341
|
-
out.output += buildChannel1Reminder(decision.level, decision.undroppedTokens);
|
|
188707
|
+
out.output += buildChannel1Reminder(decision.level, decision.undroppedTokens, state.oldestReclaimableToolTags);
|
|
188342
188708
|
sessionLog(sessionId, `channel1 nudge fired: level=${decision.level} undropped~${Math.round(decision.undroppedTokens / 1000)}k tool=${tool}`);
|
|
188343
188709
|
}
|
|
188344
188710
|
function createToolExecuteAfterHook(args) {
|
|
@@ -188410,9 +188776,7 @@ Context is managed for you entirely automatically — there's nothing to prune a
|
|
|
188410
188776
|
var CTX_NOTE_GUIDANCE = `Use \`ctx_note\` ONLY for genuinely future concerns — something to revisit much later, not work coming up in the next few turns (that's already in your active context) and not active multi-step work (use todos for that). Magic Context preserves your full context across both compaction and restarts, so an upcoming restart or "let's come back to this later" is never a reason to take a note — nothing is lost either way. Notes you do take survive compression and resurface at natural work boundaries (after commits, historian runs, todo completion).`;
|
|
188411
188777
|
var TOOL_HISTORY_GUIDANCE = `Compressed history intentionally omits tool calls and their outputs — summaries like "I edited file X" are historian records, not patterns to replicate. In the live conversation, older tool calls and their results are cleaned up to save context — you may see your own past messages referencing actions without the corresponding tool call or result visible. This is normal context management. ALWAYS use real tool calls; never simulate, fabricate, or inline tool outputs in your text. If there is no tool result message, the action did not happen. NEVER simulate, hallucinate or claim tool calls, command output, search results, file edits, or diffs in plain text as if they actually occurred.`;
|
|
188412
188778
|
var BASE_INTRO = (protectedTags) => `Messages and tool outputs are tagged with §N§ identifiers (e.g., §1§, §42§).
|
|
188413
|
-
Use \`ctx_reduce\` to
|
|
188414
|
-
- \`drop\`: Remove entirely (best for tool outputs you already acted on).
|
|
188415
|
-
Syntax: "3-5", "1,2,9", or "1-5,8,12-15". Last ${protectedTags} tags are protected.
|
|
188779
|
+
Use \`ctx_reduce\` to mark spent tagged content as discardable and reclaim space. Marking is NOT an immediate delete — it queues the content, which stays fully visible until space is actually needed (as soon as the next turn if you're already under pressure, much later if not), so mark a tool output as soon as you're done with it rather than hoarding the call for the end of the turn. The last ${protectedTags} tags are protected (marking one just queues it until it ages out). Syntax: "3-5", "1,2,9", or "1-5,8,12-15".
|
|
188416
188780
|
Do not announce or narrate \`ctx_reduce\` drops — just call the tool silently. Saying "I'll drop these outputs" wastes tokens the user does not care about.
|
|
188417
188781
|
${CTX_NOTE_GUIDANCE}
|
|
188418
188782
|
Use \`ctx_memory\` for durable project knowledge: write what future sessions must know, update/archive/merge the memories you see in \`<project-memory>\` when they drift. Memories persist across sessions and every new session starts with them.
|
|
@@ -188431,7 +188795,7 @@ Use \`ctx_expand\` to recover the raw conversation behind a \`<compartment>\` su
|
|
|
188431
188795
|
\`ctx_search\` returns ranked results from memories, git commits, and raw message history. Use message ordinals from results with \`ctx_expand\` to retrieve surrounding conversation context.
|
|
188432
188796
|
${TOOL_HISTORY_GUIDANCE}
|
|
188433
188797
|
NEVER drop large ranges blindly (e.g., "1-50"). Review each tag before deciding.
|
|
188434
|
-
|
|
188798
|
+
Keep your user's instructions and intent — never drop a user message for its directive, even an old one. But a large block of pasted content inside a user message (logs, data dumps, long code, attachments) is fair to mark discardable once you've extracted what you need — it stays searchable via \`ctx_search\`.
|
|
188435
188799
|
NEVER drop assistant text messages unless they are exceptionally large. Your conversation messages are lightweight; only large tool outputs are worth dropping.
|
|
188436
188800
|
Before your turn finishes, consider using \`ctx_reduce\` to drop large tool outputs you no longer need.`;
|
|
188437
188801
|
var BASE_INTRO_NO_REDUCE = () => `${CTX_NOTE_GUIDANCE}
|
|
@@ -188852,29 +189216,55 @@ function createMagicContextHook(deps) {
|
|
|
188852
189216
|
ensureProjectRegistered: ensureProjectRegisteredFromOpenCodeDirectory,
|
|
188853
189217
|
getNotificationParams: (sid) => getLiveNotificationParams(sid, liveModelBySession, variantBySession, agentBySession)
|
|
188854
189218
|
});
|
|
188855
|
-
const executeEmbedHistory = async (sessionId) => {
|
|
189219
|
+
const executeEmbedHistory = async (sessionId, options) => {
|
|
188856
189220
|
if (deps.config.memory?.enabled === false) {
|
|
188857
189221
|
return "Memory is disabled for this project, so there is no semantic embedding to backfill.";
|
|
188858
189222
|
}
|
|
188859
189223
|
const directory = sessionDirectoryBySession.get(sessionId) ?? deps.directory;
|
|
189224
|
+
const active = embedRunStateBySession.get(sessionId);
|
|
189225
|
+
if (active && !active.signal.aborted && !options?.signal) {
|
|
189226
|
+
return "Embedding is already running for this session.";
|
|
189227
|
+
}
|
|
188860
189228
|
await ensureProjectRegisteredFromOpenCodeDirectory(directory, db);
|
|
188861
189229
|
const sessionProjectIdentity = resolveProjectIdentity(directory);
|
|
188862
|
-
|
|
188863
|
-
const
|
|
188864
|
-
|
|
188865
|
-
|
|
188866
|
-
|
|
188867
|
-
|
|
188868
|
-
|
|
188869
|
-
|
|
188870
|
-
|
|
188871
|
-
|
|
188872
|
-
|
|
188873
|
-
|
|
189230
|
+
embedPauseBySession.delete(sessionId);
|
|
189231
|
+
const prior = embedRunStateBySession.get(sessionId);
|
|
189232
|
+
if (prior)
|
|
189233
|
+
prior.abort();
|
|
189234
|
+
const controller = new AbortController;
|
|
189235
|
+
embedRunStateBySession.set(sessionId, controller);
|
|
189236
|
+
const signal = options?.signal ?? controller.signal;
|
|
189237
|
+
if (!options?.silent) {
|
|
189238
|
+
setRecompStarting({ recompProgressBySession }, sessionId, "Embedding history…", "embed");
|
|
189239
|
+
}
|
|
189240
|
+
let runFailed = 0;
|
|
189241
|
+
let outcome;
|
|
189242
|
+
try {
|
|
189243
|
+
outcome = await embedSessionCompartmentChunks(db, sessionProjectIdentity, sessionId, {
|
|
189244
|
+
signal,
|
|
189245
|
+
onProgress: ({ embedded, total }) => {
|
|
189246
|
+
const cur = recompProgressBySession.get(sessionId);
|
|
189247
|
+
if (!cur || cur.phase !== "recomp")
|
|
189248
|
+
return;
|
|
189249
|
+
recompProgressBySession.set(sessionId, {
|
|
189250
|
+
...cur,
|
|
189251
|
+
processedMessages: embedded,
|
|
189252
|
+
totalMessages: total,
|
|
189253
|
+
updatedAt: Date.now()
|
|
189254
|
+
});
|
|
189255
|
+
}
|
|
189256
|
+
});
|
|
189257
|
+
} finally {
|
|
189258
|
+
if (embedRunStateBySession.get(sessionId) === controller) {
|
|
189259
|
+
embedRunStateBySession.delete(sessionId);
|
|
188874
189260
|
}
|
|
188875
|
-
}
|
|
189261
|
+
}
|
|
189262
|
+
if ("failed" in outcome)
|
|
189263
|
+
runFailed = outcome.failed;
|
|
188876
189264
|
const terminal = (phase, message) => {
|
|
188877
|
-
|
|
189265
|
+
if (!options?.silent) {
|
|
189266
|
+
setRecompTerminal({ recompProgressBySession }, sessionId, phase, message);
|
|
189267
|
+
}
|
|
188878
189268
|
return message;
|
|
188879
189269
|
};
|
|
188880
189270
|
switch (outcome.status) {
|
|
@@ -188883,15 +189273,78 @@ function createMagicContextHook(deps) {
|
|
|
188883
189273
|
case "disabled":
|
|
188884
189274
|
return terminal("skipped", "No embedding provider is configured, so there is nothing to embed.");
|
|
188885
189275
|
case "busy":
|
|
188886
|
-
return terminal("skipped",
|
|
188887
|
-
case "aborted":
|
|
188888
|
-
|
|
189276
|
+
return terminal("skipped", "Embedding is already running for this project. Try again shortly.");
|
|
189277
|
+
case "aborted": {
|
|
189278
|
+
const cov = getEmbeddingCoverageStatus(db, sessionProjectIdentity, sessionId);
|
|
189279
|
+
const msg = `Paused at ${cov.session.embedded}/${cov.session.total} compartments embedded.`;
|
|
189280
|
+
return terminal("skipped", msg);
|
|
189281
|
+
}
|
|
188889
189282
|
case "stalled":
|
|
188890
|
-
return terminal("skipped", `Embedded ${outcome.embedded} compartments; ${outcome.remaining} could not be embedded (the provider returned no result). Run /ctx-embed
|
|
189283
|
+
return terminal("skipped", `Embedded ${outcome.embedded} compartments; ${outcome.remaining} could not be embedded (the provider returned no result). Run /ctx-embed start again to retry them.`);
|
|
188891
189284
|
default:
|
|
188892
|
-
return terminal("done", `Embedded ${outcome.embedded} compartment${outcome.embedded === 1 ? "" : "s"} of history for semantic search.`);
|
|
189285
|
+
return terminal("done", `Embedded ${outcome.embedded} compartment${outcome.embedded === 1 ? "" : "s"} of history for semantic search${runFailed > 0 ? ` (${runFailed} failed)` : ""}.`);
|
|
188893
189286
|
}
|
|
188894
189287
|
};
|
|
189288
|
+
const pauseEmbedDrain = (sessionId) => {
|
|
189289
|
+
embedPauseBySession.add(sessionId);
|
|
189290
|
+
const ctrl = embedRunStateBySession.get(sessionId);
|
|
189291
|
+
if (ctrl)
|
|
189292
|
+
ctrl.abort();
|
|
189293
|
+
const directory = sessionDirectoryBySession.get(sessionId) ?? deps.directory;
|
|
189294
|
+
const sessionProjectIdentity = resolveProjectIdentity(directory);
|
|
189295
|
+
const cov = getEmbeddingCoverageStatus(db, sessionProjectIdentity, sessionId);
|
|
189296
|
+
return `Paused at ${cov.session.embedded}/${cov.session.total} compartments embedded.`;
|
|
189297
|
+
};
|
|
189298
|
+
const getEmbedStatusText = (sessionId) => {
|
|
189299
|
+
const directory = sessionDirectoryBySession.get(sessionId) ?? deps.directory;
|
|
189300
|
+
const sessionProjectIdentity = resolveProjectIdentity(directory);
|
|
189301
|
+
const coverage = getEmbeddingCoverageStatus(db, sessionProjectIdentity, sessionId);
|
|
189302
|
+
const progress = recompProgressBySession.get(sessionId);
|
|
189303
|
+
const drainUi = getEmbedDrainUiStatus(sessionId, progress);
|
|
189304
|
+
return formatEmbedStatusText(coverage, {
|
|
189305
|
+
status: drainUi.status,
|
|
189306
|
+
embedded: progress?.processedMessages,
|
|
189307
|
+
total: progress?.totalMessages
|
|
189308
|
+
});
|
|
189309
|
+
};
|
|
189310
|
+
const maybeAutoEmbedSession = (sessionId) => {
|
|
189311
|
+
if (autoEmbedAttemptedBySession.has(sessionId))
|
|
189312
|
+
return;
|
|
189313
|
+
if (embedPauseBySession.has(sessionId))
|
|
189314
|
+
return;
|
|
189315
|
+
if (deps.config.memory?.enabled === false)
|
|
189316
|
+
return;
|
|
189317
|
+
autoEmbedAttemptedBySession.add(sessionId);
|
|
189318
|
+
const directory = sessionDirectoryBySession.get(sessionId) ?? deps.directory;
|
|
189319
|
+
(async () => {
|
|
189320
|
+
try {
|
|
189321
|
+
await new Promise((resolve6) => setTimeout(resolve6, 0));
|
|
189322
|
+
await ensureProjectRegisteredFromOpenCodeDirectory(directory, db);
|
|
189323
|
+
const sessionProjectIdentity = resolveProjectIdentity(directory);
|
|
189324
|
+
const coverage = getEmbeddingCoverageStatus(db, sessionProjectIdentity, sessionId);
|
|
189325
|
+
if (!coverage.enabled)
|
|
189326
|
+
return;
|
|
189327
|
+
const remaining = coverage.session.total - coverage.session.embedded;
|
|
189328
|
+
if (remaining <= 0)
|
|
189329
|
+
return;
|
|
189330
|
+
const notifyParams = getLiveNotificationParams(sessionId, liveModelBySession, variantBySession, agentBySession);
|
|
189331
|
+
if (!isTuiConnected(sessionId)) {
|
|
189332
|
+
const startMsg = `Embedding ${remaining} compartment${remaining === 1 ? "" : "s"} of history in the background…`;
|
|
189333
|
+
await sendIgnoredMessage(deps.client, sessionId, startMsg, {
|
|
189334
|
+
...notifyParams
|
|
189335
|
+
});
|
|
189336
|
+
}
|
|
189337
|
+
const summary = await executeEmbedHistory(sessionId);
|
|
189338
|
+
if (!isTuiConnected(sessionId)) {
|
|
189339
|
+
await sendIgnoredMessage(deps.client, sessionId, summary, {
|
|
189340
|
+
...notifyParams
|
|
189341
|
+
});
|
|
189342
|
+
}
|
|
189343
|
+
} catch (error51) {
|
|
189344
|
+
log("[magic-context] auto-embed drain failed:", error51);
|
|
189345
|
+
}
|
|
189346
|
+
})();
|
|
189347
|
+
};
|
|
188895
189348
|
const sidekickRunnable = isSidekickRunnable(deps.config);
|
|
188896
189349
|
const sidekickConfig = sidekickRunnable ? deps.config.sidekick : undefined;
|
|
188897
189350
|
const transform2 = createTransform({
|
|
@@ -188953,7 +189406,8 @@ function createMagicContextHook(deps) {
|
|
|
188953
189406
|
cavemanTextCompression: ctxReduceEnabled === false && deps.config.caveman_text_compression?.enabled === true ? {
|
|
188954
189407
|
enabled: true,
|
|
188955
189408
|
minChars: deps.config.caveman_text_compression.min_chars ?? 500
|
|
188956
|
-
} : undefined
|
|
189409
|
+
} : undefined,
|
|
189410
|
+
maybeAutoEmbedSession
|
|
188957
189411
|
});
|
|
188958
189412
|
const eventHandler = createEventHandler2({
|
|
188959
189413
|
contextUsageMap,
|
|
@@ -188982,6 +189436,7 @@ function createMagicContextHook(deps) {
|
|
|
188982
189436
|
recompProgressBySession.delete(sessionId);
|
|
188983
189437
|
internalChildSessions.delete(sessionId);
|
|
188984
189438
|
channel1StateBySession.delete(sessionId);
|
|
189439
|
+
clearEmbedSessionState(sessionId);
|
|
188985
189440
|
}
|
|
188986
189441
|
});
|
|
188987
189442
|
const runDreamQueueInBackground = () => {
|
|
@@ -189047,6 +189502,8 @@ function createMagicContextHook(deps) {
|
|
|
189047
189502
|
executeRecomp: historianRunnable ? async (sessionId, options) => runManagedRecomp(buildManagedRecompCtx(sessionId), sessionId, options) : undefined,
|
|
189048
189503
|
runUpgrade: historianRunnable ? async (sessionId) => runManagedUpgrade(buildManagedRecompCtx(sessionId), sessionId) : undefined,
|
|
189049
189504
|
executeEmbedHistory,
|
|
189505
|
+
pauseEmbedDrain,
|
|
189506
|
+
getEmbedStatusText,
|
|
189050
189507
|
sendNotification: async (sessionId, text, params) => {
|
|
189051
189508
|
await sendIgnoredMessage(deps.client, sessionId, text, {
|
|
189052
189509
|
...getLiveNotificationParams(sessionId, liveModelBySession, variantBySession, agentBySession),
|
|
@@ -189259,6 +189716,7 @@ function truncateError(name2, code, message, maxLen = 240) {
|
|
|
189259
189716
|
|
|
189260
189717
|
// src/plugin/rpc-handlers.ts
|
|
189261
189718
|
init_project_identity();
|
|
189719
|
+
init_project_embedding_registry();
|
|
189262
189720
|
init_tool_definition_tokens();
|
|
189263
189721
|
await init_storage();
|
|
189264
189722
|
|
|
@@ -189979,6 +190437,26 @@ function buildStatusDetail(db, sessionId, directory, modelKey, config2, liveSess
|
|
|
189979
190437
|
}
|
|
189980
190438
|
return detail;
|
|
189981
190439
|
}
|
|
190440
|
+
function buildEmbedDetail(db, sessionId, dir, liveSessionState) {
|
|
190441
|
+
const projectIdentity = resolveProjectIdentity(dir);
|
|
190442
|
+
const coverage = getEmbeddingCoverageStatus(db, projectIdentity, sessionId);
|
|
190443
|
+
const progress = liveSessionState.recompProgressBySession.get(sessionId);
|
|
190444
|
+
const drainUi = getEmbedDrainUiStatus(sessionId, progress);
|
|
190445
|
+
const statusText = formatEmbedStatusText(coverage, {
|
|
190446
|
+
status: drainUi.status,
|
|
190447
|
+
embedded: progress?.processedMessages,
|
|
190448
|
+
total: progress?.totalMessages
|
|
190449
|
+
});
|
|
190450
|
+
return {
|
|
190451
|
+
enabled: coverage.enabled,
|
|
190452
|
+
model: coverage.model,
|
|
190453
|
+
provider: coverage.provider,
|
|
190454
|
+
session: coverage.session,
|
|
190455
|
+
memories: coverage.memories,
|
|
190456
|
+
commits: coverage.commits,
|
|
190457
|
+
statusText
|
|
190458
|
+
};
|
|
190459
|
+
}
|
|
189982
190460
|
function registerRpcHandlers(rpcServer, args) {
|
|
189983
190461
|
const { directory, config: config2, liveSessionState } = args;
|
|
189984
190462
|
const rawConfig = config2;
|
|
@@ -190001,6 +190479,19 @@ function registerRpcHandlers(rpcServer, args) {
|
|
|
190001
190479
|
return { error: "unavailable" };
|
|
190002
190480
|
return buildStatusDetail(db, sessionId, dir, modelKey, rawConfig, liveSessionState, injectionBudgetTokens);
|
|
190003
190481
|
});
|
|
190482
|
+
rpcServer.handle("embed-detail", async (params) => {
|
|
190483
|
+
const sessionId = String(params.sessionId ?? "");
|
|
190484
|
+
const dir = String(params.directory ?? directory);
|
|
190485
|
+
const db = getDb();
|
|
190486
|
+
if (!db || !sessionId)
|
|
190487
|
+
return { error: "unavailable" };
|
|
190488
|
+
try {
|
|
190489
|
+
return buildEmbedDetail(db, sessionId, dir, liveSessionState);
|
|
190490
|
+
} catch (err) {
|
|
190491
|
+
log("[rpc] embed-detail error:", err);
|
|
190492
|
+
return { error: "unavailable" };
|
|
190493
|
+
}
|
|
190494
|
+
});
|
|
190004
190495
|
rpcServer.handle("compartment-count", async (params) => {
|
|
190005
190496
|
const sessionId = String(params.sessionId ?? "");
|
|
190006
190497
|
const db = getDb();
|
|
@@ -190123,27 +190614,225 @@ Older parts of this session are summarized into <compartment> blocks inside <ses
|
|
|
190123
190614
|
|
|
190124
190615
|
ctx_expand(start=120, end=245) ← the compartment's own start/end attributes
|
|
190125
190616
|
|
|
190126
|
-
Returns the raw transcript as [N] U:/A: lines, capped at ~15K tokens; an oversized range returns the head and tells you where to continue. Also works with ordinals from ctx_search message results — expand a window around a hit (e.g. start=N-10, end=N+5). Ranges after the last compartment are your live tail — already visible in context, not expandable
|
|
190617
|
+
Returns the raw transcript as [N] U:/A: lines, capped at ~15K tokens; an oversized range returns the head and tells you where to continue. Also works with ordinals from ctx_search message results — expand a window around a hit (e.g. start=N-10, end=N+5). Ranges after the last compartment are your live tail — already visible in context, not expandable.
|
|
190618
|
+
|
|
190619
|
+
Two recovery modes for finer detail:
|
|
190620
|
+
- ctx_expand(start=120, end=245, verbose=true) — lists each message SEPARATELY with its ordinal [N] and a per-part preview (each tool call shown with its output size). Use this to find the exact message or tool call you want, then recover it in full by ordinal.
|
|
190621
|
+
- ctx_expand(message=138) — returns the FULL untruncated content of the message at that ordinal: every text part, and every tool call's complete input + output, read from stored history. This is the cheap way to get back a tool output you dropped with ctx_reduce — the original is still in storage even though the wire shows [dropped §N§]. If the message was deleted from history (session prune/revert), it says so.`;
|
|
190127
190622
|
var CTX_EXPAND_TOKEN_BUDGET = 15000;
|
|
190128
190623
|
|
|
190624
|
+
// src/tools/ctx-expand/render.ts
|
|
190625
|
+
init_read_session_formatting();
|
|
190626
|
+
await init_read_session_chunk();
|
|
190627
|
+
function isRecord3(value) {
|
|
190628
|
+
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
190629
|
+
}
|
|
190630
|
+
function roleLabel(role) {
|
|
190631
|
+
if (role === "assistant")
|
|
190632
|
+
return "A (assistant)";
|
|
190633
|
+
if (role === "user")
|
|
190634
|
+
return "U (user)";
|
|
190635
|
+
return role;
|
|
190636
|
+
}
|
|
190637
|
+
function truncate2(value, max) {
|
|
190638
|
+
const t = value.trim();
|
|
190639
|
+
return t.length <= max ? t : `${t.slice(0, max)}…`;
|
|
190640
|
+
}
|
|
190641
|
+
function keyArg(input) {
|
|
190642
|
+
if (!input)
|
|
190643
|
+
return "";
|
|
190644
|
+
for (const k of ["filePath", "path", "pattern", "query", "symbol", "module", "action"]) {
|
|
190645
|
+
const v = input[k];
|
|
190646
|
+
if (typeof v === "string" && v.length > 0)
|
|
190647
|
+
return truncate2(v, 60);
|
|
190648
|
+
}
|
|
190649
|
+
if (typeof input.description === "string")
|
|
190650
|
+
return truncate2(input.description, 60);
|
|
190651
|
+
return "";
|
|
190652
|
+
}
|
|
190653
|
+
function asToolPart(part) {
|
|
190654
|
+
const type = typeof part.type === "string" ? part.type : "";
|
|
190655
|
+
if (type === "tool") {
|
|
190656
|
+
const state = isRecord3(part.state) ? part.state : null;
|
|
190657
|
+
const output = state && typeof state.output === "string" ? state.output : state && state.output != null ? JSON.stringify(state.output) : null;
|
|
190658
|
+
const metadata = state && isRecord3(state.metadata) ? state.metadata : null;
|
|
190659
|
+
const title = state && typeof state.title === "string" && state.title || metadata && typeof metadata.title === "string" && metadata.title || null;
|
|
190660
|
+
return {
|
|
190661
|
+
name: typeof part.tool === "string" ? part.tool : "tool",
|
|
190662
|
+
callId: typeof part.callID === "string" ? part.callID : "",
|
|
190663
|
+
title,
|
|
190664
|
+
input: state && isRecord3(state.input) ? state.input : null,
|
|
190665
|
+
output
|
|
190666
|
+
};
|
|
190667
|
+
}
|
|
190668
|
+
if (type === "tool_use") {
|
|
190669
|
+
return {
|
|
190670
|
+
name: typeof part.name === "string" ? part.name : "tool",
|
|
190671
|
+
callId: typeof part.id === "string" ? part.id : "",
|
|
190672
|
+
title: null,
|
|
190673
|
+
input: isRecord3(part.input) ? part.input : null,
|
|
190674
|
+
output: null
|
|
190675
|
+
};
|
|
190676
|
+
}
|
|
190677
|
+
if (type === "tool_result") {
|
|
190678
|
+
const content = part.content;
|
|
190679
|
+
const output = typeof content === "string" ? content : content != null ? JSON.stringify(content) : null;
|
|
190680
|
+
return {
|
|
190681
|
+
name: "tool_result",
|
|
190682
|
+
callId: typeof part.tool_use_id === "string" ? part.tool_use_id : "",
|
|
190683
|
+
title: null,
|
|
190684
|
+
input: null,
|
|
190685
|
+
output
|
|
190686
|
+
};
|
|
190687
|
+
}
|
|
190688
|
+
return null;
|
|
190689
|
+
}
|
|
190690
|
+
function textOf(part) {
|
|
190691
|
+
if (part.type === "text" && typeof part.text === "string")
|
|
190692
|
+
return part.text;
|
|
190693
|
+
return null;
|
|
190694
|
+
}
|
|
190695
|
+
function reasoningOf(part) {
|
|
190696
|
+
if ((part.type === "reasoning" || part.type === "thinking") && typeof part.text === "string") {
|
|
190697
|
+
return part.text;
|
|
190698
|
+
}
|
|
190699
|
+
return null;
|
|
190700
|
+
}
|
|
190701
|
+
function renderPartPreview(part) {
|
|
190702
|
+
if (!isRecord3(part))
|
|
190703
|
+
return null;
|
|
190704
|
+
const text = textOf(part);
|
|
190705
|
+
if (text !== null) {
|
|
190706
|
+
const t = truncate2(text, 200);
|
|
190707
|
+
return t.length > 0 ? ` • ${t}` : null;
|
|
190708
|
+
}
|
|
190709
|
+
const tool = asToolPart(part);
|
|
190710
|
+
if (tool) {
|
|
190711
|
+
const arg = keyArg(tool.input);
|
|
190712
|
+
const head = arg ? `${tool.name}(${arg})` : tool.name;
|
|
190713
|
+
return tool.output !== null ? ` • tool ${head} → output ~${estimateTokens(tool.output)} tok` : ` • tool ${head}`;
|
|
190714
|
+
}
|
|
190715
|
+
const reasoning = reasoningOf(part);
|
|
190716
|
+
if (reasoning !== null)
|
|
190717
|
+
return ` • [reasoning] ${truncate2(reasoning, 120)}`;
|
|
190718
|
+
const type = typeof part.type === "string" ? part.type : "part";
|
|
190719
|
+
if (type === "file")
|
|
190720
|
+
return " • [file]";
|
|
190721
|
+
if (type === "step-start" || type === "step-finish")
|
|
190722
|
+
return null;
|
|
190723
|
+
return ` • [${type}]`;
|
|
190724
|
+
}
|
|
190725
|
+
function renderPartFull(part) {
|
|
190726
|
+
if (!isRecord3(part))
|
|
190727
|
+
return null;
|
|
190728
|
+
const text = textOf(part);
|
|
190729
|
+
if (text !== null) {
|
|
190730
|
+
return text.trim().length > 0 ? ` [text]
|
|
190731
|
+
${text}` : null;
|
|
190732
|
+
}
|
|
190733
|
+
const tool = asToolPart(part);
|
|
190734
|
+
if (tool) {
|
|
190735
|
+
const lines = [];
|
|
190736
|
+
const idSuffix = tool.callId ? ` #${tool.callId}` : "";
|
|
190737
|
+
lines.push(` [tool: ${tool.name}${idSuffix}]`);
|
|
190738
|
+
if (tool.title && tool.title.trim().length > 0) {
|
|
190739
|
+
lines.push(` description: ${tool.title.trim()}`);
|
|
190740
|
+
}
|
|
190741
|
+
if (tool.input)
|
|
190742
|
+
lines.push(` input: ${JSON.stringify(tool.input)}`);
|
|
190743
|
+
if (tool.output !== null)
|
|
190744
|
+
lines.push(` output:
|
|
190745
|
+
${tool.output}`);
|
|
190746
|
+
return lines.join(`
|
|
190747
|
+
`);
|
|
190748
|
+
}
|
|
190749
|
+
const type = typeof part.type === "string" ? part.type : "part";
|
|
190750
|
+
if (type === "file") {
|
|
190751
|
+
const name2 = typeof part.filename === "string" && part.filename || typeof part.url === "string" && part.url || "";
|
|
190752
|
+
return ` [file]${name2 ? ` ${name2}` : ""}`;
|
|
190753
|
+
}
|
|
190754
|
+
return null;
|
|
190755
|
+
}
|
|
190756
|
+
function renderMessageByOrdinal(sessionId, ordinal) {
|
|
190757
|
+
const msg = readRawSessionMessages(sessionId).find((m) => m.ordinal === ordinal);
|
|
190758
|
+
if (!msg) {
|
|
190759
|
+
return `No message at ordinal ${ordinal} in this session's stored history — it was deleted ` + `(session prune/revert) or the ordinal is wrong, so it can't be recovered. ` + `Re-run the tool if you still need the data.`;
|
|
190760
|
+
}
|
|
190761
|
+
const rendered = msg.parts.map(renderPartFull).filter((l) => l !== null);
|
|
190762
|
+
const lines = [`[${msg.ordinal}] ${roleLabel(msg.role)} — full recovery:`, ""];
|
|
190763
|
+
if (rendered.length === 0) {
|
|
190764
|
+
lines.push(" (no recoverable content — message had only structural/reasoning parts)");
|
|
190765
|
+
} else {
|
|
190766
|
+
lines.push(...rendered);
|
|
190767
|
+
}
|
|
190768
|
+
return lines.join(`
|
|
190769
|
+
`);
|
|
190770
|
+
}
|
|
190771
|
+
function renderVerboseRange(sessionId, start, end, tokenBudget) {
|
|
190772
|
+
const messages = readRawSessionMessages(sessionId).filter((m) => m.ordinal >= start && m.ordinal <= end);
|
|
190773
|
+
const out = [];
|
|
190774
|
+
let usedTokens = 0;
|
|
190775
|
+
let lastOrdinal = start - 1;
|
|
190776
|
+
let truncated = false;
|
|
190777
|
+
for (const msg of messages) {
|
|
190778
|
+
const header = `[${msg.ordinal}] ${roleLabel(msg.role)}`;
|
|
190779
|
+
const partLines = msg.parts.map(renderPartPreview).filter((l) => l !== null);
|
|
190780
|
+
const block = partLines.length > 0 ? `${header}
|
|
190781
|
+
${partLines.join(`
|
|
190782
|
+
`)}` : header;
|
|
190783
|
+
const blockTokens = estimateTokens(block);
|
|
190784
|
+
if (usedTokens + blockTokens > tokenBudget && out.length > 0) {
|
|
190785
|
+
truncated = true;
|
|
190786
|
+
break;
|
|
190787
|
+
}
|
|
190788
|
+
out.push(block);
|
|
190789
|
+
usedTokens += blockTokens;
|
|
190790
|
+
lastOrdinal = msg.ordinal;
|
|
190791
|
+
}
|
|
190792
|
+
return { text: out.join(`
|
|
190793
|
+
|
|
190794
|
+
`), lastOrdinal, truncated };
|
|
190795
|
+
}
|
|
190796
|
+
|
|
190129
190797
|
// src/tools/ctx-expand/tools.ts
|
|
190130
190798
|
function createCtxExpandTool(deps) {
|
|
190131
190799
|
return tool({
|
|
190132
190800
|
description: CTX_EXPAND_DESCRIPTION,
|
|
190133
190801
|
args: {
|
|
190134
|
-
start: tool.schema.number().describe(`First message ordinal to expand — a compartment's start="N" attribute, or an ordinal from a ctx_search message hit`),
|
|
190135
|
-
end: tool.schema.number().describe(`Last message ordinal to expand (inclusive) — a compartment's end="M" attribute`)
|
|
190802
|
+
start: tool.schema.number().optional().describe(`First message ordinal to expand — a compartment's start="N" attribute, or an ordinal from a ctx_search message hit`),
|
|
190803
|
+
end: tool.schema.number().optional().describe(`Last message ordinal to expand (inclusive) — a compartment's end="M" attribute`),
|
|
190804
|
+
verbose: tool.schema.boolean().optional().describe("With start/end: list each message separately with its ordinal [N] and per-part preview (each tool call shown with its output size), so you can pick one to recover in full by ordinal."),
|
|
190805
|
+
message: tool.schema.number().optional().describe("Full untruncated recovery of ONE message by its ordinal (every text part + every tool call's complete input/output). Use an ordinal from a compartment, ctx_search hit, or verbose range. Recovers a tool output you dropped with ctx_reduce.")
|
|
190136
190806
|
},
|
|
190137
190807
|
async execute(args, toolContext) {
|
|
190138
190808
|
const sessionId = toolContext.sessionID;
|
|
190809
|
+
if (typeof args.message === "number" && args.message >= 1) {
|
|
190810
|
+
return renderMessageByOrdinal(sessionId, args.message);
|
|
190811
|
+
}
|
|
190139
190812
|
if (!args.start || !args.end || args.start < 1 || args.end < args.start) {
|
|
190140
|
-
return "Error: start and end
|
|
190813
|
+
return "Error: provide either message=<ordinal>, or start and end (positive integers, start <= end).";
|
|
190141
190814
|
}
|
|
190142
190815
|
const lastCompartmentEnd = getLastCompartmentEndMessage(deps.db, sessionId);
|
|
190143
190816
|
if (lastCompartmentEnd >= 0 && args.start > lastCompartmentEnd) {
|
|
190144
190817
|
return `Range ${args.start}-${args.end} is entirely within the live tail (after the last compacted message ${lastCompartmentEnd}); those messages are already visible in context.`;
|
|
190145
190818
|
}
|
|
190146
190819
|
const effectiveEnd = lastCompartmentEnd >= 0 ? Math.min(args.end, lastCompartmentEnd) : args.end;
|
|
190820
|
+
if (args.verbose === true) {
|
|
190821
|
+
const v = renderVerboseRange(sessionId, args.start, effectiveEnd, CTX_EXPAND_TOKEN_BUDGET);
|
|
190822
|
+
if (!v.text) {
|
|
190823
|
+
return `No messages found in range ${args.start}-${effectiveEnd}. The range may be outside this session's history.`;
|
|
190824
|
+
}
|
|
190825
|
+
const out = [
|
|
190826
|
+
`Messages ${args.start}-${v.lastOrdinal} (verbose). Recover any one in full with ctx_expand(message=<ordinal>):`,
|
|
190827
|
+
"",
|
|
190828
|
+
v.text
|
|
190829
|
+
];
|
|
190830
|
+
if (v.truncated) {
|
|
190831
|
+
out.push("", `Truncated at message ${v.lastOrdinal} (budget: ~${CTX_EXPAND_TOKEN_BUDGET} tokens). Call again with start=${v.lastOrdinal + 1} end=${effectiveEnd} verbose=true for more.`);
|
|
190832
|
+
}
|
|
190833
|
+
return out.join(`
|
|
190834
|
+
`);
|
|
190835
|
+
}
|
|
190147
190836
|
const chunk = readSessionChunk(sessionId, CTX_EXPAND_TOKEN_BUDGET, args.start, effectiveEnd + 1);
|
|
190148
190837
|
if (!chunk.text || chunk.messageCount === 0) {
|
|
190149
190838
|
return `No messages found in range ${args.start}-${args.end}. The range may be outside this session's history.`;
|
|
@@ -190837,15 +191526,16 @@ function createCtxNoteTools(deps) {
|
|
|
190837
191526
|
};
|
|
190838
191527
|
}
|
|
190839
191528
|
// src/tools/ctx-reduce/constants.ts
|
|
190840
|
-
var CTX_REDUCE_DESCRIPTION = `
|
|
190841
|
-
|
|
190842
|
-
|
|
190843
|
-
|
|
190844
|
-
-
|
|
190845
|
-
-
|
|
190846
|
-
|
|
190847
|
-
|
|
190848
|
-
|
|
191529
|
+
var CTX_REDUCE_DESCRIPTION = `Mark spent tagged content as discardable to reclaim context space. This is NOT an immediate delete. Use §N§ identifiers visible in the conversation. The \`drop\` param accepts ranges: "3-5", "1,2,9", "1-5,8".
|
|
191530
|
+
|
|
191531
|
+
How it works:
|
|
191532
|
+
- Marking QUEUES content for release. It stays fully visible to you until context space is actually needed — which may be as soon as the next turn if you are already under pressure, or many turns later if not. So mark spent outputs as soon as you finish with them; don't hoard the call for the end of the turn.
|
|
191533
|
+
- The newest tags are protected: marking one just queues it until it ages out of the recent window, so marking recent output is harmless.
|
|
191534
|
+
- When content is finally released it becomes a short placeholder, and re-running the tool is the only way to get it back. So mark only what you are genuinely DONE with — the test is "have I extracted what I need from this?", not "is it safe / do I have time before it drops?".
|
|
191535
|
+
|
|
191536
|
+
Mark discardable once processed: large outputs you've summarized, repeated or redundant dumps, data written to disk, status/log output that only confirmed an expected state.
|
|
191537
|
+
Keep: user messages, unresolved errors, raw evidence you haven't extracted yet, and outputs whose exact wording may matter later.
|
|
191538
|
+
Never blanket-mark large ranges (e.g. "1-50") — review what each tag holds first.`;
|
|
190849
191539
|
// src/tools/ctx-reduce/tools.ts
|
|
190850
191540
|
import { tool as tool4 } from "@opencode-ai/plugin";
|
|
190851
191541
|
|
|
@@ -191428,6 +192118,9 @@ class MagicContextRpcServer {
|
|
|
191428
192118
|
}
|
|
191429
192119
|
|
|
191430
192120
|
// src/index.ts
|
|
192121
|
+
var HISTORIAN_MAX_STEPS = 40;
|
|
192122
|
+
var SIDEKICK_MAX_STEPS = 40;
|
|
192123
|
+
var DREAMER_MAX_STEPS = 150;
|
|
191431
192124
|
var plugin = async (ctx) => {
|
|
191432
192125
|
const pluginConfig = loadPluginConfig(ctx.directory);
|
|
191433
192126
|
setSqlitePragmaConfig({
|
|
@@ -191620,11 +192313,13 @@ var plugin = async (ctx) => {
|
|
|
191620
192313
|
await hooks.magicContext?.["experimental.text.complete"]?.(input, output);
|
|
191621
192314
|
},
|
|
191622
192315
|
config: async (config2) => {
|
|
191623
|
-
const buildHiddenAgentConfig = (agentId, prompt, allowedTools, overrides) => {
|
|
192316
|
+
const buildHiddenAgentConfig = (agentId, prompt, allowedTools, maxSteps, overrides) => {
|
|
191624
192317
|
const { permission: overridePermission, ...restOverrides } = overrides ?? {};
|
|
191625
192318
|
const basePermission = buildAllowOnlyPermission(allowedTools);
|
|
191626
192319
|
return {
|
|
191627
192320
|
prompt,
|
|
192321
|
+
steps: maxSteps,
|
|
192322
|
+
maxSteps,
|
|
191628
192323
|
...getAgentFallbackModels(agentId) ? { fallback_models: getAgentFallbackModels(agentId) } : {},
|
|
191629
192324
|
...restOverrides,
|
|
191630
192325
|
permission: {
|
|
@@ -191665,10 +192360,10 @@ var plugin = async (ctx) => {
|
|
|
191665
192360
|
})() : undefined;
|
|
191666
192361
|
config2.agent = {
|
|
191667
192362
|
...config2.agent ?? {},
|
|
191668
|
-
[DREAMER_AGENT]: buildHiddenAgentConfig(DREAMER_AGENT, DREAMER_SYSTEM_PROMPT, DREAMER_ALLOWED_TOOLS, dreamerAgentOverrides),
|
|
191669
|
-
[HISTORIAN_AGENT]: buildHiddenAgentConfig(HISTORIAN_AGENT, COMPARTMENT_AGENT_SYSTEM_PROMPT, HISTORIAN_ALLOWED_TOOLS, historianAgentOverrides),
|
|
191670
|
-
[HISTORIAN_EDITOR_AGENT]: buildHiddenAgentConfig(HISTORIAN_EDITOR_AGENT, HISTORIAN_EDITOR_SYSTEM_PROMPT, HISTORIAN_ALLOWED_TOOLS, historianAgentOverrides),
|
|
191671
|
-
[SIDEKICK_AGENT]: buildHiddenAgentConfig(SIDEKICK_AGENT, SIDEKICK_SYSTEM_PROMPT, SIDEKICK_ALLOWED_TOOLS, sidekickAgentOverrides)
|
|
192363
|
+
[DREAMER_AGENT]: buildHiddenAgentConfig(DREAMER_AGENT, DREAMER_SYSTEM_PROMPT, DREAMER_ALLOWED_TOOLS, DREAMER_MAX_STEPS, dreamerAgentOverrides),
|
|
192364
|
+
[HISTORIAN_AGENT]: buildHiddenAgentConfig(HISTORIAN_AGENT, COMPARTMENT_AGENT_SYSTEM_PROMPT, HISTORIAN_ALLOWED_TOOLS, HISTORIAN_MAX_STEPS, historianAgentOverrides),
|
|
192365
|
+
[HISTORIAN_EDITOR_AGENT]: buildHiddenAgentConfig(HISTORIAN_EDITOR_AGENT, HISTORIAN_EDITOR_SYSTEM_PROMPT, HISTORIAN_ALLOWED_TOOLS, HISTORIAN_MAX_STEPS, historianAgentOverrides),
|
|
192366
|
+
[SIDEKICK_AGENT]: buildHiddenAgentConfig(SIDEKICK_AGENT, SIDEKICK_SYSTEM_PROMPT, SIDEKICK_ALLOWED_TOOLS, SIDEKICK_MAX_STEPS, sidekickAgentOverrides)
|
|
191672
192367
|
};
|
|
191673
192368
|
}
|
|
191674
192369
|
};
|