@cortexkit/opencode-magic-context 0.35.1 → 0.36.1
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 +9 -5
- package/dist/agents/permissions.d.ts +17 -0
- package/dist/agents/permissions.d.ts.map +1 -1
- package/dist/{announcement-gms2nhya.js → announcement-6c1g4es4.js} +2 -2
- package/dist/config/index.d.ts.map +1 -1
- package/dist/config/schema/magic-context.d.ts +10 -0
- package/dist/config/schema/magic-context.d.ts.map +1 -1
- package/dist/{conflict-warning-hook-p2pmhvn7.js → conflict-warning-hook-mt0ttc4x.js} +5 -5
- package/dist/{derive-budgets-9crp0cvd.js → derive-budgets-88mxk2w1.js} +3 -3
- package/dist/features/magic-context/context-authority.d.ts +12 -0
- package/dist/features/magic-context/context-authority.d.ts.map +1 -1
- package/dist/features/magic-context/dreamer/classify.d.ts +2 -0
- package/dist/features/magic-context/dreamer/classify.d.ts.map +1 -1
- package/dist/features/magic-context/dreamer/evaluate-smart-notes.d.ts +4 -0
- package/dist/features/magic-context/dreamer/evaluate-smart-notes.d.ts.map +1 -1
- package/dist/features/magic-context/dreamer/lease.d.ts +10 -3
- package/dist/features/magic-context/dreamer/lease.d.ts.map +1 -1
- package/dist/features/magic-context/dreamer/map-memories.d.ts +2 -0
- package/dist/features/magic-context/dreamer/map-memories.d.ts.map +1 -1
- package/dist/features/magic-context/dreamer/module-apply.d.ts +5 -0
- package/dist/features/magic-context/dreamer/module-apply.d.ts.map +1 -1
- package/dist/features/magic-context/dreamer/promote-primers.d.ts +2 -0
- package/dist/features/magic-context/dreamer/promote-primers.d.ts.map +1 -1
- package/dist/features/magic-context/dreamer/refresh-primers.d.ts +2 -0
- package/dist/features/magic-context/dreamer/refresh-primers.d.ts.map +1 -1
- package/dist/features/magic-context/dreamer/task-executor.d.ts +1 -0
- package/dist/features/magic-context/dreamer/task-executor.d.ts.map +1 -1
- package/dist/features/magic-context/dreamer/task-scheduler.d.ts +5 -2
- package/dist/features/magic-context/dreamer/task-scheduler.d.ts.map +1 -1
- package/dist/features/magic-context/dreamer/verify.d.ts +2 -0
- package/dist/features/magic-context/dreamer/verify.d.ts.map +1 -1
- package/dist/features/magic-context/message-index-async.d.ts.map +1 -1
- package/dist/features/magic-context/migrations.d.ts.map +1 -1
- package/dist/features/magic-context/mural/compress-cues.d.ts +2 -0
- package/dist/features/magic-context/mural/compress-cues.d.ts.map +1 -1
- package/dist/features/magic-context/project-embedding-registry.d.ts.map +1 -1
- package/dist/features/magic-context/schema-fence-probe.d.ts +1 -0
- package/dist/features/magic-context/schema-fence-probe.d.ts.map +1 -1
- package/dist/features/magic-context/smart-notes/condition-compiler.d.ts +38 -0
- package/dist/features/magic-context/smart-notes/condition-compiler.d.ts.map +1 -0
- package/dist/features/magic-context/smart-notes/runner.d.ts +1 -0
- package/dist/features/magic-context/smart-notes/runner.d.ts.map +1 -1
- package/dist/features/magic-context/smart-notes/storage.d.ts +3 -3
- package/dist/features/magic-context/smart-notes/storage.d.ts.map +1 -1
- package/dist/features/magic-context/storage-clone.d.ts +6 -0
- package/dist/features/magic-context/storage-clone.d.ts.map +1 -1
- package/dist/features/magic-context/storage-db.d.ts +2 -2
- package/dist/features/magic-context/storage-db.d.ts.map +1 -1
- package/dist/features/magic-context/storage-identity-merge.d.ts.map +1 -1
- package/dist/features/magic-context/storage-notes.d.ts +13 -0
- package/dist/features/magic-context/storage-notes.d.ts.map +1 -1
- package/dist/features/magic-context/storage-tags.d.ts +2 -0
- package/dist/features/magic-context/storage-tags.d.ts.map +1 -1
- package/dist/features/magic-context/storage.d.ts +2 -2
- package/dist/features/magic-context/storage.d.ts.map +1 -1
- package/dist/features/magic-context/user-memory/review-user-memories.d.ts +2 -0
- package/dist/features/magic-context/user-memory/review-user-memories.d.ts.map +1 -1
- package/dist/hooks/magic-context/child-session-spawn.d.ts +1 -0
- package/dist/hooks/magic-context/child-session-spawn.d.ts.map +1 -1
- package/dist/hooks/magic-context/command-handler.d.ts.map +1 -1
- package/dist/hooks/magic-context/compaction-off-transition.d.ts.map +1 -1
- package/dist/hooks/magic-context/compartment-render-epoch.d.ts +5 -3
- package/dist/hooks/magic-context/compartment-render-epoch.d.ts.map +1 -1
- package/dist/hooks/magic-context/embed-session-state.d.ts +1 -1
- package/dist/hooks/magic-context/embed-session-state.d.ts.map +1 -1
- package/dist/hooks/magic-context/hook.d.ts +3 -0
- package/dist/hooks/magic-context/hook.d.ts.map +1 -1
- package/dist/hooks/magic-context/inject-compartments.d.ts +8 -0
- package/dist/hooks/magic-context/inject-compartments.d.ts.map +1 -1
- package/dist/hooks/magic-context/lkg-replay.d.ts +5 -2
- package/dist/hooks/magic-context/lkg-replay.d.ts.map +1 -1
- package/dist/hooks/magic-context/lkg-slot.d.ts +15 -1
- package/dist/hooks/magic-context/lkg-slot.d.ts.map +1 -1
- package/dist/hooks/magic-context/module-state-sync.d.ts +7 -0
- package/dist/hooks/magic-context/module-state-sync.d.ts.map +1 -1
- package/dist/hooks/magic-context/module-transport.d.ts +29 -3
- package/dist/hooks/magic-context/module-transport.d.ts.map +1 -1
- package/dist/hooks/magic-context/raw-fallback-context-limit.d.ts +10 -0
- package/dist/hooks/magic-context/raw-fallback-context-limit.d.ts.map +1 -0
- package/dist/hooks/magic-context/read-session-formatting.d.ts +1 -0
- package/dist/hooks/magic-context/read-session-formatting.d.ts.map +1 -1
- package/dist/hooks/magic-context/rust-mode-transform.d.ts +10 -2
- package/dist/hooks/magic-context/rust-mode-transform.d.ts.map +1 -1
- package/dist/hooks/magic-context/strip-content.d.ts +6 -1
- package/dist/hooks/magic-context/strip-content.d.ts.map +1 -1
- package/dist/hooks/magic-context/system-prompt-hash.d.ts.map +1 -1
- package/dist/hooks/magic-context/transform-postprocess-phase.d.ts +1 -0
- package/dist/hooks/magic-context/transform-postprocess-phase.d.ts.map +1 -1
- package/dist/hooks/magic-context/transform.d.ts.map +1 -1
- package/dist/{index-fkyamz2w.js → index-1skzp4dc.js} +444 -98
- package/dist/{index-w0nygb4p.js → index-3tnkymva.js} +2 -2
- package/dist/{index-dpdnjawy.js → index-3zqcdwqr.js} +140 -13
- package/dist/{index-0c9dmw9m.js → index-8mtsfhyg.js} +33 -3
- package/dist/{index-k1esqfwk.js → index-f1tnb3vm.js} +1 -1
- package/dist/{index-kvrcg31b.js → index-mmrhhk9a.js} +8 -1
- package/dist/{index-h5zjfesc.js → index-nsx2n9eg.js} +3 -3
- package/dist/{index-dmr999a2.js → index-qf20mv7e.js} +1 -1
- package/dist/{index-73xz0247.js → index-tsgs7td8.js} +1 -1
- package/dist/{index-ry8rh8cv.js → index-wgvxkqpx.js} +5 -4
- package/dist/{index-8aaadh98.js → index-zp6x6s6a.js} +3 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1556 -619
- package/dist/plugin/dream-timer.d.ts +1 -0
- package/dist/plugin/dream-timer.d.ts.map +1 -1
- package/dist/plugin/hooks/create-session-hooks.d.ts +3 -0
- package/dist/plugin/hooks/create-session-hooks.d.ts.map +1 -1
- package/dist/plugin/messages-transform.d.ts +5 -5
- package/dist/plugin/messages-transform.d.ts.map +1 -1
- package/dist/plugin/rust-tool-backends.d.ts +4 -0
- package/dist/plugin/rust-tool-backends.d.ts.map +1 -1
- package/dist/{recomp-orchestrator-29f4rqax.js → recomp-orchestrator-a0g9b52q.js} +8 -8
- package/dist/{safe-notification-target-q9jk5n44.js → safe-notification-target-c11fdda2.js} +3 -3
- package/dist/{send-session-notification-sr5g06hz.js → send-session-notification-bgtf4853.js} +4 -4
- package/dist/shared/conflict-fixer.d.ts.map +1 -1
- package/dist/shared/data-path.d.ts +27 -0
- package/dist/shared/data-path.d.ts.map +1 -1
- package/dist/shared/harness-provider-map.d.ts +23 -20
- package/dist/shared/harness-provider-map.d.ts.map +1 -1
- package/dist/shared/jsonc-edit.d.ts +18 -0
- package/dist/shared/jsonc-edit.d.ts.map +1 -0
- package/dist/shared/jsonc-parser.d.ts +11 -1
- package/dist/shared/jsonc-parser.d.ts.map +1 -1
- package/dist/shared/prompt-surface-runtime.d.ts +15 -2
- package/dist/shared/prompt-surface-runtime.d.ts.map +1 -1
- package/dist/shared/prompt-surface.d.ts +5 -3
- package/dist/shared/prompt-surface.d.ts.map +1 -1
- package/dist/shared/rpc-utils.d.ts +16 -0
- package/dist/shared/rpc-utils.d.ts.map +1 -1
- package/dist/shared/tui-preferences.d.ts +9 -0
- package/dist/shared/tui-preferences.d.ts.map +1 -1
- package/dist/{storage-meta-session-ev8b55a9.js → storage-meta-session-df9tstzr.js} +4 -4
- package/dist/tools/ctx-note/tools.d.ts.map +1 -1
- package/package.json +4 -3
- package/src/agents/permissions.ts +87 -0
- package/src/config/compaction-accessor-guard.test.ts +9 -4
- package/src/config/index.test.ts +23 -0
- package/src/config/index.ts +41 -9
- package/src/config/schema/magic-context.test.ts +4 -1
- package/src/config/schema/magic-context.ts +18 -3
- package/src/shared/conflict-fixer.test.ts +174 -0
- package/src/shared/conflict-fixer.ts +66 -70
- package/src/shared/data-path.test.ts +65 -9
- package/src/shared/data-path.ts +66 -1
- package/src/shared/harness-provider-map.test.ts +42 -1
- package/src/shared/harness-provider-map.ts +48 -26
- package/src/shared/jsonc-edit.ts +295 -0
- package/src/shared/jsonc-parser.test.ts +33 -0
- package/src/shared/jsonc-parser.ts +54 -2
- package/src/shared/prompt-surface-runtime.ts +13 -5
- package/src/shared/prompt-surface.test.ts +53 -2
- package/src/shared/prompt-surface.ts +20 -9
- package/src/shared/rpc-utils.test.ts +36 -0
- package/src/shared/rpc-utils.ts +71 -0
- package/src/shared/tui-preferences.test.ts +52 -2
- package/src/shared/tui-preferences.ts +42 -17
package/dist/index.js
CHANGED
|
@@ -25,6 +25,14 @@ import {
|
|
|
25
25
|
GLOBAL_USER_PROFILE_PROJECT_PATH,
|
|
26
26
|
HISTORIAN_EDITOR_SYSTEM_PROMPT,
|
|
27
27
|
LATEST_SUPPORTED_VERSION,
|
|
28
|
+
LKG_SNAPSHOT_ARRAY,
|
|
29
|
+
LKG_SNAPSHOT_BOOLEAN,
|
|
30
|
+
LKG_SNAPSHOT_KEY,
|
|
31
|
+
LKG_SNAPSHOT_NULL,
|
|
32
|
+
LKG_SNAPSHOT_NUMBER,
|
|
33
|
+
LKG_SNAPSHOT_OBJECT,
|
|
34
|
+
LKG_SNAPSHOT_STRING,
|
|
35
|
+
LKG_SNAPSHOT_UNDEFINED,
|
|
28
36
|
MARKER_SUMMARY_TEXT,
|
|
29
37
|
MAX_EXECUTE_THRESHOLD,
|
|
30
38
|
MagicContextConfigSchema,
|
|
@@ -52,6 +60,7 @@ import {
|
|
|
52
60
|
appendAutoSearchHintDecision,
|
|
53
61
|
applyDeferredCompactionMarker,
|
|
54
62
|
applyMirrorPage,
|
|
63
|
+
applyMirroredNoteCompileFields,
|
|
55
64
|
applyStrippedPlaceholderDelta,
|
|
56
65
|
archiveMemory,
|
|
57
66
|
backfillTagTokenCounts,
|
|
@@ -72,6 +81,7 @@ import {
|
|
|
72
81
|
clearEmergencyDropSample,
|
|
73
82
|
clearEmergencyRecovery,
|
|
74
83
|
clearHistorianFailureState,
|
|
84
|
+
clearHookInitFailure,
|
|
75
85
|
clearInjectionCache,
|
|
76
86
|
clearMemoryVerifications,
|
|
77
87
|
clearNoteNudgeTriggerAndCooldown,
|
|
@@ -91,6 +101,7 @@ import {
|
|
|
91
101
|
countEmbeddedCommits,
|
|
92
102
|
countPrimerCandidatesForProject,
|
|
93
103
|
createChildSessionWithFence,
|
|
104
|
+
createFailClosedController,
|
|
94
105
|
createPrimer,
|
|
95
106
|
createPromptSurfaceGuidanceEpochCache,
|
|
96
107
|
createPromptSurfaceRuntime,
|
|
@@ -145,6 +156,7 @@ import {
|
|
|
145
156
|
getHistorianFailureState,
|
|
146
157
|
getLastCompartmentEndMessage,
|
|
147
158
|
getLastCompartmentEndMessageId,
|
|
159
|
+
getLastHookInitFailure,
|
|
148
160
|
getLastNudgeLevel,
|
|
149
161
|
getLastNudgeUndropped,
|
|
150
162
|
getLatestIndexedCommitTimeMs,
|
|
@@ -227,9 +239,11 @@ import {
|
|
|
227
239
|
isDatabasePersisted,
|
|
228
240
|
isEmbeddingEnabled,
|
|
229
241
|
isEmergencyRecoveryArmed,
|
|
242
|
+
isFailClosedBlockingError,
|
|
230
243
|
isPidAlive,
|
|
231
244
|
isProviderOverflowReconfirmed,
|
|
232
245
|
lkgContentDigest,
|
|
246
|
+
lkgContentDigestFromFields,
|
|
233
247
|
loadCompartmentChunkEmbeddingsForSearch,
|
|
234
248
|
loadPersistedUsage,
|
|
235
249
|
loadProjectCommitEmbeddings,
|
|
@@ -265,6 +279,7 @@ import {
|
|
|
265
279
|
prepareCompartmentInjection,
|
|
266
280
|
primerOccurrenceKey,
|
|
267
281
|
primerOccurrenceUtcDay,
|
|
282
|
+
promptSurfaceConfigIdentity,
|
|
268
283
|
promptSurfaceHashMaterial,
|
|
269
284
|
promptSyncWithValidatedOutputRetry,
|
|
270
285
|
pruneAutoSearchHintDecisions,
|
|
@@ -282,6 +297,7 @@ import {
|
|
|
282
297
|
recordDetectedContextLimit,
|
|
283
298
|
recordEmbeddingMeasurement,
|
|
284
299
|
recordHighPressureNoEligibleHead,
|
|
300
|
+
recordHookInitFailure,
|
|
285
301
|
recordMemoryMapping,
|
|
286
302
|
recordMemoryVerifications,
|
|
287
303
|
recordMuralCueRejection,
|
|
@@ -311,6 +327,7 @@ import {
|
|
|
311
327
|
resetLastNudgeCycleIfTailShrank,
|
|
312
328
|
resetNoteNudgeCooldownOnly,
|
|
313
329
|
resetProtectedTailNoEligibleHead,
|
|
330
|
+
resolveAgentNameFromMessages,
|
|
314
331
|
resolveCompactionModeRecord,
|
|
315
332
|
resolveGitTopLevel,
|
|
316
333
|
resolveLegacyConfigSources,
|
|
@@ -356,6 +373,7 @@ import {
|
|
|
356
373
|
setRecompTerminal,
|
|
357
374
|
setSessionWorkMetrics,
|
|
358
375
|
setSqlitePragmaConfig,
|
|
376
|
+
shouldBypassFailClosedBlock,
|
|
359
377
|
shouldKeepSubagents,
|
|
360
378
|
snapRangeToCompartments,
|
|
361
379
|
sourceNameForMemory,
|
|
@@ -382,7 +400,7 @@ import {
|
|
|
382
400
|
upsertCommits,
|
|
383
401
|
verificationFileExists,
|
|
384
402
|
withContentLanguageDirective
|
|
385
|
-
} from "./index-
|
|
403
|
+
} from "./index-1skzp4dc.js";
|
|
386
404
|
import {
|
|
387
405
|
deriveHistorianChunkTokens,
|
|
388
406
|
deriveTriggerBudget,
|
|
@@ -394,7 +412,7 @@ import {
|
|
|
394
412
|
setOutputReserveConfig,
|
|
395
413
|
setStoragePrivatePermissionEnforcement,
|
|
396
414
|
shouldEnforcePrivateStoragePermissions
|
|
397
|
-
} from "./index-
|
|
415
|
+
} from "./index-wgvxkqpx.js";
|
|
398
416
|
import {
|
|
399
417
|
modelBodyField,
|
|
400
418
|
resolveFallbackChain
|
|
@@ -406,7 +424,7 @@ import {
|
|
|
406
424
|
getErrorMessage,
|
|
407
425
|
sendIgnoredMessage,
|
|
408
426
|
sendUserPrompt
|
|
409
|
-
} from "./index-
|
|
427
|
+
} from "./index-nsx2n9eg.js";
|
|
410
428
|
import {
|
|
411
429
|
ToolMutationBatch,
|
|
412
430
|
advanceToolReclaimWatermark,
|
|
@@ -446,6 +464,7 @@ import {
|
|
|
446
464
|
markSessionCleanupPending,
|
|
447
465
|
normalizeText,
|
|
448
466
|
partHasCompletedResult,
|
|
467
|
+
preloadTokenizer,
|
|
449
468
|
prependTag,
|
|
450
469
|
primeInMemoryTailRawMessageCache,
|
|
451
470
|
primeTailRawMessageCache,
|
|
@@ -463,7 +482,7 @@ import {
|
|
|
463
482
|
textMentionsRecentCommit,
|
|
464
483
|
updateSessionMeta,
|
|
465
484
|
withRawSessionMessageCache
|
|
466
|
-
} from "./index-
|
|
485
|
+
} from "./index-3zqcdwqr.js";
|
|
467
486
|
import {
|
|
468
487
|
Database,
|
|
469
488
|
closeQuietly,
|
|
@@ -472,17 +491,18 @@ import {
|
|
|
472
491
|
isMidTurn,
|
|
473
492
|
openCodeDbExists,
|
|
474
493
|
withReadOnlySessionDb
|
|
475
|
-
} from "./index-
|
|
494
|
+
} from "./index-3tnkymva.js";
|
|
476
495
|
import {
|
|
477
496
|
cleanupConflictWarnings,
|
|
478
497
|
detectConflicts,
|
|
479
498
|
sendConflictWarning
|
|
480
|
-
} from "./index-
|
|
499
|
+
} from "./index-zp6x6s6a.js";
|
|
481
500
|
import {
|
|
482
501
|
detectConfigFile,
|
|
502
|
+
isPrototypePollutionKey,
|
|
483
503
|
parseJsonc,
|
|
484
504
|
stripJsonComments
|
|
485
|
-
} from "./index-
|
|
505
|
+
} from "./index-8mtsfhyg.js";
|
|
486
506
|
import {
|
|
487
507
|
ANNOUNCEMENT_FEATURES,
|
|
488
508
|
ANNOUNCEMENT_FOOTER,
|
|
@@ -491,7 +511,7 @@ import {
|
|
|
491
511
|
isValidSemver,
|
|
492
512
|
markAnnouncementSeen,
|
|
493
513
|
shouldShowAnnouncement
|
|
494
|
-
} from "./index-
|
|
514
|
+
} from "./index-qf20mv7e.js";
|
|
495
515
|
import {
|
|
496
516
|
acknowledgeNotifications,
|
|
497
517
|
drainNotifications,
|
|
@@ -499,17 +519,17 @@ import {
|
|
|
499
519
|
pushNotification,
|
|
500
520
|
registerNotificationSink
|
|
501
521
|
} from "./index-d62ypazr.js";
|
|
502
|
-
import"./index-
|
|
522
|
+
import"./index-tsgs7td8.js";
|
|
503
523
|
import {
|
|
504
524
|
log,
|
|
505
525
|
sessionLog
|
|
506
|
-
} from "./index-
|
|
526
|
+
} from "./index-f1tnb3vm.js";
|
|
507
527
|
import {
|
|
508
528
|
getDataDir,
|
|
509
529
|
getHarness,
|
|
510
530
|
getMagicContextStorageDir,
|
|
511
531
|
getOpenCodeStorageDir
|
|
512
|
-
} from "./index-
|
|
532
|
+
} from "./index-mmrhhk9a.js";
|
|
513
533
|
import {
|
|
514
534
|
resolvePromptContext
|
|
515
535
|
} from "./index-szf8w1p5.js";
|
|
@@ -8370,6 +8390,49 @@ function buildAllowOnlyPermission(allowedTools, agentLabel) {
|
|
|
8370
8390
|
}
|
|
8371
8391
|
return permission;
|
|
8372
8392
|
}
|
|
8393
|
+
function isPermissionAction(value) {
|
|
8394
|
+
return value === "ask" || value === "allow" || value === "deny";
|
|
8395
|
+
}
|
|
8396
|
+
function isPermissionMap(value) {
|
|
8397
|
+
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
8398
|
+
}
|
|
8399
|
+
function denyTaskRoutingToAgents(permission, internalAgentIds) {
|
|
8400
|
+
const configured = isPermissionAction(permission) ? { "*": permission } : isPermissionMap(permission) ? permission : {};
|
|
8401
|
+
const { task, ...otherPermissions } = configured;
|
|
8402
|
+
const configuredTask = isPermissionAction(task) ? { "*": task } : isPermissionMap(task) ? task : {};
|
|
8403
|
+
const internalAgentIdSet = new Set(internalAgentIds);
|
|
8404
|
+
const retainedTask = Object.fromEntries(Object.entries(configuredTask).filter(([agentId]) => !internalAgentIdSet.has(agentId)));
|
|
8405
|
+
return {
|
|
8406
|
+
...otherPermissions,
|
|
8407
|
+
task: {
|
|
8408
|
+
...retainedTask,
|
|
8409
|
+
...Object.fromEntries(internalAgentIds.map((agentId) => [agentId, "deny"]))
|
|
8410
|
+
}
|
|
8411
|
+
};
|
|
8412
|
+
}
|
|
8413
|
+
var BUILTIN_TASK_CALLER_IDS = ["build", "plan"];
|
|
8414
|
+
function isTaskRoutingCaller(agentId, config) {
|
|
8415
|
+
const mode = config.mode;
|
|
8416
|
+
if (mode === "primary")
|
|
8417
|
+
return true;
|
|
8418
|
+
if (mode === "subagent" || mode === "all")
|
|
8419
|
+
return false;
|
|
8420
|
+
return agentId === "build" || agentId === "plan";
|
|
8421
|
+
}
|
|
8422
|
+
function denyTaskRoutingToCallerAgents(agentConfigs, internalAgentIds) {
|
|
8423
|
+
const result = { ...agentConfigs };
|
|
8424
|
+
const candidateIds = new Set([...BUILTIN_TASK_CALLER_IDS, ...Object.keys(agentConfigs)]);
|
|
8425
|
+
for (const agentId of candidateIds) {
|
|
8426
|
+
const agentConfig = agentConfigs[agentId] ?? {};
|
|
8427
|
+
if (!isTaskRoutingCaller(agentId, agentConfig))
|
|
8428
|
+
continue;
|
|
8429
|
+
result[agentId] = {
|
|
8430
|
+
...agentConfig,
|
|
8431
|
+
permission: denyTaskRoutingToAgents(agentConfig.permission, internalAgentIds)
|
|
8432
|
+
};
|
|
8433
|
+
}
|
|
8434
|
+
return result;
|
|
8435
|
+
}
|
|
8373
8436
|
function applyDisallowedTools(defaults, disallowed) {
|
|
8374
8437
|
if (disallowed.includes("*"))
|
|
8375
8438
|
return [];
|
|
@@ -9463,10 +9526,15 @@ function loadConfigFileDetailed(configPath, source) {
|
|
|
9463
9526
|
configPath,
|
|
9464
9527
|
isProjectConfig: source === "project"
|
|
9465
9528
|
});
|
|
9529
|
+
const rejectedKeyPaths = [];
|
|
9530
|
+
const config = parseJsonc(substituted.text, {
|
|
9531
|
+
onRejectedKey: (path) => rejectedKeyPaths.push(path.join("."))
|
|
9532
|
+
});
|
|
9533
|
+
const unsafeKeyWarnings = rejectedKeyPaths.map((path) => `Ignored unsafe config key "${path}" (security: prototype-pollution keys are not allowed).`);
|
|
9466
9534
|
return {
|
|
9467
|
-
config
|
|
9468
|
-
warnings: substituted.warnings.map((
|
|
9469
|
-
outcome: substituted.warnings.length > 0 ? "substitution-failure" : "ok",
|
|
9535
|
+
config,
|
|
9536
|
+
warnings: [...substituted.warnings, ...unsafeKeyWarnings].map((warning) => `${configPath}: ${warning}`),
|
|
9537
|
+
outcome: rejectedKeyPaths.length > 0 ? "schema-recovery" : substituted.warnings.length > 0 ? "substitution-failure" : "ok",
|
|
9470
9538
|
source
|
|
9471
9539
|
};
|
|
9472
9540
|
} catch (error) {
|
|
@@ -9480,18 +9548,35 @@ function loadConfigFileDetailed(configPath, source) {
|
|
|
9480
9548
|
};
|
|
9481
9549
|
}
|
|
9482
9550
|
}
|
|
9551
|
+
function defineOwnConfigValue(target, key, value) {
|
|
9552
|
+
Object.defineProperty(target, key, {
|
|
9553
|
+
value,
|
|
9554
|
+
enumerable: true,
|
|
9555
|
+
configurable: true,
|
|
9556
|
+
writable: true
|
|
9557
|
+
});
|
|
9558
|
+
}
|
|
9483
9559
|
function deepMergeRawConfig(base, override) {
|
|
9484
|
-
const result = {
|
|
9560
|
+
const result = {};
|
|
9561
|
+
for (const key of Object.keys(base)) {
|
|
9562
|
+
if (isPrototypePollutionKey(key))
|
|
9563
|
+
continue;
|
|
9564
|
+
defineOwnConfigValue(result, key, base[key]);
|
|
9565
|
+
}
|
|
9485
9566
|
for (const key of Object.keys(override)) {
|
|
9486
|
-
|
|
9567
|
+
if (isPrototypePollutionKey(key))
|
|
9568
|
+
continue;
|
|
9569
|
+
const baseVal = Object.hasOwn(base, key) ? base[key] : undefined;
|
|
9487
9570
|
const overrideVal = override[key];
|
|
9571
|
+
let mergedValue;
|
|
9488
9572
|
if (baseVal !== null && typeof baseVal === "object" && !Array.isArray(baseVal) && overrideVal !== null && typeof overrideVal === "object" && !Array.isArray(overrideVal)) {
|
|
9489
|
-
|
|
9573
|
+
mergedValue = deepMergeRawConfig(baseVal, overrideVal);
|
|
9490
9574
|
} else if (key === "disabled_hooks" && Array.isArray(baseVal) && Array.isArray(overrideVal)) {
|
|
9491
|
-
|
|
9575
|
+
mergedValue = [...new Set([...baseVal, ...overrideVal])];
|
|
9492
9576
|
} else {
|
|
9493
|
-
|
|
9577
|
+
mergedValue = overrideVal;
|
|
9494
9578
|
}
|
|
9579
|
+
defineOwnConfigValue(result, key, mergedValue);
|
|
9495
9580
|
}
|
|
9496
9581
|
return result;
|
|
9497
9582
|
}
|
|
@@ -10105,171 +10190,6 @@ function buildDreamTaskPrompt(task, args) {
|
|
|
10105
10190
|
}
|
|
10106
10191
|
}
|
|
10107
10192
|
|
|
10108
|
-
// src/features/magic-context/fail-closed-block.ts
|
|
10109
|
-
var FAIL_CLOSED_DOCTOR_COMMAND = "npx @cortexkit/magic-context@latest doctor";
|
|
10110
|
-
var FAIL_CLOSED_REPROBE_EVERY_N = 5;
|
|
10111
|
-
|
|
10112
|
-
class FailClosedBlockingError extends Error {
|
|
10113
|
-
code = "FAIL_CLOSED_BLOCKING";
|
|
10114
|
-
reason;
|
|
10115
|
-
constructor(message, reason, options) {
|
|
10116
|
-
super(message, options);
|
|
10117
|
-
this.name = "FailClosedBlockingError";
|
|
10118
|
-
this.reason = reason;
|
|
10119
|
-
}
|
|
10120
|
-
}
|
|
10121
|
-
var OPENCODE_INTERNAL_AGENT_NAMES = new Set(["title", "summary", "compaction"]);
|
|
10122
|
-
function isMagicContextHiddenAgentName(agent) {
|
|
10123
|
-
if (agent === "sidekick" || agent === "smart-note-compiler" || agent.startsWith("smart-note-")) {
|
|
10124
|
-
return true;
|
|
10125
|
-
}
|
|
10126
|
-
if (agent === "historian" || agent.startsWith("historian-"))
|
|
10127
|
-
return true;
|
|
10128
|
-
if (agent === "dreamer" || agent.startsWith("dreamer-"))
|
|
10129
|
-
return true;
|
|
10130
|
-
return false;
|
|
10131
|
-
}
|
|
10132
|
-
var MAX_FORMATTED_BLOCKING_PROCESSES = 8;
|
|
10133
|
-
function formatFailClosedBlockingProcesses(processes) {
|
|
10134
|
-
const uniqueProcesses = new Map;
|
|
10135
|
-
for (const process2 of processes) {
|
|
10136
|
-
if (!process2.harness.trim() || !Number.isInteger(process2.pid) || process2.pid <= 0)
|
|
10137
|
-
continue;
|
|
10138
|
-
uniqueProcesses.set(`${process2.harness}\x00${process2.pid}`, {
|
|
10139
|
-
harness: process2.harness.trim(),
|
|
10140
|
-
pid: process2.pid
|
|
10141
|
-
});
|
|
10142
|
-
}
|
|
10143
|
-
const entries = [...uniqueProcesses.values()];
|
|
10144
|
-
const visible = entries.slice(0, MAX_FORMATTED_BLOCKING_PROCESSES);
|
|
10145
|
-
const rendered = visible.map(({ harness, pid }) => `${harness} (PID ${pid})`);
|
|
10146
|
-
const omitted = entries.length - visible.length;
|
|
10147
|
-
if (omitted > 0)
|
|
10148
|
-
rendered.push(`${omitted} more blocking process(es)`);
|
|
10149
|
-
if (rendered.length === 0)
|
|
10150
|
-
return "a live harness process";
|
|
10151
|
-
if (rendered.length === 1)
|
|
10152
|
-
return rendered[0];
|
|
10153
|
-
const last = rendered.pop();
|
|
10154
|
-
return `${rendered.join(", ")}, and ${last}`;
|
|
10155
|
-
}
|
|
10156
|
-
function formatFailClosedBlockingMessage(reason) {
|
|
10157
|
-
if (reason.kind === "migration_guard") {
|
|
10158
|
-
if (reason.unreadableFile) {
|
|
10159
|
-
const arm = reason.unreadableArm ?? "io";
|
|
10160
|
-
const recovery = arm === "io" ? `If no OpenCode server is running, it is safe to delete ${reason.unreadableFile} and retry.` : `The file may be a recent incomplete write; retry after the file is older than the ten-minute grace window, or stop OpenCode before deleting it.`;
|
|
10161
|
-
return [
|
|
10162
|
-
`Magic Context cannot migrate the shared database because RPC discovery file ${reason.unreadableFile} is uncertain (${arm} arm), so the absence of a live OpenCode server cannot be proven.`,
|
|
10163
|
-
recovery,
|
|
10164
|
-
`Recovery: ${FAIL_CLOSED_DOCTOR_COMMAND}`
|
|
10165
|
-
].join(" ");
|
|
10166
|
-
}
|
|
10167
|
-
return [
|
|
10168
|
-
`Magic Context cannot migrate the shared database because ${formatFailClosedBlockingProcesses(reason.blockingProcesses)} may be running an older Magic Context build that would fail against the migrated database.`,
|
|
10169
|
-
"Restart the blocking process (it will pick up the new build and migrate on start), or shut it down and retry.",
|
|
10170
|
-
`Recovery: ${FAIL_CLOSED_DOCTOR_COMMAND}`
|
|
10171
|
-
].join(" ");
|
|
10172
|
-
}
|
|
10173
|
-
if (reason.kind === "schema_fence") {
|
|
10174
|
-
return [
|
|
10175
|
-
`Magic Context cannot operate: this Magic Context build is older than the database; upgrade/restart this harness (upstream migration lane v${reason.persistedVersion}, build supports through v${reason.supportedVersion}).`,
|
|
10176
|
-
`Recovery: ${FAIL_CLOSED_DOCTOR_COMMAND}`
|
|
10177
|
-
].join(" ");
|
|
10178
|
-
}
|
|
10179
|
-
const cause = reason.cause.trim().length > 0 ? reason.cause.trim() : "unknown storage error";
|
|
10180
|
-
return [
|
|
10181
|
-
`Magic Context cannot operate: persistent storage failed (${cause}).`,
|
|
10182
|
-
"The plugin will not silently degrade to native compaction while enabled.",
|
|
10183
|
-
`Recovery: ${FAIL_CLOSED_DOCTOR_COMMAND}`
|
|
10184
|
-
].join(" ");
|
|
10185
|
-
}
|
|
10186
|
-
function createFailClosedBlockingError(reason, options) {
|
|
10187
|
-
return new FailClosedBlockingError(formatFailClosedBlockingMessage(reason), reason, options);
|
|
10188
|
-
}
|
|
10189
|
-
function isFailClosedBlockingError(error) {
|
|
10190
|
-
return error instanceof FailClosedBlockingError || typeof error === "object" && error !== null && error.name === "FailClosedBlockingError" && error.code === "FAIL_CLOSED_BLOCKING";
|
|
10191
|
-
}
|
|
10192
|
-
function shouldBypassFailClosedBlock(input) {
|
|
10193
|
-
if (input.isPiSubagentEnv === true)
|
|
10194
|
-
return true;
|
|
10195
|
-
if (input.isInternalChildSession === true)
|
|
10196
|
-
return true;
|
|
10197
|
-
const agent = typeof input.agent === "string" ? input.agent.trim() : "";
|
|
10198
|
-
if (agent.length === 0)
|
|
10199
|
-
return false;
|
|
10200
|
-
if (OPENCODE_INTERNAL_AGENT_NAMES.has(agent))
|
|
10201
|
-
return true;
|
|
10202
|
-
if (isMagicContextHiddenAgentName(agent))
|
|
10203
|
-
return true;
|
|
10204
|
-
return false;
|
|
10205
|
-
}
|
|
10206
|
-
function resolveAgentNameFromMessages(messages) {
|
|
10207
|
-
for (let i = messages.length - 1;i >= 0; i -= 1) {
|
|
10208
|
-
const info = messages[i]?.info;
|
|
10209
|
-
if (!info || typeof info !== "object")
|
|
10210
|
-
continue;
|
|
10211
|
-
const agent = info.agent;
|
|
10212
|
-
if (typeof agent === "string" && agent.length > 0)
|
|
10213
|
-
return agent;
|
|
10214
|
-
}
|
|
10215
|
-
return;
|
|
10216
|
-
}
|
|
10217
|
-
function createFailClosedController(options) {
|
|
10218
|
-
const reprobeEveryN = Math.max(1, options?.reprobeEveryN ?? FAIL_CLOSED_REPROBE_EVERY_N);
|
|
10219
|
-
let reason = null;
|
|
10220
|
-
let blockedPassCount = 0;
|
|
10221
|
-
return {
|
|
10222
|
-
arm(next) {
|
|
10223
|
-
reason = next;
|
|
10224
|
-
blockedPassCount = 0;
|
|
10225
|
-
},
|
|
10226
|
-
clear() {
|
|
10227
|
-
reason = null;
|
|
10228
|
-
blockedPassCount = 0;
|
|
10229
|
-
},
|
|
10230
|
-
isArmed() {
|
|
10231
|
-
return reason !== null;
|
|
10232
|
-
},
|
|
10233
|
-
getReason() {
|
|
10234
|
-
return reason;
|
|
10235
|
-
},
|
|
10236
|
-
async enforce(input) {
|
|
10237
|
-
if (!reason)
|
|
10238
|
-
return;
|
|
10239
|
-
if (!input.blockingEnabled)
|
|
10240
|
-
return;
|
|
10241
|
-
if (input.exempt)
|
|
10242
|
-
return;
|
|
10243
|
-
blockedPassCount += 1;
|
|
10244
|
-
const shouldReprobe = typeof input.tryReopen === "function" && (blockedPassCount === 1 || blockedPassCount % reprobeEveryN === 0);
|
|
10245
|
-
if (shouldReprobe) {
|
|
10246
|
-
try {
|
|
10247
|
-
const healed = await input.tryReopen?.();
|
|
10248
|
-
if (healed) {
|
|
10249
|
-
reason = null;
|
|
10250
|
-
blockedPassCount = 0;
|
|
10251
|
-
return;
|
|
10252
|
-
}
|
|
10253
|
-
} catch {}
|
|
10254
|
-
}
|
|
10255
|
-
const blockedReason = reason;
|
|
10256
|
-
if (!blockedReason)
|
|
10257
|
-
return;
|
|
10258
|
-
throw createFailClosedBlockingError(blockedReason);
|
|
10259
|
-
}
|
|
10260
|
-
};
|
|
10261
|
-
}
|
|
10262
|
-
var lastHookInitFailure = null;
|
|
10263
|
-
function recordHookInitFailure(failure) {
|
|
10264
|
-
lastHookInitFailure = failure;
|
|
10265
|
-
}
|
|
10266
|
-
function clearHookInitFailure() {
|
|
10267
|
-
lastHookInitFailure = null;
|
|
10268
|
-
}
|
|
10269
|
-
function getLastHookInitFailure() {
|
|
10270
|
-
return lastHookInitFailure;
|
|
10271
|
-
}
|
|
10272
|
-
|
|
10273
10193
|
// src/features/magic-context/session-project-backfill.ts
|
|
10274
10194
|
import { randomUUID } from "node:crypto";
|
|
10275
10195
|
import { existsSync as existsSync4 } from "node:fs";
|
|
@@ -11523,7 +11443,10 @@ var CONNECT_BACKOFF_INITIAL_MS = 1000;
|
|
|
11523
11443
|
var CONNECT_BACKOFF_MAX_MS = 30000;
|
|
11524
11444
|
var HANDSHAKE_TIMEOUT_MS = 2000;
|
|
11525
11445
|
var MODULE_SEND_TIMEOUT_MS = 15000;
|
|
11446
|
+
var TRANSFORM_SEND_TIMEOUT_MS = 5000;
|
|
11447
|
+
var MAX_WRAPUP_REQUEST_BUDGET_MS = 3800000;
|
|
11526
11448
|
var SERIAL_LANE_MAX_WAITERS = 16;
|
|
11449
|
+
var SERIAL_LANE_MAX_WAITERS_PER_SESSION = 8;
|
|
11527
11450
|
var SERIAL_LANE_MIN_REMAINING_MS = 25;
|
|
11528
11451
|
var CANONICAL_ROOT_CACHE_MAX_ENTRIES = 256;
|
|
11529
11452
|
function getDefaultConnectionFile() {
|
|
@@ -11558,15 +11481,24 @@ function isConnectionFailure(error) {
|
|
|
11558
11481
|
if (error instanceof SocketClosedError || error instanceof SocketTimeoutError || error instanceof StaleRouteHandleError || isConsumerReconnectTransient(error) || isStaleOrDeadRouteFailure(error)) {
|
|
11559
11482
|
return true;
|
|
11560
11483
|
}
|
|
11561
|
-
return errorChainSome(error, (current) =>
|
|
11562
|
-
"
|
|
11563
|
-
"
|
|
11564
|
-
|
|
11565
|
-
|
|
11566
|
-
|
|
11567
|
-
|
|
11568
|
-
|
|
11569
|
-
|
|
11484
|
+
return errorChainSome(error, (current) => {
|
|
11485
|
+
const code = typeof current.code === "string" ? current.code : "";
|
|
11486
|
+
const message = typeof current.message === "string" ? current.message : "";
|
|
11487
|
+
return [
|
|
11488
|
+
"ENOENT",
|
|
11489
|
+
"ECONNREFUSED",
|
|
11490
|
+
"ECONNRESET",
|
|
11491
|
+
"EPIPE",
|
|
11492
|
+
"ETIMEDOUT",
|
|
11493
|
+
"request_deadline",
|
|
11494
|
+
"deadline_exceeded_no_drop_observed",
|
|
11495
|
+
"connection_dropped",
|
|
11496
|
+
"SUBC_CONNECTION_BACKOFF"
|
|
11497
|
+
].includes(code) || /\bclient closed\b|\bconnection closed\b|\bclosed the connection\b/i.test(message);
|
|
11498
|
+
});
|
|
11499
|
+
}
|
|
11500
|
+
function isModuleTransportGenerationChangedResult(value) {
|
|
11501
|
+
return isRecord(value) && value.transport_status === "connection_generation_changed" && typeof value.previous_generation === "number" && typeof value.current_generation === "number";
|
|
11570
11502
|
}
|
|
11571
11503
|
|
|
11572
11504
|
class SubcModuleTransport {
|
|
@@ -11576,15 +11508,31 @@ class SubcModuleTransport {
|
|
|
11576
11508
|
routeSessionPrefix;
|
|
11577
11509
|
client = null;
|
|
11578
11510
|
routes = new Map;
|
|
11511
|
+
routeOpenings = new Map;
|
|
11579
11512
|
canonicalRootCache = new Map;
|
|
11580
|
-
|
|
11513
|
+
sessionLanes = new Map;
|
|
11514
|
+
queuedLaneWaiters = 0;
|
|
11515
|
+
wrapupSessions = new Map;
|
|
11581
11516
|
nextProbeMs = 0;
|
|
11582
|
-
|
|
11517
|
+
connectionPromise = null;
|
|
11583
11518
|
authorityProjectRoot = "";
|
|
11584
11519
|
authorityBindRoot = "";
|
|
11585
11520
|
backoffMs = CONNECT_BACKOFF_INITIAL_MS;
|
|
11586
11521
|
connectionGeneration = 0;
|
|
11522
|
+
stateSyncCapabilityCache = null;
|
|
11523
|
+
getCachedStateSyncCapabilities() {
|
|
11524
|
+
const cached = this.stateSyncCapabilityCache;
|
|
11525
|
+
if (!cached || cached.generation !== this.connectionGeneration)
|
|
11526
|
+
return;
|
|
11527
|
+
return cached.capabilities;
|
|
11528
|
+
}
|
|
11529
|
+
invalidateStateSyncCapabilities() {
|
|
11530
|
+
this.stateSyncCapabilityCache = null;
|
|
11531
|
+
}
|
|
11587
11532
|
async stateSyncCapabilities(args) {
|
|
11533
|
+
const cached = this.getCachedStateSyncCapabilities();
|
|
11534
|
+
if (cached)
|
|
11535
|
+
return cached;
|
|
11588
11536
|
const response = await this.call({
|
|
11589
11537
|
sessionId: args.sessionId,
|
|
11590
11538
|
projectRoot: args.projectRoot,
|
|
@@ -11594,7 +11542,9 @@ class SubcModuleTransport {
|
|
|
11594
11542
|
const raw = isRecord(response) ? response : {};
|
|
11595
11543
|
const value = isRecord(raw.result) ? raw.result : raw;
|
|
11596
11544
|
const epochs = isRecord(value.epochs) ? value.epochs : {};
|
|
11597
|
-
|
|
11545
|
+
const capabilities = { state_sync_deltas: epochs.state_sync_deltas === true };
|
|
11546
|
+
this.stateSyncCapabilityCache = { generation: this.connectionGeneration, capabilities };
|
|
11547
|
+
return capabilities;
|
|
11598
11548
|
}
|
|
11599
11549
|
constructor(connectionFile, moduleId = DEFAULT_MODULE_ID, requestTimeoutMs = MODULE_SEND_TIMEOUT_MS, routeSessionPrefix = "") {
|
|
11600
11550
|
this.connectionFile = connectionFile ?? getDefaultConnectionFile();
|
|
@@ -11602,27 +11552,60 @@ class SubcModuleTransport {
|
|
|
11602
11552
|
this.requestTimeoutMs = requestTimeoutMs;
|
|
11603
11553
|
this.routeSessionPrefix = routeSessionPrefix;
|
|
11604
11554
|
}
|
|
11605
|
-
|
|
11606
|
-
const error = new Error(
|
|
11555
|
+
deadlineError(detail) {
|
|
11556
|
+
const error = new Error(`module transport deadline expired ${detail}`);
|
|
11607
11557
|
error.code = "ETIMEDOUT";
|
|
11608
11558
|
return error;
|
|
11609
11559
|
}
|
|
11610
|
-
|
|
11560
|
+
laneTimeoutError() {
|
|
11561
|
+
return this.deadlineError("while queued");
|
|
11562
|
+
}
|
|
11563
|
+
connectionChangedError(detail) {
|
|
11564
|
+
const error = new Error(detail);
|
|
11565
|
+
error.code = "ECONNRESET";
|
|
11566
|
+
return error;
|
|
11567
|
+
}
|
|
11568
|
+
async beforeDeadline(operation, deadlineMs, detail) {
|
|
11569
|
+
const remainingMs = deadlineMs - Date.now();
|
|
11570
|
+
if (remainingMs <= 0)
|
|
11571
|
+
throw this.deadlineError(detail);
|
|
11572
|
+
let timer;
|
|
11573
|
+
try {
|
|
11574
|
+
return await Promise.race([
|
|
11575
|
+
operation,
|
|
11576
|
+
new Promise((_resolve, reject) => {
|
|
11577
|
+
timer = setTimeout(() => reject(this.deadlineError(detail)), remainingMs);
|
|
11578
|
+
})
|
|
11579
|
+
]);
|
|
11580
|
+
} finally {
|
|
11581
|
+
if (timer)
|
|
11582
|
+
clearTimeout(timer);
|
|
11583
|
+
}
|
|
11584
|
+
}
|
|
11585
|
+
cleanupLane(sessionId, lane) {
|
|
11586
|
+
if (!lane.active && lane.waiters.length === 0 && this.sessionLanes.get(sessionId) === lane) {
|
|
11587
|
+
this.sessionLanes.delete(sessionId);
|
|
11588
|
+
}
|
|
11589
|
+
}
|
|
11590
|
+
laneRelease(sessionId, lane) {
|
|
11611
11591
|
let released = false;
|
|
11612
11592
|
return () => {
|
|
11613
11593
|
if (released)
|
|
11614
11594
|
return;
|
|
11615
11595
|
released = true;
|
|
11616
|
-
|
|
11617
|
-
this.dispatchNextLaneWaiter();
|
|
11596
|
+
lane.active = false;
|
|
11597
|
+
this.dispatchNextLaneWaiter(sessionId, lane);
|
|
11618
11598
|
};
|
|
11619
11599
|
}
|
|
11620
|
-
dispatchNextLaneWaiter() {
|
|
11621
|
-
if (
|
|
11600
|
+
dispatchNextLaneWaiter(sessionId, lane) {
|
|
11601
|
+
if (lane.active)
|
|
11622
11602
|
return;
|
|
11623
|
-
while (
|
|
11624
|
-
const waiter =
|
|
11625
|
-
if (!waiter
|
|
11603
|
+
while (lane.waiters.length > 0) {
|
|
11604
|
+
const waiter = lane.waiters.shift();
|
|
11605
|
+
if (!waiter)
|
|
11606
|
+
continue;
|
|
11607
|
+
this.queuedLaneWaiters = Math.max(0, this.queuedLaneWaiters - 1);
|
|
11608
|
+
if (waiter.settled)
|
|
11626
11609
|
continue;
|
|
11627
11610
|
waiter.settled = true;
|
|
11628
11611
|
clearTimeout(waiter.timer);
|
|
@@ -11635,10 +11618,16 @@ class SubcModuleTransport {
|
|
|
11635
11618
|
waiter.reject(this.laneTimeoutError());
|
|
11636
11619
|
continue;
|
|
11637
11620
|
}
|
|
11638
|
-
|
|
11639
|
-
waiter.resolve(this.laneRelease());
|
|
11621
|
+
lane.active = true;
|
|
11622
|
+
waiter.resolve(this.laneRelease(sessionId, lane));
|
|
11640
11623
|
return;
|
|
11641
11624
|
}
|
|
11625
|
+
this.cleanupLane(sessionId, lane);
|
|
11626
|
+
}
|
|
11627
|
+
queueFullError() {
|
|
11628
|
+
const error = new Error("module transport queue is full");
|
|
11629
|
+
error.code = "EBUSY";
|
|
11630
|
+
return error;
|
|
11642
11631
|
}
|
|
11643
11632
|
acquireCorrectnessLane(sessionId, signal, deadlineMs) {
|
|
11644
11633
|
if (signal?.aborted) {
|
|
@@ -11647,14 +11636,14 @@ class SubcModuleTransport {
|
|
|
11647
11636
|
if (deadlineMs - Date.now() < SERIAL_LANE_MIN_REMAINING_MS) {
|
|
11648
11637
|
return Promise.reject(this.laneTimeoutError());
|
|
11649
11638
|
}
|
|
11650
|
-
|
|
11651
|
-
|
|
11652
|
-
|
|
11639
|
+
const lane = this.sessionLanes.get(sessionId) ?? { active: false, waiters: [] };
|
|
11640
|
+
this.sessionLanes.set(sessionId, lane);
|
|
11641
|
+
if (!lane.active && lane.waiters.length === 0) {
|
|
11642
|
+
lane.active = true;
|
|
11643
|
+
return Promise.resolve(this.laneRelease(sessionId, lane));
|
|
11653
11644
|
}
|
|
11654
|
-
if (this.
|
|
11655
|
-
|
|
11656
|
-
error.code = "EBUSY";
|
|
11657
|
-
return Promise.reject(error);
|
|
11645
|
+
if (this.queuedLaneWaiters >= SERIAL_LANE_MAX_WAITERS || lane.waiters.length >= SERIAL_LANE_MAX_WAITERS_PER_SESSION) {
|
|
11646
|
+
return Promise.reject(this.queueFullError());
|
|
11658
11647
|
}
|
|
11659
11648
|
return new Promise((resolve3, reject) => {
|
|
11660
11649
|
const waiter = {};
|
|
@@ -11664,14 +11653,14 @@ class SubcModuleTransport {
|
|
|
11664
11653
|
waiter.settled = true;
|
|
11665
11654
|
clearTimeout(waiter.timer);
|
|
11666
11655
|
signal?.removeEventListener("abort", waiter.onAbort);
|
|
11667
|
-
const index =
|
|
11668
|
-
if (index >= 0)
|
|
11669
|
-
|
|
11656
|
+
const index = lane.waiters.indexOf(waiter);
|
|
11657
|
+
if (index >= 0) {
|
|
11658
|
+
lane.waiters.splice(index, 1);
|
|
11659
|
+
this.queuedLaneWaiters = Math.max(0, this.queuedLaneWaiters - 1);
|
|
11660
|
+
}
|
|
11670
11661
|
reject(error);
|
|
11671
|
-
|
|
11672
|
-
this.dispatchNextLaneWaiter();
|
|
11662
|
+
this.cleanupLane(sessionId, lane);
|
|
11673
11663
|
};
|
|
11674
|
-
waiter.sessionId = sessionId;
|
|
11675
11664
|
waiter.signal = signal;
|
|
11676
11665
|
waiter.deadlineMs = deadlineMs;
|
|
11677
11666
|
waiter.resolve = resolve3;
|
|
@@ -11680,46 +11669,78 @@ class SubcModuleTransport {
|
|
|
11680
11669
|
waiter.onAbort = () => removeAndReject(signal?.reason ?? new Error("module transport call aborted"));
|
|
11681
11670
|
waiter.timer = setTimeout(() => removeAndReject(this.laneTimeoutError()), Math.max(0, deadlineMs - Date.now()));
|
|
11682
11671
|
signal?.addEventListener("abort", waiter.onAbort, { once: true });
|
|
11683
|
-
|
|
11672
|
+
lane.waiters.push(waiter);
|
|
11673
|
+
this.queuedLaneWaiters += 1;
|
|
11684
11674
|
});
|
|
11685
11675
|
}
|
|
11686
11676
|
async call(args) {
|
|
11687
|
-
const
|
|
11688
|
-
const
|
|
11689
|
-
const
|
|
11677
|
+
const wrapupInFlight = (this.wrapupSessions.get(args.sessionId) ?? 0) > 0;
|
|
11678
|
+
const attemptTimeoutMs = args.timeoutMs ?? (args.method === "session.wrapup" || args.method === "session.status" && wrapupInFlight ? MAX_WRAPUP_REQUEST_BUDGET_MS : args.method === "transform" ? Math.min(this.requestTimeoutMs, TRANSFORM_SEND_TIMEOUT_MS) : this.requestTimeoutMs);
|
|
11679
|
+
const tracksWrapup = args.method === "session.wrapup";
|
|
11680
|
+
if (tracksWrapup) {
|
|
11681
|
+
this.wrapupSessions.set(args.sessionId, (this.wrapupSessions.get(args.sessionId) ?? 0) + 1);
|
|
11682
|
+
}
|
|
11683
|
+
const finishWrapupTracking = () => {
|
|
11684
|
+
if (!tracksWrapup)
|
|
11685
|
+
return;
|
|
11686
|
+
const remaining = (this.wrapupSessions.get(args.sessionId) ?? 1) - 1;
|
|
11687
|
+
if (remaining > 0)
|
|
11688
|
+
this.wrapupSessions.set(args.sessionId, remaining);
|
|
11689
|
+
else
|
|
11690
|
+
this.wrapupSessions.delete(args.sessionId);
|
|
11691
|
+
};
|
|
11692
|
+
const laneDeadlineMs = Date.now() + attemptTimeoutMs;
|
|
11693
|
+
let releaseLane;
|
|
11694
|
+
try {
|
|
11695
|
+
releaseLane = await this.acquireCorrectnessLane(args.sessionId, args.signal, laneDeadlineMs);
|
|
11696
|
+
} catch (error) {
|
|
11697
|
+
finishWrapupTracking();
|
|
11698
|
+
throw error;
|
|
11699
|
+
}
|
|
11700
|
+
let activeAttemptClient = null;
|
|
11701
|
+
const onAbort = () => this.invalidateConnection(activeAttemptClient ?? this.client);
|
|
11690
11702
|
args.signal?.addEventListener("abort", onAbort, { once: true });
|
|
11691
11703
|
try {
|
|
11692
11704
|
for (let attempt = 0;attempt < 2; attempt += 1) {
|
|
11705
|
+
activeAttemptClient = null;
|
|
11693
11706
|
let ensuredRoute = null;
|
|
11694
11707
|
try {
|
|
11695
11708
|
if (args.signal?.aborted) {
|
|
11696
11709
|
throw args.signal.reason ?? new Error("module transport call aborted");
|
|
11697
11710
|
}
|
|
11698
|
-
const
|
|
11699
|
-
|
|
11700
|
-
|
|
11701
|
-
ensuredRoute = await this.ensureRoute(args.sessionId, args.projectRoot);
|
|
11711
|
+
const attemptDeadlineMs = Date.now() + attemptTimeoutMs;
|
|
11712
|
+
ensuredRoute = await this.ensureRoute(args.sessionId, args.projectRoot, attemptDeadlineMs);
|
|
11713
|
+
activeAttemptClient = ensuredRoute.client;
|
|
11702
11714
|
if (args.signal?.aborted) {
|
|
11703
11715
|
throw args.signal.reason ?? new Error("module transport call aborted");
|
|
11704
11716
|
}
|
|
11705
|
-
|
|
11717
|
+
const response = await this.beforeDeadline(ensuredRoute.client.request(ensuredRoute.route, args.body, {
|
|
11706
11718
|
priority: Priority.Background,
|
|
11707
11719
|
admissionClass: AdmissionClass.Normal,
|
|
11708
|
-
timeoutMs: Math.max(1,
|
|
11709
|
-
});
|
|
11720
|
+
timeoutMs: Math.max(1, attemptDeadlineMs - Date.now())
|
|
11721
|
+
}), attemptDeadlineMs, "waiting for the module response");
|
|
11722
|
+
if (this.client !== ensuredRoute.client || this.connectionGeneration !== ensuredRoute.generation) {
|
|
11723
|
+
throw this.connectionChangedError("subc connection changed while awaiting the module response");
|
|
11724
|
+
}
|
|
11725
|
+
return response;
|
|
11710
11726
|
} catch (error) {
|
|
11711
|
-
|
|
11712
|
-
|
|
11727
|
+
if (isConnectionFailure(error)) {
|
|
11728
|
+
const previousGeneration = ensuredRoute?.generation ?? this.connectionGeneration;
|
|
11713
11729
|
if (ensuredRoute) {
|
|
11714
11730
|
this.dropRoute(ensuredRoute.routeKey, ensuredRoute.route);
|
|
11715
11731
|
this.invalidateConnection(ensuredRoute.client);
|
|
11716
11732
|
} else {
|
|
11717
11733
|
this.invalidateConnection();
|
|
11718
11734
|
}
|
|
11735
|
+
if (args.generationSensitive && !args.signal?.aborted) {
|
|
11736
|
+
return {
|
|
11737
|
+
transport_status: "connection_generation_changed",
|
|
11738
|
+
previous_generation: previousGeneration,
|
|
11739
|
+
current_generation: this.connectionGeneration
|
|
11740
|
+
};
|
|
11741
|
+
}
|
|
11719
11742
|
if (attempt === 0 && !args.signal?.aborted)
|
|
11720
11743
|
continue;
|
|
11721
|
-
} else if (isConnectionFailure(error)) {
|
|
11722
|
-
this.invalidateConnection(ensuredRoute?.client);
|
|
11723
11744
|
}
|
|
11724
11745
|
throw error;
|
|
11725
11746
|
}
|
|
@@ -11727,6 +11748,7 @@ class SubcModuleTransport {
|
|
|
11727
11748
|
throw new Error("module transport route retry exhausted");
|
|
11728
11749
|
} finally {
|
|
11729
11750
|
args.signal?.removeEventListener("abort", onAbort);
|
|
11751
|
+
finishWrapupTracking();
|
|
11730
11752
|
releaseLane();
|
|
11731
11753
|
}
|
|
11732
11754
|
}
|
|
@@ -11817,11 +11839,11 @@ class SubcModuleTransport {
|
|
|
11817
11839
|
});
|
|
11818
11840
|
}
|
|
11819
11841
|
}
|
|
11820
|
-
if (routes.length === 0 && this.
|
|
11842
|
+
if (routes.length === 0 && this.sessionLanes.get(sessionId)?.active) {
|
|
11821
11843
|
this.invalidateConnection(client);
|
|
11822
11844
|
}
|
|
11823
11845
|
}
|
|
11824
|
-
async ensureRoute(sessionId, rawProjectRoot) {
|
|
11846
|
+
async ensureRoute(sessionId, rawProjectRoot, deadlineMs = Date.now() + this.requestTimeoutMs) {
|
|
11825
11847
|
const projectRoot = this.canonicalRoot(rawProjectRoot);
|
|
11826
11848
|
const routeKey = `${sessionId}\x00${projectRoot}`;
|
|
11827
11849
|
const client = await this.ensureConnected();
|
|
@@ -11832,23 +11854,36 @@ class SubcModuleTransport {
|
|
|
11832
11854
|
}
|
|
11833
11855
|
if (existing)
|
|
11834
11856
|
this.routes.delete(routeKey);
|
|
11835
|
-
const
|
|
11836
|
-
|
|
11837
|
-
|
|
11838
|
-
|
|
11839
|
-
|
|
11840
|
-
|
|
11841
|
-
|
|
11842
|
-
|
|
11843
|
-
|
|
11844
|
-
|
|
11845
|
-
}
|
|
11846
|
-
const
|
|
11847
|
-
|
|
11848
|
-
|
|
11857
|
+
const opening = this.routeOpenings.get(routeKey);
|
|
11858
|
+
if (opening?.client === client && opening.generation === generation) {
|
|
11859
|
+
return await opening.promise;
|
|
11860
|
+
}
|
|
11861
|
+
const promise = (async () => {
|
|
11862
|
+
const target = { kind: "tool_provider", module_id: this.moduleId };
|
|
11863
|
+
const identity = {
|
|
11864
|
+
project_root: projectRoot,
|
|
11865
|
+
harness: getHarness(),
|
|
11866
|
+
session: `${this.routeSessionPrefix}${sessionId}`
|
|
11867
|
+
};
|
|
11868
|
+
const route = await this.beforeDeadline(client.routeOpen(target, identity), deadlineMs, "opening the module route");
|
|
11869
|
+
if (this.client !== client || generation !== this.connectionGeneration) {
|
|
11870
|
+
await client.closeRoute(route).catch(() => {
|
|
11871
|
+
return;
|
|
11872
|
+
});
|
|
11873
|
+
throw this.connectionChangedError("subc connection changed while opening module route");
|
|
11874
|
+
}
|
|
11875
|
+
this.routes.set(routeKey, { route, generation });
|
|
11876
|
+
return { client, route, routeKey, generation };
|
|
11877
|
+
})();
|
|
11878
|
+
const routeOpening = { client, generation, promise };
|
|
11879
|
+
this.routeOpenings.set(routeKey, routeOpening);
|
|
11880
|
+
try {
|
|
11881
|
+
return await promise;
|
|
11882
|
+
} finally {
|
|
11883
|
+
if (this.routeOpenings.get(routeKey) === routeOpening) {
|
|
11884
|
+
this.routeOpenings.delete(routeKey);
|
|
11885
|
+
}
|
|
11849
11886
|
}
|
|
11850
|
-
this.routes.set(routeKey, { route, generation });
|
|
11851
|
-
return { client, route, routeKey, generation };
|
|
11852
11887
|
}
|
|
11853
11888
|
dropRoute(routeKey, route) {
|
|
11854
11889
|
const existing = this.routes.get(routeKey);
|
|
@@ -11876,9 +11911,17 @@ class SubcModuleTransport {
|
|
|
11876
11911
|
}
|
|
11877
11912
|
return resolved;
|
|
11878
11913
|
}
|
|
11914
|
+
connectClient() {
|
|
11915
|
+
return SubcClient.connect({
|
|
11916
|
+
connectionFile: this.connectionFile,
|
|
11917
|
+
handshakeTimeoutMs: HANDSHAKE_TIMEOUT_MS
|
|
11918
|
+
});
|
|
11919
|
+
}
|
|
11879
11920
|
async ensureConnected() {
|
|
11880
11921
|
if (this.client)
|
|
11881
11922
|
return this.client;
|
|
11923
|
+
if (this.connectionPromise)
|
|
11924
|
+
return await this.connectionPromise;
|
|
11882
11925
|
const now = Date.now();
|
|
11883
11926
|
if (now < this.nextProbeMs) {
|
|
11884
11927
|
const error = new Error(`subc connection backoff active until ${this.nextProbeMs}`);
|
|
@@ -11886,37 +11929,44 @@ class SubcModuleTransport {
|
|
|
11886
11929
|
throw error;
|
|
11887
11930
|
}
|
|
11888
11931
|
const generation = this.connectionGeneration;
|
|
11889
|
-
|
|
11890
|
-
|
|
11891
|
-
|
|
11892
|
-
|
|
11893
|
-
|
|
11894
|
-
|
|
11895
|
-
|
|
11896
|
-
|
|
11897
|
-
|
|
11898
|
-
|
|
11932
|
+
const connecting = (async () => {
|
|
11933
|
+
let candidate = null;
|
|
11934
|
+
try {
|
|
11935
|
+
candidate = await this.connectClient();
|
|
11936
|
+
if (generation !== this.connectionGeneration) {
|
|
11937
|
+
candidate.close();
|
|
11938
|
+
throw this.connectionChangedError("subc connection attempt was superseded");
|
|
11939
|
+
}
|
|
11940
|
+
this.client = candidate;
|
|
11941
|
+
this.routes.clear();
|
|
11942
|
+
this.backoffMs = CONNECT_BACKOFF_INITIAL_MS;
|
|
11943
|
+
this.nextProbeMs = 0;
|
|
11944
|
+
return candidate;
|
|
11945
|
+
} catch (error) {
|
|
11946
|
+
candidate?.close();
|
|
11947
|
+
if (generation === this.connectionGeneration)
|
|
11948
|
+
this.invalidateConnection();
|
|
11949
|
+
this.nextProbeMs = Date.now() + this.backoffMs;
|
|
11950
|
+
this.backoffMs = Math.min(this.backoffMs * 2, CONNECT_BACKOFF_MAX_MS);
|
|
11899
11951
|
throw error;
|
|
11900
11952
|
}
|
|
11901
|
-
|
|
11902
|
-
|
|
11903
|
-
|
|
11904
|
-
|
|
11905
|
-
|
|
11906
|
-
|
|
11907
|
-
|
|
11908
|
-
this.invalidateConnection();
|
|
11909
|
-
this.nextProbeMs = Date.now() + this.backoffMs;
|
|
11910
|
-
this.backoffMs = Math.min(this.backoffMs * 2, CONNECT_BACKOFF_MAX_MS);
|
|
11911
|
-
throw error;
|
|
11953
|
+
})();
|
|
11954
|
+
this.connectionPromise = connecting;
|
|
11955
|
+
try {
|
|
11956
|
+
return await connecting;
|
|
11957
|
+
} finally {
|
|
11958
|
+
if (this.connectionPromise === connecting)
|
|
11959
|
+
this.connectionPromise = null;
|
|
11912
11960
|
}
|
|
11913
11961
|
}
|
|
11914
11962
|
invalidateConnection(client = this.client) {
|
|
11915
|
-
if (client && this.client
|
|
11963
|
+
if (client && this.client !== client)
|
|
11916
11964
|
return;
|
|
11917
11965
|
this.connectionGeneration += 1;
|
|
11966
|
+
this.invalidateStateSyncCapabilities();
|
|
11918
11967
|
this.client = null;
|
|
11919
11968
|
this.routes.clear();
|
|
11969
|
+
this.routeOpenings.clear();
|
|
11920
11970
|
client?.close();
|
|
11921
11971
|
}
|
|
11922
11972
|
}
|
|
@@ -11971,13 +12021,15 @@ function rowKeys(leaseKey) {
|
|
|
11971
12021
|
return {
|
|
11972
12022
|
holder: "dreaming_lease_holder",
|
|
11973
12023
|
heartbeat: "dreaming_lease_heartbeat",
|
|
11974
|
-
expiry: "dreaming_lease_expiry"
|
|
12024
|
+
expiry: "dreaming_lease_expiry",
|
|
12025
|
+
generation: "dreaming_lease_generation"
|
|
11975
12026
|
};
|
|
11976
12027
|
}
|
|
11977
12028
|
return {
|
|
11978
12029
|
holder: `lease:${leaseKey}:holder`,
|
|
11979
12030
|
heartbeat: `lease:${leaseKey}:heartbeat`,
|
|
11980
|
-
expiry: `lease:${leaseKey}:expiry
|
|
12031
|
+
expiry: `lease:${leaseKey}:expiry`,
|
|
12032
|
+
generation: `lease:${leaseKey}:generation`
|
|
11981
12033
|
};
|
|
11982
12034
|
}
|
|
11983
12035
|
function getLeaseExpiry(db, keys) {
|
|
@@ -11995,6 +12047,13 @@ function isLeaseActive(db, leaseKey = DREAMING_LEASE_KEY) {
|
|
|
11995
12047
|
function getLeaseHolder(db, leaseKey = DREAMING_LEASE_KEY) {
|
|
11996
12048
|
return getDreamState(db, rowKeys(leaseKey).holder);
|
|
11997
12049
|
}
|
|
12050
|
+
function getLeaseGeneration(db, leaseKey = DREAMING_LEASE_KEY) {
|
|
12051
|
+
const value = getDreamState(db, rowKeys(leaseKey).generation);
|
|
12052
|
+
if (!value)
|
|
12053
|
+
return null;
|
|
12054
|
+
const generation = Number(value);
|
|
12055
|
+
return Number.isSafeInteger(generation) && generation > 0 ? generation : null;
|
|
12056
|
+
}
|
|
11998
12057
|
function peekLeaseHolderAndExpiry(db, expectedHolder, leaseKey = DREAMING_LEASE_KEY) {
|
|
11999
12058
|
const keys = rowKeys(leaseKey);
|
|
12000
12059
|
const holder = getDreamState(db, keys.holder);
|
|
@@ -12006,6 +12065,9 @@ function peekLeaseHolderAndExpiry(db, expectedHolder, leaseKey = DREAMING_LEASE_
|
|
|
12006
12065
|
const expiry = Number(expiryStr);
|
|
12007
12066
|
return Number.isFinite(expiry) && expiry >= Date.now();
|
|
12008
12067
|
}
|
|
12068
|
+
function leaseOwnershipMatches(db, expectedHolder, expectedGeneration, leaseKey = DREAMING_LEASE_KEY) {
|
|
12069
|
+
return getLeaseGeneration(db, leaseKey) === expectedGeneration && peekLeaseHolderAndExpiry(db, expectedHolder, leaseKey);
|
|
12070
|
+
}
|
|
12009
12071
|
function runImmediate(db, body) {
|
|
12010
12072
|
db.exec("BEGIN IMMEDIATE");
|
|
12011
12073
|
let committed = false;
|
|
@@ -12022,26 +12084,30 @@ function runImmediate(db, body) {
|
|
|
12022
12084
|
}
|
|
12023
12085
|
}
|
|
12024
12086
|
}
|
|
12025
|
-
function
|
|
12087
|
+
function acquireLeaseWithAcquisition(db, holderId, leaseKey = DREAMING_LEASE_KEY) {
|
|
12026
12088
|
const keys = rowKeys(leaseKey);
|
|
12027
12089
|
return runImmediate(db, () => {
|
|
12028
|
-
|
|
12029
|
-
|
|
12030
|
-
|
|
12031
|
-
return false;
|
|
12032
|
-
}
|
|
12090
|
+
const existingHolder = getLeaseHolder(db, leaseKey);
|
|
12091
|
+
if (isLeaseActive(db, leaseKey) && existingHolder && existingHolder !== holderId) {
|
|
12092
|
+
return null;
|
|
12033
12093
|
}
|
|
12034
12094
|
const now = Date.now();
|
|
12095
|
+
const priorGeneration = getLeaseGeneration(db, leaseKey) ?? 0;
|
|
12096
|
+
const generation = existingHolder === holderId ? Math.max(1, priorGeneration) : priorGeneration + 1;
|
|
12035
12097
|
setDreamState(db, keys.holder, holderId);
|
|
12036
12098
|
setDreamState(db, keys.heartbeat, String(now));
|
|
12037
12099
|
setDreamState(db, keys.expiry, String(now + LEASE_DURATION_MS));
|
|
12038
|
-
|
|
12100
|
+
setDreamState(db, keys.generation, String(generation));
|
|
12101
|
+
return { acquiredAt: now, generation };
|
|
12039
12102
|
});
|
|
12040
12103
|
}
|
|
12041
|
-
function
|
|
12104
|
+
function acquireLease(db, holderId, leaseKey = DREAMING_LEASE_KEY) {
|
|
12105
|
+
return acquireLeaseWithAcquisition(db, holderId, leaseKey) !== null;
|
|
12106
|
+
}
|
|
12107
|
+
function renewLease(db, holderId, leaseKey = DREAMING_LEASE_KEY, expectedGeneration) {
|
|
12042
12108
|
const keys = rowKeys(leaseKey);
|
|
12043
12109
|
return runImmediate(db, () => {
|
|
12044
|
-
if (getLeaseHolder(db, leaseKey) !== holderId || !isLeaseActive(db, leaseKey)) {
|
|
12110
|
+
if (getLeaseHolder(db, leaseKey) !== holderId || !isLeaseActive(db, leaseKey) || expectedGeneration !== undefined && getLeaseGeneration(db, leaseKey) !== expectedGeneration) {
|
|
12045
12111
|
return false;
|
|
12046
12112
|
}
|
|
12047
12113
|
const now = Date.now();
|
|
@@ -12059,9 +12125,12 @@ function runLeaseGuardedWrite(db, holderId, leaseKey, fn) {
|
|
|
12059
12125
|
});
|
|
12060
12126
|
}
|
|
12061
12127
|
var LEASE_HEARTBEAT_INTERVAL_MS = 60 * 1000;
|
|
12062
|
-
function startLeaseHeartbeat(db, holderId, leaseKey, onLost,
|
|
12128
|
+
function startLeaseHeartbeat(db, holderId, leaseKey, onLost, intervalOrAcquisition = LEASE_HEARTBEAT_INTERVAL_MS) {
|
|
12129
|
+
const intervalMs = typeof intervalOrAcquisition === "number" ? intervalOrAcquisition : LEASE_HEARTBEAT_INTERVAL_MS;
|
|
12130
|
+
const acquisition = typeof intervalOrAcquisition === "number" ? undefined : intervalOrAcquisition;
|
|
12063
12131
|
let lost = false;
|
|
12064
|
-
let
|
|
12132
|
+
let expectedGeneration = acquisition?.generation ?? getLeaseGeneration(db, leaseKey);
|
|
12133
|
+
let lastConfirmedAt = acquisition?.acquiredAt ?? Date.now();
|
|
12065
12134
|
const declareLost = (reason) => {
|
|
12066
12135
|
if (lost)
|
|
12067
12136
|
return;
|
|
@@ -12072,15 +12141,25 @@ function startLeaseHeartbeat(db, holderId, leaseKey, onLost, intervalMs = LEASE_
|
|
|
12072
12141
|
if (lost)
|
|
12073
12142
|
return;
|
|
12074
12143
|
try {
|
|
12075
|
-
if (renewLease(db, holderId, leaseKey)) {
|
|
12144
|
+
if (renewLease(db, holderId, leaseKey, expectedGeneration === null ? undefined : expectedGeneration)) {
|
|
12076
12145
|
lastConfirmedAt = Date.now();
|
|
12077
12146
|
return;
|
|
12078
12147
|
}
|
|
12148
|
+
if (expectedGeneration !== null && getLeaseGeneration(db, leaseKey) !== expectedGeneration) {
|
|
12149
|
+
declareLost("lease generation changed — another holder acquired it");
|
|
12150
|
+
return;
|
|
12151
|
+
}
|
|
12079
12152
|
if (Date.now() - lastConfirmedAt > LEASE_DURATION_MS) {
|
|
12080
12153
|
declareLost("lease lapsed past TTL — another holder may have run");
|
|
12081
12154
|
return;
|
|
12082
12155
|
}
|
|
12083
|
-
|
|
12156
|
+
const reacquired = acquireLeaseWithAcquisition(db, holderId, leaseKey);
|
|
12157
|
+
if (reacquired) {
|
|
12158
|
+
if (expectedGeneration !== null && reacquired.generation !== expectedGeneration) {
|
|
12159
|
+
declareLost("lease generation changed during reacquisition");
|
|
12160
|
+
return;
|
|
12161
|
+
}
|
|
12162
|
+
expectedGeneration = reacquired.generation;
|
|
12084
12163
|
lastConfirmedAt = Date.now();
|
|
12085
12164
|
return;
|
|
12086
12165
|
}
|
|
@@ -12587,7 +12666,7 @@ var DREAMER_DOCS_AGENT = "dreamer-docs";
|
|
|
12587
12666
|
var DREAMER_REVIEWER_AGENT = "dreamer-reviewer";
|
|
12588
12667
|
|
|
12589
12668
|
// src/features/magic-context/mural/compress-cues.ts
|
|
12590
|
-
import { createHash as
|
|
12669
|
+
import { createHash as createHash3 } from "node:crypto";
|
|
12591
12670
|
|
|
12592
12671
|
// src/features/magic-context/dreamer/manifest-parser.ts
|
|
12593
12672
|
function extractCompleteManifestBody(text, rootName) {
|
|
@@ -12623,6 +12702,16 @@ function assertManifestCoversExactly(ids, expectedIds, rootName) {
|
|
|
12623
12702
|
}
|
|
12624
12703
|
|
|
12625
12704
|
// src/features/magic-context/dreamer/module-apply.ts
|
|
12705
|
+
class DreamerModuleBusyError extends Error {
|
|
12706
|
+
state;
|
|
12707
|
+
transient = true;
|
|
12708
|
+
constructor(state) {
|
|
12709
|
+
super(`Rust memory authority is ${state}; dreamer mutation deferred until authority settles.`);
|
|
12710
|
+
this.state = state;
|
|
12711
|
+
this.name = "DreamerModuleBusyError";
|
|
12712
|
+
}
|
|
12713
|
+
}
|
|
12714
|
+
|
|
12626
12715
|
class DreamerModuleFailureError extends Error {
|
|
12627
12716
|
transient = true;
|
|
12628
12717
|
constructor(operation, cause) {
|
|
@@ -12644,9 +12733,12 @@ async function resolveDreamerModuleRoute(args) {
|
|
|
12644
12733
|
projectRoot: args.projectRoot,
|
|
12645
12734
|
domain: "memories"
|
|
12646
12735
|
});
|
|
12647
|
-
|
|
12736
|
+
const authority = result.authority;
|
|
12737
|
+
if (authority?.state === "DRAINING")
|
|
12738
|
+
throw new DreamerModuleBusyError(authority.state);
|
|
12739
|
+
if (authority?.state !== "MODULE")
|
|
12648
12740
|
return;
|
|
12649
|
-
const generation =
|
|
12741
|
+
const generation = authority.generation;
|
|
12650
12742
|
if (typeof generation !== "number")
|
|
12651
12743
|
throw new Error("Rust authority status omitted generation");
|
|
12652
12744
|
return {
|
|
@@ -12680,6 +12772,68 @@ function getModuleMemoryIdentities(db, projectIdentity, contextIds) {
|
|
|
12680
12772
|
] : []));
|
|
12681
12773
|
}
|
|
12682
12774
|
|
|
12775
|
+
// src/features/magic-context/dreamer/provider-output-failure.ts
|
|
12776
|
+
import { createHash as createHash2 } from "node:crypto";
|
|
12777
|
+
var MAX_NEAR_ZERO_OUTPUT_TOKENS = 32;
|
|
12778
|
+
|
|
12779
|
+
class DreamerProviderOutputFailureError extends Error {
|
|
12780
|
+
fingerprint;
|
|
12781
|
+
outputTokens;
|
|
12782
|
+
reasoningTokens;
|
|
12783
|
+
transient = true;
|
|
12784
|
+
constructor(fingerprint, outputTokens, reasoningTokens, responseText) {
|
|
12785
|
+
const preview = responseText.trim().replace(/\s+/g, " ").slice(0, 160);
|
|
12786
|
+
super(`dreamer provider-outage completion (output_tokens=${outputTokens}, reasoning_tokens=${reasoningTokens}): ${JSON.stringify(preview)}`);
|
|
12787
|
+
this.fingerprint = fingerprint;
|
|
12788
|
+
this.outputTokens = outputTokens;
|
|
12789
|
+
this.reasoningTokens = reasoningTokens;
|
|
12790
|
+
this.name = "DreamerProviderOutputFailureError";
|
|
12791
|
+
}
|
|
12792
|
+
}
|
|
12793
|
+
function finiteTokenCount(value) {
|
|
12794
|
+
return typeof value === "number" && Number.isFinite(value) && value >= 0 ? value : null;
|
|
12795
|
+
}
|
|
12796
|
+
function completionShape(value) {
|
|
12797
|
+
if (!isRecord(value))
|
|
12798
|
+
return null;
|
|
12799
|
+
const info = isRecord(value.info) ? value.info : value;
|
|
12800
|
+
if (info.role !== "assistant")
|
|
12801
|
+
return null;
|
|
12802
|
+
const time = isRecord(info.time) ? info.time : null;
|
|
12803
|
+
const tokens = isRecord(info.tokens) ? info.tokens : null;
|
|
12804
|
+
return {
|
|
12805
|
+
createdAt: typeof time?.created === "number" ? time.created : 0,
|
|
12806
|
+
finish: typeof info.finish === "string" ? info.finish : typeof info.finish_reason === "string" ? info.finish_reason : typeof info.finishReason === "string" ? info.finishReason : null,
|
|
12807
|
+
error: info.error,
|
|
12808
|
+
outputTokens: finiteTokenCount(tokens?.output),
|
|
12809
|
+
reasoningTokens: finiteTokenCount(tokens?.reasoning)
|
|
12810
|
+
};
|
|
12811
|
+
}
|
|
12812
|
+
function latestAssistantCompletion(messages) {
|
|
12813
|
+
if (!Array.isArray(messages))
|
|
12814
|
+
return null;
|
|
12815
|
+
let latest = null;
|
|
12816
|
+
for (const message of messages) {
|
|
12817
|
+
const completion = completionShape(message);
|
|
12818
|
+
if (completion && (!latest || completion.createdAt >= latest.createdAt))
|
|
12819
|
+
latest = completion;
|
|
12820
|
+
}
|
|
12821
|
+
return latest;
|
|
12822
|
+
}
|
|
12823
|
+
function providerOutputFailureFromInvalidManifest(messages, responseText) {
|
|
12824
|
+
const completion = latestAssistantCompletion(messages);
|
|
12825
|
+
if (completion?.finish?.toLowerCase() !== "stop")
|
|
12826
|
+
return null;
|
|
12827
|
+
if (completion.error != null || completion.outputTokens === null || completion.outputTokens > MAX_NEAR_ZERO_OUTPUT_TOKENS || completion.reasoningTokens !== 0) {
|
|
12828
|
+
return null;
|
|
12829
|
+
}
|
|
12830
|
+
const normalized = responseText.trim().replace(/\s+/g, " ").toLowerCase();
|
|
12831
|
+
if (!normalized)
|
|
12832
|
+
return null;
|
|
12833
|
+
const fingerprint = createHash2("sha256").update(normalized).digest("hex").slice(0, 16);
|
|
12834
|
+
return new DreamerProviderOutputFailureError(fingerprint, completion.outputTokens, completion.reasoningTokens, responseText);
|
|
12835
|
+
}
|
|
12836
|
+
|
|
12683
12837
|
// src/features/magic-context/mural/compress-cues-prompt.ts
|
|
12684
12838
|
var CUE_BUDGET_HIGH = 90;
|
|
12685
12839
|
var CUE_BUDGET_LOW = 50;
|
|
@@ -12852,7 +13006,7 @@ async function runCompressCues(args) {
|
|
|
12852
13006
|
chunks.push(candidates.slice(i, i + COMPRESS_CUES_CHUNK_SIZE));
|
|
12853
13007
|
}
|
|
12854
13008
|
const abortController = new AbortController;
|
|
12855
|
-
const heartbeat = startLeaseHeartbeat(args.db, args.holderId, args.leaseKey, () => abortController.abort());
|
|
13009
|
+
const heartbeat = startLeaseHeartbeat(args.db, args.holderId, args.leaseKey, () => abortController.abort(), args.leaseAcquisition);
|
|
12856
13010
|
try {
|
|
12857
13011
|
let consecutiveTimeouts = 0;
|
|
12858
13012
|
let timeoutStreakElapsedMs = [];
|
|
@@ -12947,7 +13101,14 @@ async function compressOneChunk(args, chunk, sliceMs, signal) {
|
|
|
12947
13101
|
const text = extractLatestAssistantText(messages);
|
|
12948
13102
|
if (!text)
|
|
12949
13103
|
throw new Error("compress-cues returned no output");
|
|
12950
|
-
|
|
13104
|
+
try {
|
|
13105
|
+
parseCuesManifest(text);
|
|
13106
|
+
} catch (error) {
|
|
13107
|
+
const providerFailure = providerOutputFailureFromInvalidManifest(messages, text);
|
|
13108
|
+
if (providerFailure)
|
|
13109
|
+
throw providerFailure;
|
|
13110
|
+
throw error;
|
|
13111
|
+
}
|
|
12951
13112
|
return text;
|
|
12952
13113
|
}
|
|
12953
13114
|
});
|
|
@@ -12955,7 +13116,7 @@ async function compressOneChunk(args, chunk, sliceMs, signal) {
|
|
|
12955
13116
|
} catch (error) {
|
|
12956
13117
|
const desc = describeError(error);
|
|
12957
13118
|
log(`[dreamer] compress-cues chunk failed: ${desc.brief}`, desc.stackHead ? { stackHead: desc.stackHead } : undefined);
|
|
12958
|
-
if (signal.aborted)
|
|
13119
|
+
if (signal.aborted || error instanceof DreamerProviderOutputFailureError)
|
|
12959
13120
|
throw error;
|
|
12960
13121
|
return {
|
|
12961
13122
|
compressed: 0,
|
|
@@ -13063,7 +13224,7 @@ async function applyCuesThroughModule(args, chunk, manifestText, signal) {
|
|
|
13063
13224
|
log(`[dreamer] compress-cues: skipped cue for memory ${entry.id} (${failure.reason}; rejection ${rejectionCount}/${CUE_REJECTION_LATCH_THRESHOLD})`);
|
|
13064
13225
|
}
|
|
13065
13226
|
}
|
|
13066
|
-
const commandId = `mural-cues:${route.moduleCommandId}:${
|
|
13227
|
+
const commandId = `mural-cues:${route.moduleCommandId}:${createHash3("sha256").update(chunk.map((candidate) => candidate.memory.id).join(",")).digest("hex").slice(0, 24)}`;
|
|
13067
13228
|
let response;
|
|
13068
13229
|
try {
|
|
13069
13230
|
response = await route.moduleClient.call({
|
|
@@ -13200,7 +13361,7 @@ If no promotions are warranted, return empty arrays. Always consume reviewed can
|
|
|
13200
13361
|
const heartbeat = startLeaseHeartbeat(args.db, args.holderId, leaseKey, (reason) => {
|
|
13201
13362
|
log(`[dreamer] user-memories: lease lost (${reason}) — aborting`);
|
|
13202
13363
|
abortController.abort();
|
|
13203
|
-
});
|
|
13364
|
+
}, args.leaseAcquisition);
|
|
13204
13365
|
try {
|
|
13205
13366
|
const createResponse = await createChildSessionWithFence({
|
|
13206
13367
|
client: args.client,
|
|
@@ -13323,7 +13484,7 @@ If no promotions are warranted, return empty arrays. Always consume reviewed can
|
|
|
13323
13484
|
}
|
|
13324
13485
|
|
|
13325
13486
|
// src/features/magic-context/dreamer/classify.ts
|
|
13326
|
-
import { createHash as
|
|
13487
|
+
import { createHash as createHash4 } from "node:crypto";
|
|
13327
13488
|
|
|
13328
13489
|
// src/plugin/rust-tool-backends.ts
|
|
13329
13490
|
function toolCallIdFromContext(context) {
|
|
@@ -13725,7 +13886,7 @@ async function runClassify(args) {
|
|
|
13725
13886
|
chunks.push(toClassify.slice(i, i + CLASSIFY_CHUNK_SIZE));
|
|
13726
13887
|
}
|
|
13727
13888
|
const abortController = new AbortController;
|
|
13728
|
-
const heartbeat = startLeaseHeartbeat(args.db, args.holderId, args.leaseKey, () => abortController.abort());
|
|
13889
|
+
const heartbeat = startLeaseHeartbeat(args.db, args.holderId, args.leaseKey, () => abortController.abort(), args.leaseAcquisition);
|
|
13729
13890
|
try {
|
|
13730
13891
|
for (let i = 0;i < chunks.length; i += 1) {
|
|
13731
13892
|
const remainingMs = Math.max(0, args.deadline - Date.now());
|
|
@@ -13805,7 +13966,14 @@ async function classifyOneChunk(args, chunk, anchors, sliceMs, signal) {
|
|
|
13805
13966
|
const text = extractLatestAssistantText(messages);
|
|
13806
13967
|
if (!text)
|
|
13807
13968
|
throw new Error("classify returned no output");
|
|
13808
|
-
|
|
13969
|
+
try {
|
|
13970
|
+
parseClassifyManifest(text);
|
|
13971
|
+
} catch (error) {
|
|
13972
|
+
const providerFailure = providerOutputFailureFromInvalidManifest(messages, text);
|
|
13973
|
+
if (providerFailure)
|
|
13974
|
+
throw providerFailure;
|
|
13975
|
+
throw error;
|
|
13976
|
+
}
|
|
13809
13977
|
return text;
|
|
13810
13978
|
}
|
|
13811
13979
|
});
|
|
@@ -13816,7 +13984,7 @@ async function classifyOneChunk(args, chunk, anchors, sliceMs, signal) {
|
|
|
13816
13984
|
const desc = describeError(failure);
|
|
13817
13985
|
log(`[dreamer] classify chunk failed: ${desc.brief}`, desc.stackHead ? { stackHead: desc.stackHead } : undefined);
|
|
13818
13986
|
recordInvocation(args, startedAt, { status: "failed", error: failure });
|
|
13819
|
-
if (moduleRoute || signal.aborted)
|
|
13987
|
+
if (moduleRoute || signal.aborted || failure instanceof DreamerProviderOutputFailureError)
|
|
13820
13988
|
throw failure;
|
|
13821
13989
|
return { classified: 0, changed: 0 };
|
|
13822
13990
|
} finally {
|
|
@@ -13845,7 +14013,7 @@ async function runClassifyThroughModule(args, chunk, anchors, signal) {
|
|
|
13845
14013
|
v: 1,
|
|
13846
14014
|
session_id: args.moduleSessionId,
|
|
13847
14015
|
task: "classify",
|
|
13848
|
-
command_id: `classify:${args.moduleCommandId ?? Date.now()}:${
|
|
14016
|
+
command_id: `classify:${args.moduleCommandId ?? Date.now()}:${createHash4("sha256").update(chunk.map((candidate) => candidate.id).join(",")).digest("hex").slice(0, 24)}`,
|
|
13849
14017
|
authority_generation: args.moduleAuthorityGeneration,
|
|
13850
14018
|
payload: {
|
|
13851
14019
|
prompt_body: prompt,
|
|
@@ -14541,7 +14709,7 @@ function throwIfAborted2(signal) {
|
|
|
14541
14709
|
}
|
|
14542
14710
|
|
|
14543
14711
|
// src/features/magic-context/smart-notes/compiler.ts
|
|
14544
|
-
import { createHash as
|
|
14712
|
+
import { createHash as createHash5 } from "node:crypto";
|
|
14545
14713
|
|
|
14546
14714
|
// src/features/magic-context/smart-notes/sandbox-runner.ts
|
|
14547
14715
|
var asyncModulePromise = null;
|
|
@@ -14935,7 +15103,7 @@ function manifestAdvisoryWarnings(code, manifest) {
|
|
|
14935
15103
|
return warnings;
|
|
14936
15104
|
}
|
|
14937
15105
|
function hashCheck(surfaceCondition, compiledCheck, manifest, checkCron) {
|
|
14938
|
-
return
|
|
15106
|
+
return createHash5("sha256").update(surfaceCondition ?? "").update("\x00").update(compiledCheck).update("\x00").update(JSON.stringify(manifest)).update("\x00").update(checkCron).digest("hex");
|
|
14939
15107
|
}
|
|
14940
15108
|
function extractJsonObject(output) {
|
|
14941
15109
|
const fenced = output.match(/```(?:json)?\s*([\s\S]*?)```/i);
|
|
@@ -15068,16 +15236,16 @@ function claimExpectedState(db, expected) {
|
|
|
15068
15236
|
WHERE id = ? AND type = 'smart' AND status = 'pending'
|
|
15069
15237
|
AND content = ? AND surface_condition IS ? AND updated_at = ?${statusClause}`).run(...params).changes > 0;
|
|
15070
15238
|
}
|
|
15071
|
-
function getDueCompiledSmartNoteChecks(db, projectPath, now, limit) {
|
|
15072
|
-
return getPendingSmartNotes(db, projectPath).map(toSmartNote).filter((note) => note.checkStatus === "compiled" && note.compiledCheck !== null && note.policyVersion === SMART_NOTE_CHECK_POLICY_VERSION && (note.checkQuarantinedUntil === null || note.checkQuarantinedUntil <= now) && (note.checkNextDueAt === null || note.checkNextDueAt <= now)).sort((a, b) => (a.checkNextDueAt ?? 0) - (b.checkNextDueAt ?? 0) || a.id - b.id).slice(0, Math.max(1, limit));
|
|
15239
|
+
function getDueCompiledSmartNoteChecks(db, projectPath, now, limit, retinaHandoff = false) {
|
|
15240
|
+
return getPendingSmartNotes(db, projectPath).filter((note) => !retinaHandoff || note.compileStatus !== "compiled").map(toSmartNote).filter((note) => note.checkStatus === "compiled" && note.compiledCheck !== null && note.policyVersion === SMART_NOTE_CHECK_POLICY_VERSION && (note.checkQuarantinedUntil === null || note.checkQuarantinedUntil <= now) && (note.checkNextDueAt === null || note.checkNextDueAt <= now)).sort((a, b) => (a.checkNextDueAt ?? 0) - (b.checkNextDueAt ?? 0) || a.id - b.id).slice(0, Math.max(1, limit));
|
|
15073
15241
|
}
|
|
15074
|
-
function getSmartNotesNeedingCompilation(db, projectPath, now, limit) {
|
|
15075
|
-
return getPendingSmartNotes(db, projectPath).map(toSmartNote).filter((note) => (note.checkNextDueAt === null || note.checkNextDueAt <= now) && (note.checkStatus === "uncompiled" || note.checkStatus === "failing" || note.compiledCheck === null || note.policyVersion !== SMART_NOTE_CHECK_POLICY_VERSION)).sort((a, b) => a.createdAt - b.createdAt || a.id - b.id).slice(0, Math.max(1, limit));
|
|
15242
|
+
function getSmartNotesNeedingCompilation(db, projectPath, now, limit, retinaHandoff = false) {
|
|
15243
|
+
return getPendingSmartNotes(db, projectPath).filter((note) => !retinaHandoff || note.compileStatus !== "compiled").map(toSmartNote).filter((note) => (note.checkNextDueAt === null || note.checkNextDueAt <= now) && (note.checkStatus === "uncompiled" || note.checkStatus === "failing" || note.compiledCheck === null || note.policyVersion !== SMART_NOTE_CHECK_POLICY_VERSION)).sort((a, b) => a.createdAt - b.createdAt || a.id - b.id).slice(0, Math.max(1, limit));
|
|
15076
15244
|
}
|
|
15077
|
-
function getStaleCompiledSmartNotes(db, projectPath, now, limit) {
|
|
15245
|
+
function getStaleCompiledSmartNotes(db, projectPath, now, limit, retinaHandoff = false) {
|
|
15078
15246
|
const staleBefore = now - SMART_NOTE_CHECK_MAX_STALENESS_MS;
|
|
15079
15247
|
const livenessBefore = now - SMART_NOTE_CHECK_LIVENESS_RECHECK_MS;
|
|
15080
|
-
return getPendingSmartNotes(db, projectPath).map(toSmartNote).filter((note) => note.checkStatus === "compiled" && note.compiledCheck !== null && note.policyVersion === SMART_NOTE_CHECK_POLICY_VERSION && note.checkFalseSinceAt !== null && note.checkFalseSinceAt <= staleBefore && (note.checkLastLivenessAt === null || note.checkLastLivenessAt <= livenessBefore)).sort((a, b) => (a.checkFalseSinceAt ?? 0) - (b.checkFalseSinceAt ?? 0) || a.id - b.id).slice(0, Math.max(1, limit));
|
|
15248
|
+
return getPendingSmartNotes(db, projectPath).filter((note) => !retinaHandoff || note.compileStatus !== "compiled").map(toSmartNote).filter((note) => note.checkStatus === "compiled" && note.compiledCheck !== null && note.policyVersion === SMART_NOTE_CHECK_POLICY_VERSION && note.checkFalseSinceAt !== null && note.checkFalseSinceAt <= staleBefore && (note.checkLastLivenessAt === null || note.checkLastLivenessAt <= livenessBefore)).sort((a, b) => (a.checkFalseSinceAt ?? 0) - (b.checkFalseSinceAt ?? 0) || a.id - b.id).slice(0, Math.max(1, limit));
|
|
15081
15249
|
}
|
|
15082
15250
|
function storeCompiledSmartNoteCheck(db, args) {
|
|
15083
15251
|
db.prepare(`UPDATE notes
|
|
@@ -15173,7 +15341,7 @@ var MAX_FAILURES_BEFORE_REAUTHOR = 3;
|
|
|
15173
15341
|
async function runDueCompiledSmartNoteChecks(args) {
|
|
15174
15342
|
const startedAt = Date.now();
|
|
15175
15343
|
const now = args.now ?? startedAt;
|
|
15176
|
-
const due = getDueCompiledSmartNoteChecks(args.db, args.projectIdentity, now, args.maxChecks ?? DEFAULT_MAX_CHECKS);
|
|
15344
|
+
const due = getDueCompiledSmartNoteChecks(args.db, args.projectIdentity, now, args.maxChecks ?? DEFAULT_MAX_CHECKS, args.retinaHandoff);
|
|
15177
15345
|
let ran = 0;
|
|
15178
15346
|
let surfaced = 0;
|
|
15179
15347
|
let failed = 0;
|
|
@@ -15303,7 +15471,8 @@ async function evaluateSmartNotes(args) {
|
|
|
15303
15471
|
const projectRoot = args.sessionDirectory ?? args.projectIdentity;
|
|
15304
15472
|
const moduleBridge = getModuleNoteEvaluationBridge(args.projectIdentity);
|
|
15305
15473
|
await moduleBridge?.sync();
|
|
15306
|
-
const
|
|
15474
|
+
const pendingNotes = () => getPendingSmartNotes(args.db, args.projectIdentity).filter((note) => !args.retinaHandoff || note.compileStatus !== "compiled");
|
|
15475
|
+
const pendingAtStart = pendingNotes().length;
|
|
15307
15476
|
if (pendingAtStart === 0) {
|
|
15308
15477
|
log("[dreamer] smart notes: no pending notes");
|
|
15309
15478
|
return { surfaced: 0, pending: 0, ran: false };
|
|
@@ -15322,12 +15491,12 @@ async function evaluateSmartNotes(args) {
|
|
|
15322
15491
|
leaseAbortController.abort(new Error("Dream lease lost during smart notes"));
|
|
15323
15492
|
log("[dreamer] smart notes: lease lost — aborting");
|
|
15324
15493
|
args.onLeaseLost?.("smart notes");
|
|
15325
|
-
});
|
|
15494
|
+
}, args.leaseAcquisition);
|
|
15326
15495
|
let surfaced = 0;
|
|
15327
15496
|
let didWork = false;
|
|
15328
15497
|
try {
|
|
15329
15498
|
if (moduleBridge) {
|
|
15330
|
-
const candidates2 =
|
|
15499
|
+
const candidates2 = pendingNotes().slice(0, MAX_COMPILE_PER_RUN);
|
|
15331
15500
|
for (const note of candidates2) {
|
|
15332
15501
|
if (Date.now() >= args.deadline)
|
|
15333
15502
|
break;
|
|
@@ -15348,7 +15517,7 @@ async function evaluateSmartNotes(args) {
|
|
|
15348
15517
|
surfaced += 1;
|
|
15349
15518
|
}
|
|
15350
15519
|
await moduleBridge.sync();
|
|
15351
|
-
const pending2 =
|
|
15520
|
+
const pending2 = pendingNotes().length;
|
|
15352
15521
|
return { surfaced, pending: pending2, ran: didWork };
|
|
15353
15522
|
}
|
|
15354
15523
|
const dueRun = await runDueCompiledSmartNoteChecks({
|
|
@@ -15358,11 +15527,12 @@ async function evaluateSmartNotes(args) {
|
|
|
15358
15527
|
maxChecks: 10,
|
|
15359
15528
|
sweepBudgetMs: 1e4,
|
|
15360
15529
|
leaseHeld,
|
|
15361
|
-
signal: leaseAbortController.signal
|
|
15530
|
+
signal: leaseAbortController.signal,
|
|
15531
|
+
retinaHandoff: args.retinaHandoff
|
|
15362
15532
|
});
|
|
15363
15533
|
surfaced += dueRun.surfaced;
|
|
15364
15534
|
didWork ||= dueRun.ran > 0;
|
|
15365
|
-
const candidates = getSmartNotesNeedingCompilation(args.db, args.projectIdentity, Date.now(), MAX_COMPILE_PER_RUN);
|
|
15535
|
+
const candidates = getSmartNotesNeedingCompilation(args.db, args.projectIdentity, Date.now(), MAX_COMPILE_PER_RUN, args.retinaHandoff);
|
|
15366
15536
|
for (const note of candidates) {
|
|
15367
15537
|
if (Date.now() >= args.deadline)
|
|
15368
15538
|
break;
|
|
@@ -15372,7 +15542,7 @@ async function evaluateSmartNotes(args) {
|
|
|
15372
15542
|
if (compiled)
|
|
15373
15543
|
surfaced += 1;
|
|
15374
15544
|
}
|
|
15375
|
-
const stale = getStaleCompiledSmartNotes(args.db, args.projectIdentity, Date.now(), MAX_FALLBACK_PER_RUN);
|
|
15545
|
+
const stale = getStaleCompiledSmartNotes(args.db, args.projectIdentity, Date.now(), MAX_FALLBACK_PER_RUN, args.retinaHandoff);
|
|
15376
15546
|
for (const note of stale) {
|
|
15377
15547
|
if (Date.now() >= args.deadline)
|
|
15378
15548
|
break;
|
|
@@ -15382,7 +15552,7 @@ async function evaluateSmartNotes(args) {
|
|
|
15382
15552
|
if (met)
|
|
15383
15553
|
surfaced += 1;
|
|
15384
15554
|
}
|
|
15385
|
-
const fallbackNotes =
|
|
15555
|
+
const fallbackNotes = pendingNotes().filter((note) => note.checkStatus === "fallback").slice(0, MAX_FALLBACK_PER_RUN);
|
|
15386
15556
|
for (const note of fallbackNotes) {
|
|
15387
15557
|
if (Date.now() >= args.deadline)
|
|
15388
15558
|
break;
|
|
@@ -15762,7 +15932,7 @@ function enforceMaintainDocsProtectedRegions(args) {
|
|
|
15762
15932
|
}
|
|
15763
15933
|
|
|
15764
15934
|
// src/features/magic-context/dreamer/map-memories.ts
|
|
15765
|
-
import { createHash as
|
|
15935
|
+
import { createHash as createHash6 } from "node:crypto";
|
|
15766
15936
|
|
|
15767
15937
|
// src/features/magic-context/dreamer/map-memories-prompt.ts
|
|
15768
15938
|
import { existsSync as existsSync8, statSync as statSync2 } from "node:fs";
|
|
@@ -15879,7 +16049,7 @@ async function mapMemories(args) {
|
|
|
15879
16049
|
}
|
|
15880
16050
|
result.remaining = inputs.length;
|
|
15881
16051
|
const abortController = new AbortController;
|
|
15882
|
-
const heartbeat = startLeaseHeartbeat(args.db, args.holderId, args.leaseKey, () => abortController.abort());
|
|
16052
|
+
const heartbeat = startLeaseHeartbeat(args.db, args.holderId, args.leaseKey, () => abortController.abort(), args.leaseAcquisition);
|
|
15883
16053
|
try {
|
|
15884
16054
|
for (let i = 0;i < batches.length; i += 1) {
|
|
15885
16055
|
const remainingMs = Math.max(0, args.deadline - Date.now());
|
|
@@ -16023,7 +16193,7 @@ async function applyBatchMappings(args, batch, manifestText) {
|
|
|
16023
16193
|
memory_project: args.projectIdentity,
|
|
16024
16194
|
context_store_uuid: args.moduleRoute.moduleContextStoreUuid,
|
|
16025
16195
|
authority_generation: args.moduleRoute.moduleAuthorityGeneration,
|
|
16026
|
-
command_id: `${args.moduleRoute.moduleCommandId}:${
|
|
16196
|
+
command_id: `${args.moduleRoute.moduleCommandId}:${createHash6("sha256").update(rows.map((row) => row.memory_id).join(",")).digest("hex").slice(0, 16)}`,
|
|
16027
16197
|
rows
|
|
16028
16198
|
}
|
|
16029
16199
|
}
|
|
@@ -16248,7 +16418,7 @@ async function promotePrimers(args) {
|
|
|
16248
16418
|
const heartbeat = startLeaseHeartbeat(args.db, args.holderId, args.leaseKey, () => {
|
|
16249
16419
|
leaseLost = true;
|
|
16250
16420
|
log("[dreamer] primers: lease lost during promote-primers — aborting");
|
|
16251
|
-
});
|
|
16421
|
+
}, args.leaseAcquisition);
|
|
16252
16422
|
try {
|
|
16253
16423
|
assertLeaseHeld("prune start");
|
|
16254
16424
|
result.pruned = pruneExpiredPrimerCandidatesForProject(args.db, args.projectIdentity, Date.now(), PRIMER_CANDIDATE_TTL_MS);
|
|
@@ -16480,7 +16650,7 @@ async function refreshPrimers(args) {
|
|
|
16480
16650
|
if (primers.length === 0)
|
|
16481
16651
|
return result;
|
|
16482
16652
|
const abortController = new AbortController;
|
|
16483
|
-
const heartbeat = startLeaseHeartbeat(args.db, args.holderId, args.leaseKey, () => abortController.abort());
|
|
16653
|
+
const heartbeat = startLeaseHeartbeat(args.db, args.holderId, args.leaseKey, () => abortController.abort(), args.leaseAcquisition);
|
|
16484
16654
|
try {
|
|
16485
16655
|
for (let i = 0;i < primers.length; i += 1) {
|
|
16486
16656
|
const primer = primers[i];
|
|
@@ -16967,68 +17137,6 @@ function evaluateTaskGate(task, ctx) {
|
|
|
16967
17137
|
// src/features/magic-context/dreamer/verify.ts
|
|
16968
17138
|
import { createHash as createHash7 } from "node:crypto";
|
|
16969
17139
|
|
|
16970
|
-
// src/features/magic-context/dreamer/provider-output-failure.ts
|
|
16971
|
-
import { createHash as createHash6 } from "node:crypto";
|
|
16972
|
-
var MAX_NEAR_ZERO_OUTPUT_TOKENS = 32;
|
|
16973
|
-
|
|
16974
|
-
class DreamerProviderOutputFailureError extends Error {
|
|
16975
|
-
fingerprint;
|
|
16976
|
-
outputTokens;
|
|
16977
|
-
reasoningTokens;
|
|
16978
|
-
transient = true;
|
|
16979
|
-
constructor(fingerprint, outputTokens, reasoningTokens, responseText) {
|
|
16980
|
-
const preview = responseText.trim().replace(/\s+/g, " ").slice(0, 160);
|
|
16981
|
-
super(`verify provider-outage completion (output_tokens=${outputTokens}, reasoning_tokens=${reasoningTokens}): ${JSON.stringify(preview)}`);
|
|
16982
|
-
this.fingerprint = fingerprint;
|
|
16983
|
-
this.outputTokens = outputTokens;
|
|
16984
|
-
this.reasoningTokens = reasoningTokens;
|
|
16985
|
-
this.name = "DreamerProviderOutputFailureError";
|
|
16986
|
-
}
|
|
16987
|
-
}
|
|
16988
|
-
function finiteTokenCount(value) {
|
|
16989
|
-
return typeof value === "number" && Number.isFinite(value) && value >= 0 ? value : null;
|
|
16990
|
-
}
|
|
16991
|
-
function completionShape(value) {
|
|
16992
|
-
if (!isRecord(value))
|
|
16993
|
-
return null;
|
|
16994
|
-
const info = isRecord(value.info) ? value.info : value;
|
|
16995
|
-
if (info.role !== "assistant")
|
|
16996
|
-
return null;
|
|
16997
|
-
const time = isRecord(info.time) ? info.time : null;
|
|
16998
|
-
const tokens = isRecord(info.tokens) ? info.tokens : null;
|
|
16999
|
-
return {
|
|
17000
|
-
createdAt: typeof time?.created === "number" ? time.created : 0,
|
|
17001
|
-
finish: typeof info.finish === "string" ? info.finish : typeof info.finish_reason === "string" ? info.finish_reason : typeof info.finishReason === "string" ? info.finishReason : null,
|
|
17002
|
-
error: info.error,
|
|
17003
|
-
outputTokens: finiteTokenCount(tokens?.output),
|
|
17004
|
-
reasoningTokens: finiteTokenCount(tokens?.reasoning)
|
|
17005
|
-
};
|
|
17006
|
-
}
|
|
17007
|
-
function latestAssistantCompletion(messages) {
|
|
17008
|
-
if (!Array.isArray(messages))
|
|
17009
|
-
return null;
|
|
17010
|
-
let latest = null;
|
|
17011
|
-
for (const message of messages) {
|
|
17012
|
-
const completion = completionShape(message);
|
|
17013
|
-
if (completion && (!latest || completion.createdAt >= latest.createdAt))
|
|
17014
|
-
latest = completion;
|
|
17015
|
-
}
|
|
17016
|
-
return latest;
|
|
17017
|
-
}
|
|
17018
|
-
function providerOutputFailureFromInvalidManifest(messages, responseText) {
|
|
17019
|
-
const completion = latestAssistantCompletion(messages);
|
|
17020
|
-
if (completion?.finish?.toLowerCase() !== "stop")
|
|
17021
|
-
return null;
|
|
17022
|
-
if (completion.error != null || completion.outputTokens === null || completion.outputTokens > MAX_NEAR_ZERO_OUTPUT_TOKENS || completion.reasoningTokens !== 0) {
|
|
17023
|
-
return null;
|
|
17024
|
-
}
|
|
17025
|
-
const normalized = responseText.trim().replace(/\s+/g, " ").toLowerCase();
|
|
17026
|
-
if (!normalized)
|
|
17027
|
-
return null;
|
|
17028
|
-
const fingerprint = createHash6("sha256").update(normalized).digest("hex").slice(0, 16);
|
|
17029
|
-
return new DreamerProviderOutputFailureError(fingerprint, completion.outputTokens, completion.reasoningTokens, responseText);
|
|
17030
|
-
}
|
|
17031
|
-
|
|
17032
17140
|
// src/features/magic-context/dreamer/verify-gate.ts
|
|
17033
17141
|
import path4 from "node:path";
|
|
17034
17142
|
function minOf(values) {
|
|
@@ -17273,7 +17381,7 @@ async function runVerify(args) {
|
|
|
17273
17381
|
batches.push(gate.inScope.slice(i, i + VERIFY_BATCH_SIZE));
|
|
17274
17382
|
}
|
|
17275
17383
|
const abortController = new AbortController;
|
|
17276
|
-
const heartbeat = startLeaseHeartbeat(args.db, args.holderId, args.leaseKey, () => abortController.abort());
|
|
17384
|
+
const heartbeat = startLeaseHeartbeat(args.db, args.holderId, args.leaseKey, () => abortController.abort(), args.leaseAcquisition);
|
|
17277
17385
|
let consecutiveProviderFailures = 0;
|
|
17278
17386
|
let priorProviderFailureFingerprint = null;
|
|
17279
17387
|
let lastProviderFailure = null;
|
|
@@ -17609,6 +17717,9 @@ function createDreamTaskExecutor(deps) {
|
|
|
17609
17717
|
return async (config, ctx) => {
|
|
17610
17718
|
const { db, projectIdentity, holderId, leaseKey } = ctx;
|
|
17611
17719
|
const startedAt = Date.now();
|
|
17720
|
+
const leaseAcquisition = ctx.leaseAcquisition ?? acquireLeaseWithAcquisition(db, holderId, leaseKey) ?? (() => {
|
|
17721
|
+
throw new Error("Dream lease unavailable during executor setup");
|
|
17722
|
+
})();
|
|
17612
17723
|
const deadline = startedAt + config.timeoutMinutes * 60 * 1000;
|
|
17613
17724
|
const backlogAtStart = getDreamTaskBacklog(db, projectIdentity, config.task);
|
|
17614
17725
|
const reportProgress = (processed) => {
|
|
@@ -17626,7 +17737,7 @@ function createDreamTaskExecutor(deps) {
|
|
|
17626
17737
|
};
|
|
17627
17738
|
const parent = await resolveParentSessionId();
|
|
17628
17739
|
let moduleRoute;
|
|
17629
|
-
if (config.task === "map-memories" || config.task === "compress-cues" || config.task === "verify" || config.task === "verify-broad" || config.task === "retrospective") {
|
|
17740
|
+
if (config.task === "map-memories" || config.task === "compress-cues" || config.task === "classify-memories" || config.task === "verify" || config.task === "verify-broad" || config.task === "retrospective") {
|
|
17630
17741
|
try {
|
|
17631
17742
|
moduleRoute = await resolveDreamerModuleRoute({
|
|
17632
17743
|
db,
|
|
@@ -17640,6 +17751,9 @@ function createDreamTaskExecutor(deps) {
|
|
|
17640
17751
|
throw new DreamerModuleFailureError("authority.status", error);
|
|
17641
17752
|
}
|
|
17642
17753
|
}
|
|
17754
|
+
if (!leaseOwnershipMatches(db, holderId, leaseAcquisition.generation, leaseKey)) {
|
|
17755
|
+
throw new Error("Dream lease lost during executor setup");
|
|
17756
|
+
}
|
|
17643
17757
|
const recordRun = (status, error, extra) => {
|
|
17644
17758
|
try {
|
|
17645
17759
|
insertDreamRun(db, {
|
|
@@ -17712,6 +17826,7 @@ function createDreamTaskExecutor(deps) {
|
|
|
17712
17826
|
holderId,
|
|
17713
17827
|
leaseKey,
|
|
17714
17828
|
deadline,
|
|
17829
|
+
leaseAcquisition,
|
|
17715
17830
|
model: config.model ?? deps.mural.model ?? deps.dreamerModel,
|
|
17716
17831
|
fallbackModels: config.fallbackModels,
|
|
17717
17832
|
moduleRoute,
|
|
@@ -17735,6 +17850,7 @@ function createDreamTaskExecutor(deps) {
|
|
|
17735
17850
|
holderId,
|
|
17736
17851
|
leaseKey,
|
|
17737
17852
|
deadline,
|
|
17853
|
+
leaseAcquisition,
|
|
17738
17854
|
promotionThreshold: config.promotionThreshold ?? 3,
|
|
17739
17855
|
model: config.model,
|
|
17740
17856
|
fallbackModels: config.fallbackModels,
|
|
@@ -17754,6 +17870,7 @@ function createDreamTaskExecutor(deps) {
|
|
|
17754
17870
|
holderId,
|
|
17755
17871
|
leaseKey,
|
|
17756
17872
|
deadline,
|
|
17873
|
+
leaseAcquisition,
|
|
17757
17874
|
model: config.model,
|
|
17758
17875
|
fallbackModels: config.fallbackModels,
|
|
17759
17876
|
moduleRoute,
|
|
@@ -17779,6 +17896,7 @@ function createDreamTaskExecutor(deps) {
|
|
|
17779
17896
|
holderId,
|
|
17780
17897
|
leaseKey,
|
|
17781
17898
|
deadline,
|
|
17899
|
+
leaseAcquisition,
|
|
17782
17900
|
forceBroad: config.task === "verify-broad",
|
|
17783
17901
|
model: config.model,
|
|
17784
17902
|
fallbackModels: config.fallbackModels,
|
|
@@ -17812,40 +17930,15 @@ function createDreamTaskExecutor(deps) {
|
|
|
17812
17930
|
}
|
|
17813
17931
|
if (config.task === "classify-memories") {
|
|
17814
17932
|
let moduleArgs;
|
|
17815
|
-
|
|
17816
|
-
|
|
17817
|
-
|
|
17818
|
-
|
|
17819
|
-
|
|
17820
|
-
|
|
17821
|
-
|
|
17822
|
-
|
|
17823
|
-
|
|
17824
|
-
context_store_uuid: contextStoreUuid,
|
|
17825
|
-
project: projectIdentity,
|
|
17826
|
-
projectRoot: deps.sessionDirectory,
|
|
17827
|
-
domain: "memories"
|
|
17828
|
-
});
|
|
17829
|
-
} catch (error) {
|
|
17830
|
-
throw new ClassifyModuleFailureError("authority.status", error);
|
|
17831
|
-
}
|
|
17832
|
-
if (authority.authority?.state === "MODULE") {
|
|
17833
|
-
const generation = authority.authority.generation;
|
|
17834
|
-
if (typeof generation !== "number") {
|
|
17835
|
-
throw new ClassifyModuleFailureError("authority.status", new Error("response omitted generation"));
|
|
17836
|
-
}
|
|
17837
|
-
const moduleClient = {
|
|
17838
|
-
call: (callArgs) => moduleTransport.call(callArgs)
|
|
17839
|
-
};
|
|
17840
|
-
moduleArgs = {
|
|
17841
|
-
moduleClient,
|
|
17842
|
-
moduleSessionId: projectIdentity,
|
|
17843
|
-
moduleProjectRoot: deps.sessionDirectory,
|
|
17844
|
-
moduleContextStoreUuid: contextStoreUuid,
|
|
17845
|
-
moduleAuthorityGeneration: generation,
|
|
17846
|
-
moduleCommandId: `${startedAt}:${holderId}`
|
|
17847
|
-
};
|
|
17848
|
-
}
|
|
17933
|
+
if (moduleRoute) {
|
|
17934
|
+
moduleArgs = {
|
|
17935
|
+
moduleClient: moduleRoute.moduleClient,
|
|
17936
|
+
moduleSessionId: moduleRoute.moduleSessionId,
|
|
17937
|
+
moduleProjectRoot: moduleRoute.moduleProjectRoot,
|
|
17938
|
+
moduleContextStoreUuid: moduleRoute.moduleContextStoreUuid,
|
|
17939
|
+
moduleAuthorityGeneration: moduleRoute.moduleAuthorityGeneration,
|
|
17940
|
+
moduleCommandId: moduleRoute.moduleCommandId
|
|
17941
|
+
};
|
|
17849
17942
|
}
|
|
17850
17943
|
const result = await runClassify({
|
|
17851
17944
|
db,
|
|
@@ -17856,6 +17949,7 @@ function createDreamTaskExecutor(deps) {
|
|
|
17856
17949
|
holderId,
|
|
17857
17950
|
leaseKey,
|
|
17858
17951
|
deadline,
|
|
17952
|
+
leaseAcquisition,
|
|
17859
17953
|
model: config.model,
|
|
17860
17954
|
fallbackModels: config.fallbackModels,
|
|
17861
17955
|
...moduleArgs,
|
|
@@ -17879,6 +17973,7 @@ function createDreamTaskExecutor(deps) {
|
|
|
17879
17973
|
holderId,
|
|
17880
17974
|
leaseKey,
|
|
17881
17975
|
deadline,
|
|
17976
|
+
leaseAcquisition,
|
|
17882
17977
|
promotionThreshold: config.promotionThreshold ?? 2,
|
|
17883
17978
|
ensureProjectRegistered: deps.ensureProjectRegistered
|
|
17884
17979
|
});
|
|
@@ -17896,6 +17991,7 @@ function createDreamTaskExecutor(deps) {
|
|
|
17896
17991
|
holderId,
|
|
17897
17992
|
leaseKey,
|
|
17898
17993
|
deadline,
|
|
17994
|
+
leaseAcquisition,
|
|
17899
17995
|
model: config.model,
|
|
17900
17996
|
fallbackModels: config.fallbackModels,
|
|
17901
17997
|
language: config.language ?? deps.language,
|
|
@@ -17916,8 +18012,10 @@ function createDreamTaskExecutor(deps) {
|
|
|
17916
18012
|
holderId,
|
|
17917
18013
|
leaseKey,
|
|
17918
18014
|
deadline,
|
|
18015
|
+
leaseAcquisition,
|
|
17919
18016
|
model: config.model,
|
|
17920
|
-
fallbackModels: config.fallbackModels
|
|
18017
|
+
fallbackModels: config.fallbackModels,
|
|
18018
|
+
retinaHandoff: deps.retinaHandoff
|
|
17921
18019
|
});
|
|
17922
18020
|
recordRun("completed", null, {
|
|
17923
18021
|
smartNotesSurfaced: result.surfaced,
|
|
@@ -18060,7 +18158,7 @@ async function runRetrospectiveTask(config, ctx, helpers) {
|
|
|
18060
18158
|
const heartbeat = startLeaseHeartbeat(db, holderId, leaseKey, () => {
|
|
18061
18159
|
leaseLost = true;
|
|
18062
18160
|
abortController.abort();
|
|
18063
|
-
});
|
|
18161
|
+
}, ctx.leaseAcquisition);
|
|
18064
18162
|
let childSessionId = null;
|
|
18065
18163
|
try {
|
|
18066
18164
|
const createResponse = await createChildSessionWithFence({
|
|
@@ -18250,7 +18348,7 @@ async function runAgenticTask(config, ctx, helpers) {
|
|
|
18250
18348
|
const heartbeat = startLeaseHeartbeat(db, holderId, leaseKey, () => {
|
|
18251
18349
|
leaseLost = true;
|
|
18252
18350
|
abortController.abort();
|
|
18253
|
-
});
|
|
18351
|
+
}, ctx.leaseAcquisition);
|
|
18254
18352
|
let childSessionId = null;
|
|
18255
18353
|
try {
|
|
18256
18354
|
const createResponse = await createChildSessionWithFence({
|
|
@@ -18433,15 +18531,15 @@ async function runDomainGroup(deps, group, cb) {
|
|
|
18433
18531
|
const { db, projectIdentity, executor } = deps;
|
|
18434
18532
|
const leaseKey = leaseKeyFor(group[0].config.task, projectIdentity);
|
|
18435
18533
|
const holderId = crypto.randomUUID();
|
|
18436
|
-
let
|
|
18437
|
-
if (!
|
|
18534
|
+
let acquisition = acquireLeaseWithAcquisition(db, holderId, leaseKey);
|
|
18535
|
+
if (!acquisition && cb?.leaseWaitMs) {
|
|
18438
18536
|
const deadline = Date.now() + cb.leaseWaitMs;
|
|
18439
|
-
while (!
|
|
18537
|
+
while (!acquisition && Date.now() < deadline) {
|
|
18440
18538
|
await new Promise((resolve3) => setTimeout(resolve3, LEASE_WAIT_POLL_MS));
|
|
18441
|
-
|
|
18539
|
+
acquisition = acquireLeaseWithAcquisition(db, holderId, leaseKey);
|
|
18442
18540
|
}
|
|
18443
18541
|
}
|
|
18444
|
-
if (!
|
|
18542
|
+
if (!acquisition) {
|
|
18445
18543
|
log(`[dreamer] domain lease busy (${leaseKey}) — deferring ${group.length} task(s)`);
|
|
18446
18544
|
for (const due of group)
|
|
18447
18545
|
cb?.onBusy?.(due.config.task);
|
|
@@ -18449,7 +18547,7 @@ async function runDomainGroup(deps, group, cb) {
|
|
|
18449
18547
|
}
|
|
18450
18548
|
try {
|
|
18451
18549
|
for (const due of [...group].sort((a, b) => compareTaskOrder(a.config.task, b.config.task))) {
|
|
18452
|
-
if (!
|
|
18550
|
+
if (!leaseOwnershipMatches(db, holderId, acquisition.generation, leaseKey)) {
|
|
18453
18551
|
log(`[dreamer] domain lease lost (${leaseKey}) — stopping remaining task(s)`);
|
|
18454
18552
|
break;
|
|
18455
18553
|
}
|
|
@@ -18468,7 +18566,13 @@ async function runDomainGroup(deps, group, cb) {
|
|
|
18468
18566
|
}
|
|
18469
18567
|
let outcome;
|
|
18470
18568
|
try {
|
|
18471
|
-
outcome = await executor(due.config, {
|
|
18569
|
+
outcome = await executor(due.config, {
|
|
18570
|
+
db,
|
|
18571
|
+
projectIdentity,
|
|
18572
|
+
holderId,
|
|
18573
|
+
leaseKey,
|
|
18574
|
+
leaseAcquisition: acquisition
|
|
18575
|
+
});
|
|
18472
18576
|
} catch (error) {
|
|
18473
18577
|
outcome = { status: "failed", transient: true, error: String(error) };
|
|
18474
18578
|
}
|
|
@@ -19133,6 +19237,7 @@ async function sweepProject(reg, origin, db, gitCommitEnabled) {
|
|
|
19133
19237
|
dreamerModel: dreamerConfig.model,
|
|
19134
19238
|
mural: reg.mural,
|
|
19135
19239
|
memoryInjectionBudgetTokens: reg.memoryInjectionBudgetTokens,
|
|
19240
|
+
retinaHandoff: reg.retinaHandoff,
|
|
19136
19241
|
transformMode: reg.transformMode,
|
|
19137
19242
|
moduleClient: reg.moduleClient,
|
|
19138
19243
|
onProgress: (progress, completedTask) => reg.onDreamerProgress?.(progress, completedTask)
|
|
@@ -19176,7 +19281,8 @@ async function runCompiledSmartNoteSweep(reg, db) {
|
|
|
19176
19281
|
const result = await runDueCompiledSmartNoteChecks({
|
|
19177
19282
|
db,
|
|
19178
19283
|
projectIdentity: reg.projectIdentity,
|
|
19179
|
-
projectRoot: reg.directory
|
|
19284
|
+
projectRoot: reg.directory,
|
|
19285
|
+
retinaHandoff: reg.retinaHandoff
|
|
19180
19286
|
});
|
|
19181
19287
|
if (result.ran > 0) {
|
|
19182
19288
|
log(`[dreamer] compiled smart-note sweep ${reg.projectIdentity}: ran=${result.ran} surfaced=${result.surfaced} logic_failed=${result.failed} network_failed=${result.networkFailed}`);
|
|
@@ -20991,14 +21097,15 @@ function createMagicContextCommandHandler(deps) {
|
|
|
20991
21097
|
const isSessionUpgradeCommand = (command) => command === "ctx-session-upgrade";
|
|
20992
21098
|
const isEmbedCommand = (command) => command === "ctx-embed";
|
|
20993
21099
|
const rustMode = deps.transformMode === "rust" && deps.rustModeModuleClient;
|
|
20994
|
-
const callRust = async (method, body) => {
|
|
21100
|
+
const callRust = async (method, body, timeoutMs) => {
|
|
20995
21101
|
if (!rustMode)
|
|
20996
21102
|
throw new Error("Rust module client is unavailable");
|
|
20997
21103
|
return moduleResponseValue(await rustMode.call({
|
|
20998
21104
|
sessionId: body.session_id,
|
|
20999
21105
|
projectRoot: deps.projectRoot ?? process.cwd(),
|
|
21000
21106
|
method,
|
|
21001
|
-
body
|
|
21107
|
+
body,
|
|
21108
|
+
...timeoutMs === undefined ? {} : { timeoutMs }
|
|
21002
21109
|
}));
|
|
21003
21110
|
};
|
|
21004
21111
|
return {
|
|
@@ -21143,7 +21250,7 @@ Starting wrapup…`, {});
|
|
|
21143
21250
|
session_id: sessionId,
|
|
21144
21251
|
keep,
|
|
21145
21252
|
command_id: rustCommandId("wrapup")
|
|
21146
|
-
});
|
|
21253
|
+
}, MAX_WRAPUP_REQUEST_BUDGET_MS);
|
|
21147
21254
|
result = formatRustOperationMessage("wrapup", value);
|
|
21148
21255
|
} catch (error) {
|
|
21149
21256
|
result = `## Magic Wrapup — Failed
|
|
@@ -21542,6 +21649,13 @@ var sessionLocks = new Map;
|
|
|
21542
21649
|
var incrementalTimers = new Map;
|
|
21543
21650
|
var pendingIncrementalKeys = new Set;
|
|
21544
21651
|
var completedIncrementalKeys = new Set;
|
|
21652
|
+
function clearCompletedIncrementalKeys(sessionId) {
|
|
21653
|
+
const prefix = `${sessionId}\x00`;
|
|
21654
|
+
for (const key of completedIncrementalKeys) {
|
|
21655
|
+
if (key.startsWith(prefix))
|
|
21656
|
+
completedIncrementalKeys.delete(key);
|
|
21657
|
+
}
|
|
21658
|
+
}
|
|
21545
21659
|
function defer(fn) {
|
|
21546
21660
|
const immediate = globalThis.setImmediate;
|
|
21547
21661
|
if (typeof immediate === "function") {
|
|
@@ -21656,14 +21770,12 @@ function scheduleIncrementalIndex(db, sessionId, messageId, messageSource) {
|
|
|
21656
21770
|
function scheduleClearAndReindex(db, sessionId, readMessages) {
|
|
21657
21771
|
reconciledSessions.delete(sessionId);
|
|
21658
21772
|
reconciliationScheduledSessions.delete(sessionId);
|
|
21659
|
-
|
|
21660
|
-
for (const key of completedIncrementalKeys) {
|
|
21661
|
-
if (key.startsWith(prefix))
|
|
21662
|
-
completedIncrementalKeys.delete(key);
|
|
21663
|
-
}
|
|
21773
|
+
clearCompletedIncrementalKeys(sessionId);
|
|
21664
21774
|
scheduleAfterBootQuiet(() => {
|
|
21665
21775
|
defer(() => {
|
|
21666
21776
|
runWithSessionLock(sessionId, () => {
|
|
21777
|
+
reconciledSessions.delete(sessionId);
|
|
21778
|
+
clearCompletedIncrementalKeys(sessionId);
|
|
21667
21779
|
clearIndexedMessages(db, sessionId);
|
|
21668
21780
|
}).then(() => reconcileSessionIndex(db, sessionId, readMessages)).catch((error) => {
|
|
21669
21781
|
reconciledSessions.delete(sessionId);
|
|
@@ -22693,16 +22805,8 @@ function reconcileCompactionMode(args) {
|
|
|
22693
22805
|
notice: COMPACTION_ON_WRAPUP_SUGGESTION
|
|
22694
22806
|
};
|
|
22695
22807
|
}
|
|
22696
|
-
|
|
22697
|
-
|
|
22698
|
-
return {
|
|
22699
|
-
...NO_TRANSITION,
|
|
22700
|
-
recordToWrite: markerCleanup2.verified ? "off" : "off_cleanup_pending",
|
|
22701
|
-
notice: COMPACTION_OFF_FLIP_NOTICE,
|
|
22702
|
-
markerCleanup: markerCleanup2
|
|
22703
|
-
};
|
|
22704
|
-
}
|
|
22705
|
-
if (!args.compactionOff) {
|
|
22808
|
+
const completingOffNotice = stored === "off_notice_pending";
|
|
22809
|
+
if (!args.compactionOff && !completingOffNotice) {
|
|
22706
22810
|
if (stored === null || resolveCompactionModeRecord(stored) === "on") {
|
|
22707
22811
|
return stored === null ? { ...NO_TRANSITION, recordToWrite: "on" } : NO_TRANSITION;
|
|
22708
22812
|
}
|
|
@@ -22738,6 +22842,9 @@ function reconcileCompactionMode(args) {
|
|
|
22738
22842
|
markerCleanup: markerCleanup2
|
|
22739
22843
|
};
|
|
22740
22844
|
}
|
|
22845
|
+
if (!completingOffNotice) {
|
|
22846
|
+
setCompactionModeRecord(db, sessionId, "off_notice_pending");
|
|
22847
|
+
}
|
|
22741
22848
|
let clearedSomething = false;
|
|
22742
22849
|
const markerCleanup = cleanupOffMarkers(sessionId);
|
|
22743
22850
|
if (markerCleanup.removedRows > 0)
|
|
@@ -22775,10 +22882,8 @@ function reconcileCompactionMode(args) {
|
|
|
22775
22882
|
loggedUnverifiedMarkerCleanupRetry = true;
|
|
22776
22883
|
sessionLog(sessionId, "compaction-off transition could not verify complete marker cleanup; durable cleanup retry will run on the next pass");
|
|
22777
22884
|
}
|
|
22778
|
-
const notice = clearedSomething ? COMPACTION_OFF_FLIP_NOTICE : null;
|
|
22779
|
-
if (notice) {
|
|
22780
|
-
setCompactionModeRecord(db, sessionId, "off_notice_pending");
|
|
22781
|
-
} else if (!markerCleanup.verified) {
|
|
22885
|
+
const notice = clearedSomething || completingOffNotice ? COMPACTION_OFF_FLIP_NOTICE : null;
|
|
22886
|
+
if (!notice && !markerCleanup.verified) {
|
|
22782
22887
|
setCompactionModeRecord(db, sessionId, "off_cleanup_pending");
|
|
22783
22888
|
}
|
|
22784
22889
|
return {
|
|
@@ -23607,6 +23712,22 @@ function partIsAnthropicThinking(part) {
|
|
|
23607
23712
|
const type = part.type;
|
|
23608
23713
|
return type === "thinking" || type === "reasoning" || type === "redacted_thinking";
|
|
23609
23714
|
}
|
|
23715
|
+
function partEndsAnthropicAssistantRun(part) {
|
|
23716
|
+
if (!part || typeof part !== "object")
|
|
23717
|
+
return false;
|
|
23718
|
+
const value = part;
|
|
23719
|
+
if (value.type !== "tool" || value.providerExecuted === true || !value.state || typeof value.state !== "object") {
|
|
23720
|
+
return false;
|
|
23721
|
+
}
|
|
23722
|
+
const status = value.state.status;
|
|
23723
|
+
return status === "completed" || status === "error";
|
|
23724
|
+
}
|
|
23725
|
+
function partIsOpenCodeStepMetadata(part) {
|
|
23726
|
+
if (!part || typeof part !== "object")
|
|
23727
|
+
return false;
|
|
23728
|
+
const type = part.type;
|
|
23729
|
+
return type === "step-start" || type === "step-finish";
|
|
23730
|
+
}
|
|
23610
23731
|
function validateAnthropicReasoningRuns(messages) {
|
|
23611
23732
|
let index = 0;
|
|
23612
23733
|
while (index < messages.length) {
|
|
@@ -23622,7 +23743,10 @@ function validateAnthropicReasoningRuns(messages) {
|
|
|
23622
23743
|
thinkingBlocks += 1;
|
|
23623
23744
|
if (thinkingBlocks > 1 || sawOtherContent)
|
|
23624
23745
|
return false;
|
|
23625
|
-
} else {
|
|
23746
|
+
} else if (partEndsAnthropicAssistantRun(part)) {
|
|
23747
|
+
thinkingBlocks = 0;
|
|
23748
|
+
sawOtherContent = false;
|
|
23749
|
+
} else if (!partIsOpenCodeStepMetadata(part)) {
|
|
23626
23750
|
sawOtherContent = true;
|
|
23627
23751
|
}
|
|
23628
23752
|
}
|
|
@@ -24270,23 +24394,68 @@ function encodeOpenCodeMessagesToCk(messages) {
|
|
|
24270
24394
|
|
|
24271
24395
|
// src/hooks/magic-context/module-state-sync.ts
|
|
24272
24396
|
async function mirrorModuleCompartments(args) {
|
|
24273
|
-
const
|
|
24274
|
-
|
|
24275
|
-
|
|
24276
|
-
|
|
24277
|
-
|
|
24278
|
-
|
|
24279
|
-
|
|
24280
|
-
|
|
24281
|
-
|
|
24397
|
+
const authoritative = [];
|
|
24398
|
+
let afterSequence = -1;
|
|
24399
|
+
let maxSequence = null;
|
|
24400
|
+
for (;; ) {
|
|
24401
|
+
const published = await args.reader.getCompartmentsAfter(args.sessionId, afterSequence);
|
|
24402
|
+
if (!Number.isSafeInteger(published.max_sequence) || published.max_sequence < -1 || maxSequence !== null && published.max_sequence !== maxSequence) {
|
|
24403
|
+
throw new Error("module compartment mirror changed while its authoritative set was read");
|
|
24404
|
+
}
|
|
24405
|
+
maxSequence ??= published.max_sequence;
|
|
24406
|
+
let pageAdvanced = false;
|
|
24282
24407
|
for (const compartment of published.compartments) {
|
|
24283
|
-
if (!Number.
|
|
24284
|
-
|
|
24408
|
+
if (!Number.isSafeInteger(compartment.sequence) || compartment.sequence <= afterSequence || compartment.sequence > maxSequence || !Number.isSafeInteger(compartment.start_message) || !Number.isSafeInteger(compartment.end_message) || typeof compartment.start_message_id !== "string" || typeof compartment.end_message_id !== "string" || typeof compartment.title !== "string" || typeof compartment.content !== "string") {
|
|
24409
|
+
throw new Error("module compartment mirror returned an invalid authoritative row");
|
|
24285
24410
|
}
|
|
24286
|
-
|
|
24411
|
+
authoritative.push(compartment);
|
|
24412
|
+
afterSequence = compartment.sequence;
|
|
24413
|
+
pageAdvanced = true;
|
|
24414
|
+
}
|
|
24415
|
+
if (afterSequence >= maxSequence)
|
|
24416
|
+
break;
|
|
24417
|
+
if (!pageAdvanced) {
|
|
24418
|
+
throw new Error("module compartment mirror returned an incomplete authoritative set");
|
|
24419
|
+
}
|
|
24420
|
+
}
|
|
24421
|
+
const local = args.db.prepare("SELECT sequence, end_message FROM compartments WHERE session_id = ? ORDER BY sequence ASC").all(args.sessionId);
|
|
24422
|
+
let firstDifference = 0;
|
|
24423
|
+
while (firstDifference < local.length && firstDifference < authoritative.length && local[firstDifference]?.sequence === authoritative[firstDifference]?.sequence && local[firstDifference]?.end_message === authoritative[firstDifference]?.end_message) {
|
|
24424
|
+
firstDifference += 1;
|
|
24425
|
+
}
|
|
24426
|
+
const localDifference = local[firstDifference]?.sequence;
|
|
24427
|
+
const authoritativeDifference = authoritative[firstDifference]?.sequence;
|
|
24428
|
+
const divergentSequence = localDifference === undefined ? authoritativeDifference : authoritativeDifference === undefined ? localDifference : Math.min(localDifference, authoritativeDifference);
|
|
24429
|
+
const upsert = args.db.prepare(`INSERT INTO compartments
|
|
24430
|
+
(session_id, sequence, start_message, end_message, start_message_id, end_message_id,
|
|
24431
|
+
title, content, p1, p2, p3, p4, importance, episode_type, legacy, created_at, harness)
|
|
24432
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
24433
|
+
ON CONFLICT(session_id, sequence) DO UPDATE SET
|
|
24434
|
+
start_message = excluded.start_message,
|
|
24435
|
+
end_message = excluded.end_message,
|
|
24436
|
+
start_message_id = excluded.start_message_id,
|
|
24437
|
+
end_message_id = excluded.end_message_id,
|
|
24438
|
+
title = excluded.title,
|
|
24439
|
+
content = excluded.content,
|
|
24440
|
+
p1 = excluded.p1,
|
|
24441
|
+
p2 = excluded.p2,
|
|
24442
|
+
p3 = excluded.p3,
|
|
24443
|
+
p4 = excluded.p4,
|
|
24444
|
+
importance = excluded.importance,
|
|
24445
|
+
episode_type = excluded.episode_type,
|
|
24446
|
+
legacy = excluded.legacy,
|
|
24447
|
+
created_at = excluded.created_at,
|
|
24448
|
+
harness = excluded.harness`);
|
|
24449
|
+
const now = Date.now();
|
|
24450
|
+
args.db.transaction(() => {
|
|
24451
|
+
if (divergentSequence !== undefined) {
|
|
24452
|
+
args.db.prepare("DELETE FROM compartments WHERE session_id = ? AND sequence >= ?").run(args.sessionId, divergentSequence);
|
|
24453
|
+
}
|
|
24454
|
+
for (const compartment of authoritative) {
|
|
24455
|
+
upsert.run(args.sessionId, compartment.sequence, compartment.start_message, compartment.end_message, compartment.start_message_id, compartment.end_message_id, compartment.title, compartment.content, compartment.p1 ?? null, compartment.p2 ?? null, compartment.p3 ?? null, compartment.p4 ?? null, compartment.importance ?? 50, compartment.episode_type ?? null, compartment.legacy ?? (compartment.p1 ? 0 : 1), compartment.created_at ?? now, getHarness());
|
|
24287
24456
|
}
|
|
24288
24457
|
})();
|
|
24289
|
-
return
|
|
24458
|
+
return maxSequence;
|
|
24290
24459
|
}
|
|
24291
24460
|
function stableHash(value) {
|
|
24292
24461
|
return createHmac("sha256", "magic-context-shadow-watermark").update(value).digest("hex");
|
|
@@ -24906,7 +25075,7 @@ async function buildModuleStateSyncPayload(args) {
|
|
|
24906
25075
|
workspace,
|
|
24907
25076
|
nowMs: args.pass.nowMs
|
|
24908
25077
|
}) : [];
|
|
24909
|
-
const userProfile = includeUserProfile
|
|
25078
|
+
const userProfile = includeUserProfile ? getActiveUserMemories(args.pass.db).map((memory) => memory.content) : [];
|
|
24910
25079
|
const memoryMutations = memoryMutationsChanged && args.pass.projectPath ? getMemoryMutationsForRenderByProjects(args.pass.db, workspace.expandedIdentities, acked.memory_mutation_id, renderedMemoryIds).map((row) => ({
|
|
24911
25080
|
id: row.id,
|
|
24912
25081
|
project_path: row.projectPath,
|
|
@@ -25051,62 +25220,87 @@ function readAuthoritySeqMismatch(error) {
|
|
|
25051
25220
|
async function syncModuleState(args) {
|
|
25052
25221
|
let force = args.force;
|
|
25053
25222
|
const adoption = args.options?.authoritySeqAdoption ?? { used: false };
|
|
25054
|
-
|
|
25055
|
-
|
|
25056
|
-
|
|
25057
|
-
|
|
25058
|
-
|
|
25059
|
-
|
|
25060
|
-
})).state_sync_deltas === true;
|
|
25061
|
-
} catch {
|
|
25062
|
-
stateSyncDeltas = false;
|
|
25063
|
-
}
|
|
25064
|
-
}
|
|
25065
|
-
for (;; ) {
|
|
25066
|
-
const payload = await buildModuleStateSyncPayload({
|
|
25067
|
-
state: args.state,
|
|
25068
|
-
pass: args.pass,
|
|
25069
|
-
force,
|
|
25070
|
-
options: { ...args.options, stateSyncDeltas }
|
|
25071
|
-
});
|
|
25072
|
-
if (payload === null)
|
|
25073
|
-
return { status: "no_change" };
|
|
25074
|
-
if (payload === "m0_mutation" || payload === "mismatch" || payload === "unresolved" || payload === "seed_budget") {
|
|
25075
|
-
throw new Error(`module state sync ${payload}`);
|
|
25076
|
-
}
|
|
25077
|
-
try {
|
|
25078
|
-
const batches = payload.wireBatches ?? [payload];
|
|
25079
|
-
for (const batch of batches) {
|
|
25080
|
-
const response = await args.client.call({
|
|
25223
|
+
const resolveStateSyncDeltas = async (afterGenerationChange = false) => {
|
|
25224
|
+
let capability = afterGenerationChange ? undefined : args.options?.stateSyncDeltas;
|
|
25225
|
+
capability ??= args.client.getCachedStateSyncCapabilities?.()?.state_sync_deltas;
|
|
25226
|
+
if (capability === undefined && args.client.stateSyncCapabilities) {
|
|
25227
|
+
try {
|
|
25228
|
+
capability = (await args.client.stateSyncCapabilities({
|
|
25081
25229
|
sessionId: args.pass.sessionId,
|
|
25082
|
-
projectRoot: args.projectRoot
|
|
25083
|
-
|
|
25084
|
-
|
|
25085
|
-
|
|
25086
|
-
|
|
25230
|
+
projectRoot: args.projectRoot
|
|
25231
|
+
})).state_sync_deltas;
|
|
25232
|
+
} catch {
|
|
25233
|
+
capability = false;
|
|
25234
|
+
}
|
|
25235
|
+
}
|
|
25236
|
+
return capability === true;
|
|
25237
|
+
};
|
|
25238
|
+
let stateSyncDeltas = await resolveStateSyncDeltas();
|
|
25239
|
+
syncLoop:
|
|
25240
|
+
for (;; ) {
|
|
25241
|
+
const payload = await buildModuleStateSyncPayload({
|
|
25242
|
+
state: args.state,
|
|
25243
|
+
pass: args.pass,
|
|
25244
|
+
force,
|
|
25245
|
+
options: { ...args.options, stateSyncDeltas }
|
|
25246
|
+
});
|
|
25247
|
+
if (payload === null)
|
|
25248
|
+
return { status: "no_change" };
|
|
25249
|
+
if (payload === "m0_mutation" || payload === "mismatch" || payload === "unresolved" || payload === "seed_budget") {
|
|
25250
|
+
throw new Error(`module state sync ${payload}`);
|
|
25251
|
+
}
|
|
25252
|
+
try {
|
|
25253
|
+
const batches = payload.wireBatches ?? [payload];
|
|
25254
|
+
for (const batch of batches) {
|
|
25255
|
+
const response = await args.client.call({
|
|
25256
|
+
sessionId: args.pass.sessionId,
|
|
25257
|
+
projectRoot: args.projectRoot,
|
|
25258
|
+
method: "state_sync",
|
|
25259
|
+
body: {
|
|
25260
|
+
method: batch.method,
|
|
25261
|
+
...batch.params
|
|
25262
|
+
},
|
|
25263
|
+
generationSensitive: stateSyncDeltas
|
|
25264
|
+
});
|
|
25265
|
+
if (isModuleTransportGenerationChangedResult(response)) {
|
|
25266
|
+
stateSyncDeltas = await resolveStateSyncDeltas(true);
|
|
25267
|
+
continue syncLoop;
|
|
25268
|
+
}
|
|
25269
|
+
if (args.options?.authority === true && responseMemoriesSkipped(response) && !args.state.authorityMemorySyncSkipLogged) {
|
|
25270
|
+
args.state.authorityMemorySyncSkipLogged = true;
|
|
25271
|
+
sessionLog(args.pass.sessionId, "authority state sync skipped module-owned memory sections");
|
|
25087
25272
|
}
|
|
25088
|
-
});
|
|
25089
|
-
if (args.options?.authority === true && responseMemoriesSkipped(response) && !args.state.authorityMemorySyncSkipLogged) {
|
|
25090
|
-
args.state.authorityMemorySyncSkipLogged = true;
|
|
25091
|
-
sessionLog(args.pass.sessionId, "authority state sync skipped module-owned memory sections");
|
|
25092
25273
|
}
|
|
25274
|
+
} catch (error) {
|
|
25275
|
+
if (isHistorianCompartmentSyncBusy(error)) {
|
|
25276
|
+
return { status: "retry_busy" };
|
|
25277
|
+
}
|
|
25278
|
+
const durableSeq = args.options?.authority ? readAuthoritySeqMismatch(error) : null;
|
|
25279
|
+
if (durableSeq === null || adoption.used)
|
|
25280
|
+
throw error;
|
|
25281
|
+
adoption.used = true;
|
|
25282
|
+
args.state.lastAckedSeq = durableSeq;
|
|
25283
|
+
args.state.lastAckedWatermarks = null;
|
|
25284
|
+
force = true;
|
|
25285
|
+
continue;
|
|
25093
25286
|
}
|
|
25094
|
-
|
|
25095
|
-
|
|
25096
|
-
|
|
25097
|
-
}
|
|
25098
|
-
const durableSeq = args.options?.authority ? readAuthoritySeqMismatch(error) : null;
|
|
25099
|
-
if (durableSeq === null || adoption.used)
|
|
25100
|
-
throw error;
|
|
25101
|
-
adoption.used = true;
|
|
25102
|
-
args.state.lastAckedSeq = durableSeq;
|
|
25103
|
-
args.state.lastAckedWatermarks = null;
|
|
25104
|
-
force = true;
|
|
25105
|
-
continue;
|
|
25287
|
+
args.state.lastAckedWatermarks = payload.watermarks;
|
|
25288
|
+
args.state.lastAckedSeq += 1;
|
|
25289
|
+
return { status: "acked", watermarks: payload.watermarks };
|
|
25106
25290
|
}
|
|
25107
|
-
|
|
25108
|
-
|
|
25109
|
-
|
|
25291
|
+
}
|
|
25292
|
+
|
|
25293
|
+
// src/hooks/magic-context/raw-fallback-context-limit.ts
|
|
25294
|
+
class RawFallbackContextLimitError extends Error {
|
|
25295
|
+
estimatedTokens;
|
|
25296
|
+
contextLimitTokens;
|
|
25297
|
+
code = "RAW_FALLBACK_CONTEXT_LIMIT";
|
|
25298
|
+
recoverable = true;
|
|
25299
|
+
constructor(estimatedTokens, contextLimitTokens, options) {
|
|
25300
|
+
super(`Magic Context could not safely serve the raw prompt: the best local estimate is ${estimatedTokens.toLocaleString()} tokens, above the known ${contextLimitTokens.toLocaleString()}-token context limit. Retry the turn so the module can reconnect.`, options);
|
|
25301
|
+
this.estimatedTokens = estimatedTokens;
|
|
25302
|
+
this.contextLimitTokens = contextLimitTokens;
|
|
25303
|
+
this.name = "RawFallbackContextLimitError";
|
|
25110
25304
|
}
|
|
25111
25305
|
}
|
|
25112
25306
|
|
|
@@ -27590,7 +27784,7 @@ var REASONING_IGNORED_PART_TYPES = new Set([
|
|
|
27590
27784
|
"compaction"
|
|
27591
27785
|
]);
|
|
27592
27786
|
var REASONING_PART_TYPES = new Set(["reasoning", "thinking", "redacted_thinking"]);
|
|
27593
|
-
function stripReasoningFromMergedAssistants(messages, providerID) {
|
|
27787
|
+
function stripReasoningFromMergedAssistants(messages, providerID, options) {
|
|
27594
27788
|
if (providerID !== "anthropic")
|
|
27595
27789
|
return 0;
|
|
27596
27790
|
let stripped = 0;
|
|
@@ -27606,6 +27800,10 @@ function stripReasoningFromMergedAssistants(messages, providerID) {
|
|
|
27606
27800
|
const firstInRun = prevRole !== "assistant";
|
|
27607
27801
|
if (firstInRun)
|
|
27608
27802
|
keptReasoningInRun = false;
|
|
27803
|
+
if (message === options?.mutationExemptMessage) {
|
|
27804
|
+
prevRole = role;
|
|
27805
|
+
continue;
|
|
27806
|
+
}
|
|
27609
27807
|
let keepIndex = -1;
|
|
27610
27808
|
if (firstInRun && !keptReasoningInRun) {
|
|
27611
27809
|
for (let i = 0;i < message.parts.length; i++) {
|
|
@@ -28700,11 +28898,21 @@ function finalizeMessageRepresentation(messages, resolvedProviderID, options) {
|
|
|
28700
28898
|
clearedParts = stripClearedReasoning(targetedMessages);
|
|
28701
28899
|
}
|
|
28702
28900
|
}
|
|
28703
|
-
const mergedReasoningParts = stripReasoningFromMergedAssistants(messages, resolvedProviderID
|
|
28901
|
+
const mergedReasoningParts = stripReasoningFromMergedAssistants(messages, resolvedProviderID, {
|
|
28902
|
+
mutationExemptMessage: options?.reasoningMutationExemptMessage
|
|
28903
|
+
});
|
|
28704
28904
|
return { clearedParts, mergedReasoningParts };
|
|
28705
28905
|
}
|
|
28706
28906
|
async function runPostTransformPhase(args) {
|
|
28707
28907
|
const compactionOff = args.compactionOff === true;
|
|
28908
|
+
let reasoningMutationExemptMessage;
|
|
28909
|
+
for (let index = args.messages.length - 1;index >= 0; index -= 1) {
|
|
28910
|
+
const message = args.messages[index];
|
|
28911
|
+
if (message.info.role !== "assistant")
|
|
28912
|
+
continue;
|
|
28913
|
+
reasoningMutationExemptMessage = message;
|
|
28914
|
+
break;
|
|
28915
|
+
}
|
|
28708
28916
|
const pendingMaterializationAtPassStart = args.pendingMaterializationSessions.has(args.sessionId);
|
|
28709
28917
|
const deferredMaterializationAtPassStart = args.deferredMaterializationSessions.has(args.sessionId);
|
|
28710
28918
|
const isExplicitFlush = pendingMaterializationAtPassStart;
|
|
@@ -28723,6 +28931,10 @@ async function runPostTransformPhase(args) {
|
|
|
28723
28931
|
state: args.sessionMeta,
|
|
28724
28932
|
projectPath: args.m0M1.projectPath,
|
|
28725
28933
|
projectDirectory: args.m0M1.projectDirectory,
|
|
28934
|
+
injectDocs: args.m0M1.injectDocs,
|
|
28935
|
+
muralEnabled: args.m0M1.muralEnabled,
|
|
28936
|
+
memoryInjectionBudgetTokens: args.m0M1.memoryInjectionBudgetTokens,
|
|
28937
|
+
historyBudgetTokens: args.m0M1.historyBudgetTokens,
|
|
28726
28938
|
hardSignals: args.m0M1.hardSignals
|
|
28727
28939
|
}).value : false;
|
|
28728
28940
|
const bypassCompartmentGate = forceMaterialization || m0HardFoldThisPass;
|
|
@@ -29251,7 +29463,8 @@ async function runPostTransformPhase(args) {
|
|
|
29251
29463
|
const tFinalRepresentation = performance.now();
|
|
29252
29464
|
const finalRepresentation = finalizeMessageRepresentation(args.messages, args.resolvedProviderID, {
|
|
29253
29465
|
prependedMessageCount,
|
|
29254
|
-
reasoningMutatedMessages
|
|
29466
|
+
reasoningMutatedMessages,
|
|
29467
|
+
reasoningMutationExemptMessage
|
|
29255
29468
|
});
|
|
29256
29469
|
sessionLog(args.sessionId, `final representation: clearedParts=${finalRepresentation.clearedParts} mergedReasoningParts=${finalRepresentation.mergedReasoningParts}`);
|
|
29257
29470
|
logTransformTiming(args.sessionId, "finalizeMessageRepresentation", tFinalRepresentation, `clearedParts=${finalRepresentation.clearedParts} mergedReasoningParts=${finalRepresentation.mergedReasoningParts}`);
|
|
@@ -29293,6 +29506,15 @@ var RUST_PARK_RETRY_INTERVAL = 5;
|
|
|
29293
29506
|
var RUST_EMERGENCY_WALL_PCT = 95;
|
|
29294
29507
|
var RUST_PARK_PROBE_PRESSURE_BYPASS_PCT = 90;
|
|
29295
29508
|
var RUST_SEND_TIMEOUT_MS = 15000;
|
|
29509
|
+
var RAW_FALLBACK_BYTES_PER_CONTEXT_TOKEN = 4;
|
|
29510
|
+
function rawFallbackSerializedBytes(messages) {
|
|
29511
|
+
try {
|
|
29512
|
+
const serialized = JSON.stringify(messages);
|
|
29513
|
+
return typeof serialized === "string" ? Buffer.byteLength(serialized) : null;
|
|
29514
|
+
} catch {
|
|
29515
|
+
return null;
|
|
29516
|
+
}
|
|
29517
|
+
}
|
|
29296
29518
|
function isRecord3(value) {
|
|
29297
29519
|
return value !== null && typeof value === "object";
|
|
29298
29520
|
}
|
|
@@ -29321,34 +29543,26 @@ function updateFnv1a32(hash, value) {
|
|
|
29321
29543
|
}
|
|
29322
29544
|
return next;
|
|
29323
29545
|
}
|
|
29324
|
-
var SNAPSHOT_ARRAY = Symbol("array");
|
|
29325
|
-
var SNAPSHOT_OBJECT = Symbol("object");
|
|
29326
|
-
var SNAPSHOT_KEY = Symbol("key");
|
|
29327
|
-
var SNAPSHOT_STRING = Symbol("string");
|
|
29328
|
-
var SNAPSHOT_NUMBER = Symbol("number");
|
|
29329
|
-
var SNAPSHOT_BOOLEAN = Symbol("boolean");
|
|
29330
|
-
var SNAPSHOT_NULL = Symbol("null");
|
|
29331
|
-
var SNAPSHOT_UNDEFINED = Symbol("undefined");
|
|
29332
29546
|
function isSnapshotObjectChild(value) {
|
|
29333
29547
|
return value !== undefined && typeof value !== "function" && typeof value !== "symbol";
|
|
29334
29548
|
}
|
|
29335
29549
|
function visitMessageContentFields(value, visitor) {
|
|
29336
29550
|
if (value === null)
|
|
29337
|
-
return visitor.field(
|
|
29551
|
+
return visitor.field(LKG_SNAPSHOT_NULL);
|
|
29338
29552
|
if (typeof value === "string") {
|
|
29339
|
-
return visitor.field(
|
|
29553
|
+
return visitor.field(LKG_SNAPSHOT_STRING) && visitor.field(value);
|
|
29340
29554
|
}
|
|
29341
29555
|
if (typeof value === "number") {
|
|
29342
|
-
return visitor.field(
|
|
29556
|
+
return visitor.field(LKG_SNAPSHOT_NUMBER) && visitor.field(value);
|
|
29343
29557
|
}
|
|
29344
29558
|
if (typeof value === "boolean") {
|
|
29345
|
-
return visitor.field(
|
|
29559
|
+
return visitor.field(LKG_SNAPSHOT_BOOLEAN) && visitor.field(value);
|
|
29346
29560
|
}
|
|
29347
29561
|
if (value === undefined || typeof value === "function" || typeof value === "symbol") {
|
|
29348
|
-
return visitor.field(
|
|
29562
|
+
return visitor.field(LKG_SNAPSHOT_UNDEFINED);
|
|
29349
29563
|
}
|
|
29350
29564
|
if (Array.isArray(value)) {
|
|
29351
|
-
if (!visitor.field(
|
|
29565
|
+
if (!visitor.field(LKG_SNAPSHOT_ARRAY) || !visitor.field(value.length))
|
|
29352
29566
|
return false;
|
|
29353
29567
|
for (const item of value) {
|
|
29354
29568
|
if (!visitMessageContentFields(item, visitor))
|
|
@@ -29357,7 +29571,7 @@ function visitMessageContentFields(value, visitor) {
|
|
|
29357
29571
|
return true;
|
|
29358
29572
|
}
|
|
29359
29573
|
if (typeof value === "object") {
|
|
29360
|
-
if (!visitor.field(
|
|
29574
|
+
if (!visitor.field(LKG_SNAPSHOT_OBJECT))
|
|
29361
29575
|
return false;
|
|
29362
29576
|
const objectToken = visitor.beginObject();
|
|
29363
29577
|
if (objectToken === undefined)
|
|
@@ -29370,13 +29584,13 @@ function visitMessageContentFields(value, visitor) {
|
|
|
29370
29584
|
if (!isSnapshotObjectChild(child))
|
|
29371
29585
|
continue;
|
|
29372
29586
|
entryCount += 1;
|
|
29373
|
-
if (!visitor.field(
|
|
29587
|
+
if (!visitor.field(LKG_SNAPSHOT_KEY) || !visitor.field(key) || !visitMessageContentFields(child, visitor)) {
|
|
29374
29588
|
return false;
|
|
29375
29589
|
}
|
|
29376
29590
|
}
|
|
29377
29591
|
return visitor.endObject(objectToken, entryCount);
|
|
29378
29592
|
}
|
|
29379
|
-
return visitor.field(
|
|
29593
|
+
return visitor.field(LKG_SNAPSHOT_UNDEFINED);
|
|
29380
29594
|
}
|
|
29381
29595
|
function messageContentFields(message) {
|
|
29382
29596
|
const fields = [];
|
|
@@ -29533,6 +29747,19 @@ function responseValue(response) {
|
|
|
29533
29747
|
return response;
|
|
29534
29748
|
throw new Error("module transform returned a non-object response");
|
|
29535
29749
|
}
|
|
29750
|
+
function mirrorRustRenderedMemoryIds(args) {
|
|
29751
|
+
if (!("rendered_memory_ids" in args.response))
|
|
29752
|
+
return;
|
|
29753
|
+
const rawIds = args.response.rendered_memory_ids;
|
|
29754
|
+
if (!Array.isArray(rawIds) || rawIds.some((id) => typeof id !== "number" || !Number.isSafeInteger(id) || id <= 0)) {
|
|
29755
|
+
throw new Error("module transform returned an invalid rendered-memory manifest");
|
|
29756
|
+
}
|
|
29757
|
+
const serialized = JSON.stringify(rawIds);
|
|
29758
|
+
args.db.prepare(`UPDATE session_meta
|
|
29759
|
+
SET memory_block_ids = ?, memory_block_count = ?
|
|
29760
|
+
WHERE session_id = ?
|
|
29761
|
+
AND (COALESCE(memory_block_ids, '') <> ? OR COALESCE(memory_block_count, -1) <> ?)`).run(serialized, rawIds.length, args.sessionId, serialized, rawIds.length);
|
|
29762
|
+
}
|
|
29536
29763
|
function noteDeliveryPassIds(response) {
|
|
29537
29764
|
if (!Array.isArray(response.note_deliveries))
|
|
29538
29765
|
return [];
|
|
@@ -29587,7 +29814,10 @@ function ensureState(states, sessionId) {
|
|
|
29587
29814
|
memoryAuthorityProject: null,
|
|
29588
29815
|
memoryAuthorityRoot: null,
|
|
29589
29816
|
memoryAuthorityReady: false,
|
|
29590
|
-
authorityMemorySyncSkipLogged: false
|
|
29817
|
+
authorityMemorySyncSkipLogged: false,
|
|
29818
|
+
lkgCaptureSequence: 0,
|
|
29819
|
+
lkgLastCapturedRowVersion: 0,
|
|
29820
|
+
lkgSyncCaptureRequired: false
|
|
29591
29821
|
};
|
|
29592
29822
|
states.set(sessionId, state);
|
|
29593
29823
|
}
|
|
@@ -29878,8 +30108,10 @@ function buildTransformBody(args) {
|
|
|
29878
30108
|
model_key: args.modelKey,
|
|
29879
30109
|
provider_id: args.providerId,
|
|
29880
30110
|
tool_present: args.passInputs.tool_present === true,
|
|
30111
|
+
...typeof args.passInputs.todo_tool_present === "boolean" ? { todo_tool_present: args.passInputs.todo_tool_present } : {},
|
|
29881
30112
|
prompt_surface_preset: args.passInputs.prompt_surface_preset ?? "full",
|
|
29882
30113
|
prompt_surface_model_key: args.passInputs.prompt_surface_model_key,
|
|
30114
|
+
prompt_surface_config_identity: args.passInputs.prompt_surface_config_identity,
|
|
29883
30115
|
prompt_surface_tool_descriptions: args.passInputs.prompt_surface_tool_descriptions ?? {},
|
|
29884
30116
|
effective_execute_threshold: args.passInputs.effective_execute_threshold,
|
|
29885
30117
|
history_budget_tokens: args.passInputs.history_budget_tokens,
|
|
@@ -29901,6 +30133,8 @@ function buildTransformBody(args) {
|
|
|
29901
30133
|
function createRustModeTransform(deps, options) {
|
|
29902
30134
|
const states = new Map;
|
|
29903
30135
|
const wireCaches = new Map;
|
|
30136
|
+
const scheduleLkgCapture = options.scheduleLkgCapture ?? ((capture) => setImmediate(capture));
|
|
30137
|
+
const rawFallbackEstimator = options.rawFallbackEstimatorForTests ?? estimateFinalWireInputTokens;
|
|
29904
30138
|
const timeoutMs = Math.max(1, options.moduleTimeoutMs ?? RUST_SEND_TIMEOUT_MS);
|
|
29905
30139
|
const logStage = (sessionId, stage, startedAt, timings, extra) => {
|
|
29906
30140
|
const elapsed = Math.max(0, performance.now() - startedAt);
|
|
@@ -30019,28 +30253,50 @@ function createRustModeTransform(deps, options) {
|
|
|
30019
30253
|
sessionLog(sessionId, "lkg_replay_served");
|
|
30020
30254
|
return true;
|
|
30021
30255
|
};
|
|
30022
|
-
const
|
|
30023
|
-
|
|
30024
|
-
|
|
30025
|
-
|
|
30256
|
+
const prepareRustCapture = (state, sessionId, input, inputSnapshots, response, responseRowVersion) => {
|
|
30257
|
+
state.lkgCaptureSequence += 1;
|
|
30258
|
+
const inputIds = input.map((message) => message.info.id);
|
|
30259
|
+
if (inputIds.some((id) => typeof id !== "string") || new Set(inputIds).size !== inputIds.length || inputIds.length === 0 || inputSnapshots.length !== inputIds.length) {
|
|
30260
|
+
return null;
|
|
30026
30261
|
}
|
|
30027
|
-
const inputContentDigests = input.map((message) => lkgContentDigest(message));
|
|
30028
|
-
if (inputContentDigests.some((digest) => digest === null))
|
|
30029
|
-
return false;
|
|
30030
30262
|
const native = response.native_messages;
|
|
30031
30263
|
const jsonPrefix = typeof native === "string" ? native : JSON.stringify(native);
|
|
30032
30264
|
if (typeof jsonPrefix !== "string")
|
|
30033
|
-
return
|
|
30265
|
+
return null;
|
|
30034
30266
|
const keys = resolveLkgModelKeys(input);
|
|
30035
|
-
return
|
|
30267
|
+
return {
|
|
30268
|
+
sessionId,
|
|
30269
|
+
inputIds,
|
|
30270
|
+
inputSnapshots,
|
|
30036
30271
|
jsonPrefix,
|
|
30037
|
-
inputIdSeq: ids,
|
|
30038
|
-
inputContentDigests,
|
|
30039
|
-
lastInputMessageId: ids[ids.length - 1],
|
|
30040
30272
|
modelKey: keys.modelKey,
|
|
30041
30273
|
providerKey: keys.providerKey,
|
|
30042
|
-
capturedAt: Date.now()
|
|
30274
|
+
capturedAt: Date.now(),
|
|
30275
|
+
rowVersion: responseRowVersion,
|
|
30276
|
+
captureSequence: state.lkgCaptureSequence
|
|
30277
|
+
};
|
|
30278
|
+
};
|
|
30279
|
+
const commitRustCapture = (state, plan) => {
|
|
30280
|
+
if (states.get(plan.sessionId) !== state || plan.captureSequence !== state.lkgCaptureSequence || plan.rowVersion < state.lkgLastCapturedRowVersion) {
|
|
30281
|
+
return "superseded";
|
|
30282
|
+
}
|
|
30283
|
+
const inputContentDigests = plan.inputSnapshots.map((snapshot) => lkgContentDigestFromFields(snapshot.fields));
|
|
30284
|
+
const captured = captureSlot(plan.sessionId, {
|
|
30285
|
+
jsonPrefix: plan.jsonPrefix,
|
|
30286
|
+
inputIdSeq: plan.inputIds,
|
|
30287
|
+
inputContentDigests,
|
|
30288
|
+
lastInputMessageId: plan.inputIds[plan.inputIds.length - 1],
|
|
30289
|
+
modelKey: plan.modelKey,
|
|
30290
|
+
providerKey: plan.providerKey,
|
|
30291
|
+
capturedAt: plan.capturedAt,
|
|
30292
|
+
rowVersion: plan.rowVersion,
|
|
30293
|
+
captureSequence: plan.captureSequence
|
|
30043
30294
|
});
|
|
30295
|
+
if (!captured)
|
|
30296
|
+
throw new Error("LKG slot rejected the prepared snapshot");
|
|
30297
|
+
state.lkgLastCapturedRowVersion = plan.rowVersion;
|
|
30298
|
+
state.lkgSyncCaptureRequired = false;
|
|
30299
|
+
return "captured";
|
|
30044
30300
|
};
|
|
30045
30301
|
const run = async (sessionId, messages, output, sessionMeta) => {
|
|
30046
30302
|
const passStartedAt = performance.now();
|
|
@@ -30098,6 +30354,29 @@ function createRustModeTransform(deps, options) {
|
|
|
30098
30354
|
const hasProviderProof = overflowState.detectedContextLimit > 0 && detectedLimitMatchesModel || isProviderOverflowReconfirmed(sessionId);
|
|
30099
30355
|
emergencyFailClosed ||= overflowState.needsEmergencyRecovery && overflowState.emergencyRecoveryOrigin === "provider_overflow" && hasProviderProof;
|
|
30100
30356
|
}
|
|
30357
|
+
const serveRawFallback = (cause) => {
|
|
30358
|
+
const contextLimit = resolvedContextLimit ?? (overflowState && overflowState.detectedContextLimit > 0 ? overflowState.detectedContextLimit : undefined);
|
|
30359
|
+
if (contextLimit !== undefined) {
|
|
30360
|
+
let estimate;
|
|
30361
|
+
try {
|
|
30362
|
+
estimate = rawFallbackEstimator({
|
|
30363
|
+
messages,
|
|
30364
|
+
systemPromptTokens: sessionMeta.systemPromptTokens,
|
|
30365
|
+
providerID: model?.providerID,
|
|
30366
|
+
modelID: model?.modelID,
|
|
30367
|
+
agentName: deps.getNotificationParams?.(sessionId)?.agent
|
|
30368
|
+
});
|
|
30369
|
+
} catch {}
|
|
30370
|
+
const rawBytes = rawFallbackSerializedBytes(messages);
|
|
30371
|
+
const proxyTokens = rawBytes === null ? contextLimit + 1 : Math.ceil(rawBytes / RAW_FALLBACK_BYTES_PER_CONTEXT_TOKEN);
|
|
30372
|
+
const refusalTokens = Math.max(estimate?.tokens ?? 0, proxyTokens);
|
|
30373
|
+
if (refusalTokens > contextLimit) {
|
|
30374
|
+
sessionLog(sessionId, `raw_fallback_over_context_limit estimated=${estimate?.tokens ?? "unavailable"} ` + `proxy_bytes=${rawBytes ?? "unavailable"} proxy_tokens=${proxyTokens} limit=${contextLimit}`);
|
|
30375
|
+
throw new RawFallbackContextLimitError(refusalTokens, contextLimit, { cause });
|
|
30376
|
+
}
|
|
30377
|
+
}
|
|
30378
|
+
replaceMessagesInPlace(output, messages);
|
|
30379
|
+
};
|
|
30101
30380
|
const finishPass = (applied, served = true) => {
|
|
30102
30381
|
const elapsedAt = applied && appliedAt !== undefined ? appliedAt : performance.now();
|
|
30103
30382
|
const elapsedMs = Math.max(0, elapsedAt - passStartedAt);
|
|
@@ -30128,11 +30407,19 @@ function createRustModeTransform(deps, options) {
|
|
|
30128
30407
|
servedFrom = typeof response.served_from === "string" ? response.served_from : "unknown";
|
|
30129
30408
|
materializeReason = typeof response.materialize_reason === "string" && response.materialize_reason.length > 0 ? response.materialize_reason : "none";
|
|
30130
30409
|
const timings2 = isRecord3(response.timings) ? response.timings : undefined;
|
|
30131
|
-
const
|
|
30132
|
-
|
|
30410
|
+
const applyOnceTotal = timings2?.total;
|
|
30411
|
+
const handlerTotal = timings2?.handler_total;
|
|
30412
|
+
moduleElapsedMs = typeof handlerTotal === "number" && Number.isFinite(handlerTotal) ? handlerTotal : typeof applyOnceTotal === "number" && Number.isFinite(applyOnceTotal) ? applyOnceTotal : 0;
|
|
30133
30413
|
rowVersion = typeof response.row_version === "number" && Number.isSafeInteger(response.row_version) ? response.row_version : 0;
|
|
30414
|
+
if (timings2 && (typeof timings2.handler_total === "number" || typeof timings2.native_cache_reused_messages === "number" || typeof timings2.native_cache_encoded_messages === "number")) {
|
|
30415
|
+
const stage = (name) => {
|
|
30416
|
+
const value = timings2[name];
|
|
30417
|
+
return typeof value === "number" && Number.isFinite(value) ? value.toFixed(1) : "n/a";
|
|
30418
|
+
};
|
|
30419
|
+
sessionLog(sessionId, `rust module stages: handler=${stage("handler_total")} apply_once=${stage("total")} ` + `request_to_handler=${stage("request_observed_to_handler")} ` + `projection=${stage("projection")} selection=${stage("selection")} ` + `build_output=${stage("build_output")} store_commit=${stage("store_commit")} ` + `post_attach=${stage("post_attach")} response_encode=${stage("response_encode")} ` + `native_cache_reused=${stage("native_cache_reused_messages")} ` + `native_cache_encoded=${stage("native_cache_encoded_messages")}`);
|
|
30420
|
+
}
|
|
30134
30421
|
if (timings2 && moduleElapsedMs >= 1000) {
|
|
30135
|
-
const detail = Object.entries(timings2).filter(([key, value]) => key !== "total" && typeof value === "number").map(([key, value]) => `${key}:${value.toFixed(1)}`).join(" ");
|
|
30422
|
+
const detail = Object.entries(timings2).filter(([key, value]) => key !== "total" && key !== "handler_total" && typeof value === "number").map(([key, value]) => `${key}:${value.toFixed(1)}`).join(" ");
|
|
30136
30423
|
if (detail)
|
|
30137
30424
|
sessionLog(sessionId, `rust module stages (slow pass): ${detail}`);
|
|
30138
30425
|
}
|
|
@@ -30146,7 +30433,12 @@ function createRustModeTransform(deps, options) {
|
|
|
30146
30433
|
servedFrom = "lkg";
|
|
30147
30434
|
} else {
|
|
30148
30435
|
servedFrom = "raw";
|
|
30149
|
-
|
|
30436
|
+
try {
|
|
30437
|
+
serveRawFallback();
|
|
30438
|
+
} catch (error) {
|
|
30439
|
+
finishPass(false, false);
|
|
30440
|
+
throw error;
|
|
30441
|
+
}
|
|
30150
30442
|
}
|
|
30151
30443
|
finishPass(false);
|
|
30152
30444
|
return;
|
|
@@ -30154,7 +30446,9 @@ function createRustModeTransform(deps, options) {
|
|
|
30154
30446
|
}
|
|
30155
30447
|
const reduceAvailability = resolveCtxReduceAvailability(sessionId);
|
|
30156
30448
|
resolveTodowriteAvailabilityFromMessages(sessionId, messages);
|
|
30449
|
+
const todoAvailability = resolveTodowriteAvailability(sessionId);
|
|
30157
30450
|
const toolPresent = reduceAvailability.frozen && reduceAvailability.callable;
|
|
30451
|
+
const todoToolPresent = todoAvailability.frozen ? todoAvailability.callable : undefined;
|
|
30158
30452
|
try {
|
|
30159
30453
|
if (preflightError)
|
|
30160
30454
|
throw preflightError;
|
|
@@ -30188,8 +30482,10 @@ function createRustModeTransform(deps, options) {
|
|
|
30188
30482
|
system_prompt_hash: sessionMeta.systemPromptHash ?? "",
|
|
30189
30483
|
upgrade_state: readUpgradeState(deps.db, sessionId),
|
|
30190
30484
|
tool_present: toolPresent,
|
|
30485
|
+
todo_tool_present: todoToolPresent,
|
|
30191
30486
|
prompt_surface_preset: promptSurface.preset,
|
|
30192
30487
|
prompt_surface_model_key: modelKey,
|
|
30488
|
+
prompt_surface_config_identity: promptSurfaceConfigIdentity(deps.promptSurface),
|
|
30193
30489
|
prompt_surface_tool_descriptions: deps.promptSurface?.tool_descriptions ?? {},
|
|
30194
30490
|
protected_tags: deps.protectedTags ?? DEFAULT_PROTECTED_TAGS,
|
|
30195
30491
|
temporal_awareness: deps.experimentalTemporalAwareness === true,
|
|
@@ -30306,10 +30602,12 @@ function createRustModeTransform(deps, options) {
|
|
|
30306
30602
|
};
|
|
30307
30603
|
}
|
|
30308
30604
|
}
|
|
30605
|
+
const getCachedStateSyncCapabilities = options.moduleClient.getCachedStateSyncCapabilities;
|
|
30309
30606
|
const stateSyncCapabilities = options.moduleClient.stateSyncCapabilities;
|
|
30310
30607
|
const stateSyncResult = await syncModuleState({
|
|
30311
30608
|
client: {
|
|
30312
30609
|
call: callModule,
|
|
30610
|
+
getCachedStateSyncCapabilities: getCachedStateSyncCapabilities ? () => getCachedStateSyncCapabilities.call(options.moduleClient) : undefined,
|
|
30313
30611
|
stateSyncCapabilities: stateSyncCapabilities ? (capabilityArgs) => stateSyncCapabilities.call(options.moduleClient, capabilityArgs) : undefined
|
|
30314
30612
|
},
|
|
30315
30613
|
state,
|
|
@@ -30434,6 +30732,7 @@ function createRustModeTransform(deps, options) {
|
|
|
30434
30732
|
throw new Error("rust module returned no transform response");
|
|
30435
30733
|
captureResponseTelemetry(response);
|
|
30436
30734
|
if (isNeedFullSync(response)) {
|
|
30735
|
+
options.moduleClient.invalidateStateSyncCapabilities?.();
|
|
30437
30736
|
state.forceFullWire = true;
|
|
30438
30737
|
if (wireDelta) {
|
|
30439
30738
|
const retryOrdinalStartedAt = performance.now();
|
|
@@ -30587,13 +30886,46 @@ function createRustModeTransform(deps, options) {
|
|
|
30587
30886
|
}
|
|
30588
30887
|
logStage(sessionId, "apply", applyStartedAt, timings);
|
|
30589
30888
|
const lkgSnapshotStartedAt = performance.now();
|
|
30590
|
-
if (cacheBustingPass
|
|
30591
|
-
|
|
30592
|
-
|
|
30593
|
-
|
|
30889
|
+
if (cacheBustingPass) {
|
|
30890
|
+
dropSlot(sessionId, "lkg_cache_bust_pending_capture");
|
|
30891
|
+
}
|
|
30892
|
+
const capturePlan = prepareRustCapture(state, sessionId, messages, pendingWireCache.rawContentSnapshots, response, rowVersion);
|
|
30893
|
+
let captureMode = "async";
|
|
30894
|
+
const captureFailed = (mode, error) => {
|
|
30895
|
+
if (states.get(sessionId) !== state || capturePlan && capturePlan.captureSequence !== state.lkgCaptureSequence) {
|
|
30896
|
+
return;
|
|
30897
|
+
}
|
|
30898
|
+
dropSlot(sessionId, `lkg_${mode}_capture_failed`);
|
|
30899
|
+
state.lkgSyncCaptureRequired = true;
|
|
30900
|
+
sessionLog(sessionId, `LKG ${mode.toUpperCase()} CAPTURE FAILED; forcing synchronous capture on the next applied pass:`, error);
|
|
30901
|
+
};
|
|
30902
|
+
if (!capturePlan) {
|
|
30903
|
+
captureMode = "declined";
|
|
30904
|
+
captureFailed("async", new Error("LKG snapshot preparation was rejected"));
|
|
30905
|
+
} else if (state.lkgSyncCaptureRequired) {
|
|
30906
|
+
captureMode = "sync_recovery";
|
|
30907
|
+
try {
|
|
30908
|
+
commitRustCapture(state, capturePlan);
|
|
30909
|
+
} catch (error) {
|
|
30910
|
+
captureFailed("sync", error);
|
|
30911
|
+
}
|
|
30912
|
+
} else {
|
|
30913
|
+
try {
|
|
30914
|
+
scheduleLkgCapture(() => {
|
|
30915
|
+
const asyncStartedAt = performance.now();
|
|
30916
|
+
try {
|
|
30917
|
+
const result = commitRustCapture(state, capturePlan);
|
|
30918
|
+
logTransformTiming(sessionId, "rust.lkg_snapshot_async", asyncStartedAt, `result=${result} row_version=${capturePlan.rowVersion}`);
|
|
30919
|
+
} catch (error) {
|
|
30920
|
+
captureFailed("async", error);
|
|
30921
|
+
}
|
|
30922
|
+
});
|
|
30923
|
+
} catch (error) {
|
|
30924
|
+
captureMode = "schedule_failed";
|
|
30925
|
+
captureFailed("async", error);
|
|
30594
30926
|
}
|
|
30595
30927
|
}
|
|
30596
|
-
logStage(sessionId, "lkgSnapshot", lkgSnapshotStartedAt, timings,
|
|
30928
|
+
logStage(sessionId, "lkgSnapshot", lkgSnapshotStartedAt, timings, `mode=${captureMode} row_version=${rowVersion}`);
|
|
30597
30929
|
const applyReplaceStartedAt = performance.now();
|
|
30598
30930
|
replaceMessagesInPlace(output, appliedMessages);
|
|
30599
30931
|
logStage(sessionId, "apply", applyReplaceStartedAt, timings);
|
|
@@ -30606,6 +30938,11 @@ function createRustModeTransform(deps, options) {
|
|
|
30606
30938
|
}
|
|
30607
30939
|
throw error;
|
|
30608
30940
|
}
|
|
30941
|
+
try {
|
|
30942
|
+
mirrorRustRenderedMemoryIds({ db: deps.db, sessionId, response });
|
|
30943
|
+
} catch (error) {
|
|
30944
|
+
sessionLog(sessionId, "rust rendered-memory mirror write failed (ignored):", error);
|
|
30945
|
+
}
|
|
30609
30946
|
if (deliveryPassIds.length > 0) {
|
|
30610
30947
|
try {
|
|
30611
30948
|
await sendNoteDeliveryDisposition("transform.ack");
|
|
@@ -30700,13 +31037,19 @@ function createRustModeTransform(deps, options) {
|
|
|
30700
31037
|
throw new EmergencyFailClosedError("Rust Magic Context was unavailable at a provider-proven context limit", { cause: error });
|
|
30701
31038
|
}
|
|
30702
31039
|
const replayed = replayLastGood(sessionId, messages, output, sessionMeta.systemPromptTokens);
|
|
30703
|
-
if (!replayed)
|
|
30704
|
-
replaceMessagesInPlace(output, messages);
|
|
30705
31040
|
servedFrom = replayed ? "lkg" : "raw";
|
|
30706
31041
|
if (decision.toLowerCase() !== "need_full_sync")
|
|
30707
31042
|
decision = "error";
|
|
30708
31043
|
materializeReason = "none";
|
|
30709
31044
|
markFailure(sessionId, state, error);
|
|
31045
|
+
if (!replayed) {
|
|
31046
|
+
try {
|
|
31047
|
+
serveRawFallback(error);
|
|
31048
|
+
} catch (rawFallbackError) {
|
|
31049
|
+
finishPass(false, false);
|
|
31050
|
+
throw rawFallbackError;
|
|
31051
|
+
}
|
|
31052
|
+
}
|
|
30710
31053
|
finishPass(false);
|
|
30711
31054
|
return;
|
|
30712
31055
|
}
|
|
@@ -31156,16 +31499,6 @@ function createTransform(deps) {
|
|
|
31156
31499
|
sessionLog(sessionId, "transform skipped (internal magic-context child session)");
|
|
31157
31500
|
return;
|
|
31158
31501
|
}
|
|
31159
|
-
if (deps.transformMode === "rust") {
|
|
31160
|
-
if (!rustModeTransform) {
|
|
31161
|
-
sessionLog(sessionId, "rust transform unavailable; using raw passthrough");
|
|
31162
|
-
return;
|
|
31163
|
-
}
|
|
31164
|
-
await rustModeTransform.run(sessionId, messages, output, sessionMeta);
|
|
31165
|
-
return;
|
|
31166
|
-
}
|
|
31167
|
-
const reducedMode = sessionMeta.isSubagent;
|
|
31168
|
-
const fullFeatureMode = !reducedMode;
|
|
31169
31502
|
const compactionOff = deps.compactionOff === true;
|
|
31170
31503
|
try {
|
|
31171
31504
|
const transition = reconcileCompactionMode({
|
|
@@ -31207,6 +31540,18 @@ function createTransform(deps) {
|
|
|
31207
31540
|
passOutcome.record("compaction-mode-transition-failure");
|
|
31208
31541
|
sessionLog(sessionId, "compaction mode transition failed (retrying next pass):", error);
|
|
31209
31542
|
}
|
|
31543
|
+
if (deps.transformMode === "rust") {
|
|
31544
|
+
if (compactionOff)
|
|
31545
|
+
return;
|
|
31546
|
+
if (!rustModeTransform) {
|
|
31547
|
+
sessionLog(sessionId, "rust transform unavailable; using raw passthrough");
|
|
31548
|
+
return;
|
|
31549
|
+
}
|
|
31550
|
+
await rustModeTransform.run(sessionId, messages, output, sessionMeta);
|
|
31551
|
+
return;
|
|
31552
|
+
}
|
|
31553
|
+
const reducedMode = sessionMeta.isSubagent;
|
|
31554
|
+
const fullFeatureMode = !reducedMode;
|
|
31210
31555
|
const ctxReduceAvailability = resolveCtxReduceAvailabilityFromMessages(sessionId, messages);
|
|
31211
31556
|
const ctxReduceCallable = ctxReduceAvailability.callable;
|
|
31212
31557
|
const todowriteAvailability = resolveTodowriteAvailabilityFromMessages(sessionId, messages);
|
|
@@ -33284,37 +33629,49 @@ function createSystemPromptHashHandler(deps) {
|
|
|
33284
33629
|
}
|
|
33285
33630
|
const isCacheBusting = deps.systemPromptRefreshSessions.has(sessionId);
|
|
33286
33631
|
const DATE_PATTERN = /Today's date: .+/;
|
|
33632
|
+
const DATE_PATTERN_ALL = /Today's date: .+/g;
|
|
33633
|
+
const liveSystemContent = output.system.join(`
|
|
33634
|
+
`);
|
|
33635
|
+
if (liveSystemContent.length === 0)
|
|
33636
|
+
return;
|
|
33637
|
+
const previousHash = sessionMetaEarly?.systemPromptHash ?? "";
|
|
33638
|
+
const hasPersistedHash = previousHash !== "" && previousHash !== "0";
|
|
33639
|
+
const dateElementIndexes = [];
|
|
33640
|
+
let currentDate;
|
|
33287
33641
|
for (let i = 0;i < output.system.length; i++) {
|
|
33288
33642
|
const match = output.system[i].match(DATE_PATTERN);
|
|
33289
33643
|
if (!match)
|
|
33290
33644
|
continue;
|
|
33291
|
-
|
|
33292
|
-
|
|
33293
|
-
|
|
33645
|
+
dateElementIndexes.push(i);
|
|
33646
|
+
currentDate ??= match[0];
|
|
33647
|
+
}
|
|
33648
|
+
const stickyDate = stickyDateBySession.get(sessionId);
|
|
33649
|
+
const stableCandidate = currentDate && stickyDate && currentDate !== stickyDate ? liveSystemContent.replace(DATE_PATTERN_ALL, stickyDate) : liveSystemContent;
|
|
33650
|
+
const stableCandidateHash = createHash14("md5").update(promptSurfaceHashMaterial(stableCandidate, promptSurface.preset)).digest("hex");
|
|
33651
|
+
const contentOrPresetChanged = hasPersistedHash && stableCandidateHash !== previousHash;
|
|
33652
|
+
const dateMayAdvance = isCacheBusting || contentOrPresetChanged;
|
|
33653
|
+
if (currentDate && !stickyDate) {
|
|
33654
|
+
stickyDateBySession.set(sessionId, currentDate);
|
|
33655
|
+
} else if (currentDate && stickyDate && currentDate !== stickyDate) {
|
|
33656
|
+
if (dateMayAdvance) {
|
|
33294
33657
|
stickyDateBySession.set(sessionId, currentDate);
|
|
33295
|
-
|
|
33296
|
-
|
|
33297
|
-
|
|
33298
|
-
|
|
33299
|
-
} else {
|
|
33300
|
-
output.system[i] = output.system[i].replace(DATE_PATTERN, stickyDate);
|
|
33301
|
-
sessionLog(sessionId, `system prompt date frozen: real=${currentDate}, using=${stickyDate} (defer pass)`);
|
|
33658
|
+
sessionLog(sessionId, `system prompt date updated: ${stickyDate} → ${currentDate} (cache-busting pass)`);
|
|
33659
|
+
} else if (dateElementIndexes.length > 0) {
|
|
33660
|
+
for (const index of dateElementIndexes) {
|
|
33661
|
+
output.system[index] = output.system[index].replace(DATE_PATTERN_ALL, stickyDate);
|
|
33302
33662
|
}
|
|
33663
|
+
sessionLog(sessionId, `system prompt date frozen: real=${currentDate}, using=${stickyDate} (defer pass)`);
|
|
33303
33664
|
}
|
|
33304
|
-
break;
|
|
33305
33665
|
}
|
|
33306
33666
|
const systemContent = output.system.join(`
|
|
33307
33667
|
`);
|
|
33308
|
-
if (
|
|
33309
|
-
return;
|
|
33310
|
-
if (!availability.frozen)
|
|
33668
|
+
if (!availability.frozen || !modelKey)
|
|
33311
33669
|
return;
|
|
33312
33670
|
const currentHash = createHash14("md5").update(promptSurfaceHashMaterial(systemContent, promptSurface.preset)).digest("hex");
|
|
33313
33671
|
if (!sessionMetaEarly) {
|
|
33314
33672
|
return;
|
|
33315
33673
|
}
|
|
33316
33674
|
const sessionMeta = sessionMetaEarly;
|
|
33317
|
-
const previousHash = sessionMeta.systemPromptHash;
|
|
33318
33675
|
if (previousHash !== "" && previousHash !== "0" && previousHash !== currentHash) {
|
|
33319
33676
|
sessionLog(sessionId, `system prompt hash changed: ${previousHash} → ${currentHash} (len=${systemContent.length}), triggering flush`);
|
|
33320
33677
|
deps.historyRefreshSessions.add(sessionId);
|
|
@@ -33487,6 +33844,37 @@ function notifyMagicContextDisabled(client, reason) {
|
|
|
33487
33844
|
log("[magic-context] failed to show disabled toast:", error);
|
|
33488
33845
|
});
|
|
33489
33846
|
}
|
|
33847
|
+
function moduleNoteRowId(response, depth = 0) {
|
|
33848
|
+
if (depth > 4 || response === null || response === undefined)
|
|
33849
|
+
return null;
|
|
33850
|
+
if (typeof response === "string") {
|
|
33851
|
+
const match = response.match(/\b(?:smart\s+)?note\s+#(\d+)/i);
|
|
33852
|
+
return match ? Number(match[1]) : null;
|
|
33853
|
+
}
|
|
33854
|
+
if (Array.isArray(response)) {
|
|
33855
|
+
for (const item of response) {
|
|
33856
|
+
const id = moduleNoteRowId(item, depth + 1);
|
|
33857
|
+
if (id !== null)
|
|
33858
|
+
return id;
|
|
33859
|
+
}
|
|
33860
|
+
return null;
|
|
33861
|
+
}
|
|
33862
|
+
if (typeof response !== "object")
|
|
33863
|
+
return null;
|
|
33864
|
+
const record = response;
|
|
33865
|
+
return moduleNoteRowId(record.result, depth + 1) ?? moduleNoteRowId(record.content, depth + 1) ?? moduleNoteRowId(record.text, depth + 1);
|
|
33866
|
+
}
|
|
33867
|
+
function moduleNoteResponseIsError(response, depth = 0) {
|
|
33868
|
+
if (depth > 4 || response === null || typeof response !== "object")
|
|
33869
|
+
return false;
|
|
33870
|
+
if (Array.isArray(response)) {
|
|
33871
|
+
return response.some((item) => moduleNoteResponseIsError(item, depth + 1));
|
|
33872
|
+
}
|
|
33873
|
+
const record = response;
|
|
33874
|
+
if (record.isError === true || record.ok === false || record.error !== undefined)
|
|
33875
|
+
return true;
|
|
33876
|
+
return moduleNoteResponseIsError(record.result, depth + 1);
|
|
33877
|
+
}
|
|
33490
33878
|
function createMagicContextHook(deps) {
|
|
33491
33879
|
const contextUsageMap = new Map;
|
|
33492
33880
|
let db;
|
|
@@ -33761,6 +34149,7 @@ function createMagicContextHook(deps) {
|
|
|
33761
34149
|
autoEmbedAttemptedBySession.add(sessionId);
|
|
33762
34150
|
const directory = sessionDirectoryBySession.get(sessionId) ?? deps.directory;
|
|
33763
34151
|
(async () => {
|
|
34152
|
+
let completedDrainWithWork = false;
|
|
33764
34153
|
try {
|
|
33765
34154
|
await new Promise((resolve3) => setTimeout(resolve3, 0));
|
|
33766
34155
|
await ensureProjectRegisteredFromOpenCodeDirectory(directory, db);
|
|
@@ -33782,6 +34171,8 @@ function createMagicContextHook(deps) {
|
|
|
33782
34171
|
});
|
|
33783
34172
|
}
|
|
33784
34173
|
const summary = await executeEmbedHistory(sessionId);
|
|
34174
|
+
const completedCoverage = getEmbeddingCoverageStatus(db, sessionProjectIdentity, sessionId);
|
|
34175
|
+
completedDrainWithWork = completedCoverage.session.total - completedCoverage.session.embedded <= 0;
|
|
33785
34176
|
if (!isTuiConnected(sessionId)) {
|
|
33786
34177
|
await sendIgnoredMessage(deps.client, sessionId, summary, {
|
|
33787
34178
|
...notifyParams
|
|
@@ -33789,6 +34180,9 @@ function createMagicContextHook(deps) {
|
|
|
33789
34180
|
}
|
|
33790
34181
|
} catch (error) {
|
|
33791
34182
|
log("[magic-context] auto-embed drain failed:", error);
|
|
34183
|
+
} finally {
|
|
34184
|
+
if (!completedDrainWithWork)
|
|
34185
|
+
autoEmbedAttemptedBySession.delete(sessionId);
|
|
33792
34186
|
}
|
|
33793
34187
|
})();
|
|
33794
34188
|
};
|
|
@@ -33878,6 +34272,10 @@ function createMagicContextHook(deps) {
|
|
|
33878
34272
|
action,
|
|
33879
34273
|
content,
|
|
33880
34274
|
surfaceCondition,
|
|
34275
|
+
compiledProvider,
|
|
34276
|
+
compiledConfig,
|
|
34277
|
+
compiledAt,
|
|
34278
|
+
compileStatus,
|
|
33881
34279
|
filter,
|
|
33882
34280
|
limit,
|
|
33883
34281
|
offset,
|
|
@@ -33903,6 +34301,22 @@ function createMagicContextHook(deps) {
|
|
|
33903
34301
|
}
|
|
33904
34302
|
});
|
|
33905
34303
|
await syncModuleNotes();
|
|
34304
|
+
if (compileStatus && !moduleNoteResponseIsError(response)) {
|
|
34305
|
+
const moduleRowId = action === "write" ? moduleNoteRowId(response) : noteId ?? null;
|
|
34306
|
+
if (moduleRowId === null || !applyMirroredNoteCompileFields({
|
|
34307
|
+
db,
|
|
34308
|
+
moduleProject: memoryProject,
|
|
34309
|
+
moduleRowId,
|
|
34310
|
+
fields: {
|
|
34311
|
+
compiledProvider: compiledProvider ?? null,
|
|
34312
|
+
compiledConfig: compiledConfig ?? null,
|
|
34313
|
+
compiledAt: compiledAt ?? null,
|
|
34314
|
+
compileStatus
|
|
34315
|
+
}
|
|
34316
|
+
})) {
|
|
34317
|
+
throw new Error("Rust note was written but its host compilation metadata could not be mirrored");
|
|
34318
|
+
}
|
|
34319
|
+
}
|
|
33906
34320
|
return response;
|
|
33907
34321
|
},
|
|
33908
34322
|
memory: async ({
|
|
@@ -34130,6 +34544,7 @@ function createMagicContextHook(deps) {
|
|
|
34130
34544
|
}),
|
|
34131
34545
|
userMemoryCollectionEnabled: userMemoryCollectionEnabled(dreaming),
|
|
34132
34546
|
language: deps.config.language,
|
|
34547
|
+
retinaHandoff: deps.config.smart_notes?.retina_handoff === true,
|
|
34133
34548
|
transformMode: deps.config.transform_mode,
|
|
34134
34549
|
moduleClient: rustModeModuleClient,
|
|
34135
34550
|
onProgress: (progress, completedTask) => {
|
|
@@ -34215,6 +34630,7 @@ function createMagicContextHook(deps) {
|
|
|
34215
34630
|
language: deps.config.language,
|
|
34216
34631
|
mural: deps.config.mural,
|
|
34217
34632
|
memoryInjectionBudgetTokens: deps.config.memory?.injection_budget_tokens,
|
|
34633
|
+
retinaHandoff: deps.config.smart_notes?.retina_handoff === true,
|
|
34218
34634
|
transformMode: deps.config.transform_mode,
|
|
34219
34635
|
moduleClient: rustModeModuleClient,
|
|
34220
34636
|
onProgress: (progress, completedTask) => {
|
|
@@ -34443,6 +34859,8 @@ function createMessagesTransformHandler(args) {
|
|
|
34443
34859
|
await magicContext?.["experimental.chat.messages.transform"]?.(input, output);
|
|
34444
34860
|
return output.messages;
|
|
34445
34861
|
} catch (error) {
|
|
34862
|
+
if (error instanceof RawFallbackContextLimitError)
|
|
34863
|
+
throw error;
|
|
34446
34864
|
if (error instanceof EmergencyFailClosedError || isFailClosedBlockingError(error)) {
|
|
34447
34865
|
if (!args.compactionOff)
|
|
34448
34866
|
throw error;
|
|
@@ -35182,7 +35600,7 @@ function registerRpcHandlers(rpcServer, args) {
|
|
|
35182
35600
|
}
|
|
35183
35601
|
});
|
|
35184
35602
|
const buildManagedCtx = async (db) => {
|
|
35185
|
-
const { deriveHistorianChunkTokens: deriveHistorianChunkTokens2, resolveHistorianContextLimit: resolveHistorianContextLimit2 } = await import("./derive-budgets-
|
|
35603
|
+
const { deriveHistorianChunkTokens: deriveHistorianChunkTokens2, resolveHistorianContextLimit: resolveHistorianContextLimit2 } = await import("./derive-budgets-88mxk2w1.js");
|
|
35186
35604
|
const { resolveFallbackChain: resolveFallbackChain2 } = await import("./resolve-fallbacks-5n5tvge1.js");
|
|
35187
35605
|
const { userMemoryCollectionEnabled: userMemoryCollectionEnabled2 } = await import("./task-config-gbp7r23g.js");
|
|
35188
35606
|
const DEFAULT_HISTORIAN_TIMEOUT_MS2 = 600000;
|
|
@@ -35209,8 +35627,8 @@ function registerRpcHandlers(rpcServer, args) {
|
|
|
35209
35627
|
const db = getDb();
|
|
35210
35628
|
if (!db)
|
|
35211
35629
|
return { ok: false, error: "db unavailable" };
|
|
35212
|
-
const { runManagedRecomp: runManagedRecomp2 } = await import("./recomp-orchestrator-
|
|
35213
|
-
const { sendIgnoredMessage: sendIgnoredMessage2 } = await import("./send-session-notification-
|
|
35630
|
+
const { runManagedRecomp: runManagedRecomp2 } = await import("./recomp-orchestrator-a0g9b52q.js");
|
|
35631
|
+
const { sendIgnoredMessage: sendIgnoredMessage2 } = await import("./send-session-notification-bgtf4853.js");
|
|
35214
35632
|
log(`[rpc] recomp requested for session ${sessionId}`);
|
|
35215
35633
|
const ctx = await buildManagedCtx(db);
|
|
35216
35634
|
runManagedRecomp2(ctx, sessionId).then((message) => {
|
|
@@ -35225,8 +35643,8 @@ function registerRpcHandlers(rpcServer, args) {
|
|
|
35225
35643
|
const db = getDb();
|
|
35226
35644
|
if (!db)
|
|
35227
35645
|
return { ok: false, error: "db unavailable" };
|
|
35228
|
-
const { runManagedUpgrade: runManagedUpgrade2 } = await import("./recomp-orchestrator-
|
|
35229
|
-
const { sendIgnoredMessage: sendIgnoredMessage2 } = await import("./send-session-notification-
|
|
35646
|
+
const { runManagedUpgrade: runManagedUpgrade2 } = await import("./recomp-orchestrator-a0g9b52q.js");
|
|
35647
|
+
const { sendIgnoredMessage: sendIgnoredMessage2 } = await import("./send-session-notification-bgtf4853.js");
|
|
35230
35648
|
log(`[rpc] session-upgrade requested for session ${sessionId}`);
|
|
35231
35649
|
const ctx = await buildManagedCtx(db);
|
|
35232
35650
|
runManagedUpgrade2(ctx, sessionId).then((message) => {
|
|
@@ -35242,7 +35660,7 @@ function registerRpcHandlers(rpcServer, args) {
|
|
|
35242
35660
|
if (!db)
|
|
35243
35661
|
return { ok: false, error: "db unavailable" };
|
|
35244
35662
|
try {
|
|
35245
|
-
const { updateSessionMeta: updateSessionMeta2 } = await import("./storage-meta-session-
|
|
35663
|
+
const { updateSessionMeta: updateSessionMeta2 } = await import("./storage-meta-session-df9tstzr.js");
|
|
35246
35664
|
updateSessionMeta2(db, sessionId, { upgradeRemindedAt: Date.now() });
|
|
35247
35665
|
return { ok: true };
|
|
35248
35666
|
} catch (error) {
|
|
@@ -36198,6 +36616,496 @@ Smart notes: pass surface_condition and the note stays hidden until a background
|
|
|
36198
36616
|
Example: ctx_note(action="write", content="Re-run the perf benchmark once the boundary rework ships", surface_condition="When the latest release tag is >= v0.23.0")`;
|
|
36199
36617
|
// src/tools/ctx-note/tools.ts
|
|
36200
36618
|
import { tool as tool3 } from "@opencode-ai/plugin";
|
|
36619
|
+
|
|
36620
|
+
// src/features/magic-context/smart-notes/condition-compiler.ts
|
|
36621
|
+
import { existsSync as existsSync11 } from "node:fs";
|
|
36622
|
+
import { isAbsolute as isAbsolute4 } from "node:path";
|
|
36623
|
+
|
|
36624
|
+
// ../retina-local-fs/src/path-fence.ts
|
|
36625
|
+
import { lstat as lstat2, readlink, realpath as realpath2 } from "node:fs/promises";
|
|
36626
|
+
import { homedir as homedir4 } from "node:os";
|
|
36627
|
+
import { basename, dirname as dirname4, isAbsolute as isAbsolute3, join as join6, relative, resolve as resolve3, sep } from "node:path";
|
|
36628
|
+
|
|
36629
|
+
// ../retina-local-fs/src/errors.ts
|
|
36630
|
+
class ProviderError extends Error {
|
|
36631
|
+
code;
|
|
36632
|
+
constructor(code, message) {
|
|
36633
|
+
super(message);
|
|
36634
|
+
this.code = code;
|
|
36635
|
+
this.name = "ProviderError";
|
|
36636
|
+
}
|
|
36637
|
+
}
|
|
36638
|
+
|
|
36639
|
+
// ../retina-local-fs/src/path-fence.ts
|
|
36640
|
+
async function resolveAndFenceProviderPath(configuredPath, options) {
|
|
36641
|
+
const { home, dataDirectory } = await resolveFenceRoots(options);
|
|
36642
|
+
const expanded = configuredPath.startsWith("~/") ? join6(home, configuredPath.slice(2)) : configuredPath === "~" ? home : configuredPath;
|
|
36643
|
+
const absolute = isAbsolute3(expanded) ? resolve3(expanded) : resolve3(options.cwd ?? process.cwd(), expanded);
|
|
36644
|
+
const canonical = await canonicalPath(absolute, options.allowMissing);
|
|
36645
|
+
if (isFencedPath(canonical, home, dataDirectory)) {
|
|
36646
|
+
throw new ProviderError("fenced_path", `Refusing fenced path: ${canonical}`);
|
|
36647
|
+
}
|
|
36648
|
+
return canonical;
|
|
36649
|
+
}
|
|
36650
|
+
async function resolveFenceRoots(options) {
|
|
36651
|
+
const configuredHomePath = resolve3(options.homeDirectory ?? process.env.HOME ?? homedir4());
|
|
36652
|
+
let home;
|
|
36653
|
+
try {
|
|
36654
|
+
home = await realpath2(configuredHomePath);
|
|
36655
|
+
} catch (error) {
|
|
36656
|
+
throw fsError(configuredHomePath, error);
|
|
36657
|
+
}
|
|
36658
|
+
const configuredDataDirectory = resolve3(options.dataDirectory ?? process.env.XDG_DATA_HOME ?? join6(home, ".local", "share"));
|
|
36659
|
+
const dataDirectory = await canonicalPath(configuredDataDirectory, true);
|
|
36660
|
+
return { home, dataDirectory };
|
|
36661
|
+
}
|
|
36662
|
+
async function canonicalPath(path6, allowMissing) {
|
|
36663
|
+
try {
|
|
36664
|
+
return await realpath2(path6);
|
|
36665
|
+
} catch (error) {
|
|
36666
|
+
if (!allowMissing || !isMissingError(error)) {
|
|
36667
|
+
throw fsError(path6, error);
|
|
36668
|
+
}
|
|
36669
|
+
const suffix = [];
|
|
36670
|
+
let candidate = path6;
|
|
36671
|
+
while (true) {
|
|
36672
|
+
try {
|
|
36673
|
+
const metadata = await lstat2(candidate);
|
|
36674
|
+
if (metadata.isSymbolicLink()) {
|
|
36675
|
+
const target = await readlink(candidate);
|
|
36676
|
+
const resolvedTarget = resolve3(dirname4(candidate), target);
|
|
36677
|
+
return canonicalPath(join6(resolvedTarget, ...suffix), true);
|
|
36678
|
+
}
|
|
36679
|
+
} catch (candidateError) {
|
|
36680
|
+
if (!isMissingError(candidateError)) {
|
|
36681
|
+
throw fsError(path6, candidateError);
|
|
36682
|
+
}
|
|
36683
|
+
}
|
|
36684
|
+
const parent = dirname4(candidate);
|
|
36685
|
+
if (parent === candidate) {
|
|
36686
|
+
throw fsError(path6, error);
|
|
36687
|
+
}
|
|
36688
|
+
suffix.unshift(basename(candidate));
|
|
36689
|
+
candidate = parent;
|
|
36690
|
+
try {
|
|
36691
|
+
return join6(await realpath2(candidate), ...suffix);
|
|
36692
|
+
} catch (parentError) {
|
|
36693
|
+
if (!isMissingError(parentError)) {
|
|
36694
|
+
throw fsError(path6, parentError);
|
|
36695
|
+
}
|
|
36696
|
+
}
|
|
36697
|
+
}
|
|
36698
|
+
}
|
|
36699
|
+
}
|
|
36700
|
+
function isFencedPath(canonicalPath2, homeDirectory, dataDirectory = process.env.XDG_DATA_HOME ?? join6(resolve3(homeDirectory), ".local", "share")) {
|
|
36701
|
+
const cortexkitRoot = join6(resolve3(dataDirectory), "cortexkit");
|
|
36702
|
+
const relativeToCortexkit = relative(cortexkitRoot, canonicalPath2);
|
|
36703
|
+
const insideCortexkit = relativeToCortexkit !== "" && relativeToCortexkit !== ".." && !relativeToCortexkit.startsWith(`..${sep}`) && !isAbsolute3(relativeToCortexkit);
|
|
36704
|
+
const parts = insideCortexkit ? relativeToCortexkit.split(sep) : [];
|
|
36705
|
+
const pathParts = canonicalPath2.split(sep).filter(Boolean);
|
|
36706
|
+
const name = basename(canonicalPath2);
|
|
36707
|
+
const catalogDirectoryCarveIn = pathParts.includes("catalog");
|
|
36708
|
+
const moduleBinCarveIn = parts.length >= 2 && parts[1] === "bin";
|
|
36709
|
+
const catalogJsonCarveIn = name.endsWith(".json") && name.includes("catalog");
|
|
36710
|
+
const rootWithoutCarveIns = insideCortexkit && (parts[0] === "run" || parts[0] === "magic-context");
|
|
36711
|
+
if (!rootWithoutCarveIns && (catalogDirectoryCarveIn || moduleBinCarveIn || catalogJsonCarveIn)) {
|
|
36712
|
+
return false;
|
|
36713
|
+
}
|
|
36714
|
+
const inFencedRoot = insideCortexkit && ["plexus", "claustrum", "staging", "run", "magic-context"].includes(parts[0] ?? "");
|
|
36715
|
+
const fencedBasename = name.includes("binding-key") || name.endsWith(".handle");
|
|
36716
|
+
const plexusStore = insideCortexkit && parts[0] === "plexus" && name.startsWith("store.db");
|
|
36717
|
+
return inFencedRoot || fencedBasename || plexusStore;
|
|
36718
|
+
}
|
|
36719
|
+
function fsError(path6, error) {
|
|
36720
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
36721
|
+
return new ProviderError("unreadable_path", `Could not read ${path6}: ${message}`);
|
|
36722
|
+
}
|
|
36723
|
+
function isMissingError(error) {
|
|
36724
|
+
return error !== null && typeof error === "object" && "code" in error && (error.code === "ENOENT" || error.code === "ENOTDIR");
|
|
36725
|
+
}
|
|
36726
|
+
|
|
36727
|
+
// ../retina-local-fs/src/provider.ts
|
|
36728
|
+
import { execFile as execFile3 } from "node:child_process";
|
|
36729
|
+
import { promisify as promisify3 } from "node:util";
|
|
36730
|
+
var execFileAsync3 = promisify3(execFile3);
|
|
36731
|
+
function parseSemver(value) {
|
|
36732
|
+
const match = /^v?(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-([0-9A-Za-z.-]+))?(?:\+[0-9A-Za-z.-]+)?$/.exec(value);
|
|
36733
|
+
if (!match) {
|
|
36734
|
+
throw new ProviderError("invalid_config", `Invalid semantic version: ${value}`);
|
|
36735
|
+
}
|
|
36736
|
+
return {
|
|
36737
|
+
major: Number(match[1]),
|
|
36738
|
+
minor: Number(match[2]),
|
|
36739
|
+
patch: Number(match[3]),
|
|
36740
|
+
prerelease: match[4] ? match[4].split(".").map((part) => /^\d+$/.test(part) ? Number(part) : part) : []
|
|
36741
|
+
};
|
|
36742
|
+
}
|
|
36743
|
+
function validateProviderConfig(input) {
|
|
36744
|
+
try {
|
|
36745
|
+
return { success: true, config: parseConfig(input) };
|
|
36746
|
+
} catch (error) {
|
|
36747
|
+
return {
|
|
36748
|
+
success: false,
|
|
36749
|
+
reason: error instanceof Error ? error.message : String(error)
|
|
36750
|
+
};
|
|
36751
|
+
}
|
|
36752
|
+
}
|
|
36753
|
+
function parseConfig(value) {
|
|
36754
|
+
const config = requireObject(value, "config");
|
|
36755
|
+
if ("any" in config) {
|
|
36756
|
+
requireOnlyKeys(config, ["any"], "compound config");
|
|
36757
|
+
if (!Array.isArray(config.any) || config.any.length < 1 || config.any.length > 4) {
|
|
36758
|
+
invalid("config.any must contain between 1 and 4 predicates");
|
|
36759
|
+
}
|
|
36760
|
+
return { any: config.any.map(parseAtomicPredicate) };
|
|
36761
|
+
}
|
|
36762
|
+
return parseAtomicPredicate(config);
|
|
36763
|
+
}
|
|
36764
|
+
function parseAtomicPredicate(value) {
|
|
36765
|
+
const predicate = requireObject(value, "predicate");
|
|
36766
|
+
if (typeof predicate.kind !== "string") {
|
|
36767
|
+
invalid("predicate.kind must be a string");
|
|
36768
|
+
}
|
|
36769
|
+
switch (predicate.kind) {
|
|
36770
|
+
case "file_contains":
|
|
36771
|
+
requireOnlyKeys(predicate, ["kind", "path", "needle", "absent", "resolved_path_exists"], predicate.kind);
|
|
36772
|
+
return {
|
|
36773
|
+
kind: predicate.kind,
|
|
36774
|
+
path: requireString(predicate.path, "path"),
|
|
36775
|
+
needle: requireString(predicate.needle, "needle", true),
|
|
36776
|
+
...optionalBoolean(predicate.absent, "absent") === undefined ? {} : { absent: predicate.absent },
|
|
36777
|
+
...predicateAudit(predicate)
|
|
36778
|
+
};
|
|
36779
|
+
case "path_exists":
|
|
36780
|
+
requireOnlyKeys(predicate, ["kind", "path", "gone", "resolved_path_exists"], predicate.kind);
|
|
36781
|
+
return {
|
|
36782
|
+
kind: predicate.kind,
|
|
36783
|
+
path: requireString(predicate.path, "path"),
|
|
36784
|
+
...optionalBoolean(predicate.gone, "gone") === undefined ? {} : { gone: predicate.gone },
|
|
36785
|
+
...predicateAudit(predicate)
|
|
36786
|
+
};
|
|
36787
|
+
case "mtime_after":
|
|
36788
|
+
requireOnlyKeys(predicate, ["kind", "path", "since_ms", "resolved_path_exists"], predicate.kind);
|
|
36789
|
+
return {
|
|
36790
|
+
kind: predicate.kind,
|
|
36791
|
+
path: requireString(predicate.path, "path"),
|
|
36792
|
+
since_ms: requireFiniteNumber(predicate.since_ms, "since_ms"),
|
|
36793
|
+
...predicateAudit(predicate)
|
|
36794
|
+
};
|
|
36795
|
+
case "git_commit_after":
|
|
36796
|
+
requireOnlyKeys(predicate, ["kind", "repo_path", "ref", "sha", "resolved_path_exists"], predicate.kind);
|
|
36797
|
+
return {
|
|
36798
|
+
kind: predicate.kind,
|
|
36799
|
+
repo_path: requireString(predicate.repo_path, "repo_path"),
|
|
36800
|
+
sha: requireString(predicate.sha, "sha"),
|
|
36801
|
+
...predicate.ref === undefined ? {} : { ref: requireString(predicate.ref, "ref") },
|
|
36802
|
+
...predicateAudit(predicate)
|
|
36803
|
+
};
|
|
36804
|
+
case "git_tag_matching": {
|
|
36805
|
+
requireOnlyKeys(predicate, ["kind", "repo_path", "pattern", "above", "resolved_path_exists"], predicate.kind);
|
|
36806
|
+
const above = predicate.above === undefined ? undefined : requireString(predicate.above, "above");
|
|
36807
|
+
if (above !== undefined) {
|
|
36808
|
+
parseSemver(above);
|
|
36809
|
+
}
|
|
36810
|
+
return {
|
|
36811
|
+
kind: predicate.kind,
|
|
36812
|
+
repo_path: requireString(predicate.repo_path, "repo_path"),
|
|
36813
|
+
pattern: requireString(predicate.pattern, "pattern"),
|
|
36814
|
+
...above === undefined ? {} : { above },
|
|
36815
|
+
...predicateAudit(predicate)
|
|
36816
|
+
};
|
|
36817
|
+
}
|
|
36818
|
+
default:
|
|
36819
|
+
invalid(`Unsupported predicate kind: ${predicate.kind}`);
|
|
36820
|
+
}
|
|
36821
|
+
}
|
|
36822
|
+
function requireObject(value, field) {
|
|
36823
|
+
if (typeof value !== "object" || value === null || Array.isArray(value)) {
|
|
36824
|
+
invalid(`${field} must be an object`);
|
|
36825
|
+
}
|
|
36826
|
+
return value;
|
|
36827
|
+
}
|
|
36828
|
+
function requireOnlyKeys(value, allowed, field) {
|
|
36829
|
+
const unknown = Object.keys(value).filter((key) => !allowed.includes(key));
|
|
36830
|
+
if (unknown.length > 0) {
|
|
36831
|
+
invalid(`${field} contains unknown field(s): ${unknown.join(", ")}`);
|
|
36832
|
+
}
|
|
36833
|
+
}
|
|
36834
|
+
function requireString(value, field, allowEmpty = false) {
|
|
36835
|
+
if (typeof value !== "string" || !allowEmpty && value.length === 0) {
|
|
36836
|
+
invalid(`${field} must be ${allowEmpty ? "a string" : "a non-empty string"}`);
|
|
36837
|
+
}
|
|
36838
|
+
return value;
|
|
36839
|
+
}
|
|
36840
|
+
function predicateAudit(predicate) {
|
|
36841
|
+
const exists = optionalBoolean(predicate.resolved_path_exists, "resolved_path_exists");
|
|
36842
|
+
return exists === undefined ? {} : { resolved_path_exists: exists };
|
|
36843
|
+
}
|
|
36844
|
+
function optionalBoolean(value, field) {
|
|
36845
|
+
if (value !== undefined && typeof value !== "boolean") {
|
|
36846
|
+
invalid(`${field} must be a boolean`);
|
|
36847
|
+
}
|
|
36848
|
+
return value;
|
|
36849
|
+
}
|
|
36850
|
+
function requireFiniteNumber(value, field) {
|
|
36851
|
+
if (typeof value !== "number" || !Number.isFinite(value)) {
|
|
36852
|
+
invalid(`${field} must be a finite number`);
|
|
36853
|
+
}
|
|
36854
|
+
return value;
|
|
36855
|
+
}
|
|
36856
|
+
function invalid(message) {
|
|
36857
|
+
throw new ProviderError("invalid_config", message);
|
|
36858
|
+
}
|
|
36859
|
+
|
|
36860
|
+
// src/features/magic-context/smart-notes/condition-compiler.ts
|
|
36861
|
+
var RETINA_LOCAL_FS_PROVIDER = "local-fs";
|
|
36862
|
+
var VALUE = String.raw`(?:"(?:[^"\\]|\\.)*"|'(?:[^'\\]|\\.)*'|\S+)`;
|
|
36863
|
+
async function compileSurfaceCondition(surfaceCondition, options) {
|
|
36864
|
+
const plainReason = unsafeGrammarReason(surfaceCondition);
|
|
36865
|
+
if (plainReason)
|
|
36866
|
+
return { status: "plain", reason: plainReason };
|
|
36867
|
+
const parsed = parseCondition(surfaceCondition, options.projectPath);
|
|
36868
|
+
if (parsed === null)
|
|
36869
|
+
return { status: "plain" };
|
|
36870
|
+
const now = (options.now ?? Date.now)();
|
|
36871
|
+
const resolvePath = options.resolvePath ?? (async (path6) => {
|
|
36872
|
+
const resolved = await resolveAndFenceProviderPath(path6, {
|
|
36873
|
+
allowMissing: true,
|
|
36874
|
+
homeDirectory: options.homeDirectory,
|
|
36875
|
+
cwd: options.projectPath
|
|
36876
|
+
});
|
|
36877
|
+
return { path: resolved, exists: existsSync11(resolved) };
|
|
36878
|
+
});
|
|
36879
|
+
let predicates;
|
|
36880
|
+
try {
|
|
36881
|
+
predicates = [];
|
|
36882
|
+
for (const predicate of parsed) {
|
|
36883
|
+
predicates.push(await resolvePredicate(predicate, resolvePath, now));
|
|
36884
|
+
}
|
|
36885
|
+
} catch (error) {
|
|
36886
|
+
const code = error !== null && typeof error === "object" && "code" in error ? error.code : undefined;
|
|
36887
|
+
return {
|
|
36888
|
+
status: "refused",
|
|
36889
|
+
reason: code === "fenced_path" ? "fenced path" : "path resolution failed"
|
|
36890
|
+
};
|
|
36891
|
+
}
|
|
36892
|
+
const candidate = predicates.length === 1 ? predicates[0] : { any: predicates };
|
|
36893
|
+
const validation = validateProviderConfig(candidate);
|
|
36894
|
+
if (!validation.success) {
|
|
36895
|
+
return {
|
|
36896
|
+
status: "refused",
|
|
36897
|
+
reason: `provider schema: ${singleLine(validation.reason)}`.slice(0, 180)
|
|
36898
|
+
};
|
|
36899
|
+
}
|
|
36900
|
+
return {
|
|
36901
|
+
status: "compiled",
|
|
36902
|
+
provider: RETINA_LOCAL_FS_PROVIDER,
|
|
36903
|
+
config: validation.config,
|
|
36904
|
+
compiledAt: now
|
|
36905
|
+
};
|
|
36906
|
+
}
|
|
36907
|
+
function conditionCompileStorageFields(result) {
|
|
36908
|
+
if (result.status === "compiled") {
|
|
36909
|
+
return {
|
|
36910
|
+
compiledProvider: result.provider,
|
|
36911
|
+
compiledConfig: JSON.stringify(result.config),
|
|
36912
|
+
compiledAt: result.compiledAt,
|
|
36913
|
+
compileStatus: result.status
|
|
36914
|
+
};
|
|
36915
|
+
}
|
|
36916
|
+
return {
|
|
36917
|
+
compiledProvider: null,
|
|
36918
|
+
compiledConfig: null,
|
|
36919
|
+
compiledAt: null,
|
|
36920
|
+
compileStatus: result.status
|
|
36921
|
+
};
|
|
36922
|
+
}
|
|
36923
|
+
function conditionCompileReplySuffix(result) {
|
|
36924
|
+
if (result.status === "compiled") {
|
|
36925
|
+
return `
|
|
36926
|
+
- Retina provider: ${result.provider}`;
|
|
36927
|
+
}
|
|
36928
|
+
if (result.status === "refused") {
|
|
36929
|
+
return `
|
|
36930
|
+
- Retina compile refused: ${result.reason}`;
|
|
36931
|
+
}
|
|
36932
|
+
return "";
|
|
36933
|
+
}
|
|
36934
|
+
function parseCondition(surfaceCondition, projectPath) {
|
|
36935
|
+
const trimmed = surfaceCondition.trim();
|
|
36936
|
+
const either = trimmed.match(/^either\s+(.+)$/i);
|
|
36937
|
+
if (!either) {
|
|
36938
|
+
const predicate = parseAtomicCondition(trimmed, projectPath);
|
|
36939
|
+
return predicate ? [predicate] : null;
|
|
36940
|
+
}
|
|
36941
|
+
const clauses = splitOrClauses(either[1]);
|
|
36942
|
+
if (clauses.length < 2)
|
|
36943
|
+
return null;
|
|
36944
|
+
const predicates = clauses.map((clause) => parseAtomicCondition(clause, projectPath));
|
|
36945
|
+
return predicates.every((predicate) => predicate !== null) ? predicates : null;
|
|
36946
|
+
}
|
|
36947
|
+
function parseAtomicCondition(text, projectPath) {
|
|
36948
|
+
const fileContains = text.match(new RegExp(`^(?:when\\s+)?file\\s+(${VALUE})\\s+(no longer contains|contains)\\s+(${VALUE})$`, "i"));
|
|
36949
|
+
if (fileContains) {
|
|
36950
|
+
const path6 = unquote(fileContains[1]);
|
|
36951
|
+
const needle = unquote(fileContains[3].trim());
|
|
36952
|
+
if (path6 === null || needle === null)
|
|
36953
|
+
return null;
|
|
36954
|
+
return {
|
|
36955
|
+
kind: "file_contains",
|
|
36956
|
+
path: path6,
|
|
36957
|
+
needle,
|
|
36958
|
+
...fileContains[2].toLowerCase() === "no longer contains" ? { absent: true } : {}
|
|
36959
|
+
};
|
|
36960
|
+
}
|
|
36961
|
+
const commit = text.match(new RegExp(`^(?:when\\s+)?(?:repo(?:sitory)?\\s+)?(${VALUE})\\s+has\\s+a\\s+commit\\s+(?:after|newer than)\\s+([0-9a-f]{7,64})$`, "i"));
|
|
36962
|
+
if (commit) {
|
|
36963
|
+
const repoPath = unquote(commit[1]);
|
|
36964
|
+
if (repoPath === null)
|
|
36965
|
+
return null;
|
|
36966
|
+
return {
|
|
36967
|
+
kind: "git_commit_after",
|
|
36968
|
+
repo_path: repoPath,
|
|
36969
|
+
sha: commit[2]
|
|
36970
|
+
};
|
|
36971
|
+
}
|
|
36972
|
+
const tag = text.match(new RegExp(`^(?:when\\s+)?a\\s+tag\\s+(?:(?:matching\\s+(${VALUE})(?:\\s+above\\s+semver\\s+(${VALUE}))?)|(?:above\\s+semver\\s+(${VALUE})))\\s+appears(?:\\s+in\\s+(?:repo(?:sitory)?\\s+)?(${VALUE}))?$`, "i"));
|
|
36973
|
+
if (tag) {
|
|
36974
|
+
const pattern = tag[1] ? unquote(tag[1]) : "*";
|
|
36975
|
+
const above = unquote(tag[2] ?? tag[3] ?? "");
|
|
36976
|
+
const repoPath = tag[4] ? unquote(tag[4]) : projectPath;
|
|
36977
|
+
if (pattern === null || above === null || repoPath === null)
|
|
36978
|
+
return null;
|
|
36979
|
+
return {
|
|
36980
|
+
kind: "git_tag_matching",
|
|
36981
|
+
repo_path: repoPath,
|
|
36982
|
+
pattern,
|
|
36983
|
+
...above.length > 0 ? { above } : {}
|
|
36984
|
+
};
|
|
36985
|
+
}
|
|
36986
|
+
const mtime = text.match(new RegExp(`^(?:when\\s+)?(?:file\\s+)?(${VALUE})\\s+(changes|is rebuilt|mtime moves)$`, "i"));
|
|
36987
|
+
if (mtime) {
|
|
36988
|
+
const path6 = unquote(mtime[1]);
|
|
36989
|
+
if (path6 === null)
|
|
36990
|
+
return null;
|
|
36991
|
+
return {
|
|
36992
|
+
kind: "mtime_after",
|
|
36993
|
+
path: path6
|
|
36994
|
+
};
|
|
36995
|
+
}
|
|
36996
|
+
const pathExists = text.match(new RegExp(`^(?:when\\s+)?(?:path\\s+)?(${VALUE})\\s+(exists|is gone)$`, "i"));
|
|
36997
|
+
if (pathExists) {
|
|
36998
|
+
const path6 = unquote(pathExists[1]);
|
|
36999
|
+
if (path6 === null)
|
|
37000
|
+
return null;
|
|
37001
|
+
return {
|
|
37002
|
+
kind: "path_exists",
|
|
37003
|
+
path: path6,
|
|
37004
|
+
...pathExists[2].toLowerCase() === "is gone" ? { gone: true } : {}
|
|
37005
|
+
};
|
|
37006
|
+
}
|
|
37007
|
+
return null;
|
|
37008
|
+
}
|
|
37009
|
+
async function resolvePredicate(predicate, resolvePath, now) {
|
|
37010
|
+
const configuredPath = "repo_path" in predicate ? predicate.repo_path : predicate.path;
|
|
37011
|
+
const resolved = await resolvePath(configuredPath);
|
|
37012
|
+
const sourceIsResolvable = isAbsolute4(configuredPath) || configuredPath === "~" || configuredPath.startsWith("~/");
|
|
37013
|
+
const audit = sourceIsResolvable && resolved.exists ? {} : { resolved_path_exists: false };
|
|
37014
|
+
switch (predicate.kind) {
|
|
37015
|
+
case "file_contains":
|
|
37016
|
+
return { ...predicate, path: resolved.path, ...audit };
|
|
37017
|
+
case "path_exists":
|
|
37018
|
+
return { ...predicate, path: resolved.path, ...audit };
|
|
37019
|
+
case "mtime_after":
|
|
37020
|
+
return { kind: predicate.kind, path: resolved.path, since_ms: now, ...audit };
|
|
37021
|
+
case "git_commit_after":
|
|
37022
|
+
return { ...predicate, repo_path: resolved.path, ...audit };
|
|
37023
|
+
case "git_tag_matching":
|
|
37024
|
+
return { ...predicate, repo_path: resolved.path, ...audit };
|
|
37025
|
+
}
|
|
37026
|
+
}
|
|
37027
|
+
function splitOrClauses(text) {
|
|
37028
|
+
const clauses = [];
|
|
37029
|
+
let start = 0;
|
|
37030
|
+
let quote = null;
|
|
37031
|
+
let escaped = false;
|
|
37032
|
+
for (let index = 0;index < text.length; index += 1) {
|
|
37033
|
+
const character = text[index];
|
|
37034
|
+
if (escaped) {
|
|
37035
|
+
escaped = false;
|
|
37036
|
+
continue;
|
|
37037
|
+
}
|
|
37038
|
+
if (quote && character === "\\") {
|
|
37039
|
+
escaped = true;
|
|
37040
|
+
continue;
|
|
37041
|
+
}
|
|
37042
|
+
if (character === '"' || character === "'") {
|
|
37043
|
+
quote = quote === character ? null : quote === null ? character : quote;
|
|
37044
|
+
continue;
|
|
37045
|
+
}
|
|
37046
|
+
if (quote !== null)
|
|
37047
|
+
continue;
|
|
37048
|
+
const separator = text.slice(index).match(/^\s+or\s+/i);
|
|
37049
|
+
if (!separator)
|
|
37050
|
+
continue;
|
|
37051
|
+
clauses.push(text.slice(start, index).trim());
|
|
37052
|
+
index += separator[0].length - 1;
|
|
37053
|
+
start = index + 1;
|
|
37054
|
+
}
|
|
37055
|
+
clauses.push(text.slice(start).trim());
|
|
37056
|
+
return clauses.filter(Boolean);
|
|
37057
|
+
}
|
|
37058
|
+
function unsafeGrammarReason(value) {
|
|
37059
|
+
let quote = null;
|
|
37060
|
+
let escaped = false;
|
|
37061
|
+
for (const character of value) {
|
|
37062
|
+
if (escaped) {
|
|
37063
|
+
escaped = false;
|
|
37064
|
+
continue;
|
|
37065
|
+
}
|
|
37066
|
+
if (quote && character === "\\") {
|
|
37067
|
+
escaped = true;
|
|
37068
|
+
continue;
|
|
37069
|
+
}
|
|
37070
|
+
if (character === '"' || character === "'") {
|
|
37071
|
+
quote = quote === character ? null : quote === null ? character : quote;
|
|
37072
|
+
}
|
|
37073
|
+
}
|
|
37074
|
+
if (quote !== null)
|
|
37075
|
+
return "unbalanced quote; leaving condition dreamer-evaluated";
|
|
37076
|
+
if (/\bcontains\s+no(?:\s|$)/i.test(value)) {
|
|
37077
|
+
return "ambiguous negation after contains; leaving condition dreamer-evaluated";
|
|
37078
|
+
}
|
|
37079
|
+
const temporalSuffix = new RegExp(`\\bcontains\\s+${VALUE}\\s+(?:since|until|after|before|when|while|for|as\\s+of)\\b`, "i");
|
|
37080
|
+
if (temporalSuffix.test(value)) {
|
|
37081
|
+
return "temporal suffix after contains; leaving condition dreamer-evaluated";
|
|
37082
|
+
}
|
|
37083
|
+
return null;
|
|
37084
|
+
}
|
|
37085
|
+
function unquote(value) {
|
|
37086
|
+
const quote = value[0];
|
|
37087
|
+
const final = value.at(-1);
|
|
37088
|
+
const startsQuoted = quote === '"' || quote === "'";
|
|
37089
|
+
const endsQuoted = final === '"' || final === "'";
|
|
37090
|
+
if (!startsQuoted && !endsQuoted)
|
|
37091
|
+
return value;
|
|
37092
|
+
if (!startsQuoted || final !== quote || value.length < 2)
|
|
37093
|
+
return null;
|
|
37094
|
+
if (quote === '"') {
|
|
37095
|
+
try {
|
|
37096
|
+
const parsed = JSON.parse(value);
|
|
37097
|
+
return typeof parsed === "string" ? parsed : null;
|
|
37098
|
+
} catch {
|
|
37099
|
+
return null;
|
|
37100
|
+
}
|
|
37101
|
+
}
|
|
37102
|
+
return value.slice(1, -1).replace(/\\'/g, "'").replace(/\\\\/g, "\\");
|
|
37103
|
+
}
|
|
37104
|
+
function singleLine(value) {
|
|
37105
|
+
return value.replace(/\s+/g, " ").trim();
|
|
37106
|
+
}
|
|
37107
|
+
|
|
37108
|
+
// src/tools/ctx-note/tools.ts
|
|
36201
37109
|
function captureAnchorOrdinal(db, sessionId) {
|
|
36202
37110
|
try {
|
|
36203
37111
|
const ordinal = getLastIndexedOrdinal(db, sessionId);
|
|
@@ -36377,8 +37285,15 @@ function createCtxNoteTool(deps) {
|
|
|
36377
37285
|
if (!rustNote || !projectIdentity) {
|
|
36378
37286
|
return "Error: Rust notes authority is active, but this module transport does not support ctx_note.";
|
|
36379
37287
|
}
|
|
36380
|
-
|
|
36381
|
-
|
|
37288
|
+
const surfaceCondition = args.surface_condition?.trim();
|
|
37289
|
+
let compilation;
|
|
37290
|
+
if ((action === "write" || action === "update") && surfaceCondition) {
|
|
37291
|
+
if (deps.rustToolBackends?.noteEvaluationAvailable?.(projectIdentity) !== true) {
|
|
37292
|
+
return "Error: Smart-note evaluation is unavailable for this Rust-authority project; the note was not written.";
|
|
37293
|
+
}
|
|
37294
|
+
compilation = await compileSurfaceCondition(surfaceCondition, {
|
|
37295
|
+
projectPath: toolContext.directory
|
|
37296
|
+
});
|
|
36382
37297
|
}
|
|
36383
37298
|
const commandId = toolCallIdFromContext(toolContext);
|
|
36384
37299
|
const request2 = {
|
|
@@ -36389,7 +37304,8 @@ function createCtxNoteTool(deps) {
|
|
|
36389
37304
|
memoryProject: projectIdentity,
|
|
36390
37305
|
action,
|
|
36391
37306
|
content: args.content,
|
|
36392
|
-
surfaceCondition
|
|
37307
|
+
surfaceCondition,
|
|
37308
|
+
...compilation ? conditionCompileStorageFields(compilation) : {},
|
|
36393
37309
|
filter: args.filter,
|
|
36394
37310
|
limit: args.limit,
|
|
36395
37311
|
offset: args.offset,
|
|
@@ -36397,9 +37313,13 @@ function createCtxNoteTool(deps) {
|
|
|
36397
37313
|
};
|
|
36398
37314
|
try {
|
|
36399
37315
|
const text = moduleNoteText(await rustNote(request2));
|
|
36400
|
-
if (text
|
|
36401
|
-
return
|
|
36402
|
-
|
|
37316
|
+
if (text === null) {
|
|
37317
|
+
return "Error: Rust module returned an invalid ctx_note response.";
|
|
37318
|
+
}
|
|
37319
|
+
if (compilation && !text.startsWith("Error:")) {
|
|
37320
|
+
return text + conditionCompileReplySuffix(compilation);
|
|
37321
|
+
}
|
|
37322
|
+
return text;
|
|
36403
37323
|
} catch (error) {
|
|
36404
37324
|
if (isRustAuthorityDrainingError(error)) {
|
|
36405
37325
|
return "Error: Rust notes authority is not ready; TypeScript fallback is disabled.";
|
|
@@ -36423,16 +37343,21 @@ function createCtxNoteTool(deps) {
|
|
|
36423
37343
|
if (!projectIdentity) {
|
|
36424
37344
|
return "Error: Could not resolve project identity for smart note.";
|
|
36425
37345
|
}
|
|
37346
|
+
const surfaceCondition = args.surface_condition.trim();
|
|
37347
|
+
const compilation = await compileSurfaceCondition(surfaceCondition, {
|
|
37348
|
+
projectPath: toolContext.directory
|
|
37349
|
+
});
|
|
36426
37350
|
const note2 = addNote(deps.db, "smart", {
|
|
36427
37351
|
content,
|
|
36428
37352
|
projectPath: projectIdentity,
|
|
36429
37353
|
sessionId,
|
|
36430
|
-
surfaceCondition
|
|
36431
|
-
anchorOrdinal
|
|
37354
|
+
surfaceCondition,
|
|
37355
|
+
anchorOrdinal,
|
|
37356
|
+
...conditionCompileStorageFields(compilation)
|
|
36432
37357
|
});
|
|
36433
37358
|
return `Created smart note #${note2.id}. Dreamer will evaluate the condition during nightly runs:
|
|
36434
37359
|
- Content: ${content}
|
|
36435
|
-
- Condition: ${
|
|
37360
|
+
- Condition: ${surfaceCondition}${conditionCompileReplySuffix(compilation)}`;
|
|
36436
37361
|
}
|
|
36437
37362
|
const note = addNote(deps.db, "session", { sessionId, content, anchorOrdinal });
|
|
36438
37363
|
return `Saved session note #${note.id}.`;
|
|
@@ -36459,8 +37384,15 @@ function createCtxNoteTool(deps) {
|
|
|
36459
37384
|
const updates = {};
|
|
36460
37385
|
if (args.content?.trim())
|
|
36461
37386
|
updates.content = args.content.trim();
|
|
36462
|
-
|
|
36463
|
-
|
|
37387
|
+
let compilation;
|
|
37388
|
+
if (args.surface_condition?.trim()) {
|
|
37389
|
+
const surfaceCondition = args.surface_condition.trim();
|
|
37390
|
+
updates.surfaceCondition = surfaceCondition;
|
|
37391
|
+
compilation = await compileSurfaceCondition(surfaceCondition, {
|
|
37392
|
+
projectPath: toolContext.directory
|
|
37393
|
+
});
|
|
37394
|
+
Object.assign(updates, conditionCompileStorageFields(compilation));
|
|
37395
|
+
}
|
|
36464
37396
|
if (!updates.content && !updates.surfaceCondition) {
|
|
36465
37397
|
return "Error: Provide 'content' and/or 'surface_condition' to update.";
|
|
36466
37398
|
}
|
|
@@ -36481,7 +37413,7 @@ function createCtxNoteTool(deps) {
|
|
|
36481
37413
|
parts.push(`Condition: ${updates.surfaceCondition}`);
|
|
36482
37414
|
return `Updated note #${noteId}:
|
|
36483
37415
|
${parts.join(`
|
|
36484
|
-
`)}`;
|
|
37416
|
+
`)}${compilation ? conditionCompileReplySuffix(compilation) : ""}`;
|
|
36485
37417
|
}
|
|
36486
37418
|
const limit = typeof args.limit === "number" && args.limit > 0 ? Math.floor(args.limit) : DEFAULT_READ_LIMIT;
|
|
36487
37419
|
const offset = typeof args.offset === "number" && args.offset > 0 ? Math.floor(args.offset) : 0;
|
|
@@ -37050,7 +37982,7 @@ import {
|
|
|
37050
37982
|
unlinkSync,
|
|
37051
37983
|
writeFileSync as writeFileSync4
|
|
37052
37984
|
} from "node:fs";
|
|
37053
|
-
import { dirname as
|
|
37985
|
+
import { dirname as dirname5 } from "node:path";
|
|
37054
37986
|
var MAX_BODY_BYTES = 1048576;
|
|
37055
37987
|
var WS_AUTH_TIMEOUT_MS = 5000;
|
|
37056
37988
|
var WS_CLOSE_UNAUTHORIZED = 4401;
|
|
@@ -37124,7 +38056,7 @@ class MagicContextRpcServer {
|
|
|
37124
38056
|
this.port = server.port ?? 0;
|
|
37125
38057
|
try {
|
|
37126
38058
|
this.warnIfOtherLiveInstance();
|
|
37127
|
-
const dir =
|
|
38059
|
+
const dir = dirname5(this.portFilePath);
|
|
37128
38060
|
const enforcePrivatePermissions = shouldEnforcePrivateStoragePermissions();
|
|
37129
38061
|
if (enforcePrivatePermissions) {
|
|
37130
38062
|
mkdirSync2(dir, { recursive: true, mode: 448 });
|
|
@@ -37357,7 +38289,7 @@ var server = async (ctx) => {
|
|
|
37357
38289
|
`);
|
|
37358
38290
|
setTimeout(async () => {
|
|
37359
38291
|
try {
|
|
37360
|
-
const { sendIgnoredMessage: sendIgnoredMessage2 } = await import("./send-session-notification-
|
|
38292
|
+
const { sendIgnoredMessage: sendIgnoredMessage2 } = await import("./send-session-notification-bgtf4853.js");
|
|
37361
38293
|
const clientWithSessions = ctx.client;
|
|
37362
38294
|
const sessions = await Promise.resolve(clientWithSessions.session?.list?.()).catch(() => null);
|
|
37363
38295
|
const sessionList = Array.isArray(sessions) ? sessions : sessions?.data;
|
|
@@ -37501,6 +38433,7 @@ var server = async (ctx) => {
|
|
|
37501
38433
|
memoryEnabled: pluginConfig.memory?.enabled === true,
|
|
37502
38434
|
memoryInjectionBudgetTokens: pluginConfig.memory?.injection_budget_tokens,
|
|
37503
38435
|
mural: pluginConfig.mural,
|
|
38436
|
+
retinaHandoff: pluginConfig.smart_notes.retina_handoff,
|
|
37504
38437
|
gitCommitIndexing: pluginConfig.memory.git_commit_indexing?.enabled ? {
|
|
37505
38438
|
enabled: true,
|
|
37506
38439
|
since_days: pluginConfig.memory.git_commit_indexing.since_days,
|
|
@@ -37538,7 +38471,7 @@ var server = async (ctx) => {
|
|
|
37538
38471
|
{
|
|
37539
38472
|
const fence = getSchemaFenceRejection();
|
|
37540
38473
|
if (fence) {
|
|
37541
|
-
import("./conflict-warning-hook-
|
|
38474
|
+
import("./conflict-warning-hook-mt0ttc4x.js").then(({ sendSchemaFenceWarning }) => sendSchemaFenceWarning(ctx.client, ctx.directory, fence));
|
|
37542
38475
|
}
|
|
37543
38476
|
}
|
|
37544
38477
|
if (conflictResult?.hasConflict) {
|
|
@@ -37556,10 +38489,10 @@ var server = async (ctx) => {
|
|
|
37556
38489
|
ANNOUNCEMENT_FEATURES: ANNOUNCEMENT_FEATURES2,
|
|
37557
38490
|
ANNOUNCEMENT_FOOTER: ANNOUNCEMENT_FOOTER2,
|
|
37558
38491
|
markAnnouncementSeen: markAnnouncementSeen2
|
|
37559
|
-
} = await import("./announcement-
|
|
38492
|
+
} = await import("./announcement-6c1g4es4.js");
|
|
37560
38493
|
if (shouldShowAnnouncement2()) {
|
|
37561
38494
|
setTimeout(() => {
|
|
37562
|
-
import("./conflict-warning-hook-
|
|
38495
|
+
import("./conflict-warning-hook-mt0ttc4x.js").then(({ sendStartupAnnouncement }) => sendStartupAnnouncement(ctx.client, ctx.directory, ANNOUNCEMENT_VERSION2, ANNOUNCEMENT_FEATURES2, ANNOUNCEMENT_FOOTER2, markAnnouncementSeen2)).catch(() => {});
|
|
37563
38496
|
}, 8000);
|
|
37564
38497
|
}
|
|
37565
38498
|
} catch {}
|
|
@@ -37611,6 +38544,7 @@ var server = async (ctx) => {
|
|
|
37611
38544
|
await magicContextRuntime.magicContext?.["command.execute.before"]?.(input, output);
|
|
37612
38545
|
},
|
|
37613
38546
|
"chat.message": async (input, _output) => {
|
|
38547
|
+
await preloadTokenizer();
|
|
37614
38548
|
const typed = input;
|
|
37615
38549
|
const provId = typed.model?.providerID;
|
|
37616
38550
|
const modId = typed.model?.modelID;
|
|
@@ -37686,14 +38620,17 @@ var server = async (ctx) => {
|
|
|
37686
38620
|
historianDisallowed: pluginConfig.historian?.disallowed_tools ?? []
|
|
37687
38621
|
});
|
|
37688
38622
|
const agentConfig = { ...config.agent ?? {} };
|
|
38623
|
+
const agentConfigRecord = agentConfig;
|
|
38624
|
+
const internalAgentIds = registrations.map((registration) => registration.id);
|
|
37689
38625
|
for (const reg of registrations) {
|
|
37690
38626
|
if (typeof reg.prompt !== "string" || reg.prompt.length === 0) {
|
|
37691
38627
|
log(`[magic-context] skipping hidden agent '${reg.id}' — prompt unavailable at config time (dir=${ctx.directory}); will re-register on a later complete pass`);
|
|
37692
38628
|
continue;
|
|
37693
38629
|
}
|
|
37694
|
-
|
|
38630
|
+
agentConfigRecord[reg.id] = buildHiddenAgentConfig(reg.prompt, reg.allowedTools, reg.maxSteps, reg.overrides, reg.id, reg.lockPermissions === true, reg.description);
|
|
37695
38631
|
}
|
|
37696
|
-
|
|
38632
|
+
const callerAgentConfig = denyTaskRoutingToCallerAgents(agentConfigRecord, internalAgentIds);
|
|
38633
|
+
config.agent = callerAgentConfig;
|
|
37697
38634
|
} catch (error) {
|
|
37698
38635
|
const e = error;
|
|
37699
38636
|
log(`[magic-context] config hook failed (commands/agents NOT registered; transform still active): ${e?.message ?? error}`, e?.stack ? { stackHead: e.stack.split(`
|