@sema-agent/core 1.292.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.
Files changed (72) hide show
  1. package/dist/agents/subagent.d.ts.map +1 -1
  2. package/dist/agents/subagent.js +1 -0
  3. package/dist/agents/subagent.js.map +1 -1
  4. package/dist/agents/verify.d.ts +1 -0
  5. package/dist/agents/verify.d.ts.map +1 -1
  6. package/dist/agents/verify.js +1 -1
  7. package/dist/agents/verify.js.map +1 -1
  8. package/dist/core/auto-compaction.d.ts +2 -0
  9. package/dist/core/auto-compaction.d.ts.map +1 -1
  10. package/dist/core/auto-compaction.js +32 -5
  11. package/dist/core/auto-compaction.js.map +1 -1
  12. package/dist/core/checkpoint-store.d.ts +14 -2
  13. package/dist/core/checkpoint-store.d.ts.map +1 -1
  14. package/dist/core/checkpoint-store.js.map +1 -1
  15. package/dist/core/fs-write-gate-policy.d.ts +1 -0
  16. package/dist/core/fs-write-gate-policy.d.ts.map +1 -1
  17. package/dist/core/fs-write-gate-policy.js +16 -0
  18. package/dist/core/fs-write-gate-policy.js.map +1 -1
  19. package/dist/core/hooks.d.ts.map +1 -1
  20. package/dist/core/hooks.js.map +1 -1
  21. package/dist/core/runner/prepare-task.d.ts +17 -1
  22. package/dist/core/runner/prepare-task.d.ts.map +1 -1
  23. package/dist/core/runner/prepare-task.js +269 -8
  24. package/dist/core/runner/prepare-task.js.map +1 -1
  25. package/dist/core/runner/runtask.d.ts +3 -1
  26. package/dist/core/runner/runtask.d.ts.map +1 -1
  27. package/dist/core/runner/runtask.js +120 -20
  28. package/dist/core/runner/runtask.js.map +1 -1
  29. package/dist/core/runner/synthetic-tools.d.ts +7 -1
  30. package/dist/core/runner/synthetic-tools.d.ts.map +1 -1
  31. package/dist/core/runner/synthetic-tools.js +62 -6
  32. package/dist/core/runner/synthetic-tools.js.map +1 -1
  33. package/dist/core/trace.d.ts +1 -1
  34. package/dist/core/trace.d.ts.map +1 -1
  35. package/dist/core/trace.js.map +1 -1
  36. package/dist/core/types.d.ts +6 -0
  37. package/dist/core/types.d.ts.map +1 -1
  38. package/dist/engine/compaction/compaction.d.ts +4 -2
  39. package/dist/engine/compaction/compaction.d.ts.map +1 -1
  40. package/dist/engine/compaction/compaction.js +21 -6
  41. package/dist/engine/compaction/compaction.js.map +1 -1
  42. package/dist/engine/compaction/utils.d.ts +13 -0
  43. package/dist/engine/compaction/utils.d.ts.map +1 -1
  44. package/dist/engine/compaction/utils.js +126 -0
  45. package/dist/engine/compaction/utils.js.map +1 -1
  46. package/dist/engine/harness/agent-harness.d.ts.map +1 -1
  47. package/dist/engine/harness/agent-harness.js +5 -1
  48. package/dist/engine/harness/agent-harness.js.map +1 -1
  49. package/dist/engine/harness/types.d.ts +5 -1
  50. package/dist/engine/harness/types.d.ts.map +1 -1
  51. package/dist/engine/harness/types.js.map +1 -1
  52. package/dist/engine/session/session.d.ts +3 -2
  53. package/dist/engine/session/session.d.ts.map +1 -1
  54. package/dist/engine/session/session.js +14 -4
  55. package/dist/engine/session/session.js.map +1 -1
  56. package/dist/internal/harness.d.ts +3 -1
  57. package/dist/internal/harness.d.ts.map +1 -1
  58. package/dist/internal/harness.js +2 -1
  59. package/dist/internal/harness.js.map +1 -1
  60. package/dist/orchestration/run-workflow-tool.d.ts +2 -0
  61. package/dist/orchestration/run-workflow-tool.d.ts.map +1 -1
  62. package/dist/orchestration/run-workflow-tool.js +13 -3
  63. package/dist/orchestration/run-workflow-tool.js.map +1 -1
  64. package/dist/orchestration/workflow.d.ts +5 -1
  65. package/dist/orchestration/workflow.d.ts.map +1 -1
  66. package/dist/orchestration/workflow.js +8 -2
  67. package/dist/orchestration/workflow.js.map +1 -1
  68. package/dist/prompts/supervisor.d.ts +1 -1
  69. package/dist/prompts/supervisor.d.ts.map +1 -1
  70. package/dist/prompts/supervisor.js +9 -4
  71. package/dist/prompts/supervisor.js.map +1 -1
  72. package/package.json +1 -1
