/**
 * defineSkill — sugar for LLM-activated Injections that target both
 * system-prompt + tools.
 *
 * A Skill is a bundle of (1) a body of guidance and (2) optionally some
 * tools. The LLM decides when a Skill is needed by calling a designated
 * activation tool — by default `read_skill(<id>)`.
 *
 * Activation is about the BODY. A Skill's tools are registered up front
 * and callable from iteration 1 unless the Skill sets
 * `autoActivate: 'currentSkill'` — see that option.
 *
 * **Activation lifetime: the rest of the turn.** Once the model picks a
 * skill with `read_skill`, the activation lasts until the turn ends — every
 * later iteration of that `run()` keeps the body active, and there is no
 * mid-turn deactivation (nothing removes an id from
 * `ctx.activatedInjectionIds`; the next `run()` starts clean). This is
 * deliberate: the cache layer's skill history and the context ledger both
 * lean on the cumulative property. A skill that should stop applying
 * mid-turn is a `rule` trigger or a `skillGraph()` route, not a read_skill
 * pick.
 *
 * Produces an `Injection` with:
 *   - flavor: `'skill'`
 *   - trigger: `{ kind: 'llm-activated', viaToolName: 'read_skill' }`
 *   - inject: `{ systemPrompt: body, tools }`
 *
 * The Agent integration auto-attaches the `read_skill` tool when one
 * or more Skills are present. When the LLM calls
 * `read_skill('billing')`, the engine adds `'billing'` to
 * `ctx.activatedInjectionIds`; the next iteration's evaluator
 * matches this Skill's `id`, activates it, and the body lands in the
 * slot subflows (plus the tools, for an `autoActivate` Skill — every
 * other Skill's tools were already there).
 *
 * @example
 *   const billingSkill = defineSkill({
 *     id: 'billing',
 *     description: 'Use for refunds, charges, billing questions.',
 *     body: 'When handling billing: confirm identity first, then…',
 *     tools: [refundTool, chargeHistoryTool],
 *   });
 */
import type { Injection } from '../types.js';
import type { Tool } from '../../tools/tools.js';
import type { CachePolicy } from '../../cache/types.js';
import { type OnSkipPolicy, type SkillStep } from '../skillSteps.js';
/**
 * Where the Skill's body lands when activated.
 *
 * Delivery reads the mode you DECLARED, literally — `buildSystemPromptSlot`
 * decides the system slot, the `read_skill` tool decides its own result:
 *
 * - `'system-prompt'` — body appended to the system slot on the
 *   iteration after activation; the `read_skill` result is a one-line
 *   confirmation. Best on Claude ≥ 3.5 (training-time adherence to
 *   system-prompt instructions is strong).
 * - `'tool-only'` — body SUPPRESSED from the system slot and returned as
 *   the `read_skill` tool result instead. Recency-first by protocol;
 *   doesn't rely on the model's training to honor system-prompt
 *   anchoring. Legal only on a Skill that `read_skill` really activates —
 *   a Skill a skill graph routes to is refused at build time, because the
 *   tool call that would carry the body never happens (`skillBodyDelivery.ts`).
 * - `'both'` — body lands in the system slot AND in the tool result.
 *   Belt-and-suspenders for high-stakes Skills on long-context runs.
 * - `'auto'` (the default) — delivered exactly like `'system-prompt'`:
 *   body in the system slot, tool result is a confirmation. It is NOT
 *   resolved per provider on the delivery path.
 *
 * `resolveSurfaceMode(provider, model)` — Claude ≥ 3.5 → `'both'`, else
 * `'tool-only'` — is the per-provider RECOMMENDATION, and it runs only where
 * something asks for it: `SkillRegistry.resolveForSkill(...)` (the skill →
 * registry → provider cascade) and `resolvedSurfaceModeOf(skill, provider,
 * model)`. Nothing on the delivery path calls it, so feed its answer back in
 * as an explicit `surfaceMode` if you want it honored.
 */
