@sema-agent/core 7.7.0 → 7.9.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 +88 -0
- 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/send-message-tool.js +2 -1
- package/dist/agents/subagent-steps.js +5 -4
- package/dist/agents/subagent.d.ts +1 -1
- package/dist/agents/subagent.js +2 -3
- package/dist/core/ask-origin.d.ts +12 -1
- package/dist/core/ask-origin.js +5 -1
- package/dist/core/ask-question.js +2 -2
- package/dist/core/checkpoint-store.d.ts +64 -24
- package/dist/core/context-edit.d.ts +0 -22
- package/dist/core/context-edit.js +2 -11
- package/dist/core/engine-notice.d.ts +6 -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 +53 -26
- package/dist/core/gate-outcome.d.ts +8 -4
- package/dist/core/gate-outcome.js +2 -1
- package/dist/core/governance-codes.d.ts +1 -1
- package/dist/core/governance-codes.js +6 -0
- package/dist/core/hooks.d.ts +64 -33
- 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-rule-consent.d.ts +29 -36
- package/dist/core/permission-rule-consent.js +110 -60
- package/dist/core/permission-rule-model.d.ts +254 -55
- package/dist/core/permission-rule-model.js +323 -43
- package/dist/core/permission-rule-org.d.ts +9 -8
- package/dist/core/permission-rule-org.js +6 -15
- package/dist/core/permission-rule-provider.d.ts +10 -6
- package/dist/core/permission-rule-provider.js +12 -8
- package/dist/core/permission-rule-session.d.ts +7 -6
- package/dist/core/permission-rule-session.js +29 -10
- package/dist/core/permission-rule-store.d.ts +40 -18
- package/dist/core/permission-rule-store.js +68 -42
- package/dist/core/permission-rule-sync.d.ts +9 -3
- package/dist/core/permission-rule-sync.js +29 -25
- package/dist/core/permission-rule-syntax.d.ts +30 -0
- package/dist/core/permission-rule-syntax.js +44 -0
- package/dist/core/permission-rules.d.ts +85 -33
- package/dist/core/permission-rules.js +104 -88
- package/dist/core/persisted-rule-arms.d.ts +56 -0
- package/dist/core/persisted-rule-arms.js +48 -0
- package/dist/core/present-plan-tool.js +3 -4
- package/dist/core/runner/active-skill-scope.js +7 -4
- package/dist/core/runner/compaction-call-options.d.ts +1 -1
- package/dist/core/runner/contracts.d.ts +46 -3
- package/dist/core/runner/permission-rule-lanes.d.ts +33 -26
- package/dist/core/runner/permission-rule-lanes.js +27 -21
- 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 +16 -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 +4 -2
- 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-run-refs.d.ts +16 -0
- package/dist/core/runner/prepare-run-refs.js +6 -0
- package/dist/core/runner/prepare-safety-scan.js +48 -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/resume-admission.d.ts +53 -0
- package/dist/core/runner/resume-admission.js +83 -0
- package/dist/core/runner/resume-apply.d.ts +50 -0
- package/dist/core/runner/resume-apply.js +184 -0
- package/dist/core/runner/resume-checkpoint-screen.d.ts +18 -0
- package/dist/core/runner/resume-checkpoint-screen.js +108 -0
- package/dist/core/runner/resume-claim.d.ts +32 -0
- package/dist/core/runner/resume-claim.js +27 -0
- package/dist/core/runner/resume-internals-and-config.d.ts +33 -0
- package/dist/core/runner/resume-internals-and-config.js +50 -0
- package/dist/core/runner/resume-policy-outcome.d.ts +31 -0
- package/dist/core/runner/resume-policy-outcome.js +127 -0
- package/dist/core/runner/resume-preflight.d.ts +40 -0
- package/dist/core/runner/resume-preflight.js +122 -0
- package/dist/core/runner/resume-review-outcome.d.ts +30 -0
- package/dist/core/runner/resume-review-outcome.js +88 -0
- 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 +20 -0
- package/dist/core/runner/runtask.js +129 -1774
- package/dist/core/runner/session-rule-policy.js +9 -4
- 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 +12 -5
- package/dist/core/runner/tool-end-body.js +8 -7
- 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 +14 -1
- package/dist/core/runner/tool-output-projection.js +24 -18
- package/dist/core/runner/turn-attachments.d.ts +2 -2
- 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.js +23 -0
- package/dist/core/store-contracts/permission-rule-sync-contract.js +29 -10
- 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 +459 -0
- package/dist/core/tool-roster.js +507 -0
- package/dist/core/tool-spec.d.ts +54 -3
- package/dist/core/tools.js +7 -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 +17 -6
- package/dist/index.js +17 -6
- 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.js +1 -1
- package/dist/stores/file/permission-rule-store.d.ts +28 -23
- package/dist/stores/file/permission-rule-store.js +64 -16
- package/dist/tools/fs/bash-readonly-classifier.d.ts +1 -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-pdf.d.ts +1 -1
- 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/notebook.d.ts +1 -1
- package/dist/tools/fs/repo-map.js +2 -2
- package/dist/tools/fs/safety.d.ts +3 -2
- 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 +189 -17
|
@@ -301,6 +301,29 @@ export async function checkpointStoreContract(make, runAssertion) {
|
|
|
301
301
|
const stored = (await store.get(bitless.token)).pendingAction;
|
|
302
302
|
assert.equal("hasBidiControls" in stored, false, "projection backfill must not write back to the row");
|
|
303
303
|
});
|
|
304
|
+
run("design/388 B18 × B6 identity + face group: a row's seven optional members (capabilityId/contractId/shapeDigest/implementationRevision/rosterDigest + family/pathTarget) survive the round-trip verbatim; an absent group stays absent", async () => {
|
|
305
|
+
const store = make();
|
|
306
|
+
const carried = createCheckpointFixture({ token: mintCheckpointToken(), sessionId: "id-carried" });
|
|
307
|
+
const group = {
|
|
308
|
+
capabilityId: "caller::Write@acme.write@2",
|
|
309
|
+
contractId: "acme.write@2",
|
|
310
|
+
shapeDigest: "sha256:0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef",
|
|
311
|
+
implementationRevision: "r7",
|
|
312
|
+
rosterDigest: "sha256:fedcba9876543210fedcba9876543210fedcba9876543210fedcba9876543210",
|
|
313
|
+
family: "file-write",
|
|
314
|
+
pathTarget: { param: "destination", aliases: ["path"], access: "create", skillScopeEligible: true },
|
|
315
|
+
};
|
|
316
|
+
Object.assign(carried.pendingAction, group);
|
|
317
|
+
const bare = createCheckpointFixture({ token: mintCheckpointToken(), sessionId: "id-bare" });
|
|
318
|
+
for (const cp of [carried, bare])
|
|
319
|
+
await store.put(cp.token, cp);
|
|
320
|
+
const back = (await store.get(carried.token)).pendingAction;
|
|
321
|
+
for (const [k, v] of Object.entries(group))
|
|
322
|
+
assert.deepEqual(back[k], v, `the row's ${k} must survive the round-trip verbatim (a whitelisting serializer that drops it makes every resume-edit recheck judge by the catalog's slot for the NAME)`);
|
|
323
|
+
const bareBack = (await store.get(bare.token)).pendingAction;
|
|
324
|
+
for (const k of Object.keys(group))
|
|
325
|
+
assert.equal(k in bareBack, false, `an absent ${k} must stay OMITTED (a pre-388 row reads name-only, never a partial face)`);
|
|
326
|
+
});
|
|
304
327
|
run("#457 previewWithheld three-form matrix: a row's spelling survives + projects; absent stays absent; an out-of-contract spelling reads as absent", async () => {
|
|
305
328
|
const store = make();
|
|
306
329
|
const oversize = createCheckpointFixture({ token: mintCheckpointToken(), sessionId: "pw-oversize" });
|
|
@@ -5,14 +5,15 @@ const GLOBAL = { kind: "global" };
|
|
|
5
5
|
function add(actor, counter, origin = "user") {
|
|
6
6
|
return { dot: { actor, counter }, origin, createdAt: "2026-01-01T00:00:00.000Z" };
|
|
7
7
|
}
|
|
8
|
-
function rule(text, adds, scope = GLOBAL) {
|
|
8
|
+
function rule(text, adds, scope = GLOBAL, behavior = "allow") {
|
|
9
9
|
const m = /^Bash\((.+?)(:\*)?\)$/.exec(text);
|
|
10
10
|
if (m === null || m[1] === undefined)
|
|
11
11
|
throw new Error(`contract fixture rule "${text}" is not a Bash(...) form`);
|
|
12
|
-
return { rule: text, tool: "Bash", match: m[2] !== undefined ? "prefix" : "exact", command: m[1], scope, adds };
|
|
12
|
+
return { behavior, rule: text, tool: "Bash", match: m[2] !== undefined ? "prefix" : "exact", command: m[1], scope, adds };
|
|
13
13
|
}
|
|
14
|
-
function tomb(text, removed, deletedBy, scope = GLOBAL) {
|
|
14
|
+
function tomb(text, removed, deletedBy, scope = GLOBAL, behavior = "allow") {
|
|
15
15
|
return {
|
|
16
|
+
behavior,
|
|
16
17
|
rule: text,
|
|
17
18
|
scope,
|
|
18
19
|
removedDots: removed.map(([actor, counter]) => ({ actor, counter })),
|
|
@@ -25,10 +26,10 @@ function state(rules = [], tombstones = []) {
|
|
|
25
26
|
function liveDots(s) {
|
|
26
27
|
const out = new Set();
|
|
27
28
|
for (const r of s.rules) {
|
|
28
|
-
const removed = s.tombstones.filter((t) => t.rule === r.rule && sameScope(t.scope, r.scope)).flatMap((t) => t.removedDots);
|
|
29
|
+
const removed = s.tombstones.filter((t) => t.behavior === r.behavior && t.rule === r.rule && sameScope(t.scope, r.scope)).flatMap((t) => t.removedDots);
|
|
29
30
|
for (const a of r.adds) {
|
|
30
31
|
if (!removed.some((d) => d.actor === a.dot.actor && d.counter === a.dot.counter))
|
|
31
|
-
out.add(`${r.rule}|${a.dot.actor}#${a.dot.counter}`);
|
|
32
|
+
out.add(`${r.behavior === "allow" ? "" : r.behavior + ":"}${r.rule}|${a.dot.actor}#${a.dot.counter}`);
|
|
32
33
|
}
|
|
33
34
|
}
|
|
34
35
|
return out;
|
|
@@ -41,7 +42,7 @@ function sameScope(a, b) {
|
|
|
41
42
|
return b.kind === "project" && a.root === b.root;
|
|
42
43
|
}
|
|
43
44
|
function allDots(s) {
|
|
44
|
-
return new Set(s.rules.flatMap((r) => r.adds.map((a) => `${r.rule}|${a.dot.actor}#${a.dot.counter}`)));
|
|
45
|
+
return new Set(s.rules.flatMap((r) => r.adds.map((a) => `${r.behavior === "allow" ? "" : r.behavior + ":"}${r.rule}|${a.dot.actor}#${a.dot.counter}`)));
|
|
45
46
|
}
|
|
46
47
|
export async function permissionRuleSyncContract(hooks = {}) {
|
|
47
48
|
const join = hooks.join ?? joinRuleStates;
|
|
@@ -141,8 +142,24 @@ export async function permissionRuleSyncContract(hooks = {}) {
|
|
|
141
142
|
assert.deepStrictEqual(new Set(ab.tombstones[0]?.removedDots.map((d) => `${d.actor}#${d.counter}`)), new Set(["a#1", "a#2"]), "the union — a one-sided pick can drop an observed removal");
|
|
142
143
|
assert.deepStrictEqual(ab, join(b, a));
|
|
143
144
|
});
|
|
145
|
+
run("behavior is an identity member: the same text as an allow and as a deny are two rows, each with its own adds and its own tombstone", async () => {
|
|
146
|
+
const both = state([rule("Bash(ls)", [add("a", 1)]), rule("Bash(ls)", [add("a", 2)], GLOBAL, "deny")], [tomb("Bash(ls)", [["a", 1]], ["a", 3])]);
|
|
147
|
+
const merged = join(both, state());
|
|
148
|
+
assert.strictEqual(merged.rules.length, 2, "one text, two behaviors — two identity groups, never folded");
|
|
149
|
+
assert.deepStrictEqual(liveDots(merged), new Set(["deny:Bash(ls)|a#2"]), "the allow tombstone must not reach the deny's add");
|
|
150
|
+
assert.deepStrictEqual(join(state(), both), merged, "commutative across the behavior axis");
|
|
151
|
+
const badWord = state([rule("Bash(pwd)", [add("b", 1)])], [Object.assign(tomb("Bash(pwd)", [["b", 1]], ["b", 2]), { behavior: "maybe" })]);
|
|
152
|
+
const screened = join(badWord, state());
|
|
153
|
+
assert.strictEqual(screened.tombstones.length, 0, "an unreadable behavior word on a tombstone must not land");
|
|
154
|
+
assert.ok(liveDots(screened).has("Bash(pwd)|b#1"), "…and must not cover anything");
|
|
155
|
+
});
|
|
156
|
+
run("closed-set identity: a row carrying a behavior word outside the closed set is refused like invalid text", async () => {
|
|
157
|
+
const forgedWord = Object.assign(rule("Bash(ls)", [add("z", 1)]), { behavior: "sometimes" });
|
|
158
|
+
const merged = join(state([forgedWord]), state());
|
|
159
|
+
assert.strictEqual(allDots(merged).size, 0, "a behavior this engine cannot read must not become an allow (or a deny) by falling through");
|
|
160
|
+
});
|
|
144
161
|
run("metadata re-projection (r2-F2): a record whose stored fields contradict its rule text is refused, both orders", async () => {
|
|
145
|
-
const forged = { rule: "Bash(ls)", tool: "Bash", match: "prefix", command: "rm -rf /", scope: GLOBAL, adds: [add("z", 1)] };
|
|
162
|
+
const forged = { behavior: "allow", rule: "Bash(ls)", tool: "Bash", match: "prefix", command: "rm -rf /", scope: GLOBAL, adds: [add("z", 1)] };
|
|
146
163
|
const clean = state([rule("Bash(git status)", [add("a", 1)])]);
|
|
147
164
|
const ab = join(state([forged]), clean);
|
|
148
165
|
const ba = join(clean, state([forged]));
|
|
@@ -150,9 +167,11 @@ export async function permissionRuleSyncContract(hooks = {}) {
|
|
|
150
167
|
assert.deepStrictEqual(ab, ba, "refusal must preserve commutativity");
|
|
151
168
|
assert.ok(allDots(ab).has("Bash(git status)|a#1"), "refusing one record must not disturb the rest");
|
|
152
169
|
});
|
|
153
|
-
run("single-validator door: an illegal
|
|
170
|
+
run("single-validator door: an illegal ALLOW shape (bare-interpreter prefix) cannot ride a join — while the same text as a DENY is a legitimate wide tightening and lands", async () => {
|
|
154
171
|
const merged = join(state([rule("Bash(node:*)", [add("z", 1)])]), state());
|
|
155
172
|
assert.strictEqual(allDots(merged).size, 0, "Bash(node:*) must be refused by the shared validator inside the join");
|
|
173
|
+
const denied = join(state([rule("Bash(node:*)", [add("z", 1)], GLOBAL, "deny")]), state());
|
|
174
|
+
assert.deepStrictEqual(allDots(denied), new Set(["deny:Bash(node:*)|z#1"]), "the tightening floor admits the interpreter-headed prefix");
|
|
156
175
|
});
|
|
157
176
|
run("durable two-member face (design/382 §4.3): a session-scope row or tombstone never survives a join, and never poisons the round", async () => {
|
|
158
177
|
const sessionScope = { kind: "session", sessionId: "sess-1" };
|
|
@@ -168,8 +187,8 @@ export async function permissionRuleSyncContract(hooks = {}) {
|
|
|
168
187
|
const scopeA = { kind: "project", root: "/x" };
|
|
169
188
|
const scopeB = { kind: "project", root: "/x a" };
|
|
170
189
|
const s = state([rule("Bash(ls)", [add("v", 1)], scopeA), rule("Bash(ls)", [add("w", 1)], scopeB)], [
|
|
171
|
-
{ rule: "Bash(ls)", scope: scopeA, removedDots: [{ actor: "v", counter: 1 }], deletedBy: { actor: "a 1", counter: 2 } },
|
|
172
|
-
{ rule: "Bash(ls)", scope: scopeB, removedDots: [{ actor: "w", counter: 1 }], deletedBy: { actor: "1", counter: 2 } },
|
|
190
|
+
{ behavior: "allow", rule: "Bash(ls)", scope: scopeA, removedDots: [{ actor: "v", counter: 1 }], deletedBy: { actor: "a 1", counter: 2 } },
|
|
191
|
+
{ behavior: "allow", rule: "Bash(ls)", scope: scopeB, removedDots: [{ actor: "w", counter: 1 }], deletedBy: { actor: "1", counter: 2 } },
|
|
173
192
|
]);
|
|
174
193
|
const merged = join(s, state());
|
|
175
194
|
assert.strictEqual(merged.tombstones.length, 2, "two distinct delete intents must both survive — a colliding key folds one away");
|
|
@@ -885,6 +885,16 @@ export type TaskEvent = ({
|
|
|
885
885
|
*/
|
|
886
886
|
type: "wiring_manifest";
|
|
887
887
|
manifest: import("./wiring-manifest.js").WiringManifest;
|
|
888
|
+
} & TaskEventIdentity) | ({
|
|
889
|
+
/**
|
|
890
|
+
* design/388 §2.5 — a RUN-TIME change to this leg's mounted tool set (today: the RefreshMcpTools
|
|
891
|
+
* seam re-inserting a server's tools in place). Carries the WHOLE post-change roster (positions
|
|
892
|
+
* come from it; a consumer replaces its copy) plus a summary usable only when the consumer holds
|
|
893
|
+
* `fromDigest` — otherwise it adopts the snapshot and records a skew (never rejects). The prepared
|
|
894
|
+
* roster itself rides `wiring_manifest.manifest.tools`; this frame never precedes that one.
|
|
895
|
+
*/
|
|
896
|
+
type: "tool_roster_delta";
|
|
897
|
+
delta: import("./tool-roster.js").ToolRosterDelta;
|
|
888
898
|
} & TaskEventIdentity) | {
|
|
889
899
|
type: "done";
|
|
890
900
|
result: TaskResult;
|
|
@@ -9,8 +9,9 @@ import { registerMonitorLane, pollMonitorLane, stopMonitorLane } from "./task-re
|
|
|
9
9
|
import { registerWorkflowLane, pollWorkflowLane, stopWorkflowLane } from "./task-registry-workflow.js";
|
|
10
10
|
import { mintCompletionId, canAccessWorkflowRun, formatWorkflowRun, clipTaskOutput, assertOwnership, sleepPollStep, statusFromBackground, rollSpoolText, accountDroppedBytes, renderSpoolBody, spoolDropNote, droppedGapNote, alreadyTerminalStopNote, terminalTaskSummary, TASK_OUTPUT_MAX_CHARS, MONITOR_BATCH_WINDOW_MS, MONITOR_DEFAULT_TIMEOUT_MS, MONITOR_MAX_TIMEOUT_MS, MONITOR_MAX_BATCHES_PER_MINUTE, canAccess, DURABLE_AGENT_HANDLE_RE, } from "./task-registry-shared.js";
|
|
11
11
|
export { normalizeAgentName, DURABLE_AGENT_HEARTBEAT_MS, DURABLE_AGENT_HANDLE_RE, BG_AGENT_REAP_STOP_ERROR } from "./task-registry-shared.js";
|
|
12
|
-
import { TASK_OUTPUT_TOOL_NAME, TASK_STOP_TOOL_NAME,
|
|
12
|
+
import { TASK_OUTPUT_TOOL_NAME, TASK_STOP_TOOL_NAME, TASK_OUTPUT_MISSING_ID_MESSAGE, TASK_STOP_MISSING_ID_MESSAGE, TASK_STOP_PARAMS, resolveTaskIdArg, REGISTRY_TASK_TOOL_CAPS, composeTaskOutputDescription, composeTaskOutputParams, composeTaskStopDescription, } from "./task-tool-shape.js";
|
|
13
13
|
import { durableAgentArmedLane, durableAgentRowProbeLane, beginDurableClaimLane, endDurableClaimLane, reapDurableAgentsLane, noteBackgroundAgentActivityLane, reapStaleSessionBackgroundAgentsLane, releaseDurableTranscriptAnchorLane, bindBackgroundAgentSessionLane, registerBackgroundAgentLane, recordBackgroundAgentOrgAdmissionLane, parkBackgroundAgentLane, reconcileParkedAgentsLane, claimParkedAgentLane, rollbackParkedClaimLane, consumeParkedFlipLane, finalizeParkedResumeLane, settleBackgroundAgentLane, abortBackgroundAgentsForOwnerLane, serveDurableAgentRowLane, resolveBackgroundAgentByNameLane, backgroundAgentCycleSeqLane, activeDelegationHandlesLane, markRetainedContinuationLane, reviveBackgroundAgentLane, settleRevivedAgentLane, unmarkRetainedContinuationLane, attachAgentNotifyLane, deliverToRunningAgentLane, runningBackgroundAgentLabelsLane, runningAgentFooterLane, notFoundRunningAgentsTail, pollBackgroundAgentLane, stopBackgroundAgentLane, } from "./task-registry-agent.js";
|
|
14
|
+
import { toolFace } from "./tool-catalog-entries.js";
|
|
14
15
|
export { canAccessWorkflowRun, clipTaskOutput, MONITOR_BATCH_WINDOW_MS, MONITOR_DEFAULT_TIMEOUT_MS, MONITOR_MAX_TIMEOUT_MS, MONITOR_MAX_BATCHES_PER_MINUTE };
|
|
15
16
|
const BLOCK_DEFAULT_TIMEOUT_MS = 30_000;
|
|
16
17
|
const BLOCK_MAX_TIMEOUT_MS = 600_000;
|
|
@@ -1234,10 +1235,9 @@ export function createTaskOutputTool(opts) {
|
|
|
1234
1235
|
const caps = { ...REGISTRY_TASK_TOOL_CAPS, notification: opts.notificationWired !== false };
|
|
1235
1236
|
return defineTool({
|
|
1236
1237
|
name: TASK_OUTPUT_TOOL_NAME,
|
|
1237
|
-
|
|
1238
|
+
...toolFace("task-output"),
|
|
1238
1239
|
description: composeTaskOutputDescription(caps),
|
|
1239
1240
|
parameters: composeTaskOutputParams(caps),
|
|
1240
|
-
effect: "read",
|
|
1241
1241
|
execute: async (rawArgs, ctx) => {
|
|
1242
1242
|
const args = rawArgs;
|
|
1243
1243
|
const id = resolveTaskIdArg(args.task_id);
|
|
@@ -1283,10 +1283,9 @@ export function createTaskOutputTool(opts) {
|
|
|
1283
1283
|
export function createTaskStopTool(opts) {
|
|
1284
1284
|
return defineTool({
|
|
1285
1285
|
name: TASK_STOP_TOOL_NAME,
|
|
1286
|
-
|
|
1286
|
+
...toolFace("task-stop"),
|
|
1287
1287
|
description: composeTaskStopDescription(REGISTRY_TASK_TOOL_CAPS),
|
|
1288
1288
|
parameters: TASK_STOP_PARAMS,
|
|
1289
|
-
effect: "write",
|
|
1290
1289
|
execute: async (rawArgs, ctx) => {
|
|
1291
1290
|
const args = rawArgs;
|
|
1292
1291
|
const id = resolveTaskIdArg(args.task_id, args.shell_id);
|
package/dist/core/task-spec.d.ts
CHANGED
|
@@ -387,6 +387,14 @@ export interface TaskSpec {
|
|
|
387
387
|
* owns that risk, same trust level as assembling `spec.tools` itself.
|
|
388
388
|
*/
|
|
389
389
|
excludeTools?: string[];
|
|
390
|
+
/**
|
|
391
|
+
* design/388 §2.2 ⑥ — unmount the WHOLE tool face: the leg mounts nothing (no hands, no
|
|
392
|
+
* scaffolds, no MCP or skill tools; the effect roster reads `entries: []` and the model request
|
|
393
|
+
* carries `tools: []`). The utility-task shape a shell used to express with a hand-kept exclusion
|
|
394
|
+
* list. Not spelled `excludeTools: ["*"]` on purpose — `"*"` is a legal caller tool name (only `__`
|
|
395
|
+
* is reserved). `excludeTools` beside it is redundant, not an error.
|
|
396
|
+
*/
|
|
397
|
+
excludeAllTools?: true;
|
|
390
398
|
/**
|
|
391
399
|
* Per-request DEFERRED disclosure for ALREADY-MOUNTED tools (built-ins
|
|
392
400
|
* included — `ToolSpec.defer` only covers caller specs): wire names listed here ship as
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The STATIC TOOL CATALOG (design/388 §2.1 "静态目录"): one row per built-in / synthetic tool DEFINITION
|
|
3
|
+
* core owns — its wire name, the conditions core (or a host scenario factory) mounts it under, the
|
|
4
|
+
* `details.type` cards it mints, and its declared FACE (family / axes / contract / path target / rule
|
|
5
|
+
* vocabulary / render hints / policy bits).
|
|
6
|
+
*
|
|
7
|
+
* SINGLE SOURCE, TWO READERS. Each definition module spreads its row's `face` into the `ToolSpec` it
|
|
8
|
+
* hands `defineTool` (`...TOOL_FACES.read`), so the face a tool declares at mount time IS the face
|
|
9
|
+
* listed here — there is no second declaration to drift. The effect roster (tool-roster.ts) reads every
|
|
10
|
+
* axis off the MOUNTED INSTANCE; the static catalog (`describeToolCatalog()`) reads this table without
|
|
11
|
+
* an env or a deps object. The conformance gate (test/tool-catalog-conformance.test.ts) proves the two
|
|
12
|
+
* agree for every definition it can instantiate; the catalog completeness gate
|
|
13
|
+
* (scripts/verify-tool-catalog.mjs) proves every `defineTool` site in src/ that mints a core-owned name
|
|
14
|
+
* has a row here that declares a `family` — a missing declaration is a RED gate naming the file, never a
|
|
15
|
+
* silent `"other"`.
|
|
16
|
+
*
|
|
17
|
+
* LEAF MODULE by design: it imports vocabulary types and one leaf constant module only. Every definition
|
|
18
|
+
* module and every policy module that derives a name set from the catalog imports THIS file, so a
|
|
19
|
+
* dependency from here back into a tool module would be a load-order cycle with a `const` table in it.
|
|
20
|
+
*
|
|
21
|
+
* Keyed by DEFINITION identity (`id`), not by name — the full and the read-only shell both answer to
|
|
22
|
+
* `Bash`; a catalog predicate counts a name as a member when ANY row under that name matches.
|
|
23
|
+
*/
|
|
24
|
+
import type { ToolCatalogEntry, ToolFaceDeclaration } from "./tool-face.js";
|
|
25
|
+
/** The full shell's contract id — declared here (the leaf) and re-exported by fs-bash.ts. */
|
|
26
|
+
export declare const FULL_SHELL_CONTRACT_ID = "core.bash@1";
|
|
27
|
+
export declare const READONLY_SHELL_CONTRACT_ID = "core.bash_readonly@1";
|
|
28
|
+
/** Wire-name constants for definitions that had none (design/388 A-21: literals become references). */
|
|
29
|
+
export declare const TASK_CREATE_TOOL_NAME = "TaskCreate";
|
|
30
|
+
export declare const TASK_GET_TOOL_NAME = "TaskGet";
|
|
31
|
+
export declare const TASK_UPDATE_TOOL_NAME = "TaskUpdate";
|
|
32
|
+
export declare const TASK_LIST_TOOL_NAME = "TaskList";
|
|
33
|
+
export declare const TODO_WRITE_TOOL_NAME = "TodoWrite";
|
|
34
|
+
export declare const REFRESH_MCP_TOOLS_TOOL_NAME = "RefreshMcpTools";
|
|
35
|
+
/**
|
|
36
|
+
* Every row. Order is documentation order (hands → delegation → scaffolds → memory → scheduler → host
|
|
37
|
+
* scenarios); nothing reads the order.
|
|
38
|
+
*/
|
|
39
|
+
export declare const TOOL_CATALOG_ENTRIES: readonly ToolCatalogEntry[];
|
|
40
|
+
/**
|
|
41
|
+
* `details.type` cards the ENGINE mints outside any tool definition — the protocol channels' result
|
|
42
|
+
* cards and the fs boundary refusals (minted by the shared safety module on behalf of every fs tool).
|
|
43
|
+
*/
|
|
44
|
+
export declare const ENGINE_CARDS: Readonly<Record<string, string>>;
|
|
45
|
+
/** The declared face of one definition, by definition id — what a definition module spreads into its spec. */
|
|
46
|
+
export declare function toolFace(id: string): ToolFaceDeclaration;
|
|
47
|
+
/** Definition-id → face, for the modules that spread one (`...TOOL_FACES.read`). Frozen: a face is data. */
|
|
48
|
+
export declare const TOOL_FACES: Readonly<Record<string, ToolFaceDeclaration>>;
|
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
import { TASK_OUTPUT_CONTRACT, TASK_STOP_CONTRACT } from "./task-tool-shape.js";
|
|
2
|
+
export const FULL_SHELL_CONTRACT_ID = "core.bash@1";
|
|
3
|
+
export const READONLY_SHELL_CONTRACT_ID = "core.bash_readonly@1";
|
|
4
|
+
export const TASK_CREATE_TOOL_NAME = "TaskCreate";
|
|
5
|
+
export const TASK_GET_TOOL_NAME = "TaskGet";
|
|
6
|
+
export const TASK_UPDATE_TOOL_NAME = "TaskUpdate";
|
|
7
|
+
export const TASK_LIST_TOOL_NAME = "TaskList";
|
|
8
|
+
export const TODO_WRITE_TOOL_NAME = "TodoWrite";
|
|
9
|
+
export const REFRESH_MCP_TOOLS_TOOL_NAME = "RefreshMcpTools";
|
|
10
|
+
const SHELL_RULE_FACE = { primaryParams: ["command"], params: ["command", "timeout", "description", "run_in_background"] };
|
|
11
|
+
const c = (contractId, implementationRevision = "1") => ({ contractId, implementationRevision });
|
|
12
|
+
export const TOOL_CATALOG_ENTRIES = [
|
|
13
|
+
{
|
|
14
|
+
id: "read", name: "Read", source: "builtin", definedIn: "src/tools/fs/fs-read.ts", mountedBy: ["hands"],
|
|
15
|
+
cards: ["text", "notebook", "file_unchanged", "image", "document"],
|
|
16
|
+
face: {
|
|
17
|
+
family: "file-read", effect: "read", contract: c("core.read@1"),
|
|
18
|
+
pathTarget: { param: "file_path", aliases: ["path"], access: "read" },
|
|
19
|
+
ruleFace: { params: ["file_path", "path", "offset", "limit", "pages"] },
|
|
20
|
+
renderHints: { summaryParams: ["file_path"] },
|
|
21
|
+
offload: false, compactable: true, budgetExempt: true,
|
|
22
|
+
},
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
id: "edit", name: "Edit", source: "builtin", definedIn: "src/tools/fs/fs-write.ts", mountedBy: ["hands"],
|
|
26
|
+
cards: ["edit"],
|
|
27
|
+
face: {
|
|
28
|
+
family: "file-write", effect: "write", contract: c("core.edit@1"),
|
|
29
|
+
pathTarget: { param: "file_path", aliases: ["path"], access: "edit", skillScopeEligible: true },
|
|
30
|
+
ruleFace: { params: ["file_path", "path", "old_string", "new_string", "replace_all"] },
|
|
31
|
+
renderHints: { summaryParams: ["file_path"], approvalCard: "file-edit" },
|
|
32
|
+
compactable: true,
|
|
33
|
+
},
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
id: "write", name: "Write", source: "builtin", definedIn: "src/tools/fs/fs-write.ts", mountedBy: ["hands"],
|
|
37
|
+
cards: ["create", "update"],
|
|
38
|
+
face: {
|
|
39
|
+
family: "file-write", effect: "write", contract: c("core.write@1"),
|
|
40
|
+
pathTarget: { param: "file_path", aliases: ["path"], access: "create", skillScopeEligible: true },
|
|
41
|
+
ruleFace: { params: ["file_path", "path", "content"] },
|
|
42
|
+
renderHints: { summaryParams: ["file_path"], approvalCard: "file-write" },
|
|
43
|
+
offload: false, compactable: true,
|
|
44
|
+
},
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
id: "notebook-edit", name: "NotebookEdit", source: "builtin", definedIn: "src/tools/fs/fs-write.ts", mountedBy: ["hands"],
|
|
48
|
+
cards: ["notebook-edit"],
|
|
49
|
+
face: {
|
|
50
|
+
family: "file-write", effect: "write", contract: c("core.notebook_edit@1"),
|
|
51
|
+
pathTarget: { param: "notebook_path", aliases: ["path"], access: "edit" },
|
|
52
|
+
ruleFace: { params: ["notebook_path", "path", "cell_id", "cell_type", "edit_mode", "new_source"] },
|
|
53
|
+
renderHints: { userFacingName: "Edit Notebook", summaryParams: ["notebook_path"], approvalCard: "notebook-edit" },
|
|
54
|
+
},
|
|
55
|
+
},
|
|
56
|
+
{
|
|
57
|
+
id: "bash", name: "Bash", source: "builtin", definedIn: "src/tools/fs/fs-bash.ts", mountedBy: ["hands"],
|
|
58
|
+
cards: ["bash", "bash_invalid_timeout"],
|
|
59
|
+
face: {
|
|
60
|
+
family: "shell", effect: "write", contentOrigin: "execution", contract: c(FULL_SHELL_CONTRACT_ID),
|
|
61
|
+
ruleFace: SHELL_RULE_FACE,
|
|
62
|
+
renderHints: { summaryParams: ["command"], approvalCard: "shell" },
|
|
63
|
+
offloadThresholdChars: 30_000, compactable: true,
|
|
64
|
+
},
|
|
65
|
+
},
|
|
66
|
+
{
|
|
67
|
+
id: "bash-readonly", name: "Bash", source: "builtin", definedIn: "src/tools/fs/fs-bash.ts", mountedBy: ["hands"],
|
|
68
|
+
cards: ["bash", "readonly_out_of_root", "bash_invalid_timeout"],
|
|
69
|
+
face: {
|
|
70
|
+
family: "shell", effect: "read", contract: c(READONLY_SHELL_CONTRACT_ID),
|
|
71
|
+
ruleFace: SHELL_RULE_FACE,
|
|
72
|
+
renderHints: { summaryParams: ["command"], approvalCard: "shell" },
|
|
73
|
+
offloadThresholdChars: 30_000, compactable: true,
|
|
74
|
+
},
|
|
75
|
+
},
|
|
76
|
+
{
|
|
77
|
+
id: "grep", name: "Grep", source: "builtin", definedIn: "src/tools/fs/fs-search-tools.ts", mountedBy: ["hands"],
|
|
78
|
+
cards: ["grep"],
|
|
79
|
+
face: {
|
|
80
|
+
family: "search", effect: "read", contract: c("core.grep@1"),
|
|
81
|
+
pathTarget: { param: "path", access: "read" },
|
|
82
|
+
ruleFace: { params: ["pattern", "path", "glob", "type", "output_mode", "head_limit", "offset", "multiline", "context", "ignore_case", "-i", "-n", "-o", "-A", "-B", "-C"] },
|
|
83
|
+
renderHints: { userFacingName: "Search", summaryParams: ["pattern", "path"] },
|
|
84
|
+
offloadThresholdChars: 20_000, compactable: true,
|
|
85
|
+
},
|
|
86
|
+
},
|
|
87
|
+
{
|
|
88
|
+
id: "glob", name: "Glob", source: "builtin", definedIn: "src/tools/fs/fs-search-tools.ts", mountedBy: ["hands"],
|
|
89
|
+
cards: ["glob"],
|
|
90
|
+
face: {
|
|
91
|
+
family: "search", effect: "read", contract: c("core.glob@1"),
|
|
92
|
+
pathTarget: { param: "path", access: "read" },
|
|
93
|
+
ruleFace: { params: ["pattern", "path", "max_results"] },
|
|
94
|
+
renderHints: { userFacingName: "Search", summaryParams: ["pattern", "path"] },
|
|
95
|
+
compactable: true,
|
|
96
|
+
},
|
|
97
|
+
},
|
|
98
|
+
{ id: "repo-map", name: "RepoMap", source: "builtin", definedIn: "src/tools/fs/repo-map.ts", mountedBy: ["hands"], cards: ["repo-map"], face: { family: "search", effect: "read", contract: c("core.repo_map@1") } },
|
|
99
|
+
{ id: "lsp", name: "LSP", source: "builtin", definedIn: "src/core/lsp.ts", mountedBy: ["optional"], cards: [], face: { family: "search", effect: "read", contract: c("core.lsp@1") } },
|
|
100
|
+
{ id: "enter-worktree", name: "EnterWorktree", source: "builtin", definedIn: "src/tools/worktree.ts", mountedBy: ["hands"], cards: ["worktree"], face: { family: "other", effect: "write", contract: c("core.enter_worktree@1") } },
|
|
101
|
+
{ id: "exit-worktree", name: "ExitWorktree", source: "builtin", definedIn: "src/tools/worktree.ts", mountedBy: ["hands"], cards: ["worktree"], face: { family: "other", effect: "write", contract: c("core.exit_worktree@1") } },
|
|
102
|
+
{ id: "task-output-hands", name: "TaskOutput", source: "builtin", definedIn: "src/tools/fs/fs-bash.ts", mountedBy: ["hands"], cards: [], face: { family: "delegate", effect: "read", contract: TASK_OUTPUT_CONTRACT } },
|
|
103
|
+
{ id: "task-stop-hands", name: "TaskStop", source: "builtin", definedIn: "src/tools/fs/fs-bash.ts", mountedBy: ["hands"], cards: [], face: { family: "delegate", effect: "write", contract: TASK_STOP_CONTRACT } },
|
|
104
|
+
{ id: "task-output", name: "TaskOutput", source: "builtin", definedIn: "src/core/task-registry.ts", mountedBy: ["delegation"], cards: ["task-output"], face: { family: "delegate", effect: "read", contract: TASK_OUTPUT_CONTRACT } },
|
|
105
|
+
{ id: "task-stop", name: "TaskStop", source: "builtin", definedIn: "src/core/task-registry.ts", mountedBy: ["delegation"], cards: ["task-stop"], face: { family: "delegate", effect: "write", contract: TASK_STOP_CONTRACT } },
|
|
106
|
+
{ id: "monitor", name: "Monitor", source: "builtin", definedIn: "src/tools/monitor.ts", mountedBy: ["backgroundTasks"], cards: ["monitor-start"], face: { family: "other", effect: "write", contract: c("core.monitor@1"), offloadThresholdChars: 10_000 } },
|
|
107
|
+
{ id: "send-message", name: "SendMessage", source: "builtin", definedIn: "src/agents/send-message-tool.ts", mountedBy: ["delegation", "hostInternals", "peerLane"], cards: ["send-message"], face: { family: "protocol", effect: "write", contract: c("core.send_message@1") } },
|
|
108
|
+
{ id: "agent-transcript", name: "AgentTranscript", source: "builtin", definedIn: "src/agents/agent-transcript-tool.ts", mountedBy: ["delegation"], cards: ["agent-transcript"], face: { family: "delegate", effect: "read", contract: c("core.agent_transcript@1") } },
|
|
109
|
+
{ id: "list-agents", name: "ListAgents", source: "builtin", definedIn: "src/agents/list-agents-tool.ts", mountedBy: ["peerLane"], cards: ["list-agents"], face: { family: "protocol", effect: "read", aliases: ["ListPeers"], contract: c("core.list_agents@1") } },
|
|
110
|
+
{ id: "workflow", name: "Workflow", source: "builtin", definedIn: "src/orchestration/run-workflow-tool.ts", mountedBy: ["workflow"], cards: ["workflow-run"], face: { family: "delegate", effect: "write", contract: c("core.workflow@1") } },
|
|
111
|
+
{ id: "report-blocked", name: "ReportBlocked", source: "builtin", definedIn: "src/core/runner/synthetic-tools.ts", mountedBy: ["always"], cards: [], face: { family: "scaffold", effect: "read", contract: c("core.report_blocked@1") } },
|
|
112
|
+
{ id: "report-findings", name: "ReportFindings", source: "builtin", definedIn: "src/core/runner/synthetic-tools.ts", mountedBy: ["always"], cards: ["report-findings"], face: { family: "scaffold", effect: "read", contract: c("core.report_findings@1") } },
|
|
113
|
+
{ id: "structured-output", name: "StructuredOutput", source: "synthetic", definedIn: "src/core/runner/synthetic-tools.ts", mountedBy: ["optional"], cards: [], face: { family: "scaffold", effect: "read", contract: c("core.structured_output@1") } },
|
|
114
|
+
{ id: "skill", name: "Skill", source: "builtin", definedIn: "src/core/runner/synthetic-tools.ts", mountedBy: ["optional"], cards: [], face: { family: "scaffold", effect: "read", contract: c("core.skill@1") } },
|
|
115
|
+
{ id: "read-tool-result", name: "ReadToolResult", source: "builtin", definedIn: "src/core/tool-result-store.ts", mountedBy: ["optional"], cards: [], face: { family: "scaffold", effect: "read", contract: c("core.read_tool_result@1"), budgetExempt: true } },
|
|
116
|
+
{ id: "tool-search", name: "ToolSearch", source: "builtin", definedIn: "src/core/runner/tool-disclosure.ts", mountedBy: ["optional"], cards: ["tool-search"], face: { family: "scaffold", effect: "read", contract: c("core.tool_search@1") } },
|
|
117
|
+
{ id: "ask-user-question", name: "AskUserQuestion", source: "builtin", definedIn: "src/core/ask-question.ts", mountedBy: ["optional"], cards: ["ask-question"], face: { family: "other", effect: "read", contract: c("core.ask_user_question@1"), renderHints: { approvalCard: "question" } } },
|
|
118
|
+
{ id: "exit-plan-mode", name: "ExitPlanMode", source: "builtin", definedIn: "src/core/present-plan-tool.ts", mountedBy: ["optional"], cards: ["exit-plan-mode"], face: { family: "plan", effect: "read", contract: c("core.exit_plan_mode@1"), renderHints: { userFacingName: "", approvalCard: "plan" } } },
|
|
119
|
+
{ id: "enter-plan-mode", name: "EnterPlanMode", source: "builtin", definedIn: "src/core/present-plan-tool.ts", mountedBy: ["optional"], cards: ["enter-plan-mode"], face: { family: "plan", effect: "read", contract: c("core.enter_plan_mode@1") } },
|
|
120
|
+
{ id: "refresh-mcp-tools", name: REFRESH_MCP_TOOLS_TOOL_NAME, source: "builtin", definedIn: "src/core/runner/prepare-protocol-tools.ts", mountedBy: ["optional"], cards: [], face: { family: "protocol", effect: "read" } },
|
|
121
|
+
{ id: "memory-search", name: "memory_search", source: "builtin", definedIn: "src/core/memory-engine/tools.ts", mountedBy: ["memory"], cards: [], face: { family: "memory", effect: "read", contentOrigin: "local", contract: c("core.memory_search@1", "6"), offload: false } },
|
|
122
|
+
{ id: "memory-get", name: "memory_get", source: "builtin", definedIn: "src/core/memory-engine/tools.ts", mountedBy: ["memory"], cards: [], face: { family: "memory", effect: "read", contentOrigin: "local", contract: c("core.memory_get@1", "6"), offload: false } },
|
|
123
|
+
{ id: "memory-index", name: "memory_index", source: "builtin", definedIn: "src/core/memory-engine/tools.ts", mountedBy: ["memory"], cards: [], face: { family: "memory", effect: "read", contentOrigin: "local", contract: c("core.memory_index@1"), offload: false } },
|
|
124
|
+
{ id: "memory-list", name: "memory_list", source: "builtin", definedIn: "src/core/shared-memory/tools.ts", mountedBy: ["memory"], cards: [], face: { family: "memory", effect: "read", contract: c("core.memory_list@1"), offload: false } },
|
|
125
|
+
{ id: "memory-read", name: "memory_read", source: "builtin", definedIn: "src/core/shared-memory/tools.ts", mountedBy: ["memory"], cards: [], face: { family: "memory", effect: "read", contract: c("core.memory_read@1"), offload: false } },
|
|
126
|
+
{ id: "cron-create", name: "CronCreate", source: "builtin", definedIn: "src/tools/scheduler-tools.ts", mountedBy: ["scheduler"], cards: ["cron-create"], face: { family: "other", effect: "write", contract: c("core.cron_create@1") } },
|
|
127
|
+
{ id: "cron-delete", name: "CronDelete", source: "builtin", definedIn: "src/tools/scheduler-tools.ts", mountedBy: ["scheduler"], cards: ["cron-delete"], face: { family: "other", effect: "idempotent", contract: c("core.cron_delete@1") } },
|
|
128
|
+
{ id: "cron-list", name: "CronList", source: "builtin", definedIn: "src/tools/scheduler-tools.ts", mountedBy: ["scheduler"], cards: ["cron-list"], face: { family: "other", effect: "read", contract: c("core.cron_list@1") } },
|
|
129
|
+
{ id: "schedule-wakeup", name: "ScheduleWakeup", source: "builtin", definedIn: "src/tools/scheduler-tools.ts", mountedBy: ["scheduler"], cards: ["schedule-wakeup"], face: { family: "other", effect: "write", contract: c("core.schedule_wakeup@1") } },
|
|
130
|
+
{
|
|
131
|
+
id: "web-fetch", name: "WebFetch", source: "builtin", definedIn: "src/tools/web.ts", mountedBy: ["scenario"], cards: ["web-fetch"],
|
|
132
|
+
face: { family: "web", effect: "read", contentOrigin: "external", contract: c("core.web_fetch@1"), ruleFace: { primaryParams: ["url"] }, renderHints: { summaryParams: ["url"], approvalCard: "fetch" }, compactable: true },
|
|
133
|
+
},
|
|
134
|
+
{
|
|
135
|
+
id: "web-search", name: "WebSearch", source: "builtin", definedIn: "src/tools/web.ts", mountedBy: ["scenario"], cards: ["web-search"],
|
|
136
|
+
face: { family: "web", effect: "read", contentOrigin: "external", contract: c("core.web_search@1"), ruleFace: { primaryParams: ["query"] }, renderHints: { summaryParams: ["query"] }, compactable: true },
|
|
137
|
+
},
|
|
138
|
+
{ id: "todo-write", name: TODO_WRITE_TOOL_NAME, source: "builtin", definedIn: "src/tools/todo.ts", mountedBy: ["scenario"], cards: ["todo"], modelGate: "task-scaffold", face: { family: "plan", effect: "idempotent", contract: c("core.todo_write@1") } },
|
|
139
|
+
{ id: "task-create", name: TASK_CREATE_TOOL_NAME, source: "builtin", definedIn: "src/tools/task-list.ts", mountedBy: ["scenario"], cards: ["task"], modelGate: "task-scaffold", face: { family: "plan", effect: "write", contract: c("core.task_create@1") } },
|
|
140
|
+
{ id: "task-get", name: TASK_GET_TOOL_NAME, source: "builtin", definedIn: "src/tools/task-list.ts", mountedBy: ["scenario"], cards: ["task"], modelGate: "task-scaffold", face: { family: "plan", effect: "read", contract: c("core.task_get@1") } },
|
|
141
|
+
{ id: "task-update", name: TASK_UPDATE_TOOL_NAME, source: "builtin", definedIn: "src/tools/task-list.ts", mountedBy: ["scenario"], cards: ["task"], modelGate: "task-scaffold", face: { family: "plan", effect: "idempotent", contract: c("core.task_update@1") } },
|
|
142
|
+
{ id: "task-list", name: TASK_LIST_TOOL_NAME, source: "builtin", definedIn: "src/tools/task-list.ts", mountedBy: ["scenario"], cards: ["task-list"], modelGate: "task-scaffold", face: { family: "plan", effect: "read", contract: c("core.task_list@1") } },
|
|
143
|
+
{ id: "agent", name: "Agent", source: "builtin", definedIn: "src/agents/subagent.ts", mountedBy: ["scenario"], cards: ["agent", "fork"], face: { family: "delegate", contentOrigin: "local", contract: c("core.agent@1") } },
|
|
144
|
+
{ id: "observer-report", name: "ObserverReport", source: "builtin", definedIn: "src/agents/observer.ts", mountedBy: ["scenario"], cards: [], face: { family: "scaffold", effect: "write", contract: c("core.observer_report@1") } },
|
|
145
|
+
{ id: "declare-done", name: "DeclareDone", source: "builtin", definedIn: "src/orchestration/goal.ts", mountedBy: ["scenario"], cards: [], face: { family: "scaffold", effect: "read" } },
|
|
146
|
+
];
|
|
147
|
+
export const ENGINE_CARDS = Object.freeze({
|
|
148
|
+
mcp: "src/core/mcp.ts",
|
|
149
|
+
a2a: "src/core/a2a.ts",
|
|
150
|
+
path_not_in_root: "src/tools/fs/safety.ts",
|
|
151
|
+
read_path_denied: "src/tools/fs/safety.ts",
|
|
152
|
+
});
|
|
153
|
+
const byId = new Map();
|
|
154
|
+
for (const e of TOOL_CATALOG_ENTRIES) {
|
|
155
|
+
if (byId.has(e.id))
|
|
156
|
+
throw new Error(`tool catalog: duplicate definition id ${JSON.stringify(e.id)}`);
|
|
157
|
+
byId.set(e.id, e);
|
|
158
|
+
}
|
|
159
|
+
export function toolFace(id) {
|
|
160
|
+
const e = byId.get(id);
|
|
161
|
+
if (e === undefined)
|
|
162
|
+
throw new Error(`tool catalog: no definition ${JSON.stringify(id)}`);
|
|
163
|
+
return structuredClone(e.face);
|
|
164
|
+
}
|
|
165
|
+
function deepFreeze(value) {
|
|
166
|
+
if (value !== null && typeof value === "object" && !Object.isFrozen(value)) {
|
|
167
|
+
Object.freeze(value);
|
|
168
|
+
for (const k of Object.keys(value))
|
|
169
|
+
deepFreeze(value[k]);
|
|
170
|
+
}
|
|
171
|
+
return value;
|
|
172
|
+
}
|
|
173
|
+
deepFreeze(TOOL_CATALOG_ENTRIES);
|
|
174
|
+
export const TOOL_FACES = Object.freeze(Object.fromEntries(TOOL_CATALOG_ENTRIES.map((e) => [e.id, e.face])));
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { ToolMountTag } from "./tool-face.js";
|
|
2
|
+
export interface ToolConformanceVector {
|
|
3
|
+
id: string;
|
|
4
|
+
/** The mount conditions the vector activates. */
|
|
5
|
+
active: readonly ToolMountTag[];
|
|
6
|
+
/** Predicted names the vector cannot mount, each with the seat it lacks. */
|
|
7
|
+
absent: ReadonlyArray<{
|
|
8
|
+
name: string;
|
|
9
|
+
why: string;
|
|
10
|
+
}>;
|
|
11
|
+
/** Mounted names no tag spells, each with the seat that mounts them. */
|
|
12
|
+
extra: ReadonlyArray<{
|
|
13
|
+
name: string;
|
|
14
|
+
why: string;
|
|
15
|
+
}>;
|
|
16
|
+
/** The vector's expected core-mounted name set: predict(active) − absent + extra. */
|
|
17
|
+
expected: readonly string[];
|
|
18
|
+
}
|
|
19
|
+
/** The matrix. Vector ids are stable (a host's own conformance test keys on them). */
|
|
20
|
+
export declare const TOOL_CONFORMANCE_VECTORS: readonly ToolConformanceVector[];
|
|
21
|
+
/** The matrix as a host reads it (a frozen copy). */
|
|
22
|
+
export declare function describeToolConformanceVectors(): readonly ToolConformanceVector[];
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { predictMountedToolNames } from "./tool-registry.js";
|
|
2
|
+
const vector = (id, active, absent = [], extra = []) => {
|
|
3
|
+
const predicted = new Set(predictMountedToolNames(new Set(active)));
|
|
4
|
+
for (const a of absent)
|
|
5
|
+
predicted.delete(a.name);
|
|
6
|
+
for (const e of extra)
|
|
7
|
+
predicted.add(e.name);
|
|
8
|
+
return { id, active, absent, extra, expected: [...predicted].sort() };
|
|
9
|
+
};
|
|
10
|
+
const OFFLOAD_READER = { name: "ReadToolResult", why: "the offload store is wired by default (the deployment threshold), an `optional` seat every vector carries" };
|
|
11
|
+
export const TOOL_CONFORMANCE_VECTORS = [
|
|
12
|
+
vector("bare", ["always"], [], [OFFLOAD_READER]),
|
|
13
|
+
vector("hands-full", ["always", "hands", "backgroundTasks", "delegation"], [
|
|
14
|
+
{ name: "SendMessage", why: "needs the runner self seat (a direct prepare has none)" },
|
|
15
|
+
{ name: "AgentTranscript", why: "needs the runner self seat (a direct prepare has none)" },
|
|
16
|
+
], [OFFLOAD_READER]),
|
|
17
|
+
vector("hands-readonly", ["always", "hands"], [
|
|
18
|
+
{ name: "Edit", why: "the read-only band mounts the read half only" },
|
|
19
|
+
{ name: "Write", why: "the read-only band mounts the read half only" },
|
|
20
|
+
{ name: "NotebookEdit", why: "the read-only band mounts the read half only" },
|
|
21
|
+
{ name: "TaskOutput", why: "the background-shell pair mounts on the full shell only" },
|
|
22
|
+
{ name: "TaskStop", why: "the background-shell pair mounts on the full shell only" },
|
|
23
|
+
{ name: "EnterWorktree", why: "the worktree pair needs the tracked cwd the full shell owns" },
|
|
24
|
+
{ name: "ExitWorktree", why: "the worktree pair needs the tracked cwd the full shell owns" },
|
|
25
|
+
], [OFFLOAD_READER]),
|
|
26
|
+
vector("plan-mode", ["always", "optional"], [
|
|
27
|
+
{ name: "LSP", why: "needs a wired LSP manager" },
|
|
28
|
+
{ name: "Skill", why: "needs a skills listing" },
|
|
29
|
+
{ name: "StructuredOutput", why: "needs an output schema" },
|
|
30
|
+
{ name: "ToolSearch", why: "needs a deferred tool" },
|
|
31
|
+
{ name: "RefreshMcpTools", why: "needs a declared MCP server" },
|
|
32
|
+
{ name: "EnterPlanMode", why: "needs a checkpoint store beside plan mode" },
|
|
33
|
+
]),
|
|
34
|
+
];
|
|
35
|
+
export function describeToolConformanceVectors() {
|
|
36
|
+
return TOOL_CONFORMANCE_VECTORS;
|
|
37
|
+
}
|