@sema-agent/core 5.44.0 → 5.46.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (79) hide show
  1. package/CHANGELOG.md +109 -0
  2. package/dist/agents/subagent.d.ts +3 -1
  3. package/dist/agents/subagent.js +1 -1
  4. package/dist/brain/reasoning.d.ts +50 -4
  5. package/dist/brain/reasoning.js +28 -7
  6. package/dist/brain/request-params.d.ts +0 -12
  7. package/dist/brain/request-params.js +1 -1
  8. package/dist/core/checkpoint-store.d.ts +12 -0
  9. package/dist/core/governance-codes.js +1 -0
  10. package/dist/core/hooks.d.ts +9 -2
  11. package/dist/core/hooks.js +6 -5
  12. package/dist/core/memory-engine/content-origin.d.ts +9 -4
  13. package/dist/core/memory-engine/delegation-provenance.d.ts +12 -7
  14. package/dist/core/memory-engine/engine.d.ts +50 -3
  15. package/dist/core/memory-engine/engine.js +194 -32
  16. package/dist/core/memory-engine/export-bundle.d.ts +10 -1
  17. package/dist/core/memory-engine/export-bundle.js +21 -0
  18. package/dist/core/memory-engine/file-backend.d.ts +33 -4
  19. package/dist/core/memory-engine/file-backend.js +165 -39
  20. package/dist/core/memory-engine/frontmatter.d.ts +42 -1
  21. package/dist/core/memory-engine/frontmatter.js +141 -1
  22. package/dist/core/memory-engine/header-hints.d.ts +17 -0
  23. package/dist/core/memory-engine/header-hints.js +6 -0
  24. package/dist/core/memory-engine/index.d.ts +4 -3
  25. package/dist/core/memory-engine/index.js +3 -2
  26. package/dist/core/memory-engine/layout.d.ts +25 -2
  27. package/dist/core/memory-engine/layout.js +25 -12
  28. package/dist/core/memory-engine/memory-backend-contract.js +65 -0
  29. package/dist/core/memory-engine/sync-client.d.ts +1 -1
  30. package/dist/core/memory-engine/sync-client.js +33 -1
  31. package/dist/core/memory-engine/tools.d.ts +7 -0
  32. package/dist/core/memory-engine/tools.js +3 -0
  33. package/dist/core/memory-engine/types.d.ts +75 -1
  34. package/dist/core/memory-engine/types.js +1 -1
  35. package/dist/core/reminder-mint.d.ts +70 -0
  36. package/dist/core/reminder-mint.js +25 -0
  37. package/dist/core/runner/assemble-result.d.ts +5 -0
  38. package/dist/core/runner/assemble-result.js +1 -1
  39. package/dist/core/runner/git-status-frame.d.ts +3 -14
  40. package/dist/core/runner/git-status-frame.js +39 -14
  41. package/dist/core/runner/prepare-config-doors.d.ts +10 -0
  42. package/dist/core/runner/prepare-config-doors.js +32 -0
  43. package/dist/core/runner/prepare-hands-readface.d.ts +5 -11
  44. package/dist/core/runner/prepare-hands-readface.js +26 -0
  45. package/dist/core/runner/prepare-memory.d.ts +11 -0
  46. package/dist/core/runner/prepare-memory.js +12 -10
  47. package/dist/core/runner/prepare-task.d.ts +25 -2
  48. package/dist/core/runner/prepare-task.js +71 -14
  49. package/dist/core/runner/runtask.js +82 -72
  50. package/dist/core/side-query.d.ts +11 -1
  51. package/dist/core/side-query.js +3 -0
  52. package/dist/core/trace.d.ts +17 -2
  53. package/dist/core/types.d.ts +119 -8
  54. package/dist/engine/harness/types.d.ts +46 -1
  55. package/dist/engine/harness/types.js +11 -0
  56. package/dist/engine/session/import-validate.js +6 -1
  57. package/dist/engine/session/session.d.ts +20 -0
  58. package/dist/engine/session/session.js +26 -1
  59. package/dist/index.d.ts +2 -1
  60. package/dist/index.js +2 -1
  61. package/dist/orchestration/run-workflow-tool.d.ts +16 -0
  62. package/dist/orchestration/run-workflow-tool.js +23 -3
  63. package/dist/orchestration/workflow-governance.d.ts +8 -1
  64. package/dist/prompt-assembly/epoch.js +2 -0
  65. package/dist/prompt-assembly/types.d.ts +6 -0
  66. package/dist/prompts/default.d.ts +13 -1
  67. package/dist/prompts/default.js +5 -1
  68. package/dist/tools/fs/fs-bash.d.ts +4 -0
  69. package/dist/tools/fs/fs-bash.js +1 -1
  70. package/dist/tools/fs/fs-read.d.ts +1 -1
  71. package/dist/tools/fs/fs-read.js +8 -7
  72. package/dist/tools/fs/fs-shared.d.ts +10 -4
  73. package/dist/tools/fs/fs-shared.js +6 -3
  74. package/dist/tools/fs/gh-rate-limit.d.ts +4 -1
  75. package/dist/tools/fs/gh-rate-limit.js +3 -2
  76. package/dist/tools/fs/index.d.ts +10 -2
  77. package/dist/tools/fs/index.js +2 -1
  78. package/package.json +1 -1
  79. package/test/export-surface.snapshot.json +12 -1
