@sema-agent/core 7.12.0 → 7.13.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.
Files changed (57) hide show
  1. package/CHANGELOG.md +44 -0
  2. package/dist/core/ask-origin.d.ts +55 -0
  3. package/dist/core/ask-origin.js +21 -0
  4. package/dist/core/engine-notice.d.ts +18 -0
  5. package/dist/core/gate-lanes.d.ts +0 -40
  6. package/dist/core/gate-lanes.js +3 -17
  7. package/dist/core/governance-codes.d.ts +1 -1
  8. package/dist/core/governance-codes.js +2 -0
  9. package/dist/core/hooks.d.ts +1 -1
  10. package/dist/core/hooks.js +1 -1
  11. package/dist/core/runner/assemble-result.d.ts +45 -1
  12. package/dist/core/runner/assemble-result.js +4 -1
  13. package/dist/core/runner/compaction-seams.d.ts +42 -0
  14. package/dist/core/runner/compaction-seams.js +80 -0
  15. package/dist/core/runner/contracts.d.ts +44 -6
  16. package/dist/core/runner/denial-limit-arms.js +3 -2
  17. package/dist/core/runner/permission-rule-lanes.d.ts +2 -1
  18. package/dist/core/runner/permission-rule-lanes.js +2 -1
  19. package/dist/core/runner/prepare-policy-chain.js +3 -2
  20. package/dist/core/runner/prepare-protocol-tools.js +5 -0
  21. package/dist/core/runner/prepare-safety-scan.js +11 -16
  22. package/dist/core/runner/prepare-task.d.ts +9 -1
  23. package/dist/core/runner/prepare-task.js +6 -1
  24. package/dist/core/runner/resume-claim.d.ts +2 -2
  25. package/dist/core/runner/resume-preflight.d.ts +2 -2
  26. package/dist/core/runner/run-attachment-seats.d.ts +2 -2
  27. package/dist/core/runner/run-git-lane.d.ts +1 -1
  28. package/dist/core/runner/run-harness-handlers.js +2 -0
  29. package/dist/core/runner/run-identity-wiring.d.ts +7 -0
  30. package/dist/core/runner/run-identity-wiring.js +3 -1
  31. package/dist/core/runner/run-leg.d.ts +7 -5
  32. package/dist/core/runner/run-leg.js +256 -5
  33. package/dist/core/runner/run-notification-lane.d.ts +4 -3
  34. package/dist/core/runner/run-recovery-lanes.d.ts +4 -17
  35. package/dist/core/runner/run-recovery-lanes.js +5 -4
  36. package/dist/core/runner/run-settle-and-teardown.d.ts +14 -10
  37. package/dist/core/runner/run-settle-and-teardown.js +112 -4
  38. package/dist/core/runner/run-stop-and-final-verify.d.ts +2 -2
  39. package/dist/core/runner/run-terminal-adoption.d.ts +16 -16
  40. package/dist/core/runner/run-terminal-adoption.js +87 -7
  41. package/dist/core/runner/run-turn-boundary.js +5 -4
  42. package/dist/core/runner/runtask.d.ts +10 -90
  43. package/dist/core/runner/runtask.js +77 -596
  44. package/dist/core/runner/stream-lifecycle-verbs.js +10 -1
  45. package/dist/core/task-stream.d.ts +10 -1
  46. package/dist/core/tool-face.d.ts +8 -0
  47. package/dist/core/tool-face.js +1 -0
  48. package/dist/core/tool-policy.d.ts +5 -3
  49. package/dist/core/tool-registry.d.ts +11 -3
  50. package/dist/core/tool-registry.js +7 -1
  51. package/dist/core/tool-roster.d.ts +26 -0
  52. package/dist/core/tool-roster.js +38 -7
  53. package/dist/index.d.ts +3 -3
  54. package/dist/index.js +3 -3
  55. package/dist/server/http.js +2 -1
  56. package/package.json +1 -1
  57. package/test/export-surface.snapshot.json +11 -1
@@ -114,9 +114,18 @@ export function streamLifecycleVerbs(input) {
114
114
  detachHub.request(toolCallId);
115
115
  };
