@sema-agent/core 7.35.2 → 7.36.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 +61 -0
- package/dist/brain/anthropic.js +6 -6
- package/dist/brain/errors.d.ts +1 -14
- package/dist/brain/errors.js +2 -6
- package/dist/brain/open-responses.js +7 -7
- package/dist/brain/openai.js +7 -7
- package/dist/brain/provider-echo-shape.d.ts +26 -0
- package/dist/brain/provider-echo-shape.js +12 -0
- package/dist/brain/tool-call-id.d.ts +27 -15
- package/dist/brain/tool-call-id.js +43 -0
- package/dist/core/ask-question.d.ts +0 -30
- package/dist/core/ask-question.js +3 -2
- package/dist/core/checkpoint-store.d.ts +5 -3
- package/dist/core/checkpoint-store.js +2 -1
- package/dist/core/context-edit.d.ts +4 -0
- package/dist/core/context-edit.js +5 -2
- package/dist/core/engine-notice.d.ts +7 -0
- package/dist/core/gate-lanes.js +12 -10
- package/dist/core/governance-codes.d.ts +1 -1
- package/dist/core/governance-codes.js +2 -0
- package/dist/core/hooks.d.ts +3 -0
- package/dist/core/hooks.js +4 -2
- package/dist/core/mode-policy.js +2 -1
- package/dist/core/permission-rule-model.d.ts +2 -2
- package/dist/core/permission-rule-model.js +2 -2
- package/dist/core/permission-rules.js +2 -5
- package/dist/core/runner/active-skill-scope.js +5 -5
- package/dist/core/runner/decide-continuation.js +2 -1
- package/dist/core/runner/permission-rule-lanes.d.ts +3 -0
- package/dist/core/runner/permission-rule-lanes.js +7 -6
- package/dist/core/runner/prepare-context-lane.d.ts +4 -0
- package/dist/core/runner/prepare-context-lane.js +7 -5
- package/dist/core/runner/prepare-gate-stations.js +17 -12
- package/dist/core/runner/prepare-park-ask.d.ts +2 -0
- package/dist/core/runner/prepare-park-ask.js +7 -6
- package/dist/core/runner/prepare-policy-chain.d.ts +2 -0
- package/dist/core/runner/prepare-policy-chain.js +10 -9
- package/dist/core/runner/prepare-safety-scan.js +9 -2
- package/dist/core/runner/prepare-task.js +3 -3
- package/dist/core/runner/resume-apply.js +2 -1
- package/dist/core/runner/run-attachment-seats.js +3 -1
- package/dist/core/runner/run-harness-handlers.js +6 -1
- package/dist/core/runner/run-leg.js +11 -9
- package/dist/core/runner/run-recovery-lanes.js +2 -0
- package/dist/core/runner/session-rule-policy.js +5 -4
- package/dist/core/runner/tool-call-id-fold-seat.d.ts +13 -0
- package/dist/core/runner/tool-call-id-fold-seat.js +31 -0
- package/dist/core/sensitive-path-policy.js +2 -2
- package/dist/core/side-query.d.ts +5 -1
- package/dist/core/side-query.js +5 -1
- package/dist/core/tool-name-readings.d.ts +366 -0
- package/dist/core/tool-name-readings.js +136 -0
- package/dist/core/tool-policy.d.ts +5 -5
- package/dist/core/tool-policy.js +15 -13
- package/dist/core/tool-registry.d.ts +1 -31
- package/dist/core/tool-registry.js +2 -22
- package/dist/core/tool-result-budget.d.ts +3 -0
- package/dist/core/tool-result-budget.js +5 -3
- package/dist/core/tool-roster.d.ts +30 -9
- package/dist/core/tool-roster.js +45 -5
- package/dist/engine/llm/types.d.ts +4 -0
- package/dist/tools/fs/file-read-check.d.ts +1 -1
- package/dist/tools/fs/file-read-check.js +4 -3
- package/dist/tools/fs/shell-read-check.d.ts +15 -1
- package/dist/tools/fs/shell-read-check.js +5 -2
- package/package.json +2 -1
- package/wire-changes/core@7.36.0.json +288 -0
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { TOOL_MOUNT_TAGS, pathTargetSlotOnly } from "./tool-face.js";
|
|
2
2
|
import { ENGINE_CARDS, TOOL_CATALOG_ENTRIES } from "./tool-catalog-entries.js";
|
|
3
|
+
import { seatOf } from "./tool-name-readings.js";
|
|
3
4
|
export function describeToolCatalog() {
|
|
4
5
|
return TOOL_CATALOG_ENTRIES;
|
|
5
6
|
}
|
|
@@ -51,31 +52,10 @@ export function pathTargetValue(args, pt) {
|
|
|
51
52
|
}
|
|
52
53
|
return undefined;
|
|
53
54
|
}
|
|
54
|
-
export function ruleNamesOf(req) {
|
|
55
|
-
const names = req.face?.names;
|
|
56
|
-
return names !== undefined && names.includes(req.toolName) ? names : [req.toolName];
|
|
57
|
-
}
|
|
58
|
-
export function callAnswersTo(req, name) {
|
|
59
|
-
return ruleNamesOf(req).includes(name);
|
|
60
|
-
}
|
|
61
|
-
export function toolNameSetHas(set, req) {
|
|
62
|
-
return anyNamed(set, ruleNamesOf(req));
|
|
63
|
-
}
|
|
64
|
-
export function anyNamed(set, names) {
|
|
65
|
-
return names.some((n) => set.has(n));
|
|
66
|
-
}
|
|
67
|
-
export function firstNamed(map, names) {
|
|
68
|
-
for (const name of names) {
|
|
69
|
-
const value = map.get(name);
|
|
70
|
-
if (value !== undefined)
|
|
71
|
-
return { name, value };
|
|
72
|
-
}
|
|
73
|
-
return undefined;
|
|
74
|
-
}
|
|
75
55
|
export function protectivePathTargetOf(call) {
|
|
76
56
|
if (call.face?.pathTarget !== undefined)
|
|
77
57
|
return call.face.pathTarget;
|
|
78
|
-
const floor =
|
|
58
|
+
const floor = seatOf("floor.protectivePathTarget", { get: pathTargetOf }, call)?.value;
|
|
79
59
|
return floor === undefined || call.face === undefined ? floor : pathTargetSlotOnly(floor);
|
|
80
60
|
}
|
|
81
61
|
export const BARE_REQUEST_CODE = "policy.bare_request";
|
|
@@ -23,6 +23,9 @@ export interface AggregateBudgetOptions {
|
|
|
23
23
|
budgetChars?: number;
|
|
24
24
|
/** Tool names exempt from the budget (their own caps bound them) — e.g. read_file, read_tool_result. */
|
|
25
25
|
exemptTools?: ReadonlySet<string>;
|
|
26
|
+
/** The wire name a result's recorded tool name resolves to on the leg's roster (an exemption is judged on the tool the
|
|
27
|
+
* call ran, not the spelling the model used). Absent ⇒ the recorded name. */
|
|
28
|
+
toolNameOf?: (recorded: string) => string;
|
|
26
29
|
/** design/30 store for offload+read-back. Absent ⇒ self-contained truncation preview. */
|
|
27
30
|
store?: ToolResultStore;
|
|
28
31
|
/** Namespaces the stable ref so an offloaded result is globally addressable. */
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { isToolResult } from "./message-utils.js";
|
|
2
2
|
import { buildPreview, buildToolResultRef, PERSISTED_OUTPUT_PREFIX, toolResultContentSegment, toolResultProvenanceOf, } from "./tool-result-store.js";
|
|
3
3
|
import { budgetExemptToolNames } from "./tool-registry.js";
|
|
4
|
+
import { wireOf } from "./tool-name-readings.js";
|
|
4
5
|
export const AGGREGATE_TOOL_RESULT_BUDGET_CHARS = 200_000;
|
|
5
6
|
const HEAD = 1_000;
|
|
6
7
|
const TAIL = 1_000;
|
|
@@ -38,6 +39,7 @@ const CATALOG_BUDGET_EXEMPT_TOOLS = budgetExemptToolNames();
|
|
|
38
39
|
export async function capAggregateToolResults(messages, opts) {
|
|
39
40
|
const budget = opts.budgetChars ?? AGGREGATE_TOOL_RESULT_BUDGET_CHARS;
|
|
40
41
|
const exempt = opts.exemptTools ?? CATALOG_BUDGET_EXEMPT_TOOLS;
|
|
42
|
+
const exemptResult = (m) => m.toolName !== undefined && exempt.has(wireOf("budget.exemptResult", { toolName: opts.toolNameOf !== undefined ? opts.toolNameOf(m.toolName) : m.toolName }));
|
|
41
43
|
let out;
|
|
42
44
|
let i = 0;
|
|
43
45
|
while (i < messages.length) {
|
|
@@ -52,7 +54,7 @@ export async function capAggregateToolResults(messages, opts) {
|
|
|
52
54
|
let total = 0;
|
|
53
55
|
for (let k = i; k < j; k++) {
|
|
54
56
|
const m = arr[k];
|
|
55
|
-
if (
|
|
57
|
+
if (exemptResult(m))
|
|
56
58
|
continue;
|
|
57
59
|
total += textChars(m.content);
|
|
58
60
|
}
|
|
@@ -94,7 +96,7 @@ export async function capAggregateToolResults(messages, opts) {
|
|
|
94
96
|
const cand = [];
|
|
95
97
|
for (let k = i; k < j; k++) {
|
|
96
98
|
const m = out[k];
|
|
97
|
-
if (
|
|
99
|
+
if (exemptResult(m))
|
|
98
100
|
continue;
|
|
99
101
|
if (isOffloadedPreview(m.content))
|
|
100
102
|
continue;
|
|
@@ -112,7 +114,7 @@ export async function capAggregateToolResults(messages, opts) {
|
|
|
112
114
|
const cand2 = [];
|
|
113
115
|
for (let k = i; k < j; k++) {
|
|
114
116
|
const m = out[k];
|
|
115
|
-
if (
|
|
117
|
+
if (exemptResult(m))
|
|
116
118
|
continue;
|
|
117
119
|
if (isOffloadedPreview(messages[k].content))
|
|
118
120
|
continue;
|
|
@@ -257,11 +257,11 @@ export declare function rosterEntryNamed(roster: ToolRoster, toolName: string):
|
|
|
257
257
|
* an alias and one written against the wire name are one rule.
|
|
258
258
|
*/
|
|
259
259
|
export declare function rosterToolName(roster: ToolRoster | undefined, name: string): string;
|
|
260
|
-
export {
|
|
260
|
+
export { ruleNamesOf } from "./tool-name-readings.js";
|
|
261
261
|
/** design/388 B6 — the per-call face a gated request carries, read off a roster snapshot by name (aliases resolve).
|
|
262
262
|
* `names` leads with the name the face was minted under (the model's spelling at the gate), then the wire name and the
|
|
263
|
-
* other aliases: a reader that must pick
|
|
264
|
-
* as the same call was judged before name resolution. */
|
|
263
|
+
* other aliases — the ONE order of a call's names: a reader that must pick one of them by position (a `member` seat)
|
|
264
|
+
* picks the spelling first, as the same call was judged before name resolution. */
|
|
265
265
|
export declare function toolCallFaceOf(roster: ToolRoster | undefined, toolName: string): import("./tool-policy.js").ToolCallFace | undefined;
|
|
266
266
|
/** design/388 B18 — the identity members a park row carries, read off a roster snapshot by name; an empty object when
|
|
267
267
|
* the name is not on the snapshot (the row then reads pre-identity and the resume takes the name-only path). */
|
|
@@ -272,16 +272,30 @@ export declare function parkedToolIdentity(roster: ToolRoster | undefined, toolN
|
|
|
272
272
|
implementationRevision?: string;
|
|
273
273
|
rosterDigest?: string;
|
|
274
274
|
};
|
|
275
|
-
/** design/388 B6 × B18
|
|
276
|
-
*
|
|
277
|
-
* the
|
|
278
|
-
*
|
|
279
|
-
*
|
|
280
|
-
|
|
275
|
+
/** design/388 B6 × B18 — the FACE members a park row carries beside its identity: the display family, the declared
|
|
276
|
+
* path target and the names the parked call was judged under. `names` is copied from the face the gate stamped on the
|
|
277
|
+
* request (the model's spelling first — the row carries the judged fact, it is not re-derived); a request with no face
|
|
278
|
+
* takes the roster's names for its row. A recheck that runs before the leg's roster exists (the pre-CAS resume-edit
|
|
279
|
+
* re-adjudication) rebuilds the call face from the row through {@link parkedCallFaceOf}, so it judges the same object
|
|
280
|
+
* the live gate judged. An empty object when the name is not on the snapshot (the row then reads pre-face and the
|
|
281
|
+
* recheck falls to the catalog for the name). */
|
|
282
|
+
export declare function parkedToolFace(roster: ToolRoster | undefined, req: {
|
|
283
|
+
readonly toolName: string;
|
|
284
|
+
readonly face?: {
|
|
285
|
+
readonly names?: readonly string[];
|
|
286
|
+
} | undefined;
|
|
287
|
+
}): {
|
|
281
288
|
family?: ToolFamily;
|
|
282
289
|
pathTarget?: ToolRosterEntry["pathTarget"];
|
|
283
290
|
names?: readonly string[];
|
|
284
291
|
};
|
|
292
|
+
/** The live face a resumed park row is re-judged under: minted under the row's recorded spelling (`names[0]`) when that
|
|
293
|
+
* spelling still resolves to the row's own tool on this roster, else under the row's wire name — a spelling that no
|
|
294
|
+
* longer resolves, or that another row now owns, never lends the row another tool's face. */
|
|
295
|
+
export declare function parkedRowLiveFace(roster: ToolRoster | undefined, row: {
|
|
296
|
+
readonly toolName: string;
|
|
297
|
+
readonly names?: readonly string[];
|
|
298
|
+
}): import("./tool-policy.js").ToolCallFace | undefined;
|
|
285
299
|
/** The call face a park row carries — present iff the row was minted with BOTH its face members and its four
|
|
286
300
|
* identity members (one mint writes all of them; a row missing any is pre-388 and yields undefined, never a
|
|
287
301
|
* partial face). This is the face every recheck of the row judges under, roster or no roster. */
|
|
@@ -443,6 +457,13 @@ export declare class RosterBuilder {
|
|
|
443
457
|
* yielded instance's position and never a row per object. */
|
|
444
458
|
snapshot(facts: RosterSnapshotFacts): ToolRoster;
|
|
445
459
|
}
|
|
460
|
+
/**
|
|
461
|
+
* The roster's one declaration rule on engine names: a row whose names (its wire name and the aliases that resolve to it,
|
|
462
|
+
* {@link namesResolvingTo}) belong to TWO or more engine tools is refused — one tool answering as two engine tools would
|
|
463
|
+
* have every per-call seat keyed on engine names choose between two definitions of the call. A row answering to one engine
|
|
464
|
+
* tool under several of that tool's names, and an alias another row owns, are not counted twice. Undefined ⇒ none.
|
|
465
|
+
*/
|
|
466
|
+
export declare function rosterEngineNamesProblem(roster: ToolRoster): string | undefined;
|
|
446
467
|
/** Which source a `TaskSpec.tools` entry mounts as: a definition carrying a CORE contract is a built-in the host chose
|
|
447
468
|
* to mount; anything else is the caller's own tool. Identity follows the object, never the name. */
|
|
448
469
|
export declare function callerMountSource(tool: AgentTool): RosterSource;
|
package/dist/core/tool-roster.js
CHANGED
|
@@ -2,6 +2,7 @@ import { createHash } from "node:crypto";
|
|
|
2
2
|
import { Type } from "typebox";
|
|
3
3
|
import { getToolContract } from "../prompt-assembly/tool-catalog.js";
|
|
4
4
|
import { protocolOf } from "./protocol-table.js";
|
|
5
|
+
import { describeToolCatalog } from "./tool-registry.js";
|
|
5
6
|
import { RENDER_HINT_ACTIVITY_MAX_CHARS, RENDER_HINT_MAX_CHARS, RENDER_HINT_MAX_LIST, TOOL_APPROVAL_CARDS, TOOL_CARD_ID_MAX_CHARS, TOOL_CONTRACT_MAX_CHARS, TOOL_FAMILIES, TOOL_KEYS_MAX, TOOL_KEY_MAX_CHARS, TOOL_MOUNT_TAGS, TOOL_WIRE_NAME_MAX_CHARS, TOOL_PATH_ABSENCES, TOOL_PATH_BASES, } from "./tool-face.js";
|
|
6
7
|
function lit(values) {
|
|
7
8
|
return Type.Union(values.map((v) => Type.Literal(v)));
|
|
@@ -80,7 +81,7 @@ export function rosterToolName(roster, name) {
|
|
|
80
81
|
function namesResolvingTo(roster, e) {
|
|
81
82
|
return [e.name, ...e.aliases.filter((a) => a !== e.name && rosterToolName(roster, a) === e.name)];
|
|
82
83
|
}
|
|
83
|
-
export {
|
|
84
|
+
export { ruleNamesOf } from "./tool-name-readings.js";
|
|
84
85
|
export function toolCallFaceOf(roster, toolName) {
|
|
85
86
|
if (roster === undefined)
|
|
86
87
|
return undefined;
|
|
@@ -106,13 +107,19 @@ export function parkedToolIdentity(roster, toolName) {
|
|
|
106
107
|
return {};
|
|
107
108
|
return { capabilityId: e.capabilityId, contractId: e.contract.contractId, shapeDigest: e.shapeDigest, implementationRevision: e.contract.implementationRevision, rosterDigest: roster.digest };
|
|
108
109
|
}
|
|
109
|
-
export function parkedToolFace(roster,
|
|
110
|
+
export function parkedToolFace(roster, req) {
|
|
110
111
|
if (roster === undefined)
|
|
111
112
|
return {};
|
|
112
|
-
const e = rosterEntryNamed(roster, toolName);
|
|
113
|
+
const e = rosterEntryNamed(roster, req.toolName);
|
|
113
114
|
if (e === undefined)
|
|
114
115
|
return {};
|
|
115
|
-
|
|
116
|
+
const judged = req.face?.names;
|
|
117
|
+
return { family: e.family, ...(e.pathTarget !== undefined ? { pathTarget: e.pathTarget } : {}), names: judged !== undefined && judged.includes(req.toolName) ? [...judged] : namesResolvingTo(roster, e) };
|
|
118
|
+
}
|
|
119
|
+
export function parkedRowLiveFace(roster, row) {
|
|
120
|
+
const spelled = row.names?.[0];
|
|
121
|
+
const under = spelled !== undefined && roster !== undefined && rosterToolName(roster, spelled) === row.toolName ? spelled : row.toolName;
|
|
122
|
+
return toolCallFaceOf(roster, under);
|
|
116
123
|
}
|
|
117
124
|
export function parkedCallFaceOf(pending) {
|
|
118
125
|
if (pending.family === undefined || pending.capabilityId === undefined || pending.contractId === undefined || pending.shapeDigest === undefined || pending.implementationRevision === undefined)
|
|
@@ -369,8 +376,41 @@ export class RosterBuilder {
|
|
|
369
376
|
const meta = this.#meta.get(survivor) ?? { source: "caller", mountedBy: "scenario" };
|
|
370
377
|
entries.push(mintRosterEntry(survivor, meta, facts));
|
|
371
378
|
}
|
|
372
|
-
|
|
379
|
+
const roster = { schemaVersion: 1, count: entries.length, entries, digest: rosterDigestOf(entries) };
|
|
380
|
+
const worn = rosterEngineNamesProblem(roster);
|
|
381
|
+
if (worn !== undefined)
|
|
382
|
+
throw configError("config.tool_face_invalid", worn);
|
|
383
|
+
return roster;
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
let catalogOwners;
|
|
387
|
+
function catalogOwnerOf(name) {
|
|
388
|
+
if (catalogOwners === undefined) {
|
|
389
|
+
const owners = new Map();
|
|
390
|
+
for (const e of describeToolCatalog()) {
|
|
391
|
+
owners.set(e.name, e.name);
|
|
392
|
+
for (const a of e.face.aliases ?? [])
|
|
393
|
+
if (!owners.has(a))
|
|
394
|
+
owners.set(a, e.name);
|
|
395
|
+
}
|
|
396
|
+
catalogOwners = owners;
|
|
373
397
|
}
|
|
398
|
+
return catalogOwners.get(name);
|
|
399
|
+
}
|
|
400
|
+
export function rosterEngineNamesProblem(roster) {
|
|
401
|
+
for (const e of roster.entries) {
|
|
402
|
+
const resolving = namesResolvingTo(roster, e);
|
|
403
|
+
const worn = new Map();
|
|
404
|
+
for (const n of resolving) {
|
|
405
|
+
const owner = catalogOwnerOf(n);
|
|
406
|
+
if (owner !== undefined && !worn.has(owner))
|
|
407
|
+
worn.set(owner, n);
|
|
408
|
+
}
|
|
409
|
+
if (worn.size >= 2) {
|
|
410
|
+
return `tool ${JSON.stringify(e.name)} answers to the names of ${worn.size} engine tools (${[...worn.values()].map((n) => JSON.stringify(n)).join(", ")}): a tool may answer to at most one engine tool's names — keep one of those aliases`;
|
|
411
|
+
}
|
|
412
|
+
}
|
|
413
|
+
return undefined;
|
|
374
414
|
}
|
|
375
415
|
export function callerMountSource(tool) {
|
|
376
416
|
return getToolContract(tool, "caller").origin === "core" ? "builtin" : "caller";
|
|
@@ -242,6 +242,10 @@ export interface DocumentContent {
|
|
|
242
242
|
export interface ToolCall {
|
|
243
243
|
type: "toolCall";
|
|
244
244
|
id: string;
|
|
245
|
+
/** The provider's own spelling of {@link id}, present only when the brain folded it (`brain/tool-call-id.ts`);
|
|
246
|
+
* handed back to the provider for the call and its result, persisted with the message. Upstream bytes: render
|
|
247
|
+
* {@link id}. */
|
|
248
|
+
wireId?: string;
|
|
245
249
|
name: string;
|
|
246
250
|
arguments: Record<string, unknown>;
|
|
247
251
|
executionMode?: "sequential" | "parallel";
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
import type { ExecutionEnv } from "../../internal/harness-types.js";
|
|
16
16
|
import type { ContainmentFace } from "./containment-face.js";
|
|
17
17
|
import { type ReadDenyMatcher } from "./read-deny.js";
|
|
18
|
-
import type
|
|
18
|
+
import { type ShellReadCheck } from "./shell-read-check.js";
|
|
19
19
|
export interface FileReadStation {
|
|
20
20
|
readonly check: ShellReadCheck;
|
|
21
21
|
/** The station's membership: the tool names whose declared read target it judges. */
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { effectivePathSpellingOf } from "../../core/effective-path-target.js";
|
|
2
|
-
import {
|
|
2
|
+
import { pathTargetOf } from "../../core/tool-registry.js";
|
|
3
3
|
import { fitMiddle, READ_DENY_SENTENCE_PART_MAX } from "./read-deny.js";
|
|
4
4
|
import { resolveKey, violationDetails } from "./safety.js";
|
|
5
|
+
import { readStationMemberOf } from "./shell-read-check.js";
|
|
5
6
|
import { grantOfferFor, parentDirLexically } from "./shell-read-judge.js";
|
|
6
7
|
const ADMISSION_MAX = 1024;
|
|
7
8
|
const VOUCH = { disposition: "vouch", finding: "none" };
|
|
@@ -17,7 +18,7 @@ export function createFileReadStation(opts) {
|
|
|
17
18
|
};
|
|
18
19
|
const check = {
|
|
19
20
|
judge(call, args, cwd, signal, callOpts) {
|
|
20
|
-
const member =
|
|
21
|
+
const member = readStationMemberOf(call, opts.tools)?.name;
|
|
21
22
|
if (member === undefined)
|
|
22
23
|
return null;
|
|
23
24
|
const toolName = call.toolName;
|
|
@@ -71,7 +72,7 @@ export function composeReadChecks(stations) {
|
|
|
71
72
|
for (const n of s.tools)
|
|
72
73
|
if (!byName.has(n))
|
|
73
74
|
byName.set(n, s);
|
|
74
|
-
const stationOf = (call) =>
|
|
75
|
+
const stationOf = (call) => readStationMemberOf(call, byName)?.value;
|
|
75
76
|
return {
|
|
76
77
|
judge: (call, args, cwd, signal, callOpts) => stationOf(call)?.check.judge(call, args, cwd, signal, callOpts) ?? null,
|
|
77
78
|
unanswered: (call, cause) => (stationOf(call) ?? stations[0]).check.unanswered(call, cause),
|
|
@@ -22,7 +22,7 @@ import { violationDetails } from "./safety.js";
|
|
|
22
22
|
import { type ShellReadPlan } from "./shell-read-plan.js";
|
|
23
23
|
import { type EstablishedRead, type ShellReadBoundary, type ShellReadDisposition, type ShellReadFinding, type ShellReadSeat } from "./shell-read-judge.js";
|
|
24
24
|
import type { ReadRootGrantCandidate } from "../../core/tool-spec.js";
|
|
25
|
-
import {
|
|
25
|
+
import type { ToolCallLike } from "../../core/tool-registry.js";
|
|
26
26
|
/** The ONE mint of the containment card — the targets a finding established OUTSIDE the roots (an out-of-root read, a
|
|
27
27
|
* target that resolves elsewhere by the spawn). */
|
|
28
28
|
declare function containmentDetails(paths: readonly string[]): {
|
|
@@ -105,6 +105,20 @@ export interface ShellReadCheck {
|
|
|
105
105
|
}
|
|
106
106
|
/** The call a read station judges: its wire name and the face the gate stamped (whose `names` the station reads). */
|
|
107
107
|
export type ReadStationCall = Pick<ToolCallLike, "toolName" | "face">;
|
|
108
|
+
/** The read station a call belongs to — the first of its names (the spelling first) a station's membership holds; every
|
|
109
|
+
* station reads the call's slot and seat under that one name. */
|
|
110
|
+
export declare function readStationMemberOf<V>(call: ReadStationCall, members: {
|
|
111
|
+
get(name: string): V | undefined;
|
|
112
|
+
}): {
|
|
113
|
+
readonly name: string;
|
|
114
|
+
readonly value: V;
|
|
115
|
+
} | undefined;
|
|
116
|
+
export declare function readStationMemberOf(call: ReadStationCall, members: {
|
|
117
|
+
has(name: string): boolean;
|
|
118
|
+
}): {
|
|
119
|
+
readonly name: string;
|
|
120
|
+
readonly value: true;
|
|
121
|
+
} | undefined;
|
|
108
122
|
/** The pre-spawn admission the shell tools call: re-establishes what the station established for this
|
|
109
123
|
* call and refuses when any canonical target moved. `undefined` ⇒ spawn. A call the station never judged
|
|
110
124
|
* (no gate ran) has nothing to re-establish and spawns. */
|
|
@@ -8,7 +8,7 @@ import { planShellReads } from "./shell-read-plan.js";
|
|
|
8
8
|
import { createShellReadEstablisher, establishShellReadsLexically } from "./shell-read-establish.js";
|
|
9
9
|
import { programArgs, spellsOption } from "./shell-read-write-targets.js";
|
|
10
10
|
import { allFindings, decideShellRead, denyRowAtOrBelow, foldShellReadFindings, judgeEstablishedPlan, readRootGrantCandidateOf, } from "./shell-read-judge.js";
|
|
11
|
-
import {
|
|
11
|
+
import { seatOf } from "../../core/tool-name-readings.js";
|
|
12
12
|
import { normalizeReadRootCandidate } from "../../core/read-root-candidate.js";
|
|
13
13
|
import { argvOf, lexShellText } from "../../shell/lex.js";
|
|
14
14
|
function containmentDetails(paths) {
|
|
@@ -178,6 +178,9 @@ async function writeGuardsOf(judged, boundary, placed, env, signal) {
|
|
|
178
178
|
}
|
|
179
179
|
return { unplaced, writeProtected };
|
|
180
180
|
}
|
|
181
|
+
export function readStationMemberOf(call, members) {
|
|
182
|
+
return seatOf("fold.readStation", members, call);
|
|
183
|
+
}
|
|
181
184
|
const ADMISSION_MAX = 1024;
|
|
182
185
|
function shellCommandOf(args) {
|
|
183
186
|
const command = args?.command;
|
|
@@ -360,7 +363,7 @@ export function createShellReadStation(opts) {
|
|
|
360
363
|
}
|
|
361
364
|
admissions.set(toolCallId, a);
|
|
362
365
|
};
|
|
363
|
-
const memberOf = (call) =>
|
|
366
|
+
const memberOf = (call) => readStationMemberOf(call, opts.tools)?.name;
|
|
364
367
|
const check = {
|
|
365
368
|
judge(call, args, cwd, signal, callOpts) {
|
|
366
369
|
const member = memberOf(call);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sema-agent/core",
|
|
3
|
-
"version": "7.
|
|
3
|
+
"version": "7.36.0",
|
|
4
4
|
"description": "Stateless, task-oriented AI agent core",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "BUSL-1.1",
|
|
@@ -83,6 +83,7 @@
|
|
|
83
83
|
"gate:contract-sentences": "node scripts/verify-contract-sentences.mjs",
|
|
84
84
|
"gate:tool-catalog": "node scripts/verify-tool-catalog.mjs",
|
|
85
85
|
"gate:tool-names": "node scripts/verify-tool-name-tables.mjs",
|
|
86
|
+
"gate:name-readings": "node scripts/verify-name-readings.mjs",
|
|
86
87
|
"gate:tool-docs": "node scripts/gen-tool-spec-fields.mjs --check",
|
|
87
88
|
"gate:backlog-ledger": "node scripts/verify-backlog-ledger.mjs",
|
|
88
89
|
"gate:child-clamp-seats": "node scripts/verify-child-clamp-seats.mjs",
|
|
@@ -0,0 +1,288 @@
|
|
|
1
|
+
{
|
|
2
|
+
"repo": "core",
|
|
3
|
+
"version": "7.36.0",
|
|
4
|
+
"from": "df0162002e59d5f355bda182d867378859405254",
|
|
5
|
+
"to": "e033cec051a178169a17a3f55d5fdaac98bedf2d",
|
|
6
|
+
"added": [],
|
|
7
|
+
"removed": [],
|
|
8
|
+
"changed": [],
|
|
9
|
+
"narrowed": [],
|
|
10
|
+
"closedSetMembers": [
|
|
11
|
+
{
|
|
12
|
+
"set": "ENGINE_NOTICE_CODES",
|
|
13
|
+
"at": [
|
|
14
|
+
"src/core/governance-codes.ts:344"
|
|
15
|
+
],
|
|
16
|
+
"newSet": false,
|
|
17
|
+
"added": [
|
|
18
|
+
"route.tool_call_id_folded"
|
|
19
|
+
],
|
|
20
|
+
"removed": [],
|
|
21
|
+
"breaking": false,
|
|
22
|
+
"criteriaCovered": true
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
"set": "ToolCallIdFoldReason",
|
|
26
|
+
"at": [
|
|
27
|
+
"src/brain/tool-call-id.ts:65"
|
|
28
|
+
],
|
|
29
|
+
"newSet": true,
|
|
30
|
+
"added": [
|
|
31
|
+
"charset",
|
|
32
|
+
"length"
|
|
33
|
+
],
|
|
34
|
+
"removed": [],
|
|
35
|
+
"breaking": false,
|
|
36
|
+
"criteriaCovered": false
|
|
37
|
+
}
|
|
38
|
+
],
|
|
39
|
+
"closedSetsUnreadable": [],
|
|
40
|
+
"typeKeys": [
|
|
41
|
+
{
|
|
42
|
+
"type": "AggregateBudgetOptions",
|
|
43
|
+
"at": [
|
|
44
|
+
"src/core/tool-result-budget.ts:86"
|
|
45
|
+
],
|
|
46
|
+
"added": [
|
|
47
|
+
"toolNameOf"
|
|
48
|
+
],
|
|
49
|
+
"addedDetail": [
|
|
50
|
+
{
|
|
51
|
+
"key": "toolNameOf",
|
|
52
|
+
"optional": true
|
|
53
|
+
}
|
|
54
|
+
],
|
|
55
|
+
"addedRequired": [],
|
|
56
|
+
"removed": [],
|
|
57
|
+
"breaking": false,
|
|
58
|
+
"criteriaCovered": false
|
|
59
|
+
},
|
|
60
|
+
{
|
|
61
|
+
"type": "ContextEditOptions",
|
|
62
|
+
"at": [
|
|
63
|
+
"src/core/context-edit.ts:240"
|
|
64
|
+
],
|
|
65
|
+
"added": [
|
|
66
|
+
"toolNameOf"
|
|
67
|
+
],
|
|
68
|
+
"addedDetail": [
|
|
69
|
+
{
|
|
70
|
+
"key": "toolNameOf",
|
|
71
|
+
"optional": true
|
|
72
|
+
}
|
|
73
|
+
],
|
|
74
|
+
"addedRequired": [],
|
|
75
|
+
"removed": [],
|
|
76
|
+
"breaking": false,
|
|
77
|
+
"criteriaCovered": false
|
|
78
|
+
},
|
|
79
|
+
{
|
|
80
|
+
"type": "ToolCall",
|
|
81
|
+
"at": [
|
|
82
|
+
"src/engine/llm/types.ts:309"
|
|
83
|
+
],
|
|
84
|
+
"added": [
|
|
85
|
+
"wireId"
|
|
86
|
+
],
|
|
87
|
+
"addedDetail": [
|
|
88
|
+
{
|
|
89
|
+
"key": "wireId",
|
|
90
|
+
"optional": true
|
|
91
|
+
}
|
|
92
|
+
],
|
|
93
|
+
"addedRequired": [],
|
|
94
|
+
"removed": [],
|
|
95
|
+
"breaking": false,
|
|
96
|
+
"criteriaCovered": true
|
|
97
|
+
}
|
|
98
|
+
],
|
|
99
|
+
"typeKeysUnreadableArms": [],
|
|
100
|
+
"typeKeysFlattenedCount": 219,
|
|
101
|
+
"declarationMoves": [
|
|
102
|
+
{
|
|
103
|
+
"name": "PROVIDER_ECHO_SHAPE",
|
|
104
|
+
"kind": "variable",
|
|
105
|
+
"onSurface": true,
|
|
106
|
+
"from": [
|
|
107
|
+
"src/brain/errors.ts",
|
|
108
|
+
"src/index.ts"
|
|
109
|
+
],
|
|
110
|
+
"to": [
|
|
111
|
+
"src/brain/errors.ts",
|
|
112
|
+
"src/brain/provider-echo-shape.ts",
|
|
113
|
+
"src/index.ts"
|
|
114
|
+
]
|
|
115
|
+
},
|
|
116
|
+
{
|
|
117
|
+
"name": "isProviderEchoShape",
|
|
118
|
+
"kind": "function",
|
|
119
|
+
"onSurface": true,
|
|
120
|
+
"from": [
|
|
121
|
+
"src/brain/errors.ts",
|
|
122
|
+
"src/index.ts"
|
|
123
|
+
],
|
|
124
|
+
"to": [
|
|
125
|
+
"src/brain/errors.ts",
|
|
126
|
+
"src/brain/provider-echo-shape.ts",
|
|
127
|
+
"src/index.ts"
|
|
128
|
+
]
|
|
129
|
+
},
|
|
130
|
+
{
|
|
131
|
+
"name": "ruleNamesOf",
|
|
132
|
+
"kind": "function",
|
|
133
|
+
"onSurface": true,
|
|
134
|
+
"from": [
|
|
135
|
+
"src/core/tool-registry.ts",
|
|
136
|
+
"src/core/tool-roster.ts",
|
|
137
|
+
"src/index.ts"
|
|
138
|
+
],
|
|
139
|
+
"to": [
|
|
140
|
+
"src/core/tool-name-readings.ts",
|
|
141
|
+
"src/core/tool-roster.ts",
|
|
142
|
+
"src/index.ts"
|
|
143
|
+
]
|
|
144
|
+
}
|
|
145
|
+
],
|
|
146
|
+
"mintMoves": [],
|
|
147
|
+
"criteriaObserves": [
|
|
148
|
+
{
|
|
149
|
+
"kind": "engineNoticeCode",
|
|
150
|
+
"name": "route.tool_call_id_folded",
|
|
151
|
+
"assertions": [
|
|
152
|
+
"G8.b"
|
|
153
|
+
]
|
|
154
|
+
},
|
|
155
|
+
{
|
|
156
|
+
"kind": "taskEventField",
|
|
157
|
+
"name": "message_committed.toolCallId",
|
|
158
|
+
"assertions": [
|
|
159
|
+
"G8.a"
|
|
160
|
+
]
|
|
161
|
+
},
|
|
162
|
+
{
|
|
163
|
+
"kind": "taskEventField",
|
|
164
|
+
"name": "tool_end.toolCallId",
|
|
165
|
+
"assertions": [
|
|
166
|
+
"G7.a",
|
|
167
|
+
"G8.a",
|
|
168
|
+
"G9.a",
|
|
169
|
+
"G10.a",
|
|
170
|
+
"G10.b"
|
|
171
|
+
]
|
|
172
|
+
},
|
|
173
|
+
{
|
|
174
|
+
"kind": "taskEventField",
|
|
175
|
+
"name": "tool_end.toolName",
|
|
176
|
+
"assertions": [
|
|
177
|
+
"G4.b"
|
|
178
|
+
]
|
|
179
|
+
},
|
|
180
|
+
{
|
|
181
|
+
"kind": "taskEventField",
|
|
182
|
+
"name": "tool_start.toolCallId",
|
|
183
|
+
"assertions": [
|
|
184
|
+
"G7.a",
|
|
185
|
+
"G7.b",
|
|
186
|
+
"G8.a",
|
|
187
|
+
"G9.a"
|
|
188
|
+
]
|
|
189
|
+
},
|
|
190
|
+
{
|
|
191
|
+
"kind": "taskEventField",
|
|
192
|
+
"name": "tool_start.toolName",
|
|
193
|
+
"assertions": [
|
|
194
|
+
"G2.a"
|
|
195
|
+
]
|
|
196
|
+
},
|
|
197
|
+
{
|
|
198
|
+
"kind": "typeMember",
|
|
199
|
+
"name": "AskRequest.riskAxes",
|
|
200
|
+
"assertions": [
|
|
201
|
+
"G1.a",
|
|
202
|
+
"G1.b"
|
|
203
|
+
]
|
|
204
|
+
},
|
|
205
|
+
{
|
|
206
|
+
"kind": "typeMember",
|
|
207
|
+
"name": "HookToolContext.toolName",
|
|
208
|
+
"assertions": [
|
|
209
|
+
"G2.a",
|
|
210
|
+
"G2.b"
|
|
211
|
+
]
|
|
212
|
+
},
|
|
213
|
+
{
|
|
214
|
+
"kind": "typeMember",
|
|
215
|
+
"name": "PostToolBatchCall.toolName",
|
|
216
|
+
"assertions": [
|
|
217
|
+
"G2.a"
|
|
218
|
+
]
|
|
219
|
+
},
|
|
220
|
+
{
|
|
221
|
+
"kind": "typeMember",
|
|
222
|
+
"name": "SideQueryResult.toolCalls",
|
|
223
|
+
"assertions": [
|
|
224
|
+
"G8.d"
|
|
225
|
+
]
|
|
226
|
+
},
|
|
227
|
+
{
|
|
228
|
+
"kind": "typeMember",
|
|
229
|
+
"name": "TaskResult.terminal",
|
|
230
|
+
"assertions": [
|
|
231
|
+
"G3.a",
|
|
232
|
+
"G3.b"
|
|
233
|
+
]
|
|
234
|
+
},
|
|
235
|
+
{
|
|
236
|
+
"kind": "typeMember",
|
|
237
|
+
"name": "ToolCall.id",
|
|
238
|
+
"assertions": [
|
|
239
|
+
"G7.b",
|
|
240
|
+
"G8.a"
|
|
241
|
+
]
|
|
242
|
+
},
|
|
243
|
+
{
|
|
244
|
+
"kind": "typeMember",
|
|
245
|
+
"name": "ToolCall.wireId",
|
|
246
|
+
"assertions": [
|
|
247
|
+
"G7.a",
|
|
248
|
+
"G8.a",
|
|
249
|
+
"G8.c",
|
|
250
|
+
"G10.a",
|
|
251
|
+
"G10.c"
|
|
252
|
+
]
|
|
253
|
+
},
|
|
254
|
+
{
|
|
255
|
+
"kind": "typeMember",
|
|
256
|
+
"name": "ToolCallFace.names",
|
|
257
|
+
"assertions": [
|
|
258
|
+
"G4.a",
|
|
259
|
+
"G4.b",
|
|
260
|
+
"G5.a"
|
|
261
|
+
]
|
|
262
|
+
},
|
|
263
|
+
{
|
|
264
|
+
"kind": "typeMember",
|
|
265
|
+
"name": "ToolSpec.effect",
|
|
266
|
+
"assertions": [
|
|
267
|
+
"G6.a"
|
|
268
|
+
]
|
|
269
|
+
}
|
|
270
|
+
],
|
|
271
|
+
"consumersHint": {
|
|
272
|
+
"cli": [
|
|
273
|
+
"ContextEditOptions",
|
|
274
|
+
"ENGINE_NOTICE_CODES",
|
|
275
|
+
"ToolCall"
|
|
276
|
+
],
|
|
277
|
+
"server": [
|
|
278
|
+
"ContextEditOptions",
|
|
279
|
+
"ENGINE_NOTICE_CODES"
|
|
280
|
+
],
|
|
281
|
+
"sdk": [
|
|
282
|
+
"ENGINE_NOTICE_CODES"
|
|
283
|
+
],
|
|
284
|
+
"note": "scanned cli@6b6025f7 server@25d6b7a6 sdk@e8f6f0d — a name listed is MENTIONED there today, which is evidence of consumption, not proof of it. Ledger files (**/docs/core-consumption/**, **/docs/wire-consumption/**, **/*LEDGER*.json) are not evidence of use — server: 2 name(s) matched ONLY in bookkeeping files and were set aside (AggregateBudgetOptions, ToolCall)"
|
|
285
|
+
},
|
|
286
|
+
"breakingCount": 0,
|
|
287
|
+
"breakingItems": []
|
|
288
|
+
}
|