import type { AudioFrame, VideoFrame } from '@livekit/rtc-node';
import type { LLM } from './llm.js';
import { type ProviderFormat } from './provider_format/index.js';
import type { JSONObject, JSONValue, ToolContext } from './tool_context.js';
export type ChatRole = 'developer' | 'system' | 'user' | 'assistant';
export interface ImageContent {
    id: string;
    type: 'image_content';
    /**
     * Either a string URL or a VideoFrame object.
     */
    image: string | VideoFrame;
    inferenceDetail: 'auto' | 'high' | 'low';
    inferenceWidth?: number;
    inferenceHeight?: number;
    mimeType?: string;
    _cache: Record<any, any>;
}
export interface AudioContent {
    type: 'audio_content';
    frame: AudioFrame[];
    transcript?: string;
}
type InstructionsOptions = {
    /** The audio/voice variant of the instructions. */
    audio: string;
    /** The text variant of the instructions; falls back to `audio` when omitted. */
    text?: string;
    /** The currently rendered string value, used by `value`/`toString()`. */
    represent?: string;
};
declare const INSTRUCTIONS_SYMBOL: unique symbol;
export declare function isInstructions(value: unknown): value is Instructions;
/**
 * Instructions that adapt based on the user's input modality (audio vs. text).
 *
 * The `value` property is the rendered string providers see. By default it
 * equals the `audio` variant; after {@link asModality} it equals the chosen
 * variant. Both the `audio` variant and the raw `text` variant are preserved
 * so {@link asModality} can be called again for a different modality (e.g.,
 * when the same `ChatContext` is reused across tool-call turns).
 */
export declare class Instructions {
    readonly type: "instructions";
    private readonly _audioVariant;
    /** Raw text variant; falls back to {@link audio} when omitted. */
    private readonly _textVariant?;
    /** The currently rendered string (what providers should treat as content). */
    readonly value: string;
    /** @internal Symbol marker for type identification */
    readonly [INSTRUCTIONS_SYMBOL] = true;
    constructor(options: InstructionsOptions);
    static tpl(strings: TemplateStringsArray, ...values: Array<Instructions | string | number | boolean | null | undefined>): Instructions;
    /** The audio (voice) variant of the instructions. */
    get audio(): string;
    /** The text variant of the instructions. Falls back to {@link audio}. */
    get text(): string;
    /**
     * Return a copy whose {@link value} is the variant matching `modality`.
     * Both `audio` and `text` variants are preserved on the result, so this can
     * be called again for a different modality (e.g. across tool-call turns).
     */
    asModality(modality: 'audio' | 'text'): Instructions;
    /** Concatenate, propagating both variants and the current rendered value. */
    concat(other: string | Instructions): Instructions;
    toString(): string;
    toJSON(): {
        type: 'instructions';
        audio: string;
        text?: string;
    };
}
export declare function renderInstructions(instructions: string | Instructions, modality?: 'audio' | 'text'): string;
/**
 * Compare two instruction values by content. Plain strings compare by value;
 * {@link Instructions} compare by their audio + text variants so that two
 * distinct instances with the same content are treated as equal.
 */
export declare function instructionsEqual(a: string | Instructions | undefined, b: string | Instructions | undefined): boolean;
/**
 * Concatenate any mix of plain strings and {@link Instructions}, propagating
 * both audio/text variants. If no argument is an {@link Instructions} the
 * result is a plain string; otherwise the result is an {@link Instructions}
 * preserving both variants from every contributing operand.
 */
