@sema-agent/core
Version:
Stateless, task-oriented AI agent core
531 lines (530 loc) • 36 kB
TypeScript
import { Type, type Static, type TSchema } from "typebox";
import type { AgentTool } from "../internal/harness-types.js";
import { type ToolFamily, type ToolRosterPathTarget, type ToolMountTag, type ToolPathTarget, type ToolRenderHints, type ToolRuleFace } from "./tool-face.js";
import type { ToolContentOrigin, ToolEffect } from "./tool-spec.js";
export declare const ROSTER_SOURCES: readonly ["builtin", "caller", "host", "mcp", "a2a", "external", "synthetic"];
export type RosterSource = (typeof ROSTER_SOURCES)[number];
export declare const ToolRosterRenderHints: Type.TObject<{
userFacingName: Type.TOptional<Type.TString>;
activity: Type.TOptional<Type.TString>;
summaryParams: Type.TOptional<Type.TArray<Type.TString>>;
resultCards: Type.TOptional<Type.TArray<Type.TString>>;
approvalCard: Type.TOptional<Type.TUnion<[Type.TLiteral<"file-edit">, Type.TLiteral<"file-write">, Type.TLiteral<"notebook-edit">, Type.TLiteral<"shell">, Type.TLiteral<"fetch">, Type.TLiteral<"plan">, Type.TLiteral<"question">, Type.TLiteral<"generic">]>>;
}>;
export declare const ToolRosterEntry: Type.TObject<{
name: Type.TString;
/** Always present (empty when the tool answers to no other name). */
aliases: Type.TArray<Type.TString>;
source: Type.TUnion<[Type.TLiteral<"builtin">, Type.TLiteral<"caller">, Type.TLiteral<"host">, Type.TLiteral<"mcp">, Type.TLiteral<"a2a">, Type.TLiteral<"external">, Type.TLiteral<"synthetic">]>;
/** Present iff `source` ∈ {mcp, a2a, external} (run-time validated at the mint). */
origin: Type.TOptional<Type.TObject<{
peer: Type.TString;
declaredBy: Type.TOptional<Type.TUnion<[Type.TLiteral<"center">, Type.TLiteral<"file">, Type.TLiteral<"request">]>>;
}>>;
/** Undeclared ⇒ `legacy:<shapeDigest>` / `unversioned`. */
contract: Type.TObject<{
contractId: Type.TString;
implementationRevision: Type.TString;
}>;
shapeDigest: Type.TString;
wireSchemaDigest: Type.TString;
/** `builtin:<name>` | `caller:<contractId>` | `mcp:<peer>/<tool>` | `a2a:<peer>/<skill>` | `external:<contractId>`. */
cardId: Type.TString;
/** ENGINE-minted: sha256 prefix over the canonical tuple {source, peer, name, contractId}; unique per leg. */
capabilityId: Type.TString;
/** The materialized schema's top-level properties (name + coarse type). */
inputKeys: Type.TArray<Type.TObject<{
name: Type.TString;
type: Type.TUnion<[Type.TLiteral<"string">, Type.TLiteral<"number">, Type.TLiteral<"integer">, Type.TLiteral<"boolean">, Type.TLiteral<"object">, Type.TLiteral<"array">, Type.TLiteral<"null">, Type.TLiteral<"mixed">]>;
}>>;
effect: Type.TUnion<[Type.TLiteral<"read">, Type.TLiteral<"write">, Type.TLiteral<"idempotent">]>;
effectProvenance: Type.TUnion<[Type.TLiteral<"declared">, Type.TLiteral<"caller">, Type.TLiteral<"synthetic">, Type.TLiteral<"default">]>;
offload: Type.TBoolean;
offloadThresholdChars: Type.TOptional<Type.TInteger>;
compactable: Type.TBoolean;
budgetExempt: Type.TBoolean;
egress: Type.TBoolean;
egressProvenance: Type.TUnion<[Type.TLiteral<"declared">, Type.TLiteral<"caller">, Type.TLiteral<"default">]>;
irreversibility: Type.TOptional<Type.TUnion<[Type.TLiteral<"never">, Type.TLiteral<"maybe">, Type.TLiteral<"always">]>>;
reversibilityProbe: Type.TBoolean;
contentOrigin: Type.TUnion<[Type.TLiteral<"local">, Type.TLiteral<"execution">, Type.TLiteral<"external">]>;
contentOriginProvenance: Type.TUnion<[Type.TLiteral<"declared">, Type.TLiteral<"server">, Type.TLiteral<"exempted">, Type.TLiteral<"default">]>;
family: Type.TUnion<[Type.TLiteral<"shell">, Type.TLiteral<"file-read">, Type.TLiteral<"file-write">, Type.TLiteral<"search">, Type.TLiteral<"web">, Type.TLiteral<"delegate">, Type.TLiteral<"plan">, Type.TLiteral<"scaffold">, Type.TLiteral<"memory">, Type.TLiteral<"protocol">, Type.TLiteral<"other">]>;
pathTarget: Type.TOptional<Type.TObject<{
param: Type.TString;
aliases: Type.TArray<Type.TString>;
access: Type.TUnion<[Type.TLiteral<"read">, Type.TLiteral<"create">, Type.TLiteral<"edit">]>;
skillScopeEligible: Type.TBoolean;
base: Type.TOptional<Type.TUnion<[Type.TLiteral<"cwd">, Type.TLiteral<"root">]>>;
absent: Type.TOptional<Type.TUnion<[Type.TLiteral<"none">, Type.TLiteral<"base">]>>;
patternParam: Type.TOptional<Type.TString>;
}>>;
ruleFace: Type.TObject<{
primaryParams: Type.TArray<Type.TString>;
params: Type.TArray<Type.TString>;
}>;
approvalPreview: Type.TBoolean;
validateInput: Type.TBoolean;
deferred: Type.TBoolean;
alwaysLoad: Type.TBoolean;
/** Present iff the definition carries a model-gate class and survived the gate. */
modelGate: Type.TOptional<Type.TString>;
renderHints: Type.TOptional<Type.TObject<{
userFacingName: Type.TOptional<Type.TString>;
activity: Type.TOptional<Type.TString>;
summaryParams: Type.TOptional<Type.TArray<Type.TString>>;
resultCards: Type.TOptional<Type.TArray<Type.TString>>;
approvalCard: Type.TOptional<Type.TUnion<[Type.TLiteral<"file-edit">, Type.TLiteral<"file-write">, Type.TLiteral<"notebook-edit">, Type.TLiteral<"shell">, Type.TLiteral<"fetch">, Type.TLiteral<"plan">, Type.TLiteral<"question">, Type.TLiteral<"generic">]>>;
}>>;
/** The ONE mount condition that fired for this instance. */
mountedBy: Type.TUnion<[Type.TLiteral<"hands">, Type.TLiteral<"backgroundTasks">, Type.TLiteral<"workflow">, Type.TLiteral<"delegation">, Type.TLiteral<"hostInternals">, Type.TLiteral<"peerLane">, Type.TLiteral<"scheduler">, Type.TLiteral<"memory">, Type.TLiteral<"scenario">, Type.TLiteral<"always">, Type.TLiteral<"optional">]>;
}>;
export type ToolRosterEntry = Static<typeof ToolRosterEntry>;
export declare const ToolRoster: Type.TObject<{
schemaVersion: Type.TLiteral<1>;
/** Run-time asserted equal to `entries.length`. */
count: Type.TInteger;
/** Declaration order = the model's `tools[]` order; names unique (run-time asserted). */
entries: Type.TArray<Type.TObject<{
name: Type.TString;
/** Always present (empty when the tool answers to no other name). */
aliases: Type.TArray<Type.TString>;
source: Type.TUnion<[Type.TLiteral<"builtin">, Type.TLiteral<"caller">, Type.TLiteral<"host">, Type.TLiteral<"mcp">, Type.TLiteral<"a2a">, Type.TLiteral<"external">, Type.TLiteral<"synthetic">]>;
/** Present iff `source` ∈ {mcp, a2a, external} (run-time validated at the mint). */
origin: Type.TOptional<Type.TObject<{
peer: Type.TString;
declaredBy: Type.TOptional<Type.TUnion<[Type.TLiteral<"center">, Type.TLiteral<"file">, Type.TLiteral<"request">]>>;
}>>;
/** Undeclared ⇒ `legacy:<shapeDigest>` / `unversioned`. */
contract: Type.TObject<{
contractId: Type.TString;
implementationRevision: Type.TString;
}>;
shapeDigest: Type.TString;
wireSchemaDigest: Type.TString;
/** `builtin:<name>` | `caller:<contractId>` | `mcp:<peer>/<tool>` | `a2a:<peer>/<skill>` | `external:<contractId>`. */
cardId: Type.TString;
/** ENGINE-minted: sha256 prefix over the canonical tuple {source, peer, name, contractId}; unique per leg. */
capabilityId: Type.TString;
/** The materialized schema's top-level properties (name + coarse type). */
inputKeys: Type.TArray<Type.TObject<{
name: Type.TString;
type: Type.TUnion<[Type.TLiteral<"string">, Type.TLiteral<"number">, Type.TLiteral<"integer">, Type.TLiteral<"boolean">, Type.TLiteral<"object">, Type.TLiteral<"array">, Type.TLiteral<"null">, Type.TLiteral<"mixed">]>;
}>>;
effect: Type.TUnion<[Type.TLiteral<"read">, Type.TLiteral<"write">, Type.TLiteral<"idempotent">]>;
effectProvenance: Type.TUnion<[Type.TLiteral<"declared">, Type.TLiteral<"caller">, Type.TLiteral<"synthetic">, Type.TLiteral<"default">]>;
offload: Type.TBoolean;
offloadThresholdChars: Type.TOptional<Type.TInteger>;
compactable: Type.TBoolean;
budgetExempt: Type.TBoolean;
egress: Type.TBoolean;
egressProvenance: Type.TUnion<[Type.TLiteral<"declared">, Type.TLiteral<"caller">, Type.TLiteral<"default">]>;
irreversibility: Type.TOptional<Type.TUnion<[Type.TLiteral<"never">, Type.TLiteral<"maybe">, Type.TLiteral<"always">]>>;
reversibilityProbe: Type.TBoolean;
contentOrigin: Type.TUnion<[Type.TLiteral<"local">, Type.TLiteral<"execution">, Type.TLiteral<"external">]>;
contentOriginProvenance: Type.TUnion<[Type.TLiteral<"declared">, Type.TLiteral<"server">, Type.TLiteral<"exempted">, Type.TLiteral<"default">]>;
family: Type.TUnion<[Type.TLiteral<"shell">, Type.TLiteral<"file-read">, Type.TLiteral<"file-write">, Type.TLiteral<"search">, Type.TLiteral<"web">, Type.TLiteral<"delegate">, Type.TLiteral<"plan">, Type.TLiteral<"scaffold">, Type.TLiteral<"memory">, Type.TLiteral<"protocol">, Type.TLiteral<"other">]>;
pathTarget: Type.TOptional<Type.TObject<{
param: Type.TString;
aliases: Type.TArray<Type.TString>;
access: Type.TUnion<[Type.TLiteral<"read">, Type.TLiteral<"create">, Type.TLiteral<"edit">]>;
skillScopeEligible: Type.TBoolean;
base: Type.TOptional<Type.TUnion<[Type.TLiteral<"cwd">, Type.TLiteral<"root">]>>;
absent: Type.TOptional<Type.TUnion<[Type.TLiteral<"none">, Type.TLiteral<"base">]>>;
patternParam: Type.TOptional<Type.TString>;
}>>;
ruleFace: Type.TObject<{
primaryParams: Type.TArray<Type.TString>;
params: Type.TArray<Type.TString>;
}>;
approvalPreview: Type.TBoolean;
validateInput: Type.TBoolean;
deferred: Type.TBoolean;
alwaysLoad: Type.TBoolean;
/** Present iff the definition carries a model-gate class and survived the gate. */
modelGate: Type.TOptional<Type.TString>;
renderHints: Type.TOptional<Type.TObject<{
userFacingName: Type.TOptional<Type.TString>;
activity: Type.TOptional<Type.TString>;
summaryParams: Type.TOptional<Type.TArray<Type.TString>>;
resultCards: Type.TOptional<Type.TArray<Type.TString>>;
approvalCard: Type.TOptional<Type.TUnion<[Type.TLiteral<"file-edit">, Type.TLiteral<"file-write">, Type.TLiteral<"notebook-edit">, Type.TLiteral<"shell">, Type.TLiteral<"fetch">, Type.TLiteral<"plan">, Type.TLiteral<"question">, Type.TLiteral<"generic">]>>;
}>>;
/** The ONE mount condition that fired for this instance. */
mountedBy: Type.TUnion<[Type.TLiteral<"hands">, Type.TLiteral<"backgroundTasks">, Type.TLiteral<"workflow">, Type.TLiteral<"delegation">, Type.TLiteral<"hostInternals">, Type.TLiteral<"peerLane">, Type.TLiteral<"scheduler">, Type.TLiteral<"memory">, Type.TLiteral<"scenario">, Type.TLiteral<"always">, Type.TLiteral<"optional">]>;
}>>;
/** sha256 prefix over the canonical COMPLETE rows — any axis / hint / contract / alias change moves it. */
digest: Type.TString;
}>;
export type ToolRoster = Static<typeof ToolRoster>;
export declare const ToolRosterDelta: Type.TObject<{
/** The digest the consumer is expected to hold. A mismatch is NOT a rejection: the carried `roster` is the
* new state regardless, only `summary` becomes unusable (the consumer records a skew and re-syncs). */
fromDigest: Type.TString;
/** The whole post-change roster; positions come from it, never from the summary. */
roster: Type.TObject<{
schemaVersion: Type.TLiteral<1>;
/** Run-time asserted equal to `entries.length`. */
count: Type.TInteger;
/** Declaration order = the model's `tools[]` order; names unique (run-time asserted). */
entries: Type.TArray<Type.TObject<{
name: Type.TString;
/** Always present (empty when the tool answers to no other name). */
aliases: Type.TArray<Type.TString>;
source: Type.TUnion<[Type.TLiteral<"builtin">, Type.TLiteral<"caller">, Type.TLiteral<"host">, Type.TLiteral<"mcp">, Type.TLiteral<"a2a">, Type.TLiteral<"external">, Type.TLiteral<"synthetic">]>;
/** Present iff `source` ∈ {mcp, a2a, external} (run-time validated at the mint). */
origin: Type.TOptional<Type.TObject<{
peer: Type.TString;
declaredBy: Type.TOptional<Type.TUnion<[Type.TLiteral<"center">, Type.TLiteral<"file">, Type.TLiteral<"request">]>>;
}>>;
/** Undeclared ⇒ `legacy:<shapeDigest>` / `unversioned`. */
contract: Type.TObject<{
contractId: Type.TString;
implementationRevision: Type.TString;
}>;
shapeDigest: Type.TString;
wireSchemaDigest: Type.TString;
/** `builtin:<name>` | `caller:<contractId>` | `mcp:<peer>/<tool>` | `a2a:<peer>/<skill>` | `external:<contractId>`. */
cardId: Type.TString;
/** ENGINE-minted: sha256 prefix over the canonical tuple {source, peer, name, contractId}; unique per leg. */
capabilityId: Type.TString;
/** The materialized schema's top-level properties (name + coarse type). */
inputKeys: Type.TArray<Type.TObject<{
name: Type.TString;
type: Type.TUnion<[Type.TLiteral<"string">, Type.TLiteral<"number">, Type.TLiteral<"integer">, Type.TLiteral<"boolean">, Type.TLiteral<"object">, Type.TLiteral<"array">, Type.TLiteral<"null">, Type.TLiteral<"mixed">]>;
}>>;
effect: Type.TUnion<[Type.TLiteral<"read">, Type.TLiteral<"write">, Type.TLiteral<"idempotent">]>;
effectProvenance: Type.TUnion<[Type.TLiteral<"declared">, Type.TLiteral<"caller">, Type.TLiteral<"synthetic">, Type.TLiteral<"default">]>;
offload: Type.TBoolean;
offloadThresholdChars: Type.TOptional<Type.TInteger>;
compactable: Type.TBoolean;
budgetExempt: Type.TBoolean;
egress: Type.TBoolean;
egressProvenance: Type.TUnion<[Type.TLiteral<"declared">, Type.TLiteral<"caller">, Type.TLiteral<"default">]>;
irreversibility: Type.TOptional<Type.TUnion<[Type.TLiteral<"never">, Type.TLiteral<"maybe">, Type.TLiteral<"always">]>>;
reversibilityProbe: Type.TBoolean;
contentOrigin: Type.TUnion<[Type.TLiteral<"local">, Type.TLiteral<"execution">, Type.TLiteral<"external">]>;
contentOriginProvenance: Type.TUnion<[Type.TLiteral<"declared">, Type.TLiteral<"server">, Type.TLiteral<"exempted">, Type.TLiteral<"default">]>;
family: Type.TUnion<[Type.TLiteral<"shell">, Type.TLiteral<"file-read">, Type.TLiteral<"file-write">, Type.TLiteral<"search">, Type.TLiteral<"web">, Type.TLiteral<"delegate">, Type.TLiteral<"plan">, Type.TLiteral<"scaffold">, Type.TLiteral<"memory">, Type.TLiteral<"protocol">, Type.TLiteral<"other">]>;
pathTarget: Type.TOptional<Type.TObject<{
param: Type.TString;
aliases: Type.TArray<Type.TString>;
access: Type.TUnion<[Type.TLiteral<"read">, Type.TLiteral<"create">, Type.TLiteral<"edit">]>;
skillScopeEligible: Type.TBoolean;
base: Type.TOptional<Type.TUnion<[Type.TLiteral<"cwd">, Type.TLiteral<"root">]>>;
absent: Type.TOptional<Type.TUnion<[Type.TLiteral<"none">, Type.TLiteral<"base">]>>;
patternParam: Type.TOptional<Type.TString>;
}>>;
ruleFace: Type.TObject<{
primaryParams: Type.TArray<Type.TString>;
params: Type.TArray<Type.TString>;
}>;
approvalPreview: Type.TBoolean;
validateInput: Type.TBoolean;
deferred: Type.TBoolean;
alwaysLoad: Type.TBoolean;
/** Present iff the definition carries a model-gate class and survived the gate. */
modelGate: Type.TOptional<Type.TString>;
renderHints: Type.TOptional<Type.TObject<{
userFacingName: Type.TOptional<Type.TString>;
activity: Type.TOptional<Type.TString>;
summaryParams: Type.TOptional<Type.TArray<Type.TString>>;
resultCards: Type.TOptional<Type.TArray<Type.TString>>;
approvalCard: Type.TOptional<Type.TUnion<[Type.TLiteral<"file-edit">, Type.TLiteral<"file-write">, Type.TLiteral<"notebook-edit">, Type.TLiteral<"shell">, Type.TLiteral<"fetch">, Type.TLiteral<"plan">, Type.TLiteral<"question">, Type.TLiteral<"generic">]>>;
}>>;
/** The ONE mount condition that fired for this instance. */
mountedBy: Type.TUnion<[Type.TLiteral<"hands">, Type.TLiteral<"backgroundTasks">, Type.TLiteral<"workflow">, Type.TLiteral<"delegation">, Type.TLiteral<"hostInternals">, Type.TLiteral<"peerLane">, Type.TLiteral<"scheduler">, Type.TLiteral<"memory">, Type.TLiteral<"scenario">, Type.TLiteral<"always">, Type.TLiteral<"optional">]>;
}>>;
/** sha256 prefix over the canonical COMPLETE rows — any axis / hint / contract / alias change moves it. */
digest: Type.TString;
}>;
/** Three pairwise-disjoint name lists; a `changed` name's new row is in `roster`. */
summary: Type.TObject<{
added: Type.TArray<Type.TString>;
removed: Type.TArray<Type.TString>;
changed: Type.TArray<Type.TString>;
}>;
}>;
export type ToolRosterDelta = Static<typeof ToolRosterDelta>;
/** The ONE name→row resolution every per-call reader shares (the call face, the park identity): the wire name first,
* then an alias — the same order the dispatcher resolves a model's call. */
export declare function rosterEntryNamed(roster: ToolRoster, toolName: string): ToolRosterEntry | undefined;
/**
* The ONE tool-name canonicalization: the wire name of the row `name` resolves to on the roster ({@link rosterEntryNamed}
* — the wire name first, then an alias, the dispatcher's order), or `name` itself when no row answers to it. The gate
* reads a call's name through it before any policy runs, and a rule's tool name reaches a call exactly when it
* canonicalizes to the same wire name (`ToolCallFace.names` is that set, minted here) — so a rule written against
* an alias and one written against the wire name are one rule.
*/
export declare function rosterToolName(roster: ToolRoster | undefined, name: string): string;
export { ruleNamesOf } from "./tool-name-readings.js";
/** design/388 B6 — the per-call face a gated request carries, read off a roster snapshot by name (aliases resolve).
* `names` leads with the name the face was minted under (the model's spelling at the gate), then the wire name and the
* other aliases — the ONE order of a call's names: a reader that must pick one of them by position (a `member` seat)
* picks the spelling first, as the same call was judged before name resolution. */
export declare function toolCallFaceOf(roster: ToolRoster | undefined, toolName: string): import("./tool-policy.js").ToolCallFace | undefined;
/** design/388 B18 — the identity members a park row carries, read off a roster snapshot by name; an empty object when
* the name is not on the snapshot (the row then reads pre-identity and the resume takes the name-only path). */
export declare function parkedToolIdentity(roster: ToolRoster | undefined, toolName: string): {
capabilityId?: string;
contractId?: string;
shapeDigest?: string;
implementationRevision?: string;
rosterDigest?: string;
};
/** design/388 B6 × B18 — the FACE members a park row carries beside its identity: the display family, the declared
* path target and the names the parked call was judged under. `names` is copied from the face the gate stamped on the
* request (the model's spelling first — the row carries the judged fact, it is not re-derived); a request with no face
* takes the roster's names for its row. A recheck that runs before the leg's roster exists (the pre-CAS resume-edit
* re-adjudication) rebuilds the call face from the row through {@link parkedCallFaceOf}, so it judges the same object
* the live gate judged. An empty object when the name is not on the snapshot (the row then reads pre-face and the
* recheck falls to the catalog for the name). */
export declare function parkedToolFace(roster: ToolRoster | undefined, req: {
readonly toolName: string;
readonly face?: {
readonly names?: readonly string[];
} | undefined;
}): {
family?: ToolFamily;
pathTarget?: ToolRosterEntry["pathTarget"];
names?: readonly string[];
};
/** The live face a resumed park row is re-judged under: minted under the row's recorded spelling (`names[0]`) when that
* spelling still resolves to the row's own tool on this roster, else under the row's wire name — a spelling that no
* longer resolves, or that another row now owns, never lends the row another tool's face. */
export declare function parkedRowLiveFace(roster: ToolRoster | undefined, row: {
readonly toolName: string;
readonly names?: readonly string[];
}): import("./tool-policy.js").ToolCallFace | undefined;
/** The call face a park row carries — present iff the row was minted with BOTH its face members and its four
* identity members (one mint writes all of them; a row missing any is pre-388 and yields undefined, never a
* partial face). This is the face every recheck of the row judges under, roster or no roster. */
export declare function parkedCallFaceOf(pending: {
family?: ToolFamily;
pathTarget?: ToolRosterPathTarget;
names?: readonly string[];
capabilityId?: string;
contractId?: string;
shapeDigest?: string;
implementationRevision?: string;
}): import("./tool-policy.js").ToolCallFace | undefined;
/** The optional `face` seat of a ToolCallRequest: present iff a face was read (a bare request carries no key). */
export declare function callFaceSeat(face: import("./tool-policy.js").ToolCallFace | undefined): {
face?: import("./tool-policy.js").ToolCallFace;
};
/** The four-tuple that decides "still the same tool" across a park (design/388 §2.5 boundary ②). */
export interface ToolIdentity {
capabilityId: string;
contractId: string;
shapeDigest: string;
implementationRevision: string;
}
export declare function toolIdentityOf(entry: ToolRosterEntry): ToolIdentity;
/** The engine-minted capability identity: a STRUCTURED tuple (never a joined string — `a:b`+`c` and `a`+`b:c`
* must not collide). Stable across legs for the same source/peer/name/contract. */
export declare function mintCapabilityId(t: {
source: RosterSource;
peer: string | null;
name: string;
contractId: string;
}): string;
export declare function rosterDigestOf(entries: readonly ToolRosterEntry[]): string;
/** The materialized schema's top-level properties, in declaration order. */
export declare function inputKeysOf(schema: TSchema | undefined): {
keys: ToolRosterEntry["inputKeys"];
scalar: Set<string>;
};
/** The roster's KEY bounds over a schema (design/388 B20): a problem sentence, or undefined when every top-level key fits.
* Shared by the caller declaration door (typed refusal) and the MCP intake (disclosed drop) — a key is never truncated. */
export declare function schemaKeyBoundProblem(schema: TSchema | undefined): string | undefined;
/** The identity members of one roster row the wire bounds hold, as a DECLARATION (the door) or a MINTED row hands them. */
export interface RosterBoundMembers {
name: string;
aliases?: readonly string[];
/** An MCP/A2A mount's peer (the row's `origin.peer`) — a NAME on the roster, held to the wire name bound. */
peer?: string;
contractId?: string;
implementationRevision?: string;
modelGate?: string;
cardId?: string;
}
/** The typed refusal a member over its bound mints — the door's two codes, and the mint's own for the members no
* declaration door names (`modelGate`, the derived `cardId`). Spelled out as literals (a consumer's tooling reads
* the words); each is a member of {@link ToolDeclarationCode}, which every mint below satisfies. */
export type RosterBoundCode = "config.tool_name_too_long" | "config.tool_contract_too_long" | "config.tool_roster_bound";
/**
* design/388 B20 / #626 ① — the ONE bound judge over a row's identity members: a problem `{ code, message }`, or
* undefined when every member fits. Read by the declaration door (a `TaskSpec.tools` entry, refused before session
* acquire) and by the row mint (every source — an MCP/A2A peer, a definition that reached the mint by a route the
* door does not cover — refused before the row exists). A member over its bound is NEVER truncated onto the row: a
* truncated identity is a different identity (`judgeParkedToolIdentity` compares it across a park; the card
* namespace door reads it), and the schema's own bounds would then describe a row the mint never made.
*/
export declare function rosterMemberBoundProblem(m: RosterBoundMembers): {
code: RosterBoundCode;
message: string;
} | undefined;
/**
* The rule vocabulary of ONE mounted instance (design/388 §2.2 ③ / D-3): DERIVED = the scalar top-level
* keys ∪ the path target's `param` + aliases; a declared `params` list can only NARROW it (a declared
* name outside the derived set is dropped — the L6 gate names it for a built-in); `primaryParams` =
* declared, else the path target's `param` + aliases.
*/
export declare function ruleFaceOfInstance(schema: TSchema | undefined, declared: ToolRuleFace | undefined, pathTarget: ToolPathTarget | undefined): {
primaryParams: string[];
params: string[];
};
/** What a mount site knows that the instance does not: where the tool came from and which condition fired. */
export interface RosterMountMeta {
source: RosterSource;
mountedBy: ToolMountTag;
/** Required for `mcp` / `a2a` / `external`; refused otherwise. */
origin?: {
peer: string;
declaredBy?: "center" | "file" | "request";
};
}
/** The face a mounted instance carries (forwarded by `defineTool`; read here by the same untyped-carry convention
* every other axis reader in the runner uses). */
export interface MountedToolFace {
effect?: ToolEffect;
egress?: true;
irreversibility?: "never" | "maybe" | "always";
reversibilityProbe?: unknown;
contentOrigin?: ToolContentOrigin;
offload?: boolean;
offloadThresholdChars?: number;
defer?: boolean;
alwaysLoad?: boolean;
mcpAlwaysLoad?: boolean;
family?: ToolFamily;
pathTarget?: ToolPathTarget;
ruleFace?: ToolRuleFace;
renderHints?: ToolRenderHints;
compactable?: true;
budgetExempt?: true;
modelGate?: string;
}
export declare const faceOf: (t: AgentTool) => MountedToolFace;
/** The leg facts the snapshot reads beside the instances — the safety scan's folds and the per-task knobs. */
export interface RosterSnapshotFacts {
/** The leg's by-name effect map (the builder is its mount-time writer; the protocol folds also write it). */
effects: ReadonlyMap<string, ToolEffect>;
egress: ReadonlySet<string>;
irreversibilityTier: ReadonlyMap<string, "never" | "maybe" | "always">;
reversibilityProbes: ReadonlyMap<string, unknown>;
/** Names the defer classification ships as placeholders. */
deferred: ReadonlySet<string>;
/** `TaskSpec.memory.trustedTools` — the exemption channel for an undeclared content class. */
trustedTools: ReadonlySet<string>;
}
export declare class RosterBuilder {
#private;
constructor(effects: Map<string, ToolEffect>);
/** The mount array as a READ face. The order is the wire order. */
get tools(): readonly AgentTool[];
get length(): number;
metaOf(tool: AgentTool): RosterMountMeta | undefined;
/** Mount one instance at the tail. An instance that DECLARES an effect writes it into the leg's effect map —
* the later mount under a name is the one the harness dispatches to (`snapshot`'s yield rule), so its
* declaration is the map's truth for that name; a pre-mount registration (the hand band, the plan pair, an
* MCP axis) stands only for names no mounted instance declares. ONE lane is different by construction: the
* `scenario` lane's declarations were latched by the safety scan BEFORE any mount, on the synchronous
* doors+scan stretch (a microtask cannot flip them) — so a scenario mount never re-reads its instance's
* effect over a registered name; an engine lane's mount under that name still displaces it. */
mount(tool: AgentTool, meta: RosterMountMeta): void;
/** An ENGINE-INJECTED instance the harness list carries outside the mount array (the ToolSearch lane): a roster
* row — the model can call it — never a mount-array element (the disclosure lane owns that list and appends the
* instance itself). Its row follows the mount array's rows in the snapshot; the same admission rules apply. */
mountEngineLane(tool: AgentTool, meta: RosterMountMeta): void;
mountAll(tools: readonly AgentTool[], meta: RosterMountMeta): void;
/** Remove every instance the predicate selects; returns them in mount order. */
unmountWhere(pred: (tool: AgentTool, index: number) => boolean): AgentTool[];
/** Swap the instance at `index` for another object standing for the SAME mount (a presentation re-render, a
* wrapper): the mount meta carries over. */
replaceAt(index: number, tool: AgentTool): void;
/**
* Re-insert a NAME-PREFIX domain in place (the RefreshMcpTools seam): every instance whose name starts with
* `prefix` is removed and `fresh` is spliced in at the domain's lowest former index (the wire prefix a
* provider cache reads stays put); a domain that was not mounted appends at the tail.
*/
replaceDomain(prefix: string, fresh: readonly AgentTool[], meta: RosterMountMeta): {
anchor: number;
};
/** Mint the roster: one row per mounted NAME, in order. Two mounted instances under one name follow the
* harness's own yield (the LATER mount is the one the model dispatches to — design/141 Q4, the
* `auditToolCollisions` "yield" record): the roster carries the surviving instance's row at the
* yielded instance's position and never a row per object. */
snapshot(facts: RosterSnapshotFacts): ToolRoster;
}
/**
* The roster's one declaration rule on engine names: a row whose names (its wire name and the aliases that resolve to it,
* {@link namesResolvingTo}) belong to TWO or more engine tools is refused — one tool answering as two engine tools would
* have every per-call seat keyed on engine names choose between two definitions of the call. A row answering to one engine
* tool under several of that tool's names, and an alias another row owns, are not counted twice. Undefined ⇒ none.
*/
export declare function rosterEngineNamesProblem(roster: ToolRoster): string | undefined;
/** Which source a `TaskSpec.tools` entry mounts as: a definition carrying a CORE contract is a built-in the host chose
* to mount; anything else is the caller's own tool. Identity follows the object, never the name. */
export declare function callerMountSource(tool: AgentTool): RosterSource;
/** The card namespace a roster row owns (design/388 §2.2 ④) — ONE mint, read by the row and by the prepare door that
* judges a caller's `renderHints.resultCards` against it: `builtin:<name>` for engine-owned definitions,
* `<mcp|a2a>:<peer>/<tool>` for protocol tools, `<caller|external>:<contractId>` for everything the caller mounts. */
export declare function rosterCardId(source: RosterSource, toolName: string, peer: string | null, protocolTool: string, contractId: string): string;
/** The card namespace a `TaskSpec.tools` entry will own once mounted — the same mint the row makes, so the prepare
* door and the roster row cannot disagree about which namespace a caller card must live under. */
export declare function callerCardIdOf(tool: Pick<AgentTool, "name" | "parameters">): string;
/** One row (design/388 §2.5). Every axis is read off the instance or the leg facts; nothing off a name table. */
export declare function mintRosterEntry(tool: AgentTool, meta: RosterMountMeta, facts: RosterSnapshotFacts): ToolRosterEntry;
/**
* The run-time delta seat: armed with the leg's minted roster and a re-snapshot closure at prepare, it
* re-mints the roster after every run-time roster change (the RefreshMcpTools seam), diffs it against the
* last published one and hands the delta to the stream (`tool_roster_delta`). Deltas published before a
* sink subscribes are buffered (bounded) and flushed at subscription, so the first consumer sees them.
*/
export declare class ToolRosterDeltaSeat {
#private;
arm(current: ToolRoster, snapshot: () => ToolRoster): void;
/** The last minted roster (the prepared one until a run-time change re-mints it). */
get current(): ToolRoster | undefined;
/** Re-mint after a run-time change; publishes and returns the delta (undefined before arming). A
* byte-identical re-mint still publishes: the consumer's summary is empty and its digest unchanged. */
republish(): ToolRosterDelta | undefined;
/** Install the stream sink; anything published before is flushed in order. */
subscribe(sink: (delta: ToolRosterDelta) => void): void;
/** The leg ended: drop the sink so a late republish never reaches a closed stream (it buffers, bounded, unread). */
unsubscribe(): void;
/** Take the buffered deltas (a consumer that polls instead of subscribing). */
drain(): ToolRosterDelta[];
}
/**
* design/388 B15 — the rule-face resolver a leg hands the rule compiler: every roster row answers with its
* derived vocabulary, the carried-but-non-scalar keys (so `Edit(edits:x)` reads `param_non_scalar`, not
* `param_unknown`) and whether it names a path target; a name off the roster answers undefined.
*/
export declare function ruleFacesFromRoster(roster: ToolRoster): (toolName: string) => {
primaryParams: readonly string[];
params: readonly string[];
nonScalar: readonly string[];
pathTargeting: boolean;
} | undefined;
/** The delta between two snapshots (design/388 §2.5): the whole `next` roster plus the name summary. */
export declare function diffToolRoster(prev: ToolRoster, next: ToolRoster): ToolRosterDelta;
/**
* The resume-side identity judgement (design/388 §2.5 boundary ②, B18/B19): a parked action carrying the
* four identity members is redeemed only against a same-name row whose four members ALL match; a row
* whose contract / shape / revision / source-peer moved is a replacement wearing the name, and the
* resume refuses it (`resume.tool_contract_mismatch`, same family and disposition as
* `resume.tool_unavailable`). A parked action minted BEFORE the identity members existed (all four absent)
* follows the name-only path and is never widened by their absence.
*/
export declare function judgeParkedToolIdentity(pending: {
capabilityId?: string;
contractId?: string;
shapeDigest?: string;
implementationRevision?: string;
}, row: ToolRosterEntry | undefined): "match" | "mismatch" | "name_only" | "absent";
/** The card-namespace check a CALLER declaration must pass at prepare (design/388 §2.2 ④): a `resultCards`
* entry must live under the tool's own `cardId`; naming an engine card (`builtin:*`, or a bare engine card
* type) is refused. Returns the offending entry, or undefined. */
export declare function offendingResultCard(hints: ToolRenderHints | undefined, cardId: string, engineCards: ReadonlySet<string>): string | undefined;