import { ZodSchema, ZodInfer } from '../../../zod/dist/index.cjs';
import { Logger } from '@llamaindex/env';
import { Tokenizers } from '@llamaindex/env/tokenizers';
import { JSONSchemaType } from 'ajv';
import { JSONObject, JSONValue } from '../../../global/dist/index.cjs';

/**
 * @internal
 */
interface LLMChat<AdditionalChatOptions extends object = object, AdditionalMessageOptions extends object = object> {
    chat(params: LLMChatParamsStreaming<AdditionalChatOptions> | LLMChatParamsNonStreaming<AdditionalChatOptions>): Promise<ChatResponse<AdditionalMessageOptions> | AsyncIterable<ChatResponseChunk<AdditionalMessageOptions>>>;
}
/**
 * Unified language model interface
 */
interface LLM<AdditionalChatOptions extends object = object, AdditionalMessageOptions extends object = object> extends LLMChat<AdditionalChatOptions> {
    metadata: LLMMetadata;
    /**
     * Get a chat response from the LLM
     */
    chat(params: LLMChatParamsStreaming<AdditionalChatOptions, AdditionalMessageOptions>): Promise<AsyncIterable<ChatResponseChunk>>;
    chat(params: LLMChatParamsNonStreaming<AdditionalChatOptions, AdditionalMessageOptions>): Promise<ChatResponse<AdditionalMessageOptions>>;
    /**
     * Get a prompt completion from the LLM
     */
    complete(params: LLMCompletionParamsStreaming): Promise<AsyncIterable<CompletionResponse>>;
    complete(params: LLMCompletionParamsNonStreaming): Promise<CompletionResponse>;
}
type MessageType = "user" | "assistant" | "system" | "memory" | "developer";
type ChatMessage<AdditionalMessageOptions extends object = object> = {
    content: MessageContent;
    role: MessageType;
    options?: undefined | AdditionalMessageOptions;
};
interface ChatResponse<AdditionalMessageOptions extends object = object> {
    message: ChatMessage<AdditionalMessageOptions>;
    /**
     * Raw response from the LLM
     *
     * If LLM response an iterable of chunks, this will be an array of those chunks
     */
    raw: object | null;
}
type ChatResponseChunk<AdditionalMessageOptions extends object = object> = {
    raw: object | null;
    delta: string;
    options?: undefined | AdditionalMessageOptions;
};
interface ExecResponse<AdditionalMessageOptions extends object = object, O = JSONObject> {
    newMessages: ChatMessage<AdditionalMessageOptions>[];
    toolCalls: ToolCall[];
    object?: O | undefined;
}
interface ExecStreamResponse<AdditionalMessageOptions extends object = object, O = JSONObject> {
    stream: AsyncIterable<ChatResponseChunk<AdditionalMessageOptions>>;
    newMessages(): ChatMessage<AdditionalMessageOptions>[];
    toolCalls: ToolCall[];
    object?: O | undefined;
}
interface CompletionResponse {
    text: string;
    /**
     * Raw response from the LLM
     *
     * It's possible that this is `null` if the LLM response an iterable of chunks
     */
    raw: object | null;
}
type LLMMetadata = {
    model: string;
    temperature: number;
    topP: number;
    maxTokens?: number | undefined;
    contextWindow: number;
    tokenizer: Tokenizers | undefined;
    structuredOutput: boolean;
};
interface LLMChatParamsBase<AdditionalChatOptions extends object = object, AdditionalMessageOptions extends object = object, Schema extends ZodSchema = ZodSchema> {
    messages: ChatMessage<AdditionalMessageOptions>[];
    additionalChatOptions?: AdditionalChatOptions | undefined;
    tools?: BaseTool[] | undefined;
    responseFormat?: Schema | object | undefined;
    logger?: Logger | undefined;
}
interface LLMChatParamsStreaming<AdditionalChatOptions extends object = object, AdditionalMessageOptions extends object = object, Schema extends ZodSchema = ZodSchema> extends LLMChatParamsBase<AdditionalChatOptions, AdditionalMessageOptions, Schema> {
    stream: true;
}
interface LLMChatParamsNonStreaming<AdditionalChatOptions extends object = object, AdditionalMessageOptions extends object = object, Schema extends ZodSchema = ZodSchema> extends LLMChatParamsBase<AdditionalChatOptions, AdditionalMessageOptions, Schema> {
    stream?: false;
}
interface LLMCompletionParamsBase {
    prompt: MessageContent;
    responseFormat?: ZodSchema | object;
}
interface LLMCompletionParamsStreaming extends LLMCompletionParamsBase {
    stream: true;
}
interface LLMCompletionParamsNonStreaming extends LLMCompletionParamsBase {
    stream?: false | null | undefined;
}
type MessageContentTextDetail = {
    type: "text";
    text: string;
};
type MessageContentImageDetail = {
    type: "image_url";
    image_url: {
        url: string;
    };
    detail?: "high" | "low" | "auto";
};
type MessageContentAudioDetail = {
    type: "audio";
    data: string;
    mimeType: string;
};
type MessageContentVideoDetail = {
    type: "video";
    data: string;
    mimeType: string;
};
type MessageContentImageDataDetail = {
    type: "image";
    data: string;
    mimeType: string;
};
type MessageContentFileDetail = {
    type: "file";
    data: string;
    mimeType: string;
};
type MessageContentDetail = MessageContentTextDetail | MessageContentImageDetail | MessageContentAudioDetail | MessageContentVideoDetail | MessageContentImageDataDetail | MessageContentFileDetail;
/**
 * Extended type for the content of a message that allows for multi-modal messages.
 */
