@sema-agent/core 7.6.3 → 7.8.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 +70 -10
- package/dist/agents/agent-transcript-tool.js +2 -2
- package/dist/agents/list-agents-tool.js +2 -3
- package/dist/agents/observer.js +2 -2
- package/dist/agents/peer-admission.d.ts +1 -1
- package/dist/agents/send-message-tool.js +2 -1
- package/dist/agents/subagent-steps.js +5 -4
- package/dist/agents/subagent.js +2 -3
- package/dist/brain/anthropic.js +8 -2
- package/dist/brain/open-responses.js +5 -3
- package/dist/brain/openai.js +31 -8
- package/dist/brain/reasoning.d.ts +32 -0
- package/dist/brain/reasoning.js +18 -0
- package/dist/core/ask-question.js +2 -2
- package/dist/core/auto-mode-defaults.d.ts +16 -0
- package/dist/core/auto-mode-defaults.js +1 -0
- package/dist/core/auto-mode.d.ts +19 -0
- package/dist/core/auto-mode.js +74 -56
- package/dist/core/checkpoint-execution-record.d.ts +110 -0
- package/dist/core/checkpoint-execution-record.js +49 -0
- package/dist/core/checkpoint-store.d.ts +114 -2
- package/dist/core/checkpoint-store.js +35 -2
- package/dist/core/context-edit.d.ts +0 -22
- package/dist/core/context-edit.js +2 -11
- package/dist/core/engine-notice.d.ts +17 -0
- package/dist/core/fs-write-gate-policy.d.ts +7 -1
- package/dist/core/fs-write-gate-policy.js +7 -7
- package/dist/core/gate-fold.js +2 -2
- package/dist/core/gate-lanes.js +4 -3
- package/dist/core/governance-codes.d.ts +1 -1
- package/dist/core/governance-codes.js +8 -0
- package/dist/core/hooks.d.ts +8 -2
- package/dist/core/hooks.js +1 -1
- package/dist/core/lsp.js +2 -2
- package/dist/core/mcp-server-spec.d.ts +17 -0
- package/dist/core/mcp.js +3 -1
- package/dist/core/memory-engine/tools.js +4 -12
- package/dist/core/permission-rules.d.ts +32 -2
- package/dist/core/permission-rules.js +43 -37
- package/dist/core/present-plan-tool.js +3 -4
- package/dist/core/runner/active-skill-scope.js +7 -4
- package/dist/core/runner/clock-and-limits.d.ts +117 -0
- package/dist/core/runner/clock-and-limits.js +118 -0
- package/dist/core/runner/compaction-call-options.d.ts +1 -1
- package/dist/core/runner/contracts.d.ts +37 -3
- package/dist/core/runner/decide-continuation.d.ts +98 -0
- package/dist/core/runner/decide-continuation.js +133 -0
- package/dist/core/runner/execution-record.d.ts +26 -0
- package/dist/core/runner/execution-record.js +19 -0
- package/dist/core/runner/git-leg-delivery.d.ts +28 -0
- package/dist/core/runner/git-leg-delivery.js +94 -0
- package/dist/core/runner/initial-run-state.d.ts +14 -0
- package/dist/core/runner/initial-run-state.js +11 -0
- package/dist/core/runner/prepare-ask-lane.d.ts +1 -1
- package/dist/core/runner/prepare-caps-and-workflow.d.ts +5 -4
- package/dist/core/runner/prepare-caps-and-workflow.js +33 -11
- package/dist/core/runner/prepare-defer-classify.d.ts +5 -26
- package/dist/core/runner/prepare-defer-classify.js +10 -10
- package/dist/core/runner/prepare-delegation-surface.d.ts +5 -4
- package/dist/core/runner/prepare-delegation-surface.js +15 -17
- package/dist/core/runner/prepare-gate-stations.d.ts +4 -1
- package/dist/core/runner/prepare-gate-stations.js +3 -1
- package/dist/core/runner/prepare-hands-readface.d.ts +3 -2
- package/dist/core/runner/prepare-hands-readface.js +3 -2
- package/dist/core/runner/prepare-inherited-gate.d.ts +1 -1
- package/dist/core/runner/prepare-inherited-gate.js +1 -0
- package/dist/core/runner/prepare-lsp.d.ts +4 -3
- package/dist/core/runner/prepare-lsp.js +3 -2
- package/dist/core/runner/prepare-memory-engine-session.d.ts +4 -4
- package/dist/core/runner/prepare-memory-engine-session.js +4 -2
- package/dist/core/runner/prepare-offload-wrappers.js +7 -5
- package/dist/core/runner/prepare-park-ask.d.ts +4 -0
- package/dist/core/runner/prepare-park-ask.js +4 -1
- package/dist/core/runner/prepare-project-context.d.ts +5 -23
- package/dist/core/runner/prepare-project-context.js +7 -5
- package/dist/core/runner/prepare-prompt-assembly.d.ts +1 -1
- package/dist/core/runner/prepare-protocol-tools.d.ts +5 -1
- package/dist/core/runner/prepare-protocol-tools.js +38 -21
- package/dist/core/runner/prepare-question-face.d.ts +4 -3
- package/dist/core/runner/prepare-question-face.js +5 -3
- package/dist/core/runner/prepare-safety-scan.js +42 -2
- package/dist/core/runner/prepare-task.js +37 -19
- package/dist/core/runner/prepare-tool-disclosure-mount.d.ts +5 -2
- package/dist/core/runner/prepare-tool-disclosure-mount.js +3 -1
- package/dist/core/runner/prepare-wiring-manifest.d.ts +4 -0
- package/dist/core/runner/prepare-wiring-manifest.js +3 -8
- package/dist/core/runner/run-harness-handlers.d.ts +46 -0
- package/dist/core/runner/run-harness-handlers.js +345 -0
- package/dist/core/runner/run-turn-boundary.d.ts +69 -0
- package/dist/core/runner/run-turn-boundary.js +694 -0
- package/dist/core/runner/runtask.d.ts +0 -68
- package/dist/core/runner/runtask.js +66 -1486
- package/dist/core/runner/session-rule-policy.js +9 -4
- package/dist/core/runner/steer-admission.d.ts +17 -0
- package/dist/core/runner/steer-admission.js +17 -0
- package/dist/core/runner/synthetic-tools.js +5 -8
- package/dist/core/runner/tool-disclosure.d.ts +4 -0
- package/dist/core/runner/tool-disclosure.js +9 -5
- package/dist/core/runner/tool-end-body.d.ts +71 -0
- package/dist/core/runner/tool-end-body.js +75 -0
- package/dist/core/runner/tool-face-overlay.d.ts +40 -0
- package/dist/core/runner/tool-face-overlay.js +125 -0
- package/dist/core/runner/tool-output-projection.d.ts +10 -0
- package/dist/core/runner/tool-output-projection.js +33 -10
- package/dist/core/sensitive-path-policy.d.ts +3 -0
- package/dist/core/sensitive-path-policy.js +6 -5
- package/dist/core/shared-memory/tools.js +3 -6
- package/dist/core/store-contracts/checkpoint-store-contract.d.ts +4 -0
- package/dist/core/store-contracts/checkpoint-store-contract.js +108 -0
- package/dist/core/task-event.d.ts +10 -0
- package/dist/core/task-registry.js +4 -5
- package/dist/core/task-spec.d.ts +8 -0
- package/dist/core/tool-catalog-entries.d.ts +48 -0
- package/dist/core/tool-catalog-entries.js +174 -0
- package/dist/core/tool-conformance.d.ts +22 -0
- package/dist/core/tool-conformance.js +37 -0
- package/dist/core/tool-face.d.ts +171 -0
- package/dist/core/tool-face.js +25 -0
- package/dist/core/tool-policy.d.ts +24 -0
- package/dist/core/tool-policy.js +4 -2
- package/dist/core/tool-registry.d.ts +114 -0
- package/dist/core/tool-registry.js +114 -0
- package/dist/core/tool-result-budget.d.ts +0 -3
- package/dist/core/tool-result-budget.js +4 -3
- package/dist/core/tool-result-store.d.ts +0 -18
- package/dist/core/tool-result-store.js +2 -18
- package/dist/core/tool-roster.d.ts +450 -0
- package/dist/core/tool-roster.js +497 -0
- package/dist/core/tool-spec.d.ts +54 -3
- package/dist/core/tools.js +7 -0
- package/dist/core/trace.d.ts +24 -0
- package/dist/core/wiring-manifest.d.ts +13 -0
- package/dist/core/wiring-manifest.js +2 -1
- package/dist/core/write-protect.d.ts +2 -1
- package/dist/core/write-protect.js +5 -4
- package/dist/engine/compaction/utils.d.ts +6 -0
- package/dist/engine/compaction/utils.js +19 -19
- package/dist/engine/loop/types.d.ts +6 -0
- package/dist/index.d.ts +20 -8
- package/dist/index.js +19 -7
- package/dist/orchestration/goal.js +2 -1
- package/dist/orchestration/run-spec.js +3 -5
- package/dist/orchestration/run-workflow-tool.js +2 -2
- package/dist/prompt-assembly/event-registry.js +3 -3
- package/dist/prompt-assembly/tool-catalog.d.ts +2 -2
- package/dist/stores/file/checkpoint-store.d.ts +7 -0
- package/dist/stores/file/checkpoint-store.js +20 -1
- package/dist/tools/fs/fs-bash.d.ts +1 -1
- package/dist/tools/fs/fs-bash.js +7 -11
- package/dist/tools/fs/fs-read.js +2 -2
- package/dist/tools/fs/fs-search-tools.d.ts +0 -7
- package/dist/tools/fs/fs-search-tools.js +3 -16
- package/dist/tools/fs/fs-write.js +4 -6
- package/dist/tools/fs/repo-map.js +2 -2
- package/dist/tools/fs/safety.d.ts +2 -1
- package/dist/tools/fs/safety.js +6 -5
- package/dist/tools/monitor.js +2 -2
- package/dist/tools/scheduler-tools.js +5 -8
- package/dist/tools/task-list.js +5 -8
- package/dist/tools/todo.js +2 -2
- package/dist/tools/web.js +3 -6
- package/dist/tools/worktree.js +3 -4
- package/package.json +4 -1
- package/test/export-surface.snapshot.json +183 -7
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import type { AgentTool, ExecutionEnv } from "../../internal/harness-types.js";
|
|
2
|
-
import type { ToolEffect } from "../../core/types.js";
|
|
3
2
|
import type { ReadDenyMatcher } from "./read-deny.js";
|
|
4
3
|
import type { ReadFace } from "./read-face.js";
|
|
5
4
|
/**
|
|
@@ -13,9 +12,3 @@ import type { ReadFace } from "./read-face.js";
|
|
|
13
12
|
export declare function grepDetailFields(text: string, mode: "files_with_matches" | "content" | "count", offset?: number, structuredRows?: readonly import("./search.js").GrepRow[]): Record<string, unknown>;
|
|
14
13
|
export declare function createGrepTool(env: ExecutionEnv, rootCanonical: string, additionalRoots?: readonly string[], readDeny?: ReadDenyMatcher, readFace?: ReadFace): AgentTool;
|
|
15
14
|
export declare function createGlobTool(env: ExecutionEnv, rootCanonical: string, additionalRoots?: readonly string[], readDeny?: ReadDenyMatcher, readFace?: ReadFace): AgentTool;
|
|
16
|
-
/** Static side-effect class of every hand tool, by name (design/44 §3). Used by prepare-task to (a) feed
|
|
17
|
-
* wake/resume reconciliation and (b) drive the verifier read-only boundary. Every mutating hand tool is
|
|
18
|
-
* `write` (RB-264 ⑥W1 folded `Write` back in — see below); `bash` is `write` (a command can do anything);
|
|
19
|
-
* `bash_readonly` is `read` (so it survives the verifier boundary — but still goes through the policy
|
|
20
|
-
* gate, council #7: effect:read is a redo-safety class, never a policy circumvention). */
|
|
21
|
-
export declare const HAND_TOOL_EFFECTS: Readonly<Record<string, ToolEffect>>;
|
|
@@ -2,6 +2,7 @@ import { Type } from "typebox";
|
|
|
2
2
|
import { defineTool, errorResult } from "../../core/tools.js";
|
|
3
3
|
import { resolveKey, violationText, violationDetails } from "./safety.js";
|
|
4
4
|
import { runGrepDetailed, runGlobDetailed, splitAbsoluteGlobPattern, invalidGlobTokens } from "./search.js";
|
|
5
|
+
import { toolFace } from "../../core/tool-catalog-entries.js";
|
|
5
6
|
export function grepDetailFields(text, mode, offset, structuredRows) {
|
|
6
7
|
const structuredIdentityComplete = structuredRows !== undefined && structuredRows.every((r) => r.path !== undefined || r.text === "--");
|
|
7
8
|
const structuredPaths = structuredIdentityComplete && structuredRows !== undefined ? [...new Set(structuredRows.filter((r) => r.path !== undefined).map((r) => r.path))] : undefined;
|
|
@@ -74,7 +75,7 @@ export function grepDetailFields(text, mode, offset, structuredRows) {
|
|
|
74
75
|
export function createGrepTool(env, rootCanonical, additionalRoots, readDeny, readFace) {
|
|
75
76
|
return defineTool({
|
|
76
77
|
name: "Grep",
|
|
77
|
-
|
|
78
|
+
...toolFace("grep"),
|
|
78
79
|
description: "Content search built on ripgrep. Prefer this over `grep`/`rg` via Bash — results integrate with the permission UI and file links.\n" +
|
|
79
80
|
"\n" +
|
|
80
81
|
'- Full regex syntax (e.g. "log.*Error", "function\\s+\\w+"). Ripgrep, not grep — escape literal braces (`interface\\{\\}`).\n' +
|
|
@@ -107,7 +108,6 @@ export function createGrepTool(env, rootCanonical, additionalRoots, readDeny, re
|
|
|
107
108
|
})),
|
|
108
109
|
offset: Type.Optional(Type.Number({ description: "Skip the first N output lines (pagination partner of head_limit)." })),
|
|
109
110
|
}),
|
|
110
|
-
effect: "read",
|
|
111
111
|
execute: async (args, ctx) => {
|
|
112
112
|
const retired = args;
|
|
113
113
|
for (const [name, repair] of [
|
|
@@ -175,7 +175,7 @@ export function createGrepTool(env, rootCanonical, additionalRoots, readDeny, re
|
|
|
175
175
|
export function createGlobTool(env, rootCanonical, additionalRoots, readDeny, readFace) {
|
|
176
176
|
return defineTool({
|
|
177
177
|
name: "Glob",
|
|
178
|
-
|
|
178
|
+
...toolFace("glob"),
|
|
179
179
|
description: 'Fast file pattern matching. Supports glob patterns like "**/*.js" or "src/**/*.ts". Returns matching file paths sorted by modification time.\n' +
|
|
180
180
|
"\n" +
|
|
181
181
|
"- On environments that do not report modification times, results fall back to alphabetical order\n" +
|
|
@@ -194,7 +194,6 @@ export function createGlobTool(env, rootCanonical, additionalRoots, readDeny, re
|
|
|
194
194
|
})),
|
|
195
195
|
max_results: Type.Optional(Type.Number({ description: "Cap results (default 500)." })),
|
|
196
196
|
}),
|
|
197
|
-
effect: "read",
|
|
198
197
|
execute: async (args, ctx) => {
|
|
199
198
|
let { pattern, path } = args;
|
|
200
199
|
const { max_results } = args;
|
|
@@ -222,15 +221,3 @@ export function createGlobTool(env, rootCanonical, additionalRoots, readDeny, re
|
|
|
222
221
|
},
|
|
223
222
|
});
|
|
224
223
|
}
|
|
225
|
-
export const HAND_TOOL_EFFECTS = {
|
|
226
|
-
Read: "read",
|
|
227
|
-
Edit: "write",
|
|
228
|
-
Write: "write",
|
|
229
|
-
NotebookEdit: "write",
|
|
230
|
-
Grep: "read",
|
|
231
|
-
Glob: "read",
|
|
232
|
-
RepoMap: "read",
|
|
233
|
-
Bash: "write",
|
|
234
|
-
TaskOutput: "read",
|
|
235
|
-
TaskStop: "write",
|
|
236
|
-
};
|
|
@@ -4,6 +4,7 @@ import { defineTool, errorResult } from "../../core/tools.js";
|
|
|
4
4
|
import { sha256, resolveKey, violationText, violationDetails, requireRead, checkStale, checkEditMatch, checkNoChange, fileArgPath, resolveQuoteMatch, adaptNewStringQuotes, resolveEscapeMatch, adaptNewStringEscapes, escapeMatchWasAttempted, ESCAPE_MATCH_MISS_NOTE, deletionOldString, countOccurrences, READ_REFUSED_ESCAPE_HINT, } from "./safety.js";
|
|
5
5
|
import { decodeTextBytes, encodeTextForFile, normalizeEditText, normalizeFileText } from "./encoding.js";
|
|
6
6
|
import { MAX_EDIT_BYTES, decodeEditBytes, tooLargeToEditMessage, truncatedUtf16BodyMessage, persistedTextOf, notReadRefusalText, enoentMessage, FILE_STATE_TRAILER, FILE_PATH_PARAMS, ipynbRedirect, countLines, applyRecordedEdit, } from "./fs-shared.js";
|
|
7
|
+
import { toolFace } from "../../core/tool-catalog-entries.js";
|
|
7
8
|
async function envFinalWrite(env, key, content, signal, opts) {
|
|
8
9
|
const fireEdited = () => {
|
|
9
10
|
if (opts?.edited?.hook === undefined)
|
|
@@ -88,7 +89,7 @@ async function gateToolWrite(hook, tool, path, key, content) {
|
|
|
88
89
|
export function createEditFileTool(env, state, rootCanonical, cwdRef, additionalRoots, beforeWrite, trackEdit, onEdited) {
|
|
89
90
|
return defineTool({
|
|
90
91
|
name: "Edit",
|
|
91
|
-
|
|
92
|
+
...toolFace("edit"),
|
|
92
93
|
description: "Performs exact string replacement in a file.\n" +
|
|
93
94
|
"\n" +
|
|
94
95
|
"- You must Read the file in this conversation before editing, or the call will fail.\n" +
|
|
@@ -101,7 +102,6 @@ export function createEditFileTool(env, state, rootCanonical, cwdRef, additional
|
|
|
101
102
|
new_string: Type.Optional(Type.String({ description: "The text to replace it with (must be different from old_string)" })),
|
|
102
103
|
replace_all: Type.Optional(Type.Boolean({ description: "Replace all occurrences of old_string (default false)" })),
|
|
103
104
|
}),
|
|
104
|
-
effect: "write",
|
|
105
105
|
validateInput: async (args, ctx) => {
|
|
106
106
|
const a = args;
|
|
107
107
|
if (Array.isArray(a.edits) && a.edits.length > 0)
|
|
@@ -327,7 +327,7 @@ export function createEditFileTool(env, state, rootCanonical, cwdRef, additional
|
|
|
327
327
|
export function createWriteFileTool(env, state, rootCanonical, cwdRef, additionalRoots, beforeWrite, trackEdit, onEdited) {
|
|
328
328
|
return defineTool({
|
|
329
329
|
name: "Write",
|
|
330
|
-
|
|
330
|
+
...toolFace("write"),
|
|
331
331
|
description: "Writes a file to the local filesystem, overwriting if one exists.\n" +
|
|
332
332
|
"\n" +
|
|
333
333
|
"When to use: creating a new file, or fully replacing one you've already Read. Overwriting an existing " +
|
|
@@ -337,7 +337,6 @@ export function createWriteFileTool(env, state, rootCanonical, cwdRef, additiona
|
|
|
337
337
|
...FILE_PATH_PARAMS,
|
|
338
338
|
content: Type.String({ description: "The content to write to the file" }),
|
|
339
339
|
}),
|
|
340
|
-
effect: "write",
|
|
341
340
|
validateInput: async (args, ctx) => {
|
|
342
341
|
const path = fileArgPath(args);
|
|
343
342
|
if (path === undefined)
|
|
@@ -427,7 +426,7 @@ const NOTEBOOK_CELL_ID_REQUIRED_MESSAGE = `Error (NotebookEdit): cell_id is requ
|
|
|
427
426
|
export function createNotebookEditTool(env, state, rootCanonical, cwdRef, additionalRoots, beforeWrite, trackEdit, onEdited) {
|
|
428
427
|
return defineTool({
|
|
429
428
|
name: "NotebookEdit",
|
|
430
|
-
|
|
429
|
+
...toolFace("notebook-edit"),
|
|
431
430
|
description: "Replaces, inserts, or deletes a single cell in a Jupyter notebook (.ipynb file).\n" +
|
|
432
431
|
"\n" +
|
|
433
432
|
"Usage:\n" +
|
|
@@ -449,7 +448,6 @@ export function createNotebookEditTool(env, state, rootCanonical, cwdRef, additi
|
|
|
449
448
|
description: "The type of edit to make (replace, insert, delete). Defaults to replace.",
|
|
450
449
|
})),
|
|
451
450
|
}),
|
|
452
|
-
effect: "write",
|
|
453
451
|
validateInput: async (args, ctx) => {
|
|
454
452
|
const a = args;
|
|
455
453
|
const mode = a.edit_mode ?? "replace";
|
|
@@ -2,6 +2,7 @@ import { Type } from "typebox";
|
|
|
2
2
|
import { defineTool, errorResult } from "../../core/tools.js";
|
|
3
3
|
import { resolveKey, violationText, violationDetails } from "./safety.js";
|
|
4
4
|
import { buildIgnore, denyWithheldNote, walk, walkIsPartial } from "./search.js";
|
|
5
|
+
import { toolFace } from "../../core/tool-catalog-entries.js";
|
|
5
6
|
const DEFAULT_MAX_CHARS = 16_000;
|
|
6
7
|
const DEFAULT_MAX_FILES = 400;
|
|
7
8
|
const FILE_SCAN_MAX_BYTES = 256 * 1024;
|
|
@@ -82,7 +83,7 @@ function rankEntries(a, b) {
|
|
|
82
83
|
export function createRepoMapTool(env, rootCanonical, additionalRoots, readDeny, readFace) {
|
|
83
84
|
return defineTool({
|
|
84
85
|
name: "RepoMap",
|
|
85
|
-
|
|
86
|
+
...toolFace("repo-map"),
|
|
86
87
|
description: "Get a compact map of the repository: each source file with its top-level symbols (functions, " +
|
|
87
88
|
"classes, types). Use this FIRST to orient in an unfamiliar codebase before grepping — it shows " +
|
|
88
89
|
"what exists and where, so you can jump to the relevant files. Token-budgeted and honest about " +
|
|
@@ -92,7 +93,6 @@ export function createRepoMapTool(env, rootCanonical, additionalRoots, readDeny,
|
|
|
92
93
|
max_chars: Type.Optional(Type.Number({ description: `Token budget for the rendered map in chars (default ${DEFAULT_MAX_CHARS}; a very small value yields only a truncation note).` })),
|
|
93
94
|
max_files: Type.Optional(Type.Number({ description: `Max files to scan (default ${DEFAULT_MAX_FILES}).` })),
|
|
94
95
|
}),
|
|
95
|
-
effect: "read",
|
|
96
96
|
execute: async (args, ctx) => {
|
|
97
97
|
const a = args;
|
|
98
98
|
const signal = ctx.signal;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { ExecutionEnv } from "../../internal/harness-types.js";
|
|
2
|
+
import { protectivePathTargetOf, type ToolCallLike } from "../../core/tool-registry.js";
|
|
2
3
|
/**
|
|
3
4
|
* batch-B (CC 2.1.187 parity): Read/Edit/Write take the file path as `file_path`. Read the target the same way
|
|
4
5
|
* EVERYWHERE the path is consumed from a tool-call's args — not just the tool body but ALSO every gate that
|
|
@@ -28,7 +29,7 @@ export declare function fileArgPath(args: unknown): string | undefined;
|
|
|
28
29
|
* this module stays dependency-free of the alias table — "NotebookEdit" is the canonical CC name and
|
|
29
30
|
* old→new normalization is identity for it).
|
|
30
31
|
*/
|
|
31
|
-
export declare function writeTargetPath(
|
|
32
|
+
export declare function writeTargetPath(call: ToolCallLike, pt?: ReturnType<typeof protectivePathTargetOf>): string | undefined;
|
|
32
33
|
/**
|
|
33
34
|
* The "hand" file tools (design/44) — safety invariants ported from CC's `FileEditTool` (design/43 Rule
|
|
34
35
|
* 7): without these a weak model blind-edits / overwrites files (P0 safety, not polish). This module is
|
package/dist/tools/fs/safety.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { createHash } from "node:crypto";
|
|
2
2
|
import { sliceHeadSafe } from "../../core/surrogate-safe-slice.js";
|
|
3
|
+
import { pathTargetValue, protectivePathTargetOf } from "../../core/tool-registry.js";
|
|
3
4
|
export function fileArgPath(args) {
|
|
4
5
|
const a = args;
|
|
5
6
|
const fp = a?.file_path;
|
|
@@ -8,12 +9,12 @@ export function fileArgPath(args) {
|
|
|
8
9
|
const p = a?.path;
|
|
9
10
|
return typeof p === "string" && p.length > 0 ? p : undefined;
|
|
10
11
|
}
|
|
11
|
-
export function writeTargetPath(
|
|
12
|
-
|
|
12
|
+
export function writeTargetPath(call, pt = protectivePathTargetOf(call)) {
|
|
13
|
+
if (pt !== undefined)
|
|
14
|
+
return pathTargetValue(call.args, pt);
|
|
15
|
+
const np = call.args?.notebook_path;
|
|
13
16
|
const notebook = typeof np === "string" && np.length > 0 ? np : undefined;
|
|
14
|
-
|
|
15
|
-
return notebook ?? fileArgPath(args);
|
|
16
|
-
return fileArgPath(args) ?? notebook;
|
|
17
|
+
return fileArgPath(call.args) ?? notebook;
|
|
17
18
|
}
|
|
18
19
|
export function sha256(content) {
|
|
19
20
|
return createHash("sha256").update(content, "utf8").digest("hex");
|
package/dist/tools/monitor.js
CHANGED
|
@@ -2,6 +2,7 @@ import { Type } from "typebox";
|
|
|
2
2
|
import { defineTool, errorResult } from "../core/tools.js";
|
|
3
3
|
import { hasBackgroundShell } from "../core/background-shell.js";
|
|
4
4
|
import { MONITOR_DEFAULT_TIMEOUT_MS, MONITOR_MAX_TIMEOUT_MS, } from "../core/task-registry.js";
|
|
5
|
+
import { toolFace } from "../core/tool-catalog-entries.js";
|
|
5
6
|
const MONITOR_DESCRIPTION = "Run a shell command in the background and watch its stdout as a stream of events.\n" +
|
|
6
7
|
"\n" +
|
|
7
8
|
"- Each line the command writes to stdout becomes a notification event delivered to you between turns; " +
|
|
@@ -42,7 +43,7 @@ function envBackgroundWallSec(caps, requestedSec) {
|
|
|
42
43
|
export function createMonitorTool(env, opts) {
|
|
43
44
|
return defineTool({
|
|
44
45
|
name: "Monitor",
|
|
45
|
-
|
|
46
|
+
...toolFace("monitor"),
|
|
46
47
|
description: MONITOR_DESCRIPTION,
|
|
47
48
|
parameters: Type.Object({
|
|
48
49
|
command: Type.String({
|
|
@@ -58,7 +59,6 @@ export function createMonitorTool(env, opts) {
|
|
|
58
59
|
description: "Set to true for a session-resident monitor with no watch timeout of its own (default false). It keeps watching until the execution environment's background time budget expires, until you stop it with TaskStop, or until the session ends.",
|
|
59
60
|
})),
|
|
60
61
|
}),
|
|
61
|
-
effect: "write",
|
|
62
62
|
execute: async (args, ctx) => {
|
|
63
63
|
const { command, description, timeout_ms, persistent } = args;
|
|
64
64
|
if (!hasBackgroundShell(env)) {
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { Type } from "typebox";
|
|
2
2
|
import { defineTool, errorResult } from "../core/tools.js";
|
|
3
3
|
import { hasScheduler, isValidCronExpr, } from "../core/scheduler.js";
|
|
4
|
+
import { toolFace } from "../core/tool-catalog-entries.js";
|
|
4
5
|
export const SCHEDULE_WAKEUP_TOOL_NAME = "ScheduleWakeup";
|
|
5
6
|
export const AUTONOMOUS_LOOP_SENTINEL = "<<autonomous-loop>>";
|
|
6
7
|
export const AUTONOMOUS_LOOP_DYNAMIC_SENTINEL = "<<autonomous-loop-dynamic>>";
|
|
@@ -199,7 +200,7 @@ Every user who asks for "9am" gets \`0 9\`, and every user who asks for "hourly"
|
|
|
199
200
|
Only use minute 0 or 30 when the user names that exact time and clearly means it ("at 9:00 sharp", "at half past", coordinating with a meeting). When in doubt, nudge a few minutes early or late — the user will not notice, and the fleet will.`;
|
|
200
201
|
const cronCreate = defineTool({
|
|
201
202
|
name: "CronCreate",
|
|
202
|
-
|
|
203
|
+
...toolFace("cron-create"),
|
|
203
204
|
description: cronCreateDescription,
|
|
204
205
|
parameters: Type.Object({
|
|
205
206
|
prompt: Type.String({ description: "Self-contained instructions for the future task (it runs unattended)." }),
|
|
@@ -222,7 +223,6 @@ Only use minute 0 or 30 when the user names that exact time and clearly means it
|
|
|
222
223
|
})),
|
|
223
224
|
label: Type.Optional(Type.String({ description: "Short label (also a dedup key with the schedule)." })),
|
|
224
225
|
}),
|
|
225
|
-
effect: "write",
|
|
226
226
|
execute: async (args) => serializedCronCreateOp(async () => {
|
|
227
227
|
const a = args;
|
|
228
228
|
if (a.schedule !== undefined && a.cron !== undefined) {
|
|
@@ -305,10 +305,9 @@ Only use minute 0 or 30 when the user names that exact time and clearly means it
|
|
|
305
305
|
};
|
|
306
306
|
const cronCancel = defineTool({
|
|
307
307
|
name: "CronDelete",
|
|
308
|
-
|
|
308
|
+
...toolFace("cron-delete"),
|
|
309
309
|
description: "Cancel a cron job previously scheduled with CronCreate. Idempotent; ids also appear in CronList.",
|
|
310
310
|
parameters: Type.Object({ id: Type.String({ description: "Job ID returned by CronCreate." }) }),
|
|
311
|
-
effect: "idempotent",
|
|
312
311
|
execute: async (args) => {
|
|
313
312
|
const { id } = args;
|
|
314
313
|
const taskId = id;
|
|
@@ -329,10 +328,9 @@ Only use minute 0 or 30 when the user names that exact time and clearly means it
|
|
|
329
328
|
});
|
|
330
329
|
const cronList = defineTool({
|
|
331
330
|
name: "CronList",
|
|
332
|
-
|
|
331
|
+
...toolFace("cron-list"),
|
|
333
332
|
description: "List all cron jobs scheduled via CronCreate (id, when, label).",
|
|
334
333
|
parameters: Type.Object({}),
|
|
335
|
-
effect: "read",
|
|
336
334
|
execute: async () => {
|
|
337
335
|
const rows = [];
|
|
338
336
|
const seen = new Set();
|
|
@@ -409,7 +407,7 @@ MOUNT NOTE: this host has no resident wakeup leg, so ${SCHEDULE_WAKEUP_TOOL_NAME
|
|
|
409
407
|
MOUNT NOTE: this host does not vouch for session-scoped scheduling, so a wakeup scheduled here is PERSISTENT — contrary to the paragraph above, it can outlive this session instead of ending with it. End the loop explicitly with \`stop: true\` when the work is done; do not rely on the session ending to cancel it.`;
|
|
410
408
|
const scheduleWakeup = defineTool({
|
|
411
409
|
name: SCHEDULE_WAKEUP_TOOL_NAME,
|
|
412
|
-
|
|
410
|
+
...toolFace("schedule-wakeup"),
|
|
413
411
|
description: `${SCHEDULE_WAKEUP_PROMPT}${wakeupMountNote}`,
|
|
414
412
|
parameters: Type.Object({
|
|
415
413
|
delaySeconds: Type.Optional(Type.Number({
|
|
@@ -428,7 +426,6 @@ MOUNT NOTE: this host does not vouch for session-scoped scheduling, so a wakeup
|
|
|
428
426
|
description: "true = nothing changed (you checked and there is nothing to report). false = something happened worth keeping (edited a file, posted a message, advanced state, surfaced a finding). Consecutive noop:true ticks are collapsed in the user's terminal view and tracked as a streak. Required unless `stop` is true.",
|
|
429
427
|
})),
|
|
430
428
|
}),
|
|
431
|
-
effect: "write",
|
|
432
429
|
execute: async (args) => serializedWakeupOp(async () => {
|
|
433
430
|
const a = args;
|
|
434
431
|
if (a.stop === true) {
|
package/dist/tools/task-list.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { Type } from "typebox";
|
|
2
|
+
import { toolFace } from "../core/tool-catalog-entries.js";
|
|
2
3
|
const STATUS = Type.Union([
|
|
3
4
|
Type.Literal("pending"),
|
|
4
5
|
Type.Literal("in_progress"),
|
|
@@ -96,7 +97,7 @@ export function createTaskListTools(store) {
|
|
|
96
97
|
const tasks = store ?? createMemoryTaskListStore();
|
|
97
98
|
const taskCreate = {
|
|
98
99
|
name: "TaskCreate",
|
|
99
|
-
|
|
100
|
+
...toolFace("task-create"),
|
|
100
101
|
description: "Use this tool to create a structured task list for your current session. This helps you track progress, organize complex tasks, and demonstrate thoroughness.\n" +
|
|
101
102
|
"It also helps the user understand the progress of the task and overall progress of their requests.\n" +
|
|
102
103
|
"\n" +
|
|
@@ -144,7 +145,6 @@ export function createTaskListTools(store) {
|
|
|
144
145
|
activeForm: Type.Optional(Type.String({ description: 'Present continuous form shown when in_progress (e.g., "Running tests")' })),
|
|
145
146
|
metadata: Type.Optional(Type.Record(Type.String(), Type.Unknown(), { description: "Arbitrary metadata to attach to the task" })),
|
|
146
147
|
}),
|
|
147
|
-
effect: "write",
|
|
148
148
|
execute: (args) => serialized(tasks, async (tx) => {
|
|
149
149
|
const a = args;
|
|
150
150
|
if (a.metadata)
|
|
@@ -169,7 +169,7 @@ export function createTaskListTools(store) {
|
|
|
169
169
|
};
|
|
170
170
|
const taskGet = {
|
|
171
171
|
name: "TaskGet",
|
|
172
|
-
|
|
172
|
+
...toolFace("task-get"),
|
|
173
173
|
description: "Use this tool to retrieve a task by its ID from the task list.\n" +
|
|
174
174
|
"\n" +
|
|
175
175
|
"## When to Use This Tool\n" +
|
|
@@ -189,7 +189,6 @@ export function createTaskListTools(store) {
|
|
|
189
189
|
parameters: Type.Object({
|
|
190
190
|
taskId: Type.String({ description: "The ID of the task to retrieve" }),
|
|
191
191
|
}),
|
|
192
|
-
effect: "read",
|
|
193
192
|
execute: (args) => serialized(tasks, async (tx) => {
|
|
194
193
|
const id = String(args.taskId);
|
|
195
194
|
const t = await tx.get(id);
|
|
@@ -201,7 +200,7 @@ export function createTaskListTools(store) {
|
|
|
201
200
|
};
|
|
202
201
|
const taskUpdate = {
|
|
203
202
|
name: "TaskUpdate",
|
|
204
|
-
|
|
203
|
+
...toolFace("task-update"),
|
|
205
204
|
description: "Use this tool to update a task in the task list.\n" +
|
|
206
205
|
"\n" +
|
|
207
206
|
"## When to Use This Tool\n" +
|
|
@@ -285,7 +284,6 @@ export function createTaskListTools(store) {
|
|
|
285
284
|
addBlocks: Type.Optional(Type.Array(Type.String(), { description: "Task IDs that this task blocks" })),
|
|
286
285
|
addBlockedBy: Type.Optional(Type.Array(Type.String(), { description: "Task IDs that block this task" })),
|
|
287
286
|
}),
|
|
288
|
-
effect: "idempotent",
|
|
289
287
|
execute: (args) => serialized(tasks, async (tx) => {
|
|
290
288
|
const a = args;
|
|
291
289
|
const id = String(a.taskId);
|
|
@@ -395,7 +393,7 @@ export function createTaskListTools(store) {
|
|
|
395
393
|
};
|
|
396
394
|
const taskList = {
|
|
397
395
|
name: "TaskList",
|
|
398
|
-
|
|
396
|
+
...toolFace("task-list"),
|
|
399
397
|
description: "Use this tool to list all tasks in the task list.\n" +
|
|
400
398
|
"\n" +
|
|
401
399
|
"## When to Use This Tool\n" +
|
|
@@ -420,7 +418,6 @@ export function createTaskListTools(store) {
|
|
|
420
418
|
"\n" +
|
|
421
419
|
"Use TaskGet with a specific task ID to view full details including description and metadata.",
|
|
422
420
|
parameters: Type.Object({}),
|
|
423
|
-
effect: "read",
|
|
424
421
|
execute: () => serialized(tasks, async (tx) => {
|
|
425
422
|
const all = await tx.list();
|
|
426
423
|
if (all.length === 0) {
|
package/dist/tools/todo.js
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import { Type } from "typebox";
|
|
2
2
|
import { errorResult } from "../core/tools.js";
|
|
3
|
+
import { toolFace } from "../core/tool-catalog-entries.js";
|
|
3
4
|
export function createTodoWriteTool() {
|
|
4
5
|
let todos = [];
|
|
5
6
|
return {
|
|
6
7
|
name: "TodoWrite",
|
|
7
|
-
|
|
8
|
+
...toolFace("todo-write"),
|
|
8
9
|
description: "Create and update a task list for the current session. The list is rendered to the user as your working plan.\n" +
|
|
9
10
|
"\n" +
|
|
10
11
|
'- Each todo has `content`, `status` ("pending" | "in_progress" | "completed"), and `activeForm` (present-tense label shown while in progress).\n' +
|
|
@@ -80,7 +81,6 @@ export function createTodoWriteTool() {
|
|
|
80
81
|
activeForm: Type.String({ minLength: 1, description: "Present-continuous form shown while in progress (e.g. \"Running the tests\")." }),
|
|
81
82
|
})),
|
|
82
83
|
}),
|
|
83
|
-
effect: "idempotent",
|
|
84
84
|
execute: (args) => {
|
|
85
85
|
const shape = (t) => ({ content: t.content, status: t.status, activeForm: t.activeForm });
|
|
86
86
|
const oldTodos = todos.map(shape);
|
package/dist/tools/web.js
CHANGED
|
@@ -7,6 +7,7 @@ import { isPrivateHost } from "../core/runner/image.js";
|
|
|
7
7
|
import { DEFAULT_CHARS_PER_TOKEN } from "../internal/harness.js";
|
|
8
8
|
import { binaryMagicFormat } from "./fs/safety.js";
|
|
9
9
|
import { pdfMagicMatches } from "./fs/pdf.js";
|
|
10
|
+
import { toolFace } from "../core/tool-catalog-entries.js";
|
|
10
11
|
const MAX_REDIRECTS = 10;
|
|
11
12
|
const MAX_URL_LENGTH = 2048;
|
|
12
13
|
const WEBFETCH_ACCEPT = "text/markdown, text/html, */*";
|
|
@@ -262,7 +263,7 @@ export function webFetchToolSpec(config = {}) {
|
|
|
262
263
|
const canSummarize = config.summarize !== undefined;
|
|
263
264
|
return {
|
|
264
265
|
name: "WebFetch",
|
|
265
|
-
|
|
266
|
+
...toolFace("web-fetch"),
|
|
266
267
|
description: (canSummarize
|
|
267
268
|
? "Fetches a URL, converts the page to markdown, and answers `prompt` against it with a sub-model.\n"
|
|
268
269
|
: "Fetches a URL, converts the page to markdown, and returns the markdown. This deployment has no " +
|
|
@@ -278,8 +279,6 @@ export function webFetchToolSpec(config = {}) {
|
|
|
278
279
|
? { prompt: Type.Optional(Type.String({ description: "The prompt to run on the fetched content (answered by the configured sub-model)." })) }
|
|
279
280
|
: {}),
|
|
280
281
|
}),
|
|
281
|
-
effect: "read",
|
|
282
|
-
contentOrigin: "external",
|
|
283
282
|
execute: async (args, ctx) => {
|
|
284
283
|
const { url, prompt } = args;
|
|
285
284
|
const startedAt = Date.now();
|
|
@@ -844,7 +843,7 @@ export function createWebSearchTool(config) {
|
|
|
844
843
|
const currentMonthYear = new Date().toLocaleString("en-US", { month: "long", year: "numeric" });
|
|
845
844
|
return {
|
|
846
845
|
name: "WebSearch",
|
|
847
|
-
|
|
846
|
+
...toolFace("web-search"),
|
|
848
847
|
description: "Search the web. Returns result blocks with titles and URLs.\n" +
|
|
849
848
|
"\n" +
|
|
850
849
|
`- The current month is ${currentMonthYear} — use this when searching for recent information.\n` +
|
|
@@ -857,8 +856,6 @@ export function createWebSearchTool(config) {
|
|
|
857
856
|
allowed_domains: Type.Optional(Type.Array(Type.String(), { description: "Only include search results from these domains" })),
|
|
858
857
|
blocked_domains: Type.Optional(Type.Array(Type.String(), { description: "Never include search results from these domains" })),
|
|
859
858
|
}),
|
|
860
|
-
effect: "read",
|
|
861
|
-
contentOrigin: "external",
|
|
862
859
|
execute: async (args, ctx) => {
|
|
863
860
|
const { query, allowed_domains, blocked_domains } = args;
|
|
864
861
|
const startedAt = Date.now();
|
package/dist/tools/worktree.js
CHANGED
|
@@ -2,6 +2,7 @@ import { resolve } from "node:path";
|
|
|
2
2
|
import { Type } from "typebox";
|
|
3
3
|
import { defineTool, errorResult } from "../core/tools.js";
|
|
4
4
|
import { addWorktree, pruneWorktrees, WORKTREE_PARENT } from "../core/git-worktree-env.js";
|
|
5
|
+
import { toolFace } from "../core/tool-catalog-entries.js";
|
|
5
6
|
const ENTER_DESCRIPTION = "Use this tool ONLY when explicitly instructed to work in a worktree — either by the user directly, or by " +
|
|
6
7
|
"project instructions. This tool creates an isolated git worktree and switches the current session into it.\n" +
|
|
7
8
|
"\n" +
|
|
@@ -108,7 +109,7 @@ export function createWorktreeTools(env, opts) {
|
|
|
108
109
|
const session = opts.session ?? {};
|
|
109
110
|
const enter = defineTool({
|
|
110
111
|
name: "EnterWorktree",
|
|
111
|
-
|
|
112
|
+
...toolFace("enter-worktree"),
|
|
112
113
|
description: ENTER_DESCRIPTION,
|
|
113
114
|
parameters: Type.Object({
|
|
114
115
|
name: Type.Optional(Type.String({
|
|
@@ -121,7 +122,6 @@ export function createWorktreeTools(env, opts) {
|
|
|
121
122
|
description: '"fresh" (default) bases the worktree on the default branch tip (origin default branch, else local main/master, else the current HEAD with a note); "head" bases it on the current local HEAD (unpushed commits present).',
|
|
122
123
|
})),
|
|
123
124
|
}),
|
|
124
|
-
effect: "write",
|
|
125
125
|
execute: async (args) => {
|
|
126
126
|
const { name, path, baseRef } = args;
|
|
127
127
|
if (path !== undefined && name !== undefined) {
|
|
@@ -238,7 +238,7 @@ export function createWorktreeTools(env, opts) {
|
|
|
238
238
|
});
|
|
239
239
|
const exit = defineTool({
|
|
240
240
|
name: "ExitWorktree",
|
|
241
|
-
|
|
241
|
+
...toolFace("exit-worktree"),
|
|
242
242
|
description: EXIT_DESCRIPTION,
|
|
243
243
|
parameters: Type.Object({
|
|
244
244
|
keep: Type.Optional(Type.Boolean({
|
|
@@ -254,7 +254,6 @@ export function createWorktreeTools(env, opts) {
|
|
|
254
254
|
description: 'Set true to remove the worktree even when it has uncommitted files or unmerged commits — they are permanently discarded. Without it a changed worktree is KEPT (the exit still completes and the reply lists the changes plus this escape), never refused.',
|
|
255
255
|
})),
|
|
256
256
|
}),
|
|
257
|
-
effect: "write",
|
|
258
257
|
execute: async (args) => {
|
|
259
258
|
const raw = args;
|
|
260
259
|
const keep = raw.keep ?? (raw.action === "keep" ? true : undefined);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sema-agent/core",
|
|
3
|
-
"version": "7.
|
|
3
|
+
"version": "7.8.0",
|
|
4
4
|
"description": "Stateless, task-oriented AI agent core",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "BUSL-1.1",
|
|
@@ -79,6 +79,9 @@
|
|
|
79
79
|
"gate:closed-sets": "node scripts/verify-closed-sets.mjs",
|
|
80
80
|
"gate:agent-returns": "node scripts/verify-agent-returns.mjs",
|
|
81
81
|
"gate:contract-sentences": "node scripts/verify-contract-sentences.mjs",
|
|
82
|
+
"gate:tool-catalog": "node scripts/verify-tool-catalog.mjs",
|
|
83
|
+
"gate:tool-names": "node scripts/verify-tool-name-tables.mjs",
|
|
84
|
+
"gate:tool-docs": "node scripts/gen-tool-spec-fields.mjs --check",
|
|
82
85
|
"gate:all": "node scripts/gate-all.mjs"
|
|
83
86
|
},
|
|
84
87
|
"dependencies": {
|