@sema-agent/core 1.293.0 → 1.294.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/dist/agents/subagent.d.ts.map +1 -1
- package/dist/agents/subagent.js +1 -0
- package/dist/agents/subagent.js.map +1 -1
- package/dist/core/checkpoint-store.d.ts +14 -2
- package/dist/core/checkpoint-store.d.ts.map +1 -1
- package/dist/core/checkpoint-store.js.map +1 -1
- package/dist/core/fs-write-gate-policy.d.ts +1 -0
- package/dist/core/fs-write-gate-policy.d.ts.map +1 -1
- package/dist/core/fs-write-gate-policy.js +16 -0
- package/dist/core/fs-write-gate-policy.js.map +1 -1
- package/dist/core/hooks.d.ts.map +1 -1
- package/dist/core/hooks.js.map +1 -1
- package/dist/core/runner/prepare-task.d.ts +17 -1
- package/dist/core/runner/prepare-task.d.ts.map +1 -1
- package/dist/core/runner/prepare-task.js +261 -6
- package/dist/core/runner/prepare-task.js.map +1 -1
- package/dist/core/runner/runtask.d.ts +2 -0
- package/dist/core/runner/runtask.d.ts.map +1 -1
- package/dist/core/runner/runtask.js +59 -5
- package/dist/core/runner/runtask.js.map +1 -1
- package/dist/core/types.d.ts +1 -0
- package/dist/core/types.d.ts.map +1 -1
- package/dist/orchestration/run-workflow-tool.d.ts +1 -0
- package/dist/orchestration/run-workflow-tool.d.ts.map +1 -1
- package/dist/orchestration/run-workflow-tool.js +3 -0
- package/dist/orchestration/run-workflow-tool.js.map +1 -1
- package/dist/orchestration/workflow.d.ts +1 -0
- package/dist/orchestration/workflow.d.ts.map +1 -1
- package/dist/orchestration/workflow.js +1 -0
- package/dist/orchestration/workflow.js.map +1 -1
- package/package.json +1 -1
|
@@ -213,6 +213,8 @@ export class Runner {
|
|
|
213
213
|
sessionLocks = new Map();
|
|
214
214
|
snapshotTooLargeRoots = new Map();
|
|
215
215
|
pendingSessionNotifications = new PendingSessionNotifications();
|
|
216
|
+
parentConstraintRegistry = new Map();
|
|
217
|
+
static PARENT_CONSTRAINT_REGISTRY_CAP = 1024;
|
|
216
218
|
constructor(deps) {
|
|
217
219
|
this.deps = deps.memoryStore
|
|
218
220
|
? { ...deps, memoryStore: guardedMemoryStore(deps.memoryStore, deps.utilityGate) }
|
|
@@ -347,6 +349,18 @@ export class Runner {
|
|
|
347
349
|
try {
|
|
348
350
|
await this.runLocked(spec, queue, (r) => {
|
|
349
351
|
resultValue = r;
|
|
352
|
+
const pcs = internals?.inheritedGate?.parentConstraints;
|
|
353
|
+
if (resume !== undefined && r.checkpointToken !== resume.cp.token) {
|
|
354
|
+
this.parentConstraintRegistry.delete(resume.cp.token);
|
|
355
|
+
}
|
|
356
|
+
if (r.status === "suspended" && r.checkpointToken !== undefined && pcs !== undefined && pcs.length > 0) {
|
|
357
|
+
if (this.parentConstraintRegistry.size >= Runner.PARENT_CONSTRAINT_REGISTRY_CAP) {
|
|
358
|
+
const oldest = this.parentConstraintRegistry.keys().next().value;
|
|
359
|
+
if (oldest !== undefined)
|
|
360
|
+
this.parentConstraintRegistry.delete(oldest);
|
|
361
|
+
}
|
|
362
|
+
this.parentConstraintRegistry.set(r.checkpointToken, pcs);
|
|
363
|
+
}
|
|
350
364
|
}, (p) => {
|
|
351
365
|
consolidationDone = p;
|
|
352
366
|
}, (p) => {
|
|
@@ -365,7 +379,7 @@ export class Runner {
|
|
|
365
379
|
}
|
|
366
380
|
})();
|
|
367
381
|
const settled = run.catch(async (err) => {
|
|
368
|
-
|
|
382
|
+
let code = errorCodeOf(err);
|
|
369
383
|
const reopenReason = code === "resume.env_failed"
|
|
370
384
|
? "env_failed"
|
|
371
385
|
: code === "resume.tool_unavailable"
|
|
@@ -376,10 +390,20 @@ export class Runner {
|
|
|
376
390
|
try {
|
|
377
391
|
await resume.onEnvRestoreFailed(reopenReason);
|
|
378
392
|
}
|
|
379
|
-
catch {
|
|
393
|
+
catch (reopenErr) {
|
|
394
|
+
this.parentConstraintRegistry.delete(resume.cp.token);
|
|
395
|
+
if (errorCodeOf(reopenErr) === "checkpoint.reopen_failed") {
|
|
396
|
+
const original = err instanceof Error ? err : new Error(String(err));
|
|
397
|
+
const reopenMsg = reopenErr instanceof Error ? reopenErr.message : String(reopenErr);
|
|
398
|
+
err = Object.assign(new Error(`${reopenMsg} (original resume failure: ${original.message})`, { cause: original }), {
|
|
399
|
+
code: "checkpoint.reopen_failed",
|
|
400
|
+
});
|
|
401
|
+
code = "checkpoint.reopen_failed";
|
|
402
|
+
}
|
|
380
403
|
}
|
|
381
404
|
}
|
|
382
|
-
else if (resume
|
|
405
|
+
else if (resume) {
|
|
406
|
+
this.parentConstraintRegistry.delete(resume.cp.token);
|
|
383
407
|
try {
|
|
384
408
|
await this.sessions.unpin?.(resume.cp.sessionId);
|
|
385
409
|
}
|
|
@@ -445,6 +469,7 @@ export class Runner {
|
|
|
445
469
|
}
|
|
446
470
|
if (!won)
|
|
447
471
|
return;
|
|
472
|
+
this.parentConstraintRegistry.delete(rh.token);
|
|
448
473
|
if (rh.env && hasDestroy(rh.env)) {
|
|
449
474
|
try {
|
|
450
475
|
await rh.env.destroy();
|
|
@@ -2663,6 +2688,15 @@ export class Runner {
|
|
|
2663
2688
|
if (!cp) {
|
|
2664
2689
|
throw new CheckpointError("checkpoint.not_found", "no checkpoint found for the supplied token");
|
|
2665
2690
|
}
|
|
2691
|
+
if ((internals?.inheritedGate?.parentConstraints?.length ?? 0) === 0) {
|
|
2692
|
+
const parked = this.parentConstraintRegistry.get(token);
|
|
2693
|
+
if (parked !== undefined) {
|
|
2694
|
+
internals = {
|
|
2695
|
+
...(internals ?? {}),
|
|
2696
|
+
inheritedGate: { ...(internals?.inheritedGate ?? {}), parentConstraints: parked },
|
|
2697
|
+
};
|
|
2698
|
+
}
|
|
2699
|
+
}
|
|
2666
2700
|
let wakeMessage;
|
|
2667
2701
|
if (outcome.gate === "wake") {
|
|
2668
2702
|
const gk = cp.gate.kind;
|
|
@@ -2756,12 +2790,28 @@ export class Runner {
|
|
|
2756
2790
|
if (cp.state.workspaceHandle !== undefined && this.deps.executionEnvFactory === undefined) {
|
|
2757
2791
|
throw new CheckpointError("checkpoint.unsupported_version", "checkpoint has a remote workspaceHandle but no RunnerDeps.executionEnvFactory is wired to rebuild the env");
|
|
2758
2792
|
}
|
|
2793
|
+
if (cp.state.inheritedGate?.requiresParentConstraint === true) {
|
|
2794
|
+
const supplied = internals?.inheritedGate?.parentConstraints?.length ?? 0;
|
|
2795
|
+
if (supplied === 0) {
|
|
2796
|
+
throw new CheckpointError("resume.parent_constraint_missing", "this checkpoint's task ran under inherited parent-policy constraints (state.inheritedGate.requiresParentConstraint) " +
|
|
2797
|
+
"— the live policy/onAsk closures cannot be persisted, so the resume must re-supply them via " +
|
|
2798
|
+
"resumeStream(token, outcome, taskConfig, internals) with internals.inheritedGate.parentConstraints; " +
|
|
2799
|
+
"rejected pre-CAS (the checkpoint stays pending) rather than silently dropping the ancestors' gate");
|
|
2800
|
+
}
|
|
2801
|
+
const expected = cp.state.inheritedGate.parentConstraintCount;
|
|
2802
|
+
if (expected !== undefined && supplied !== expected) {
|
|
2803
|
+
throw new CheckpointError("resume.parent_constraint_mismatch", `re-supplied ${supplied} parent constraint(s) but the checkpoint recorded ${expected} — a partial/mismatched ` +
|
|
2804
|
+
"re-supply would run the resumed leg under a different ancestor chain than it suspended with; " +
|
|
2805
|
+
"rejected pre-CAS (the checkpoint stays pending) — re-resume with the full original chain");
|
|
2806
|
+
}
|
|
2807
|
+
}
|
|
2759
2808
|
const won = await store.resolve(token, cp.scope, outcome, { rev: cp.rev ?? 0 });
|
|
2760
2809
|
if (!won) {
|
|
2761
2810
|
const live = await store.get(token);
|
|
2762
2811
|
if (live?.status === "pending") {
|
|
2763
2812
|
throw new CheckpointError("checkpoint.reopened_concurrently", "checkpoint changed concurrently (its revision advanced via a resolve/reopen cycle since this resume validated) — not executed; re-resume against the current state");
|
|
2764
2813
|
}
|
|
2814
|
+
this.parentConstraintRegistry.delete(token);
|
|
2765
2815
|
throw new CheckpointError("checkpoint.already_resolved", "checkpoint already resolved or expired — not re-executed (idempotent)");
|
|
2766
2816
|
}
|
|
2767
2817
|
const spec = {
|
|
@@ -2770,9 +2820,13 @@ export class Runner {
|
|
|
2770
2820
|
sessionId: cp.sessionId,
|
|
2771
2821
|
preemptSignal: taskConfig.preemptSignal?.aborted ? undefined : taskConfig.preemptSignal,
|
|
2772
2822
|
};
|
|
2773
|
-
const
|
|
2823
|
+
const reopenFn = store.reopen?.bind(store);
|
|
2824
|
+
const onEnvRestoreFailed = reopenFn
|
|
2774
2825
|
? async (reason) => {
|
|
2775
|
-
await
|
|
2826
|
+
const reopened = await reopenFn(token, cp.scope, reason);
|
|
2827
|
+
if (!reopened) {
|
|
2828
|
+
throw new CheckpointError("checkpoint.reopen_failed", "checkpoint could not be reopened for a retry (missing, expired, or changed concurrently) — the resume failure is terminal");
|
|
2829
|
+
}
|
|
2776
2830
|
}
|
|
2777
2831
|
: undefined;
|
|
2778
2832
|
return this.runTaskStream(spec, { cp, outcome, onEnvRestoreFailed, ...(wakeMessage !== undefined ? { wakeMessage } : {}) }, internals);
|