@sema-agent/core 5.22.0 → 5.24.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 +169 -1
- package/dist/agents/subagent.js +3 -2
- package/dist/core/checkpoint-store.d.ts +38 -3
- package/dist/core/checkpoint-store.js +2 -1
- package/dist/core/governance-codes.js +3 -0
- package/dist/core/hooks.d.ts +69 -2
- package/dist/core/hooks.js +100 -15
- package/dist/core/memory-engine/engine.d.ts +28 -1
- package/dist/core/memory-engine/engine.js +62 -3
- package/dist/core/memory-engine/index.d.ts +1 -1
- package/dist/core/memory-engine/index.js +1 -1
- package/dist/core/memory-engine/layout.d.ts +69 -3
- package/dist/core/memory-engine/layout.js +75 -6
- package/dist/core/permission-rule-consent.js +2 -1
- package/dist/core/permission-rule-org.d.ts +36 -2
- package/dist/core/permission-rule-org.js +23 -0
- package/dist/core/permission-rule-store.d.ts +25 -14
- package/dist/core/permission-rule-store.js +7 -2
- package/dist/core/permission-rule-sync.d.ts +8 -0
- package/dist/core/permission-rule-sync.js +35 -6
- package/dist/core/runner/prepare-task.d.ts +10 -2
- package/dist/core/runner/prepare-task.js +120 -11
- package/dist/core/runner/runtask.js +46 -1
- package/dist/core/runner/session-file-state-replay.js +3 -0
- package/dist/core/tool-policy.d.ts +37 -4
- package/dist/core/tool-policy.js +49 -19
- package/dist/core/tool-result-store.d.ts +17 -1
- package/dist/core/tool-result-store.js +79 -4
- package/dist/core/trace.d.ts +47 -0
- package/dist/core/types.d.ts +45 -5
- package/dist/core/wiring-manifest.d.ts +16 -1
- package/dist/core/wiring-manifest.js +7 -1
- package/dist/index.d.ts +18 -10
- package/dist/index.js +5 -3
- package/dist/orchestration/goal.d.ts +10 -0
- package/dist/orchestration/goal.js +6 -5
- package/dist/stores/file/adoption/adopt.d.ts +146 -0
- package/dist/stores/file/adoption/adopt.js +611 -0
- package/dist/stores/file/adoption/marker.d.ts +202 -0
- package/dist/stores/file/adoption/marker.js +205 -0
- package/dist/stores/file/background-agent-store.js +2 -0
- package/dist/stores/file/checkpoint-store.js +2 -0
- package/dist/stores/file/file-snapshot-store.js +2 -0
- package/dist/stores/file/index.d.ts +2 -0
- package/dist/stores/file/index.js +4 -0
- package/dist/stores/file/mailbox-store.js +2 -0
- package/dist/stores/file/memory-store.js +2 -0
- package/dist/stores/file/session-policy-store.d.ts +11 -1
- package/dist/stores/file/session-policy-store.js +9 -2
- package/dist/stores/file/session-store.js +2 -0
- package/dist/stores/file/task-list-store.js +2 -0
- package/dist/stores/file/tool-result-store.js +2 -0
- package/dist/stores/file/usage-window-store.js +2 -0
- package/dist/stores/file/workflow-journal-store.js +2 -0
- package/dist/stores/file/workflow-run-store.js +2 -0
- package/dist/tools/fs/bash-readonly-classifier.js +59 -10
- package/dist/tools/fs/fs-bash.js +7 -4
- package/dist/tools/monitor.js +3 -3
- package/package.json +3 -2
|
@@ -4,6 +4,7 @@ import { join } from "node:path";
|
|
|
4
4
|
import { callKeyOrdinal } from "../../core/workflow-journal-store.js";
|
|
5
5
|
import { AppendLog } from "./fs-atomic.js";
|
|
6
6
|
import { canonicalStoreKey, sanitizePathComponent, writeThenLink } from "./fs-atomic.js";
|
|
7
|
+
import { assertAdoptionBootGate } from "./adoption/marker.js";
|
|
7
8
|
import { oversizeJournalResult } from "../../core/workflow-journal-store.js";
|
|
8
9
|
export { MAX_JOURNAL_RESULT_BYTES, oversizeJournalResult } from "../../core/workflow-journal-store.js";
|
|
9
10
|
export const RESUME_CLAIM_TTL_MS = 60 * 60 * 1000;
|
|
@@ -28,6 +29,7 @@ export class FileWorkflowJournalStore {
|
|
|
28
29
|
}
|
|
29
30
|
constructor(root, fsyncEnabled = true) {
|
|
30
31
|
this.fsyncEnabled = fsyncEnabled;
|
|
32
|
+
assertAdoptionBootGate(root, "FileWorkflowJournalStore");
|
|
31
33
|
this.dir = join(root, "workflow-journal");
|
|
32
34
|
mkdirSync(this.dir, { recursive: true, mode: 0o700 });
|
|
33
35
|
this.claimsDir = join(this.dir, "claims");
|
|
@@ -2,6 +2,7 @@ import { join } from "node:path";
|
|
|
2
2
|
import { assertRetentionPolicy } from "../../core/retention-policy.js";
|
|
3
3
|
import { WorkflowRunStoreError, isTerminalWorkflowStatus, nextWorkflowRunOnUpdate, queryWorkflowRuns, } from "../../core/workflow-run-store.js";
|
|
4
4
|
import { SharedLedgerTable } from "./shared-ledger.js";
|
|
5
|
+
import { assertAdoptionBootGate } from "./adoption/marker.js";
|
|
5
6
|
const runLedgers = new SharedLedgerTable({
|
|
6
7
|
keyOf: (run) => run.id,
|
|
7
8
|
apply: (runs, ev) => {
|
|
@@ -21,6 +22,7 @@ export class FileWorkflowRunStore {
|
|
|
21
22
|
return this.ledger.rows;
|
|
22
23
|
}
|
|
23
24
|
constructor(root, opts = {}) {
|
|
25
|
+
assertAdoptionBootGate(root, "FileWorkflowRunStore");
|
|
24
26
|
this.fsyncEnabled = opts.fsync !== false;
|
|
25
27
|
this.compactEvery = opts.compactEvery ?? 1000;
|
|
26
28
|
const dir = join(root, "workflow-runs");
|
|
@@ -238,11 +238,51 @@ function isGrepClusterFileStdin(tok) {
|
|
|
238
238
|
}
|
|
239
239
|
return false;
|
|
240
240
|
}
|
|
241
|
-
|
|
242
|
-
|
|
241
|
+
const SEPARATED_VALUE_OPTIONS = {
|
|
242
|
+
head: { short: "cn", long: ["bytes", "lines"] },
|
|
243
|
+
tail: { short: "cns", long: ["bytes", "lines", "sleep-interval", "pid", "max-unchanged-stats"] },
|
|
244
|
+
cut: { short: "bcdf", long: ["bytes", "characters", "delimiter", "fields", "output-delimiter"] },
|
|
245
|
+
grep: {
|
|
246
|
+
ownsValueButNotSkippable: "ef",
|
|
247
|
+
short: "mABCdD",
|
|
248
|
+
long: [
|
|
249
|
+
"max-count",
|
|
250
|
+
"after-context",
|
|
251
|
+
"before-context",
|
|
252
|
+
"context",
|
|
253
|
+
"devices",
|
|
254
|
+
"directories",
|
|
255
|
+
"label",
|
|
256
|
+
"binary-files",
|
|
257
|
+
"group-separator",
|
|
258
|
+
"include",
|
|
259
|
+
"exclude",
|
|
260
|
+
"exclude-dir",
|
|
261
|
+
],
|
|
262
|
+
},
|
|
263
|
+
};
|
|
264
|
+
function takesSeparatedValue(name, tok) {
|
|
265
|
+
const model = SEPARATED_VALUE_OPTIONS[name];
|
|
266
|
+
if (model === undefined)
|
|
243
267
|
return false;
|
|
244
|
-
|
|
245
|
-
|
|
268
|
+
if (tok.startsWith("--")) {
|
|
269
|
+
if (tok.includes("="))
|
|
270
|
+
return false;
|
|
271
|
+
const long = longOptionNameOf(tok);
|
|
272
|
+
return long !== undefined && model.long.some((full) => isLongOptionAbbrevOf(long, full));
|
|
273
|
+
}
|
|
274
|
+
if (!/^-[A-Za-z0-9]/.test(tok))
|
|
275
|
+
return false;
|
|
276
|
+
for (let i = 1; i < tok.length; i++) {
|
|
277
|
+
const ch = tok[i];
|
|
278
|
+
if ((model.ownsValueButNotSkippable ?? "").includes(ch))
|
|
279
|
+
return false;
|
|
280
|
+
if (model.short.includes(ch))
|
|
281
|
+
return i === tok.length - 1;
|
|
282
|
+
if (!/[A-Za-z0-9]/.test(ch))
|
|
283
|
+
return false;
|
|
284
|
+
}
|
|
285
|
+
return false;
|
|
246
286
|
}
|
|
247
287
|
function isGrepFileStdinLongOption(tok) {
|
|
248
288
|
const eq = tok.indexOf("=");
|
|
@@ -478,19 +518,28 @@ export function classifyCompoundReadonlyDetailed(command, allow, boundary) {
|
|
|
478
518
|
let sawNonFlagOperand = false;
|
|
479
519
|
let hasStdinDash = false;
|
|
480
520
|
let operandCount = 0;
|
|
521
|
+
let endOfOptions = false;
|
|
481
522
|
if (name !== "tr") {
|
|
482
523
|
for (let k = 0; k < restArgs.length; k++) {
|
|
483
524
|
const t = restArgs[k];
|
|
484
|
-
if (
|
|
525
|
+
if (endOfOptions) {
|
|
526
|
+
}
|
|
527
|
+
else if (t === "--") {
|
|
528
|
+
endOfOptions = true;
|
|
529
|
+
continue;
|
|
530
|
+
}
|
|
531
|
+
else if (takesSeparatedValue(name, t)) {
|
|
485
532
|
k++;
|
|
486
533
|
continue;
|
|
487
534
|
}
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
535
|
+
else {
|
|
536
|
+
if (name === "grep" && (isGrepClusterFileStdin(t) || isGrepFileStdinLongOption(t))) {
|
|
537
|
+
hasStdinDash = true;
|
|
538
|
+
break;
|
|
539
|
+
}
|
|
540
|
+
if (t.startsWith("-") && t !== "-")
|
|
541
|
+
continue;
|
|
491
542
|
}
|
|
492
|
-
if (t.startsWith("-") && t !== "-")
|
|
493
|
-
continue;
|
|
494
543
|
const isGrepPatternPosition = name === "grep" && !grepPatternSuppliedByFlag && !sawNonFlagOperand;
|
|
495
544
|
sawNonFlagOperand = true;
|
|
496
545
|
operandCount++;
|
package/dist/tools/fs/fs-bash.js
CHANGED
|
@@ -14,9 +14,12 @@ import { BASH_READONLY_DEFAULT_ALLOW, coarseReadonlyCheck, classifyBoundedReadon
|
|
|
14
14
|
export function bashReversibilityProbe(allow, boundary) {
|
|
15
15
|
const allowSet = new Set(allow ?? BASH_READONLY_DEFAULT_ALLOW);
|
|
16
16
|
return (args) => {
|
|
17
|
-
const
|
|
17
|
+
const a = args;
|
|
18
|
+
const command = a?.command;
|
|
18
19
|
if (typeof command !== "string")
|
|
19
20
|
return { reversible: false };
|
|
21
|
+
if (a?.run_in_background === true)
|
|
22
|
+
return { reversible: false };
|
|
20
23
|
const resolved = typeof boundary === "function" ? boundary() : boundary;
|
|
21
24
|
if (classifyCompoundReadonly(command, allowSet, resolved) === undefined)
|
|
22
25
|
return { reversible: true };
|
|
@@ -555,8 +558,8 @@ export function createBashTool(env, rootCanonical, coAuthor = false, cwdRef = {
|
|
|
555
558
|
const bgCappedByMax = appliedTimeoutSec !== undefined && requestedTimeoutSec !== undefined && typeof bgCaps.maxBgTimeoutSec === "number" && requestedTimeoutSec > bgCaps.maxBgTimeoutSec;
|
|
556
559
|
const budgetNote = appliedTimeoutSec !== undefined
|
|
557
560
|
? bgCappedByMax
|
|
558
|
-
? ` Time budget: requested ${requestedTimeoutSec}s, capped at ${bgCaps.maxBgTimeoutSec}s (env ceiling: requests above ${bgCaps.maxBgTimeoutSec}s are reduced to it) —
|
|
559
|
-
: ` Time budget:
|
|
561
|
+
? ` Time budget: requested ${requestedTimeoutSec}s, capped at ${bgCaps.maxBgTimeoutSec}s (env ceiling: requests above ${bgCaps.maxBgTimeoutSec}s are reduced to it) — the process may run up to ${appliedTimeoutSec}s.`
|
|
562
|
+
: ` Time budget: the process may run up to ${appliedTimeoutSec}s (hard cap ${bgCaps.maxBgTimeoutSec}s).`
|
|
560
563
|
: "";
|
|
561
564
|
const lifetimeNote = backgroundLifetimeNote(bgCaps, bgSessionScoped, bgEnvIsolatedOwned);
|
|
562
565
|
const registry = taskOpts.taskRegistry;
|
|
@@ -655,7 +658,7 @@ export function createBashTool(env, rootCanonical, coAuthor = false, cwdRef = {
|
|
|
655
658
|
const tail = stdoutSoFar.slice(-1_000);
|
|
656
659
|
const adoptCaps = detachEnv.backgroundCapabilities;
|
|
657
660
|
const adoptBudgetNote = typeof adoptCaps.defaultBgTimeoutSec === "number" && typeof adoptCaps.maxBgTimeoutSec === "number"
|
|
658
|
-
? ` Time budget:
|
|
661
|
+
? ` Time budget: the process may run up to ${Math.min(adoptCaps.defaultBgTimeoutSec, adoptCaps.maxBgTimeoutSec)}s (hard cap ${adoptCaps.maxBgTimeoutSec}s).`
|
|
659
662
|
: "";
|
|
660
663
|
return {
|
|
661
664
|
content: (cause === "timeout"
|
package/dist/tools/monitor.js
CHANGED
|
@@ -121,7 +121,7 @@ export function createMonitorTool(env, opts) {
|
|
|
121
121
|
const envWallMs = bgTimeout !== undefined ? bgTimeout * 1000 : undefined;
|
|
122
122
|
const envWallWins = !isPersistent && envWallMs !== undefined && envWallMs < timeoutMs;
|
|
123
123
|
const persistentBudget = bgTimeout !== undefined
|
|
124
|
-
? `the execution environment
|
|
124
|
+
? `the execution environment's background time budget ends the watch after ${bgTimeout}s`
|
|
125
125
|
: `the execution environment's background time budget still applies`;
|
|
126
126
|
const retainedByEnv = env.backgroundCapabilities.retainBackgroundProcesses === true;
|
|
127
127
|
const retainedBySpec = opts.retainBackgroundProcesses === true;
|
|
@@ -142,8 +142,8 @@ export function createMonitorTool(env, opts) {
|
|
|
142
142
|
const lifetime = isPersistent
|
|
143
143
|
? `It is persistent: no watch timeout of its own${timeoutIgnoredNote}, but ${persistentBudget}${persistentAnchor}`
|
|
144
144
|
: envWallWins
|
|
145
|
-
? `
|
|
146
|
-
: `
|
|
145
|
+
? `The watch may run up to ${envWallMs}ms — the execution environment's background time budget (${bgTimeout}s) is shorter than the ${timeoutMs}ms watch timeout${clampNote}, and the shorter of the two wins.`
|
|
146
|
+
: `The watch may run up to ${timeoutMs}ms${clampNote}.`;
|
|
147
147
|
const content = onNotify !== undefined
|
|
148
148
|
? `Monitoring in background; task_id=${taskId}. Each stdout line becomes a notification event (lines within ` +
|
|
149
149
|
`~200ms are batched); you'll get a final notification with the exit code when it ends — do not poll. ` +
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sema-agent/core",
|
|
3
|
-
"version": "5.
|
|
3
|
+
"version": "5.24.0",
|
|
4
4
|
"description": "Stateless, task-oriented AI agent core",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "BUSL-1.1",
|
|
@@ -63,7 +63,8 @@
|
|
|
63
63
|
"gate:domain-lexicon": "node scripts/verify-domain-lexicon.mjs",
|
|
64
64
|
"gate:single-mint": "node scripts/verify-single-mint.mjs",
|
|
65
65
|
"gate:nuia": "node scripts/verify-nuia-baseline.mjs",
|
|
66
|
-
"gate:field-liveness": "node scripts/verify-field-liveness.mjs"
|
|
66
|
+
"gate:field-liveness": "node scripts/verify-field-liveness.mjs",
|
|
67
|
+
"gate:error-surface": "node scripts/verify-error-surface.mjs"
|
|
67
68
|
},
|
|
68
69
|
"dependencies": {
|
|
69
70
|
"@modelcontextprotocol/sdk": "1.30.0",
|