@cortexkit/opencode-magic-context 0.22.3 → 0.22.5
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 +1 -1
- package/dist/agents/magic-context-prompt.d.ts.map +1 -1
- package/dist/config/index.d.ts.map +1 -1
- package/dist/config/project-security.d.ts +25 -0
- package/dist/config/project-security.d.ts.map +1 -0
- package/dist/config/prune-config-leaf.d.ts +27 -0
- package/dist/config/prune-config-leaf.d.ts.map +1 -0
- package/dist/config/schema/magic-context.d.ts +7 -0
- package/dist/config/schema/magic-context.d.ts.map +1 -1
- package/dist/config/variable.d.ts.map +1 -1
- package/dist/features/magic-context/compartment-storage.d.ts +9 -6
- package/dist/features/magic-context/compartment-storage.d.ts.map +1 -1
- package/dist/features/magic-context/dreamer/runner.d.ts.map +1 -1
- package/dist/features/magic-context/dreamer/scheduler.d.ts.map +1 -1
- package/dist/features/magic-context/key-files/aft-availability.d.ts.map +1 -1
- package/dist/features/magic-context/key-files/identify-key-files.d.ts.map +1 -1
- package/dist/features/magic-context/key-files/read-stats.d.ts +0 -2
- package/dist/features/magic-context/key-files/read-stats.d.ts.map +1 -1
- package/dist/features/magic-context/memory/embedding-openai.d.ts.map +1 -1
- package/dist/features/magic-context/memory/embedding-ssrf.d.ts +29 -0
- package/dist/features/magic-context/memory/embedding-ssrf.d.ts.map +1 -0
- package/dist/features/magic-context/memory/memory-migration.d.ts.map +1 -1
- package/dist/features/magic-context/memory/project-identity.d.ts +10 -0
- package/dist/features/magic-context/memory/project-identity.d.ts.map +1 -1
- package/dist/features/magic-context/migrations.d.ts.map +1 -1
- package/dist/features/magic-context/project-docs-hash.d.ts.map +1 -1
- package/dist/features/magic-context/project-embedding-registry.d.ts.map +1 -1
- package/dist/features/magic-context/range-parser.d.ts +6 -0
- package/dist/features/magic-context/range-parser.d.ts.map +1 -1
- package/dist/features/magic-context/sidekick/agent.d.ts.map +1 -1
- package/dist/features/magic-context/storage-db.d.ts +1 -1
- package/dist/features/magic-context/storage-db.d.ts.map +1 -1
- package/dist/features/magic-context/storage-meta-persisted.d.ts +41 -1
- package/dist/features/magic-context/storage-meta-persisted.d.ts.map +1 -1
- package/dist/features/magic-context/storage-meta-session.d.ts.map +1 -1
- package/dist/features/magic-context/storage-meta-shared.d.ts +7 -1
- package/dist/features/magic-context/storage-meta-shared.d.ts.map +1 -1
- package/dist/features/magic-context/storage-meta.d.ts +1 -1
- package/dist/features/magic-context/storage-meta.d.ts.map +1 -1
- package/dist/features/magic-context/storage.d.ts +2 -2
- package/dist/features/magic-context/storage.d.ts.map +1 -1
- package/dist/features/magic-context/tool-definition-tokens.d.ts +21 -0
- package/dist/features/magic-context/tool-definition-tokens.d.ts.map +1 -1
- package/dist/features/magic-context/types.d.ts +4 -0
- package/dist/features/magic-context/types.d.ts.map +1 -1
- package/dist/features/magic-context/user-memory/review-user-memories.d.ts.map +1 -1
- package/dist/hooks/auto-update-checker/cache.d.ts.map +1 -1
- package/dist/hooks/auto-update-checker/checker.d.ts.map +1 -1
- package/dist/hooks/auto-update-checker/semver.d.ts +17 -0
- package/dist/hooks/auto-update-checker/semver.d.ts.map +1 -0
- package/dist/hooks/magic-context/command-handler.d.ts +1 -6
- package/dist/hooks/magic-context/command-handler.d.ts.map +1 -1
- package/dist/hooks/magic-context/compaction-marker-manager.d.ts +1 -1
- package/dist/hooks/magic-context/compaction-marker-manager.d.ts.map +1 -1
- 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-validation.d.ts +25 -0
- package/dist/hooks/magic-context/compartment-runner-validation.d.ts.map +1 -1
- package/dist/hooks/magic-context/decay-render.d.ts.map +1 -1
- package/dist/hooks/magic-context/drop-stale-reduce-calls.d.ts +36 -1
- package/dist/hooks/magic-context/drop-stale-reduce-calls.d.ts.map +1 -1
- package/dist/hooks/magic-context/hook-handlers.d.ts.map +1 -1
- package/dist/hooks/magic-context/hook.d.ts.map +1 -1
- package/dist/hooks/magic-context/inject-compartments.d.ts +41 -0
- package/dist/hooks/magic-context/inject-compartments.d.ts.map +1 -1
- package/dist/hooks/magic-context/reference-retrieval.d.ts.map +1 -1
- package/dist/hooks/magic-context/transform-postprocess-phase.d.ts +2 -1
- package/dist/hooks/magic-context/transform-postprocess-phase.d.ts.map +1 -1
- package/dist/hooks/magic-context/transform.d.ts +8 -0
- package/dist/hooks/magic-context/transform.d.ts.map +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +818 -259
- package/dist/plugin/embedding-bootstrap-helpers.d.ts.map +1 -1
- package/dist/plugin/hooks/create-session-hooks.d.ts.map +1 -1
- package/dist/shared/keep-subagents.d.ts +7 -0
- package/dist/shared/keep-subagents.d.ts.map +1 -0
- package/dist/shared/rpc-server.d.ts.map +1 -1
- package/dist/tools/ctx-memory/tools.d.ts.map +1 -1
- package/dist/tools/ctx-search/tools.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/shared/keep-subagents.test.ts +39 -0
- package/src/shared/keep-subagents.ts +33 -0
- package/src/shared/rpc-server.ts +18 -2
- package/src/tui/index.tsx +9 -5
package/dist/index.js
CHANGED
|
@@ -287,7 +287,7 @@ __export(exports_util, {
|
|
|
287
287
|
jsonStringifyReplacer: () => jsonStringifyReplacer,
|
|
288
288
|
joinValues: () => joinValues,
|
|
289
289
|
issue: () => issue,
|
|
290
|
-
isPlainObject: () =>
|
|
290
|
+
isPlainObject: () => isPlainObject3,
|
|
291
291
|
isObject: () => isObject,
|
|
292
292
|
hexToUint8Array: () => hexToUint8Array,
|
|
293
293
|
getSizableOrigin: () => getSizableOrigin,
|
|
@@ -452,7 +452,7 @@ function slugify(input) {
|
|
|
452
452
|
function isObject(data) {
|
|
453
453
|
return typeof data === "object" && data !== null && !Array.isArray(data);
|
|
454
454
|
}
|
|
455
|
-
function
|
|
455
|
+
function isPlainObject3(o) {
|
|
456
456
|
if (isObject(o) === false)
|
|
457
457
|
return false;
|
|
458
458
|
const ctor = o.constructor;
|
|
@@ -469,7 +469,7 @@ function isPlainObject(o) {
|
|
|
469
469
|
return true;
|
|
470
470
|
}
|
|
471
471
|
function shallowClone(o) {
|
|
472
|
-
if (
|
|
472
|
+
if (isPlainObject3(o))
|
|
473
473
|
return { ...o };
|
|
474
474
|
if (Array.isArray(o))
|
|
475
475
|
return [...o];
|
|
@@ -609,7 +609,7 @@ function omit(schema, mask) {
|
|
|
609
609
|
return clone(schema, def);
|
|
610
610
|
}
|
|
611
611
|
function extend(schema, shape) {
|
|
612
|
-
if (!
|
|
612
|
+
if (!isPlainObject3(shape)) {
|
|
613
613
|
throw new Error("Invalid input to extend: expected a plain object");
|
|
614
614
|
}
|
|
615
615
|
const checks = schema._zod.def.checks;
|
|
@@ -632,7 +632,7 @@ function extend(schema, shape) {
|
|
|
632
632
|
return clone(schema, def);
|
|
633
633
|
}
|
|
634
634
|
function safeExtend(schema, shape) {
|
|
635
|
-
if (!
|
|
635
|
+
if (!isPlainObject3(shape)) {
|
|
636
636
|
throw new Error("Invalid input to safeExtend: expected a plain object");
|
|
637
637
|
}
|
|
638
638
|
const def = mergeDefs(schema._zod.def, {
|
|
@@ -2115,7 +2115,7 @@ function mergeValues(a, b) {
|
|
|
2115
2115
|
if (a instanceof Date && b instanceof Date && +a === +b) {
|
|
2116
2116
|
return { valid: true, data: a };
|
|
2117
2117
|
}
|
|
2118
|
-
if (
|
|
2118
|
+
if (isPlainObject3(a) && isPlainObject3(b)) {
|
|
2119
2119
|
const bKeys = Object.keys(b);
|
|
2120
2120
|
const sharedKeys = Object.keys(a).filter((key) => bKeys.indexOf(key) !== -1);
|
|
2121
2121
|
const newObj = { ...a, ...b };
|
|
@@ -3372,7 +3372,7 @@ var init_schemas = __esm(() => {
|
|
|
3372
3372
|
$ZodType.init(inst, def);
|
|
3373
3373
|
inst._zod.parse = (payload, ctx) => {
|
|
3374
3374
|
const input = payload.value;
|
|
3375
|
-
if (!
|
|
3375
|
+
if (!isPlainObject3(input)) {
|
|
3376
3376
|
payload.issues.push({
|
|
3377
3377
|
expected: "record",
|
|
3378
3378
|
code: "invalid_type",
|
|
@@ -14968,6 +14968,7 @@ var init_magic_context = __esm(() => {
|
|
|
14968
14968
|
model: DEFAULT_LOCAL_EMBEDDING_MODEL
|
|
14969
14969
|
}).describe("Embedding provider configuration"),
|
|
14970
14970
|
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).'),
|
|
14971
|
+
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."),
|
|
14971
14972
|
caveman_text_compression: exports_external.object({
|
|
14972
14973
|
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%)."),
|
|
14973
14974
|
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.")
|
|
@@ -15161,6 +15162,9 @@ function normalizeStoredProjectPath(rawOrStored) {
|
|
|
15161
15162
|
return directoryFallback(rawOrStored);
|
|
15162
15163
|
}
|
|
15163
15164
|
}
|
|
15165
|
+
function storedPathBelongsToIdentity(storedProjectPath, projectIdentity) {
|
|
15166
|
+
return storedProjectPath === projectIdentity || normalizeStoredProjectPath(storedProjectPath) === projectIdentity;
|
|
15167
|
+
}
|
|
15164
15168
|
var GIT_TIMEOUT_MS = 5000, identityCache, directoryFallbackCache, ProjectIdentityError;
|
|
15165
15169
|
var init_project_identity = __esm(() => {
|
|
15166
15170
|
identityCache = new Map;
|
|
@@ -15746,6 +15750,15 @@ function extractLatestAssistantText(messages) {
|
|
|
15746
15750
|
}
|
|
15747
15751
|
var init_assistant_message_extractor = () => {};
|
|
15748
15752
|
|
|
15753
|
+
// src/shared/keep-subagents.ts
|
|
15754
|
+
function setKeepSubagents(value) {
|
|
15755
|
+
keepSubagents = value === true;
|
|
15756
|
+
}
|
|
15757
|
+
function shouldKeepSubagents() {
|
|
15758
|
+
return keepSubagents;
|
|
15759
|
+
}
|
|
15760
|
+
var keepSubagents = false;
|
|
15761
|
+
|
|
15749
15762
|
// src/features/magic-context/compartment-lease.ts
|
|
15750
15763
|
function acquireCompartmentLease(db, sessionId, holderId) {
|
|
15751
15764
|
const acquiredAt = Date.now();
|
|
@@ -15832,7 +15845,7 @@ function isSessionMetaRow(row) {
|
|
|
15832
15845
|
if (row === null || typeof row !== "object")
|
|
15833
15846
|
return false;
|
|
15834
15847
|
const r = row;
|
|
15835
|
-
return typeof r.session_id === "string" && typeof r.last_response_time === "number" && isStringOrNull(r.cache_ttl) && typeof r.counter === "number" && typeof r.last_nudge_tokens === "number" && isStringOrNull(r.last_nudge_band) && isStringOrNull(r.last_transform_error) && typeof r.is_subagent === "number" && typeof r.last_context_percentage === "number" && typeof r.last_input_tokens === "number" && isNumberOrNull(r.observed_safe_input_tokens) && isNumberOrNull(r.cache_alert_sent) && isNumberOrNull(r.times_execute_threshold_reached) && isNumberOrNull(r.compartment_in_progress) && (r.system_prompt_hash === null || typeof r.system_prompt_hash === "string" || typeof r.system_prompt_hash === "number") && isNumberOrNull(r.system_prompt_tokens) && isNumberOrNull(r.conversation_tokens) && isNumberOrNull(r.tool_call_tokens) && isNumberOrNull(r.cleared_reasoning_through_tag) && isStringOrNull(r.last_todo_state) && isBlobOrNull(r.cached_m0_bytes) && isBlobOrNull(r.cached_m1_bytes) && isNumberOrNull(r.cached_m0_project_memory_epoch) && isNumberOrNull(r.cached_m0_project_user_profile_version) && isNumberOrNull(r.cached_m0_max_compartment_seq) && isNumberOrNull(r.cached_m0_max_memory_id) && isNumberOrNull(r.cached_m0_max_mutation_id) && isNumberOrNull(r.cached_m0_max_memory_mutation_id) && isStringOrNull(r.cached_m0_project_docs_hash) && isNumberOrNull(r.cached_m0_materialized_at) && isNumberOrNull(r.cached_m0_session_facts_version) && isStringOrNull(r.cached_m0_upgrade_state) && isStringOrNull(r.last_observed_model_key) && isNumberOrNull(r.upgrade_reminded_at) && isNumberOrNull(r.pi_stable_id_scheme);
|
|
15848
|
+
return typeof r.session_id === "string" && typeof r.last_response_time === "number" && isStringOrNull(r.cache_ttl) && typeof r.counter === "number" && typeof r.last_nudge_tokens === "number" && isStringOrNull(r.last_nudge_band) && isStringOrNull(r.last_transform_error) && typeof r.is_subagent === "number" && typeof r.last_context_percentage === "number" && typeof r.last_input_tokens === "number" && isNumberOrNull(r.observed_safe_input_tokens) && isNumberOrNull(r.cache_alert_sent) && isNumberOrNull(r.times_execute_threshold_reached) && isNumberOrNull(r.compartment_in_progress) && (r.system_prompt_hash === null || typeof r.system_prompt_hash === "string" || typeof r.system_prompt_hash === "number") && isNumberOrNull(r.system_prompt_tokens) && isNumberOrNull(r.conversation_tokens) && isNumberOrNull(r.tool_call_tokens) && isNumberOrNull(r.cleared_reasoning_through_tag) && isStringOrNull(r.last_todo_state) && isBlobOrNull(r.cached_m0_bytes) && isBlobOrNull(r.cached_m1_bytes) && isNumberOrNull(r.cached_m0_project_memory_epoch) && isNumberOrNull(r.cached_m0_project_user_profile_version) && isNumberOrNull(r.cached_m0_max_compartment_seq) && isNumberOrNull(r.cached_m0_max_memory_id) && isNumberOrNull(r.cached_m0_max_mutation_id) && isNumberOrNull(r.cached_m0_max_memory_mutation_id) && isStringOrNull(r.cached_m0_project_docs_hash) && isNumberOrNull(r.cached_m0_materialized_at) && isNumberOrNull(r.cached_m0_session_facts_version) && isStringOrNull(r.cached_m0_upgrade_state) && isStringOrNull(r.cached_m0_system_hash) && isStringOrNull(r.cached_m0_tool_set_hash) && isStringOrNull(r.cached_m0_model_key) && isStringOrNull(r.last_observed_model_key) && isNumberOrNull(r.upgrade_reminded_at) && isNumberOrNull(r.pi_stable_id_scheme);
|
|
15836
15849
|
}
|
|
15837
15850
|
function getDefaultSessionMeta(sessionId) {
|
|
15838
15851
|
return {
|
|
@@ -15868,6 +15881,9 @@ function getDefaultSessionMeta(sessionId) {
|
|
|
15868
15881
|
cachedM0MaterializedAt: null,
|
|
15869
15882
|
cachedM0SessionFactsVersion: null,
|
|
15870
15883
|
cachedM0UpgradeState: null,
|
|
15884
|
+
cachedM0SystemHash: null,
|
|
15885
|
+
cachedM0ToolSetHash: null,
|
|
15886
|
+
cachedM0ModelKey: null,
|
|
15871
15887
|
lastObservedModelKey: null,
|
|
15872
15888
|
upgradeRemindedAt: null,
|
|
15873
15889
|
piStableIdScheme: null
|
|
@@ -15919,6 +15935,9 @@ function toSessionMeta(row) {
|
|
|
15919
15935
|
cachedM0MaterializedAt: numOrNull(row.cached_m0_materialized_at),
|
|
15920
15936
|
cachedM0SessionFactsVersion: numOrNull(row.cached_m0_session_facts_version),
|
|
15921
15937
|
cachedM0UpgradeState: stringOrNull(row.cached_m0_upgrade_state),
|
|
15938
|
+
cachedM0SystemHash: stringOrNull(row.cached_m0_system_hash),
|
|
15939
|
+
cachedM0ToolSetHash: stringOrNull(row.cached_m0_tool_set_hash),
|
|
15940
|
+
cachedM0ModelKey: stringOrNull(row.cached_m0_model_key),
|
|
15922
15941
|
lastObservedModelKey: stringOrNull(row.last_observed_model_key),
|
|
15923
15942
|
upgradeRemindedAt: numOrNull(row.upgrade_reminded_at),
|
|
15924
15943
|
piStableIdScheme: numOrNull(row.pi_stable_id_scheme)
|
|
@@ -15938,8 +15957,11 @@ function persistCachedM0(db, sessionId, payload) {
|
|
|
15938
15957
|
cached_m0_project_docs_hash = ?,
|
|
15939
15958
|
cached_m0_materialized_at = ?,
|
|
15940
15959
|
cached_m0_session_facts_version = ?,
|
|
15941
|
-
cached_m0_upgrade_state =
|
|
15942
|
-
|
|
15960
|
+
cached_m0_upgrade_state = ?,
|
|
15961
|
+
cached_m0_system_hash = ?,
|
|
15962
|
+
cached_m0_tool_set_hash = ?,
|
|
15963
|
+
cached_m0_model_key = ?
|
|
15964
|
+
WHERE session_id = ?`).run(Buffer2.from(payload.m0Bytes), payload.projectMemoryEpoch, payload.projectUserProfileVersion, payload.maxCompartmentSeq, payload.maxMemoryId, payload.maxMutationId, payload.maxMemoryMutationId ?? null, payload.m1Bytes ? Buffer2.from(payload.m1Bytes) : null, payload.projectDocsHash, payload.materializedAt, payload.sessionFactsVersion, payload.upgradeState, payload.systemHash ?? "", payload.toolSetHash ?? "", payload.modelKey ?? "", sessionId);
|
|
15943
15965
|
}
|
|
15944
15966
|
function clearCachedM0M1(db, sessionId) {
|
|
15945
15967
|
ensureSessionMetaRow(db, sessionId);
|
|
@@ -15957,6 +15979,9 @@ function clearCachedM0M1(db, sessionId) {
|
|
|
15957
15979
|
["cached_m0_materialized_at", null],
|
|
15958
15980
|
["cached_m0_session_facts_version", null],
|
|
15959
15981
|
["cached_m0_upgrade_state", null],
|
|
15982
|
+
["cached_m0_system_hash", null],
|
|
15983
|
+
["cached_m0_tool_set_hash", null],
|
|
15984
|
+
["cached_m0_model_key", null],
|
|
15960
15985
|
["cached_m0_last_baseline_end_message_id", null],
|
|
15961
15986
|
["memory_block_cache", ""],
|
|
15962
15987
|
["memory_block_count", 0],
|
|
@@ -16009,6 +16034,9 @@ var init_storage_meta_shared = __esm(() => {
|
|
|
16009
16034
|
"cached_m0_materialized_at",
|
|
16010
16035
|
"cached_m0_session_facts_version",
|
|
16011
16036
|
"cached_m0_upgrade_state",
|
|
16037
|
+
"cached_m0_system_hash",
|
|
16038
|
+
"cached_m0_tool_set_hash",
|
|
16039
|
+
"cached_m0_model_key",
|
|
16012
16040
|
"last_observed_model_key",
|
|
16013
16041
|
"upgrade_reminded_at",
|
|
16014
16042
|
"pi_stable_id_scheme"
|
|
@@ -16045,6 +16073,9 @@ var init_storage_meta_shared = __esm(() => {
|
|
|
16045
16073
|
cachedM0MaterializedAt: "cached_m0_materialized_at",
|
|
16046
16074
|
cachedM0SessionFactsVersion: "cached_m0_session_facts_version",
|
|
16047
16075
|
cachedM0UpgradeState: "cached_m0_upgrade_state",
|
|
16076
|
+
cachedM0SystemHash: "cached_m0_system_hash",
|
|
16077
|
+
cachedM0ToolSetHash: "cached_m0_tool_set_hash",
|
|
16078
|
+
cachedM0ModelKey: "cached_m0_model_key",
|
|
16048
16079
|
lastObservedModelKey: "last_observed_model_key",
|
|
16049
16080
|
upgradeRemindedAt: "upgrade_reminded_at",
|
|
16050
16081
|
piStableIdScheme: "pi_stable_id_scheme"
|
|
@@ -16090,12 +16121,6 @@ function isCompartmentRow(row) {
|
|
|
16090
16121
|
const candidate = row;
|
|
16091
16122
|
return typeof candidate.id === "number" && typeof candidate.session_id === "string" && typeof candidate.sequence === "number" && typeof candidate.start_message === "number" && typeof candidate.end_message === "number" && typeof candidate.start_message_id === "string" && typeof candidate.end_message_id === "string" && typeof candidate.title === "string" && typeof candidate.content === "string" && isStringOrNullish(candidate.p1) && isStringOrNullish(candidate.p2) && isStringOrNullish(candidate.p3) && isStringOrNullish(candidate.p4) && isNumberOrNullish(candidate.importance) && isStringOrNullish(candidate.episode_type) && isNumberOrNullish(candidate.legacy) && typeof candidate.created_at === "number";
|
|
16092
16123
|
}
|
|
16093
|
-
function isSessionFactRow(row) {
|
|
16094
|
-
if (row === null || typeof row !== "object")
|
|
16095
|
-
return false;
|
|
16096
|
-
const candidate = row;
|
|
16097
|
-
return typeof candidate.id === "number" && typeof candidate.session_id === "string" && typeof candidate.category === "string" && typeof candidate.content === "string" && typeof candidate.created_at === "number" && typeof candidate.updated_at === "number";
|
|
16098
|
-
}
|
|
16099
16124
|
function insertCompartmentRows(db, sessionId, compartments, now) {
|
|
16100
16125
|
const stmt = getInsertCompartmentStatement(db);
|
|
16101
16126
|
for (const compartment of compartments) {
|
|
@@ -16124,16 +16149,6 @@ function toCompartment(row) {
|
|
|
16124
16149
|
createdAt: row.created_at
|
|
16125
16150
|
};
|
|
16126
16151
|
}
|
|
16127
|
-
function toSessionFact(row) {
|
|
16128
|
-
return {
|
|
16129
|
-
id: row.id,
|
|
16130
|
-
sessionId: row.session_id,
|
|
16131
|
-
category: row.category,
|
|
16132
|
-
content: row.content,
|
|
16133
|
-
createdAt: row.created_at,
|
|
16134
|
-
updatedAt: row.updated_at
|
|
16135
|
-
};
|
|
16136
|
-
}
|
|
16137
16152
|
function getCompartments(db, sessionId) {
|
|
16138
16153
|
const rows = db.prepare("SELECT * FROM compartments WHERE session_id = ? ORDER BY sequence ASC").all(sessionId).filter(isCompartmentRow);
|
|
16139
16154
|
return rows.map(toCompartment);
|
|
@@ -16142,6 +16157,11 @@ function getLastCompartmentEndMessage(db, sessionId) {
|
|
|
16142
16157
|
const row = db.prepare("SELECT MAX(end_message) as max_end FROM compartments WHERE session_id = ?").get(sessionId);
|
|
16143
16158
|
return row?.max_end ?? -1;
|
|
16144
16159
|
}
|
|
16160
|
+
function getLastCompartmentEndMessageId(db, sessionId) {
|
|
16161
|
+
const row = db.prepare("SELECT end_message_id FROM compartments WHERE session_id = ? ORDER BY sequence DESC LIMIT 1").get(sessionId);
|
|
16162
|
+
const id = row?.end_message_id;
|
|
16163
|
+
return id && id.length > 0 ? id : null;
|
|
16164
|
+
}
|
|
16145
16165
|
function getCompartmentsByEndMessageId(db, sessionId, endMessageId) {
|
|
16146
16166
|
const rows = db.prepare("SELECT * FROM compartments WHERE session_id = ? AND end_message_id = ? ORDER BY sequence ASC").all(sessionId, endMessageId).filter(isCompartmentRow);
|
|
16147
16167
|
return rows.map(toCompartment);
|
|
@@ -16154,10 +16174,6 @@ function appendCompartments(db, sessionId, compartments) {
|
|
|
16154
16174
|
insertCompartmentRows(db, sessionId, compartments, now);
|
|
16155
16175
|
})();
|
|
16156
16176
|
}
|
|
16157
|
-
function getSessionFacts(db, sessionId) {
|
|
16158
|
-
const rows = db.prepare("SELECT * FROM session_facts WHERE session_id = ? ORDER BY category ASC, id ASC").all(sessionId).filter(isSessionFactRow);
|
|
16159
|
-
return rows.map(toSessionFact);
|
|
16160
|
-
}
|
|
16161
16177
|
function buildCompartmentBlock(compartments, facts, memoryBlock, dateRanges) {
|
|
16162
16178
|
const lines = [];
|
|
16163
16179
|
if (memoryBlock) {
|
|
@@ -150113,6 +150129,18 @@ function keyFor(providerID, modelID, agentName) {
|
|
|
150113
150129
|
function fingerprintFor(description, parameters) {
|
|
150114
150130
|
return createHash3("sha256").update(description).update("\x00").update(stableStringify(parameters)).digest("hex");
|
|
150115
150131
|
}
|
|
150132
|
+
function getCurrentToolSetHash(providerID, modelID, agentName) {
|
|
150133
|
+
const key = keyFor(providerID, modelID, agentName);
|
|
150134
|
+
const inner = fingerprints.get(key);
|
|
150135
|
+
if (!inner || inner.size === 0)
|
|
150136
|
+
return "";
|
|
150137
|
+
const parts = [];
|
|
150138
|
+
for (const [toolID, fp] of inner)
|
|
150139
|
+
parts.push(`${toolID}\x00${fp}`);
|
|
150140
|
+
parts.sort();
|
|
150141
|
+
return createHash3("sha256").update(parts.join(`
|
|
150142
|
+
`)).digest("hex");
|
|
150143
|
+
}
|
|
150116
150144
|
function setDatabase(db) {
|
|
150117
150145
|
persistenceDb = db;
|
|
150118
150146
|
cachedInsertStmt = null;
|
|
@@ -150906,6 +150934,9 @@ CREATE INDEX IF NOT EXISTS idx_dream_queue_pending ON dream_queue(started_at, en
|
|
|
150906
150934
|
cached_m0_materialized_at INTEGER,
|
|
150907
150935
|
cached_m0_session_facts_version INTEGER,
|
|
150908
150936
|
cached_m0_upgrade_state TEXT,
|
|
150937
|
+
cached_m0_system_hash TEXT,
|
|
150938
|
+
cached_m0_tool_set_hash TEXT,
|
|
150939
|
+
cached_m0_model_key TEXT,
|
|
150909
150940
|
cached_m0_last_baseline_end_message_id TEXT,
|
|
150910
150941
|
upgrade_reminded_at INTEGER,
|
|
150911
150942
|
pi_stable_id_scheme INTEGER
|
|
@@ -151036,6 +151067,7 @@ CREATE INDEX IF NOT EXISTS idx_dream_queue_pending ON dream_queue(started_at, en
|
|
|
151036
151067
|
ensureColumn(db, "session_meta", "system_prompt_hash", "TEXT DEFAULT ''");
|
|
151037
151068
|
ensureColumn(db, "session_meta", "cleared_reasoning_through_tag", "INTEGER DEFAULT 0");
|
|
151038
151069
|
ensureColumn(db, "session_meta", "stripped_placeholder_ids", "TEXT DEFAULT ''");
|
|
151070
|
+
ensureColumn(db, "session_meta", "stale_reduce_stripped_ids", "TEXT DEFAULT ''");
|
|
151039
151071
|
ensureColumn(db, "compartments", "start_message_id", "TEXT DEFAULT ''");
|
|
151040
151072
|
ensureColumn(db, "compartments", "end_message_id", "TEXT DEFAULT ''");
|
|
151041
151073
|
ensureColumn(db, "memory_embeddings", "model_id", "TEXT");
|
|
@@ -151097,6 +151129,9 @@ CREATE INDEX IF NOT EXISTS idx_dream_queue_pending ON dream_queue(started_at, en
|
|
|
151097
151129
|
ensureColumn(db, "session_meta", "cached_m0_materialized_at", "INTEGER");
|
|
151098
151130
|
ensureColumn(db, "session_meta", "cached_m0_session_facts_version", "INTEGER");
|
|
151099
151131
|
ensureColumn(db, "session_meta", "cached_m0_upgrade_state", "TEXT");
|
|
151132
|
+
ensureColumn(db, "session_meta", "cached_m0_system_hash", "TEXT");
|
|
151133
|
+
ensureColumn(db, "session_meta", "cached_m0_tool_set_hash", "TEXT");
|
|
151134
|
+
ensureColumn(db, "session_meta", "cached_m0_model_key", "TEXT");
|
|
151100
151135
|
ensureColumn(db, "session_meta", "cached_m0_last_baseline_end_message_id", "TEXT");
|
|
151101
151136
|
ensureColumn(db, "session_meta", "upgrade_reminded_at", "INTEGER");
|
|
151102
151137
|
db.exec(`
|
|
@@ -151183,6 +151218,7 @@ function healNullTextColumns(db) {
|
|
|
151183
151218
|
["todo_synthetic_state_json", ""],
|
|
151184
151219
|
["system_prompt_hash", ""],
|
|
151185
151220
|
["stripped_placeholder_ids", ""],
|
|
151221
|
+
["stale_reduce_stripped_ids", ""],
|
|
151186
151222
|
["memory_block_cache", ""],
|
|
151187
151223
|
["memory_block_ids", ""],
|
|
151188
151224
|
["compaction_marker_state", ""],
|
|
@@ -151301,7 +151337,7 @@ function getDatabasePersistenceError(db) {
|
|
|
151301
151337
|
return null;
|
|
151302
151338
|
return persistenceErrorByDatabase.get(db) ?? null;
|
|
151303
151339
|
}
|
|
151304
|
-
var databases, persistenceByDatabase, persistenceErrorByDatabase, lastSchemaFenceRejection = null, LATEST_SUPPORTED_VERSION =
|
|
151340
|
+
var databases, persistenceByDatabase, persistenceErrorByDatabase, lastSchemaFenceRejection = null, LATEST_SUPPORTED_VERSION = 30, sqlitePragmaConfig;
|
|
151305
151341
|
var init_storage_db = __esm(async () => {
|
|
151306
151342
|
init_data_path();
|
|
151307
151343
|
init_logger();
|
|
@@ -152124,6 +152160,28 @@ var init_migrations = __esm(async () => {
|
|
|
152124
152160
|
db.exec("ALTER TABLE notes ADD COLUMN anchor_ordinal INTEGER");
|
|
152125
152161
|
}
|
|
152126
152162
|
}
|
|
152163
|
+
},
|
|
152164
|
+
{
|
|
152165
|
+
version: 30,
|
|
152166
|
+
description: "HARD-bust m[0] markers: cached system/tool-set/model identity",
|
|
152167
|
+
up: (db) => {
|
|
152168
|
+
const hasSessionMeta = db.prepare("SELECT 1 FROM sqlite_master WHERE type='table' AND name='session_meta' LIMIT 1").get();
|
|
152169
|
+
if (!hasSessionMeta)
|
|
152170
|
+
return;
|
|
152171
|
+
ensureColumn(db, "session_meta", "cached_m0_system_hash", "TEXT");
|
|
152172
|
+
ensureColumn(db, "session_meta", "cached_m0_tool_set_hash", "TEXT");
|
|
152173
|
+
ensureColumn(db, "session_meta", "cached_m0_model_key", "TEXT");
|
|
152174
|
+
const columns = new Set(db.prepare("PRAGMA table_info(session_meta)").all().map((column) => column.name));
|
|
152175
|
+
if (columns.has("cached_m0_bytes")) {
|
|
152176
|
+
db.prepare(`UPDATE session_meta SET
|
|
152177
|
+
cached_m0_bytes = NULL,
|
|
152178
|
+
cached_m1_bytes = NULL,
|
|
152179
|
+
cached_m0_materialized_at = NULL,
|
|
152180
|
+
cached_m0_system_hash = NULL,
|
|
152181
|
+
cached_m0_tool_set_hash = NULL,
|
|
152182
|
+
cached_m0_model_key = NULL`).run();
|
|
152183
|
+
}
|
|
152184
|
+
}
|
|
152127
152185
|
}
|
|
152128
152186
|
];
|
|
152129
152187
|
LATEST_MIGRATION_VERSION = MIGRATIONS.reduce((max, m) => Math.max(max, m.version), 0);
|
|
@@ -152131,7 +152189,7 @@ var init_migrations = __esm(async () => {
|
|
|
152131
152189
|
|
|
152132
152190
|
// src/features/magic-context/project-docs-hash.ts
|
|
152133
152191
|
import { createHash as createHash4 } from "node:crypto";
|
|
152134
|
-
import { readFileSync as readFileSync5, statSync as statSync2 } from "node:fs";
|
|
152192
|
+
import { lstatSync, readFileSync as readFileSync5, statSync as statSync2 } from "node:fs";
|
|
152135
152193
|
import path4 from "node:path";
|
|
152136
152194
|
function canonicalizeDocContent(raw) {
|
|
152137
152195
|
return raw.replace(/^\uFEFF/, "").replace(/\r\n/g, `
|
|
@@ -152141,9 +152199,10 @@ function canonicalizeDocContent(raw) {
|
|
|
152141
152199
|
}
|
|
152142
152200
|
function fingerprintFile(filePath) {
|
|
152143
152201
|
try {
|
|
152144
|
-
const stat =
|
|
152202
|
+
const stat = lstatSync(filePath);
|
|
152203
|
+
const isReadableDoc = stat.isFile() && stat.size <= MAX_PROJECT_DOC_BYTES;
|
|
152145
152204
|
return {
|
|
152146
|
-
exists:
|
|
152205
|
+
exists: isReadableDoc,
|
|
152147
152206
|
mtimeMs: stat.mtimeMs,
|
|
152148
152207
|
size: stat.size
|
|
152149
152208
|
};
|
|
@@ -152186,6 +152245,16 @@ function readCanonicalPieces(projectDirectory, files) {
|
|
|
152186
152245
|
if (!fingerprint?.exists) {
|
|
152187
152246
|
continue;
|
|
152188
152247
|
}
|
|
152248
|
+
let safeToRead = false;
|
|
152249
|
+
try {
|
|
152250
|
+
const st = lstatSync(filePath);
|
|
152251
|
+
safeToRead = st.isFile() && st.size <= MAX_PROJECT_DOC_BYTES;
|
|
152252
|
+
} catch {
|
|
152253
|
+
safeToRead = false;
|
|
152254
|
+
}
|
|
152255
|
+
if (!safeToRead) {
|
|
152256
|
+
continue;
|
|
152257
|
+
}
|
|
152189
152258
|
const canonicalContent = canonicalizeDocContent(readFileSync5(filePath, "utf8"));
|
|
152190
152259
|
hashPieces.push(`file:${filename}
|
|
152191
152260
|
${canonicalContent}`);
|
|
@@ -152240,10 +152309,11 @@ var PROJECT_DOC_FILES, PROJECT_DOCS_DELIMITER = `
|
|
|
152240
152309
|
|
|
152241
152310
|
---
|
|
152242
152311
|
|
|
152243
|
-
`, docsCache;
|
|
152312
|
+
`, MAX_PROJECT_DOC_BYTES, docsCache;
|
|
152244
152313
|
var init_project_docs_hash = __esm(() => {
|
|
152245
152314
|
init_compartment_storage();
|
|
152246
152315
|
PROJECT_DOC_FILES = ["ARCHITECTURE.md", "STRUCTURE.md"];
|
|
152316
|
+
MAX_PROJECT_DOC_BYTES = 256 * 1024;
|
|
152247
152317
|
docsCache = new Map;
|
|
152248
152318
|
});
|
|
152249
152319
|
|
|
@@ -152580,7 +152650,8 @@ function casUpdateJsonArrayColumn(db, sessionId, column, validator, mutate, opti
|
|
|
152580
152650
|
}
|
|
152581
152651
|
for (let attempt = 0;attempt < CAS_RETRY_LIMIT; attempt += 1) {
|
|
152582
152652
|
const row = db.prepare(`SELECT ${column} FROM session_meta WHERE session_id = ?`).get(sessionId);
|
|
152583
|
-
const
|
|
152653
|
+
const rawCurrent = row?.[column] ?? null;
|
|
152654
|
+
const currentBlob = rawCurrent ?? "[]";
|
|
152584
152655
|
const current = parseJsonArray(currentBlob, validator);
|
|
152585
152656
|
const next = mutate(current);
|
|
152586
152657
|
if (next === null)
|
|
@@ -152588,7 +152659,7 @@ function casUpdateJsonArrayColumn(db, sessionId, column, validator, mutate, opti
|
|
|
152588
152659
|
const nextBlob = stableStringify(next);
|
|
152589
152660
|
if (nextBlob === currentBlob)
|
|
152590
152661
|
return true;
|
|
152591
|
-
const result = db.prepare(`UPDATE session_meta SET ${column} = ? WHERE session_id = ? AND ${column}
|
|
152662
|
+
const result = db.prepare(`UPDATE session_meta SET ${column} = ? WHERE session_id = ? AND ${column} IS ?`).run(nextBlob, sessionId, rawCurrent);
|
|
152592
152663
|
if (result.changes > 0)
|
|
152593
152664
|
return true;
|
|
152594
152665
|
}
|
|
@@ -152735,14 +152806,16 @@ function getHistorianFailureState(db, sessionId) {
|
|
|
152735
152806
|
};
|
|
152736
152807
|
}
|
|
152737
152808
|
function incrementHistorianFailure(db, sessionId, error51) {
|
|
152809
|
+
let nextCount = 1;
|
|
152738
152810
|
db.transaction(() => {
|
|
152739
152811
|
ensureSessionMetaRow(db, sessionId);
|
|
152740
152812
|
const current = getHistorianFailureState(db, sessionId);
|
|
152741
|
-
|
|
152813
|
+
nextCount = current.failureCount + 1;
|
|
152742
152814
|
db.prepare("UPDATE session_meta SET historian_failure_count = ?, historian_last_error = ?, historian_last_failure_at = ? WHERE session_id = ?").run(nextCount, error51, Date.now(), sessionId);
|
|
152743
152815
|
const reason = error51.replace(/\s+/g, " ").trim().slice(0, 300);
|
|
152744
152816
|
sessionLog(sessionId, `historian failure recorded: count=${nextCount} reason="${reason}"`);
|
|
152745
152817
|
})();
|
|
152818
|
+
return nextCount;
|
|
152746
152819
|
}
|
|
152747
152820
|
function clearHistorianFailureState(db, sessionId) {
|
|
152748
152821
|
db.transaction(() => {
|
|
@@ -152819,19 +152892,78 @@ function getStrippedPlaceholderIds(db, sessionId) {
|
|
|
152819
152892
|
} catch {}
|
|
152820
152893
|
return new Set;
|
|
152821
152894
|
}
|
|
152822
|
-
function
|
|
152895
|
+
function applyStrippedPlaceholderDelta(db, sessionId, delta) {
|
|
152896
|
+
const add = delta.add ? [...delta.add] : [];
|
|
152897
|
+
const remove = delta.remove ? [...delta.remove] : [];
|
|
152898
|
+
if (add.length === 0 && remove.length === 0)
|
|
152899
|
+
return true;
|
|
152823
152900
|
ensureSessionMetaRow(db, sessionId);
|
|
152824
|
-
|
|
152825
|
-
|
|
152901
|
+
for (let attempt = 0;attempt < CAS_RETRY_LIMIT; attempt += 1) {
|
|
152902
|
+
const row = db.prepare("SELECT stripped_placeholder_ids FROM session_meta WHERE session_id = ?").get(sessionId);
|
|
152903
|
+
const rawStored = row ? row.stripped_placeholder_ids ?? null : null;
|
|
152904
|
+
const current = new Set(parseStrippedBlob(rawStored));
|
|
152905
|
+
for (const id of add)
|
|
152906
|
+
current.add(id);
|
|
152907
|
+
for (const id of remove)
|
|
152908
|
+
current.delete(id);
|
|
152909
|
+
const nextBlob = current.size > 0 ? JSON.stringify([...current]) : "";
|
|
152910
|
+
if (nextBlob === (rawStored ?? ""))
|
|
152911
|
+
return true;
|
|
152912
|
+
const result = db.prepare("UPDATE session_meta SET stripped_placeholder_ids = ? WHERE session_id = ? AND stripped_placeholder_ids IS ?").run(nextBlob, sessionId, rawStored);
|
|
152913
|
+
if (result.changes > 0)
|
|
152914
|
+
return true;
|
|
152915
|
+
}
|
|
152916
|
+
sessionLog(sessionId, `stripped_placeholder_ids CAS: ${CAS_RETRY_LIMIT} retries exhausted`);
|
|
152917
|
+
return false;
|
|
152918
|
+
}
|
|
152919
|
+
function parseStrippedBlob(raw) {
|
|
152920
|
+
if (!raw || raw.length === 0)
|
|
152921
|
+
return [];
|
|
152922
|
+
try {
|
|
152923
|
+
const parsed = JSON.parse(raw);
|
|
152924
|
+
if (Array.isArray(parsed))
|
|
152925
|
+
return parsed.filter((v) => typeof v === "string");
|
|
152926
|
+
} catch {}
|
|
152927
|
+
return [];
|
|
152826
152928
|
}
|
|
152827
152929
|
function removeStrippedPlaceholderId(db, sessionId, messageId) {
|
|
152828
|
-
const
|
|
152829
|
-
if (!
|
|
152930
|
+
const before = getStrippedPlaceholderIds(db, sessionId);
|
|
152931
|
+
if (!before.has(messageId)) {
|
|
152830
152932
|
return false;
|
|
152831
152933
|
}
|
|
152832
|
-
|
|
152934
|
+
applyStrippedPlaceholderDelta(db, sessionId, { remove: [messageId] });
|
|
152833
152935
|
return true;
|
|
152834
152936
|
}
|
|
152937
|
+
function getStaleReduceStrippedIds(db, sessionId) {
|
|
152938
|
+
const row = db.prepare("SELECT stale_reduce_stripped_ids FROM session_meta WHERE session_id = ?").get(sessionId);
|
|
152939
|
+
return new Set(parseStrippedBlob(row?.stale_reduce_stripped_ids));
|
|
152940
|
+
}
|
|
152941
|
+
function addStaleReduceStrippedIds(db, sessionId, ids) {
|
|
152942
|
+
const add = [...ids];
|
|
152943
|
+
if (add.length === 0)
|
|
152944
|
+
return true;
|
|
152945
|
+
ensureSessionMetaRow(db, sessionId);
|
|
152946
|
+
for (let attempt = 0;attempt < CAS_RETRY_LIMIT; attempt += 1) {
|
|
152947
|
+
const row = db.prepare("SELECT stale_reduce_stripped_ids FROM session_meta WHERE session_id = ?").get(sessionId);
|
|
152948
|
+
const rawStored = row ? row.stale_reduce_stripped_ids ?? null : null;
|
|
152949
|
+
const current = new Set(parseStrippedBlob(rawStored));
|
|
152950
|
+
let changed = false;
|
|
152951
|
+
for (const id of add) {
|
|
152952
|
+
if (!current.has(id)) {
|
|
152953
|
+
current.add(id);
|
|
152954
|
+
changed = true;
|
|
152955
|
+
}
|
|
152956
|
+
}
|
|
152957
|
+
if (!changed)
|
|
152958
|
+
return true;
|
|
152959
|
+
const nextBlob = JSON.stringify([...current]);
|
|
152960
|
+
const result = db.prepare("UPDATE session_meta SET stale_reduce_stripped_ids = ? WHERE session_id = ? AND stale_reduce_stripped_ids IS ?").run(nextBlob, sessionId, rawStored);
|
|
152961
|
+
if (result.changes > 0)
|
|
152962
|
+
return true;
|
|
152963
|
+
}
|
|
152964
|
+
sessionLog(sessionId, `stale_reduce_stripped_ids CAS: ${CAS_RETRY_LIMIT} retries exhausted`);
|
|
152965
|
+
return false;
|
|
152966
|
+
}
|
|
152835
152967
|
function isPendingCompactionMarker(value) {
|
|
152836
152968
|
return typeof value === "object" && value !== null && typeof value.ordinal === "number" && typeof value.endMessageId === "string" && typeof value.publishedAt === "number";
|
|
152837
152969
|
}
|
|
@@ -153042,6 +153174,9 @@ var init_storage_meta_session = __esm(async () => {
|
|
|
153042
153174
|
cached_m0_materialized_at: "NULL AS cached_m0_materialized_at",
|
|
153043
153175
|
cached_m0_session_facts_version: "NULL AS cached_m0_session_facts_version",
|
|
153044
153176
|
cached_m0_upgrade_state: "NULL AS cached_m0_upgrade_state",
|
|
153177
|
+
cached_m0_system_hash: "NULL AS cached_m0_system_hash",
|
|
153178
|
+
cached_m0_tool_set_hash: "NULL AS cached_m0_tool_set_hash",
|
|
153179
|
+
cached_m0_model_key: "NULL AS cached_m0_model_key",
|
|
153045
153180
|
last_observed_model_key: "NULL AS last_observed_model_key",
|
|
153046
153181
|
upgrade_reminded_at: "NULL AS upgrade_reminded_at"
|
|
153047
153182
|
};
|
|
@@ -163018,25 +163153,56 @@ var init_conflict_warning_hook = __esm(() => {
|
|
|
163018
163153
|
// src/features/magic-context/key-files/aft-availability.ts
|
|
163019
163154
|
import { existsSync as existsSync12, readFileSync as readFileSync10 } from "node:fs";
|
|
163020
163155
|
import { homedir as homedir8 } from "node:os";
|
|
163021
|
-
import { join as join14 } from "node:path";
|
|
163156
|
+
import { isAbsolute as isAbsolute3, join as join14, resolve as resolve5 } from "node:path";
|
|
163157
|
+
import { fileURLToPath as fileURLToPath2 } from "node:url";
|
|
163022
163158
|
function parseConfig(path6) {
|
|
163023
163159
|
if (!existsSync12(path6))
|
|
163024
163160
|
return null;
|
|
163025
163161
|
return import_comment_json3.parse(readFileSync10(path6, "utf-8"));
|
|
163026
163162
|
}
|
|
163027
|
-
function
|
|
163163
|
+
function stringMentionsAft(value) {
|
|
163164
|
+
return AFT_NAME_NEEDLES.some((needle) => value.includes(needle));
|
|
163165
|
+
}
|
|
163166
|
+
function resolveLocalEntryPackageName(value, configDir) {
|
|
163167
|
+
let dir = null;
|
|
163168
|
+
if (value.startsWith("file://")) {
|
|
163169
|
+
try {
|
|
163170
|
+
dir = fileURLToPath2(value);
|
|
163171
|
+
} catch {
|
|
163172
|
+
return null;
|
|
163173
|
+
}
|
|
163174
|
+
} else if (value.startsWith("~/")) {
|
|
163175
|
+
dir = join14(homedir8(), value.slice(2));
|
|
163176
|
+
} else if (value.startsWith("/") || value.startsWith("./") || value.startsWith("../")) {
|
|
163177
|
+
dir = isAbsolute3(value) ? value : resolve5(configDir, value);
|
|
163178
|
+
} else {
|
|
163179
|
+
return null;
|
|
163180
|
+
}
|
|
163181
|
+
try {
|
|
163182
|
+
const pkg = JSON.parse(readFileSync10(join14(dir, "package.json"), "utf-8"));
|
|
163183
|
+
return typeof pkg.name === "string" ? pkg.name : null;
|
|
163184
|
+
} catch {
|
|
163185
|
+
return null;
|
|
163186
|
+
}
|
|
163187
|
+
}
|
|
163188
|
+
function entryMatchesAft(entry, configDir) {
|
|
163028
163189
|
const value = Array.isArray(entry) ? entry[0] : entry;
|
|
163029
|
-
|
|
163190
|
+
if (typeof value !== "string")
|
|
163191
|
+
return false;
|
|
163192
|
+
if (stringMentionsAft(value))
|
|
163193
|
+
return true;
|
|
163194
|
+
const name2 = resolveLocalEntryPackageName(value, configDir);
|
|
163195
|
+
return name2 != null && stringMentionsAft(name2);
|
|
163030
163196
|
}
|
|
163031
|
-
function hasAftInArray(value) {
|
|
163032
|
-
return Array.isArray(value) && value.some(entryMatchesAft);
|
|
163197
|
+
function hasAftInArray(value, configDir) {
|
|
163198
|
+
return Array.isArray(value) && value.some((entry) => entryMatchesAft(entry, configDir));
|
|
163033
163199
|
}
|
|
163034
|
-
function hasAftAtKeys(value, keys) {
|
|
163200
|
+
function hasAftAtKeys(value, keys, configDir) {
|
|
163035
163201
|
if (!value || typeof value !== "object")
|
|
163036
163202
|
return false;
|
|
163037
163203
|
const record2 = value;
|
|
163038
163204
|
for (const key of keys) {
|
|
163039
|
-
if (hasAftInArray(record2[key]))
|
|
163205
|
+
if (hasAftInArray(record2[key], configDir))
|
|
163040
163206
|
return true;
|
|
163041
163207
|
}
|
|
163042
163208
|
return false;
|
|
@@ -163053,7 +163219,8 @@ function getAftAvailability() {
|
|
|
163053
163219
|
for (const path6 of opencodePaths) {
|
|
163054
163220
|
try {
|
|
163055
163221
|
const config2 = parseConfig(path6);
|
|
163056
|
-
|
|
163222
|
+
const configDir = join14(path6, "..");
|
|
163223
|
+
if (hasAftAtKeys(config2, ["plugin", "plugins", "mcp", "mcp_servers"], configDir)) {
|
|
163057
163224
|
opencode = true;
|
|
163058
163225
|
break;
|
|
163059
163226
|
}
|
|
@@ -163063,12 +163230,13 @@ function getAftAvailability() {
|
|
|
163063
163230
|
for (const path6 of piPaths) {
|
|
163064
163231
|
try {
|
|
163065
163232
|
const config2 = parseConfig(path6);
|
|
163066
|
-
|
|
163233
|
+
const configDir = join14(path6, "..");
|
|
163234
|
+
if (hasAftAtKeys(config2, ["packages", "extensions"], configDir)) {
|
|
163067
163235
|
pi = true;
|
|
163068
163236
|
break;
|
|
163069
163237
|
}
|
|
163070
163238
|
const agent = config2?.agent;
|
|
163071
|
-
if (hasAftAtKeys(agent, ["packages", "extensions"])) {
|
|
163239
|
+
if (hasAftAtKeys(agent, ["packages", "extensions"], configDir)) {
|
|
163072
163240
|
pi = true;
|
|
163073
163241
|
break;
|
|
163074
163242
|
}
|
|
@@ -163085,9 +163253,10 @@ function getAftAvailability() {
|
|
|
163085
163253
|
function isAftAvailable() {
|
|
163086
163254
|
return getAftAvailability().available;
|
|
163087
163255
|
}
|
|
163088
|
-
var import_comment_json3, overrideAvailability = null;
|
|
163256
|
+
var import_comment_json3, overrideAvailability = null, AFT_NAME_NEEDLES;
|
|
163089
163257
|
var init_aft_availability = __esm(() => {
|
|
163090
163258
|
import_comment_json3 = __toESM(require_src2(), 1);
|
|
163259
|
+
AFT_NAME_NEEDLES = ["@cortexkit/aft", "aft-opencode", "aft-pi"];
|
|
163091
163260
|
});
|
|
163092
163261
|
|
|
163093
163262
|
// src/features/magic-context/memory/storage-memory-embeddings.ts
|
|
@@ -163706,7 +163875,7 @@ function cosineSimilarity(a, b) {
|
|
|
163706
163875
|
}
|
|
163707
163876
|
|
|
163708
163877
|
// src/features/magic-context/memory/embedding-identity.ts
|
|
163709
|
-
function
|
|
163878
|
+
function normalizeEndpoint2(endpoint) {
|
|
163710
163879
|
return endpoint?.trim().replace(/\/+$/, "") ?? "";
|
|
163711
163880
|
}
|
|
163712
163881
|
function getEmbeddingProviderIdentity(config2) {
|
|
@@ -163716,7 +163885,7 @@ function getEmbeddingProviderIdentity(config2) {
|
|
|
163716
163885
|
const identityInput = config2.provider === "openai-compatible" ? {
|
|
163717
163886
|
provider: "openai-compatible",
|
|
163718
163887
|
model: config2.model.trim(),
|
|
163719
|
-
endpoint:
|
|
163888
|
+
endpoint: normalizeEndpoint2(config2.endpoint),
|
|
163720
163889
|
apiKeyPresent: Boolean(config2.api_key?.trim()),
|
|
163721
163890
|
inputType: config2.input_type?.trim() || ""
|
|
163722
163891
|
} : {
|
|
@@ -163772,7 +163941,7 @@ async function acquireModelLoadLock(lockPath) {
|
|
|
163772
163941
|
if (Date.now() - waitStart > MAX_LOCK_WAIT_MS) {
|
|
163773
163942
|
throw new Error(`[magic-context] embedding-load lock wait exceeded ${MAX_LOCK_WAIT_MS}ms; another process is still loading the model. Skipping this init attempt to avoid an unsynchronized native load.`);
|
|
163774
163943
|
}
|
|
163775
|
-
await new Promise((
|
|
163944
|
+
await new Promise((resolve7) => setTimeout(resolve7, LOCK_POLL_MS));
|
|
163776
163945
|
}
|
|
163777
163946
|
}
|
|
163778
163947
|
}
|
|
@@ -163941,7 +164110,7 @@ class LocalEmbeddingProvider {
|
|
|
163941
164110
|
}
|
|
163942
164111
|
const delayMs = 300 * attempt + Math.floor(Math.random() * 200);
|
|
163943
164112
|
log(`[magic-context] embedding model load attempt ${attempt}/${MAX_ATTEMPTS} failed transiently, retrying in ${delayMs}ms`);
|
|
163944
|
-
await new Promise((
|
|
164113
|
+
await new Promise((resolve7) => setTimeout(resolve7, delayMs));
|
|
163945
164114
|
}
|
|
163946
164115
|
}
|
|
163947
164116
|
if (this.pipeline) {
|
|
@@ -163969,8 +164138,8 @@ class LocalEmbeddingProvider {
|
|
|
163969
164138
|
if (this.inFlight === 0) {
|
|
163970
164139
|
return Promise.resolve();
|
|
163971
164140
|
}
|
|
163972
|
-
return new Promise((
|
|
163973
|
-
this.inFlightWaiters.push(
|
|
164141
|
+
return new Promise((resolve7) => {
|
|
164142
|
+
this.inFlightWaiters.push(resolve7);
|
|
163974
164143
|
});
|
|
163975
164144
|
}
|
|
163976
164145
|
finishInFlight() {
|
|
@@ -164077,8 +164246,64 @@ var init_embedding_local = __esm(() => {
|
|
|
164077
164246
|
MAX_LOCK_WAIT_MS = 5 * 60000;
|
|
164078
164247
|
});
|
|
164079
164248
|
|
|
164249
|
+
// src/features/magic-context/memory/embedding-ssrf.ts
|
|
164250
|
+
function isLinkLocalIpv4(host) {
|
|
164251
|
+
return /^169\.254\.\d{1,3}\.\d{1,3}$/.test(host);
|
|
164252
|
+
}
|
|
164253
|
+
function ipv4FromMappedIpv6(host) {
|
|
164254
|
+
const m = /^::ffff:(.+)$/.exec(host);
|
|
164255
|
+
if (!m)
|
|
164256
|
+
return null;
|
|
164257
|
+
const tail = m[1];
|
|
164258
|
+
if (/^\d{1,3}(\.\d{1,3}){3}$/.test(tail))
|
|
164259
|
+
return tail;
|
|
164260
|
+
const hex3 = /^([0-9a-f]{1,4}):([0-9a-f]{1,4})$/.exec(tail);
|
|
164261
|
+
if (hex3) {
|
|
164262
|
+
const hi = Number.parseInt(hex3[1], 16);
|
|
164263
|
+
const lo = Number.parseInt(hex3[2], 16);
|
|
164264
|
+
if (Number.isNaN(hi) || Number.isNaN(lo))
|
|
164265
|
+
return null;
|
|
164266
|
+
return `${hi >> 8 & 255}.${hi & 255}.${lo >> 8 & 255}.${lo & 255}`;
|
|
164267
|
+
}
|
|
164268
|
+
return null;
|
|
164269
|
+
}
|
|
164270
|
+
function blockedEmbeddingEndpointReason(endpoint) {
|
|
164271
|
+
const trimmed = endpoint.trim();
|
|
164272
|
+
if (trimmed.length === 0)
|
|
164273
|
+
return null;
|
|
164274
|
+
let url2;
|
|
164275
|
+
try {
|
|
164276
|
+
url2 = new URL(trimmed);
|
|
164277
|
+
} catch {
|
|
164278
|
+
return `embedding endpoint is not a valid URL: ${trimmed}`;
|
|
164279
|
+
}
|
|
164280
|
+
const host = url2.hostname.toLowerCase().replace(/^\[/, "").replace(/\]$/, "");
|
|
164281
|
+
if (METADATA_HOSTNAMES.has(host)) {
|
|
164282
|
+
return `embedding endpoint host ${host} is a cloud metadata service (blocked)`;
|
|
164283
|
+
}
|
|
164284
|
+
if (IPV6_METADATA_HOSTS.has(host)) {
|
|
164285
|
+
return `embedding endpoint host ${host} is the AWS IPv6 metadata service (blocked)`;
|
|
164286
|
+
}
|
|
164287
|
+
if (isLinkLocalIpv4(host)) {
|
|
164288
|
+
return `embedding endpoint host ${host} is link-local / cloud metadata (blocked)`;
|
|
164289
|
+
}
|
|
164290
|
+
const mappedV4 = ipv4FromMappedIpv6(host);
|
|
164291
|
+
if (mappedV4 && isLinkLocalIpv4(mappedV4)) {
|
|
164292
|
+
return `embedding endpoint host ${host} (IPv4-mapped ${mappedV4}) is link-local / cloud metadata (blocked)`;
|
|
164293
|
+
}
|
|
164294
|
+
if (host.startsWith("fe80:")) {
|
|
164295
|
+
return `embedding endpoint host ${host} is link-local / cloud metadata (blocked)`;
|
|
164296
|
+
}
|
|
164297
|
+
return null;
|
|
164298
|
+
}
|
|
164299
|
+
var METADATA_HOSTNAMES, IPV6_METADATA_HOSTS;
|
|
164300
|
+
var init_embedding_ssrf = __esm(() => {
|
|
164301
|
+
METADATA_HOSTNAMES = new Set(["metadata.google.internal", "metadata.goog"]);
|
|
164302
|
+
IPV6_METADATA_HOSTS = new Set(["fd00:ec2::254"]);
|
|
164303
|
+
});
|
|
164304
|
+
|
|
164080
164305
|
// src/features/magic-context/memory/embedding-openai.ts
|
|
164081
|
-
function
|
|
164306
|
+
function normalizeEndpoint3(endpoint) {
|
|
164082
164307
|
return endpoint?.trim().replace(/\/+$/, "") ?? "";
|
|
164083
164308
|
}
|
|
164084
164309
|
|
|
@@ -164095,7 +164320,7 @@ class OpenAICompatibleEmbeddingProvider {
|
|
|
164095
164320
|
openLogged = false;
|
|
164096
164321
|
halfOpenProbeInFlight = false;
|
|
164097
164322
|
constructor(options) {
|
|
164098
|
-
this.endpoint =
|
|
164323
|
+
this.endpoint = normalizeEndpoint3(options.endpoint);
|
|
164099
164324
|
this.model = options.model?.trim() ?? "";
|
|
164100
164325
|
this.apiKey = options.apiKey?.trim() ?? "";
|
|
164101
164326
|
this.inputType = options.inputType?.trim() ?? "";
|
|
@@ -164115,6 +164340,12 @@ class OpenAICompatibleEmbeddingProvider {
|
|
|
164115
164340
|
this.initialized = false;
|
|
164116
164341
|
return false;
|
|
164117
164342
|
}
|
|
164343
|
+
const blockedReason = blockedEmbeddingEndpointReason(this.endpoint);
|
|
164344
|
+
if (blockedReason) {
|
|
164345
|
+
log(`[magic-context] embedding endpoint blocked: ${blockedReason}`);
|
|
164346
|
+
this.initialized = false;
|
|
164347
|
+
return false;
|
|
164348
|
+
}
|
|
164118
164349
|
this.initialized = true;
|
|
164119
164350
|
return true;
|
|
164120
164351
|
}
|
|
@@ -164160,6 +164391,7 @@ class OpenAICompatibleEmbeddingProvider {
|
|
|
164160
164391
|
...this.inputType ? { input_type: this.inputType } : {},
|
|
164161
164392
|
...this.truncate ? { truncate: this.truncate } : {}
|
|
164162
164393
|
}),
|
|
164394
|
+
redirect: "error",
|
|
164163
164395
|
signal: internalController.signal
|
|
164164
164396
|
});
|
|
164165
164397
|
if (!response.ok) {
|
|
@@ -164290,6 +164522,7 @@ var FAILURE_THRESHOLD = 3, FAILURE_WINDOW_MS = 60000, OPEN_DURATION_MS, FETCH_TI
|
|
|
164290
164522
|
var init_embedding_openai = __esm(() => {
|
|
164291
164523
|
init_logger();
|
|
164292
164524
|
init_embedding_identity();
|
|
164525
|
+
init_embedding_ssrf();
|
|
164293
164526
|
OPEN_DURATION_MS = 5 * 60000;
|
|
164294
164527
|
});
|
|
164295
164528
|
|
|
@@ -164530,11 +164763,15 @@ function resolveEmbeddingConfig(config2) {
|
|
|
164530
164763
|
}
|
|
164531
164764
|
if (config2.provider === "openai-compatible") {
|
|
164532
164765
|
const apiKey = config2.api_key?.trim();
|
|
164766
|
+
const inputType = config2.input_type?.trim();
|
|
164767
|
+
const truncate = config2.truncate?.trim();
|
|
164533
164768
|
return {
|
|
164534
164769
|
provider: "openai-compatible",
|
|
164535
164770
|
model: config2.model.trim(),
|
|
164536
164771
|
endpoint: config2.endpoint.trim(),
|
|
164537
|
-
...apiKey ? { api_key: apiKey } : {}
|
|
164772
|
+
...apiKey ? { api_key: apiKey } : {},
|
|
164773
|
+
...inputType ? { input_type: inputType } : {},
|
|
164774
|
+
...truncate ? { truncate } : {}
|
|
164538
164775
|
};
|
|
164539
164776
|
}
|
|
164540
164777
|
return { provider: "off" };
|
|
@@ -164550,7 +164787,9 @@ function createProvider(config2) {
|
|
|
164550
164787
|
return new OpenAICompatibleEmbeddingProvider({
|
|
164551
164788
|
endpoint: config2.endpoint,
|
|
164552
164789
|
model: config2.model,
|
|
164553
|
-
apiKey: config2.api_key
|
|
164790
|
+
apiKey: config2.api_key,
|
|
164791
|
+
inputType: config2.input_type,
|
|
164792
|
+
truncate: config2.truncate
|
|
164554
164793
|
});
|
|
164555
164794
|
}
|
|
164556
164795
|
return new LocalEmbeddingProvider(config2.model);
|
|
@@ -164957,7 +165196,7 @@ async function refreshModelLimitsFromApi(client, options) {
|
|
|
164957
165196
|
if (ok)
|
|
164958
165197
|
return;
|
|
164959
165198
|
if (attempt < attempts) {
|
|
164960
|
-
await new Promise((
|
|
165199
|
+
await new Promise((resolve7) => setTimeout(resolve7, delayMs));
|
|
164961
165200
|
}
|
|
164962
165201
|
}
|
|
164963
165202
|
}
|
|
@@ -165328,15 +165567,15 @@ function updateCompactionMarkerAfterPublication(db, sessionId, lastCompartmentEn
|
|
|
165328
165567
|
const existing = getPersistedCompactionMarkerState(db, sessionId);
|
|
165329
165568
|
if (existing) {
|
|
165330
165569
|
if (existing.boundaryOrdinal === lastCompartmentEnd) {
|
|
165331
|
-
return;
|
|
165570
|
+
return true;
|
|
165332
165571
|
}
|
|
165333
|
-
|
|
165334
|
-
|
|
165335
|
-
|
|
165336
|
-
|
|
165337
|
-
} catch (error51) {
|
|
165338
|
-
sessionLog(sessionId, `compaction-marker: failed to remove old boundary at ordinal ${existing.boundaryOrdinal}, proceeding with new injection:`, error51);
|
|
165572
|
+
const removed = removeCompactionMarker(existing);
|
|
165573
|
+
if (!removed) {
|
|
165574
|
+
sessionLog(sessionId, `compaction-marker: failed to remove old boundary at ordinal ${existing.boundaryOrdinal}; preserving persisted state for retry (not injecting new marker this pass)`);
|
|
165575
|
+
return false;
|
|
165339
165576
|
}
|
|
165577
|
+
setPersistedCompactionMarkerState(db, sessionId, null);
|
|
165578
|
+
sessionLog(sessionId, `compaction-marker: removed old boundary at ordinal ${existing.boundaryOrdinal}, moving to ${lastCompartmentEnd}`);
|
|
165340
165579
|
}
|
|
165341
165580
|
const result = injectCompactionMarker({
|
|
165342
165581
|
sessionId,
|
|
@@ -165350,7 +165589,9 @@ function updateCompactionMarkerAfterPublication(db, sessionId, lastCompartmentEn
|
|
|
165350
165589
|
boundaryOrdinal: lastCompartmentEnd
|
|
165351
165590
|
});
|
|
165352
165591
|
sessionLog(sessionId, `compaction-marker: injected at ordinal ${lastCompartmentEnd}, boundary user msg ${result.boundaryMessageId}`);
|
|
165592
|
+
return true;
|
|
165353
165593
|
}
|
|
165594
|
+
return false;
|
|
165354
165595
|
}
|
|
165355
165596
|
function removeCompactionMarkerForSession(db, sessionId) {
|
|
165356
165597
|
const existing = getPersistedCompactionMarkerState(db, sessionId);
|
|
@@ -165385,10 +165626,10 @@ function checkCompactionMarkerConsistency(db) {
|
|
|
165385
165626
|
const state = getPersistedCompactionMarkerState(db, row.session_id);
|
|
165386
165627
|
if (!state)
|
|
165387
165628
|
continue;
|
|
165388
|
-
const boundaryExists = checkMessage.get(state.boundaryMessageId)
|
|
165389
|
-
const summaryMessageExists = checkMessage.get(state.summaryMessageId)
|
|
165390
|
-
const compactionPartExists = checkPart.get(state.compactionPartId)
|
|
165391
|
-
const summaryPartExists = checkPart.get(state.summaryPartId)
|
|
165629
|
+
const boundaryExists = checkMessage.get(state.boundaryMessageId) != null;
|
|
165630
|
+
const summaryMessageExists = checkMessage.get(state.summaryMessageId) != null;
|
|
165631
|
+
const compactionPartExists = checkPart.get(state.compactionPartId) != null;
|
|
165632
|
+
const summaryPartExists = checkPart.get(state.summaryPartId) != null;
|
|
165392
165633
|
const allPresent = boundaryExists && summaryMessageExists && compactionPartExists && summaryPartExists;
|
|
165393
165634
|
if (allPresent)
|
|
165394
165635
|
continue;
|
|
@@ -165648,6 +165889,26 @@ function validateHistorianOutput(text, _sessionId, chunk, _priorCompartments, se
|
|
|
165648
165889
|
events: parsed.events.length > 0 ? parsed.events : undefined
|
|
165649
165890
|
};
|
|
165650
165891
|
}
|
|
165892
|
+
function buildHistorianFailureNotice(failureCount, lastError) {
|
|
165893
|
+
if (failureCount >= HISTORIAN_PERSISTENT_FAILURE_THRESHOLD) {
|
|
165894
|
+
return [
|
|
165895
|
+
"## Magic Context — history comparting needs attention",
|
|
165896
|
+
"",
|
|
165897
|
+
`Magic Context has been unable to compart this session's history ${failureCount} times in a row. This usually means the configured historian model is misconfigured or unreachable (Magic Context already retried every fallback model automatically).`,
|
|
165898
|
+
"",
|
|
165899
|
+
`Last error: ${lastError}`,
|
|
165900
|
+
"",
|
|
165901
|
+
"Check your historian model in magic-context.jsonc, then restart. Your conversation keeps working normally in the meantime — this only affects how older history is summarized."
|
|
165902
|
+
].join(`
|
|
165903
|
+
`);
|
|
165904
|
+
}
|
|
165905
|
+
return [
|
|
165906
|
+
"## Magic Context",
|
|
165907
|
+
"",
|
|
165908
|
+
"Hit a transient issue comparting history this turn — Magic Context will retry automatically on the next turn. Nothing is lost and your conversation continues normally. You'll only be alerted again if this keeps happening."
|
|
165909
|
+
].join(`
|
|
165910
|
+
`);
|
|
165911
|
+
}
|
|
165651
165912
|
function buildHistorianRepairPrompt(originalPrompt, previousOutput, validationError) {
|
|
165652
165913
|
return [
|
|
165653
165914
|
originalPrompt,
|
|
@@ -165736,7 +165997,7 @@ function getReducedRecompTokenBudget(currentBudget) {
|
|
|
165736
165997
|
const reducedBudget = Math.max(MIN_RECOMP_CHUNK_TOKEN_BUDGET, Math.floor(currentBudget / 2));
|
|
165737
165998
|
return reducedBudget < currentBudget ? reducedBudget : null;
|
|
165738
165999
|
}
|
|
165739
|
-
var MIN_RECOMP_CHUNK_TOKEN_BUDGET = 20;
|
|
166000
|
+
var MIN_RECOMP_CHUNK_TOKEN_BUDGET = 20, HISTORIAN_PERSISTENT_FAILURE_THRESHOLD = 3;
|
|
165740
166001
|
var init_compartment_runner_validation = __esm(async () => {
|
|
165741
166002
|
init_compartment_parser();
|
|
165742
166003
|
await init_compartment_runner_mapping();
|
|
@@ -165943,12 +166204,12 @@ async function runHistorianPrompt(args) {
|
|
|
165943
166204
|
error: `Historian failed while processing this session: ${desc.brief}`
|
|
165944
166205
|
};
|
|
165945
166206
|
} finally {
|
|
165946
|
-
if (agentSessionId && outcomeOk) {
|
|
166207
|
+
if (agentSessionId && outcomeOk && !shouldKeepSubagents()) {
|
|
165947
166208
|
await client.session.delete({ path: { id: agentSessionId } }).catch((e) => {
|
|
165948
166209
|
sessionLog(parentSessionId, "compartment agent: session cleanup failed", getErrorMessage(e));
|
|
165949
166210
|
});
|
|
165950
|
-
} else if (agentSessionId && !outcomeOk) {
|
|
165951
|
-
sessionLog(parentSessionId, `historian: KEEPING
|
|
166211
|
+
} else if (agentSessionId && (!outcomeOk || shouldKeepSubagents())) {
|
|
166212
|
+
sessionLog(parentSessionId, `historian: KEEPING child session ${agentSessionId} (${outcomeOk ? "keep_subagents" : "failed"}) — not deleted`);
|
|
165952
166213
|
}
|
|
165953
166214
|
}
|
|
165954
166215
|
}
|
|
@@ -166027,8 +166288,8 @@ function isTransientHistorianPromptError(message) {
|
|
|
166027
166288
|
].some((token) => normalized.includes(token));
|
|
166028
166289
|
}
|
|
166029
166290
|
function sleep(ms) {
|
|
166030
|
-
return new Promise((
|
|
166031
|
-
setTimeout(
|
|
166291
|
+
return new Promise((resolve7) => {
|
|
166292
|
+
setTimeout(resolve7, ms);
|
|
166032
166293
|
});
|
|
166033
166294
|
}
|
|
166034
166295
|
function cleanupHistorianDump(sessionId, dumpPath) {
|
|
@@ -166439,6 +166700,9 @@ function escapeXmlAttr2(s) {
|
|
|
166439
166700
|
function escapeXmlContent2(s) {
|
|
166440
166701
|
return s.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">");
|
|
166441
166702
|
}
|
|
166703
|
+
function isTieredRow(c) {
|
|
166704
|
+
return typeof c.p1 === "string" && c.p1.length > 0;
|
|
166705
|
+
}
|
|
166442
166706
|
function tierBody(c, tier2) {
|
|
166443
166707
|
const tiers = [c.p1, c.p2, c.p3, c.p4];
|
|
166444
166708
|
const requested = tiers[tier2 - 1];
|
|
@@ -166468,12 +166732,13 @@ function renderOneCompartment(c, tier2) {
|
|
|
166468
166732
|
const baseAttrs = `start="${c.startMessage}" end="${c.endMessage}" title="${escapeXmlAttr2(c.title)}"`;
|
|
166469
166733
|
if (tier2 >= 5)
|
|
166470
166734
|
return "";
|
|
166471
|
-
if (c.legacy === 1) {
|
|
166472
|
-
|
|
166735
|
+
if (c.legacy === 1 || !isTieredRow(c)) {
|
|
166736
|
+
const flat = (c.content ?? "").trim();
|
|
166737
|
+
if (tier2 >= 4 || flat.length === 0)
|
|
166473
166738
|
return `<compartment ${baseAttrs} />`;
|
|
166474
166739
|
return [
|
|
166475
166740
|
`<compartment ${baseAttrs}>`,
|
|
166476
|
-
escapeXmlContent2(legacyBodyForTier(
|
|
166741
|
+
escapeXmlContent2(legacyBodyForTier(flat, tier2)),
|
|
166477
166742
|
"</compartment>"
|
|
166478
166743
|
].join(`
|
|
166479
166744
|
`);
|
|
@@ -166936,7 +167201,18 @@ function prepareCompartmentInjection(db, sessionId, messages, isCacheBusting, pr
|
|
|
166936
167201
|
const lastCompartment = compartments[compartments.length - 1];
|
|
166937
167202
|
const lastEnd = lastCompartment.endMessage;
|
|
166938
167203
|
const lastEndMessageId = lastCompartment.endMessageId;
|
|
166939
|
-
|
|
167204
|
+
let trimEndMessageId = lastEndMessageId;
|
|
167205
|
+
if (!isCacheBusting) {
|
|
167206
|
+
const baseline = readCachedBaselineState(db, sessionId);
|
|
167207
|
+
if (baseline.hasCachedM0) {
|
|
167208
|
+
if (baseline.boundary) {
|
|
167209
|
+
trimEndMessageId = baseline.boundary;
|
|
167210
|
+
} else {
|
|
167211
|
+
trimEndMessageId = "";
|
|
167212
|
+
}
|
|
167213
|
+
}
|
|
167214
|
+
}
|
|
167215
|
+
if (trimEndMessageId.length === 0) {
|
|
166940
167216
|
sessionLog(sessionId, "injecting legacy compartments without visible-prefix trimming because latest stored compartment has no end_message_id", {
|
|
166941
167217
|
compartmentCount: compartments.length,
|
|
166942
167218
|
compartmentEndMessage: lastEnd
|
|
@@ -166955,18 +167231,18 @@ function prepareCompartmentInjection(db, sessionId, messages, isCacheBusting, pr
|
|
|
166955
167231
|
return result2;
|
|
166956
167232
|
}
|
|
166957
167233
|
let skippedVisibleMessages = 0;
|
|
166958
|
-
const cutoffIndex = messages.findIndex((message) => message.info.id ===
|
|
167234
|
+
const cutoffIndex = messages.findIndex((message) => message.info.id === trimEndMessageId);
|
|
166959
167235
|
if (cutoffIndex >= 0) {
|
|
166960
167236
|
skippedVisibleMessages = cutoffIndex + 1;
|
|
166961
167237
|
const remaining = messages.slice(cutoffIndex + 1);
|
|
166962
167238
|
messages.splice(0, messages.length, ...remaining);
|
|
166963
167239
|
} else {
|
|
166964
|
-
sessionLog(sessionId, `compartment injection entering degraded mode: boundary ${
|
|
167240
|
+
sessionLog(sessionId, `compartment injection entering degraded mode: boundary ${trimEndMessageId} not in visible messages`);
|
|
166965
167241
|
}
|
|
166966
167242
|
const result = {
|
|
166967
167243
|
block,
|
|
166968
167244
|
compartmentEndMessage: lastEnd,
|
|
166969
|
-
compartmentEndMessageId: cutoffIndex >= 0 ?
|
|
167245
|
+
compartmentEndMessageId: cutoffIndex >= 0 ? trimEndMessageId : null,
|
|
166970
167246
|
compartmentCount: compartments.length,
|
|
166971
167247
|
skippedVisibleMessages,
|
|
166972
167248
|
factCount: facts.length,
|
|
@@ -166976,6 +167252,14 @@ function prepareCompartmentInjection(db, sessionId, messages, isCacheBusting, pr
|
|
|
166976
167252
|
injectionCache.set(sessionId, { kind: "populated", injection: result });
|
|
166977
167253
|
return result;
|
|
166978
167254
|
}
|
|
167255
|
+
function readCachedBaselineState(db, sessionId) {
|
|
167256
|
+
const row = db.prepare("SELECT cached_m0_bytes AS m0, cached_m0_last_baseline_end_message_id AS boundary FROM session_meta WHERE session_id = ?").get(sessionId);
|
|
167257
|
+
const boundary = row?.boundary;
|
|
167258
|
+
return {
|
|
167259
|
+
hasCachedM0: row?.m0 != null,
|
|
167260
|
+
boundary: boundary && boundary.length > 0 ? boundary : null
|
|
167261
|
+
};
|
|
167262
|
+
}
|
|
166979
167263
|
function renderCompartmentInjection(sessionId, messages, prepared) {
|
|
166980
167264
|
const historyBlock = `<session-history>
|
|
166981
167265
|
${prepared.block}
|
|
@@ -167019,6 +167303,10 @@ function findFirstTextPart(parts) {
|
|
|
167019
167303
|
function isDroppedPlaceholder(text) {
|
|
167020
167304
|
return /^\[dropped §\d+§\]$/.test(text.trim());
|
|
167021
167305
|
}
|
|
167306
|
+
function lastCompartmentBoundaryId(compartments) {
|
|
167307
|
+
const last = compartments.at(-1);
|
|
167308
|
+
return last?.endMessageId && last.endMessageId.length > 0 ? last.endMessageId : null;
|
|
167309
|
+
}
|
|
167022
167310
|
function cachedStatement(cache, db, sql) {
|
|
167023
167311
|
let stmt = cache.get(db);
|
|
167024
167312
|
if (!stmt) {
|
|
@@ -167037,12 +167325,6 @@ function getMaxCompartmentSeq(db, sessionId) {
|
|
|
167037
167325
|
const row = cachedStatement(maxCompartmentSeqStatements, db, "SELECT COALESCE(MAX(sequence), -1) AS s FROM compartments WHERE session_id = ?").get(sessionId);
|
|
167038
167326
|
return numberFromRow(row, "s");
|
|
167039
167327
|
}
|
|
167040
|
-
function normalizeCachedMaxCompartmentSeq(db, sessionId, stored) {
|
|
167041
|
-
if (stored === 0 && getMaxCompartmentSeq(db, sessionId) === EMPTY_MAX_COMPARTMENT_SEQ) {
|
|
167042
|
-
return EMPTY_MAX_COMPARTMENT_SEQ;
|
|
167043
|
-
}
|
|
167044
|
-
return stored;
|
|
167045
|
-
}
|
|
167046
167328
|
function getMaxMemoryId(db, projectPath) {
|
|
167047
167329
|
if (!projectPath)
|
|
167048
167330
|
return 0;
|
|
@@ -167066,6 +167348,7 @@ function getGlobalUserProfileVersion(db) {
|
|
|
167066
167348
|
}
|
|
167067
167349
|
function readCurrentM0SnapshotMarkers(args) {
|
|
167068
167350
|
const projectDirectory = args.projectDirectory ?? args.projectPath ?? "";
|
|
167351
|
+
const hard = args.hardSignals ?? EMPTY_HARD_SIGNALS;
|
|
167069
167352
|
return {
|
|
167070
167353
|
projectMemoryEpoch: getProjectMemoryEpoch(args.db, args.projectPath),
|
|
167071
167354
|
projectUserProfileVersion: getGlobalUserProfileVersion(args.db),
|
|
@@ -167076,7 +167359,10 @@ function readCurrentM0SnapshotMarkers(args) {
|
|
|
167076
167359
|
projectDocsHash: projectDirectory ? computeProjectDocsHash(projectDirectory) : "",
|
|
167077
167360
|
materializedAt: Date.now(),
|
|
167078
167361
|
sessionFactsVersion: getSessionFactsVersion(args.db, args.sessionId),
|
|
167079
|
-
upgradeState: getUpgradeState(args.db, args.sessionId)
|
|
167362
|
+
upgradeState: getUpgradeState(args.db, args.sessionId),
|
|
167363
|
+
systemHash: hard.systemHash,
|
|
167364
|
+
toolSetHash: hard.toolSetHash,
|
|
167365
|
+
modelKey: hard.modelKey
|
|
167080
167366
|
};
|
|
167081
167367
|
}
|
|
167082
167368
|
function snapshotMarkersFromCachedM0(state) {
|
|
@@ -167106,7 +167392,10 @@ function snapshotMarkersFromCachedM0(state) {
|
|
|
167106
167392
|
projectDocsHash: state.cachedM0ProjectDocsHash ?? "",
|
|
167107
167393
|
materializedAt: state.cachedM0MaterializedAt ?? 0,
|
|
167108
167394
|
sessionFactsVersion: state.cachedM0SessionFactsVersion,
|
|
167109
|
-
upgradeState: state.cachedM0UpgradeState
|
|
167395
|
+
upgradeState: state.cachedM0UpgradeState,
|
|
167396
|
+
systemHash: state.cachedM0SystemHash ?? "",
|
|
167397
|
+
toolSetHash: state.cachedM0ToolSetHash ?? "",
|
|
167398
|
+
modelKey: state.cachedM0ModelKey ?? ""
|
|
167110
167399
|
};
|
|
167111
167400
|
}
|
|
167112
167401
|
function mustMaterialize(args) {
|
|
@@ -167114,16 +167403,22 @@ function mustMaterialize(args) {
|
|
|
167114
167403
|
return { value: true, reason: "first_render" };
|
|
167115
167404
|
if (!args.state.cachedM1Bytes)
|
|
167116
167405
|
return { value: true, reason: "cached_m1_missing" };
|
|
167406
|
+
const hard = args.hardSignals ?? EMPTY_HARD_SIGNALS;
|
|
167117
167407
|
const current = readCurrentM0SnapshotMarkers(args);
|
|
167118
|
-
if (args.state.
|
|
167119
|
-
return { value: true, reason: "
|
|
167408
|
+
if (hard.modelKey !== "" && hard.modelKey !== (args.state.cachedM0ModelKey ?? "")) {
|
|
167409
|
+
return { value: true, reason: "model_change" };
|
|
167410
|
+
}
|
|
167411
|
+
if (hard.systemHash !== "" && hard.systemHash !== (args.state.cachedM0SystemHash ?? "")) {
|
|
167412
|
+
return { value: true, reason: "system_hash" };
|
|
167413
|
+
}
|
|
167414
|
+
if (hard.toolSetHash !== "" && hard.toolSetHash !== (args.state.cachedM0ToolSetHash ?? "")) {
|
|
167415
|
+
return { value: true, reason: "tool_set_hash" };
|
|
167120
167416
|
}
|
|
167121
|
-
if (args.state.
|
|
167122
|
-
return { value: true, reason: "
|
|
167417
|
+
if (hard.cacheExpired && hard.lastResponseTime > 0 && hard.lastResponseTime > (args.state.cachedM0MaterializedAt ?? 0)) {
|
|
167418
|
+
return { value: true, reason: "ttl_idle" };
|
|
167123
167419
|
}
|
|
167124
|
-
|
|
167125
|
-
|
|
167126
|
-
return { value: true, reason: "max_compartment_seq" };
|
|
167420
|
+
if (args.state.cachedM0ProjectMemoryEpoch !== current.projectMemoryEpoch) {
|
|
167421
|
+
return { value: true, reason: "project_memory_epoch" };
|
|
167127
167422
|
}
|
|
167128
167423
|
if (args.state.cachedM0MaxMutationId !== current.maxMutationId) {
|
|
167129
167424
|
return { value: true, reason: "max_mutation_id" };
|
|
@@ -167312,6 +167607,9 @@ function applyMarkersToState(state, m0Bytes, markers, m1Bytes) {
|
|
|
167312
167607
|
state.cachedM0MaterializedAt = markers.materializedAt;
|
|
167313
167608
|
state.cachedM0SessionFactsVersion = markers.sessionFactsVersion;
|
|
167314
167609
|
state.cachedM0UpgradeState = markers.upgradeState;
|
|
167610
|
+
state.cachedM0SystemHash = markers.systemHash;
|
|
167611
|
+
state.cachedM0ToolSetHash = markers.toolSetHash;
|
|
167612
|
+
state.cachedM0ModelKey = markers.modelKey;
|
|
167315
167613
|
state.snapshotMarkers = markers;
|
|
167316
167614
|
}
|
|
167317
167615
|
function historySliceTokens(m0Text) {
|
|
@@ -167336,7 +167634,8 @@ function materializeM0(options) {
|
|
|
167336
167634
|
db: options.db,
|
|
167337
167635
|
sessionId: options.sessionId,
|
|
167338
167636
|
projectPath,
|
|
167339
|
-
projectDirectory
|
|
167637
|
+
projectDirectory,
|
|
167638
|
+
hardSignals: options.hardSignals
|
|
167340
167639
|
});
|
|
167341
167640
|
docs = projectDirectory ? readProjectDocsCanonical(projectDirectory) : { renderedBlock: "", canonicalHash: "" };
|
|
167342
167641
|
snapshotMarkers.projectDocsHash = docs.canonicalHash;
|
|
@@ -167402,7 +167701,10 @@ function materializeM0(options) {
|
|
|
167402
167701
|
projectDocsHash: phase3ProjectDocsHash,
|
|
167403
167702
|
materializedAt: Date.now(),
|
|
167404
167703
|
sessionFactsVersion: getSessionFactsVersion(options.db, options.sessionId),
|
|
167405
|
-
upgradeState: getUpgradeState(options.db, options.sessionId)
|
|
167704
|
+
upgradeState: getUpgradeState(options.db, options.sessionId),
|
|
167705
|
+
systemHash: snapshotMarkers.systemHash,
|
|
167706
|
+
toolSetHash: snapshotMarkers.toolSetHash,
|
|
167707
|
+
modelKey: snapshotMarkers.modelKey
|
|
167406
167708
|
};
|
|
167407
167709
|
const stale = current.projectMemoryEpoch !== snapshotMarkers.projectMemoryEpoch || current.projectUserProfileVersion !== snapshotMarkers.projectUserProfileVersion || current.maxCompartmentSeq !== snapshotMarkers.maxCompartmentSeq || current.maxMutationId !== snapshotMarkers.maxMutationId || current.maxMemoryMutationId !== snapshotMarkers.maxMemoryMutationId || current.projectDocsHash !== snapshotMarkers.projectDocsHash || current.sessionFactsVersion !== snapshotMarkers.sessionFactsVersion || current.upgradeState !== snapshotMarkers.upgradeState;
|
|
167408
167710
|
if (stale) {
|
|
@@ -167424,9 +167726,14 @@ function materializeM0(options) {
|
|
|
167424
167726
|
projectDocsHash: snapshotMarkers.projectDocsHash,
|
|
167425
167727
|
materializedAt: snapshotMarkers.materializedAt,
|
|
167426
167728
|
sessionFactsVersion: snapshotMarkers.sessionFactsVersion,
|
|
167427
|
-
upgradeState: snapshotMarkers.upgradeState
|
|
167729
|
+
upgradeState: snapshotMarkers.upgradeState,
|
|
167730
|
+
systemHash: snapshotMarkers.systemHash,
|
|
167731
|
+
toolSetHash: snapshotMarkers.toolSetHash,
|
|
167732
|
+
modelKey: snapshotMarkers.modelKey
|
|
167428
167733
|
});
|
|
167429
167734
|
options.db.prepare("UPDATE session_meta SET memory_block_count = ?, memory_block_ids = ? WHERE session_id = ?").run(renderedMemoryIds.length, JSON.stringify(renderedMemoryIds), options.sessionId);
|
|
167735
|
+
const baselineEndMessageId = lastCompartmentBoundaryId(compartments);
|
|
167736
|
+
options.db.prepare("UPDATE session_meta SET cached_m0_last_baseline_end_message_id = ? WHERE session_id = ?").run(baselineEndMessageId, options.sessionId);
|
|
167430
167737
|
options.db.exec("COMMIT");
|
|
167431
167738
|
} catch (error51) {
|
|
167432
167739
|
try {
|
|
@@ -167583,6 +167890,9 @@ function readCachedM0M1Row(db, sessionId) {
|
|
|
167583
167890
|
cached_m0_materialized_at,
|
|
167584
167891
|
cached_m0_session_facts_version,
|
|
167585
167892
|
cached_m0_upgrade_state,
|
|
167893
|
+
cached_m0_system_hash,
|
|
167894
|
+
cached_m0_tool_set_hash,
|
|
167895
|
+
cached_m0_model_key,
|
|
167586
167896
|
memory_block_ids
|
|
167587
167897
|
FROM session_meta
|
|
167588
167898
|
WHERE session_id = ?`).get(sessionId);
|
|
@@ -167614,11 +167924,14 @@ function markersFromCachedRow(row) {
|
|
|
167614
167924
|
projectDocsHash: row.cached_m0_project_docs_hash ?? "",
|
|
167615
167925
|
materializedAt: row.cached_m0_materialized_at ?? 0,
|
|
167616
167926
|
sessionFactsVersion: row.cached_m0_session_facts_version,
|
|
167617
|
-
upgradeState: row.cached_m0_upgrade_state
|
|
167927
|
+
upgradeState: row.cached_m0_upgrade_state,
|
|
167928
|
+
systemHash: row.cached_m0_system_hash ?? "",
|
|
167929
|
+
toolSetHash: row.cached_m0_tool_set_hash ?? "",
|
|
167930
|
+
modelKey: row.cached_m0_model_key ?? ""
|
|
167618
167931
|
};
|
|
167619
167932
|
}
|
|
167620
167933
|
function cachedRowMatchesState(row, state) {
|
|
167621
|
-
return bufferEqualsNullable(row.cached_m0_bytes, state.cachedM0Bytes) && row.cached_m0_project_memory_epoch === state.cachedM0ProjectMemoryEpoch && row.cached_m0_project_user_profile_version === state.cachedM0ProjectUserProfileVersion && row.cached_m0_max_compartment_seq === state.cachedM0MaxCompartmentSeq && row.cached_m0_max_memory_id === state.cachedM0MaxMemoryId && row.cached_m0_max_mutation_id === state.cachedM0MaxMutationId && row.cached_m0_max_memory_mutation_id === state.cachedM0MaxMemoryMutationId && (row.cached_m0_project_docs_hash ?? "") === (state.cachedM0ProjectDocsHash ?? "") && row.cached_m0_materialized_at === state.cachedM0MaterializedAt && row.cached_m0_session_facts_version === state.cachedM0SessionFactsVersion && (row.cached_m0_upgrade_state ?? null) === (state.cachedM0UpgradeState ?? null);
|
|
167934
|
+
return bufferEqualsNullable(row.cached_m0_bytes, state.cachedM0Bytes) && row.cached_m0_project_memory_epoch === state.cachedM0ProjectMemoryEpoch && row.cached_m0_project_user_profile_version === state.cachedM0ProjectUserProfileVersion && row.cached_m0_max_compartment_seq === state.cachedM0MaxCompartmentSeq && row.cached_m0_max_memory_id === state.cachedM0MaxMemoryId && row.cached_m0_max_mutation_id === state.cachedM0MaxMutationId && row.cached_m0_max_memory_mutation_id === state.cachedM0MaxMemoryMutationId && (row.cached_m0_project_docs_hash ?? "") === (state.cachedM0ProjectDocsHash ?? "") && row.cached_m0_materialized_at === state.cachedM0MaterializedAt && row.cached_m0_session_facts_version === state.cachedM0SessionFactsVersion && (row.cached_m0_upgrade_state ?? null) === (state.cachedM0UpgradeState ?? null) && (row.cached_m0_system_hash ?? "") === (state.cachedM0SystemHash ?? "") && (row.cached_m0_tool_set_hash ?? "") === (state.cachedM0ToolSetHash ?? "") && (row.cached_m0_model_key ?? "") === (state.cachedM0ModelKey ?? "");
|
|
167622
167935
|
}
|
|
167623
167936
|
function applyCachedRowToState(state, row) {
|
|
167624
167937
|
const markers = markersFromCachedRow(row);
|
|
@@ -167637,6 +167950,9 @@ function applyCachedRowToState(state, row) {
|
|
|
167637
167950
|
state.cachedM0MaterializedAt = markers.materializedAt;
|
|
167638
167951
|
state.cachedM0SessionFactsVersion = markers.sessionFactsVersion;
|
|
167639
167952
|
state.cachedM0UpgradeState = markers.upgradeState;
|
|
167953
|
+
state.cachedM0SystemHash = markers.systemHash;
|
|
167954
|
+
state.cachedM0ToolSetHash = markers.toolSetHash;
|
|
167955
|
+
state.cachedM0ModelKey = markers.modelKey;
|
|
167640
167956
|
state.snapshotMarkers = markers;
|
|
167641
167957
|
}
|
|
167642
167958
|
function replayCachedM1(state) {
|
|
@@ -167664,7 +167980,8 @@ function softRefreshCachedM1(options) {
|
|
|
167664
167980
|
const renderedMemoryIds = parseMemoryBlockIds(row.memory_block_ids);
|
|
167665
167981
|
const rendered = renderM1WithMetadata({ ...options, preRenderedKeyFilesBlock }, markers, renderedMemoryIds);
|
|
167666
167982
|
const m1Bytes = Buffer4.from(rendered.text, "utf8");
|
|
167667
|
-
|
|
167983
|
+
const baselineEndMessageId = getLastCompartmentEndMessageId(options.db, options.sessionId);
|
|
167984
|
+
options.db.prepare("UPDATE session_meta SET cached_m1_bytes = ?, cached_m0_last_baseline_end_message_id = ? WHERE session_id = ?").run(m1Bytes, baselineEndMessageId, options.sessionId);
|
|
167668
167985
|
options.db.exec("COMMIT");
|
|
167669
167986
|
options.state.cachedM1Bytes = m1Bytes;
|
|
167670
167987
|
options.state.snapshotMarkers = markers;
|
|
@@ -167753,7 +168070,8 @@ function injectM0M1(options) {
|
|
|
167753
168070
|
sessionId: options.sessionId,
|
|
167754
168071
|
state: options.state,
|
|
167755
168072
|
projectPath: options.projectPath,
|
|
167756
|
-
projectDirectory: options.projectDirectory
|
|
168073
|
+
projectDirectory: options.projectDirectory,
|
|
168074
|
+
hardSignals: options.hardSignals
|
|
167757
168075
|
});
|
|
167758
168076
|
let rematerialized = false;
|
|
167759
168077
|
let contentionExhausted = false;
|
|
@@ -167810,8 +168128,15 @@ function injectM0M1(options) {
|
|
|
167810
168128
|
} else {
|
|
167811
168129
|
m1Text = replayCachedM1(options.state);
|
|
167812
168130
|
}
|
|
167813
|
-
const
|
|
167814
|
-
|
|
168131
|
+
const M0_DRIFT_RATIO_FLOOR_TOKENS = 500;
|
|
168132
|
+
const M1_DRIFT_RATIO = 0.15;
|
|
168133
|
+
const M1_ABSOLUTE_CAP_RATIO = 0.2;
|
|
168134
|
+
const m1AbsoluteBudget = (options.historyBudgetTokens ?? DEFAULT_HISTORY_BUDGET_TOKENS) * M1_ABSOLUTE_CAP_RATIO;
|
|
168135
|
+
const m1HasContent = m1Text !== M1_EMPTY_PLACEHOLDER;
|
|
168136
|
+
const m1Tokens = m1HasContent ? estimateTokens(m1Text) : 0;
|
|
168137
|
+
const m0Tokens = estimateTokens(m0Text);
|
|
168138
|
+
const m1OverAbsoluteCap = m1HasContent && m1Tokens > m1AbsoluteBudget;
|
|
168139
|
+
if (!rematerialized && !contentionExhausted && m1Recomputed && options.isCacheBustingPass && (memoryUpdateCount > 40 || m1OverAbsoluteCap || m1HasContent && m0Tokens >= M0_DRIFT_RATIO_FLOOR_TOKENS && m1Tokens > m0Tokens * M1_DRIFT_RATIO)) {
|
|
167815
168140
|
try {
|
|
167816
168141
|
const refolded = materializeWithRetry(options);
|
|
167817
168142
|
applyMarkersToState(options.state, refolded.m0Bytes, refolded.snapshotMarkers, refolded.m1Bytes);
|
|
@@ -167835,7 +168160,7 @@ function injectM0M1(options) {
|
|
|
167835
168160
|
m1Text
|
|
167836
168161
|
};
|
|
167837
168162
|
}
|
|
167838
|
-
var INJECTION_CACHE_MAX = 100, injectionCache, CONSTRAINT_KEYWORDS, MaterializeContentionError, RenderM1InvalidMarkersError, DEFAULT_HISTORY_BUDGET_TOKENS = 60000, DEFAULT_MEMORY_BUDGET_TOKENS = 8000, MEMORY_BLOCK_WRAPPER_TOKENS = 6, DEFAULT_USER_PROFILE_BUDGET_TOKENS = 4000, M0_EMPTY_BODY = "<session-history></session-history>", M1_EMPTY_PLACEHOLDER = "<session-history-since>(no new content since last materialization)</session-history-since>", maxCompartmentSeqStatements, maxMemoryIdStatements, legacyCompartmentCountStatements, m0CompartmentStatements, newCompartmentStatements
|
|
168163
|
+
var INJECTION_CACHE_MAX = 100, injectionCache, CONSTRAINT_KEYWORDS, EMPTY_HARD_SIGNALS, MaterializeContentionError, RenderM1InvalidMarkersError, DEFAULT_HISTORY_BUDGET_TOKENS = 60000, DEFAULT_MEMORY_BUDGET_TOKENS = 8000, MEMORY_BLOCK_WRAPPER_TOKENS = 6, DEFAULT_USER_PROFILE_BUDGET_TOKENS = 4000, M0_EMPTY_BODY = "<session-history></session-history>", M1_EMPTY_PLACEHOLDER = "<session-history-since>(no new content since last materialization)</session-history-since>", maxCompartmentSeqStatements, maxMemoryIdStatements, legacyCompartmentCountStatements, m0CompartmentStatements, newCompartmentStatements;
|
|
167839
168164
|
var init_inject_compartments = __esm(async () => {
|
|
167840
168165
|
init_compartment_storage();
|
|
167841
168166
|
init_constants();
|
|
@@ -167851,6 +168176,13 @@ var init_inject_compartments = __esm(async () => {
|
|
|
167851
168176
|
]);
|
|
167852
168177
|
injectionCache = new BoundedSessionMap(INJECTION_CACHE_MAX);
|
|
167853
168178
|
CONSTRAINT_KEYWORDS = /\b(must|never|always|cannot|should not|must not)\b/i;
|
|
168179
|
+
EMPTY_HARD_SIGNALS = {
|
|
168180
|
+
systemHash: "",
|
|
168181
|
+
toolSetHash: "",
|
|
168182
|
+
modelKey: "",
|
|
168183
|
+
cacheExpired: false,
|
|
168184
|
+
lastResponseTime: 0
|
|
168185
|
+
};
|
|
167854
168186
|
MaterializeContentionError = class MaterializeContentionError extends Error {
|
|
167855
168187
|
retries;
|
|
167856
168188
|
reason;
|
|
@@ -169715,7 +170047,7 @@ ${body}
|
|
|
169715
170047
|
function renderSessionRefCompartment(c) {
|
|
169716
170048
|
const importance = c.importance ?? 50;
|
|
169717
170049
|
const attrs = `start="${c.startMessage}" end="${c.endMessage}" title="${escapeXmlAttr(c.title)}"` + (c.episodeType ? ` episode_type="${escapeXmlAttr(c.episodeType)}"` : "") + ` importance="${importance}"`;
|
|
169718
|
-
if (c.p1
|
|
170050
|
+
if (typeof c.p1 === "string" && c.p1.length > 0) {
|
|
169719
170051
|
const p4 = c.p4 && c.p4.length > 0 ? `<p4>
|
|
169720
170052
|
${escapeXmlContent(c.p4)}
|
|
169721
170053
|
</p4>` : "<p4/>";
|
|
@@ -169966,13 +170298,9 @@ async function runCompartmentAgent(deps) {
|
|
|
169966
170298
|
const existingValidationError = validateStoredCompartments(priorCompartments);
|
|
169967
170299
|
if (existingValidationError) {
|
|
169968
170300
|
sessionLog(sessionId, `historian failure: source=existing-validation reason="${existingValidationError}"`);
|
|
169969
|
-
incrementHistorianFailure(db, sessionId, existingValidationError);
|
|
170301
|
+
const failCount = incrementHistorianFailure(db, sessionId, existingValidationError);
|
|
169970
170302
|
telemetry.failureReason = `existing-validation: ${existingValidationError}`;
|
|
169971
|
-
await notifyHistorianIssue(
|
|
169972
|
-
|
|
169973
|
-
Historian skipped this session because existing stored compartments are invalid: ${existingValidationError}
|
|
169974
|
-
|
|
169975
|
-
No new compartments or facts were written. Rebuild or clear the broken compartments before continuing.`);
|
|
170303
|
+
await notifyHistorianIssue(buildHistorianFailureNotice(failCount, existingValidationError));
|
|
169976
170304
|
return;
|
|
169977
170305
|
}
|
|
169978
170306
|
const offset = priorCompartments.length > 0 ? priorCompartments[priorCompartments.length - 1].endMessage + 1 : 1;
|
|
@@ -169998,12 +170326,8 @@ No new compartments or facts were written. Rebuild or clear the broken compartme
|
|
|
169998
170326
|
if (chunkCoverageError) {
|
|
169999
170327
|
telemetry.failureReason = `chunk-coverage: ${chunkCoverageError}`;
|
|
170000
170328
|
sessionLog(sessionId, `historian failure: source=chunk-coverage reason="${chunkCoverageError}" chunkRange=${chunk.startIndex}-${chunk.endIndex}`);
|
|
170001
|
-
incrementHistorianFailure(db, sessionId, chunkCoverageError);
|
|
170002
|
-
await notifyHistorianIssue(
|
|
170003
|
-
|
|
170004
|
-
Historian skipped this session because the raw chunk could not be represented safely: ${chunkCoverageError}
|
|
170005
|
-
|
|
170006
|
-
No new compartments or facts were written.`);
|
|
170329
|
+
const failCount = incrementHistorianFailure(db, sessionId, chunkCoverageError);
|
|
170330
|
+
await notifyHistorianIssue(buildHistorianFailureNotice(failCount, chunkCoverageError));
|
|
170007
170331
|
return;
|
|
170008
170332
|
}
|
|
170009
170333
|
const projectPath = resolveProjectIdentity(directory ?? process.cwd());
|
|
@@ -170044,13 +170368,9 @@ ${chunk.text}`,
|
|
|
170044
170368
|
});
|
|
170045
170369
|
if (!validatedPass.ok) {
|
|
170046
170370
|
sessionLog(sessionId, `historian failure: source=validation reason="${validatedPass.error}" chunkRange=${chunk.startIndex}-${chunk.endIndex} fallbackModel=${deps.fallbackModelId ?? "<none>"} twoPass=${deps.historianTwoPass ? "true" : "false"}`);
|
|
170047
|
-
incrementHistorianFailure(db, sessionId, validatedPass.error);
|
|
170371
|
+
const failCount = incrementHistorianFailure(db, sessionId, validatedPass.error);
|
|
170048
170372
|
telemetry.failureReason = `validation: ${validatedPass.error}`;
|
|
170049
|
-
await notifyHistorianIssue(
|
|
170050
|
-
|
|
170051
|
-
${validatedPass.error}
|
|
170052
|
-
|
|
170053
|
-
No new compartments or facts were written. Check the historian model/output and try again.`);
|
|
170373
|
+
await notifyHistorianIssue(buildHistorianFailureNotice(failCount, validatedPass.error));
|
|
170054
170374
|
return;
|
|
170055
170375
|
}
|
|
170056
170376
|
const emittedCompartments = validatedPass.compartments;
|
|
@@ -170071,12 +170391,8 @@ No new compartments or facts were written. Check the historian model/output and
|
|
|
170071
170391
|
if (lastNewEnd + 1 <= offset) {
|
|
170072
170392
|
telemetry.failureReason = `no forward progress beyond raw message ${offset - 1}`;
|
|
170073
170393
|
sessionLog(sessionId, `historian failure: source=no-progress reason="historian returned compartments that did not advance past raw message ${offset - 1}" newCompartmentCount=${newCompartments.length} lastNewEnd=${lastNewEnd} priorEnd=${offset - 1}`);
|
|
170074
|
-
incrementHistorianFailure(db, sessionId, `no forward progress beyond raw message ${offset - 1}`);
|
|
170075
|
-
await notifyHistorianIssue(
|
|
170076
|
-
|
|
170077
|
-
Historian returned compartments that made no forward progress beyond raw message ${offset - 1}.
|
|
170078
|
-
|
|
170079
|
-
No new compartments or facts were written. Check the historian model/output and try again.`);
|
|
170394
|
+
const failCount = incrementHistorianFailure(db, sessionId, `no forward progress beyond raw message ${offset - 1}`);
|
|
170395
|
+
await notifyHistorianIssue(buildHistorianFailureNotice(failCount, `historian made no forward progress beyond raw message ${offset - 1}`));
|
|
170080
170396
|
return;
|
|
170081
170397
|
}
|
|
170082
170398
|
const deferMarkerApplication = deps.preserveInjectionCacheUntilConsumed === true;
|
|
@@ -170117,7 +170433,6 @@ No new compartments or facts were written. Check the historian model/output and
|
|
|
170117
170433
|
if (deps.preserveInjectionCacheUntilConsumed !== true) {
|
|
170118
170434
|
clearInjectionCache(sessionId);
|
|
170119
170435
|
}
|
|
170120
|
-
deps.onCompartmentStatePublished?.(sessionId);
|
|
170121
170436
|
const promotionDirectory = sessionDirectory || deps.directory;
|
|
170122
170437
|
const discardedLast = persistedCompartments.length < emittedCompartments.length;
|
|
170123
170438
|
const embeddingActive = !!promotionDirectory && deps.memoryEnabled !== false;
|
|
@@ -170144,6 +170459,7 @@ No new compartments or facts were written. Check the historian model/output and
|
|
|
170144
170459
|
embedAndStoreCompartments(db, sessionId, projectIdentity, toEmbed);
|
|
170145
170460
|
}
|
|
170146
170461
|
queueDropsForCompartmentalizedMessages(db, sessionId, lastCompartmentEnd);
|
|
170462
|
+
deps.onCompartmentStatePublished?.(sessionId);
|
|
170147
170463
|
if (deferMarkerApplication) {
|
|
170148
170464
|
deps.onDeferredMarkerPending?.(sessionId);
|
|
170149
170465
|
} else {
|
|
@@ -170188,12 +170504,8 @@ No new compartments or facts were written. Check the historian model/output and
|
|
|
170188
170504
|
telemetry.failureReason = `exception: ${desc.brief}`;
|
|
170189
170505
|
sessionLog(sessionId, `historian failure: source=exception ${desc.brief}${desc.stackHead ? ` stackHead="${desc.stackHead}"` : ""}`);
|
|
170190
170506
|
if (!issueNotified) {
|
|
170191
|
-
incrementHistorianFailure(db, sessionId, desc.brief);
|
|
170192
|
-
await notifyHistorianIssue(
|
|
170193
|
-
|
|
170194
|
-
Historian failed unexpectedly: ${desc.brief}
|
|
170195
|
-
|
|
170196
|
-
No new compartments or facts were written. Check the historian model/output and try again.`);
|
|
170507
|
+
const failCount = incrementHistorianFailure(db, sessionId, desc.brief);
|
|
170508
|
+
await notifyHistorianIssue(buildHistorianFailureNotice(failCount, desc.brief));
|
|
170197
170509
|
}
|
|
170198
170510
|
} finally {
|
|
170199
170511
|
if (!completedSuccessfully) {
|
|
@@ -170357,7 +170669,6 @@ Found ${existingStaging.compartments.length} staged compartment(s) from ${existi
|
|
|
170357
170669
|
if (deps.preserveInjectionCacheUntilConsumed !== true) {
|
|
170358
170670
|
clearInjectionCache(sessionId);
|
|
170359
170671
|
}
|
|
170360
|
-
deps.onCompartmentStatePublished?.(sessionId);
|
|
170361
170672
|
promoted2.facts;
|
|
170362
170673
|
if (deps.memoryEnabled !== false) {
|
|
170363
170674
|
const projectIdentity = resolveProjectIdentity(sessionDirectory);
|
|
@@ -170370,11 +170681,14 @@ Found ${existingStaging.compartments.length} staged compartment(s) from ${existi
|
|
|
170370
170681
|
if (lastCompartmentEnd2 > 0) {
|
|
170371
170682
|
queueDropsForCompartmentalizedMessages(db, sessionId, lastCompartmentEnd2);
|
|
170372
170683
|
}
|
|
170684
|
+
deps.onCompartmentStatePublished?.(sessionId);
|
|
170373
170685
|
if (lastCompartmentEnd2 > 0) {
|
|
170374
|
-
updateCompactionMarkerAfterPublication(db, sessionId, lastCompartmentEnd2, deps.directory);
|
|
170375
|
-
|
|
170376
|
-
|
|
170377
|
-
|
|
170686
|
+
const markerUpdated = updateCompactionMarkerAfterPublication(db, sessionId, lastCompartmentEnd2, deps.directory);
|
|
170687
|
+
if (markerUpdated) {
|
|
170688
|
+
const stalePending = getPendingCompactionMarkerState(db, sessionId);
|
|
170689
|
+
if (stalePending) {
|
|
170690
|
+
clearPendingCompactionMarkerStateIf(db, sessionId, stalePending);
|
|
170691
|
+
}
|
|
170378
170692
|
}
|
|
170379
170693
|
}
|
|
170380
170694
|
return [
|
|
@@ -170563,13 +170877,13 @@ Another process acquired the compartment-state lease before recomp could publish
|
|
|
170563
170877
|
if (deps.preserveInjectionCacheUntilConsumed !== true) {
|
|
170564
170878
|
clearInjectionCache(sessionId);
|
|
170565
170879
|
}
|
|
170566
|
-
deps.onCompartmentStatePublished?.(sessionId);
|
|
170567
170880
|
const finalCompartments = promoted?.compartments ?? candidateCompartments;
|
|
170568
170881
|
const finalFacts = promoted?.facts ?? candidateFacts;
|
|
170569
170882
|
const lastCompartmentEnd = finalCompartments[finalCompartments.length - 1]?.endMessage ?? 0;
|
|
170570
170883
|
if (lastCompartmentEnd > 0) {
|
|
170571
170884
|
queueDropsForCompartmentalizedMessages(db, sessionId, lastCompartmentEnd);
|
|
170572
170885
|
}
|
|
170886
|
+
deps.onCompartmentStatePublished?.(sessionId);
|
|
170573
170887
|
if (deps.memoryEnabled !== false) {
|
|
170574
170888
|
const projectIdentity = resolveProjectIdentity(sessionDirectory);
|
|
170575
170889
|
await deps.ensureProjectRegistered?.(sessionDirectory, db);
|
|
@@ -170578,10 +170892,12 @@ Another process acquired the compartment-state lease before recomp could publish
|
|
|
170578
170892
|
embedAndStoreCompartments(db, sessionId, projectIdentity, toEmbed);
|
|
170579
170893
|
}
|
|
170580
170894
|
if (lastCompartmentEnd > 0) {
|
|
170581
|
-
updateCompactionMarkerAfterPublication(db, sessionId, lastCompartmentEnd, deps.directory);
|
|
170582
|
-
|
|
170583
|
-
|
|
170584
|
-
|
|
170895
|
+
const markerUpdated = updateCompactionMarkerAfterPublication(db, sessionId, lastCompartmentEnd, deps.directory);
|
|
170896
|
+
if (markerUpdated) {
|
|
170897
|
+
const stalePending = getPendingCompactionMarkerState(db, sessionId);
|
|
170898
|
+
if (stalePending) {
|
|
170899
|
+
clearPendingCompactionMarkerStateIf(db, sessionId, stalePending);
|
|
170900
|
+
}
|
|
170585
170901
|
}
|
|
170586
170902
|
}
|
|
170587
170903
|
return [
|
|
@@ -170738,7 +171054,7 @@ Could not acquire the compartment-state lease for this session.`;
|
|
|
170738
171054
|
log(`[magic-context] partial recomp merged validation failed: ${mergedError}`);
|
|
170739
171055
|
return null;
|
|
170740
171056
|
}
|
|
170741
|
-
saveRecompStagingPass(db, sessionId, passCount + 1, merged,
|
|
171057
|
+
saveRecompStagingPass(db, sessionId, passCount + 1, merged, stagedFacts);
|
|
170742
171058
|
const promoted = promoteRecompStagingWithM0Mutation(db, sessionId, leaseHolderId);
|
|
170743
171059
|
if (!promoted) {
|
|
170744
171060
|
log("[magic-context] partial recomp promote returned null");
|
|
@@ -170758,10 +171074,12 @@ Could not acquire the compartment-state lease for this session.`;
|
|
|
170758
171074
|
}
|
|
170759
171075
|
const lastEnd = merged[merged.length - 1]?.endMessage ?? snapEnd;
|
|
170760
171076
|
if (lastEnd > 0) {
|
|
170761
|
-
updateCompactionMarkerAfterPublication(db, sessionId, lastEnd, deps.directory);
|
|
170762
|
-
|
|
170763
|
-
|
|
170764
|
-
|
|
171077
|
+
const markerUpdated = updateCompactionMarkerAfterPublication(db, sessionId, lastEnd, deps.directory);
|
|
171078
|
+
if (markerUpdated) {
|
|
171079
|
+
const stalePending = getPendingCompactionMarkerState(db, sessionId);
|
|
171080
|
+
if (stalePending) {
|
|
171081
|
+
clearPendingCompactionMarkerStateIf(db, sessionId, stalePending);
|
|
171082
|
+
}
|
|
170765
171083
|
}
|
|
170766
171084
|
}
|
|
170767
171085
|
return { compartmentCount: merged.length, lastEndMessage: lastEnd };
|
|
@@ -170803,10 +171121,7 @@ Snapped range ${snapStart}-${snapEnd} would cross into the protected tail (start
|
|
|
170803
171121
|
].join(`
|
|
170804
171122
|
`);
|
|
170805
171123
|
}
|
|
170806
|
-
const
|
|
170807
|
-
category: f.category,
|
|
170808
|
-
content: f.content
|
|
170809
|
-
}));
|
|
171124
|
+
const stagedFacts = [];
|
|
170810
171125
|
const parentSessionResponse = await client.session.get({ path: { id: sessionId } }).catch(() => null);
|
|
170811
171126
|
const parentSession = normalizeSDKResponse(parentSessionResponse, null, { preferResponseOnMissingData: true });
|
|
170812
171127
|
const sessionDirectory = parentSession?.directory ?? directory;
|
|
@@ -170823,7 +171138,7 @@ Snapped range ${snapStart}-${snapEnd} would cross into the protected tail (start
|
|
|
170823
171138
|
candidateCompartments = priorCompartments.map((c, idx) => compartmentToInput(c, idx));
|
|
170824
171139
|
passCount = 0;
|
|
170825
171140
|
offset = snapStart;
|
|
170826
|
-
saveRecompStagingPass(db, sessionId, 0, candidateCompartments,
|
|
171141
|
+
saveRecompStagingPass(db, sessionId, 0, candidateCompartments, stagedFacts);
|
|
170827
171142
|
setRecompPartialRange(db, sessionId, { start: snapStart, end: snapEnd });
|
|
170828
171143
|
}
|
|
170829
171144
|
let currentTokenBudget = historianChunkTokens;
|
|
@@ -170916,7 +171231,7 @@ Original state preserved (staging kept for retry).`;
|
|
|
170916
171231
|
passCount += 1;
|
|
170917
171232
|
currentTokenBudget = historianChunkTokens;
|
|
170918
171233
|
passAttempt = 1;
|
|
170919
|
-
saveRecompStagingPass(db, sessionId, passCount, candidateCompartments,
|
|
171234
|
+
saveRecompStagingPass(db, sessionId, passCount, candidateCompartments, stagedFacts);
|
|
170920
171235
|
const nextOffset = (validatedPass.compartments?.[validatedPass.compartments.length - 1]?.endMessage ?? chunk.endIndex) + 1;
|
|
170921
171236
|
if (nextOffset <= offset) {
|
|
170922
171237
|
return `## Magic Recomp — Failed
|
|
@@ -170937,7 +171252,6 @@ Partial recomp completed historian passes but the final compartment set failed v
|
|
|
170937
171252
|
...resumed ? ["Resumed from previous interrupted partial run."] : [],
|
|
170938
171253
|
`Rebuilt compartments covering messages ${snapStart}-${snapEnd} using ${passCount} historian pass${passCount === 1 ? "" : "es"}.`,
|
|
170939
171254
|
`Preserved ${priorCompartments.length} prior compartment(s) and ${tailCompartments.length} tail compartment(s) unchanged.`,
|
|
170940
|
-
`Facts unchanged (${currentFacts.length} entr${currentFacts.length === 1 ? "y" : "ies"}).`,
|
|
170941
171255
|
`Total compartments: ${finalResult.compartmentCount}.`
|
|
170942
171256
|
].join(`
|
|
170943
171257
|
`);
|
|
@@ -171256,6 +171570,10 @@ async function runMemoryMigration(deps) {
|
|
|
171256
171570
|
const cleanupChildSession = async (sid) => {
|
|
171257
171571
|
if (!sid)
|
|
171258
171572
|
return;
|
|
171573
|
+
if (shouldKeepSubagents()) {
|
|
171574
|
+
sessionLog(parentSessionId, `memory-migration: KEEPING child session ${sid} (keep_subagents)`);
|
|
171575
|
+
return;
|
|
171576
|
+
}
|
|
171259
171577
|
await client.session.delete({ path: { id: sid } }).catch((e) => {
|
|
171260
171578
|
sessionLog(parentSessionId, `memory-migration: child cleanup failed: ${String(e)}`);
|
|
171261
171579
|
});
|
|
@@ -171927,6 +172245,95 @@ function migrateLegacyExperimental(rawConfig, warnings) {
|
|
|
171927
172245
|
return patched;
|
|
171928
172246
|
}
|
|
171929
172247
|
|
|
172248
|
+
// src/config/project-security.ts
|
|
172249
|
+
var HIDDEN_AGENT_KEYS = ["historian", "dreamer", "sidekick"];
|
|
172250
|
+
var AGENT_ESCALATION_FIELDS = ["prompt", "permission", "tools", "system_prompt"];
|
|
172251
|
+
function isPlainObject(value) {
|
|
172252
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
172253
|
+
}
|
|
172254
|
+
function stripUnsafeProjectConfigFields(projectRaw) {
|
|
172255
|
+
const warnings = [];
|
|
172256
|
+
if ("auto_update" in projectRaw) {
|
|
172257
|
+
delete projectRaw.auto_update;
|
|
172258
|
+
warnings.push("Ignoring auto_update from project config (security: this setting only honors user-level config).");
|
|
172259
|
+
}
|
|
172260
|
+
for (const agentKey of HIDDEN_AGENT_KEYS) {
|
|
172261
|
+
const block = projectRaw[agentKey];
|
|
172262
|
+
if (!isPlainObject(block))
|
|
172263
|
+
continue;
|
|
172264
|
+
const removed = [];
|
|
172265
|
+
for (const field of AGENT_ESCALATION_FIELDS) {
|
|
172266
|
+
if (field in block) {
|
|
172267
|
+
delete block[field];
|
|
172268
|
+
removed.push(field);
|
|
172269
|
+
}
|
|
172270
|
+
}
|
|
172271
|
+
if (removed.length > 0) {
|
|
172272
|
+
warnings.push(`Ignoring ${agentKey}.${removed.join("/")} from project config ` + "(security: a repository cannot reprogram or re-permission hidden agents).");
|
|
172273
|
+
}
|
|
172274
|
+
}
|
|
172275
|
+
return warnings;
|
|
172276
|
+
}
|
|
172277
|
+
function normalizeEndpoint(value) {
|
|
172278
|
+
if (typeof value !== "string")
|
|
172279
|
+
return;
|
|
172280
|
+
const trimmed = value.trim().replace(/\/+$/, "");
|
|
172281
|
+
return trimmed.length > 0 ? trimmed.toLowerCase() : undefined;
|
|
172282
|
+
}
|
|
172283
|
+
function dropInheritedEmbeddingKeyOnRedirect(projectRaw, mergedRaw, userRaw) {
|
|
172284
|
+
const projectEmbedding = projectRaw.embedding;
|
|
172285
|
+
if (!isPlainObject(projectEmbedding))
|
|
172286
|
+
return [];
|
|
172287
|
+
const redirectsEndpoint = "endpoint" in projectEmbedding;
|
|
172288
|
+
if (!redirectsEndpoint)
|
|
172289
|
+
return [];
|
|
172290
|
+
const userEmbedding = userRaw?.embedding;
|
|
172291
|
+
if (isPlainObject(userEmbedding)) {
|
|
172292
|
+
const projectEndpoint = normalizeEndpoint(projectEmbedding.endpoint);
|
|
172293
|
+
const userEndpoint = normalizeEndpoint(userEmbedding.endpoint);
|
|
172294
|
+
if (projectEndpoint !== undefined && projectEndpoint === userEndpoint) {
|
|
172295
|
+
return [];
|
|
172296
|
+
}
|
|
172297
|
+
}
|
|
172298
|
+
const providesOwnKey = typeof projectEmbedding.api_key === "string" && projectEmbedding.api_key.length > 0;
|
|
172299
|
+
if (providesOwnKey)
|
|
172300
|
+
return [];
|
|
172301
|
+
const mergedEmbedding = mergedRaw.embedding;
|
|
172302
|
+
if (!isPlainObject(mergedEmbedding))
|
|
172303
|
+
return [];
|
|
172304
|
+
if (!("api_key" in mergedEmbedding))
|
|
172305
|
+
return [];
|
|
172306
|
+
delete mergedEmbedding.api_key;
|
|
172307
|
+
return [
|
|
172308
|
+
"Dropped inherited user embedding api_key because project config redirected " + "embedding.endpoint without supplying its own key (security: prevents key " + "exfiltration to a repository-chosen endpoint)."
|
|
172309
|
+
];
|
|
172310
|
+
}
|
|
172311
|
+
|
|
172312
|
+
// src/config/prune-config-leaf.ts
|
|
172313
|
+
function isPlainObject2(value) {
|
|
172314
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
172315
|
+
}
|
|
172316
|
+
function pruneNestedConfigLeaf(block, relativePath) {
|
|
172317
|
+
if (relativePath.length === 0)
|
|
172318
|
+
return null;
|
|
172319
|
+
const result = { ...block };
|
|
172320
|
+
let cursor = result;
|
|
172321
|
+
for (let i = 0;i < relativePath.length - 1; i++) {
|
|
172322
|
+
const seg = String(relativePath[i]);
|
|
172323
|
+
const child = cursor[seg];
|
|
172324
|
+
if (!isPlainObject2(child))
|
|
172325
|
+
return null;
|
|
172326
|
+
const clonedChild = { ...child };
|
|
172327
|
+
cursor[seg] = clonedChild;
|
|
172328
|
+
cursor = clonedChild;
|
|
172329
|
+
}
|
|
172330
|
+
const leaf = String(relativePath[relativePath.length - 1]);
|
|
172331
|
+
if (!(leaf in cursor))
|
|
172332
|
+
return null;
|
|
172333
|
+
delete cursor[leaf];
|
|
172334
|
+
return { block: result, removed: relativePath.map(String).join(".") };
|
|
172335
|
+
}
|
|
172336
|
+
|
|
171930
172337
|
// src/config/index.ts
|
|
171931
172338
|
init_magic_context();
|
|
171932
172339
|
|
|
@@ -171937,6 +172344,21 @@ import { homedir } from "node:os";
|
|
|
171937
172344
|
import { dirname, isAbsolute, resolve } from "node:path";
|
|
171938
172345
|
var ENV_PATTERN = /\{env:([^}]+)\}/g;
|
|
171939
172346
|
var FILE_PATTERN = /\{file:([^}]+)\}/g;
|
|
172347
|
+
function sensitiveFilePathReason(resolvedPath) {
|
|
172348
|
+
const home = homedir();
|
|
172349
|
+
const sensitiveDirs = [
|
|
172350
|
+
{ dir: resolve(home, ".ssh"), label: "SSH keys" },
|
|
172351
|
+
{ dir: resolve(home, ".aws"), label: "AWS credentials" },
|
|
172352
|
+
{ dir: resolve(home, ".gnupg"), label: "GnuPG keyring" },
|
|
172353
|
+
{ dir: resolve(home, ".config", "gh"), label: "GitHub CLI auth" }
|
|
172354
|
+
];
|
|
172355
|
+
for (const { dir, label } of sensitiveDirs) {
|
|
172356
|
+
if (resolvedPath === dir || resolvedPath.startsWith(`${dir}/`)) {
|
|
172357
|
+
return label;
|
|
172358
|
+
}
|
|
172359
|
+
}
|
|
172360
|
+
return null;
|
|
172361
|
+
}
|
|
171940
172362
|
function substituteConfigVariables(input) {
|
|
171941
172363
|
const warnings = [];
|
|
171942
172364
|
let text = input.text;
|
|
@@ -171990,6 +172412,10 @@ function substituteConfigVariables(input) {
|
|
|
171990
172412
|
} else if (!isAbsolute(filePath)) {
|
|
171991
172413
|
filePath = resolve(configDir, filePath);
|
|
171992
172414
|
}
|
|
172415
|
+
const sensitiveReason = sensitiveFilePathReason(filePath);
|
|
172416
|
+
if (sensitiveReason) {
|
|
172417
|
+
warnings.push(`${token} resolves to a sensitive path (${sensitiveReason}: ${filePath}); ` + "inlining its contents into config — make sure this is intentional.");
|
|
172418
|
+
}
|
|
171993
172419
|
if (!existsSync2(filePath)) {
|
|
171994
172420
|
warnings.push(`File not found for ${token} (resolved to ${filePath}); using empty string`);
|
|
171995
172421
|
continue;
|
|
@@ -172092,9 +172518,6 @@ function deepMergeRawConfig(base, override) {
|
|
|
172092
172518
|
}
|
|
172093
172519
|
return result;
|
|
172094
172520
|
}
|
|
172095
|
-
function getProjectUserOnlyFields(config2) {
|
|
172096
|
-
return "auto_update" in config2 ? ["auto_update"] : [];
|
|
172097
|
-
}
|
|
172098
172521
|
function redactConfigValue(value) {
|
|
172099
172522
|
if (value === undefined)
|
|
172100
172523
|
return "<missing>";
|
|
@@ -172133,12 +172556,16 @@ function parsePluginConfig(rawConfig, recoveredTopLevelKeys = []) {
|
|
|
172133
172556
|
const warnings = [];
|
|
172134
172557
|
const errorPaths = new Set;
|
|
172135
172558
|
const customMessagesByKey = new Map;
|
|
172559
|
+
const issuePathsByKey = new Map;
|
|
172136
172560
|
const GENERIC_ZOD_PREFIXES = ["Too big", "Too small", "Invalid input", "Invalid", "Expected"];
|
|
172137
172561
|
for (const issue2 of parsed.error.issues) {
|
|
172138
172562
|
const topKey = issue2.path[0];
|
|
172139
172563
|
if (topKey !== undefined) {
|
|
172140
172564
|
const key = String(topKey);
|
|
172141
172565
|
errorPaths.add(key);
|
|
172566
|
+
const paths = issuePathsByKey.get(key) ?? [];
|
|
172567
|
+
paths.push([...issue2.path]);
|
|
172568
|
+
issuePathsByKey.set(key, paths);
|
|
172142
172569
|
const msg = issue2.message;
|
|
172143
172570
|
if (msg && !GENERIC_ZOD_PREFIXES.some((p) => msg.startsWith(p))) {
|
|
172144
172571
|
if (!customMessagesByKey.has(key)) {
|
|
@@ -172154,12 +172581,33 @@ function parsePluginConfig(rawConfig, recoveredTopLevelKeys = []) {
|
|
|
172154
172581
|
if (isAgentConfig) {
|
|
172155
172582
|
delete patched[key];
|
|
172156
172583
|
warnings.push(`"${key}": invalid agent configuration, ignoring. Check your magic-context.jsonc.`);
|
|
172157
|
-
|
|
172158
|
-
|
|
172159
|
-
|
|
172160
|
-
|
|
172161
|
-
|
|
172584
|
+
continue;
|
|
172585
|
+
}
|
|
172586
|
+
const issuePaths = issuePathsByKey.get(key) ?? [];
|
|
172587
|
+
const rawValue = rawConfig[key];
|
|
172588
|
+
const allNested = issuePaths.length > 0 && issuePaths.every((p) => p.length >= 2) && typeof rawValue === "object" && rawValue !== null && !Array.isArray(rawValue);
|
|
172589
|
+
if (allNested) {
|
|
172590
|
+
let prunedBlock = {
|
|
172591
|
+
...rawValue
|
|
172592
|
+
};
|
|
172593
|
+
const prunedLeaves = [];
|
|
172594
|
+
for (const p of issuePaths) {
|
|
172595
|
+
const relative = p.slice(1);
|
|
172596
|
+
const result = pruneNestedConfigLeaf(prunedBlock, relative);
|
|
172597
|
+
if (result) {
|
|
172598
|
+
prunedBlock = result.block;
|
|
172599
|
+
prunedLeaves.push(result.removed);
|
|
172600
|
+
}
|
|
172601
|
+
}
|
|
172602
|
+
patched[key] = prunedBlock;
|
|
172603
|
+
const reason2 = customMessagesByKey.get(key);
|
|
172604
|
+
warnings.push(`"${key}": invalid nested field(s) ${prunedLeaves.map((l) => `"${l}"`).join(", ")}, using defaults for those.${reason2 ? ` ${reason2}` : ""}`);
|
|
172605
|
+
continue;
|
|
172162
172606
|
}
|
|
172607
|
+
delete patched[key];
|
|
172608
|
+
const defaultVal = defaults[key];
|
|
172609
|
+
const reason = customMessagesByKey.get(key);
|
|
172610
|
+
warnings.push(`"${key}": invalid value (${redactConfigValue(rawConfig[key])}), using default ${JSON.stringify(defaultVal)}.${reason ? ` ${reason}` : ""}`);
|
|
172163
172611
|
}
|
|
172164
172612
|
const retryMigrated = migrateLegacyExperimental(patched, preMigrationWarnings);
|
|
172165
172613
|
const retryParsed = MagicContextConfigSchema.safeParse(retryMigrated);
|
|
@@ -172195,14 +172643,13 @@ function loadPluginConfig(directory) {
|
|
|
172195
172643
|
if (projectLoaded) {
|
|
172196
172644
|
allWarnings.push(...projectLoaded.warnings.map((w) => `[project config] ${w}`));
|
|
172197
172645
|
const projectRaw = { ...projectLoaded.config };
|
|
172198
|
-
const
|
|
172199
|
-
|
|
172200
|
-
for (const key of strippedUserOnlyFields) {
|
|
172201
|
-
delete projectRaw[key];
|
|
172202
|
-
}
|
|
172203
|
-
allWarnings.push(`[project config] Ignoring ${strippedUserOnlyFields.join(", ")} from project config (security: these settings only honor user-level config)`);
|
|
172646
|
+
for (const warning of stripUnsafeProjectConfigFields(projectRaw)) {
|
|
172647
|
+
allWarnings.push(`[project config] ${warning}`);
|
|
172204
172648
|
}
|
|
172205
172649
|
mergedRaw = deepMergeRawConfig(mergedRaw, projectRaw);
|
|
172650
|
+
for (const warning of dropInheritedEmbeddingKeyOnRedirect(projectRaw, mergedRaw, userLoaded?.config)) {
|
|
172651
|
+
allWarnings.push(`[project config] ${warning}`);
|
|
172652
|
+
}
|
|
172206
172653
|
}
|
|
172207
172654
|
const config2 = parsePluginConfig(mergedRaw);
|
|
172208
172655
|
if (config2.configWarnings?.length) {
|
|
@@ -172276,14 +172723,13 @@ function loadPluginConfigDetailed(directory) {
|
|
|
172276
172723
|
if (projectLoaded) {
|
|
172277
172724
|
allWarnings.push(...projectLoaded.warnings.map((w) => `[project config] ${w}`));
|
|
172278
172725
|
const projectRaw = { ...projectLoaded.config };
|
|
172279
|
-
const
|
|
172280
|
-
|
|
172281
|
-
for (const key of strippedUserOnlyFields) {
|
|
172282
|
-
delete projectRaw[key];
|
|
172283
|
-
}
|
|
172284
|
-
allWarnings.push(`[project config] Ignoring ${strippedUserOnlyFields.join(", ")} from project config (security: these settings only honor user-level config)`);
|
|
172726
|
+
for (const warning of stripUnsafeProjectConfigFields(projectRaw)) {
|
|
172727
|
+
allWarnings.push(`[project config] ${warning}`);
|
|
172285
172728
|
}
|
|
172286
172729
|
mergedRaw = deepMergeRawConfig(mergedRaw, projectRaw);
|
|
172730
|
+
for (const warning of dropInheritedEmbeddingKeyOnRedirect(projectRaw, mergedRaw, userLoaded?.config)) {
|
|
172731
|
+
allWarnings.push(`[project config] ${warning}`);
|
|
172732
|
+
}
|
|
172287
172733
|
}
|
|
172288
172734
|
const recoveredTopLevelKeys = [];
|
|
172289
172735
|
const config2 = parsePluginConfig(mergedRaw, recoveredTopLevelKeys);
|
|
@@ -172821,7 +173267,7 @@ async function runSidekick(deps) {
|
|
|
172821
173267
|
}
|
|
172822
173268
|
return null;
|
|
172823
173269
|
} finally {
|
|
172824
|
-
if (agentSessionId) {
|
|
173270
|
+
if (agentSessionId && !shouldKeepSubagents()) {
|
|
172825
173271
|
await deps.client.session.delete({
|
|
172826
173272
|
path: { id: agentSessionId }
|
|
172827
173273
|
}).catch((error51) => {
|
|
@@ -173098,6 +173544,11 @@ var CACHE_DIR = join7(getOpenCodeCacheRoot(), "packages");
|
|
|
173098
173544
|
var USER_OPENCODE_CONFIG = join7(getOpenCodeConfigRoot(), "opencode.json");
|
|
173099
173545
|
var USER_OPENCODE_CONFIG_JSONC = join7(getOpenCodeConfigRoot(), "opencode.jsonc");
|
|
173100
173546
|
|
|
173547
|
+
// src/hooks/auto-update-checker/semver.ts
|
|
173548
|
+
function isValidSemver(version2) {
|
|
173549
|
+
return /^\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?(?:\+[0-9A-Za-z.-]+)?$/.test(version2);
|
|
173550
|
+
}
|
|
173551
|
+
|
|
173101
173552
|
// src/hooks/auto-update-checker/types.ts
|
|
173102
173553
|
init_zod();
|
|
173103
173554
|
var NpmPackageEnvelopeSchema = exports_external.object({
|
|
@@ -173433,6 +173884,10 @@ function resolveInstallContext(runtimePackageJsonPath = getCurrentRuntimePackage
|
|
|
173433
173884
|
}
|
|
173434
173885
|
function preparePackageUpdate(version2, packageName = PACKAGE_NAME, runtimePackageJsonPath = getCurrentRuntimePackageJsonPath()) {
|
|
173435
173886
|
try {
|
|
173887
|
+
if (!isValidSemver(version2)) {
|
|
173888
|
+
warn2(`[auto-update-checker] Refusing to prepare update for invalid version "${version2}"`);
|
|
173889
|
+
return null;
|
|
173890
|
+
}
|
|
173436
173891
|
const installContext = resolveInstallContext(runtimePackageJsonPath);
|
|
173437
173892
|
if (!installContext) {
|
|
173438
173893
|
warn2("[auto-update-checker] No install context found for auto-update");
|
|
@@ -173873,13 +174328,14 @@ init_shared();
|
|
|
173873
174328
|
init_assistant_message_extractor();
|
|
173874
174329
|
init_logger();
|
|
173875
174330
|
import { readFileSync as readFileSync11 } from "node:fs";
|
|
173876
|
-
import { isAbsolute as
|
|
174331
|
+
import { isAbsolute as isAbsolute4, join as join15, relative as relative2 } from "node:path";
|
|
174332
|
+
init_subagent_token_capture();
|
|
173877
174333
|
init_aft_availability();
|
|
173878
174334
|
init_project_key_files();
|
|
173879
174335
|
|
|
173880
174336
|
// src/features/magic-context/key-files/read-history.ts
|
|
173881
174337
|
import { realpathSync as realpathSync3 } from "node:fs";
|
|
173882
|
-
import { relative, resolve as
|
|
174338
|
+
import { relative, resolve as resolve6 } from "node:path";
|
|
173883
174339
|
function toMs(value) {
|
|
173884
174340
|
if (typeof value === "number" && Number.isFinite(value))
|
|
173885
174341
|
return value;
|
|
@@ -173916,7 +174372,7 @@ function coalesceRanges(ranges) {
|
|
|
173916
174372
|
}
|
|
173917
174373
|
function normalizeProjectRelativePath(projectPath, filePath) {
|
|
173918
174374
|
const root = realpathSync3(projectPath);
|
|
173919
|
-
const abs = filePath.startsWith("/") ?
|
|
174375
|
+
const abs = filePath.startsWith("/") ? resolve6(filePath) : resolve6(root, filePath);
|
|
173920
174376
|
let real = abs;
|
|
173921
174377
|
try {
|
|
173922
174378
|
real = realpathSync3(abs);
|
|
@@ -174284,11 +174740,13 @@ async function runKeyFilesLlm(args) {
|
|
|
174284
174740
|
const text = extractLatestAssistantText(messages);
|
|
174285
174741
|
if (!text)
|
|
174286
174742
|
throw new Error("Dreamer returned no key-files output.");
|
|
174287
|
-
return text;
|
|
174743
|
+
return { text, messages };
|
|
174288
174744
|
} finally {
|
|
174289
|
-
|
|
174290
|
-
|
|
174291
|
-
|
|
174745
|
+
if (!shouldKeepSubagents()) {
|
|
174746
|
+
await args.client.session.delete({ path: { id: agentSessionId } }).catch(() => {
|
|
174747
|
+
return;
|
|
174748
|
+
});
|
|
174749
|
+
}
|
|
174292
174750
|
}
|
|
174293
174751
|
}
|
|
174294
174752
|
async function runKeyFilesTask(args) {
|
|
@@ -174334,9 +174792,27 @@ async function runKeyFilesTask(args) {
|
|
|
174334
174792
|
log(`[key-files] lease renewal threw: ${getErrorMessage(error51)}`);
|
|
174335
174793
|
}
|
|
174336
174794
|
}, 60000);
|
|
174795
|
+
let invocationRecorded = false;
|
|
174796
|
+
const llmStartedAt = Date.now();
|
|
174797
|
+
const recordKeyFilesInvocation = (params) => {
|
|
174798
|
+
if (!args.parentSessionId || invocationRecorded)
|
|
174799
|
+
return;
|
|
174800
|
+
invocationRecorded = true;
|
|
174801
|
+
recordChildInvocation({
|
|
174802
|
+
db: args.db,
|
|
174803
|
+
parentSessionId: args.parentSessionId,
|
|
174804
|
+
harness: getHarness(),
|
|
174805
|
+
subagent: "dreamer",
|
|
174806
|
+
task: "key files",
|
|
174807
|
+
startedAt: llmStartedAt,
|
|
174808
|
+
status: params.status,
|
|
174809
|
+
messages: params.messages,
|
|
174810
|
+
error: params.error
|
|
174811
|
+
});
|
|
174812
|
+
};
|
|
174337
174813
|
try {
|
|
174338
174814
|
try {
|
|
174339
|
-
const raw = await runKeyFilesLlm({
|
|
174815
|
+
const { text: raw, messages: llmMessages } = await runKeyFilesLlm({
|
|
174340
174816
|
client: args.client,
|
|
174341
174817
|
parentSessionId: args.parentSessionId,
|
|
174342
174818
|
projectPath,
|
|
@@ -174344,8 +174820,10 @@ async function runKeyFilesTask(args) {
|
|
|
174344
174820
|
deadline: args.deadline,
|
|
174345
174821
|
fallbackModels: args.fallbackModels
|
|
174346
174822
|
});
|
|
174823
|
+
recordKeyFilesInvocation({ status: "completed", messages: llmMessages });
|
|
174347
174824
|
validated = validateLlmOutput(raw, args.config, projectPath, new Set(candidates.map((candidate) => candidate.path)));
|
|
174348
174825
|
} catch (error51) {
|
|
174826
|
+
recordKeyFilesInvocation({ status: "failed", error: error51 });
|
|
174349
174827
|
log(`[key-files] LLM validation failed: ${getErrorMessage(error51)}`);
|
|
174350
174828
|
throw error51;
|
|
174351
174829
|
}
|
|
@@ -174444,7 +174922,8 @@ If no promotions are warranted, return empty arrays. Always consume reviewed can
|
|
|
174444
174922
|
db: args.db,
|
|
174445
174923
|
parentSessionId: args.parentSessionId,
|
|
174446
174924
|
harness: "opencode",
|
|
174447
|
-
subagent: "
|
|
174925
|
+
subagent: "dreamer",
|
|
174926
|
+
task: "user memories",
|
|
174448
174927
|
startedAt,
|
|
174449
174928
|
status: params.status,
|
|
174450
174929
|
messages: params.messages,
|
|
@@ -174568,7 +175047,7 @@ If no promotions are warranted, return empty arrays. Always consume reviewed can
|
|
|
174568
175047
|
return result;
|
|
174569
175048
|
} finally {
|
|
174570
175049
|
clearInterval(leaseInterval);
|
|
174571
|
-
if (agentSessionId) {
|
|
175050
|
+
if (agentSessionId && !shouldKeepSubagents()) {
|
|
174572
175051
|
await args.client.session.delete({
|
|
174573
175052
|
path: { id: agentSessionId },
|
|
174574
175053
|
query: { directory: args.sessionDirectory }
|
|
@@ -174694,7 +175173,7 @@ async function runDream(args) {
|
|
|
174694
175173
|
}
|
|
174695
175174
|
}
|
|
174696
175175
|
const deadline = startedAt + args.maxRuntimeMinutes * 60 * 1000;
|
|
174697
|
-
const lastDreamAt = getDreamState(args.db, `last_dream_at:${args.projectIdentity}`)
|
|
175176
|
+
const lastDreamAt = getDreamState(args.db, `last_dream_at:${args.projectIdentity}`);
|
|
174698
175177
|
log(`[dreamer] last dream at: ${lastDreamAt ?? "never"} (project=${args.projectIdentity})`);
|
|
174699
175178
|
let lastErrorSignature = null;
|
|
174700
175179
|
let consecutiveSameErrorFailures = 0;
|
|
@@ -174891,14 +175370,14 @@ async function runDream(args) {
|
|
|
174891
175370
|
}
|
|
174892
175371
|
} finally {
|
|
174893
175372
|
clearInterval(leaseRenewalInterval);
|
|
174894
|
-
if (agentSessionId && !taskFailed) {
|
|
175373
|
+
if (agentSessionId && !taskFailed && !shouldKeepSubagents()) {
|
|
174895
175374
|
await args.client.session.delete({
|
|
174896
175375
|
path: { id: agentSessionId }
|
|
174897
175376
|
}).catch((error51) => {
|
|
174898
175377
|
log("[dreamer] failed to delete child session:", error51);
|
|
174899
175378
|
});
|
|
174900
|
-
} else if (agentSessionId && taskFailed) {
|
|
174901
|
-
log(`[dreamer] KEEPING
|
|
175379
|
+
} else if (agentSessionId && (taskFailed || shouldKeepSubagents())) {
|
|
175380
|
+
log(`[dreamer] KEEPING child session ${agentSessionId} for task ${taskName} (${taskFailed ? "failed" : "keep_subagents"})`);
|
|
174902
175381
|
}
|
|
174903
175382
|
}
|
|
174904
175383
|
if (lostLease) {
|
|
@@ -175076,7 +175555,6 @@ async function runDream(args) {
|
|
|
175076
175555
|
const hasSuccessfulTask = result.tasks.some((t) => !t.error && !POST_TASK_NAMES.has(t.name));
|
|
175077
175556
|
if (hasSuccessfulTask && !lostLease) {
|
|
175078
175557
|
setDreamState(args.db, `last_dream_at:${args.projectIdentity}`, String(result.finishedAt));
|
|
175079
|
-
setDreamState(args.db, "last_dream_at", String(result.finishedAt));
|
|
175080
175558
|
}
|
|
175081
175559
|
const totalDuration = ((result.finishedAt - startedAt) / 1000).toFixed(1);
|
|
175082
175560
|
const succeeded = result.tasks.filter((t) => !t.error).length;
|
|
@@ -175183,7 +175661,7 @@ Only include notes whose conditions you could definitively evaluate against exte
|
|
|
175183
175661
|
parts: [{ type: "text", text: evaluationPrompt, synthetic: true }]
|
|
175184
175662
|
}
|
|
175185
175663
|
}, {
|
|
175186
|
-
timeoutMs: Math.min(remainingMs,
|
|
175664
|
+
timeoutMs: Math.min(remainingMs, 5 * 60 * 1000),
|
|
175187
175665
|
signal: abortController.signal,
|
|
175188
175666
|
fallbackModels: args.fallbackModels,
|
|
175189
175667
|
callContext: "dreamer:smart-notes"
|
|
@@ -175259,7 +175737,7 @@ Only include notes whose conditions you could definitively evaluate against exte
|
|
|
175259
175737
|
});
|
|
175260
175738
|
} finally {
|
|
175261
175739
|
clearInterval(leaseInterval);
|
|
175262
|
-
if (agentSessionId) {
|
|
175740
|
+
if (agentSessionId && !shouldKeepSubagents()) {
|
|
175263
175741
|
await args.client.session.delete({
|
|
175264
175742
|
path: { id: agentSessionId }
|
|
175265
175743
|
}).catch(() => {});
|
|
@@ -175270,7 +175748,7 @@ var MAX_LEASE_RETRIES = 3;
|
|
|
175270
175748
|
async function processDreamQueue(args) {
|
|
175271
175749
|
const maxRuntimeMs = args.maxRuntimeMinutes * 60 * 1000;
|
|
175272
175750
|
if (!hasActiveDreamLease(args.db)) {
|
|
175273
|
-
clearStaleEntries(args.db, maxRuntimeMs +
|
|
175751
|
+
clearStaleEntries(args.db, maxRuntimeMs + 30 * 60 * 1000, args.projectIdentity);
|
|
175274
175752
|
}
|
|
175275
175753
|
const entry = dequeueNext(args.db, args.projectIdentity);
|
|
175276
175754
|
if (!entry) {
|
|
@@ -175353,8 +175831,7 @@ function findProjectsNeedingDream(db) {
|
|
|
175353
175831
|
const now = new Date;
|
|
175354
175832
|
for (const row of projectRows) {
|
|
175355
175833
|
const lastDreamAtStr = getDreamState(db, `last_dream_at:${row.project_path}`);
|
|
175356
|
-
const
|
|
175357
|
-
const lastDreamAt = Number(lastDreamAtStr ?? fallbackStr ?? "0") || 0;
|
|
175834
|
+
const lastDreamAt = Number(lastDreamAtStr ?? "0") || 0;
|
|
175358
175835
|
if (lastDreamAt > 0 && isDreamFromCurrentWindow(lastDreamAt, now)) {
|
|
175359
175836
|
continue;
|
|
175360
175837
|
}
|
|
@@ -176004,10 +176481,20 @@ var EMBEDDING_AFFECTING_KEYS = new Set([
|
|
|
176004
176481
|
"embedding.api_key",
|
|
176005
176482
|
"embedding.endpoint",
|
|
176006
176483
|
"embedding.model",
|
|
176007
|
-
"embedding.provider"
|
|
176484
|
+
"embedding.provider",
|
|
176485
|
+
"embedding.input_type",
|
|
176486
|
+
"embedding.truncate"
|
|
176008
176487
|
]);
|
|
176009
176488
|
var EMBEDDING_AFFECTING_TOP_LEVEL_KEYS = new Set(["embedding", "memory", "experimental"]);
|
|
176010
|
-
var EMBEDDING_WARNING_TERMS = [
|
|
176489
|
+
var EMBEDDING_WARNING_TERMS = [
|
|
176490
|
+
"api_key",
|
|
176491
|
+
"endpoint",
|
|
176492
|
+
"model",
|
|
176493
|
+
"provider",
|
|
176494
|
+
"embedding",
|
|
176495
|
+
"input_type",
|
|
176496
|
+
"truncate"
|
|
176497
|
+
];
|
|
176011
176498
|
var loggedFailureSignatures = new Map;
|
|
176012
176499
|
function sha256Prefix2(value, length = 16) {
|
|
176013
176500
|
return createHash8("sha256").update(value).digest("hex").slice(0, length);
|
|
@@ -176629,6 +177116,7 @@ function createTagger() {
|
|
|
176629
177116
|
// src/hooks/magic-context/hook.ts
|
|
176630
177117
|
init_magic_context();
|
|
176631
177118
|
init_project_identity();
|
|
177119
|
+
init_tool_definition_tokens();
|
|
176632
177120
|
await init_storage();
|
|
176633
177121
|
init_logger();
|
|
176634
177122
|
init_resolve_fallbacks();
|
|
@@ -178610,7 +179098,7 @@ async function runCompartmentPhase(args) {
|
|
|
178610
179098
|
async function awaitCompartmentRun(activeRun, reason) {
|
|
178611
179099
|
sessionLog(args.sessionId, reason);
|
|
178612
179100
|
const timeoutMs = args.historianTimeoutMs ?? 120000;
|
|
178613
|
-
const timeout = new Promise((
|
|
179101
|
+
const timeout = new Promise((resolve7) => setTimeout(() => resolve7("timeout"), timeoutMs));
|
|
178614
179102
|
const result = await Promise.race([activeRun.promise.then(() => "done"), timeout]);
|
|
178615
179103
|
if (result === "timeout") {
|
|
178616
179104
|
sessionLog(args.sessionId, `transform: compartment await timed out after ${timeoutMs}ms — proceeding without waiting`);
|
|
@@ -179021,32 +179509,53 @@ function hasAnyMeaningfulPart(parts) {
|
|
|
179021
179509
|
}
|
|
179022
179510
|
return false;
|
|
179023
179511
|
}
|
|
179024
|
-
function
|
|
179025
|
-
|
|
179512
|
+
function messageHasReducePart(message) {
|
|
179513
|
+
for (const part of message.parts) {
|
|
179514
|
+
if (isSentinel(part))
|
|
179515
|
+
continue;
|
|
179516
|
+
if (isReduceToolPart(part))
|
|
179517
|
+
return true;
|
|
179518
|
+
}
|
|
179519
|
+
return false;
|
|
179520
|
+
}
|
|
179521
|
+
function sentinelizeReduceParts(message) {
|
|
179522
|
+
let touched = false;
|
|
179523
|
+
for (let j = 0;j < message.parts.length; j++) {
|
|
179524
|
+
const part = message.parts[j];
|
|
179525
|
+
if (isSentinel(part))
|
|
179526
|
+
continue;
|
|
179527
|
+
if (isReduceToolPart(part)) {
|
|
179528
|
+
message.parts[j] = makeSentinel(part);
|
|
179529
|
+
touched = true;
|
|
179530
|
+
}
|
|
179531
|
+
}
|
|
179532
|
+
if (touched && !hasAnyMeaningfulPart(message.parts)) {
|
|
179533
|
+
message.parts.length = 0;
|
|
179534
|
+
message.parts.push(makeSentinel(undefined));
|
|
179535
|
+
}
|
|
179536
|
+
return touched;
|
|
179537
|
+
}
|
|
179538
|
+
function dropStaleReduceCalls(messages, frozenIds, options = {}) {
|
|
179539
|
+
const detect = options.detect ?? false;
|
|
179540
|
+
const protectedCount = options.protectedCount ?? 0;
|
|
179026
179541
|
const protectedStart = messages.length - protectedCount;
|
|
179542
|
+
const newlyStrippedIds = [];
|
|
179543
|
+
let didDrop = false;
|
|
179027
179544
|
for (let i = 0;i < messages.length; i++) {
|
|
179028
|
-
if (i >= protectedStart)
|
|
179029
|
-
break;
|
|
179030
179545
|
const message = messages[i];
|
|
179031
|
-
|
|
179032
|
-
|
|
179033
|
-
|
|
179034
|
-
|
|
179035
|
-
|
|
179036
|
-
|
|
179037
|
-
message.parts[j] = makeSentinel(part);
|
|
179038
|
-
touched = true;
|
|
179039
|
-
}
|
|
179040
|
-
}
|
|
179546
|
+
const id = typeof message.info.id === "string" ? message.info.id : undefined;
|
|
179547
|
+
const inFrozen = id !== undefined && frozenIds.has(id);
|
|
179548
|
+
const isNewDetection = !inFrozen && detect && i < protectedStart && id !== undefined && messageHasReducePart(message);
|
|
179549
|
+
if (!inFrozen && !isNewDetection)
|
|
179550
|
+
continue;
|
|
179551
|
+
const touched = sentinelizeReduceParts(message);
|
|
179041
179552
|
if (touched) {
|
|
179042
179553
|
didDrop = true;
|
|
179043
|
-
if (
|
|
179044
|
-
|
|
179045
|
-
message.parts.push(makeSentinel(undefined));
|
|
179046
|
-
}
|
|
179554
|
+
if (isNewDetection && id !== undefined)
|
|
179555
|
+
newlyStrippedIds.push(id);
|
|
179047
179556
|
}
|
|
179048
179557
|
}
|
|
179049
|
-
return didDrop;
|
|
179558
|
+
return { didDrop, newlyStrippedIds };
|
|
179050
179559
|
}
|
|
179051
179560
|
|
|
179052
179561
|
// src/hooks/magic-context/tag-messages.ts
|
|
@@ -180093,10 +180602,10 @@ var AUTO_SEARCH_TIMEOUT_MS = 3000;
|
|
|
180093
180602
|
async function unifiedSearchWithTimeout(db, sessionId, projectPath, prompt, options, timeoutMs) {
|
|
180094
180603
|
const controller = new AbortController;
|
|
180095
180604
|
let timer;
|
|
180096
|
-
const timeoutPromise = new Promise((
|
|
180605
|
+
const timeoutPromise = new Promise((resolve7) => {
|
|
180097
180606
|
timer = setTimeout(() => {
|
|
180098
180607
|
controller.abort();
|
|
180099
|
-
|
|
180608
|
+
resolve7(null);
|
|
180100
180609
|
}, timeoutMs);
|
|
180101
180610
|
});
|
|
180102
180611
|
try {
|
|
@@ -180632,7 +181141,7 @@ function isTodoItem(value) {
|
|
|
180632
181141
|
|
|
180633
181142
|
// src/hooks/magic-context/transform-postprocess-phase.ts
|
|
180634
181143
|
var DEGRADE_CACHE_WARNING_THRESHOLD = 10;
|
|
180635
|
-
var degradedCacheCountBySession = new
|
|
181144
|
+
var degradedCacheCountBySession = new BoundedSessionMap(100);
|
|
180636
181145
|
function resetDegradedCacheCount(sessionId) {
|
|
180637
181146
|
degradedCacheCountBySession.delete(sessionId);
|
|
180638
181147
|
}
|
|
@@ -180767,14 +181276,19 @@ async function runPostTransformPhase(args) {
|
|
|
180767
181276
|
if (didMutateFromPendingOperations && isCacheBustingPass) {
|
|
180768
181277
|
args.nudgePlacements.clear(args.sessionId);
|
|
180769
181278
|
}
|
|
180770
|
-
|
|
180771
|
-
|
|
180772
|
-
|
|
180773
|
-
|
|
180774
|
-
|
|
180775
|
-
|
|
180776
|
-
|
|
181279
|
+
try {
|
|
181280
|
+
const t8 = performance.now();
|
|
181281
|
+
const frozenStaleReduceIds = getStaleReduceStrippedIds(args.db, args.sessionId);
|
|
181282
|
+
const staleReduceResult = dropStaleReduceCalls(args.messages, frozenStaleReduceIds, {
|
|
181283
|
+
detect: isCacheBustingPass,
|
|
181284
|
+
protectedCount: args.protectedTags
|
|
181285
|
+
});
|
|
181286
|
+
if (isCacheBustingPass && staleReduceResult.newlyStrippedIds.length > 0) {
|
|
181287
|
+
addStaleReduceStrippedIds(args.db, args.sessionId, staleReduceResult.newlyStrippedIds);
|
|
180777
181288
|
}
|
|
181289
|
+
logTransformTiming(args.sessionId, "dropStaleReduceCalls", t8);
|
|
181290
|
+
} catch (error51) {
|
|
181291
|
+
sessionLog(args.sessionId, "transform failed dropping stale ctx_reduce calls:", error51);
|
|
180778
181292
|
}
|
|
180779
181293
|
const m0M1Enabled = args.fullFeatureMode && args.m0M1 !== undefined && (!!args.m0M1.projectPath || !!args.m0M1.projectDirectory);
|
|
180780
181294
|
if (m0M1Enabled && args.m0M1) {
|
|
@@ -180790,7 +181304,8 @@ async function runPostTransformPhase(args) {
|
|
|
180790
181304
|
memoryInjectionBudgetTokens: args.m0M1.memoryInjectionBudgetTokens,
|
|
180791
181305
|
historyBudgetTokens: args.m0M1.historyBudgetTokens,
|
|
180792
181306
|
keyFiles: args.m0M1.keyFiles,
|
|
180793
|
-
isCacheBustingPass
|
|
181307
|
+
isCacheBustingPass,
|
|
181308
|
+
hardSignals: args.m0M1.hardSignals
|
|
180794
181309
|
});
|
|
180795
181310
|
if (result.injected) {
|
|
180796
181311
|
sessionLog(args.sessionId, `transform: injected m[0]/m[1] (rematerialized=${result.m0RematerializedThisPass}, reason=${result.decision.reason ?? "cache_hit"})`);
|
|
@@ -180805,6 +181320,7 @@ async function runPostTransformPhase(args) {
|
|
|
180805
181320
|
sessionLog(args.sessionId, "transform: legacy fallback injection also failed:", getErrorMessage(fallbackError));
|
|
180806
181321
|
}
|
|
180807
181322
|
}
|
|
181323
|
+
clearInjectionCache(args.sessionId);
|
|
180808
181324
|
}
|
|
180809
181325
|
logTransformTiming(args.sessionId, "pp.injectM0M1", tInjectM0M1);
|
|
180810
181326
|
} else if (args.fullFeatureMode && args.pendingCompartmentInjection) {
|
|
@@ -180828,7 +181344,7 @@ async function runPostTransformPhase(args) {
|
|
|
180828
181344
|
if (missingIds.length > 0) {
|
|
180829
181345
|
for (const id of missingIds)
|
|
180830
181346
|
persistedIds.delete(id);
|
|
180831
|
-
|
|
181347
|
+
applyStrippedPlaceholderDelta(args.db, args.sessionId, { remove: missingIds });
|
|
180832
181348
|
}
|
|
180833
181349
|
}
|
|
180834
181350
|
if (isCacheBustingPass) {
|
|
@@ -180837,11 +181353,13 @@ async function runPostTransformPhase(args) {
|
|
|
180837
181353
|
const systemInjectedResult = stripSystemInjectedMessages(args.messages, protectedTailStart, args.liveProviderID);
|
|
180838
181354
|
const newlyNeutralized = droppedResult.sentineledIds.length + systemInjectedResult.sentineledIds.length;
|
|
180839
181355
|
if (newlyNeutralized > 0) {
|
|
180840
|
-
|
|
181356
|
+
const addedIds = [
|
|
181357
|
+
...droppedResult.sentineledIds,
|
|
181358
|
+
...systemInjectedResult.sentineledIds
|
|
181359
|
+
];
|
|
181360
|
+
for (const id of addedIds)
|
|
180841
181361
|
persistedIds.add(id);
|
|
180842
|
-
|
|
180843
|
-
persistedIds.add(id);
|
|
180844
|
-
setStrippedPlaceholderIds(args.db, args.sessionId, persistedIds);
|
|
181362
|
+
applyStrippedPlaceholderDelta(args.db, args.sessionId, { add: addedIds });
|
|
180845
181363
|
sessionLog(args.sessionId, `neutralized ${droppedResult.stripped} dropped + ${systemInjectedResult.stripped} system-injected messages (${newlyNeutralized} new, ${persistedIds.size} total persisted)`);
|
|
180846
181364
|
}
|
|
180847
181365
|
}
|
|
@@ -181360,7 +181878,11 @@ function createTransform(deps) {
|
|
|
181360
181878
|
lastEmergencyNotificationCount.set(sessionId, historianFailureState.failureCount);
|
|
181361
181879
|
sendIgnoredMessage(deps.client, sessionId, `⚠️ Context Emergency — Context is at ${emergencyPercentage}% and historian has failed ${historianFailureState.failureCount} times (last error: ${truncateHistorianEmergencyError(historianFailureState.lastError)}). Aborting this message to prevent context overflow. Historian will retry automatically. If this persists, change your historian model in magic-context.jsonc and restart OpenCode.`, notificationParams);
|
|
181362
181880
|
}
|
|
181363
|
-
startRecoveryRun();
|
|
181881
|
+
const recoveryStarted = startRecoveryRun();
|
|
181882
|
+
if (!recoveryStarted && !getEligibleHistoryForCompartment()) {
|
|
181883
|
+
clearEmergencyRecovery(db, sessionId);
|
|
181884
|
+
sessionLog(sessionId, "transform: disarming emergency recovery — no eligible pre-tail history to compact (would otherwise loop at 95%)");
|
|
181885
|
+
}
|
|
181364
181886
|
sessionLog(sessionId, `EMERGENCY: aborting session at ${emergencyPercentage}%, historian failures: ${historianFailureState.failureCount}`);
|
|
181365
181887
|
} else if (fullFeatureMode && isFirstTransformPassForSession && historianFailureState.failureCount > 0 && getEligibleHistoryForCompartment() && startRecoveryRun()) {
|
|
181366
181888
|
sessionLog(sessionId, `transform: historian recovery triggered on session load after ${historianFailureState.failureCount} failure(s)`);
|
|
@@ -181538,6 +182060,22 @@ Historian previously failed ${historianFailureState.failureCount} time(s), so Ma
|
|
|
181538
182060
|
const compartmentInProgress = compartmentPhase.compartmentInProgress;
|
|
181539
182061
|
sessionMeta = { ...sessionMeta, compartmentInProgress };
|
|
181540
182062
|
logTransformTiming(sessionId, "compartmentPhase", tCompartmentPhase);
|
|
182063
|
+
const hardModel = deps.liveModelBySession?.get(sessionId);
|
|
182064
|
+
const hardModelKey = hardModel ? `${hardModel.providerID}/${hardModel.modelID}` : "";
|
|
182065
|
+
const hardToolSetHash = deps.getToolSetHash?.(sessionId) ?? "";
|
|
182066
|
+
const hardSystemHash = typeof sessionMeta.systemPromptHash === "string" ? sessionMeta.systemPromptHash : "";
|
|
182067
|
+
let hardTtlMs = 5 * 60 * 1000;
|
|
182068
|
+
try {
|
|
182069
|
+
hardTtlMs = parseCacheTtl(sessionMeta.cacheTtl);
|
|
182070
|
+
} catch {}
|
|
182071
|
+
const hardCacheExpired = sessionMeta.lastResponseTime > 0 && Date.now() - sessionMeta.lastResponseTime >= hardTtlMs;
|
|
182072
|
+
const m0HardSignals = {
|
|
182073
|
+
systemHash: hardSystemHash,
|
|
182074
|
+
toolSetHash: hardToolSetHash,
|
|
182075
|
+
modelKey: hardModelKey,
|
|
182076
|
+
cacheExpired: hardCacheExpired,
|
|
182077
|
+
lastResponseTime: sessionMeta.lastResponseTime
|
|
182078
|
+
};
|
|
181541
182079
|
const lateActiveRunBlocksMaterialization = getActiveCompartmentRun(sessionId) !== undefined && contextUsageEarly.percentage < FORCE_MATERIALIZE_PERCENTAGE;
|
|
181542
182080
|
const canConsumeDeferredLate = canConsumeDeferredOnThisPass({
|
|
181543
182081
|
schedulerDecision: midTurnAdjustedSchedulerDecision,
|
|
@@ -181601,7 +182139,8 @@ Historian previously failed ${historianFailureState.failureCount} time(s), so Ma
|
|
|
181601
182139
|
keyFiles: {
|
|
181602
182140
|
enabled: deps.experimentalPinKeyFiles === true,
|
|
181603
182141
|
tokenBudget: deps.experimentalPinKeyFilesTokenBudget ?? 1e4
|
|
181604
|
-
}
|
|
182142
|
+
},
|
|
182143
|
+
hardSignals: m0HardSignals
|
|
181605
182144
|
}
|
|
181606
182145
|
});
|
|
181607
182146
|
logTransformTiming(sessionId, "postTransformPhase", tPostProcess);
|
|
@@ -182386,6 +182925,8 @@ function createEventHook(args) {
|
|
|
182386
182925
|
sessionLog(assistantInfo.sessionID, `model changed (${previous.providerID}/${previous.modelID} -> ${assistantInfo.providerID}/${assistantInfo.modelID}), clearing historian failure state and reasoning watermark`);
|
|
182387
182926
|
clearHistorianFailureState(args.db, assistantInfo.sessionID);
|
|
182388
182927
|
clearPersistedReasoningWatermark(args.db, assistantInfo.sessionID);
|
|
182928
|
+
clearDetectedContextLimit(args.db, assistantInfo.sessionID);
|
|
182929
|
+
clearEmergencyRecovery(args.db, assistantInfo.sessionID);
|
|
182389
182930
|
updateSessionMeta(args.db, assistantInfo.sessionID, {
|
|
182390
182931
|
clearedReasoningThroughTag: 0,
|
|
182391
182932
|
observedSafeInputTokens: 0,
|
|
@@ -182489,6 +183030,7 @@ var PARTNER_FRAME_CLOSER_REDUCE = `
|
|
|
182489
183030
|
Reduction prompts are routine housekeeping to keep the session fast and cheap — act on them as light maintenance, never as scarcity warnings. Keep individual operations efficient, but never let context size change *what* work you take on or *how thoroughly* you do it.`;
|
|
182490
183031
|
var PARTNER_FRAME_CLOSER_NO_REDUCE = `
|
|
182491
183032
|
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.`;
|
|
183033
|
+
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).`;
|
|
182492
183034
|
function getToolHistoryGuidance(dropToolStructure) {
|
|
182493
183035
|
if (dropToolStructure) {
|
|
182494
183036
|
return `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.`;
|
|
@@ -182499,7 +183041,8 @@ var BASE_INTRO = (protectedTags, dropToolStructure) => `Messages and tool output
|
|
|
182499
183041
|
Use \`ctx_reduce\` to manage context size. It supports one operation:
|
|
182500
183042
|
- \`drop\`: Remove entirely (best for tool outputs you already acted on).
|
|
182501
183043
|
Syntax: "3-5", "1,2,9", or "1-5,8,12-15". Last ${protectedTags} tags are protected.
|
|
182502
|
-
|
|
183044
|
+
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.
|
|
183045
|
+
${CTX_NOTE_GUIDANCE}
|
|
182503
183046
|
Use \`ctx_memory\` to manage cross-session project memories. Write new memories or delete stale ones. Memories persist across sessions and are automatically injected into new sessions.
|
|
182504
183047
|
**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:
|
|
182505
183048
|
- Found a project's source code path after searching → \`ctx_memory(action="write", category="ENVIRONMENT", content="OpenCode source is at ~/Work/OSS/opencode")\`
|
|
@@ -182519,7 +183062,7 @@ NEVER drop large ranges blindly (e.g., "1-50"). Review each tag before deciding.
|
|
|
182519
183062
|
NEVER drop user messages — they are short and will be summarized by compartmentalization automatically. Dropping them loses context the historian needs.
|
|
182520
183063
|
NEVER drop assistant text messages unless they are exceptionally large. Your conversation messages are lightweight; only large tool outputs are worth dropping.
|
|
182521
183064
|
Before your turn finishes, consider using \`ctx_reduce\` to drop large tool outputs you no longer need.`;
|
|
182522
|
-
var BASE_INTRO_NO_REDUCE = (dropToolStructure) =>
|
|
183065
|
+
var BASE_INTRO_NO_REDUCE = (dropToolStructure) => `${CTX_NOTE_GUIDANCE}
|
|
182523
183066
|
Use \`ctx_memory\` to manage cross-session project memories. Write new memories or delete stale ones. Memories persist across sessions and are automatically injected into new sessions.
|
|
182524
183067
|
**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:
|
|
182525
183068
|
- Found a project's source code path after searching → \`ctx_memory(action="write", category="ENVIRONMENT", content="OpenCode source is at ~/Work/OSS/opencode")\`
|
|
@@ -182970,6 +183513,12 @@ function createMagicContextHook(deps) {
|
|
|
182970
183513
|
const model = liveModelBySession.get(sessionId);
|
|
182971
183514
|
return resolveModelKey(model?.providerID, model?.modelID);
|
|
182972
183515
|
},
|
|
183516
|
+
getToolSetHash: (sessionId) => {
|
|
183517
|
+
const model = liveModelBySession.get(sessionId);
|
|
183518
|
+
if (!model)
|
|
183519
|
+
return "";
|
|
183520
|
+
return getCurrentToolSetHash(model.providerID, model.modelID, agentBySession.get(sessionId));
|
|
183521
|
+
},
|
|
182973
183522
|
getFallbackModelId: (sessionId) => {
|
|
182974
183523
|
const model = liveModelBySession.get(sessionId);
|
|
182975
183524
|
return model ? `${model.providerID}/${model.modelID}` : undefined;
|
|
@@ -184357,7 +184906,7 @@ function projectIdentityForStoredPath(rawProjectPath) {
|
|
|
184357
184906
|
return normalizeStoredProjectPath(rawProjectPath);
|
|
184358
184907
|
}
|
|
184359
184908
|
function memoryBelongsToProject(memory, projectPath) {
|
|
184360
|
-
return memory.projectPath
|
|
184909
|
+
return storedPathBelongsToIdentity(memory.projectPath, projectPath);
|
|
184361
184910
|
}
|
|
184362
184911
|
function updateMemoryContentInCurrentTransaction(db, memory, content, normalizedHash) {
|
|
184363
184912
|
db.prepare("UPDATE memories SET content = ?, normalized_hash = ?, updated_at = ? WHERE id = ?").run(content, normalizedHash, Date.now(), memory.id);
|
|
@@ -184850,7 +185399,7 @@ import { tool as tool4 } from "@opencode-ai/plugin";
|
|
|
184850
185399
|
// src/features/magic-context/range-parser.ts
|
|
184851
185400
|
function parseRangeString(input) {
|
|
184852
185401
|
const maxRangeElements = 1000;
|
|
184853
|
-
const trimmed = input.trim();
|
|
185402
|
+
const trimmed = input.replace(/§/g, "").trim();
|
|
184854
185403
|
if (trimmed === "") {
|
|
184855
185404
|
throw new Error("Range string must not be empty");
|
|
184856
185405
|
}
|
|
@@ -185096,6 +185645,7 @@ function createCtxSearchTool(deps) {
|
|
|
185096
185645
|
return "Error: 'query' is required.";
|
|
185097
185646
|
}
|
|
185098
185647
|
const lastCompartmentEnd = getLastCompartmentEndMessage(deps.db, toolContext.sessionID);
|
|
185648
|
+
const messageOrdinalCutoff = lastCompartmentEnd >= 0 ? lastCompartmentEnd : 0;
|
|
185099
185649
|
const visibleMemoryIds = getVisibleMemoryIds(deps.db, toolContext.sessionID);
|
|
185100
185650
|
const projectPath = deps.resolveProjectPath(toolContext.directory);
|
|
185101
185651
|
await deps.ensureProjectRegistered?.(toolContext.directory, deps.db);
|
|
@@ -185113,7 +185663,7 @@ function createCtxSearchTool(deps) {
|
|
|
185113
185663
|
},
|
|
185114
185664
|
isEmbeddingRuntimeEnabled: () => embeddingEnabled === true,
|
|
185115
185665
|
readMessages: deps.readMessages,
|
|
185116
|
-
maxMessageOrdinal:
|
|
185666
|
+
maxMessageOrdinal: messageOrdinalCutoff,
|
|
185117
185667
|
gitCommitsEnabled,
|
|
185118
185668
|
sources: normalizeSources(args.sources),
|
|
185119
185669
|
visibleMemoryIds,
|
|
@@ -185216,7 +185766,7 @@ init_models_dev_cache();
|
|
|
185216
185766
|
|
|
185217
185767
|
// src/shared/rpc-server.ts
|
|
185218
185768
|
init_logger();
|
|
185219
|
-
import { randomBytes } from "node:crypto";
|
|
185769
|
+
import { randomBytes, timingSafeEqual } from "node:crypto";
|
|
185220
185770
|
import {
|
|
185221
185771
|
mkdirSync as mkdirSync9,
|
|
185222
185772
|
readdirSync,
|
|
@@ -185283,6 +185833,14 @@ function isValidPort(port) {
|
|
|
185283
185833
|
}
|
|
185284
185834
|
|
|
185285
185835
|
// src/shared/rpc-server.ts
|
|
185836
|
+
function tokensMatch(presented, expected) {
|
|
185837
|
+
const a = Buffer.from(presented, "utf8");
|
|
185838
|
+
const b = Buffer.from(expected, "utf8");
|
|
185839
|
+
if (a.length !== b.length)
|
|
185840
|
+
return false;
|
|
185841
|
+
return timingSafeEqual(a, b);
|
|
185842
|
+
}
|
|
185843
|
+
|
|
185286
185844
|
class MagicContextRpcServer {
|
|
185287
185845
|
server = null;
|
|
185288
185846
|
port = 0;
|
|
@@ -185299,7 +185857,7 @@ class MagicContextRpcServer {
|
|
|
185299
185857
|
this.handlers.set(method, handler);
|
|
185300
185858
|
}
|
|
185301
185859
|
async start() {
|
|
185302
|
-
return new Promise((
|
|
185860
|
+
return new Promise((resolve7, reject) => {
|
|
185303
185861
|
const server = createServer((req, res) => this.dispatch(req, res));
|
|
185304
185862
|
server.on("error", (err) => {
|
|
185305
185863
|
log(`[rpc] server error: ${err.message}`);
|
|
@@ -185329,7 +185887,7 @@ class MagicContextRpcServer {
|
|
|
185329
185887
|
} catch (err) {
|
|
185330
185888
|
log(`[rpc] failed to write port file: ${err}`);
|
|
185331
185889
|
}
|
|
185332
|
-
|
|
185890
|
+
resolve7(this.port);
|
|
185333
185891
|
});
|
|
185334
185892
|
server.unref();
|
|
185335
185893
|
});
|
|
@@ -185370,7 +185928,7 @@ class MagicContextRpcServer {
|
|
|
185370
185928
|
}
|
|
185371
185929
|
const auth = req.headers.authorization;
|
|
185372
185930
|
const presented = typeof auth === "string" ? auth.replace(/^Bearer\s+/i, "") : "";
|
|
185373
|
-
if (presented
|
|
185931
|
+
if (!tokensMatch(presented, this.token)) {
|
|
185374
185932
|
res.writeHead(401, { "Content-Type": "application/json" });
|
|
185375
185933
|
res.end(JSON.stringify({ error: "Unauthorized" }));
|
|
185376
185934
|
req.resume();
|
|
@@ -185422,6 +185980,7 @@ var plugin = async (ctx) => {
|
|
|
185422
185980
|
cacheSizeMb: pluginConfig.sqlite.cache_size_mb,
|
|
185423
185981
|
mmapSizeMb: pluginConfig.sqlite.mmap_size_mb
|
|
185424
185982
|
});
|
|
185983
|
+
setKeepSubagents(pluginConfig.keep_subagents === true);
|
|
185425
185984
|
const autoUpdateAbort = new AbortController;
|
|
185426
185985
|
process.once("exit", () => {
|
|
185427
185986
|
autoUpdateAbort.abort();
|