@@ -2,7 +2,7 @@ import { AgentHarness, DEFAULT_COMPACTION_SETTINGS, uuidv7 } from "../../interna
2
2
  import { CheckpointError, BINDING_CHECKPOINT_VERSION, checkpointVersionOf, MAX_SUPPORTED_CHECKPOINT_VERSION, remainingBudgetMicroUsd, validatePendingSteer, winnerFromOutcome, } from "../checkpoint-store.js";
3
3
  import { effectiveCushionMs, estimateCycleMs, minLiveWriteoutWindowMs, recordCallSample, recordToolSample, recordTtftSample, softExecDeadlineMs, writeoutCushionMs } from "./call-cap.js";
4
4
  import { engineVersion } from "../version.js";
5
- import { DEFAULT_COMPACTION_INSTRUCTIONS, createRapidRefillState, isCompactionWalltimeAbort, maybeCompact, nextTrimForceBackoff, recordCompactionAndCheckRapidRefill } from "../auto-compaction.js";
5
+ import { DEFAULT_COMPACTION_INSTRUCTIONS, createRapidRefillState, isCompactionManualCancel, isCompactionWalltimeAbort, maybeCompact, nextTrimForceBackoff, recordCompactionAndCheckRapidRefill } from "../auto-compaction.js";
6
6
  import { ASK_USER_QUESTION_TOOL_NAME } from "../ask-question.js";
7
7
  import { computeCostMicroUsd, modelCostToPricing } from "../pricing.js";
8
8
  import { emitTrace } from "../trace.js";
@@ -41,7 +41,7 @@ import { createBrainMemorySelector } from "../memory-recall.js";
41
41
  import { buildRecallQuery, runDynamicRecall } from "../dynamic-recall.js";
42
42
  import { guardedMemoryStore } from "../memory.js";
43
43
  import { releaseSession } from "../../agents/session-util.js";
44
- export const DEFAULT_MAX_TURNS = 500;
44
+ export const DEFAULT_MAX_TURNS = 1000;
45
45
  const MAX_CONSECUTIVE_COMPACTION_FAILURES = 3;
46
46
  const STOP_HOOK_BLOCK_CAP = 8;
47
47
  const COMPACTION_REGROWTH_FACTOR = 1.5;
