UNPKG

@sema-agent/core

Version:

Stateless, task-oriented AI agent core

75 lines (74 loc) • 5.5 kB
/** * `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;