@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.
- package/CHANGELOG.md +115 -0
- package/dist/agents/subagent.d.ts +10 -0
- package/dist/agents/subagent.js +29 -2
- package/dist/core/auto-compaction.d.ts +23 -0
- package/dist/core/auto-compaction.js +8 -0
- package/dist/core/checkpoint-store.d.ts +16 -0
- package/dist/core/context-guard.d.ts +41 -0
- package/dist/core/context-guard.js +76 -0
- package/dist/core/governance-codes.js +4 -0
- package/dist/core/memory-engine/engine.d.ts +142 -0
- package/dist/core/memory-engine/engine.js +265 -3
- package/dist/core/memory-engine/file-backend.d.ts +490 -16
- package/dist/core/memory-engine/file-backend.js +1099 -36
- package/dist/core/memory-engine/index.d.ts +2 -2
- package/dist/core/memory-engine/index.js +1 -1
- package/dist/core/memory-engine/layout.d.ts +42 -2
- package/dist/core/memory-engine/layout.js +76 -12
- package/dist/core/memory-engine/memory-backend-contract.d.ts +13 -0
- package/dist/core/memory-engine/memory-backend-contract.js +89 -0
- package/dist/core/park-selfcheck.d.ts +5 -0
- package/dist/core/protocol-table.d.ts +4 -4
- package/dist/core/runner/assemble-result.d.ts +8 -0
- package/dist/core/runner/assemble-result.js +4 -1
- package/dist/core/runner/git-status-frame.d.ts +219 -0
- package/dist/core/runner/git-status-frame.js +212 -0
- package/dist/core/runner/prepare-memory.d.ts +11 -1
- package/dist/core/runner/prepare-memory.js +48 -2
- package/dist/core/runner/prepare-task.d.ts +21 -0
- package/dist/core/runner/prepare-task.js +28 -35
- package/dist/core/runner/runtask.js +270 -5
- package/dist/core/task-registry-agent.d.ts +15 -0
- package/dist/core/task-registry-agent.js +9 -0
- package/dist/core/task-registry.d.ts +3 -0
- package/dist/core/task-registry.js +4 -1
- package/dist/core/types.d.ts +122 -7
- package/dist/engine/harness/types.d.ts +65 -1
- package/dist/engine/harness/types.js +20 -0
- package/dist/engine/session/import-validate.js +10 -1
- package/dist/engine/session/session.d.ts +37 -1
- package/dist/engine/session/session.js +56 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.js +1 -1
- package/dist/internal/harness-types.d.ts +1 -0
- package/dist/internal/harness.d.ts +2 -0
- package/dist/internal/harness.js +2 -0
- package/dist/prompt-assembly/epoch.js +1 -1
- package/dist/prompt-assembly/event-registry.js +1 -0
- package/dist/prompts/default.d.ts +20 -7
- package/dist/prompts/default.js +2 -7
- package/package.json +1 -1
- 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,
|
|
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
|
}
|