@sema-agent/core 5.35.0 → 5.37.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 (51) hide show
  1. package/CHANGELOG.md +115 -0
  2. package/dist/agents/subagent.d.ts +10 -0
  3. package/dist/agents/subagent.js +29 -2
  4. package/dist/core/auto-compaction.d.ts +23 -0
  5. package/dist/core/auto-compaction.js +8 -0
  6. package/dist/core/checkpoint-store.d.ts +16 -0
  7. package/dist/core/context-guard.d.ts +41 -0
  8. package/dist/core/context-guard.js +76 -0
  9. package/dist/core/governance-codes.js +4 -0
  10. package/dist/core/memory-engine/engine.d.ts +142 -0
  11. package/dist/core/memory-engine/engine.js +265 -3
  12. package/dist/core/memory-engine/file-backend.d.ts +490 -16
  13. package/dist/core/memory-engine/file-backend.js +1099 -36
  14. package/dist/core/memory-engine/index.d.ts +2 -2
  15. package/dist/core/memory-engine/index.js +1 -1
  16. package/dist/core/memory-engine/layout.d.ts +42 -2
  17. package/dist/core/memory-engine/layout.js +76 -12
  18. package/dist/core/memory-engine/memory-backend-contract.d.ts +13 -0
  19. package/dist/core/memory-engine/memory-backend-contract.js +89 -0
  20. package/dist/core/park-selfcheck.d.ts +5 -0
  21. package/dist/core/protocol-table.d.ts +4 -4
  22. package/dist/core/runner/assemble-result.d.ts +8 -0
  23. package/dist/core/runner/assemble-result.js +4 -1
  24. package/dist/core/runner/git-status-frame.d.ts +219 -0
  25. package/dist/core/runner/git-status-frame.js +212 -0
  26. package/dist/core/runner/prepare-memory.d.ts +11 -1
  27. package/dist/core/runner/prepare-memory.js +48 -2
  28. package/dist/core/runner/prepare-task.d.ts +21 -0
  29. package/dist/core/runner/prepare-task.js +28 -35
  30. package/dist/core/runner/runtask.js +270 -5
  31. package/dist/core/task-registry-agent.d.ts +15 -0
  32. package/dist/core/task-registry-agent.js +9 -0
  33. package/dist/core/task-registry.d.ts +3 -0
  34. package/dist/core/task-registry.js +4 -1
  35. package/dist/core/types.d.ts +122 -7
  36. package/dist/engine/harness/types.d.ts +65 -1
  37. package/dist/engine/harness/types.js +20 -0
  38. package/dist/engine/session/import-validate.js +10 -1
  39. package/dist/engine/session/session.d.ts +37 -1
  40. package/dist/engine/session/session.js +56 -1
  41. package/dist/index.d.ts +2 -2
  42. package/dist/index.js +1 -1
  43. package/dist/internal/harness-types.d.ts +1 -0
  44. package/dist/internal/harness.d.ts +2 -0
  45. package/dist/internal/harness.js +2 -0
  46. package/dist/prompt-assembly/epoch.js +1 -1
  47. package/dist/prompt-assembly/event-registry.js +1 -0
  48. package/dist/prompts/default.d.ts +20 -7
  49. package/dist/prompts/default.js +2 -7
  50. package/package.json +1 -1
  51. package/test/export-surface.snapshot.json +13 -1
@@ -56,7 +56,8 @@ import { limitConfigError, prepareConfigDoors } from "./prepare-config-doors.js"
56
56
  import { NAMESPACED_NAME_SHAPES, prepareSafetyScan } from "./prepare-safety-scan.js";
57
57
  import { prepareAcquireReconcile } from "./prepare-acquire-reconcile.js";
58
58
  import { prepareWorkspaceRestore, rebaseWorkspacePath, remoteEnvFailureNote, restoreWorkspaceWithRetry } from "./prepare-workspace-restore.js";
59
- import { defaultPromptProvider, buildEnvironmentContext, buildGitSnapshot, formatLocalDate, isValidTimeZone, PROJECT_CONTEXT_FRAMING } from "../../prompts/default.js";
59
+ import { defaultPromptProvider, buildEnvironmentContext, formatLocalDate, isValidTimeZone, PROJECT_CONTEXT_FRAMING } from "../../prompts/default.js";
60
+ import { applyGitFrameGuard, probeGitStatusLane } from "./git-status-frame.js";
60
61
  import { assemblePrompt } from "../../prompt-assembly/assemble.js";
61
62
  import { auditToolCollisions, getToolContract, projectToolManifest } from "../../prompt-assembly/tool-catalog.js";
62
63
  import { resolveEpochAgainstBundled } from "../../prompt-assembly/epoch.js";
@@ -1554,7 +1555,7 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
1554
1555
  const memoryPairExcludedName = MEMORY_ENGINE_TOOL_NAMES.find((n) => (toolFaceSnapshot.exclude ?? []).includes(n));
1555
1556
  const memoryPairOccupiedName = MEMORY_ENGINE_TOOL_NAMES.find((n) => memoryPairNameDomain.has(n));
1556
1557
  const memorySearchToolsPlanned = memoryPairExcludedName === undefined && memoryPairOccupiedName === undefined;