@@ -142,6 +142,11 @@ export interface Prepared {
142
142
  * the `Session` contract instead. */
143
143
  session: StoredSession;
144
144
  sessionId: string;
145
+ /** design/319 (A ticket) — the session's reminder provenance mark this run mints under (adopted
146
+ * through the prepare adoption ladder: checkpoint seed → trusted fork channel → session entry →
147
+ * fresh mint). Every engine-authored `<system-reminder>` open tag in the run carries it, and the
148
+ * system prompt's Harness declaration names it. Always present on a completed prepare. */
149
+ reminderMark: string;
145
150
  /** The ISOLATION-AWARE working-tree root for this task (a worktree's cwd when `isolation: "worktree"`, else
146
151
  * `deps.rootPath ?? executionEnv.cwd`) — the same value the hands/LSP/policy/restore use. The Runner's
147
152
  * rewind/snapshot path MUST key off THIS, not `deps.rootPath`, or a worktree-isolated turn snapshots the base
@@ -414,8 +419,13 @@ export interface Prepared {
414
419
  polluted: () => {
415
420
  at: number;
416
421
  reason: string;
422
+ cause?: import("../memory-engine/types.js").MemoryOriginCause;
417
423
  } | undefined;
418
- markPolluted: (reason: string) => void;
424
+ /** design/336 §2.2 `cause` is the structured mechanical fact the mark records (and the
425
+ * origin marker minted off it carries): `"observed"` for a witnessed external event,
426
+ * `"static"` for the capability over-approximation, `"derived"` for recall-taint. Absent
427
+ * folds to `"observed"` at mint time (the honest floor). */
428
+ markPolluted: (reason: string, cause?: import("../memory-engine/types.js").MemoryOriginCause) => void;
419
429
  };
420
430
  /** design/178 §3 — the task's content-safety config (normalized memory spec): the allowlist for
421
431
  * UNDECLARED tools and the strict execution-class upgrade. Consumed by the tool wrap only. */
@@ -1092,7 +1102,9 @@ export interface RunInternals {
1092
1102
  * it); `contentSafety` is the chain's FROZEN classification snapshot — the child may narrow it
1093
1103
  * with its own config, never widen (design/180 A-2). Trusted internals chain only, same posture as
1094
1104
  * {@link inheritedGate}. Absent ⇒ the child records nothing (its deliveries then read `unknown`,
1095
- * and every judgment falls back to the static floor — fail-closed by construction).
1105
+ * and every judgment falls back to the static floor — fail-closed by construction; whether the
1106
+ * floor's verdict MARKS the judging session follows that run's deployment evidence standard,
1107
+ * {@link RunnerDeps.memoryDelegationEvidence}).
1096
1108
  */
