import type { Message } from '../types/messages.js'; import type { MemoryStore } from '../types/memory.js'; import type { Provider, ReasoningConfig, ReasoningRequest, Request } from '../types/provider.js'; import type { OneShotOrchestrator } from './one-shot-llm.js'; /** * Prompt refinement ("did you mean this?"). * * Runs a one-shot LLM call in a SEPARATE context (its own system prompt, no * conversation history, no tools) that rewrites a raw user message into a * clearer, more complete instruction BEFORE the main agent sees it. The goal * is to make the main context start from a well-understood request rather than * guessing intent from terse input like "fix the bug". * * This mirrors `IntelligentCompactor.callSummarizer` — a plain * `provider.complete()` with a dedicated system prompt — and is deliberately * free of React / TUI dependencies so it can be unit-tested in isolation. */ export declare const ENHANCER_SYSTEM_PROMPT: string; /** * Heuristic gate: should this raw input be sent through the refiner at all? * Pure + exported for unit testing. Returns false for inputs where refinement * is pointless or unwanted (slash commands, one-word affirmations, trivially * short text, bare numbers). */ export declare function shouldEnhance(text: string): boolean; /** * Build a reasoning directive for the refiner that minimizes wasted thinking, * gated to what the model actually accepts. Refinement is a shallow rewrite * task — extended thinking adds latency and (hidden) token cost for little * gain — so we ask the model to spend as little reasoning as it safely can. * * The gating mirrors `resolveReasoningForRequest` so we never send a field the * model would reject: * - effort-capable model → its lowest advertised effort level; * - else disable-capable model → disable thinking (`enabled: false`); * - else (always-on / unknown) → `undefined` (leave the provider default). * * Returns `undefined` whenever nothing can be safely reduced. Callers forward * that verbatim to `enhanceUserPrompt`, which then sends no reasoning field — * identical to the behavior before this hint existed. Pure + exported for unit * testing. */ export declare function gatedEnhancerReasoning(rc: ReasoningConfig | undefined): ReasoningRequest | undefined; /** * Normalize for "did the refiner actually change anything?" comparison — * collapse whitespace and lowercase so trivial reformatting doesn't trigger * the confirmation panel. */ export declare function normalizedEqual(a: string, b: string): boolean; /** * Conservative validation for the English half of a bilingual refinement. * It requires explicit English instruction vocabulary and rejects every known * non-English marker; identifiers and file paths alone are not language proof. */ export declare function isValidEnglishRefinement(text: string): boolean; /** * Parse and validate the two-version wire format emitted by the refiner. * Visually blank separator padding (ASCII/non-breaking/zero-width whitespace) * and CRLF are tolerated, but exactly one separator and two non-empty versions * are required. The second version must be English. */ export declare function parseBilingualEnhancement(raw: string, original: string): EnhanceResult | null; /** A single text-only conversation turn used as refiner context. */ export interface ConversationTurn { role: 'user' | 'assistant'; text: string; } /** Additional context the refiner may use to resolve references. */ export interface RefinerContextSection { title: string; items: string[]; } /** * Minimal structural shape of the live agent context needed to enrich the * refiner. Kept structural so browser/client bundles do not need the Context * class and tests can pass plain objects. */ export interface RefinerSessionContextLike { projectRoot?: unknown; cwd?: unknown; workingDir?: unknown; readFiles?: unknown; writtenFiles?: unknown; todos?: unknown; } /** * Result of a successful prompt refinement. Carries the original-language and * validated English versions so the UI can offer both. English input still * uses the two-part wire contract; both fields may contain identical text. */ export interface EnhanceResult { /** Refined in the user's original language. */ refined: string; /** Refined in English. Equals `refined` when the input was already English. */ english: string; } /** * Why a refine attempt fell through. Callers use this to decide the recovery * path: `timeout` is a transient capacity/latency failure worth an automatic * retry with a longer window (the model was reachable, just slow); `empty` and * `provider_error` mean the attempt produced nothing useful, so the caller * should surface the recovery options (retry, switch model, send as-is) rather * than silently retry. User-initiated cancellation is NOT reported here (it * returns `null` with no `onError` call). */ export type EnhanceFailureKind = 'timeout' | 'empty' | 'provider_error'; export declare const DEFAULT_REFINER_RETRY_FEEDBACK = "Make another pass that is sharper and more self-contained. Use the provided project memory, current session context, and recent conversation only to resolve references and preserve project vocabulary; keep the original scope unchanged."; export interface EnhanceUserPromptOptions { provider: Provider; model: string; text: string; /** * Recent conversation turns (oldest→newest), text only, used purely as * CONTEXT so the refiner can resolve references in a follow-up message * ("it", "the same", "that file"). Without this, the refiner is blind to * the conversation and can only refine self-contained prompts. Build with * `recentTextTurns(ctx.messages)`. */ history?: ConversationTurn[] | undefined; /** * Project/session context snippets, already filtered and compacted by the * caller. They are context only: the refiner may use them to resolve * references, names, files, conventions, and constraints, but must not turn * them into extra requirements. */ contextSections?: RefinerContextSection[] | undefined; /** Previous refinement when the user asks for another pass. */ previousRefinement?: EnhanceResult | undefined; /** Short instruction for a retry pass. Defaults to `DEFAULT_REFINER_RETRY_FEEDBACK`. */ retryFeedback?: string | undefined; /** Parent abort signal (e.g. the run controller / Esc). */ signal?: AbortSignal | undefined; /** Hard cap on how long to wait for the refiner before giving up. Default 90s. */ timeoutMs?: number | undefined; /** Max tokens for the refined output. Default 2048. */ maxTokens?: number | undefined; /** * Reasoning directive for the refiner call. Refinement is a shallow * restate-this-more-clearly task that does not benefit from extended * thinking, so callers pass a low-effort / thinking-disabled hint here to * cut latency and (hidden) reasoning-token cost — most impactful on slow * reasoning models. Build it with `gatedEnhancerReasoning(rc)` so the field * is gated to what the model accepts. Omit (undefined) to send no reasoning * directive at all (the provider's own default applies). */ reasoning?: ReasoningRequest | undefined; /** * Called with a short reason and a machine-readable `kind` when refinement * fails (provider error, timeout, empty response). NOT called when the caller * cancels via `signal`. The `kind` lets the UI drive recovery: `timeout` is * eligible for an automatic longer-window retry; `empty` / `provider_error` * surface the recovery options instead. The second argument is optional so * existing callers that only read the reason keep compiling. */ onError?: ((reason: string, kind?: EnhanceFailureKind) => void) | undefined; /** * OneShotOrchestrator for the refiner LLM call. When set, uses it instead * of direct provider.complete(), gaining fallback chain support. */ oneShotOrchestrator?: OneShotOrchestrator | undefined; } export declare function buildRefinerContextSections(opts: { text: string; memoryStore?: MemoryStore | undefined; context?: RefinerSessionContextLike | undefined; }): Promise; /** * Refine a raw user prompt. Returns the refined text, or `null` when the * caller should fall back to the original (refiner errored, timed out, was * aborted, or returned nothing useful). NEVER throws — refinement is a * best-effort convenience and must never block the user from sending. */ export interface RefinerCompletionOptions { provider: Provider; oneShotOrchestrator?: OneShotOrchestrator | undefined; request: Request; signal: AbortSignal; timeoutMs: number; } /** Execute one refiner pass through either the orchestrator or direct provider. */ export declare function completeRefinerPass(input: string, opts: RefinerCompletionOptions): Promise<{ text: string; error?: string | undefined; }>; export declare function enhanceUserPrompt(opts: EnhanceUserPromptOptions): Promise; /** * Extract the last few user/assistant TEXT turns from a conversation, newest * last, for use as refiner context. Skips system messages and tool-only turns * (tool_use / tool_result carry no useful natural-language context and bloat * the call). Each turn is truncated to `maxChars`; at most `maxTurns` are * returned. Pure + exported for unit testing. */ export declare function recentTextTurns(messages: Message[], maxTurns?: number, maxChars?: number): ConversationTurn[]; //# sourceMappingURL=prompt-enhancer.d.ts.map