import type { PluginSummary } from "./registry.js"; /** * Progressive tool disclosure: which plugins are loaded right now, and how a * persisted set is restored across a run boundary. * * Two-tier disclosure exists because tool-selection accuracy degrades once a * model sees more than a few dozen tools, and because every tool's JSON Schema * is resent on every turn. Core plugins load unconditionally; the rest are * announced as a compact catalog and activated on demand. * * The governing rule for restoring a persisted set is that **it is a hint, not * a fact**. Names are persisted; implementations are resolved at load time, and * anything that no longer resolves is dropped rather than reported as active — * a plugin can be renamed, gated off, or (for a dynamically connected one) fail * to reconnect between runs. */ /** Why a persisted activation could not be restored. */ export type ActivationDropReason = "unknown" | "unavailable" | "unreachable" | "error"; export interface DroppedActivation { /** The canonicalized name that was dropped. */ name: string; reason: ActivationDropReason; } export interface RehydrateResult { /** Canonicalized, de-duplicated names that resolved and stay active. */ active: string[]; /** Everything that did not survive, for the host to log. */ dropped: DroppedActivation[]; } export interface RehydrateOptions { /** Map a persisted (possibly legacy) name to its current canonical name. */ canonicalizeName: (name: string) => string; /** * Can this name be activated on THIS run? Async because restoring a * dynamically connected plugin may require re-establishing a connection — * the harness owns the policy, the host owns the transport. * * Return `true` to keep, or a drop reason to discard. */ resolve: (name: string) => ActivationDropReason | true | Promise; /** * Observe a resolver rejection. The entry is dropped as `"error"` either way, * and an observer that throws is swallowed — reporting a failure must not * turn one bad name into a failed restore. */ onResolveError?: (name: string, error: unknown) => void; } /** * Restore a persisted activation set, re-validating every entry against * current reality. Order is preserved; duplicates (including two legacy names * that canonicalize to the same plugin) collapse to the first occurrence. */ export declare function rehydrateActivation(persisted: readonly string[], options: RehydrateOptions): Promise; /** The activation set a fresh run starts from. */ export declare function initialActivePlugins(corePlugins: readonly string[]): string[]; export interface CatalogPartition { active: PluginSummary[]; loadable: PluginSummary[]; } /** * Split the catalog into what is already active and what the model may load. * * This returns **data, not prose**: the wording of a catalog belongs to the * host's system prompt, which is a product surface with its own voice and * (in Monad's case) its own byte-for-byte prompt-cache concerns. */ export declare function partitionPluginCatalog(activePlugins: ReadonlySet, allSummaries: readonly PluginSummary[]): CatalogPartition;