@cortexkit/opencode-magic-context 0.43.0 → 0.43.2

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.
Files changed (102) hide show
  1. package/dist/{announcement-8mgn61fw.js → announcement-1a8bvswd.js} +2 -1
  2. package/dist/{conflict-warning-hook-t2vb0wnx.js → conflict-warning-hook-hyk9y29x.js} +6 -4
  3. package/dist/{derive-budgets-0sg5vp61.js → derive-budgets-b8ybssh9.js} +3 -2
  4. package/dist/features/magic-context/dreamer/classify.d.ts +12 -0
  5. package/dist/features/magic-context/dreamer/classify.d.ts.map +1 -1
  6. package/dist/features/magic-context/dreamer/hidden-single-shot.d.ts +7 -4
  7. package/dist/features/magic-context/dreamer/hidden-single-shot.d.ts.map +1 -1
  8. package/dist/features/magic-context/dreamer/map-memories.d.ts +3 -1
  9. package/dist/features/magic-context/dreamer/map-memories.d.ts.map +1 -1
  10. package/dist/features/magic-context/dreamer/refresh-primers.d.ts +3 -1
  11. package/dist/features/magic-context/dreamer/refresh-primers.d.ts.map +1 -1
  12. package/dist/features/magic-context/dreamer/task-executor.d.ts.map +1 -1
  13. package/dist/features/magic-context/dreamer/verify.d.ts +4 -1
  14. package/dist/features/magic-context/dreamer/verify.d.ts.map +1 -1
  15. package/dist/features/magic-context/memory/verification-paths.d.ts.map +1 -1
  16. package/dist/features/magic-context/store-generation-rebase.d.ts +62 -1
  17. package/dist/features/magic-context/store-generation-rebase.d.ts.map +1 -1
  18. package/dist/hooks/auto-update-checker/checker.d.ts +1 -0
  19. package/dist/hooks/auto-update-checker/checker.d.ts.map +1 -1
  20. package/dist/hooks/magic-context/command-handler.d.ts.map +1 -1
  21. package/dist/hooks/magic-context/compartment-runner-incremental.d.ts +6 -0
  22. package/dist/hooks/magic-context/compartment-runner-incremental.d.ts.map +1 -1
  23. package/dist/hooks/magic-context/compartment-runner-validation.d.ts +7 -0
  24. package/dist/hooks/magic-context/compartment-runner-validation.d.ts.map +1 -1
  25. package/dist/hooks/magic-context/compartment-trigger.d.ts +2 -1
  26. package/dist/hooks/magic-context/compartment-trigger.d.ts.map +1 -1
  27. package/dist/hooks/magic-context/ctx-reduce-availability.d.ts +60 -8
  28. package/dist/hooks/magic-context/ctx-reduce-availability.d.ts.map +1 -1
  29. package/dist/hooks/magic-context/hook.d.ts +3 -1
  30. package/dist/hooks/magic-context/hook.d.ts.map +1 -1
  31. package/dist/hooks/magic-context/lkg-slot.d.ts +1 -0
  32. package/dist/hooks/magic-context/lkg-slot.d.ts.map +1 -1
  33. package/dist/hooks/magic-context/rust-mode-transform.d.ts +2 -0
  34. package/dist/hooks/magic-context/rust-mode-transform.d.ts.map +1 -1
  35. package/dist/hooks/magic-context/send-session-notification.d.ts +1 -0
  36. package/dist/hooks/magic-context/send-session-notification.d.ts.map +1 -1
  37. package/dist/hooks/magic-context/system-prompt-hash.d.ts +9 -0
  38. package/dist/hooks/magic-context/system-prompt-hash.d.ts.map +1 -1
  39. package/dist/hooks/magic-context/transform-postprocess-phase.d.ts.map +1 -1
  40. package/dist/hooks/magic-context/transform.d.ts.map +1 -1
  41. package/dist/{index-8w1skpnm.js → index-0ccmyzbj.js} +6 -6
  42. package/dist/{index-ntbmt6rq.js → index-4b30nf6z.js} +1 -1
  43. package/dist/{index-rpz2me0v.js → index-6j8th2hd.js} +2 -2
  44. package/dist/{index-99sfbrrf.js → index-6w9p73jz.js} +1 -1
  45. package/dist/{index-4ftb5hcq.js → index-6z9g64js.js} +7 -1
  46. package/dist/{index-9skq8m9y.js → index-9r1cbh9e.js} +1 -1
  47. package/dist/{index-ykg9sdzz.js → index-bmzt6xgy.js} +3 -3
  48. package/dist/{safe-notification-target-fepvcbsj.js → index-febg06dy.js} +6 -7
  49. package/dist/{index-d0dh7v0f.js → index-g6hpfkqa.js} +361 -118
  50. package/dist/{index-rvwvdq59.js → index-jgnag7sa.js} +38 -4
  51. package/dist/{index-w2ety11c.js → index-pa67brzn.js} +3 -3
  52. package/dist/{index-ygwdyntq.js → index-tdrv6nd0.js} +6 -4
  53. package/dist/{index-qp20p2py.js → index-wgzyeyf5.js} +1 -1
  54. package/dist/index.d.ts.map +1 -1
  55. package/dist/index.js +801 -240
  56. package/dist/{message-time-backfill-gzjer78y.js → message-time-backfill-0ccvyk9n.js} +3 -2
  57. package/dist/plugin/hooks/create-session-hooks.d.ts.map +1 -1
  58. package/dist/{read-session-chunk-ec3jkvhg.js → read-session-chunk-53a7qbrh.js} +4 -3
  59. package/dist/{recomp-orchestrator-6akjp11f.js → recomp-orchestrator-adsgqgse.js} +9 -7
  60. package/dist/safe-notification-target-vrkjrbgb.js +10 -0
  61. package/dist/{send-session-notification-f6gwkesy.js → send-session-notification-e28r4xx2.js} +7 -3
  62. package/dist/shared/data-path.d.ts.map +1 -1
  63. package/dist/shared/model-suggestion-retry.d.ts.map +1 -1
  64. package/dist/shared/opencode-db-path.d.ts.map +1 -1
  65. package/dist/shared/test-fake-executable.d.ts +38 -0
  66. package/dist/shared/test-fake-executable.d.ts.map +1 -0
  67. package/dist/shared/test-temp-dir.d.ts +1 -1
  68. package/dist/shared/test-temp-dir.d.ts.map +1 -1
  69. package/dist/shared/user-facing-codes.d.ts +10 -0
  70. package/dist/shared/user-facing-codes.d.ts.map +1 -1
  71. package/dist/{task-config-ex4nt0q0.js → task-config-mgf5nsh3.js} +1 -1
  72. package/dist/v2/hidden-completion.d.ts.map +1 -1
  73. package/dist/v2/hooks/context.d.ts.map +1 -1
  74. package/dist/v2/hooks/hidden-child.d.ts +6 -0
  75. package/dist/v2/hooks/hidden-child.d.ts.map +1 -1
  76. package/dist/v2/hooks/payload.d.ts.map +1 -1
  77. package/dist/v2/hooks/refusal.d.ts +9 -1
  78. package/dist/v2/hooks/refusal.d.ts.map +1 -1
  79. package/dist/v2/hooks/restore-rows.d.ts +29 -0
  80. package/dist/v2/hooks/restore-rows.d.ts.map +1 -0
  81. package/dist/v2/hooks/types.d.ts +1 -0
  82. package/dist/v2/hooks/types.d.ts.map +1 -1
  83. package/dist/v2/hooks/update-check.d.ts +8 -0
  84. package/dist/v2/hooks/update-check.d.ts.map +1 -1
  85. package/dist/v2/host-service.d.ts +1 -1
  86. package/dist/v2/host-service.d.ts.map +1 -1
  87. package/dist/v2/server.js +1171 -366
  88. package/dist/v2/store-reader.d.ts +8 -0
  89. package/dist/v2/store-reader.d.ts.map +1 -1
  90. package/dist/wrapup-orchestrator-8xzbpvm8.js +18 -0
  91. package/package.json +2 -1
  92. package/src/features/magic-context/dreamer/task-registry.ts +1 -1
  93. package/src/shared/data-path.ts +6 -6
  94. package/src/shared/model-suggestion-retry.test.ts +43 -0
  95. package/src/shared/model-suggestion-retry.ts +17 -0
  96. package/src/shared/opencode-db-path.test.ts +18 -0
  97. package/src/shared/opencode-db-path.ts +5 -2
  98. package/src/shared/test-fake-executable.test.ts +54 -0
  99. package/src/shared/test-fake-executable.ts +110 -0
  100. package/src/shared/test-temp-dir.ts +3 -0
  101. package/src/shared/user-facing-codes.ts +11 -0
  102. package/dist/wrapup-orchestrator-5akc87gr.js +0 -16
