import { type SkillSummary } from "./types.js"; /** * Total order over summaries: origin, then name, then ref. * * A **total** order, not just a stable one: `ref` is the unique tiebreak so two * skills that collide on name still sort deterministically. Both the catalog * and the injected instruction bodies use this comparator, which is what keeps * the system prompt byte-stable across a fresh run and a resumed one — the * active set is persisted in load order, and rendering in *that* order would * shift the prefix on every resume. */ export declare function compareSkillSummaries(a: SkillSummary, b: SkillSummary): number; /** How much of a skill's catalog entry survived the budget. */ export type SkillCatalogDetail = "full" | "name_only"; export interface SkillCatalogEntry { summary: SkillSummary; detail: SkillCatalogDetail; } export interface SkillCatalogPartition { /** Already loaded. Always rendered in full — the body's cost is already paid. */ active: SkillSummary[]; /** Loadable, each marked with the detail the budget allows. */ loadable: SkillCatalogEntry[]; /** How many loadable entries were demoted to `name_only`. */ truncated: number; } export interface SkillCatalogOptions { /** Defaults to {@link SKILL_CATALOG_TOKEN_BUDGET}. */ tokenBudget?: number; /** * Cost of one entry at a given detail, in tokens. Defaults to an estimate of * `- name: description — whenToUse`. * * A host that renders a different line should pass its own: the budget is * only as honest as its measurement, and a default that under-counts a * verbose format silently overruns the prefix it was meant to protect. */ cost?: (summary: SkillSummary, detail: SkillCatalogDetail) => number; } /** * Split the catalog into active and loadable, demoting the loadable tail to * names only once the budget is spent. * * **Demote, never drop.** A skill the model cannot see is a skill it cannot * ask for, and a workspace's library grows past any budget worth setting. A * bare name still routes: it is enough for the model to call `load_skill` and * read the real description. The host is expected to say so in the line it * renders for the truncated tail — `truncated` is there to let it. * * The active set is charged against the budget but never demoted: those bodies * are already in the prompt, so shortening their catalog lines would save * nothing that matters while hiding what the agent is currently working from. */ export declare function partitionSkillCatalog(activeSkills: ReadonlySet, available: readonly SkillSummary[], options?: SkillCatalogOptions): SkillCatalogPartition;