@sema-agent/core
Version:
Stateless, task-oriented AI agent core
75 lines (74 loc) • 5.5 kB
TypeScript
/**
* `mcp.injection_dropped` — the one mint of the notice a host raises when an entry of the user's own
* MCP injection (a `.mcp.json` row handed to the engine through the host's request lane) was NOT
* mounted for the leg. L-167: three drop sites in the host's intake and one cap site each produced
* their own wording and none reached the user; the engine did not see the entry at all (it never
* reached `prepareTask`), so no core-side notice could stand for it.
*
* Division of labour, the settlement pattern (`settlement.single_mint`): the HOST supplies FACTS
* (which session, which server name, which of four reasons, optionally which field was bad) and
* CORE composes the notice — the code word, the audience row, the message text per reason. A host
* never spells the code or the text itself: a second wording is a second source that drifts, and a
* host-spelled code is not in {@link import("./governance-codes.js").ENGINE_NOTICE_CODES}'s
* mint scan, so its audience row could silently rot.
*
* Audience `"user"`: the dropped entry is the user's own configuration and the recovery (rename the
* server, fix the field, trim the list) is in their hands — an operator channel does not reach them.
* `sessionId` is therefore REQUIRED at the mint (the routing half of a user row: a user disclosure
* that cannot name its session has nowhere to be delivered) — a host with no session has no user to
* tell and must not mint. Dedup unit: per leg per server name — the HOST's obligation (it owns the
* leg's intake loop); this module is pure.
*/
import type { AssertAllKeysHandled } from "./ask-origin.js";
import type { EngineNotice } from "./engine-notice.js";
/**
* The closed set of drop reasons ({@link McpInjectionDropFacts.reason}) — the host's intake
* enumerates exactly these, and a consumer rendering the notice keys on the word:
* · `malformed_entry` — the entry did not parse as a server declaration (a missing
* `command`/`url`, a `toolFaces` value of the wrong shape, …);
* `field` names the offending key when the host knows it;
* · `name_reserved_by_deployment` — the entry's server name collides with one the deployment
* itself mounts, and the deployment's wins;
* · `gate_closed` — the deployment does not accept request-lane MCP injection on
* this leg at all (a multi-tenant posture): the whole list is
* ignored, one notice per entry;
* · `over_cap` — the entry sits beyond the deployment's injection cap.
*/
export declare const MCP_INJECTION_DROP_REASONS: readonly ["malformed_entry", "name_reserved_by_deployment", "gate_closed", "over_cap"];
export type McpInjectionDropReason = (typeof MCP_INJECTION_DROP_REASONS)[number];
/**
* The user-facing sentence per reason — the disposition table over {@link MCP_INJECTION_DROP_REASONS}
* (one reason, one wording; a consumer that wants its own phrasing keys on `detail.reason`, never on
* this text). Each names the recovery, because the reader is the person who can perform it.
*/
export declare const MCP_INJECTION_DROP_TEXT: {
readonly malformed_entry: "its declaration could not be read — fix the entry and start a new session";
readonly name_reserved_by_deployment: "the deployment mounts a server of that name and its own wins — rename the entry";
readonly gate_closed: "this deployment does not accept MCP servers from the request on this leg — ask the operator, or use the deployment's servers";
readonly over_cap: "the request named more MCP servers than this deployment mounts per leg — trim the list";
};
export type DropTextCoversEveryReason = AssertAllKeysHandled<Exclude<McpInjectionDropReason, keyof typeof MCP_INJECTION_DROP_TEXT>>;
/** What a host knows at the drop site — facts only, no words of the engine's vocabulary composed. */
export interface McpInjectionDropFacts {
/** The session whose injection carried the entry — the notice's routing key, required (see module note). */
readonly sessionId: string;
/** The entry's server name as the user spelled it (the message quotes it verbatim). */
readonly server: string;
readonly reason: McpInjectionDropReason;
/** `malformed_entry` only, optional: the key the host found bad, so the user knows what to edit. */
readonly field?: string;
}
/**
* Compose the `mcp.injection_dropped` notice from a host's facts.
*
* @contract mcp.injection_dropped.single_mint — the `mcp.injection_dropped` notice is composed by CORE
* from a host's drop FACTS (session, server name, one of four reasons, optionally the bad field); a
* host never spells the code, the audience or the sentence, and a fact outside the vocabulary (an
* unlisted reason word, an empty session or server name) is refused at the mint with a `TypeError`
* rather than shaped into a notice that would route nowhere or read as an unknown word downstream.
*
* `detail: { sessionId, server, reason, field? }` — `sessionId` is lifted onto the typed key by
* {@link import("./engine-notice.js").deliverEngineNotice}, the one throat, so the two spellings
* cannot disagree; `field` is present only when the host supplied a non-empty one.
*/
export declare function mcpInjectionDroppedNotice(facts: McpInjectionDropFacts): EngineNotice;