1557
- const { memoryEngineSession, memoryBlock: memoryBlockFromEngine, memoryTools, seedFiles: memorySeedFiles, admittedOrgScopes: memoryAdmittedOrgScopes, ownOrgVerdict: memoryOwnOrgVerdict, } = await prepareMemory({
1558
+ const { memoryEngineSession, memoryBlock: memoryBlockFromEngine, memoryTools, seedFiles: memorySeedFiles, admittedOrgScopes: memoryAdmittedOrgScopes, ownOrgVerdict: memoryOwnOrgVerdict, effectiveMemoryScopes: memoryEffectiveScopes, } = await prepareMemory({
1558
1559
  spec,
1559
1560
  deps,
1560
1561
  sessionId,
@@ -1875,38 +1876,14 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
1875
1876
  }
1876
1877
  catch {
1877
1878
  }
1878
- if (envFacts.isGitRepo === true) {
1879
- const SEP = "@@SEMA_ENV_GIT_SPLIT@@";
1880
- try {
1881
- const snap = await executionEnv.exec(`(m=$(git symbolic-ref --short refs/remotes/origin/HEAD 2>/dev/null); m=\${m#origin/}; for s in "$m" main master; do if [ -n "$s" ] && git show-ref --verify --quiet "refs/remotes/origin/$s"; then echo "$s"; break; fi; done) || true; echo "${SEP}"; (git config user.name 2>/dev/null || true); echo "${SEP}"; gs=$(git --no-optional-locks status --short) || exit 41; printf '%s\\n' "$gs"; echo "${SEP}"; gl=$(git --no-optional-locks log --oneline -n 5) || exit 42; printf '%s\\n' "$gl"`, { cwd: envFacts.cwd, timeout: 10 });
1882
- if (snap.ok && snap.value.exitCode === 0) {
1883
- const parts = snap.value.stdout.split(`${SEP}\n`);
1884
- if (parts.length === 4) {
1885
- envFacts.gitSnapshot = buildGitSnapshot({
1886
- branch: envFacts.gitBranch ?? "HEAD",
1887
- mainBranch: parts[0].trim() || "main",
1888
- ...(parts[1].trim() ? { userName: parts[1].trim() } : {}),
1889
- status: parts[2],
1890
- log: parts[3],
1891
- });
1892
- }
1893
- }
1894
- else {
1895
- const reason = snap.ok
1896
- ? snap.value.exitCode === 41
1897
- ? "git status failed (exit 41)"
1898
- : snap.value.exitCode === 42
1899
- ? "git log failed (exit 42)"
1900
- : `git exited ${snap.value.exitCode}`
1901
- : `exec failed: ${snap.error.message}`;
1902
- deps.onError?.(new Error(`env git snapshot skipped — ${reason}`), { phase: "degraded", sessionId, classification: "env-git-snapshot" });
1903
- }
1904
- }
1905
- catch (err) {
1906
- deps.onError?.(new Error(`env git snapshot skipped — ${err instanceof Error ? err.message : String(err)}`), { phase: "degraded", sessionId, classification: "env-git-snapshot" });
1907
- }
1908
- }
1909
1879
  }
1880
+ const gitStatusRef = await probeGitStatusLane({
1881
+ executionEnv,
1882
+ envFacts,
1883
+ handsEnabled,
1884
+ taskRoot: taskRootFinal,
1885
+ onDegrade: (reason) => deps.onError?.(new Error(`env git snapshot degraded — ${reason}`), { phase: "degraded", sessionId, classification: "env-git-snapshot" }),
1886
+ });
1910
1887
  if (toolFaceSnapshot.exclude !== undefined && toolFaceSnapshot.exclude.length > 0) {
1911
1888
  const excluded = new Set(toolFaceSnapshot.exclude);
1912
1889
  for (let i = tools.length - 1; i >= 0; i--)
@@ -3577,6 +3554,7 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
3577
3554
  ...(announcedListingsRef.models !== undefined ? { models: [...announcedListingsRef.models] } : {}),
3578
3555
  }
3579
3556
  : undefined,
3557
+ gitAnnouncement: gitStatusRef.announced !== undefined ? { ...gitStatusRef.announced } : undefined,
3580
3558
  delegationProvenance: internals?.delegationProvenance !== undefined ? { ...internals.delegationProvenance.ref.current } : undefined,
3581
3559
  });
3582
3560
  const commitSuspendSaga = async (token, cp, remoteEnv, remoteHandle) => {
@@ -4388,6 +4366,20 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
4388
4366
  ts: Date.now(),
4389
4367
  }));
4390
4368
  }
4369
+ trimmed = applyGitFrameGuard({
4370
+ before: edited,
4371
+ trimmed,
4372
+ budgetTokens: guardAt,
4373
+ ref: gitStatusRef,
4374
+ charsPerToken,
4375
+ onDegrade: (message) => {
4376
+ try {
4377
+ deps.onError?.(new Error(message), { phase: "degraded", sessionId, classification: "env-git-snapshot" });
4378
+ }
4379
+ catch {
4380
+ }
4381
+ },
4382
+ });
4391
4383
  const swept = dropOrphanToolResults(trimmed);
4392
4384
  if (swept.dropped.length > 0) {
4393
4385
  try {
@@ -4404,7 +4396,8 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
4404
4396
  mediaCapped !== capped ||
4405
4397
  edited !== mediaCapped ||
4406
4398
  trimDroppedMessages ||
4407
- swept.dropped.length > 0;
4399
+ swept.dropped.length > 0 ||
4400
+ gitStatusRef.overBudgetShrunk === true;
4408
4401
  return { messages: swept.messages };
4409
4402
  });
4410
4403
  const cacheBreakDetector = deps.cacheBreakDetection === false ? undefined : new CacheBreakDetector();
@@ -4593,7 +4586,7 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
4593
4586
  const effectiveReadFaceObserved = carrierReadFace();
4594
4587
  const effectiveReadDenyObserved = readDenyAdditionsNormalized.length > 0 ? readDenyAdditionsNormalized.map((e) => ({ ...e })) : undefined;
4595
4588
  const preparedHolder = {};
4596
- 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 } : {}), 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, listBackgroundTasks, ...(turnSnapshotRef.current !== undefined ? { turnSnapshot: turnSnapshotRef.current } : {}), ...(centerCompactionCandidate !== undefined ? { centerCompactionCandidate } : {}) });
4589
+ 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, ...(turnSnapshotRef.current !== undefined ? { turnSnapshot: turnSnapshotRef.current } : {}), ...(centerCompactionCandidate !== undefined ? { centerCompactionCandidate } : {}) });
4597
4590
  const prepared = buildPrepared();
4598
4591
  preparedHolder.current = prepared;
4599
4592
  return prepared;
@@ -3,6 +3,8 @@ import { createSafeNotifier, observeThenableRejection } from "../safe-notify.js"
3
3
  import { AgentHarness, DEFAULT_COMPACTION_SETTINGS, uuidv7 } from "../../internal/harness.js";
4
4
  import { snapshotActorAssertion } from "../../internal/llm.js";
