import { type LanguageModel } from 'ai';
import { type ResolveModelOptions } from './model-resolver.js';
/** Loose shape of a SpecVerse prompt YAML — system block + user.template. */
export interface PromptYaml {
    name?: string;
    version?: string;
    /**
     * Backing Claude skill family (e.g. `'analyse'`). Stamped onto COMPOSED
     * prompts by self/scripts/compose-prompts.mjs from the family map. When set,
     * the same operation's grounding is also available as the installed skill's
     * `reference/<operation>.md`, so on the claude-cli path (with the skill
     * installed) {@link runPrompt} sends a THIN system (role + a read-the-skill
     * pointer) and lets the CLI auto-load the grounding — no double-send. Absent
     * on source prompts and on INLINE_ONLY ops (e.g. realize-owner), which keep
     * the full-grounding delivery.
     */
    skill?: string;
    system?: {
        intro?: string;
        role?: string;
        minimalContext?: string;
        fullContext?: string;
        context?: string;
    };
    user?: {
        template?: string;
    };
}
/** The active composed-prompt tag — selects which `_composed/<tag>/` bundle to
 *  load, and is recorded in run manifests for A/B traceability across prompt
 *  iterations. Override via the SPECVERSE_PROMPT_TAG env var; default `current`. */
export declare function promptTag(): string;
/** Resolve the canonical prompt YAML for a given operation. */
export declare function loadPrompt(operation: string): PromptYaml;
/** Substitute {{var}} placeholders in `text` from `values` + auto-filled schema paths. */
export declare function substitute(text: string, values: Record<string, string | undefined>): string;
/** Assemble the system message from a prompt YAML. */
export declare function assembleSystem(prompt: PromptYaml): string;
/**
 * Provider-aware skill inlining. Used by {@link runPrompt} to combine
 * the assembled base system prompt with the content of named skills
 * for providers that can't auto-load skills from the filesystem.
 *
 *   - `claude-cli` → returns `baseSystem` unchanged. The CLI loads
 *     skills natively from `~/.claude/skills/` based on the
 *     SKILL.md description; inlining would double-pay the tokens.
 *   - any other provider AND skills installed → prepends each skill's
 *     content (SKILL.md body + reference/*.md) to the base system
 *     prompt, separated by `---` rules.
 *   - any other provider AND skills NOT installed → returns
 *     `baseSystem` unchanged.
 *
 * Exported for testing in isolation; `runPrompt` calls this with the
 * resolved model's `provider` field.
 */
export declare function assembleSystemWithSkills(baseSystem: string, providerId: string | undefined, skillNames: string[], cwd?: string): string;
/**
 * The THIN system for a skill-backed op on the claude-cli path: the always-sent
 * `role` (identity) plus an explicit pointer telling the CLI to read the backing
 * skill's per-operation reference. The grounding itself is NOT inlined — the CLI
 * auto-loads the installed skill, so inlining would double-pay the tokens (the
 * whole point of the skill path). The reference body is byte-identical to the
 * grounding the full path inlines (compose-prompts parity gate), so output is
 * equivalent. Used only when {@link runPrompt} has confirmed the skill installed.
 *
 * Exported for testing in isolation.
 */
export declare function assembleSystemThin(prompt: PromptYaml, skillName: string, operation: string): string;
/**
 * The single delivery decision point (Phase 2b/3): given a loaded prompt + the
 * resolved provider, return the system message to send.
 *
 *   - skill-backed op (`prompt.skill` stamped by compose) + claude-cli + that
 *     skill installed → THIN (role + a read-the-skill pointer); the CLI auto-loads
 *     the grounding, so it isn't inlined — no double-send.
 *   - everything else → FULL grounding: the composed prompt's system as-is, plus
 *     any `skills` inlined for non-claude (the grounding-is-skill-only realize-owner
 *     path passes `skills:['realize-emit']`; that skill's content lives only in the
 *     skill files, so non-claude providers need it inlined here).
 *
 * Used by {@link runPrompt} and by BehaviorAIService so both share one code path
 * (the "fold behavior into runPrompt's delivery" cleanup).
 */
export declare function assembleDeliverySystem(prompt: PromptYaml, providerId: string | undefined, operation: string, opts?: {
    skills?: string[];
    cwd?: string;
}): string;
/** Assemble the user message — substitute case variables into user.template. */
export declare function assembleUser(prompt: PromptYaml, values: Record<string, string | undefined>): string;
export interface BuildRunModelOptions extends ResolveModelOptions {
    timeoutMs?: number;
}
/**
 * Build a single model instance for a whole run. Pass the returned model to
 * every runPrompt call in the run so the claude-cli provider's session-resume
 * (--session-id then --resume) actually fires across cases — first case pays
 * the system-prompt cost, subsequent cases hit cache. ~75% input-token
 * reduction on a typical 8-case run.
 */
export declare function buildRunModel({ timeoutMs, ...modelOptions }?: BuildRunModelOptions): LanguageModel;
export interface RunPromptOptions {
    operation: string;
    values: Record<string, string | undefined>;
    model?: LanguageModel;
    modelOptions?: ResolveModelOptions;
    timeoutMs?: number;
    onAssembled?: (parts: {
        system: string;
        user: string;
    }) => void;
    userPrefix?: string;
    /**
     * Claude-skill names to inline into the system prompt for providers
     * that don't auto-load skills natively (anything other than
     * `claude-cli`). For `claude-cli`, skills are loaded by the CLI from
     * `~/.claude/skills/` based on prompt-context relevance — the prompt
     * runner does NOT need to inline. For other providers
     * (`anthropic`, `openai-compatible`, `stub`), we read each named
     * skill's `SKILL.md` + `reference/*.md` from disk and prepend the
     * content to the system message so the LLM sees the same
     * CONSTRAINTS / GUIDANCE / EXAMPLE content claude-cli users get.
     *
     * Skill content lives at one source of truth on disk; the loading
     * mechanism differs per provider, but the LLM sees equivalent
     * context either way.
     *
     * Names are skill directory names under `~/.claude/skills/` (e.g.
     * `'realize-emit'`). Missing skills are silently skipped; callers
     * fall back to the thin prompt as-is.
     */
    skills?: string[];
}
export interface RunPromptResult {
    text: string;
    tokens: {
        input: number | null;
        output: number | null;
    };
    duration_ms: number;
    system: string;
    user: string;
    providerId: string;
    modelId: string;
}
/**
 * Run a prompt with given values. Returns the LLM's text + telemetry.
 */
export declare function runPrompt({ operation, values, model, modelOptions, timeoutMs, onAssembled, userPrefix, skills, }: RunPromptOptions): Promise<RunPromptResult>;
/** Strip a markdown ```yaml/```specly fence + leading prose from a model output.
 *  Returns the FIRST fenced block's content. */
export declare function extractSpec(text: string): string;
/**
 * Extract two consecutive fenced blocks from a model output — used by the
 * analyse pipeline (TODO #36) where the LLM emits a `specly` block followed
 * by a `yaml` manifest block.
 *
 * Returns:
 *   { spec: <first block>, manifest: <second block> | null }
 *
 * If only one block is present, `manifest` is null and the caller should
 * fall back (legacy single-block specs treated as spec-only). If a top-
 * level `manifest:` key is detected inside the spec block, the caller may
 * additionally choose to extract that as a backup — but new analyse
 * outputs should not include it (see analyse.prompt.yaml v9.6+).
 */
export declare function extractSpecAndManifest(text: string): {
    spec: string;
    manifest: string | null;
};
//# sourceMappingURL=prompt-runner.d.ts.map