type MessageContent = string | MessageContentDetail[];
type ToolCall = {
    name: string;
    input: JSONObject;
    id: string;
};
type PartialToolCall = {
    name: string;
    id: string;
    input: string;
};
type ToolResult = {
    id: string;
    result: string;
    isError: boolean;
};
type ToolCallOptions = {
    toolCall: (ToolCall | PartialToolCall)[];
};
type ToolResultOptions = {
    toolResult: ToolResult;
};
type ToolCallLLMMessageOptions = ToolResultOptions | ToolCallOptions | object;
type Known = {
    [key: string]: Known;
} | [Known, ...Known[]] | Known[] | number | string | boolean | null;
type ToolMetadata<Parameters extends Record<string, unknown> = Record<string, unknown>> = {
    description: string;
    name: string;
    /**
     * OpenAI uses JSON Schema to describe the parameters that a tool can take.
     * @link https://json-schema.org/understanding-json-schema
     */
    parameters?: Parameters;
};
/**
 * Simple Tool interface. Likely to change.
 */
interface BaseTool<Input = any> {
    /**
     * This could be undefined if the implementation is not provided,
     *  which might be the case when communicating with a llm.
     *
     * @return {JSONValue | Promise<JSONValue>} The output of the tool.
     */
    call?: (input: Input) => JSONValue | Promise<JSONValue>;
    metadata: Input extends Known ? ToolMetadata<JSONSchemaType<Input>> : ToolMetadata;
}

declare abstract class BaseLLM<AdditionalChatOptions extends object = object, AdditionalMessageOptions extends object = object> implements LLM<AdditionalChatOptions> {
    abstract metadata: LLMMetadata;
    complete(params: LLMCompletionParamsStreaming): Promise<AsyncIterable<CompletionResponse>>;
    complete(params: LLMCompletionParamsNonStreaming): Promise<CompletionResponse>;
    abstract chat(params: LLMChatParamsStreaming<AdditionalChatOptions, AdditionalMessageOptions>): Promise<AsyncIterable<ChatResponseChunk<AdditionalMessageOptions>>>;
    abstract chat(params: LLMChatParamsNonStreaming<AdditionalChatOptions, AdditionalMessageOptions>): Promise<ChatResponse<AdditionalMessageOptions>>;
    exec<Z extends ZodSchema>(params: LLMChatParamsStreaming<AdditionalChatOptions, AdditionalMessageOptions, Z>): Promise<ExecStreamResponse<AdditionalMessageOptions, ZodInfer<Z>>>;
    exec<Z extends ZodSchema>(params: LLMChatParamsNonStreaming<AdditionalChatOptions, AdditionalMessageOptions, Z>): Promise<ExecResponse<AdditionalMessageOptions, ZodInfer<Z>>>;
    streamExec<Z extends ZodSchema>(params: LLMChatParamsStreaming<AdditionalChatOptions, AdditionalMessageOptions, Z>): Promise<ExecStreamResponse<AdditionalMessageOptions, ZodInfer<Z>>>;
}
declare abstract class ToolCallLLM<AdditionalChatOptions extends object = object, AdditionalMessageOptions extends ToolCallLLMMessageOptions = ToolCallLLMMessageOptions> extends BaseLLM<AdditionalChatOptions, AdditionalMessageOptions> {
    abstract supportToolCall: boolean;
}

declare class MockLLM extends ToolCallLLM {
    metadata: LLMMetadata;
    options: {
        timeBetweenToken: number;
        responseMessage: string;
        mockToolCallResponse?: {
            toolCalls: ToolCall[];
            responseMessage?: string;
        };
    };
    supportToolCall: boolean;
    constructor(options?: {
        timeBetweenToken?: number;
        responseMessage?: string;
        metadata?: LLMMetadata;
        mockToolCallResponse?: {
            toolCalls: ToolCall[];
            responseMessage?: string;
        };
    });
    chat(params: LLMChatParamsStreaming<object, object>): Promise<AsyncIterable<ChatResponseChunk>>;
    chat(params: LLMChatParamsNonStreaming<object, object>): Promise<ChatResponse<object>>;
    complete(params: LLMCompletionParamsStreaming): Promise<AsyncIterable<CompletionResponse>>;
    complete(params: LLMCompletionParamsNonStreaming): Promise<CompletionResponse>;
}

export { MockLLM };