@@ -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) }
@@ -335,9 +337,8 @@ export class Runner {
335
337
  const manualCompactRef = { requested: false, waiters: [] };
336
338
  const drainManualCompactWaiters = (outcome) => {
337
339
  manualCompactRef.requested = false;
338
- manualCompactRef.instructions = undefined;
339
340
  for (const w of manualCompactRef.waiters.splice(0))
340
- w(outcome);
341
+ w.resolve(outcome);
341
342
  };
342
343
  const runStartedAt = Date.now();
343
344
  const taskIdRef = { current: spec.taskId, sessionId: spec.sessionId };
@@ -348,6 +349,18 @@ export class Runner {
348
349
  try {
349
350
  await this.runLocked(spec, queue, (r) => {
350
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
+ }
351
364
  }, (p) => {
352
365
  consolidationDone = p;
353
366
  }, (p) => {
@@ -366,7 +379,7 @@ export class Runner {
366
379
  }
367
380
  })();
368
381
  const settled = run.catch(async (err) => {
369
- const code = errorCodeOf(err);
382
+ let code = errorCodeOf(err);
370
383
  const reopenReason = code === "resume.env_failed"
371
384
  ? "env_failed"
372
385
  : code === "resume.tool_unavailable"
@@ -377,10 +390,20 @@ export class Runner {
377
390
  try {
378
391
  await resume.onEnvRestoreFailed(reopenReason);
379
392
  }
380
- 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
+ }
381
403
  }
382
404
  }
383
- else if (resume && !reopenable) {
405
+ else if (resume) {
406
+ this.parentConstraintRegistry.delete(resume.cp.token);
384
407
  try {
385
408
  await this.sessions.unpin?.(resume.cp.sessionId);
386
409
  }
@@ -446,6 +469,7 @@ export class Runner {
446
469
  }
447
470
  if (!won)
448
471
  return;
472
+ this.parentConstraintRegistry.delete(rh.token);
449
473
  if (rh.env && hasDestroy(rh.env)) {
450
474
  try {
451
475
  await rh.env.destroy();
@@ -532,15 +556,39 @@ export class Runner {
532
556
  compact: async (opts) => {
533
557
  if (resultValue)
534
558
  throw steeringError("the task has already finished");
559
+ if (opts?.signal?.aborted)
560
+ return "mooted";
535
561
  const h = handle ?? (await orTimeout(ready));
536
562
  if (!h)
537
563
  throw steeringError("the task is not running");
564
+ if (opts?.signal?.aborted)
565
+ return "mooted";
538
566
  return new Promise((resolve) => {
539
- manualCompactRef.requested = true;
540
- if (opts?.instructions !== undefined) {
541
- manualCompactRef.instructions = opts.instructions;
567
+ const signal = opts?.signal;
568
+ const entry = {
569
+ resolve,
570
+ ...(signal !== undefined ? { signal } : {}),
571
+ ...(opts?.instructions !== undefined ? { instructions: opts.instructions } : {}),
572
+ };
573
+ if (signal !== undefined) {
574
+ const onAbort = () => {
575
+ const i = manualCompactRef.waiters.indexOf(entry);
576
+ if (i >= 0) {
577
+ manualCompactRef.waiters.splice(i, 1);
578
+ if (manualCompactRef.waiters.length === 0) {
579
+ manualCompactRef.requested = false;
580
+ }
581
+ entry.resolve("mooted");
582
+ }
583
+ };
584
+ entry.resolve = (outcome) => {
585
+ signal.removeEventListener("abort", onAbort);
586
+ resolve(outcome);
587
+ };
588
+ signal.addEventListener("abort", onAbort, { once: true });
542
589
  }
543
- manualCompactRef.waiters.push(resolve);
590
+ manualCompactRef.requested = true;
591
+ manualCompactRef.waiters.push(entry);
544
592
  });
545
593
  },
546
594
  detach: (toolCallId) => {
@@ -1626,9 +1674,8 @@ export class Runner {
1626
1674
  let trimForceBackoff = false;
1627
1675
  const drainManualCompact = (outcome) => {
1628
1676
  manualCompactRef.requested = false;
1629
- manualCompactRef.instructions = undefined;
1630
1677
  for (const w of manualCompactRef.waiters.splice(0))
1631
- w(outcome);
1678
+ w.resolve(outcome);
1632
1679
  };
1633
1680
  const onTurnBoundary = async (event) => {
1634
1681
  let boundarySteered = false;
@@ -1863,17 +1910,35 @@ export class Runner {
1863
1910
  return undefined;
1864
1911
  }
1865
1912
  const claimedManual = forceManual
1866
- ? { instructions: manualCompactRef.instructions, waiters: manualCompactRef.waiters.splice(0) }
1913
+ ? (() => {
1914
+ const waiters = manualCompactRef.waiters.splice(0);
1915
+ let instructions;
1916
+ for (let i = waiters.length - 1; i >= 0; i--) {
1917
+ if (waiters[i].instructions !== undefined) {
1918
+ instructions = waiters[i].instructions;
1919
+ break;
1920
+ }
1921
+ }
1922
+ return { instructions, waiters };
1923
+ })()
1867
1924
  : undefined;
1868
1925
  if (forceManual) {
1869
1926
  manualCompactRef.requested = false;
1870
- manualCompactRef.instructions = undefined;
1871
1927
  }
1872
1928
  const resolveClaimedWaiters = (outcome) => {
1873
1929
  if (claimedManual !== undefined)
1874
1930
  for (const w of claimedManual.waiters.splice(0))
1875
- w(outcome);
1931
+ w.resolve(outcome);
1876
1932
  };
1933
+ const claimedCancelSignals = claimedManual?.waiters.flatMap((w) => (w.signal !== undefined ? [w.signal] : [])) ?? [];
1934
+ const manualCancelSignal = claimedCancelSignals.length === 0
1935
+ ? undefined
1936
+ : claimedCancelSignals.length === 1
1937
+ ? claimedCancelSignals[0]
1938
+ : AbortSignal.any(claimedCancelSignals);
1939
+ const compactionPassSignal = claimedCancelSignals.length > 0
1940
+ ? AbortSignal.any([prepared.abortController.signal, ...claimedCancelSignals])
1941
+ : prepared.abortController.signal;
1877
1942
  const trimPressureArmed = prepared.trimPressureRef.droppedMessages;
1878
1943
  if (trimPressureArmed)
1879
1944
  prepared.trimPressureRef.droppedMessages = false;
@@ -1893,7 +1958,8 @@ export class Runner {
1893
1958
  thinking: prepared.thinking,
1894
1959
  settings: { ...DEFAULT_COMPACTION_SETTINGS, ...spec.compaction },
1895
1960
  customInstructions: manualInstructions ?? spec.compaction?.instructions ?? DEFAULT_COMPACTION_INSTRUCTIONS,
1896
- signal: prepared.abortController.signal,
1961
+ signal: compactionPassSignal,
1962
+ ...(manualCancelSignal !== undefined ? { manualCancelSignal } : {}),
1897
1963
  minTokens: forceManual ? 0 : compactionFloor,
1898
1964
  force: forceManual,
1899
1965
  onInputTruncated: (info) => emitTrace(tracer, () => ({ kind: "compaction.input_truncated", version: 1, taskId, label: info.label, droppedChars: info.droppedChars, keptChars: info.keptChars, ts: Date.now() })),
@@ -1984,7 +2050,12 @@ export class Runner {
1984
2050
  }
1985
2051
  }
1986
2052
  catch (err) {
1987
- if (!prepared.abortController.signal.aborted) {
2053
+ const manualCancelAbort = !prepared.abortController.signal.aborted && isCompactionManualCancel(err);
2054
+ if (manualCancelAbort) {
2055
+ emitTrace(tracer, () => ({ kind: "compaction.mooted", version: 1, taskId, reason: "cancelled", ts: Date.now() }));
2056
+ manualOutcome = "mooted";
2057
+ }
2058
+ else if (!prepared.abortController.signal.aborted) {
1988
2059
  const walltimeAbort = isCompactionWalltimeAbort(err);
1989
2060
  if (!walltimeAbort)
1990
2061
  compactionBreaker.failures += 1;
@@ -2617,6 +2688,15 @@ export class Runner {
2617
2688
  if (!cp) {
2618
2689
  throw new CheckpointError("checkpoint.not_found", "no checkpoint found for the supplied token");
2619
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
+ }
2620
2700
  let wakeMessage;
2621
2701
  if (outcome.gate === "wake") {
2622
2702
  const gk = cp.gate.kind;
@@ -2710,12 +2790,28 @@ export class Runner {
2710
2790
  if (cp.state.workspaceHandle !== undefined && this.deps.executionEnvFactory === undefined) {
2711
2791
  throw new CheckpointError("checkpoint.unsupported_version", "checkpoint has a remote workspaceHandle but no RunnerDeps.executionEnvFactory is wired to rebuild the env");
2712
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
+ }
2713
2808
  const won = await store.resolve(token, cp.scope, outcome, { rev: cp.rev ?? 0 });
2714
2809
  if (!won) {
2715
2810
  const live = await store.get(token);
2716
2811
  if (live?.status === "pending") {
2717
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");
2718
2813
  }
2814
+ this.parentConstraintRegistry.delete(token);
2719
2815
  throw new CheckpointError("checkpoint.already_resolved", "checkpoint already resolved or expired — not re-executed (idempotent)");
2720
2816
  }
2721
2817
  const spec = {
@@ -2724,9 +2820,13 @@ export class Runner {
2724
2820
  sessionId: cp.sessionId,
2725
2821
  preemptSignal: taskConfig.preemptSignal?.aborted ? undefined : taskConfig.preemptSignal,
2726
2822
  };
2727
- const onEnvRestoreFailed = store.reopen
2823
+ const reopenFn = store.reopen?.bind(store);
2824
+ const onEnvRestoreFailed = reopenFn
2728
2825
  ? async (reason) => {
2729
- await store.reopen?.(token, cp.scope, reason);
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
+ }
2730
2830
  }
2731
2831
  : undefined;
2732
2832
  return this.runTaskStream(spec, { cp, outcome, onEnvRestoreFailed, ...(wakeMessage !== undefined ? { wakeMessage } : {}) }, internals);