@sema-agent/core 7.11.1 → 7.12.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 +41 -0
- package/dist/core/auto-mode-arming.d.ts +10 -14
- package/dist/core/auto-mode-arming.js +3 -9
- package/dist/core/auto-mode-defaults.d.ts +0 -2
- package/dist/core/auto-mode-defaults.js +0 -1
- package/dist/core/auto-mode-rebuild.d.ts +6 -13
- package/dist/core/auto-mode-rebuild.js +0 -2
- package/dist/core/auto-mode.d.ts +30 -89
- package/dist/core/auto-mode.js +12 -59
- package/dist/core/checkpoint-store.d.ts +1 -3
- package/dist/core/gate-fold.js +1 -9
- package/dist/core/gate-lanes.js +15 -9
- package/dist/core/hooks.d.ts +6 -0
- package/dist/core/runner/compaction-knobs.d.ts +45 -0
- package/dist/core/runner/compaction-knobs.js +3 -0
- package/dist/core/runner/contracts.d.ts +49 -10
- package/dist/core/runner/denial-limit-arms.d.ts +10 -13
- package/dist/core/runner/denial-limit-arms.js +9 -7
- package/dist/core/runner/gate-exit.js +9 -1
- package/dist/core/runner/prepare-caps-and-workflow.d.ts +1 -1
- package/dist/core/runner/prepare-caps-and-workflow.js +0 -5
- package/dist/core/runner/prepare-suspend-saga.d.ts +0 -2
- package/dist/core/runner/prepare-suspend-saga.js +2 -10
- package/dist/core/runner/prepare-task.js +1 -1
- package/dist/core/runner/prepare-wiring-manifest.d.ts +1 -1
- package/dist/core/runner/prepare-wiring-manifest.js +1 -8
- package/dist/core/runner/run-attachment-seats.d.ts +22 -0
- package/dist/core/runner/run-attachment-seats.js +187 -0
- package/dist/core/runner/run-brain-sinks.d.ts +29 -0
- package/dist/core/runner/run-brain-sinks.js +61 -0
- package/dist/core/runner/run-clock-and-content.d.ts +52 -0
- package/dist/core/runner/run-clock-and-content.js +26 -0
- package/dist/core/runner/run-compaction-machinery.d.ts +35 -0
- package/dist/core/runner/run-compaction-machinery.js +98 -0
- package/dist/core/runner/run-git-lane.d.ts +64 -0
- package/dist/core/runner/run-git-lane.js +102 -0
- package/dist/core/runner/run-identity-wiring.d.ts +77 -0
- package/dist/core/runner/run-identity-wiring.js +85 -0
- package/dist/core/runner/run-leg.d.ts +106 -0
- package/dist/core/runner/run-leg.js +462 -0
- package/dist/core/runner/run-notification-lane.d.ts +55 -0
- package/dist/core/runner/run-notification-lane.js +128 -0
- package/dist/core/runner/run-reasoning-seat.d.ts +27 -0
- package/dist/core/runner/run-reasoning-seat.js +48 -0
- package/dist/core/runner/run-recovery-lanes.d.ts +54 -0
- package/dist/core/runner/run-recovery-lanes.js +180 -0
- package/dist/core/runner/run-settle-and-teardown.d.ts +109 -0
- package/dist/core/runner/run-settle-and-teardown.js +324 -0
- package/dist/core/runner/run-stop-and-final-verify.d.ts +32 -0
- package/dist/core/runner/run-stop-and-final-verify.js +159 -0
- package/dist/core/runner/run-telemetry-and-budget-seats.d.ts +38 -0
- package/dist/core/runner/run-telemetry-and-budget-seats.js +159 -0
- package/dist/core/runner/run-terminal-adoption.d.ts +99 -0
- package/dist/core/runner/run-terminal-adoption.js +120 -0
- package/dist/core/runner/run-tool-mount-facts.d.ts +26 -0
- package/dist/core/runner/run-tool-mount-facts.js +58 -0
- package/dist/core/runner/run-turn-boundary.d.ts +0 -35
- package/dist/core/runner/run-turn-boundary.js +1 -3
- package/dist/core/runner/runtask.d.ts +14 -3
- package/dist/core/runner/runtask.js +125 -2102
- package/dist/core/runner-deps.d.ts +4 -14
- package/dist/core/store-contracts/workflow-journal-store-contract.d.ts +7 -0
- package/dist/core/store-contracts/workflow-journal-store-contract.js +85 -0
- package/dist/core/tool-policy.d.ts +37 -93
- package/dist/core/tool-policy.js +1 -11
- package/dist/core/trace.d.ts +6 -7
- package/dist/core/wiring-manifest.d.ts +5 -22
- package/dist/core/wiring-manifest.js +3 -11
- package/dist/core/workflow-journal-store.d.ts +35 -4
- package/dist/core/workflow-journal-store.js +19 -2
- package/dist/index.d.ts +3 -2
- package/dist/index.js +3 -2
- package/dist/orchestration/workflow.js +2 -0
- package/dist/stores/file/workflow-journal-store.d.ts +7 -10
- package/dist/stores/file/workflow-journal-store.js +2 -4
- package/dist/tools/fs/fs-bash.js +3 -2
- package/package.json +1 -1
- package/test/export-surface.snapshot.json +10 -10
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import { GIT_STATUS_ECHO_PREVIEW } from "./git-status-frame.js";
|
|
2
|
+
import { wrapGitFrame } from "./git-leg-delivery.js";
|
|
3
|
+
export function runGitLane(input) {
|
|
4
|
+
const { prepared, queue, rs, ident, onMessageUpdate, onMessageEnd, onToolStart, onToolEnd, onTurnEnd, onTurnBoundary, runner } = input;
|
|
5
|
+
prepared.gitStatusRef.reassert = async () => {
|
|
6
|
+
const ref = prepared.gitStatusRef;
|
|
7
|
+
const frame = ref.frame;
|
|
8
|
+
if (frame === undefined)
|
|
9
|
+
return;
|
|
10
|
+
delete ref.mirrorOwed;
|
|
11
|
+
const use = ref.overBudgetShrunk && frame.shrunk !== undefined
|
|
12
|
+
? { kind: "degraded", body: frame.shrunk.body, hash: frame.shrunk.hash }
|
|
13
|
+
: { kind: frame.kind, body: frame.body, hash: frame.hash };
|
|
14
|
+
const wrapped = wrapGitFrame(use.body, prepared.reminderMark);
|
|
15
|
+
try {
|
|
16
|
+
const entryId = await prepared.session.appendMessage({
|
|
17
|
+
role: "user",
|
|
18
|
+
content: [{ type: "text", text: wrapped }],
|
|
19
|
+
timestamp: Date.now(),
|
|
20
|
+
engineMinted: true,
|
|
21
|
+
});
|
|
22
|
+
ref.announced = { kind: use.kind, hash: use.hash, entryId };
|
|
23
|
+
ref.protectedText = wrapped;
|
|
24
|
+
if (use.kind === "full" && frame.shrunk !== undefined) {
|
|
25
|
+
ref.wrappedShrink = { find: wrapped, replace: wrapGitFrame(frame.shrunk.body, prepared.reminderMark) };
|
|
26
|
+
}
|
|
27
|
+
else {
|
|
28
|
+
delete ref.wrappedShrink;
|
|
29
|
+
}
|
|
30
|
+
queue.push({ type: "steering_injected", source: "git_status", preview: GIT_STATUS_ECHO_PREVIEW[use.kind], ...ident() });
|
|
31
|
+
rs.attach.attachmentsInjected += 1;
|
|
32
|
+
try {
|
|
33
|
+
await prepared.session.appendGitAnnouncement?.({ kind: use.kind, hash: use.hash, entryId });
|
|
34
|
+
}
|
|
35
|
+
catch (mirrorErr) {
|
|
36
|
+
try {
|
|
37
|
+
runner.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 });
|
|
38
|
+
}
|
|
39
|
+
catch {
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
catch (err) {
|
|
44
|
+
ref.announced = { kind: use.kind, hash: use.hash, pending: true };
|
|
45
|
+
try {
|
|
46
|
+
runner.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 });
|
|
47
|
+
}
|
|
48
|
+
catch {
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
};
|
|
52
|
+
const flushGitMirror = async () => {
|
|
53
|
+
const owed = prepared.gitStatusRef.mirrorOwed;
|
|
54
|
+
if (owed === undefined)
|
|
55
|
+
return;
|
|
56
|
+
if (prepared.gitStatusRef.overBudgetShrunk && owed.kind === "full") {
|
|
57
|
+
delete prepared.gitStatusRef.mirrorOwed;
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
delete prepared.gitStatusRef.mirrorOwed;
|
|
61
|
+
try {
|
|
62
|
+
await prepared.session.appendGitAnnouncement?.(owed);
|
|
63
|
+
}
|
|
64
|
+
catch (mirrorErr) {
|
|
65
|
+
prepared.gitStatusRef.mirrorOwed = owed;
|
|
66
|
+
try {
|
|
67
|
+
runner.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 });
|
|
68
|
+
}
|
|
69
|
+
catch {
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
};
|
|
73
|
+
const unsubGitRetry = prepared.harness.on("turn_boundary", async () => {
|
|
74
|
+
await flushGitMirror();
|
|
75
|
+
if (prepared.gitStatusRef.announced?.pending === true)
|
|
76
|
+
await prepared.gitStatusRef.reassert?.();
|
|
77
|
+
return undefined;
|
|
78
|
+
});
|
|
79
|
+
const unsubBoundary = prepared.harness.on("turn_boundary", onTurnBoundary);
|
|
80
|
+
const unsub = prepared.harness.subscribe((event) => {
|
|
81
|
+
switch (event.type) {
|
|
82
|
+
case "message_update":
|
|
83
|
+
onMessageUpdate(event);
|
|
84
|
+
break;
|
|
85
|
+
case "message_end":
|
|
86
|
+
onMessageEnd(event);
|
|
87
|
+
break;
|
|
88
|
+
case "tool_execution_start":
|
|
89
|
+
onToolStart(event);
|
|
90
|
+
break;
|
|
91
|
+
case "tool_execution_end":
|
|
92
|
+
onToolEnd(event);
|
|
93
|
+
break;
|
|
94
|
+
case "turn_end":
|
|
95
|
+
onTurnEnd();
|
|
96
|
+
break;
|
|
97
|
+
default:
|
|
98
|
+
break;
|
|
99
|
+
}
|
|
100
|
+
});
|
|
101
|
+
return { flushGitMirror, unsubGitRetry, unsubBoundary, unsub };
|
|
102
|
+
}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import type { PeerInboundChainRef } from "../../agents/peer-admission.js";
|
|
2
|
+
import { type PendingSessionNotifications, type SystemInjectionPriority, type TaskNotificationPayload } from "../task-notification.js";
|
|
3
|
+
import type { PushQueue } from "../push-queue.js";
|
|
4
|
+
import type { TaskEvent, TaskSpec } from "../types.js";
|
|
5
|
+
import type { Stats } from "./assemble-result.js";
|
|
6
|
+
import type { CaptureOptOutRef, LiveHandle, ManualCompactRef, NotificationLaneBindings, NotifyRef, Prepared, RunInternals, RunnerDepsSeat, TaskIdRef } from "./contracts.js";
|
|
7
|
+
export interface RunIdentityWiringInput {
|
|
8
|
+
/** borrowed-readonly — the task spec: the task id and the memory / notification seats it names. */
|
|
9
|
+
spec: TaskSpec;
|
|
10
|
+
/** borrowed-mutable — the run's event queue: the manifest, roster-delta, compaction_outcome and redelivered
|
|
11
|
+
* task_notification frames. */
|
|
12
|
+
queue: PushQueue<TaskEvent>;
|
|
13
|
+
/** borrowed-mutable — the leg's prepared seat: the harness sinks (`onUndrainedEngineNotes`, `engineInjectionsHeld`,
|
|
14
|
+
* `onUndrainedUserInputs`, `onEngineNoteConsumed`) are installed, `nextTurn` is appended to; the ids, the identity
|
|
15
|
+
* envelope, the hold refs, the memory session and the listing / roster faces are read. */
|
|
16
|
+
prepared: Prepared;
|
|
17
|
+
/** borrowed-readonly — the trusted run-scoped channel: `parentToolCallId`, `onNotifyInjectorReady`. */
|
|
18
|
+
internals: RunInternals | undefined;
|
|
19
|
+
/** borrowed-mutable — the stream layer's backstop carrier: the memory scopes, the edited-files reader and the
|
|
20
|
+
* owed delegation terminal are published here the moment they exist. */
|
|
21
|
+
taskIdRef: TaskIdRef | undefined;
|
|
22
|
+
/** borrowed-readonly — the stream layer's readiness callback, fired ONCE with the live-task handle. */
|
|
23
|
+
onReady: (handle: LiveHandle) => void;
|
|
24
|
+
/** borrowed-mutable — the manual /compact seat: its mooted-frame channel is installed here. */
|
|
25
|
+
manualCompactRef: ManualCompactRef;
|
|
26
|
+
/** borrowed-mutable — the notify() bridge: `inject` is bound here (absent on the public path). */
|
|
27
|
+
notifyRef: NotifyRef | undefined;
|
|
28
|
+
/** borrowed-mutable — the capture opt-out bridge: `flip` is bound here when a memory session mounted. */
|
|
29
|
+
captureOptOutRef: CaptureOptOutRef | undefined;
|
|
30
|
+
/** borrowed-readonly — the notification lane's ONE injection entry (the R0 lane's). */
|
|
31
|
+
injectTaskNotification: (notification: TaskNotificationPayload, opts?: {
|
|
32
|
+
priority?: SystemInjectionPriority;
|
|
33
|
+
}) => Promise<"queued" | "parked" | "dropped_duplicate">;
|
|
34
|
+
/** borrowed-mutable — the turn-open dedup set (the cross-layer double-park dedup): a redelivered frame's key is registered here. */
|
|
35
|
+
deliveredAtTurnOpen: Set<string>;
|
|
36
|
+
/** borrowed-mutable — design/176: the peer inbound chain, overwritten by each consumed peer-class payload. */
|
|
37
|
+
peerInboundChainRef: PeerInboundChainRef;
|
|
38
|
+
/** borrowed-mutable — the notification lane's bindings seat (its own `let`s behind getters / setters, never a copy):
|
|
39
|
+
* this lane binds the harness, the session anchor and the identity mint the lane's closures read, and reads the
|
|
40
|
+
* anchor back in the undrained-notes sink. */
|
|
41
|
+
notificationLane: NotificationLaneBindings;
|
|
42
|
+
/** borrowed-mutable — the Runner's per-session parked-notification store: drained at turn open, re-pended on failure. */
|
|
43
|
+
pendingSessionNotifications: PendingSessionNotifications;
|
|
44
|
+
/** borrowed-readonly — the Runner's deployment deps, read LIVE (`onDelegationLifecycle`, `onNotice`). */
|
|
45
|
+
runner: RunnerDepsSeat;
|
|
46
|
+
}
|
|
47
|
+
export interface RunIdentityWiringResult {
|
|
48
|
+
/** The run's canonical task id (`spec.taskId ?? sessionId`) — one source, shared with `ident()`. */
|
|
49
|
+
runSourceTaskId: string;
|
|
50
|
+
/** The spawning tool call's id when this task runs AS A SUB-AGENT; undefined on a top-level run. */
|
|
51
|
+
parentToolCallId: string | undefined;
|
|
52
|
+
/** The event-identity mint: a fresh eventId per event, plus the sub-agent attribution when there is one. */
|
|
53
|
+
ident: () => {
|
|
54
|
+
eventId: string;
|
|
55
|
+
parentToolCallId?: string;
|
|
56
|
+
sourceTaskId?: string;
|
|
57
|
+
};
|
|
58
|
+
/** #281 件B: the delegation-lifecycle emission closure both stations share (spawn here, terminal in the driver). */
|
|
59
|
+
emitDelegationLifecycle: (event: import("../types.js").DelegationLifecycleEvent) => void;
|
|
60
|
+
/** The loop-liveness latch and the two attribution seats (ended / userInterrupted / userHalted). */
|
|
61
|
+
loopLatch: {
|
|
62
|
+
ended: boolean;
|
|
63
|
+
userInterrupted: boolean;
|
|
64
|
+
userHalted: boolean;
|
|
65
|
+
};
|
|
66
|
+
/** This leg's usage counters, zeroed here; the harness-handlers lane is their writer from the first turn on. */
|
|
67
|
+
stats: Stats;
|
|
68
|
+
/** backlog #389 — the held agent_end account, a READ FACE over this lane's own `let` (the undrained-inputs sink writes it
|
|
69
|
+
* when the run committed a durable park); the terminal-adoption lane settles it minus what the park carried. */
|
|
70
|
+
undrainedUserAtEnd: {
|
|
71
|
+
readonly current: {
|
|
72
|
+
steer: number;
|
|
73
|
+
followUp: number;
|
|
74
|
+
} | undefined;
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
export declare function runIdentityWiring(input: RunIdentityWiringInput): RunIdentityWiringResult;
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import { uuidv7 } from "../../internal/harness.js";
|
|
2
|
+
import { createSafeNotifier } from "../safe-notify.js";
|
|
3
|
+
import { discloseDroppedPending, renderTaskNotificationXml, taskNotificationDedupKey } from "../task-notification.js";
|
|
4
|
+
import { deliverDelegationLifecycle, deliverEngineNotice, undrainedUserInputNotices } from "../types.js";
|
|
5
|
+
export function runIdentityWiring(input) {
|
|
6
|
+
const { spec, queue, prepared, internals, taskIdRef, onReady, manualCompactRef, notifyRef, captureOptOutRef, injectTaskNotification, deliveredAtTurnOpen, peerInboundChainRef, notificationLane, pendingSessionNotifications, runner } = input;
|
|
7
|
+
notificationLane.harness = prepared.harness;
|
|
8
|
+
notificationLane.sessionId = prepared.sessionId;
|
|
9
|
+
if (taskIdRef)
|
|
10
|
+
taskIdRef.effectiveMemoryScopes = prepared.effectiveMemoryScopes;
|
|
11
|
+
if (taskIdRef)
|
|
12
|
+
taskIdRef.editedFiles = prepared.editedFilesSnapshot;
|
|
13
|
+
const runSourceTaskId = spec.taskId ?? prepared.sessionId;
|
|
14
|
+
const parentToolCallId = internals?.parentToolCallId;
|
|
15
|
+
const ident = () => parentToolCallId !== undefined ? { eventId: uuidv7(), parentToolCallId, sourceTaskId: runSourceTaskId } : { eventId: uuidv7() };
|
|
16
|
+
notificationLane.ident = ident;
|
|
17
|
+
queue.push({ type: "wiring_manifest", manifest: prepared.wiringManifest, ...ident() });
|
|
18
|
+
prepared.toolRosterDeltas.subscribe((delta) => queue.push({ type: "tool_roster_delta", delta, ...ident() }));
|
|
19
|
+
const delegationLifecycleNotifier = createSafeNotifier({
|
|
20
|
+
onError: (f) => console.warn(`[sema-core] ${f.site}: delegation-lifecycle observer threw (contained; further failures counted, not re-disclosed): ${f.error.message}`),
|
|
21
|
+
});
|
|
22
|
+
const emitDelegationLifecycle = (event) => {
|
|
23
|
+
if (!prepared.hookIdentity.isDelegatedChild)
|
|
24
|
+
return;
|
|
25
|
+
if (runner.deps.onDelegationLifecycle === undefined)
|
|
26
|
+
return;
|
|
27
|
+
deliverDelegationLifecycle(runner.deps.onDelegationLifecycle, event, delegationLifecycleNotifier, "runtask.onDelegationLifecycle");
|
|
28
|
+
};
|
|
29
|
+
emitDelegationLifecycle({ phase: "spawn", identity: prepared.hookIdentity });
|
|
30
|
+
if (taskIdRef !== undefined && prepared.hookIdentity.isDelegatedChild && runner.deps.onDelegationLifecycle !== undefined) {
|
|
31
|
+
taskIdRef.delegationTerminalOwed = prepared.hookIdentity;
|
|
32
|
+
}
|
|
33
|
+
manualCompactRef.emitMooted = (reason) => {
|
|
34
|
+
queue.push({ type: "compaction_outcome", outcome: "mooted", trigger: "manual", reason, ...ident() });
|
|
35
|
+
};
|
|
36
|
+
prepared.harness.onUndrainedEngineNotes = (payloads) => {
|
|
37
|
+
if (notificationLane.sessionId === undefined)
|
|
38
|
+
return;
|
|
39
|
+
for (const p of payloads)
|
|
40
|
+
pendingSessionNotifications.pend(notificationLane.sessionId, p);
|
|
41
|
+
};
|
|
42
|
+
prepared.harness.engineInjectionsHeld = () => prepared.batchHaltRef.current !== undefined;
|
|
43
|
+
let undrainedUserAtEnd;
|
|
44
|
+
prepared.harness.onUndrainedUserInputs = (counts) => {
|
|
45
|
+
if (prepared.pausedRef.current !== undefined) {
|
|
46
|
+
undrainedUserAtEnd = counts;
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
for (const notice of undrainedUserInputNotices(counts, spec.taskId ?? prepared.sessionId, prepared.sessionId, prepared.runId)) {
|
|
50
|
+
deliverEngineNotice(runner.deps.onNotice, notice);
|
|
51
|
+
}
|
|
52
|
+
};
|
|
53
|
+
prepared.harness.onEngineNoteConsumed = (p) => {
|
|
54
|
+
const peer = p?.peer;
|
|
55
|
+
if (peer !== undefined && Array.isArray(peer.hopChain))
|
|
56
|
+
peerInboundChainRef.current = [...peer.hopChain];
|
|
57
|
+
};
|
|
58
|
+
if (notifyRef)
|
|
59
|
+
notifyRef.inject = injectTaskNotification;
|
|
60
|
+
if (captureOptOutRef && prepared.memoryEngineSession?.captureOptOut !== undefined) {
|
|
61
|
+
captureOptOutRef.flip = prepared.memoryEngineSession.captureOptOut.flip;
|
|
62
|
+
}
|
|
63
|
+
try {
|
|
64
|
+
internals?.onNotifyInjectorReady?.(injectTaskNotification);
|
|
65
|
+
}
|
|
66
|
+
catch {
|
|
67
|
+
}
|
|
68
|
+
{
|
|
69
|
+
const pendingIdle = pendingSessionNotifications.drain(prepared.sessionId);
|
|
70
|
+
if (pendingIdle !== undefined) {
|
|
71
|
+
for (const payload of discloseDroppedPending(pendingIdle)) {
|
|
72
|
+
const parkedPriority = pendingIdle.priorities?.get(payload);
|
|
73
|
+
deliveredAtTurnOpen.add(taskNotificationDedupKey(payload));
|
|
74
|
+
queue.push({ type: "task_notification", notification: payload, ...(parkedPriority !== undefined ? { priority: parkedPriority } : {}), ...ident() });
|
|
75
|
+
void prepared.harness.nextTurn(renderTaskNotificationXml(payload), { provenance: "engine-note", enginePayload: payload }).catch(() => {
|
|
76
|
+
pendingSessionNotifications.pend(prepared.sessionId, payload, parkedPriority);
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
const loopLatch = { ended: false, userInterrupted: false, userHalted: false };
|
|
82
|
+
onReady({ harness: prepared.harness, abortController: prepared.abortController, loop: loopLatch, reminderMark: prepared.reminderMark, sessionId: prepared.sessionId, runId: prepared.runId, hookTimeoutMs: prepared.hookTimeoutMs, hookIdentity: prepared.hookIdentity });
|
|
83
|
+
const stats = { turns: 0, tokens: 0, toolCalls: 0, promptTokens: 0, totalInputTokens: 0, cachedTokens: 0, cacheWriteTokens: 0, cacheWriteTokensLong: 0, outputTokens: 0, costMicroUsd: 0 };
|
|
84
|
+
return { runSourceTaskId, parentToolCallId, ident, emitDelegationLifecycle, loopLatch, stats, undrainedUserAtEnd: { get current() { return undrainedUserAtEnd; } } };
|
|
85
|
+
}
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* design/393 S6 — the run body's LEG (R13), verbatim from `Runner.runLocked`: the one `harness.prompt` of the leg and
|
|
3
|
+
* everything that decides whether it is issued. Two legs behind one try / catch / finally: the RESUME leg (the walltime
|
|
4
|
+
* and governance-window entrance claims, the gated decision's application, the exhaustion arms, the continuation prompt's
|
|
5
|
+
* assembly — orphaned background tasks, the git frame, the parked steer queue and the wake message each under its own trust
|
|
6
|
+
* framing and redelivery screen — and the prompt itself) and the OBJECTIVE leg (the UserPromptSubmit screen, the git
|
|
7
|
+
* frame's primary delivery, the first-frame listings, the pre-call budget / token / entry-governance gates, the image
|
|
8
|
+
* conversion, the objective's human-input frame and the prompt itself). The tail captures the abort facts; the catch
|
|
9
|
+
* re-throws the resume-equivalent env failures after a bounded teardown and adopts everything else as the leg's throw;
|
|
10
|
+
* the finally releases the timer, the diagnostics, the signal, the content-ask bindings, flips the notification lane
|
|
11
|
+
* and releases the four subscriptions in their order.
|
|
12
|
+
*
|
|
13
|
+
* Async (twenty first-level awaits, the same awaits at the same positions). It ends by entering the terminal adoption
|
|
14
|
+
* (`next`) in its LAST continuation — the adoption's first read sits on the tick the finally ran on, as it did in the
|
|
15
|
+
* one-function body — and returns what it returns. The two legs stay ONE function on purpose: splitting them into two
|
|
16
|
+
* async functions (the design's "internal split") costs a microtask on the leg → tail edge, and the tail's first reads
|
|
17
|
+
* there — `abortController.signal.aborted`, `loopLatch.userInterrupted` — are host-mutable attribution facts a late read
|
|
18
|
+
* would mis-sign (the adversarial r2 HIGH-1 finding recorded on them); the forwarded-frame depth ratchet measured the
|
|
19
|
+
* extra hop (58 → 59) when the split was tried.
|
|
20
|
+
*/
|
|
21
|
+
import type { AssistantMessage } from "../../internal/llm.js";
|
|
22
|
+
import { type ActorAssertion } from "../checkpoint-store.js";
|
|
23
|
+
import type { PushQueue } from "../push-queue.js";
|
|
24
|
+
import { type TaskEvent, type TaskSpec } from "../types.js";
|
|
25
|
+
import { type WriteFamily } from "./turn-attachments.js";
|
|
26
|
+
import type { NotificationLaneBindings, Prepared, ResumeRun, RunnerDepsSeat, RunState } from "./contracts.js";
|
|
27
|
+
export interface RunLegInput<R> {
|
|
28
|
+
/** borrowed-readonly — the task spec: the objective, the images, the hooks slot, the principal, the task id. */
|
|
29
|
+
spec: TaskSpec;
|
|
30
|
+
/** borrowed-mutable — the run's event queue: the human-input frames, the git echo frames, the listing echo frames. */
|
|
31
|
+
queue: PushQueue<TaskEvent>;
|
|
32
|
+
/** borrowed-mutable — the leg's prepared seat: the harness is prompted, the blocked / git / listing refs written, the abort controller aborted and the signal released in the finally. */
|
|
33
|
+
prepared: Prepared;
|
|
34
|
+
/** borrowed-readonly — the resume plan when this leg resumes a checkpoint: chooses the resume leg; its delivery bits are written. */
|
|
35
|
+
resume: ResumeRun | undefined;
|
|
36
|
+
/** borrowed-mutable — the run's mutable state: the limit flags and the platform terminal are written by the entrance gates. */
|
|
37
|
+
rs: RunState;
|
|
38
|
+
/** borrowed-readonly — the API-boundary attribution snapshot of the objective's actor (the objective leg's speaker envelope). */
|
|
39
|
+
entryActor: ActorAssertion | undefined;
|
|
40
|
+
/** borrowed-readonly — the effective walltime window (undefined = unbounded): `<= 0` refuses the first turn. */
|
|
41
|
+
effectiveTimeoutMs: number | undefined;
|
|
42
|
+
/** borrowed-mutable — the hard walltime timer: claimed (`fired`) and cleared by the exhausted arms and the finally. */
|
|
43
|
+
timeout: {
|
|
44
|
+
fired: boolean;
|
|
45
|
+
clear: () => void;
|
|
46
|
+
};
|
|
47
|
+
/** borrowed-readonly — the content push (the resumed batch's frames ride it with the leg's identity). */
|
|
48
|
+
pushContent: (e: TaskEvent) => void;
|
|
49
|
+
/** borrowed-readonly — the run's event-identity mint. */
|
|
50
|
+
ident: () => {
|
|
51
|
+
eventId: string;
|
|
52
|
+
parentToolCallId?: string;
|
|
53
|
+
sourceTaskId?: string;
|
|
54
|
+
};
|
|
55
|
+
/** borrowed-readonly — the `message_committed` mint (the resumed batch's re-applied tool results). */
|
|
56
|
+
emitCommitted: (entryId: string, role: "user" | "assistant" | "toolResult", toolCallId?: string) => void;
|
|
57
|
+
/** borrowed-readonly — the write-family resolver (the resume-executed gated write's attachment anchor). */
|
|
58
|
+
writeFamilyOf: (name: string) => WriteFamily | undefined;
|
|
59
|
+
/** borrowed-mutable — the observed tool-start ids: the resume-executed gated call registers itself here. */
|
|
60
|
+
startedToolCallIds: Set<string>;
|
|
61
|
+
/** borrowed-readonly — the harness-handlers lane's workspace-move announcer (the approved `cd`'s frame). */
|
|
62
|
+
announceWorkspaceMove: () => void;
|
|
63
|
+
/** borrowed-readonly — the brain-sinks composition the leg's prompt runs under. */
|
|
64
|
+
withBrainSinks: <T>(fn: () => Promise<T>) => Promise<T>;
|
|
65
|
+
/** borrowed-readonly — the git lane's parked-mirror flush, settled after the prompt (single-turn legs reach no boundary). */
|
|
66
|
+
flushGitMirror: () => Promise<void>;
|
|
67
|
+
/** borrowed-mutable — the loop-liveness latch: `ended` flips when the prompt settles (or a no-prompt / throw arm is taken); `userInterrupted` is snapshotted. */
|
|
68
|
+
loopLatch: {
|
|
69
|
+
ended: boolean;
|
|
70
|
+
readonly userInterrupted: boolean;
|
|
71
|
+
};
|
|
72
|
+
/** borrowed-mutable — the notification lane's bindings seat: `live` flips false in the finally (every later notification parks). */
|
|
73
|
+
notificationLane: NotificationLaneBindings;
|
|
74
|
+
/** borrowed-readonly — the notification lane's subscription release, called in the finally right after the flip. */
|
|
75
|
+
unsubscribeTaskNotifications: () => void;
|
|
76
|
+
/** borrowed-readonly — the git lane's owed-frame retry release, called in the finally first of the three. */
|
|
77
|
+
unsubGitRetry: () => void;
|
|
78
|
+
/** borrowed-readonly — the git lane's boundary-handler release, called second. */
|
|
79
|
+
unsubBoundary: () => void;
|
|
80
|
+
/** borrowed-readonly — the git lane's harness-event release, called third. */
|
|
81
|
+
unsub: () => void;
|
|
82
|
+
/** borrowed-readonly — the Runner's deployment deps, read LIVE (`onError`, `hooks`, `onNotice`, `allowImageUrl`); the one home of
|
|
83
|
+
* why it is a seat and not a captured object is {@link RunnerDepsSeat}. */
|
|
84
|
+
runner: RunnerDepsSeat;
|
|
85
|
+
/** borrowed-readonly — the Runner's application of the resumed decision (its private method, as a delegate). */
|
|
86
|
+
applyResumeDecision: (prepared: Prepared, resume: ResumeRun, emit: (e: TaskEvent) => void, emitCommitted: (entryId: string, role: "user" | "assistant" | "toolResult", toolCallId?: string) => void, onResolvedToolSuccess?: (toolName: string, details: unknown) => void, onExecuteStart?: (toolCallId: string) => void) => Promise<void>;
|
|
87
|
+
/** borrowed-readonly — the terminal adoption, entered in this lane's last continuation with the leg's facts. */
|
|
88
|
+
next: (leg: RunLegResult) => Promise<R>;
|
|
89
|
+
}
|
|
90
|
+
/** The leg's facts — what the terminal adoption and the settle read. */
|
|
91
|
+
export interface RunLegResult {
|
|
92
|
+
/** The final assistant message; undefined on every no-prompt arm (blocked, refused, exhausted). */
|
|
93
|
+
final: AssistantMessage | undefined;
|
|
94
|
+
/** What the leg threw (undefined on a clean end); the terminal adoption may lift a typed cause over it. */
|
|
95
|
+
threw: unknown;
|
|
96
|
+
/** The live-abort flag, captured before the finally's unconditional release-abort. */
|
|
97
|
+
abortedLive: boolean;
|
|
98
|
+
/** The snapshot of `loopLatch.userInterrupted`, taken with `abortedLive`. */
|
|
99
|
+
userInterruptedLive: boolean;
|
|
100
|
+
/** design/174: the answered-but-never-collected deliveries the finally settled. */
|
|
101
|
+
strandedHumanAnswers: ReadonlyArray<{
|
|
102
|
+
deliveryId: string;
|
|
103
|
+
toolCallId: string;
|
|
104
|
+
}>;
|
|
105
|
+
}
|
|
106
|
+
export declare function runLeg<R>(input: RunLegInput<R>): Promise<R>;
|