/**
 * LLM Client for Franklin
 * Calls BlockRun API directly with x402 payment handling and streaming.
 * Original implementation — not derived from any existing codebase.
 */
import { type Chain } from '../config.js';
import type { Dialogue, CapabilityDefinition, ContentPart, CapabilityInvocation } from './types.js';
/**
 * Anthropic-compatible tool_choice. Forwarded as-is through the proxy and on
 * to the backend (Anthropic / OpenAI / Gemini gateways translate as needed).
 *
 * - `auto`  — model decides (default if omitted)
 * - `any`   — must call SOME tool, model picks which
 * - `tool`  — must call the specifically named tool
 * - `none`  — must not call any tool
 *
 * Used by the grounding-retry path in `loop.ts`: when the evaluator catches
 * an ungrounded answer that should have invoked tools, the next round sets
 * `tool_choice` to force tool use rather than relying on a soft instruction
 * the model can defy by fabricating citations.
 */
export type ToolChoice = {
    type: 'auto';
} | {
    type: 'any';
} | {
    type: 'tool';
    name: string;
} | {
    type: 'none';
};
export interface ModelRequest {
    model: string;
    messages: Dialogue[];
    system?: string;
    tools?: CapabilityDefinition[];
    max_tokens?: number;
    stream?: boolean;
    temperature?: number;
    tool_choice?: ToolChoice;
}
export interface StreamChunk {
    kind: 'content_block_start' | 'content_block_delta' | 'content_block_stop' | 'message_start' | 'message_delta' | 'message_stop' | 'ping' | 'error';
    payload: Record<string, unknown>;
}
export interface CompletionUsage {
    inputTokens: number;
    outputTokens: number;
}
export interface LLMClientOptions {
    apiUrl: string;
    chain: Chain;
    debug?: boolean;
}
/**
 * Extract the most human-readable message from an error body.
 * Some gateways wrap provider errors multiple times, e.g.
 * `{"error":{"message":"{\"error\":{\"message\":\"...\"}}"}}`.
 * Peel those layers so the UI doesn't show raw nested JSON.
 */
export declare function extractApiErrorMessage(errorBody: string): string;
/**
 * Apply Anthropic prompt caching using the `system_and_3` strategy.
 * Pattern from nousresearch/hermes-agent `agent/prompt_caching.py`.
 *
 * Places 4 cache_control breakpoints (Anthropic's max):
 *   1. System prompt (stable across all turns)
 *   2-4. Last 3 non-system messages (rolling window)
 *
 * Also caches the last tool definition (tools are stable across turns).
 *
 * This keeps the cache warm: each new turn extends the cached prefix rather
 * than invalidating it. Multi-turn conversations see ~75% input token savings
 * on Anthropic models.
 */
/**
 * True if the given Anthropic model accepts the `thinking: { type: 'enabled' }`
 * API flag (so-called *extended thinking*). Models using *adaptive thinking*
 * (Opus 4.7 and later) reject that flag — the behavior is built in and not
 * opt-in via API. Keeping the allowlist explicit, not derived from a regex,
 * so a future model that happens to include "opus" in its name doesn't
 * silently re-enable extended thinking on a model that can't handle it.
 *
 * Exported so tests can pin this decision without a live API.
 */
export declare function modelHasExtendedThinking(model: string): boolean;
/**
 * Classify an unparseable tool-call JSON failure so the user and the model
 * get an actionable message instead of a single generic line. Exported for
 * direct unit testing — the happy path hits it only on stream error.
 */
export declare function classifyToolCallFailure(toolName: string, rawInput: string, signal: AbortSignal | undefined, model: string): string;
export declare function isRoleplayedJsonToolCallText(text: string): boolean;
export declare class ModelClient {
    private apiUrl;
    private chain;
    private debug;
    private walletAddress;
    private cachedBaseWallet;
    private cachedSolanaWallet;
    private walletCacheTime;
    private static WALLET_CACHE_TTL;
    constructor(opts: LLMClientOptions);
    /**
     * Stream a completion from the BlockRun API.
     * Yields parsed SSE chunks as they arrive.
     * Handles x402 payment automatically on 402 responses.
     */
    /**
     * Resolve virtual routing profiles (blockrun/auto, blockrun/free) to
     * concrete models. This is the final safety net — if the router in
     * loop.ts didn't resolve it (e.g. old global install without router),
     * we resolve it here before hitting the API. Legacy blockrun/eco and
     * blockrun/premium fall through the unknown-key path to the same
     * default model.
     */
    private resolveVirtualModel;
    streamCompletion(request: ModelRequest, signal?: AbortSignal): AsyncGenerator<StreamChunk>;
    /**
     * Non-streaming completion for simple requests.
     */
    complete(request: ModelRequest, signal?: AbortSignal, onToolReady?: (tool: CapabilityInvocation) => void, onStreamDelta?: (delta: {
        type: 'text' | 'thinking';
        text: string;
    }) => void): Promise<{
        content: ContentPart[];
        usage: CompletionUsage;
        stopReason: string;
    }>;
    private signPayment;
    private signBasePayment;
    private signSolanaPayment;
    private extractPaymentReq;
    private parseSSEStream;
    private mapEventType;
}
