@retaw106/mmc-oc 2.3.0 → 2.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.js +12 -1
- package/dist/config/schema/magic-context.d.ts +33 -0
- package/dist/config/schema/magic-context.d.ts.map +1 -1
- package/dist/config-init.js +12 -1
- package/dist/{context-wt7g4f8k.js → context-c72brxe5.js} +717 -206
- package/dist/features/magic-context/memory-maintainer/launcher.d.ts +13 -4
- package/dist/features/magic-context/memory-maintainer/launcher.d.ts.map +1 -1
- package/dist/features/magic-context/memory-maintainer/manual-commands.d.ts.map +1 -1
- package/dist/features/magic-context/memory-maintainer/model-chain.d.ts +47 -0
- package/dist/features/magic-context/memory-maintainer/model-chain.d.ts.map +1 -0
- package/dist/features/magic-context/memory-maintainer/oc2-adapter.d.ts +17 -4
- package/dist/features/magic-context/memory-maintainer/oc2-adapter.d.ts.map +1 -1
- package/dist/features/magic-context/memory-maintainer/pipeline.d.ts +6 -0
- package/dist/features/magic-context/memory-maintainer/pipeline.d.ts.map +1 -1
- package/dist/features/magic-context/storage-tags.d.ts +4 -0
- package/dist/features/magic-context/storage-tags.d.ts.map +1 -1
- package/dist/features/magic-context/transform-decision-log.d.ts +57 -2
- package/dist/features/magic-context/transform-decision-log.d.ts.map +1 -1
- package/dist/hooks/magic-context/__fixtures__/tail-hygiene-refresh.d.ts +34 -0
- package/dist/hooks/magic-context/__fixtures__/tail-hygiene-refresh.d.ts.map +1 -0
- package/dist/hooks/magic-context/apply-operations.d.ts +3 -1
- package/dist/hooks/magic-context/apply-operations.d.ts.map +1 -1
- package/dist/hooks/magic-context/compartment-runner-types.d.ts +2 -2
- package/dist/hooks/magic-context/compartment-runner-types.d.ts.map +1 -1
- package/dist/hooks/magic-context/compartment-runner.d.ts +4 -0
- package/dist/hooks/magic-context/compartment-runner.d.ts.map +1 -1
- package/dist/hooks/magic-context/compartment-trigger-error.d.ts +11 -0
- package/dist/hooks/magic-context/compartment-trigger-error.d.ts.map +1 -0
- package/dist/hooks/magic-context/compartment-trigger.d.ts +1 -1
- package/dist/hooks/magic-context/compartment-trigger.d.ts.map +1 -1
- package/dist/hooks/magic-context/ctx-reduce-nudge.d.ts +1 -0
- package/dist/hooks/magic-context/ctx-reduce-nudge.d.ts.map +1 -1
- package/dist/hooks/magic-context/degraded-pass-refusal.d.ts +2 -0
- package/dist/hooks/magic-context/degraded-pass-refusal.d.ts.map +1 -1
- package/dist/hooks/magic-context/edit-marker.d.ts +2 -0
- package/dist/hooks/magic-context/edit-marker.d.ts.map +1 -1
- package/dist/hooks/magic-context/final-wire-token-estimate.d.ts +2 -0
- package/dist/hooks/magic-context/final-wire-token-estimate.d.ts.map +1 -1
- package/dist/hooks/magic-context/pending-drop-eligibility.d.ts +14 -0
- package/dist/hooks/magic-context/pending-drop-eligibility.d.ts.map +1 -0
- package/dist/hooks/magic-context/pending-materialization.d.ts +2 -0
- package/dist/hooks/magic-context/pending-materialization.d.ts.map +1 -1
- package/dist/hooks/magic-context/provider-visible-parts.d.ts +10 -4
- package/dist/hooks/magic-context/provider-visible-parts.d.ts.map +1 -1
- package/dist/hooks/magic-context/render-options.d.ts +19 -0
- package/dist/hooks/magic-context/render-options.d.ts.map +1 -0
- package/dist/hooks/magic-context/supersession-reclaim.d.ts +5 -3
- package/dist/hooks/magic-context/supersession-reclaim.d.ts.map +1 -1
- package/dist/hooks/magic-context/system-prompt-hash.d.ts.map +1 -1
- package/dist/hooks/magic-context/tail-hygiene-output-count.d.ts +18 -0
- package/dist/hooks/magic-context/tail-hygiene-output-count.d.ts.map +1 -0
- package/dist/hooks/magic-context/tail-hygiene-walk.d.ts +8 -4
- package/dist/hooks/magic-context/tail-hygiene-walk.d.ts.map +1 -1
- package/dist/hooks/magic-context/tool-drop-target.d.ts.map +1 -1
- package/dist/hooks/magic-context/tool-reclaim.d.ts +5 -2
- package/dist/hooks/magic-context/tool-reclaim.d.ts.map +1 -1
- package/dist/hooks/magic-context/transform-compartment-phase.d.ts.map +1 -1
- package/dist/hooks/magic-context/transform-postprocess-phase.d.ts +2 -0
- package/dist/hooks/magic-context/transform-postprocess-phase.d.ts.map +1 -1
- package/dist/hooks/magic-context/transform.d.ts +0 -7
- package/dist/hooks/magic-context/transform.d.ts.map +1 -1
- package/dist/hooks/magic-context/unresolved-history-boundary.d.ts +5 -1
- package/dist/hooks/magic-context/unresolved-history-boundary.d.ts.map +1 -1
- package/dist/{index-3gj1ak4c.js → index-27ddyx39.js} +1 -1
- package/dist/{index-z2w1eq3y.js → index-48e9znrc.js} +491 -197
- package/dist/{index-z2g20msd.js → index-azbmnekv.js} +4 -4
- package/dist/{index-czba8tw3.js → index-dwh99z66.js} +33 -10
- package/dist/{index-kw21z5pe.js → index-kahkxcqw.js} +7005 -6903
- package/dist/{index-a5mw0xp3.js → index-r7s7d350.js} +1 -1
- package/dist/{index-18yrysyj.js → index-ykq24x1n.js} +1 -1
- package/dist/index.js +2 -2
- package/dist/{message-time-backfill-sykevdax.js → message-time-backfill-j96x1sab.js} +1 -1
- package/dist/model-resolution-cvyrrcjw.js +8 -0
- package/dist/plugin/rpc-handlers.d.ts.map +1 -1
- package/dist/{read-session-chunk-863d6c06.js → read-session-chunk-t8bg6wkz.js} +3 -3
- package/dist/{recomp-orchestrator-wrjy3qym.js → recomp-orchestrator-k760qy1n.js} +6 -6
- package/dist/{send-session-notification-cz6ev088.js → send-session-notification-njjf3b4s.js} +3 -3
- package/dist/shared/model-suggestion-retry.d.ts +21 -0
- package/dist/shared/model-suggestion-retry.d.ts.map +1 -1
- package/dist/shared/prompt-surface-runtime.d.ts +5 -0
- package/dist/shared/prompt-surface-runtime.d.ts.map +1 -1
- package/dist/shared/reclaim-distance.d.ts +33 -0
- package/dist/shared/reclaim-distance.d.ts.map +1 -0
- package/dist/shared/sqlite.d.ts +2 -0
- package/dist/shared/sqlite.d.ts.map +1 -1
- package/dist/shared/stable-json.d.ts +7 -0
- package/dist/shared/stable-json.d.ts.map +1 -1
- package/dist/shared/tail-hygiene-json.d.ts +22 -0
- package/dist/shared/tail-hygiene-json.d.ts.map +1 -0
- package/dist/shared/user-facing-codes.d.ts +2 -2
- package/dist/v2/hidden-completion.d.ts +20 -1
- package/dist/v2/hidden-completion.d.ts.map +1 -1
- package/dist/v2/hooks/context.d.ts.map +1 -1
- package/dist/v2/hooks/hidden-child.d.ts +22 -1
- package/dist/v2/hooks/hidden-child.d.ts.map +1 -1
- package/dist/v2/server.js +8312 -7354
- package/dist/v2/store-reader.d.ts +27 -1
- package/dist/v2/store-reader.d.ts.map +1 -1
- package/dist/web/main.js +34 -10
- package/dist/{wrapup-orchestrator-bmybc5p5.js → wrapup-orchestrator-b2gswatj.js} +6 -6
- package/package.json +1 -1
- package/src/config/latch-permanence-guard.test.ts +4 -0
- package/src/config/project-security.test.ts +17 -0
- package/src/config/schema/magic-context.test.ts +50 -0
- package/src/config/schema/magic-context.ts +34 -1
- package/src/shared/model-suggestion-retry.ts +5 -1
- package/src/shared/prompt-surface-runtime.ts +12 -0
- package/src/shared/reclaim-distance.test.ts +111 -0
- package/src/shared/reclaim-distance.ts +91 -0
- package/src/shared/root-async-context.probe.mjs +36 -0
- package/src/shared/root-async-context.test.ts +49 -0
- package/src/shared/sqlite-busy-budget-review.test.ts +291 -0
- package/src/shared/sqlite-foreground-wait.test.ts +237 -1
- package/src/shared/sqlite.ts +55 -14
- package/src/shared/stable-json.ts +56 -14
- package/src/shared/tail-hygiene-json.test.ts +117 -0
- package/src/shared/tail-hygiene-json.ts +217 -0
- package/src/shared/user-facing-codes.ts +2 -2
- package/dist/model-resolution-wazv26n0.js +0 -6
|
@@ -110,17 +110,43 @@ interface ReaderConnection {
|
|
|
110
110
|
}
|
|
111
111
|
/** Boot-scoped read-only handles. Each lease still closes in the caller's finally block.
|
|
112
112
|
* Statements, not results, are cached: WAL updates are visible on the next query.
|
|
113
|
-
* A replaced/missing file cannot reuse the old inode, and disposal releases all handles.
|
|
113
|
+
* A replaced/missing file cannot reuse the old inode, and disposal releases all handles.
|
|
114
|
+
*
|
|
115
|
+
* Work that opens readers over a long time (a hidden run polls the store for its whole
|
|
116
|
+
* lifetime) takes a `hold()`. Closing the pool while a hold is outstanding only marks it
|
|
117
|
+
* closing: readers can still be opened, and the pool closes when the last hold is
|
|
118
|
+
* released. Without that, disposing the plugin instance mid-run made the run's next poll
|
|
119
|
+
* fail with "Store reader pool is closed". */
|
|
114
120
|
export declare class V2StoreReaderPool {
|
|
115
121
|
private readonly capacity;
|
|
116
122
|
private readonly connections;
|
|
117
123
|
private closed;
|
|
124
|
+
private closing;
|
|
125
|
+
private holds;
|
|
126
|
+
private readonly idleWaiters;
|
|
118
127
|
constructor(capacity?: number);
|
|
119
128
|
open(path: string): V2StoreReader;
|
|
120
129
|
acquire(path: string): ReaderConnection;
|
|
121
130
|
release(connection: ReaderConnection): void;
|
|
122
131
|
private retire;
|
|
132
|
+
/**
|
|
133
|
+
* Keep the pool open until the returned release is called. Refused once the pool is
|
|
134
|
+
* closing or closed, so a close always finishes once the existing holders are done.
|
|
135
|
+
*/
|
|
136
|
+
hold(): () => void;
|
|
137
|
+
/** True once every handle is closed and no further reader can be opened. */
|
|
138
|
+
isClosed(): boolean;
|
|
139
|
+
/** Number of outstanding holds. */
|
|
140
|
+
holdCount(): number;
|
|
141
|
+
/** Close now when nothing holds the pool; otherwise close after the last hold is released. */
|
|
123
142
|
close(): void;
|
|
143
|
+
/**
|
|
144
|
+
* `close()`, then wait at most `timeoutMs` for the pool to actually close. Resolves
|
|
145
|
+
* true when it closed within the wait. On false the pool is still closing and will
|
|
146
|
+
* close when its last hold is released; the caller is not kept waiting for that.
|
|
147
|
+
*/
|
|
148
|
+
closeWhenIdle(timeoutMs: number): Promise<boolean>;
|
|
149
|
+
private finishClose;
|
|
124
150
|
}
|
|
125
151
|
/** Opens an existing store read-only; missing/corrupt stores propagate errors, never an empty history. */
|
|
126
152
|
export declare class V2StoreReader {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"store-reader.d.ts","sourceRoot":"","sources":["../../src/v2/store-reader.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"store-reader.d.ts","sourceRoot":"","sources":["../../src/v2/store-reader.ts"],"names":[],"mappings":"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"}
|
package/dist/web/main.js
CHANGED
|
@@ -446,7 +446,10 @@ var init_logger = __esm(() => {
|
|
|
446
446
|
});
|
|
447
447
|
|
|
448
448
|
// src/shared/sqlite.ts
|
|
449
|
-
import { AsyncLocalStorage } from "node:async_hooks";
|
|
449
|
+
import { AsyncLocalStorage, AsyncResource } from "node:async_hooks";
|
|
450
|
+
function inRootAsyncContext(operation) {
|
|
451
|
+
return resourceRoot.runInAsyncScope(operation);
|
|
452
|
+
}
|
|
450
453
|
function registerSlowWriteReporter(reporter) {
|
|
451
454
|
reportSlowPrivilegedWrite = reporter;
|
|
452
455
|
}
|
|
@@ -597,7 +600,7 @@ function installTransactionRouting(db, readonly) {
|
|
|
597
600
|
return endWriterTransaction(db, () => nativeExec(sql), sql);
|
|
598
601
|
if (!/^\s*(?:SELECT|EXPLAIN|PRAGMA|COMMIT|END|ROLLBACK|SAVEPOINT|RELEASE)\b/i.test(sql)) {
|
|
599
602
|
try {
|
|
600
|
-
return withAutocommitTimeout(db, () => nativeExec(sql));
|
|
603
|
+
return withAutocommitTimeout(db, () => nativeExec(sql), false);
|
|
601
604
|
} finally {
|
|
602
605
|
if (mayChangeTagIdentity(sql))
|
|
603
606
|
tagIdentityWriteGeneration += 1;
|
|
@@ -839,29 +842,48 @@ function foregroundWaitLease() {
|
|
|
839
842
|
const lease = transformPassScope.getStore();
|
|
840
843
|
return lease?.active && !admissionScope.getStore() && !backgroundWriterScope.getStore() ? lease : undefined;
|
|
841
844
|
}
|
|
842
|
-
function withAutocommitTimeout(db, operation) {
|
|
845
|
+
function withAutocommitTimeout(db, operation, singleStatement = true) {
|
|
843
846
|
assertTransformWrite();
|
|
844
847
|
const lease = foregroundWaitLease();
|
|
845
848
|
if (isInTransaction(db))
|
|
846
849
|
return operation();
|
|
847
850
|
const scoped = lease || backgroundWriterScope.getStore();
|
|
848
851
|
const previous = scoped ? pragmaNumber(db, "busy_timeout") : null;
|
|
849
|
-
if (scoped)
|
|
850
|
-
db.exec(`PRAGMA busy_timeout=${lease ? Math.floor(Math.min(lease.remainingWaitMs, lease.guard?.remainingMs() ?? Infinity)) : SHORT_BUSY_TIMEOUT_MS}`);
|
|
851
852
|
const started = performance.now();
|
|
852
853
|
let completed = false;
|
|
853
|
-
|
|
854
|
+
const execute = () => {
|
|
854
855
|
const result = operation();
|
|
855
856
|
completed = true;
|
|
856
857
|
return result;
|
|
858
|
+
};
|
|
859
|
+
try {
|
|
860
|
+
if (!scoped)
|
|
861
|
+
return execute();
|
|
862
|
+
if (singleStatement) {
|
|
863
|
+
db.exec("PRAGMA busy_timeout=0");
|
|
864
|
+
try {
|
|
865
|
+
return execute();
|
|
866
|
+
} catch (error) {
|
|
867
|
+
if (!isTransientSqliteError(error) || isInTransaction(db))
|
|
868
|
+
throw error;
|
|
869
|
+
}
|
|
870
|
+
assertTransformWrite();
|
|
871
|
+
}
|
|
872
|
+
const timeout = Math.floor(Math.min(lease?.remainingWaitMs ?? SHORT_BUSY_TIMEOUT_MS, lease?.guard?.remainingMs() ?? Infinity));
|
|
873
|
+
db.exec(`PRAGMA busy_timeout=${timeout}`);
|
|
874
|
+
const waitStarted = performance.now();
|
|
875
|
+
try {
|
|
876
|
+
return execute();
|
|
877
|
+
} finally {
|
|
878
|
+
if (lease)
|
|
879
|
+
lease.remainingWaitMs = Math.max(0, lease.remainingWaitMs - (performance.now() - waitStarted));
|
|
880
|
+
}
|
|
857
881
|
} catch (error) {
|
|
858
882
|
if (lease && isTransientSqliteError(error))
|
|
859
883
|
throw new SqliteAcquisitionBusyError(error, "autocommit");
|
|
860
884
|
throw error;
|
|
861
885
|
} finally {
|
|
862
886
|
const elapsed = performance.now() - started;
|
|
863
|
-
if (lease)
|
|
864
|
-
lease.remainingWaitMs = Math.max(0, lease.remainingWaitMs - elapsed);
|
|
865
887
|
if (previous !== null)
|
|
866
888
|
db.exec(`PRAGMA busy_timeout=${previous}`);
|
|
867
889
|
if (elapsed >= SLOW_WRITER_LOG_MS)
|
|
@@ -935,8 +957,9 @@ function isInTransaction(db) {
|
|
|
935
957
|
const candidate = db;
|
|
936
958
|
return candidate.inTransaction === true || candidate.isTransaction === true;
|
|
937
959
|
}
|
|
938
|
-
var reportSlowPrivilegedWrite, sqliteDiagnosticSink, sqliteDiagnosticHost = () => "unknown", bunSpec, nodeSpec, SqliteRuntimeUnavailableError, detectedRuntime, isBun, sqliteModule, DatabaseImpl, trackedSqliteConnections, nextSqliteConnectionSequence = 1, TAG_COLUMNS_OUTSIDE_IDENTITY, tagIdentityWriteGeneration = 0, TrackedDatabase, Database, statementOwners, FIRST_PRUNE_AT = 256, privilegeDepth, transformPassScope, admissionScope, backgroundWriterScope, SqliteAcquisitionBusyError, SHORT_BUSY_TIMEOUT_MS = 25, SLOW_WRITER_LOG_MS = 100, WRITER_TRANSACTION_END, writerAcquisitionScope, openWriterTransactions, indexCoordinationKey, indexCoordinationHeap, indexCoordinationBuffer, indexCoordinationState;
|
|
960
|
+
var resourceRoot, reportSlowPrivilegedWrite, sqliteDiagnosticSink, sqliteDiagnosticHost = () => "unknown", bunSpec, nodeSpec, SqliteRuntimeUnavailableError, detectedRuntime, isBun, sqliteModule, DatabaseImpl, trackedSqliteConnections, nextSqliteConnectionSequence = 1, TAG_COLUMNS_OUTSIDE_IDENTITY, tagIdentityWriteGeneration = 0, TrackedDatabase, Database, statementOwners, FIRST_PRUNE_AT = 256, privilegeDepth, transformPassScope, admissionScope, backgroundWriterScope, SqliteAcquisitionBusyError, SHORT_BUSY_TIMEOUT_MS = 25, SLOW_WRITER_LOG_MS = 100, WRITER_TRANSACTION_END, writerAcquisitionScope, openWriterTransactions, indexCoordinationKey, indexCoordinationHeap, indexCoordinationBuffer, indexCoordinationState;
|
|
939
961
|
var init_sqlite = __esm(async () => {
|
|
962
|
+
resourceRoot = new AsyncResource("magic-context:root");
|
|
940
963
|
bunSpec = "bun:" + "sqlite";
|
|
941
964
|
nodeSpec = "node:" + "sqlite";
|
|
942
965
|
SqliteRuntimeUnavailableError = class SqliteRuntimeUnavailableError extends Error {
|
|
@@ -970,7 +993,7 @@ var init_sqlite = __esm(async () => {
|
|
|
970
993
|
]);
|
|
971
994
|
TrackedDatabase = new Proxy(DatabaseImpl, {
|
|
972
995
|
construct(target, args) {
|
|
973
|
-
const db = Reflect.construct(target, args, target);
|
|
996
|
+
const db = inRootAsyncContext(() => Reflect.construct(target, args, target));
|
|
974
997
|
return trackSqliteConnection(db, args[0], args[1]);
|
|
975
998
|
}
|
|
976
999
|
});
|
|
@@ -5150,6 +5173,7 @@ var AGENT_STEP_CAPS = {
|
|
|
5150
5173
|
[MEMORY_MAINTAINER_A_AGENT]: MEMORY_MAINTAINER_A_STEP_CAP,
|
|
5151
5174
|
[HIDDEN_HISTORIAN_AGENT]: HISTORIAN_STEP_CAP
|
|
5152
5175
|
};
|
|
5176
|
+
var DISPOSED_CHILDREN_KEY = Symbol.for("magic-context.v2.disposed-hidden-children");
|
|
5153
5177
|
|
|
5154
5178
|
// src/v2/hidden-child-record.ts
|
|
5155
5179
|
var HIDDEN_CHILD_ROLE_TITLES = {
|
|
@@ -21,11 +21,11 @@ import {
|
|
|
21
21
|
getActiveCompartmentRun,
|
|
22
22
|
markActiveCompartmentRunPublished,
|
|
23
23
|
registerActiveCompartmentRun
|
|
24
|
-
} from "./index-
|
|
25
|
-
import"./index-
|
|
24
|
+
} from "./index-kahkxcqw.js";
|
|
25
|
+
import"./index-dwh99z66.js";
|
|
26
26
|
import"./index-x37vg474.js";
|
|
27
|
-
import"./index-
|
|
28
|
-
import"./index-
|
|
27
|
+
import"./index-48e9znrc.js";
|
|
28
|
+
import"./index-ykq24x1n.js";
|
|
29
29
|
import {
|
|
30
30
|
pushNotification2
|
|
31
31
|
} from "./index-jdxxq8cz.js";
|
|
@@ -33,11 +33,11 @@ import"./index-5ty9rnbx.js";
|
|
|
33
33
|
import"./index-kmbme1v1.js";
|
|
34
34
|
import {
|
|
35
35
|
sendStatusNotification2
|
|
36
|
-
} from "./index-
|
|
36
|
+
} from "./index-r7s7d350.js";
|
|
37
37
|
import {
|
|
38
38
|
setRecompStarting2,
|
|
39
39
|
setRecompTerminal2
|
|
40
|
-
} from "./index-
|
|
40
|
+
} from "./index-27ddyx39.js";
|
|
41
41
|
import"./index-yjv8dpht.js";
|
|
42
42
|
|
|
43
43
|
// src/hooks/magic-context/wrapup-orchestrator.ts
|
package/package.json
CHANGED
|
@@ -153,6 +153,10 @@ const KNOWN_SLOTS: Record<string, KnownSlot> = {
|
|
|
153
153
|
classification: "DIAGNOSTIC",
|
|
154
154
|
reason: "Most-recent diagnostic: every open attempt clears or overwrites it.",
|
|
155
155
|
},
|
|
156
|
+
"packages/pi-plugin/src/index.ts:loggedPiMaintenanceModelMissing": {
|
|
157
|
+
classification: "PUBLICATION",
|
|
158
|
+
reason: "Once-per-process log dedup only (plan 18): the unconfigured-maintenance diagnosis is logged once to avoid per-pass spam. It gates no behavior — buildPiMaintenanceOptions re-evaluates the model chain on every call.",
|
|
159
|
+
},
|
|
156
160
|
"packages/plugin/src/shared/models-dev-cache.ts:apiCache": {
|
|
157
161
|
classification: "PUBLICATION",
|
|
158
162
|
reason: "Publishes last-known-good model metadata, not a failure verdict; refresh writes a later successful value.",
|
|
@@ -268,6 +268,23 @@ describe("stripUnsafeProjectConfigFields", () => {
|
|
|
268
268
|
expect(warnings.some((w) => w.includes("maintenance"))).toBe(true);
|
|
269
269
|
});
|
|
270
270
|
|
|
271
|
+
it("plan 18: strips a project-injected maintenance model chain (no model hijack)", () => {
|
|
272
|
+
const raw: Record<string, unknown> = {
|
|
273
|
+
maintenance: {
|
|
274
|
+
enabled: true,
|
|
275
|
+
model: "attacker/spender",
|
|
276
|
+
fallback_models: ["attacker/backup"],
|
|
277
|
+
},
|
|
278
|
+
};
|
|
279
|
+
const warnings = stripUnsafeProjectConfigFields(raw);
|
|
280
|
+
|
|
281
|
+
// The whole-group strip removes the model fields with everything
|
|
282
|
+
// else: a cloned repo cannot redirect the user's maintenance runs
|
|
283
|
+
// onto its own (possibly billable) models.
|
|
284
|
+
expect(raw.maintenance).toBeUndefined();
|
|
285
|
+
expect(warnings.some((w) => w.includes("maintenance"))).toBe(true);
|
|
286
|
+
});
|
|
287
|
+
|
|
271
288
|
it("is a no-op for a clean project config", () => {
|
|
272
289
|
const raw: Record<string, unknown> = { dreamer: { model: "x" }, memory: { enabled: true } };
|
|
273
290
|
const warnings = stripUnsafeProjectConfigFields(raw);
|
|
@@ -135,6 +135,7 @@ describe("MagicContextConfigSchema", () => {
|
|
|
135
135
|
},
|
|
136
136
|
maintenance: {
|
|
137
137
|
enabled: true,
|
|
138
|
+
fallback_models: [],
|
|
138
139
|
budgets: {
|
|
139
140
|
inputTokens: 400_000,
|
|
140
141
|
outputTokens: 32_000,
|
|
@@ -159,6 +160,55 @@ describe("MagicContextConfigSchema", () => {
|
|
|
159
160
|
expect(result).toEqual(input);
|
|
160
161
|
});
|
|
161
162
|
|
|
163
|
+
it("parses both maintenance model spellings and distinguishes absent from empty fallbacks", () => {
|
|
164
|
+
const stringForm = MagicContextConfigSchema.parse({
|
|
165
|
+
maintenance: { enabled: true, model: "openai/gpt-6-luna" },
|
|
166
|
+
}).maintenance;
|
|
167
|
+
expect(stringForm.model).toBe("openai/gpt-6-luna");
|
|
168
|
+
expect(stringForm.fallback_models).toBeUndefined();
|
|
169
|
+
expect(
|
|
170
|
+
MagicContextConfigSchema.parse({
|
|
171
|
+
maintenance: { fallback_models: [] },
|
|
172
|
+
}).maintenance.fallback_models,
|
|
173
|
+
).toEqual([]);
|
|
174
|
+
|
|
175
|
+
const objectForm = MagicContextConfigSchema.parse({
|
|
176
|
+
maintenance: {
|
|
177
|
+
enabled: true,
|
|
178
|
+
model: { model: "xiaomi/mimo-v2.6-flash", variant: "high" },
|
|
179
|
+
fallback_models: ["openai/gpt-6-luna", { model: "p/l", thinking_level: "off" }],
|
|
180
|
+
},
|
|
181
|
+
}).maintenance;
|
|
182
|
+
// Object entries keep both harness qualifiers verbatim — the
|
|
183
|
+
// active harness reads its own, no cross-harness mapping.
|
|
184
|
+
expect(objectForm.model).toEqual({
|
|
185
|
+
model: "xiaomi/mimo-v2.6-flash",
|
|
186
|
+
variant: "high",
|
|
187
|
+
});
|
|
188
|
+
expect(objectForm.fallback_models).toEqual([
|
|
189
|
+
"openai/gpt-6-luna",
|
|
190
|
+
{ model: "p/l", thinking_level: "off" },
|
|
191
|
+
]);
|
|
192
|
+
});
|
|
193
|
+
|
|
194
|
+
it("plan 18: rejects blank maintenance model references at parse time (no silent executor flow)", () => {
|
|
195
|
+
expect(
|
|
196
|
+
MagicContextConfigSchema.safeParse({
|
|
197
|
+
maintenance: { enabled: true, model: " " },
|
|
198
|
+
}).success,
|
|
199
|
+
).toBe(false);
|
|
200
|
+
expect(
|
|
201
|
+
MagicContextConfigSchema.safeParse({
|
|
202
|
+
maintenance: { enabled: true, model: { model: "" } },
|
|
203
|
+
}).success,
|
|
204
|
+
).toBe(false);
|
|
205
|
+
expect(
|
|
206
|
+
MagicContextConfigSchema.safeParse({
|
|
207
|
+
maintenance: { enabled: true, fallback_models: ["ok/one", " "] },
|
|
208
|
+
}).success,
|
|
209
|
+
).toBe(false);
|
|
210
|
+
});
|
|
211
|
+
|
|
162
212
|
it("accepts a boolean storage permission policy and rejects non-booleans", () => {
|
|
163
213
|
expect(
|
|
164
214
|
MagicContextConfigSchema.parse({
|
|
@@ -135,6 +135,23 @@ const HistorianModelEntryObjectSchema = z
|
|
|
135
135
|
export const HistorianModelEntrySchema = z.union([z.string(), HistorianModelEntryObjectSchema]);
|
|
136
136
|
export type HistorianModelEntry = z.infer<typeof HistorianModelEntrySchema>;
|
|
137
137
|
|
|
138
|
+
/**
|
|
139
|
+
* A maintenance model entry (plan 18): the same string/object shape as a
|
|
140
|
+
* historian model entry, but blank references are REJECTED at parse time —
|
|
141
|
+
* a blank primary must surface as a config diagnostic, never silently flow
|
|
142
|
+
* into the hidden executor or get corrected to some other model.
|
|
143
|
+
*/
|
|
144
|
+
const MaintenanceModelEntrySchema = HistorianModelEntrySchema.superRefine((entry, ctx) => {
|
|
145
|
+
const model = typeof entry === "string" ? entry : entry.model;
|
|
146
|
+
if (typeof model !== "string" || model.trim().length === 0) {
|
|
147
|
+
ctx.addIssue({
|
|
148
|
+
code: "custom",
|
|
149
|
+
message:
|
|
150
|
+
"maintenance model entries must be non-empty: a bare provider/model string or { model, variant?, thinking_level? }",
|
|
151
|
+
});
|
|
152
|
+
}
|
|
153
|
+
});
|
|
154
|
+
|
|
138
155
|
/**
|
|
139
156
|
* A profile may select models but must not alter execution policy. It uses the
|
|
140
157
|
* same flat historian model-resolution fields; execution metadata is not
|
|
@@ -400,6 +417,13 @@ export interface MagicContextConfig {
|
|
|
400
417
|
*/
|
|
401
418
|
maintenance: {
|
|
402
419
|
enabled: boolean;
|
|
420
|
+
/**
|
|
421
|
+
* Primary maintenance model entry. When absent, inherit historian
|
|
422
|
+
* model configuration; never inherit the main-session model.
|
|
423
|
+
*/
|
|
424
|
+
model?: HistorianModelEntry;
|
|
425
|
+
/** Ordered fallbacks; absent inherits historian fallbacks only with an inherited primary. */
|
|
426
|
+
fallback_models?: HistorianModelEntry[];
|
|
403
427
|
/** Per-run four-dimensional budget (decision 9; provisional, calibrated in P3/P4). */
|
|
404
428
|
budgets: {
|
|
405
429
|
inputTokens: number;
|
|
@@ -800,6 +824,15 @@ export const MagicContextConfigSchema = z.object({
|
|
|
800
824
|
.describe(
|
|
801
825
|
"Enable the automatic memory-maintenance task (default: true). USER-LEVEL ONLY — the whole maintenance group is stripped from project-tier config.",
|
|
802
826
|
),
|
|
827
|
+
model: MaintenanceModelEntrySchema.optional().describe(
|
|
828
|
+
"Primary maintenance model entry: a bare provider/model string or { model, variant? (OpenCode), thinking_level? (Pi) }. USER-LEVEL ONLY. When absent, inherit historian model configuration. If neither has a primary, automatic passes skip and manual runs refuse. The main-session model is never inherited.",
|
|
829
|
+
),
|
|
830
|
+
fallback_models: z
|
|
831
|
+
.array(MaintenanceModelEntrySchema)
|
|
832
|
+
.optional()
|
|
833
|
+
.describe(
|
|
834
|
+
"Ordered fallback maintenance model entries, tried after CALL failures only. When absent and the primary is inherited, inherit historian fallbacks; explicit [] disables fallbacks. Illegal manifests, permission refusals, and exhausted budgets never switch models.",
|
|
835
|
+
),
|
|
803
836
|
budgets: z
|
|
804
837
|
.object({
|
|
805
838
|
inputTokens: z
|
|
@@ -922,7 +955,7 @@ export const MagicContextConfigSchema = z.object({
|
|
|
922
955
|
anomalyThreshold: { absoluteRows: 10, poolFraction: 0.25 },
|
|
923
956
|
})
|
|
924
957
|
.describe(
|
|
925
|
-
"Automatic memory-maintenance run controls (dreamer replacement). USER-LEVEL ONLY:
|
|
958
|
+
"Automatic memory-maintenance run controls (dreamer replacement). USER-LEVEL ONLY: project-tier config cannot pick maintenance models or change run controls. An absent model inherits historian model configuration, never the session model.",
|
|
926
959
|
),
|
|
927
960
|
});
|
|
928
961
|
|
|
@@ -361,8 +361,12 @@ async function abortChildRun(client: Client, sessionId: string): Promise<void> {
|
|
|
361
361
|
* Everything else (auth errors, ProviderModelNotFoundError without suggestion,
|
|
362
362
|
* rate limits, transient network failures, etc.) is considered retryable on a
|
|
363
363
|
* different model.
|
|
364
|
+
* Exported as the shared fallback-switch classifier (plan 18): the
|
|
365
|
+
* memory-maintenance attempt loop reuses this exact predicate so "which
|
|
366
|
+
* failures may switch models" has ONE definition across historian and
|
|
367
|
+
* maintainer call sites.
|
|
364
368
|
*/
|
|
365
|
-
function isNonRetryable(error: unknown, externalSignal?: AbortSignal): boolean {
|
|
369
|
+
export function isNonRetryable(error: unknown, externalSignal?: AbortSignal): boolean {
|
|
366
370
|
if (
|
|
367
371
|
externalSignal?.aborted ||
|
|
368
372
|
(error instanceof HiddenCompletionRefusal && error.terminal) ||
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
1
2
|
import { readFileSync, statSync } from "node:fs";
|
|
2
3
|
import { dirname, isAbsolute, resolve } from "node:path";
|
|
3
4
|
|
|
@@ -59,6 +60,17 @@ export function promptSurfaceHashMaterial(
|
|
|
59
60
|
: `${systemContent}\n\0magic-context-prompt-surface:${preset}`;
|
|
60
61
|
}
|
|
61
62
|
|
|
63
|
+
/**
|
|
64
|
+
* Hash system text after the caller resolves guidance and freezes host date lines.
|
|
65
|
+
* Keep the legacy MD5 hex encoding so existing cached heads retain their identity.
|
|
66
|
+
*/
|
|
67
|
+
export function systemPromptFingerprint(
|
|
68
|
+
systemContent: string,
|
|
69
|
+
preset: PromptSurfacePreset = "full",
|
|
70
|
+
): string {
|
|
71
|
+
return createHash("md5").update(promptSurfaceHashMaterial(systemContent, preset)).digest("hex");
|
|
72
|
+
}
|
|
73
|
+
|
|
62
74
|
const PROMPT_SURFACE_TOOL_ID_SET = new Set<string>(ACTIVE_TOOL_IDS);
|
|
63
75
|
|
|
64
76
|
export interface PromptSurfaceGuidanceSelection {
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
import { describe, expect, it } from "bun:test";
|
|
2
|
+
import {
|
|
3
|
+
farBehindToolBookmark,
|
|
4
|
+
isReclaimUserTurn,
|
|
5
|
+
type ReclaimDistanceEntry,
|
|
6
|
+
} from "./reclaim-distance";
|
|
7
|
+
|
|
8
|
+
const output = (tag: number, tokens = 1000): ReclaimDistanceEntry => ({
|
|
9
|
+
toolOutputTag: tag,
|
|
10
|
+
tokens,
|
|
11
|
+
});
|
|
12
|
+
const turn = (): ReclaimDistanceEntry => ({ userTurn: true, tokens: 10 });
|
|
13
|
+
|
|
14
|
+
describe("reclaim distance", () => {
|
|
15
|
+
it("repeated rebuilds cannot age the current task", () => {
|
|
16
|
+
const entries = [turn(), ...Array.from({ length: 28 }, (_, i) => output(i + 1))];
|
|
17
|
+
for (const count of [2, 3, 5]) {
|
|
18
|
+
let bookmark = 0;
|
|
19
|
+
for (let pass = 0; pass < count + 1; pass++) {
|
|
20
|
+
expect(bookmark).toBe(0);
|
|
21
|
+
bookmark = Math.max(bookmark, farBehindToolBookmark(entries, 200_000));
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
it("three newer user turns establish a bookmark, not two", () => {
|
|
27
|
+
const entries = [turn(), output(1), turn(), output(2), turn()];
|
|
28
|
+
expect(farBehindToolBookmark(entries, 200_000)).toBe(0);
|
|
29
|
+
expect(farBehindToolBookmark([...entries, turn()], 200_000)).toBe(1);
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
it("single-turn tool loop ages at exactly a quarter of the usable window", () => {
|
|
33
|
+
const entries = [turn(), output(1), output(2, 49_999)];
|
|
34
|
+
expect(farBehindToolBookmark(entries, 200_000)).toBe(0);
|
|
35
|
+
expect(farBehindToolBookmark([...entries, { tokens: 1 }], 200_000)).toBe(1);
|
|
36
|
+
expect(farBehindToolBookmark([turn(), output(1, 100_000)], 200_000)).toBe(0);
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
it("multipart outputs never age from their own trailing chunks", () => {
|
|
40
|
+
expect(farBehindToolBookmark([output(1), output(1, 60_000)], 200_000)).toBe(0);
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
it("unknown windows disable only token distance", () => {
|
|
44
|
+
expect(farBehindToolBookmark([output(1), output(2, 99_999)], 0)).toBe(0);
|
|
45
|
+
expect(farBehindToolBookmark([output(1), turn(), turn(), turn()], 0)).toBe(1);
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
it("excludes synthetic host wakes, MC reminders, heads and result carriers", () => {
|
|
49
|
+
expect(
|
|
50
|
+
isReclaimUserTurn({
|
|
51
|
+
role: "user",
|
|
52
|
+
parts: [
|
|
53
|
+
{
|
|
54
|
+
kind: "text",
|
|
55
|
+
synthetic: true,
|
|
56
|
+
text: "<system-reminder>Background task finished.</system-reminder>",
|
|
57
|
+
},
|
|
58
|
+
],
|
|
59
|
+
}),
|
|
60
|
+
).toBe(false);
|
|
61
|
+
expect(
|
|
62
|
+
isReclaimUserTurn({
|
|
63
|
+
role: "user",
|
|
64
|
+
parts: [
|
|
65
|
+
{
|
|
66
|
+
kind: "text",
|
|
67
|
+
text: "<system-reminder>Your next step: call ctx_reduce on the outputs you've already used (5).</system-reminder>",
|
|
68
|
+
},
|
|
69
|
+
],
|
|
70
|
+
}),
|
|
71
|
+
).toBe(false);
|
|
72
|
+
expect(
|
|
73
|
+
isReclaimUserTurn({
|
|
74
|
+
role: "user",
|
|
75
|
+
syntheticHead: true,
|
|
76
|
+
parts: [{ kind: "text", text: "history" }],
|
|
77
|
+
}),
|
|
78
|
+
).toBe(false);
|
|
79
|
+
expect(
|
|
80
|
+
isReclaimUserTurn({ role: "user", parts: [{ kind: "tool_result", text: "output" }] }),
|
|
81
|
+
).toBe(false);
|
|
82
|
+
expect(
|
|
83
|
+
isReclaimUserTurn({
|
|
84
|
+
role: "user",
|
|
85
|
+
parts: [
|
|
86
|
+
{ kind: "tool_result", text: "output" },
|
|
87
|
+
{ kind: "text", text: "continue" },
|
|
88
|
+
],
|
|
89
|
+
}),
|
|
90
|
+
).toBe(true);
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
it("counts an authored part even after synthetic or ignored parts", () => {
|
|
94
|
+
for (const provenance of [{ synthetic: true }, { ignored: true }]) {
|
|
95
|
+
expect(
|
|
96
|
+
isReclaimUserTurn({ role: "user", parts: [{ kind: "image", ...provenance }] }),
|
|
97
|
+
).toBe(false);
|
|
98
|
+
expect(
|
|
99
|
+
isReclaimUserTurn({
|
|
100
|
+
role: "user",
|
|
101
|
+
parts: [{ kind: "text", text: "notice", ...provenance }, { kind: "image" }],
|
|
102
|
+
}),
|
|
103
|
+
).toBe(true);
|
|
104
|
+
}
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
it("a young lower-tag result holds back distant higher tags", () => {
|
|
108
|
+
expect(farBehindToolBookmark([output(2), output(3, 50_000), output(1)], 200_000)).toBe(0);
|
|
109
|
+
expect(farBehindToolBookmark([output(1), output(3, 50_000), output(2)], 200_000)).toBe(1);
|
|
110
|
+
});
|
|
111
|
+
});
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
export const RECLAIM_DISTANCE_USER_TURNS = 3;
|
|
2
|
+
export const RECLAIM_DISTANCE_WINDOW_FRACTION = 0.25;
|
|
3
|
+
|
|
4
|
+
export interface ReclaimDistanceEntry {
|
|
5
|
+
/** Local content tokens, excluding Magic Context's history and reduction/note reminders. */
|
|
6
|
+
tokens: number;
|
|
7
|
+
/** One event per authored user-role message, after any folded tool results. */
|
|
8
|
+
userTurn?: boolean;
|
|
9
|
+
/** Durable identifier of the tool invocation whose result ends at this entry. */
|
|
10
|
+
toolOutputTag?: number;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
/** Only authored content starts a user turn; host control notices do not. */
|
|
14
|
+
export function isReclaimUserTurn(args: {
|
|
15
|
+
role?: string;
|
|
16
|
+
syntheticHead?: boolean;
|
|
17
|
+
synthetic?: boolean;
|
|
18
|
+
ignored?: boolean;
|
|
19
|
+
parts: readonly { kind: string; text?: string; synthetic?: boolean; ignored?: boolean }[];
|
|
20
|
+
}): boolean {
|
|
21
|
+
return (
|
|
22
|
+
args.role === "user" &&
|
|
23
|
+
!args.syntheticHead &&
|
|
24
|
+
!args.synthetic &&
|
|
25
|
+
!args.ignored &&
|
|
26
|
+
args.parts.some((part) => {
|
|
27
|
+
if (part.synthetic || part.ignored) return false;
|
|
28
|
+
if (part.kind !== "text" && part.kind !== "image" && part.kind !== "file") return false;
|
|
29
|
+
if (part.kind !== "text") return true;
|
|
30
|
+
return stripReclaimMcText(part.text ?? "").trim().length > 0;
|
|
31
|
+
})
|
|
32
|
+
);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/** Remove Magic Context's reduction/note reminders, not generic host wake notices. */
|
|
36
|
+
export function stripReclaimMcText(text: string): string {
|
|
37
|
+
return text
|
|
38
|
+
.replace(/^§\d+§\s*/, "")
|
|
39
|
+
.replace(/<system-reminder>[\s\S]*?<\/system-reminder>/g, (reminder) =>
|
|
40
|
+
/^(?:Your next step: call ctx_reduce on the outputs you've already used|Still unstamped:|Housekeeping: .* are reclaimable\. Stamp each output with ctx_reduce|.* are reclaimable\. Make a ctx_reduce pass now|.* are still unstamped\. Call ctx_reduce now)/.test(
|
|
41
|
+
reminder.slice("<system-reminder>".length).trimStart(),
|
|
42
|
+
)
|
|
43
|
+
? ""
|
|
44
|
+
: reminder,
|
|
45
|
+
)
|
|
46
|
+
.replace(/<instruction name="deferred_notes">[\s\S]*?<\/instruction>/g, "");
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* A free cache rebuild is not evidence that the model has moved on. An output
|
|
51
|
+
* is far behind only after three newer user turns or a quarter-window of newer
|
|
52
|
+
* content. Return a prefix of qualifying tags; callers drop against the PREVIOUS
|
|
53
|
+
* durable bookmark before advancing it, so distance must survive two rebuilds.
|
|
54
|
+
*/
|
|
55
|
+
export function farBehindToolBookmark(
|
|
56
|
+
entries: readonly ReclaimDistanceEntry[],
|
|
57
|
+
usableWindow: number,
|
|
58
|
+
): number {
|
|
59
|
+
let newerTurns = 0;
|
|
60
|
+
let newerTokens = 0;
|
|
61
|
+
const farTags: number[] = [];
|
|
62
|
+
let firstYoungTag = Infinity;
|
|
63
|
+
const seenOutputs = new Set<number>();
|
|
64
|
+
const tokenDistance =
|
|
65
|
+
usableWindow > 0 && Number.isFinite(usableWindow)
|
|
66
|
+
? usableWindow * RECLAIM_DISTANCE_WINDOW_FRACTION
|
|
67
|
+
: Infinity;
|
|
68
|
+
for (let index = entries.length - 1; index >= 0; index--) {
|
|
69
|
+
const entry = entries[index];
|
|
70
|
+
if (!entry) continue;
|
|
71
|
+
const tag = entry.toolOutputTag;
|
|
72
|
+
// Multi-part outputs are positioned at their last result, not their call
|
|
73
|
+
// or first chunk: an output must never count its own remaining payload.
|
|
74
|
+
if (tag !== undefined && !seenOutputs.has(tag)) {
|
|
75
|
+
seenOutputs.add(tag);
|
|
76
|
+
if (newerTurns >= RECLAIM_DISTANCE_USER_TURNS || newerTokens >= tokenDistance) {
|
|
77
|
+
farTags.push(tag);
|
|
78
|
+
} else {
|
|
79
|
+
firstYoungTag = Math.min(firstYoungTag, tag);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
if (entry.userTurn) newerTurns++;
|
|
83
|
+
if (Number.isFinite(entry.tokens) && entry.tokens > 0) newerTokens += entry.tokens;
|
|
84
|
+
}
|
|
85
|
+
// Tags follow call order, not result arrival. A late lower-tag sibling must
|
|
86
|
+
// hold the prefix even when a higher-tag result is already distant.
|
|
87
|
+
return farTags.reduce(
|
|
88
|
+
(bookmark, tag) => (tag < firstYoungTag ? Math.max(bookmark, tag) : bookmark),
|
|
89
|
+
0,
|
|
90
|
+
);
|
|
91
|
+
}
|