export declare function concatInstructions(...parts: Array<string | Instructions>): string | Instructions;
export type ChatContent = ImageContent | AudioContent | Instructions | string;
export declare function createImageContent(params: {
    image: string | VideoFrame;
    id?: string;
    inferenceDetail?: 'auto' | 'high' | 'low';
    inferenceWidth?: number;
    inferenceHeight?: number;
    mimeType?: string;
}): ImageContent;
export declare function createAudioContent(params: {
    frame: AudioFrame[];
    transcript?: string;
}): AudioContent;
export interface MetricsReport {
    /**
     * Provider-known request or response IDs associated with this turn.
     *
     * Assistant `ChatMessage` only. These IDs can be used to correlate a turn with
     * provider-side logs.
     */
    providerRequestIds?: string[];
    startedSpeakingAt?: number;
    stoppedSpeakingAt?: number;
    transcriptionDelay?: number;
    endOfTurnDelay?: number;
    onUserTurnCompletedDelay?: number;
    llmNodeTtft?: number;
    ttsNodeTtfb?: number;
    /**
     * Delay (in seconds) between forwarding the first audio frame and the `AudioOutput`
     * reporting playback started. Near-zero for the default room output (self-reported
     * when the frame is pushed to the track, so it doesn't account for network delivery
     * to the client); meaningful when a remote avatar worker is in the chain and reports
     * playback via the `lk.playback_started` RPC.
     *
     * Assistant `ChatMessage` only.
     */
    playbackLatency?: number;
    e2eLatency?: number;
}
export declare class ChatMessage {
    readonly id: string;
    readonly type: "message";
    readonly role: ChatRole;
    content: ChatContent[];
    interrupted: boolean;
    transcriptConfidence?: number;
    extra: Record<string, unknown>;
    metrics: MetricsReport;
    hash?: Uint8Array;
    createdAt: number;
    constructor(params: {
        role: ChatRole;
        content: ChatContent[] | string;
        id?: string;
        interrupted?: boolean;
        createdAt?: number;
        transcriptConfidence?: number;
        metrics?: MetricsReport;
        extra?: Record<string, unknown>;
    });
    static create(params: {
        role: ChatRole;
        content: ChatContent[] | string;
        id?: string;
        interrupted?: boolean;
        createdAt?: number;
        transcriptConfidence?: number;
        metrics?: MetricsReport;
        extra?: Record<string, unknown>;
    }): ChatMessage;
    /**
     * Returns a single string with all text parts of the message joined by new
     * lines, with LiveKit's expressive `<expr/>` tags removed from assistant
     * messages. If no string content is present, returns `undefined`.
     */
    get textContent(): string | undefined;
    /**
     * Returns a single string with all text parts of the message joined by new
     * lines, exactly as generated. Assistant messages may contain expressive
     * `<expr/>` tags.
     */
    get rawTextContent(): string | undefined;
    toJSONContent(): JSONValue[];
    toJSON(excludeTimestamp?: boolean): JSONValue;
}
export declare class FunctionCall {
    readonly id: string;
    readonly type: "function_call";
    callId: string;
    args: string;
    name: string;
    createdAt: number;
    extra: Record<string, unknown>;
    /**
     * Optional grouping identifier for parallel tool calls.
     */
    groupId?: string;
    /**
     * Opaque signature for Gemini thinking mode.
     * When using Gemini 3+ models with thinking enabled, this signature must be
     * preserved and returned with function responses to maintain thought context.
     */
    thoughtSignature?: string;
    constructor(params: {
        callId: string;
        name: string;
        args: string;
        id?: string;
        createdAt?: number;
        extra?: Record<string, unknown>;
        groupId?: string;
        thoughtSignature?: string;
    });
    static create(params: {
        callId: string;
        name: string;
        args: string;
        id?: string;
        createdAt?: number;
        extra?: Record<string, unknown>;
        groupId?: string;
        thoughtSignature?: string;
    }): FunctionCall;
    toJSON(excludeTimestamp?: boolean): JSONValue;
}
export declare class FunctionCallOutput {
    readonly id: string;
    readonly type: "function_call_output";
    name: string;
    callId: string;
    output: string;
    isError: boolean;
    createdAt: number;
    constructor(params: {
        callId: string;
        output: string;
        isError: boolean;
        id?: string;
        createdAt?: number;
        name?: string;
    });
    static create(params: {
        callId: string;
        output: string;
        isError: boolean;
        id?: string;
        createdAt?: number;
        name?: string;
    }): FunctionCallOutput;
    toJSON(excludeTimestamp?: boolean): JSONValue;
}
export declare class AgentHandoffItem {
    readonly id: string;
    readonly type: "agent_handoff";
    oldAgentId: string | undefined;
    newAgentId: string;
    createdAt: number;
    constructor(params: {
        oldAgentId?: string;
        newAgentId: string;
        id?: string;
        createdAt?: number;
    });
    static create(params: {
        oldAgentId?: string;
        newAgentId: string;
        id?: string;
        createdAt?: number;
    }): AgentHandoffItem;
    toJSON(excludeTimestamp?: boolean): JSONValue;
}
export declare class AgentConfigUpdate {
    readonly id: string;
    readonly type: "agent_config_update";
    instructions?: string | Instructions;
    toolsAdded?: string[];
    toolsRemoved?: string[];
    createdAt: number;
    constructor(params?: {
        id?: string;
        instructions?: string | Instructions;
        toolsAdded?: string[];
        toolsRemoved?: string[];
        createdAt?: number;
    });
    static create(params: {
        id?: string;
        instructions?: string | Instructions;
        toolsAdded?: string[];
        toolsRemoved?: string[];
        createdAt?: number;
    }): AgentConfigUpdate;
    toJSON(excludeTimestamp?: boolean): JSONValue;
}
export type ChatItem = ChatMessage | FunctionCall | FunctionCallOutput | AgentHandoffItem | AgentConfigUpdate;
export declare class ChatContext {
    protected _items: ChatItem[];
    constructor(items?: ChatItem[]);
    static empty(): ChatContext;
    get items(): ChatItem[];
    set items(items: ChatItem[]);
    /**
     * Add a new message to the context and return it.
     */
    addMessage(params: {
        role: ChatRole;
        content: ChatContent[] | string;
        id?: string;
        interrupted?: boolean;
        createdAt?: number;
        transcriptConfidence?: number;
        metrics?: MetricsReport;
        extra?: Record<string, unknown>;
    }): ChatMessage;
    /**
     * Insert a single item or multiple items based on their `createdAt` field so
     * that the array keeps its chronological order.
     */
    insert(item: ChatItem | ChatItem[]): void;
    /**
     * Remove the first item from the chat context by item or item ID.
     *
     * Throws if the item or ID is not found.
     */
    remove(item: ChatItem | string): void;
    getById(itemId: string): ChatItem | undefined;
    indexById(itemId: string): number | undefined;
    copy(options?: {
        excludeFunctionCall?: boolean;
        excludeInstructions?: boolean;
        excludeEmptyMessage?: boolean;
        excludeHandoff?: boolean;
        excludeConfigUpdate?: boolean;
        toolCtx?: ToolContext<any>;
    }): ChatContext;
    merge(other: ChatContext, options?: {
        excludeFunctionCall?: boolean;
        excludeInstructions?: boolean;
        excludeConfigUpdate?: boolean;
    }): ChatContext;
    truncate(maxItems: number): ChatContext;
    toJSON(options?: {
        excludeImage?: boolean;
        excludeAudio?: boolean;
        excludeTimestamp?: boolean;
        excludeFunctionCall?: boolean;
        excludeConfigUpdate?: boolean;
        stripMarkup?: boolean;
    }): JSONObject;
    toProviderFormat(format: ProviderFormat, injectDummyUserMessage?: boolean): Promise<Record<string, any>[] | [Record<string, unknown>[], import("./provider_format/google.js").GoogleFormatData] | [Record<string, unknown>[], import("./provider_format/mistralai.js").MistralFormatData]>;
    /**
     * Internal helper used by `truncate` & `addMessage` to find the correct
     * insertion index for a timestamp so the list remains sorted.
     */
    private findInsertionIndex;
    /**
     * Return true if `other` has the same sequence of items with matching
     * essential fields (IDs, types, and payload) as this context.
     *
     * Comparison rules:
     * - Messages: compares the full `content` list, `role` and `interrupted`.
     * - Function calls: compares `name`, `callId`, and `args`.
     * - Function call outputs: compares `name`, `callId`, `output`, and `isError`.
     *
     * Does not consider timestamps or other metadata.
     */
    isEquivalent(other: ChatContext): boolean;
    /**
     * Compare two content arrays for equality.
     */
    private compareContent;
    _summarize(llm: LLM, options?: {
        keepLastTurns?: number;
    }): Promise<ChatContext>;
    /**
     * Indicates whether the context is read-only
     */
    get readonly(): boolean;
}
export declare class ReadonlyChatContext extends ChatContext {
    static readonly errorMsg = "Please use .copy() and agent.update_chat_ctx() to modify the chat context.";
    constructor(items: ChatItem[]);
    get items(): ChatItem[];
    set items(items: ChatItem[]);
    get readonly(): boolean;
}
export {};
//# sourceMappingURL=chat_context.d.ts.map