/** * Slim-index renderer. * * Renders the `` block injected into the SDK's wire * `instructions` field. The renderer is pure: input = catalog + * options, output = `{ text, included, truncated, telemetry }`. * * Per `skills.md` §5 and `skills-activation.md` §3: * * - Per-entry combined `description + when_to_use` capped at 1,536 chars. * - Total block capped at `min(8000, ceil(0.01 * contextWindow))`, * configurable via `SkillsConfig.indexCharBudget`. * - When the catalog fits: include every latest-version skill that is * not `disable-model-invocation: true` and matches the optional * `paths:` filter context. * - When the catalog exceeds budget AND no embedder is configured: * truncate by `mtime` descending, then alphabetical; emit * `sdk.skill.index_truncated`. * - Caller-pinned skills are always included. If a pinned skill's * entry doesn't fit, the budget is exceeded — emit * `sdk.skill.index_overflow_pinned` and proceed. * - `disable-model-invocation: true` skills are **filtered out** of * the model-visible slim index unless caller-pinned. Pinning is the * explicit human-in-the-loop waiver (`skills-activation.md` §2.85). * Pinned user-only skills are still rendered with the `[loaded]` * marker. * - Caller-pinned + already-loaded entries marked `[loaded]`. */ import type { ParsedSkill, SkillEvent } from './types.js'; /** * Per-call rendering options. Each field has a sensible default — the * minimum input is `{ skills }`. */ export interface RenderOptions { /** Total block char budget. Defaults to `DEFAULT_INDEX_CHAR_BUDGET` (8000). */ readonly charBudget?: number; /** * Caller-pinned skills (FQNs or bare names). The renderer includes * these unconditionally and decorates them with the `[loaded]` marker * since pinning means the body is already in conversation. */ readonly pinned?: readonly string[]; /** * "Current file" context for `paths:` filtering. Consumers without a * current-file concept omit this; the renderer treats `paths:` as a * no-op for those skills. */ readonly currentFilePath?: string; /** * Whether the renderer is rendering in `paths`-aware mode. Defaults to * `true` iff `currentFilePath` is set; consumers can force-disable * by passing `false` so a skill carrying `paths:` is always shown * regardless of context (useful for Slack-bot-style consumers). */ readonly enablePathsFilter?: boolean; } export interface RenderResult { /** The rendered `...` block. Empty string when no skills land. */ readonly text: string; /** Skills that made it into the rendered block, in render order. */ readonly included: readonly ParsedSkill[]; /** `true` iff one or more skills were dropped by budget pressure. */ readonly truncated: boolean; /** Total char count of `text`. */ readonly charsUsed: number; /** Telemetry events the renderer would emit. Caller dispatches to the configured sink. */ readonly events: readonly SkillEvent[]; /** * Pinned skills that were dropped because rendering them would have * pushed the block past the renderer's hard cap (F5 — `2 × * charBudget`, floored at `charBudget + 4096`). Empty in the common * case. `TaskClient` throws `SkillsBudgetExceededError` when this is * non-empty so a buggy caller-pin list surfaces as a loud failure * instead of a silently truncated wire payload. */ readonly omittedPinned: readonly ParsedSkill[]; } /** * Render the slim index. Pure function — no IO, no state mutation; the * caller routes the returned `events` to the configured telemetry sink. */ export declare function renderSlimIndex(skills: readonly ParsedSkill[], opts?: RenderOptions): RenderResult; //# sourceMappingURL=render.d.ts.map