5
5
  import { CheckpointError, BINDING_CHECKPOINT_VERSION, checkpointVersionOf, F012_CHECKPOINT_VERSION, MAX_SUPPORTED_CHECKPOINT_VERSION, REAL_APPROVAL_CHECKPOINT_VERSION, FACE_CHECKPOINT_VERSION, remainingBudgetMicroUsd, readPendingSteerQueue, remainingTokens, LEGACY_PENDING_STEER_INPUT_ID, MAX_STEER_INPUT_ID_CHARS, validatePendingSteer, winnerFromOutcome, } from "../checkpoint-store.js";
6
+ import { GIT_STATUS_ECHO_PREVIEW, branchCarriesVisiblePositiveGitFrame, newestEngineGitFrame, stripGitStatusUnits } from "./git-status-frame.js";
7
+ import { gitFrameContextVisible, normalizeGitAnnouncement } from "../../internal/harness.js";
6
8
  import { engineVersion } from "../version.js";
7
9
  import { CONFIG_CATALOG_VERSION, declarationReasons, resolveEffectiveConfig } from "../../config/catalog.js";
8
10
  import { eventDefaultOn } from "../../prompt-assembly/event-registry.js";
@@ -868,6 +870,7 @@ function makeTurnBoundary(prepared, stats, rs, deps) {
868
870
  workingFileAttachments: buildWorkingFileAttachments(spec, prepared),
869
871
  ...(prepared.onCompactionApplied ? { onApplied: prepared.onCompactionApplied } : {}),
870
872
  ...runnerHooks.seamCCompactionOptions(prepared),
873
+ ...gitRestateOption(prepared),
871
874
  ...windowSafetyOptions(event.model),
872
875
  ...runnerHooks.compactionHookOptions(spec, prepared.sessionId, passTrigger),
873
876
  });
@@ -996,6 +999,96 @@ function makeTurnBoundary(prepared, stats, rs, deps) {
996
999
  };
997
1000
  return onTurnBoundary;
998
1001
  }
