@sema-agent/core 1.293.0 → 1.295.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 (96) hide show
  1. package/dist/agents/subagent.d.ts.map +1 -1
  2. package/dist/agents/subagent.js +25 -3
  3. package/dist/agents/subagent.js.map +1 -1
  4. package/dist/bin/sema-tb.d.ts.map +1 -1
  5. package/dist/bin/sema-tb.js +7 -2
  6. package/dist/bin/sema-tb.js.map +1 -1
  7. package/dist/brain/anthropic.d.ts.map +1 -1
  8. package/dist/brain/anthropic.js +9 -3
  9. package/dist/brain/anthropic.js.map +1 -1
  10. package/dist/brain/openai.d.ts +1 -0
  11. package/dist/brain/openai.d.ts.map +1 -1
  12. package/dist/brain/openai.js +320 -298
  13. package/dist/brain/openai.js.map +1 -1
  14. package/dist/core/checkpoint-store.d.ts +14 -2
  15. package/dist/core/checkpoint-store.d.ts.map +1 -1
  16. package/dist/core/checkpoint-store.js.map +1 -1
  17. package/dist/core/fs-write-gate-policy.d.ts +1 -0
  18. package/dist/core/fs-write-gate-policy.d.ts.map +1 -1
  19. package/dist/core/fs-write-gate-policy.js +16 -0
  20. package/dist/core/fs-write-gate-policy.js.map +1 -1
  21. package/dist/core/hooks.d.ts +3 -3
  22. package/dist/core/hooks.d.ts.map +1 -1
  23. package/dist/core/hooks.js +11 -4
  24. package/dist/core/hooks.js.map +1 -1
  25. package/dist/core/present-plan-tool.d.ts.map +1 -1
  26. package/dist/core/present-plan-tool.js +12 -13
  27. package/dist/core/present-plan-tool.js.map +1 -1
  28. package/dist/core/runner/prepare-task.d.ts +17 -1
  29. package/dist/core/runner/prepare-task.d.ts.map +1 -1
  30. package/dist/core/runner/prepare-task.js +302 -20
  31. package/dist/core/runner/prepare-task.js.map +1 -1
  32. package/dist/core/runner/runtask.d.ts +2 -0
  33. package/dist/core/runner/runtask.d.ts.map +1 -1
  34. package/dist/core/runner/runtask.js +68 -10
  35. package/dist/core/runner/runtask.js.map +1 -1
  36. package/dist/core/sensitive-path-policy.d.ts +2 -1
  37. package/dist/core/sensitive-path-policy.d.ts.map +1 -1
  38. package/dist/core/sensitive-path-policy.js +22 -0
  39. package/dist/core/sensitive-path-policy.js.map +1 -1
  40. package/dist/core/task-registry.d.ts +4 -0
  41. package/dist/core/task-registry.d.ts.map +1 -1
  42. package/dist/core/task-registry.js +83 -15
  43. package/dist/core/task-registry.js.map +1 -1
  44. package/dist/core/tool-policy.d.ts +5 -2
  45. package/dist/core/tool-policy.d.ts.map +1 -1
  46. package/dist/core/tool-policy.js +9 -0
  47. package/dist/core/tool-policy.js.map +1 -1
  48. package/dist/core/types.d.ts +5 -0
  49. package/dist/core/types.d.ts.map +1 -1
  50. package/dist/engine/compaction/utils.d.ts.map +1 -1
  51. package/dist/engine/compaction/utils.js +3 -1
  52. package/dist/engine/compaction/utils.js.map +1 -1
  53. package/dist/engine/harness/messages.d.ts +2 -0
  54. package/dist/engine/harness/messages.d.ts.map +1 -1
  55. package/dist/engine/harness/messages.js +52 -3
  56. package/dist/engine/harness/messages.js.map +1 -1
  57. package/dist/engine/llm/types.d.ts.map +1 -1
  58. package/dist/engine/session/import-validate.d.ts.map +1 -1
  59. package/dist/engine/session/import-validate.js +64 -0
  60. package/dist/engine/session/import-validate.js.map +1 -1
  61. package/dist/index.d.ts +2 -2
  62. package/dist/index.d.ts.map +1 -1
  63. package/dist/index.js +1 -1
  64. package/dist/index.js.map +1 -1
  65. package/dist/orchestration/run-workflow-tool.d.ts +1 -0
  66. package/dist/orchestration/run-workflow-tool.d.ts.map +1 -1
  67. package/dist/orchestration/run-workflow-tool.js +3 -0
  68. package/dist/orchestration/run-workflow-tool.js.map +1 -1
  69. package/dist/orchestration/workflow.d.ts +1 -0
  70. package/dist/orchestration/workflow.d.ts.map +1 -1
  71. package/dist/orchestration/workflow.js +1 -0
  72. package/dist/orchestration/workflow.js.map +1 -1
  73. package/dist/scenarios/full-body.d.ts.map +1 -1
  74. package/dist/scenarios/full-body.js +3 -2
  75. package/dist/scenarios/full-body.js.map +1 -1
  76. package/dist/tools/fs/index.d.ts +4 -1
  77. package/dist/tools/fs/index.d.ts.map +1 -1
  78. package/dist/tools/fs/index.js +59 -20
  79. package/dist/tools/fs/index.js.map +1 -1
  80. package/dist/tools/fs/safety.d.ts +1 -1
  81. package/dist/tools/fs/safety.d.ts.map +1 -1
  82. package/dist/tools/fs/safety.js +3 -1
  83. package/dist/tools/fs/safety.js.map +1 -1
  84. package/dist/tools/fs/search.d.ts +7 -2
  85. package/dist/tools/fs/search.d.ts.map +1 -1
  86. package/dist/tools/fs/search.js +465 -57
  87. package/dist/tools/fs/search.js.map +1 -1
  88. package/dist/tools/monitor.d.ts.map +1 -1
  89. package/dist/tools/monitor.js +12 -1
  90. package/dist/tools/monitor.js.map +1 -1
  91. package/dist/tools/task-list.d.ts.map +1 -1
  92. package/dist/tools/task-list.js.map +1 -1
  93. package/dist/tools/worktree.d.ts.map +1 -1
  94. package/dist/tools/worktree.js +15 -2
  95. package/dist/tools/worktree.js.map +1 -1
  96. 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
