@cortexkit/opencode-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/README.md +26 -1
- package/dist/agents/language-directive.d.ts +27 -0
- package/dist/agents/language-directive.d.ts.map +1 -0
- package/dist/agents/magic-context-prompt.d.ts +1 -1
- package/dist/agents/magic-context-prompt.d.ts.map +1 -1
- package/dist/config/project-security.d.ts +1 -0
- package/dist/config/project-security.d.ts.map +1 -1
- package/dist/config/schema/magic-context.d.ts +15 -0
- package/dist/config/schema/magic-context.d.ts.map +1 -1
- package/dist/features/magic-context/dreamer/refresh-primers.d.ts +1 -0
- package/dist/features/magic-context/dreamer/refresh-primers.d.ts.map +1 -1
- package/dist/features/magic-context/dreamer/task-config.d.ts +1 -1
- package/dist/features/magic-context/dreamer/task-config.d.ts.map +1 -1
- package/dist/features/magic-context/dreamer/task-executor.d.ts +1 -0
- package/dist/features/magic-context/dreamer/task-executor.d.ts.map +1 -1
- package/dist/features/magic-context/dreamer/task-prompts.d.ts +1 -1
- package/dist/features/magic-context/dreamer/task-prompts.d.ts.map +1 -1
- package/dist/features/magic-context/dreamer/task-scheduler.d.ts +1 -0
- package/dist/features/magic-context/dreamer/task-scheduler.d.ts.map +1 -1
- package/dist/features/magic-context/dreamer/verify.d.ts +1 -0
- package/dist/features/magic-context/dreamer/verify.d.ts.map +1 -1
- package/dist/features/magic-context/memory/memory-migration.d.ts +1 -0
- package/dist/features/magic-context/memory/memory-migration.d.ts.map +1 -1
- package/dist/features/magic-context/sidekick/agent.d.ts +1 -0
- package/dist/features/magic-context/sidekick/agent.d.ts.map +1 -1
- package/dist/features/magic-context/smart-notes/sandbox-runner.d.ts.map +1 -1
- package/dist/features/magic-context/storage-tags.d.ts +0 -5
- package/dist/features/magic-context/storage-tags.d.ts.map +1 -1
- package/dist/features/magic-context/types.d.ts +12 -1
- package/dist/features/magic-context/types.d.ts.map +1 -1
- package/dist/features/magic-context/user-memory/review-user-memories.d.ts +1 -0
- package/dist/features/magic-context/user-memory/review-user-memories.d.ts.map +1 -1
- package/dist/hooks/magic-context/apply-operations.d.ts +8 -1
- package/dist/hooks/magic-context/apply-operations.d.ts.map +1 -1
- package/dist/hooks/magic-context/command-handler.d.ts +1 -0
- package/dist/hooks/magic-context/command-handler.d.ts.map +1 -1
- package/dist/hooks/magic-context/compartment-runner-historian.d.ts +1 -0
- package/dist/hooks/magic-context/compartment-runner-historian.d.ts.map +1 -1
- package/dist/hooks/magic-context/compartment-runner-incremental.d.ts.map +1 -1
- package/dist/hooks/magic-context/compartment-runner-partial-recomp.d.ts.map +1 -1
- package/dist/hooks/magic-context/compartment-runner-recomp.d.ts.map +1 -1
- package/dist/hooks/magic-context/compartment-runner-types.d.ts +1 -0
- package/dist/hooks/magic-context/compartment-runner-types.d.ts.map +1 -1
- package/dist/hooks/magic-context/compartment-runner-validation.d.ts +1 -1
- package/dist/hooks/magic-context/compartment-runner-validation.d.ts.map +1 -1
- package/dist/hooks/magic-context/ctx-reduce-nudge.d.ts +13 -3
- package/dist/hooks/magic-context/ctx-reduce-nudge.d.ts.map +1 -1
- package/dist/hooks/magic-context/edit-marker.d.ts +11 -0
- package/dist/hooks/magic-context/edit-marker.d.ts.map +1 -0
- package/dist/hooks/magic-context/hook-handlers.d.ts.map +1 -1
- package/dist/hooks/magic-context/hook.d.ts +2 -0
- package/dist/hooks/magic-context/hook.d.ts.map +1 -1
- package/dist/hooks/magic-context/read-session-formatting.d.ts.map +1 -1
- package/dist/hooks/magic-context/recomp-orchestrator.d.ts +1 -0
- package/dist/hooks/magic-context/recomp-orchestrator.d.ts.map +1 -1
- package/dist/hooks/magic-context/supersession-reclaim.d.ts +34 -0
- package/dist/hooks/magic-context/supersession-reclaim.d.ts.map +1 -0
- package/dist/hooks/magic-context/system-prompt-hash.d.ts +7 -0
- package/dist/hooks/magic-context/system-prompt-hash.d.ts.map +1 -1
- package/dist/hooks/magic-context/tag-messages.d.ts +8 -0
- package/dist/hooks/magic-context/tag-messages.d.ts.map +1 -1
- package/dist/hooks/magic-context/tool-drop-target.d.ts +2 -0
- package/dist/hooks/magic-context/tool-drop-target.d.ts.map +1 -1
- package/dist/hooks/magic-context/transform-postprocess-phase.d.ts +8 -0
- package/dist/hooks/magic-context/transform-postprocess-phase.d.ts.map +1 -1
- package/dist/hooks/magic-context/transform.d.ts +4 -0
- package/dist/hooks/magic-context/transform.d.ts.map +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +492 -80
- package/dist/plugin/dream-timer.d.ts +1 -0
- package/dist/plugin/dream-timer.d.ts.map +1 -1
- package/dist/plugin/hooks/create-session-hooks.d.ts.map +1 -1
- package/dist/plugin/tool-registry.d.ts.map +1 -1
- package/dist/shared/announcement.d.ts +1 -1
- package/dist/shared/announcement.d.ts.map +1 -1
- package/dist/shared/commit-detection.d.ts +29 -0
- package/dist/shared/commit-detection.d.ts.map +1 -0
- package/dist/shared/tag-transcript.d.ts.map +1 -1
- package/dist/shared/transcript.d.ts +15 -0
- package/dist/shared/transcript.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/shared/announcement.ts +3 -6
- package/src/shared/commit-detection.test.ts +63 -0
- package/src/shared/commit-detection.ts +53 -0
- package/src/shared/tag-transcript.ts +32 -0
- package/src/shared/transcript-opencode.ts +33 -0
- package/src/shared/transcript.ts +17 -0
package/dist/index.js
CHANGED
|
@@ -169,6 +169,98 @@ var init_logger = __esm(() => {
|
|
|
169
169
|
}
|
|
170
170
|
});
|
|
171
171
|
|
|
172
|
+
// src/agents/language-directive.ts
|
|
173
|
+
function resolveLanguageName(language) {
|
|
174
|
+
const code = typeof language === "string" ? language.trim().toLowerCase() : "";
|
|
175
|
+
if (!/^[a-z]{2}$/.test(code))
|
|
176
|
+
return "";
|
|
177
|
+
let english;
|
|
178
|
+
try {
|
|
179
|
+
english = ENGLISH_LANGUAGE_NAMES.of(code) ?? undefined;
|
|
180
|
+
} catch {
|
|
181
|
+
return "";
|
|
182
|
+
}
|
|
183
|
+
if (!english)
|
|
184
|
+
return "";
|
|
185
|
+
let endonym;
|
|
186
|
+
try {
|
|
187
|
+
endonym = new Intl.DisplayNames([code], { type: "language", fallback: "none" }).of(code) ?? undefined;
|
|
188
|
+
} catch {
|
|
189
|
+
endonym = undefined;
|
|
190
|
+
}
|
|
191
|
+
return endonym && endonym !== english ? `${english} (${endonym})` : english;
|
|
192
|
+
}
|
|
193
|
+
function isValidLanguageCode(language) {
|
|
194
|
+
return resolveLanguageName(language) !== "";
|
|
195
|
+
}
|
|
196
|
+
function buildContentLanguageDirective(language, options = {}) {
|
|
197
|
+
const target = resolveLanguageName(language);
|
|
198
|
+
if (!target)
|
|
199
|
+
return "";
|
|
200
|
+
const lines = [
|
|
201
|
+
"## Output language",
|
|
202
|
+
"",
|
|
203
|
+
`Write human-readable prose you author in: ${target}.`,
|
|
204
|
+
"",
|
|
205
|
+
"Do not translate or rename structural tokens. Copy required output schemas exactly:",
|
|
206
|
+
"- 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.",
|
|
207
|
+
"- 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.",
|
|
208
|
+
"- Localize only free-text prose values/content: summaries, memory text, explanations, titles, observations, and answers — unless the prompt says to preserve original wording.",
|
|
209
|
+
"",
|
|
210
|
+
"These literal values must remain English when used:",
|
|
211
|
+
"PROJECT_RULES, ARCHITECTURE, CONSTRAINTS, CONFIG_VALUES, NAMING;",
|
|
212
|
+
"causal_incident, trajectory_correction;",
|
|
213
|
+
"feature, design, docs, release, investigation, bug, refactor, infra;",
|
|
214
|
+
"memory, observation; true, false; No relevant memories found.",
|
|
215
|
+
"",
|
|
216
|
+
"Preserve the required output shape. Do not add commentary outside the requested XML/JSON/tool output."
|
|
217
|
+
];
|
|
218
|
+
if (options.preserveUserQuotes) {
|
|
219
|
+
lines.push("", `Preserve U: lines and directly quoted user text in their original source language; write the surrounding summary prose in ${target}.`);
|
|
220
|
+
}
|
|
221
|
+
if (options.retrospective) {
|
|
222
|
+
lines.push("", `Write the lesson text in ${target}; paraphrase source text and never quote the user.`);
|
|
223
|
+
}
|
|
224
|
+
return lines.join(`
|
|
225
|
+
`);
|
|
226
|
+
}
|
|
227
|
+
function withContentLanguageDirective(systemPrompt, language, options = {}) {
|
|
228
|
+
const directive = buildContentLanguageDirective(language, options);
|
|
229
|
+
return directive ? `${systemPrompt}
|
|
230
|
+
|
|
231
|
+
${directive}` : systemPrompt;
|
|
232
|
+
}
|
|
233
|
+
function buildMigrationLanguageDirective(language) {
|
|
234
|
+
const target = resolveLanguageName(language);
|
|
235
|
+
if (!target)
|
|
236
|
+
return "";
|
|
237
|
+
return [
|
|
238
|
+
"## Output language",
|
|
239
|
+
"",
|
|
240
|
+
"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."
|
|
241
|
+
].join(`
|
|
242
|
+
`);
|
|
243
|
+
}
|
|
244
|
+
function withMigrationLanguageDirective(systemPrompt, language) {
|
|
245
|
+
const directive = buildMigrationLanguageDirective(language);
|
|
246
|
+
return directive ? `${systemPrompt}
|
|
247
|
+
|
|
248
|
+
${directive}` : systemPrompt;
|
|
249
|
+
}
|
|
250
|
+
function buildPrimaryLanguageDirective(language) {
|
|
251
|
+
const target = resolveLanguageName(language);
|
|
252
|
+
if (!target)
|
|
253
|
+
return "";
|
|
254
|
+
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.`;
|
|
255
|
+
}
|
|
256
|
+
var ENGLISH_LANGUAGE_NAMES;
|
|
257
|
+
var init_language_directive = __esm(() => {
|
|
258
|
+
ENGLISH_LANGUAGE_NAMES = new Intl.DisplayNames(["en"], {
|
|
259
|
+
type: "language",
|
|
260
|
+
fallback: "none"
|
|
261
|
+
});
|
|
262
|
+
});
|
|
263
|
+
|
|
172
264
|
// src/shared/jsonc-parser.ts
|
|
173
265
|
import { existsSync as existsSync2, readFileSync as readFileSync2 } from "node:fs";
|
|
174
266
|
function stripJsonComments(content) {
|
|
@@ -15155,6 +15247,7 @@ function defaultTaskConfig(task) {
|
|
|
15155
15247
|
var DEFAULT_EXECUTE_THRESHOLD_PERCENTAGE = 65, EXECUTE_THRESHOLD_CAP_MESSAGE = "execute_threshold is capped at 80% for cache safety: a single large agent step can overflow the context window before Magic Context can compact between turns, forcing OpenCode's native compaction (hard to recover from). 80% also leaves headroom below the 85%/95% emergency bands. Use a value between 20 and 80.", DEFAULT_HISTORIAN_TIMEOUT_MS = 300000, DEFAULT_HISTORY_BUDGET_PERCENTAGE = 0.15, DEFAULT_LOCAL_EMBEDDING_MODEL = "Xenova/all-MiniLM-L6-v2", DreamingTaskSchema, PiThinkingLevelSchema, CronScheduleSchema, DreamTaskBaseConfigSchema, PromotionThresholdSchema, PrimerPromotionThresholdSchema, DreamTaskConfigSchema, ReviewUserMemoriesTaskConfigSchema, PromotePrimersTaskConfigSchema, DEFAULT_TASK_SCHEDULES, DreamTasksSchema, DreamerConfigSchema, SidekickConfigSchema, HistorianConfigSchema, BaseEmbeddingConfigSchema, EmbeddingConfigSchema, MagicContextConfigSchema;
|
|
15156
15248
|
var init_magic_context = __esm(() => {
|
|
15157
15249
|
init_zod();
|
|
15250
|
+
init_language_directive();
|
|
15158
15251
|
init_cron();
|
|
15159
15252
|
init_task_registry();
|
|
15160
15253
|
init_agent_overrides();
|
|
@@ -15276,6 +15369,7 @@ var init_magic_context = __esm(() => {
|
|
|
15276
15369
|
MagicContextConfigSchema = exports_external.object({
|
|
15277
15370
|
enabled: exports_external.boolean().default(true).describe("Enable magic context (default: true)"),
|
|
15278
15371
|
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."),
|
|
15372
|
+
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."),
|
|
15279
15373
|
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)"),
|
|
15280
15374
|
historian: HistorianConfigSchema.describe("Historian agent configuration (model, fallback_models, variant, temperature, maxTokens, permission, two_pass, etc.)"),
|
|
15281
15375
|
dreamer: DreamerConfigSchema.optional().describe("Dreamer agent + scheduling configuration (model, fallback_models, disable, schedule, tasks, etc.)"),
|
|
@@ -15313,6 +15407,7 @@ var init_magic_context = __esm(() => {
|
|
|
15313
15407
|
}).describe("Embedding provider configuration"),
|
|
15314
15408
|
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).'),
|
|
15315
15409
|
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."),
|
|
15410
|
+
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."),
|
|
15316
15411
|
caveman_text_compression: exports_external.object({
|
|
15317
15412
|
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%)."),
|
|
15318
15413
|
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.")
|
|
@@ -16828,6 +16923,19 @@ var init_read_session_db = __esm(async () => {
|
|
|
16828
16923
|
await init_sqlite();
|
|
16829
16924
|
});
|
|
16830
16925
|
|
|
16926
|
+
// src/shared/commit-detection.ts
|
|
16927
|
+
function textMentionsRecentCommit(text) {
|
|
16928
|
+
return COMMIT_HASH_TEST_PATTERN.test(text) && COMMIT_VERB_PATTERN.test(text);
|
|
16929
|
+
}
|
|
16930
|
+
function createCommitHashExtractPattern() {
|
|
16931
|
+
return new RegExp(`\`?\\b(${HASH_HEX})\\b\`?`, "gi");
|
|
16932
|
+
}
|
|
16933
|
+
var HASH_HEX = "[0-9a-f]{7,12}", COMMIT_HASH_TEST_PATTERN, COMMIT_VERB_PATTERN;
|
|
16934
|
+
var init_commit_detection = __esm(() => {
|
|
16935
|
+
COMMIT_HASH_TEST_PATTERN = new RegExp(`\\b${HASH_HEX}\\b`, "i");
|
|
16936
|
+
COMMIT_VERB_PATTERN = /\b(?:commit(?:ted|ting|s)?|cherry-?pick(?:ed|ing|s)?|merge[ds]?|merging|rebas(?:e|ed|es|ing))\b/i;
|
|
16937
|
+
});
|
|
16938
|
+
|
|
16831
16939
|
// ../../node_modules/.bun/ai-tokenizer@1.0.6/node_modules/ai-tokenizer/dist/index.js
|
|
16832
16940
|
function _typeof(o) {
|
|
16833
16941
|
"@babel/helpers - typeof";
|
|
@@ -149377,7 +149485,7 @@ function formatBlock(block) {
|
|
|
149377
149485
|
function extractCommitHashes(text) {
|
|
149378
149486
|
const hashes = [];
|
|
149379
149487
|
const seen = new Set;
|
|
149380
|
-
for (const match of text.matchAll(
|
|
149488
|
+
for (const match of text.matchAll(createCommitHashExtractPattern())) {
|
|
149381
149489
|
const hash2 = match[1]?.toLowerCase();
|
|
149382
149490
|
if (!hash2 || seen.has(hash2))
|
|
149383
149491
|
continue;
|
|
@@ -149390,10 +149498,10 @@ function extractCommitHashes(text) {
|
|
|
149390
149498
|
}
|
|
149391
149499
|
function compactTextForSummary(text, role) {
|
|
149392
149500
|
const commitHashes = role === "assistant" ? extractCommitHashes(text) : [];
|
|
149393
|
-
if (commitHashes.length === 0 || !
|
|
149501
|
+
if (commitHashes.length === 0 || !COMMIT_VERB_PATTERN.test(text)) {
|
|
149394
149502
|
return { text, commitHashes };
|
|
149395
149503
|
}
|
|
149396
|
-
const withoutHashes = text.replace(
|
|
149504
|
+
const withoutHashes = text.replace(createCommitHashExtractPattern(), "").replace(/\(\s*\)/g, "").replace(/\s+,/g, ",").replace(/,\s*,+/g, ", ").replace(/\s{2,}/g, " ").replace(/\s+([,.;:])/g, "$1").trim();
|
|
149397
149505
|
return {
|
|
149398
149506
|
text: withoutHashes.length > 0 ? withoutHashes : text,
|
|
149399
149507
|
commitHashes
|
|
@@ -149412,12 +149520,11 @@ function mergeCommitHashes(existing, next) {
|
|
|
149412
149520
|
}
|
|
149413
149521
|
return merged;
|
|
149414
149522
|
}
|
|
149415
|
-
var
|
|
149523
|
+
var MAX_COMMITS_PER_BLOCK = 5, tokenizer;
|
|
149416
149524
|
var init_read_session_formatting = __esm(() => {
|
|
149525
|
+
init_commit_detection();
|
|
149417
149526
|
init_dist();
|
|
149418
149527
|
init_claude();
|
|
149419
|
-
COMMIT_HASH_PATTERN = /`?\b([0-9a-f]{6,12})\b`?/gi;
|
|
149420
|
-
COMMIT_HINT_PATTERN = /\b(commit(?:ted)?|cherry-?pick(?:ed)?|hash(?:es)?|sha)\b/i;
|
|
149421
149528
|
tokenizer = new src_default(exports_claude);
|
|
149422
149529
|
});
|
|
149423
149530
|
|
|
@@ -149724,6 +149831,37 @@ var init_tag_part_guards = __esm(() => {
|
|
|
149724
149831
|
init_tag_content_primitives();
|
|
149725
149832
|
});
|
|
149726
149833
|
|
|
149834
|
+
// src/hooks/magic-context/edit-marker.ts
|
|
149835
|
+
function safeSlice(str, maxLen) {
|
|
149836
|
+
if (str.length <= maxLen)
|
|
149837
|
+
return str;
|
|
149838
|
+
const lastCharCode = str.charCodeAt(maxLen - 1);
|
|
149839
|
+
if (lastCharCode >= 55296 && lastCharCode <= 56319) {
|
|
149840
|
+
return str.slice(0, maxLen - 1);
|
|
149841
|
+
}
|
|
149842
|
+
return str.slice(0, maxLen);
|
|
149843
|
+
}
|
|
149844
|
+
function isEditTool(name2) {
|
|
149845
|
+
return name2 === "edit" || name2 === "write";
|
|
149846
|
+
}
|
|
149847
|
+
function applyEditMarkerToInput(input) {
|
|
149848
|
+
for (const key of Object.keys(input)) {
|
|
149849
|
+
if (PATH_KEYS.has(key))
|
|
149850
|
+
continue;
|
|
149851
|
+
const value = input[key];
|
|
149852
|
+
if (typeof value !== "string" || !DIFF_KEYS.has(key))
|
|
149853
|
+
continue;
|
|
149854
|
+
if (value.endsWith(TRUNCATION_SENTINEL))
|
|
149855
|
+
continue;
|
|
149856
|
+
input[key] = value.length > EDIT_REGION_HINT_LEN ? `${safeSlice(value, EDIT_REGION_HINT_LEN)}${TRUNCATION_SENTINEL}` : value;
|
|
149857
|
+
}
|
|
149858
|
+
}
|
|
149859
|
+
var TRUNCATION_SENTINEL = "...[truncated]", EDIT_REGION_HINT_LEN = 40, PATH_KEYS, DIFF_KEYS;
|
|
149860
|
+
var init_edit_marker = __esm(() => {
|
|
149861
|
+
PATH_KEYS = new Set(["filePath", "file_path", "path"]);
|
|
149862
|
+
DIFF_KEYS = new Set(["oldString", "newString", "content", "old_string", "new_string"]);
|
|
149863
|
+
});
|
|
149864
|
+
|
|
149727
149865
|
// src/hooks/magic-context/tool-drop-target.ts
|
|
149728
149866
|
function isToolCallId(value) {
|
|
149729
149867
|
return typeof value === "string" && value.length > 0;
|
|
@@ -149790,7 +149928,41 @@ function estimateInputSize(input) {
|
|
|
149790
149928
|
return 0;
|
|
149791
149929
|
}
|
|
149792
149930
|
}
|
|
149793
|
-
function
|
|
149931
|
+
function editMarkerToolPart(part, tagId) {
|
|
149932
|
+
if (!isRecord(part))
|
|
149933
|
+
return;
|
|
149934
|
+
const sentinel = `[dropped §${tagId}§]`;
|
|
149935
|
+
if (part.type === "tool" && isRecord(part.state)) {
|
|
149936
|
+
part.state.output = sentinel;
|
|
149937
|
+
if (isRecord(part.state.input))
|
|
149938
|
+
applyEditMarkerToInput(part.state.input);
|
|
149939
|
+
return;
|
|
149940
|
+
}
|
|
149941
|
+
if (part.type === "tool_result") {
|
|
149942
|
+
part.content = sentinel;
|
|
149943
|
+
return;
|
|
149944
|
+
}
|
|
149945
|
+
if (part.type === "tool-invocation" && isRecord(part.args)) {
|
|
149946
|
+
applyEditMarkerToInput(part.args);
|
|
149947
|
+
return;
|
|
149948
|
+
}
|
|
149949
|
+
if (part.type === "tool_use" && isRecord(part.input)) {
|
|
149950
|
+
applyEditMarkerToInput(part.input);
|
|
149951
|
+
}
|
|
149952
|
+
}
|
|
149953
|
+
function readToolPartInput(part) {
|
|
149954
|
+
if (!isRecord(part))
|
|
149955
|
+
return null;
|
|
149956
|
+
if (part.type === "tool" && isRecord(part.state) && isRecord(part.state.input)) {
|
|
149957
|
+
return part.state.input;
|
|
149958
|
+
}
|
|
149959
|
+
if (part.type === "tool-invocation" && isRecord(part.args))
|
|
149960
|
+
return part.args;
|
|
149961
|
+
if (part.type === "tool_use" && isRecord(part.input))
|
|
149962
|
+
return part.input;
|
|
149963
|
+
return null;
|
|
149964
|
+
}
|
|
149965
|
+
function safeSlice2(str, maxLen) {
|
|
149794
149966
|
if (str.length <= maxLen)
|
|
149795
149967
|
return str;
|
|
149796
149968
|
const lastCharCode = str.charCodeAt(maxLen - 1);
|
|
@@ -149803,9 +149975,9 @@ function truncateInputValues(input) {
|
|
|
149803
149975
|
for (const key of Object.keys(input)) {
|
|
149804
149976
|
const value = input[key];
|
|
149805
149977
|
if (typeof value === "string") {
|
|
149806
|
-
if (value.endsWith(
|
|
149978
|
+
if (value.endsWith(TRUNCATION_SENTINEL2) || value === "[object]" || /^\[\d+ items\]$/.test(value))
|
|
149807
149979
|
continue;
|
|
149808
|
-
input[key] = value.length > 5 ? `${
|
|
149980
|
+
input[key] = value.length > 5 ? `${safeSlice2(value, 5)}${TRUNCATION_SENTINEL2}` : value;
|
|
149809
149981
|
} else if (Array.isArray(value)) {
|
|
149810
149982
|
input[key] = `[${value.length} items]`;
|
|
149811
149983
|
} else if (value !== null && typeof value === "object") {
|
|
@@ -149909,6 +150081,18 @@ function createToolDropTarget(compositeKey, thinkingParts, index, batch, tagId)
|
|
|
149909
150081
|
clearThinkingParts(thinkingParts);
|
|
149910
150082
|
return "truncated";
|
|
149911
150083
|
};
|
|
150084
|
+
const editMarker = () => {
|
|
150085
|
+
const entry = index.get(compositeKey);
|
|
150086
|
+
if (!entry || entry.occurrences.length === 0)
|
|
150087
|
+
return "absent";
|
|
150088
|
+
if (!entry.hasResult)
|
|
150089
|
+
return "incomplete";
|
|
150090
|
+
for (const occurrence of entry.occurrences) {
|
|
150091
|
+
editMarkerToolPart(occurrence.part, tagId);
|
|
150092
|
+
}
|
|
150093
|
+
clearThinkingParts(thinkingParts);
|
|
150094
|
+
return "truncated";
|
|
150095
|
+
};
|
|
149912
150096
|
return {
|
|
149913
150097
|
setContent: (content) => {
|
|
149914
150098
|
if (isDropContent(content)) {
|
|
@@ -149932,14 +150116,34 @@ function createToolDropTarget(compositeKey, thinkingParts, index, batch, tagId)
|
|
|
149932
150116
|
},
|
|
149933
150117
|
drop,
|
|
149934
150118
|
truncate,
|
|
150119
|
+
editMarker,
|
|
149935
150120
|
canDrop: () => {
|
|
149936
150121
|
const entry = index.get(compositeKey);
|
|
149937
150122
|
return !!entry && entry.occurrences.length > 0 && entry.hasResult;
|
|
150123
|
+
},
|
|
150124
|
+
readInput: () => {
|
|
150125
|
+
const entry = index.get(compositeKey);
|
|
150126
|
+
if (!entry)
|
|
150127
|
+
return null;
|
|
150128
|
+
for (const occurrence of entry.occurrences) {
|
|
150129
|
+
if (occurrence.kind !== "invocation")
|
|
150130
|
+
continue;
|
|
150131
|
+
const input = readToolPartInput(occurrence.part);
|
|
150132
|
+
if (input)
|
|
150133
|
+
return input;
|
|
150134
|
+
}
|
|
150135
|
+
for (const occurrence of entry.occurrences) {
|
|
150136
|
+
const input = readToolPartInput(occurrence.part);
|
|
150137
|
+
if (input)
|
|
150138
|
+
return input;
|
|
150139
|
+
}
|
|
150140
|
+
return null;
|
|
149938
150141
|
}
|
|
149939
150142
|
};
|
|
149940
150143
|
}
|
|
149941
|
-
var DROP_PREFIX = "[dropped", IGNORE_PART_TYPES,
|
|
150144
|
+
var DROP_PREFIX = "[dropped", IGNORE_PART_TYPES, TRUNCATION_SENTINEL2 = "...[truncated]";
|
|
149942
150145
|
var init_tool_drop_target = __esm(() => {
|
|
150146
|
+
init_edit_marker();
|
|
149943
150147
|
init_tag_content_primitives();
|
|
149944
150148
|
IGNORE_PART_TYPES = new Set([
|
|
149945
150149
|
"thinking",
|
|
@@ -155736,10 +155940,18 @@ function getOldestActiveUnprotectedToolTags(db, sessionId, protectedTags = 0, li
|
|
|
155736
155940
|
WHERE session_id = ? AND status = 'active'
|
|
155737
155941
|
ORDER BY tag_number DESC LIMIT 1 OFFSET ?
|
|
155738
155942
|
)` : "";
|
|
155739
|
-
const
|
|
155943
|
+
const excludeStateTools = RECLAIM_HINT_EXCLUDED_LIST ? `AND (tool_name IS NULL OR tool_name NOT IN (${RECLAIM_HINT_EXCLUDED_LIST}))` : "";
|
|
155944
|
+
const valueFloor = `AND (
|
|
155945
|
+
(token_count IS NULL AND input_token_count IS NULL)
|
|
155946
|
+
OR (COALESCE(token_count, 0) + COALESCE(input_token_count, 0)) >= ?
|
|
155947
|
+
)`;
|
|
155948
|
+
const params = protectedTags > 0 ? [sessionId, RECLAIM_HINT_MIN_TOKENS, sessionId, protectedTags - 1, boundedLimit] : [sessionId, RECLAIM_HINT_MIN_TOKENS, boundedLimit];
|
|
155740
155949
|
const rows = db.prepare(`SELECT tag_number, tool_name
|
|
155741
155950
|
FROM tags
|
|
155742
|
-
WHERE session_id = ? AND status = 'active' AND type = 'tool'
|
|
155951
|
+
WHERE session_id = ? AND status = 'active' AND type = 'tool'
|
|
155952
|
+
${excludeStateTools}
|
|
155953
|
+
${valueFloor}
|
|
155954
|
+
${whereProtected}
|
|
155743
155955
|
ORDER BY tag_number ASC, id ASC
|
|
155744
155956
|
LIMIT ?`).all(...params);
|
|
155745
155957
|
return rows.filter((row) => typeof row.tag_number === "number").map((row) => ({
|
|
@@ -155873,7 +156085,7 @@ function toTagEntry(row) {
|
|
|
155873
156085
|
messageId: row.message_id,
|
|
155874
156086
|
type,
|
|
155875
156087
|
status,
|
|
155876
|
-
dropMode: row.drop_mode === "truncated" ? "truncated" : "full",
|
|
156088
|
+
dropMode: row.drop_mode === "truncated" ? "truncated" : row.drop_mode === "edit_marker" ? "edit_marker" : "full",
|
|
155877
156089
|
toolName: row.tool_name ?? null,
|
|
155878
156090
|
inputByteSize: row.input_byte_size ?? 0,
|
|
155879
156091
|
byteSize: row.byte_size,
|
|
@@ -156129,7 +156341,7 @@ function deleteToolTagsByOwner(db, sessionId, ownerMsgId) {
|
|
|
156129
156341
|
const result = getDeleteToolTagsByOwnerStatement(db).run(sessionId, ownerMsgId);
|
|
156130
156342
|
return result.changes ?? 0;
|
|
156131
156343
|
}
|
|
156132
|
-
var insertTagStatements, updateTagStatusStatements, updateTagDropModeStatements, updateTagMessageIdStatements, getTagNumbersByMessageIdStatements, deleteTagsByMessageIdStatements, getMaxTagNumberBySessionStatements, getTagNumberByMessageIdStatements, updateTagByteSizeStatements, updateTagInputByteSizeStatements, CONTENT_ID_SUFFIX, updateTagTokenCountStatements, updateTagInputTokenCountStatements, getOwnerScopedToolTagNumbersStatements, getMinMessageTagNumberForRawIdStatements, TAGGER_FLOOR_SCAN_MESSAGES = 8, TAGGER_FLOOR_MAX_PROBES = 64, TAGGER_FLOOR_SAFETY_MARGIN = 256, TAGGER_FLOOR_PER_SKIP_MARGIN = 64, TAG_SELECT_COLUMNS = "id, message_id, type, status, drop_mode, tool_name, input_byte_size, byte_size, reasoning_byte_size, session_id, tag_number, caveman_depth, tool_owner_message_id", getActiveTagsBySessionStatements, getMaxDroppedTagNumberStatements, getToolTagNumberByOwnerStatements, getNullOwnerToolTagStatements, adoptNullOwnerToolTagStatements, deleteToolTagsByOwnerStatements;
|
|
156344
|
+
var insertTagStatements, updateTagStatusStatements, updateTagDropModeStatements, updateTagMessageIdStatements, getTagNumbersByMessageIdStatements, deleteTagsByMessageIdStatements, getMaxTagNumberBySessionStatements, getTagNumberByMessageIdStatements, updateTagByteSizeStatements, updateTagInputByteSizeStatements, CONTENT_ID_SUFFIX, RECLAIM_HINT_EXCLUDED_TOOLS, RECLAIM_HINT_MIN_TOKENS = 250, RECLAIM_HINT_EXCLUDED_LIST, updateTagTokenCountStatements, updateTagInputTokenCountStatements, getOwnerScopedToolTagNumbersStatements, getMinMessageTagNumberForRawIdStatements, TAGGER_FLOOR_SCAN_MESSAGES = 8, TAGGER_FLOOR_MAX_PROBES = 64, TAGGER_FLOOR_SAFETY_MARGIN = 256, TAGGER_FLOOR_PER_SKIP_MARGIN = 64, TAG_SELECT_COLUMNS = "id, message_id, type, status, drop_mode, tool_name, input_byte_size, byte_size, reasoning_byte_size, session_id, tag_number, caveman_depth, tool_owner_message_id", getActiveTagsBySessionStatements, getMaxDroppedTagNumberStatements, getToolTagNumberByOwnerStatements, getNullOwnerToolTagStatements, adoptNullOwnerToolTagStatements, deleteToolTagsByOwnerStatements;
|
|
156133
156345
|
var init_storage_tags = __esm(() => {
|
|
156134
156346
|
insertTagStatements = new WeakMap;
|
|
156135
156347
|
updateTagStatusStatements = new WeakMap;
|
|
@@ -156142,6 +156354,8 @@ var init_storage_tags = __esm(() => {
|
|
|
156142
156354
|
updateTagByteSizeStatements = new WeakMap;
|
|
156143
156355
|
updateTagInputByteSizeStatements = new WeakMap;
|
|
156144
156356
|
CONTENT_ID_SUFFIX = /:(?:p|file)\d+$/;
|
|
156357
|
+
RECLAIM_HINT_EXCLUDED_TOOLS = ["todowrite"];
|
|
156358
|
+
RECLAIM_HINT_EXCLUDED_LIST = RECLAIM_HINT_EXCLUDED_TOOLS.map((name2) => `'${name2.replace(/'/g, "''")}'`).join(", ");
|
|
156145
156359
|
updateTagTokenCountStatements = new WeakMap;
|
|
156146
156360
|
updateTagInputTokenCountStatements = new WeakMap;
|
|
156147
156361
|
getOwnerScopedToolTagNumbersStatements = new WeakMap;
|
|
@@ -165855,7 +166069,7 @@ __export(exports_task_config, {
|
|
|
165855
166069
|
dreamTaskScheduled: () => dreamTaskScheduled,
|
|
165856
166070
|
buildDreamTaskRuntimeConfigs: () => buildDreamTaskRuntimeConfigs
|
|
165857
166071
|
});
|
|
165858
|
-
function buildDreamTaskRuntimeConfigs(dreamer) {
|
|
166072
|
+
function buildDreamTaskRuntimeConfigs(dreamer, language) {
|
|
165859
166073
|
const tasks = dreamer.tasks ?? {};
|
|
165860
166074
|
return CANONICAL_DREAM_TASKS.map((task) => {
|
|
165861
166075
|
const t = tasks[task] ?? {
|
|
@@ -165871,6 +166085,7 @@ function buildDreamTaskRuntimeConfigs(dreamer) {
|
|
|
165871
166085
|
model,
|
|
165872
166086
|
fallbackModels,
|
|
165873
166087
|
thinkingLevel,
|
|
166088
|
+
language,
|
|
165874
166089
|
timeoutMinutes: t.timeout_minutes ?? 20,
|
|
165875
166090
|
promotionThreshold: t.promotion_threshold
|
|
165876
166091
|
};
|
|
@@ -177223,8 +177438,8 @@ function buildHistorianFailureNotice(failureCount, lastError) {
|
|
|
177223
177438
|
].join(`
|
|
177224
177439
|
`);
|
|
177225
177440
|
}
|
|
177226
|
-
function buildHistorianRepairPrompt(originalPrompt, previousOutput, validationError) {
|
|
177227
|
-
|
|
177441
|
+
function buildHistorianRepairPrompt(originalPrompt, previousOutput, validationError, language) {
|
|
177442
|
+
const prompt = [
|
|
177228
177443
|
originalPrompt,
|
|
177229
177444
|
"",
|
|
177230
177445
|
"Your previous XML response was invalid and cannot be persisted.",
|
|
@@ -177237,6 +177452,7 @@ function buildHistorianRepairPrompt(originalPrompt, previousOutput, validationEr
|
|
|
177237
177452
|
previousOutput
|
|
177238
177453
|
].join(`
|
|
177239
177454
|
`);
|
|
177455
|
+
return withContentLanguageDirective(prompt, language, { preserveUserQuotes: true });
|
|
177240
177456
|
}
|
|
177241
177457
|
function validateStoredCompartments(compartments) {
|
|
177242
177458
|
if (compartments.length === 0) {
|
|
@@ -177313,6 +177529,7 @@ function getReducedRecompTokenBudget(currentBudget) {
|
|
|
177313
177529
|
}
|
|
177314
177530
|
var MIN_RECOMP_CHUNK_TOKEN_BUDGET = 20, HISTORIAN_PERSISTENT_FAILURE_THRESHOLD = 3;
|
|
177315
177531
|
var init_compartment_runner_validation = __esm(async () => {
|
|
177532
|
+
init_language_directive();
|
|
177316
177533
|
init_compartment_parser();
|
|
177317
177534
|
await init_compartment_runner_mapping();
|
|
177318
177535
|
});
|
|
@@ -177350,7 +177567,7 @@ async function runValidatedHistorianPass(args) {
|
|
|
177350
177567
|
return finalResult;
|
|
177351
177568
|
}
|
|
177352
177569
|
await args.callbacks?.onRepairRetry?.(firstValidation.error ?? "invalid compartment output");
|
|
177353
|
-
const repairPrompt = buildHistorianRepairPrompt(args.prompt, firstRun.result, firstValidation.error ?? "invalid compartment output");
|
|
177570
|
+
const repairPrompt = buildHistorianRepairPrompt(args.prompt, firstRun.result, firstValidation.error ?? "invalid compartment output", args.language);
|
|
177354
177571
|
const repairRun = await runHistorianPrompt({
|
|
177355
177572
|
...args,
|
|
177356
177573
|
prompt: repairPrompt,
|
|
@@ -182735,7 +182952,8 @@ ${chunkText}`,
|
|
|
182735
182952
|
timeoutMs: historianTimeoutMs,
|
|
182736
182953
|
fallbackModelId: deps.fallbackModelId,
|
|
182737
182954
|
fallbackModels: deps.fallbackModels,
|
|
182738
|
-
twoPass: deps.historianTwoPass
|
|
182955
|
+
twoPass: deps.historianTwoPass,
|
|
182956
|
+
language: deps.language
|
|
182739
182957
|
});
|
|
182740
182958
|
if (!validatedPass.ok) {
|
|
182741
182959
|
sessionLog(sessionId, `historian failure: source=validation reason="${validatedPass.error}" chunkRange=${chunk.startIndex}-${chunk.endIndex} fallbackModel=${deps.fallbackModelId ?? "<none>"} twoPass=${deps.historianTwoPass ? "true" : "false"}`);
|
|
@@ -183211,6 +183429,7 @@ Historian pass ${passCount + 1}, attempt ${passAttempt} started for messages ${c
|
|
|
183211
183429
|
twoPass: deps.historianTwoPass,
|
|
183212
183430
|
subagentKind: "recomp",
|
|
183213
183431
|
agentId: HISTORIAN_RECOMP_AGENT,
|
|
183432
|
+
language: deps.language,
|
|
183214
183433
|
callbacks: {
|
|
183215
183434
|
onRepairRetry: async (error51) => {
|
|
183216
183435
|
emitProgress(`Repair retry (pass ${passCount + 1})…`);
|
|
@@ -183653,6 +183872,7 @@ Historian pass ${passCount + 1}, attempt ${passAttempt} started for messages ${c
|
|
|
183653
183872
|
twoPass: deps.historianTwoPass,
|
|
183654
183873
|
subagentKind: "recomp",
|
|
183655
183874
|
agentId: HISTORIAN_RECOMP_AGENT,
|
|
183875
|
+
language: deps.language,
|
|
183656
183876
|
callbacks: {
|
|
183657
183877
|
onRepairRetry: async (error51) => {
|
|
183658
183878
|
await sendIgnoredMessage(client, sessionId, `## Magic Recomp — Partial
|
|
@@ -186013,7 +186233,7 @@ async function runMemoryMigration(deps) {
|
|
|
186013
186233
|
query: { directory },
|
|
186014
186234
|
body: {
|
|
186015
186235
|
agent: HISTORIAN_AGENT,
|
|
186016
|
-
system: MIGRATION_SYSTEM_PROMPT,
|
|
186236
|
+
system: withMigrationLanguageDirective(MIGRATION_SYSTEM_PROMPT, deps.language),
|
|
186017
186237
|
...modelOverride ? { model: modelOverride } : {},
|
|
186018
186238
|
parts: [{ type: "text", text: prompt, synthetic: true }]
|
|
186019
186239
|
}
|
|
@@ -186092,6 +186312,7 @@ async function runMemoryMigration(deps) {
|
|
|
186092
186312
|
}
|
|
186093
186313
|
var V2_CATEGORIES, MIGRATED_BLOCK_RE, USER_OBS_BLOCK_RE, CATEGORY_BLOCK_RE = (cat) => new RegExp(`<${cat}>([\\s\\S]*?)</${cat}>`), MIGRATION_SYSTEM_PROMPT;
|
|
186094
186314
|
var init_memory_migration = __esm(async () => {
|
|
186315
|
+
init_language_directive();
|
|
186095
186316
|
init_shared();
|
|
186096
186317
|
init_assistant_message_extractor();
|
|
186097
186318
|
init_logger();
|
|
@@ -186208,6 +186429,7 @@ function buildRecompDeps(ctx, sessionId) {
|
|
|
186208
186429
|
memoryEnabled: ctx.memoryEnabled,
|
|
186209
186430
|
autoPromote: ctx.autoPromote,
|
|
186210
186431
|
fallbackModels: ctx.fallbackModels,
|
|
186432
|
+
language: ctx.language,
|
|
186211
186433
|
fallbackModelId: ctx.fallbackModelId ?? resolveLiveModelKey(ctx.liveSessionState, sessionId),
|
|
186212
186434
|
historianTwoPass: ctx.historianTwoPass,
|
|
186213
186435
|
ensureProjectRegistered: ctx.ensureProjectRegistered,
|
|
@@ -186339,7 +186561,8 @@ async function runUpgradeMemoryMigration(ctx, sessionId, migrationDirectory) {
|
|
|
186339
186561
|
primaryModelId: ctx.fallbackModelId ?? resolveLiveModelKey(ctx.liveSessionState, sessionId),
|
|
186340
186562
|
fallbackModels: ctx.fallbackModels,
|
|
186341
186563
|
timeoutMs: ctx.historianTimeoutMs,
|
|
186342
|
-
userMemoriesEnabled: ctx.userMemoriesEnabled
|
|
186564
|
+
userMemoriesEnabled: ctx.userMemoriesEnabled,
|
|
186565
|
+
language: ctx.language
|
|
186343
186566
|
});
|
|
186344
186567
|
return outcome.summary;
|
|
186345
186568
|
} catch (error51) {
|
|
@@ -186415,15 +186638,12 @@ function shouldShowAnnouncement() {
|
|
|
186415
186638
|
}
|
|
186416
186639
|
return ordering > 0;
|
|
186417
186640
|
}
|
|
186418
|
-
var ANNOUNCEMENT_VERSION = "0.
|
|
186641
|
+
var ANNOUNCEMENT_VERSION = "0.29.0", ANNOUNCEMENT_FEATURES, ANNOUNCEMENT_FOOTER = "Join us on Discord: https://discord.gg/F2uWxjGnU", STATE_FILENAME = "last_announced_version";
|
|
186419
186642
|
var init_announcement = __esm(() => {
|
|
186420
186643
|
init_data_path();
|
|
186421
186644
|
ANNOUNCEMENT_FEATURES = [
|
|
186422
|
-
|
|
186423
|
-
"
|
|
186424
|
-
"New Primers: durable answers to the questions that keep coming up about your project, kept current by the dreamer investigating the actual code.",
|
|
186425
|
-
"Embedding storage no longer wipes your vectors when you change model or endpoint. Different models now coexist, so switching providers keeps your existing vectors.",
|
|
186426
|
-
"Config moved to a shared CortexKit location (~/.config/cortexkit/ and <project>/.cortexkit/). This happens automatically on first run; your old file is preserved."
|
|
186645
|
+
`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.`,
|
|
186646
|
+
"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."
|
|
186427
186647
|
];
|
|
186428
186648
|
});
|
|
186429
186649
|
|
|
@@ -186717,6 +186937,9 @@ function buildHiddenAgentConfig(prompt, allowedTools, maxSteps, overrides, agent
|
|
|
186717
186937
|
};
|
|
186718
186938
|
}
|
|
186719
186939
|
|
|
186940
|
+
// src/index.ts
|
|
186941
|
+
init_language_directive();
|
|
186942
|
+
|
|
186720
186943
|
// src/config/index.ts
|
|
186721
186944
|
init_jsonc_parser();
|
|
186722
186945
|
import { existsSync as existsSync5, readFileSync as readFileSync5 } from "node:fs";
|
|
@@ -187461,6 +187684,10 @@ function stripUnsafeProjectConfigFields(projectRaw) {
|
|
|
187461
187684
|
delete projectRaw.auto_update;
|
|
187462
187685
|
warnings.push("Ignoring auto_update from project config (security: this setting only honors user-level config).");
|
|
187463
187686
|
}
|
|
187687
|
+
if ("language" in projectRaw) {
|
|
187688
|
+
delete projectRaw.language;
|
|
187689
|
+
warnings.push("Ignoring language from project config (security: output language is a user-level setting).");
|
|
187690
|
+
}
|
|
187464
187691
|
if ("sqlite" in projectRaw) {
|
|
187465
187692
|
delete projectRaw.sqlite;
|
|
187466
187693
|
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).");
|
|
@@ -188024,6 +188251,7 @@ var MAINTAIN_DOCS_SYSTEM_PROMPT = `You are a documentation maintainer for the ma
|
|
|
188024
188251
|
|
|
188025
188252
|
## Rules
|
|
188026
188253
|
- **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.
|
|
188254
|
+
- **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.
|
|
188027
188255
|
- **Be prescriptive** ("Use X pattern", not "X pattern is used"). **Current state only** — no temporal language, no history.
|
|
188028
188256
|
- **Verify before writing** — read the actual files, never guess. All file paths in the docs must point to files that exist.`;
|
|
188029
188257
|
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.
|
|
@@ -188139,7 +188367,7 @@ Return only XML in this exact shape:
|
|
|
188139
188367
|
function buildMaintainDocsPrompt(projectPath, lastDreamAt, existingDocs) {
|
|
188140
188368
|
const hasAny = existingDocs.architecture || existingDocs.structure;
|
|
188141
188369
|
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.";
|
|
188142
|
-
const modeIntro = hasAny ? `Some docs already exist.
|
|
188370
|
+
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.`;
|
|
188143
188371
|
return `## Task: Maintain Codebase Documentation
|
|
188144
188372
|
|
|
188145
188373
|
**Project:** ${projectPath}
|
|
@@ -188154,15 +188382,16 @@ ${modeIntro}
|
|
|
188154
188382
|
### Process
|
|
188155
188383
|
|
|
188156
188384
|
1. **Check what changed.** ${gitSinceClause}
|
|
188157
|
-
2. **Read existing docs** (if they exist) to understand current
|
|
188385
|
+
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.
|
|
188158
188386
|
3. **Explore the codebase** to verify and update:
|
|
188159
188387
|
- Directory structure: \`find . -type d -not -path '*/node_modules/*' -not -path '*/.git/*' -not -path '*/dist/*' | head -60\`
|
|
188160
188388
|
- Entry points: \`ls src/index.* src/main.* 2>/dev/null\`
|
|
188161
188389
|
- Key imports: \`grep -r "^import\\|^export" src/ --include="*.ts" | head -80\`
|
|
188162
|
-
4. **
|
|
188390
|
+
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/\`.
|
|
188163
188391
|
|
|
188164
188392
|
### Rules
|
|
188165
188393
|
- **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.
|
|
188394
|
+
- **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.
|
|
188166
188395
|
- **Be prescriptive**: "Use X pattern" not "X pattern is used"
|
|
188167
188396
|
- **Always include file paths** in backticks
|
|
188168
188397
|
- **Write current state only**: no temporal language, no history
|
|
@@ -188293,6 +188522,9 @@ function buildDreamTaskPrompt(task, args) {
|
|
|
188293
188522
|
// src/index.ts
|
|
188294
188523
|
init_project_identity();
|
|
188295
188524
|
|
|
188525
|
+
// src/features/magic-context/sidekick/agent.ts
|
|
188526
|
+
init_language_directive();
|
|
188527
|
+
|
|
188296
188528
|
// src/agents/sidekick.ts
|
|
188297
188529
|
var SIDEKICK_AGENT = "sidekick";
|
|
188298
188530
|
|
|
@@ -188360,12 +188592,13 @@ async function runSidekick(deps) {
|
|
|
188360
188592
|
throw error51;
|
|
188361
188593
|
}
|
|
188362
188594
|
const childSessionId = agentSessionId;
|
|
188595
|
+
const systemPrompt = withContentLanguageDirective(deps.config.system_prompt?.trim() || deps.config.prompt?.trim() || SIDEKICK_SYSTEM_PROMPT, deps.language);
|
|
188363
188596
|
const sidekickRun = await promptSyncWithValidatedOutputRetry(deps.client, {
|
|
188364
188597
|
path: { id: childSessionId },
|
|
188365
188598
|
query: { directory: deps.sessionDirectory ?? deps.projectPath },
|
|
188366
188599
|
body: {
|
|
188367
188600
|
agent: SIDEKICK_AGENT,
|
|
188368
|
-
system:
|
|
188601
|
+
system: systemPrompt,
|
|
188369
188602
|
parts: [{ type: "text", text: deps.userMessage, synthetic: true }]
|
|
188370
188603
|
}
|
|
188371
188604
|
}, {
|
|
@@ -189928,6 +190161,7 @@ var DREAMER_DOCS_AGENT = "dreamer-docs";
|
|
|
189928
190161
|
var DREAMER_REVIEWER_AGENT = "dreamer-reviewer";
|
|
189929
190162
|
|
|
189930
190163
|
// src/features/magic-context/dreamer/task-executor.ts
|
|
190164
|
+
init_language_directive();
|
|
189931
190165
|
init_shared();
|
|
189932
190166
|
init_assistant_message_extractor();
|
|
189933
190167
|
init_logger();
|
|
@@ -189936,6 +190170,7 @@ init_memory();
|
|
|
189936
190170
|
init_subagent_token_capture();
|
|
189937
190171
|
|
|
189938
190172
|
// src/features/magic-context/user-memory/review-user-memories.ts
|
|
190173
|
+
init_language_directive();
|
|
189939
190174
|
init_shared();
|
|
189940
190175
|
init_assistant_message_extractor();
|
|
189941
190176
|
init_logger();
|
|
@@ -190050,7 +190285,7 @@ If no promotions are warranted, return empty arrays. Always consume reviewed can
|
|
|
190050
190285
|
query: { directory: args.sessionDirectory },
|
|
190051
190286
|
body: {
|
|
190052
190287
|
agent: DREAMER_REVIEWER_AGENT,
|
|
190053
|
-
system: REVIEW_USER_MEMORIES_SYSTEM_PROMPT,
|
|
190288
|
+
system: withContentLanguageDirective(REVIEW_USER_MEMORIES_SYSTEM_PROMPT, args.language),
|
|
190054
190289
|
...modelBodyField(args.model),
|
|
190055
190290
|
parts: [{ type: "text", text: prompt, synthetic: true }]
|
|
190056
190291
|
}
|
|
@@ -191136,10 +191371,23 @@ function getAsyncModule() {
|
|
|
191136
191371
|
asyncModulePromise ??= newQuickJSAsyncWASMModuleFromVariant(import_quickjs_singlefile_cjs_release_asyncify.default);
|
|
191137
191372
|
return asyncModulePromise;
|
|
191138
191373
|
}
|
|
191374
|
+
var sandboxRunChain = Promise.resolve();
|
|
191375
|
+
function withSandboxLock(fn) {
|
|
191376
|
+
const run = sandboxRunChain.then(fn, fn);
|
|
191377
|
+
sandboxRunChain = run.then(() => {
|
|
191378
|
+
return;
|
|
191379
|
+
}, () => {
|
|
191380
|
+
return;
|
|
191381
|
+
});
|
|
191382
|
+
return run;
|
|
191383
|
+
}
|
|
191139
191384
|
var DEFAULT_TIMEOUT_MS = 2000;
|
|
191140
191385
|
var DEFAULT_HEAP_LIMIT_BYTES = 8 * 1024 * 1024;
|
|
191141
191386
|
var DEFAULT_STACK_LIMIT_BYTES = 512 * 1024;
|
|
191142
191387
|
async function runCompiledSmartNoteCheck(options) {
|
|
191388
|
+
return withSandboxLock(() => runCompiledSmartNoteCheckLocked(options));
|
|
191389
|
+
}
|
|
191390
|
+
async function runCompiledSmartNoteCheckLocked(options) {
|
|
191143
191391
|
const timeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUT_MS;
|
|
191144
191392
|
const controller = new AbortController;
|
|
191145
191393
|
const externalAbort = () => controller.abort(options.signal?.reason);
|
|
@@ -192634,6 +192882,7 @@ async function promotePrimers(args) {
|
|
|
192634
192882
|
}
|
|
192635
192883
|
|
|
192636
192884
|
// src/features/magic-context/dreamer/refresh-primers.ts
|
|
192885
|
+
init_language_directive();
|
|
192637
192886
|
init_read_session_formatting();
|
|
192638
192887
|
init_shared();
|
|
192639
192888
|
init_assistant_message_extractor();
|
|
@@ -192872,7 +193121,7 @@ async function refreshOnePrimer(args, primer, sliceMs, signal) {
|
|
|
192872
193121
|
query: { directory: args.sessionDirectory },
|
|
192873
193122
|
body: {
|
|
192874
193123
|
agent: DREAMER_PRIMER_INVESTIGATOR_AGENT,
|
|
192875
|
-
system: PRIMER_INVESTIGATOR_SYSTEM_PROMPT,
|
|
193124
|
+
system: withContentLanguageDirective(PRIMER_INVESTIGATOR_SYSTEM_PROMPT, args.language),
|
|
192876
193125
|
...modelBodyField(args.model),
|
|
192877
193126
|
parts: [{ type: "text", text: prompt, synthetic: true }]
|
|
192878
193127
|
}
|
|
@@ -193108,6 +193357,7 @@ function insertDreamRun(db, run) {
|
|
|
193108
193357
|
init_task_registry();
|
|
193109
193358
|
|
|
193110
193359
|
// src/features/magic-context/dreamer/verify.ts
|
|
193360
|
+
init_language_directive();
|
|
193111
193361
|
init_shared();
|
|
193112
193362
|
init_assistant_message_extractor();
|
|
193113
193363
|
init_logger();
|
|
@@ -193335,7 +193585,7 @@ async function verifyOneBatch(args, batch, sliceMs, signal) {
|
|
|
193335
193585
|
query: { directory: args.sessionDirectory },
|
|
193336
193586
|
body: {
|
|
193337
193587
|
agent: DREAMER_MEMORY_MAPPER_AGENT,
|
|
193338
|
-
system: VERIFY_SYSTEM_PROMPT,
|
|
193588
|
+
system: withContentLanguageDirective(VERIFY_SYSTEM_PROMPT, args.language),
|
|
193339
193589
|
...modelBodyField(args.model),
|
|
193340
193590
|
parts: [{ type: "text", text: prompt, synthetic: true }]
|
|
193341
193591
|
}
|
|
@@ -193615,7 +193865,8 @@ function createDreamTaskExecutor(deps) {
|
|
|
193615
193865
|
deadline,
|
|
193616
193866
|
promotionThreshold: config2.promotionThreshold ?? 3,
|
|
193617
193867
|
model: config2.model,
|
|
193618
|
-
fallbackModels: config2.fallbackModels
|
|
193868
|
+
fallbackModels: config2.fallbackModels,
|
|
193869
|
+
language: config2.language ?? deps.language
|
|
193619
193870
|
});
|
|
193620
193871
|
recordRun("completed", null);
|
|
193621
193872
|
log(`[dreamer] review-user-memories: promoted=${result.promoted} merged=${result.merged} dismissed=${result.dismissed}`);
|
|
@@ -193651,7 +193902,8 @@ function createDreamTaskExecutor(deps) {
|
|
|
193651
193902
|
deadline,
|
|
193652
193903
|
forceBroad: config2.task === "verify-broad",
|
|
193653
193904
|
model: config2.model,
|
|
193654
|
-
fallbackModels: config2.fallbackModels
|
|
193905
|
+
fallbackModels: config2.fallbackModels,
|
|
193906
|
+
language: config2.language ?? deps.language
|
|
193655
193907
|
});
|
|
193656
193908
|
recordRun("completed", null, {
|
|
193657
193909
|
memoryChanges: computeMemoryDelta(memoryBefore)
|
|
@@ -193703,6 +193955,7 @@ function createDreamTaskExecutor(deps) {
|
|
|
193703
193955
|
deadline,
|
|
193704
193956
|
model: config2.model,
|
|
193705
193957
|
fallbackModels: config2.fallbackModels,
|
|
193958
|
+
language: config2.language ?? deps.language,
|
|
193706
193959
|
rawProviderFactory: deps.primerRawProviderFactory
|
|
193707
193960
|
});
|
|
193708
193961
|
recordRun("completed", null);
|
|
@@ -193820,6 +194073,7 @@ function retrospectiveEventsForSessions(db, sessionIds) {
|
|
|
193820
194073
|
try {
|
|
193821
194074
|
for (const event of getCompartmentEvents(db, sessionId)) {
|
|
193822
194075
|
if (event.kind !== "causal_incident" && event.kind !== "trajectory_correction") {
|
|
194076
|
+
log(`[dreamer] dropping event: unknown kind="${event.kind}"`);
|
|
193823
194077
|
continue;
|
|
193824
194078
|
}
|
|
193825
194079
|
events.push({
|
|
@@ -193944,7 +194198,9 @@ async function runRetrospectiveTask(config2, ctx, helpers) {
|
|
|
193944
194198
|
const frictionWindow = renderFrictionWindow(messages, flagged.map((message) => message.ordinal));
|
|
193945
194199
|
const eventSessionIds = new Set(messages.map((message) => message.sessionId));
|
|
193946
194200
|
const events = retrospectiveEventsForSessions(db, eventSessionIds);
|
|
193947
|
-
const deepenRun = await runChildTurn(RETROSPECTIVE_SYSTEM_PROMPT,
|
|
194201
|
+
const deepenRun = await runChildTurn(withContentLanguageDirective(RETROSPECTIVE_SYSTEM_PROMPT, config2.language ?? deps.language, {
|
|
194202
|
+
retrospective: true
|
|
194203
|
+
}), buildRetrospectivePrompt({ projectPath: projectIdentity, frictionWindow, events }));
|
|
193948
194204
|
if (leaseLost)
|
|
193949
194205
|
throw new Error("Dream lease lost during retrospective");
|
|
193950
194206
|
const sourceSessionId = flagged[0]?.sessionId ?? userMessages[0]?.sessionId ?? "retrospective";
|
|
@@ -194030,7 +194286,7 @@ async function runAgenticTask(config2, ctx, helpers) {
|
|
|
194030
194286
|
query: { directory: docsDir },
|
|
194031
194287
|
body: {
|
|
194032
194288
|
agent: task === "maintain-docs" ? DREAMER_DOCS_AGENT : DREAMER_AGENT,
|
|
194033
|
-
system: task === "maintain-docs" ? MAINTAIN_DOCS_SYSTEM_PROMPT : CURATE_SYSTEM_PROMPT,
|
|
194289
|
+
system: task === "maintain-docs" ? MAINTAIN_DOCS_SYSTEM_PROMPT : withContentLanguageDirective(CURATE_SYSTEM_PROMPT, config2.language ?? deps.language),
|
|
194034
194290
|
...modelBodyField(config2.model),
|
|
194035
194291
|
parts: [{ type: "text", text: taskPrompt, synthetic: true }]
|
|
194036
194292
|
}
|
|
@@ -194852,7 +195108,7 @@ async function sweepProject(reg, origin, db, gitCommitEnabled) {
|
|
|
194852
195108
|
}
|
|
194853
195109
|
try {
|
|
194854
195110
|
await runCompiledSmartNoteSweep(reg, db);
|
|
194855
|
-
const runtimeConfigs = buildDreamTaskRuntimeConfigs(dreamerConfig);
|
|
195111
|
+
const runtimeConfigs = buildDreamTaskRuntimeConfigs(dreamerConfig, reg.language);
|
|
194856
195112
|
const executor = createDreamTaskExecutor({
|
|
194857
195113
|
client: reg.client,
|
|
194858
195114
|
sessionDirectory: reg.directory,
|
|
@@ -194860,7 +195116,8 @@ async function sweepProject(reg, origin, db, gitCommitEnabled) {
|
|
|
194860
195116
|
retrospectiveRawProvider: reg.retrospectiveRawProvider ?? ((db2) => new OpenCodeRetrospectiveRawProvider({ contextDb: db2, openOpenCodeDb })),
|
|
194861
195117
|
primerRawProviderFactory: reg.primerRawProviderFactory,
|
|
194862
195118
|
userMemoryCollectionEnabled: userMemoryCollectionEnabled(dreamerConfig),
|
|
194863
|
-
ensureProjectRegistered: reg.ensureRegistered
|
|
195119
|
+
ensureProjectRegistered: reg.ensureRegistered,
|
|
195120
|
+
language: reg.language
|
|
194864
195121
|
});
|
|
194865
195122
|
const ran = await runDueTasksForProject({
|
|
194866
195123
|
db,
|
|
@@ -196224,7 +196481,8 @@ Provide a prompt to augment with project memory context.`, {});
|
|
|
196224
196481
|
projectPath: deps.sidekick.projectPath,
|
|
196225
196482
|
sessionDirectory: deps.sidekick.sessionDirectory,
|
|
196226
196483
|
userMessage: prompt,
|
|
196227
|
-
config: deps.sidekick.config
|
|
196484
|
+
config: deps.sidekick.config,
|
|
196485
|
+
language: deps.sidekick.language
|
|
196228
196486
|
});
|
|
196229
196487
|
let augmentedPrompt;
|
|
196230
196488
|
if (sidekickResult) {
|
|
@@ -196831,6 +197089,7 @@ function channel1RefireTokens(workingWindowTokens) {
|
|
|
196831
197089
|
var S_GENTLE = 0.2;
|
|
196832
197090
|
var S_FIRM = 0.4;
|
|
196833
197091
|
var S_URGENT = 0.65;
|
|
197092
|
+
var CHANNEL1_PRESSURE_FLOOR = 0.8;
|
|
196834
197093
|
var LEVEL_RANK = { gentle: 1, firm: 2, urgent: 3 };
|
|
196835
197094
|
var DROP_SENTINELS = ["[dropped", "[truncated"];
|
|
196836
197095
|
function isDroppedToolOutput(output) {
|
|
@@ -196895,7 +197154,8 @@ function computeTailTokenEstimate(messages) {
|
|
|
196895
197154
|
};
|
|
196896
197155
|
}
|
|
196897
197156
|
function decideChannel1(input) {
|
|
196898
|
-
const { undroppedTokens,
|
|
197157
|
+
const { undroppedTokens, workingWindowTokens, hasRecentReduce } = input;
|
|
197158
|
+
const pressure = Math.min(1, Math.max(0, input.pressure));
|
|
196899
197159
|
const resetCycle = hasRecentReduce || undroppedTokens < input.lastNudgeUndropped;
|
|
196900
197160
|
const lastNudge = resetCycle ? 0 : input.lastNudgeUndropped;
|
|
196901
197161
|
const lastLevel = resetCycle ? "" : input.lastNudgeLevel;
|
|
@@ -196910,8 +197170,10 @@ function decideChannel1(input) {
|
|
|
196910
197170
|
return quiet();
|
|
196911
197171
|
if (undroppedTokens < CHANNEL1_FLOOR_TOKENS)
|
|
196912
197172
|
return quiet();
|
|
196913
|
-
|
|
196914
|
-
|
|
197173
|
+
if (pressure < CHANNEL1_PRESSURE_FLOOR)
|
|
197174
|
+
return quiet();
|
|
197175
|
+
const denom = Math.max(input.estimatedInputTokens, 1);
|
|
197176
|
+
const severity = Math.min(1, undroppedTokens / denom);
|
|
196915
197177
|
if (severity < S_GENTLE)
|
|
196916
197178
|
return quiet();
|
|
196917
197179
|
let level;
|
|
@@ -198580,7 +198842,7 @@ var RECENT_TOOL_SKELETON_WINDOW = 20;
|
|
|
198580
198842
|
function buildReplacementContent(tagId) {
|
|
198581
198843
|
return `[dropped §${tagId}§]`;
|
|
198582
198844
|
}
|
|
198583
|
-
function applyPendingOperations(sessionId, db, targets, protectedTags = 0, preloadedTags, preloadedPendingOps, syntheticPendingOps = []) {
|
|
198845
|
+
function applyPendingOperations(sessionId, db, targets, protectedTags = 0, preloadedTags, preloadedPendingOps, syntheticPendingOps = [], editMarkerTagIds = new Set) {
|
|
198584
198846
|
let didMutateMessage = false;
|
|
198585
198847
|
db.transaction(() => {
|
|
198586
198848
|
const tags = preloadedTags ?? getTagsBySession(db, sessionId);
|
|
@@ -198611,7 +198873,15 @@ function applyPendingOperations(sessionId, db, targets, protectedTags = 0, prelo
|
|
|
198611
198873
|
}
|
|
198612
198874
|
let shouldPersistDrop = false;
|
|
198613
198875
|
if (isToolTag) {
|
|
198614
|
-
if (
|
|
198876
|
+
if (editMarkerTagIds.has(pendingOp.tagId)) {
|
|
198877
|
+
const markResult = target?.editMarker?.() ?? "absent";
|
|
198878
|
+
if (markResult === "incomplete" || markResult === "absent") {
|
|
198879
|
+
continue;
|
|
198880
|
+
}
|
|
198881
|
+
didMutateMessage = true;
|
|
198882
|
+
updateTagDropMode(db, sessionId, pendingOp.tagId, "edit_marker");
|
|
198883
|
+
shouldPersistDrop = true;
|
|
198884
|
+
} else if (skeletonWindow.has(pendingOp.tagId)) {
|
|
198615
198885
|
const truncResult = target?.truncate?.() ?? "absent";
|
|
198616
198886
|
if (truncResult === "incomplete" || synthetic && truncResult !== "truncated") {
|
|
198617
198887
|
continue;
|
|
@@ -198656,7 +198926,12 @@ function applyFlushedStatuses(sessionId, db, targets, preloadedTags) {
|
|
|
198656
198926
|
if (tag.status === "dropped") {
|
|
198657
198927
|
const target = targets.get(tag.tagNumber);
|
|
198658
198928
|
if (tag.type === "tool") {
|
|
198659
|
-
if (tag.dropMode === "
|
|
198929
|
+
if (tag.dropMode === "edit_marker") {
|
|
198930
|
+
const markResult = target?.editMarker?.() ?? "absent";
|
|
198931
|
+
if (markResult === "truncated") {
|
|
198932
|
+
didMutateMessage = true;
|
|
198933
|
+
}
|
|
198934
|
+
} else if (tag.dropMode === "truncated") {
|
|
198660
198935
|
const truncResult = target?.truncate?.() ?? "absent";
|
|
198661
198936
|
if (truncResult === "truncated") {
|
|
198662
198937
|
didMutateMessage = true;
|
|
@@ -198711,6 +198986,7 @@ function stripStructuralNoise(messages) {
|
|
|
198711
198986
|
// src/hooks/magic-context/tag-messages.ts
|
|
198712
198987
|
init_storage_tags();
|
|
198713
198988
|
await init_storage();
|
|
198989
|
+
init_commit_detection();
|
|
198714
198990
|
// src/hooks/magic-context/drop-stale-reduce-calls.ts
|
|
198715
198991
|
var STALE_TOOL_NAMES = new Set(["ctx_reduce"]);
|
|
198716
198992
|
function isReduceToolPart(part) {
|
|
@@ -199031,7 +199307,6 @@ function tagMessages(sessionId, messages, tagger, db, options = {}) {
|
|
|
199031
199307
|
let lastReduceMessageIndex = -1;
|
|
199032
199308
|
const RECENT_REDUCE_LOOKBACK = 10;
|
|
199033
199309
|
const COMMIT_LOOKBACK = 5;
|
|
199034
|
-
const COMMIT_HASH_PATTERN2 = /\b[0-9a-f]{7,12}\b/;
|
|
199035
199310
|
let commitDetected = false;
|
|
199036
199311
|
let accDerive = 0;
|
|
199037
199312
|
let accGetToolTag = 0;
|
|
@@ -199222,7 +199497,7 @@ function tagMessages(sessionId, messages, tagger, db, options = {}) {
|
|
|
199222
199497
|
for (const part of message.parts) {
|
|
199223
199498
|
if (isTextPart(part)) {
|
|
199224
199499
|
const text = part.text;
|
|
199225
|
-
if (
|
|
199500
|
+
if (textMentionsRecentCommit(text)) {
|
|
199226
199501
|
commitDetected = true;
|
|
199227
199502
|
break;
|
|
199228
199503
|
}
|
|
@@ -200717,6 +200992,99 @@ function isVisibleNoteReadPart(part) {
|
|
|
200717
200992
|
return false;
|
|
200718
200993
|
}
|
|
200719
200994
|
|
|
200995
|
+
// src/hooks/magic-context/supersession-reclaim.ts
|
|
200996
|
+
init_edit_marker();
|
|
200997
|
+
await init_storage();
|
|
200998
|
+
var TODOWRITE_KEEP = 1;
|
|
200999
|
+
var CTX_REDUCE_KEEP = 5;
|
|
201000
|
+
var ZERO_VALUE_META_TOOLS = new Set(["bash_status", "bash_kill"]);
|
|
201001
|
+
var CTX_NOTE_ZERO_VALUE_ACTIONS = new Set(["read", "dismiss"]);
|
|
201002
|
+
function buildSupersessionReclaimOps(input) {
|
|
201003
|
+
const realPendingTagIds = new Set((input.pendingOps ?? []).map((op) => op.tagId));
|
|
201004
|
+
const tags = getActiveTagsBySession(input.db, input.sessionId);
|
|
201005
|
+
const toolTags = tags.filter((tag) => tag.type === "tool" && tag.status === "active").sort((left, right) => right.tagNumber - left.tagNumber);
|
|
201006
|
+
const dropTagIds = [];
|
|
201007
|
+
let todowriteSeen = 0;
|
|
201008
|
+
let ctxReduceSeen = 0;
|
|
201009
|
+
for (const tag of toolTags) {
|
|
201010
|
+
const name2 = tag.toolName;
|
|
201011
|
+
if (!name2)
|
|
201012
|
+
continue;
|
|
201013
|
+
let isTarget = false;
|
|
201014
|
+
if (name2 === "todowrite") {
|
|
201015
|
+
todowriteSeen += 1;
|
|
201016
|
+
isTarget = todowriteSeen > TODOWRITE_KEEP;
|
|
201017
|
+
} else if (name2 === "ctx_reduce") {
|
|
201018
|
+
ctxReduceSeen += 1;
|
|
201019
|
+
isTarget = ctxReduceSeen > CTX_REDUCE_KEEP;
|
|
201020
|
+
} else if (ZERO_VALUE_META_TOOLS.has(name2)) {
|
|
201021
|
+
isTarget = true;
|
|
201022
|
+
} else if (name2 === "ctx_note") {
|
|
201023
|
+
const action = input.targets.get(tag.tagNumber)?.readInput?.()?.action;
|
|
201024
|
+
isTarget = typeof action === "string" && CTX_NOTE_ZERO_VALUE_ACTIONS.has(action);
|
|
201025
|
+
}
|
|
201026
|
+
if (isTarget)
|
|
201027
|
+
dropTagIds.push(tag.tagNumber);
|
|
201028
|
+
}
|
|
201029
|
+
const synthetic = [];
|
|
201030
|
+
for (const tagId of dropTagIds) {
|
|
201031
|
+
if (realPendingTagIds.has(tagId))
|
|
201032
|
+
continue;
|
|
201033
|
+
if (input.targets.get(tagId)?.canDrop?.() !== true)
|
|
201034
|
+
continue;
|
|
201035
|
+
synthetic.push({
|
|
201036
|
+
id: 0,
|
|
201037
|
+
sessionId: input.sessionId,
|
|
201038
|
+
tagId,
|
|
201039
|
+
operation: "drop",
|
|
201040
|
+
queuedAt: 0
|
|
201041
|
+
});
|
|
201042
|
+
}
|
|
201043
|
+
return synthetic;
|
|
201044
|
+
}
|
|
201045
|
+
function buildEditSupersessionReclaim(input) {
|
|
201046
|
+
const realPendingTagIds = new Set((input.pendingOps ?? []).map((op) => op.tagId));
|
|
201047
|
+
const tags = getActiveTagsBySession(input.db, input.sessionId);
|
|
201048
|
+
const editTags = tags.filter((tag) => tag.type === "tool" && tag.status === "active" && isEditTool(tag.toolName)).sort((left, right) => right.tagNumber - left.tagNumber);
|
|
201049
|
+
const seenFile = new Set;
|
|
201050
|
+
const ops = [];
|
|
201051
|
+
const editMarkerTagIds = new Set;
|
|
201052
|
+
for (const tag of editTags) {
|
|
201053
|
+
const filePath = readFilePath(input.targets.get(tag.tagNumber));
|
|
201054
|
+
if (!filePath)
|
|
201055
|
+
continue;
|
|
201056
|
+
if (!seenFile.has(filePath)) {
|
|
201057
|
+
seenFile.add(filePath);
|
|
201058
|
+
continue;
|
|
201059
|
+
}
|
|
201060
|
+
if (realPendingTagIds.has(tag.tagNumber))
|
|
201061
|
+
continue;
|
|
201062
|
+
if (input.targets.get(tag.tagNumber)?.canDrop?.() !== true)
|
|
201063
|
+
continue;
|
|
201064
|
+
editMarkerTagIds.add(tag.tagNumber);
|
|
201065
|
+
ops.push({
|
|
201066
|
+
id: 0,
|
|
201067
|
+
sessionId: input.sessionId,
|
|
201068
|
+
tagId: tag.tagNumber,
|
|
201069
|
+
operation: "drop",
|
|
201070
|
+
queuedAt: 0
|
|
201071
|
+
});
|
|
201072
|
+
}
|
|
201073
|
+
return { ops, editMarkerTagIds };
|
|
201074
|
+
}
|
|
201075
|
+
var FILE_PATH_KEYS = ["filePath", "file_path", "path"];
|
|
201076
|
+
function readFilePath(target) {
|
|
201077
|
+
const input = target?.readInput?.();
|
|
201078
|
+
if (!input)
|
|
201079
|
+
return null;
|
|
201080
|
+
for (const key of FILE_PATH_KEYS) {
|
|
201081
|
+
const value = input[key];
|
|
201082
|
+
if (typeof value === "string" && value.length > 0)
|
|
201083
|
+
return value;
|
|
201084
|
+
}
|
|
201085
|
+
return null;
|
|
201086
|
+
}
|
|
201087
|
+
|
|
200720
201088
|
// src/hooks/magic-context/todo-view.ts
|
|
200721
201089
|
import { createHash as createHash12 } from "node:crypto";
|
|
200722
201090
|
var TERMINAL_STATUSES = new Set(["completed", "cancelled"]);
|
|
@@ -200987,9 +201355,38 @@ async function runPostTransformPhase(args) {
|
|
|
200987
201355
|
watermark: args.sessionMeta.toolReclaimWatermark ?? 0,
|
|
200988
201356
|
pendingOps
|
|
200989
201357
|
});
|
|
201358
|
+
const editMarkerTagIds = new Set;
|
|
201359
|
+
if (args.smartDrops) {
|
|
201360
|
+
const selectedIds = new Set(syntheticPendingOps.map((op) => op.tagId));
|
|
201361
|
+
const supersessionOps = buildSupersessionReclaimOps({
|
|
201362
|
+
db: args.db,
|
|
201363
|
+
sessionId: args.sessionId,
|
|
201364
|
+
targets: args.targets,
|
|
201365
|
+
pendingOps
|
|
201366
|
+
});
|
|
201367
|
+
for (const op of supersessionOps) {
|
|
201368
|
+
if (!selectedIds.has(op.tagId)) {
|
|
201369
|
+
syntheticPendingOps.push(op);
|
|
201370
|
+
selectedIds.add(op.tagId);
|
|
201371
|
+
}
|
|
201372
|
+
}
|
|
201373
|
+
const editReclaim = buildEditSupersessionReclaim({
|
|
201374
|
+
db: args.db,
|
|
201375
|
+
sessionId: args.sessionId,
|
|
201376
|
+
targets: args.targets,
|
|
201377
|
+
pendingOps
|
|
201378
|
+
});
|
|
201379
|
+
for (const op of editReclaim.ops) {
|
|
201380
|
+
if (!selectedIds.has(op.tagId)) {
|
|
201381
|
+
syntheticPendingOps.push(op);
|
|
201382
|
+
selectedIds.add(op.tagId);
|
|
201383
|
+
editMarkerTagIds.add(op.tagId);
|
|
201384
|
+
}
|
|
201385
|
+
}
|
|
201386
|
+
}
|
|
200990
201387
|
autoReclaimTargetCount = syntheticPendingOps.length;
|
|
200991
201388
|
if (syntheticPendingOps.length > 0) {
|
|
200992
|
-
autoReclaimDidMutate = applyPendingOperations(args.sessionId, args.db, args.targets, args.protectedTags, undefined, [], syntheticPendingOps);
|
|
201389
|
+
autoReclaimDidMutate = applyPendingOperations(args.sessionId, args.db, args.targets, args.protectedTags, undefined, [], syntheticPendingOps, editMarkerTagIds);
|
|
200993
201390
|
if (autoReclaimDidMutate) {
|
|
200994
201391
|
droppedCount += syntheticPendingOps.length;
|
|
200995
201392
|
autoReclaimDidMutateThisPass = true;
|
|
@@ -201931,6 +202328,7 @@ Historian previously failed ${historianFailureState.failureCount} time(s), so Ma
|
|
|
201931
202328
|
sessionDirectory,
|
|
201932
202329
|
autoSearch: deps.autoSearch,
|
|
201933
202330
|
cavemanTextCompression: deps.ctxReduceEnabled === false && !reducedMode ? deps.cavemanTextCompression : undefined,
|
|
202331
|
+
smartDrops: deps.smartDrops === true,
|
|
201934
202332
|
resolvedProviderID,
|
|
201935
202333
|
historyRefreshSessions: deps.historyRefreshSessions,
|
|
201936
202334
|
m0M1: {
|
|
@@ -202764,6 +203162,7 @@ function maybeInjectChannel1Nudge(args, sessionId, tool, output) {
|
|
|
202764
203162
|
const decision = decideChannel1({
|
|
202765
203163
|
undroppedTokens,
|
|
202766
203164
|
pressure,
|
|
203165
|
+
estimatedInputTokens: state.lastInputTokens + state.turnToolTokens,
|
|
202767
203166
|
workingWindowTokens,
|
|
202768
203167
|
lastNudgeUndropped: getLastNudgeUndropped(args.db, sessionId),
|
|
202769
203168
|
lastNudgeLevel: getLastNudgeLevel(args.db, sessionId),
|
|
@@ -202829,6 +203228,7 @@ init_send_session_notification();
|
|
|
202829
203228
|
import { createHash as createHash13 } from "node:crypto";
|
|
202830
203229
|
|
|
202831
203230
|
// src/agents/magic-context-prompt.ts
|
|
203231
|
+
init_language_directive();
|
|
202832
203232
|
var LONG_TERM_PARTNER_FRAME = `### You are the user's long-term partner on this project — not a one-off hire
|
|
202833
203233
|
|
|
202834
203234
|
Most AI sessions are disposable: one session per task, discarded when it's done — like hiring a developer for a single bug fix and letting them go the moment they finish. Magic Context changes this completely. This session is a durable working relationship: you carry the full history and accumulated knowledge of this project, and you continue across many tasks, bugs, and features — with memory that persists across restarts. This session may continue for weeks, months, or even years.
|
|
@@ -202844,16 +203244,20 @@ var PARTNER_FRAME_CLOSER_NO_REDUCE = `
|
|
|
202844
203244
|
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.`;
|
|
202845
203245
|
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).`;
|
|
202846
203246
|
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.`;
|
|
202847
|
-
var
|
|
202848
|
-
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".
|
|
202849
|
-
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.
|
|
202850
|
-
${CTX_NOTE_GUIDANCE}
|
|
202851
|
-
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.
|
|
203247
|
+
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.
|
|
202852
203248
|
**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:
|
|
202853
203249
|
- Found a project's source code path after searching → \`ctx_memory(action="write", category="CONFIG_VALUES", content="OpenCode source is at ~/Work/OSS/opencode")\`
|
|
202854
203250
|
- Discovered a non-obvious build/test command → \`ctx_memory(action="write", category="PROJECT_RULES", content="Always use scripts/release.sh for releases")\`
|
|
202855
|
-
- Learned a constraint the hard way → \`ctx_memory(action="write", category="CONSTRAINTS", content="Dashboard Tauri build needs RGBA PNGs, not grayscale")
|
|
202856
|
-
|
|
203251
|
+
- Learned a constraint the hard way → \`ctx_memory(action="write", category="CONSTRAINTS", content="Dashboard Tauri build needs RGBA PNGs, not grayscale")\``;
|
|
203252
|
+
function memoryGuidanceBlock(memoryEnabled) {
|
|
203253
|
+
return memoryEnabled ? `${MEMORY_GUIDANCE}
|
|
203254
|
+
` : "";
|
|
203255
|
+
}
|
|
203256
|
+
var BASE_INTRO = (protectedTags, memoryEnabled) => `Messages and tool outputs are tagged with §N§ identifiers (e.g., §1§, §42§).
|
|
203257
|
+
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".
|
|
203258
|
+
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.
|
|
203259
|
+
${CTX_NOTE_GUIDANCE}
|
|
203260
|
+
${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.
|
|
202857
203261
|
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).
|
|
202858
203262
|
**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:
|
|
202859
203263
|
- Can't remember where a related codebase or dependency lives → \`ctx_search(query="opencode source code path")\`
|
|
@@ -202867,13 +203271,8 @@ NEVER drop large ranges blindly (e.g., "1-50"). Review each tag before deciding.
|
|
|
202867
203271
|
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\`.
|
|
202868
203272
|
NEVER drop assistant text messages unless they are exceptionally large. Your conversation messages are lightweight; only large tool outputs are worth dropping.
|
|
202869
203273
|
Before your turn finishes, consider using \`ctx_reduce\` to drop large tool outputs you no longer need.`;
|
|
202870
|
-
var BASE_INTRO_NO_REDUCE = () => `${CTX_NOTE_GUIDANCE}
|
|
202871
|
-
Use \`
|
|
202872
|
-
**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:
|
|
202873
|
-
- Found a project's source code path after searching → \`ctx_memory(action="write", category="CONFIG_VALUES", content="OpenCode source is at ~/Work/OSS/opencode")\`
|
|
202874
|
-
- Discovered a non-obvious build/test command → \`ctx_memory(action="write", category="PROJECT_RULES", content="Always use scripts/release.sh for releases")\`
|
|
202875
|
-
- Learned a constraint the hard way → \`ctx_memory(action="write", category="CONSTRAINTS", content="Dashboard Tauri build needs RGBA PNGs, not grayscale")\`
|
|
202876
|
-
Use \`ctx_search\` to search across project memories, indexed git commits, and this session's full conversation history (including compacted parts) from one query.
|
|
203274
|
+
var BASE_INTRO_NO_REDUCE = (memoryEnabled) => `${CTX_NOTE_GUIDANCE}
|
|
203275
|
+
${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.
|
|
202877
203276
|
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).
|
|
202878
203277
|
**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:
|
|
202879
203278
|
- Can't remember where a related codebase or dependency lives → \`ctx_search(query="opencode source code path")\`
|
|
@@ -202907,7 +203306,7 @@ Drop silently — do not narrate it. NEVER drop large ranges blindly (e.g., "1-5
|
|
|
202907
203306
|
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.`;
|
|
202908
203307
|
var CAVEMAN_COMPRESSION_WARNING = `
|
|
202909
203308
|
**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.`;
|
|
202910
|
-
function buildMagicContextSection(_agent, protectedTags, ctxReduceEnabled = true, dreamerEnabled = false, temporalAwarenessEnabled = false, cavemanTextCompressionEnabled = false, subagentMode = false) {
|
|
203309
|
+
function buildMagicContextSection(_agent, protectedTags, ctxReduceEnabled = true, dreamerEnabled = false, temporalAwarenessEnabled = false, cavemanTextCompressionEnabled = false, subagentMode = false, language, memoryEnabled = true) {
|
|
202911
203310
|
if (subagentMode) {
|
|
202912
203311
|
return `## Magic Context
|
|
202913
203312
|
|
|
@@ -202919,23 +203318,27 @@ The dreamer evaluates smart note conditions during nightly runs and surfaces the
|
|
|
202919
203318
|
Example: \`ctx_note(action="write", content="Implement X because Y", surface_condition="When PR #42 is merged in this repo")\`` : "";
|
|
202920
203319
|
const temporalGuidance = temporalAwarenessEnabled ? TEMPORAL_AWARENESS_GUIDANCE : "";
|
|
202921
203320
|
const cavemanWarning = cavemanTextCompressionEnabled && !ctxReduceEnabled ? CAVEMAN_COMPRESSION_WARNING : "";
|
|
203321
|
+
const languageDirective = buildPrimaryLanguageDirective(language);
|
|
203322
|
+
const languageGuidance = languageDirective ? `
|
|
203323
|
+
|
|
203324
|
+
${languageDirective}` : "";
|
|
202922
203325
|
if (!ctxReduceEnabled) {
|
|
202923
203326
|
return `## Magic Context
|
|
202924
203327
|
|
|
202925
203328
|
${LONG_TERM_PARTNER_FRAME}
|
|
202926
203329
|
${PARTNER_FRAME_CLOSER_NO_REDUCE}
|
|
202927
203330
|
|
|
202928
|
-
${BASE_INTRO_NO_REDUCE()}${smartNoteGuidance}${temporalGuidance}${cavemanWarning}`;
|
|
203331
|
+
${BASE_INTRO_NO_REDUCE(memoryEnabled)}${smartNoteGuidance}${temporalGuidance}${cavemanWarning}${languageGuidance}`;
|
|
202929
203332
|
}
|
|
202930
203333
|
return `## Magic Context
|
|
202931
203334
|
|
|
202932
203335
|
${LONG_TERM_PARTNER_FRAME}
|
|
202933
203336
|
${PARTNER_FRAME_CLOSER_REDUCE}
|
|
202934
203337
|
|
|
202935
|
-
${BASE_INTRO(protectedTags)}${smartNoteGuidance}${temporalGuidance}
|
|
203338
|
+
${BASE_INTRO(protectedTags, memoryEnabled)}${smartNoteGuidance}${temporalGuidance}
|
|
202936
203339
|
${GENERIC_SECTION}
|
|
202937
203340
|
|
|
202938
|
-
Prefer many small targeted operations over one large blanket operation, and keep the working set tidy as routine maintenance
|
|
203341
|
+
Prefer many small targeted operations over one large blanket operation, and keep the working set tidy as routine maintenance.${languageGuidance}`;
|
|
202939
203342
|
}
|
|
202940
203343
|
|
|
202941
203344
|
// src/hooks/magic-context/system-prompt-hash.ts
|
|
@@ -202993,7 +203396,7 @@ function createSystemPromptHashHandler(deps) {
|
|
|
202993
203396
|
const fullPrompt = output.system.join(`
|
|
202994
203397
|
`);
|
|
202995
203398
|
if (fullPrompt.length > 0 && !fullPrompt.includes(MAGIC_CONTEXT_MARKER) && !skipGuidanceForDisabledSubagent) {
|
|
202996
|
-
const guidance = buildMagicContextSection(null, deps.protectedTags, effectiveCtxReduceEnabled, deps.dreamerEnabled, deps.experimentalTemporalAwareness, deps.experimentalCavemanTextCompression, subagentReduceMode);
|
|
203399
|
+
const guidance = buildMagicContextSection(null, deps.protectedTags, effectiveCtxReduceEnabled, deps.dreamerEnabled, deps.experimentalTemporalAwareness, deps.experimentalCavemanTextCompression, subagentReduceMode, deps.language, deps.memoryEnabled !== false);
|
|
202997
203400
|
output.system.push(guidance);
|
|
202998
203401
|
sessionLog(sessionId, `injected generic guidance into system prompt (ctxReduce=${effectiveCtxReduceEnabled}, subagent=${isSubagentSession}, subagentReduceMode=${subagentReduceMode})`);
|
|
202999
203402
|
}
|
|
@@ -203281,6 +203684,7 @@ function createMagicContextHook(deps) {
|
|
|
203281
203684
|
memoryEnabled: deps.config.memory?.enabled ?? true,
|
|
203282
203685
|
autoPromote: deps.config.memory?.auto_promote ?? true,
|
|
203283
203686
|
fallbackModels: historianFallbackModels,
|
|
203687
|
+
language: deps.config.language,
|
|
203284
203688
|
fallbackModelId: (() => {
|
|
203285
203689
|
const model = resolveLiveModel(sessionId);
|
|
203286
203690
|
return model ? `${model.providerID}/${model.modelID}` : undefined;
|
|
@@ -203319,7 +203723,7 @@ function createMagicContextHook(deps) {
|
|
|
203319
203723
|
signal,
|
|
203320
203724
|
onProgress: ({ embedded, total }) => {
|
|
203321
203725
|
const cur = recompProgressBySession.get(sessionId);
|
|
203322
|
-
if (
|
|
203726
|
+
if (cur?.phase !== "recomp")
|
|
203323
203727
|
return;
|
|
203324
203728
|
recompProgressBySession.set(sessionId, {
|
|
203325
203729
|
...cur,
|
|
@@ -203430,6 +203834,7 @@ function createMagicContextHook(deps) {
|
|
|
203430
203834
|
channel1StateBySession,
|
|
203431
203835
|
protectedTags: deps.config.protected_tags,
|
|
203432
203836
|
ctxReduceEnabled,
|
|
203837
|
+
smartDrops: deps.config.smart_drops === true,
|
|
203433
203838
|
clearReasoningAge: deps.config.clear_reasoning_age ?? 50,
|
|
203434
203839
|
commitClusterTrigger: deps.config.commit_cluster_trigger,
|
|
203435
203840
|
historyRefreshSessions,
|
|
@@ -203522,7 +203927,7 @@ function createMagicContextHook(deps) {
|
|
|
203522
203927
|
return;
|
|
203523
203928
|
}
|
|
203524
203929
|
lastScheduleCheckMs = now;
|
|
203525
|
-
const runtimeConfigs = buildDreamTaskRuntimeConfigs(dreaming);
|
|
203930
|
+
const runtimeConfigs = buildDreamTaskRuntimeConfigs(dreaming, deps.config.language);
|
|
203526
203931
|
const executor = createDreamTaskExecutor({
|
|
203527
203932
|
client: deps.client,
|
|
203528
203933
|
sessionDirectory: deps.directory,
|
|
@@ -203531,7 +203936,8 @@ function createMagicContextHook(deps) {
|
|
|
203531
203936
|
contextDb: providerDb,
|
|
203532
203937
|
openOpenCodeDb
|
|
203533
203938
|
}),
|
|
203534
|
-
userMemoryCollectionEnabled: userMemoryCollectionEnabled(dreaming)
|
|
203939
|
+
userMemoryCollectionEnabled: userMemoryCollectionEnabled(dreaming),
|
|
203940
|
+
language: deps.config.language
|
|
203535
203941
|
});
|
|
203536
203942
|
runDueTasksForProject({
|
|
203537
203943
|
db,
|
|
@@ -203580,7 +203986,8 @@ function createMagicContextHook(deps) {
|
|
|
203580
203986
|
config: sidekickConfig,
|
|
203581
203987
|
projectPath,
|
|
203582
203988
|
sessionDirectory: deps.directory,
|
|
203583
|
-
client: deps.client
|
|
203989
|
+
client: deps.client,
|
|
203990
|
+
language: deps.config.language
|
|
203584
203991
|
} : undefined,
|
|
203585
203992
|
dreamer: dreamerConfig ? {
|
|
203586
203993
|
config: dreamerConfig,
|
|
@@ -203588,7 +203995,7 @@ function createMagicContextHook(deps) {
|
|
|
203588
203995
|
runManual: (task) => runManualDream({
|
|
203589
203996
|
db,
|
|
203590
203997
|
projectIdentity: projectPath,
|
|
203591
|
-
tasks: buildDreamTaskRuntimeConfigs(dreamerConfig),
|
|
203998
|
+
tasks: buildDreamTaskRuntimeConfigs(dreamerConfig, deps.config.language),
|
|
203592
203999
|
executor: createDreamTaskExecutor({
|
|
203593
204000
|
client: deps.client,
|
|
203594
204001
|
sessionDirectory: deps.directory,
|
|
@@ -203597,7 +204004,8 @@ function createMagicContextHook(deps) {
|
|
|
203597
204004
|
contextDb: providerDb,
|
|
203598
204005
|
openOpenCodeDb
|
|
203599
204006
|
}),
|
|
203600
|
-
userMemoryCollectionEnabled: userMemoryCollectionEnabled(dreamerConfig)
|
|
204007
|
+
userMemoryCollectionEnabled: userMemoryCollectionEnabled(dreamerConfig),
|
|
204008
|
+
language: deps.config.language
|
|
203601
204009
|
}),
|
|
203602
204010
|
task
|
|
203603
204011
|
})
|
|
@@ -203608,6 +204016,8 @@ function createMagicContextHook(deps) {
|
|
|
203608
204016
|
protectedTags: deps.config.protected_tags,
|
|
203609
204017
|
ctxReduceEnabled,
|
|
203610
204018
|
dreamerEnabled: dreamerRunnable,
|
|
204019
|
+
memoryEnabled: deps.config.memory?.enabled !== false,
|
|
204020
|
+
language: deps.config.language,
|
|
203611
204021
|
injectDocs: deps.config.dreamer?.inject_docs !== false,
|
|
203612
204022
|
directory: deps.directory,
|
|
203613
204023
|
historyRefreshSessions,
|
|
@@ -205993,6 +206403,7 @@ function createToolRegistry(args) {
|
|
|
205993
206403
|
ensureProjectRegisteredFromOpenCodeDirectory(ctx.directory, db);
|
|
205994
206404
|
const resolveProjectPath = (directory) => resolveProjectIdentity(directory);
|
|
205995
206405
|
const ctxReduceEnabled = pluginConfig.ctx_reduce_enabled !== false;
|
|
206406
|
+
const memoryEnabled = pluginConfig.memory?.enabled !== false;
|
|
205996
206407
|
const allTools = {
|
|
205997
206408
|
...ctxReduceEnabled ? createCtxReduceTools({
|
|
205998
206409
|
db,
|
|
@@ -206009,12 +206420,12 @@ function createToolRegistry(args) {
|
|
|
206009
206420
|
resolveProjectPath,
|
|
206010
206421
|
ensureProjectRegistered: ensureProjectRegisteredFromOpenCodeDirectory
|
|
206011
206422
|
}),
|
|
206012
|
-
...createCtxMemoryTools({
|
|
206423
|
+
...memoryEnabled ? createCtxMemoryTools({
|
|
206013
206424
|
db,
|
|
206014
206425
|
resolveProjectPath,
|
|
206015
206426
|
ensureProjectRegistered: ensureProjectRegisteredFromOpenCodeDirectory,
|
|
206016
206427
|
allowedActions: [...CTX_MEMORY_ACTIONS]
|
|
206017
|
-
})
|
|
206428
|
+
}) : {}
|
|
206018
206429
|
};
|
|
206019
206430
|
for (const toolDefinition of Object.values(allTools)) {
|
|
206020
206431
|
normalizeToolArgSchemas(toolDefinition);
|
|
@@ -206339,6 +206750,7 @@ var server2 = async (ctx) => {
|
|
|
206339
206750
|
projectIdentity: resolveProjectIdentity(ctx.directory),
|
|
206340
206751
|
client: ctx.client,
|
|
206341
206752
|
dreamerConfig: dreamerRunnable ? pluginConfig.dreamer : undefined,
|
|
206753
|
+
language: pluginConfig.language,
|
|
206342
206754
|
embeddingConfig: pluginConfig.embedding,
|
|
206343
206755
|
memoryEnabled: pluginConfig.memory?.enabled === true,
|
|
206344
206756
|
gitCommitIndexing: pluginConfig.memory.git_commit_indexing?.enabled ? {
|
|
@@ -206510,9 +206922,9 @@ var server2 = async (ctx) => {
|
|
|
206510
206922
|
const registrations = buildHiddenAgentRegistrations({
|
|
206511
206923
|
dreamerPrompt: DREAMER_SYSTEM_PROMPT,
|
|
206512
206924
|
smartNoteCompilerPrompt: SMART_NOTE_COMPILER_SYSTEM_PROMPT,
|
|
206513
|
-
historianPrompt: COMPARTMENT_AGENT_SYSTEM_PROMPT,
|
|
206514
|
-
historianRecompPrompt: COMPARTMENT_STRUCTURAL_SYSTEM_PROMPT,
|
|
206515
|
-
historianEditorPrompt: HISTORIAN_EDITOR_SYSTEM_PROMPT,
|
|
206925
|
+
historianPrompt: withContentLanguageDirective(COMPARTMENT_AGENT_SYSTEM_PROMPT, pluginConfig.language, { preserveUserQuotes: true }),
|
|
206926
|
+
historianRecompPrompt: withContentLanguageDirective(COMPARTMENT_STRUCTURAL_SYSTEM_PROMPT, pluginConfig.language, { preserveUserQuotes: true }),
|
|
206927
|
+
historianEditorPrompt: withContentLanguageDirective(HISTORIAN_EDITOR_SYSTEM_PROMPT, pluginConfig.language, { preserveUserQuotes: true }),
|
|
206516
206928
|
sidekickPrompt: SIDEKICK_SYSTEM_PROMPT,
|
|
206517
206929
|
dreamerOverrides: dreamerAgentOverrides,
|
|
206518
206930
|
historianOverrides: historianAgentOverrides,
|