package/dist/index.js CHANGED
@@ -1,3 +1,11 @@
1
+ import {
2
+ setHarness,
3
+ getHarness,
4
+ getDataDir,
5
+ getOpenCodeStorageDir,
6
+ getMagicContextStorageResolution,
7
+ getMagicContextStorageDir
8
+ } from "./index-6z9g64js.js";
1
9
  import {
2
10
  sanitizeDiagnosticText,
3
11
  hasShareabilitySensitiveText,
@@ -5,7 +13,7 @@ import {
5
13
  sessionLog,
6
14
  getLoggerDiagnostics,
7
15
  flushLogger
8
- } from "./index-qp20p2py.js";
16
+ } from "./index-wgzyeyf5.js";
9
17
  import {
10
18
  withContentLanguageDirective,
11
19
  buildPrimaryLanguageDirective,
@@ -224,6 +232,7 @@ import {
224
232
  registerLkgPersistence,
225
233
  beginLkgPass,
226
234
  visitMessageContentFields,
235
+ contentSnapshotValue,
227
236
  messageContentFields,
228
237
  signatureForFields,
229
238
  exactReusablePrefix,
@@ -289,6 +298,8 @@ import {
289
298
  detectThinkingBindingMismatch,
290
299
  isFable51ThinkingBindingModel,
291
300
  detectOverflow,
301
+ extractLatestAssistantText,
302
+ hasLengthCappedOutput,
292
303
  parseProviderModel,
293
304
  modelBodyField,
294
305
  toModelEntry,
@@ -299,8 +310,6 @@ import {
299
310
  promptSurfaceHashMaterial,
300
311
  createPromptSurfaceRuntime,
301
312
  createPromptSurfaceGuidanceEpochCache,
302
- extractLatestAssistantText,
303
- hasLengthCappedOutput,
304
313
  setKeepSubagents,
305
314
  teardownChildSession,
306
315
  renderUserFacingFailure,
@@ -465,7 +474,7 @@ import {
465
474
  setRecompStarting2,
466
475
  setRecompTerminal2,
467
476
  runManagedRecomp2
468
- } from "./index-d0dh7v0f.js";
477
+ } from "./index-g6hpfkqa.js";
469
478
  import {
470
479
  stripJsonComments,
471
480
  isPrototypePollutionKey,
@@ -496,7 +505,7 @@ import {
496
505
  deriveHistorianChunkTokens2,
497
506
  resolveKnownHistorianContextLimit2,
498
507
  resolveHistorianContextLimit2
499
- } from "./index-8w1skpnm.js";
508
+ } from "./index-0ccmyzbj.js";
500
509
  import {
501
510
  resolveOpenCodeDbPath,
502
511
  assertOpenCodeStoreGeneration,
@@ -519,7 +528,7 @@ import {
519
528
  latestPersistedMessageForRecovery,
520
529
  getMessageTimesFromOpenCodeDb,
521
530
  findLastAssistantModelFromOpenCodeDb
522
- } from "./index-ykg9sdzz.js";
531
+ } from "./index-bmzt6xgy.js";
523
532
  import {
524
533
  textMentionsRecentCommit,
525
534
  hasMeaningfulUserText2,
@@ -637,22 +646,23 @@ import {
637
646
  readRawSessionMessageById2,
638
647
  readSessionChunk2,
639
648
  readRawSessionSeedTail2
640
- } from "./index-ygwdyntq.js";
649
+ } from "./index-tdrv6nd0.js";
650
+ import"./index-febg06dy.js";
641
651
  import {
642
652
  getErrorMessage,
643
653
  describeError,
644
- sendIgnoredMessage2,
654
+ sendCommandResult2,
645
655
  flushIgnoredMessages2,
646
656
  clearIgnoredMessages2,
647
657
  observeIgnoredNotificationEvent2,
648
658
  sendStatusNotification2
649
- } from "./index-rvwvdq59.js";
659
+ } from "./index-jgnag7sa.js";
650
660
  import {
651
661
  detectConflicts,
652
662
  resolveCompactionForBoot,
653
663
  sendConflictWarning2,
654
664
  cleanupConflictWarnings2
655
- } from "./index-rpz2me0v.js";
665
+ } from "./index-6j8th2hd.js";
656
666
  import {
657
667
  resolveModelCalibration,
658
668
  calibrateBuckets
@@ -676,7 +686,7 @@ import {
676
686
  compareTaskOrder,
677
687
  buildDreamTaskRuntimeConfigs2,
678
688
  userMemoryCollectionEnabled2
679
- } from "./index-99sfbrrf.js";
689
+ } from "./index-6w9p73jz.js";
680
690
  import {
681
691
  registerNotificationSink2,
682
692
  pushNotification2,
@@ -692,24 +702,16 @@ import {
692
702
  ANNOUNCEMENT_FOOTER2,
693
703
  markAnnouncementSeen2,
694
704
  shouldShowAnnouncement2
695
- } from "./index-ntbmt6rq.js";
705
+ } from "./index-4b30nf6z.js";
696
706
  import {
697
707
  resolvePromptContext2
698
708
  } from "./index-fmsr7v69.js";
699
709
  import {
700
710
  runManagedWrapup2
701
- } from "./index-w2ety11c.js";
711
+ } from "./index-pa67brzn.js";
702
712
  import {
703
713
  logSlowWriteTransaction
704
- } from "./index-9skq8m9y.js";
705
- import {
706
- setHarness,
707
- getHarness,
708
- getDataDir,
709
- getOpenCodeStorageDir,
710
- getMagicContextStorageResolution,
711
- getMagicContextStorageDir
712
- } from "./index-4ftb5hcq.js";
714
+ } from "./index-9r1cbh9e.js";
713
715
  import {
714
716
  __toESM,
715
717
  __commonJS
@@ -12053,7 +12055,7 @@ async function getLatestVersion(channel = "latest", options = {}) {
12053
12055
  try {
12054
12056
  if (options.signal?.aborted)
12055
12057
  return null;
12056
- const response = await fetch(buildRegistryUrl(options.registryUrl ?? NPM_REGISTRY_URL), {
12058
+ const response = await (options.fetch ?? fetch)(buildRegistryUrl(options.registryUrl ?? NPM_REGISTRY_URL), {
12057
12059
  signal: controller.signal,
12058
12060
  headers: { Accept: "application/json" }
12059
12061
  });
@@ -14575,13 +14577,13 @@ async function runHiddenSingleShotPrompt(args) {
14575
14577
  throw new Error(`${args.callContext} returned length-capped output`);
14576
14578
  }
14577
14579
  const text = completion.text;
14578
- if (!text)
14580
+ if (!text && !args.allowEmpty)
14579
14581
  throw new Error(`${args.callContext} returned no output`);
14580
- return args.parse(text);
14582
+ return args.parse(text ?? "", completion);
14581
14583
  }
14582
14584
  });
14583
14585
  promptSettled = true;
14584
- return { validated: run.validated, completion: run.output };
14586
+ return { validated: run.validated, completion: run.output, childSessionId: handle.id };
14585
14587
  } finally {
14586
14588
  await args.executor.close(handle, {
14587
14589
  promptSettled,
@@ -15155,8 +15157,11 @@ async function classifyOneChunk(args, chunk, anchors, sliceMs, signal) {
15155
15157
  anchors
15156
15158
  });
15157
15159
  if (moduleRoute) {
15158
- const run = await runClassifyThroughModule(args, chunk, anchors, signal);
15159
- recordInvocation(args, startedAt, { status: "completed" });
15160
+ const { accounting, ...run } = await runClassifyThroughModule(args, chunk, anchors, signal);
15161
+ recordInvocation(args, startedAt, {
15162
+ status: "completed",
15163
+ moduleAccounting: accounting
15164
+ });
15160
15165
  return run;
15161
15166
  }
15162
15167
  const executor = resolveHiddenCompletionExecutor(args.hiddenCompletionExecutor, args.client, args.db, args.sessionDirectory, "classify-memories");
@@ -15258,7 +15263,7 @@ async function runClassifyThroughModule(args, chunk, anchors, signal) {
15258
15263
  task: "classify",
15259
15264
  command_id: `classify:${args.moduleCommandId ?? Date.now()}:${createHash5("sha256").update(chunk.map((candidate) => candidate.id).join(",")).digest("hex").slice(0, 24)}`,
15260
15265
  authority_generation: args.moduleAuthorityGeneration,
15261
- ...resolvedModelChain.length > 0 ? { model_chain: resolvedModelChain } : {},
15266
+ model_chain: resolvedModelChain,
15262
15267
  payload: {
15263
15268
  prompt_body: prompt,
15264
15269
  items: chunk.map((candidate) => ({
@@ -15279,6 +15284,7 @@ async function runClassifyThroughModule(args, chunk, anchors, signal) {
15279
15284
  if (result.truncated === true) {
15280
15285
  throw new Error("classify returned length-capped output");
15281
15286
  }
15287
+ const accounting = moduleClassifyAccounting(result);
15282
15288
  const parsed = validateClassifyManifest(manifestText, new Set(chunk.map((candidate) => candidate.id)));
15283
15289
  const rows = parsed.map((entry) => {
15284
15290
  const candidate = chunk.find((item) => item.id === entry.id);
@@ -15351,7 +15357,39 @@ async function runClassifyThroughModule(args, chunk, anchors, signal) {
15351
15357
  throw new Error(`module accepted unknown memory ${moduleId}`);
15352
15358
  return candidate.contextMemory.id;
15353
15359
  });
15354
- return { classified: acceptedContextIds.length, changed: acceptedContextIds.length };
15360
+ return {
15361
+ classified: acceptedContextIds.length,
15362
+ changed: acceptedContextIds.length,
15363
+ accounting
15364
+ };
15365
+ }
15366
+ function nonNegativeCount(value) {
15367
+ return typeof value === "number" && Number.isFinite(value) && value >= 0 ? value : 0;
15368
+ }
15369
+ function moduleClassifyAccounting(result) {
15370
+ const accounting = {};
15371
+ const usage = result.usage;
15372
+ if (usage && typeof usage === "object") {
15373
+ const record = usage;
15374
+ accounting.tokens = {
15375
+ input: nonNegativeCount(record.input),
15376
+ output: nonNegativeCount(record.output),
15377
+ cacheRead: nonNegativeCount(record.cache_read),
15378
+ cacheWrite: nonNegativeCount(record.cache_write)
15379
+ };
15380
+ }
15381
+ const diagnostics = result.diagnostics;
15382
+ const model = diagnostics && typeof diagnostics === "object" ? diagnostics.model : undefined;
15383
+ if (typeof model === "string") {
15384
+ const parsed = parseProviderModel(model);
15385
+ if (parsed) {
15386
+ accounting.providerId = parsed.providerID;
15387
+ accounting.modelId = parsed.modelID;
15388
+ } else if (model.trim()) {
15389
+ accounting.modelId = model.trim();
15390
+ }
15391
+ }
15392
+ return accounting;
15355
15393
  }
15356
15394
  function applyClassifications(args, chunk, manifestText) {
15357
15395
  const byId = new Map(chunk.map((m) => [m.id, m]));
@@ -15396,6 +15434,11 @@ function recordInvocation(args, startedAt, params) {
15396
15434
  providerId: params.completion.providerId,
15397
15435
  modelId: params.completion.modelId
15398
15436
  } : {},
15437
+ ...params.moduleAccounting ? {
15438
+ tokens: params.moduleAccounting.tokens,
15439
+ providerId: params.moduleAccounting.providerId,
15440
+ modelId: params.moduleAccounting.modelId
15441
+ } : {},
15399
15442
  error: params.error
15400
15443
  });
15401
15444
  }
@@ -18044,8 +18087,36 @@ async function mapOneBatch(args, batch, sliceMs, signal) {
18044
18087
  let promptSettled = false;
18045
18088
  const startedAt = Date.now();
18046
18089
  try {
18090
+ const prompt = buildMapMemoriesPrompt(args.projectIdentity, batch);
18091
+ if (args.hiddenCompletionExecutor) {
18092
+ const run = await runHiddenSingleShotPrompt({
18093
+ executor: args.hiddenCompletionExecutor,
18094
+ parentSessionId: args.parentSessionId,
18095
+ sessionDirectory: args.sessionDirectory,
18096
+ agent: DREAMER_MEMORY_MAPPER_AGENT,
18097
+ system: MAP_MEMORIES_SYSTEM_PROMPT,
18098
+ prompt,
18099
+ title: "magic-context-dream-map-memories",
18100
+ callContext: "dreamer:map-memories",
18101
+ model: args.model,
18102
+ fallbackModels: args.fallbackModels,
18103
+ timeoutMs: sliceMs,
18104
+ signal,
18105
+ parse: (text) => validateMapMemoriesManifest(text, new Set(batch.map((memory) => memory.id)))
18106
+ });
18107
+ recordInvocation2(args, startedAt, {
18108
+ status: "completed",
18109
+ messages: run.completion.messages ?? []
18110
+ });
18111
+ const outcome = await applyParsedBatchMappings(args, batch, run.validated);
18112
+ const returnedIds = new Set(run.validated.map((entry) => entry.id));
18113
+ return { ...outcome, requeue: batch.filter((memory) => !returnedIds.has(memory.id)) };
18114
+ }
18115
+ const client = args.client;
18116
+ if (!client)
18117
+ throw new Error("map-memories requires a client or hidden completion executor");
18047
18118
  const createResponse = await createChildSessionWithFence({
18048
- client: args.client,
18119
+ client,
18049
18120
  db: args.db,
18050
18121
  parentSessionId: args.parentSessionId,
18051
18122
  title: "magic-context-dream-map-memories",
@@ -18057,8 +18128,7 @@ async function mapOneBatch(args, batch, sliceMs, signal) {
18057
18128
  agentSessionId = typeof created?.id === "string" ? created.id : null;
18058
18129
  if (!agentSessionId)
18059
18130
  throw new Error("Could not create map-memories session.");
18060
- const prompt = buildMapMemoriesPrompt(args.projectIdentity, batch);
18061
- const run = await promptSyncWithValidatedOutputRetry(args.client, {
18131
+ const run = await promptSyncWithValidatedOutputRetry(client, {
18062
18132
  path: { id: agentSessionId },
18063
18133
  query: { directory: args.sessionDirectory },
18064
18134
  body: {
@@ -18073,7 +18143,7 @@ async function mapOneBatch(args, batch, sliceMs, signal) {
18073
18143
  fallbackModels: args.fallbackModels,
18074
18144
  callContext: "dreamer:map-memories",
18075
18145
  fetchOutput: async () => {
18076
- const messagesResponse = await args.client.session.messages({
18146
+ const messagesResponse = await client.session.messages({
18077
18147
  path: { id: agentSessionId },
18078
18148
  query: { directory: args.sessionDirectory, limit: 100 }
18079
18149
  });
@@ -18116,15 +18186,16 @@ async function mapOneBatch(args, batch, sliceMs, signal) {
18116
18186
  }
18117
18187
  };
18118
18188
  } finally {
18119
- await teardownChildSession({
18120
- client: args.client,
18121
- sessionId: agentSessionId,
18122
- sessionDirectory: args.sessionDirectory,
18123
- promptSettled,
18124
- privacySensitive: true,
18125
- context: "[dreamer] map-memories",
18126
- log
18127
- });
18189
+ if (agentSessionId && args.client)
18190
+ await teardownChildSession({
18191
+ client: args.client,
18192
+ sessionId: agentSessionId,
18193
+ sessionDirectory: args.sessionDirectory,
18194
+ promptSettled,
18195
+ privacySensitive: true,
18196
+ context: "[dreamer] map-memories",
18197
+ log
18198
+ });
18128
18199
  }
18129
18200
  }
18130
18201
  async function applyParsedBatchMappings(args, batch, parsed) {
@@ -18717,8 +18788,41 @@ async function refreshOnePrimer(args, primer, sliceMs, signal) {
18717
18788
  let promptSettled = false;
18718
18789
  const startedAt = Date.now();
18719
18790
  try {
18791
+ const prompt = buildInvestigationPrompt(primer, seed.kind, seed.orientation, seed.prePost);
18792
+ if (args.hiddenCompletionExecutor) {
18793
+ const run = await runHiddenSingleShotPrompt({
18794
+ executor: args.hiddenCompletionExecutor,
18795
+ parentSessionId: args.parentSessionId,
18796
+ sessionDirectory: args.sessionDirectory,
18797
+ agent: DREAMER_PRIMER_INVESTIGATOR_AGENT,
18798
+ system: PRIMER_INVESTIGATOR_SYSTEM_PROMPT,
18799
+ prompt,
18800
+ title: "magic-context-dream-refresh-primers",
18801
+ callContext: "dreamer:refresh-primers",
18802
+ model: args.model,
18803
+ fallbackModels: args.fallbackModels,
18804
+ language: args.language,
18805
+ timeoutMs: sliceMs,
18806
+ signal,
18807
+ parse: (text) => parseAnswer([{ info: { role: "assistant" }, parts: [{ type: "text", text }] }], primer.answer)
18808
+ });
18809
+ recordInvocation3(args, startedAt, {
18810
+ status: "completed",
18811
+ messages: run.completion.messages ?? []
18812
+ });
18813
+ const answer = run.validated.trim();
18814
+ if (!answer || investigationToolCallCount(run.completion.messages ?? []) === 0)
18815
+ return false;
18816
+ runLeaseGuardedWrite(args.db, args.holderId, args.leaseKey, () => {
18817
+ updatePrimerAnswer(args.db, primer.id, answer);
18818
+ });
18819
+ return true;
18820
+ }
18821
+ const client = args.client;
18822
+ if (!client)
18823
+ throw new Error("refresh-primers requires a client or hidden completion executor");
18720
18824
  const createResponse = await createChildSessionWithFence({
18721
- client: args.client,
18825
+ client,
18722
18826
  db: args.db,
18723
18827
  parentSessionId: args.parentSessionId,
18724
18828
  title: "magic-context-dream-refresh-primers",
@@ -18730,8 +18834,7 @@ async function refreshOnePrimer(args, primer, sliceMs, signal) {
18730
18834
  agentSessionId = typeof created?.id === "string" ? created.id : null;
18731
18835
  if (!agentSessionId)
18732
18836
  throw new Error("Could not create primer refresh session.");
18733
- const prompt = buildInvestigationPrompt(primer, seed.kind, seed.orientation, seed.prePost);
18734
- const run = await promptSyncWithValidatedOutputRetry(args.client, {
18837
+ const run = await promptSyncWithValidatedOutputRetry(client, {
18735
18838
  path: { id: agentSessionId },
18736
18839
  query: { directory: args.sessionDirectory },
18737
18840
  body: {
@@ -18746,7 +18849,7 @@ async function refreshOnePrimer(args, primer, sliceMs, signal) {
18746
18849
  fallbackModels: args.fallbackModels,
18747
18850
  callContext: "dreamer:refresh-primers",
18748
18851
  fetchOutput: async () => {
18749
- const messagesResponse = await args.client.session.messages({
18852
+ const messagesResponse = await client.session.messages({
18750
18853
  path: { id: agentSessionId },
18751
18854
  query: { directory: args.sessionDirectory, limit: 100 }
18752
18855
  });
@@ -18775,15 +18878,16 @@ async function refreshOnePrimer(args, primer, sliceMs, signal) {
18775
18878
  recordInvocation3(args, startedAt, { status: failedInvocationStatus(error), error });
18776
18879
  throw error;
18777
18880
  } finally {
18778
- await teardownChildSession({
18779
- client: args.client,
18780
- sessionId: agentSessionId,
18781
- sessionDirectory: args.sessionDirectory,
18782
- promptSettled,
18783
- privacySensitive: true,
18784
- context: "[dreamer] refresh-primers",
18785
- log
18786
- });
18881
+ if (agentSessionId && args.client)
18882
+ await teardownChildSession({
18883
+ client: args.client,
18884
+ sessionId: agentSessionId,
18885
+ sessionDirectory: args.sessionDirectory,
18886
+ promptSettled,
18887
+ privacySensitive: true,
18888
+ context: "[dreamer] refresh-primers",
18889
+ log
18890
+ });
18787
18891
  }
18788
18892
  }
18789
18893
  function originSessionIdForPrimer(args, primer) {
@@ -19518,8 +19622,40 @@ async function verifyOneBatch(args, batch, sliceMs, signal) {
19518
19622
  let promptSettled = false;
19519
19623
  const startedAt = Date.now();
19520
19624
  try {
19625
+ const prompt = buildVerifyPrompt(args.projectIdentity, batch);
19626
+ if (args.hiddenCompletionExecutor) {
19627
+ const run = await runHiddenSingleShotPrompt({
19628
+ executor: args.hiddenCompletionExecutor,
19629
+ parentSessionId: args.parentSessionId,
19630
+ sessionDirectory: args.sessionDirectory,
19631
+ agent: DREAMER_MEMORY_MAPPER_AGENT,
19632
+ system: VERIFY_SYSTEM_PROMPT,
19633
+ prompt,
19634
+ title: "magic-context-dream-verify",
19635
+ callContext: "dreamer:verify",
19636
+ model: args.model,
19637
+ fallbackModels: args.fallbackModels,
19638
+ language: args.language,
19639
+ timeoutMs: sliceMs,
19640
+ signal,
19641
+ parse: (text) => {
19642
+ const providerFailure = providerOutputFailureFromInvalidManifest([], text);
19643
+ if (providerFailure)
19644
+ throw providerFailure;
19645
+ return validateVerifyManifest(text, new Set(batch.map((memory) => memory.id)));
19646
+ }
19647
+ });
19648
+ recordInvocation4(args, startedAt, {
19649
+ status: "completed",
19650
+ messages: run.completion.messages ?? []
19651
+ });
19652
+ return applyParsedVerifyManifest(args, batch, run.validated);
19653
+ }
19654
+ const client = args.client;
19655
+ if (!client)
19656
+ throw new Error("verify requires a client or hidden completion executor");
19521
19657
  const createResponse = await createChildSessionWithFence({
19522
- client: args.client,
19658
+ client,
19523
19659
  db: args.db,
19524
19660
  parentSessionId: args.parentSessionId,
19525
19661
  title: "magic-context-dream-verify",
@@ -19531,8 +19667,7 @@ async function verifyOneBatch(args, batch, sliceMs, signal) {
19531
19667
  agentSessionId = typeof created?.id === "string" ? created.id : null;
19532
19668
  if (!agentSessionId)
19533
19669
  throw new Error("Could not create verify session.");
19534
- const prompt = buildVerifyPrompt(args.projectIdentity, batch);
19535
- const run = await promptSyncWithValidatedOutputRetry(args.client, {
19670
+ const run = await promptSyncWithValidatedOutputRetry(client, {
19536
19671
  path: { id: agentSessionId },
19537
19672
  query: { directory: args.sessionDirectory },
19538
19673
  body: {
@@ -19547,7 +19682,7 @@ async function verifyOneBatch(args, batch, sliceMs, signal) {
19547
19682
  fallbackModels: args.fallbackModels,
19548
19683
  callContext: "dreamer:verify",
19549
19684
  fetchOutput: async () => {
19550
- const messagesResponse = await args.client.session.messages({
19685
+ const messagesResponse = await client.session.messages({
19551
19686
  path: { id: agentSessionId },
19552
19687
  query: { directory: args.sessionDirectory, limit: 100 }
19553
19688
  });
@@ -19588,15 +19723,16 @@ async function verifyOneBatch(args, batch, sliceMs, signal) {
19588
19723
  providerFailure
19589
19724
  };
19590
19725
  } finally {
19591
- await teardownChildSession({
19592
- client: args.client,
19593
- sessionId: agentSessionId,
19594
- sessionDirectory: args.sessionDirectory,
19595
- promptSettled,
19596
- privacySensitive: true,
19597
- context: "[dreamer] verify",
19598
- log
19599
- });
19726
+ if (agentSessionId && args.client)
19727
+ await teardownChildSession({
19728
+ client: args.client,
19729
+ sessionId: agentSessionId,
19730
+ sessionDirectory: args.sessionDirectory,
19731
+ promptSettled,
19732
+ privacySensitive: true,
19733
+ context: "[dreamer] verify",
19734
+ log
19735
+ });
19600
19736
  }
19601
19737
  }
19602
19738
  async function applyParsedVerifyManifest(args, batch, parsed) {
@@ -19764,6 +19900,8 @@ async function applyParsedVerifyManifest(args, batch, parsed) {
19764
19900
  async function normalizeFiles(args, rawFiles) {
19765
19901
  if (rawFiles.length === 0)
19766
19902
  return [];
19903
+ if (args.normalizeFiles)
19904
+ return args.normalizeFiles(rawFiles);
19767
19905
  const normalized = await normalizeVerificationFiles({
19768
19906
  cwd: args.sessionDirectory,
19769
19907
  files: rawFiles
@@ -20097,7 +20235,8 @@ function createDreamTaskExecutor(deps) {
20097
20235
  if (config.task === "map-memories") {
20098
20236
  const result = await mapMemories({
20099
20237
  db,
20100
- client: requireDreamClient(deps.client),
20238
+ client: deps.client,
20239
+ hiddenCompletionExecutor: deps.hiddenCompletionExecutor,
20101
20240
  projectIdentity,
20102
20241
  parentSessionId: parent,
20103
20242
  sessionDirectory: deps.sessionDirectory,
@@ -20134,7 +20273,8 @@ function createDreamTaskExecutor(deps) {
20134
20273
  const memoryBefore = getMemoryCountsByStatus(db, projectIdentity);
20135
20274
  const result = await runVerify({
20136
20275
  db,
20137
- client: requireDreamClient(deps.client),
20276
+ client: deps.client,
20277
+ hiddenCompletionExecutor: deps.hiddenCompletionExecutor,
20138
20278
  projectIdentity,
20139
20279
  parentSessionId: parent,
20140
20280
  sessionDirectory: deps.sessionDirectory,
@@ -20235,7 +20375,8 @@ function createDreamTaskExecutor(deps) {
20235
20375
  if (config.task === "refresh-primers") {
20236
20376
  const result = await refreshPrimers({
20237
20377
  db,
20238
- client: requireDreamClient(deps.client),
20378
+ client: deps.client,
20379
+ hiddenCompletionExecutor: deps.hiddenCompletionExecutor,
20239
20380
  projectIdentity,
20240
20381
  parentSessionId: parent,
20241
20382
  sessionDirectory: deps.sessionDirectory,
@@ -20503,24 +20644,45 @@ async function runRetrospectiveTask(config, ctx, helpers) {
20503
20644
  abortController.abort();
20504
20645
  }, ctx.leaseAcquisition);
20505
20646
  let childSessionId = null;
20647
+ let hiddenHandle = null;
20506
20648
  let promptSettled = false;
20507
20649
  try {
20508
- const createResponse = await createChildSessionWithFence({
20509
- client: requireDreamClient(deps.client),
20510
- db,
20511
- parentSessionId: parent ?? undefined,
20512
- title: "magic-context-dream-retrospective",
20513
- directory: deps.sessionDirectory
20514
- });
20515
- const created = normalizeSDKResponse(createResponse, null, { preferResponseOnMissingData: true });
20516
- childSessionId = typeof created?.id === "string" ? created.id : null;
20517
- if (!childSessionId)
20518
- throw new Error("Retrospective could not create its child session.");
20650
+ if (deps.hiddenCompletionExecutor) {
20651
+ hiddenHandle = await deps.hiddenCompletionExecutor.open({
20652
+ parentSessionId: parent ?? undefined,
20653
+ agent: DREAMER_RETROSPECTIVE_AGENT,
20654
+ kind: "dreamer-task",
20655
+ system: FRICTION_GATE_SYSTEM_PROMPT,
20656
+ model: config.model,
20657
+ configuredModels: [
20658
+ ...config.model ? [config.model] : [],
20659
+ ...config.fallbackModels ?? []
20660
+ ],
20661
+ timeoutMs: Math.max(1, deadline - Date.now()),
20662
+ title: "magic-context-dream-retrospective",
20663
+ directory: deps.sessionDirectory
20664
+ });
20665
+ childSessionId = hiddenHandle.id;
20666
+ } else {
20667
+ const createResponse = await createChildSessionWithFence({
20668
+ client: requireDreamClient(deps.client),
20669
+ db,
20670
+ parentSessionId: parent ?? undefined,
20671
+ title: "magic-context-dream-retrospective",
20672
+ directory: deps.sessionDirectory
20673
+ });
20674
+ const created = normalizeSDKResponse(createResponse, null, { preferResponseOnMissingData: true });
20675
+ childSessionId = typeof created?.id === "string" ? created.id : null;
20676
+ if (!childSessionId)
20677
+ throw new Error("Retrospective could not create its child session.");
20678
+ }
20519
20679
  const sessionId = childSessionId;
20680
+ if (!sessionId)
20681
+ throw new Error("Retrospective could not create its child session.");
20520
20682
  const runChildTurn = async (system, userText) => {
20521
20683
  const remainingMs = Math.max(0, deadline - Date.now());
20522
20684
  promptSettled = false;
20523
- const run = await promptSyncWithValidatedOutputRetry(requireDreamClient(deps.client), {
20685
+ const run = await promptSyncWithValidatedOutputRetry(deps.hiddenCompletionExecutor ? undefined : requireDreamClient(deps.client), {
20524
20686
  path: { id: sessionId },
20525
20687
  query: { directory: deps.sessionDirectory },
20526
20688
  body: {
@@ -20534,7 +20696,13 @@ async function runRetrospectiveTask(config, ctx, helpers) {
20534
20696
  signal: abortController.signal,
20535
20697
  fallbackModels: config.fallbackModels,
20536
20698
  callContext: "dreamer:retrospective",
20699
+ ...hiddenHandle && deps.hiddenCompletionExecutor ? {
20700
+ transport: Object.assign((request) => deps.hiddenCompletionExecutor?.attempt(hiddenHandle, request) ?? Promise.reject(new Error("Hidden transport unavailable")), { childSessionId: hiddenHandle.childSessionId })
20701
+ } : {},
20537
20702
  fetchOutput: async () => {
20703
+ if (hiddenHandle && deps.hiddenCompletionExecutor) {
20704
+ return deps.hiddenCompletionExecutor.collect(hiddenHandle, 50);
20705
+ }
20538
20706
  const messagesResponse = await requireDreamClient(deps.client).session.messages({
20539
20707
  path: { id: sessionId },
20540
20708
  query: { directory: deps.sessionDirectory, limit: 50 }
@@ -20544,14 +20712,15 @@ async function runRetrospectiveTask(config, ctx, helpers) {
20544
20712
  });
20545
20713
  },
20546
20714
  validateOutput: (outputMessages) => {
20547
- const text = extractLatestAssistantText(outputMessages);
20715
+ const text = hiddenHandle ? outputMessages.text : extractLatestAssistantText(outputMessages);
20548
20716
  if (!text)
20549
20717
  throw new Error("Retrospective child returned no output.");
20550
20718
  return text;
20551
20719
  }
20552
20720
  });
20553
20721
  promptSettled = true;
20554
- return run;
20722
+ const output = hiddenHandle ? run.output.messages ?? [] : run.output;
20723
+ return { ...run, output };
20555
20724
  };
20556
20725
  const finish = (run, watermark) => {
20557
20726
  if (parent && run) {
@@ -20681,15 +20850,23 @@ async function runRetrospectiveTask(config, ctx, helpers) {
20681
20850
  });
20682
20851
  } finally {
20683
20852
  heartbeat.stop();
20684
- await teardownChildSession({
20685
- client: requireDreamClient(deps.client),
20686
- sessionId: childSessionId,
20687
- sessionDirectory: deps.sessionDirectory,
20688
- promptSettled,
20689
- privacySensitive: true,
20690
- context: "[dreamer] retrospective",
20691
- log
20692
- });
20853
+ if (hiddenHandle && deps.hiddenCompletionExecutor) {
20854
+ await deps.hiddenCompletionExecutor.close(hiddenHandle, {
20855
+ promptSettled,
20856
+ privacySensitive: true,
20857
+ context: "[dreamer] retrospective",
20858
+ log
20859
+ });
20860
+ } else
20861
+ await teardownChildSession({
20862
+ client: requireDreamClient(deps.client),
20863
+ sessionId: childSessionId,
20864
+ sessionDirectory: deps.sessionDirectory,
20865
+ promptSettled,
20866
+ privacySensitive: true,
20867
+ context: "[dreamer] retrospective",
20868
+ log
20869
+ });
20693
20870
  }
20694
20871
  }
20695
20872
  async function runAgenticTask(config, ctx, helpers) {
@@ -20763,72 +20940,107 @@ async function runAgenticTask(config, ctx, helpers) {
20763
20940
  docsCurrentTokens: maintainDocsSnapshot ? Math.ceil([...maintainDocsSnapshot.values()].join("").length / 3.5) : 0,
20764
20941
  curate: curateMemories && curateCategory ? { category: curateCategory, memories: curateMemories } : undefined
20765
20942
  });
20766
- const createResponse = await createChildSessionWithFence({
20767
- client: requireDreamClient(deps.client),
20768
- db,
20769
- parentSessionId: parent ?? undefined,
20770
- title: `magic-context-dream-${task}`,
20771
- directory: docsDir
20772
- });
20773
- const created = normalizeSDKResponse(createResponse, null, {
20774
- preferResponseOnMissingData: true
20775
- });
20776
- childSessionId = typeof created?.id === "string" ? created.id : null;
20777
- if (!childSessionId)
20778
- throw new Error("Dreamer could not create its child session.");
20779
- const sessionId = childSessionId;
20780
- const remainingMs = Math.max(0, deadline - Date.now());
20781
- const run = await promptSyncWithValidatedOutputRetry(requireDreamClient(deps.client), {
20782
- path: { id: sessionId },
20783
- query: { directory: docsDir },
20784
- body: {
20943
+ let run;
20944
+ if (deps.hiddenCompletionExecutor) {
20945
+ const hidden = await runHiddenSingleShotPrompt({
20946
+ executor: deps.hiddenCompletionExecutor,
20947
+ parentSessionId: parent ?? undefined,
20948
+ sessionDirectory: docsDir,
20785
20949
  agent: task === "maintain-docs" ? DREAMER_DOCS_AGENT : DREAMER_AGENT,
20786
- system: task === "maintain-docs" ? MAINTAIN_DOCS_SYSTEM_PROMPT : withContentLanguageDirective(CURATE_SYSTEM_PROMPT, config.language ?? deps.language),
20787
- ...modelBodyField(config.model),
20788
- parts: [{ type: "text", text: taskPrompt, synthetic: true }]
20789
- }
20790
- }, {
20791
- timeoutMs: Math.min(remainingMs, config.timeoutMinutes * 60 * 1000),
20792
- signal: abortController.signal,
20793
- fallbackModels: config.fallbackModels,
20794
- callContext: `dreamer:${task}`,
20795
- fetchOutput: async () => {
20796
- const messagesResponse = await requireDreamClient(deps.client).session.messages({
20797
- path: { id: sessionId },
20798
- query: {
20799
- directory: docsDir,
20800
- ...task === "curate" ? {} : { limit: 50 }
20950
+ system: task === "maintain-docs" ? MAINTAIN_DOCS_SYSTEM_PROMPT : CURATE_SYSTEM_PROMPT,
20951
+ prompt: taskPrompt,
20952
+ title: `magic-context-dream-${task}`,
20953
+ callContext: `dreamer:${task}`,
20954
+ allowEmpty: task === "curate",
20955
+ model: config.model,
20956
+ fallbackModels: config.fallbackModels,
20957
+ language: task === "curate" ? config.language ?? deps.language : undefined,
20958
+ timeoutMs: Math.min(Math.max(0, deadline - Date.now()), config.timeoutMinutes * 60 * 1000),
20959
+ signal: abortController.signal,
20960
+ parse: (text, completion) => {
20961
+ if (task !== "curate")
20962
+ return text;
20963
+ const memoryOperations = inspectCurateMemoryOperations(completion.messages);
20964
+ if (text)
20965
+ validateCurateAssistantText(text);
20966
+ if (memoryOperations.totalCalls > 0 && memoryOperations.completedActions.length === 0)
20967
+ throw new Error("Curate returned no completed ctx_memory tool result.");
20968
+ if (!text && memoryOperations.completedActions.length === 0)
20969
+ throw new Error("Dreamer returned no assistant output.");
20970
+ return { text: text || null, memoryOperations };
20971
+ }
20972
+ });
20973
+ childSessionId = hidden.childSessionId;
20974
+ run = { output: hidden.completion.messages ?? [], validated: hidden.validated };
20975
+ promptSettled = true;
20976
+ } else {
20977
+ const createResponse = await createChildSessionWithFence({
20978
+ client: requireDreamClient(deps.client),
20979
+ db,
20980
+ parentSessionId: parent ?? undefined,
20981
+ title: `magic-context-dream-${task}`,
20982
+ directory: docsDir
20983
+ });
20984
+ const created = normalizeSDKResponse(createResponse, null, {
20985
+ preferResponseOnMissingData: true
20986
+ });
20987
+ childSessionId = typeof created?.id === "string" ? created.id : null;
20988
+ if (!childSessionId)
20989
+ throw new Error("Dreamer could not create its child session.");
20990
+ const sessionId = childSessionId;
20991
+ const remainingMs = Math.max(0, deadline - Date.now());
20992
+ run = await promptSyncWithValidatedOutputRetry(requireDreamClient(deps.client), {
20993
+ path: { id: sessionId },
20994
+ query: { directory: docsDir },
20995
+ body: {
20996
+ agent: task === "maintain-docs" ? DREAMER_DOCS_AGENT : DREAMER_AGENT,
20997
+ system: task === "maintain-docs" ? MAINTAIN_DOCS_SYSTEM_PROMPT : withContentLanguageDirective(CURATE_SYSTEM_PROMPT, config.language ?? deps.language),
20998
+ ...modelBodyField(config.model),
20999
+ parts: [{ type: "text", text: taskPrompt, synthetic: true }]
21000
+ }
21001
+ }, {
21002
+ timeoutMs: Math.min(remainingMs, config.timeoutMinutes * 60 * 1000),
21003
+ signal: abortController.signal,
21004
+ fallbackModels: config.fallbackModels,
21005
+ callContext: `dreamer:${task}`,
21006
+ fetchOutput: async () => {
21007
+ const messagesResponse = await requireDreamClient(deps.client).session.messages({
21008
+ path: { id: sessionId },
21009
+ query: {
21010
+ directory: docsDir,
21011
+ ...task === "curate" ? {} : { limit: 50 }
21012
+ }
21013
+ });
21014
+ return normalizeSDKResponse(messagesResponse, [], {
21015
+ preferResponseOnMissingData: true
21016
+ });
21017
+ },
21018
+ validateOutput: (messages) => {
21019
+ const text = extractLatestAssistantText(messages);
21020
+ if (task !== "curate") {
21021
+ if (!text)
21022
+ throw new Error("Dreamer returned no assistant output.");
21023
+ return text;
21024
+ }
21025
+ const memoryOperations = inspectCurateMemoryOperations(messages);
21026
+ if (text)
21027
+ validateCurateAssistantText(text);
21028
+ if (memoryOperations.completedActions.length > 0) {
21029
+ return { text, memoryOperations };
20801
21030
  }
20802
- });
20803
- return normalizeSDKResponse(messagesResponse, [], {
20804
- preferResponseOnMissingData: true
20805
- });
20806
- },
20807
- validateOutput: (messages) => {
20808
- const text = extractLatestAssistantText(messages);
20809
- if (task !== "curate") {
20810
21031
  if (!text)
20811
21032
  throw new Error("Dreamer returned no assistant output.");
20812
- return text;
20813
- }
20814
- const memoryOperations = inspectCurateMemoryOperations(messages);
20815
- if (text)
20816
- validateCurateAssistantText(text);
20817
- if (memoryOperations.completedActions.length > 0) {
21033
+ if (memoryOperations.totalCalls > 0) {
21034
+ throw new Error("Curate returned no completed ctx_memory tool result.");
21035
+ }
20818
21036
  return { text, memoryOperations };
20819
21037
  }
20820
- if (!text)
20821
- throw new Error("Dreamer returned no assistant output.");
20822
- if (memoryOperations.totalCalls > 0) {
20823
- throw new Error("Curate returned no completed ctx_memory tool result.");
20824
- }
20825
- return { text, memoryOperations };
20826
- }
20827
- });
20828
- promptSettled = true;
21038
+ });
21039
+ promptSettled = true;
21040
+ }
20829
21041
  if (leaseLost)
20830
21042
  throw new Error("Dream lease lost during task");
20831
- const curateRefused = task === "curate" ? takeCurateSafetyRefusalCount(sessionId) : 0;
21043
+ const curateRefused = task === "curate" ? takeCurateSafetyRefusalCount(childSessionId ?? "") : 0;
20832
21044
  if (curateRefused > 0) {
20833
21045
  helpers.reportProgress(curateRefused, curateRefused);
20834
21046
  log(`[dreamer] curate safety summary: refused=${curateRefused}`);
@@ -20898,15 +21110,16 @@ async function runAgenticTask(config, ctx, helpers) {
20898
21110
  heartbeat.stop();
20899
21111
  if (childSessionId)
20900
21112
  takeCurateSafetyRefusalCount(childSessionId);
20901
- await teardownChildSession({
20902
- client: requireDreamClient(deps.client),
20903
- sessionId: childSessionId,
20904
- sessionDirectory: docsDir,
20905
- promptSettled,
20906
- privacySensitive: true,
20907
- context: `[dreamer] ${task}`,
20908
- log
20909
- });
21113
+ if (!deps.hiddenCompletionExecutor)
21114
+ await teardownChildSession({
21115
+ client: requireDreamClient(deps.client),
21116
+ sessionId: childSessionId,
21117
+ sessionDirectory: docsDir,
21118
+ promptSettled,
21119
+ privacySensitive: true,
21120
+ context: `[dreamer] ${task}`,
21121
+ log
21122
+ });
20910
21123
  }
20911
21124
  }
20912
21125
 
@@ -25926,6 +26139,8 @@ var TODOWRITE_TOOL = "todowrite";
25926
26139
  var availabilityBySession = new BoundedSessionMap(1000);
25927
26140
  var permissionDeniedBySession = new BoundedSessionMap(2000);
25928
26141
  var ctxReducePermissionDenyLogged = new BoundedSessionMap(1000);
26142
+ var ctxReduceSpawnPermissionDenied = new BoundedSessionMap(1000);
26143
+ var ctxReduceSpawnPermissionReads = new Map;
25929
26144
  function permissionCacheKey(toolName, sessionId) {
25930
26145
  return `${toolName}\x00${sessionId}`;
25931
26146
  }
@@ -25944,6 +26159,12 @@ function verdictFromToolsMap(tools, toolName) {
25944
26159
  return false;
25945
26160
  return null;
25946
26161
  }
26162
+ function unfrozenVerdict(sessionId, toolName, mapVerdict) {
26163
+ if (toolName === CTX_REDUCE_TOOL && ctxReduceSpawnPermissionDenied.get(sessionId) === true) {
26164
+ return false;
26165
+ }
26166
+ return mapVerdict ?? true;
26167
+ }
25947
26168
  function resolveToolAvailabilityFromMessages(sessionId, toolName, messages) {
25948
26169
  if (toolName === CTX_REDUCE_TOOL && !ctxReduceRegisteredGlobally) {
25949
26170
  return { callable: false, frozen: true };
@@ -25955,7 +26176,7 @@ function resolveToolAvailabilityFromMessages(sessionId, toolName, messages) {
25955
26176
  for (const message of messages) {
25956
26177
  if (message.info?.role !== "user")
25957
26178
  continue;
25958
- const verdict = verdictFromToolsMap(message.info.tools, toolName) ?? true;
26179
+ const verdict = unfrozenVerdict(sessionId, toolName, verdictFromToolsMap(message.info.tools, toolName));
25959
26180
  availabilityBySession.set(key, verdict);
25960
26181
  return { callable: verdict, frozen: true };
25961
26182
  }
@@ -25978,7 +26199,7 @@ function resolveToolAvailability(sessionId, toolName) {
25978
26199
  if (!row)
25979
26200
  return { callable: true, frozen: false };
25980
26201
  const verdict = row.tools === null ? null : verdictFromToolsMap(JSON.parse(row.tools), toolName);
25981
- const resolved = verdict ?? true;
26202
+ const resolved = unfrozenVerdict(sessionId, toolName, verdict);
25982
26203
  availabilityBySession.set(key, resolved);
25983
26204
  return { callable: resolved, frozen: true };
25984
26205
  } catch (error) {
@@ -26094,6 +26315,58 @@ async function resolveToolPermissionDenied(client, sessionId, toolName, activeAg
26094
26315
  permissionDeniedBySession.set(permissionCacheKey(toolName, sessionId), denied);
26095
26316
  return denied;
26096
26317
  }
26318
+ function primeCtxReduceSpawnPermission(client, sessionId, spawnAgent) {
26319
+ if (!ctxReduceSpawnPermissionReadNeeded(sessionId))
26320
+ return Promise.resolve();
26321
+ const inFlight = ctxReduceSpawnPermissionReads.get(sessionId);
26322
+ if (inFlight)
26323
+ return inFlight;
26324
+ const read = (async () => {
26325
+ try {
26326
+ const denied = await resolveToolPermissionDenied(client, sessionId, CTX_REDUCE_TOOL, spawnAgent);
26327
+ ctxReduceSpawnPermissionDenied.set(sessionId, denied);
26328
+ if (denied) {
26329
+ sessionLog(sessionId, `ctx_reduce permission is denied for agent=${spawnAgent ?? "(session default)"}; session freezes without ctx_reduce tags, guidance, or nudges`);
26330
+ }
26331
+ } catch (error) {
26332
+ sessionLog(sessionId, "ctx_reduce permission read before freeze failed (fail-open):", error);
26333
+ } finally {
26334
+ ctxReduceSpawnPermissionReads.delete(sessionId);
26335
+ }
26336
+ })();
26337
+ ctxReduceSpawnPermissionReads.set(sessionId, read);
26338
+ return read;
26339
+ }
26340
+ function ctxReduceSpawnPermissionReadNeeded(sessionId) {
26341
+ return ctxReduceRegisteredGlobally && availabilityBySession.get(cacheKey(CTX_REDUCE_TOOL, sessionId)) === undefined && ctxReduceSpawnPermissionDenied.get(sessionId) === undefined;
26342
+ }
26343
+ function spawnAgentFromMessages(messages) {
26344
+ for (const message of messages) {
26345
+ if (message.info?.role !== "user")
26346
+ continue;
26347
+ const agent = message.info.agent;
26348
+ return typeof agent === "string" && agent.length > 0 ? agent : undefined;
26349
+ }
26350
+ return;
26351
+ }
26352
+ function spawnAgentFromOpenCodeDb(sessionId) {
26353
+ if (!openCodeDbExists())
26354
+ return { persisted: false };
26355
+ try {
26356
+ const row = withReadOnlySessionDb((db) => db.prepare(`SELECT json_extract(data, '$.agent') AS agent FROM message
26357
+ WHERE session_id = ? AND json_extract(data, '$.role') = 'user'
26358
+ ORDER BY time_created ASC LIMIT 1`).get(sessionId));
26359
+ if (!row)
26360
+ return { persisted: false };
26361
+ return {
26362
+ persisted: true,
26363
+ agent: typeof row.agent === "string" && row.agent.length > 0 ? row.agent : undefined
26364
+ };
26365
+ } catch (error) {
26366
+ sessionLog(sessionId, "ctx_reduce spawn agent read failed:", error);
26367
+ return { persisted: false };
26368
+ }
26369
+ }
26097
26370
  function todowritePermissionDenied(client, sessionId, activeAgent) {
26098
26371
  return resolveToolPermissionDenied(client, sessionId, TODOWRITE_TOOL, activeAgent);
26099
26372
  }
@@ -26603,6 +26876,21 @@ function formatThresholdClampNote(opts) {
26603
26876
  // src/shared/rust-mode-status.ts
26604
26877
  var RUST_MODE_HOST_PATHS_LINE = "Host backends → MODULE: ctx_memory, ctx_note; historian: module-side";
26605
26878
 
26879
+ // src/hooks/magic-context/cache-busting-signals.ts
26880
+ function canConsumeDeferredOnThisPass(args) {
26881
+ if (args.justAwaitedPublication)
26882
+ return true;
26883
+ return args.schedulerDecision === "execute" || args.contextPercentage >= (args.forceMaterializationPercentage ?? escalationBands(65).forceMaterializationPercentage);
26884
+ }
26885
+ function hasReclaimRide(signals) {
26886
+ return signals.hardFold || signals.force || signals.explicitFlush || signals.publishedHistory;
26887
+ }
26888
+ var RECLAIM_RIDE_NAMES = ["hardFold", "force", "explicitFlush", "publishedHistory"];
26889
+ function reclaimRideLabel(signals) {
26890
+ const active = RECLAIM_RIDE_NAMES.filter((name) => signals[name]);
26891
+ return `ride=${active.length > 0 ? active.join("+") : "none"}`;
26892
+ }
26893
+
26606
26894
  // src/hooks/magic-context/compartment-trigger.ts
26607
26895
  var PROACTIVE_TRIGGER_OFFSET_PERCENTAGE = 2;
26608
26896
  var POST_DROP_TARGET_RATIO = 0.75;
@@ -26780,7 +27068,7 @@ function getUnsummarizedTailInfo(db, sessionId, triggerBudget, usage, executeThr
26780
27068
  function formatProjectedPostDropPercentage(value) {
26781
27069
  return value === null ? "none" : `${value.toFixed(1)}%`;
26782
27070
  }
26783
- function checkCompartmentTrigger(db, sessionId, sessionMeta, usage, _previousPercentage, executeThresholdPercentage, triggerBudget, clearReasoningAge, commitClusterTrigger, preloadedActiveTags, contextLimit, inMemoryTail, taggerFloorOverride, reasoningProjection) {
27071
+ function checkCompartmentTrigger(db, sessionId, sessionMeta, usage, _previousPercentage, executeThresholdPercentage, triggerBudget, clearReasoningAge, commitClusterTrigger, preloadedActiveTags, contextLimit, inMemoryTail, taggerFloorOverride, reasoningProjection, reclaimRide) {
26784
27072
  if (sessionMeta.compartmentInProgress) {
26785
27073
  sessionLog(sessionId, `compartment trigger: skipped — historian already in progress (usage=${usage.percentage.toFixed(1)}%)`);
26786
27074
  return { shouldFire: false };
@@ -26838,10 +27126,12 @@ function checkCompartmentTrigger(db, sessionId, sessionMeta, usage, _previousPer
26838
27126
  const canClearReasoning = reasoningProjection?.canClearReasoning ?? modelAcceptsEmptyContent(reasoningProjection?.providerID);
26839
27127
  const projectedPostDropPercentage = estimateProjectedPostDropPercentage(db, sessionId, usage, preloadedActiveTags ?? getActiveTagsBySession(db, sessionId), clearReasoningAge, sessionMeta.clearedReasoningThroughTag, canClearReasoning);
26840
27128
  const relativePostDropTarget = executeThresholdPercentage * POST_DROP_TARGET_RATIO;
27129
+ const rideLabel = reclaimRide ? reclaimRideLabel(reclaimRide) : "ride=none";
27130
+ const dropsCanLand = reclaimRide !== undefined && hasReclaimRide(reclaimRide);
26841
27131
  const forceMaterializationPercentage = escalationBands(executeThresholdPercentage).forceMaterializationPercentage;
26842
27132
  if (usage.percentage >= forceMaterializationPercentage) {
26843
- if (projectedPostDropPercentage !== null && projectedPostDropPercentage <= relativePostDropTarget) {
26844
- sessionLog(sessionId, `historian redundancy skip: summarizer not needed this pass — force band is ${forceMaterializationPercentage}%; queued/automatic drops are projected to reclaim to ${projectedPostDropPercentage.toFixed(1)}% (target ${relativePostDropTarget.toFixed(1)}%) on the next eligible execute pass`);
27133
+ if (dropsCanLand && projectedPostDropPercentage !== null && projectedPostDropPercentage <= relativePostDropTarget) {
27134
+ sessionLog(sessionId, `historian redundancy skip: summarizer not needed this pass — force band is ${forceMaterializationPercentage}%; queued/automatic drops are projected to reclaim to ${projectedPostDropPercentage.toFixed(1)}% (target ${relativePostDropTarget.toFixed(1)}%) on this pass (${rideLabel})`);
26845
27135
  return { shouldFire: false };
26846
27136
  }
26847
27137
  sessionLog(sessionId, `compartment trigger: force-firing at ${usage.percentage.toFixed(1)}% (projected post-drop ${formatProjectedPostDropPercentage(projectedPostDropPercentage)})`);
@@ -26901,8 +27191,8 @@ function checkCompartmentTrigger(db, sessionId, sessionMeta, usage, _previousPer
26901
27191
  sessionLog(sessionId, `compartment trigger: not firing at ${usage.percentage.toFixed(1)}% — below proactive floor (${proactiveTriggerPercentage}%)`);
26902
27192
  return { shouldFire: false };
26903
27193
  }
26904
- if (projectedPostDropPercentage !== null && projectedPostDropPercentage <= relativePostDropTarget) {
26905
- sessionLog(sessionId, `historian redundancy skip: summarizer not needed this pass — usage is ${usage.percentage.toFixed(1)}%; queued/automatic drops are projected to reclaim to ${projectedPostDropPercentage.toFixed(1)}% (target ${relativePostDropTarget.toFixed(1)}%) on the next eligible execute pass`);
27194
+ if (dropsCanLand && projectedPostDropPercentage !== null && projectedPostDropPercentage <= relativePostDropTarget) {
27195
+ sessionLog(sessionId, `historian redundancy skip: summarizer not needed this pass — usage is ${usage.percentage.toFixed(1)}%; queued/automatic drops are projected to reclaim to ${projectedPostDropPercentage.toFixed(1)}% (target ${relativePostDropTarget.toFixed(1)}%) on this pass (${rideLabel})`);
26906
27196
  return { shouldFire: false };
26907
27197
  }
26908
27198
  if (!tailInfo.hasProtectedEligibleHead || !tailInfo.isMeaningful) {
@@ -27226,6 +27516,12 @@ function moduleResponseValue(response) {
27226
27516
  function rustCommandId(operation) {
27227
27517
  return `opencode-${operation}-${randomUUID2()}`;
27228
27518
  }
27519
+ var LEGACY_TRANSFORM_NOT_OBSERVED_SUMMARY = "wrapup unavailable until a full session transform has been observed";
27520
+ function wrapupNeedsSessionMessage(value) {
27521
+ if (value.reason === "transform_not_observed")
27522
+ return true;
27523
+ return value.reason === "snapshot_unavailable" && value.summary === LEGACY_TRANSFORM_NOT_OBSERVED_SUMMARY;
27524
+ }
27229
27525
  function formatRustOperationMessage(operation, value) {
27230
27526
  const disposition = typeof value.disposition === "string" ? value.disposition : "failed";
27231
27527
  const summary = typeof value.summary === "string" ? value.summary : "";
@@ -27247,7 +27543,7 @@ ${summary || "Nothing to compact."}`;
27247
27543
  case "retryable":
27248
27544
  return `## Magic Wrapup — Partial
27249
27545
 
27250
- ${renderCapabilityRefusal("history_compression")}`;
27546
+ ${wrapupNeedsSessionMessage(value) ? renderUserFacingFailure("history_compression_needs_message") : renderCapabilityRefusal("history_compression")}`;
27251
27547
  default:
27252
27548
  return `## Magic Wrapup — Failed
27253
27549
 
@@ -30888,9 +31184,9 @@ function registerRpcHandlers(rpcServer, args) {
30888
31184
  return { count: buildCompartmentCount(db, sessionId, moduleStatus) };
30889
31185
  });
30890
31186
  const buildManagedCtx = async (db) => {
30891
- const { deriveHistorianChunkTokens, resolveHistorianContextLimit } = await import("./derive-budgets-0sg5vp61.js");
31187
+ const { deriveHistorianChunkTokens, resolveHistorianContextLimit } = await import("./derive-budgets-b8ybssh9.js");
30892
31188
  const { resolveHistorianModel } = await import("./model-resolution-dxatzjde.js");
30893
- const { userMemoryCollectionEnabled } = await import("./task-config-ex4nt0q0.js");
31189
+ const { userMemoryCollectionEnabled } = await import("./task-config-mgf5nsh3.js");
30894
31190
  const DEFAULT_HISTORIAN_TIMEOUT_MS = 600000;
30895
31191
  const runConfig = historianRunConfig(config, currentPluginConfigReader(directory)?.poll().effective ?? config);
30896
31192
  const historianModel = resolveHistorianModel(runConfig, "opencode");
@@ -30922,8 +31218,8 @@ function registerRpcHandlers(rpcServer, args) {
30922
31218
  const db = getDb();
30923
31219
  if (!db)
30924
31220
  return { ok: false, error: "db unavailable" };
30925
- const { runManagedRecomp } = await import("./recomp-orchestrator-6akjp11f.js");
30926
- const { sendIgnoredMessage } = await import("./send-session-notification-f6gwkesy.js");
31221
+ const { runManagedRecomp } = await import("./recomp-orchestrator-adsgqgse.js");
31222
+ const { sendIgnoredMessage } = await import("./send-session-notification-e28r4xx2.js");
30927
31223
  log(`[rpc] recomp requested for session ${sessionId}`);
30928
31224
  const ctx = await buildManagedCtx(db);
30929
31225
  runManagedRecomp(ctx, sessionId).then((message) => {
@@ -30981,7 +31277,7 @@ function registerRpcHandlers(rpcServer, args) {
30981
31277
  const db = getDb();
30982
31278
  if (!db)
30983
31279
  return { ok: false, error: "db unavailable" };
30984
- const { runManagedWrapup } = await import("./wrapup-orchestrator-5akc87gr.js");
31280
+ const { runManagedWrapup } = await import("./wrapup-orchestrator-8xzbpvm8.js");
30985
31281
  const model = liveSessionState.liveModelBySession.get(sessionId);
30986
31282
  const contextLimit = model ? resolveContextLimit(model.providerID, model.modelID, { db, sessionID: sessionId }) : 128000;
30987
31283
  const ctx = {
@@ -31838,21 +32134,6 @@ async function maybeDeliverChannel2(sessionId, deps) {
31838
32134
  }
31839
32135
  }
31840
32136
 
31841
- // src/hooks/magic-context/cache-busting-signals.ts
31842
- function canConsumeDeferredOnThisPass(args) {
31843
- if (args.justAwaitedPublication)
31844
- return true;
31845
- return args.schedulerDecision === "execute" || args.contextPercentage >= (args.forceMaterializationPercentage ?? escalationBands(65).forceMaterializationPercentage);
31846
- }
31847
- function hasReclaimRide(signals) {
31848
- return signals.hardFold || signals.force || signals.explicitFlush || signals.publishedHistory;
31849
- }
31850
- var RECLAIM_RIDE_NAMES = ["hardFold", "force", "explicitFlush", "publishedHistory"];
31851
- function reclaimRideLabel(signals) {
31852
- const active = RECLAIM_RIDE_NAMES.filter((name) => signals[name]);
31853
- return `ride=${active.length > 0 ? active.join("+") : "none"}`;
31854
- }
31855
-
31856
32137
  // src/hooks/magic-context/caveman-cleanup.ts
31857
32138
  var DEPTH_UNTOUCHED = 0;
31858
32139
  var DEPTH_LITE = 1;
@@ -36620,7 +36901,7 @@ function rustCaptureDigests(inputs, prior, acceptedInputs) {
36620
36901
  }
36621
36902
  function messageMatchesContentSnapshot(message, snapshot) {
36622
36903
  let fieldIndex = 0;
36623
- const matched = visitMessageContentFields(message, {
36904
+ const matched = visitMessageContentFields(contentSnapshotValue(message), {
36624
36905
  field(value) {
36625
36906
  if (!Object.is(value, snapshot.fields[fieldIndex]))
36626
36907
  return false;
@@ -36875,6 +37156,7 @@ function ensureState(states, sessionId) {
36875
37156
  if (!state) {
36876
37157
  state = {
36877
37158
  initialized: false,
37159
+ baselineSystemHashOmitted: false,
36878
37160
  consecutiveFailures: 0,
36879
37161
  passCount: 0,
36880
37162
  parked: false,
@@ -37836,6 +38118,7 @@ function createRustModeTransform(deps, options) {
37836
38118
  }
37837
38119
  }
37838
38120
  timings.preflight = performance.now() - passStartedAt;
38121
+ resolveCtxReduceAvailabilityFromMessages(sessionId, messages);
37839
38122
  const reduceAvailability = resolveCtxReduceAvailability(sessionId);
37840
38123
  resolveTodowriteAvailabilityFromMessages(sessionId, messages);
37841
38124
  const todoAvailability = resolveTodowriteAvailability(sessionId);
@@ -37907,6 +38190,8 @@ function createRustModeTransform(deps, options) {
37907
38190
  }
37908
38191
  const effectiveFloor = protectionFloorResolution.floor;
37909
38192
  const historianRun = deps.resolveHistorianRun?.();
38193
+ const observedSystemHash = sessionMeta.systemPromptHash ?? "";
38194
+ const rustSystemHash = state.baselineSystemHashOmitted && sessionMeta.cachedM0SystemHash === observedSystemHash ? "" : observedSystemHash;
37910
38195
  const passInputs = {
37911
38196
  now_ms: requestObservedAtMs,
37912
38197
  model_key: modelKey,
@@ -37928,7 +38213,7 @@ function createRustModeTransform(deps, options) {
37928
38213
  caveman_min_chars: deps.cavemanTextCompression?.minChars ?? 500,
37929
38214
  cache_ttl: sessionMeta.cacheTtl,
37930
38215
  is_subagent: sessionMeta.isSubagent,
37931
- system_prompt_hash: sessionMeta.systemPromptHash ?? "",
38216
+ system_prompt_hash: rustSystemHash,
37932
38217
  upgrade_state: readUpgradeState(deps.db, sessionId),
37933
38218
  tool_present: toolPresent,
37934
38219
  todo_tool_present: false,
@@ -38203,7 +38488,7 @@ function createRustModeTransform(deps, options) {
38203
38488
  modelKey: modelKey ?? null,
38204
38489
  providerId: model?.providerID ?? null,
38205
38490
  variant: deps.variantBySession?.get(sessionId),
38206
- systemPromptHash: sessionMeta.systemPromptHash ?? "",
38491
+ systemPromptHash: rustSystemHash,
38207
38492
  upgradeState: String(passInputs.upgrade_state ?? "")
38208
38493
  };
38209
38494
  let body = buildTransformBody({
@@ -38637,6 +38922,9 @@ function createRustModeTransform(deps, options) {
38637
38922
  state.ordinalContinuationBase = ordinalContinuationBase;
38638
38923
  }
38639
38924
  if (!stateSyncRetryBusy) {
38925
+ if (!state.initialized && !observedSystemHash) {
38926
+ state.baselineSystemHashOmitted = true;
38927
+ }
38640
38928
  state.initialized = true;
38641
38929
  state.seedPassPending = false;
38642
38930
  }
@@ -39425,6 +39713,9 @@ function createTransform(deps) {
39425
39713
  passOutcome.record("compaction-mode-transition-failure");
39426
39714
  sessionLog(sessionId, "compaction mode transition failed (retrying next pass):", error);
39427
39715
  }
39716
+ if (deps.client !== undefined && !compactionOff) {
39717
+ await primeCtxReduceSpawnPermission(deps.client, sessionId, spawnAgentFromMessages(messages));
39718
+ }
39428
39719
  if (deps.transformMode === "rust") {
39429
39720
  if (!rustModeTransform) {
39430
39721
  sessionLog(sessionId, "rust transform unavailable; using raw passthrough");
@@ -39757,7 +40048,12 @@ Historian previously failed ${historianFailureState.failureCount} time(s), so Ma
39757
40048
  const tTrigger = performance.now();
39758
40049
  try {
39759
40050
  const inMemoryTail = buildTriggerInMemoryTail(db, sessionId, extractInMemoryMessageViews(messages));
39760
- const triggerResult = checkCompartmentTrigger(db, sessionId, sessionMeta, boundaryUsageForProtectedTail, sessionMeta.lastContextPercentage, boundaryExecuteThreshold, deriveTriggerBudget2(boundaryContextLimit, boundaryExecuteThreshold), deps.clearReasoningAge, historianRun?.commitClusterTrigger ?? deps.commitClusterTrigger, undefined, boundaryContextLimit, inMemoryTail, taggerFloor, { providerID: resolvedProviderID });
40051
+ const triggerResult = checkCompartmentTrigger(db, sessionId, sessionMeta, boundaryUsageForProtectedTail, sessionMeta.lastContextPercentage, boundaryExecuteThreshold, deriveTriggerBudget2(boundaryContextLimit, boundaryExecuteThreshold), deps.clearReasoningAge, historianRun?.commitClusterTrigger ?? deps.commitClusterTrigger, undefined, boundaryContextLimit, inMemoryTail, taggerFloor, { providerID: resolvedProviderID }, {
40052
+ hardFold: false,
40053
+ force: contextUsageEarly.percentage >= forceMaterializationPercentage && (contextUsageEarly.percentage >= 95 || getEmergencyInputSample(db, sessionId) === 0),
40054
+ explicitFlush: deps.pendingMaterializationSessions.has(sessionId),
40055
+ publishedHistory: isCacheBusting
40056
+ });
39761
40057
  if (triggerResult.shouldFire) {
39762
40058
  sessionLog(sessionId, `compartment trigger: firing (reason=${triggerResult.reason})`);
39763
40059
  updateSessionMeta(db, sessionId, { compartmentInProgress: true });
@@ -41145,6 +41441,12 @@ function createSystemPromptHashHandler(deps) {
41145
41441
  sessionLog(sessionId, "system-prompt-hash session meta load failed:", error);
41146
41442
  }
41147
41443
  const isSubagentSession = sessionMetaEarly?.isSubagent === true;
41444
+ if (deps.client && ctxReduceSpawnPermissionReadNeeded(sessionId)) {
41445
+ const spawn = spawnAgentFromOpenCodeDb(sessionId);
41446
+ if (spawn.persisted) {
41447
+ await primeCtxReduceSpawnPermission(deps.client, sessionId, spawn.agent);
41448
+ }
41449
+ }
41148
41450
  const availability = resolveCtxReduceAvailability(sessionId);
41149
41451
  const ctxReduceCallable = availability.callable;
41150
41452
  const subagentReduceMode = isSubagentSession && ctxReduceCallable;
@@ -41990,7 +42292,7 @@ function createMagicContextHook(deps) {
41990
42292
  pauseEmbedDrain,
41991
42293
  getEmbedStatusText,
41992
42294
  sendNotification: async (sessionId, text, params) => {
41993
- await sendIgnoredMessage2(deps.client, sessionId, text, {
42295
+ await sendCommandResult2(deps.client, sessionId, text, {
41994
42296
  ...getLiveNotificationParams(sessionId, liveModelBySession, variantBySession, agentBySession, (deps.sampleDreamConfig?.() ?? deps.config).toast_duration_ms),
41995
42297
  ...params
41996
42298
  });
@@ -42050,6 +42352,7 @@ function createMagicContextHook(deps) {
42050
42352
  "<!-- magic-context: skip -->"
42051
42353
  ],
42052
42354
  internalChildSessions,
42355
+ client: deps.client,
42053
42356
  experimentalUserMemories: userMemoryCollectionEnabled2(deps.config.dreamer),
42054
42357
  experimentalTemporalAwareness: deps.config.temporal_awareness === true,
42055
42358
  experimentalCavemanTextCompression: deps.config.caveman_text_compression?.enabled === true
@@ -45728,9 +46031,33 @@ ${data.output?.output ?? ""}`
45728
46031
  var HIDDEN_HISTORIAN_AGENT = "historian";
45729
46032
  var HIDDEN_DREAMER_AGENT = "dreamer-classifier";
45730
46033
  var HIDDEN_CURATE_AGENT = DREAMER_AGENT;
46034
+ var READ_TOOLS = ["read", "grep", "glob"];
46035
+ var AGENT_TOOLS = {
46036
+ [HIDDEN_HISTORIAN_AGENT]: [],
46037
+ [HIDDEN_DREAMER_AGENT]: [],
46038
+ [HIDDEN_CURATE_AGENT]: ["ctx_memory", "ctx_memory_list"],
46039
+ [DREAMER_MEMORY_MAPPER_AGENT]: READ_TOOLS,
46040
+ [DREAMER_PRIMER_INVESTIGATOR_AGENT]: [...READ_TOOLS, "ctx_search"],
46041
+ [DREAMER_RETROSPECTIVE_AGENT]: ["ctx_search"]
46042
+ };
46043
+ var AGENT_STEPS = {
46044
+ [HIDDEN_CURATE_AGENT]: 150,
46045
+ [DREAMER_MEMORY_MAPPER_AGENT]: 60,
46046
+ [DREAMER_DOCS_AGENT]: 60,
46047
+ [DREAMER_PRIMER_INVESTIGATOR_AGENT]: 40,
46048
+ [DREAMER_RETROSPECTIVE_AGENT]: 40
46049
+ };
46050
+ function hiddenAgentFor(identity) {
46051
+ if (identity.kind === "dreamer-task" && identity.agent === DREAMER_DOCS_AGENT)
46052
+ return DREAMER_MEMORY_MAPPER_AGENT;
46053
+ return identity.kind === "dreamer-task" && AGENT_TOOLS[identity.agent] ? identity.agent : identity.kind === "dreamer-task" ? HIDDEN_DREAMER_AGENT : HIDDEN_HISTORIAN_AGENT;
46054
+ }
46055
+ function hiddenToolLoop(identity) {
46056
+ return identity.kind === "dreamer-task" && AGENT_STEPS[identity.agent] !== undefined;
46057
+ }
45731
46058
  async function registerHiddenChildAgents(agent) {
45732
46059
  await agent.transform((editor) => {
45733
- for (const id of [HIDDEN_HISTORIAN_AGENT, HIDDEN_DREAMER_AGENT, HIDDEN_CURATE_AGENT]) {
46060
+ for (const id of Object.keys(AGENT_TOOLS)) {
45734
46061
  editor.update(id, (config) => {
45735
46062
  config.system = "Magic Context hidden completion carrier.";
45736
46063
  config.description = "Internal Magic Context hidden completion carrier.";
@@ -45739,16 +46066,14 @@ async function registerHiddenChildAgents(agent) {
45739
46066
  config.request.settings = {};
45740
46067
  config.request.headers = {};
45741
46068
  config.request.body = {};
46069
+ config.steps = AGENT_STEPS[id];
45742
46070
  config.permissions = [
45743
46071
  { action: "*", resource: "*", effect: "deny" },
45744
- ...id === HIDDEN_CURATE_AGENT ? [
45745
- { action: "tool", resource: "ctx_memory", effect: "allow" },
45746
- {
45747
- action: "tool",
45748
- resource: "ctx_memory_list",
45749
- effect: "allow"
45750
- }
45751
- ] : []
46072
+ ...(AGENT_TOOLS[id] ?? []).map((tool) => ({
46073
+ action: tool,
46074
+ resource: "*",
46075
+ effect: "allow"
46076
+ }))
45752
46077
  ];
45753
46078
  });
45754
46079
  }
@@ -45793,15 +46118,21 @@ function calibratedParts(attempt) {
45793
46118
  class HiddenChildHook {
45794
46119
  childIDs = new Set;
45795
46120
  attempts = new Map;
46121
+ active = new Map;
45796
46122
  registerChild(sessionID) {
45797
46123
  this.childIDs.add(sessionID);
45798
46124
  }
45799
46125
  registerAttempt(marker, attempt) {
45800
46126
  this.registerChild(attempt.childSessionId);
46127
+ attempt.marker = marker;
45801
46128
  this.attempts.set(marker, attempt);
45802
46129
  }
45803
46130
  releaseAttempt(marker) {
46131
+ const attempt = this.attempts.get(marker);
45804
46132
  this.attempts.delete(marker);
46133
+ if (attempt && this.active.get(attempt.childSessionId) === attempt) {
46134
+ this.active.delete(attempt.childSessionId);
46135
+ }
45805
46136
  }
45806
46137
  owns(sessionID) {
45807
46138
  return this.childIDs.has(sessionID);
@@ -45812,19 +46143,43 @@ class HiddenChildHook {
45812
46143
  const raw = newestUserText(draft);
45813
46144
  const stripped = raw === undefined ? undefined : stripWellFormedLeadingTagPrefix(raw);
45814
46145
  const attempt = (raw !== undefined ? this.attempts.get(raw) : undefined) ?? (stripped && stripped !== raw ? this.attempts.get(stripped) : undefined);
45815
- if (!attempt || attempt.childSessionId !== draft.sessionID) {
46146
+ const current = this.active.get(draft.sessionID);
46147
+ const selected = attempt ?? current;
46148
+ if (!selected || selected.childSessionId !== draft.sessionID || attempt && current && current !== attempt) {
45816
46149
  throw new HiddenCompletionRefusal("hidden_prompt_unrecognized", "Refusing an unregistered prompt on a Magic Context hidden-run session", true);
45817
46150
  }
45818
- if (attempt.request.signal?.aborted) {
46151
+ if (selected.request.signal?.aborted) {
45819
46152
  throw new Error("Hidden completion prompt aborted");
45820
46153
  }
45821
- const system = typeof attempt.request.body.system === "string" ? attempt.request.body.system : attempt.identity.system;
46154
+ if (!selected.shaped) {
46155
+ if (!attempt)
46156
+ throw new HiddenCompletionRefusal("hidden_prompt_unrecognized", "Hidden child first step requires a registered marker", true);
46157
+ this.active.set(draft.sessionID, selected);
46158
+ }
46159
+ const steps = (selected.steps ?? 0) + 1;
46160
+ const cap = AGENT_STEPS[selected.identity.agent];
46161
+ if (cap !== undefined && steps > cap) {
46162
+ throw new Error(`Hidden agent exceeded its ${cap}-step limit`);
46163
+ }
46164
+ selected.steps = steps;
46165
+ const system = typeof selected.request.body.system === "string" ? selected.request.body.system : selected.identity.system;
45822
46166
  draft.system = [{ type: "text", text: system }];
45823
- draft.messages = [{ role: "user", content: calibratedParts(attempt) }];
45824
- draft.options = authoredOptions(attempt);
45825
- const dreamerTools = attempt.identity.agent === DREAMER_AGENT ? Object.fromEntries(["ctx_memory", "ctx_memory_list"].flatMap((id) => draft.tools[id] ? [[id, draft.tools[id]]] : [])) : {};
45826
- draft.tools = dreamerTools;
45827
- attempt.shaped = true;
46167
+ if (!selected.shaped) {
46168
+ draft.messages = [{ role: "user", content: calibratedParts(selected) }];
46169
+ } else {
46170
+ const first = draft.messages[0];
46171
+ const firstText = first && newestUserText({ ...draft, messages: [first] });
46172
+ const normalized = firstText === undefined ? undefined : stripWellFormedLeadingTagPrefix(firstText);
46173
+ if (normalized !== selected.marker) {
46174
+ throw new HiddenCompletionRefusal("hidden_prompt_unrecognized", "Hidden child history does not begin with this run's registered marker", true);
46175
+ }
46176
+ draft.messages[0] = { ...first, content: calibratedParts(selected) };
46177
+ }
46178
+ draft.options = authoredOptions(selected);
46179
+ const allowed = AGENT_TOOLS[hiddenAgentFor(selected.identity)] ?? [];
46180
+ draft.tools = Object.fromEntries(allowed.flatMap((id) => draft.tools[id] ? [[id, draft.tools[id]]] : []));
46181
+ selected.observedMessages = draft.messages;
46182
+ selected.shaped = true;
45828
46183
  return true;
45829
46184
  }
45830
46185
  }
@@ -45906,9 +46261,9 @@ function resolveOwnerHostService(owner, env = process.env, pid = process.pid) {
45906
46261
  }
45907
46262
  return own;
45908
46263
  }
45909
- async function removeHostSession(sessionID, owner, env = process.env) {
46264
+ async function removeHostSession(sessionID, owner, env = process.env, fetchSession = fetch) {
45910
46265
  const service = resolveOwnerHostService(owner, env);
45911
- const response = await fetch(`${service.url}/api/session/${encodeURIComponent(sessionID)}`, {
46266
+ const response = await fetchSession(`${service.url}/api/session/${encodeURIComponent(sessionID)}`, {
45912
46267
  method: "DELETE",
45913
46268
  headers: service.headers,
45914
46269
  signal: AbortSignal.timeout(60000)
@@ -46110,6 +46465,37 @@ function settledProviderError(row) {
46110
46465
  function successfulReusableAssistant(row) {
46111
46466
  return row !== undefined && (typeof row.data.finish === "string" || assistantOutcome(row) === "succeeded") && row.data.error === undefined && row.data.tokens !== undefined;
46112
46467
  }
46468
+ function toolLoopMessages(attempt) {
46469
+ const messages = attempt.observedMessages ?? [];
46470
+ const results = new Map;
46471
+ for (const message of messages) {
46472
+ if (message.role !== "tool")
46473
+ continue;
46474
+ for (const part of message.content) {
46475
+ if (part.type !== "tool-result" || typeof part.id !== "string")
46476
+ continue;
46477
+ const result = part.result;
46478
+ results.set(part.id, { status: result?.type === "error" ? "error" : "completed" });
46479
+ }
46480
+ }
46481
+ return messages.flatMap((message) => {
46482
+ if (message.role !== "assistant")
46483
+ return [];
46484
+ const parts = message.content.flatMap((part) => {
46485
+ if (part.type !== "tool-call" || typeof part.id !== "string" || typeof part.name !== "string")
46486
+ return [];
46487
+ const result = results.get(part.id);
46488
+ return [
46489
+ {
46490
+ type: "tool",
46491
+ tool: part.name,
46492
+ state: { status: result?.status ?? "pending", input: part.input }
46493
+ }
46494
+ ];
46495
+ });
46496
+ return parts.length ? [{ info: { role: "assistant" }, parts }] : [];
46497
+ });
46498
+ }
46113
46499
  function assistantText(row) {
46114
46500
  const text = (row.data.content ?? []).flatMap((part) => part.type === "text" && typeof part.text === "string" ? [part.text] : []).join("");
46115
46501
  return text.length > 0 ? text : null;
@@ -46361,7 +46747,7 @@ async function createV2HiddenCompletionExecutor(host, options) {
46361
46747
  }
46362
46748
  };
46363
46749
  return {
46364
- capabilities: { tools: false, harness: "opencode2" },
46750
+ capabilities: { tools: true, harness: "opencode2" },
46365
46751
  async open(identity) {
46366
46752
  const role = roleFor(identity);
46367
46753
  const releaseRole = await acquireRole(role);
@@ -46370,6 +46756,10 @@ async function createV2HiddenCompletionExecutor(host, options) {
46370
46756
  await options.ensureAgent?.();
46371
46757
  const head = await resolveHead(identity);
46372
46758
  let active = store.read().active[role];
46759
+ if (active && hiddenToolLoop(identity)) {
46760
+ retireChild(active, "fresh-tool-loop-run");
46761
+ active = undefined;
46762
+ }
46373
46763
  if (active && active.generation !== generation) {
46374
46764
  retireChild(active, "host-generation-changed");
46375
46765
  active = undefined;
@@ -46392,7 +46782,7 @@ async function createV2HiddenCompletionExecutor(host, options) {
46392
46782
  const title = roleTitle(role);
46393
46783
  const created = await host.create({
46394
46784
  title,
46395
- agent: roleAgent(role),
46785
+ agent: hiddenToolLoop(identity) ? hiddenAgentFor(identity) : roleAgent(role),
46396
46786
  model: {
46397
46787
  providerID: head.providerID,
46398
46788
  id: head.modelID,
@@ -46450,6 +46840,7 @@ async function createV2HiddenCompletionExecutor(host, options) {
46450
46840
  await switchChildModel(run, requested);
46451
46841
  const baseline = withReader(options.openReader, (reader) => reader.latestSequence(run.child.id));
46452
46842
  const marker = `mc:hidden:${crypto.randomUUID()}:${crypto.randomUUID()}`;
46843
+ run.completion = undefined;
46453
46844
  const attempt = {
46454
46845
  childSessionId: run.child.id,
46455
46846
  identity: run.identity,
@@ -46509,6 +46900,7 @@ async function createV2HiddenCompletionExecutor(host, options) {
46509
46900
  }
46510
46901
  run.completion = {
46511
46902
  text,
46903
+ ...hiddenToolLoop(run.identity) ? { messages: toolLoopMessages(attempt) } : {},
46512
46904
  reasoning: null,
46513
46905
  usage: reportedInput !== undefined || reportedOutput !== undefined ? {
46514
46906
  input: reportedInput ?? 0,
@@ -46553,7 +46945,9 @@ async function createV2HiddenCompletionExecutor(host, options) {
46553
46945
  return;
46554
46946
  try {
46555
46947
  const reusable = run.failed && !run.unsettledFailure;
46556
- if (!run.completion && (run.failed || !settlement.promptSettled) && !reusable) {
46948
+ if (hiddenToolLoop(run.identity)) {
46949
+ retire(run, settlement.promptSettled ? "tool-loop-settled" : "tool-loop-failed");
46950
+ } else if (!run.completion && (run.failed || !settlement.promptSettled) && !reusable) {
46557
46951
  retire(run, "hidden-run-failed");
46558
46952
  }
46559
46953
  } finally {
@@ -46831,6 +47225,17 @@ class V2StoreReader {
46831
47225
  range(sessionID, after, through) {
46832
47226
  return trackDecodeOperation("range", () => through <= after ? [] : this.all(sessionID, after, undefined, through));
46833
47227
  }
47228
+ spanRowStamps(sessionID, after, through) {
47229
+ if (!Number.isSafeInteger(after) || !Number.isSafeInteger(through))
47230
+ throw new Error("Invalid seq span");
47231
+ const rows = this.db.prepare(`SELECT seq, id, time_updated AS updated, length(CAST(data AS BLOB)) AS bytes
47232
+ FROM session_message WHERE session_id = ? AND seq > ? AND seq <= ?
47233
+ ORDER BY seq ASC`).all(sessionID, after, through);
47234
+ const stamps = new Map;
47235
+ for (const row of rows)
47236
+ stamps.set(row.seq, `${row.id}\x00${row.updated ?? ""}\x00${row.bytes ?? ""}`);
47237
+ return stamps;
47238
+ }
46834
47239
  rawRowsThrough(sessionID, throughSeq, limit) {
46835
47240
  return trackDecodeOperation("rawRowsThrough", () => {
46836
47241
  if (!Number.isSafeInteger(throughSeq))
@@ -47279,6 +47684,23 @@ async function warmModelLimitCacheFromCatalog(context, options = {}) {
47279
47684
 
47280
47685
  // src/v2/hooks/payload.ts
47281
47686
  var HEAD_IDS = ["__magic_context_v2_m0__", "__magic_context_v2_m1__"];
47687
+ var HOST_CONTENT_TYPES = new Set([
47688
+ "text",
47689
+ "media",
47690
+ "tool-call",
47691
+ "tool-result",
47692
+ "reasoning",
47693
+ "compaction",
47694
+ "effort"
47695
+ ]);
47696
+ function rejectContentPart(message, part, reason) {
47697
+ const type = typeof part.type === "string" ? part.type : "<missing>";
47698
+ const text = `v2 context omitted a content part the host would reject: type=${type} message=${String(message.info.id ?? "<head>")} reason=${reason}`;
47699
+ if (typeof message.info.sessionID === "string")
47700
+ sessionLog(message.info.sessionID, text);
47701
+ else
47702
+ log(text);
47703
+ }
47282
47704
  function isHostInstance(value) {
47283
47705
  if (!value || typeof value !== "object" || Array.isArray(value))
47284
47706
  return false;
@@ -47469,6 +47891,56 @@ function adaptPayload(draft, admittedIDs = new Set) {
47469
47891
  const part = candidate;
47470
47892
  const bridge = bridges.get(part) ?? (part.type === "tool" && typeof part.callID === "string" ? bridgesFor(message)?.get(part.callID) : undefined);
47471
47893
  if (!bridge) {
47894
+ if (part.type === "tool") {
47895
+ const state = part.state;
47896
+ if (typeof part.callID !== "string" || typeof part.tool !== "string" || !state || typeof state !== "object") {
47897
+ rejectContentPart(message, part, "tool has no call ID, name, or state");
47898
+ continue;
47899
+ }
47900
+ content.push({
47901
+ type: "tool-call",
47902
+ id: part.callID,
47903
+ name: part.tool,
47904
+ input: state.input
47905
+ });
47906
+ if (state.status === "completed" || state.status === "error") {
47907
+ following.push({
47908
+ role: "tool",
47909
+ content: [
47910
+ {
47911
+ type: "tool-result",
47912
+ id: part.callID,
47913
+ name: part.tool,
47914
+ result: {
47915
+ type: state.status === "error" ? "error" : "text",
47916
+ value: toolStateContent(state)
47917
+ }
47918
+ }
47919
+ ]
47920
+ });
47921
+ }
47922
+ continue;
47923
+ }
47924
+ if (part.type === "file") {
47925
+ const mime = part.mime;
47926
+ const url = part.url;
47927
+ const prefix = `data:${mime};base64,`;
47928
+ if (typeof mime !== "string" || !/^image\/(png|jpeg|gif|webp)$/.test(mime) || typeof url !== "string" || !url.startsWith(prefix)) {
47929
+ rejectContentPart(message, part, "file is not an inline supported image");
47930
+ continue;
47931
+ }
47932
+ const asset = hostMediaAsset(url.slice(prefix.length), mime);
47933
+ if (typeof asset === "string") {
47934
+ rejectContentPart(message, part, `host media unavailable: ${asset}`);
47935
+ continue;
47936
+ }
47937
+ content.push({ type: "media", media: asset });
47938
+ continue;
47939
+ }
47940
+ if (!HOST_CONTENT_TYPES.has(String(part.type))) {
47941
+ rejectContentPart(message, part, "unknown host content type");
47942
+ continue;
47943
+ }
47472
47944
  const { synthetic: _synthetic, ...clean } = part;
47473
47945
  const original = hostPartTypes.has(clean.type) && !containsHostInstance(clean) ? hostParts.get(contentKey(clean)) : undefined;
47474
47946
  content.push(original ?? clean);
@@ -47476,14 +47948,23 @@ function adaptPayload(draft, admittedIDs = new Set) {
47476
47948
  }
47477
47949
  const state = part.state;
47478
47950
  if (bridge.native) {
47479
- const sourceState = bridge.native.state && typeof bridge.native.state === "object" ? bridge.native.state : {};
47480
- const nextState = { ...sourceState, input: state.input };
47481
- if (sourceState.content !== undefined) {
47482
- nextState.content = state.output === bridge.output ? sourceState.content : [{ type: "text", text: state.output }];
47483
- } else {
47484
- nextState.output = state.output;
47951
+ const native = bridge.native;
47952
+ const callID = String(native.id ?? native.callID ?? part.callID);
47953
+ const name = String(native.name ?? native.tool ?? part.tool);
47954
+ content.push({ type: "tool-call", id: callID, name, input: state.input });
47955
+ if (state.status === "completed" || state.status === "error") {
47956
+ following.push({
47957
+ role: "tool",
47958
+ content: [
47959
+ {
47960
+ type: "tool-result",
47961
+ id: callID,
47962
+ name,
47963
+ result: { type: "text", value: state.output }
47964
+ }
47965
+ ]
47966
+ });
47485
47967
  }
47486
- content.push({ ...bridge.native, state: nextState });
47487
47968
  continue;
47488
47969
  }
47489
47970
  if (bridge.call)
@@ -47537,13 +48018,18 @@ class V2ContextRefusal extends Error {
47537
48018
  this.name = "V2ContextRefusal";
47538
48019
  }
47539
48020
  }
47540
- async function interruptBeforeProvider(session, sessionID) {
48021
+ var INTERRUPT_CONFIRMATION_TIMEOUT_MS = 2000;
48022
+ var systemTimers = {
48023
+ setTimeout: (callback, ms) => setTimeout(callback, ms),
48024
+ clearTimeout: (handle) => clearTimeout(handle)
48025
+ };
48026
+ async function interruptBeforeProvider(session, sessionID, timers = systemTimers) {
47541
48027
  let timer;
47542
48028
  try {
47543
48029
  const result = await Promise.race([
47544
48030
  session.interrupt({ sessionID }),
47545
48031
  new Promise((_, reject) => {
47546
- timer = setTimeout(() => reject(new Error("interrupt exceeded 2000 ms")), 2000);
48032
+ timer = timers.setTimeout(() => reject(new Error(`interrupt exceeded ${INTERRUPT_CONFIRMATION_TIMEOUT_MS} ms`)), INTERRUPT_CONFIRMATION_TIMEOUT_MS);
47547
48033
  })
47548
48034
  ]);
47549
48035
  if (result.interrupted !== true)
@@ -47551,10 +48037,80 @@ async function interruptBeforeProvider(session, sessionID) {
47551
48037
  } catch (cause) {
47552
48038
  throw new V2ContextRefusal(undefined, { cause });
47553
48039
  } finally {
47554
- clearTimeout(timer);
48040
+ if (timer !== undefined)
48041
+ timers.clearTimeout(timer);
47555
48042
  }
47556
48043
  }
47557
48044
 
48045
+ // src/v2/hooks/restore-rows.ts
48046
+ class RestoredRowCache {
48047
+ capacity;
48048
+ sessions = new Map;
48049
+ constructor(capacity = 16) {
48050
+ this.capacity = capacity;
48051
+ }
48052
+ rows(reader, sessionID, after, through) {
48053
+ if (through <= after)
48054
+ return [];
48055
+ const kept = this.sessions.get(sessionID) ?? new Map;
48056
+ const stamps = reader.spanRowStamps(sessionID, after, through);
48057
+ const runs = [];
48058
+ let previous = after;
48059
+ let open;
48060
+ for (const [seq, stamp] of stamps) {
48061
+ if (kept.get(seq)?.stamp === stamp) {
48062
+ open = undefined;
48063
+ } else if (open) {
48064
+ open.through = seq;
48065
+ } else {
48066
+ open = { after: previous, through: seq };
48067
+ runs.push(open);
48068
+ }
48069
+ previous = seq;
48070
+ }
48071
+ const fresh = new Map;
48072
+ for (const run of runs)
48073
+ for (const row of readPages(reader, sessionID, run.after, run.through))
48074
+ fresh.set(row.seq, row);
48075
+ const next = new Map;
48076
+ const rows = [];
48077
+ for (const [seq, stamp] of stamps) {
48078
+ const row = fresh.get(seq) ?? kept.get(seq)?.row;
48079
+ if (!row)
48080
+ continue;
48081
+ next.set(seq, { stamp, row });
48082
+ rows.push(row);
48083
+ }
48084
+ this.sessions.delete(sessionID);
48085
+ this.sessions.set(sessionID, next);
48086
+ while (this.sessions.size > this.capacity) {
48087
+ const oldest = this.sessions.keys().next().value;
48088
+ if (oldest === undefined)
48089
+ break;
48090
+ this.sessions.delete(oldest);
48091
+ }
48092
+ return structuredClone(rows);
48093
+ }
48094
+ forget(sessionID) {
48095
+ this.sessions.delete(sessionID);
48096
+ }
48097
+ clear() {
48098
+ this.sessions.clear();
48099
+ }
48100
+ }
48101
+ function readPages(reader, sessionID, after, through) {
48102
+ const rows = [];
48103
+ let cursor = after;
48104
+ while (cursor < through) {
48105
+ const page = reader.page(sessionID, { after: cursor, through, limit: 100 });
48106
+ rows.push(...page.rows);
48107
+ if (page.rows.length < 100 || page.cursor === undefined)
48108
+ break;
48109
+ cursor = page.cursor;
48110
+ }
48111
+ return rows;
48112
+ }
48113
+
47558
48114
  // src/v2/hooks/rpc-live-state.ts
47559
48115
  function createV2RpcLiveSessionState(overrides) {
47560
48116
  return Object.assign(createLiveSessionState(), overrides);
@@ -48078,6 +48634,7 @@ async function registerContext(context) {
48078
48634
  const historyRefreshSessions = new Set;
48079
48635
  const pendingMaterializationSessions = new Set;
48080
48636
  const lastHeuristicsTurnId = new Map;
48637
+ const restoredRows = new RestoredRowCache;
48081
48638
  const rawProviders = new Map;
48082
48639
  let passDuties;
48083
48640
  let toolDuties;
@@ -48238,6 +48795,7 @@ async function registerContext(context) {
48238
48795
  historyRefreshSessions.delete(sessionID);
48239
48796
  pendingMaterializationSessions.delete(sessionID);
48240
48797
  lastHeuristicsTurnId.delete(sessionID);
48798
+ restoredRows.forget(sessionID);
48241
48799
  systemPromptRefreshSessions.delete(sessionID);
48242
48800
  systemPrompt?.clearSession(sessionID);
48243
48801
  tagger.cleanup(sessionID);
@@ -48462,7 +49020,7 @@ async function registerContext(context) {
48462
49020
  const servedBoundary = boundaryID ? servedBoundaryRow(reader, draft.sessionID, boundaryID) : null;
48463
49021
  const boundary = servedBoundary?.seq ?? reader.sequenceForId(draft.sessionID, boundaryID) ?? (reader.earliestSequence(draft.sessionID) ?? 0) - 1;
48464
49022
  const present = new Set(draft.messages.map((message) => message.id));
48465
- const restored = reader.range(draft.sessionID, boundary, cut.seq).filter((row) => !present.has(row.id)).flatMap((row) => restoreRow(row, draft.model, hostUsesMediaAssets() ? {
49023
+ const restored = restoredRows.rows(reader, draft.sessionID, boundary, cut.seq).filter((row) => !present.has(row.id)).flatMap((row) => restoreRow(row, draft.model, hostUsesMediaAssets() ? {
48466
49024
  asset: hostMediaAsset,
48467
49025
  unavailable: (detail) => sessionLog(draft.sessionID, `v2 restore: attachment replaced by a note row=${detail.rowID} name=${JSON.stringify(detail.name ?? null)} mediaType=${detail.mediaType} reason=${JSON.stringify(detail.reason)}`)
48468
49026
  } : undefined));
@@ -48615,6 +49173,7 @@ ${baseline}
48615
49173
  for (const release of rawProviders.values())
48616
49174
  release();
48617
49175
  rawProviders.clear();
49176
+ restoredRows.clear();
48618
49177
  }
48619
49178
  };
48620
49179
  }
@@ -48641,6 +49200,9 @@ function packageInfo() {
48641
49200
  directory = parent;
48642
49201
  }
48643
49202
  }
49203
+ function formatUpdateAvailableMessage(latest, current) {
49204
+ return `Magic Context ${latest} is available (running ${current}). To install it, open /plugins, select Magic Context and press ctrl+u, or run \`opencode plugin update\`. A version-pinned plugin entry must be changed in your OpenCode config instead.`;
49205
+ }
48644
49206
  function startUpdateChecks(context, check = (signal) => {
48645
49207
  return packageInfo().development ? Promise.resolve(null) : getLatestVersion("latest", { signal });
48646
49208
  }) {
@@ -48655,10 +49217,11 @@ function startUpdateChecks(context, check = (signal) => {
48655
49217
  continue;
48656
49218
  await context.storage.set("version-check-at", Date.now());
48657
49219
  const latest = await check(controller.signal);
48658
- const comparison = latest ? compareSemverCore(latest, packageInfo().version) : null;
48659
- if (!controller.signal.aborted && comparison !== null && comparison > 0) {
49220
+ const current = packageInfo().version;
49221
+ const comparison = latest ? compareSemverCore(latest, current) : null;
49222
+ if (latest && !controller.signal.aborted && comparison !== null && comparison > 0) {
48660
49223
  pushNotification2("toast", {
48661
- message: `Magic Context ${latest} is available. Update the plugin to install it.`,
49224
+ message: formatUpdateAvailableMessage(latest, current),
48662
49225
  variant: "info"
48663
49226
  });
48664
49227
  }
@@ -48753,7 +49316,7 @@ var server = async (ctx) => {
48753
49316
  if (hasBannerEntries)
48754
49317
  setTimeout(async () => {
48755
49318
  try {
48756
- const { sendStatusNotification } = await import("./send-session-notification-f6gwkesy.js");
49319
+ const { sendStatusNotification } = await import("./send-session-notification-e28r4xx2.js");
48757
49320
  const clientWithSessions = ctx.client;
48758
49321
  const sessions = await Promise.resolve(clientWithSessions.session?.list?.()).catch(() => null);
48759
49322
  const sessionList = Array.isArray(sessions) ? sessions : sessions?.data;
@@ -48770,7 +49333,7 @@ var server = async (ctx) => {
48770
49333
  log(`[magic-context] opencode_db_missing path=${openCodeDbResolution.path} source=${openCodeDbResolution.source}`);
48771
49334
  setTimeout(async () => {
48772
49335
  try {
48773
- const { sendStatusNotification } = await import("./send-session-notification-f6gwkesy.js");
49336
+ const { sendStatusNotification } = await import("./send-session-notification-e28r4xx2.js");
48774
49337
  const clientWithSessions = ctx.client;
48775
49338
  const sessions = await Promise.resolve(clientWithSessions.session?.list?.()).catch(() => null);
48776
49339
  const sessionList = Array.isArray(sessions) ? sessions : sessions?.data;
@@ -49037,12 +49600,12 @@ var server = async (ctx) => {
49037
49600
  {
49038
49601
  const fence = getSchemaFenceRejection();
49039
49602
  if (fence) {
49040
- import("./conflict-warning-hook-t2vb0wnx.js").then(({ sendSchemaFenceWarning }) => sendSchemaFenceWarning(ctx.client, ctx.directory, fence));
49603
+ import("./conflict-warning-hook-hyk9y29x.js").then(({ sendSchemaFenceWarning }) => sendSchemaFenceWarning(ctx.client, ctx.directory, fence));
49041
49604
  }
49042
49605
  }
49043
49606
  const serverUrl = ctx.serverUrl;
49044
49607
  const serverUrlStr = serverUrl instanceof URL ? serverUrl.toString().replace(/\/$/, "") : typeof serverUrl === "string" ? serverUrl.replace(/\/$/, "") : undefined;
49045
- import("./send-session-notification-f6gwkesy.js").then(({ setNotificationServerUrl }) => {
49608
+ import("./send-session-notification-e28r4xx2.js").then(({ setNotificationServerUrl }) => {
49046
49609
  setNotificationServerUrl(serverUrlStr);
49047
49610
  });
49048
49611
  if (conflictResult?.hasConflict) {
@@ -49056,7 +49619,7 @@ var server = async (ctx) => {
49056
49619
  }
49057
49620
  if (pluginConfig.enabled && !conflictResult?.hasConflict) {
49058
49621
  setTimeout(() => {
49059
- import("./announcement-8mgn61fw.js").then(({
49622
+ import("./announcement-1a8bvswd.js").then(({
49060
49623
  shouldShowAnnouncement,
49061
49624
  ANNOUNCEMENT_VERSION,
49062
49625
  ANNOUNCEMENT_FEATURES,
@@ -49065,7 +49628,7 @@ var server = async (ctx) => {
49065
49628
  }) => {
49066
49629
  if (!shouldShowAnnouncement())
49067
49630
  return;
49068
- return import("./conflict-warning-hook-t2vb0wnx.js").then(({ sendStartupAnnouncement }) => sendStartupAnnouncement(ctx.client, ctx.directory, ANNOUNCEMENT_VERSION, ANNOUNCEMENT_FEATURES, ANNOUNCEMENT_FOOTER, markAnnouncementSeen));
49631
+ return import("./conflict-warning-hook-hyk9y29x.js").then(({ sendStartupAnnouncement }) => sendStartupAnnouncement(ctx.client, ctx.directory, ANNOUNCEMENT_VERSION, ANNOUNCEMENT_FEATURES, ANNOUNCEMENT_FOOTER, markAnnouncementSeen));
49069
49632
  }).catch(() => {});
49070
49633
  }, 8000);
49071
49634
  }
@@ -49138,9 +49701,7 @@ var server = async (ctx) => {
49138
49701
  const provId = typed.model?.providerID;
49139
49702
  const modId = typed.model?.modelID;
49140
49703
  const agent = typed.agent;
49141
- if (provId && modId && agent) {
49142
- lastChatContext = { providerID: provId, modelID: modId, agentName: agent };
49143
- }
49704
+ lastChatContext = provId && modId ? { providerID: provId, modelID: modId, agentName: agent || "default" } : null;
49144
49705
  await magicContextRuntime.magicContext?.["chat.message"]?.(input, output);
49145
49706
  },
49146
49707
  "tool.definition": async (input, output) => {