@sema-agent/core 5.0.1 → 5.2.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 +67 -0
- package/dist/agents/roster-store.d.ts +9 -2
- package/dist/agents/roster-store.js +32 -6
- package/dist/agents/subagent.js +8 -3
- package/dist/bin/sema-tb.d.ts +1 -2
- package/dist/bin/sema-tb.js +14 -27
- package/dist/brain/anthropic.js +2 -3
- package/dist/brain/degrading.d.ts +2 -8
- package/dist/brain/degrading.js +3 -3
- package/dist/brain/openai.js +3 -5
- package/dist/brain/terminal-cause.d.ts +1 -1
- package/dist/brain/terminal-cause.js +2 -8
- package/dist/core/hooks.js +12 -7
- package/dist/core/lsp.js +2 -3
- package/dist/core/mcp.d.ts +1 -1
- package/dist/core/mcp.js +2 -1
- package/dist/core/memory-engine/dual-root.js +2 -1
- package/dist/core/memory-engine/engine.d.ts +4 -0
- package/dist/core/memory-engine/engine.js +25 -6
- package/dist/core/memory-engine/file-backend.d.ts +7 -5
- package/dist/core/memory-engine/file-backend.js +3 -1
- 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 +7 -0
- package/dist/core/memory-engine/layout.js +98 -5
- package/dist/core/memory.d.ts +0 -1
- package/dist/core/memory.js +7 -1
- package/dist/core/permission-rules.js +8 -7
- package/dist/core/protocol-table.d.ts +17 -0
- package/dist/core/protocol-table.js +37 -0
- package/dist/core/runner/active-skill-scope.js +7 -7
- package/dist/core/runner/prepare-memory.js +7 -4
- package/dist/core/runner/prepare-task.js +43 -26
- package/dist/core/runner/runtask.js +18 -6
- package/dist/core/runner/session-rule-policy.js +1 -1
- package/dist/core/runner/synthetic-tools.js +2 -2
- package/dist/core/runner/tool-disclosure.d.ts +0 -1
- package/dist/core/runner/tool-disclosure.js +6 -3
- package/dist/core/runner/turn-attachments.js +2 -1
- package/dist/core/sensitive-path-policy.js +2 -2
- package/dist/core/tool-policy.d.ts +1 -3
- package/dist/core/tool-policy.js +40 -16
- package/dist/index.d.ts +3 -2
- package/dist/index.js +2 -1
- package/dist/orchestration/run-spec.js +1 -1
- package/dist/orchestration/run-workflow-tool.js +7 -3
- package/dist/orchestration/workflow-script-store.d.ts +1 -1
- package/dist/orchestration/workflow-script-store.js +1 -1
- package/dist/prompt-assembly/assemble.js +0 -2
- package/dist/prompt-assembly/tool-catalog.d.ts +2 -1
- package/dist/prompts/default.d.ts +0 -2
- package/dist/prompts/default.js +1 -5
- package/dist/stores/cc/mailbox-store.d.ts +4 -0
- package/dist/stores/cc/mailbox-store.js +67 -9
- package/dist/stores/file/file-snapshot-store.d.ts +9 -1
- package/dist/stores/file/file-snapshot-store.js +28 -5
- package/dist/stores/file/fs-atomic.d.ts +4 -1
- package/dist/stores/file/fs-atomic.js +2 -1
- package/dist/stores/file/index.d.ts +10 -3
- package/dist/stores/file/index.js +4 -3
- package/dist/stores/file/mailbox-store.d.ts +5 -0
- package/dist/stores/file/mailbox-store.js +15 -3
- package/dist/stores/file/session-policy-store.d.ts +13 -1
- package/dist/stores/file/session-policy-store.js +39 -6
- package/dist/stores/file/session-store.d.ts +9 -1
- package/dist/stores/file/session-store.js +19 -4
- package/dist/tools/fs/fs-search-tools.js +10 -2
- package/dist/tools/fs/fs-shared.d.ts +1 -2
- package/dist/tools/fs/fs-shared.js +1 -2
- package/dist/tools/todo.js +14 -7
- package/package.json +1 -1
|
@@ -54,12 +54,21 @@ class FileSessionStorage extends BaseSessionStorage {
|
|
|
54
54
|
export class FileSessionRepo {
|
|
55
55
|
dir;
|
|
56
56
|
tmpDir;
|
|
57
|
+
onCorruptRead;
|
|
57
58
|
joined = new Map();
|
|
58
|
-
constructor(root) {
|
|
59
|
+
constructor(root, opts) {
|
|
59
60
|
this.dir = join(root, "sessions");
|
|
60
61
|
this.tmpDir = join(root, "tmp");
|
|
61
62
|
ensureDir(this.dir);
|
|
62
63
|
ensureDir(this.tmpDir);
|
|
64
|
+
this.onCorruptRead = opts?.onCorruptRead;
|
|
65
|
+
}
|
|
66
|
+
disclose(path, reason) {
|
|
67
|
+
try {
|
|
68
|
+
this.onCorruptRead?.({ path, reason });
|
|
69
|
+
}
|
|
70
|
+
catch {
|
|
71
|
+
}
|
|
63
72
|
}
|
|
64
73
|
pathFor(id) {
|
|
65
74
|
return join(this.dir, `${sanitizePathComponent(id)}${SUFFIX}`);
|
|
@@ -69,7 +78,7 @@ export class FileSessionRepo {
|
|
|
69
78
|
if (!existsSync(path)) {
|
|
70
79
|
throw new SessionError("not_found", `Session not found: ${id}`);
|
|
71
80
|
}
|
|
72
|
-
const lines = readJsonlRecords(path);
|
|
81
|
+
const lines = readJsonlRecords(path, (info) => this.disclose(info.path, info.reason));
|
|
73
82
|
let createdAt = "";
|
|
74
83
|
let forkedFrom;
|
|
75
84
|
const entries = [];
|
|
@@ -132,7 +141,10 @@ export class FileSessionRepo {
|
|
|
132
141
|
try {
|
|
133
142
|
names = readdirSync(this.dir);
|
|
134
143
|
}
|
|
135
|
-
catch {
|
|
144
|
+
catch (err) {
|
|
145
|
+
if (err.code !== "ENOENT") {
|
|
146
|
+
this.disclose(this.dir, `session directory unreadable (${err.code ?? "unknown"}) — listed as empty`);
|
|
147
|
+
}
|
|
136
148
|
return [];
|
|
137
149
|
}
|
|
138
150
|
const out = [];
|
|
@@ -144,7 +156,10 @@ export class FileSessionRepo {
|
|
|
144
156
|
const { createdAt, forkedFrom } = this.read(id);
|
|
145
157
|
out.push({ id, createdAt, ...(forkedFrom !== undefined ? { forkedFrom } : {}) });
|
|
146
158
|
}
|
|
147
|
-
catch {
|
|
159
|
+
catch (err) {
|
|
160
|
+
if (!(err instanceof SessionError && err.code === "not_found")) {
|
|
161
|
+
this.disclose(this.pathFor(id), `session log unreadable (${err instanceof Error ? err.message : String(err)}) — skipped from the listing`);
|
|
162
|
+
}
|
|
148
163
|
}
|
|
149
164
|
}
|
|
150
165
|
return out.sort((a, b) => a.createdAt.localeCompare(b.createdAt));
|
|
@@ -37,10 +37,18 @@ export function createGrepTool(env, rootCanonical, additionalRoots) {
|
|
|
37
37
|
description: 'Limit output to first N lines/entries, equivalent to "| head -N". Works across all output modes: content (limits output lines), files_with_matches (limits file paths), count (limits count entries). Defaults to 250 when unspecified. Pass 0 for unlimited (use sparingly — large result sets waste context).',
|
|
38
38
|
})),
|
|
39
39
|
offset: Type.Optional(Type.Number({ description: "Skip the first N output lines (pagination partner of head_limit)." })),
|
|
40
|
-
max_results: Type.Optional(Type.Number({ description: "Deprecated alias for head_limit." })),
|
|
41
40
|
}),
|
|
42
41
|
effect: "read",
|
|
43
42
|
execute: async (args, ctx) => {
|
|
43
|
+
const retired = args;
|
|
44
|
+
for (const [name, repair] of [
|
|
45
|
+
["regex", "the `pattern` is ALWAYS evaluated as a regular expression (ripgrep semantics) — drop the key; to match text literally, escape the regex metacharacters in `pattern`"],
|
|
46
|
+
["max_results", "cap the result count with `head_limit` (0 = unlimited), paginating with `offset`"],
|
|
47
|
+
]) {
|
|
48
|
+
if (retired[name] !== undefined) {
|
|
49
|
+
return errorResult(`Error (Grep): \`${name}\` is not a Grep parameter (retired) — ${repair}. Nothing was searched.`);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
44
52
|
const a = args;
|
|
45
53
|
for (const [name, value] of [
|
|
46
54
|
["head_limit", a.head_limit],
|
|
@@ -69,7 +77,7 @@ export function createGrepTool(env, rootCanonical, additionalRoots) {
|
|
|
69
77
|
const grepRun = await runGrepDetailed(env, rootCanonical, {
|
|
70
78
|
...a,
|
|
71
79
|
path: scoped,
|
|
72
|
-
head_limit: a.head_limit
|
|
80
|
+
head_limit: a.head_limit,
|
|
73
81
|
context: a.context ?? a["-C"],
|
|
74
82
|
context_after: a.context_after ?? a["-A"],
|
|
75
83
|
context_before: a.context_before ?? a["-B"],
|
|
@@ -42,8 +42,7 @@ export declare function bashTimeoutCapsSec(caps: {
|
|
|
42
42
|
};
|
|
43
43
|
export declare function bashMaxOutputChars(): number;
|
|
44
44
|
export declare const FILE_PATH_PARAMS: {
|
|
45
|
-
file_path: Type.
|
|
46
|
-
path: Type.TOptional<Type.TString>;
|
|
45
|
+
file_path: Type.TString;
|
|
47
46
|
};
|
|
48
47
|
export declare function clipShellOutput(s: string): string;
|
|
49
48
|
export declare function writeShellOverflowFile(env: ExecutionEnv, stdout: string, stderr: string): Promise<string | undefined>;
|
|
@@ -76,8 +76,7 @@ export function bashMaxOutputChars() {
|
|
|
76
76
|
return Math.min(Math.floor(raw), BASH_MAX_OUTPUT_CHARS_CEILING);
|
|
77
77
|
}
|
|
78
78
|
export const FILE_PATH_PARAMS = {
|
|
79
|
-
file_path: Type.
|
|
80
|
-
path: Type.Optional(Type.String({ description: "Deprecated alias for `file_path` (back-compat; prefer file_path)." })),
|
|
79
|
+
file_path: Type.String({ description: "File path (within the configured root)." }),
|
|
81
80
|
};
|
|
82
81
|
export function clipShellOutput(s) {
|
|
83
82
|
return clipWithFilePointer(s, bashMaxOutputChars());
|
package/dist/tools/todo.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { Type } from "typebox";
|
|
2
|
+
import { errorResult } from "../core/tools.js";
|
|
2
3
|
export function createTodoWriteTool() {
|
|
3
4
|
let todos = [];
|
|
4
5
|
return {
|
|
@@ -6,7 +7,7 @@ export function createTodoWriteTool() {
|
|
|
6
7
|
contract: { contractId: "core.todo_write@1", implementationRevision: "1" },
|
|
7
8
|
description: "Create and update a task list for the current session. The list is rendered to the user as your working plan.\n" +
|
|
8
9
|
"\n" +
|
|
9
|
-
'- Each todo has `content`, `status` ("pending" | "in_progress" | "completed"), and
|
|
10
|
+
'- Each todo has `content`, `status` ("pending" | "in_progress" | "completed"), and `activeForm` (present-tense label shown while in progress).\n' +
|
|
10
11
|
"- Send the full list each call; it replaces the previous one.\n" +
|
|
11
12
|
"- Keep one item `in_progress` at a time and mark it `completed` when done.",
|
|
12
13
|
descriptionClassic: "Use this tool to create and manage a structured task list for your current coding session. This helps you track progress, organize complex tasks, and demonstrate thoroughness to the user.\n" +
|
|
@@ -76,18 +77,24 @@ export function createTodoWriteTool() {
|
|
|
76
77
|
todos: Type.Array(Type.Object({
|
|
77
78
|
content: Type.String({ description: "The task, in imperative form (e.g. \"Run the tests\")." }),
|
|
78
79
|
status: Type.Union([Type.Literal("pending"), Type.Literal("in_progress"), Type.Literal("completed")]),
|
|
79
|
-
activeForm: Type.
|
|
80
|
+
activeForm: Type.String({ minLength: 1, description: "Present-continuous form shown while in progress (e.g. \"Running the tests\")." }),
|
|
80
81
|
})),
|
|
81
82
|
}),
|
|
82
83
|
effect: "idempotent",
|
|
83
84
|
execute: (args) => {
|
|
84
|
-
const shape = (t) => ({
|
|
85
|
-
content: t.content,
|
|
86
|
-
status: t.status,
|
|
87
|
-
activeForm: t.activeForm && t.activeForm.length > 0 ? t.activeForm : t.content,
|
|
88
|
-
});
|
|
85
|
+
const shape = (t) => ({ content: t.content, status: t.status, activeForm: t.activeForm });
|
|
89
86
|
const oldTodos = todos.map(shape);
|
|
90
87
|
const written = args.todos;
|
|
88
|
+
for (let i = 0; i < written.length; i++) {
|
|
89
|
+
const activeForm = written[i].activeForm;
|
|
90
|
+
if (typeof activeForm !== "string" || activeForm.length === 0) {
|
|
91
|
+
const what = activeForm === undefined ? "is missing" : "has an empty or non-string";
|
|
92
|
+
return errorResult(`Error (TodoWrite): todo ${i + 1} of ${written.length} ${what} \`activeForm\` — every todo needs the ` +
|
|
93
|
+
`present-continuous label shown while it runs (e.g. content "Run the tests" → activeForm "Running the ` +
|
|
94
|
+
`tests"), alongside its imperative \`content\`. Nothing was stored; resend the COMPLETE list with the ` +
|
|
95
|
+
`label filled in on every item.`);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
91
98
|
const allDone = written.every((t) => t.status === "completed");
|
|
92
99
|
todos = allDone ? [] : written;
|
|
93
100
|
const newTodos = written.map(shape);
|