export type SurfaceMode = 'auto' | 'system-prompt' | 'tool-only' | 'both';
export interface DefineSkillOptions {
    readonly id: string;
    /** Visible to the LLM via the activation tool's description. */
    readonly description: string;
    /**
     * The skill's plain name for a PERSON — "array estate report" for the id
     * `array-inventory`. Optional: at most 60 characters, one line, and not the
     * id itself.
     *
     * Record-only: it rides `agentfootprint.skill.graph_declared` (`nodes[].title`)
     * so a report can name the skill in plain words, and nothing the model reads
     * changes — the activation menu, the graph's drawn `label`, Mermaid and the
     * lens captions keep the id. Absent = not declared, and the event carries
     * the bytes it always did.
     */
    readonly title?: string;
    /** Body appended to the system-prompt slot once activated. */
    readonly body: string;
    /** Tools this Skill contributes. **By default they are added to the agent's tool
     *  registry at build time and are visible to the model from the first iteration,
     *  whether or not the Skill is ever activated** — activation adds the Skill's
     *  body, not its tools. To make the tools appear only while the Skill is active,
     *  set `autoActivate: 'currentSkill'`; `skillGraph().tree()` sets it for you on
     *  every leaf. If a tool must never be offered before activation, that is not a
     *  default — say so with `autoActivate`. */
    readonly tools?: readonly Tool[];
    /**
     * Where the body lands when activated. See `SurfaceMode`. Default
     * `'auto'`, which delivers like `'system-prompt'`; name a mode
     * explicitly to get the other channels.
     */
    readonly surfaceMode?: SurfaceMode;
    /**
     * Per-skill tool gating — the field that makes this Skill's `tools`
     * appear only while the Skill is active.
     *
     * - `'currentSkill'` — this Skill's `tools` are held out of the agent's
     *   static tool list and offered to the model only on iterations where
     *   the Skill is active. Outside the Agent's own wiring, materialize the
     *   same gate with `skillScopedTools(id, tools)` from
     *   `agentfootprint/providers`.
     * - `undefined` (default) — additive: this Skill's tools go into the
     *   agent's registry at BUILD time and the model can see and call them
     *   from iteration 1, activated or not.
     *
     * Saying it once for the whole agent instead of once per skill:
     * `.toolsFromActiveSkill()` on the builder (9.36.0) stamps this field on
     * every tool-carrying skill, and `skillGraph({ scopeTools: true })` stamps it
     * on the skills a graph wires. Both are DEFAULTS — a skill that declared its
     * own keeps it — and since `'currentSkill'` is the only legal value, none of
     * the three can contradict another.
     *
     * Wired at runtime since v2.5: `buildToolRegistry` holds these tools out of the
     * static registry and `buildToolsSlot` readmits them per-iteration from the
     * active injections. Dispatch is unaffected either way — an autoActivate tool
     * stays callable by name once activated. Read `skill.metadata.autoActivate` if
     * you compose your own ToolProvider.
     */
    readonly autoActivate?: AutoActivateMode;
    /**
     * The procedure, as data (9.18.0). An ordered list of `{ tool, note }`
     * pairs naming this skill's OWN tools (a step naming a tool the skill
     * does not carry is refused here, where both arrive together).
     *
     * While this skill holds the tenure, the framework owns sequence and
     * scope at the protocol level: the tools slot offers the CURRENT step's
     * tool (its description led by `[Step k of n — <note>]`) plus `skip_step`
     * — and every escape hatch stays offered (`read_skill`, other active
     * skills' tools, the baseline `.tool()` registry, provider tools), so an
     * input the author never imagined still has the whole normal surface.
     * The model owns judgment inside a step: run it, skip it with a recorded
     * reason, work around it, or stop and say why.
     *
     * Absent → this skill is byte-identical to today (zero-cost-when-unused:
     * no tool, no scope key, no event, no slot change).
     *
     * Steps are TURN-scoped: the pointer resets on every cursor move and on
     * every new run. Under a graph's `continuity: 'conversation'` the CURSOR
     * carries across turns and the re-tenured skill starts at step 1 on the
     * continued turn — the pointer is subordinate to the cursor, made
     * visible. (The prior turn's completed step results are still in the
     * restored history; the record is not lost, the pointer is fresh.)
     */
    readonly steps?: readonly SkillStep[];
    /**
     * What the framework does when the model skips a step with `skip_step`
     * (9.18.0): `'advance'` (default) — record the skip and move to the next
     * step; `'hold'` — record the skip and keep the step current (its tool
     * stays the offer; the model may retry it, use an escape hatch, or finish
     * and explain). Legal only beside `steps`.
     */
    readonly onSkip?: OnSkipPolicy;
    /**
     * Artifact KINDS this skill leaves behind (9.25.0) — the producer half of
     * its data vocabulary: `produces: ['chart/spec']`.
     *
     * A DECLARATION, not machinery. Nothing at run time reads it, nothing is
     * enforced at dispatch (that is `wants`' job, against the live store), and
     * a skill that declares none is byte-identical to one that never heard of
     * them. What it buys: the build-time check that a consumer's kind has a
     * producer somewhere (`artifact-kind-unsatisfied`), and a fact on this
     * skill's metadata that a lens can draw — the data legs of a run, before
     * the run.
     */
    readonly produces?: readonly string[];
    /**
     * Artifact KINDS this skill needs to have arrived (9.25.0):
     * `consumes: ['dataset/rows']` — "somebody upstream made a dataset; this
     * skill turns it into something".
     *
     * Checked at build against what the agent declares it produces. The check
     * is deliberately weak-but-true: it warns only when NOTHING on the agent
     * declares that kind, and it never fires when one of this skill's tools
     * declares `wants` for it (that ref is redeemed at dispatch from a store
     * that outlives the turn, so the kind can legitimately arrive from another
     * agent or an earlier run). See `skillVocabulary.ts` for the whole rule and
     * everything it cannot see.
     */
    readonly consumes?: readonly string[];
    /**
     * This skill's BRAIN (9.19.0) — "the cursor picks the brain": while a
     * mounted skill graph's cursor is on this skill, `callLLM` runs on this
     * provider instead of the agent's. Any `LLMProvider` port implementation;
     * vendor-neutral by construction. A provider whose `name` differs from
     * the agent's MUST also name `model` (the agent's model id belongs to
     * another vendor's namespace — refused at `Agent.build()` otherwise).
     * Legal only on agents that mount a graph; the same skill id may also be
     * declared in `skillGraph(graph, { providers })` — same choice is fine,
     * different choices are refused naming both homes. Absent → this skill is
     * byte-identical to today.
     */
    readonly provider?: import('../../provider-contract/types.js').LLMProvider;
    /**
     * The model this skill's calls run on (9.19.0). Legal ALONE — the agent's
     * own provider, another model ("triage runs on the small one") — or
     * beside `provider`. Absent with `provider` set: inherits down the
     * precedence chain (escalation > skill brain > `.configure()` >
     * build-time default), which is legal only while the provider is the
     * agent's own.
     */
    readonly model?: string;
    /**
     * Cache policy for this skill's body. Defaults to `'while-active'` —
     * the body caches while the skill is in `activeInjections[]` (i.e.,
     * while it's the most-recently-activated skill); invalidates the
     * moment it deactivates.
     *
     * For skills with stable, frequently-accessed bodies, consider
     * `'always'` to keep the body cached even when temporarily inactive.
     * For skills with bodies that depend on per-iter state, use
     * `'never'` or `{ until: ... }`.
     *
     * See `CachePolicy` in `agentfootprint/src/cache/types.ts`.
     */
    readonly cache?: CachePolicy;
}
/**
 * Per-skill tool gating mode. See `DefineSkillOptions.autoActivate`.
 *
 * Reserved future values: `'always'` (always show this Skill's tools
 * regardless of activation), `'group'` (gate by a named skill group).
 */
export type AutoActivateMode = 'currentSkill';
/**
 * Resolve `surfaceMode: 'auto'` to a concrete mode based on provider
 * + model. The defaults match the per-provider attention profile
 * documented in the Skills, explained essay:
 *
 *   - Claude >= 3.5  → 'both'      (cheap to cache, high adherence)
 *   - Claude pre-3.5 → 'tool-only' (recency-first more reliable)
 *   - OpenAI / Bedrock / Ollama / Mock / unknown → 'tool-only'
 *
 * Pure function — no side effects. Consumers can call directly to
 * inspect what `'auto'` will resolve to in their stack.
 */
export declare function resolveSurfaceMode(provider: string, model?: string): SurfaceMode;
export declare function defineSkill(opts: DefineSkillOptions): Injection;
/**
 * Internal facade entry, deliberately absent from every public barrel.
 * Validate the original declaration, preserving inherited options and getter
 * receivers. Only this entry consumes the unified factory's discriminant.
 */
export declare function defineSkillInjection(opts: DefineSkillOptions & {
    readonly type: 'skill';
}): Injection;
//# sourceMappingURL=defineSkill.d.ts.map