@cortexkit/pi-magic-context 0.27.3 → 0.29.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/index.js +451 -76
- package/dist/subagent-entry.js +153 -8
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -15568,7 +15568,7 @@ function compareTaskOrder(a, b) {
|
|
|
15568
15568
|
}
|
|
15569
15569
|
|
|
15570
15570
|
// ../plugin/src/features/magic-context/dreamer/task-config.ts
|
|
15571
|
-
function buildDreamTaskRuntimeConfigs(dreamer) {
|
|
15571
|
+
function buildDreamTaskRuntimeConfigs(dreamer, language) {
|
|
15572
15572
|
const tasks = dreamer.tasks ?? {};
|
|
15573
15573
|
return CANONICAL_DREAM_TASKS.map((task) => {
|
|
15574
15574
|
const t = tasks[task] ?? {
|
|
@@ -15584,6 +15584,7 @@ function buildDreamTaskRuntimeConfigs(dreamer) {
|
|
|
15584
15584
|
model,
|
|
15585
15585
|
fallbackModels,
|
|
15586
15586
|
thinkingLevel,
|
|
15587
|
+
language,
|
|
15587
15588
|
timeoutMinutes: t.timeout_minutes ?? 20,
|
|
15588
15589
|
promotionThreshold: t.promotion_threshold
|
|
15589
15590
|
};
|
|
@@ -15905,6 +15906,17 @@ function getRawSessionMessageCountFromDb(db, sessionId) {
|
|
|
15905
15906
|
return typeof row?.count === "number" ? row.count : 0;
|
|
15906
15907
|
}
|
|
15907
15908
|
|
|
15909
|
+
// ../plugin/src/shared/commit-detection.ts
|
|
15910
|
+
var HASH_HEX = "[0-9a-f]{7,12}";
|
|
15911
|
+
var COMMIT_HASH_TEST_PATTERN = new RegExp(`\\b${HASH_HEX}\\b`, "i");
|
|
15912
|
+
var COMMIT_VERB_PATTERN = /\b(?:commit(?:ted|ting|s)?|cherry-?pick(?:ed|ing|s)?|merge[ds]?|merging|rebas(?:e|ed|es|ing))\b/i;
|
|
15913
|
+
function textMentionsRecentCommit(text) {
|
|
15914
|
+
return COMMIT_HASH_TEST_PATTERN.test(text) && COMMIT_VERB_PATTERN.test(text);
|
|
15915
|
+
}
|
|
15916
|
+
function createCommitHashExtractPattern() {
|
|
15917
|
+
return new RegExp(`\`?\\b(${HASH_HEX})\\b\`?`, "gi");
|
|
15918
|
+
}
|
|
15919
|
+
|
|
15908
15920
|
// ../../node_modules/.bun/ai-tokenizer@1.0.6/node_modules/ai-tokenizer/dist/index.js
|
|
15909
15921
|
function _typeof(o) {
|
|
15910
15922
|
"@babel/helpers - typeof";
|
|
@@ -148344,8 +148356,6 @@ var decoder = {
|
|
|
148344
148356
|
};
|
|
148345
148357
|
|
|
148346
148358
|
// ../plugin/src/hooks/magic-context/read-session-formatting.ts
|
|
148347
|
-
var COMMIT_HASH_PATTERN = /`?\b([0-9a-f]{6,12})\b`?/gi;
|
|
148348
|
-
var COMMIT_HINT_PATTERN = /\b(commit(?:ted)?|cherry-?pick(?:ed)?|hash(?:es)?|sha)\b/i;
|
|
148349
148359
|
var MAX_COMMITS_PER_BLOCK = 5;
|
|
148350
148360
|
function hasMeaningfulUserText(parts) {
|
|
148351
148361
|
for (const part of parts) {
|
|
@@ -148449,7 +148459,7 @@ function formatBlock(block) {
|
|
|
148449
148459
|
function extractCommitHashes(text) {
|
|
148450
148460
|
const hashes = [];
|
|
148451
148461
|
const seen = new Set;
|
|
148452
|
-
for (const match of text.matchAll(
|
|
148462
|
+
for (const match of text.matchAll(createCommitHashExtractPattern())) {
|
|
148453
148463
|
const hash = match[1]?.toLowerCase();
|
|
148454
148464
|
if (!hash || seen.has(hash))
|
|
148455
148465
|
continue;
|
|
@@ -148462,10 +148472,10 @@ function extractCommitHashes(text) {
|
|
|
148462
148472
|
}
|
|
148463
148473
|
function compactTextForSummary(text, role) {
|
|
148464
148474
|
const commitHashes = role === "assistant" ? extractCommitHashes(text) : [];
|
|
148465
|
-
if (commitHashes.length === 0 || !
|
|
148475
|
+
if (commitHashes.length === 0 || !COMMIT_VERB_PATTERN.test(text)) {
|
|
148466
148476
|
return { text, commitHashes };
|
|
148467
148477
|
}
|
|
148468
|
-
const withoutHashes = text.replace(
|
|
148478
|
+
const withoutHashes = text.replace(createCommitHashExtractPattern(), "").replace(/\(\s*\)/g, "").replace(/\s+,/g, ",").replace(/,\s*,+/g, ", ").replace(/\s{2,}/g, " ").replace(/\s+([,.;:])/g, "$1").trim();
|
|
148469
148479
|
return {
|
|
148470
148480
|
text: withoutHashes.length > 0 ? withoutHashes : text,
|
|
148471
148481
|
commitHashes
|
|
@@ -148687,6 +148697,36 @@ function isRecord(value) {
|
|
|
148687
148697
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
148688
148698
|
}
|
|
148689
148699
|
|
|
148700
|
+
// ../plugin/src/hooks/magic-context/edit-marker.ts
|
|
148701
|
+
var TRUNCATION_SENTINEL = "...[truncated]";
|
|
148702
|
+
var EDIT_REGION_HINT_LEN = 40;
|
|
148703
|
+
var PATH_KEYS = new Set(["filePath", "file_path", "path"]);
|
|
148704
|
+
var DIFF_KEYS = new Set(["oldString", "newString", "content", "old_string", "new_string"]);
|
|
148705
|
+
function safeSlice(str, maxLen) {
|
|
148706
|
+
if (str.length <= maxLen)
|
|
148707
|
+
return str;
|
|
148708
|
+
const lastCharCode = str.charCodeAt(maxLen - 1);
|
|
148709
|
+
if (lastCharCode >= 55296 && lastCharCode <= 56319) {
|
|
148710
|
+
return str.slice(0, maxLen - 1);
|
|
148711
|
+
}
|
|
148712
|
+
return str.slice(0, maxLen);
|
|
148713
|
+
}
|
|
148714
|
+
function isEditTool(name2) {
|
|
148715
|
+
return name2 === "edit" || name2 === "write";
|
|
148716
|
+
}
|
|
148717
|
+
function applyEditMarkerToInput(input) {
|
|
148718
|
+
for (const key of Object.keys(input)) {
|
|
148719
|
+
if (PATH_KEYS.has(key))
|
|
148720
|
+
continue;
|
|
148721
|
+
const value = input[key];
|
|
148722
|
+
if (typeof value !== "string" || !DIFF_KEYS.has(key))
|
|
148723
|
+
continue;
|
|
148724
|
+
if (value.endsWith(TRUNCATION_SENTINEL))
|
|
148725
|
+
continue;
|
|
148726
|
+
input[key] = value.length > EDIT_REGION_HINT_LEN ? `${safeSlice(value, EDIT_REGION_HINT_LEN)}${TRUNCATION_SENTINEL}` : value;
|
|
148727
|
+
}
|
|
148728
|
+
}
|
|
148729
|
+
|
|
148690
148730
|
// ../plugin/src/hooks/magic-context/tool-drop-target.ts
|
|
148691
148731
|
var IGNORE_PART_TYPES = new Set([
|
|
148692
148732
|
"thinking",
|
|
@@ -155056,6 +155096,9 @@ function getActiveTagTokenAggregate(db, sessionId, protectedTags = 0) {
|
|
|
155056
155096
|
nullCount: row?.null_count ?? 0
|
|
155057
155097
|
};
|
|
155058
155098
|
}
|
|
155099
|
+
var RECLAIM_HINT_EXCLUDED_TOOLS = ["todowrite"];
|
|
155100
|
+
var RECLAIM_HINT_MIN_TOKENS = 250;
|
|
155101
|
+
var RECLAIM_HINT_EXCLUDED_LIST = RECLAIM_HINT_EXCLUDED_TOOLS.map((name2) => `'${name2.replace(/'/g, "''")}'`).join(", ");
|
|
155059
155102
|
function getOldestActiveUnprotectedToolTags(db, sessionId, protectedTags = 0, limit = 4) {
|
|
155060
155103
|
if (limit <= 0)
|
|
155061
155104
|
return [];
|
|
@@ -155065,10 +155108,18 @@ function getOldestActiveUnprotectedToolTags(db, sessionId, protectedTags = 0, li
|
|
|
155065
155108
|
WHERE session_id = ? AND status = 'active'
|
|
155066
155109
|
ORDER BY tag_number DESC LIMIT 1 OFFSET ?
|
|
155067
155110
|
)` : "";
|
|
155068
|
-
const
|
|
155111
|
+
const excludeStateTools = RECLAIM_HINT_EXCLUDED_LIST ? `AND (tool_name IS NULL OR tool_name NOT IN (${RECLAIM_HINT_EXCLUDED_LIST}))` : "";
|
|
155112
|
+
const valueFloor = `AND (
|
|
155113
|
+
(token_count IS NULL AND input_token_count IS NULL)
|
|
155114
|
+
OR (COALESCE(token_count, 0) + COALESCE(input_token_count, 0)) >= ?
|
|
155115
|
+
)`;
|
|
155116
|
+
const params = protectedTags > 0 ? [sessionId, RECLAIM_HINT_MIN_TOKENS, sessionId, protectedTags - 1, boundedLimit] : [sessionId, RECLAIM_HINT_MIN_TOKENS, boundedLimit];
|
|
155069
155117
|
const rows = db.prepare(`SELECT tag_number, tool_name
|
|
155070
155118
|
FROM tags
|
|
155071
|
-
WHERE session_id = ? AND status = 'active' AND type = 'tool'
|
|
155119
|
+
WHERE session_id = ? AND status = 'active' AND type = 'tool'
|
|
155120
|
+
${excludeStateTools}
|
|
155121
|
+
${valueFloor}
|
|
155122
|
+
${whereProtected}
|
|
155072
155123
|
ORDER BY tag_number ASC, id ASC
|
|
155073
155124
|
LIMIT ?`).all(...params);
|
|
155074
155125
|
return rows.filter((row) => typeof row.tag_number === "number").map((row) => ({
|
|
@@ -155179,7 +155230,7 @@ function toTagEntry(row) {
|
|
|
155179
155230
|
messageId: row.message_id,
|
|
155180
155231
|
type,
|
|
155181
155232
|
status,
|
|
155182
|
-
dropMode: row.drop_mode === "truncated" ? "truncated" : "full",
|
|
155233
|
+
dropMode: row.drop_mode === "truncated" ? "truncated" : row.drop_mode === "edit_marker" ? "edit_marker" : "full",
|
|
155183
155234
|
toolName: row.tool_name ?? null,
|
|
155184
155235
|
inputByteSize: row.input_byte_size ?? 0,
|
|
155185
155236
|
byteSize: row.byte_size,
|
|
@@ -156335,13 +156386,10 @@ function compareSemverCore(a, b) {
|
|
|
156335
156386
|
|
|
156336
156387
|
// ../plugin/src/shared/announcement.ts
|
|
156337
156388
|
init_data_path();
|
|
156338
|
-
var ANNOUNCEMENT_VERSION = "0.
|
|
156389
|
+
var ANNOUNCEMENT_VERSION = "0.29.0";
|
|
156339
156390
|
var ANNOUNCEMENT_FEATURES = [
|
|
156340
|
-
|
|
156341
|
-
"
|
|
156342
|
-
"New Primers: durable answers to the questions that keep coming up about your project, kept current by the dreamer investigating the actual code.",
|
|
156343
|
-
"Embedding storage no longer wipes your vectors when you change model or endpoint. Different models now coexist, so switching providers keeps your existing vectors.",
|
|
156344
|
-
"Config moved to a shared CortexKit location (~/.config/cortexkit/ and <project>/.cortexkit/). This happens automatically on first run; your old file is preserved."
|
|
156391
|
+
`New 'smart_drops' option (opt-in, off by default): on long, edit-heavy sessions it reclaims more context by dropping tool output a later call made obsolete (superseded edits, old todowrite/ctx_reduce, spent status calls) instead of only the oldest. When off, the prompt is byte-identical to before. Enable with "smart_drops": true.`,
|
|
156392
|
+
"When memory is disabled, the ctx_memory tool and its guidance are no longer shown (they had nothing to write to). ctx_search stays, searching conversation history and git commits."
|
|
156345
156393
|
];
|
|
156346
156394
|
var ANNOUNCEMENT_FOOTER = "Join us on Discord: https://discord.gg/F2uWxjGnU";
|
|
156347
156395
|
var STATE_FILENAME = "last_announced_version";
|
|
@@ -156403,6 +156451,95 @@ function shouldKeepSubagents() {
|
|
|
156403
156451
|
// src/index.ts
|
|
156404
156452
|
init_logger();
|
|
156405
156453
|
|
|
156454
|
+
// ../plugin/src/agents/language-directive.ts
|
|
156455
|
+
var ENGLISH_LANGUAGE_NAMES = new Intl.DisplayNames(["en"], {
|
|
156456
|
+
type: "language",
|
|
156457
|
+
fallback: "none"
|
|
156458
|
+
});
|
|
156459
|
+
function resolveLanguageName(language) {
|
|
156460
|
+
const code = typeof language === "string" ? language.trim().toLowerCase() : "";
|
|
156461
|
+
if (!/^[a-z]{2}$/.test(code))
|
|
156462
|
+
return "";
|
|
156463
|
+
let english;
|
|
156464
|
+
try {
|
|
156465
|
+
english = ENGLISH_LANGUAGE_NAMES.of(code) ?? undefined;
|
|
156466
|
+
} catch {
|
|
156467
|
+
return "";
|
|
156468
|
+
}
|
|
156469
|
+
if (!english)
|
|
156470
|
+
return "";
|
|
156471
|
+
let endonym;
|
|
156472
|
+
try {
|
|
156473
|
+
endonym = new Intl.DisplayNames([code], { type: "language", fallback: "none" }).of(code) ?? undefined;
|
|
156474
|
+
} catch {
|
|
156475
|
+
endonym = undefined;
|
|
156476
|
+
}
|
|
156477
|
+
return endonym && endonym !== english ? `${english} (${endonym})` : english;
|
|
156478
|
+
}
|
|
156479
|
+
function isValidLanguageCode(language) {
|
|
156480
|
+
return resolveLanguageName(language) !== "";
|
|
156481
|
+
}
|
|
156482
|
+
function buildContentLanguageDirective(language, options = {}) {
|
|
156483
|
+
const target = resolveLanguageName(language);
|
|
156484
|
+
if (!target)
|
|
156485
|
+
return "";
|
|
156486
|
+
const lines = [
|
|
156487
|
+
"## Output language",
|
|
156488
|
+
"",
|
|
156489
|
+
`Write human-readable prose you author in: ${target}.`,
|
|
156490
|
+
"",
|
|
156491
|
+
"Do not translate or rename structural tokens. Copy required output schemas exactly:",
|
|
156492
|
+
"- XML tag names, XML attribute names, JSON keys, tool names, tool-call argument keys, enum values, booleans/null, and required sentinel strings stay in English exactly as shown.",
|
|
156493
|
+
"- Keep code identifiers, file paths, commands, config keys, CLI flags, URLs, commit hashes, model/provider IDs, stack traces, diagnostics, and transcript role markers such as U:, A:, and TC: verbatim.",
|
|
156494
|
+
"- Localize only free-text prose values/content: summaries, memory text, explanations, titles, observations, and answers — unless the prompt says to preserve original wording.",
|
|
156495
|
+
"",
|
|
156496
|
+
"These literal values must remain English when used:",
|
|
156497
|
+
"PROJECT_RULES, ARCHITECTURE, CONSTRAINTS, CONFIG_VALUES, NAMING;",
|
|
156498
|
+
"causal_incident, trajectory_correction;",
|
|
156499
|
+
"feature, design, docs, release, investigation, bug, refactor, infra;",
|
|
156500
|
+
"memory, observation; true, false; No relevant memories found.",
|
|
156501
|
+
"",
|
|
156502
|
+
"Preserve the required output shape. Do not add commentary outside the requested XML/JSON/tool output."
|
|
156503
|
+
];
|
|
156504
|
+
if (options.preserveUserQuotes) {
|
|
156505
|
+
lines.push("", `Preserve U: lines and directly quoted user text in their original source language; write the surrounding summary prose in ${target}.`);
|
|
156506
|
+
}
|
|
156507
|
+
if (options.retrospective) {
|
|
156508
|
+
lines.push("", `Write the lesson text in ${target}; paraphrase source text and never quote the user.`);
|
|
156509
|
+
}
|
|
156510
|
+
return lines.join(`
|
|
156511
|
+
`);
|
|
156512
|
+
}
|
|
156513
|
+
function withContentLanguageDirective(systemPrompt, language, options = {}) {
|
|
156514
|
+
const directive = buildContentLanguageDirective(language, options);
|
|
156515
|
+
return directive ? `${systemPrompt}
|
|
156516
|
+
|
|
156517
|
+
${directive}` : systemPrompt;
|
|
156518
|
+
}
|
|
156519
|
+
function buildMigrationLanguageDirective(language) {
|
|
156520
|
+
const target = resolveLanguageName(language);
|
|
156521
|
+
if (!target)
|
|
156522
|
+
return "";
|
|
156523
|
+
return [
|
|
156524
|
+
"## Output language",
|
|
156525
|
+
"",
|
|
156526
|
+
"Preserve each migrated memory's existing language — do NOT translate a memory just because an output language is set. When merging memories written in different languages, use the language of the clearest / source-majority memory; otherwise keep the source phrasing. Only the category re-mapping changes."
|
|
156527
|
+
].join(`
|
|
156528
|
+
`);
|
|
156529
|
+
}
|
|
156530
|
+
function withMigrationLanguageDirective(systemPrompt, language) {
|
|
156531
|
+
const directive = buildMigrationLanguageDirective(language);
|
|
156532
|
+
return directive ? `${systemPrompt}
|
|
156533
|
+
|
|
156534
|
+
${directive}` : systemPrompt;
|
|
156535
|
+
}
|
|
156536
|
+
function buildPrimaryLanguageDirective(language) {
|
|
156537
|
+
const target = resolveLanguageName(language);
|
|
156538
|
+
if (!target)
|
|
156539
|
+
return "";
|
|
156540
|
+
return `Use ${target} for your natural-language replies to the user unless the user explicitly asks for another language. Keep code, identifiers, file paths, commands, logs, and quoted text verbatim.`;
|
|
156541
|
+
}
|
|
156542
|
+
|
|
156406
156543
|
// ../plugin/src/features/magic-context/sidekick/core.ts
|
|
156407
156544
|
var SIDEKICK_SYSTEM_PROMPT = `You are Sidekick, a focused memory-retrieval subagent for an AI coding assistant.
|
|
156408
156545
|
|
|
@@ -157123,7 +157260,7 @@ function registerCtxAugCommand(pi, config) {
|
|
|
157123
157260
|
sessionLog(sessionLabel, "/ctx-aug: project identity", projectIdentity);
|
|
157124
157261
|
const result = await runner.run({
|
|
157125
157262
|
agent: "sidekick",
|
|
157126
|
-
systemPrompt: config.systemPrompt ?? SIDEKICK_SYSTEM_PROMPT,
|
|
157263
|
+
systemPrompt: withContentLanguageDirective(config.systemPrompt ?? SIDEKICK_SYSTEM_PROMPT, config.language),
|
|
157127
157264
|
userMessage: prompt,
|
|
157128
157265
|
model: config.model,
|
|
157129
157266
|
fallbackModels: config.fallbackModels,
|
|
@@ -172319,6 +172456,7 @@ var EmbeddingConfigSchema = BaseEmbeddingConfigSchema.transform((data) => {
|
|
|
172319
172456
|
var MagicContextConfigSchema = exports_external.object({
|
|
172320
172457
|
enabled: exports_external.boolean().default(true).describe("Enable magic context (default: true)"),
|
|
172321
172458
|
auto_update: exports_external.boolean().optional().describe("Enable automatic npm self-update checks for the OpenCode plugin. Security: USER-only in config loader, so hostile project configs cannot suppress updates."),
|
|
172459
|
+
language: exports_external.string().trim().toLowerCase().refine((s) => isValidLanguageCode(s), 'language must be a 2-letter ISO 639-1 code (e.g. "tr", "es", "de")').optional().describe("Output language for Magic Context's generated content and guidance, as a " + '2-letter ISO 639-1 code (e.g. "tr", "es", "de", "ja", "pt"). When set, the ' + "historian, dreamer, sidekick, and the agent-guidance block instruct the model to " + "write its PROSE in this language while keeping all structural tokens (XML tags, " + "the five memory category names, code identifiers, file paths) in English. " + "USER-LEVEL ONLY (ignored in project config for security). Unset = today's " + "behavior (model mirrors the conversation; English scaffolding). Changing it " + "triggers one cache re-materialization; existing compartments/memories keep their " + "original language until naturally rewritten."),
|
|
172322
172460
|
ctx_reduce_enabled: exports_external.boolean().default(true).describe("When false, ctx_reduce tool is hidden, all nudges disabled, and prompt guidance about ctx_reduce stripped. Heuristic cleanup, compartments, memory, and other features still work. (default: true)"),
|
|
172323
172461
|
historian: HistorianConfigSchema.describe("Historian agent configuration (model, fallback_models, variant, temperature, maxTokens, permission, two_pass, etc.)"),
|
|
172324
172462
|
dreamer: DreamerConfigSchema.optional().describe("Dreamer agent + scheduling configuration (model, fallback_models, disable, schedule, tasks, etc.)"),
|
|
@@ -172356,6 +172494,7 @@ var MagicContextConfigSchema = exports_external.object({
|
|
|
172356
172494
|
}).describe("Embedding provider configuration"),
|
|
172357
172495
|
temporal_awareness: exports_external.boolean().default(true).describe('Inject wall-clock gap markers (<!-- +Xm -->) between user messages where > 5 min elapsed since the previous message, and add start/end date attributes on compartments. Gives the agent a sense of session pacing and "how long ago" across multi-day sessions. Graduated from experimental.temporal_awareness; default: true (set false to opt out).'),
|
|
172358
172496
|
keep_subagents: exports_external.boolean().default(false).describe("Debug: keep the child sessions Magic Context spawns for its own subagents (historian, dreamer, sidekick, memory-migration) instead of deleting them on success. Useful for short-term inspection/data collection — their full transcript (prompt, tool calls, token usage, output) stays in the host session store. Kept sessions accumulate until manually cleared; leave false for normal use. Requires a restart to take effect."),
|
|
172497
|
+
smart_drops: exports_external.boolean().default(false).describe("Content-aware reclaim of provably-superseded tool output, layered on the existing execute-pass auto-drop. When on: superseded todowrite (keep newest 1), spent ctx_reduce (keep newest 5), and zero-value meta (bash_status, bash_kill, ctx_note read/dismiss) outputs are dropped; older edits to a file are compressed to a filePath-preserving marker while the newest edit per file stays full. Only acts on passes already busting the cache, so it never originates a cache bust. Honors the protected-tag reserve. Experimental: opt-in, default off until cache stability is proven; when off the wire is byte-identical to the positional-only reclaim. Requires a restart."),
|
|
172359
172498
|
caveman_text_compression: exports_external.object({
|
|
172360
172499
|
enabled: exports_external.boolean().default(false).describe("Apply deterministic caveman-style text compression to old conversation text. Only active when ctx_reduce_enabled=false. Compresses user/assistant text in oldest-first tiers: ultra (oldest 20%), full, lite, untouched (newest 40%)."),
|
|
172361
172500
|
min_chars: exports_external.number().min(100).max(1e4).default(500).describe("Text parts shorter than this (characters) stay untouched. Min 100, max 10000. Default: 500.")
|
|
@@ -176175,6 +176314,7 @@ var MAINTAIN_DOCS_SYSTEM_PROMPT = `You are a documentation maintainer for the ma
|
|
|
176175
176314
|
|
|
176176
176315
|
## Rules
|
|
176177
176316
|
- **NEVER touch protected regions.** Any content between \`<!-- mc:protected START ... -->\` and \`<!-- mc:protected END -->\` is hand-authored and cache-critical. Reproduce it BYTE-FOR-BYTE — do not edit, reword, reorder, summarize, trim, or drop a single line, and keep the marker comments. Only a human edits that region.
|
|
176317
|
+
- **Preserve an existing doc's structure, voice, and density.** When a doc already exists, it is the source of truth for shape: keep its headings, ordering, level of detail, and writing style. Make the SMALLEST edits that bring it back in sync with the code. NEVER reshape hand-written prose into a generic template, collapse a dense section into bullet stubs, or drop hard-won detail (specific invariants, edge cases, mechanism descriptions) because it does not fit a standard layout. A doc denser and more specific than a template is BETTER, not worse: leave it that way.
|
|
176178
176318
|
- **Be prescriptive** ("Use X pattern", not "X pattern is used"). **Current state only** — no temporal language, no history.
|
|
176179
176319
|
- **Verify before writing** — read the actual files, never guess. All file paths in the docs must point to files that exist.`;
|
|
176180
176320
|
var REVIEW_USER_MEMORIES_SYSTEM_PROMPT = `You are a user-profile reviewer for the magic-context system. You run during a scheduled dream window to decide which recurring behavioral observations about the human user are real, persistent patterns worth keeping in their global user profile.
|
|
@@ -176290,7 +176430,7 @@ Return only XML in this exact shape:
|
|
|
176290
176430
|
function buildMaintainDocsPrompt(projectPath, lastDreamAt, existingDocs) {
|
|
176291
176431
|
const hasAny = existingDocs.architecture || existingDocs.structure;
|
|
176292
176432
|
const gitSinceClause = lastDreamAt ? `Run \`git log --oneline --since="${new Date(Number(lastDreamAt)).toISOString()}"\` to see what changed since the last dream.` : "No previous dream timestamp — treat this as a full analysis.";
|
|
176293
|
-
const modeIntro = hasAny ? `Some docs already exist.
|
|
176433
|
+
const modeIntro = hasAny ? `Some docs already exist and are the source of truth for shape. Make SURGICAL \`edit\` changes to only the sections affected by recent code changes; preserve every other section, the existing structure, and the existing density verbatim. Do NOT regenerate a whole file, do NOT reshape prose into a template, and do NOT use the templates below (they are for creation only). If nothing material changed, change nothing.` : `No docs exist yet. Create both ARCHITECTURE.md and STRUCTURE.md from scratch using the templates below as a STARTING shape, then go deeper than the template wherever the code warrants it.`;
|
|
176294
176434
|
return `## Task: Maintain Codebase Documentation
|
|
176295
176435
|
|
|
176296
176436
|
**Project:** ${projectPath}
|
|
@@ -176305,15 +176445,16 @@ ${modeIntro}
|
|
|
176305
176445
|
### Process
|
|
176306
176446
|
|
|
176307
176447
|
1. **Check what changed.** ${gitSinceClause}
|
|
176308
|
-
2. **Read existing docs** (if they exist) to understand current
|
|
176448
|
+
2. **Read existing docs** (if they exist) IN FULL to understand their current structure, depth, and voice; you will preserve all of it except what code changes force you to touch.
|
|
176309
176449
|
3. **Explore the codebase** to verify and update:
|
|
176310
176450
|
- Directory structure: \`find . -type d -not -path '*/node_modules/*' -not -path '*/.git/*' -not -path '*/dist/*' | head -60\`
|
|
176311
176451
|
- Entry points: \`ls src/index.* src/main.* 2>/dev/null\`
|
|
176312
176452
|
- Key imports: \`grep -r "^import\\|^export" src/ --include="*.ts" | head -80\`
|
|
176313
|
-
4. **
|
|
176453
|
+
4. **Apply the change.** If the doc EXISTS: use \`edit\` for the specific sections that drifted, never rewrite the whole file with \`write\`. If the doc is MISSING: create it with \`write\`. Always at project root, NOT \`.planning/\`.
|
|
176314
176454
|
|
|
176315
176455
|
### Rules
|
|
176316
176456
|
- **NEVER touch protected regions**: any content between \`<!-- mc:protected START ... -->\` and \`<!-- mc:protected END -->\` is hand-authored and cache-critical. Reproduce it BYTE-FOR-BYTE in your rewrite — do not edit, reword, reorder, summarize, trim, or drop a single line of it, and keep the marker comments themselves. Only a human edits that region.
|
|
176457
|
+
- **Preserve existing structure and density**: when a doc exists, keep its headings, ordering, level of detail, and voice. Make the smallest edits that re-sync it with the code. NEVER flatten dense hand-written prose into the generic template, collapse a detailed section into bullet stubs, or drop specific invariants/edge-cases/mechanism detail because it does not match a standard layout. Denser and more specific than the template is BETTER.
|
|
176317
176458
|
- **Be prescriptive**: "Use X pattern" not "X pattern is used"
|
|
176318
176459
|
- **Always include file paths** in backticks
|
|
176319
176460
|
- **Write current state only**: no temporal language, no history
|
|
@@ -176616,7 +176757,7 @@ If no promotions are warranted, return empty arrays. Always consume reviewed can
|
|
|
176616
176757
|
query: { directory: args.sessionDirectory },
|
|
176617
176758
|
body: {
|
|
176618
176759
|
agent: DREAMER_REVIEWER_AGENT,
|
|
176619
|
-
system: REVIEW_USER_MEMORIES_SYSTEM_PROMPT,
|
|
176760
|
+
system: withContentLanguageDirective(REVIEW_USER_MEMORIES_SYSTEM_PROMPT, args.language),
|
|
176620
176761
|
...modelBodyField(args.model),
|
|
176621
176762
|
parts: [{ type: "text", text: prompt, synthetic: true }]
|
|
176622
176763
|
}
|
|
@@ -177718,10 +177859,23 @@ function getAsyncModule() {
|
|
|
177718
177859
|
asyncModulePromise ??= newQuickJSAsyncWASMModuleFromVariant(import_quickjs_singlefile_cjs_release_asyncify.default);
|
|
177719
177860
|
return asyncModulePromise;
|
|
177720
177861
|
}
|
|
177862
|
+
var sandboxRunChain = Promise.resolve();
|
|
177863
|
+
function withSandboxLock(fn) {
|
|
177864
|
+
const run = sandboxRunChain.then(fn, fn);
|
|
177865
|
+
sandboxRunChain = run.then(() => {
|
|
177866
|
+
return;
|
|
177867
|
+
}, () => {
|
|
177868
|
+
return;
|
|
177869
|
+
});
|
|
177870
|
+
return run;
|
|
177871
|
+
}
|
|
177721
177872
|
var DEFAULT_TIMEOUT_MS = 2000;
|
|
177722
177873
|
var DEFAULT_HEAP_LIMIT_BYTES = 8 * 1024 * 1024;
|
|
177723
177874
|
var DEFAULT_STACK_LIMIT_BYTES = 512 * 1024;
|
|
177724
177875
|
async function runCompiledSmartNoteCheck(options) {
|
|
177876
|
+
return withSandboxLock(() => runCompiledSmartNoteCheckLocked(options));
|
|
177877
|
+
}
|
|
177878
|
+
async function runCompiledSmartNoteCheckLocked(options) {
|
|
177725
177879
|
const timeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUT_MS;
|
|
177726
177880
|
const controller = new AbortController;
|
|
177727
177881
|
const externalAbort = () => controller.abort(options.signal?.reason);
|
|
@@ -179430,7 +179584,7 @@ async function refreshOnePrimer(args, primer, sliceMs, signal) {
|
|
|
179430
179584
|
query: { directory: args.sessionDirectory },
|
|
179431
179585
|
body: {
|
|
179432
179586
|
agent: DREAMER_PRIMER_INVESTIGATOR_AGENT,
|
|
179433
|
-
system: PRIMER_INVESTIGATOR_SYSTEM_PROMPT,
|
|
179587
|
+
system: withContentLanguageDirective(PRIMER_INVESTIGATOR_SYSTEM_PROMPT, args.language),
|
|
179434
179588
|
...modelBodyField(args.model),
|
|
179435
179589
|
parts: [{ type: "text", text: prompt, synthetic: true }]
|
|
179436
179590
|
}
|
|
@@ -180211,7 +180365,7 @@ async function verifyOneBatch(args, batch, sliceMs, signal) {
|
|
|
180211
180365
|
query: { directory: args.sessionDirectory },
|
|
180212
180366
|
body: {
|
|
180213
180367
|
agent: DREAMER_MEMORY_MAPPER_AGENT,
|
|
180214
|
-
system: VERIFY_SYSTEM_PROMPT,
|
|
180368
|
+
system: withContentLanguageDirective(VERIFY_SYSTEM_PROMPT, args.language),
|
|
180215
180369
|
...modelBodyField(args.model),
|
|
180216
180370
|
parts: [{ type: "text", text: prompt, synthetic: true }]
|
|
180217
180371
|
}
|
|
@@ -180491,7 +180645,8 @@ function createDreamTaskExecutor(deps) {
|
|
|
180491
180645
|
deadline,
|
|
180492
180646
|
promotionThreshold: config2.promotionThreshold ?? 3,
|
|
180493
180647
|
model: config2.model,
|
|
180494
|
-
fallbackModels: config2.fallbackModels
|
|
180648
|
+
fallbackModels: config2.fallbackModels,
|
|
180649
|
+
language: config2.language ?? deps.language
|
|
180495
180650
|
});
|
|
180496
180651
|
recordRun("completed", null);
|
|
180497
180652
|
log(`[dreamer] review-user-memories: promoted=${result.promoted} merged=${result.merged} dismissed=${result.dismissed}`);
|
|
@@ -180527,7 +180682,8 @@ function createDreamTaskExecutor(deps) {
|
|
|
180527
180682
|
deadline,
|
|
180528
180683
|
forceBroad: config2.task === "verify-broad",
|
|
180529
180684
|
model: config2.model,
|
|
180530
|
-
fallbackModels: config2.fallbackModels
|
|
180685
|
+
fallbackModels: config2.fallbackModels,
|
|
180686
|
+
language: config2.language ?? deps.language
|
|
180531
180687
|
});
|
|
180532
180688
|
recordRun("completed", null, {
|
|
180533
180689
|
memoryChanges: computeMemoryDelta(memoryBefore)
|
|
@@ -180579,6 +180735,7 @@ function createDreamTaskExecutor(deps) {
|
|
|
180579
180735
|
deadline,
|
|
180580
180736
|
model: config2.model,
|
|
180581
180737
|
fallbackModels: config2.fallbackModels,
|
|
180738
|
+
language: config2.language ?? deps.language,
|
|
180582
180739
|
rawProviderFactory: deps.primerRawProviderFactory
|
|
180583
180740
|
});
|
|
180584
180741
|
recordRun("completed", null);
|
|
@@ -180696,6 +180853,7 @@ function retrospectiveEventsForSessions(db, sessionIds) {
|
|
|
180696
180853
|
try {
|
|
180697
180854
|
for (const event of getCompartmentEvents(db, sessionId)) {
|
|
180698
180855
|
if (event.kind !== "causal_incident" && event.kind !== "trajectory_correction") {
|
|
180856
|
+
log(`[dreamer] dropping event: unknown kind="${event.kind}"`);
|
|
180699
180857
|
continue;
|
|
180700
180858
|
}
|
|
180701
180859
|
events.push({
|
|
@@ -180820,7 +180978,9 @@ async function runRetrospectiveTask(config2, ctx, helpers) {
|
|
|
180820
180978
|
const frictionWindow = renderFrictionWindow(messages, flagged.map((message) => message.ordinal));
|
|
180821
180979
|
const eventSessionIds = new Set(messages.map((message) => message.sessionId));
|
|
180822
180980
|
const events = retrospectiveEventsForSessions(db, eventSessionIds);
|
|
180823
|
-
const deepenRun = await runChildTurn(RETROSPECTIVE_SYSTEM_PROMPT,
|
|
180981
|
+
const deepenRun = await runChildTurn(withContentLanguageDirective(RETROSPECTIVE_SYSTEM_PROMPT, config2.language ?? deps.language, {
|
|
180982
|
+
retrospective: true
|
|
180983
|
+
}), buildRetrospectivePrompt({ projectPath: projectIdentity, frictionWindow, events }));
|
|
180824
180984
|
if (leaseLost)
|
|
180825
180985
|
throw new Error("Dream lease lost during retrospective");
|
|
180826
180986
|
const sourceSessionId = flagged[0]?.sessionId ?? userMessages[0]?.sessionId ?? "retrospective";
|
|
@@ -180906,7 +181066,7 @@ async function runAgenticTask(config2, ctx, helpers) {
|
|
|
180906
181066
|
query: { directory: docsDir },
|
|
180907
181067
|
body: {
|
|
180908
181068
|
agent: task === "maintain-docs" ? DREAMER_DOCS_AGENT : DREAMER_AGENT,
|
|
180909
|
-
system: task === "maintain-docs" ? MAINTAIN_DOCS_SYSTEM_PROMPT : CURATE_SYSTEM_PROMPT,
|
|
181069
|
+
system: task === "maintain-docs" ? MAINTAIN_DOCS_SYSTEM_PROMPT : withContentLanguageDirective(CURATE_SYSTEM_PROMPT, config2.language ?? deps.language),
|
|
180910
181070
|
...modelBodyField(config2.model),
|
|
180911
181071
|
parts: [{ type: "text", text: taskPrompt, synthetic: true }]
|
|
180912
181072
|
}
|
|
@@ -181788,7 +181948,7 @@ async function sweepProject(reg, origin, db, gitCommitEnabled) {
|
|
|
181788
181948
|
}
|
|
181789
181949
|
try {
|
|
181790
181950
|
await runCompiledSmartNoteSweep(reg, db);
|
|
181791
|
-
const runtimeConfigs = buildDreamTaskRuntimeConfigs(dreamerConfig);
|
|
181951
|
+
const runtimeConfigs = buildDreamTaskRuntimeConfigs(dreamerConfig, reg.language);
|
|
181792
181952
|
const executor = createDreamTaskExecutor({
|
|
181793
181953
|
client: reg.client,
|
|
181794
181954
|
sessionDirectory: reg.directory,
|
|
@@ -181796,7 +181956,8 @@ async function sweepProject(reg, origin, db, gitCommitEnabled) {
|
|
|
181796
181956
|
retrospectiveRawProvider: reg.retrospectiveRawProvider ?? ((db2) => new OpenCodeRetrospectiveRawProvider({ contextDb: db2, openOpenCodeDb })),
|
|
181797
181957
|
primerRawProviderFactory: reg.primerRawProviderFactory,
|
|
181798
181958
|
userMemoryCollectionEnabled: userMemoryCollectionEnabled(dreamerConfig),
|
|
181799
|
-
ensureProjectRegistered: reg.ensureRegistered
|
|
181959
|
+
ensureProjectRegistered: reg.ensureRegistered,
|
|
181960
|
+
language: reg.language
|
|
181800
181961
|
});
|
|
181801
181962
|
const ran = await runDueTasksForProject({
|
|
181802
181963
|
db,
|
|
@@ -182349,6 +182510,10 @@ function stripUnsafeProjectConfigFields(projectRaw) {
|
|
|
182349
182510
|
delete projectRaw.auto_update;
|
|
182350
182511
|
warnings.push("Ignoring auto_update from project config (security: this setting only honors user-level config).");
|
|
182351
182512
|
}
|
|
182513
|
+
if ("language" in projectRaw) {
|
|
182514
|
+
delete projectRaw.language;
|
|
182515
|
+
warnings.push("Ignoring language from project config (security: output language is a user-level setting).");
|
|
182516
|
+
}
|
|
182352
182517
|
if ("sqlite" in projectRaw) {
|
|
182353
182518
|
delete projectRaw.sqlite;
|
|
182354
182519
|
warnings.push("Ignoring sqlite.* from project config (security: SQLite cache/mmap PRAGMAs apply to the " + "process-global shared database handle; only user-level config may set them).");
|
|
@@ -183404,6 +183569,7 @@ function registerPiDreamerProject(opts) {
|
|
|
183404
183569
|
projectIdentity: opts.projectIdentity,
|
|
183405
183570
|
client,
|
|
183406
183571
|
dreamerConfig: opts.config,
|
|
183572
|
+
language: opts.language,
|
|
183407
183573
|
gitCommitIndexing: opts.gitCommitIndexing,
|
|
183408
183574
|
ensureRegistered: ensureProjectRegisteredFromPiDirectory,
|
|
183409
183575
|
retrospectiveRawProvider: () => new PiRetrospectiveRawProvider({ projectCwd: opts.projectDir }),
|
|
@@ -183418,7 +183584,7 @@ function registerPiDreamerProject(opts) {
|
|
|
183418
183584
|
const runManual = async (task) => runManualDream({
|
|
183419
183585
|
db: opts.db,
|
|
183420
183586
|
projectIdentity: opts.projectIdentity,
|
|
183421
|
-
tasks: buildDreamTaskRuntimeConfigs(opts.config),
|
|
183587
|
+
tasks: buildDreamTaskRuntimeConfigs(opts.config, opts.language),
|
|
183422
183588
|
executor: createDreamTaskExecutor({
|
|
183423
183589
|
client,
|
|
183424
183590
|
sessionDirectory: opts.projectDir,
|
|
@@ -183428,7 +183594,8 @@ function registerPiDreamerProject(opts) {
|
|
|
183428
183594
|
}),
|
|
183429
183595
|
primerRawProviderFactory: createPiPrimerRawProviderFactory(),
|
|
183430
183596
|
userMemoryCollectionEnabled: userMemoryCollectionEnabled(opts.config),
|
|
183431
|
-
ensureProjectRegistered: ensureProjectRegisteredFromPiDirectory
|
|
183597
|
+
ensureProjectRegistered: ensureProjectRegisteredFromPiDirectory,
|
|
183598
|
+
language: opts.language
|
|
183432
183599
|
}),
|
|
183433
183600
|
task
|
|
183434
183601
|
});
|
|
@@ -184540,7 +184707,7 @@ var RECENT_TOOL_SKELETON_WINDOW = 20;
|
|
|
184540
184707
|
function buildReplacementContent(tagId) {
|
|
184541
184708
|
return `[dropped §${tagId}§]`;
|
|
184542
184709
|
}
|
|
184543
|
-
function applyPendingOperations(sessionId, db, targets, protectedTags = 0, preloadedTags, preloadedPendingOps, syntheticPendingOps = []) {
|
|
184710
|
+
function applyPendingOperations(sessionId, db, targets, protectedTags = 0, preloadedTags, preloadedPendingOps, syntheticPendingOps = [], editMarkerTagIds = new Set) {
|
|
184544
184711
|
let didMutateMessage = false;
|
|
184545
184712
|
db.transaction(() => {
|
|
184546
184713
|
const tags = preloadedTags ?? getTagsBySession(db, sessionId);
|
|
@@ -184571,7 +184738,15 @@ function applyPendingOperations(sessionId, db, targets, protectedTags = 0, prelo
|
|
|
184571
184738
|
}
|
|
184572
184739
|
let shouldPersistDrop = false;
|
|
184573
184740
|
if (isToolTag) {
|
|
184574
|
-
if (
|
|
184741
|
+
if (editMarkerTagIds.has(pendingOp.tagId)) {
|
|
184742
|
+
const markResult = target?.editMarker?.() ?? "absent";
|
|
184743
|
+
if (markResult === "incomplete" || markResult === "absent") {
|
|
184744
|
+
continue;
|
|
184745
|
+
}
|
|
184746
|
+
didMutateMessage = true;
|
|
184747
|
+
updateTagDropMode(db, sessionId, pendingOp.tagId, "edit_marker");
|
|
184748
|
+
shouldPersistDrop = true;
|
|
184749
|
+
} else if (skeletonWindow.has(pendingOp.tagId)) {
|
|
184575
184750
|
const truncResult = target?.truncate?.() ?? "absent";
|
|
184576
184751
|
if (truncResult === "incomplete" || synthetic && truncResult !== "truncated") {
|
|
184577
184752
|
continue;
|
|
@@ -184616,7 +184791,12 @@ function applyFlushedStatuses(sessionId, db, targets, preloadedTags) {
|
|
|
184616
184791
|
if (tag.status === "dropped") {
|
|
184617
184792
|
const target = targets.get(tag.tagNumber);
|
|
184618
184793
|
if (tag.type === "tool") {
|
|
184619
|
-
if (tag.dropMode === "
|
|
184794
|
+
if (tag.dropMode === "edit_marker") {
|
|
184795
|
+
const markResult = target?.editMarker?.() ?? "absent";
|
|
184796
|
+
if (markResult === "truncated") {
|
|
184797
|
+
didMutateMessage = true;
|
|
184798
|
+
}
|
|
184799
|
+
} else if (tag.dropMode === "truncated") {
|
|
184620
184800
|
const truncResult = target?.truncate?.() ?? "absent";
|
|
184621
184801
|
if (truncResult === "truncated") {
|
|
184622
184802
|
didMutateMessage = true;
|
|
@@ -186213,6 +186393,7 @@ function channel1RefireTokens(workingWindowTokens) {
|
|
|
186213
186393
|
var S_GENTLE = 0.2;
|
|
186214
186394
|
var S_FIRM = 0.4;
|
|
186215
186395
|
var S_URGENT = 0.65;
|
|
186396
|
+
var CHANNEL1_PRESSURE_FLOOR = 0.8;
|
|
186216
186397
|
var LEVEL_RANK = { gentle: 1, firm: 2, urgent: 3 };
|
|
186217
186398
|
var DROP_SENTINELS = ["[dropped", "[truncated"];
|
|
186218
186399
|
function isDroppedToolOutput(output) {
|
|
@@ -186223,7 +186404,8 @@ function toolOutputTokens(output) {
|
|
|
186223
186404
|
return Math.round(byteSize(output) * TOKENS_PER_BYTE);
|
|
186224
186405
|
}
|
|
186225
186406
|
function decideChannel1(input) {
|
|
186226
|
-
const { undroppedTokens,
|
|
186407
|
+
const { undroppedTokens, workingWindowTokens, hasRecentReduce } = input;
|
|
186408
|
+
const pressure = Math.min(1, Math.max(0, input.pressure));
|
|
186227
186409
|
const resetCycle = hasRecentReduce || undroppedTokens < input.lastNudgeUndropped;
|
|
186228
186410
|
const lastNudge = resetCycle ? 0 : input.lastNudgeUndropped;
|
|
186229
186411
|
const lastLevel = resetCycle ? "" : input.lastNudgeLevel;
|
|
@@ -186238,8 +186420,10 @@ function decideChannel1(input) {
|
|
|
186238
186420
|
return quiet();
|
|
186239
186421
|
if (undroppedTokens < CHANNEL1_FLOOR_TOKENS)
|
|
186240
186422
|
return quiet();
|
|
186241
|
-
|
|
186242
|
-
|
|
186423
|
+
if (pressure < CHANNEL1_PRESSURE_FLOOR)
|
|
186424
|
+
return quiet();
|
|
186425
|
+
const denom = Math.max(input.estimatedInputTokens, 1);
|
|
186426
|
+
const severity = Math.min(1, undroppedTokens / denom);
|
|
186243
186427
|
if (severity < S_GENTLE)
|
|
186244
186428
|
return quiet();
|
|
186245
186429
|
let level;
|
|
@@ -186763,6 +186947,97 @@ function renderMemoryBlockV2(memories, wrapper = "project-memory", renderOptions
|
|
|
186763
186947
|
`);
|
|
186764
186948
|
}
|
|
186765
186949
|
|
|
186950
|
+
// ../plugin/src/hooks/magic-context/supersession-reclaim.ts
|
|
186951
|
+
var TODOWRITE_KEEP = 1;
|
|
186952
|
+
var CTX_REDUCE_KEEP = 5;
|
|
186953
|
+
var ZERO_VALUE_META_TOOLS = new Set(["bash_status", "bash_kill"]);
|
|
186954
|
+
var CTX_NOTE_ZERO_VALUE_ACTIONS = new Set(["read", "dismiss"]);
|
|
186955
|
+
function buildSupersessionReclaimOps(input) {
|
|
186956
|
+
const realPendingTagIds = new Set((input.pendingOps ?? []).map((op) => op.tagId));
|
|
186957
|
+
const tags = getActiveTagsBySession(input.db, input.sessionId);
|
|
186958
|
+
const toolTags = tags.filter((tag) => tag.type === "tool" && tag.status === "active").sort((left, right) => right.tagNumber - left.tagNumber);
|
|
186959
|
+
const dropTagIds = [];
|
|
186960
|
+
let todowriteSeen = 0;
|
|
186961
|
+
let ctxReduceSeen = 0;
|
|
186962
|
+
for (const tag of toolTags) {
|
|
186963
|
+
const name2 = tag.toolName;
|
|
186964
|
+
if (!name2)
|
|
186965
|
+
continue;
|
|
186966
|
+
let isTarget = false;
|
|
186967
|
+
if (name2 === "todowrite") {
|
|
186968
|
+
todowriteSeen += 1;
|
|
186969
|
+
isTarget = todowriteSeen > TODOWRITE_KEEP;
|
|
186970
|
+
} else if (name2 === "ctx_reduce") {
|
|
186971
|
+
ctxReduceSeen += 1;
|
|
186972
|
+
isTarget = ctxReduceSeen > CTX_REDUCE_KEEP;
|
|
186973
|
+
} else if (ZERO_VALUE_META_TOOLS.has(name2)) {
|
|
186974
|
+
isTarget = true;
|
|
186975
|
+
} else if (name2 === "ctx_note") {
|
|
186976
|
+
const action = input.targets.get(tag.tagNumber)?.readInput?.()?.action;
|
|
186977
|
+
isTarget = typeof action === "string" && CTX_NOTE_ZERO_VALUE_ACTIONS.has(action);
|
|
186978
|
+
}
|
|
186979
|
+
if (isTarget)
|
|
186980
|
+
dropTagIds.push(tag.tagNumber);
|
|
186981
|
+
}
|
|
186982
|
+
const synthetic = [];
|
|
186983
|
+
for (const tagId of dropTagIds) {
|
|
186984
|
+
if (realPendingTagIds.has(tagId))
|
|
186985
|
+
continue;
|
|
186986
|
+
if (input.targets.get(tagId)?.canDrop?.() !== true)
|
|
186987
|
+
continue;
|
|
186988
|
+
synthetic.push({
|
|
186989
|
+
id: 0,
|
|
186990
|
+
sessionId: input.sessionId,
|
|
186991
|
+
tagId,
|
|
186992
|
+
operation: "drop",
|
|
186993
|
+
queuedAt: 0
|
|
186994
|
+
});
|
|
186995
|
+
}
|
|
186996
|
+
return synthetic;
|
|
186997
|
+
}
|
|
186998
|
+
function buildEditSupersessionReclaim(input) {
|
|
186999
|
+
const realPendingTagIds = new Set((input.pendingOps ?? []).map((op) => op.tagId));
|
|
187000
|
+
const tags = getActiveTagsBySession(input.db, input.sessionId);
|
|
187001
|
+
const editTags = tags.filter((tag) => tag.type === "tool" && tag.status === "active" && isEditTool(tag.toolName)).sort((left, right) => right.tagNumber - left.tagNumber);
|
|
187002
|
+
const seenFile = new Set;
|
|
187003
|
+
const ops = [];
|
|
187004
|
+
const editMarkerTagIds = new Set;
|
|
187005
|
+
for (const tag of editTags) {
|
|
187006
|
+
const filePath = readFilePath(input.targets.get(tag.tagNumber));
|
|
187007
|
+
if (!filePath)
|
|
187008
|
+
continue;
|
|
187009
|
+
if (!seenFile.has(filePath)) {
|
|
187010
|
+
seenFile.add(filePath);
|
|
187011
|
+
continue;
|
|
187012
|
+
}
|
|
187013
|
+
if (realPendingTagIds.has(tag.tagNumber))
|
|
187014
|
+
continue;
|
|
187015
|
+
if (input.targets.get(tag.tagNumber)?.canDrop?.() !== true)
|
|
187016
|
+
continue;
|
|
187017
|
+
editMarkerTagIds.add(tag.tagNumber);
|
|
187018
|
+
ops.push({
|
|
187019
|
+
id: 0,
|
|
187020
|
+
sessionId: input.sessionId,
|
|
187021
|
+
tagId: tag.tagNumber,
|
|
187022
|
+
operation: "drop",
|
|
187023
|
+
queuedAt: 0
|
|
187024
|
+
});
|
|
187025
|
+
}
|
|
187026
|
+
return { ops, editMarkerTagIds };
|
|
187027
|
+
}
|
|
187028
|
+
var FILE_PATH_KEYS = ["filePath", "file_path", "path"];
|
|
187029
|
+
function readFilePath(target) {
|
|
187030
|
+
const input = target?.readInput?.();
|
|
187031
|
+
if (!input)
|
|
187032
|
+
return null;
|
|
187033
|
+
for (const key of FILE_PATH_KEYS) {
|
|
187034
|
+
const value = input[key];
|
|
187035
|
+
if (typeof value === "string" && value.length > 0)
|
|
187036
|
+
return value;
|
|
187037
|
+
}
|
|
187038
|
+
return null;
|
|
187039
|
+
}
|
|
187040
|
+
|
|
186766
187041
|
// ../plugin/src/hooks/magic-context/tool-reclaim.ts
|
|
186767
187042
|
function buildSyntheticToolReclaimOps(input) {
|
|
186768
187043
|
const watermark = Math.max(0, input.watermark);
|
|
@@ -187257,9 +187532,35 @@ function buildAggregateTarget(tagId, occurrences) {
|
|
|
187257
187532
|
}
|
|
187258
187533
|
return any2 ? "truncated" : "absent";
|
|
187259
187534
|
},
|
|
187535
|
+
editMarker() {
|
|
187536
|
+
const sentinel = `[dropped §${tagId}§]`;
|
|
187537
|
+
let any2 = false;
|
|
187538
|
+
for (const occ of occurrences) {
|
|
187539
|
+
if (occ.kind === "tool_use") {
|
|
187540
|
+
const input = occ.part.getToolInput?.();
|
|
187541
|
+
if (input) {
|
|
187542
|
+
const next = { ...input };
|
|
187543
|
+
applyEditMarkerToInput(next);
|
|
187544
|
+
if (occ.part.setToolInput?.(next))
|
|
187545
|
+
any2 = true;
|
|
187546
|
+
}
|
|
187547
|
+
} else if (setToolContentOrText(occ.part, sentinel)) {
|
|
187548
|
+
any2 = true;
|
|
187549
|
+
}
|
|
187550
|
+
}
|
|
187551
|
+
return any2 ? "truncated" : "absent";
|
|
187552
|
+
},
|
|
187260
187553
|
canDrop() {
|
|
187261
187554
|
return occurrences.length > 0;
|
|
187262
187555
|
},
|
|
187556
|
+
readInput() {
|
|
187557
|
+
for (const occ of occurrences) {
|
|
187558
|
+
const input = occ.part.getToolInput?.();
|
|
187559
|
+
if (input)
|
|
187560
|
+
return input;
|
|
187561
|
+
}
|
|
187562
|
+
return null;
|
|
187563
|
+
},
|
|
187263
187564
|
message: {
|
|
187264
187565
|
info: { id: messageId, role },
|
|
187265
187566
|
parts: []
|
|
@@ -188555,6 +188856,7 @@ function maybeChannel1ReminderForToolResult(args) {
|
|
|
188555
188856
|
const decision = decideChannel1({
|
|
188556
188857
|
undroppedTokens,
|
|
188557
188858
|
pressure,
|
|
188859
|
+
estimatedInputTokens: state.lastInputTokens + state.turnToolTokens,
|
|
188558
188860
|
workingWindowTokens,
|
|
188559
188861
|
lastNudgeUndropped: getLastNudgeUndropped(db, sessionId),
|
|
188560
188862
|
lastNudgeLevel: getLastNudgeLevel(db, sessionId),
|
|
@@ -188643,8 +188945,6 @@ function maybeDeliverChannel2Pi(pi, db, sessionId, deliverAs = "followUp") {
|
|
|
188643
188945
|
|
|
188644
188946
|
// src/detect-recent-commit.ts
|
|
188645
188947
|
var COMMIT_LOOKBACK = 5;
|
|
188646
|
-
var COMMIT_HASH_PATTERN2 = /\b[0-9a-f]{7,12}\b/;
|
|
188647
|
-
var COMMIT_VERB_PATTERN = /\b(commit|committed|cherry-pick|merge|rebas)/i;
|
|
188648
188948
|
function detectRecentCommit(messages) {
|
|
188649
188949
|
let assistantsScanned = 0;
|
|
188650
188950
|
for (let i = messages.length - 1;i >= 0; i--) {
|
|
@@ -188662,8 +188962,7 @@ function detectRecentCommit(messages) {
|
|
|
188662
188962
|
continue;
|
|
188663
188963
|
for (const part of content) {
|
|
188664
188964
|
if (part && typeof part === "object" && "type" in part && part.type === "text" && "text" in part && typeof part.text === "string") {
|
|
188665
|
-
|
|
188666
|
-
if (COMMIT_HASH_PATTERN2.test(text) && COMMIT_VERB_PATTERN.test(text)) {
|
|
188965
|
+
if (textMentionsRecentCommit(part.text)) {
|
|
188667
188966
|
return true;
|
|
188668
188967
|
}
|
|
188669
188968
|
}
|
|
@@ -191362,8 +191661,8 @@ function buildHistorianFailureNotice(failureCount, lastError) {
|
|
|
191362
191661
|
].join(`
|
|
191363
191662
|
`);
|
|
191364
191663
|
}
|
|
191365
|
-
function buildHistorianRepairPrompt(originalPrompt, previousOutput, validationError) {
|
|
191366
|
-
|
|
191664
|
+
function buildHistorianRepairPrompt(originalPrompt, previousOutput, validationError, language) {
|
|
191665
|
+
const prompt = [
|
|
191367
191666
|
originalPrompt,
|
|
191368
191667
|
"",
|
|
191369
191668
|
"Your previous XML response was invalid and cannot be persisted.",
|
|
@@ -191376,6 +191675,7 @@ function buildHistorianRepairPrompt(originalPrompt, previousOutput, validationEr
|
|
|
191376
191675
|
previousOutput
|
|
191377
191676
|
].join(`
|
|
191378
191677
|
`);
|
|
191678
|
+
return withContentLanguageDirective(prompt, language, { preserveUserQuotes: true });
|
|
191379
191679
|
}
|
|
191380
191680
|
function validateStoredCompartments(compartments) {
|
|
191381
191681
|
if (compartments.length === 0) {
|
|
@@ -193499,9 +193799,11 @@ ${chunkText}`,
|
|
|
193499
193799
|
};
|
|
193500
193800
|
};
|
|
193501
193801
|
retainDrainReservationForRetryThrottle = true;
|
|
193802
|
+
const historianSystemPrompt = withContentLanguageDirective(COMPARTMENT_AGENT_SYSTEM_PROMPT, deps.language, { preserveUserQuotes: true });
|
|
193803
|
+
const historianEditorSystemPrompt = withContentLanguageDirective(HISTORIAN_EDITOR_SYSTEM_PROMPT, deps.language, { preserveUserQuotes: true });
|
|
193502
193804
|
const firstResult = await runner.run({
|
|
193503
193805
|
agent: HISTORIAN_AGENT_NAME,
|
|
193504
|
-
systemPrompt:
|
|
193806
|
+
systemPrompt: historianSystemPrompt,
|
|
193505
193807
|
userMessage: prompt,
|
|
193506
193808
|
model: historianModel,
|
|
193507
193809
|
fallbackModels,
|
|
@@ -193516,10 +193818,10 @@ ${chunkText}`,
|
|
|
193516
193818
|
let validatedDraftText = firstResult.ok ? firstResult.assistantText : null;
|
|
193517
193819
|
if (validatedPass.kind === "validation-failed") {
|
|
193518
193820
|
sessionLog(sessionId, `historian: first pass validation failed, retrying with repair prompt: ${validatedPass.error}`);
|
|
193519
|
-
const repairPrompt = buildHistorianRepairPrompt(prompt, validatedPass.rawText, validatedPass.error);
|
|
193821
|
+
const repairPrompt = buildHistorianRepairPrompt(prompt, validatedPass.rawText, validatedPass.error, deps.language);
|
|
193520
193822
|
const repairResult = await runner.run({
|
|
193521
193823
|
agent: HISTORIAN_AGENT_NAME,
|
|
193522
|
-
systemPrompt:
|
|
193824
|
+
systemPrompt: historianSystemPrompt,
|
|
193523
193825
|
userMessage: repairPrompt,
|
|
193524
193826
|
model: historianModel,
|
|
193525
193827
|
fallbackModels,
|
|
@@ -193544,7 +193846,7 @@ ${chunkText}`,
|
|
|
193544
193846
|
sessionLog(sessionId, `historian: escalating to configured fallback model ${candidate}`);
|
|
193545
193847
|
const fbResult = await runner.run({
|
|
193546
193848
|
agent: HISTORIAN_AGENT_NAME,
|
|
193547
|
-
systemPrompt:
|
|
193849
|
+
systemPrompt: historianSystemPrompt,
|
|
193548
193850
|
userMessage: prompt,
|
|
193549
193851
|
model: candidate,
|
|
193550
193852
|
fallbackModels: undefined,
|
|
@@ -193580,7 +193882,7 @@ ${chunkText}`,
|
|
|
193580
193882
|
sessionLog(sessionId, "historian two-pass: running editor on draft");
|
|
193581
193883
|
const editorResult = await runner.run({
|
|
193582
193884
|
agent: HISTORIAN_AGENT_NAME,
|
|
193583
|
-
systemPrompt:
|
|
193885
|
+
systemPrompt: historianEditorSystemPrompt,
|
|
193584
193886
|
userMessage: buildHistorianEditorPrompt(draftAssistantText),
|
|
193585
193887
|
model: historianModel,
|
|
193586
193888
|
timeoutMs: historianTimeoutMs,
|
|
@@ -194338,16 +194640,20 @@ var PARTNER_FRAME_CLOSER_NO_REDUCE = `
|
|
|
194338
194640
|
Context is managed for you entirely automatically — there's nothing to prune and no warnings to act on. Stay reasonably concise per operation, and never let context size change *what* work you take on or *how thoroughly* you do it.`;
|
|
194339
194641
|
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).`;
|
|
194340
194642
|
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.`;
|
|
194341
|
-
var
|
|
194342
|
-
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".
|
|
194343
|
-
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.
|
|
194344
|
-
${CTX_NOTE_GUIDANCE}
|
|
194345
|
-
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.
|
|
194643
|
+
var MEMORY_GUIDANCE = `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.
|
|
194346
194644
|
**Save to memory proactively**: If you spent multiple turns finding something (a file path, a DB location, a config pattern, a workaround), save it with \`ctx_memory\` so future sessions don't repeat the search. Examples:
|
|
194347
194645
|
- Found a project's source code path after searching → \`ctx_memory(action="write", category="CONFIG_VALUES", content="OpenCode source is at ~/Work/OSS/opencode")\`
|
|
194348
194646
|
- Discovered a non-obvious build/test command → \`ctx_memory(action="write", category="PROJECT_RULES", content="Always use scripts/release.sh for releases")\`
|
|
194349
|
-
- Learned a constraint the hard way → \`ctx_memory(action="write", category="CONSTRAINTS", content="Dashboard Tauri build needs RGBA PNGs, not grayscale")
|
|
194350
|
-
|
|
194647
|
+
- Learned a constraint the hard way → \`ctx_memory(action="write", category="CONSTRAINTS", content="Dashboard Tauri build needs RGBA PNGs, not grayscale")\``;
|
|
194648
|
+
function memoryGuidanceBlock(memoryEnabled) {
|
|
194649
|
+
return memoryEnabled ? `${MEMORY_GUIDANCE}
|
|
194650
|
+
` : "";
|
|
194651
|
+
}
|
|
194652
|
+
var BASE_INTRO = (protectedTags, memoryEnabled) => `Messages and tool outputs are tagged with §N§ identifiers (e.g., §1§, §42§).
|
|
194653
|
+
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".
|
|
194654
|
+
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.
|
|
194655
|
+
${CTX_NOTE_GUIDANCE}
|
|
194656
|
+
${memoryGuidanceBlock(memoryEnabled)}Use \`ctx_search\` to search across project memories, indexed git commits, and this session's full conversation history (including compacted parts) from one query.
|
|
194351
194657
|
Use \`ctx_expand\` to recover the raw conversation behind a \`<compartment>\` summary in \`<session-history>\` — pass its \`start\`/\`end\` attributes when the summary is not enough (exact wording, values, error text).
|
|
194352
194658
|
**Search before asking the user**: If you can't remember or don't know something that might have been discussed before or stored in project memory, use \`ctx_search\` before asking the user. Examples:
|
|
194353
194659
|
- Can't remember where a related codebase or dependency lives → \`ctx_search(query="opencode source code path")\`
|
|
@@ -194361,13 +194667,8 @@ NEVER drop large ranges blindly (e.g., "1-50"). Review each tag before deciding.
|
|
|
194361
194667
|
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\`.
|
|
194362
194668
|
NEVER drop assistant text messages unless they are exceptionally large. Your conversation messages are lightweight; only large tool outputs are worth dropping.
|
|
194363
194669
|
Before your turn finishes, consider using \`ctx_reduce\` to drop large tool outputs you no longer need.`;
|
|
194364
|
-
var BASE_INTRO_NO_REDUCE = () => `${CTX_NOTE_GUIDANCE}
|
|
194365
|
-
Use \`
|
|
194366
|
-
**Save to memory proactively**: If you spent multiple turns finding something (a file path, a DB location, a config pattern, a workaround), save it with \`ctx_memory\` so future sessions don't repeat the search. Examples:
|
|
194367
|
-
- Found a project's source code path after searching → \`ctx_memory(action="write", category="CONFIG_VALUES", content="OpenCode source is at ~/Work/OSS/opencode")\`
|
|
194368
|
-
- Discovered a non-obvious build/test command → \`ctx_memory(action="write", category="PROJECT_RULES", content="Always use scripts/release.sh for releases")\`
|
|
194369
|
-
- Learned a constraint the hard way → \`ctx_memory(action="write", category="CONSTRAINTS", content="Dashboard Tauri build needs RGBA PNGs, not grayscale")\`
|
|
194370
|
-
Use \`ctx_search\` to search across project memories, indexed git commits, and this session's full conversation history (including compacted parts) from one query.
|
|
194670
|
+
var BASE_INTRO_NO_REDUCE = (memoryEnabled) => `${CTX_NOTE_GUIDANCE}
|
|
194671
|
+
${memoryGuidanceBlock(memoryEnabled)}Use \`ctx_search\` to search across project memories, indexed git commits, and this session's full conversation history (including compacted parts) from one query.
|
|
194371
194672
|
Use \`ctx_expand\` to recover the raw conversation behind a \`<compartment>\` summary in \`<session-history>\` — pass its \`start\`/\`end\` attributes when the summary is not enough (exact wording, values, error text).
|
|
194372
194673
|
**Search before asking the user**: If you can't remember or don't know something that might have been discussed before or stored in project memory, use \`ctx_search\` before asking the user. Examples:
|
|
194373
194674
|
- Can't remember where a related codebase or dependency lives → \`ctx_search(query="opencode source code path")\`
|
|
@@ -194401,7 +194702,7 @@ Drop silently — do not narrate it. NEVER drop large ranges blindly (e.g., "1-5
|
|
|
194401
194702
|
Older tool calls may show \`[dropped §N§]\` sentinels; that is normal context management, not a pattern to copy. ALWAYS make fresh real tool calls when you need data again; never fabricate or inline tool output.`;
|
|
194402
194703
|
var CAVEMAN_COMPRESSION_WARNING = `
|
|
194403
194704
|
**BEWARE**: History compression is on; older user AND assistant text — including your own earlier responses — has been deterministically rewritten in a terse caveman style (dropped articles, missing auxiliaries, \`//\` instead of connectives like \`because\`). This is automatic context compression that runs after the fact, not your actual prior wording or the user's. **DO NOT mimic this style in new turns.** Write fresh responses in normal prose. If you notice your output drifting into caveman cadence, that drift is in-context-learning bleeding from the compressed history — consciously revert to full sentences.`;
|
|
194404
|
-
function buildMagicContextSection(_agent, protectedTags, ctxReduceEnabled = true, dreamerEnabled = false, temporalAwarenessEnabled = false, cavemanTextCompressionEnabled = false, subagentMode = false) {
|
|
194705
|
+
function buildMagicContextSection(_agent, protectedTags, ctxReduceEnabled = true, dreamerEnabled = false, temporalAwarenessEnabled = false, cavemanTextCompressionEnabled = false, subagentMode = false, language, memoryEnabled = true) {
|
|
194405
194706
|
if (subagentMode) {
|
|
194406
194707
|
return `## Magic Context
|
|
194407
194708
|
|
|
@@ -194413,23 +194714,27 @@ The dreamer evaluates smart note conditions during nightly runs and surfaces the
|
|
|
194413
194714
|
Example: \`ctx_note(action="write", content="Implement X because Y", surface_condition="When PR #42 is merged in this repo")\`` : "";
|
|
194414
194715
|
const temporalGuidance = temporalAwarenessEnabled ? TEMPORAL_AWARENESS_GUIDANCE : "";
|
|
194415
194716
|
const cavemanWarning = cavemanTextCompressionEnabled && !ctxReduceEnabled ? CAVEMAN_COMPRESSION_WARNING : "";
|
|
194717
|
+
const languageDirective = buildPrimaryLanguageDirective(language);
|
|
194718
|
+
const languageGuidance = languageDirective ? `
|
|
194719
|
+
|
|
194720
|
+
${languageDirective}` : "";
|
|
194416
194721
|
if (!ctxReduceEnabled) {
|
|
194417
194722
|
return `## Magic Context
|
|
194418
194723
|
|
|
194419
194724
|
${LONG_TERM_PARTNER_FRAME}
|
|
194420
194725
|
${PARTNER_FRAME_CLOSER_NO_REDUCE}
|
|
194421
194726
|
|
|
194422
|
-
${BASE_INTRO_NO_REDUCE()}${smartNoteGuidance}${temporalGuidance}${cavemanWarning}`;
|
|
194727
|
+
${BASE_INTRO_NO_REDUCE(memoryEnabled)}${smartNoteGuidance}${temporalGuidance}${cavemanWarning}${languageGuidance}`;
|
|
194423
194728
|
}
|
|
194424
194729
|
return `## Magic Context
|
|
194425
194730
|
|
|
194426
194731
|
${LONG_TERM_PARTNER_FRAME}
|
|
194427
194732
|
${PARTNER_FRAME_CLOSER_REDUCE}
|
|
194428
194733
|
|
|
194429
|
-
${BASE_INTRO(protectedTags)}${smartNoteGuidance}${temporalGuidance}
|
|
194734
|
+
${BASE_INTRO(protectedTags, memoryEnabled)}${smartNoteGuidance}${temporalGuidance}
|
|
194430
194735
|
${GENERIC_SECTION}
|
|
194431
194736
|
|
|
194432
|
-
Prefer many small targeted operations over one large blanket operation, and keep the working set tidy as routine maintenance
|
|
194737
|
+
Prefer many small targeted operations over one large blanket operation, and keep the working set tidy as routine maintenance.${languageGuidance}`;
|
|
194433
194738
|
}
|
|
194434
194739
|
|
|
194435
194740
|
// src/system-prompt.ts
|
|
@@ -194441,7 +194746,7 @@ function buildMagicContextBlock(opts) {
|
|
|
194441
194746
|
const includeGuidance = (opts.includeGuidance ?? true) && !existing.includes(MAGIC_CONTEXT_MARKER);
|
|
194442
194747
|
if (!includeGuidance)
|
|
194443
194748
|
return null;
|
|
194444
|
-
return buildMagicContextSection(null, opts.protectedTags ?? 20, opts.ctxReduceEnabled ?? true, opts.dreamerEnabled ?? false, opts.temporalAwarenessEnabled ?? false, opts.cavemanTextCompressionEnabled ?? false);
|
|
194749
|
+
return buildMagicContextSection(null, opts.protectedTags ?? 20, opts.ctxReduceEnabled ?? true, opts.dreamerEnabled ?? false, opts.temporalAwarenessEnabled ?? false, opts.cavemanTextCompressionEnabled ?? false, false, opts.language, opts.memoryEnabled !== false);
|
|
194445
194750
|
}
|
|
194446
194751
|
var DATE_PATTERN = /Today's date: .+/;
|
|
194447
194752
|
function processSystemPromptForCache(args) {
|
|
@@ -194976,6 +195281,31 @@ function createPiAssistantPart(working, messageIndex, partIndex, markDirty) {
|
|
|
194976
195281
|
}
|
|
194977
195282
|
return { toolName: p.name, inputByteSize, inputTokenCount };
|
|
194978
195283
|
},
|
|
195284
|
+
getToolInput() {
|
|
195285
|
+
const current = working[messageIndex].content;
|
|
195286
|
+
const p = current[partIndex];
|
|
195287
|
+
if (p?.type !== "toolCall")
|
|
195288
|
+
return null;
|
|
195289
|
+
return p.arguments && typeof p.arguments === "object" ? p.arguments : null;
|
|
195290
|
+
},
|
|
195291
|
+
setToolInput(input) {
|
|
195292
|
+
const current = working[messageIndex].content;
|
|
195293
|
+
const p = current[partIndex];
|
|
195294
|
+
if (p?.type !== "toolCall")
|
|
195295
|
+
return false;
|
|
195296
|
+
try {
|
|
195297
|
+
if (JSON.stringify(p.arguments) === JSON.stringify(input))
|
|
195298
|
+
return false;
|
|
195299
|
+
} catch {}
|
|
195300
|
+
const newContent = current.slice();
|
|
195301
|
+
newContent[partIndex] = { ...p, arguments: input };
|
|
195302
|
+
working[messageIndex] = {
|
|
195303
|
+
...working[messageIndex],
|
|
195304
|
+
content: newContent
|
|
195305
|
+
};
|
|
195306
|
+
markDirty(messageIndex);
|
|
195307
|
+
return true;
|
|
195308
|
+
},
|
|
194979
195309
|
replaceWithSentinel(sentinelText) {
|
|
194980
195310
|
const current = working[messageIndex].content;
|
|
194981
195311
|
const existing = current[partIndex];
|
|
@@ -195809,6 +196139,7 @@ function registerPiContextHandler(pi, baseOptions) {
|
|
|
195809
196139
|
projectDirectory,
|
|
195810
196140
|
messages: event.messages,
|
|
195811
196141
|
ctxReduceEnabled: options.ctxReduceEnabled,
|
|
196142
|
+
smartDrops: options.smartDrops === true,
|
|
195812
196143
|
protectedTags: options.protectedTags ?? 20,
|
|
195813
196144
|
heuristics: options.heuristics,
|
|
195814
196145
|
emergencyCeilingTokens,
|
|
@@ -196133,6 +196464,7 @@ function spawnPiHistorianRun(args) {
|
|
|
196133
196464
|
memoryEnabled: historian.memoryEnabled,
|
|
196134
196465
|
autoPromote: historian.autoPromote,
|
|
196135
196466
|
userMemoriesEnabled: historian.userMemoriesEnabled,
|
|
196467
|
+
language: historian.language,
|
|
196136
196468
|
compartmentLeaseHolderId: holderId,
|
|
196137
196469
|
onPublished: () => {
|
|
196138
196470
|
const sessionStillActive = isContextHandlerSessionActive(sessionId);
|
|
@@ -196598,9 +196930,38 @@ async function runPipeline(args) {
|
|
|
196598
196930
|
watermark: reclaimMeta.toolReclaimWatermark ?? 0,
|
|
196599
196931
|
pendingOps
|
|
196600
196932
|
});
|
|
196933
|
+
const editMarkerTagIds = new Set;
|
|
196934
|
+
if (args.smartDrops) {
|
|
196935
|
+
const selectedIds = new Set(syntheticPendingOps.map((op) => op.tagId));
|
|
196936
|
+
const supersessionOps = buildSupersessionReclaimOps({
|
|
196937
|
+
db: args.db,
|
|
196938
|
+
sessionId: args.sessionId,
|
|
196939
|
+
targets,
|
|
196940
|
+
pendingOps
|
|
196941
|
+
});
|
|
196942
|
+
for (const op of supersessionOps) {
|
|
196943
|
+
if (!selectedIds.has(op.tagId)) {
|
|
196944
|
+
syntheticPendingOps.push(op);
|
|
196945
|
+
selectedIds.add(op.tagId);
|
|
196946
|
+
}
|
|
196947
|
+
}
|
|
196948
|
+
const editReclaim = buildEditSupersessionReclaim({
|
|
196949
|
+
db: args.db,
|
|
196950
|
+
sessionId: args.sessionId,
|
|
196951
|
+
targets,
|
|
196952
|
+
pendingOps
|
|
196953
|
+
});
|
|
196954
|
+
for (const op of editReclaim.ops) {
|
|
196955
|
+
if (!selectedIds.has(op.tagId)) {
|
|
196956
|
+
syntheticPendingOps.push(op);
|
|
196957
|
+
selectedIds.add(op.tagId);
|
|
196958
|
+
editMarkerTagIds.add(op.tagId);
|
|
196959
|
+
}
|
|
196960
|
+
}
|
|
196961
|
+
}
|
|
196601
196962
|
autoReclaimTargetCount = syntheticPendingOps.length;
|
|
196602
196963
|
if (syntheticPendingOps.length > 0) {
|
|
196603
|
-
autoReclaimDidMutate = applyPendingOperations(args.sessionId, args.db, targets, args.protectedTags, undefined, [], syntheticPendingOps);
|
|
196964
|
+
autoReclaimDidMutate = applyPendingOperations(args.sessionId, args.db, targets, args.protectedTags, undefined, [], syntheticPendingOps, editMarkerTagIds);
|
|
196604
196965
|
if (autoReclaimDidMutate) {
|
|
196605
196966
|
droppedCount += syntheticPendingOps.length;
|
|
196606
196967
|
autoReclaimDidMutateThisPass = true;
|
|
@@ -197082,7 +197443,7 @@ async function runValidatedHistorianPass(args) {
|
|
|
197082
197443
|
return finalResult;
|
|
197083
197444
|
}
|
|
197084
197445
|
await args.callbacks?.onRepairRetry?.(firstValidation.error ?? "invalid compartment output");
|
|
197085
|
-
const repairPrompt = buildHistorianRepairPrompt(args.prompt, firstRun.result, firstValidation.error ?? "invalid compartment output");
|
|
197446
|
+
const repairPrompt = buildHistorianRepairPrompt(args.prompt, firstRun.result, firstValidation.error ?? "invalid compartment output", args.language);
|
|
197086
197447
|
const repairRun = await runHistorianPrompt({
|
|
197087
197448
|
...args,
|
|
197088
197449
|
prompt: repairPrompt,
|
|
@@ -197724,6 +198085,7 @@ Historian pass ${passCount + 1}, attempt ${passAttempt} started for messages ${c
|
|
|
197724
198085
|
twoPass: deps.historianTwoPass,
|
|
197725
198086
|
subagentKind: "recomp",
|
|
197726
198087
|
agentId: HISTORIAN_RECOMP_AGENT,
|
|
198088
|
+
language: deps.language,
|
|
197727
198089
|
callbacks: {
|
|
197728
198090
|
onRepairRetry: async (error51) => {
|
|
197729
198091
|
emitProgress(`Repair retry (pass ${passCount + 1})…`);
|
|
@@ -198142,6 +198504,7 @@ Historian pass ${passCount + 1}, attempt ${passAttempt} started for messages ${c
|
|
|
198142
198504
|
twoPass: deps.historianTwoPass,
|
|
198143
198505
|
subagentKind: "recomp",
|
|
198144
198506
|
agentId: HISTORIAN_RECOMP_AGENT,
|
|
198507
|
+
language: deps.language,
|
|
198145
198508
|
callbacks: {
|
|
198146
198509
|
onRepairRetry: async (error51) => {
|
|
198147
198510
|
await sendIgnoredMessage(client, sessionId, `## Magic Recomp — Partial
|
|
@@ -198634,7 +198997,7 @@ Historian recomp started. Rebuilding compartments and facts from raw Pi session
|
|
|
198634
198997
|
client: createPiHistorianClient({
|
|
198635
198998
|
runner: deps.runner,
|
|
198636
198999
|
model: deps.historianModel,
|
|
198637
|
-
systemPrompt: COMPARTMENT_STRUCTURAL_SYSTEM_PROMPT,
|
|
199000
|
+
systemPrompt: withContentLanguageDirective(COMPARTMENT_STRUCTURAL_SYSTEM_PROMPT, deps.language, { preserveUserQuotes: true }),
|
|
198638
199001
|
fallbackModels: deps.historianFallbacks,
|
|
198639
199002
|
timeoutMs: deps.historianTimeoutMs,
|
|
198640
199003
|
thinkingLevel: deps.historianThinkingLevel,
|
|
@@ -198657,6 +199020,7 @@ Historian recomp started. Rebuilding compartments and facts from raw Pi session
|
|
|
198657
199020
|
autoPromote: deps.autoPromote,
|
|
198658
199021
|
ensureProjectRegistered: ensureProjectRegisteredFromPiDirectory,
|
|
198659
199022
|
fallbackModels: deps.historianFallbacks,
|
|
199023
|
+
language: deps.language,
|
|
198660
199024
|
fallbackModelId: ctx.model ? `${ctx.model.provider}/${ctx.model.id}` : undefined
|
|
198661
199025
|
}, parsed.kind === "partial" ? { range: parsed.range } : {});
|
|
198662
199026
|
if (result.published) {
|
|
@@ -198909,7 +199273,7 @@ async function runPiMemoryMigration(deps) {
|
|
|
198909
199273
|
}
|
|
198910
199274
|
const result = await deps.runner.run({
|
|
198911
199275
|
agent: "magic-context-historian",
|
|
198912
|
-
systemPrompt: MIGRATION_SYSTEM_PROMPT2,
|
|
199276
|
+
systemPrompt: withMigrationLanguageDirective(MIGRATION_SYSTEM_PROMPT2, deps.language),
|
|
198913
199277
|
userMessage: prompt,
|
|
198914
199278
|
model,
|
|
198915
199279
|
fallbackModels: undefined,
|
|
@@ -199021,7 +199385,8 @@ An upgrade or recomp is already running for this session in the background. Wait
|
|
|
199021
199385
|
thinkingLevel: deps.historianThinkingLevel,
|
|
199022
199386
|
directory: ctx.cwd,
|
|
199023
199387
|
sessionId,
|
|
199024
|
-
userMemoriesEnabled: deps.userMemoriesEnabled
|
|
199388
|
+
userMemoriesEnabled: deps.userMemoriesEnabled,
|
|
199389
|
+
language: deps.language
|
|
199025
199390
|
});
|
|
199026
199391
|
return outcome.summary;
|
|
199027
199392
|
} catch (error51) {
|
|
@@ -199093,7 +199458,7 @@ Rebuilding compartments into the v2 format and re-organizing project memories. T
|
|
|
199093
199458
|
thinkingLevel: deps.historianThinkingLevel,
|
|
199094
199459
|
directory: ctx.cwd,
|
|
199095
199460
|
accountingSessionId: sessionId,
|
|
199096
|
-
systemPrompt: COMPARTMENT_STRUCTURAL_SYSTEM_PROMPT,
|
|
199461
|
+
systemPrompt: withContentLanguageDirective(COMPARTMENT_STRUCTURAL_SYSTEM_PROMPT, deps.language, { preserveUserQuotes: true }),
|
|
199097
199462
|
notify: (text) => sendCtxStatusMessage(pi, {
|
|
199098
199463
|
title: "/ctx-session-upgrade",
|
|
199099
199464
|
text,
|
|
@@ -199109,7 +199474,8 @@ Rebuilding compartments into the v2 format and re-organizing project memories. T
|
|
|
199109
199474
|
autoPromote: deps.autoPromote,
|
|
199110
199475
|
ensureProjectRegistered: ensureProjectRegisteredFromPiDirectory,
|
|
199111
199476
|
fallbackModels: deps.historianFallbacks,
|
|
199112
|
-
fallbackModelId: sessionMainModel
|
|
199477
|
+
fallbackModelId: sessionMainModel,
|
|
199478
|
+
language: deps.language
|
|
199113
199479
|
}, {});
|
|
199114
199480
|
if (!recompResult.published || !isRecompComplete(recompResult.message)) {
|
|
199115
199481
|
const reason = contextualizeUpgradeReason(isRecompFailure(recompResult.message) ? extractRecompReason(recompResult.message) : `Compartments were not fully rebuilt: ${extractRecompReason(recompResult.message)}`);
|
|
@@ -199321,7 +199687,7 @@ function formatThresholdPercent(value) {
|
|
|
199321
199687
|
// package.json
|
|
199322
199688
|
var package_default = {
|
|
199323
199689
|
name: "@cortexkit/pi-magic-context",
|
|
199324
|
-
version: "0.
|
|
199690
|
+
version: "0.29.0",
|
|
199325
199691
|
type: "module",
|
|
199326
199692
|
description: "Pi coding agent extension for Magic Context — cross-session memory and context management",
|
|
199327
199693
|
main: "dist/index.js",
|
|
@@ -205476,7 +205842,8 @@ function resolveSidekickFromConfig(config2) {
|
|
|
205476
205842
|
systemPrompt: sidekick.system_prompt,
|
|
205477
205843
|
timeoutMs: sidekick.timeout_ms,
|
|
205478
205844
|
thinking_level: sidekick.thinking_level,
|
|
205479
|
-
fallbackModels: resolveFallbackChain(sidekick.fallback_models)
|
|
205845
|
+
fallbackModels: resolveFallbackChain(sidekick.fallback_models),
|
|
205846
|
+
language: config2.language
|
|
205480
205847
|
};
|
|
205481
205848
|
}
|
|
205482
205849
|
function resolveHistorianFromConfig(config2) {
|
|
@@ -205505,7 +205872,8 @@ function resolveHistorianFromConfig(config2) {
|
|
|
205505
205872
|
historyBudgetPercentage: config2.history_budget_percentage,
|
|
205506
205873
|
memoryEnabled: config2.memory.enabled,
|
|
205507
205874
|
autoPromote: config2.memory.auto_promote,
|
|
205508
|
-
userMemoriesEnabled: userMemoryCollectionEnabled(config2.dreamer)
|
|
205875
|
+
userMemoriesEnabled: userMemoryCollectionEnabled(config2.dreamer),
|
|
205876
|
+
language: config2.language
|
|
205509
205877
|
};
|
|
205510
205878
|
}
|
|
205511
205879
|
function resolveAutoSearchFromConfig(config2) {
|
|
@@ -205583,6 +205951,7 @@ async function src_default2(pi) {
|
|
|
205583
205951
|
db,
|
|
205584
205952
|
ensureProjectRegistered: ensureProjectRegisteredFromPiDirectory,
|
|
205585
205953
|
allowDreamerActions: false,
|
|
205954
|
+
memoryToolEnabled: true,
|
|
205586
205955
|
ctxReduceEnabled: config2.ctx_reduce_enabled === true,
|
|
205587
205956
|
protectedTags: config2.protected_tags ?? 20,
|
|
205588
205957
|
dreamerEnabled: isDreamerRunnable(config2)
|
|
@@ -205602,6 +205971,7 @@ async function src_default2(pi) {
|
|
|
205602
205971
|
const buildContextOptions = (cfg, hist, auto) => ({
|
|
205603
205972
|
db: database,
|
|
205604
205973
|
ctxReduceEnabled: cfg.ctx_reduce_enabled,
|
|
205974
|
+
smartDrops: cfg.smart_drops === true,
|
|
205605
205975
|
protectedTags: cfg.protected_tags ?? 20,
|
|
205606
205976
|
heuristics: {
|
|
205607
205977
|
caveman: cfg.ctx_reduce_enabled === false && cfg.caveman_text_compression ? {
|
|
@@ -205620,6 +205990,7 @@ async function src_default2(pi) {
|
|
|
205620
205990
|
executeThresholdTokens: cfg.execute_threshold_tokens
|
|
205621
205991
|
},
|
|
205622
205992
|
historian: hist,
|
|
205993
|
+
language: cfg.language,
|
|
205623
205994
|
autoSearch: auto,
|
|
205624
205995
|
resolveForProject: resolveContextOptionsForProject,
|
|
205625
205996
|
maybeAutoEmbedSession: (sessionId, dir, identity) => {
|
|
@@ -205692,6 +206063,7 @@ async function src_default2(pi) {
|
|
|
205692
206063
|
historianFallbacks: historianConfig?.fallbackModels,
|
|
205693
206064
|
historianTimeoutMs: config2.historian_timeout_ms,
|
|
205694
206065
|
historianThinkingLevel: historianConfig?.thinkingLevel,
|
|
206066
|
+
language: config2.language,
|
|
205695
206067
|
memoryEnabled: config2.memory.enabled,
|
|
205696
206068
|
autoPromote: config2.memory.auto_promote
|
|
205697
206069
|
});
|
|
@@ -205704,6 +206076,7 @@ async function src_default2(pi) {
|
|
|
205704
206076
|
historianFallbacks: historianConfig?.fallbackModels,
|
|
205705
206077
|
historianTimeoutMs: config2.historian_timeout_ms,
|
|
205706
206078
|
historianThinkingLevel: historianConfig?.thinkingLevel,
|
|
206079
|
+
language: config2.language,
|
|
205707
206080
|
memoryEnabled: config2.memory.enabled,
|
|
205708
206081
|
autoPromote: config2.memory.auto_promote,
|
|
205709
206082
|
userMemoriesEnabled: userMemoryCollectionEnabled(config2.dreamer)
|
|
@@ -205735,6 +206108,7 @@ async function src_default2(pi) {
|
|
|
205735
206108
|
config: dreamerConfig,
|
|
205736
206109
|
embeddingConfig: config2.embedding,
|
|
205737
206110
|
memoryEnabled: config2.memory.enabled,
|
|
206111
|
+
language: config2.language,
|
|
205738
206112
|
gitCommitIndexing: config2.memory.git_commit_indexing,
|
|
205739
206113
|
onAdjunctsRefreshNeeded: signalPiSystemPromptRefreshForProject
|
|
205740
206114
|
});
|
|
@@ -205849,6 +206223,7 @@ async function src_default2(pi) {
|
|
|
205849
206223
|
dreamerEnabled: effectiveDreamerRunnable,
|
|
205850
206224
|
temporalAwarenessEnabled: effectiveConfig.temporal_awareness ?? false,
|
|
205851
206225
|
cavemanTextCompressionEnabled: effectiveConfig.ctx_reduce_enabled === false && effectiveConfig.caveman_text_compression?.enabled === true,
|
|
206226
|
+
language: effectiveConfig.language,
|
|
205852
206227
|
userMemoriesEnabled: userMemoryCollectionEnabled(effectiveConfig.dreamer),
|
|
205853
206228
|
isCacheBusting,
|
|
205854
206229
|
existingSystemPrompt: event.systemPrompt
|