export type Role = "system" | "user" | "assistant" | "tool";
export interface ChatMessage {
    role: Role;
    content: string | ContentBlock[];
    toolCallId?: string;
    toolCalls?: ToolCall[];
}
export interface ContentBlock {
    type: "text" | "image";
    text?: string;
    /** base64 encoded image data */
    imageData?: string;
    mediaType?: string;
}
export interface ToolCall {
    id: string;
    name: string;
    arguments: Record<string, unknown>;
}
export interface ToolResult {
    toolCallId: string;
    content: string;
    isError?: boolean;
}
export interface ToolDefinition {
    name: string;
    description: string;
    parameters: Record<string, unknown>;
}
export interface LlmResponse {
    content: string;
    toolCalls: ToolCall[];
    stopReason: "stop" | "tool_use" | "length" | "error";
    usage?: {
        /**
         * "Net new" uncached input tokens — for cached requests this is just the
         * delta past the cached prefix, NOT the total input. Sum with
         * cacheCreationInputTokens + cacheReadInputTokens for the real picture.
         */
        inputTokens: number;
        outputTokens: number;
        /**
         * Tokens written to the prompt cache on this request. Charged at 1.25x
         * the input rate by Anthropic. Present only when the request used
         * cache_control breakpoints and at least one of them was a cache miss.
         */
        cacheCreationInputTokens?: number;
        /**
         * Tokens read FROM the prompt cache on this request. Charged at 0.1x the
         * input rate. This is the field that proves caching is actually saving
         * money — if it's consistently high, the cache prefix is stable.
         */
        cacheReadInputTokens?: number;
    };
}
export interface StreamEvent {
    type: "text_delta" | "tool_call_start" | "tool_call_delta" | "tool_call_end" | "done";
    text?: string;
    toolCall?: Partial<ToolCall> & {
        id: string;
    };
}
/**
 * Per-request cache hints. Providers that support explicit prefix caching
 * (e.g. Anthropic's ephemeral cache_control) consume these; providers that
 * rely on automatic prefix caching (OpenAI) may ignore them. Hints are
 * advisory: an LLM client is always free to skip them.
 */
export interface LlmCacheHints {
    /**
     * Length (in chars) of the cacheable static prefix at the START of the
     * `systemPrompt` string. Allows the client to split the system prompt
     * into a cacheable head and a dynamic tail without us having to change
     * the existing single-string signature.
     */
    systemStaticChars?: number;
    /** Place a cache breakpoint at the end of the tools list. */
    cacheTools?: boolean;
    /** Place a cache breakpoint at the end of the messages list. */
    cacheMessages?: boolean;
    /**
     * Stable identifier for the logical "session" this request belongs to.
     * Carried in the Anthropic request body as `metadata.user_id`, formatted
     * to match sub2api's expected shape so its sticky-session router pins
     * every request with the same id to the same upstream account. Without
     * this, sub2api falls back to hashing message content, which churns
     * across multi-turn tool loops and breaks both stickiness and prompt
     * cache reuse. Not really a "cache hint" semantically, but rides on the
     * same per-request metadata channel.
     */
    sessionId?: string;
}
export interface LlmClient {
    chat(messages: ChatMessage[], tools?: ToolDefinition[], systemPrompt?: string, cacheHints?: LlmCacheHints, signal?: AbortSignal): Promise<LlmResponse>;
    chatStream(messages: ChatMessage[], tools?: ToolDefinition[], systemPrompt?: string, cacheHints?: LlmCacheHints, signal?: AbortSignal): AsyncIterable<StreamEvent>;
}
