@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
|
@@ -687,17 +687,10 @@ export interface RunnerDeps {
|
|
|
687
687
|
sessionContext?: readonly string[];
|
|
688
688
|
/** Transcript-window bounds for the classify prompt (defaults: 40 entries / 2000 chars each). */
|
|
689
689
|
window?: import("./auto-mode-prompt.js").AutoModeWindowOptions;
|
|
690
|
-
/** Classify round-trip cap, ms (default 15_000).
|
|
690
|
+
/** Classify round-trip cap, ms (default 15_000). A round past the cap is `unavailable(timeout)`: the call is
|
|
691
|
+
* DENIED with a sentence that says so (CC 2.1.250 form), and the next call is classified afresh — there is no
|
|
692
|
+
* failure count and no session latch. */
|
|
691
693
|
timeoutMs?: number;
|
|
692
|
-
/** Consecutive-failure threshold opening the one-way session breaker (default 3). */
|
|
693
|
-
failureThreshold?: number;
|
|
694
|
-
/** Fired ONCE when the session breaker opens (the "退回非 auto" alarm — surface it to the operator). The engine
|
|
695
|
-
* records the trip on the session's breaker read face (`WiringManifest.autoMode.breaker`, #616) BEFORE calling
|
|
696
|
-
* this hook, so a deployment that wires nothing here still gets the read face. */
|
|
697
|
-
onBreakerOpen?: (info: {
|
|
698
|
-
consecutiveFailures: number;
|
|
699
|
-
lastCause: import("./auto-mode.js").AutoModeBreakerCause;
|
|
700
|
-
}) => void;
|
|
701
694
|
/**
|
|
702
695
|
* The classifier DENIAL LIMIT (CC 2.1.250 `FO`/`AKe`): a run whose classifier keeps blocking falls
|
|
703
696
|
* back to a PERSON instead of being denied without end. Per run: a `block` first increments the
|
|
@@ -736,10 +729,7 @@ export interface RunnerDeps {
|
|
|
736
729
|
* line); a deployment that treats those as sensitive at rest should keep them out of the arming
|
|
737
730
|
* face rather than out of this flag.
|
|
738
731
|
*
|
|
739
|
-
*
|
|
740
|
-
* already fell back to non-auto hands nothing forward (the redemption must never run wider than the
|
|
741
|
-
* ancestor it inherits). A `true` here with a non-serializable face announces once and records
|
|
742
|
-
* nothing (`phase:"config"`).
|
|
732
|
+
* A `true` here with a non-serializable face announces once and records nothing (`phase:"config"`).
|
|
743
733
|
*/
|
|
744
734
|
persistArming?: boolean;
|
|
745
735
|
/**
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { type WorkflowJournalStore } from "../workflow-journal-store.js";
|
|
2
|
+
import { type ContractAssertionRunner } from "./contract-harness.js";
|
|
3
|
+
/**
|
|
4
|
+
* The full cross-backend contract for {@link WorkflowJournalStore}. Every case builds its own store via
|
|
5
|
+
* `make()`; with no runner the cases run sequentially and the first failure throws.
|
|
6
|
+
*/
|
|
7
|
+
export declare function workflowJournalStoreContract(make: () => WorkflowJournalStore, runAssertion?: ContractAssertionRunner): Promise<void>;
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import { strict as assert } from "node:assert";
|
|
2
|
+
import { JOURNAL_OVERSIZE_ERROR_CODE, MAX_JOURNAL_RESULT_BYTES, } from "../workflow-journal-store.js";
|
|
3
|
+
import { beginContract } from "./contract-harness.js";
|
|
4
|
+
const key = (ordinal) => `${ordinal}:h`;
|
|
5
|
+
const completed = (ordinal, over = {}) => ({
|
|
6
|
+
taskId: `t-${ordinal}`,
|
|
7
|
+
sessionId: `s-${ordinal}`,
|
|
8
|
+
terminal: { kind: "completed" },
|
|
9
|
+
result: `r${ordinal}`,
|
|
10
|
+
structuredOutput: { ordinal, nested: { ok: true } },
|
|
11
|
+
stats: { turns: 1, tokens: 1, costMicroUsd: 0, nested: { tokens: 0, turns: 0, tasks: 0, costMicroUsd: 0 } },
|
|
12
|
+
...over,
|
|
13
|
+
});
|
|
14
|
+
const parked = (ordinal, over = {}) => ({
|
|
15
|
+
taskId: `t-${ordinal}`,
|
|
16
|
+
sessionId: `s-${ordinal}`,
|
|
17
|
+
terminal: { kind: "paused", token: `tok-${ordinal}`, checkpointId: `cp-${ordinal}`, gate: { kind: "human", reason: "approve", toolName: "Write" } },
|
|
18
|
+
result: "",
|
|
19
|
+
structuredOutput: { partial: ordinal },
|
|
20
|
+
stats: { turns: 1, tokens: 1, costMicroUsd: 0, nested: { tokens: 3, turns: 2, tasks: 1, costMicroUsd: 1 } },
|
|
21
|
+
...over,
|
|
22
|
+
});
|
|
23
|
+
const OVER_CAP = "x".repeat(MAX_JOURNAL_RESULT_BYTES + 1024);
|
|
24
|
+
const isOversizeRefusal = (e) => e instanceof Error && e.code === JOURNAL_OVERSIZE_ERROR_CODE;
|
|
25
|
+
export async function workflowJournalStoreContract(make, runAssertion) {
|
|
26
|
+
const { run, settle } = beginContract(runAssertion);
|
|
27
|
+
run("append → load returns entries ASCENDING by ordinal, both arms verbatim; a re-append per ordinal OVERWRITES", async () => {
|
|
28
|
+
const store = make();
|
|
29
|
+
await store.append("run-1", "tenant-a", { callKey: key(10), result: completed(10) });
|
|
30
|
+
await store.append("run-1", "tenant-a", { callKey: key(1), parked: parked(1) });
|
|
31
|
+
await store.append("run-1", "tenant-a", { callKey: key(0), result: completed(0) });
|
|
32
|
+
await store.append("run-1", "tenant-a", { callKey: key(2), result: completed(2) });
|
|
33
|
+
await store.append("run-1", "tenant-a", { callKey: key(0), result: completed(0, { result: "overwritten" }) });
|
|
34
|
+
const entries = await store.load("run-1", "tenant-a");
|
|
35
|
+
assert.deepEqual(entries.map((e) => e.callKey), [key(0), key(1), key(2), key(10)]);
|
|
36
|
+
assert.deepEqual(entries[0], { callKey: key(0), result: completed(0, { result: "overwritten" }) });
|
|
37
|
+
assert.deepEqual(entries[1], { callKey: key(1), parked: parked(1) });
|
|
38
|
+
});
|
|
39
|
+
run("scope wall: a cross-scope load is EMPTY — before and after the owner's own load, and after a refused cross-scope append — on both arms", async () => {
|
|
40
|
+
const store = make();
|
|
41
|
+
await store.append("run-1", "alice", { callKey: key(0), result: completed(0) });
|
|
42
|
+
await store.append("run-1", "alice", { callKey: key(1), parked: parked(1) });
|
|
43
|
+
assert.deepEqual(await store.load("run-1", "mallory"), []);
|
|
44
|
+
assert.equal((await store.load("run-1", "alice")).length, 2);
|
|
45
|
+
assert.deepEqual(await store.load("run-1", "mallory"), []);
|
|
46
|
+
await assert.rejects(store.append("run-1", "mallory", { callKey: key(2), result: completed(2) }));
|
|
47
|
+
await assert.rejects(store.append("run-1", "mallory", { callKey: key(3), parked: parked(3) }));
|
|
48
|
+
assert.deepEqual(await store.load("run-1", "mallory"), []);
|
|
49
|
+
assert.deepEqual((await store.load("run-1", "alice")).map((e) => e.callKey), [key(0), key(1)]);
|
|
50
|
+
});
|
|
51
|
+
run(`oversize RESULT arm ⇒ append rejects with code "${JOURNAL_OVERSIZE_ERROR_CODE}"; nothing journaled; the store stays usable`, async () => {
|
|
52
|
+
const store = make();
|
|
53
|
+
await store.append("run-1", "tenant-a", { callKey: key(0), result: completed(0) });
|
|
54
|
+
await assert.rejects(store.append("run-1", "tenant-a", { callKey: key(1), result: completed(1, { result: OVER_CAP }) }), isOversizeRefusal);
|
|
55
|
+
assert.deepEqual((await store.load("run-1", "tenant-a")).map((e) => e.callKey), [key(0)]);
|
|
56
|
+
await store.append("run-1", "tenant-a", { callKey: key(2), result: completed(2) });
|
|
57
|
+
assert.deepEqual((await store.load("run-1", "tenant-a")).map((e) => e.callKey), [key(0), key(2)]);
|
|
58
|
+
});
|
|
59
|
+
run(`oversize PARKED arm ⇒ append rejects with code "${JOURNAL_OVERSIZE_ERROR_CODE}"; nothing journaled (never a silent skip — a lost park is a resume running the ordinal live)`, async () => {
|
|
60
|
+
const store = make();
|
|
61
|
+
await store.append("run-1", "tenant-a", { callKey: key(0), result: completed(0) });
|
|
62
|
+
await assert.rejects(store.append("run-1", "tenant-a", { callKey: key(1), parked: parked(1, { result: OVER_CAP }) }), isOversizeRefusal);
|
|
63
|
+
assert.deepEqual((await store.load("run-1", "tenant-a")).map((e) => e.callKey), [key(0)]);
|
|
64
|
+
await store.append("run-1", "tenant-a", { callKey: key(1), parked: parked(1) });
|
|
65
|
+
assert.equal((await store.load("run-1", "tenant-a"))[1].parked?.terminal.kind, "paused");
|
|
66
|
+
});
|
|
67
|
+
run("the cap is inclusive: a payload of EXACTLY the cap's byte count is accepted on both arms", async () => {
|
|
68
|
+
const store = make();
|
|
69
|
+
const fit = (payload) => {
|
|
70
|
+
const base = Buffer.byteLength(JSON.stringify({ ...payload, result: "" }), "utf8");
|
|
71
|
+
return { ...payload, result: "y".repeat(MAX_JOURNAL_RESULT_BYTES - base) };
|
|
72
|
+
};
|
|
73
|
+
const r = fit(completed(0));
|
|
74
|
+
const p = fit(parked(1));
|
|
75
|
+
assert.equal(Buffer.byteLength(JSON.stringify(r), "utf8"), MAX_JOURNAL_RESULT_BYTES);
|
|
76
|
+
assert.equal(Buffer.byteLength(JSON.stringify(p), "utf8"), MAX_JOURNAL_RESULT_BYTES);
|
|
77
|
+
await store.append("run-1", "tenant-a", { callKey: key(0), result: r });
|
|
78
|
+
await store.append("run-1", "tenant-a", { callKey: key(1), parked: p });
|
|
79
|
+
const entries = await store.load("run-1", "tenant-a");
|
|
80
|
+
assert.deepEqual(entries.map((e) => e.callKey), [key(0), key(1)]);
|
|
81
|
+
assert.deepEqual(entries[0].result, r);
|
|
82
|
+
assert.deepEqual(entries[1].parked, p);
|
|
83
|
+
});
|
|
84
|
+
await settle();
|
|
85
|
+
}
|
|
@@ -207,20 +207,12 @@ export type PermissionResult = {
|
|
|
207
207
|
* same safe direction as `matchedAskRule`); it cannot state a window of its own, because the
|
|
208
208
|
* route it would be a window for has not been chosen yet. */
|
|
209
209
|
denialLimitFallback?: import("./auto-mode.js").UnarmedDenialLimitFallback;
|
|
210
|
-
/** #616 (additive): the
|
|
211
|
-
*
|
|
212
|
-
*
|
|
213
|
-
*
|
|
214
|
-
*
|
|
215
|
-
*
|
|
216
|
-
* the outcome (`automode-unavailable`) beside the decision's provenance, never in place of it, and
|
|
217
|
-
* this engine's divergence (the ask reaches a person instead of being denied) does not move the
|
|
218
|
-
* fact onto the origin axis either. ENGINE-STAMPED at the classifier stations (the gate's own and
|
|
219
|
-
* the inherited-lane arms) only when the verdict was `unavailable`; `parse_error` stamps nothing
|
|
220
|
-
* (the classifier ran and answered outside its contract — a different sentence). Display metadata:
|
|
221
|
-
* nothing reads it to decide anything, so a policy that self-declares it can only put its own
|
|
222
|
-
* sentence on its own card. Carried onto the approval request and the durable row by the carry
|
|
223
|
-
* stations. */
|
|
210
|
+
/** #616 (additive): the classifier-unavailable FACT on an ASK — `cause` is the verdict's own word
|
|
211
|
+
* ({@link import("./auto-mode.js").AutoModeUnavailableCause}). Since #661 the ENGINE no longer writes
|
|
212
|
+
* it here: an `unavailable` verdict is a DENY (the deny arm's member above), never an ask handed to a
|
|
213
|
+
* person. The member stays on the ask arm as display metadata a policy may self-declare on its own
|
|
214
|
+
* ask (nothing reads it to decide anything); the carry stations still copy it onto the approval
|
|
215
|
+
* request and the durable row when present. Retirement candidate for the next wire window. */
|
|
224
216
|
classifierUnavailable?: {
|
|
225
217
|
readonly cause: import("./auto-mode.js").AutoModeUnavailableCause;
|
|
226
218
|
};
|
|
@@ -298,6 +290,16 @@ export type PermissionResult = {
|
|
|
298
290
|
updatedInput?: unknown;
|
|
299
291
|
message?: string;
|
|
300
292
|
decisionReason?: DecisionReason;
|
|
293
|
+
/** #661 (additive): this deny is the classifier's UNAVAILABILITY — the auto-mode classifier was consulted
|
|
294
|
+
* and could not run, and the call is refused with a sentence that says so (CC 2.1.250 `Ze.unavailable` ⇒
|
|
295
|
+
* `deny`, `x1t`). `cause` is the verdict's own word ({@link import("./auto-mode.js").AutoModeUnavailableCause}).
|
|
296
|
+
* ENGINE-STAMPED beside `decisionReason: "classifier"` at the classifier stations (the gate's own and the
|
|
297
|
+
* inherited-lane arms) on an `unavailable` verdict only; a `block` and a `parse_error` deny carry nothing
|
|
298
|
+
* here. Read by the deny observer's payload ({@link import("./hooks.js").PermissionDeniedPayload}) and by
|
|
299
|
+
* nothing that decides. */
|
|
300
|
+
classifierUnavailable?: {
|
|
301
|
+
readonly cause: import("./auto-mode.js").AutoModeUnavailableCause;
|
|
302
|
+
};
|
|
301
303
|
};
|
|
302
304
|
/**
|
|
303
305
|
* design/252 G-2 — WHY a piece of rule-provenance evidence is not on an ask.
|
|
@@ -540,100 +542,42 @@ export declare function constraintChainEntryOf(policy: ToolPolicy, meta?: Constr
|
|
|
540
542
|
/**
|
|
541
543
|
* One inherited-chain LAYER as both chain-entry mint sites see it — structurally an
|
|
542
544
|
* `InheritedGate.parentConstraints[]` element, typed here structurally so this module (which owns the
|
|
543
|
-
* digest) does not depend on the runner's shapes.
|
|
545
|
+
* digest) does not depend on the runner's shapes. The classifier itself is not read: a decider carries no
|
|
546
|
+
* state between rounds, so nothing about its health enters a chain entry.
|
|
544
547
|
*/
|
|
545
548
|
export interface ConstraintChainLayerView {
|
|
546
549
|
policy: ToolPolicy;
|
|
547
550
|
autoMode?: {
|
|
548
|
-
decider: {
|
|
549
|
-
breakerOpen: () => boolean;
|
|
550
|
-
consecutiveFailures?: () => number;
|
|
551
|
-
};
|
|
552
551
|
arming?: unknown;
|
|
553
552
|
};
|
|
554
553
|
durableMandate?: boolean;
|
|
555
554
|
contentMandate?: boolean;
|
|
556
555
|
}
|
|
557
556
|
/**
|
|
558
|
-
* The WRITE-side mint: the chain entry a durable PARK records for a live inherited layer.
|
|
559
|
-
*
|
|
560
|
-
*
|
|
561
|
-
*
|
|
562
|
-
*
|
|
563
|
-
*
|
|
564
|
-
*
|
|
565
|
-
*
|
|
566
|
-
*
|
|
567
|
-
*
|
|
568
|
-
*
|
|
569
|
-
*
|
|
570
|
-
* classification from dropping the whole session to non-auto — would hand a redemption the full budget
|
|
571
|
-
* again, and the redeemed leg stays auto-classified through failures the ancestor would not have
|
|
572
|
-
* survived. So the streak must read ZERO as well. A decider that does not expose it at all is UNKNOWN
|
|
573
|
-
* state, and unknown takes the same arm as tripped: nothing is recorded (which is why a host that hand
|
|
574
|
-
* rolls a decider cannot use the persisted-arming path — it must mint through `createAutoModeDecider`,
|
|
575
|
-
* on both the arming and the redeeming side).
|
|
576
|
-
*
|
|
577
|
-
* Every read here is guarded, and every failure to read is treated as "withdrawn" — the opposite default
|
|
578
|
-
* from the gate's demote-to-ask breaker reader, and for the same reason both are right: there, an
|
|
579
|
-
* unreadable latch must not suppress a tighten; here, it must not license a carry-forward.
|
|
580
|
-
*
|
|
581
|
-
* ⚠️ WRITE SIDE ONLY. This gate reads MUTABLE state (a one-way latch, plus a streak that both grows and
|
|
582
|
-
* resets to zero on any healthy classification). The resume re-supply must NOT re-run it — it samples a
|
|
583
|
-
* different instant, and the two instants disagree for perfectly ordinary reasons: an ancestor keeps
|
|
584
|
-
* running while its delegated child sits parked awaiting a human. See
|
|
585
|
-
* {@link constraintChainEntryOfSuppliedLayer} for the verify side and the full account.
|
|
586
|
-
*
|
|
587
|
-
* ⚖️ WHAT THIS BOUND DOES NOT DO (recorded, precise shape). A withdrawn arming leaves the entry at
|
|
588
|
-
* `autoModeArmed: true` with no recipe — digest-identical to an armed layer whose deployment never opted
|
|
589
|
-
* in. So the digest does not, and cannot, stop a re-supplier from handing back a FRESH healthy decider of
|
|
590
|
-
* its own: that is the pre-existing re-supply trust posture (see `resumeStream`'s contract — a caller
|
|
591
|
-
* able to invoke it already holds full Runner authority, and the chain checks catch shape MISTAKES, not
|
|
592
|
-
* a hostile trusted caller), and it is unchanged here. What this bound governs is what CORE hands
|
|
593
|
-
* forward: a withdrawn ancestor's CRITERIA never travel, so a redemption cannot reconstruct the
|
|
594
|
-
* ancestor's classifier from the row. For a fleet running `persistArming` everywhere, the pair
|
|
595
|
-
* (`autoModeArmed` present, `autoModeArming` absent) is itself the readable signal that the ancestor's
|
|
596
|
-
* arming was withdrawn or unrecordable, and such a host should re-supply a refusing decider rather than a
|
|
597
|
-
* fresh one. Making the WITHDRAWAL itself digest-bound is a coherent stronger design — it needs a new
|
|
598
|
-
* marker plus a new re-supply obligation to reproduce it (a withdrawn row carries no recipe, so the
|
|
599
|
-
* marker cannot be derived from one), which is a scope decision for this seam's owner, not a silent
|
|
600
|
-
* mechanism change.
|
|
557
|
+
* The WRITE-side mint: the chain entry a durable PARK records for a live inherited layer. The recipe is
|
|
558
|
+
* carried whenever the layer has one (the deployment opted into `persistArming`). The former gate — "only
|
|
559
|
+
* while the ancestor's breaker is untripped and untouched" — went with the breaker: a decider carries no
|
|
560
|
+
* state between rounds, so there is no ancestor health to sample here and nothing that could make a
|
|
561
|
+
* redemption run wider than the ancestor it inherits.
|
|
562
|
+
*
|
|
563
|
+
* ⚖️ WHAT THE ROW DOES NOT SAY. An armed layer whose deployment never opted in leaves the entry at
|
|
564
|
+
* `autoModeArmed: true` with no recipe. The digest does not, and cannot, stop a re-supplier from handing
|
|
565
|
+
* back a FRESH decider of its own: that is the pre-existing re-supply trust posture (see `resumeStream`'s
|
|
566
|
+
* contract — a caller able to invoke it already holds full Runner authority, and the chain checks catch
|
|
567
|
+
* shape MISTAKES, not a hostile trusted caller). What CORE hands forward is the recipe when there is one,
|
|
568
|
+
* and nothing otherwise.
|
|
601
569
|
*/
|
|
602
570
|
export declare function constraintChainEntryOfLayer(layer: ConstraintChainLayerView): ConstraintChainEntry;
|
|
603
571
|
/**
|
|
604
572
|
* The VERIFY-side mint: the entry a resume's RE-SUPPLIED layer must reproduce for the row it is
|
|
605
573
|
* redeeming. Same body as the park mint, with the arming carry taken from the ROW rather than from the
|
|
606
|
-
* layer
|
|
607
|
-
*
|
|
608
|
-
*
|
|
609
|
-
*
|
|
610
|
-
*
|
|
611
|
-
*
|
|
612
|
-
*
|
|
613
|
-
* - the ancestor was healthy at the park (the row carries the recipe) and its breaker opened while the
|
|
614
|
-
* child sat parked ⇒ the re-supply mints WITHOUT the recipe, the digests differ, and because the
|
|
615
|
-
* latch is ONE-WAY the row is refused `resume.parent_constraint_mismatch` forever;
|
|
616
|
-
* - the ancestor was one failure into its streak at the park (the row carries no recipe) and the streak
|
|
617
|
-
* cleared on its next healthy classification ⇒ the re-supply mints WITH a recipe the row never
|
|
618
|
-
* carried, same refusal.
|
|
619
|
-
* Neither needs a host mistake: the ancestor and its siblings keep running while the child is parked, and
|
|
620
|
-
* the same-process `resume()` verb re-supplies the very same live layer objects out of the Runner's own
|
|
621
|
-
* parked-constraint registry. Nothing about the row changed; only a classifier's health did.
|
|
622
|
-
*
|
|
623
|
-
* WHAT THIS COSTS, NAMED. A row that recorded NO recipe no longer refuses a re-supply that hands one
|
|
624
|
-
* back. That is not a tunable — the re-supply side literally cannot tell "the row withdrew a recipe this
|
|
625
|
-
* same live layer still declares" (the second bullet above, a legitimate redemption) from "a re-supplier
|
|
626
|
-
* is putting a recipe onto a row that withdrew one": both are the identical pair of inputs. It is also
|
|
627
|
-
* thinner than it looks. The recipe is not an enforcement object — the DECIDER classifies, and the
|
|
628
|
-
* re-supply trust posture already permits handing back a fresh healthy one, which is the capability that
|
|
629
|
-
* would matter. What the row's absence still means is unchanged and is the property bound ① was written
|
|
630
|
-
* for: a withdrawn ancestor's criteria never travel ON THE ROW, so no redemption can reconstruct that
|
|
631
|
-
* ancestor's classifier from the checkpoint.
|
|
632
|
-
*
|
|
633
|
-
* WHAT THE DIGEST STILL BINDS. A row that DID record a recipe must have that recipe handed back: the
|
|
634
|
-
* carry is on, so a re-supply that drops the arming, or hands back a different one, mints a different
|
|
635
|
-
* entry and is refused pre-CAS exactly as before. That is the whole of the documented re-supply contract
|
|
636
|
-
* — "hand back what the row carries".
|
|
574
|
+
* layer — the digest equality is over bytes the row itself recorded, never over what a live object says at
|
|
575
|
+
* a second instant. A row that DID record a recipe must have that recipe handed back: a re-supply that drops
|
|
576
|
+
* the arming, or hands back a different one, mints a different entry and is refused pre-CAS
|
|
577
|
+
* (`resume.parent_constraint_mismatch`). A row that recorded none does not refuse a re-supply that hands one
|
|
578
|
+
* back — the recipe is not an enforcement object (the DECIDER classifies), and the re-supply trust posture
|
|
579
|
+
* already permits a fresh decider; what the row's absence still means is that no redemption can reconstruct
|
|
580
|
+
* the ancestor's classifier FROM THE CHECKPOINT.
|
|
637
581
|
*/
|
|
638
582
|
export declare function constraintChainEntryOfSuppliedLayer(layer: ConstraintChainLayerView, recorded: ConstraintChainEntry | undefined): ConstraintChainEntry;
|
|
639
583
|
/**
|
package/dist/core/tool-policy.js
CHANGED
|
@@ -128,17 +128,7 @@ function chainEntryOfLayerCarrying(layer, carryArming) {
|
|
|
128
128
|
});
|
|
129
129
|
}
|
|
130
130
|
export function constraintChainEntryOfLayer(layer) {
|
|
131
|
-
|
|
132
|
-
if (layer.autoMode?.arming !== undefined) {
|
|
133
|
-
try {
|
|
134
|
-
const d = layer.autoMode.decider;
|
|
135
|
-
armingLive = d.breakerOpen() !== true && typeof d.consecutiveFailures === "function" && d.consecutiveFailures() === 0;
|
|
136
|
-
}
|
|
137
|
-
catch {
|
|
138
|
-
armingLive = false;
|
|
139
|
-
}
|
|
140
|
-
}
|
|
141
|
-
return chainEntryOfLayerCarrying(layer, armingLive);
|
|
131
|
+
return chainEntryOfLayerCarrying(layer, layer.autoMode?.arming !== undefined);
|
|
142
132
|
}
|
|
143
133
|
export function constraintChainEntryOfSuppliedLayer(layer, recorded) {
|
|
144
134
|
return chainEntryOfLayerCarrying(layer, recorded?.autoModeArming !== undefined);
|
package/dist/core/trace.d.ts
CHANGED
|
@@ -529,11 +529,10 @@ export type TraceEvent = {
|
|
|
529
529
|
} | {
|
|
530
530
|
/**
|
|
531
531
|
* The auto-mode classifier decided (or declined to decide) one pending ask — one frame per
|
|
532
|
-
* `decide` call,
|
|
533
|
-
*
|
|
534
|
-
*
|
|
535
|
-
*
|
|
536
|
-
* read face a shell renders is a separate, additive wire face. `ms` is the wall time from the
|
|
532
|
+
* `decide` call, so a consumer can read the gate's wall-clock cost per tool call and the failure
|
|
533
|
+
* cause behind a call the classifier could not evaluate. A TRACE frame rather than a task event: it
|
|
534
|
+
* fires once per gated call and it is an operator's read (why did that ask take four seconds / why
|
|
535
|
+
* was that call denied). `ms` is the wall time from the
|
|
537
536
|
* decide call to its verdict (timeout included: a timed-out round reads the deadline).
|
|
538
537
|
*/
|
|
539
538
|
kind: "auto_mode.classified";
|
|
@@ -547,8 +546,8 @@ export type TraceEvent = {
|
|
|
547
546
|
ms: number;
|
|
548
547
|
/** The verdict kind the gate acted on (`allow` / `block` / `unavailable` / `parse_error`). */
|
|
549
548
|
verdict: "allow" | "block" | "unavailable" | "parse_error";
|
|
550
|
-
/** Present iff `verdict === "unavailable"`: `error` / `timeout
|
|
551
|
-
cause?: "error" | "timeout"
|
|
549
|
+
/** Present iff `verdict === "unavailable"`: `error` / `timeout`. */
|
|
550
|
+
cause?: "error" | "timeout";
|
|
552
551
|
ts: number;
|
|
553
552
|
} | {
|
|
554
553
|
/** C1 — the failover brain served this call from a FALLBACK entry (`createFailoverBrain`): the
|
|
@@ -71,13 +71,8 @@ export type ParkLaneReason = "no_checkpoint_store" | "no_durable_approval_opt_in
|
|
|
71
71
|
* verdict; the same fail-closed outcome as `denied`, named apart so a consumer
|
|
72
72
|
* can tell "policy said no" from "the entitlement source was unreachable".
|
|
73
73
|
* - `armed` — all three arms held; the classifier decider was minted for this leg.
|
|
74
|
-
* - `latch_open` — the session's one-way "back to non-auto" breaker has tripped. A leg-START
|
|
75
|
-
* manifest never carries it (a decider is minted fresh at prepare and its latch
|
|
76
|
-
* is closed by construction; a tripped ancestor hands no intent forward, which
|
|
77
|
-
* reads as `no_intent`); it is in the vocabulary so a consumer switching on the
|
|
78
|
-
* closed set is complete for a mid-leg re-read face, which nothing mints today.
|
|
79
74
|
*/
|
|
80
|
-
export declare const AUTO_MODE_ARM_REASONS: readonly ["armed", "no_intent", "no_face", "denied", "resolver_fault"
|
|
75
|
+
export declare const AUTO_MODE_ARM_REASONS: readonly ["armed", "no_intent", "no_face", "denied", "resolver_fault"];
|
|
81
76
|
export type AutoModeArmReason = (typeof AUTO_MODE_ARM_REASONS)[number];
|
|
82
77
|
/**
|
|
83
78
|
* One declared MCP server's materialization result for THIS leg — the per-server connection-state
|
|
@@ -243,22 +238,13 @@ export interface WiringManifest {
|
|
|
243
238
|
* per-leg READ face of the auto-mode arming decision: `armed` ⇔ `reason === "armed"` (the
|
|
244
239
|
* classifier decider was minted for this leg), and `reason` names the first arm that failed
|
|
245
240
|
* otherwise — see {@link AUTO_MODE_ARM_REASONS}. A serving layer that used to infer the mode from
|
|
246
|
-
* spec shape reads it here instead.
|
|
247
|
-
*
|
|
248
|
-
*
|
|
249
|
-
* for this session on this Runner (an EARLIER leg's decider — the latch is a per-run fact and a leg-start
|
|
250
|
-
* manifest's own decider is closed by construction, which is why there is no `open` boolean here: it
|
|
251
|
-
* would read `false` on every mint; the reason vocabulary reserves `latch_open` for a mid-leg re-read
|
|
252
|
-
* face nothing mints today). Present ⇔ a trip was recorded (never tripped, evicted or a standalone
|
|
253
|
-
* prepare ⇒ absent). `{ openedAtMs, lastCause, failures, runId }` — see
|
|
254
|
-
* {@link import("./auto-mode.js").AutoModeBreakerTrip}. A per-leg observation like `mcp`, so it is NOT
|
|
255
|
-
* part of {@link configFingerprint}: legs of one assembly must fingerprint alike whether or not a
|
|
256
|
-
* classifier was down.
|
|
241
|
+
* spec shape reads it here instead. The classifier's availability is a per-CALL fact (an unavailable
|
|
242
|
+
* round is a deny that says so, and the next round is classified afresh), so there is no session-level
|
|
243
|
+
* breaker face here and nothing about availability enters {@link configFingerprint}.
|
|
257
244
|
*/
|
|
258
245
|
autoMode?: {
|
|
259
246
|
armed: boolean;
|
|
260
247
|
reason: AutoModeArmReason;
|
|
261
|
-
breaker?: import("./auto-mode.js").AutoModeBreakerTrip;
|
|
262
248
|
};
|
|
263
249
|
/**
|
|
264
250
|
* EFFECTIVE half only, and ALWAYS present on an engine-minted effective manifest (the `autoMode`
|
|
@@ -347,13 +333,10 @@ export interface WiringFacts {
|
|
|
347
333
|
restore: string;
|
|
348
334
|
};
|
|
349
335
|
/** Effective half only — see {@link WiringManifest.autoMode}; the static half has no leg to arm.
|
|
350
|
-
* `armed` must agree with `reason` (`armed ⇔ reason === "armed"`); a contradicting pair is refused.
|
|
351
|
-
* `breaker` (#616) is the session's most recent recorded trip, or absent; a trip whose cause is outside
|
|
352
|
-
* the closed set or whose numbers are not finite is refused. */
|
|
336
|
+
* `armed` must agree with `reason` (`armed ⇔ reason === "armed"`); a contradicting pair is refused. */
|
|
353
337
|
autoMode?: {
|
|
354
338
|
armed: boolean;
|
|
355
339
|
reason: AutoModeArmReason;
|
|
356
|
-
breaker?: import("./auto-mode.js").AutoModeBreakerTrip;
|
|
357
340
|
};
|
|
358
341
|
/** Effective half only — see {@link WiringManifest.mcp}; the static half materializes nothing.
|
|
359
342
|
* Copied entry-wise onto the manifest (the caller's array is never aliased). */
|
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
import { createHash } from "node:crypto";
|
|
2
|
-
import { AUTO_MODE_BREAKER_CAUSES, isAutoModeBreakerCause } from "./auto-mode.js";
|
|
3
2
|
import { canonicalize } from "./canonical-json.js";
|
|
4
3
|
import { resolveCheckpointStore } from "./checkpoint-store.js";
|
|
5
4
|
import { isLiveQuestionFace } from "./ask-question.js";
|
|
6
|
-
export const AUTO_MODE_ARM_REASONS = ["armed", "no_intent", "no_face", "denied", "resolver_fault"
|
|
5
|
+
export const AUTO_MODE_ARM_REASONS = ["armed", "no_intent", "no_face", "denied", "resolver_fault"];
|
|
7
6
|
export function resolveDeclaredDurability(store, storeName) {
|
|
8
7
|
const declared = store?.durability;
|
|
9
8
|
if (declared === undefined)
|
|
@@ -72,13 +71,7 @@ function readAutoModeFact(fact) {
|
|
|
72
71
|
if (!AUTO_MODE_ARM_REASONS.includes(fact.reason) || fact.armed !== (fact.reason === "armed")) {
|
|
73
72
|
throw new Error(`the auto-mode wiring fact is inconsistent (armed=${String(fact.armed)}, reason=${JSON.stringify(fact.reason)}) — armed must hold exactly when reason is "armed", and reason must be one of ${AUTO_MODE_ARM_REASONS.join("|")}`);
|
|
74
73
|
}
|
|
75
|
-
|
|
76
|
-
if (b === undefined)
|
|
77
|
-
return { armed: fact.armed, reason: fact.reason };
|
|
78
|
-
if (!isAutoModeBreakerCause(b.lastCause) || !Number.isFinite(b.openedAtMs) || !Number.isInteger(b.failures) || b.failures < 1 || typeof b.runId !== "string" || b.runId === "") {
|
|
79
|
-
throw new Error(`the auto-mode breaker fact is malformed (${JSON.stringify(b)}) — lastCause must be one of ${AUTO_MODE_BREAKER_CAUSES.join("|")}, openedAtMs finite, failures a positive integer, runId a non-empty string`);
|
|
80
|
-
}
|
|
81
|
-
return { armed: fact.armed, reason: fact.reason, breaker: { openedAtMs: b.openedAtMs, lastCause: b.lastCause, failures: b.failures, runId: b.runId } };
|
|
74
|
+
return { armed: fact.armed, reason: fact.reason };
|
|
82
75
|
}
|
|
83
76
|
export function deriveWiringManifest(facts) {
|
|
84
77
|
if (facts.half === "static" && facts.leg !== undefined) {
|
|
@@ -140,9 +133,8 @@ export function deriveWiringManifest(facts) {
|
|
|
140
133
|
const { leg: _leg, mcp: _mcp, tools: _tools, ...assembly } = manifest;
|
|
141
134
|
const { provenance: _askSeat, ...askForHash } = assembly.ask;
|
|
142
135
|
const { provenance: _questionSeat, ...questionForHash } = assembly.question;
|
|
143
|
-
const { breaker: _breaker, ...autoModeForHash } = assembly.autoMode ?? {};
|
|
144
136
|
manifest.configFingerprint = createHash("sha256")
|
|
145
|
-
.update(canonicalize({ ...assembly, ask: askForHash, question: questionForHash
|
|
137
|
+
.update(canonicalize({ ...assembly, ask: askForHash, question: questionForHash }))
|
|
146
138
|
.digest("hex")
|
|
147
139
|
.slice(0, 16);
|
|
148
140
|
}
|
|
@@ -162,11 +162,42 @@ export declare function callKeyOrdinal(callKey: string): number;
|
|
|
162
162
|
* say WHY an ordinal never replays. `failed` + this code lands on the T2A-4 no-replay arm, so replay
|
|
163
163
|
* behavior is identical to the entry simply being absent (the pre-tombstone shape). */
|
|
164
164
|
export declare const JOURNAL_OVERSIZE_ERROR_CODE = "workflow.journal_oversize";
|
|
165
|
+
/**
|
|
166
|
+
* The refusal every {@link WorkflowJournalStore.append} answers an oversize entry with (#672): a stable
|
|
167
|
+
* `code` ({@link JOURNAL_OVERSIZE_ERROR_CODE} — the same word the engine's result-arm tombstone carries, so
|
|
168
|
+
* one code means "too big for the journal" on every face) and a message a person can act on (the bytes, the
|
|
169
|
+
* cap, the entry's callKey). A backend outside this package throws THIS class from its own `append` — the
|
|
170
|
+
* contract kit asserts the code only, so the class is the convenience, the code is the contract.
|
|
171
|
+
*/
|
|
172
|
+
export declare class WorkflowJournalOversizeError extends Error {
|
|
173
|
+
readonly callKey: string;
|
|
174
|
+
readonly bytes: number;
|
|
175
|
+
readonly cap: number;
|
|
176
|
+
readonly code = "workflow.journal_oversize";
|
|
177
|
+
constructor(callKey: string, bytes: number, cap?: number);
|
|
178
|
+
}
|
|
179
|
+
/**
|
|
180
|
+
* @contract workflow.journal_oversize.refused — every {@link WorkflowJournalStore.append} REFUSES an entry whose
|
|
181
|
+
* payload (the `parked` arm when present, else the `result` arm) serializes to more than
|
|
182
|
+
* {@link MAX_JOURNAL_RESULT_BYTES} UTF-8 bytes: it throws {@link WorkflowJournalOversizeError} and journals
|
|
183
|
+
* nothing, on BOTH arms alike — no backend degrades an oversize entry to a silent skip, and no backend
|
|
184
|
+
* judges the size by a rule of its own. A backend calls this first, before it touches its medium.
|
|
185
|
+
*
|
|
186
|
+
* Why a refusal and not the earlier skip (RB-168 "every backend degrades identically"): the skip was written
|
|
187
|
+
* for the `result` arm, where the engine measures the SAME serialization first and journals a small
|
|
188
|
+
* tombstone (RB-243) — a completed result never reaches this refusal. The `parked` arm (#642) is the child's
|
|
189
|
+
* whole paused TaskResult, which can exceed the cap; a park the journal dropped silently is a resume that
|
|
190
|
+
* runs the ordinal live beside the pinned child, and the write is the one moment the deployment can be told.
|
|
191
|
+
* A bad value answered with a default is the failure mode this repository refuses by default; the loud
|
|
192
|
+
* answer is the rule, the engine's tombstone the one place that pre-empts it.
|
|
193
|
+
*/
|
|
194
|
+
export declare function assertJournalEntryFits(entry: WorkflowJournalEntry): void;
|
|
165
195
|
/** RB-243: mint the tiny FAILED entry the ENGINE journals in place of an oversize result. The
|
|
166
|
-
* tombstone is minted in the engine, NOT in a store —
|
|
167
|
-
*
|
|
168
|
-
*
|
|
169
|
-
* taskId/sessionId/stats so the journal read-face still shows the session handle
|
|
196
|
+
* tombstone is minted in the engine, NOT in a store — a store REFUSES an oversize entry
|
|
197
|
+
* ({@link assertJournalEntryFits}) and never invents one; the engine measures the durable copy first, so
|
|
198
|
+
* the store sees the tombstone, not the payload. Never copies `result.result`/`structuredOutput` (the
|
|
199
|
+
* oversize payload); keeps taskId/sessionId/stats so the journal read-face still shows the session handle
|
|
200
|
+
* and the paid spend. Its own serialization is a few hundred bytes — always under the cap (pinned). */
|
|
170
201
|
export declare function journalOversizeTombstone(result: TaskResult, bytes: number): TaskResult;
|
|
171
202
|
/**
|
|
172
203
|
* RB-367 (dual-process probe, core-side judgment) — the TTL a resume claim {@link
|
|
@@ -9,6 +9,24 @@ export function callKeyOrdinal(callKey) {
|
|
|
9
9
|
return Number.isFinite(n) ? n : 0;
|
|
10
10
|
}
|
|
11
11
|
export const JOURNAL_OVERSIZE_ERROR_CODE = "workflow.journal_oversize";
|
|
12
|
+
export class WorkflowJournalOversizeError extends Error {
|
|
13
|
+
callKey;
|
|
14
|
+
bytes;
|
|
15
|
+
cap;
|
|
16
|
+
code = JOURNAL_OVERSIZE_ERROR_CODE;
|
|
17
|
+
constructor(callKey, bytes, cap = MAX_JOURNAL_RESULT_BYTES) {
|
|
18
|
+
super(`workflow journal: entry "${callKey}" is ${bytes} bytes, over the ${cap}-byte per-entry cap — refused, nothing journaled`);
|
|
19
|
+
this.callKey = callKey;
|
|
20
|
+
this.bytes = bytes;
|
|
21
|
+
this.cap = cap;
|
|
22
|
+
this.name = "WorkflowJournalOversizeError";
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
export function assertJournalEntryFits(entry) {
|
|
26
|
+
const serialized = JSON.stringify(entry.parked !== undefined ? entry.parked : entry.result);
|
|
27
|
+
if (oversizeJournalResult(serialized))
|
|
28
|
+
throw new WorkflowJournalOversizeError(entry.callKey, Buffer.byteLength(serialized, "utf8"));
|
|
29
|
+
}
|
|
12
30
|
export function journalOversizeTombstone(result, bytes) {
|
|
13
31
|
const message = `[journal] result omitted: ${bytes} bytes exceeds the ${MAX_JOURNAL_RESULT_BYTES}-byte per-entry journal cap; ` +
|
|
14
32
|
`the agent's real terminal status was "${terminalProjection(result.terminal).status}". A resume re-runs this agent (and everything after it) live.`;
|
|
@@ -65,8 +83,7 @@ export class InMemoryWorkflowJournalStore {
|
|
|
65
83
|
return [...rec.byOrdinal.entries()].sort((a, b) => a[0] - b[0]).map(([, e]) => snapshot(e));
|
|
66
84
|
}
|
|
67
85
|
async append(runId, scope, entry) {
|
|
68
|
-
|
|
69
|
-
return;
|
|
86
|
+
assertJournalEntryFits(entry);
|
|
70
87
|
let rec = this.runs.get(runId);
|
|
71
88
|
if (!rec) {
|
|
72
89
|
rec = { scope, byOrdinal: new Map() };
|
package/dist/index.d.ts
CHANGED
|
@@ -168,7 +168,7 @@ export { type AskOrigin, ASK_ORIGINS, isAskOrigin, classifierMayAnswer, ORIGIN_I
|
|
|
168
168
|
export { SETTLEMENT_KINDS, type SettlementKind, isSettlementKind, type Settlement, SETTLEMENT_IS_REFUSAL, DENIED_BY_VALUES, type DeniedBy, isDeniedBy, DENIED_BY_MAY_VETO, type GateDisposition, type GateOutcome, screenGateOutcome } from "./core/gate-outcome.js";
|
|
169
169
|
export { type AskCarry } from "./core/hooks.js";
|
|
170
170
|
export { SWAPPABLE_DEP_SEATS, SWAP_SEAT_NOTICE, isSwappableDepSeat, screenSwappableDeps, type SwappableDepSeat, type SwappableDeps } from "./core/swappable-deps.js";
|
|
171
|
-
export { parseAutoModeResponse, createAutoModeDecider, AUTO_MODE_UNAVAILABLE_CAUSES, isAutoModeUnavailableCause,
|
|
171
|
+
export { parseAutoModeResponse, createAutoModeDecider, AUTO_MODE_UNAVAILABLE_CAUSES, isAutoModeUnavailableCause, classifierUnavailableDenyMessage, CLASSIFIER_PARSE_FAILURE_DENY_MESSAGE, type AutoModeUnavailableCause, type AutoModeVerdict, type AutoModeDecider, type AutoModeDeciderOptions, type AutoModeClassified, type AutoModeClassifyFn, type AutoModeClassifyInput, createAutoModeDenialTracker, denialLimitFallbackMessage, denialLimitSentence, unarmedWindow, type AutoModeDenialTracker, type AutoModeDenialLimitOptions, type DenialLimitCounts, type DenialLimitFallbackFace, type UnarmedDenialLimitFallback, type DenialLimitFallback, type DenialLimitVerdict, } from "./core/auto-mode.js";
|
|
172
172
|
export { AUTO_MODE_DENIAL_LIMIT_DEFAULTS, AUTO_MODE_DENIAL_AUTO_DENY_DEFAULT_MS, AUTO_MODE_CLASSIFIER_MAX_TOKENS } from "./core/auto-mode-defaults.js";
|
|
173
173
|
export { buildAutoModePrompt, renderAutoModeWindow, renderAutoModeAction, AUTO_MODE_DEFAULTS_SENTINEL, type AutoModeRules, type BuildAutoModePromptOptions, type AutoModeWindowOptions, } from "./core/auto-mode-prompt.js";
|
|
174
174
|
export { AUTO_MODE_BASE_PROMPT, AUTO_MODE_PERMISSIONS_EXTERNAL } from "./core/auto-mode-prompt-assets.js";
|
|
@@ -259,6 +259,7 @@ export { checkpointStoreContract } from "./core/store-contracts/checkpoint-store
|
|
|
259
259
|
export { sessionRepoContract } from "./core/store-contracts/session-repo-contract.js";
|
|
260
260
|
export { toolResultStoreContract } from "./core/store-contracts/tool-result-store-contract.js";
|
|
261
261
|
export { fileHistoryStoreContract } from "./core/store-contracts/file-history-store-contract.js";
|
|
262
|
+
export { workflowJournalStoreContract } from "./core/store-contracts/workflow-journal-store-contract.js";
|
|
262
263
|
export { permissionRuleSyncContract, type PermissionRuleSyncContractHooks } from "./core/store-contracts/permission-rule-sync-contract.js";
|
|
263
264
|
export { MAILBOX_CONTRACT_SCOPE, mailboxStoreContract, mailboxAckOwnershipContract, mailboxBundledOnlyContract, mailboxTombstonedRecipientContract, type MailboxTombstonedRecipientContractHooks, mailboxCrossProcessContract, type MailboxCrossProcessContractHooks, } from "./core/store-contracts/mailbox-store-contract.js";
|
|
264
265
|
export { BACKGROUND_AGENT_CONTRACT_SCOPE, backgroundAgentStoreContract, backgroundAgentStoreScopesContract, } from "./core/store-contracts/background-agent-store-contract.js";
|
|
@@ -267,7 +268,7 @@ export { serveDurableAgentRowLane, buildAgentPollDetails, type AgentPollDetailsI
|
|
|
267
268
|
export type { UnifiedTaskResult } from "./core/task-registry-shared.js";
|
|
268
269
|
export { FileBackgroundAgentStore, type FileBackgroundAgentStoreOptions } from "./stores/file/background-agent-store.js";
|
|
269
270
|
export { A2A_TASK_STATES, type A2ATaskState, type A2ATaskStateReversal, type A2ATaskStateReversalFaithful, type A2ATaskStateReversalLossy, toA2ATaskState, fromA2ATaskState, } from "./core/a2a-task-state.js";
|
|
270
|
-
export { type WorkflowJournalStore, type WorkflowJournalEntry, InMemoryWorkflowJournalStore, callKeyOrdinal, JOURNAL_OVERSIZE_ERROR_CODE, } from "./core/workflow-journal-store.js";
|
|
271
|
+
export { type WorkflowJournalStore, type WorkflowJournalEntry, InMemoryWorkflowJournalStore, callKeyOrdinal, JOURNAL_OVERSIZE_ERROR_CODE, WorkflowJournalOversizeError, assertJournalEntryFits, } from "./core/workflow-journal-store.js";
|
|
271
272
|
export { untrustedEgressForHuman, redactHostLeaks, redactSecrets, boundedRedactedSummary } from "./core/untrusted-egress.js";
|
|
272
273
|
export type { RedactionFinding, RedactionReport, RedactionConfidence, RedactionSource, SummarizableFinding, } from "./core/untrusted-egress.js";
|
|
273
274
|
export { summarizeRedactions } from "./core/untrusted-egress.js";
|
package/dist/index.js
CHANGED
|
@@ -142,7 +142,7 @@ export { ASK_ORIGINS, isAskOrigin, classifierMayAnswer, ORIGIN_IMPLIES_REAL_APPR
|
|
|
142
142
|
export { SETTLEMENT_KINDS, isSettlementKind, SETTLEMENT_IS_REFUSAL, DENIED_BY_VALUES, isDeniedBy, DENIED_BY_MAY_VETO, screenGateOutcome } from "./core/gate-outcome.js";
|
|
143
143
|
export {} from "./core/hooks.js";
|
|
144
144
|
export { SWAPPABLE_DEP_SEATS, SWAP_SEAT_NOTICE, isSwappableDepSeat, screenSwappableDeps } from "./core/swappable-deps.js";
|
|
145
|
-
export { parseAutoModeResponse, createAutoModeDecider, AUTO_MODE_UNAVAILABLE_CAUSES, isAutoModeUnavailableCause,
|
|
145
|
+
export { parseAutoModeResponse, createAutoModeDecider, AUTO_MODE_UNAVAILABLE_CAUSES, isAutoModeUnavailableCause, classifierUnavailableDenyMessage, CLASSIFIER_PARSE_FAILURE_DENY_MESSAGE, createAutoModeDenialTracker, denialLimitFallbackMessage, denialLimitSentence, unarmedWindow, } from "./core/auto-mode.js";
|
|
146
146
|
export { AUTO_MODE_DENIAL_LIMIT_DEFAULTS, AUTO_MODE_DENIAL_AUTO_DENY_DEFAULT_MS, AUTO_MODE_CLASSIFIER_MAX_TOKENS } from "./core/auto-mode-defaults.js";
|
|
147
147
|
export { buildAutoModePrompt, renderAutoModeWindow, renderAutoModeAction, AUTO_MODE_DEFAULTS_SENTINEL, } from "./core/auto-mode-prompt.js";
|
|
148
148
|
export { AUTO_MODE_BASE_PROMPT, AUTO_MODE_PERMISSIONS_EXTERNAL } from "./core/auto-mode-prompt-assets.js";
|
|
@@ -217,6 +217,7 @@ export { checkpointStoreContract } from "./core/store-contracts/checkpoint-store
|
|
|
217
217
|
export { sessionRepoContract } from "./core/store-contracts/session-repo-contract.js";
|
|
218
218
|
export { toolResultStoreContract } from "./core/store-contracts/tool-result-store-contract.js";
|
|
219
219
|
export { fileHistoryStoreContract } from "./core/store-contracts/file-history-store-contract.js";
|
|
220
|
+
export { workflowJournalStoreContract } from "./core/store-contracts/workflow-journal-store-contract.js";
|
|
220
221
|
export { permissionRuleSyncContract } from "./core/store-contracts/permission-rule-sync-contract.js";
|
|
221
222
|
export { MAILBOX_CONTRACT_SCOPE, mailboxStoreContract, mailboxAckOwnershipContract, mailboxBundledOnlyContract, mailboxTombstonedRecipientContract, mailboxCrossProcessContract, } from "./core/store-contracts/mailbox-store-contract.js";
|
|
222
223
|
export { BACKGROUND_AGENT_CONTRACT_SCOPE, backgroundAgentStoreContract, backgroundAgentStoreScopesContract, } from "./core/store-contracts/background-agent-store-contract.js";
|
|
@@ -224,7 +225,7 @@ export { canAccessAgentRecord, STALE_RUNNING_REAP_ATTRIBUTION, BackgroundAgentSt
|
|
|
224
225
|
export { serveDurableAgentRowLane, buildAgentPollDetails, } from "./core/task-registry-agent.js";
|
|
225
226
|
export { FileBackgroundAgentStore } from "./stores/file/background-agent-store.js";
|
|
226
227
|
export { A2A_TASK_STATES, toA2ATaskState, fromA2ATaskState, } from "./core/a2a-task-state.js";
|
|
227
|
-
export { InMemoryWorkflowJournalStore, callKeyOrdinal, JOURNAL_OVERSIZE_ERROR_CODE, } from "./core/workflow-journal-store.js";
|
|
228
|
+
export { InMemoryWorkflowJournalStore, callKeyOrdinal, JOURNAL_OVERSIZE_ERROR_CODE, WorkflowJournalOversizeError, assertJournalEntryFits, } from "./core/workflow-journal-store.js";
|
|
228
229
|
export { untrustedEgressForHuman, redactHostLeaks, redactSecrets, boundedRedactedSummary } from "./core/untrusted-egress.js";
|
|
229
230
|
export { summarizeRedactions } from "./core/untrusted-egress.js";
|
|
230
231
|
export { MemoryRosterStore, FileRosterStore } from "./agents/roster-store.js";
|
|
@@ -923,6 +923,8 @@ export function startWorkflow(runner, fn, opts = {}, internals) {
|
|
|
923
923
|
}
|
|
924
924
|
catch (err) {
|
|
925
925
|
lastErr = err;
|
|
926
|
+
if (err?.code === JOURNAL_OVERSIZE_ERROR_CODE)
|
|
927
|
+
break;
|
|
926
928
|
if (attempt < 2)
|
|
927
929
|
await new Promise((r) => timers.setTimeout(r, 25 * (attempt + 1)));
|
|
928
930
|
}
|