@sema-agent/core 7.11.2 → 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 +42 -13
- 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/contracts.d.ts +41 -9
- 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 +4 -2
- package/dist/core/runner/run-attachment-seats.js +2 -2
- package/dist/core/runner/run-identity-wiring.d.ts +14 -33
- package/dist/core/runner/run-identity-wiring.js +4 -3
- 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 +5 -5
- package/dist/core/runner/run-reasoning-seat.js +7 -7
- 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-terminal-adoption.d.ts +99 -0
- package/dist/core/runner/run-terminal-adoption.js +120 -0
- package/dist/core/runner/runtask.d.ts +14 -3
- package/dist/core/runner/runtask.js +55 -1010
- 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/package.json +1 -1
- package/test/export-surface.snapshot.json +10 -10
package/dist/core/auto-mode.js
CHANGED
|
@@ -1,14 +1,17 @@
|
|
|
1
|
-
import {
|
|
2
|
-
export const AUTO_MODE_UNAVAILABLE_CAUSES = ["error", "timeout"
|
|
1
|
+
import { AUTO_MODE_DEFAULT_TIMEOUT_MS, AUTO_MODE_DENIAL_AUTO_DENY_DEFAULT_MS, AUTO_MODE_DENIAL_LIMIT_DEFAULTS } from "./auto-mode-defaults.js";
|
|
2
|
+
export const AUTO_MODE_UNAVAILABLE_CAUSES = ["error", "timeout"];
|
|
3
3
|
const AUTO_MODE_UNAVAILABLE_CAUSE_SET = new Set(AUTO_MODE_UNAVAILABLE_CAUSES);
|
|
4
4
|
export function isAutoModeUnavailableCause(v) {
|
|
5
5
|
return AUTO_MODE_UNAVAILABLE_CAUSE_SET.has(v);
|
|
6
6
|
}
|
|
7
|
-
export
|
|
8
|
-
const
|
|
9
|
-
|
|
10
|
-
|
|
7
|
+
export function classifierUnavailableDenyMessage(toolName, cause) {
|
|
8
|
+
const parenthetical = cause === "timeout" ? " (timed out)" : "";
|
|
9
|
+
return (`The auto-mode classifier is temporarily unavailable${parenthetical}, so auto mode cannot determine the safety of ${toolName} right now. ` +
|
|
10
|
+
"Wait a moment and then try this action again. " +
|
|
11
|
+
"If it keeps failing, continue with other tasks that don't require this action and come back to it later. " +
|
|
12
|
+
"Note: reading files, searching code, and other read-only operations do not require the classifier and can still be used.");
|
|
11
13
|
}
|
|
14
|
+
export const CLASSIFIER_PARSE_FAILURE_DENY_MESSAGE = "Auto mode could not evaluate this action and is blocking it for safety — the classifier's reply carried no verdict.";
|
|
12
15
|
export function parseAutoModeResponse(text) {
|
|
13
16
|
const rawAnswers = new Set([...text.matchAll(/<block>(yes|no)\b/gi)].map((m) => m[1].toLowerCase()));
|
|
14
17
|
if (rawAnswers.size > 1)
|
|
@@ -28,20 +31,6 @@ export function parseAutoModeResponse(text) {
|
|
|
28
31
|
}
|
|
29
32
|
export function createAutoModeDecider(opts) {
|
|
30
33
|
const timeoutMs = opts.timeoutMs ?? AUTO_MODE_DEFAULT_TIMEOUT_MS;
|
|
31
|
-
const threshold = Math.max(1, Math.floor(opts.failureThreshold ?? AUTO_MODE_DEFAULT_FAILURE_THRESHOLD));
|
|
32
|
-
let consecutiveFailures = 0;
|
|
33
|
-
let open = false;
|
|
34
|
-
const recordFailure = (cause) => {
|
|
35
|
-
consecutiveFailures++;
|
|
36
|
-
if (!open && consecutiveFailures >= threshold) {
|
|
37
|
-
open = true;
|
|
38
|
-
try {
|
|
39
|
-
opts.onBreakerOpen?.({ consecutiveFailures, lastCause: cause });
|
|
40
|
-
}
|
|
41
|
-
catch {
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
};
|
|
45
34
|
const decide = async (input, signal) => {
|
|
46
35
|
const startedAt = performance.now();
|
|
47
36
|
const verdict = await decideUnreported(input, signal);
|
|
@@ -59,14 +48,8 @@ export function createAutoModeDecider(opts) {
|
|
|
59
48
|
}
|
|
60
49
|
return verdict;
|
|
61
50
|
};
|
|
62
|
-
return {
|
|
63
|
-
breakerOpen: () => open,
|
|
64
|
-
consecutiveFailures: () => consecutiveFailures,
|
|
65
|
-
decide,
|
|
66
|
-
};
|
|
51
|
+
return { decide };
|
|
67
52
|
async function decideUnreported(input, signal) {
|
|
68
|
-
if (open)
|
|
69
|
-
return { kind: "unavailable", cause: "breaker_open" };
|
|
70
53
|
let timer;
|
|
71
54
|
const inner = new AbortController();
|
|
72
55
|
const onOuterAbort = () => inner.abort();
|
|
@@ -98,21 +81,12 @@ export function createAutoModeDecider(opts) {
|
|
|
98
81
|
}
|
|
99
82
|
});
|
|
100
83
|
});
|
|
101
|
-
|
|
102
|
-
return { kind: "unavailable", cause: "breaker_open" };
|
|
103
|
-
const verdict = parseAutoModeResponse(raw);
|
|
104
|
-
if (verdict.kind === "parse_error")
|
|
105
|
-
recordFailure("parse_error");
|
|
106
|
-
else
|
|
107
|
-
consecutiveFailures = 0;
|
|
108
|
-
return verdict;
|
|
84
|
+
return parseAutoModeResponse(raw);
|
|
109
85
|
}
|
|
110
86
|
catch (e) {
|
|
111
87
|
if (signal?.aborted)
|
|
112
88
|
return { kind: "unavailable", cause: "error" };
|
|
113
|
-
|
|
114
|
-
recordFailure(timedOut ? "timeout" : "error");
|
|
115
|
-
return { kind: "unavailable", cause: timedOut ? "timeout" : "error" };
|
|
89
|
+
return { kind: "unavailable", cause: e instanceof AutoModeTimeout ? "timeout" : "error" };
|
|
116
90
|
}
|
|
117
91
|
finally {
|
|
118
92
|
if (timer !== undefined)
|
|
@@ -127,27 +101,6 @@ class AutoModeTimeout extends Error {
|
|
|
127
101
|
super("auto-mode classify timeout");
|
|
128
102
|
}
|
|
129
103
|
}
|
|
130
|
-
export class AutoModeBreakerLedger {
|
|
131
|
-
cap;
|
|
132
|
-
trips = new Map();
|
|
133
|
-
constructor(cap = 1024) {
|
|
134
|
-
this.cap = cap;
|
|
135
|
-
}
|
|
136
|
-
record(sessionId, trip) {
|
|
137
|
-
if (this.trips.has(sessionId))
|
|
138
|
-
this.trips.delete(sessionId);
|
|
139
|
-
this.trips.set(sessionId, trip);
|
|
140
|
-
while (this.trips.size > this.cap) {
|
|
141
|
-
const oldest = this.trips.keys().next().value;
|
|
142
|
-
if (oldest === undefined)
|
|
143
|
-
break;
|
|
144
|
-
this.trips.delete(oldest);
|
|
145
|
-
}
|
|
146
|
-
}
|
|
147
|
-
lastTrip(sessionId) {
|
|
148
|
-
return this.trips.get(sessionId);
|
|
149
|
-
}
|
|
150
|
-
}
|
|
151
104
|
export function readDenialLimitFallback(v) {
|
|
152
105
|
if (typeof v !== "object" || v === null)
|
|
153
106
|
return undefined;
|
|
@@ -1123,9 +1123,7 @@ export interface CheckpointState {
|
|
|
1123
1123
|
* suspend leg did. It is a MEMORY of intent, never an authorization: the resuming deployment's
|
|
1124
1124
|
* face (`RunnerDeps.autoMode`) and the resuming principal's deny bit (`RuntimeCaps.autoMode`)
|
|
1125
1125
|
* are judged afresh on every leg — a bit on the row cannot arm where the redeeming deployment
|
|
1126
|
-
* would not.
|
|
1127
|
-
* is untripped and untouched (a session that fell back to non-auto hands nothing forward); a leg
|
|
1128
|
-
* never armed here carries the memory as is. Absent on older checkpoints and on non-auto tasks
|
|
1126
|
+
* would not. A leg never armed here carries the memory as is. Absent on older checkpoints and on non-auto tasks
|
|
1129
1127
|
* (byte-identical to the pre-bit row); an older worker that ignores it resumes un-armed, the
|
|
1130
1128
|
* narrower direction. */
|
|
1131
1129
|
autoModeRequested?: true;
|
package/dist/core/gate-fold.js
CHANGED
|
@@ -128,15 +128,7 @@ export async function runGateFold(pass) {
|
|
|
128
128
|
pass.decision = { ...pass.decision, probeMandated: true };
|
|
129
129
|
}
|
|
130
130
|
}
|
|
131
|
-
|
|
132
|
-
try {
|
|
133
|
-
return d.breakerOpen();
|
|
134
|
-
}
|
|
135
|
-
catch {
|
|
136
|
-
return false;
|
|
137
|
-
}
|
|
138
|
-
};
|
|
139
|
-
if (input.peerMessage === true && pass.decision.action === "allow" && input.autoMode !== undefined && !breakerKnownOpen(input.autoMode.decider)) {
|
|
131
|
+
if (input.peerMessage === true && pass.decision.action === "allow" && input.autoMode !== undefined) {
|
|
140
132
|
pass.decision = {
|
|
141
133
|
action: "ask",
|
|
142
134
|
message: `tool "${toolName}" sends a message to another agent — routed for classifier review in auto mode`,
|
package/dist/core/gate-lanes.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { decisionText, describeThrown } from "./tool-policy.js";
|
|
2
2
|
import { askOriginOf, classifierMayAnswer } from "./ask-origin.js";
|
|
3
|
-
import { denialLimitFallbackMessage, unarmedWindow } from "./auto-mode.js";
|
|
3
|
+
import { CLASSIFIER_PARSE_FAILURE_DENY_MESSAGE, classifierUnavailableDenyMessage, denialLimitFallbackMessage, unarmedWindow } from "./auto-mode.js";
|
|
4
4
|
import { inlineUntrusted } from "./untrusted-text.js";
|
|
5
5
|
import { isRuleBehavior } from "./permission-rule-model.js";
|
|
6
6
|
import { ASK_USER_QUESTION_TOOL_NAME } from "./ask-question.js";
|
|
@@ -388,9 +388,17 @@ export async function runGateLanes(pass) {
|
|
|
388
388
|
...(pass.policyRewrite !== undefined ? { updatedInput: pass.policyRewrite } : {}),
|
|
389
389
|
};
|
|
390
390
|
}
|
|
391
|
-
else if (verdict.kind === "
|
|
392
|
-
|
|
393
|
-
|
|
391
|
+
else if (verdict.kind === "unavailable") {
|
|
392
|
+
pass.decision = {
|
|
393
|
+
action: "deny",
|
|
394
|
+
message: classifierUnavailableDenyMessage(toolName, verdict.cause),
|
|
395
|
+
decisionReason: "classifier",
|
|
396
|
+
classifierUnavailable: { cause: verdict.cause },
|
|
397
|
+
};
|
|
398
|
+
}
|
|
399
|
+
else {
|
|
400
|
+
const reason = verdict.kind === "block" ? (verdict.reason ? inlineUntrusted(verdict.reason) : "") : CLASSIFIER_PARSE_FAILURE_DENY_MESSAGE;
|
|
401
|
+
const category = verdict.kind === "block" && verdict.category ? inlineUntrusted(verdict.category) : "";
|
|
394
402
|
const tracked = input.autoMode.denialTracking?.recordBlock();
|
|
395
403
|
if (tracked?.limitReached === true) {
|
|
396
404
|
const fallbackAsk = {
|
|
@@ -405,15 +413,13 @@ export async function runGateLanes(pass) {
|
|
|
405
413
|
else {
|
|
406
414
|
pass.decision = {
|
|
407
415
|
action: "deny",
|
|
408
|
-
message: `auto-mode classifier blocked this call${reason ? `: ${reason}` : category ? `: [${category}]` : ""}
|
|
416
|
+
message: verdict.kind === "block" ? `auto-mode classifier blocked this call${reason ? `: ${reason}` : category ? `: [${category}]` : ""}` : reason,
|
|
409
417
|
decisionReason: "classifier",
|
|
410
418
|
};
|
|
411
|
-
pass.deniedBy = "classifier";
|
|
412
419
|
}
|
|
413
420
|
}
|
|
414
|
-
|
|
415
|
-
pass.
|
|
416
|
-
}
|
|
421
|
+
if (pass.decision.action === "deny")
|
|
422
|
+
pass.deniedBy = "classifier";
|
|
417
423
|
}
|
|
418
424
|
if (input.sandboxAdmission !== undefined &&
|
|
419
425
|
pass.decision.action === "ask" &&
|
package/dist/core/hooks.d.ts
CHANGED
|
@@ -411,6 +411,12 @@ export interface PermissionDeniedPayload {
|
|
|
411
411
|
* settled none.
|
|
412
412
|
*/
|
|
413
413
|
gate: GateOutcome;
|
|
414
|
+
/** #661 (additive): present ⇔ this deny is the auto-mode classifier's UNAVAILABILITY (`deniedBy: "classifier"`
|
|
415
|
+
* with the verdict's cause word) — the structured half of the deny text's "the classifier is temporarily
|
|
416
|
+
* unavailable" sentence. A classifier BLOCK or parse-failure deny carries no member here. */
|
|
417
|
+
classifierUnavailable?: {
|
|
418
|
+
readonly cause: import("./auto-mode.js").AutoModeUnavailableCause;
|
|
419
|
+
};
|
|
414
420
|
/** {@link HookSeatSignal} — this invocation's own abort signal. On an OBSERVATION seat the deny has
|
|
415
421
|
* already happened and nothing this callback does can change it, so the signal says exactly one
|
|
416
422
|
* thing: stop reading, nobody is waiting for your answer any more. */
|
|
@@ -22,7 +22,7 @@ import type { WorkflowSizeGuideline } from "../../orchestration/workflow-size-gu
|
|
|
22
22
|
import type { ToolManifestRow } from "../../prompt-assembly/tool-catalog.js";
|
|
23
23
|
import type { CwdRef, ReadFace } from "../../tools/fs/index.js";
|
|
24
24
|
import type { MaterializedA2a } from "../a2a.js";
|
|
25
|
-
import type { CompactionForkContext, MaybeCompactOptions, RapidRefillState } from "../auto-compaction.js";
|
|
25
|
+
import type { CompactionForkContext, CompactionPhaseDurations, MaybeCompactOptions, RapidRefillState } from "../auto-compaction.js";
|
|
26
26
|
import type { AutoModeArmingRecipe } from "../auto-mode-arming.js";
|
|
27
27
|
import type { AutoModeDecider, AutoModeDenialTracker } from "../auto-mode.js";
|
|
28
28
|
import type { CacheBreakDetector, ToolFingerprintInput } from "../cache-break-detector.js";
|
|
@@ -1778,14 +1778,6 @@ export interface RunInternals {
|
|
|
1778
1778
|
* channel, same posture as every other field here.
|
|
1779
1779
|
*/
|
|
1780
1780
|
sessionReadStates?: SessionReadFileStates;
|
|
1781
|
-
/**
|
|
1782
|
-
* #616 — the Runner's per-session breaker ledger ({@link import("../auto-mode.js").AutoModeBreakerLedger}):
|
|
1783
|
-
* the arming site's `onBreakerOpen` wrap records a trip here, the wiring-manifest phase of a LATER leg of
|
|
1784
|
-
* the same session reads the most recent one onto `autoMode.breaker`. Always set by the Runner's own
|
|
1785
|
-
* prepare call (overriding any caller value, like `sessionReadStates` beside it); absent on a standalone
|
|
1786
|
-
* prepareTask, where no trip is recorded and none is reported. Trusted internals channel.
|
|
1787
|
-
*/
|
|
1788
|
-
autoModeBreakerLedger?: import("../auto-mode.js").AutoModeBreakerLedger;
|
|
1789
1781
|
onTaskNotification?: (notification: TaskNotificationPayload,
|
|
1790
1782
|
/** Injection tier (design/373 — the ladder is LIVE): "next" = the running turn's next boundary
|
|
1791
1783
|
* (arrival order, consecutive frames batch); "later" = the run's would-otherwise-stop seat
|
|
@@ -2475,6 +2467,46 @@ export interface ManualCompactRef {
|
|
|
2475
2467
|
emitMooted?: (reason: string) => void;
|
|
2476
2468
|
closed?: boolean;
|
|
2477
2469
|
}
|
|
2470
|
+
/**
|
|
2471
|
+
* design/393 S6 — the end-of-task compaction pass's outcome (`Runner.finish`'s return): what the terminal-adoption lane
|
|
2472
|
+
* hands the settle lane, which reads it for the `compacted` frame, the phase-timings frame and the detector reset. Named
|
|
2473
|
+
* once here so the two lanes and the method spell one type.
|
|
2474
|
+
*/
|
|
2475
|
+
export type EndOfTaskCompaction = {
|
|
2476
|
+
compacted: boolean;
|
|
2477
|
+
tokensBefore?: number;
|
|
2478
|
+
triggerTokens?: number;
|
|
2479
|
+
postTriggerTokens?: number;
|
|
2480
|
+
durationMs?: number;
|
|
2481
|
+
phaseDurations?: CompactionPhaseDurations;
|
|
2482
|
+
firstKeptEntryId?: string;
|
|
2483
|
+
attachedFiles?: Array<{
|
|
2484
|
+
path: string;
|
|
2485
|
+
chars: number;
|
|
2486
|
+
truncated: boolean;
|
|
2487
|
+
}>;
|
|
2488
|
+
modelFallback?: true;
|
|
2489
|
+
fallbackReason?: "window";
|
|
2490
|
+
clampedRatio?: number;
|
|
2491
|
+
clampReason?: "budget" | "tolerance";
|
|
2492
|
+
} | undefined;
|
|
2493
|
+
/**
|
|
2494
|
+
* design/393 S6 — the notification lane's BINDINGS: the run-notification-lane's own four `let`s as ONE seat (getters
|
|
2495
|
+
* and setters over the lane's variables, never a copy). The identity-wiring lane binds `harness` / `sessionId` /
|
|
2496
|
+
* `ident` the moment `prepared` exists (the lane's closures read them by variable — the routing listener, the park
|
|
2497
|
+
* destination, the injection entry); the leg lane flips `live` in its finally, from which point every notification
|
|
2498
|
+
* parks per session for the next run. One seat, four slots; nothing copies a binding out of it.
|
|
2499
|
+
*/
|
|
2500
|
+
export interface NotificationLaneBindings {
|
|
2501
|
+
harness: AgentHarness | undefined;
|
|
2502
|
+
sessionId: string | undefined;
|
|
2503
|
+
ident: () => {
|
|
2504
|
+
eventId?: string;
|
|
2505
|
+
parentToolCallId?: string;
|
|
2506
|
+
sourceTaskId?: string;
|
|
2507
|
+
};
|
|
2508
|
+
live: boolean;
|
|
2509
|
+
}
|
|
2478
2510
|
/** design/144 §2 — the `notify()` bridge: `runLocked` binds `inject` the moment the task-notification lane exists. */
|
|
2479
2511
|
export interface NotifyRef {
|
|
2480
2512
|
inject?: (n: TaskNotificationPayload, opts?: {
|
|
@@ -32,8 +32,7 @@ export interface InheritedAutoMode {
|
|
|
32
32
|
* recorded recipe — `rebuildAutoModeDecider` hands back a decider and its arming, nothing live)
|
|
33
33
|
* carries no denial tracker, and an entry with a decider but no tracker would count nothing: the
|
|
34
34
|
* rebuilt classifier could block without bound on the redeemed leg, the exact gap the limit closes.
|
|
35
|
-
* Attach a FRESH tracker (a fresh COUNT is the documented cross-process semantics
|
|
36
|
-
* restarts the same way) under the ancestor's recorded BOUNDS tightened by this deployment's own
|
|
35
|
+
* Attach a FRESH tracker (a fresh COUNT is the documented cross-process semantics) under the ancestor's recorded BOUNDS tightened by this deployment's own
|
|
37
36
|
* (#556, `tightenDenialLimit` — the same rule and the same call the arming fold makes, so the
|
|
38
37
|
* recipe's account of the criteria and the tracker's actual bounds cannot drift). Before #556 the
|
|
39
38
|
* bounds came from this deployment alone, so an ancestor that allowed three consecutive blocks
|
|
@@ -84,8 +83,8 @@ export type InheritedAsk = Extract<PermissionResult, {
|
|
|
84
83
|
}>;
|
|
85
84
|
/** The members of a surviving ask that ride onto the approval request with a COMPUTED value — what the
|
|
86
85
|
* four request mint stations (the gate's own and the three inherited-lane ones) spread after the seats
|
|
87
|
-
* they spell themselves: the ask's origin word, its denial-limit fallback and
|
|
88
|
-
* fact (#616). */
|
|
86
|
+
* they spell themselves: the ask's origin word, its denial-limit fallback and a policy-declared
|
|
87
|
+
* classifier-unavailable fact (#616; the engine's own fact rides the DENY since #661). */
|
|
89
88
|
export interface AskRequestCarry {
|
|
90
89
|
origin?: AskOrigin;
|
|
91
90
|
denialLimitFallback?: DenialLimitFallback;
|
|
@@ -117,18 +116,15 @@ export type InheritedClassifierJudgment<A extends InheritedAsk> =
|
|
|
117
116
|
kind: "deny";
|
|
118
117
|
result: PermissionResult;
|
|
119
118
|
}
|
|
120
|
-
/** Proceed to the frozen approver with `ask`: the incoming ask unchanged (classifier
|
|
121
|
-
*
|
|
119
|
+
/** Proceed to the frozen approver with `ask`: the incoming ask unchanged (classifier excluded or not
|
|
120
|
+
* armed), or — at the bound — the fallback ask minted from it (`mintedHere`).
|
|
122
121
|
* `fallback` is the member riding the ask either way (an incoming one is a deeper ancestor's).
|
|
123
122
|
* `origin` is the ask's word under the station facts, threaded to the request mint: on the two
|
|
124
123
|
* unchanged-ask branches it is the SAME read the exclusion judged by (a caller-owned decision with a
|
|
125
124
|
* stateful accessor cannot answer the exclusion with one word and the card with another); on the
|
|
126
125
|
* bound branch it is derived from the re-spoken ask this station minted (its own object). */
|
|
127
|
-
/** `ask` is the incoming ask unchanged
|
|
128
|
-
* carrying `classifierUnavailable: { cause }` (#
|
|
129
|
-
* wrapper arms hand back to the gate when the frozen approver answers unavailable (the inherited-unavailable
|
|
130
|
-
* float), and the gate's own park carry reads the fact off the decision it parks — a side member on this
|
|
131
|
-
* judgment would have been lost on that route (codex r1). The request mint reads the same object. */
|
|
126
|
+
/** `ask` is the incoming ask unchanged (the caller's own object); an UNAVAILABLE round never reaches this arm —
|
|
127
|
+
* it is a `deny` carrying `classifierUnavailable: { cause }` (#661). */
|
|
132
128
|
| {
|
|
133
129
|
kind: "resolve";
|
|
134
130
|
ask: A;
|
|
@@ -142,8 +138,9 @@ export type InheritedClassifierJudgment<A extends InheritedAsk> =
|
|
|
142
138
|
* auto-allow (and the streak resets); `block` below the bound ⇒ deny, the exact verdict the ancestor's
|
|
143
139
|
* gate would have produced; `block` AT the bound ⇒ the ask is re-spoken in the classifier's voice as
|
|
144
140
|
* the fallback (`decisionReason:"classifier"`, `requiresRealApproval`, the member carrying counts +
|
|
145
|
-
* window) for the arm to resolve at the frozen approver;
|
|
146
|
-
*
|
|
141
|
+
* window) for the arm to resolve at the frozen approver; `parse_error` ⇒ the same block path with the CC
|
|
142
|
+
* parse-failure sentence (counted); `unavailable` ⇒ a DENY that says so, carrying the fact (#661, CC
|
|
143
|
+
* 2.1.250 form); excluded / no classifier ⇒ the incoming ask, unchanged. The member may ALREADY be on the incoming
|
|
147
144
|
* ask (a deeper ancestor's fallback, minted inside the nested fold — the case the exclusion names):
|
|
148
145
|
* it rides to the approver and the headless arm unchanged, whichever tracker minted it; only a
|
|
149
146
|
* tracker that counted THIS streak is reset by the person's later allow (`mintedHere`).
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { createAutoModeDenialTracker, denialLimitFallbackMessage, denialLimitSentence, unarmedWindow } from "../auto-mode.js";
|
|
1
|
+
import { CLASSIFIER_PARSE_FAILURE_DENY_MESSAGE, classifierUnavailableDenyMessage, createAutoModeDenialTracker, denialLimitFallbackMessage, denialLimitSentence, unarmedWindow } from "../auto-mode.js";
|
|
2
2
|
import { sanitizeAutoModeArmingRecipe, tightenDenialLimit } from "../auto-mode-arming.js";
|
|
3
3
|
import { deliverEngineNotice } from "../types.js";
|
|
4
4
|
import { inlineUntrusted } from "../untrusted-text.js";
|
|
@@ -85,19 +85,21 @@ export async function judgeInheritedClassifier(opts) {
|
|
|
85
85
|
autoMode.denialTracking?.recordAllow();
|
|
86
86
|
return { kind: "allow" };
|
|
87
87
|
}
|
|
88
|
-
if (verdict.kind
|
|
89
|
-
|
|
90
|
-
|
|
88
|
+
if (verdict.kind === "unavailable") {
|
|
89
|
+
return {
|
|
90
|
+
kind: "deny",
|
|
91
|
+
result: { action: "deny", message: classifierUnavailableDenyMessage(req.toolName, verdict.cause), decisionReason: "classifier", classifierUnavailable: { cause: verdict.cause } },
|
|
92
|
+
};
|
|
91
93
|
}
|
|
92
|
-
const reason = verdict.reason ? inlineUntrusted(verdict.reason) : "";
|
|
93
|
-
const category = verdict.category ? inlineUntrusted(verdict.category) : "";
|
|
94
|
+
const reason = verdict.kind === "block" ? (verdict.reason ? inlineUntrusted(verdict.reason) : "") : CLASSIFIER_PARSE_FAILURE_DENY_MESSAGE;
|
|
95
|
+
const category = verdict.kind === "block" && verdict.category ? inlineUntrusted(verdict.category) : "";
|
|
94
96
|
const tracked = autoMode.denialTracking?.recordBlock();
|
|
95
97
|
if (tracked?.limitReached !== true) {
|
|
96
98
|
return {
|
|
97
99
|
kind: "deny",
|
|
98
100
|
result: {
|
|
99
101
|
action: "deny",
|
|
100
|
-
message: `auto-mode classifier blocked ${opts.subject} at an inherited ancestor layer${reason ? `: ${reason}` : category ? `: [${category}]` : ""}`,
|
|
102
|
+
message: verdict.kind === "block" ? `auto-mode classifier blocked ${opts.subject} at an inherited ancestor layer${reason ? `: ${reason}` : category ? `: [${category}]` : ""}` : `${reason} (${opts.subject}, at an inherited ancestor layer)`,
|
|
101
103
|
decisionReason: "classifier",
|
|
102
104
|
},
|
|
103
105
|
};
|
|
@@ -103,7 +103,15 @@ export async function exitGate(pass) {
|
|
|
103
103
|
if (pass.deniedBy === undefined)
|
|
104
104
|
throw new Error(`the tool gate refused "${toolName}" without a refusing layer — every deny site attributes itself`);
|
|
105
105
|
const gate = mintGateOutcome({ deniedBy: pass.deniedBy, ...(ledger.settled !== undefined ? { settled: ledger.settled } : {}) });
|
|
106
|
-
await notifyPermissionDenied({
|
|
106
|
+
await notifyPermissionDenied({
|
|
107
|
+
toolName,
|
|
108
|
+
input: cloneObserverInput(pass.currentInput),
|
|
109
|
+
toolCallId,
|
|
110
|
+
reason: denyReason,
|
|
111
|
+
gate,
|
|
112
|
+
...(input.identity !== undefined ? { identity: input.identity } : {}),
|
|
113
|
+
...(pass.decision.action === "deny" && pass.decision.classifierUnavailable !== undefined ? { classifierUnavailable: { cause: pass.decision.classifierUnavailable.cause } } : {}),
|
|
114
|
+
});
|
|
107
115
|
return {
|
|
108
116
|
block: true,
|
|
109
117
|
reason: formatHookFeedback(denyReason, input.reminderMark),
|
|
@@ -49,7 +49,7 @@ export interface PrepareCapsAndWorkflowInput {
|
|
|
49
49
|
deps: RunnerDeps;
|
|
50
50
|
/** borrowed-readonly — the trusted spawn-side channel; the Workflow mount forwards `rootSessionId`, `placementRoot`,
|
|
51
51
|
* `onTaskNotification`, `workflowDepth`, and the capture-floor getter reads `memoryCaptureAncestors`. */
|
|
52
|
-
internals: Pick<RunInternals, "rootSessionId" | "placementRoot" | "onTaskNotification" | "workflowDepth" | "memoryCaptureAncestors" | "workflowParkedResume"
|
|
52
|
+
internals: Pick<RunInternals, "rootSessionId" | "placementRoot" | "onTaskNotification" | "workflowDepth" | "memoryCaptureAncestors" | "workflowParkedResume"> | undefined;
|
|
53
53
|
/** borrowed-readonly — the acquired session; the classifier leg rebuilds its transcript window from `buildContext`. */
|
|
54
54
|
session: Pick<StoredSession, "buildContext">;
|
|
55
55
|
/** borrowed-readonly — the acquired session id (operator-line context, the refusal codes' phase record). */
|
|
@@ -195,11 +195,6 @@ export async function prepareCapsAndWorkflow(input) {
|
|
|
195
195
|
autoModeDenialTracking = createAutoModeDenialTracker(am.denialLimit);
|
|
196
196
|
autoModeDecider = createAutoModeDecider({
|
|
197
197
|
...(am.timeoutMs !== undefined ? { timeoutMs: am.timeoutMs } : {}),
|
|
198
|
-
...(am.failureThreshold !== undefined ? { failureThreshold: am.failureThreshold } : {}),
|
|
199
|
-
onBreakerOpen: (info) => {
|
|
200
|
-
internals?.autoModeBreakerLedger?.record(sessionId, { openedAtMs: Date.now(), lastCause: info.lastCause, failures: info.consecutiveFailures, runId });
|
|
201
|
-
am.onBreakerOpen?.(info);
|
|
202
|
-
},
|
|
203
198
|
onClassified: (info) => emitTrace(deps.tracer, () => ({
|
|
204
199
|
kind: "auto_mode.classified",
|
|
205
200
|
version: 1,
|
|
@@ -17,7 +17,6 @@
|
|
|
17
17
|
* the boundary parks and the park closure key off `saga`'s presence, so the orchestrator grows no branch.
|
|
18
18
|
*/
|
|
19
19
|
import type { AgentHarness, ExecutionEnv } from "../../internal/harness.js";
|
|
20
|
-
import type { AutoModeDecider } from "../auto-mode.js";
|
|
21
20
|
import type { OwnOrgAdmissionVerdict } from "../memory-admission.js";
|
|
22
21
|
import type { RemoteExecutionEnv, SnapshotId } from "../remote-env.js";
|
|
23
22
|
import type { CheckpointStore, SerializedCheckpointState } from "../checkpoint-store.js";
|
|
@@ -128,7 +127,6 @@ export interface PrepareSuspendSagaInput {
|
|
|
128
127
|
/** borrowed-readonly — the auto-mode intent (seat ∨ live ∨ seed), carried while the latch is healthy. */
|
|
129
128
|
autoModeIntent: boolean;
|
|
130
129
|
/** borrowed-readonly — the auto-mode decider, or undefined (the latch-health reading only). */
|
|
131
|
-
autoModeDecider: AutoModeDecider | undefined;
|
|
132
130
|
/** borrowed-readonly — the inherited admitted org scopes, or undefined (copied onto the row). */
|
|
133
131
|
inheritedAdmittedOrgScopes: readonly string[] | undefined;
|
|
134
132
|
/** borrowed-readonly — this leg's OWN org verdict seat; `current` is read at mint time. Not written here. */
|
|
@@ -77,16 +77,8 @@ export async function compensateUnparkedPause(remoteEnv, snapshotId, io) {
|
|
|
77
77
|
function stampPlacementRootSessionId(placementRootResolved) {
|
|
78
78
|
return placementValueOrAbsent(placementRootResolved);
|
|
79
79
|
}
|
|
80
|
-
function autoModeLatchHealthy(d) {
|
|
81
|
-
try {
|
|
82
|
-
return d.breakerOpen() !== true && typeof d.consecutiveFailures === "function" && d.consecutiveFailures() === 0;
|
|
83
|
-
}
|
|
84
|
-
catch {
|
|
85
|
-
return false;
|
|
86
|
-
}
|
|
87
|
-
}
|
|
88
80
|
export function prepareSuspendSaga(input) {
|
|
89
|
-
const { gateMachineryActive, abortController, harness, checkpointStore, deps, sessionId, hostTaskId, taskScope, liveSpendRef, resume, nestedStats, internals, activeTools, outputRef, readFileStateForCheckpoint, faceCheckpointSection, reminderMark, handsCwdRef, worktreeSessionRef, inheritedParentConstraints, seedInheritedGate, inheritedAncestorRules, inheritedShellGate, autoModeIntent,
|
|
81
|
+
const { gateMachineryActive, abortController, harness, checkpointStore, deps, sessionId, hostTaskId, taskScope, liveSpendRef, resume, nestedStats, internals, activeTools, outputRef, readFileStateForCheckpoint, faceCheckpointSection, reminderMark, handsCwdRef, worktreeSessionRef, inheritedParentConstraints, seedInheritedGate, inheritedAncestorRules, inheritedShellGate, autoModeIntent, inheritedAdmittedOrgScopes, ownOrgVerdictRef, orgGovernedProvenance, announcedListingsRef, gitStatusRef, hookIdentity, placementRootResolved, externalContentTargetActive, remoteEnvFailures, memoryEngineSession, suspendLoopRef, ownedEnv, incompleteSuspendAdapter } = input;
|
|
90
82
|
if (!gateMachineryActive)
|
|
91
83
|
return { saga: undefined };
|
|
92
84
|
const inFlightSpendMicroUsd = () => {
|
|
@@ -140,7 +132,7 @@ export function prepareSuspendSaga(input) {
|
|
|
140
132
|
const constraintDigest = (inheritedParentConstraints?.length ?? 0) > 0
|
|
141
133
|
? constraintChainDigest(constraintChain)
|
|
142
134
|
: seedInheritedGate?.constraintDigest;
|
|
143
|
-
const autoModeIntentCarried = autoModeIntent
|
|
135
|
+
const autoModeIntentCarried = autoModeIntent;
|
|
144
136
|
return inheritedAncestorRules !== undefined ||
|
|
145
137
|
inheritedShellGate !== undefined ||
|
|
146
138
|
autoModeIntentCarried ||
|
|
@@ -678,7 +678,7 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
|
|
|
678
678
|
});
|
|
679
679
|
}
|
|
680
680
|
const { askLane } = prepareAskLane({ gateMachineryActive, abortController, effectivePolicy, budgetSnapshot, handsCwdRef, tools, inheritedUnavailableAsks, inheritedAskGrants, onAsk, humanReviewRef, now, ruleOffersOf, askSourceIdentity, riskAxesOf, autoModeDenialTracking, spec, deps, sessionId, runId, hooks, hookTimeoutMs, notifyOwnHookCrash });
|
|
681
|
-
const { saga } = prepareSuspendSaga({ gateMachineryActive, abortController, harness, checkpointStore, deps, sessionId, hostTaskId, taskScope, liveSpendRef, resume, nestedStats, internals, activeTools, outputRef, readFileStateForCheckpoint, faceCheckpointSection, reminderMark, handsCwdRef, worktreeSessionRef, inheritedParentConstraints, seedInheritedGate, inheritedAncestorRules, inheritedShellGate, autoModeIntent,
|
|
681
|
+
const { saga } = prepareSuspendSaga({ gateMachineryActive, abortController, harness, checkpointStore, deps, sessionId, hostTaskId, taskScope, liveSpendRef, resume, nestedStats, internals, activeTools, outputRef, readFileStateForCheckpoint, faceCheckpointSection, reminderMark, handsCwdRef, worktreeSessionRef, inheritedParentConstraints, seedInheritedGate, inheritedAncestorRules, inheritedShellGate, autoModeIntent, inheritedAdmittedOrgScopes, ownOrgVerdictRef, orgGovernedProvenance, announcedListingsRef, gitStatusRef, hookIdentity, placementRootResolved, externalContentTargetActive, remoteEnvFailures, memoryEngineSession, suspendLoopRef, ownedEnv, incompleteSuspendAdapter });
|
|
682
682
|
const { suspendForResource, suspendForPlatformLimit, suspendForReview } = prepareBoundaryParks({ saga, spec, checkpointStore, abortController, harness, session, sessions, sessionId, deps, priorLedger, maxSlices, maxSuspends, resourceTotal, priorSuspendCount, suspendChainBase, humanReviewRef, liveSpendRef, now, faceCheckpointState, f012CheckpointState, orgAdmissionCheckpointState, pausedRef, remoteEnvFailures, resourceSuspendEligible, durableSuspendInfraReady, incompleteSuspendAdapter });
|
|
683
683
|
const { parkAsk } = prepareParkAsk({ askLane, saga, spec, deps, sessionId, checkpointStore, toolRosterDeltas: rosterSeat, parkLaneArmed, contentAskRoutable, liveQuestionFace, mountedQuestionTool, contentAskBindings, lateStrandedAnswers, discloseStrandedAnswers, onAsk, runtimeCaps, inheritedUnavailableAsks, basePolicyForResumeEdit, budgetSnapshot, handsCwdRef, offloadStore, ownedEnv, incompleteSuspendAdapter, session, sessions, suspendChainBase, maxSuspends, remoteEnvFailures, shellGatedBash, shellGatedMonitor, effectiveShellGate, durableApproval, priorLedger, liveSpendRef, resourceTotal, faceCheckpointState, f012CheckpointState, orgAdmissionCheckpointState, ruleOffersOf, now, humanReviewRef, abortController, harness, pausedRef });
|
|
684
684
|
prepareGateStations({ askLane, parkAsk, tools, toolRosterDeltas: rosterSeat, toolEffects, deps, toolCallGateArmedRef, effectivePolicy, hooks, egressTools, irreversibleTools, spec, complianceDenies, harness, blockedToolCalls, inheritedAskGrants, inheritedUnavailableAsks, foldAskClasses, ancestorSandboxAdmissions, preToolContexts, gateOutcomes, batchHaltRef, blockedTracked, hookIdentity, reminderMark, planModeRef, hostTaskId, sessionId, ownGatePreToolUse, hookTimeoutMs, handsCwdRef, hookEnvFace, irreversibilityTier, reversibilityProbes, abortController, shellGatedBash, shellGatedMonitor, autoModeDecider, autoModeDenialTracking, stopForDenialLimit, permissionRuleLane, permissionRuleOrgLane, questionToolMounted, sandboxAdmissionArmed, sandboxBoundaryCapable, emitSandboxAdmitted, delegation, notifyOwnHookCrash });
|
|
@@ -46,7 +46,7 @@ export interface PrepareWiringManifestInput {
|
|
|
46
46
|
deps: RunnerDeps;
|
|
47
47
|
/** borrowed-readonly — the trusted spawn-side channel: `questionFaceStripped`, `isDelegatedChild`, `onTaskNotification`,
|
|
48
48
|
* `peerSelfRef`, `explicitAgentName` (the drain), `insideFork` / `agentName` / `parentToolCallId` (the identity). */
|
|
49
|
-
internals: Pick<RunInternals, "questionFaceStripped" | "isDelegatedChild" | "onTaskNotification" | "peerSelfRef" | "explicitAgentName" | "insideFork" | "agentName" | "parentToolCallId"
|
|
49
|
+
internals: Pick<RunInternals, "questionFaceStripped" | "isDelegatedChild" | "onTaskNotification" | "peerSelfRef" | "explicitAgentName" | "insideFork" | "agentName" | "parentToolCallId"> | undefined;
|
|
50
50
|
/** borrowed-readonly — the resume leg, or undefined (the manifest's leg derivation reads presence only). */
|
|
51
51
|
resume: Pick<PrepareResume, "seed"> | undefined;
|
|
52
52
|
/** borrowed-readonly — the acquired session id. */
|
|
@@ -199,14 +199,7 @@ export function prepareWiringManifest(input) {
|
|
|
199
199
|
memoryAdmissionWired: deps.memoryScopeAdmission !== undefined,
|
|
200
200
|
retentionPolicyWired: deps.retentionPolicy !== undefined,
|
|
201
201
|
...(modelGateManifest !== undefined ? { modelGate: modelGateManifest } : {}),
|
|
202
|
-
autoMode: {
|
|
203
|
-
armed: autoModeArmReason === "armed",
|
|
204
|
-
reason: autoModeArmReason,
|
|
205
|
-
...(() => {
|
|
206
|
-
const trip = internals?.autoModeBreakerLedger?.lastTrip(sessionId);
|
|
207
|
-
return trip !== undefined ? { breaker: trip } : {};
|
|
208
|
-
})(),
|
|
209
|
-
},
|
|
202
|
+
autoMode: { armed: autoModeArmReason === "armed", reason: autoModeArmReason },
|
|
210
203
|
mcp: mcpManifestEntries(lockedPreflight.mcp, mcp.statuses),
|
|
211
204
|
tools: toolRoster,
|
|
212
205
|
});
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { TaskSpec } from "../types.js";
|
|
2
2
|
import type { Prepared, ResumeRun, RunnerDepsSeat, RunState } from "./contracts.js";
|
|
3
|
-
export interface RunAttachmentSeatsInput {
|
|
3
|
+
export interface RunAttachmentSeatsInput<R> {
|
|
4
4
|
/** borrowed-readonly — the task spec: the attachments config and the `finalVerification` opt-in. */
|
|
5
5
|
spec: TaskSpec;
|
|
6
6
|
/** borrowed-mutable — the leg's prepared seat: `announcedListingsRef` is seeded; the session, the listing faces,
|
|
@@ -13,8 +13,10 @@ export interface RunAttachmentSeatsInput {
|
|
|
13
13
|
rs: RunState;
|
|
14
14
|
/** borrowed-readonly — the Runner's deployment deps, read once for `probeInstructionSources`. */
|
|
15
15
|
runner: RunnerDepsSeat;
|
|
16
|
+
/** borrowed-readonly — the lanes after this one, entered in this lane's last continuation (the seats it wrote are on `rs`). */
|
|
17
|
+
next: (seats: RunAttachmentSeatsResult) => Promise<R>;
|
|
16
18
|
}
|
|
17
19
|
/** Nothing comes back: the lane's products are the `counters` / `attach` groups it wrote on the borrowed run state. */
|
|
18
20
|
export interface RunAttachmentSeatsResult {
|
|
19
21
|
}
|
|
20
|
-
export declare function runAttachmentSeats(input: RunAttachmentSeatsInput): Promise<
|
|
22
|
+
export declare function runAttachmentSeats<R>(input: RunAttachmentSeatsInput<R>): Promise<R>;
|
|
@@ -3,7 +3,7 @@ import { stripGitStatusUnits } from "./git-status-frame.js";
|
|
|
3
3
|
import { SKILLS_LISTING_PROBE_HEADER } from "./synthetic-tools.js";
|
|
4
4
|
import { AGENT_LISTING_REMOVED_HEADER, SKILLS_LISTING_DELTA_HEADER, SKILLS_LISTING_REMOVED_HEADER, agentListingDeltaHeader, agentListingInitialHeader, createAttachmentState, replayAnnouncedListing, replayAnnouncedModels } from "./turn-attachments.js";
|
|
5
5
|
export async function runAttachmentSeats(input) {
|
|
6
|
-
const { spec, prepared, resume, rs, runner } = input;
|
|
6
|
+
const { spec, prepared, resume, rs, runner, next } = input;
|
|
7
7
|
rs.counters.wroteThisRun = false;
|
|
8
8
|
rs.counters.finalVerifyInjections = 0;
|
|
9
9
|
rs.counters.groundingSignalPreR9 = false;
|
|
@@ -183,5 +183,5 @@ export async function runAttachmentSeats(input) {
|
|
|
183
183
|
}
|
|
184
184
|
}
|
|
185
185
|
rs.attach.attachmentsInjected = 0;
|
|
186
|
-
return {};
|
|
186
|
+
return await next({});
|
|
187
187
|
}
|
|
@@ -1,20 +1,9 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* design/393 S5 — the run body's IDENTITY WIRING (R1), verbatim from `Runner.runLocked`, the first thing after
|
|
3
|
-
* `prepared` exists: the notification lane's bindings (harness, session anchor, identity mint), the backstop
|
|
4
|
-
* carrier's immediate seats, the event-identity mint (`ident`) and the run's canonical task id, the wiring-manifest
|
|
5
|
-
* frame and the roster-delta subscription, the delegation-lifecycle spawn station and its owed-terminal carrier,
|
|
6
|
-
* the manual-compact mooted channel, the harness sinks for undrained engine notes / user inputs / consumed
|
|
7
|
-
* engine notes, the notify / capture-opt-out bridges, the spawner's injector hand-back, the idle-parked
|
|
8
|
-
* notification redelivery at turn open, the loop latch and the live-task handle publication, and the run's
|
|
9
|
-
* usage counters. Every push here happens before the run's first model/tool interaction, as it did.
|
|
10
|
-
*/
|
|
11
|
-
import { type AgentHarness } from "../../internal/harness.js";
|
|
12
1
|
import type { PeerInboundChainRef } from "../../agents/peer-admission.js";
|
|
13
2
|
import { type PendingSessionNotifications, type SystemInjectionPriority, type TaskNotificationPayload } from "../task-notification.js";
|
|
14
3
|
import type { PushQueue } from "../push-queue.js";
|
|
15
4
|
import type { TaskEvent, TaskSpec } from "../types.js";
|
|
16
5
|
import type { Stats } from "./assemble-result.js";
|
|
17
|
-
import type { CaptureOptOutRef, LiveHandle, ManualCompactRef, NotifyRef, Prepared, RunInternals, RunnerDepsSeat, TaskIdRef } from "./contracts.js";
|
|
6
|
+
import type { CaptureOptOutRef, LiveHandle, ManualCompactRef, NotificationLaneBindings, NotifyRef, Prepared, RunInternals, RunnerDepsSeat, TaskIdRef } from "./contracts.js";
|
|
18
7
|
export interface RunIdentityWiringInput {
|
|
19
8
|
/** borrowed-readonly — the task spec: the task id and the memory / notification seats it names. */
|
|
20
9
|
spec: TaskSpec;
|
|
@@ -38,7 +27,7 @@ export interface RunIdentityWiringInput {
|
|
|
38
27
|
notifyRef: NotifyRef | undefined;
|
|
39
28
|
/** borrowed-mutable — the capture opt-out bridge: `flip` is bound here when a memory session mounted. */
|
|
40
29
|
captureOptOutRef: CaptureOptOutRef | undefined;
|
|
41
|
-
/** borrowed-readonly — the notification lane's ONE injection entry (the
|
|
30
|
+
/** borrowed-readonly — the notification lane's ONE injection entry (the R0 lane's). */
|
|
42
31
|
injectTaskNotification: (notification: TaskNotificationPayload, opts?: {
|
|
43
32
|
priority?: SystemInjectionPriority;
|
|
44
33
|
}) => Promise<"queued" | "parked" | "dropped_duplicate">;
|
|
@@ -46,26 +35,10 @@ export interface RunIdentityWiringInput {
|
|
|
46
35
|
deliveredAtTurnOpen: Set<string>;
|
|
47
36
|
/** borrowed-mutable — design/176: the peer inbound chain, overwritten by each consumed peer-class payload. */
|
|
48
37
|
peerInboundChainRef: PeerInboundChainRef;
|
|
49
|
-
/** borrowed-mutable — the
|
|
50
|
-
* the harness, the session anchor and the identity mint the lane's closures read, and reads the
|
|
51
|
-
* the undrained-notes sink. */
|
|
52
|
-
notificationLane:
|
|
53
|
-
harness: AgentHarness | undefined;
|
|
54
|
-
sessionId: string | undefined;
|
|
55
|
-
ident: () => {
|
|
56
|
-
eventId?: string;
|
|
57
|
-
parentToolCallId?: string;
|
|
58
|
-
sourceTaskId?: string;
|
|
59
|
-
};
|
|
60
|
-
};
|
|
61
|
-
/** borrowed-mutable — the driver's held agent_end account (backlog #389), a view over its `let`: the undrained-inputs
|
|
62
|
-
* sink writes it when the run committed a durable park; the driver's tail reads it. */
|
|
63
|
-
undrainedUserAtEnd: {
|
|
64
|
-
current: {
|
|
65
|
-
steer: number;
|
|
66
|
-
followUp: number;
|
|
67
|
-
} | undefined;
|
|
68
|
-
};
|
|
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;
|
|
69
42
|
/** borrowed-mutable — the Runner's per-session parked-notification store: drained at turn open, re-pended on failure. */
|
|
70
43
|
pendingSessionNotifications: PendingSessionNotifications;
|
|
71
44
|
/** borrowed-readonly — the Runner's deployment deps, read LIVE (`onDelegationLifecycle`, `onNotice`). */
|
|
@@ -92,5 +65,13 @@ export interface RunIdentityWiringResult {
|
|
|
92
65
|
};
|
|
93
66
|
/** This leg's usage counters, zeroed here; the harness-handlers lane is their writer from the first turn on. */
|
|
94
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
|
+
};
|
|
95
76
|
}
|
|
96
77
|
export declare function runIdentityWiring(input: RunIdentityWiringInput): RunIdentityWiringResult;
|