@sema-agent/core
Version:
Stateless, task-oriented AI agent core
1,559 lines • 68.1 kB
JavaScript
import { randomBytes } from "node:crypto";
import { assertRetentionPolicy } from "./retention-policy.js";
import { uuidv7 } from "../internal/harness.js";
import { canAccessAgentRecord, BackgroundAgentStoreError, clearRevivedRowTerminalPayload, REVIVED_ROW_CLEARED_FIELDS, STALE_RUNNING_REAP_ATTRIBUTION, } from "./background-agent-store.js";
import { shutdownDebug } from "./shutdown-debug.js";
import { delimitUntrusted } from "./untrusted-text.js";
import { boundedRedactedSummary } from "./untrusted-egress.js";
import { mintCompletionId, commitCompletionIdIfEmpty, clipTaskOutput, assertOwnership, sleepPollStep, alreadyTerminalStopNote, canAccess, normalizeAgentName, closestName, DURABLE_AGENT_HEARTBEAT_MS, DURABLE_AGENT_HANDLE_RE, BG_AGENT_REAP_STOP_ERROR, } from "./task-registry-shared.js";
import { buildToolResultRef, OFFLOAD_TOOL_NAME, toolResultProvenanceOf } from "./tool-result-store.js";
import { thrownLabel } from "./thrown-value.js";
import { agentStateSourceOfHandle, agentStateSummary, readAgentState } from "./agent-state.js";
export function activeDelegationHandlesLane(core, scope, rootSessionId) {
const out = [];
for (const h of core.handles.values()) {
if (h.type !== "background_agent")
continue;
if (h.status !== "running" && h.status !== "pending")
continue;
if (h.scope !== scope)
continue;
const bh = h;
const root = bh.rootSessionId ?? bh.parentSessionId ?? (bh.sessionScoped ? bh.owner : undefined);
if (root !== rootSessionId)
continue;
out.push(h.id);
}
return out;
}
export function ensureDurableHeartbeatLane(core) {
if (core.durableHeartbeatTimer !== undefined)
return;
const t = setInterval(() => {
let liveLanes = 0;
for (const h of core.handles.values()) {
if (h.type !== "background_agent")
continue;
const bh = h;
if (!bh.durable || bh.durable.poisoned)
continue;
if (bh.status === "running") {
liveLanes++;
durableAgentWriteLane(bh, {});
}
else if (bh.durable.flushFailed) {
if ((bh.durable.redrives = (bh.durable.redrives ?? 0) + 1) > 60) {
bh.durable.poisoned = true;
process.emitWarning(`sema durable-agents: terminal flush for ${bh.durable.record.handle} unrecoverable after 60 heartbeat re-drives — durable writes for this row stop here`);
continue;
}
liveLanes++;
durableAgentWriteLane(bh, {});
}
}
if (liveLanes === 0) {
clearInterval(t);
core.durableHeartbeatTimer = undefined;
}
}, DURABLE_AGENT_HEARTBEAT_MS);
t.unref?.();
core.durableHeartbeatTimer = t;
}
export function durableAgentWriteLane(handle, patch, clear) {
const lane = handle.durable;
if (!lane || lane.poisoned)
return;
lane.chain = lane.chain.then(async () => {
if (lane.poisoned)
return;
Object.assign(lane.record, patch);
if (clear !== undefined)
for (const k of clear)
delete lane.record[k];
lane.record.updatedAt = Date.now();
const poison = (why) => {
lane.poisoned = true;
process.emitWarning(`sema durable-agents: ${why} for ${lane.record.handle} — durable writes for this row stop here`);
};
const adoptOwnRow = async () => {
try {
const live = await lane.store.get(lane.record.handle, lane.record.scope);
if (!live)
return "gone";
if (live.writerId !== lane.record.writerId)
return "foreign";
if (live.writerEpoch !== lane.record.writerEpoch)
return "foreign";
lane.record.rev = live.rev;
lane.written = true;
return "adopted";
}
catch {
return "unreadable";
}
};
for (let attempt = 0; attempt < 3; attempt++) {
if (lane.poisoned)
return;
if (attempt > 0) {
await new Promise((r) => {
const t = setTimeout(r, 50 * attempt);
t.unref?.();
});
}
try {
if (!lane.written) {
await lane.store.put(structuredClone(lane.record));
lane.written = true;
lane.flushFailed = false;
lane.redrives = 0;
return;
}
const ok = await lane.store.update(lane.record.handle, lane.record.scope, structuredClone(lane.record), {
rev: lane.record.rev,
});
if (ok) {
lane.record.rev += 1;
lane.flushFailed = false;
lane.redrives = 0;
return;
}
const verdict = await adoptOwnRow();
if (lane.poisoned)
return;
if (verdict === "adopted")
continue;
if (verdict === "unreadable")
continue;
poison(verdict === "gone" ? "row reaped mid-write" : "CAS lost to a foreign writer");
return;
}
catch (e) {
if (e instanceof BackgroundAgentStoreError && e.code === "agent_record.already_exists") {
const verdict = await adoptOwnRow();
if (lane.poisoned)
return;
if (verdict === "adopted")
continue;
if (verdict === "unreadable")
continue;
if (verdict === "gone")
continue;
poison("handle collision (foreign durable row left untouched)");
return;
}
shutdownDebug(`durable-agents write failed for ${lane.record.handle} (attempt ${attempt + 1}/3)`, { error: thrownLabel(e) });
}
}
lane.flushFailed = true;
});
}
export function durableAgentArmedLane(core, id) {
const h = core.handles.get(id);
if (!h || h.type !== "background_agent")
return false;
const lane = h.durable;
return lane !== undefined && !lane.poisoned;
}
export function durableAgentRowProbeLane(core, id) {
const h = core.handles.get(id);
if (!h || h.type !== "background_agent")
return undefined;
const handle = h;
if (!handle.durable)
return undefined;
return async () => {
const lane = handle.durable;
if (lane === undefined)
return false;
await lane.chain.catch(() => undefined);
return lane.written && !lane.poisoned && !lane.flushFailed;
};
}
export function beginDurableClaimLane(core, id) {
const live = core.handles.get(id);
if (live !== undefined && (live.status === "running" || live.status === "pending"))
return false;
if (core.reapingHandles.has(id) || core.claimingHandles.has(id))
return false;
core.claimingHandles.add(id);
return true;
}
export function endDurableClaimLane(core, id) {
core.claimingHandles.delete(id);
}
export async function reapDurableAgentsLane(core, scope, deps, policy) {
assertRetentionPolicy("reapDurableAgents", policy);
const now = policy.now ?? Date.now();
if (policy.staleRunningMaxAgeMs !== undefined) {
await deps.store.reap(scope, now, { staleRunningMaxAgeMs: policy.staleRunningMaxAgeMs });
}
if (policy.maxAgeMs === undefined && policy.keep === undefined)
return { rowsReaped: 0, sessionsReleased: 0, skippedNoSessions: 0, orphanPlacedReleased: 0 };
const terminal = (await deps.store.listByScope(scope)).filter((r) => r.status !== "running" && r.status !== "parked");
terminal.sort((a, b) => b.spawnedAt - a.spawnedAt);
const doomed = new Map();
if (policy.maxAgeMs !== undefined) {
for (const r of terminal) {
if ((r.settledAt ?? r.spawnedAt) < now - policy.maxAgeMs)
doomed.set(r.handle, r);
}
}
if (policy.keep !== undefined) {
for (const r of terminal.slice(Math.max(0, policy.keep)))
doomed.set(r.handle, r);
}
let rowsReaped = 0;
let sessionsReleased = 0;
let skippedNoSessions = 0;
for (const r of doomed.values()) {
if (core.claimingHandles.has(r.handle))
continue;
core.reapingHandles.add(r.handle);
try {
let live;
try {
live = await deps.store.get(r.handle, scope);
}
catch {
continue;
}
if (!live || live.status === "running" || live.status === "parked")
continue;
const inProc = core.handles.get(r.handle);
if (inProc !== undefined && (inProc.status === "running" || inProc.status === "pending" || inProc.status === "parked"))
continue;
if (live.sessionId !== undefined && deps.sessions === undefined) {
skippedNoSessions++;
continue;
}
try {
if (!(await deps.store.delete(r.handle, scope, { rev: live.rev })))
continue;
}
catch {
continue;
}
rowsReaped++;
{
const staleInProc = core.handles.get(r.handle);
if (staleInProc !== undefined && staleInProc.status !== "running" && staleInProc.status !== "pending" && staleInProc.status !== "parked") {
core.handles.delete(r.handle);
}
}
core.reapedHandles.add(r.handle);
if (deps.mailbox !== undefined) {
try {
await deps.mailbox.drop(scope, r.handle);
}
catch {
}
}
if (live.sessionId !== undefined && deps.sessions !== undefined) {
try {
await deps.sessions.unpin?.(live.sessionId);
await deps.sessions.release(live.sessionId);
sessionsReleased++;
}
catch {
}
}
}
finally {
core.reapingHandles.delete(r.handle);
core.reapedHandles.delete(r.handle);
}
}
let orphanPlacedReleased = 0;
if (policy.maxAgeMs !== undefined && deps.sessions !== undefined && typeof deps.sessions.listPlaced === "function") {
let placed = [];
try {
placed = await deps.sessions.listPlaced("subagent", { olderThanMs: policy.maxAgeMs, scope });
}
catch {
placed = [];
}
for (const p of placed) {
if ("tupleIncomplete" in p)
continue;
if (p.scope !== scope)
continue;
if (core.claimingHandles.has(p.handle) || core.reapingHandles.has(p.handle))
continue;
let row;
try {
row = await deps.store.get(p.handle, scope);
}
catch {
continue;
}
if (row !== null)
continue;
const inProc = core.handles.get(p.handle);
if (inProc !== undefined && (inProc.status === "running" || inProc.status === "pending" || inProc.status === "parked"))
continue;
try {
await deps.sessions.unpin?.(p.sessionId);
await deps.sessions.release(p.sessionId);
orphanPlacedReleased++;
}
catch {
}
if (deps.mailbox !== undefined) {
try {
await deps.mailbox.drop(scope, p.handle);
}
catch {
}
}
}
}
return { rowsReaped, sessionsReleased, skippedNoSessions, orphanPlacedReleased };
}
export function releaseDurableTranscriptAnchorLane(core, id) {
const handle = core.handles.get(id);
if (!handle || handle.type !== "background_agent")
return;
durableAgentWriteLane(handle, {}, ["sessionId"]);
}
export function bindBackgroundAgentSessionLane(core, id, sessionId) {
const handle = core.handles.get(id);
if (!handle || handle.type !== "background_agent")
return;
handle.sessionId = sessionId;
durableAgentWriteLane(handle, { sessionId });
}
export function recordBackgroundAgentOrgAdmissionLane(core, id, verdict) {
const handle = core.handles.get(id);
if (!handle || handle.type !== "background_agent")
return;
const lane = handle.durable;
if (lane === undefined)
return;
const disclose = (why) => {
process.emitWarning(`sema durable-agents: org-admission record for ${lane.record.handle} was not persisted (${why}) — the row keeps the previously recorded verdict, which a later revival will seed from`);
};
if (lane.poisoned) {
disclose("durable lane poisoned");
return;
}
durableAgentWriteLane(handle, { admittedOrgScopes: [...verdict.scopes], admittedOrgWriteScope: verdict.writeScope });
void lane.chain.then(() => {
if (lane.poisoned)
disclose("durable lane poisoned");
else if (lane.flushFailed)
disclose("durable write failed");
});
}
export function registerBackgroundAgentLane(core, input) {
assertOwnership(input, "registerBackgroundAgent");
if (input.id !== undefined && !DURABLE_AGENT_HANDLE_RE.test(input.id)) {
throw new Error(`TaskRegistry: background-agent id ${JSON.stringify(input.id)} does not match the a<hex> handle form`);
}
const id = input.id ?? core.mintTaskId("background_agent");
if (input.durableSeed !== undefined) {
const prior = core.handles.get(id);
if (prior !== undefined) {
const parkedHandoff = prior.status === "parked" && input.initialStatus === "parked";
if (prior.type !== "background_agent" || prior.status === "running" || prior.status === "pending" || (prior.status === "parked" && !parkedHandoff)) {
throw new Error(`TaskRegistry: task id already registered: ${id}`);
}
const priorLane = prior.durable;
if (priorLane !== undefined)
priorLane.poisoned = true;
core.handles.delete(id);
}
}
if (core.handles.has(id))
throw new Error(`TaskRegistry: task id already registered: ${id}`);
const now = input.now ?? Date.now();
core.handles.set(id, {
id,
type: "background_agent",
status: input.initialStatus ?? "running",
...(input.parkedCheckpointToken !== undefined ? { parkedCheckpointToken: input.parkedCheckpointToken } : {}),
...(input.resolveParkedStop !== undefined ? { resolveParkedStop: input.resolveParkedStop } : {}),
...(input.sessionScoped ? { sessionScoped: true } : {}),
...(input.description !== undefined ? { description: input.description } : {}),
...(input.name !== undefined ? { name: input.name } : {}),
...(input.agentType !== undefined ? { agentType: input.agentType } : {}),
...(input.parentTaskId !== undefined ? { parentTaskId: input.parentTaskId } : {}),
...(input.parentSessionId !== undefined ? { parentSessionId: input.parentSessionId } : {}),
...(input.rootSessionId !== undefined ? { rootSessionId: input.rootSessionId } : {}),
...(input.deliveryChannel !== undefined ? { channelState: input.deliveryChannel } : {}),
...(input.retainedContinuation !== undefined ? { retainedContinuation: input.retainedContinuation } : {}),
...(input.owner !== undefined ? { owner: input.owner } : {}),
...(input.scope !== undefined ? { scope: input.scope } : {}),
...(input.toolUseId !== undefined ? { toolUseId: input.toolUseId } : {}),
cycleSeq: input.durableSeed !== undefined ? (input.durableSeed.record.seq ?? 1) : 1,
createdAt: now,
updatedAt: now,
abort: input.abort,
});
if (input.store) {
const handle = core.handles.get(id);
if (input.durableSeed !== undefined) {
const seeded = structuredClone(input.durableSeed.record);
seeded.rev = input.durableSeed.rev;
handle.durable = {
store: input.store,
record: seeded,
chain: Promise.resolve(),
written: true,
poisoned: false,
flushFailed: false,
};
ensureDurableHeartbeatLane(core);
return id;
}
handle.durable = {
store: input.store,
record: {
handle: id,
scope: input.scope,
owner: input.owner,
sessionScoped: input.sessionScoped === true,
...(input.parentSessionId !== undefined ? { parentSessionId: input.parentSessionId } : {}),
...(input.rootSessionId !== undefined ? { rootSessionId: input.rootSessionId } : {}),
...(input.parentTaskId !== undefined ? { parentTaskId: input.parentTaskId } : {}),
...(input.name !== undefined ? { name: input.name } : {}),
...(input.agentType !== undefined ? { agentType: input.agentType } : {}),
...(input.description !== undefined ? { description: input.description } : {}),
...(input.model !== undefined ? { model: input.model } : {}),
writerId: core.writerId,
writerEpoch: 1,
spawnedAt: now,
updatedAt: now,
status: "running",
rev: 0,
},
chain: Promise.resolve(),
written: false,
poisoned: false,
flushFailed: false,
};
durableAgentWriteLane(handle, {});
ensureDurableHeartbeatLane(core);
}
return id;
}
export function parkBackgroundAgentLane(core, id, park) {
const handle = core.handles.get(id);
if (!handle || handle.type !== "background_agent")
return undefined;
if (handle.status !== "running")
return undefined;
handle.status = "parked";
handle.parkedCheckpointToken = park.checkpointToken;
handle.resolveParkedStop = park.resolveStop;
handle.notify = undefined;
for (const [, , qResolve] of handle.preAttachQueue ?? [])
qResolve?.({ ok: false, reason: "not_running" });
handle.preAttachQueue = undefined;
for (const r of [...(handle.inFlightDirect ?? [])])
r({ ok: false, reason: "not_running" });
handle.inFlightDirect = undefined;
handle.updatedAt = Date.now();
if (park.seq !== undefined)
handle.cycleSeq = park.seq;
core.pokeBgQuiescence(handle.owner);
durableAgentWriteLane(handle, {
status: "parked",
parkedCheckpointToken: park.checkpointToken,
parkedAt: Date.now(),
...(park.seq !== undefined ? { seq: park.seq } : {}),
}, ["parkClaimId"]);
return "parked";
}
export async function reconcileParkedAgentsLane(core, stores, scope, now, opts) {
let liveFailed = 0;
for (const handle of core.handles.values()) {
if (handle.type !== "background_agent" || handle.status !== "parked")
continue;
if (handle.scope !== undefined && handle.scope !== scope)
continue;
const token = handle.parkedCheckpointToken;
let state;
if (token === undefined)
state = "missing";
else {
try {
const cp = await stores.checkpointStore.get(token);
state = cp === null ? "missing" : cp.status;
}
catch {
state = "unreadable";
}
}
let error;
if (state === "expired" || state === "missing") {
error = `approval checkpoint ${state} while parked (reconciled)`;
}
else if (state === "resolved") {
let row;
try {
row = await stores.agentStore.get(handle.id, scope);
}
catch {
continue;
}
if (row === null || row.status !== "parked" || row.parkClaimId !== undefined)
continue;
try {
const reread = (await stores.checkpointStore.get(token));
if (reread === null || reread.status !== "resolved")
continue;
}
catch {
continue;
}
error =
"approval checkpoint resolved outside the registry's claim path while parked — the decision was " +
"redeemed by another leg and this row's outcome is unknown (reconciled)";
}
else {
continue;
}
if (handle.status !== "parked")
continue;
if (handle.parkedCheckpointToken !== token)
continue;
handle.status = "failed";
handle.error = error;
handle.parkedCheckpointToken = undefined;
handle.resolveParkedStop = undefined;
handle.updatedAt = now;
mintCompletionId(handle);
core.pokeBgQuiescence(handle.owner);
durableAgentWriteLane(handle, { status: "failed", error: handle.error, settledAt: now, stoppedBy: "system", completionId: handle.completionId }, ["parkedCheckpointToken", "parkClaimId", "parkedAt"]);
liveFailed++;
}
const { reconcileParkedAgents: storeReconcile } = await import("./background-agent-store.js");
const liveHandles = new Set();
for (const h of core.handles.values())
if (h.type === "background_agent")
liveHandles.add(h.id);
const storeHalf = await storeReconcile(stores, scope, now, {
...(opts?.staleClaimMaxAgeMs !== undefined ? { staleClaimMaxAgeMs: opts.staleClaimMaxAgeMs } : {}),
excludeHandles: liveHandles,
});
return { failed: storeHalf.failed + liveFailed, rolledBack: storeHalf.rolledBack };
}
export async function claimParkedAgentLane(stores, handle, access) {
if (access.scope === undefined)
return { ok: false, reason: "not_found" };
let row;
try {
row = await stores.agentStore.get(handle, access.scope);
}
catch {
return { ok: false, reason: "store_unreachable" };
}
if (!row || !canAccessAgentRecord(row, access))
return { ok: false, reason: "not_found" };
if (row.status !== "parked")
return { ok: false, reason: "not_parked" };
const token = row.parkedCheckpointToken;
if (token === undefined || row.sessionId === undefined)
return { ok: false, reason: "binding_broken" };
let cp;
try {
cp = (await stores.checkpointStore.get(token));
}
catch {
return { ok: false, reason: "store_unreachable" };
}
if (cp === null || cp.sessionId !== row.sessionId)
return { ok: false, reason: "binding_broken" };
if (cp.status !== "pending")
return { ok: false, reason: "checkpoint_not_pending" };
const claimId = randomBytes(8).toString("hex");
const reserved = structuredClone(row);
reserved.parkClaimId = claimId;
reserved.updatedAt = Date.now();
let won;
try {
won = await stores.agentStore.updateIf(handle, access.scope, reserved, {
rev: row.rev,
status: "parked",
parkedCheckpointToken: token,
parkClaimId: null,
});
}
catch {
return { ok: false, reason: "store_unreachable" };
}
if (!won)
return { ok: false, reason: "claim_lost" };
return {
ok: true,
ticket: { handle, scope: access.scope, token, claimId, reservedRev: row.rev + 1, row: structuredClone(row) },
};
}
export async function rollbackParkedClaimLane(core, stores, ticket) {
let cpStatus;
try {
const cp = (await stores.checkpointStore.get(ticket.token));
cpStatus = cp === null ? "missing" : cp.status;
}
catch {
return "retry";
}
const now = Date.now();
const rollbackCompletionIdCandidate = uuidv7();
const settleLocalParkedHandle = (error) => {
const h = core.handles.get(ticket.handle);
if (h !== undefined && h.type === "background_agent" && h.status === "parked") {
h.status = "failed";
h.error = error;
h.parkedCheckpointToken = undefined;
h.resolveParkedStop = undefined;
h.updatedAt = now;
commitCompletionIdIfEmpty(h, rollbackCompletionIdCandidate);
core.pokeBgQuiescence(h.owner);
}
};
let liveRow;
try {
liveRow = await stores.agentStore.get(ticket.handle, ticket.scope);
}
catch {
return "retry";
}
if (!liveRow || liveRow.parkClaimId !== ticket.claimId)
return "lost";
if (cpStatus === "pending") {
const restored = structuredClone(liveRow);
delete restored.parkClaimId;
restored.updatedAt = now;
restored.writerEpoch = (liveRow.writerEpoch ?? 0) + 1;
const liveHandle = core.handles.get(ticket.handle);
if (liveHandle?.type === "background_agent" &&
liveHandle.durable !== undefined &&
liveHandle.durable.record.writerId === liveRow.writerId &&
(liveHandle.durable.record.writerEpoch ?? 0) === (liveRow.writerEpoch ?? 0)) {
liveHandle.durable.record.writerEpoch = restored.writerEpoch;
}
try {
const won = await stores.agentStore.updateIf(ticket.handle, ticket.scope, restored, {
rev: liveRow.rev,
status: "parked",
parkedCheckpointToken: ticket.token,
parkClaimId: ticket.claimId,
});
if (!won)
return "lost";
try {
const cp2 = (await stores.checkpointStore.get(ticket.token));
if (cp2 !== null && cp2.status === "pending")
return "rolled_back";
const post = await stores.agentStore.get(ticket.handle, ticket.scope);
if (post && post.status === "parked") {
const term = structuredClone(post);
term.status = "failed";
term.error = `approval checkpoint ${cp2 === null ? "missing" : cp2.status} under the resume claim (claim rollback)`;
term.stoppedBy = "system";
term.settledAt = now;
term.updatedAt = now;
term.completionId = rollbackCompletionIdCandidate;
delete term.parkedCheckpointToken;
delete term.parkClaimId;
delete term.parkedAt;
if (await stores.agentStore.updateIf(ticket.handle, ticket.scope, term, { rev: post.rev, status: "parked" })) {
settleLocalParkedHandle(term.error);
return "failed";
}
}
return "lost";
}
catch {
return "rolled_back";
}
}
catch {
return "retry";
}
}
const error = cpStatus === "resolved"
? "approval consumed but the resume could not proceed — outcome unknown (claim rollback)"
: `approval checkpoint ${cpStatus} under the resume claim (claim rollback)`;
if (liveRow.status !== "parked")
return "lost";
const failed = structuredClone(liveRow);
failed.status = "failed";
failed.error = error;
failed.stoppedBy = "system";
failed.settledAt = now;
failed.updatedAt = now;
failed.completionId = rollbackCompletionIdCandidate;
delete failed.parkedCheckpointToken;
delete failed.parkClaimId;
delete failed.parkedAt;
try {
const won = await stores.agentStore.updateIf(ticket.handle, ticket.scope, failed, {
rev: liveRow.rev,
status: "parked",
parkClaimId: ticket.claimId,
});
if (won)
settleLocalParkedHandle(error);
return won ? "failed" : "lost";
}
catch {
return "retry";
}
}
export async function consumeParkedFlipLane(core, id, stores, ticket) {
const handle = core.handles.get(id);
if (!handle || handle.type !== "background_agent" || handle.status !== "parked")
return false;
const lane = handle.durable;
const doFlip = async () => {
let live;
try {
live = await stores.agentStore.get(ticket.handle, ticket.scope);
}
catch {
return undefined;
}
if (!live || live.status !== "parked" || live.parkClaimId !== ticket.claimId || live.parkedCheckpointToken !== ticket.token)
return undefined;
const flipped = structuredClone(live);
flipped.status = "running";
flipped.writerId = core.writerId;
flipped.writerEpoch = (live.writerEpoch ?? 0) + 1;
flipped.updatedAt = Date.now();
flipped.seq = (live.seq ?? 1) + 1;
delete flipped.parkedCheckpointToken;
delete flipped.parkedAt;
try {
const won = await stores.agentStore.updateIf(ticket.handle, ticket.scope, flipped, {
rev: live.rev,
status: "parked",
parkedCheckpointToken: ticket.token,
parkClaimId: ticket.claimId,
});
if (!won)
return undefined;
}
catch {
return undefined;
}
flipped.rev = live.rev + 1;
return flipped;
};
let flipped;
if (lane !== undefined && !lane.poisoned) {
const p = lane.chain.then(doFlip, doFlip);
lane.chain = p.then((f) => {
if (f !== undefined) {
lane.record = structuredClone(f);
lane.written = true;
}
});
flipped = await p;
}
else {
flipped = await doFlip();
}
if (flipped === undefined)
return false;
handle.status = "running";
handle.parkedCheckpointToken = undefined;
handle.resolveParkedStop = undefined;
handle.updatedAt = Date.now();
handle.completionId = undefined;
handle.terminalNotified = undefined;
if (flipped.seq !== undefined)
handle.cycleSeq = flipped.seq;
return true;
}
export function finalizeParkedResumeLane(core, id) {
const handle = core.handles.get(id);
if (!handle || handle.type !== "background_agent")
return;
durableAgentWriteLane(handle, {}, ["parkClaimId"]);
}
export function settleBackgroundAgentLane(core, id, outcome) {
const handle = core.handles.get(id);
if (!handle || handle.type !== "background_agent")
return undefined;
if (outcome.cycle === undefined && (handle.reviveCycle ?? 0) !== 0) {
throw new Error(`settleBackgroundAgent("${id}"): the row has been revived (cycle ${handle.reviveCycle}) — pass the cycle this settle speaks for, or use settleRevivedAgent`);
}
if ((outcome.cycle ?? 0) !== (handle.reviveCycle ?? 0))
return undefined;
if (handle.status !== "running") {
if (handle.status === "killed") {
mintCompletionId(handle);
let backfilled = false;
if (handle.result === undefined && outcome.result !== undefined && outcome.result !== "") {
handle.result = outcome.result;
handle.resultIsPartial = true;
backfilled = true;
if (outcome.resultFull !== undefined)
handle.resultFull = outcome.resultFull;
}
if (handle.error === undefined && outcome.error !== undefined && outcome.error !== BG_AGENT_REAP_STOP_ERROR) {
handle.error = outcome.error;
backfilled = true;
}
if (backfilled) {
handle.updatedAt = Date.now();
durableAgentWriteLane(handle, {
...(handle.result !== undefined ? { finalOutput: handle.result } : {}),
...(handle.resultFull !== undefined ? { finalOutputFull: handle.resultFull } : {}),
...(handle.resultIsPartial ? { resultIsPartial: true } : {}),
...(handle.error !== undefined ? { error: handle.error } : {}),
...(handle.completionId !== undefined ? { completionId: handle.completionId } : {}),
});
}
}
return handle.status === "completed" || handle.status === "failed" || handle.status === "killed" ? handle.status : undefined;
}
handle.status = outcome.status;
mintCompletionId(handle);
handle.notify = undefined;
handle.onReapTerminal = undefined;
for (const [, , qResolve] of handle.preAttachQueue ?? [])
qResolve?.({ ok: false, reason: "not_running" });
handle.preAttachQueue = undefined;
for (const r of [...(handle.inFlightDirect ?? [])])
r({ ok: false, reason: "not_running" });
handle.inFlightDirect = undefined;
if (outcome.status === "killed" && handle.stoppedBy === undefined) {
handle.stoppedBy = outcome.stoppedBy ?? handle.stopSource ?? "system";
}
if (outcome.result !== undefined)
handle.result = outcome.result;
if (outcome.resultFull !== undefined)
handle.resultFull = outcome.resultFull;
if (outcome.status === "killed" && outcome.result !== undefined && outcome.result !== "") {
handle.resultIsPartial = true;
}
if (outcome.error !== undefined && !(outcome.status === "killed" && outcome.error === BG_AGENT_REAP_STOP_ERROR)) {
handle.error = outcome.error;
if (outcome.errorCode !== undefined)
handle.errorCode = outcome.errorCode;
if (outcome.retryable !== undefined)
handle.errorRetryable = outcome.retryable;
if (outcome.errorKind !== undefined)
handle.errorKind = outcome.errorKind;
if (outcome.retryAfterMs !== undefined)
handle.errorRetryAfterMs = outcome.retryAfterMs;
}
handle.updatedAt = Date.now();
if (outcome.seq !== undefined)
handle.cycleSeq = outcome.seq;
core.pokeBgQuiescence(handle.owner);
durableAgentWriteLane(handle, {
status: outcome.status,
...(outcome.seq !== undefined ? { seq: outcome.seq } : {}),
settledAt: Date.now(),
...(handle.stoppedBy !== undefined ? { stoppedBy: handle.stoppedBy } : {}),
...(handle.completionId !== undefined ? { completionId: handle.completionId } : {}),
...(handle.result !== undefined ? { finalOutput: handle.result } : {}),
...(handle.resultFull !== undefined ? { finalOutputFull: handle.resultFull } : {}),
...(handle.resultIsPartial ? { resultIsPartial: true } : {}),
...(handle.error !== undefined ? { error: handle.error } : {}),
...(handle.errorCode !== undefined ? { errorCode: handle.errorCode } : {}),
...(handle.errorRetryable !== undefined ? { errorRetryable: handle.errorRetryable } : {}),
...(handle.errorKind !== undefined ? { errorKind: handle.errorKind } : {}),
...(handle.errorRetryAfterMs !== undefined ? { errorRetryAfterMs: handle.errorRetryAfterMs } : {}),
}, ["parkedCheckpointToken", "parkClaimId", "parkedAt"]);
return outcome.status;
}
export function abortBackgroundAgentsForOwnerLane(core, access, opts) {
let aborted = 0;
for (const handle of core.handles.values()) {
if (handle.type !== "background_agent" || handle.status !== "running" || !canAccess(handle, access))
continue;
if (opts?.skipSessionScoped && handle.sessionScoped)
continue;
if (opts?.sessionScopedOnly && !handle.sessionScoped)
continue;
core.markStopSource(handle.id, "parent");
handle.abort.abort();
aborted++;
}
return aborted;
}
export function resolveBackgroundAgentByNameLane(core, name, access, opts) {
const key = normalizeAgentName(name);
if (key === "")
return { status: "not_found" };
const latestOf = (pool) => {
let best;
for (const h of pool)
if (best === undefined || h.createdAt >= best.createdAt)
best = h;
return best;
};
const named = [];
for (const h of core.handles.values()) {
if (h.type !== "background_agent" || h.name === undefined || !canAccess(h, access))
continue;
if (h.name === name || normalizeAgentName(h.name) === key)
named.push(h);
}
if (opts?.preferRunning === true) {
const namedRunning = named.filter((h) => h.status === "running");
if (namedRunning.length > 1) {
return {
status: "ambiguous",
message: `Multiple RUNNING background agents match "${name}": ${namedRunning.map((h) => `${h.id} (${h.name ?? h.description ?? "unnamed"})`).join(", ")}. Use the task ID.`,
};
}
if (namedRunning.length === 1)
return { status: "found", handle: namedRunning[0] };
}
const namedWinner = latestOf(named);
if (namedWinner !== undefined)
return { status: "found", handle: namedWinner };
const exact = [];
for (const h of core.handles.values()) {
if (h.type !== "background_agent" || !canAccess(h, access))
continue;
if (h.description === name)
exact.push(h);
}
const exactRunning = exact.filter((h) => h.status === "running");
const exactPool = exactRunning.length > 0 ? exactRunning : exact;
if (exactPool.length === 1)
return { status: "found", handle: exactPool[0] };
if (exactPool.length > 1) {
return {
status: "ambiguous",
message: `Multiple background agents match "${name}": ${exactPool.map((h) => (h.description ? `${h.id} (${h.description})` : h.id)).join(", ")}. Use the task ID.`,
};
}
const matches = [];
for (const h of core.handles.values()) {
if (h.type !== "background_agent" || !canAccess(h, access))
continue;
if (h.description !== undefined && normalizeAgentName(h.description) === key)
matches.push(h);
}
const running = matches.filter((h) => h.status === "running");
const pool = running.length > 0 ? running : matches;
if (pool.length === 1)
return { status: "found", handle: pool[0] };
if (pool.length > 1) {
return {
status: "ambiguous",
message: `Multiple background agents match "${name}": ${pool.map((h) => (h.description ? `${h.id} (${h.description})` : h.id)).join(", ")}. Use the task ID.`,
};
}
const byKey = new Map();
for (const h of core.handles.values()) {
if (h.type !== "background_agent" || h.status !== "running" || !canAccess(h, access))
continue;
for (const label of [h.name, h.description]) {
if (label === undefined)
continue;
const k = normalizeAgentName(label);
if (k !== "" && !byKey.has(k))
byKey.set(k, label);
}
}
const closest = closestName(key, byKey.keys());
return { status: "not_found", ...(closest !== undefined ? { suggestion: byKey.get(closest) } : {}) };
}
export function markRetainedContinuationLane(core, id) {
const handle = core.handles.get(id);
if (handle && handle.type === "background_agent")
handle.retainedContinuation = true;
}
export function backgroundAgentCycleSeqLane(core, id) {
const handle = core.handles.get(id);
if (handle === undefined || handle.type !== "background_agent")
return undefined;
return handle.status === "parked" ? (handle.cycleSeq ?? 1) + 1 : handle.cycleSeq;
}
async function claimTerminalRowForRevive(core, store, handle, scope) {
for (let attempt = 0; attempt < 3; attempt++) {
let live;
try {
live = await store.get(handle, scope);
}
catch {
return { status: "still_running" };
}
if (live === null)
return { status: "not_found" };
if (live.status === "running" || live.status === "parked")
return { status: "still_running" };
const claimed = structuredClone(live);
claimed.status = "running";
clearRevivedRowTerminalPayload(claimed);
claimed.writerId = core.writerId;
claimed.writerEpoch = (live.writerEpoch ?? 0) + 1;
claimed.updatedAt = Date.now();
let won = false;
try {
won = await store.updateIf(handle, scope, claimed, { rev: live.rev, status: live.status });
}
catch {
let after;
try {
after = await store.get(handle, scope);
}
catch {
return { status: "still_running" };
}
if (after !== null && after.status === "running" && after.writerId === core.writerId && after.writerEpoch === claimed.writerEpoch) {
return { status: "claimed", row: after, previous: live };
}
return { status: "still_running" };
}
if (!won)
continue;
claimed.rev = live.rev + 1;
return { status: "claimed", row: claimed, previous: live };
}
return { status: "still_running" };
}
async function rollbackRevivalClaim(store, claim) {
const restored = structuredClone(claim.previous);
restored.writerEpoch = (claim.row.writerEpoch ?? 0) + 1;
restored.updatedAt = Date.now();
try {
await store.updateIf(restored.handle, restored.scope, restored, { rev: claim.row.rev, status: "running" });
}
catch {
}
}
export async function reviveBackgroundAgentLane(core, id, access, abort) {
const handle = core.handles.get(id);
if (!handle || handle.type !== "background_agent" || !canAccess(handle, access))
return { ok: false, reason: "not_found" };
if (core.reapedHandles.has(id))
return { ok: false, reason: "not_found" };
if (core.reapingHandles.has(id) || core.claimingHandles.has(id))
return { ok: false, reason: "recycling" };
if (handle.status === "running" || handle.status === "pending")
return { ok: false, reason: "still_running" };
if (handle.status === "parked")
return { ok: false, reason: "still_running" };
const lane = handle.durable;
let plainDurableWrite = lane === undefined;
if (lane !== undefined) {
core.claimingHandles.add(id);
let claim;
try {
const run = () => claimTerminalRowForRevive(core, lane.store, lane.record.handle, lane.record.scope);
const adopt = (row) => {
lane.poisoned = true;
handle.durable = { store: lane.store, record: structuredClone(row), chain: Promise.resolve(), written: true, poisoned: false, flushFailed: false };
};
if (lane.poisoned) {
claim = await run();
if (claim.status === "claimed")
adopt(claim.row);
}
else {
const p = lane.chain.then(run, run);
lane.chain = p.then((r) => {
if (r.status === "claimed")
adopt(r.row);
});
claim = await p;
}
}
finally {
core.claimingHandles.delete(id);
}
if (claim.status !== "claimed") {
if (claim.status === "not_found" && !lane.written && !lane.poisoned)
plainDurableWrite = true;
else
return { ok: false, reason: claim.status };
}
if (core.handles.get(id) !== handle) {
if (claim.status === "claimed")
await rollbackRevivalClaim(lane.store, claim);
return { ok: false, reason: "still_running" };
}
ensureDurableHeartbeatLane(core);
if (claim.status === "claimed" && typeof claim.row.seq === "number" && (handle.cycleSeq ?? 1) < claim.row.seq) {
handle.cycleSeq = claim.row.seq;
}
}
handle.status = "running";
handle.channelState = "attaching";
handle.notify = undefined;
if (abort !== undefined)
handle.abort = abort;
handle.result = undefined;
handle.resultFull = undefined;
handle.spillRef = undefined;
handle.spillFailed = undefined;
handle.error = undefined;
handle.errorCode = undefined;
handle.errorRetryable = undefined;
handle.errorKind = undefined;
handle.errorRetryAfterMs = undefined;
handle.resultIsPartial = undefined;
handle.stopSource = undefined;
handle.stoppedBy = undefined;
handle.completionId = undefined;
handle.terminalNotified = undefined;
handle.reviveCycle = (handle.reviveCycle ?? 0) + 1;
handle.cycleSeq = (handle.cycleSeq ?? 1) + 1;
handle.updatedAt = Date.now();
if (plainDurableWrite)
durableAgentWriteLane(handle, { status: "running" }, REVIVED_ROW_CLEARED_FIELDS);
return { ok: true, cycle: handle.reviveCycle };
}
export function settleRevivedAgentLane(core, id, cycle, outcome) {
return settleBackgroundAgentLane(core, id, { ...outcome, cycle });
}
export function noteBackgroundAgentActivityLane(core, id, now = Date.now()) {
const handle = core.handles.get(id);
if (!handle || handle.type !== "background_agent" || handle.status !== "running")
return;
handle.updatedAt = now;
}
export function reapStaleSessionBackgroundAgentsLane(core, staleMs, now = Date.now(), onTerminal) {
if (!Number.isFinite(staleMs) || staleMs <= 0) {
throw new Error(`reapStaleSessionBackgroundAgents: staleMs must be a positive finite number of milliseconds (got ${String(staleMs)})`);
}
let reaped = 0;
for (const handle of core.handles.values()) {
if (handle.type !== "background_agent" || handle.status !== "running" || handle.sessionScoped !== true)
continue;
if (now - handle.updatedAt <= staleMs)
continue;
core.markStopSource(handle.id, "system");
const reapTerminalNote = handle.onReapTerminal;
handle.abort.abort();
settleBackgroundAgentLane(core, handle.id, {
status: "killed",
error: STALE_RUNNING_REAP_ATTRIBUTION,
cycle: handle.reviveCycle ?? 0,
});
if (reapTerminalNote !== undefined && handle.terminalNotified !== true) {
handle.terminalNotified = true;
onTerminal?.(reapTerminalNote);
}
reaped++;
}
return reaped;
}
export function unmarkRetainedContinuationLane(core, id) {
const handle = core.handles.get(id);
if (handle && handle.type === "background_agent")
handle.retainedContinuation = false;
}
export function attachAgentNotifyLane(core, id, notify, cycle) {
const handle = core.handles.get(id);
if (!handle || handle.type !== "background_agent" || handle.status !== "running")
return;
if (cycle !== undefined && (handle.reviveCycle ?? 0) !== cycle)
return;
handle.notify = notify;
handle.channelState = "attaching";
const live = handle.preAttachQueue;
if (live !== undefined && live.length > 0) {
void (async () => {
while (handle.preAttachQueue === live && live.length > 0) {
const [qPayload, qOpts, qResolve] = live[0];
let result;
try {
const d = await notify(qPayload, qOpts);
result =
d === "parked" && handle.retainedContinuation !== true
? { ok: false, reason: "not_running" }
: d === "parked"
? { ok: true, disposition: "parked" }
: { ok: true, disposition: "queued" };
}
catch {
result = { ok: false, reason: "not_running" };
}
if (handle.preAttachQueue !== live)
return;
live.shift();
qResolve?.(result);
}
if (handle.preAttachQueue === live) {
handle.preAttachQueue = undefined;
handle.channelState = "attached";
}
})();
}
else {
handle.preAttachQueue = undefined;
handle.channelState = "attached";
}
}
export async function deliverToRunningAgentLane(core, id, access, notification, opts) {
const handle = core.handles.get(id);
if (!handle || handle.type !== "background_agent" || !canAccess(handle, access))
return { ok: false, reason: "not_found" };
if (handle.status !== "running")
return { ok: false, reason: "not_running" };
const bounded = (p, fallback, onTimeout) => new Promise((resolve) => {
const t = setTimeout(() => {
try {
onTimeout?.();
}
catch {
}
resolve(fallback);
}, core.deliverConfirmTimeoutMs);
t.unref?.();
void p.then((v) => {
clearTimeout(t);
resolve(v);
}, () => {
clearTimeout(t);
resolve(fallback);
});
});
if (handle.notify === undefined || handle.channelState === "attaching") {
if (handle.channelState !== "attaching")
return { ok: false, reason: "no_channel" };
const q = (handle.preAttachQueue ??= []);
if (q.length >= 8)
return { ok: false, reason: "queue_full" };
return bounded(new Promise((resolve) => {
q.push([notification, opts, resolve]);
}), { ok: true, disposition: "pending" });
}
let detachOnTimeout;
return await bounded(new Promise((resolve) => {
const inflight = (handle.inFlightDirect ??= new Set());
const settleOnce = (r) => {
if (!inflight.has(settleOnce))
return;
inflight.delete(settleOnce);
resolve(r);
};
inflight.add(settleOnce);
detachOnTimeout = () => inflight.delete(settleOnce);
void (async () => {
let result;
try {
const d = await handle.notify?.(notification, opts);
if (d === "parked" || d === "parked_durably") {
result = handle.retainedContinuation === true ? { ok: true, disposition: "parked" } : { ok: false, reason: "not_running" };
}
else {
result = { ok: true, disposition: "queued" };
}
}
catch {
result = { ok: false, reason: "not_running" };
}
settleOnce(result);
})();
}), { ok: true, disposition: "pending" }, () => detachOnTimeout?.());
}
export function runningBackgroundAgentLabelsLane(core, access) {
const out = [];
for (const h of core.handles.values()) {
if (h.type !== "background_agent" || h.status !== "running" || !canAccess(h, access))
continue;
const label = h.name ?? h.description;
out.push(label ? `${h.id} (${label})` : h.id);
}
return out;
}
export function runningAgentFooterLane(core, access) {
const named = [];
const background = [];
for (const h of core.handles.values()) {
if (h.type !== "background_agent" || h.status !== "running" || !canAccess(h, access))
continue;
if (h.name !== undefined && h.name !== "") {
named.push(h.name);
continue;
}
background.push(h.description ? `${h.id} (${h.description})` : h.id);
}
return { named, background };
}
export function notFoundRunningAgentsTail(footer) {
return ((footer.named.length > 0 ? `. Running named agents: ${footer.named.join(", ")}` : "") +
(footer.background.length > 0 ? `. Running background agents: ${footer.background.join(", ")}` : ""));
}
export function buildAgentPollDetails(input) {
const failed = input.status === "failed";
return {
task_id: input.taskId,
type: "background_agent",
status: input.status,
retrieval_status: input.retrievalStatus,
...(input.seq !== undefined ? { seq: input.seq } : {}),
...(input.stoppedBy !== undefined ? { stoppedBy: input.stoppedBy } : {}),
...(failed && input.error !== undefined ? { error: delimitUntrusted("agent error", boundedRedactedSummary(input.error, 300)) } : {}),
...(failed && input.errorCode !== undefined ? { errorCode: input.errorCode } : {}),
...(failed && input.errorRetryable !== undefined ? { retryable: input.errorRetryable } : {}),
...(failed && input.errorRetryAfterMs !== undefined ? { retryAfterMs: input.errorRetryAfterMs } : {}),
...(input.resultIsPartial === true ? { partial_result: true } : {}),
...(input.completionId !== undefined ? { completionId: input.completionId } : {}),
...(input.agentState !== undefined ? { agentState: input.agentState } : {}),
};
}
export function serveDurableAgentRowLane(row, agentState) {
const stateLine = agentState !== undefined ? `state: ${agentStateSummary(agentState)}\n` : "";
if (row.status === "parked") {
return {
content: delimitUntrusted(`TaskOutput ${row.handle}`, `status: parked
${stateLine}The agent is durably suspended, waiting for an approval decision. It resumes when the pending approval is decided (durable approval inbox), or lands failed if the approval expires.`),
details: buildAgentPollDetails({
taskId: row.handle,
status: "parked",
retrievalStatus: "success",
...(row.seq !== undefined ? { seq: row.seq } : {}),
...(agentState !== undefined ? { agentState } : {}),
}),
};
}
const kindClause = row.status === "failed" && row.errorKind !== undefined && row.errorRetryable !== undefined
? ` (error_kind: ${row.errorKind}, retryable: ${row.errorRetryable}${row.errorRetryAfterMs !== undefined ? `, retry_after_ms: ${row.errorRetryAfterMs}` : ""})`
: "";
const body = `status: ${row.status}
${stateLine}${row.error ? `error: ${row.error}${kindClause}
` : ""}${row.finalOutput ? `--- result${row.resultIsPartial ? " (partial — produced before the task was stopped)" : ""} ---
${clipTaskOutput(row.finalOutputFull ?? row.finalOutput)}` : "(no result text)"}`;
return {
content: delimitUntrusted(`TaskOutput ${row.handle}`, body),
details: buildAgentPollDetails({
taskId: row.handle,
status: row.status,
retrievalStatus: "success",
...(row.seq !== undefined ? { seq: row.seq } : {}),
...(row.stoppedBy !== undefined ? { stoppedBy: row.stoppedBy } : {}),
...(row.error !== undefined ? { error: row.error } : {}),
...(row.errorCode !== undefined ? { errorCode: row.errorCode } : {}),
...(row.errorRetryable !== undefined ? { errorRetryable: row.errorRetryable } : {}),
...(row.errorRetryAfterMs !== undefined ? { errorRetryAfterMs: row.errorRetryAfterMs } : {}),
...(row.resultIsPartial === true ? { resultIsPartial: true } : {}),
...(row.completionId !== undefined ? { completionId: row.completionId } : {}),
...(agentState !== undefined ? { agentState } : {}),
}),
...(row.status === "failed" ? { isError: true } : {}),
};
}
const AGENT_SPILL_FAILED_NOTE = "\n\n[full output could not be spilled to the offload store (the write failed or went unconfirmed) — no ref is available to read the dropped middle back.]";
export async function spillClippedAgentResult(handle, full, clipped, store, sessionId) {
if (clipped === full)
return clipped;
if (store === undefined)
return clipped;
const disclose = (ref) => `${clipped}\n\n[full output persisted — call ${OFFLOAD_TOOL_NAME} with ref "${ref}" to read it back.]`;
if (handle.spillRef !== undefined)
return disclose(handle.spillRef);
if (handle.spillFailed === true)
return `${clipped}${AGENT_SPILL_FAILED_NOTE}`;
const mintCycle = handle.reviveCycle ?? 0;
const ref = buildToolResultRef(sessionId ?? "no-session", handle.id, `c${mintCycle}`);
try {
await store.put(ref, full, sessionId === undefined ? undefined : toolResultProvenanceOf(sessionId));
}
catch {
if ((handle.reviveCycle ?? 0) === mintCycle) {
if (handle.spillRef !== undefined)
return disclose(handle.spillRef);
handle.spillFailed = true;
}
return `${clipped}${AGENT_SPILL_FAILED_NOTE}`;
}
if ((handle.reviveCycle ?? 0) === mintCycle)
handle.spillRef = ref;
return disclose(ref);
}
export async function pollBackgroundAgentLane(handle, deadline, signal, oneShot, store, sessionId, checkpointSeat) {
while (handle.status === "running" && deadline !== undefined && Date.now() < deadline && !signal?.aborted) {
await sleepPollStep(deadline, signal);
}
const running = handle.status === "running";
const retrieval = running && deadline !== undefined && Date.now() >= deadline ? "timeout" : "success";
if (handle.status === "parked") {
const parkedSource = agentStateSourceOfHandle(handle);
const parkedSeq = handle.cycleSeq;
const agentState = await readAgentState(parkedSource, checkpointSeat, Date.now());
return {
content: delimitUntrusted(`TaskOutput ${handle.id}`, `status: parked
state: ${agentStateSummary(agentState)}
The agent is durably suspended, waiting for an approval decision. It resumes when the pending approval is decided (durable approval inbox), or lands failed if the approval expires.`),
details: buildAgentPollDetails({
taskId: handle.id,
status: "parked",
retrievalStatus: "success",
...(parkedSeq !== undefined ? { seq: parkedSeq } : {}),
agentState,
}),
};
}
const snap = {
status: handle.status,
result: handle.result,
resultIsPartial: handle.resultIsPartial,
error: handle.error,
errorKind: handle.errorKind,
errorCode: handle.errorCode,
errorRetryable: handle.errorRetryable,
errorRetryAfterMs: handle.errorRetryAfterMs,
cycleSeq: handle.cycleSeq,
stoppedBy: handle.stoppedBy,
completionId: handle.completionId,
updatedAt: handle.updatedAt,
};
const stateRead = readAgentState(agentStateSourceOfHandle({ status: snap.status, updatedAt: snap.updatedAt }), checkpointSeat, Date.now());
const agentState = stateRead instanceof Promise ? await stateRead : stateRead;
const fullResult = snap.result ? (handle.resultFull ?? snap.result) : undefined;
const resultText = fullResult !== undefined ? await spillClippedAgentResult(handle, fullResult, clipTaskOutput(fullResult, handle.outputFile), store, sessionId) : undefined;
const kindClause = snap.status === "failed" && snap.errorKind !== undefined && snap.errorRetryable !== undefined
? ` (error_kind: ${snap.errorKind}, retryable: ${snap.errorRetryable}${snap.errorRetryAfterMs !== undefined ? `, retry_after_ms: ${snap.errorRetryAfterMs}` : ""})`
: "";
const stateLine = `state: ${agentStateSummary(agentState)}\n`;
const body = running
? oneShot === true
? `status: running
${stateLine}This is a ONE-SHOT submission — there is no later turn for a background notification to land in, so do NOT end your turn expecting one. Actively wait instead: TaskOutput({ task_id: "${handle.id}", block: true }). If it is still running after the wait, wait again (bounded) rather than ending the turn, or write out your best available answer now if you are near your own time budget.`
: `status: running
${stateLine}The agent is still working — you will be notified when it completes.`
: `status: ${snap.status}
${stateLine}${snap.error ? `error: ${snap.error}${kindClause}
` : ""}${snap.result ? `--- result${snap.resultIsPartial ? " (partial — produced before the task was stopped)" : ""} ---
${resultText}` : "(no result text)"}`;
return {
content: delimitUntrusted(`TaskOutput ${handle.id}`, body),
details: buildAgentPollDetails({
taskId: handle.id,
status: snap.status,
retrievalStatus: retrieval,
...(snap.cycleSeq !== undefined ? { seq: snap.cycleSeq } : {}),
...(snap.stoppedBy !== undefined ? { stoppedBy: snap.stoppedBy } : {}),
...(snap.error !== undefined ? { error: snap.error } : {}),
...(snap.errorCode !== undefined ? { errorCode: snap.errorCode } : {}),
...(snap.errorRetryable !== undefined ? { errorRetryable: snap.errorRetryable } : {}),
...(snap.errorRetryAfterMs !== undefined ? { errorRetryAfterMs: snap.errorRetryAfterMs } : {}),
...(snap.resultIsPartial === true ? { resultIsPartial: true } : {}),
...(snap.completionId !== undefined ? { completionId: snap.completionId } : {}),
agentState,
}),
...(snap.status === "failed" ? { isError: true } : {}),
};
}
export async function stopBackgroundAgentLane(core, handle) {
const entryStatus = handle.status;
if (handle.status === "parked") {
const arbiter = handle.resolveParkedStop;
if (arbiter === undefined) {
return {
content: `${handle.id} is parked on a pending approval — stop it by deciding (deny/expire) the pending approval in the durable approval inbox.`,
details: { task_id: handle.id, type: "background_agent", status: "parked", retrieval_status: "not_ready", error: "parked_pending_approval", code: "parked_pending_approval" },
};
}
let stopWon = false;
let arbiterUnreachable = false;
try {
stopWon = await arbiter();
}
catch {
stopWon = false;
arbiterUnreachable = true;
}
if (stopWon && handle.status === "parked") {
core.markStopSource(handle.id, "parent");
handle.status = "killed";
handle.stoppedBy = handle.stopSource ?? "parent";
handle.updatedAt = Date.now();
mintCompletionId(handle);
handle.parkedCheckpointToken = undefined;
handle.resolveParkedStop = undefined;
core.pokeBgQuiescence(handle.owner);
{
const lane = handle.durable;
if (lane !== undefined) {
try {
const live = await lane.store.get(handle.id, lane.record.scope);
if (live && (live.status === "parked" || live.status === "running")) {
const term = structuredClone(live);
term.status = "killed";
if (handle.stoppedBy !== undefined)
term.stoppedBy = handle.stoppedBy;
term.settledAt = Date.now();
term.updatedAt = Date.now();
delete term.parkedCheckpointToken;
delete term.parkClaimId;
delete term.parkedAt;
await lane.store.update(handle.id, lane.record.scope, term, { rev: live.rev });
}
}
catch {
}
}
}
durableAgentWriteLane(handle, {
status: "killed",
settledAt: Date.now(),
...(handle.stoppedBy !== undefined ? { stoppedBy: handle.stoppedBy } : {}),
...(handle.completionId !== undefined ? { completionId: handle.completionId } : {}),
}, ["parkedCheckpointToken", "parkClaimId"]);
return {
content: `Terminated ${handle.id} (pending approval expired).`,
details: {
task_id: handle.id,
type: "background_agent",
status: "killed",
retrieval_status: "success",
...(handle.cycleSeq !== undefined ? { seq: handle.cycleSeq } : {}),
...(handle.stoppedBy !== undefined ? { stoppedBy: handle.stoppedBy } : {}),
...(handle.completionId !== undefined ? { completionId: handle.completionId } : {}),
},
};
}
if (arbiterUnreachable) {
return {
content: `${handle.id} was not stopped: the approval arbitration store was unreachable — the row stays parked; retry the stop.`,
details: { task_id: handle.id, type: "background_agent", status: handle.status, retrieval_status: "not_ready", error: "park_arbiter_unreachable", code: "park_arbiter_unreachable" },
isError: true,
};
}
return {
content: `${handle.id} was not stopped: its pending approval was already consumed (a resume won the arbitration).`,
details: { task_id: handle.id, type: "background_agent", status: handle.status, retrieval_status: "not_ready", error: "park_resume_won", code: "park_resume_won" },
isError: true,
};
}
if (handle.status === "running") {
core.markStopSource(handle.id, "parent");
handle.abort.abort();
handle.status = "killed";
handle.stoppedBy = handle.stopSource ?? "parent";
handle.updatedAt = Date.now();
mintCompletionId(handle);
handle.notify = undefined;
for (const [, , qResolve] of handle.preAttachQueue ?? [])
qResolve?.({ ok: false, reason: "not_running" });
handle.preAttachQueue = undefined;
for (const r of [...(handle.inFlightDirect ?? [])])
r({ ok: false, reason: "not_running" });
handle.inFlightDirect = undefined;
core.pokeBgQuiescence(handle.owner);
durableAgentWriteLane(handle, {
status: "killed",
settledAt: Date.now(),
...(handle.stoppedBy !== undefined ? { stoppedBy: handle.stoppedBy } : {}),
...(handle.completionId !== undefined ? { completionId: handle.completionId } : {}),
});
}
return {
content: entryStatus === "running" ? `Terminated ${handle.id}.` : alreadyTerminalStopNote(handle.id, handle.status),
details: {
task_id: handle.id,
type: "background_agent",
status: handle.status,
retrieval_status: "success",
...(handle.cycleSeq !== undefined ? { seq: handle.cycleSeq } : {}),
...(handle.status === "killed" && handle.stoppedBy !== undefined ? { stoppedBy: handle.stoppedBy } : {}),
...(handle.completionId !== undefined ? { completionId: handle.completionId } : {}),
},
};
}