1097
1109
  delegationProvenance?: {
1098
1110
  ref: {
@@ -1165,6 +1177,17 @@ export interface RunInternals {
1165
1177
  * `TaskSpec` field — the untrusted-caller surface), mirrors `inheritedManifestScope`.
1166
1178
  */
1167
1179
  insideFork?: boolean;
1180
+ /**
1181
+ * design/319 (A ticket) — the PARENT's reminder provenance mark, set ONLY by the Agent tool's
1182
+ * fork route on the child it spawns ("one declaration, one mark": a fork runs under the parent's
1183
+ * byte-identical system-prompt declaration, so its own engine mints must carry the PARENT's mark;
1184
+ * a spawn/clone context mints its own). Verified through the mint home's verify port at adoption
1185
+ * (`isValidReminderMark` — an unrecognized value re-mints, fail-safe); the forked SESSION's own
1186
+ * `reminder_mark` entry is the primary carrier (a store fork copies committed history), this
1187
+ * channel is the in-process belt over it. TRUSTED run-scoped channel (NOT a {@link TaskSpec}
1188
+ * field), mirroring `insideFork`.
1189
+ */
1190
+ reminderMark?: string;
1168
1191
  /**
1169
1192
  * RB-204 P1 (codex review) — set UNCONDITIONALLY by every core spawn path (`createSubagentTool`'s
1170
1193
  * `childInternals` — shared by all four spawn legs sync/steer/background/fork, its persisted
@@ -26,6 +26,7 @@ import { findAdmittingRule, suggestRulesForCommand } from "../permission-rule-mo
26
26
  import { ActiveSkillScope, createActiveSkillScopePolicy } from "./active-skill-scope.js";
27
27
  import { CHANGED_FILES_MTIME_EPS_MS, fenceMcpServerInstructions, renderAgentListingDelta } from "./turn-attachments.js";
28
28
  import { inlineUntrusted } from "../untrusted-text.js";
29
+ import { isValidReminderMark, mintReminderMark, reminderMarkDeclaration } from "../reminder-mint.js";
29
30
  import { policyAskClassOf } from "../ask-class.js";
30
31
  import { emitTrace } from "../trace.js";
31
32
  import { createSessionRulePolicy, PATH_CONFINABLE_WRITE_TOOLS } from "./session-rule-policy.js";
@@ -333,7 +334,7 @@ function cwdConflictsRestoreError(requestedCwd) {
333
334
  export async function prepareTask(spec, deps, sessions, resume, internals, runnerSelf) {
334
335
  const doors = prepareConfigDoors({ spec, deps, sessions, resume, internals });
335
336
  spec = doors.spec;
336
- const { toolFaceSnapshot, promptProfile, lockedPreflight, resolvedInteractionPosture, resolvedRole, model, thinking, compModel, fableMitigations, usageWindows, brainCallGuardrailRef, brainCallGuardrailMs } = doors;
337
+ const { toolFaceSnapshot, promptProfile, lockedPreflight, resolvedInteractionPosture, resolvedRole, model, thinking, compModel, fableMitigations, memoryDelegationEvidence, memoryProvenance, usageWindows, brainCallGuardrailRef, brainCallGuardrailMs } = doors;
337
338
  announceToolModelGate(deps.onNotice, model.id, doors.modelGate);
338
339
  const { toolEffects, egressTools, irreversibleTools, irreversibilityTier, axisExplicitNegatives, reversibilityProbes, ownToolNames } = prepareSafetyScan({ spec, deps });
339
340
  let shellGatedBash = false;
@@ -351,6 +352,30 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
351
352
  const taskScope = internals?.registryScope ?? spec.principal ?? "default";
352
353
  internals?.peerSelfRef?.addAxis("s", sessionId);
353
354
  internals?.peerSelfRef?.addAxis("t", hostTaskId);
355
+ const sessionReminderMark = await (async () => {
356
+ try {
357
+ return await session.getReminderMark();
358
+ }
359
+ catch (err) {
360
+ deps.onError?.(err instanceof Error ? err : new Error(String(err)), { phase: "config", sessionId });
361
+ return undefined;
362
+ }
363
+ })();
364
+ const reminderMark = isValidReminderMark(resume?.seed.reminderMark)
365
+ ? resume.seed.reminderMark
366
+ : isValidReminderMark(internals?.reminderMark)
367
+ ? internals.reminderMark
368
+ : isValidReminderMark(sessionReminderMark)
369
+ ? sessionReminderMark
370
+ : mintReminderMark();
371
+ if (reminderMark !== sessionReminderMark) {
372
+ try {
373
+ await session.appendReminderMark(reminderMark);
374
+ }
375
+ catch (err) {
376
+ deps.onError?.(err instanceof Error ? err : new Error(String(err)), { phase: "config", sessionId });
377
+ }
378
+ }
354
379
  const offloadScope = spec.principal ?? "default";
355
380
  if (internals?.registryScope !== undefined && internals.registryScope !== offloadScope) {
356
381
  deps.onError?.(new Error(`offload/tool-result namespace note: this run mounts in registry domain "${internals.registryScope}" but its offloaded tool results live under the TRUST identity "${offloadScope}" (principal${spec.principal === undefined ? " absent → default" : ""}). Before 2.13.0 the registry domain named this namespace too; if a deployment used registryScope as its ref-tenancy boundary, that boundary is now the principal — pass one, or read refs under "${offloadScope}".`), { phase: "config", sessionId });
@@ -797,6 +822,7 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
797
822
  ...(spec.memoryPersistenceCapable !== undefined ? { memoryPersistenceCapable: spec.memoryPersistenceCapable } : {}),
798
823
  getApiKeyAndHeaders: spec.getApiKeyAndHeaders,
799
824
  parentCwd: taskRootFinal,
825
+ reminderMark,
800
826
  ...(centerAdoption !== undefined ? { centerArtifactDigest: centerAdoption.artifact.artifactDigest } : {}),
801
827
  ...(centerAdoption?.sourceRevision !== undefined ? { centerSourceRevision: centerAdoption.sourceRevision } : {}),
802
828
  activeSkillScope: () => skillScope.active(),
@@ -983,6 +1009,7 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
983
1009
  sourceTaskId: hostTaskId,
984
1010
  parentModel: () => harnessRef.current?.getModel(),
985
1011
  ...(spec.getApiKeyAndHeaders !== undefined ? { parentGetApiKeyAndHeaders: spec.getApiKeyAndHeaders } : {}),
1012
+ ...(frozenOnAsk !== undefined ? { parentOnAsk: frozenOnAsk } : {}),
986
1013
  principal: spec.principal,
987
1014
  oneShot: spec.oneShot,
988
1015
  ...(resolvedInteractionPosture !== undefined ? { parentInteractionPosture: resolvedInteractionPosture } : {}),
@@ -1198,7 +1225,7 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
1198
1225
  foldProtocolAxes(a2a.toolAxes, "A2A");
1199
1226
  const callIssuedAtRef = {};
1200
1227
  const memoryWriteGateRef = {};
1201
- const handsReadFaceInput = { handsEnabled, executionEnv, taskRootFinal, rebaseRestoredPath, resume, session, sessionId, hostTaskId, taskScope, fullShellReachable, effectiveShellGate, toolFaceSnapshot, model, spec, deps, internals, memoryWriteGateRef, firstPartyOffload, tools, egressTools, irreversibilityTier, irreversibleTools, reversibilityProbes };
1228
+ const handsReadFaceInput = { handsEnabled, executionEnv, taskRootFinal, rebaseRestoredPath, resume, session, sessionId, hostTaskId, taskScope, fullShellReachable, effectiveShellGate, toolFaceSnapshot, model, spec, deps, internals, memoryWriteGateRef, firstPartyOffload, tools, egressTools, irreversibilityTier, irreversibleTools, reversibilityProbes, reminderMark };
1202
1229
  const handsReadFace = handsEnabled ? await prepareHandsMount(handsReadFaceInput) : resolveHandsLessReadFace(handsReadFaceInput);
1203
1230
  const { readFileStateForCheckpoint, seedContextFiles, handsCwdRef, workspaceStateSettle, wsSnapshot, rebaseWsPath, backgroundTaskToolsActive, additionalRootsCanonical, additionalReadRootsCanonical, attachmentRootCanonical, readDenyMatcher } = handsReadFace;
1204
1231
  resolvedReadFace = handsReadFace.resolvedReadFace;
@@ -1439,9 +1466,11 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
1439
1466
  sessionId,
1440
1467
  taskRootPath: taskRootFinal,
1441
1468
  memoryWriteGateRef,
1469
+ reminderMark,
1442
1470
  writeToolsMounted: tools.some((t) => t.name === "Write") &&
1443
1471
  !(toolFaceSnapshot.exclude?.includes("Write") ?? false) &&
1444
1472
  !(handsEnabled && isRemoteExecutionEnv(executionEnv) && spec.memoryPersistenceCapable !== true),
1473
+ memoryProvenance,
1445
1474
  memoryPersistenceDeclared: spec.memoryPersistenceCapable,
1446
1475
  rosterCanPersist: spec.memoryPersistenceCapable ??
1447
1476
  tools.some((t) => {
@@ -1644,6 +1673,7 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
1644
1673
  policyEnabled: promptPolicyEnabled,
1645
1674
  hooksEnabled: promptHooksEnabled,
1646
1675
  isolationEnabled: isIsolated(executionEnv),
1676
+ reminderMark,
1647
1677
  readFaceOpen: resolvedReadFace === "open",
1648
1678
  orchestrationEnabled: selfOrchestrationActive,
1649
1679
  orchestrationDeferred: selfOrchestrationActive && (toolFaceSnapshot.defer?.includes("Workflow") ?? false),
@@ -1855,6 +1885,8 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
1855
1885
  const delegationProvenanceChannel = internals?.delegationProvenance;
1856
1886
  if (memoryEngineSession !== undefined || delegationProvenanceChannel !== undefined) {
1857
1887
  const pollution = memoryEngineSession?.pollution;
1888
+ const delegationEvidenceAttestedOnly = memoryDelegationEvidence === "attested-only";
1889
+ let staticMarkWaiverAnnounced = false;
1858
1890
  const effectiveSafety = narrowContentSafety(delegationProvenanceChannel?.contentSafety, memoryEngineSession?.contentSafety);
1859
1891
  const trustedTools = effectiveSafety.trustedTools;
1860
1892
  const execIsExternalContent = effectiveSafety.execIsExternalContent;
@@ -1902,9 +1934,9 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
1902
1934
  continue;
1903
1935
  }
1904
1936
  const inner = t.execute.bind(t);
1905
- const mark = (reason) => {
1937
+ const mark = (reason, cause) => {
1906
1938
  try {
1907
- pollution?.markPolluted(reason);
1939
+ pollution?.markPolluted(reason, cause);
1908
1940
  }
1909
1941
  catch {
1910
1942
  }
@@ -1913,7 +1945,7 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
1913
1945
  ...t,
1914
1946
  execute: async (toolCallId, params, signal, onUpdate) => {
1915
1947
  if (pollutes) {
1916
- mark(`tool "${t.name}" (${origin} content class) was invoked in this session`);
1948
+ mark(`tool "${t.name}" (${origin} content class) was invoked in this session`, "observed");
1917
1949
  recordExternal();
1918
1950
  }
1919
1951
  if (!isDelegation)
@@ -1929,13 +1961,33 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
1929
1961
  const att = readCardAttestation(result?.details);
1930
1962
  if (att === "external") {
1931
1963
  mark(`tool "${t.name}" returned the output of a delegated agent that invoked an external-content-class tool at runtime` +
1932
- (typeof requested === "string" ? ` (subagent_type "${requested}")` : ""));
1964
+ (typeof requested === "string" ? ` (subagent_type "${requested}")` : ""), "observed");
1933
1965
  recordExternal();
1934
1966
  }
1935
1967
  else if (att !== "clean") {
1936
1968
  if (external) {
1937
- mark(`tool "${t.name}" returned the output of a delegated agent whose tool face can reach external content` +
1938
- (typeof requested === "string" ? ` (subagent_type "${requested}")` : " (no subagent_type named — classified fail-closed)"));
1969
+ const staticFaceReason = `tool "${t.name}" returned the output of a delegated agent whose tool face can reach external content` +
1970
+ (typeof requested === "string" ? ` (subagent_type "${requested}")` : " (no subagent_type named — classified fail-closed)");
1971
+ if (!delegationEvidenceAttestedOnly) {
1972
+ mark(staticFaceReason, "static");
1973
+ }
1974
+ else if (pollution !== undefined && !staticMarkWaiverAnnounced) {
1975
+ staticMarkWaiverAnnounced = true;
1976
+ const waivedReason = inlineUntrusted(staticFaceReason, 200);
1977
+ deliverEngineNotice(deps.onNotice, {
1978
+ code: "memory.delegation_static_mark_waived",
1979
+ message: `Delegation static-face pollution mark waived: ${waivedReason}. The deployment configured ` +
1980
+ `memoryDelegationEvidence="attested-only", so a static tool-face verdict alone does not mark this ` +
1981
+ `session's memory polluted; a delivered "external" attestation and a direct polluting-class ` +
1982
+ `invocation still mark, and on a provenance-armed chain this delegation still records as ` +
1983
+ `incomplete. At most one notice per prepared task leg.`,
1984
+ detail: {
1985
+ reason: waivedReason,
1986
+ ...(typeof requested === "string" ? { subagentType: inlineUntrusted(requested, 120) } : {}),
1987
+ sessionId,
1988
+ },
1989
+ });
1990
+ }
1939
1991
  }
1940
1992
  recordIncomplete();
1941
1993
  }
@@ -2021,6 +2073,9 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
2021
2073
  centerAdoption = undefined;
2022
2074
  }
2023
2075
  let systemPrompt = assembled.systemPrompt;
2076
+ if (!systemPrompt.includes(reminderMarkDeclaration(reminderMark))) {
2077
+ deps.onError?.(new Error("reminder-mark declaration missing from the assembled system prompt: this run's PromptProvider owns the prompt and did not render the mark declaration, so engine <system-reminder> tags carry a mark the model is never told about (the impersonation defense is inactive for this deployment). Render `reminderMarkDeclaration(ctx.reminderMark)` (exported; the value rides StablePromptContext.reminderMark) in the provider, or accept the disclosure."), { phase: "config", sessionId });
2078
+ }
2024
2079
  const renderWithDate = assembled.renderWithDate
2025
2080
  ? (date) => {
2026
2081
  systemPrompt = assembled.renderWithDate(date);
@@ -3384,6 +3439,7 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
3384
3439
  consolidationNotes: undefined,
3385
3440
  readFileState: readFileStateForCheckpoint ? [...readFileStateForCheckpoint.entries()] : undefined,
3386
3441
  readFace: faceCheckpointSection(),
3442
+ reminderMark,
3387
3443
  repairBundle: repairBundleForCheckpoint(parkedSpendMicroUsd),
3388
3444
  workspaceHandle,
3389
3445
  handsCwd: handsCwdRef?.current,
@@ -4047,7 +4103,7 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
4047
4103
  if (notifyPermissionDenied) {
4048
4104
  await notifyPermissionDenied({ toolName: e.toolName, input: cloneObserverInput(e.input), toolCallId: e.toolCallId, reason: complianceDeny, source: "safety", identity: hookIdentity });
4049
4105
  }
4050
- return { block: true, reason: formatHookFeedback(complianceDeny), preToolContext: [] };
4106
+ return { block: true, reason: formatHookFeedback(complianceDeny, reminderMark), preToolContext: [] };
4051
4107
  }
4052
4108
  }
4053
4109
  if (planModeRef.active && (toolEffects.get(e.toolName) ?? "write") !== "read") {
@@ -4060,7 +4116,7 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
4060
4116
  }
4061
4117
  return {
4062
4118
  block: true,
4063
- reason: formatHookFeedback(planDenyReason),
4119
+ reason: formatHookFeedback(planDenyReason, reminderMark),
4064
4120
  preToolContext: [],
4065
4121
  };
4066
4122
  }
@@ -4070,6 +4126,7 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
4070
4126
  onNotifyError: (f) => emitTrace(deps.tracer, () => ({ kind: "observer.notify_failed", version: 1, taskId: spec.taskId ?? sessionId, site: f.site, message: f.error.message, ts: Date.now() })),
4071
4127
  event: e,
4072
4128
  identity: hookIdentity,
4129
+ reminderMark,
4073
4130
  preToolUse: ownGatePreToolUse,
4074
4131
  ...(hookEnvFace !== undefined ? { hookEnv: hookEnvFace } : {}),
4075
4132
  adjudicate,
@@ -4186,7 +4243,7 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
4186
4243
  details: clonedDetails,
4187
4244
  }, { toolCallId: e.toolCallId, toolName: e.toolName, ...(hookEnvFace !== undefined ? { env: hookEnvFace } : {}), identity: hookIdentity });
4188
4245
  if (patch?.additionalContext) {
4189
- content = [...content, { type: "text", text: formatHookFeedback(patch.additionalContext) }];
4246
+ content = [...content, { type: "text", text: formatHookFeedback(patch.additionalContext, reminderMark) }];
4190
4247
  changed = true;
4191
4248
  }
4192
4249
  }
@@ -4198,14 +4255,14 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
4198
4255
  changed = true;
4199
4256
  }
4200
4257
  if (patch?.additionalContext) {
4201
- content = [...content, { type: "text", text: formatHookFeedback(patch.additionalContext) }];
4258
+ content = [...content, { type: "text", text: formatHookFeedback(patch.additionalContext, reminderMark) }];
4202
4259
  changed = true;
4203
4260
  }
4204
4261
  }
4205
4262
  const pre = preToolContexts.get(e.toolCallId);
4206
4263
  if (pre) {
4207
4264
  preToolContexts.delete(e.toolCallId);
4208
- content = [...content, ...pre.map((t) => ({ type: "text", text: formatHookFeedback(t) }))];
4265
+ content = [...content, ...pre.map((t) => ({ type: "text", text: formatHookFeedback(t, reminderMark) }))];
4209
4266
  changed = true;
4210
4267
  }
4211
4268
  return changed ? { content } : undefined;
@@ -4479,7 +4536,7 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
4479
4536
  const effectiveReadFaceObserved = carrierReadFace();
4480
4537
  const effectiveReadDenyObserved = readDenyAdditionsNormalized.length > 0 ? readDenyAdditionsNormalized.map((e) => ({ ...e })) : undefined;
4481
4538
  const preparedHolder = {};
4482
- const buildPrepared = () => ({ harness, session, sessionId, taskRootPath: taskRootFinal, model, thinking, compModel, mcp: mcp, ...(a2a !== undefined && a2a.tools.length > 0 ? { a2a } : {}), blockedRef, outputRef, abortController, conflictRef, blockedToolCalls, approvalSettlement, nestedStats, ...(rewindNotes.length > 0 ? { rewindNotes } : {}), ...(effectiveReadFaceObserved !== undefined ? { effectiveReadFace: effectiveReadFaceObserved } : {}), ...(effectiveReadDenyObserved !== undefined ? { effectiveReadDenyPatterns: effectiveReadDenyObserved } : {}), effectiveMemoryScopes: memoryEffectiveScopes, cwdRef: handsCwdRef, ...(worktreeSessionRef !== undefined ? { worktreeSessionRef } : {}), ...(workspaceStateSettle !== undefined ? { workspaceStateSettle } : {}), denyNarrowingPolicy, ...(basePolicyForResumeEdit !== undefined ? { basePolicyForResumeEdit } : {}), ...(permissionRuleOrgLane !== undefined ? { permissionRuleOrg: permissionRuleOrgLane } : {}), releaseSignal, settleContentAskBindings, cacheBreakDetector, cacheFingerprint, wiringManifest, promptManifest, epochDeclaredSections, activeTools, ...(deferred.size > 0 ? { deferredToolNames: deferred } : {}), toolMaterializeStatic, deferDirectCall, ...(staticFaceForRef.current !== undefined ? { staticFaceFor: staticFaceForRef.current } : {}), ownedEnv, suspendRef, suspendProgressRef, reviewRef, remoteEnvFailures, reviewRequestRef, suspendLoopRef, suspendForResource, ...(suspendForPlatformLimit !== undefined ? { suspendForPlatformLimit } : {}), ...(envLifetimeSuspendAt !== undefined ? { envLifetimeSuspendAt } : {}), ...(usageGovernance !== undefined ? { usageGovernance } : {}), callIssuedAtRef, brainCallGuardrailRef, suspendForReview, resourceLedger: priorLedger, liveSpendRef, humanReviewRef, now, tools, toolEffects, wakeRecovered, promptOverheadTokens, lastBrainContext, readTaskFile, recentlyReadFiles, normalizeAttachmentPath, isDedupStubResult, ...(onCompactionApplied ? { onCompactionApplied } : {}), compactionReuseRef, trimPressureRef, ...(memoryEngineSession ? { memoryEngineSession } : {}), ...(subagentRetain ? { subagentRetain } : {}), ...(lspDiagnostics && nudgeLspOnEdit ? { lspDiagnostics: { registry: lspDiagnostics, nudge: nudgeLspOnEdit, runIdent: lspRunIdent } } : {}), planModeRef, ...(dateChange ? { dateChange } : {}), ...(instructionSources ? { instructionSources } : {}), ...(workflowSizeGuideline ? { workflowSizeGuideline } : {}), ...(detectExternalChanges ? { detectExternalChanges } : {}), ...(toolsDeltaRef ? { toolsDeltaRef } : {}), ...(agentListing ? { agentListing } : {}), ...(skillsListing ? { skillsListing } : {}), announcedListingsRef, gitStatusRef, listBackgroundTasks, hookIdentity, ...(turnSnapshotRef.current !== undefined ? { turnSnapshot: turnSnapshotRef.current } : {}), ...(centerCompactionCandidate !== undefined ? { centerCompactionCandidate } : {}) });
4539
+ const buildPrepared = () => ({ harness, session, sessionId, reminderMark, taskRootPath: taskRootFinal, model, thinking, compModel, mcp: mcp, ...(a2a !== undefined && a2a.tools.length > 0 ? { a2a } : {}), blockedRef, outputRef, abortController, conflictRef, blockedToolCalls, approvalSettlement, nestedStats, ...(rewindNotes.length > 0 ? { rewindNotes } : {}), ...(effectiveReadFaceObserved !== undefined ? { effectiveReadFace: effectiveReadFaceObserved } : {}), ...(effectiveReadDenyObserved !== undefined ? { effectiveReadDenyPatterns: effectiveReadDenyObserved } : {}), effectiveMemoryScopes: memoryEffectiveScopes, cwdRef: handsCwdRef, ...(worktreeSessionRef !== undefined ? { worktreeSessionRef } : {}), ...(workspaceStateSettle !== undefined ? { workspaceStateSettle } : {}), denyNarrowingPolicy, ...(basePolicyForResumeEdit !== undefined ? { basePolicyForResumeEdit } : {}), ...(permissionRuleOrgLane !== undefined ? { permissionRuleOrg: permissionRuleOrgLane } : {}), releaseSignal, settleContentAskBindings, cacheBreakDetector, cacheFingerprint, wiringManifest, promptManifest, epochDeclaredSections, activeTools, ...(deferred.size > 0 ? { deferredToolNames: deferred } : {}), toolMaterializeStatic, deferDirectCall, ...(staticFaceForRef.current !== undefined ? { staticFaceFor: staticFaceForRef.current } : {}), ownedEnv, suspendRef, suspendProgressRef, reviewRef, remoteEnvFailures, reviewRequestRef, suspendLoopRef, suspendForResource, ...(suspendForPlatformLimit !== undefined ? { suspendForPlatformLimit } : {}), ...(envLifetimeSuspendAt !== undefined ? { envLifetimeSuspendAt } : {}), ...(usageGovernance !== undefined ? { usageGovernance } : {}), callIssuedAtRef, brainCallGuardrailRef, suspendForReview, resourceLedger: priorLedger, liveSpendRef, humanReviewRef, now, tools, toolEffects, wakeRecovered, promptOverheadTokens, lastBrainContext, readTaskFile, recentlyReadFiles, normalizeAttachmentPath, isDedupStubResult, ...(onCompactionApplied ? { onCompactionApplied } : {}), compactionReuseRef, trimPressureRef, ...(memoryEngineSession ? { memoryEngineSession } : {}), ...(subagentRetain ? { subagentRetain } : {}), ...(lspDiagnostics && nudgeLspOnEdit ? { lspDiagnostics: { registry: lspDiagnostics, nudge: nudgeLspOnEdit, runIdent: lspRunIdent } } : {}), planModeRef, ...(dateChange ? { dateChange } : {}), ...(instructionSources ? { instructionSources } : {}), ...(workflowSizeGuideline ? { workflowSizeGuideline } : {}), ...(detectExternalChanges ? { detectExternalChanges } : {}), ...(toolsDeltaRef ? { toolsDeltaRef } : {}), ...(agentListing ? { agentListing } : {}), ...(skillsListing ? { skillsListing } : {}), announcedListingsRef, gitStatusRef, listBackgroundTasks, hookIdentity, ...(turnSnapshotRef.current !== undefined ? { turnSnapshot: turnSnapshotRef.current } : {}), ...(centerCompactionCandidate !== undefined ? { centerCompactionCandidate } : {}) });
4483
4540
  const prepared = buildPrepared();
4484
4541
  preparedHolder.current = prepared;
4485
4542
  return prepared;