import type { ResolvedSkillInstructions } from "./resolve.js"; import type { SkillSummary, SkillWarn } from "./types.js"; /** * Progressive knowledge disclosure — the skill half of `plugins/activation.ts`. * * The controller does one thing and refuses to do a second: it adds refs to the * run's active set, resolves the bodies, records the hash pin, and hands the * full resolved set back. It **never touches the transcript**. The system * message is a pure render of run state, so a host re-renders it from the * instructions it is given rather than splicing a marker or mutating a string * in place — the difference shows up the first time a run is resumed and the * spliced text is already there twice. */ /** * The skill read path, injectable. The other half of the source — the Tier-1 * catalog — is the `availableSkills` array, so a host customizes both * independently: an in-memory store for a test, an isolated one-skill store for * an always-on persona, the real registry plus its database for a live run. */ export interface SkillStore { resolveActiveInstructions(activeRefs: string[]): Promise; } export interface SkillActivation { /** * Activate skills for this run: admit the refs that are in the catalog, * resolve the bodies for the **whole** active set, pin their hashes, and hand * the instructions to `applyInstructions`. * * Resolution covers the whole set rather than the delta because the caller * re-renders one section from the result; a delta would make it the caller's * job to concatenate in the right order, which is the ordering guarantee the * resolver exists to own. A call that admits nothing new is a no-op. */ activateSkills(refs: Iterable): Promise; } export interface SkillActivationParams { /** This run's Tier-1 catalog — the set a ref must be in to be activatable. */ availableSkills: readonly SkillSummary[]; /** * Caller-owned active-ref set, mutated in place. * * Owned by the caller because two other things read it: conversation assembly * seeds it before the first turn (it is what the initial catalog renders as * active), and the host persists it when the run ends. */ activeSkills: Set; /** * Caller-owned ref → `contentSha` pin, grown on each activation. * * Also caller-owned, and for a sharper reason: a host hoists it above the try * block so the terminal-path catch can still persist what the run had loaded. * A pin the controller owned would be lost on exactly the failed runs an eval * most wants to reproduce. */ loadedSkillShas: Record; store: SkillStore; /** * Called after each activation that changed the set, with the freshly * resolved bodies for the full active set. */ applyInstructions: (instructions: string[]) => void; onWarn?: SkillWarn; } export declare function createSkillActivation(params: SkillActivationParams): SkillActivation;