- const code = errorCodeOf(err);
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 && !reopenable) {
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();
@@ -1199,7 +1224,8 @@ export class Runner {
1199
1224
  const batchArgs = postToolBatchHook ? new Map() : undefined;
1200
1225
  let toolBatch = [];
1201
1226
  const onToolStart = (event) => {
1202
- toolStartAt.set(event.toolCallId, Date.now());
1227
+ const startAt = Date.now();
1228
+ toolStartAt.set(event.toolCallId, startAt);
1203
1229
  startedToolCallIds.add(event.toolCallId);
1204
1230
  batchArgs?.set(event.toolCallId, event.args);
1205
1231
  stats.toolCalls += 1;
@@ -1210,7 +1236,7 @@ export class Runner {
1210
1236
  groundingSignalPostR9 = true;
1211
1237
  }
1212
1238
  const activityArg = primaryActivityArg(event.args);
1213
- internals?.onActivity?.({ phase: "start", toolCallId: event.toolCallId, toolName: event.toolName, ...(activityArg !== undefined ? { arg: activityArg } : {}) });
1239
+ internals?.onActivity?.({ phase: "start", toolCallId: event.toolCallId, toolName: event.toolName, at: startAt, ...(activityArg !== undefined ? { arg: activityArg } : {}) });
1214
1240
  pushContent({
1215
1241
  type: "tool_start",
1216
1242
  toolCallId: event.toolCallId,
@@ -1260,7 +1286,7 @@ export class Runner {
1260
1286
  ok: !event.isError,
1261
1287
  ts: toolNow,
1262
1288
  }));
1263
- internals?.onActivity?.({ phase: "end", toolCallId: event.toolCallId, toolName: event.toolName, isError: event.isError });
1289
+ internals?.onActivity?.({ phase: "end", toolCallId: event.toolCallId, toolName: event.toolName, isError: event.isError, at: toolNow });
1264
1290
  if (prepared.lspDiagnostics && !event.isError) {
1265
1291
  const name = canonicalToolName(event.toolName);
1266
1292
  if (name === "Edit" || name === "Write" || name === "NotebookEdit") {
@@ -2421,7 +2447,7 @@ export class Runner {
2421
2447
  prepared.suspendRef.token === undefined &&
2422
2448
  prepared.reviewRef.token === undefined;
2423
2449
  try {
2424
- await defaultTaskRegistry.settleKilledForOwner({ owner: spec.taskId ?? prepared.sessionId, scope: spec.principal ?? "default" }, {
2450
+ await defaultTaskRegistry.settleKilledForOwner({ owner: spec.taskId ?? prepared.sessionId, scope: spec.principal ?? "default", sessionId: prepared.sessionId }, {
2425
2451
  source: abortedLive &&
2426
2452
  !timeout.fired &&
2427
2453
  !turnsExceeded &&
@@ -2432,6 +2458,7 @@ export class Runner {
2432
2458
  : "parent",
2433
2459
  skipSessionScoped: true,
2434
2460
  envDying: ownedEnvDying,
2461
+ retainProcesses: spec.retainBackgroundProcesses === true,
2435
2462
  });
2436
2463
  }
2437
2464
  catch (e) {
@@ -2442,13 +2469,15 @@ export class Runner {
2442
2469
  }
2443
2470
  }
2444
2471
  const bgEnv = prepared.ownedEnv ?? this.deps.executionEnv;
2445
- if (bgEnv && hasBackgroundShell(bgEnv)) {
2472
+ const retainBgBySpec = spec.retainBackgroundProcesses === true && !ownedEnvDying;
2473
+ if (bgEnv && hasBackgroundShell(bgEnv) && !retainBgBySpec) {
2446
2474
  try {
2447
2475
  const keepAlive = ownedEnvDying && bgEnv === prepared.ownedEnv
2448
2476
  ? []
2449
2477
  : [
2450
2478
  ...defaultTaskRegistry.sessionResidentShellIds(prepared.sessionId, bgEnv),
2451
2479
  ...defaultTaskRegistry.timeoutResidentShellIds(bgEnv),
2480
+ ...defaultTaskRegistry.retainedShellIds(bgEnv),
2452
2481
  ];
2453
2482
  await bgEnv.disposeBackgroundShells(keepAlive.length > 0 ? { except: keepAlive } : undefined);
2454
2483
  }
@@ -2663,6 +2692,15 @@ export class Runner {
2663
2692
  if (!cp) {
2664
2693
  throw new CheckpointError("checkpoint.not_found", "no checkpoint found for the supplied token");
2665
2694
  }
2695
+ if ((internals?.inheritedGate?.parentConstraints?.length ?? 0) === 0) {
2696
+ const parked = this.parentConstraintRegistry.get(token);
2697
+ if (parked !== undefined) {
2698
+ internals = {
2699
+ ...(internals ?? {}),
2700
+ inheritedGate: { ...(internals?.inheritedGate ?? {}), parentConstraints: parked },
2701
+ };
2702
+ }
2703
+ }
2666
2704
  let wakeMessage;
2667
2705
  if (outcome.gate === "wake") {
2668
2706
  const gk = cp.gate.kind;
@@ -2756,12 +2794,28 @@ export class Runner {
2756
2794
  if (cp.state.workspaceHandle !== undefined && this.deps.executionEnvFactory === undefined) {
2757
2795
  throw new CheckpointError("checkpoint.unsupported_version", "checkpoint has a remote workspaceHandle but no RunnerDeps.executionEnvFactory is wired to rebuild the env");
2758
2796
  }
2797
+ if (cp.state.inheritedGate?.requiresParentConstraint === true) {
2798
+ const supplied = internals?.inheritedGate?.parentConstraints?.length ?? 0;
2799
+ if (supplied === 0) {
2800
+ throw new CheckpointError("resume.parent_constraint_missing", "this checkpoint's task ran under inherited parent-policy constraints (state.inheritedGate.requiresParentConstraint) " +
2801
+ "— the live policy/onAsk closures cannot be persisted, so the resume must re-supply them via " +
2802
+ "resumeStream(token, outcome, taskConfig, internals) with internals.inheritedGate.parentConstraints; " +
2803
+ "rejected pre-CAS (the checkpoint stays pending) rather than silently dropping the ancestors' gate");
2804
+ }
2805
+ const expected = cp.state.inheritedGate.parentConstraintCount;
2806
+ if (expected !== undefined && supplied !== expected) {
2807
+ throw new CheckpointError("resume.parent_constraint_mismatch", `re-supplied ${supplied} parent constraint(s) but the checkpoint recorded ${expected} — a partial/mismatched ` +
2808
+ "re-supply would run the resumed leg under a different ancestor chain than it suspended with; " +
2809
+ "rejected pre-CAS (the checkpoint stays pending) — re-resume with the full original chain");
2810
+ }
2811
+ }
2759
2812
  const won = await store.resolve(token, cp.scope, outcome, { rev: cp.rev ?? 0 });
2760
2813
  if (!won) {
2761
2814
  const live = await store.get(token);
2762
2815
  if (live?.status === "pending") {
2763
2816
  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
2817
  }
2818
+ this.parentConstraintRegistry.delete(token);
2765
2819
  throw new CheckpointError("checkpoint.already_resolved", "checkpoint already resolved or expired — not re-executed (idempotent)");
2766
2820
  }
2767
2821
  const spec = {
@@ -2770,9 +2824,13 @@ export class Runner {
2770
2824
  sessionId: cp.sessionId,
2771
2825
  preemptSignal: taskConfig.preemptSignal?.aborted ? undefined : taskConfig.preemptSignal,
2772
2826
  };
2773
- const onEnvRestoreFailed = store.reopen
2827
+ const reopenFn = store.reopen?.bind(store);
2828
+ const onEnvRestoreFailed = reopenFn
2774
2829
  ? async (reason) => {
2775
- await store.reopen?.(token, cp.scope, reason);
2830
+ const reopened = await reopenFn(token, cp.scope, reason);
2831
+ if (!reopened) {
2832
+ throw new CheckpointError("checkpoint.reopen_failed", "checkpoint could not be reopened for a retry (missing, expired, or changed concurrently) — the resume failure is terminal");
2833
+ }
2776
2834
  }
2777
2835
  : undefined;
2778
2836
  return this.runTaskStream(spec, { cp, outcome, onEnvRestoreFailed, ...(wakeMessage !== undefined ? { wakeMessage } : {}) }, internals);