@sema-agent/core 3.0.0 → 4.0.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 +2345 -0
- package/dist/agents/cascade.d.ts +2 -1
- package/dist/agents/cascade.js +31 -32
- package/dist/agents/cumulative-stats.d.ts +29 -0
- package/dist/agents/cumulative-stats.js +29 -0
- package/dist/agents/observer.d.ts +4 -0
- package/dist/agents/observer.js +11 -10
- package/dist/agents/repair-loop.js +27 -19
- package/dist/agents/retain-ledger.d.ts +2 -0
- package/dist/agents/retain-ledger.js +6 -5
- package/dist/agents/roster-store.js +3 -5
- package/dist/agents/subagent.js +66 -64
- package/dist/agents/teacher.d.ts +1 -9
- package/dist/agents/teacher.js +21 -24
- package/dist/agents/verify.js +15 -14
- package/dist/brain/anthropic.js +24 -21
- package/dist/brain/openai.js +24 -21
- package/dist/brain/stream-engine.js +5 -2
- package/dist/brain/stream-shared.d.ts +1 -0
- package/dist/brain/stream-shared.js +14 -0
- package/dist/brain/terminal-cause.d.ts +4 -0
- package/dist/brain/terminal-cause.js +12 -0
- package/dist/brain/tool-call-id.d.ts +1 -0
- package/dist/brain/tool-call-id.js +3 -0
- package/dist/brain/tool-call-repair.js +2 -1
- package/dist/core/auto-compaction.js +16 -25
- package/dist/core/background-agent-store.d.ts +22 -22
- package/dist/core/background-agent-store.js +19 -23
- package/dist/core/checkpoint-store.d.ts +6 -13
- package/dist/core/checkpoint-store.js +11 -5
- package/dist/core/file-snapshot-store.d.ts +8 -0
- package/dist/core/file-snapshot-store.js +4 -3
- package/dist/core/hooks.d.ts +3 -1
- package/dist/core/hooks.js +8 -18
- package/dist/core/lsp.js +4 -3
- package/dist/core/mailbox-store.d.ts +7 -10
- package/dist/core/mcp.d.ts +7 -10
- package/dist/core/mcp.js +7 -3
- package/dist/core/memory-engine/engine.d.ts +0 -1
- package/dist/core/memory-engine/engine.js +24 -34
- package/dist/core/memory-engine/file-backend.d.ts +1 -2
- package/dist/core/memory-engine/file-backend.js +25 -36
- package/dist/core/memory-engine/layout.d.ts +8 -0
- package/dist/core/memory-engine/layout.js +60 -4
- package/dist/core/memory-engine/scope-contract.js +9 -3
- package/dist/core/memory-engine/types.d.ts +1 -1
- package/dist/core/runner/active-skill-scope.d.ts +0 -1
- package/dist/core/runner/active-skill-scope.js +1 -15
- package/dist/core/runner/assemble-result.d.ts +2 -7
- package/dist/core/runner/assemble-result.js +3 -4
- package/dist/core/runner/compaction-call-options.d.ts +7 -0
- package/dist/core/runner/compaction-call-options.js +30 -0
- package/dist/core/runner/prepare-task.d.ts +6 -23
- package/dist/core/runner/prepare-task.js +20 -53
- package/dist/core/runner/runtask.d.ts +1 -0
- package/dist/core/runner/runtask.js +65 -156
- package/dist/core/runner/session-rule-policy.js +4 -1
- package/dist/core/runner/teardown-bounded.d.ts +7 -0
- package/dist/core/runner/teardown-bounded.js +36 -0
- package/dist/core/runner/tool-disclosure.d.ts +2 -5
- package/dist/core/runner/turn-attachments.d.ts +5 -15
- package/dist/core/runner/turn-attachments.js +1 -1
- package/dist/core/safe-notify.d.ts +17 -0
- package/dist/core/safe-notify.js +59 -0
- package/dist/core/sensitive-path-policy.js +2 -1
- package/dist/core/store-contracts/checkpoint-store-contract.js +1 -1
- package/dist/core/stub-env.d.ts +2 -6
- package/dist/core/surrogate-safe-slice.d.ts +4 -0
- package/dist/core/surrogate-safe-slice.js +18 -0
- package/dist/core/task-registry-monitor.js +8 -13
- package/dist/core/task-registry-shared.d.ts +22 -0
- package/dist/core/task-registry-shared.js +16 -0
- package/dist/core/task-registry.d.ts +1 -0
- package/dist/core/task-registry.js +40 -57
- package/dist/core/tool-errors.js +5 -4
- package/dist/core/tool-name-aliases.js +2 -1
- package/dist/core/tool-policy.js +10 -5
- package/dist/core/tool-result-store.d.ts +1 -0
- package/dist/core/tool-result-store.js +17 -1
- package/dist/core/trace.d.ts +2 -9
- package/dist/core/types.d.ts +15 -12
- package/dist/core/untrusted-egress.js +7 -5
- package/dist/core/workflow-journal-store.d.ts +9 -20
- package/dist/core/workflow-run-store.d.ts +11 -10
- package/dist/core/workflow-run-store.js +22 -16
- package/dist/engine/compaction/utils.js +4 -2
- package/dist/engine/execution-env/node-execution-env.d.ts +2 -24
- package/dist/engine/harness/agent-harness.d.ts +1 -0
- package/dist/engine/harness/agent-harness.js +13 -33
- package/dist/engine/harness/types.d.ts +29 -67
- package/dist/engine/llm/types.d.ts +1 -1
- package/dist/engine/loop/agent-loop.js +11 -4
- package/dist/engine/loop/types.d.ts +11 -9
- package/dist/engine/session/memory-repo.d.ts +2 -6
- package/dist/engine/session/session.d.ts +5 -30
- package/dist/index.d.ts +3 -1
- package/dist/index.js +2 -1
- package/dist/internal/harness-types.d.ts +3 -1
- package/dist/orchestration/run-spec.js +7 -4
- package/dist/orchestration/run-workflow-tool.js +3 -35
- package/dist/orchestration/workflow.d.ts +3 -11
- package/dist/orchestration/workflow.js +164 -204
- package/dist/prompt-assembly/tool-catalog.d.ts +10 -9
- package/dist/prompt-assembly/turn-snapshot.d.ts +2 -5
- package/dist/stores/file/background-agent-store.d.ts +3 -12
- package/dist/stores/file/background-agent-store.js +3 -41
- package/dist/stores/file/checkpoint-store.js +6 -6
- package/dist/stores/file/mailbox-store.d.ts +2 -6
- package/dist/stores/file/session-policy-store.js +15 -1
- package/dist/stores/file/session-store.d.ts +2 -6
- package/dist/stores/file/workflow-journal-store.d.ts +3 -11
- package/dist/stores/file/workflow-run-store.d.ts +3 -7
- package/dist/stores/file/workflow-run-store.js +4 -17
- package/dist/tools/fs/bash-readonly-classifier.d.ts +1 -0
- package/dist/tools/fs/bash-readonly-classifier.js +60 -25
- package/dist/tools/fs/fs-bash.js +324 -96
- package/dist/tools/fs/fs-pdf.d.ts +2 -12
- package/dist/tools/fs/fs-shared.js +2 -2
- package/dist/tools/fs/notebook.d.ts +2 -5
- package/dist/tools/fs/safety.d.ts +3 -0
- package/dist/tools/fs/safety.js +43 -14
- package/dist/tools/fs/search.js +5 -5
- package/dist/tools/monitor.d.ts +1 -0
- package/dist/tools/monitor.js +7 -5
- package/dist/tools/worktree.d.ts +2 -7
- package/dist/tools/worktree.js +3 -1
- package/package.json +6 -2
package/dist/tools/fs/safety.js
CHANGED
|
@@ -18,20 +18,20 @@ export function sha256(content) {
|
|
|
18
18
|
return createHash("sha256").update(content, "utf8").digest("hex");
|
|
19
19
|
}
|
|
20
20
|
const SEP = "/";
|
|
21
|
-
function isAbsolutePathForm(p) {
|
|
22
|
-
return p.startsWith("/") || /^[A-Za-z]:[\\/]/.test(p);
|
|
21
|
+
export function isAbsolutePathForm(p) {
|
|
22
|
+
return p.startsWith("/") || /^[A-Za-z]:[\\/]/.test(p) || p.startsWith("\\\\");
|
|
23
23
|
}
|
|
24
24
|
function normalizeForCompare(p) {
|
|
25
|
-
let n = p.replace(/\\/g, "/");
|
|
25
|
+
let n = isWinFormPath(p) ? p.replace(/\\/g, "/") : p;
|
|
26
26
|
if (/^[A-Za-z]:(\/|$)/.test(n))
|
|
27
27
|
n = n[0].toLowerCase() + n.slice(1);
|
|
28
28
|
return n;
|
|
29
29
|
}
|
|
30
30
|
function nativeSepOf(p) {
|
|
31
|
-
return p.includes("\\") ? "\\" : "/";
|
|
31
|
+
return isWinFormPath(p) && p.includes("\\") ? "\\" : "/";
|
|
32
32
|
}
|
|
33
33
|
function lastSepIndex(p) {
|
|
34
|
-
return Math.max(p.lastIndexOf("/"), p.lastIndexOf("\\"));
|
|
34
|
+
return isWinFormPath(p) ? Math.max(p.lastIndexOf("/"), p.lastIndexOf("\\")) : p.lastIndexOf("/");
|
|
35
35
|
}
|
|
36
36
|
const BLOCKED_DEVICE_PATHS = new Set([
|
|
37
37
|
"/dev/zero", "/dev/random", "/dev/urandom", "/dev/full",
|
|
@@ -46,7 +46,7 @@ function isProcSensitiveFile(key) {
|
|
|
46
46
|
return key.startsWith("/proc/") && PROC_SENSITIVE_SUFFIXES.some((suf) => key.endsWith(suf));
|
|
47
47
|
}
|
|
48
48
|
const WIN_RESERVED_RE = /^(CON|PRN|AUX|NUL|COM[1-9]|LPT[1-9])(\.[^\\/]*)?$/i;
|
|
49
|
-
function isWinFormPath(p) {
|
|
49
|
+
export function isWinFormPath(p) {
|
|
50
50
|
return /^[A-Za-z]:[\\/]/.test(p) || p.startsWith("\\\\") || (!p.startsWith("/") && p.includes("\\"));
|
|
51
51
|
}
|
|
52
52
|
function isWinReservedDeviceKey(key) {
|
|
@@ -60,19 +60,48 @@ export function isBlockedDevicePath(key) {
|
|
|
60
60
|
return BLOCKED_DEVICE_PATHS.has(key) || isProcStdioFd(key) || isProcSensitiveFile(key) || isWinReservedDeviceKey(key);
|
|
61
61
|
}
|
|
62
62
|
export function normalizeAbsPathLexically(p) {
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
63
|
+
return foldSegmentsLexically(p, true);
|
|
64
|
+
}
|
|
65
|
+
export function foldRedundantPathSegments(p) {
|
|
66
|
+
return foldSegmentsLexically(p, false);
|
|
67
|
+
}
|
|
68
|
+
function foldSegmentsLexically(p, foldParents) {
|
|
69
|
+
const isUnc = p.startsWith("\\\\");
|
|
70
|
+
const drive = /^[A-Za-z]:/.exec(p)?.[0] ?? "";
|
|
71
|
+
const winForm = isUnc || drive !== "" || (!p.startsWith("/") && p.includes("\\"));
|
|
72
|
+
const sep = winForm && p.includes("\\") ? "\\" : "/";
|
|
73
|
+
const splitter = winForm ? /[\\/]+/ : /\/+/;
|
|
74
|
+
let prefix = drive;
|
|
75
|
+
let rest = p.slice(drive.length + (isUnc ? 2 : 0));
|
|
76
|
+
let abs = rest.startsWith("/") || (winForm && rest.startsWith("\\"));
|
|
77
|
+
if (isUnc) {
|
|
78
|
+
const segs = rest.split(splitter).filter((seg) => seg !== "");
|
|
79
|
+
const host = segs.shift() ?? "";
|
|
80
|
+
const share = segs.shift();
|
|
81
|
+
prefix = sep + sep + host + (share === undefined ? "" : sep + share);
|
|
82
|
+
rest = segs.join(sep);
|
|
83
|
+
abs = true;
|
|
84
|
+
}
|
|
85
|
+
const outSegs = [];
|
|
86
|
+
for (const seg of rest.split(splitter)) {
|
|
67
87
|
if (seg === "" || seg === ".")
|
|
68
88
|
continue;
|
|
69
89
|
if (seg === "..") {
|
|
70
|
-
|
|
90
|
+
if (!foldParents) {
|
|
91
|
+
outSegs.push(seg);
|
|
92
|
+
continue;
|
|
93
|
+
}
|
|
94
|
+
if (outSegs.length > 0 && outSegs[outSegs.length - 1] !== "..")
|
|
95
|
+
outSegs.pop();
|
|
96
|
+
else if (!abs)
|
|
97
|
+
outSegs.push("..");
|
|
71
98
|
continue;
|
|
72
99
|
}
|
|
73
|
-
|
|
100
|
+
outSegs.push(seg);
|
|
74
101
|
}
|
|
75
|
-
|
|
102
|
+
if (outSegs.length === 0)
|
|
103
|
+
return abs ? prefix + sep : prefix === "" ? "." : prefix;
|
|
104
|
+
return prefix + (abs ? sep : "") + outSegs.join(sep);
|
|
76
105
|
}
|
|
77
106
|
const BINARY_EXTENSIONS = new Set([
|
|
78
107
|
".exe", ".dll", ".so", ".dylib", ".o", ".a", ".obj", ".lib", ".bin", ".class", ".pyc", ".pyo", ".wasm",
|
|
@@ -229,7 +258,7 @@ function parentDir(abs) {
|
|
|
229
258
|
}
|
|
230
259
|
async function canonicalizeNewPath(env, abs, signal) {
|
|
231
260
|
const sep = nativeSepOf(abs);
|
|
232
|
-
const parts = abs.split(/[\\/]/);
|
|
261
|
+
const parts = isWinFormPath(abs) ? abs.split(/[\\/]/) : abs.split("/");
|
|
233
262
|
const tail = [];
|
|
234
263
|
while (parts.length > 1) {
|
|
235
264
|
const candidate = parts.join(sep) || sep;
|
package/dist/tools/fs/search.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { delimitUntrusted } from "../../core/untrusted-text.js";
|
|
2
|
-
import { hasBinaryExtension } from "./safety.js";
|
|
2
|
+
import { hasBinaryExtension, isAbsolutePathForm } from "./safety.js";
|
|
3
3
|
const WALK_MAX_FILES = 5000;
|
|
4
4
|
const WALK_MAX_DEPTH = 32;
|
|
5
5
|
const GREP_DEFAULT_CAP = 250;
|
|
@@ -51,7 +51,7 @@ export function splitGlobParam(glob) {
|
|
|
51
51
|
return out;
|
|
52
52
|
}
|
|
53
53
|
export function splitAbsoluteGlobPattern(pattern) {
|
|
54
|
-
if (!(pattern
|
|
54
|
+
if (!isAbsolutePathForm(pattern))
|
|
55
55
|
return undefined;
|
|
56
56
|
const m = /[*?[{]/.exec(pattern);
|
|
57
57
|
if (!m) {
|
|
@@ -758,7 +758,7 @@ export async function jsGrep(env, root, p, signal, guards) {
|
|
|
758
758
|
}
|
|
759
759
|
const ignore = await buildIgnore(env, root, signal);
|
|
760
760
|
const rootPrefix = root.replace(/[\\/]+$/, "") + (root.includes("\\") ? "\\" : "/");
|
|
761
|
-
const start = p.path ? (
|
|
761
|
+
const start = p.path ? (isAbsolutePathForm(p.path) ? p.path : `${rootPrefix}${p.path}`) : root;
|
|
762
762
|
let walked;
|
|
763
763
|
if (p.path) {
|
|
764
764
|
const info = await env.fileInfo(start, signal);
|
|
@@ -992,7 +992,7 @@ async function sortRgFilesByMtime(env, root, stdout, signal) {
|
|
|
992
992
|
const rootPrefix = root.replace(/[\\/]+$/, "") + (root.includes("\\") ? "\\" : "/");
|
|
993
993
|
const toAbs = (p) => {
|
|
994
994
|
const stripped = p.startsWith("./") ? p.slice(2) : p;
|
|
995
|
-
return
|
|
995
|
+
return isAbsolutePathForm(stripped) ? stripped : `${rootPrefix}${stripped}`;
|
|
996
996
|
};
|
|
997
997
|
const infos = await Promise.all(paths.map((p) => env.fileInfo(toAbs(p), signal)));
|
|
998
998
|
const withMtime = paths.map((p, i) => {
|
|
@@ -1104,7 +1104,7 @@ export async function runGlobDetailed(env, root, pattern, opts = {}, signal) {
|
|
|
1104
1104
|
const t0 = Date.now();
|
|
1105
1105
|
const baseIgnore = await buildIgnore(env, root, signal);
|
|
1106
1106
|
const rootPrefix = root.replace(/[\\/]+$/, "") + (root.includes("\\") ? "\\" : "/");
|
|
1107
|
-
const start = opts.path ? (
|
|
1107
|
+
const start = opts.path ? (isAbsolutePathForm(opts.path) ? opts.path : `${rootPrefix}${opts.path}`) : root;
|
|
1108
1108
|
if (opts.path !== undefined) {
|
|
1109
1109
|
const probe = await env.fileInfo(start, signal);
|
|
1110
1110
|
if (!probe.ok && probe.error.code === "not_found") {
|
package/dist/tools/monitor.d.ts
CHANGED
|
@@ -17,5 +17,6 @@ export interface MonitorToolOptions {
|
|
|
17
17
|
batchWindowMs?: number;
|
|
18
18
|
maxBatchesPerMinute?: number;
|
|
19
19
|
toolResultStore?: ToolResultStore;
|
|
20
|
+
retainBackgroundProcesses?: boolean;
|
|
20
21
|
}
|
|
21
22
|
export declare function createMonitorTool(env: ExecutionEnv, opts: MonitorToolOptions): AgentTool;
|
package/dist/tools/monitor.js
CHANGED
|
@@ -124,14 +124,16 @@ export function createMonitorTool(env, opts) {
|
|
|
124
124
|
? `the execution environment kills background processes after ${bgTimeout}s`
|
|
125
125
|
: `the execution environment's background time budget still applies`;
|
|
126
126
|
const retainedByEnv = env.backgroundCapabilities.retainBackgroundProcesses === true;
|
|
127
|
+
const retainedBySpec = opts.retainBackgroundProcesses === true;
|
|
128
|
+
const retained = retainedByEnv || retainedBySpec;
|
|
127
129
|
const persistentAnchor = sessionScoped
|
|
128
|
-
?
|
|
129
|
-
? ". This environment
|
|
130
|
+
? retained
|
|
131
|
+
? ". This run retains background processes (environment capability or task spec), so at the run teardown the watch is marked retained and " +
|
|
130
132
|
"survives the session's release: only your TaskStop, the command's own exit, or that budget end it."
|
|
131
133
|
: "; it runs until then, until you stop it, or until the session ends."
|
|
132
|
-
:
|
|
134
|
+
: retained
|
|
133
135
|
? ". This mount carries no session identity, so the watch is NOT session-resident despite persistent: true; and because this " +
|
|
134
|
-
"
|
|
136
|
+
"run retains background processes (environment capability or task spec) it survives the session's release rather than being settled with the run — " +
|
|
135
137
|
"nothing but your TaskStop, the command's own exit, or that budget will end it, and no later turn can reach it " +
|
|
136
138
|
"(stop it explicitly with TaskStop before you finish)."
|
|
137
139
|
: ". This mount carries no session identity, so the watch is NOT session-resident despite persistent: true — " +
|
|
@@ -158,7 +160,7 @@ export function createMonitorTool(env, opts) {
|
|
|
158
160
|
...(envWallWins && envWallMs !== undefined ? { effectiveTimeoutMs: envWallMs } : {}),
|
|
159
161
|
...(isPersistent
|
|
160
162
|
?
|
|
161
|
-
{ timeoutIgnored: timeout_ms !== undefined, sessionScoped, ...(retainedByEnv ? { retainedByEnv: true } : {}) }
|
|
163
|
+
{ timeoutIgnored: timeout_ms !== undefined, sessionScoped, ...(retainedByEnv ? { retainedByEnv: true } : {}), ...(retainedBySpec ? { retainedBySpec: true } : {}) }
|
|
162
164
|
: { timeoutMs, ...(timeout_ms !== undefined ? { requestedTimeoutMs: timeout_ms } : {}), wasClamped }),
|
|
163
165
|
},
|
|
164
166
|
};
|
package/dist/tools/worktree.d.ts
CHANGED
|
@@ -1,11 +1,6 @@
|
|
|
1
|
-
import type { AgentTool, ExecutionEnv } from "../internal/harness-types.js";
|
|
1
|
+
import type { ActiveWorktreeSession, AgentTool, ExecutionEnv } from "../internal/harness-types.js";
|
|
2
2
|
import type { CwdRef } from "./fs/index.js";
|
|
3
|
-
export
|
|
4
|
-
worktreeDir: string;
|
|
5
|
-
originalCwd: string;
|
|
6
|
-
baseSha: string;
|
|
7
|
-
entered?: boolean;
|
|
8
|
-
}
|
|
3
|
+
export type { ActiveWorktreeSession };
|
|
9
4
|
export interface WorktreeSessionRef {
|
|
10
5
|
current?: ActiveWorktreeSession;
|
|
11
6
|
exiting?: boolean;
|
package/dist/tools/worktree.js
CHANGED
|
@@ -174,7 +174,9 @@ export function createWorktreeTools(env, opts) {
|
|
|
174
174
|
if (target === registered[0]) {
|
|
175
175
|
return errorResult(`Error (EnterWorktree): ${target} is the main working tree, not a linked worktree — nothing to enter.`);
|
|
176
176
|
}
|
|
177
|
-
|
|
177
|
+
const rootCanon = await env.canonicalPath(repoRoot);
|
|
178
|
+
const fence = rootCanon.ok ? rootCanon.value : repoRoot;
|
|
179
|
+
if (target !== fence && !target.startsWith(fence.endsWith("/") ? fence : `${fence}/`)) {
|
|
178
180
|
return errorResult(`Error (EnterWorktree): the worktree ${target} lives outside the task root ${repoRoot}; ` +
|
|
179
181
|
"file containment stays anchored at the task root, so it cannot be entered from this session.");
|
|
180
182
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sema-agent/core",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "4.0.0",
|
|
4
4
|
"description": "Stateless, task-oriented AI agent core",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "BUSL-1.1",
|
|
@@ -41,6 +41,7 @@
|
|
|
41
41
|
"dist",
|
|
42
42
|
"README.md",
|
|
43
43
|
"NOTICE.md",
|
|
44
|
+
"CHANGELOG.md",
|
|
44
45
|
"LICENSE"
|
|
45
46
|
],
|
|
46
47
|
"engines": {
|
|
@@ -60,7 +61,10 @@
|
|
|
60
61
|
"gate:blackbox": "node scripts/run-blackbox-gate.mjs",
|
|
61
62
|
"gate:ledger": "node scripts/verify-hardening-ledger.mjs",
|
|
62
63
|
"gate:compensation": "node scripts/verify-compensation-registry.mjs",
|
|
63
|
-
"gate:message-branching": "node scripts/verify-no-message-branching.mjs"
|
|
64
|
+
"gate:message-branching": "node scripts/verify-no-message-branching.mjs",
|
|
65
|
+
"gate:failloud": "node scripts/verify-failloud.mjs",
|
|
66
|
+
"gate:domain-lexicon": "node scripts/verify-domain-lexicon.mjs",
|
|
67
|
+
"gate:single-mint": "node scripts/verify-single-mint.mjs"
|
|
64
68
|
},
|
|
65
69
|
"dependencies": {
|
|
66
70
|
"@modelcontextprotocol/sdk": "1.29.0",
|