1002
+ function wrapGitFrame(body) {
1003
+ return `<system-reminder>\n${sanitizeUntrustedText(body)}\n</system-reminder>`;
1004
+ }
1005
+ async function resolveGitLegDelivery(prepared, cpMirror, report) {
1006
+ const ref = prepared.gitStatusRef;
1007
+ const frame = ref.frame;
1008
+ if (frame === undefined)
1009
+ return undefined;
1010
+ let prior;
1011
+ let pending = false;
1012
+ try {
1013
+ const branchReadout = await prepared.session.getGitAnnouncement?.();
1014
+ if (branchReadout !== undefined) {
1015
+ if (branchReadout.status === "pending") {
1016
+ pending = true;
1017
+ prior = { kind: branchReadout.kind, hash: branchReadout.hash };
1018
+ }
1019
+ else {
1020
+ prior = { kind: branchReadout.kind, hash: branchReadout.hash, ...(branchReadout.entryId !== undefined ? { entryId: branchReadout.entryId } : {}) };
1021
+ }
1022
+ }
1023
+ else {
1024
+ const shaped = normalizeGitAnnouncement(cpMirror);
1025
+ if (shaped !== undefined) {
1026
+ if (shaped.pending === true || shaped.entryId === undefined) {
1027
+ pending = true;
1028
+ prior = { kind: shaped.kind, hash: shaped.hash };
1029
+ }
1030
+ else if (gitFrameContextVisible(await prepared.session.getBranch(), shaped.entryId)) {
1031
+ prior = { kind: shaped.kind, hash: shaped.hash, entryId: shaped.entryId };
1032
+ }
1033
+ else {
1034
+ pending = true;
1035
+ prior = { kind: shaped.kind, hash: shaped.hash };
1036
+ }
1037
+ }
1038
+ }
1039
+ }
1040
+ catch (err) {
1041
+ pending = true;
1042
+ report(err instanceof Error ? err : new Error(String(err)));
1043
+ }
1044
+ if (prior !== undefined && !pending && prior.entryId !== undefined) {
1045
+ try {
1046
+ const newest = newestEngineGitFrame(await prepared.session.getBranch());
1047
+ if (newest === undefined || newest.entryId !== prior.entryId)
1048
+ pending = true;
1049
+ }
1050
+ catch (err) {
1051
+ pending = true;
1052
+ report(err instanceof Error ? err : new Error(String(err)));
1053
+ }
1054
+ }
1055
+ if (prior !== undefined)
1056
+ ref.announced = pending ? { ...prior, pending: true } : { ...prior };
1057
+ const negative = frame.kind === "unavailable" || frame.kind === "non-repo";
1058
+ if (negative) {
1059
+ if (prior === undefined && !pending) {
1060
+ let mustDisown;
1061
+ try {
1062
+ mustDisown = branchCarriesVisiblePositiveGitFrame(await prepared.session.getBranch());
1063
+ }
1064
+ catch (err) {
1065
+ mustDisown = true;
1066
+ report(err instanceof Error ? err : new Error(String(err)));
1067
+ }
1068
+ return mustDisown ? frame.body : undefined;
1069
+ }
1070
+ if (prior !== undefined && !pending && prior.kind === frame.kind && prior.hash === frame.hash)
1071
+ return undefined;
1072
+ return frame.body;
1073
+ }
1074
+ if (!pending && prior !== undefined && prior.kind === frame.kind && prior.hash === frame.hash) {
1075
+ ref.protectedText = wrapGitFrame(frame.body);
1076
+ if (frame.kind === "full" && frame.shrunk !== undefined) {
1077
+ ref.wrappedShrink = { find: ref.protectedText, replace: wrapGitFrame(frame.shrunk.body) };
1078
+ }
1079
+ return undefined;
1080
+ }
1081
+ return frame.body;
1082
+ }
1083
+ function gitRestateOption(prepared) {
1084
+ const ref = prepared.gitStatusRef;
1085
+ if (ref.frame === undefined || ref.announced === undefined || ref.reassert === undefined)
1086
+ return {};
1087
+ const use = ref.overBudgetShrunk && ref.frame.shrunk !== undefined
1088
+ ? { kind: "degraded", hash: ref.frame.shrunk.hash }
1089
+ : { kind: ref.frame.kind, hash: ref.frame.hash };
1090
+ return { gitRestate: { pending: use, land: ref.reassert } };
1091
+ }
999
1092
  function makeHarnessHandlers(prepared, stats, rs, deps) {
1000
1093
  const { spec, queue, internals, ident, parentToolCallId, subagentName, pushContent, emitCommitted, startedToolCallIds, toolStartAt, writeFamilyOf, toolLabels, postToolBatchHook, batchArgs } = deps;
1001
1094
  const internalsNotifier = createSafeNotifier({
@@ -1040,6 +1133,19 @@ function makeHarnessHandlers(prepared, stats, rs, deps) {
1040
1133
  if (event.entryId !== undefined && (m.role === "user" || m.role === "assistant" || m.role === "toolResult")) {
1041
1134
  emitCommitted(event.entryId, m.role, m.role === "toolResult" ? m.toolCallId : undefined);
1042
1135
  }
1136
+ if (event.entryId !== undefined && m.role === "user" && prepared.gitStatusRef.pendingReceipt !== undefined) {
1137
+ const pr = prepared.gitStatusRef.pendingReceipt;
1138
+ const c = m.content;
1139
+ const text = typeof c === "string"
1140
+ ? c
1141
+ : Array.isArray(c) && c.length >= 1 && c[0].type === "text"
1142
+ ? c[0].text
1143
+ : undefined;
1144
+ if (text === pr.text) {
1145
+ delete prepared.gitStatusRef.pendingReceipt;
1146
+ pr.commit(event.entryId);
1147
+ }
1148
+ }
1043
1149
  if (rs.degrade.degraded === undefined && m.role === "assistant") {
1044
1150
  const deg = readDegradation(m);
1045
1151
  if (deg)
@@ -1261,6 +1367,7 @@ function makeHarnessHandlers(prepared, stats, rs, deps) {
1261
1367
  type: "task_progress",
1262
1368
  taskId: rs.telemetry.taskId,
1263
1369
  ...(internals?.delegationTaskType !== undefined ? { taskType: internals.delegationTaskType } : {}),
1370
+ ...(internals?.cycleSeq !== undefined ? { seq: internals.cycleSeq } : {}),
1264
1371
  ...(internals?.parentTaskId !== undefined ? { parentTaskId: internals.parentTaskId } : {}),
1265
1372
  ...(subagentName ? { name: subagentName } : {}),
1266
1373
  usage: { totalTokens: stats.tokens, toolUses: stats.toolCalls, durationMs: Date.now() - rs.telemetry.taskStart },
@@ -1552,6 +1659,7 @@ export class Runner {
1552
1659
  errorMessage: err instanceof Error ? err.message : String(err),
1553
1660
  errorCode: code,
1554
1661
  ...(remoteEnvFailure !== undefined ? { remoteEnvFailures: remoteEnvFailure } : {}),
1662
+ ...(taskIdRef.effectiveMemoryScopes !== undefined ? { effectiveMemoryScopes: taskIdRef.effectiveMemoryScopes } : {}),
1555
1663
  ...(() => {
1556
1664
  const hinted = err.retryAfterMs;
1557
1665
  return code === "memory.admission_required" && typeof hinted === "number" && Number.isFinite(hinted) && hinted > 0
@@ -1922,6 +2030,8 @@ export class Runner {
1922
2030
  }, this);
1923
2031
  notificationHarness = prepared.harness;
1924
2032
  notificationSessionId = prepared.sessionId;
2033
+ if (taskIdRef)
2034
+ taskIdRef.effectiveMemoryScopes = prepared.effectiveMemoryScopes;
1925
2035
  const runSourceTaskId = spec.taskId ?? prepared.sessionId;
1926
2036
  const parentToolCallId = internals?.parentToolCallId;
1927
2037
  const ident = () => parentToolCallId !== undefined ? { eventId: uuidv7(), parentToolCallId, sourceTaskId: runSourceTaskId } : { eventId: uuidv7() };
@@ -2175,12 +2285,12 @@ export class Runner {
2175
2285
  return [];
2176
2286
  const full = textOf(e.message);
2177
2287
  if (m.engineMinted === true)
2178
- return [full];
2288
+ return [stripGitStatusUnits(full)];
2179
2289
  if (Array.isArray(m.engineSegments) && m.engineSegments.length > 0) {
2180
- return m.engineSegments.map((s) => full.slice(Math.max(0, s.start), Math.max(0, s.end)));
2290
+ return m.engineSegments.map((s) => stripGitStatusUnits(full.slice(Math.max(0, s.start), Math.max(0, s.end))));
2181
2291
  }
2182
2292
  if (typeof m.enginePrefixChars === "number" && m.enginePrefixChars > 0)
2183
- return [full.slice(0, m.enginePrefixChars)];
2293
+ return [stripGitStatusUnits(full.slice(0, m.enginePrefixChars))];
2184
2294
  return [];
2185
2295
  });
2186
2296
  }
@@ -2692,6 +2802,7 @@ export class Runner {
2692
2802
  workingFileAttachments: buildWorkingFileAttachments(spec, prepared),
2693
2803
  ...(prepared.onCompactionApplied ? { onApplied: prepared.onCompactionApplied } : {}),
2694
2804
  ...this.seamCCompactionOptions(prepared),
2805
+ ...gitRestateOption(prepared),
2695
2806
  ...windowSafetyOptions(prepared.harness.getModel()),
2696
2807
  ...this.compactionHookOptions(spec, prepared.sessionId, "forced"),
2697
2808
  });
@@ -2762,6 +2873,80 @@ export class Runner {
2762
2873
  recordCompactionReuse: (p, c) => this.recordCompactionReuse(p, c),
2763
2874
  },
2764
2875
  });
2876
+ prepared.gitStatusRef.reassert = async () => {
2877
+ const ref = prepared.gitStatusRef;
2878
+ const frame = ref.frame;
2879
+ if (frame === undefined)
2880
+ return;
2881
+ delete ref.mirrorOwed;
2882
+ const use = ref.overBudgetShrunk && frame.shrunk !== undefined
2883
+ ? { kind: "degraded", body: frame.shrunk.body, hash: frame.shrunk.hash }
2884
+ : { kind: frame.kind, body: frame.body, hash: frame.hash };
2885
+ const wrapped = wrapGitFrame(use.body);
2886
+ try {
2887
+ const entryId = await prepared.session.appendMessage({
2888
+ role: "user",
2889
+ content: [{ type: "text", text: wrapped }],
2890
+ timestamp: Date.now(),
2891
+ engineMinted: true,
2892
+ });
2893
+ ref.announced = { kind: use.kind, hash: use.hash, entryId };
2894
+ ref.protectedText = wrapped;
2895
+ if (use.kind === "full" && frame.shrunk !== undefined) {
2896
+ ref.wrappedShrink = { find: wrapped, replace: wrapGitFrame(frame.shrunk.body) };
2897
+ }
2898
+ else {
2899
+ delete ref.wrappedShrink;
2900
+ }
2901
+ queue.push({ type: "steering_injected", source: "git_status", preview: GIT_STATUS_ECHO_PREVIEW[use.kind], ...ident() });
2902
+ rs.attach.attachmentsInjected += 1;
2903
+ try {
2904
+ await prepared.session.appendGitAnnouncement?.({ kind: use.kind, hash: use.hash, entryId });
2905
+ }
2906
+ catch (mirrorErr) {
2907
+ try {
2908
+ this.deps.onError?.(new Error(`git announcement mirror write failed (frame delivered; next leg re-announces): ${mirrorErr instanceof Error ? mirrorErr.message : String(mirrorErr)}`), { phase: "degraded", sessionId: prepared.sessionId });
2909
+ }
2910
+ catch {
2911
+ }
2912
+ }
2913
+ }
2914
+ catch (err) {
2915
+ ref.announced = { kind: use.kind, hash: use.hash, pending: true };
2916
+ try {
2917
+ this.deps.onError?.(new Error(`git status frame re-assert append failed (pending; retried at the next boundary): ${err instanceof Error ? err.message : String(err)}`), { phase: "degraded", sessionId: prepared.sessionId });
2918
+ }
2919
+ catch {
2920
+ }
2921
+ }
2922
+ };
2923
+ const flushGitMirror = async () => {
2924
+ const owed = prepared.gitStatusRef.mirrorOwed;
2925
+ if (owed === undefined)
2926
+ return;
2927
+ if (prepared.gitStatusRef.overBudgetShrunk && owed.kind === "full") {
2928
+ delete prepared.gitStatusRef.mirrorOwed;
2929
+ return;
2930
+ }
2931
+ delete prepared.gitStatusRef.mirrorOwed;
2932
+ try {
2933
+ await prepared.session.appendGitAnnouncement?.(owed);
2934
+ }
2935
+ catch (mirrorErr) {
2936
+ prepared.gitStatusRef.mirrorOwed = owed;
2937
+ try {
2938
+ this.deps.onError?.(new Error(`git announcement mirror write failed (frame delivered; retried at the next serialization point): ${mirrorErr instanceof Error ? mirrorErr.message : String(mirrorErr)}`), { phase: "degraded", sessionId: prepared.sessionId });
2939
+ }
2940
+ catch {
2941
+ }
2942
+ }
2943
+ };
2944
+ const unsubGitRetry = prepared.harness.on("turn_boundary", async () => {
2945
+ await flushGitMirror();
2946
+ if (prepared.gitStatusRef.announced?.pending === true)
2947
+ await prepared.gitStatusRef.reassert?.();
2948
+ return undefined;
2949
+ });
2765
2950
  const unsubBoundary = prepared.harness.on("turn_boundary", onTurnBoundary);
2766
2951
  const unsub = prepared.harness.subscribe((event) => {
2767
2952
  switch (event.type) {
@@ -2839,6 +3024,25 @@ export class Runner {
2839
3024
  continuation += "\n\n" + formatHookFeedback(renderOrphanedBackgroundTasks(orphans));
2840
3025
  }
2841
3026
  }
3027
+ let gitResumeDelivered;
3028
+ {
3029
+ const gitBody = await resolveGitLegDelivery(prepared, resume.cp.state.gitAnnouncement, (err) => {
3030
+ try {
3031
+ this.deps.onError?.(new Error(`git announcement ladder unreadable (conservative re-announce): ${err.message}`), { phase: "degraded", sessionId: prepared.sessionId });
3032
+ }
3033
+ catch {
3034
+ }
3035
+ });
3036
+ const gitFrame = prepared.gitStatusRef.frame;
3037
+ if (gitBody !== undefined && gitFrame !== undefined) {
3038
+ const wrappedGit = wrapGitFrame(gitBody);
3039
+ continuation += "\n\n" + wrappedGit;
3040
+ gitResumeDelivered = { kind: gitFrame.kind, hash: gitFrame.hash, wrapped: wrappedGit };
3041
+ if (gitFrame.kind === "full" && gitFrame.shrunk !== undefined) {
3042
+ prepared.gitStatusRef.wrappedShrink = { find: wrappedGit, replace: wrapGitFrame(gitFrame.shrunk.body) };
3043
+ }
3044
+ }
3045
+ }
2842
3046
  const engineSegments = continuation.length > 0 ? [{ start: 0, end: continuation.length }] : [];
2843
3047
  const resumeFrames = [
2844
3048
  ...readPendingSteerQueue(resume.cp.state).map((entry) => ({ entry, source: "steer" })),
@@ -2868,7 +3072,23 @@ export class Runner {
2868
3072
  }
2869
3073
  if (resume !== undefined)
2870
3074
  resume.decisionDelivered = true;
3075
+ if (gitResumeDelivered !== undefined) {
3076
+ const delivered = gitResumeDelivered;
3077
+ prepared.gitStatusRef.protectedText = delivered.wrapped;
3078
+ prepared.gitStatusRef.pendingReceipt = {
3079
+ text: continuation,
3080
+ commit: (entryId) => {
3081
+ prepared.gitStatusRef.announced = { kind: delivered.kind, hash: delivered.hash, entryId };
3082
+ queue.push({ type: "steering_injected", source: "git_status", preview: GIT_STATUS_ECHO_PREVIEW[delivered.kind], ...ident() });
3083
+ rs.attach.attachmentsInjected += 1;
3084
+ prepared.gitStatusRef.mirrorOwed = { kind: delivered.kind, hash: delivered.hash, entryId };
3085
+ },
3086
+ };
3087
+ }
2871
3088
  final = await withBrainSinks(() => prepared.harness.prompt(continuation, { engineSegments }));
3089
+ await flushGitMirror();
3090
+ if (prepared.gitStatusRef.announced?.pending === true)
3091
+ await prepared.gitStatusRef.reassert?.();
2872
3092
  }
2873
3093
  }
2874
3094
  else {
@@ -2900,6 +3120,27 @@ export class Runner {
2900
3120
  promptBlocked = true;
2901
3121
  }
2902
3122
  }
3123
+ let gitLegDelivered;
3124
+ if (!promptBlocked) {
3125
+ const gitBody = await resolveGitLegDelivery(prepared, undefined, (err) => {
3126
+ try {
3127
+ this.deps.onError?.(new Error(`git announcement ladder unreadable (conservative re-announce): ${err.message}`), { phase: "degraded", sessionId: prepared.sessionId });
3128
+ }
3129
+ catch {
3130
+ }
3131
+ });
3132
+ const gitFrame = prepared.gitStatusRef.frame;
3133
+ if (gitBody !== undefined && gitFrame !== undefined) {
3134
+ const wrappedGit = wrapGitFrame(gitBody);
3135
+ const standalone = spec.images !== undefined && spec.images.length > 0;
3136
+ if (!standalone)
3137
+ effectiveObjective = `${wrappedGit}\n${effectiveObjective}`;
3138
+ gitLegDelivered = { kind: gitFrame.kind, hash: gitFrame.hash, standalone, wrapped: wrappedGit };
3139
+ if (gitFrame.kind === "full" && gitFrame.shrunk !== undefined) {
3140
+ prepared.gitStatusRef.wrappedShrink = { find: wrappedGit, replace: wrapGitFrame(gitFrame.shrunk.body) };
3141
+ }
3142
+ }
3143
+ }
2903
3144
  const firstFrames = [];
2904
3145
  if (rs.attach.attachState !== undefined) {
2905
3146
  const attach = rs.attach.attachState;
@@ -2937,17 +3178,18 @@ export class Runner {
2937
3178
  effectiveObjective = `${firstFrames.map((f) => `<system-reminder>\n${sanitizeUntrustedText(f.body)}\n</system-reminder>`).join("\n")}\n${effectiveObjective}`;
2938
3179
  }
2939
3180
  }
3181
+ const gitQueuedChars = gitLegDelivered !== undefined && gitLegDelivered.standalone ? gitLegDelivered.wrapped.length : 0;
2940
3182
  const precallMicroUsd = rs.budget.maxCostMicroUsd === undefined
2941
3183
  ? 0
2942
3184
  : computeCostMicroUsd({
2943
- totalInputTokens: Math.ceil(effectiveObjective.length / 4),
3185
+ totalInputTokens: Math.ceil((effectiveObjective.length + gitQueuedChars) / 4),
2944
3186
  cacheReadTokens: 0,
2945
3187
  cacheWriteTokens: 0,
2946
3188
  cacheWriteTokensLong: 0,
2947
3189
  outputTokens: prepared.model.maxTokens ?? DEFAULT_PRECALL_OUTPUT_TOKENS,
2948
3190
  }, rs.telemetry.pricing);
2949
3191
  const precallCeilingMicroUsd = prepared.suspendForResource !== undefined ? rs.budget.remainingMicroUsd : rs.budget.maxCostMicroUsd;
2950
- const precallTokens = Math.ceil(effectiveObjective.length / 4) + (prepared.model.maxTokens ?? DEFAULT_PRECALL_OUTPUT_TOKENS);
3192
+ const precallTokens = Math.ceil((effectiveObjective.length + gitQueuedChars) / 4) + (prepared.model.maxTokens ?? DEFAULT_PRECALL_OUTPUT_TOKENS);
2951
3193
  const precallCeilingTokens = prepared.suspendForResource !== undefined ? rs.budget.remainingTokens : rs.budget.maxTokensWindow;
2952
3194
  const entryUsageRetryAfterMs = prepared.usageGovernance !== undefined ? await prepared.usageGovernance.check(Date.now()) : undefined;
2953
3195
  if (promptBlocked) {
@@ -2979,6 +3221,21 @@ export class Runner {
2979
3221
  const images = spec.images
2980
3222
  ? await Promise.all(spec.images.map((img) => toImageContent(img, this.deps.allowImageUrl)))
2981
3223
  : undefined;
3224
+ if (gitLegDelivered !== undefined) {
3225
+ const delivered = gitLegDelivered;
3226
+ if (delivered.standalone)
3227
+ await prepared.harness.nextTurn(delivered.wrapped, { engineMinted: true });
3228
+ prepared.gitStatusRef.protectedText = delivered.wrapped;
3229
+ prepared.gitStatusRef.pendingReceipt = {
3230
+ text: delivered.standalone ? delivered.wrapped : effectiveObjective,
3231
+ commit: (entryId) => {
3232
+ prepared.gitStatusRef.announced = { kind: delivered.kind, hash: delivered.hash, entryId };
3233
+ queue.push({ type: "steering_injected", source: "git_status", preview: GIT_STATUS_ECHO_PREVIEW[delivered.kind], ...ident() });
3234
+ rs.attach.attachmentsInjected += 1;
3235
+ prepared.gitStatusRef.mirrorOwed = { kind: delivered.kind, hash: delivered.hash, entryId };
3236
+ },
3237
+ };
3238
+ }
2982
3239
  for (const f of firstFrames) {
2983
3240
  f.commit();
2984
3241
  queue.push({ type: "steering_injected", source: f.source, preview: f.body.slice(0, 220), ...ident() });
@@ -3004,6 +3261,9 @@ export class Runner {
3004
3261
  ...(enginePrefixChars > 0 ? { enginePrefixChars } : {}),
3005
3262
  ...(objectiveActor !== undefined ? { actor: objectiveActor } : {}),
3006
3263
  }));
3264
+ await flushGitMirror();
3265
+ if (prepared.gitStatusRef.announced?.pending === true)
3266
+ await prepared.gitStatusRef.reassert?.();
3007
3267
  }
3008
3268
  }
3009
3269
  loopLatch.ended = true;
@@ -3033,6 +3293,7 @@ export class Runner {
3033
3293
  }
3034
3294
  notificationLaneLive = false;
3035
3295
  unsubscribeTaskNotifications();
3296
+ unsubGitRetry();
3036
3297
  unsubBoundary();
3037
3298
  unsub();
3038
3299
  }
@@ -3168,6 +3429,7 @@ export class Runner {
3168
3429
  remoteEnvFailures: prepared.remoteEnvFailures,
3169
3430
  effectiveReadFace: prepared.effectiveReadFace,
3170
3431
  effectiveReadDenyPatterns: prepared.effectiveReadDenyPatterns,
3432
+ effectiveMemoryScopes: prepared.effectiveMemoryScopes,
3171
3433
  retryAfterMs: rs.limits.platformTerminal?.retryAfterMs,
3172
3434
  abortedForTimeout: timeout.fired,
3173
3435
  abortedForTurns: rs.limits.turnsExceeded,
@@ -3176,6 +3438,7 @@ export class Runner {
3176
3438
  budgetAxis: rs.limits.budgetAxis,
3177
3439
  blockedReason: prepared.blockedRef.reason,
3178
3440
  conflict: prepared.conflictRef.hit,
3441
+ gitCoreOverBudget: prepared.gitStatusRef.terminalCode === "irreducible_core_over_budget",
3179
3442
  outputInvalid: rs.degrade.outputInvalid,
3180
3443
  suspendLoop: prepared.suspendLoopRef.hit,
3181
3444
  suspendRef: prepared.suspendRef.token !== undefined && prepared.suspendRef.gate !== undefined
@@ -3304,6 +3567,7 @@ export class Runner {
3304
3567
  type: "task_progress",
3305
3568
  taskId: rs.telemetry.taskId,
3306
3569
  ...(internals?.delegationTaskType !== undefined ? { taskType: internals.delegationTaskType } : {}),
3570
+ ...(internals?.cycleSeq !== undefined ? { seq: internals.cycleSeq } : {}),
3307
3571
  ...(internals?.parentTaskId !== undefined ? { parentTaskId: internals.parentTaskId } : {}),
3308
3572
  ...(subagentName ? { name: subagentName } : {}),
3309
3573
  usage: { totalTokens: stats.tokens, toolUses: stats.toolCalls, durationMs: Date.now() - rs.telemetry.taskStart },
@@ -4316,6 +4580,7 @@ export class Runner {
4316
4580
  workingFileAttachments: buildWorkingFileAttachments(spec, prepared),
4317
4581
  ...(prepared.onCompactionApplied ? { onApplied: prepared.onCompactionApplied } : {}),
4318
4582
  ...this.seamCCompactionOptions(prepared),
4583
+ ...gitRestateOption(prepared),
4319
4584
  ...this.compactionHookOptions(spec, prepared.sessionId, "auto"),
4320
4585
  });
4321
4586
  this.recordCompactionReuse(prepared, finishComp);
@@ -275,6 +275,21 @@ export declare function resolveBackgroundAgentByNameLane(core: DurableAgentCore,
275
275
  * alone does NOT retain the child session, so declaring at register time acknowledged parks that
276
276
  * a capacity/pin failure (or plain session-scope) could never drain. No-op on unknown ids. */
277
277
  export declare function markRetainedContinuationLane(core: DurableAgentCore, id: string): void;
278
+ /**
279
+ * #258 — the stop-cycle generation of the RUN BEING SPAWNED under this row (the same counter the
280
+ * register/revive lanes keep on the handle: fresh spawn = 1, durable-seeded revive = the claimed
281
+ * row's seq, in-memory wake = the bump). The spawn lanes read it ONCE, right after registering, to
282
+ * thread into the child's `RunInternals.cycleSeq` — one authoritative source instead of each lane
283
+ * re-deriving the seed-vs-fresh arithmetic. `undefined` for an unknown id or a non-agent row.
284
+ *
285
+ * PARKED-BORN arm (falsification F1): a parked handle's counter still names the cycle that PARKED —
286
+ * the run this spawn lane is about to drive begins at the consume flip, which installs the bumped
287
+ * value (`flipped.seq = seq + 1`, the §7.2d consume write). Answering the pre-flip number made one
288
+ * resumed run speak two generations (spawn/ticks at n, terminal at n+1), so the parked arm answers
289
+ * the flip's target instead. A resume that loses the consume arbitration never runs, so the answer
290
+ * is never attached to a live cycle it doesn't describe.
291
+ */
292
+ export declare function backgroundAgentCycleSeqLane(core: DurableAgentCore, id: string): number | undefined;
278
293
  /** S2b RB-27② — REVIVE a settled background-agent row for a retained-session RESUME cycle: the
279
294
  * row flips back to "running" with a fresh "attaching" channel and a bumped revive-cycle stamp
280
295
  * (returned; the resume leg threads it through attach and settle so a stale cycle's late calls
@@ -867,6 +867,12 @@ export function markRetainedContinuationLane(core, id) {
867
867
  if (handle && handle.type === "background_agent")
868
868
  handle.retainedContinuation = true;
869
869
  }
870
+ export function backgroundAgentCycleSeqLane(core, id) {
871
+ const handle = core.handles.get(id);
872
+ if (handle === undefined || handle.type !== "background_agent")
873
+ return undefined;
874
+ return handle.status === "parked" ? (handle.cycleSeq ?? 1) + 1 : handle.cycleSeq;
875
+ }
870
876
  async function claimTerminalRowForRevive(core, store, handle, scope) {
871
877
  for (let attempt = 0; attempt < 3; attempt++) {
872
878
  let live;
@@ -972,6 +978,9 @@ export async function reviveBackgroundAgentLane(core, id, access, abort) {
972
978
  return { ok: false, reason: "still_running" };
973
979
  }
974
980
  ensureDurableHeartbeatLane(core);
981
+ if (claim.status === "claimed" && typeof claim.row.seq === "number" && (handle.cycleSeq ?? 1) < claim.row.seq) {
982
+ handle.cycleSeq = claim.row.seq;
983
+ }
975
984
  }
976
985
  handle.status = "running";
977
986
  handle.channelState = "attaching";
@@ -267,6 +267,9 @@ export declare class TaskRegistry {
267
267
  suggestion?: string;
268
268
  };
269
269
  markRetainedContinuation(id: string): void;
270
+ /** #258 — the row's current stop-cycle counter, read by the spawn lanes right after registering to
271
+ * thread into the child's `RunInternals.cycleSeq`; see {@link backgroundAgentCycleSeqLane}. */
272
+ backgroundAgentCycleSeq(id: string): number | undefined;
270
273
  /** ASYNC (revive arbitration) — the durable half is a guarded ownership claim on the row (awaited before the
271
274
  * in-memory flip), so this leg and a cross-process claim arbitrate in one domain instead of both
272
275
  * believing they own the cycle. See {@link reviveBackgroundAgentLane}. */
@@ -10,7 +10,7 @@ import { registerWorkflowLane, pollWorkflowLane, stopWorkflowLane } from "./task
10
10
  import { mintCompletionId, canAccessWorkflowRun, formatWorkflowRun, clipTaskOutput, assertOwnership, sleepPollStep, statusFromBackground, rollSpoolText, accountDroppedBytes, renderSpoolBody, spoolDropNote, droppedGapNote, alreadyTerminalStopNote, terminalTaskSummary, TASK_OUTPUT_MAX_CHARS, MONITOR_BATCH_WINDOW_MS, MONITOR_DEFAULT_TIMEOUT_MS, MONITOR_MAX_TIMEOUT_MS, MONITOR_MAX_BATCHES_PER_MINUTE, canAccess, DURABLE_AGENT_HANDLE_RE, } from "./task-registry-shared.js";
11
11
  export { normalizeAgentName, DURABLE_AGENT_HEARTBEAT_MS, DURABLE_AGENT_HANDLE_RE, BG_AGENT_REAP_STOP_ERROR } from "./task-registry-shared.js";
12
12
  import { TASK_OUTPUT_TOOL_NAME, TASK_STOP_TOOL_NAME, TASK_OUTPUT_CONTRACT, TASK_STOP_CONTRACT, TASK_OUTPUT_MISSING_ID_MESSAGE, TASK_STOP_MISSING_ID_MESSAGE, TASK_STOP_PARAMS, resolveTaskIdArg, REGISTRY_TASK_TOOL_CAPS, composeTaskOutputDescription, composeTaskOutputParams, composeTaskStopDescription, } from "./task-tool-shape.js";
13
- import { durableAgentArmedLane, durableAgentRowProbeLane, beginDurableClaimLane, endDurableClaimLane, reapDurableAgentsLane, noteBackgroundAgentActivityLane, reapStaleSessionBackgroundAgentsLane, releaseDurableTranscriptAnchorLane, bindBackgroundAgentSessionLane, registerBackgroundAgentLane, recordBackgroundAgentOrgAdmissionLane, parkBackgroundAgentLane, reconcileParkedAgentsLane, claimParkedAgentLane, rollbackParkedClaimLane, consumeParkedFlipLane, finalizeParkedResumeLane, settleBackgroundAgentLane, abortBackgroundAgentsForOwnerLane, serveDurableAgentRowLane, resolveBackgroundAgentByNameLane, markRetainedContinuationLane, reviveBackgroundAgentLane, settleRevivedAgentLane, unmarkRetainedContinuationLane, attachAgentNotifyLane, deliverToRunningAgentLane, runningBackgroundAgentLabelsLane, runningAgentFooterLane, notFoundRunningAgentsTail, pollBackgroundAgentLane, stopBackgroundAgentLane, } from "./task-registry-agent.js";
13
+ import { durableAgentArmedLane, durableAgentRowProbeLane, beginDurableClaimLane, endDurableClaimLane, reapDurableAgentsLane, noteBackgroundAgentActivityLane, reapStaleSessionBackgroundAgentsLane, releaseDurableTranscriptAnchorLane, bindBackgroundAgentSessionLane, registerBackgroundAgentLane, recordBackgroundAgentOrgAdmissionLane, parkBackgroundAgentLane, reconcileParkedAgentsLane, claimParkedAgentLane, rollbackParkedClaimLane, consumeParkedFlipLane, finalizeParkedResumeLane, settleBackgroundAgentLane, abortBackgroundAgentsForOwnerLane, serveDurableAgentRowLane, resolveBackgroundAgentByNameLane, backgroundAgentCycleSeqLane, markRetainedContinuationLane, reviveBackgroundAgentLane, settleRevivedAgentLane, unmarkRetainedContinuationLane, attachAgentNotifyLane, deliverToRunningAgentLane, runningBackgroundAgentLabelsLane, runningAgentFooterLane, notFoundRunningAgentsTail, pollBackgroundAgentLane, stopBackgroundAgentLane, } from "./task-registry-agent.js";
14
14
  export { canAccessWorkflowRun, clipTaskOutput, MONITOR_BATCH_WINDOW_MS, MONITOR_DEFAULT_TIMEOUT_MS, MONITOR_MAX_TIMEOUT_MS, MONITOR_MAX_BATCHES_PER_MINUTE };
15
15
  const BLOCK_DEFAULT_TIMEOUT_MS = 30_000;
16
16
  const BLOCK_MAX_TIMEOUT_MS = 600_000;
@@ -191,6 +191,9 @@ export class TaskRegistry {
191
191
  markRetainedContinuation(id) {
192
192
  return markRetainedContinuationLane(this.core, id);
193
193
  }
194
+ backgroundAgentCycleSeq(id) {
195
+ return backgroundAgentCycleSeqLane(this.core, id);
196
+ }
194
197
  reviveBackgroundAgent(id, access, abort) {
195
198
  return reviveBackgroundAgentLane(this.core, id, access, abort);
196
199
  }