import { type ProviderFailureDiagnosticV1 } from '@duckcodeailabs/dql-agent'; import { type AgentAnswer, type CertifiedFitConfirmation, type AgentFollowUpContext, type AgentProvider, type ConversationSnapshot, type LocalContextPack, type AgenticLane } from '@duckcodeailabs/dql-agent'; import type { AgentRunRequest, AgentRunner, ProviderId } from '../types.js'; import { buildAnswerLoopTools } from '../answer-loop-tools.js'; /** * Providers the governed answer-loop runner can drive. Beyond the API-key/local * providers this includes the subscription CLI providers (`claude-code`, `codex`) — * used as plain completion backends here, distinct from the MCP `claudeCodeRunner`. */ type SimpleProviderId = Extract | 'claude-code' | 'codex'; /** * Capture a content-free provider failure at the closest boundary. Local * runtime may later choose a user-facing headline, but must not need raw * provider errors or URLs to reconstruct the cause. */ declare function providerBoundaryDiagnostic(input: { providerId: SimpleProviderId; projectRoot: string; phase: ProviderFailureDiagnosticV1['phase']; error?: unknown; code?: string; }): ProviderFailureDiagnosticV1; declare function createCertifiedFitConfirmation(provider: AgentProvider, signal?: AbortSignal): CertifiedFitConfirmation; /** * Decide whether the answer path needs a live warehouse-schema read up front. * Generated SQL must verify retrieved relation columns against the selected * execution target: dbt/catalog metadata can legitimately be ahead of (or * behind) the deployed warehouse. The runtime performs a bounded point lookup, * not a broad warehouse scan, and falls back to the catalog if access is denied. */ declare function shouldLoadSchemaContext(contextPack: LocalContextPack | undefined, hasSemanticLayer: boolean): boolean; declare function shouldSearchProjectFiles(contextPack: LocalContextPack | undefined): boolean; declare function renderProjectSourceSearch(value: unknown): string | undefined; declare function parseCertifiedFitConfirmation(text: string): { allow: boolean; confidence?: 'high' | 'medium' | 'low'; reason?: string; }; declare function readAgentConfig(projectRoot: string): Record | null; /** * Which migration lane this turn belongs to. * * Research is identified by the server-resolved `orchestrationMode`, not by * `analysisDepth`. A reader can ask Ask AI to think deeply without opting into * the Research workflow, its wider dispatch budget, or any row-bearing tools. * * Deliberately coarse: the seam only needs to know which bucket a turn falls in * so a lane can be enabled independently. The fine-grained triage between * certified, semantic, and generated stays inside the answer path, where the * retrieval evidence lives. */ declare function agenticLaneForRequest(req: AgentRunRequest): AgenticLane; export declare function applyEvalCassette(provider: AgentProvider, projectRoot: string): AgentProvider; /** * Create a replay-only provider when the runtime is launched for an offline * evaluation. This is intentionally unavailable outside explicit cassette * replay: recording and live modes still require a configured real provider. * * The cassette's recorded provider identity is part of its key. Recover it * from a single-provider cassette directory instead of borrowing a user's * active provider or guessing from an API setting. The base provider cannot * make a network call; replay misses remain CassetteMissError failures. */ export declare function createEvalCassetteReplayProvider(projectRoot: string): AgentProvider | undefined; /** * A raw text provider for planning calls that are not the answer itself. * * Research hypothesis planning needs `generate`, not the full agent runner — * and the runner cannot be reused for it, because the runner IS the governed * answer path. Cassettes apply, so a recorded run stays hermetic. */ export declare function createGovernedTextProvider(id: SimpleProviderId, projectRoot: string): AgentProvider | undefined; export declare function createDqlAgentProviderRunner(id: SimpleProviderId, providerOverride?: AgentProvider): AgentRunner; /** * When the prior assistant turn was a clarifying question and this turn is the user's * answer, the answer alone is too vague to route — re-classifying it just re-clarifies. * Fold the ORIGINAL question together with the clarification answer so the loop has * enough to proceed. Returns the current message unchanged when this isn't a clarify * follow-up. */ export declare function resolveEffectiveQuestion(req: AgentRunRequest): string; export declare function rewriteFollowUpQuestion(question: string, followUp?: AgentFollowUpContext): string; /** * The App copilot's own app: its pages, tiles, and review-required drafts. * * `AppContextEnvelopeV1` already travelled to the prompt inside the serialized * run envelope, but only as an anonymous JSON dump — and it never carried the * app's drafts at all, because those live in `apps//drafts/` which the * manifest's block scan never reads. Rendering it here gives the drafts the * explicit trust instruction they need; the caller drops `appContext` from the * JSON dump so nothing is carried twice. * * This sits in the extra-context section, which already tells the model the * material must not override certified artifacts — the correct standing for a * review-required draft. */ export declare function renderAppContextForPrompt(value: unknown): string | undefined; export declare function renderExtraContext(req: AgentRunRequest, followUp?: AgentFollowUpContext): string | undefined; declare function inferFollowUpContext(req: AgentRunRequest, question: string): AgentFollowUpContext | undefined; /** * Deterministic stale-context protection: when the persisted working state says * the new question is a topic SHIFT, prior-turn filters must not be forced into * the follow-up (a "by X" phrasing can regex-classify as drilldown even on a * genuinely new topic). Question-derived filters are kept; carried ones drop. */ declare function applyTopicShiftGuard(followUp: AgentFollowUpContext | undefined, snapshot: ConversationSnapshot | undefined): AgentFollowUpContext | undefined; /** * Resolve the prior-turn context a follow-up may build on. * * The topic-shift guard is applied HERE rather than by the caller. It used to * be invoked at the provider call site only, while the retrieval call site * (`buildLocalContextPack`) took the raw result — so on a detected topic shift * the context pack was still built with the previous question's filters and * dimensions, and the retrieval query text was seeded with the previous * question and answer. Folding the guard in makes it impossible to forget at a * third call site. */ export declare function resolveAgentFollowUpContext(rawContext: Record | undefined, question: string, snapshot?: ConversationSnapshot): AgentFollowUpContext | undefined; declare function followUpFromConversationContext(req: AgentRunRequest, question: string): AgentFollowUpContext | undefined; export declare const __test__: { agenticLaneForRequest: typeof agenticLaneForRequest; applyTopicShiftGuard: typeof applyTopicShiftGuard; isDrilldownFollowUp: typeof isDrilldownFollowUp; buildAnswerLoopTools: typeof buildAnswerLoopTools; createCertifiedFitConfirmation: typeof createCertifiedFitConfirmation; followUpFromConversationContext: typeof followUpFromConversationContext; inferFollowUpContext: typeof inferFollowUpContext; formatCascadeOutcome: typeof formatCascadeOutcome; parseCertifiedFitConfirmation: typeof parseCertifiedFitConfirmation; rewriteFollowUpQuestion: typeof rewriteFollowUpQuestion; shouldLoadSchemaContext: typeof shouldLoadSchemaContext; shouldSearchProjectFiles: typeof shouldSearchProjectFiles; renderProjectSourceSearch: typeof renderProjectSourceSearch; researchDispatchPurposeForTool: typeof researchDispatchPurposeForTool; readAgentConfig: typeof readAgentConfig; providerBoundaryDiagnostic: typeof providerBoundaryDiagnostic; }; declare function researchDispatchPurposeForTool(toolName: string): 'research_narration' | 'research_tool'; /** * A drilldown INHERITS the previous turn's filters and dimensions, so the bar * for classifying one has to be a reference to that previous turn. * * This used to fire on a bare `by`, `for`, `only`, `where`, `compare` or a noun * like `regions`, which is present in almost every analytical question. "Show * revenue by region" on a brand-new topic was therefore treated as a drilldown * of whatever came before and silently inherited its filters — the reported * "when I ask a different question it's not giving the right solution". * * Now it needs either a deictic reference to the prior result, or an explicit * drill verb that only makes sense relative to something already on screen. */ declare function isDrilldownFollowUp(question: string, priorTerms?: string[]): boolean; declare function formatCascadeOutcome(cascade: AgentAnswer['cascade']): string | undefined; export {}; //# sourceMappingURL=dql-agent-provider.d.ts.map