@sema-agent/core 7.43.0 → 7.44.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 +73 -0
- package/dist/agents/subagent.d.ts +2 -1
- package/dist/brain/errors.d.ts +23 -2
- package/dist/brain/errors.js +26 -2
- package/dist/brain/stream-engine.d.ts +2 -1
- package/dist/brain/stream-engine.js +10 -9
- package/dist/core/checkpoint-store.d.ts +26 -13
- package/dist/core/checkpoint-store.js +4 -13
- package/dist/core/engine-notice.d.ts +16 -14
- package/dist/core/engine-notice.js +4 -3
- package/dist/core/governance-codes.d.ts +4 -3
- package/dist/core/governance-codes.js +1 -0
- package/dist/core/memory-engine/engine.d.ts +2 -2
- package/dist/core/memory-engine/engine.js +7 -14
- package/dist/core/memory-engine/file-backend.d.ts +2 -2
- package/dist/core/memory-engine/file-backend.js +5 -7
- package/dist/core/memory-engine/layout.d.ts +37 -4
- package/dist/core/memory-engine/layout.js +34 -5
- package/dist/core/runner/contracts.d.ts +1 -16
- package/dist/core/runner/runtask.js +1 -5
- package/dist/core/runner/steer-admission.d.ts +10 -11
- package/dist/core/runner/steer-admission.js +6 -8
- package/dist/core/runner/stream-steer-verb.d.ts +5 -4
- package/dist/core/runner/stream-steer-verb.js +6 -8
- package/dist/core/steer-replay.d.ts +46 -0
- package/dist/core/steer-replay.js +22 -0
- package/dist/core/task-event.d.ts +3 -2
- package/dist/core/task-stream.d.ts +12 -6
- package/dist/core/tool-errors.d.ts +2 -2
- package/dist/core/types.d.ts +2 -2
- package/dist/core/types.js +1 -1
- package/dist/index.d.ts +3 -2
- package/dist/index.js +3 -2
- package/dist/orchestration/workflow-types.d.ts +5 -0
- package/dist/orchestration/workflow.d.ts +3 -2
- package/dist/orchestration/workflow.js +14 -6
- package/package.json +1 -1
- package/test/export-surface.snapshot.json +11 -5
- package/wire-changes/core@7.44.0.json +469 -0
|
@@ -18,7 +18,7 @@ import { landedUndecided, layerDigest, layerObservationLookup, readOnlyLayerCand
|
|
|
18
18
|
import { markOriginClearanceTombstoned, openOriginClearance, readOriginClearances, settleOriginClearance } from "./origin-clearance.js";
|
|
19
19
|
import { DEFAULT_MAX_ENTRY_DEPTH, MEMORY_INDEX_FILENAME, canonicalJsonStringify, captureErasureInput, erasureRequestInvalid, erasureSelectHash, scanEntryFiles, } from "./file-backend.js";
|
|
20
20
|
import { assembleMemoryExportBundle, computeMemoryBundleHash, memoryBundleInvalid, } from "./export-bundle.js";
|
|
21
|
-
import { QUARANTINE_DIR, SCAN_FUSE_THRESHOLD, quarantineAndTombstone, restoreContainedBaseline, indexLineIsStale, readIndexRevs, writeIndexRevs, bumpScanFuse, scanFuseKey, canonicalize, landingPathOf,
|
|
21
|
+
import { QUARANTINE_DIR, SCAN_FUSE_THRESHOLD, quarantineAndTombstone, restoreContainedBaseline, indexLineIsStale, readIndexRevs, writeIndexRevs, bumpScanFuse, scanFuseKey, canonicalize, landingPathOf, landsOutsideStore, storeActRefusal, storeRootMovedRefusal, adoptRootScopeLayout, clearScanFuse, adoptCanonicalKeyedControlDir, deriveControlPlaneDir, drainMemoryAnnouncements, enqueueMemoryAnnouncement, ensureDirExists, markSessionPolluted, readSessionPollution, fileSessionCaptureRecordStore, recordRetrievedAccount, writeFileNoFollow, withPermissionRemedy, permissionRemedyOf, readRetrievedAccount, registerScope, registeredScopes, resolveMemoryEngineRoot, scopeDirFor, appendChallengeEvents, appendLineageAudit, rebuildStrictControlPlaneLedger, isStrictControlPlaneLedgerCorrupt, CHALLENGE_LEDGER_MAX_EVENTS, adjudicateLineagePending, challengedEntryIds, clearLineageForEntries, discardLineagePending, lineageAccountOfEntry, lineageContributionsOfSession, lineageLatchedIds, promoteLineagePending, readChallengeEvents, readChallengedHistory, readLineageRecord, recordChallengedHistory, recordLineageCredential, reconcileLineage, readProjectionDebts, resolveChallengeEvent, settleProjectionDebts, stageLineagePending, stageProjectionDebts, } from "./layout.js";
|
|
22
22
|
import { createSessionIncarnationSeat, recalledForAnyIdentity, recalledForIdentity, rememberForIdentity } from "./session-incarnation.js";
|
|
23
23
|
import { scanMemoryFileName, scanMemoryWrite, scanRemediation } from "./scan.js";
|
|
24
24
|
import { writableRootOf } from "./types.js";
|
|
@@ -1416,11 +1416,8 @@ export class MemoryEngine {
|
|
|
1416
1416
|
ensureDirExists(this.memoryDir);
|
|
1417
1417
|
const physicalRoot = landingPathOf(this.memoryDir);
|
|
1418
1418
|
this.mountedRoot ??= physicalRoot;
|
|
1419
|
-
if (physicalRoot !== this.mountedRoot)
|
|
1420
|
-
|
|
1421
|
-
e.code = TARGET_OUTSIDE_STORE;
|
|
1422
|
-
throw e;
|
|
1423
|
-
}
|
|
1419
|
+
if (physicalRoot !== this.mountedRoot)
|
|
1420
|
+
throw storeRootMovedRefusal("engine", this.memoryDir);
|
|
1424
1421
|
ensureDirExists(this.controlDir);
|
|
1425
1422
|
await this.adoptLayoutBeforeMount(writeScope);
|
|
1426
1423
|
const restricted = opts?.adoptionRestricted === true;
|
|
@@ -2216,7 +2213,7 @@ export class MemoryEngine {
|
|
|
2216
2213
|
if (content === undefined)
|
|
2217
2214
|
continue;
|
|
2218
2215
|
try {
|
|
2219
|
-
this.refuseOutsideStore(handle.memoryDir, m.path, "restoring");
|
|
2216
|
+
this.refuseOutsideStore(handle.memoryDir, m.path, "restoring a memory file");
|
|
2220
2217
|
mkdirSync(dirname(m.path), { recursive: true });
|
|
2221
2218
|
writeFileNoFollow(m.path, content);
|
|
2222
2219
|
report.restored.push(m.relPath);
|
|
@@ -4947,15 +4944,11 @@ export class MemoryEngine {
|
|
|
4947
4944
|
};
|
|
4948
4945
|
}
|
|
4949
4946
|
refuseOutsideStore(root, path, act) {
|
|
4950
|
-
|
|
4951
|
-
|
|
4952
|
-
return;
|
|
4953
|
-
const e = new Error(`${TARGET_OUTSIDE_STORE}: ${act} ${path} was refused — ${escape}; not performed`);
|
|
4954
|
-
e.code = TARGET_OUTSIDE_STORE;
|
|
4955
|
-
throw e;
|
|
4947
|
+
if (landsOutsideStore(root, path))
|
|
4948
|
+
throw storeActRefusal(act, path);
|
|
4956
4949
|
}
|
|
4957
4950
|
writeIfChanged(target, text, root) {
|
|
4958
|
-
this.refuseOutsideStore(root, target, "the projection write
|
|
4951
|
+
this.refuseOutsideStore(root, target, "the projection write");
|
|
4959
4952
|
const current = readNoFollowSafe(target);
|
|
4960
4953
|
if (current === text)
|
|
4961
4954
|
return;
|
|
@@ -682,9 +682,9 @@ export declare class FileMemoryEngineBackend implements MemoryBackend {
|
|
|
682
682
|
* let a transient EIO run the unlocked recovery (and its staged sweep) over a live transaction. */
|
|
683
683
|
private txnInFlight;
|
|
684
684
|
/**
|
|
685
|
-
* The act gate for store paths ({@link
|
|
685
|
+
* The act gate for store paths ({@link landsOutsideStore}) over `ops`' writes and deletes — shadow
|
|
686
686
|
* ops name control-plane files, not store paths. Refuses with `memory.target_outside_store` at the
|
|
687
|
-
* first op that would land outside the store, naming the op
|
|
687
|
+
* first op that would land outside the store, naming the op (its path on `detail.path`). Runs over a
|
|
688
688
|
* whole batch before its commit marker (no journal is written; a caller that staged files removes
|
|
689
689
|
* them) and per op at the act itself; past the marker a refusal keeps the journal, which replays
|
|
690
690
|
* once the path resolves inside the store again.
|
|
@@ -8,7 +8,7 @@ import { ambiguousOriginRepresentation, committedDistilledOf, committedOriginOf,
|
|
|
8
8
|
import { convertV1SidecarKeys } from "./delegation-settlement.js";
|
|
9
9
|
import { layerObservationLookup, observedDivergenceNotice } from "./layer-observations.js";
|
|
10
10
|
import { DEFAULT_MAX_ENTRY_DEPTH, MEMORY_INDEX_FILENAME, scanEntryFiles } from "./entry-scan.js";
|
|
11
|
-
import { ControlPlaneCorruptError, CURSORS_FILE, QUARANTINE_DIR, CHALLENGES_FILE, IMPORT_RECEIPTS_DIR, LINEAGE_FILE, SESSION_POLLUTION_DIR, appendChallengeEvents, atomicWriteFileSync, quarantineAndTombstone, captureAndClearLineageForEntries, adoptRootScopeLayout, adoptCanonicalKeyedControlDir, deriveControlPlaneDir, ensureDirExists, enqueueMemoryAnnouncement, importLatchTxnId, importLineageCommitted, importSessionPollution, isContainedIn, permissionRemedyOf, withPermissionRemedy, lineageContributionsOfSession, listSessionPollution, readChallengeEvents, readLineageRecord, registerScope, registeredScopes, releaseImportLatch, layoutNeedsAdoption, resolveMemoryEngineRoot, scopeDirFor, scopeDirName, scopeRegistryShape, stageImportLatch, landingPathOf,
|
|
11
|
+
import { ControlPlaneCorruptError, CURSORS_FILE, QUARANTINE_DIR, CHALLENGES_FILE, IMPORT_RECEIPTS_DIR, LINEAGE_FILE, SESSION_POLLUTION_DIR, appendChallengeEvents, atomicWriteFileSync, quarantineAndTombstone, captureAndClearLineageForEntries, adoptRootScopeLayout, adoptCanonicalKeyedControlDir, deriveControlPlaneDir, ensureDirExists, enqueueMemoryAnnouncement, importLatchTxnId, importLineageCommitted, importSessionPollution, isContainedIn, permissionRemedyOf, withPermissionRemedy, lineageContributionsOfSession, listSessionPollution, readChallengeEvents, readLineageRecord, registerScope, registeredScopes, releaseImportLatch, layoutNeedsAdoption, resolveMemoryEngineRoot, scopeDirFor, scopeDirName, scopeRegistryShape, stageImportLatch, landingPathOf, landsOutsideStore, storeActRefusal, storeRootMovedRefusal, writeAllSync, } from "./layout.js";
|
|
12
12
|
import { screenInboundEntries } from "./data-plane.js";
|
|
13
13
|
import { scanMemoryFileName, scanMemoryWrite } from "./scan.js";
|
|
14
14
|
import { thrownText } from "../thrown-value.js";
|
|
@@ -1404,7 +1404,7 @@ export class FileMemoryEngineBackend {
|
|
|
1404
1404
|
}
|
|
1405
1405
|
}
|
|
1406
1406
|
this.assertTxnLockOwnership(fenceToken);
|
|
1407
|
-
const replayAt =
|
|
1407
|
+
const replayAt = "the journal replay (journal kept)";
|
|
1408
1408
|
this.refuseEscapingTargets(journal.ops, replayAt);
|
|
1409
1409
|
for (const op of journal.ops) {
|
|
1410
1410
|
this.refuseEscapingTargets([op], replayAt);
|
|
@@ -1470,10 +1470,8 @@ export class FileMemoryEngineBackend {
|
|
|
1470
1470
|
if (op.kind !== "write" && op.kind !== "delete")
|
|
1471
1471
|
continue;
|
|
1472
1472
|
for (const path of op.staged === undefined ? [op.target] : [op.target, op.staged]) {
|
|
1473
|
-
|
|
1474
|
-
|
|
1475
|
-
continue;
|
|
1476
|
-
throw erasureCodedError(`${TARGET_OUTSIDE_STORE}: ${at} refused a ${op.kind} of ${op.target}${path === op.target ? "" : ` (its staged file ${path})`} — ${escape}; not performed`, TARGET_OUTSIDE_STORE);
|
|
1473
|
+
if (landsOutsideStore(this.physicalRoot, path))
|
|
1474
|
+
throw storeActRefusal(`${path === op.target ? "a" : "the staged file of a"} ${op.kind} at ${at}`, path);
|
|
1477
1475
|
}
|
|
1478
1476
|
}
|
|
1479
1477
|
}
|
|
@@ -1481,7 +1479,7 @@ export class FileMemoryEngineBackend {
|
|
|
1481
1479
|
const now = landingPathOf(this.directoryRoot);
|
|
1482
1480
|
if (now === this.physicalRoot)
|
|
1483
1481
|
return;
|
|
1484
|
-
throw
|
|
1482
|
+
throw storeRootMovedRefusal("backend", this.directoryRoot);
|
|
1485
1483
|
}
|
|
1486
1484
|
sweepStagedFiles() {
|
|
1487
1485
|
const walk = (d, depth) => {
|
|
@@ -259,8 +259,41 @@ export declare function adoptRootScopeLayout(rootPath: string, controlDir: strin
|
|
|
259
259
|
export declare const canonicalize: typeof physicalPathOfExisting;
|
|
260
260
|
/** True iff `child` (canonicalized) is `root` or inside it. */
|
|
261
261
|
export declare function isContainedIn(root: string, child: string): boolean;
|
|
262
|
-
/** The code an act on a store path is refused with when it would land outside the store ({@link
|
|
262
|
+
/** The code an act on a store path is refused with when it would land outside the store ({@link landsOutsideStore}). */
|
|
263
263
|
export declare const TARGET_OUTSIDE_STORE = "memory.target_outside_store";
|
|
264
|
+
/** The code a scope home that is not a real directory is refused with ({@link assertHomePhysicalForm}). */
|
|
265
|
+
export declare const SCOPE_HOME_NOT_DIRECTORY = "memory.scope_home_not_directory";
|
|
266
|
+
/** What a scope home can be besides a real directory (an `lstat` verdict). */
|
|
267
|
+
export declare const SCOPE_HOME_FORMS: readonly ["symlink", "file", "other"];
|
|
268
|
+
export type ScopeHomeForm = (typeof SCOPE_HOME_FORMS)[number];
|
|
269
|
+
/** How a refusal's sentence names each form. */
|
|
270
|
+
declare const SCOPE_HOME_FORM_PHRASE: {
|
|
271
|
+
readonly symlink: "a symbolic link";
|
|
272
|
+
readonly file: "a regular file";
|
|
273
|
+
readonly other: "a special file";
|
|
274
|
+
};
|
|
275
|
+
export type HomeFormPhraseCoversEveryForm = AssertAllKeysHandled<Exclude<ScopeHomeForm, keyof typeof SCOPE_HOME_FORM_PHRASE>>;
|
|
276
|
+
/** What a store-form refusal carries beside its sentence. The ONE host path lives here and never in the
|
|
277
|
+
* sentence; `form` is present on {@link SCOPE_HOME_NOT_DIRECTORY} only. */
|
|
278
|
+
export type StoreFormRefusalDetail = {
|
|
279
|
+
readonly path: string;
|
|
280
|
+
readonly form?: ScopeHomeForm;
|
|
281
|
+
};
|
|
282
|
+
/** A refusal the store's physical form earns: a plain `Error` (never the control-plane-damage class —
|
|
283
|
+
* the engine's own account is intact, the layout it was handed is not the layout it needs) carrying a
|
|
284
|
+
* `code` and a `detail`. */
|
|
285
|
+
export type StoreFormRefusal = Error & {
|
|
286
|
+
code: typeof TARGET_OUTSIDE_STORE | typeof SCOPE_HOME_NOT_DIRECTORY;
|
|
287
|
+
detail: StoreFormRefusalDetail;
|
|
288
|
+
};
|
|
289
|
+
/** Seat 1 — an act the store's physical form refuses: `act` names what was refused (no path), `path` is the
|
|
290
|
+
* target whose directory resolves outside the store ({@link landsOutsideStore}). */
|
|
291
|
+
export declare function storeActRefusal(act: string, path: string): StoreFormRefusal;
|
|
292
|
+
/** Seat 2 — the store root now resolves to another directory than the one the `holder` first opened; `path` is
|
|
293
|
+
* the root's spelling. */
|
|
294
|
+
export declare function storeRootMovedRefusal(holder: "backend" | "engine", path: string): StoreFormRefusal;
|
|
295
|
+
/** Seat 3 — a scope home that is not a real directory. */
|
|
296
|
+
export declare function scopeHomeRefusal(form: ScopeHomeForm, path: string): StoreFormRefusal;
|
|
264
297
|
/** Where an act at `p` lands: the physical path of its normalized spelling (the spelling a child path
|
|
265
298
|
* joined under it carries), a MISSING tail rejoined under the deepest existing directory (what the act
|
|
266
299
|
* creates). Any other resolution fault (EACCES, ELOOP, ENOTDIR) is THROWN as itself: an act that
|
|
@@ -268,8 +301,8 @@ export declare const TARGET_OUTSIDE_STORE = "memory.target_outside_store";
|
|
|
268
301
|
* (a link whose own mode refuses `realpath` is still followed by `unlink` and `rename`). */
|
|
269
302
|
export declare function landingPathOf(p: string): string;
|
|
270
303
|
/**
|
|
271
|
-
*
|
|
272
|
-
* `physicalRoot
|
|
304
|
+
* Whether a write, rename or delete at `target` would physically LAND outside the store, judged against the
|
|
305
|
+
* store's `physicalRoot` (`true` = outside; the refusal is {@link storeActRefusal}). The target's directory, resolved through
|
|
273
306
|
* every link on its existing prefix (a missing tail is what the act creates, under the deepest existing
|
|
274
307
|
* directory), must be the root or inside it. `physicalRoot` is the root's physical form as the store
|
|
275
308
|
* was opened and is not re-resolved here: a store mounted through a link is judged by what the link
|
|
@@ -280,7 +313,7 @@ export declare function landingPathOf(p: string): string;
|
|
|
280
313
|
* keeps the spelling while the act follows the link out. A directory that cannot be resolved throws its
|
|
281
314
|
* fault ({@link landingPathOf}).
|
|
282
315
|
*/
|
|
283
|
-
export declare function
|
|
316
|
+
export declare function landsOutsideStore(physicalRoot: string, target: string): boolean;
|
|
284
317
|
/** mkdir -p convenience used by the engine/backend (0o700 like the file stores). */
|
|
285
318
|
export declare function ensureDirExists(dir: string): void;
|
|
286
319
|
/** The one remedy every surfaced permission refusal carries — `undefined` unless `err` is a write
|
|
@@ -472,11 +472,18 @@ function assertHomePhysicalForm(home) {
|
|
|
472
472
|
return "absent";
|
|
473
473
|
if (st.isDirectory())
|
|
474
474
|
return "dir";
|
|
475
|
-
throw
|
|
475
|
+
throw scopeHomeRefusal(st.isSymbolicLink() ? "symlink" : st.isFile() ? "file" : "other", home);
|
|
476
476
|
}
|
|
477
477
|
function ensureScopeHome(home) {
|
|
478
|
-
if (assertHomePhysicalForm(home) === "absent")
|
|
479
|
-
|
|
478
|
+
if (assertHomePhysicalForm(home) === "absent") {
|
|
479
|
+
try {
|
|
480
|
+
mkdirSync(home, { recursive: true });
|
|
481
|
+
}
|
|
482
|
+
catch (err) {
|
|
483
|
+
assertHomePhysicalForm(home);
|
|
484
|
+
throw err;
|
|
485
|
+
}
|
|
486
|
+
}
|
|
480
487
|
assertHomePhysicalForm(home);
|
|
481
488
|
}
|
|
482
489
|
export function registerScope(memoryDir, controlDir, scope, opts) {
|
|
@@ -725,6 +732,28 @@ export function isContainedIn(root, child) {
|
|
|
725
732
|
return c === r || c.startsWith(`${r}${sep}`);
|
|
726
733
|
}
|
|
727
734
|
export const TARGET_OUTSIDE_STORE = "memory.target_outside_store";
|
|
735
|
+
export const SCOPE_HOME_NOT_DIRECTORY = "memory.scope_home_not_directory";
|
|
736
|
+
export const SCOPE_HOME_FORMS = Object.freeze(["symlink", "file", "other"]);
|
|
737
|
+
const SCOPE_HOME_FORM_PHRASE = {
|
|
738
|
+
symlink: "a symbolic link",
|
|
739
|
+
file: "a regular file",
|
|
740
|
+
other: "a special file",
|
|
741
|
+
};
|
|
742
|
+
function storeFormRefusal(code, sentence, detail) {
|
|
743
|
+
const e = new Error(`${code}: ${sentence}`);
|
|
744
|
+
e.code = code;
|
|
745
|
+
e.detail = detail;
|
|
746
|
+
return e;
|
|
747
|
+
}
|
|
748
|
+
export function storeActRefusal(act, path) {
|
|
749
|
+
return storeFormRefusal(TARGET_OUTSIDE_STORE, `${act} was refused — its directory resolves outside the store root; not performed`, { path });
|
|
750
|
+
}
|
|
751
|
+
export function storeRootMovedRefusal(holder, path) {
|
|
752
|
+
return storeFormRefusal(TARGET_OUTSIDE_STORE, `the ${holder === "backend" ? "store root" : "memory dir"} now resolves to a different directory than the one this ${holder} ${holder === "backend" ? "opened" : "first mounted"} — refused; open a new ${holder} on the directory you mean`, { path });
|
|
753
|
+
}
|
|
754
|
+
export function scopeHomeRefusal(form, path) {
|
|
755
|
+
return storeFormRefusal(SCOPE_HOME_NOT_DIRECTORY, `a scope home must be a real directory, but this one is ${SCOPE_HOME_FORM_PHRASE[form]} — refused (fail-closed); put the real directory back`, { path, form });
|
|
756
|
+
}
|
|
728
757
|
export function landingPathOf(p) {
|
|
729
758
|
const normalized = resolve(p);
|
|
730
759
|
try {
|
|
@@ -736,9 +765,9 @@ export function landingPathOf(p) {
|
|
|
736
765
|
return canonicalize(normalized);
|
|
737
766
|
}
|
|
738
767
|
}
|
|
739
|
-
export function
|
|
768
|
+
export function landsOutsideStore(physicalRoot, target) {
|
|
740
769
|
const dir = landingPathOf(dirname(target));
|
|
741
|
-
return dir
|
|
770
|
+
return dir !== physicalRoot && !dir.startsWith(`${physicalRoot}${sep}`);
|
|
742
771
|
}
|
|
743
772
|
export function ensureDirExists(dir) {
|
|
744
773
|
if (!existsSync(dir))
|
|
@@ -33,7 +33,7 @@ import type { AutoModeArmingRecipe } from "../auto-mode-arming.js";
|
|
|
33
33
|
import type { AutoModeDecider, AutoModeDenialTracker, DenialLimitFallbackFace } from "../auto-mode.js";
|
|
34
34
|
import type { SettlementKind } from "../gate-outcome.js";
|
|
35
35
|
import type { CacheBreakDetector, ToolFingerprintInput } from "../cache-break-detector.js";
|
|
36
|
-
import type {
|
|
36
|
+
import type { Checkpoint, CheckpointState, CheckpointStore, CheckpointToken, PendingSteerEntry, PlatformLimitReason, ReopenReason, ResourceLedger, ResourceLimitReason, ResumeOutcome, SerializedCheckpointState } from "../checkpoint-store.js";
|
|
37
37
|
import type { ExecutionOutcomeRecordWord } from "../checkpoint-execution-record.js";
|
|
38
38
|
import type { ClearedProjectionLedger, MicroCompactMachine, OccurrenceIndex } from "../context-edit.js";
|
|
39
39
|
import type { HookInvocationIdentity, Hooks, OrgGateVerdict, PermissionDeniedPayload, PostToolBatchCall, PostToolBatchResult, ToolGateInput } from "../hooks.js";
|
|
@@ -2494,21 +2494,6 @@ export interface RunState {
|
|
|
2494
2494
|
attachmentsInjected: number;
|
|
2495
2495
|
};
|
|
2496
2496
|
}
|
|
2497
|
-
/** One accepted live steer's REPLAY identity, the twin of the parked
|
|
2498
|
-
* queue's `samePendingSteerPayload`. `payload` is the exact string handed to the harness, so the text,
|
|
2499
|
-
* the speaker envelope and the trust framing all fold into it; `trusted` is kept SEPARATELY from those
|
|
2500
|
-
* framed bytes so a text that spells its own `<system-reminder>` wrapper can never read as the trusted
|
|
2501
|
-
* arm's byte-equal twin. `actor` carries the attribution the ledger frame reports. */
|
|
2502
|
-
export interface AcceptedSteerInput {
|
|
2503
|
-
payload: string;
|
|
2504
|
-
trusted: boolean;
|
|
2505
|
-
/** The NORMALIZED priority the call delivered under (absent input ⇒ "next"),
|
|
2506
|
-
* the replay identity's sixth axis: same id + same text at a DIFFERENT tier is not a replay —
|
|
2507
|
-
* a `next` input re-sent as `now` answering "idempotent success" without the interrupt would be
|
|
2508
|
-
* a disposition lie, so it refuses `duplicate_input_id` like any other identity mismatch. */
|
|
2509
|
-
priority: SystemInjectionPriority;
|
|
2510
|
-
actor?: ActorAssertion;
|
|
2511
|
-
}
|
|
2512
2497
|
/**
|
|
2513
2498
|
* Config re-supplied to {@link Runner.resume}. A suspended task's tools / model / policy /
|
|
2514
2499
|
* hooks cannot be reconstructed from a checkpoint token (the session stores neither tool implementations
|
|
@@ -40,6 +40,7 @@ import { resumeClaim } from "./resume-claim.js";
|
|
|
40
40
|
import { streamSettleBackstop } from "./stream-settle-backstop.js";
|
|
41
41
|
import { streamReap } from "./stream-reap.js";
|
|
42
42
|
import { streamSteerVerb } from "./stream-steer-verb.js";
|
|
43
|
+
import { steeringError } from "./steer-admission.js";
|
|
43
44
|
import { streamLifecycleVerbs } from "./stream-lifecycle-verbs.js";
|
|
44
45
|
import { streamHaltVerbs } from "./stream-halt-verbs.js";
|
|
45
46
|
import { streamModeVerb } from "./stream-mode-verb.js";
|
|
@@ -411,11 +412,6 @@ export class Runner {
|
|
|
411
412
|
locallyClaimedTokens: this.locallyClaimedTokens, parentConstraintRegistry: this.parentConstraintRegistry, suspendedEnvReaps: this.suspendedEnvReaps,
|
|
412
413
|
}).onRunRejected);
|
|
413
414
|
void settled.then(() => acceptedSteerInputs.clear(), () => acceptedSteerInputs.clear());
|
|
414
|
-
const steeringError = (msg, code = "steering.not_running") => {
|
|
415
|
-
const e = new Error(`cannot steer: ${msg}`);
|
|
416
|
-
e.code = code;
|
|
417
|
-
return e;
|
|
418
|
-
};
|
|
419
415
|
const { reapSuspended } = streamReap({
|
|
420
416
|
live, runner: this.depsSeat,
|
|
421
417
|
locallyClaimedTokens: this.locallyClaimedTokens, parentConstraintRegistry: this.parentConstraintRegistry, suspendedEnvReaps: this.suspendedEnvReaps,
|
|
@@ -1,14 +1,15 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Admission bookkeeping for HUMAN INPUTS accepted mid-run: the per-leg ordinal an
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
2
|
+
* Admission bookkeeping for HUMAN INPUTS accepted mid-run: the per-leg ordinal an accepted input is stamped
|
|
3
|
+
* with, and the acceptance frame's once-only seat. Two accepting arms share the ordinal — the stream's `steer`
|
|
4
|
+
* verb and the run body — which is why it is keyed on the leg's harness in a module-level WeakMap rather than
|
|
5
|
+
* held by either arm: one counter per leg, one ascending sequence across both. Also the stream verbs' typed
|
|
6
|
+
* refusal. (Whether a repeat under a used `inputId` is the same instruction is steer-replay.ts's one judgement,
|
|
7
|
+
* shared with the parked queue.)
|
|
7
8
|
*
|
|
8
9
|
* Run-loop machinery (layer 1), not a driven lane: nothing here takes an Input or hands back a Result, and
|
|
9
10
|
* nothing here reads host state. Named without the `run-` family prefix for that reason.
|
|
10
11
|
*/
|
|
11
|
-
import type {
|
|
12
|
+
import type { SteerReplayRefusalDetail } from "../steer-replay.js";
|
|
12
13
|
export declare function nextHumanInputSeq(key: object): number;
|
|
13
14
|
/** The identity keys a published `queued` frame carried beyond its own `eventId` (`parentToolCallId`, `sourceTaskId`): one fact, stated
|
|
14
15
|
* once by the frame's publisher and handed to whoever mints that input's other frames, so two frames of one input are never stamped
|
|
@@ -19,8 +20,6 @@ export type AcceptanceIdentity = {
|
|
|
19
20
|
};
|
|
20
21
|
export declare function armAcceptance(record: object, publish: () => AcceptanceIdentity): void;
|
|
21
22
|
export declare function announceAcceptance(record: object): AcceptanceIdentity | undefined;
|
|
22
|
-
/**
|
|
23
|
-
*
|
|
24
|
-
|
|
25
|
-
* callers colliding on one id must not silently lose the second instruction. */
|
|
26
|
-
export declare function sameAcceptedSteerInput(a: AcceptedSteerInput, b: AcceptedSteerInput): boolean;
|
|
23
|
+
/** The stream verbs' typed refusal: `cannot steer: <msg>`, `code` (`steering.not_running` by default), and the
|
|
24
|
+
* refusal's `detail` when the code carries one (`steering.duplicate_input_id` always does). */
|
|
25
|
+
export declare function steeringError(msg: string, code?: string, detail?: SteerReplayRefusalDetail): Error;
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { steerPriorityOf } from "../task-notification.js";
|
|
2
1
|
const humanInputOrdinals = new WeakMap();
|
|
3
2
|
export function nextHumanInputSeq(key) {
|
|
4
3
|
let box = humanInputOrdinals.get(key);
|
|
@@ -16,11 +15,10 @@ export function armAcceptance(record, publish) {
|
|
|
16
15
|
export function announceAcceptance(record) {
|
|
17
16
|
return acceptanceSeats.get(record)?.();
|
|
18
17
|
}
|
|
19
|
-
export function
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
a.actor?.issuer === b.actor?.issuer);
|
|
18
|
+
export function steeringError(msg, code = "steering.not_running", detail) {
|
|
19
|
+
const e = new Error(`cannot steer: ${msg}`);
|
|
20
|
+
e.code = code;
|
|
21
|
+
if (detail !== undefined)
|
|
22
|
+
e.detail = detail;
|
|
23
|
+
return e;
|
|
26
24
|
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { PushQueue } from "../push-queue.js";
|
|
2
2
|
import { type TaskEvent, type TaskSpec, type TaskStream } from "../types.js";
|
|
3
|
-
import type {
|
|
3
|
+
import type { LiveHandle, RunInternals, RunnerDepsSeat, TaskStreamLiveSeat } from "./contracts.js";
|
|
4
|
+
import { type SteerReplayRecord, type SteerReplayRefusalDetail } from "../steer-replay.js";
|
|
4
5
|
export interface StreamSteerVerbInput {
|
|
5
6
|
/** borrowed-readonly — the task spec (the hooks seat, `principal`, `taskId`). */
|
|
6
7
|
spec: TaskSpec;
|
|
@@ -9,7 +10,7 @@ export interface StreamSteerVerbInput {
|
|
|
9
10
|
/** borrowed-mutable — the stream's event queue: the `human_input` receipt is pushed here on acceptance. */
|
|
10
11
|
queue: PushQueue<TaskEvent>;
|
|
11
12
|
/** borrowed-mutable — this stream's accepted-input dedup domain (the SAME Map the driver clears when the run settles). */
|
|
12
|
-
acceptedSteerInputs: Map<string,
|
|
13
|
+
acceptedSteerInputs: Map<string, SteerReplayRecord>;
|
|
13
14
|
/** borrowed-readonly — the stream's live state: `resultValue` and `handle`, read at each liveness test. */
|
|
14
15
|
live: TaskStreamLiveSeat;
|
|
15
16
|
/** borrowed-readonly — the readiness promise (settles to the live handle, or `undefined` when the run ended first). */
|
|
@@ -18,8 +19,8 @@ export interface StreamSteerVerbInput {
|
|
|
18
19
|
orTimeout: <T>(p: Promise<T>) => Promise<T | undefined>;
|
|
19
20
|
/** borrowed-readonly — the readiness bound in ms; the birth-window poll's deadline reads it too. */
|
|
20
21
|
readyTimeoutMs: number;
|
|
21
|
-
/** borrowed-readonly — the driver's typed steering refusal (`steering.not_running` by default). */
|
|
22
|
-
steeringError: (msg: string, code?: string) => Error;
|
|
22
|
+
/** borrowed-readonly — the driver's typed steering refusal (`steering.not_running` by default; `detail` rides the error). */
|
|
23
|
+
steeringError: (msg: string, code?: string, detail?: SteerReplayRefusalDetail) => Error;
|
|
23
24
|
/** borrowed-readonly — the Runner's deployment deps, read LIVE (`hooks`, `onError`, `onNotice`, after awaits too). */
|
|
24
25
|
runner: RunnerDepsSeat;
|
|
25
26
|
}
|
|
@@ -6,7 +6,8 @@ import { buildHumanInputEvent, frameMidTurnUserInput, projectHumanInput } from "
|
|
|
6
6
|
import { isSystemInjectionPriority, steerPriorityOf, SYSTEM_INJECTION_PRIORITIES } from "../task-notification.js";
|
|
7
7
|
import { deliverEngineNotice } from "../types.js";
|
|
8
8
|
import { inlineUntrusted, sanitizeUntrustedText } from "../untrusted-text.js";
|
|
9
|
-
import { announceAcceptance, armAcceptance, nextHumanInputSeq
|
|
9
|
+
import { announceAcceptance, armAcceptance, nextHumanInputSeq } from "./steer-admission.js";
|
|
10
|
+
import { steerReplayRefusal } from "../steer-replay.js";
|
|
10
11
|
import { asThrownError } from "../thrown-value.js";
|
|
11
12
|
export function streamSteerVerb(input) {
|
|
12
13
|
const { spec, internals, queue, acceptedSteerInputs, live, ready, orTimeout, readyTimeoutMs: READY_TIMEOUT_MS, steeringError, runner } = input;
|
|
@@ -43,7 +44,6 @@ export function streamSteerVerb(input) {
|
|
|
43
44
|
};
|
|
44
45
|
let payload;
|
|
45
46
|
let mintsAFrame;
|
|
46
|
-
let replay;
|
|
47
47
|
const publishQueued = (h) => {
|
|
48
48
|
const identity = internals?.parentToolCallId !== undefined ? { parentToolCallId: internals.parentToolCallId, ...(spec.taskId !== undefined ? { sourceTaskId: spec.taskId } : {}) } : {};
|
|
49
49
|
queue.push({
|
|
@@ -66,7 +66,7 @@ export function streamSteerVerb(input) {
|
|
|
66
66
|
if (!mintsAFrame)
|
|
67
67
|
return;
|
|
68
68
|
if (typeof inputId === "string")
|
|
69
|
-
acceptedSteerInputs.set(inputId,
|
|
69
|
+
acceptedSteerInputs.set(inputId, parkRecord);
|
|
70
70
|
announceAcceptance(parkRecord);
|
|
71
71
|
};
|
|
72
72
|
const deliver = async () => {
|
|
@@ -77,16 +77,14 @@ export function streamSteerVerb(input) {
|
|
|
77
77
|
throw steeringError("the task is not running");
|
|
78
78
|
payload = trusted ? formatHookFeedback(projected, h.reminderMark) : frameMidTurnUserInput(projected);
|
|
79
79
|
mintsAFrame = payload.trim().length !== 0;
|
|
80
|
-
replay = { payload, trusted, priority, ...(actor !== undefined ? { actor } : {}) };
|
|
81
80
|
if (typeof inputId === "string") {
|
|
82
81
|
const prior = acceptedSteerInputs.get(inputId);
|
|
83
82
|
if (prior !== undefined) {
|
|
84
83
|
if (live.resultValue !== undefined || h.loop.ended)
|
|
85
84
|
throw steeringError("the task is no longer running");
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
}
|
|
85
|
+
const refusal = steerReplayRefusal(prior, parkRecord, { seat: "accepted" });
|
|
86
|
+
if (refusal !== undefined)
|
|
87
|
+
throw steeringError(refusal.message, "steering.duplicate_input_id", refusal.detail);
|
|
90
88
|
return;
|
|
91
89
|
}
|
|
92
90
|
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Is a repeat under an already-used steer `inputId` the same instruction? ONE answer for both seats that hold a
|
|
3
|
+
* steer under its key — the parked queue (`appendPendingSteer`) and the live verb's accepted-input domain — and that
|
|
4
|
+
* one answer feeds the replay decision, the refusal's machine-readable `detail.differs` and its sentence.
|
|
5
|
+
*
|
|
6
|
+
* Both seats compare the record the CALLER sent (text, trusted, tier, actor) — never the delivered bytes: the live
|
|
7
|
+
* delivery folds `trusted` (the framing) and the actor (the speaker label) into its payload, so comparing payloads
|
|
8
|
+
* would report one changed facet as two.
|
|
9
|
+
*/
|
|
10
|
+
import type { ActorAssertion } from "../internal/llm.js";
|
|
11
|
+
import { type SystemInjectionPriority } from "./task-notification.js";
|
|
12
|
+
/** The facets a steer's replay identity is made of, in the order a refusal lists them. Closed. */
|
|
13
|
+
export declare const STEER_REPLAY_FACETS: readonly ["text", "trusted", "priority", "actor"];
|
|
14
|
+
export type SteerReplayFacet = (typeof STEER_REPLAY_FACETS)[number];
|
|
15
|
+
/** What a seat remembers a steer by: the caller's own statement, as validated. The parked entry and the live park
|
|
16
|
+
* record both are this shape. An absent `priority` reads as `"next"` ({@link steerPriorityOf}). */
|
|
17
|
+
export interface SteerReplayRecord {
|
|
18
|
+
readonly text: string;
|
|
19
|
+
readonly trusted: boolean;
|
|
20
|
+
readonly priority?: SystemInjectionPriority;
|
|
21
|
+
readonly actor?: ActorAssertion;
|
|
22
|
+
}
|
|
23
|
+
/** The facets `repeat` differs from `held` in, in {@link STEER_REPLAY_FACETS} order. Empty = the idempotent replay. */
|
|
24
|
+
export declare function steerReplayDiffers(held: SteerReplayRecord, repeat: SteerReplayRecord): SteerReplayFacet[];
|
|
25
|
+
/** `steering.duplicate_input_id`'s machine-readable half: the facets, by name only (never the values). Always
|
|
26
|
+
* present on that code, never empty. */
|
|
27
|
+
export interface SteerReplayRefusalDetail {
|
|
28
|
+
readonly differs: readonly SteerReplayFacet[];
|
|
29
|
+
}
|
|
30
|
+
/** Which seat refuses: the parked queue names the key it holds; the live verb answers about the caller's own key. */
|
|
31
|
+
export type SteerReplaySeat = {
|
|
32
|
+
readonly seat: "parked";
|
|
33
|
+
readonly inputId: string;
|
|
34
|
+
} | {
|
|
35
|
+
readonly seat: "accepted";
|
|
36
|
+
};
|
|
37
|
+
/**
|
|
38
|
+
* The refusal for a repeat that is not a replay, or `undefined` for one that is. When `text` differs the repeat is
|
|
39
|
+
* another instruction and the caller is told to take a fresh key. When only the tier / trust / attribution differ it
|
|
40
|
+
* is the SAME instruction, already accepted, whose standing receipt those facets do not change — a fresh key would
|
|
41
|
+
* queue it a second time, so the sentence says so instead of advising one.
|
|
42
|
+
*/
|
|
43
|
+
export declare function steerReplayRefusal(held: SteerReplayRecord, repeat: SteerReplayRecord, where: SteerReplaySeat): {
|
|
44
|
+
message: string;
|
|
45
|
+
detail: SteerReplayRefusalDetail;
|
|
46
|
+
} | undefined;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { steerPriorityOf } from "./task-notification.js";
|
|
2
|
+
export const STEER_REPLAY_FACETS = Object.freeze(["text", "trusted", "priority", "actor"]);
|
|
3
|
+
const FACET_IS_SAME = {
|
|
4
|
+
text: (a, b) => a.text === b.text,
|
|
5
|
+
trusted: (a, b) => a.trusted === b.trusted,
|
|
6
|
+
priority: (a, b) => steerPriorityOf(a) === steerPriorityOf(b),
|
|
7
|
+
actor: (a, b) => a.actor?.id === b.actor?.id && a.actor?.hostAsserted === b.actor?.hostAsserted && a.actor?.issuer === b.actor?.issuer,
|
|
8
|
+
};
|
|
9
|
+
export function steerReplayDiffers(held, repeat) {
|
|
10
|
+
return STEER_REPLAY_FACETS.filter((facet) => !FACET_IS_SAME[facet](held, repeat));
|
|
11
|
+
}
|
|
12
|
+
export function steerReplayRefusal(held, repeat, where) {
|
|
13
|
+
const differs = steerReplayDiffers(held, repeat);
|
|
14
|
+
if (differs.length === 0)
|
|
15
|
+
return undefined;
|
|
16
|
+
const seat = where.seat === "parked" ? `parked under inputId "${where.inputId}"` : "accepted under this inputId";
|
|
17
|
+
const listed = differs.join(", ");
|
|
18
|
+
const message = differs.includes("text")
|
|
19
|
+
? `a different steering instruction is already ${seat} (this repeat differs in: ${listed}) — re-issue this one with a fresh inputId (an identical payload would have been an idempotent retry)`
|
|
20
|
+
: `the same steering instruction is already ${seat}; this repeat differs only in: ${listed}, which cannot change after acceptance — sending it again under another inputId would queue it a second time; to confirm the standing receipt, replay it with its original values`;
|
|
21
|
+
return { message, detail: { differs } };
|
|
22
|
+
}
|
|
@@ -94,8 +94,9 @@ export type BrainStatusPhase = "rate_limited" | "retrying" | "reconnecting" | "c
|
|
|
94
94
|
* {@link BrainStatus.errorStatus}; this bucket is the reason a consumer RENDERS and the only carrier for the
|
|
95
95
|
* transport classes, which have no status at all.) Values are about the SHAPE of the failure, never its
|
|
96
96
|
* provider taxonomy:
|
|
97
|
-
* - `connect_refused` — the attempt got a definite negative about the target
|
|
98
|
-
* at that address,
|
|
97
|
+
* - `connect_refused` — the attempt got a definite negative about the way to the target (nothing accepts
|
|
98
|
+
* at that address, the name has no address, or the proxy on the way refused the tunnel). This is the class
|
|
99
|
+
* the SHORT retry lane serves.
|
|
99
100
|
* - `transport` — any other transport-level failure: a connect timeout, a reset, a mid-stream
|
|
100
101
|
* tear. No verdict about the target; the full ladder applies.
|
|
101
102
|
* - `stall` — no failure was observed on the link at all: THIS process cancelled its own
|
|
@@ -43,15 +43,20 @@ export interface TaskStream extends AsyncIterable<TaskEvent> {
|
|
|
43
43
|
* that arrives while the task is LIVE was the only one that injected twice.
|
|
44
44
|
* - **Absent ⇒ nothing changes**: a uuidv7 is minted for the event, nothing is recorded for the call,
|
|
45
45
|
* and the delivered bytes are what they always were. Every pre-existing caller is on this arm.
|
|
46
|
-
* - **Replay ⇒ idempotent no-op**: re-steering an id this stream already ACCEPTED, with
|
|
47
|
-
*
|
|
46
|
+
* - **Replay ⇒ idempotent no-op**: re-steering an id this stream already ACCEPTED, with the same
|
|
47
|
+
* steer (same text, `trusted`, tier — absent reads `next` — and `actor`), injects nothing and emits no second
|
|
48
48
|
* `human_input` frame. What is remembered is exactly what QUEUED: a delivery that was refused
|
|
49
49
|
* (not running) can be retried under its own id, and a call whose DELIVERED payload is
|
|
50
50
|
* whitespace-only — which the harness discards without minting a frame; note a `trusted` steer is
|
|
51
51
|
* wrapped first, so it queues even for blank text — reserves nothing, leaving that id usable.
|
|
52
|
-
* - **Same id,
|
|
52
|
+
* - **Same id, not the same steer ⇒ typed throw** `steering.duplicate_input_id`: a key is not
|
|
53
53
|
* evidence of a replay, and two callers colliding on one id must not silently lose the second
|
|
54
|
-
* (the parked leg's `appendPendingSteer` refuses it identically).
|
|
54
|
+
* (the parked leg's `appendPendingSteer` judges and refuses it identically). The error carries
|
|
55
|
+
* `detail.differs` — the facets that differ (closed `STEER_REPLAY_FACETS`: `text`, `trusted`,
|
|
56
|
+
* `priority`, `actor`), compared on what the caller SENT, never on the framed bytes. With `text`
|
|
57
|
+
* among them it is another instruction: re-issue it under a fresh id. Without, it is the accepted one
|
|
58
|
+
* re-sent at another tier / trust / attribution, which acceptance does not change: a fresh id would
|
|
59
|
+
* queue it twice, so replay it with its original values to confirm the receipt.
|
|
55
60
|
* - **Bad value ⇒ typed throw** `steering.invalid_content`, never a silent fallback to "no id": the
|
|
56
61
|
* value domain is the parked leg's (a non-empty string of at most `MAX_STEER_INPUT_ID_CHARS`
|
|
57
62
|
* characters), so one key is accepted or
|
|
@@ -107,8 +112,9 @@ export interface TaskStream extends AsyncIterable<TaskEvent> {
|
|
|
107
112
|
* relaying steer must gate this option at its own face — relay IS authorization.
|
|
108
113
|
* An unknown value throws typed `steering.invalid_content` (bad-value loudness). The replay
|
|
109
114
|
* identity (`inputId` idempotency) includes the NORMALIZED tier: the same text replayed under
|
|
110
|
-
* the same id at a different tier refuses `steering.duplicate_input_id`
|
|
111
|
-
* success" that silently skipped the interrupt would be a
|
|
115
|
+
* the same id at a different tier refuses `steering.duplicate_input_id` (`detail.differs:
|
|
116
|
+
* ["priority"]`) — an "idempotent success" that silently skipped the interrupt would be a
|
|
117
|
+
* disposition lie.
|
|
112
118
|
*
|
|
113
119
|
* design/373 §4.3 (D2, ruling of 2026-08-24) — a deployment `userPromptSubmit` hook SCREENS this verb:
|
|
114
120
|
* the steer face is a SERVICE entrance (third-party callers reach a running run through it), so
|
|
@@ -123,8 +123,8 @@ export type WorkerErrorClass = "budget" | "limit" | "output" | "suspend" | "revi
|
|
|
123
123
|
* The `limits.` namespace splits into the `budget` and `limit` classes by exact code — see
|
|
124
124
|
* {@link EXACT_CODE_CLASS}. Operation-level dotted codes that are surfaced to a *caller* and never become a
|
|
125
125
|
* task outcome are deliberately OUT of scope: `steering.*` (`steering.not_running`/`steering.invalid_content`/
|
|
126
|
-
* `steering.duplicate_input_id`/`steering.blocked_by_hook`, rejected to the `steer()` caller — the
|
|
127
|
-
* rides the resume face as
|
|
126
|
+
* `steering.duplicate_input_id`/`steering.blocked_by_hook`, rejected to the `steer()` caller — the third also
|
|
127
|
+
* rides the parked queue's `setPendingSteer` face and the fourth the resume face, as `CheckpointError` codes) and `mcp.*` (`mcp.server_unavailable`, an `onWarn` warning code) — neither
|
|
128
128
|
* reaches `TaskResult.errorCode`, so a caller will never pass them here. A genuinely unmapped code → `"unknown"` (which therefore means
|
|
129
129
|
* "known-but-foreign or no code", e.g. a leaked fs/Node code, NOT "an OUR terminal class we forgot to add").
|
|
130
130
|
*/
|
package/dist/core/types.d.ts
CHANGED
|
@@ -29,6 +29,6 @@ export { AUTO_MODE_DENY_SOURCES, isAutoModeDenySource } from "./runtime-caps.js"
|
|
|
29
29
|
export type { BackgroundChildEvent, DelegationLifecycleEvent } from "./delegation-frames.js";
|
|
30
30
|
export { __resetMalformedDelegationSeatAnnouncement, deliverDelegationLifecycle } from "./delegation-frames.js";
|
|
31
31
|
export type { ProjectMemoryLoad, ResumePreflightInfo, ResumePreflightVerdict, RunnerDeps } from "./runner-deps.js";
|
|
32
|
-
export type { EngineNotice, OwedUserInputAccount,
|
|
33
|
-
export { __resetMalformedNoticeSeatAnnouncement, deliverEngineNotice, owedUserInputCounts, parentLegIds, settleOwedUserInput, undrainedUserInputNotices,
|
|
32
|
+
export type { EngineNotice, OwedUserInputAccount, UserInputUndrainedCause } from "./engine-notice.js";
|
|
33
|
+
export { __resetMalformedNoticeSeatAnnouncement, deliverEngineNotice, owedUserInputCounts, parentLegIds, settleOwedUserInput, undrainedUserInputNotices, USER_INPUT_UNDRAINED_CAUSES } from "./engine-notice.js";
|
|
34
34
|
export type { AgentTool, Model, StreamFn, ThinkingLevel, ToolInputValidationContext, ToolInputVerdict };
|
package/dist/core/types.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
export { MODEL_ROLES } from "./model-seat.js";
|
|
2
2
|
export { AUTO_MODE_DENY_SOURCES, isAutoModeDenySource } from "./runtime-caps.js";
|
|
3
3
|
export { __resetMalformedDelegationSeatAnnouncement, deliverDelegationLifecycle } from "./delegation-frames.js";
|
|
4
|
-
export { __resetMalformedNoticeSeatAnnouncement, deliverEngineNotice, owedUserInputCounts, parentLegIds, settleOwedUserInput, undrainedUserInputNotices,
|
|
4
|
+
export { __resetMalformedNoticeSeatAnnouncement, deliverEngineNotice, owedUserInputCounts, parentLegIds, settleOwedUserInput, undrainedUserInputNotices, USER_INPUT_UNDRAINED_CAUSES } from "./engine-notice.js";
|
package/dist/index.d.ts
CHANGED
|
@@ -42,7 +42,7 @@ export { StdioLspTransport, type LspChildProcess } from "./engine/lsp/stdio-lsp-
|
|
|
42
42
|
export { encodeFrame, createFrameDecoder } from "./engine/lsp/frame-decoder.js";
|
|
43
43
|
export { resolveModel, resolveTaskModel, parseModelMention, expandTiers, DEFAULT_TIER_ORDER, CC_MODEL_TIER_ALIASES, ROLE_TIER_DEFAULTS, MODEL_ROLES, type ModelRole, type RoleSpec, type ModelRoles, type ResolvedRole, type ModelMention, } from "./core/roles.js";
|
|
44
44
|
export { selectModel, selectModelOrThrow, type ModelCriteria, type ModelTier } from "./core/select-model.js";
|
|
45
|
-
export { BrainError, classifyHttp, isProviderEchoShape, PROVIDER_ECHO_SHAPE, type BrainErrorCode } from "./brain/errors.js";
|
|
45
|
+
export { BrainError, classifyHttp, isProviderEchoShape, PROVIDER_ECHO_SHAPE, PROXY_TUNNEL_REFUSED, type BrainErrorCode } from "./brain/errors.js";
|
|
46
46
|
export { looksDegenerate, inspectDegenerate, trimDegenerateTail } from "./brain/repetition.js";
|
|
47
47
|
export type { RepetitionEvent, RepetitionInspection } from "./brain/repetition.js";
|
|
48
48
|
export { computeCostMicroUsd, isModelPriced, modelCostToPricing, type ModelPricing, type TokenCounts, } from "./core/pricing.js";
|
|
@@ -63,7 +63,8 @@ export { MCP_FAILURE_KINDS, MCP_DELIVERY_VERDICTS, MCP_LIVENESS_STATES, classify
|
|
|
63
63
|
export { MCP_INJECTION_DROP_REASONS, MCP_INJECTION_DROP_TEXT, mcpInjectionDroppedNotice, type McpInjectionDropReason, type McpInjectionDropFacts } from "./core/mcp-injection-drop.js";
|
|
64
64
|
export { askUnresolvableNotice, type AskUnresolvableFacts } from "./core/ask-unresolvable-notice.js";
|
|
65
65
|
export { ASK_UNRESOLVABLE_CAUSES } from "./core/ask-unresolvable-notice.js";
|
|
66
|
-
export {
|
|
66
|
+
export { USER_INPUT_UNDRAINED_CAUSES, type UserInputUndrainedCause } from "./core/engine-notice.js";
|
|
67
|
+
export { STEER_REPLAY_FACETS, type SteerReplayFacet } from "./core/steer-replay.js";
|
|
67
68
|
export { TOOL_TURN_INCOMPLETE_CAUSES, type ToolTurnIncompleteCause } from "./internal/llm.js";
|
|
68
69
|
export { DURABLE_MANDATE_SOURCES } from "./core/tool-policy.js";
|
|
69
70
|
export { TERMINAL_CAUSE_IS_REPLAYABLE, type TerminalFailureDetail, type TerminalBlockedDetail, PROMPT_BLOCK_CAUSES, type PromptBlockCause, isPromptBlockCause } from "./core/terminal-cause.js";
|