116
116
  const interrupt = async () => {
117
+ const interruptRefused = (msg) => {
118
+ const e = new Error(`cannot interrupt: ${msg}`);
119
+ e.code = "steering.not_running";
120
+ return e;
121
+ };
122
+ if (live.resultValue)
123
+ throw interruptRefused("the task has already finished");
117
124
  const h = live.handle ?? (await orTimeout(ready));
118
125
  if (!h)
119
- return;
126
+ throw interruptRefused("the task is not running");
127
+ if (live.resultValue !== undefined || h.loop.ended)
128
+ throw interruptRefused("the task is no longer running");
120
129
  if (!h.abortController.signal.aborted)
121
130
  h.loop.userInterrupted = true;
122
131
  h.abortController.abort();
@@ -277,7 +277,16 @@ export interface TaskStream extends AsyncIterable<TaskEvent> {
277
277
  }>;
278
278
  /**
279
279
  * Hard-**interrupt** the running task — a real abort (not a best-effort hint), equivalent to firing the
280
- * task's `signal` (design/47). No-op if the task already finished. For a SOFT redirect that lets the
280
+ * task's `signal` (design/47). Refused typed (`steering.not_running`, the steer-family liveness code
281
+ * `cannot interrupt: …`) once the task has finished (the loop's end included: the teardown window
282
+ * refuses like `halt`/`steer` do), never silently dropped. **A run that has already given its answer
283
+ * is not cancellable**: once its last turn ended `stopReason:"stop"` with no queued steer / follow-up
284
+ * left to serve (a continuation the person had already asked for makes that "stop" work in progress,
285
+ * not an answer), a stop landing on the run's
286
+ * tail (this verb, the task's `signal`, the walltime or turns limit — one law) still aborts what is
287
+ * left of that tail (a final-boundary compaction is mooted) but the run ends `completed` with the
288
+ * answer as `result`, writes no interruption marker, mints no `limits.*` code, and says so once with
289
+ * the `task.interrupt_unconsumed` notice. For a SOFT redirect that lets the
281
290
  * task keep running and adjust, use {@link steer} instead. For the CC-Esc "stop and wait for my
282
291
  * input" form — cut the turn, keep the ending clean and resumable — use {@link halt}.
283
292
  */
@@ -150,7 +150,15 @@ export interface ToolRuleFace {
150
150
  * budgets a MINTED name to — a minted name is always inside this wire bound by construction; a CALLER
151
151
  * declaration is judged against it at prepare. */
152
152
  export declare const TOOL_WIRE_NAME_MAX_CHARS = 128;
153
+ /** The roster's wire bound on a SHORT identity member: a contract's `contractId` / `implementationRevision`, and the
154
+ * `modelGate` class a definition carries. Bounded at the mint (`rosterMemberBoundProblem`), never truncated. */
153
155
  export declare const TOOL_CONTRACT_MAX_CHARS = 64;
156
+ /** The roster's wire bound on a row's `cardId` — a COMPOSITE minted from bounded members, so its bound is DERIVED
157
+ * from theirs rather than declared beside them: the widest form is `<mcp|a2a>:<peer>/<tool>` with the peer and the
158
+ * protocol tool segment each inside the wire NAME bound (`builtin:<name>` and `<caller|external>:<contractId>` are
159
+ * narrower). A row minted from in-bound members therefore fits by construction; the mint's own check on it is a
160
+ * tripwire for a new source form, never a working rule. */
161
+ export declare const TOOL_CARD_ID_MAX_CHARS: number;
154
162
  /** The roster's wire bound on a KEY — a schema property name, a path-target `param`/alias, a rule-face param. A key is a
155
163
  * SEMANTIC name every fence reads an argument by, so it is never truncated: a declaration over the bound is refused at
156
164
  * the door (caller) or dropped with a disclosed reason (MCP intake), and a row carries every key exactly. */
@@ -14,6 +14,7 @@ export function pathTargetSlotOnly(pt) {
14
14
  }
15
15
  export const TOOL_WIRE_NAME_MAX_CHARS = 128;
16
16
  export const TOOL_CONTRACT_MAX_CHARS = 64;
17
+ export const TOOL_CARD_ID_MAX_CHARS = "mcp:".length + TOOL_WIRE_NAME_MAX_CHARS + "/".length + TOOL_WIRE_NAME_MAX_CHARS;
17
18
  export const TOOL_KEY_MAX_CHARS = 256;
18
19
  export const TOOL_KEYS_MAX = 1024;
19
20
  export const RENDER_HINT_MAX_CHARS = 64;
@@ -19,9 +19,11 @@ export interface ToolCallRequest {
19
19
  * (how the target may be confirmed by path), the display family, and the engine-minted identity
20
20
  * (`capabilityId` / `contractId` / `shapeDigest`) an exemption store keys on. Stamped at the gate entry
21
21
  * from the live roster, so identity follows the OBJECT the call dispatches to — a caller tool that merely
22
- * took a built-in's name carries its own face, never the built-in's. ABSENT when a policy is invoked
23
- * outside a Runner (a bare producer): a path-confining face then reads the catalog's declaration for the
24
- * NAME (the pre-388 posture, never wider), and a skill-scope face treats the write as unconfirmable.
22
+ * took a built-in's name carries its own face, never the built-in's. ABSENT only on a BARE request (a
23
+ * policy invoked outside a Runner by a producer that stamped nothing): a PROTECTIVE fence (a deny-list)
24
+ * then reads the catalog's declaration for the NAME, tighten-only; a CONTAINMENT fence (a grant admitting a
25
+ * write by its path) REFUSES the request, typed (`policy.bare_request`, #626 ②) — stamp the face yourself
26
+ * (`toolCallFaceOf(roster, name)`) when driving a policy outside a Runner.
25
27
  */
26
28
  face?: ToolCallFace;
27
29
  /**
@@ -62,13 +62,21 @@ type CallPathTarget = ToolCallPathTarget;
62
62
  * a different file, and the deny this floor exists to preserve simply misses.
63
63
  */
64
64
  export declare function protectivePathTargetOf(call: ToolCallLike): CallPathTarget | undefined;
65
+ /** The typed refusal a CONTAINMENT reader mints for a request that carries no face at all (#626 ② — design/388 B6's
66
+ * bare-producer migration seam, closed). */
67
+ export declare const BARE_REQUEST_CODE = "policy.bare_request";
65
68
  /**
66
69
  * The path target a CONTAINMENT fence reads (a grant admitting a write BY its path: session `allowDirs`, the fs-write
67
70
  * gate's accept/exempt dirs; the active-skill allowPaths face reads its own eligibility bit the same way): the object
68
71
  * face's OWN declaration only — a same-name tool that declares no path target is an UNCONFIRMABLE write (the catalog's
69
- * slot may not be the one it writes; a decoy in that slot would buy an admission), so the fence fails closed. A BARE
70
- * request (no face at all — a policy invoked outside a Runner) reads the catalog for the name: the pre-388 reading, the
71
- * documented migration seam for bare producers.
72
+ * slot may not be the one it writes; a decoy in that slot would buy an admission), so the fence fails closed.
73
+ *
74
+ * #626 ②: a BARE request (no face at all) is REFUSED, typed (`policy.bare_request`), never answered from the catalog
75
+ * for the name. A grant is a claim about the tool's OWN slot, and only a prepared leg's roster can say which object
76
+ * the call dispatches to — the catalog's declaration for a NAME is exactly the reading a same-name caller tool would
77
+ * exploit. Inside a Runner every gated request carries the leg's face (the gate entry, the resume belts and the
78
+ * pre-CAS edit recheck stamp it); a policy invoked outside a Runner stamps its own (`toolCallFaceOf(roster, name)`).
79
+ * The PROTECTIVE floor above keeps reading the catalog for a bare request: tighten-only, a deny can only gain a slot.
72
80
  */
73
81
  export declare function declaredPathTargetOf(call: ToolCallLike): CallPathTarget | undefined;
74
82
  /** Is this call a write a PROTECTIVE fence judges (a protected target whose access ≠ read)? The name sets are its static view. */
@@ -54,8 +54,14 @@ export function protectivePathTargetOf(call) {
54
54
  const floor = pathTargetOf(call.toolName);
55
55
  return floor === undefined || call.face === undefined ? floor : pathTargetSlotOnly(floor);
56
56
  }
57
+ export const BARE_REQUEST_CODE = "policy.bare_request";
57
58
  export function declaredPathTargetOf(call) {
58
- return call.face !== undefined ? call.face.pathTarget : pathTargetOf(call.toolName);
59
+ if (call.face === undefined) {
60
+ const e = new Error(`tool call ${JSON.stringify(call.toolName)} carries no face: a containment fence admits a write only by the tool's OWN declared path target, which a prepared leg's roster stamps on every gated request — a policy invoked outside a Runner must stamp \`face\` itself (toolCallFaceOf) rather than expect the catalog's declaration for the name`);
61
+ e.code = BARE_REQUEST_CODE;
62
+ throw e;
63
+ }
64
+ return call.face.pathTarget;
59
65
  }
60
66
  export function isProtectedWrite(call) {
61
67
  const pt = protectivePathTargetOf(call);
@@ -309,6 +309,32 @@ export declare function inputKeysOf(schema: TSchema | undefined): {
309
309
  /** The roster's KEY bounds over a schema (design/388 B20): a problem sentence, or undefined when every top-level key fits.
310
310
  * Shared by the caller declaration door (typed refusal) and the MCP intake (disclosed drop) — a key is never truncated. */
311
311
  export declare function schemaKeyBoundProblem(schema: TSchema | undefined): string | undefined;
312
+ /** The identity members of one roster row the wire bounds hold, as a DECLARATION (the door) or a MINTED row hands them. */
313
+ export interface RosterBoundMembers {
314
+ name: string;
315
+ aliases?: readonly string[];
316
+ /** An MCP/A2A mount's peer (the row's `origin.peer`) — a NAME on the roster, held to the wire name bound. */
317
+ peer?: string;
318
+ contractId?: string;
319
+ implementationRevision?: string;
320
+ modelGate?: string;
321
+ cardId?: string;
322
+ }
323
+ /** The typed refusal a member over its bound mints — the door's two codes, and the mint's own for the members no
324
+ * declaration door names (`modelGate`, the derived `cardId`). */
325
+ export type RosterBoundCode = "config.tool_name_too_long" | "config.tool_contract_too_long" | "config.tool_roster_bound";
326
+ /**
327
+ * design/388 B20 / #626 ① — the ONE bound judge over a row's identity members: a problem `{ code, message }`, or
328
+ * undefined when every member fits. Read by the declaration door (a `TaskSpec.tools` entry, refused before session
329
+ * acquire) and by the row mint (every source — an MCP/A2A peer, a definition that reached the mint by a route the
330
+ * door does not cover — refused before the row exists). A member over its bound is NEVER truncated onto the row: a
331
+ * truncated identity is a different identity (`judgeParkedToolIdentity` compares it across a park; the card
332
+ * namespace door reads it), and the schema's own bounds would then describe a row the mint never made.
333
+ */
334
+ export declare function rosterMemberBoundProblem(m: RosterBoundMembers): {
335
+ code: RosterBoundCode;
336
+ message: string;
337
+ } | undefined;
312
338
  /**
313
339
  * The rule vocabulary of ONE mounted instance (design/388 §2.2 ③ / D-3): DERIVED = the scalar top-level
314
340
  * keys ∪ the path target's `param` + aliases; a declared `params` list can only NARROW it (a declared
@@ -2,12 +2,12 @@ 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 { RENDER_HINT_ACTIVITY_MAX_CHARS, RENDER_HINT_MAX_CHARS, RENDER_HINT_MAX_LIST, TOOL_APPROVAL_CARDS, TOOL_FAMILIES, TOOL_KEYS_MAX, TOOL_KEY_MAX_CHARS, TOOL_MOUNT_TAGS, TOOL_PATH_ABSENCES, TOOL_PATH_BASES, } from "./tool-face.js";
5
+ 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
6
  function lit(values) {
7
7
  return Type.Union(values.map((v) => Type.Literal(v)));
8
8
  }
9
- const Name = Type.String({ minLength: 1, maxLength: 128 });
10
- const Short = Type.String({ maxLength: 64 });
9
+ const Name = Type.String({ minLength: 1, maxLength: TOOL_WIRE_NAME_MAX_CHARS });
10
+ const Short = Type.String({ maxLength: TOOL_CONTRACT_MAX_CHARS });
11
11
  const Key = Type.String({ maxLength: TOOL_KEY_MAX_CHARS });
12
12
  const Digest16 = Type.String({ minLength: 16, maxLength: 16 });
13
13
  export const ROSTER_SOURCES = ["builtin", "caller", "host", "mcp", "a2a", "external", "synthetic"];
@@ -26,7 +26,7 @@ export const ToolRosterEntry = Type.Object({
26
26
  contract: Type.Object({ contractId: Short, implementationRevision: Short }, { additionalProperties: false }),
27
27
  shapeDigest: Digest16,
28
28
  wireSchemaDigest: Digest16,
29
- cardId: Type.String({ maxLength: 160 }),
29
+ cardId: Type.String({ maxLength: TOOL_CARD_ID_MAX_CHARS }),
30
30
  capabilityId: Digest16,
31
31
  inputKeys: Type.Array(Type.Object({ name: Key, type: lit(["string", "number", "integer", "boolean", "object", "array", "null", "mixed"]) }, { additionalProperties: false }), { maxItems: TOOL_KEYS_MAX }),
32
32
  effect: lit(["read", "write", "idempotent"]),
@@ -207,6 +207,26 @@ export function schemaKeyBoundProblem(schema) {
207
207
  return `the schema property ${JSON.stringify(long.slice(0, 40) + "…")} is ${long.length} characters; a roster key is at most ${TOOL_KEY_MAX_CHARS}`;
208
208
  return undefined;
209
209
  }
210
+ export function rosterMemberBoundProblem(m) {
211
+ const over = (label, value, bound) => `${label} ${JSON.stringify(value.slice(0, 40) + "…")} is ${value.length} characters; the roster's bound is ${bound}`;
212
+ const of = (text) => `tool ${JSON.stringify(m.name.slice(0, 40))}: ${text}`;
213
+ if (m.name.length > TOOL_WIRE_NAME_MAX_CHARS)
214
+ return { code: "config.tool_name_too_long", message: over("tool name", m.name, TOOL_WIRE_NAME_MAX_CHARS) };
215
+ const alias = m.aliases?.find((a) => a.length > TOOL_WIRE_NAME_MAX_CHARS);
216
+ if (alias !== undefined)
217
+ return { code: "config.tool_name_too_long", message: of(over("alias", alias, TOOL_WIRE_NAME_MAX_CHARS)) };
218
+ if (m.peer !== undefined && m.peer.length > TOOL_WIRE_NAME_MAX_CHARS)
219
+ return { code: "config.tool_name_too_long", message: of(over("peer", m.peer, TOOL_WIRE_NAME_MAX_CHARS)) };
220
+ for (const [label, v] of [["contractId", m.contractId], ["implementationRevision", m.implementationRevision]]) {
221
+ if (v !== undefined && v.length > TOOL_CONTRACT_MAX_CHARS)
222
+ return { code: "config.tool_contract_too_long", message: of(over(`contract ${label}`, v, TOOL_CONTRACT_MAX_CHARS)) };
223
+ }
224
+ if (m.modelGate !== undefined && m.modelGate.length > TOOL_CONTRACT_MAX_CHARS)
225
+ return { code: "config.tool_roster_bound", message: of(over("modelGate", m.modelGate, TOOL_CONTRACT_MAX_CHARS)) };
226
+ if (m.cardId !== undefined && m.cardId.length > TOOL_CARD_ID_MAX_CHARS)
227
+ return { code: "config.tool_roster_bound", message: of(over("cardId", m.cardId, TOOL_CARD_ID_MAX_CHARS)) };
228
+ return undefined;
229
+ }
210
230
  export function ruleFaceOfInstance(schema, declared, pathTarget) {
211
231
  const { scalar } = inputKeysOf(schema);
212
232
  const derived = new Set(scalar);
@@ -375,15 +395,26 @@ export function mintRosterEntry(tool, meta, facts) {
375
395
  const pathTarget = face.pathTarget;
376
396
  const rf = ruleFaceOfInstance(tool.parameters, face.ruleFace, pathTarget);
377
397
  const hints = face.renderHints !== undefined ? capRenderHints(face.renderHints) : undefined;
398
+ const bound = rosterMemberBoundProblem({
399
+ name: tool.name,
400
+ aliases: tool.aliases,
401
+ ...(peer !== null ? { peer } : {}),
402
+ contractId: d.contractId,
403
+ implementationRevision: d.implementationRevision,
404
+ ...(typeof face.modelGate === "string" ? { modelGate: face.modelGate } : {}),
405
+ cardId,
406
+ });
407
+ if (bound !== undefined)
408
+ throw configError(bound.code, bound.message);
378
409
  return {
379
410
  name: tool.name,
380
411
  aliases: [...new Set(tool.aliases ?? [])],
381
412
  source: meta.source,
382
413
  ...(meta.origin !== undefined ? { origin: { peer: meta.origin.peer, ...(meta.origin.declaredBy !== undefined ? { declaredBy: meta.origin.declaredBy } : {}) } } : {}),
383
- contract: { contractId: d.contractId.slice(0, 64), implementationRevision: d.implementationRevision.slice(0, 64) },
414
+ contract: { contractId: d.contractId, implementationRevision: d.implementationRevision },
384
415
  shapeDigest: d.shapeDigest,
385
416
  wireSchemaDigest: d.wireSchemaDigest,
386
- cardId: cardId.slice(0, 160),
417
+ cardId,
387
418
  capabilityId: mintCapabilityId({ source: meta.source, peer, name: tool.name, contractId: d.contractId }),
388
419
  inputKeys,
389
420
  effect,
@@ -417,7 +448,7 @@ export function mintRosterEntry(tool, meta, facts) {
417
448
  validateInput: typeof tool.validateInput === "function",
418
449
  deferred: facts.deferred.has(tool.name),
419
450
  alwaysLoad: face.alwaysLoad === true || face.mcpAlwaysLoad === true,
420
- ...(typeof face.modelGate === "string" ? { modelGate: face.modelGate.slice(0, 64) } : {}),
451
+ ...(typeof face.modelGate === "string" ? { modelGate: face.modelGate } : {}),
421
452
  ...(hints !== undefined ? { renderHints: hints } : {}),
422
453
  mountedBy: meta.mountedBy,
423
454
  };
package/dist/index.d.ts CHANGED
@@ -126,9 +126,9 @@ export { createFsWriteGatePolicy, type FsWriteGatePolicyOptions } from "./core/f
126
126
  export { RETIRED_TOOL_NAMES } from "./core/tool-name-aliases.js";
127
127
  export { DEFAULT_SUBAGENT_TOOL_NAME } from "./agents/subagent.js";
128
128
  export { renderTaskNotificationXml, taskNotificationDedupKey, isDelegatedAgentTerminal, isTerminalTaskNotification, SystemInjectionQueue, type TaskNotificationPayload, type TaskNotificationStatus, type ExternalNotificationInput, type SystemInjection, type SystemInjectionPriority, SYSTEM_INJECTION_PRIORITIES, isSystemInjectionPriority, AGENT_MESSAGE_TAG, renderAgentMessageFrame, type SemaProvenance, } from "./core/task-notification.js";
129
- export { TOOL_FAMILIES, TOOL_MOUNT_TAGS, TOOL_APPROVAL_CARDS, TOOL_PATH_ACCESSES, TOOL_PATH_BASES, TOOL_PATH_ABSENCES, TOOL_WIRE_NAME_MAX_CHARS, TOOL_CONTRACT_MAX_CHARS, TOOL_KEY_MAX_CHARS, TOOL_KEYS_MAX, RENDER_HINT_MAX_CHARS, RENDER_HINT_ACTIVITY_MAX_CHARS, RENDER_HINT_MAX_LIST, type ToolFamily, type ToolMountTag, type ToolApprovalCard, type ToolPathAccess, type ToolPathBase, type ToolPathAbsence, type ToolPathTarget, type ToolCallPathTarget, type ToolRosterPathTarget, pathTargetSlotOnly, type ToolRuleFace, type ToolRenderHints, type ToolFaceDeclaration, type ToolCatalogEntry, } from "./core/tool-face.js";
130
- export { describeToolCatalog, catalogEntriesNamed, catalogToolNames, catalogRuleFaceOf, pathTargetOf, pathTargetValue, protectivePathTargetOf, declaredPathTargetOf, isProtectedWrite, isDeclaredWrite, fileOpAccessOf, type ToolCallLike, pathConfinableWriteToolNames, skillScopeWriteToolNames, pathTargetingToolNames, compactableToolNames, budgetExemptToolNames, handBandEffects, engineCardTypes, predictMountedToolNames, HANDS_BAND_TAGS, MOUNT_TAG_IN_HANDS_BAND, } from "./core/tool-registry.js";
131
- export { ToolRosterEntry, ToolRoster, ToolRosterDelta, ToolRosterRenderHints, ROSTER_SOURCES, type RosterSource, type ToolIdentity, toolIdentityOf, mintCapabilityId, diffToolRoster, judgeParkedToolIdentity, ruleFacesFromRoster, toolCallFaceOf, inputKeysOf, ruleFaceOfInstance, ToolRosterDeltaSeat, } from "./core/tool-roster.js";
129
+ export { TOOL_FAMILIES, TOOL_MOUNT_TAGS, TOOL_APPROVAL_CARDS, TOOL_PATH_ACCESSES, TOOL_PATH_BASES, TOOL_PATH_ABSENCES, TOOL_WIRE_NAME_MAX_CHARS, TOOL_CONTRACT_MAX_CHARS, TOOL_CARD_ID_MAX_CHARS, TOOL_KEY_MAX_CHARS, TOOL_KEYS_MAX, RENDER_HINT_MAX_CHARS, RENDER_HINT_ACTIVITY_MAX_CHARS, RENDER_HINT_MAX_LIST, type ToolFamily, type ToolMountTag, type ToolApprovalCard, type ToolPathAccess, type ToolPathBase, type ToolPathAbsence, type ToolPathTarget, type ToolCallPathTarget, type ToolRosterPathTarget, pathTargetSlotOnly, type ToolRuleFace, type ToolRenderHints, type ToolFaceDeclaration, type ToolCatalogEntry, } from "./core/tool-face.js";
130
+ export { describeToolCatalog, catalogEntriesNamed, catalogToolNames, catalogRuleFaceOf, pathTargetOf, pathTargetValue, protectivePathTargetOf, declaredPathTargetOf, BARE_REQUEST_CODE, isProtectedWrite, isDeclaredWrite, fileOpAccessOf, type ToolCallLike, pathConfinableWriteToolNames, skillScopeWriteToolNames, pathTargetingToolNames, compactableToolNames, budgetExemptToolNames, handBandEffects, engineCardTypes, predictMountedToolNames, HANDS_BAND_TAGS, MOUNT_TAG_IN_HANDS_BAND, } from "./core/tool-registry.js";
131
+ export { ToolRosterEntry, ToolRoster, ToolRosterDelta, ToolRosterRenderHints, ROSTER_SOURCES, type RosterSource, type ToolIdentity, toolIdentityOf, mintCapabilityId, diffToolRoster, judgeParkedToolIdentity, ruleFacesFromRoster, toolCallFaceOf, inputKeysOf, ruleFaceOfInstance, rosterMemberBoundProblem, type RosterBoundMembers, type RosterBoundCode, ToolRosterDeltaSeat, } from "./core/tool-roster.js";
132
132
  export { type ToolCallFace } from "./core/tool-policy.js";
133
133
  export { effectivePathTargetOf, pathTargetBaseOf, type ToolPathBases } from "./core/effective-path-target.js";
134
134
  export { TOOL_CONFORMANCE_VECTORS, describeToolConformanceVectors, type ToolConformanceVector } from "./core/tool-conformance.js";
package/dist/index.js CHANGED
@@ -102,9 +102,9 @@ export { createFsWriteGatePolicy } from "./core/fs-write-gate-policy.js";
102
102
  export { RETIRED_TOOL_NAMES } from "./core/tool-name-aliases.js";
103
103
  export { DEFAULT_SUBAGENT_TOOL_NAME } from "./agents/subagent.js";
104
104
  export { renderTaskNotificationXml, taskNotificationDedupKey, isDelegatedAgentTerminal, isTerminalTaskNotification, SystemInjectionQueue, SYSTEM_INJECTION_PRIORITIES, isSystemInjectionPriority, AGENT_MESSAGE_TAG, renderAgentMessageFrame, } from "./core/task-notification.js";
105
- export { TOOL_FAMILIES, TOOL_MOUNT_TAGS, TOOL_APPROVAL_CARDS, TOOL_PATH_ACCESSES, TOOL_PATH_BASES, TOOL_PATH_ABSENCES, TOOL_WIRE_NAME_MAX_CHARS, TOOL_CONTRACT_MAX_CHARS, TOOL_KEY_MAX_CHARS, TOOL_KEYS_MAX, RENDER_HINT_MAX_CHARS, RENDER_HINT_ACTIVITY_MAX_CHARS, RENDER_HINT_MAX_LIST, pathTargetSlotOnly, } from "./core/tool-face.js";
106
- export { describeToolCatalog, catalogEntriesNamed, catalogToolNames, catalogRuleFaceOf, pathTargetOf, pathTargetValue, protectivePathTargetOf, declaredPathTargetOf, isProtectedWrite, isDeclaredWrite, fileOpAccessOf, pathConfinableWriteToolNames, skillScopeWriteToolNames, pathTargetingToolNames, compactableToolNames, budgetExemptToolNames, handBandEffects, engineCardTypes, predictMountedToolNames, HANDS_BAND_TAGS, MOUNT_TAG_IN_HANDS_BAND, } from "./core/tool-registry.js";
107
- export { ToolRosterEntry, ToolRoster, ToolRosterDelta, ToolRosterRenderHints, ROSTER_SOURCES, toolIdentityOf, mintCapabilityId, diffToolRoster, judgeParkedToolIdentity, ruleFacesFromRoster, toolCallFaceOf, inputKeysOf, ruleFaceOfInstance, ToolRosterDeltaSeat, } from "./core/tool-roster.js";
105
+ export { TOOL_FAMILIES, TOOL_MOUNT_TAGS, TOOL_APPROVAL_CARDS, TOOL_PATH_ACCESSES, TOOL_PATH_BASES, TOOL_PATH_ABSENCES, TOOL_WIRE_NAME_MAX_CHARS, TOOL_CONTRACT_MAX_CHARS, TOOL_CARD_ID_MAX_CHARS, TOOL_KEY_MAX_CHARS, TOOL_KEYS_MAX, RENDER_HINT_MAX_CHARS, RENDER_HINT_ACTIVITY_MAX_CHARS, RENDER_HINT_MAX_LIST, pathTargetSlotOnly, } from "./core/tool-face.js";
106
+ export { describeToolCatalog, catalogEntriesNamed, catalogToolNames, catalogRuleFaceOf, pathTargetOf, pathTargetValue, protectivePathTargetOf, declaredPathTargetOf, BARE_REQUEST_CODE, isProtectedWrite, isDeclaredWrite, fileOpAccessOf, pathConfinableWriteToolNames, skillScopeWriteToolNames, pathTargetingToolNames, compactableToolNames, budgetExemptToolNames, handBandEffects, engineCardTypes, predictMountedToolNames, HANDS_BAND_TAGS, MOUNT_TAG_IN_HANDS_BAND, } from "./core/tool-registry.js";
107
+ export { ToolRosterEntry, ToolRoster, ToolRosterDelta, ToolRosterRenderHints, ROSTER_SOURCES, toolIdentityOf, mintCapabilityId, diffToolRoster, judgeParkedToolIdentity, ruleFacesFromRoster, toolCallFaceOf, inputKeysOf, ruleFaceOfInstance, rosterMemberBoundProblem, ToolRosterDeltaSeat, } from "./core/tool-roster.js";
108
108
  export {} from "./core/tool-policy.js";
109
109
  export { effectivePathTargetOf, pathTargetBaseOf } from "./core/effective-path-target.js";
110
110
  export { TOOL_CONFORMANCE_VECTORS, describeToolConformanceVectors } from "./core/tool-conformance.js";
@@ -97,7 +97,8 @@ export function createTaskServer(opts) {
97
97
  res.on("close", () => {
98
98
  if (!res.writableEnded) {
99
99
  clientGone = true;
100
- void stream.interrupt();
100
+ stream.interrupt().catch(() => {
101
+ });
101
102
  void stream.destroy();
102
103
  }
103
104
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sema-agent/core",
3
- "version": "7.12.0",
3
+ "version": "7.13.0",
4
4
  "description": "Stateless, task-oriented AI agent core",
5
5
  "type": "module",
6
6
  "license": "BUSL-1.1",
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "_comment": "design/87 L3 — frozen public export surface of src/index.ts (name -> kind). DO NOT edit by hand to silence a red test. A removed/changed entry = a SemVer-BREAKING change; bump MAJOR and update this fixture in the SAME commit (design/87 §4.2 / §5.2). Regenerate via REGEN in test/export-surface.test.ts.",
3
3
  "_tierComment": "#435 v1 — machine-readable layering of the public surface: stable = demonstrated by README.md / src/examples; internal = an `Internal`-marked name or a runner/engine deep-subtree declaration (the model seam src/engine/llm is excluded — it is the BYOM contract, not an engine internal); advanced = a supported export the front door does not walk you through. THIS IS AN INITIAL HEURISTIC, derived mechanically and expected to be refined ticket by ticket: no human reviewed these 1700+ entries one by one, and nothing here claims otherwise. Known bias: a short or English-word export name (ok, err, Result, Usage) can match ordinary prose in README.md and land `stable` on a coincidence. Every export MUST carry a tier — a new export with no row fails the gate in export-surface.test.ts.",
4
- "count": 2274,
4
+ "count": 2279,
5
5
  "exports": {
6
6
  "A2ATaskState": "type",
7
7
  "A2ATaskStateReversal": "type",
@@ -109,6 +109,7 @@
109
109
  "AutonomousLoopPromptOptions": "interface",
110
110
  "BACKGROUND_AGENT_CONTRACT_SCOPE": "variable",
111
111
  "BARE_INTERPRETER_NAMES": "variable",
112
+ "BARE_REQUEST_CODE": "variable",
112
113
  "BASH_READONLY_DEFAULT_ALLOW": "variable",
113
114
  "BUILTIN_COMPLIANCE_DENIES": "variable",
114
115
  "BUILTIN_READONLY_DENY_TOOLS": "variable",
@@ -1078,6 +1079,8 @@
1078
1079
  "RollingTailBuffer": "class",
1079
1080
  "RootAdoptionFile": "type",
1080
1081
  "RosterAccess": "interface",
1082
+ "RosterBoundCode": "type",
1083
+ "RosterBoundMembers": "interface",
1081
1084
  "RosterEntry": "interface",
1082
1085
  "RosterGcOptions": "interface",
1083
1086
  "RosterSource": "type",
@@ -1308,6 +1311,7 @@
1308
1311
  "TEAM_DISCUSSION_WORKFLOW_NAME": "variable",
1309
1312
  "TOKEN_CHECKPOINT_VERSION": "variable",
1310
1313
  "TOOL_APPROVAL_CARDS": "variable",
1314
+ "TOOL_CARD_ID_MAX_CHARS": "variable",
1311
1315
  "TOOL_CONFORMANCE_VECTORS": "variable",
1312
1316
  "TOOL_CONTRACT_MAX_CHARS": "variable",
1313
1317
  "TOOL_FAMILIES": "variable",
@@ -2137,6 +2141,7 @@
2137
2141
  "retiredWorkflowNameAliases": "function",
2138
2142
  "retryBackoffMs": "function",
2139
2143
  "riskSeverity": "function",
2144
+ "rosterMemberBoundProblem": "function",
2140
2145
  "routePairingStatus": "function",
2141
2146
  "routePeerDeliveryReceipt": "function",
2142
2147
  "routePeerDroppedReceipt": "function",
@@ -2385,6 +2390,7 @@
2385
2390
  "AutonomousLoopPromptOptions": "advanced",
2386
2391
  "BACKGROUND_AGENT_CONTRACT_SCOPE": "advanced",
2387
2392
  "BARE_INTERPRETER_NAMES": "advanced",
2393
+ "BARE_REQUEST_CODE": "advanced",
2388
2394
  "BASH_READONLY_DEFAULT_ALLOW": "advanced",
2389
2395
  "BUILTIN_COMPLIANCE_DENIES": "advanced",
2390
2396
  "BUILTIN_READONLY_DENY_TOOLS": "advanced",
@@ -3354,6 +3360,8 @@
3354
3360
  "RollingTailBuffer": "advanced",
3355
3361
  "RootAdoptionFile": "advanced",
3356
3362
  "RosterAccess": "advanced",
3363
+ "RosterBoundCode": "advanced",
3364
+ "RosterBoundMembers": "advanced",
3357
3365
  "RosterEntry": "advanced",
3358
3366
  "RosterGcOptions": "advanced",
3359
3367
  "RosterSource": "advanced",
@@ -3584,6 +3592,7 @@
3584
3592
  "TEAM_DISCUSSION_WORKFLOW_NAME": "advanced",
3585
3593
  "TOKEN_CHECKPOINT_VERSION": "advanced",
3586
3594
  "TOOL_APPROVAL_CARDS": "advanced",
3595
+ "TOOL_CARD_ID_MAX_CHARS": "advanced",
3587
3596
  "TOOL_CONFORMANCE_VECTORS": "advanced",
3588
3597
  "TOOL_CONTRACT_MAX_CHARS": "advanced",
3589
3598
  "TOOL_FAMILIES": "advanced",
@@ -4413,6 +4422,7 @@
4413
4422
  "retiredWorkflowNameAliases": "advanced",
4414
4423
  "retryBackoffMs": "advanced",
4415
4424
  "riskSeverity": "advanced",
4425
+ "rosterMemberBoundProblem": "advanced",
4416
4426
  "routePairingStatus": "advanced",
4417
4427
  "routePeerDeliveryReceipt": "advanced",
4418
4428
  "routePeerDroppedReceipt": "advanced",