import type { DeferredUsage, NeuroLinkEvents, TypedEventEmitter } from "./common.js";
import type { JSONSchema7 } from "./middleware.js";
import type { LanguageModelV3, LanguageModelV3CallOptions } from "./middleware.js";
import type { StreamOptions } from "./stream.js";
import type { Tool } from "./tools.js";
export type OpenAICompatChatRole = "system" | "user" | "assistant" | "tool";
export type OpenAICompatTextContent = {
    type: "text";
    text: string;
};
export type OpenAICompatImageURLContent = {
    type: "image_url";
    image_url: {
        url: string;
        detail?: "auto" | "low" | "high";
    };
};
export type OpenAICompatMessageContent = OpenAICompatTextContent | OpenAICompatImageURLContent;
export type OpenAICompatToolCallWire = {
    id: string;
    type: "function";
    function: {
        name: string;
        arguments: string;
    };
};
export type OpenAICompatChatMessage = {
    role: "system";
    content: string | OpenAICompatMessageContent[];
} | {
    role: "user";
    content: string | OpenAICompatMessageContent[];
} | {
    role: "assistant";
    content?: string | OpenAICompatMessageContent[] | null;
    tool_calls?: OpenAICompatToolCallWire[];
    /** The turn's reasoning, sent back only where the catalog opts in
     *  (DeepSeek's replayReasoningContent quirk). */
    reasoning_content?: string;
} | {
    role: "tool";
    content: string;
    tool_call_id: string;
};
export type OpenAICompatChatTool = {
    type: "function";
    function: {
        name: string;
        description?: string;
        parameters: JSONSchema7;
        strict?: boolean;
    };
};
export type OpenAICompatToolChoiceWire = "auto" | "none" | "required" | {
    type: "function";
    function: {
        name: string;
    };
};
export type OpenAICompatResponseFormat = {
    type: "text";
} | {
    type: "json_object";
} | {
    type: "json_schema";
    json_schema: {
        name: string;
        schema: JSONSchema7;
        description?: string;
        strict?: boolean;
    };
};
export type OpenAICompatChatRequest = {
    model: string;
    messages: OpenAICompatChatMessage[];
    stream?: boolean;
    stream_options?: {
        include_usage?: boolean;
    };
    max_tokens?: number;
    max_completion_tokens?: number;
    temperature?: number;
    top_p?: number;
    presence_penalty?: number;
    frequency_penalty?: number;
    seed?: number;
    stop?: string[];
    tools?: OpenAICompatChatTool[];
    tool_choice?: OpenAICompatToolChoiceWire;
    response_format?: OpenAICompatResponseFormat;
    parallel_tool_calls?: boolean;
    user?: string;
};
export type OpenAICompatUsage = {
    prompt_tokens?: number;
    completion_tokens?: number;
    total_tokens?: number;
    prompt_tokens_details?: {
        cached_tokens?: number;
    };
    completion_tokens_details?: {
        reasoning_tokens?: number;
    };
};
export type OpenAICompatChatChoiceMessage = {
    role: "assistant";
    content?: string | null;
    tool_calls?: OpenAICompatToolCallWire[];
    refusal?: string | null;
    reasoning_content?: string | null;
    reasoning?: string | null;
};
export type OpenAICompatChatChoice = {
    index: number;
    message: OpenAICompatChatChoiceMessage;
    finish_reason: "stop" | "length" | "tool_calls" | "function_call" | "content_filter" | null;
};
export type OpenAICompatChatResponse = {
    id?: string;
    object?: string;
    created?: number;
    model?: string;
    choices: OpenAICompatChatChoice[];
    usage?: OpenAICompatUsage;
    system_fingerprint?: string;
};
export type OpenAICompatStreamDelta = {
    role?: OpenAICompatChatRole;
    content?: string | null;
    tool_calls?: Array<{
        index: number;
        id?: string;
        type?: "function";
        function?: {
            name?: string;
            arguments?: string;
        };
    }>;
    refusal?: string | null;
    reasoning_content?: string | null;
    reasoning?: string | null;
};
export type OpenAICompatStreamChunkChoice = {
    index: number;
    delta: OpenAICompatStreamDelta;
    finish_reason: "stop" | "length" | "tool_calls" | "function_call" | "content_filter" | null;
};
export type OpenAICompatChatStreamChunk = {
    id?: string;
    object?: string;
    created?: number;
    model?: string;
    choices: OpenAICompatStreamChunkChoice[];
    usage?: OpenAICompatUsage;
};
export type OpenAICompatErrorMessage = string | ReadonlyArray<{
    msg?: string;
}>;
export type OpenAICompatErrorBody = {
    error?: {
        message?: OpenAICompatErrorMessage;
        type?: string;
        code?: string | number;
        param?: string | null;
    };
    detail?: string;
};
export type OpenAICompatConfig = {
    provider: string;
    modelId: string;
    baseURL: string;
    apiKey?: string;
    headers?: Record<string, string> | (() => Record<string, string>);
    fetch?: typeof globalThis.fetch;
};
export type OpenAICompatToolWarning = NonNullable<Awaited<ReturnType<LanguageModelV3["doGenerate"]>>["warnings"]>[number];
export type OpenAICompatV3Content = Awaited<ReturnType<LanguageModelV3["doGenerate"]>>["content"][number];
export type OpenAICompatV3FinishReason = Awaited<ReturnType<LanguageModelV3["doGenerate"]>>["finishReason"];
export type OpenAICompatV3Usage = Awaited<ReturnType<LanguageModelV3["doGenerate"]>>["usage"];
export type OpenAICompatV3StreamPart = Awaited<ReturnType<LanguageModelV3["doStream"]>>["stream"] extends ReadableStream<infer P> ? P : never;
export type OpenAICompatV3CallTools = NonNullable<LanguageModelV3CallOptions["tools"]>;
export type OpenAICompatV3CallToolChoice = NonNullable<LanguageModelV3CallOptions["toolChoice"]>;
export type OpenAICompatUserOrAssistantPart = {
    type: "text";
    text: string;
} | {
    type: "file";
    mediaType: string;
    data: Uint8Array | string | URL;
    filename?: string;
};
export type OpenAICompatMessage = {
    role: "system" | "user" | "assistant" | "tool";
    content: unknown;
    toolCallId?: string;
    toolName?: string;
};
export type OpenAICompatSSEResult = {
    text: string;
    /** Accumulated reasoner-model output (`reasoning_content` / `reasoning` deltas). */
    reasoning: string;
    toolCalls: Map<number, {
        id: string;
        name: string;
        argsBuffered: string;
    }>;
    finishReason: "stop" | "length" | "tool_calls" | "function_call" | "content_filter" | null;
    usage?: OpenAICompatUsage;
    /** Response id from the first stream chunk that carried one. */
    id?: string;
    /** Served model from the first stream chunk that carried one. */
    model?: string;
};
export type OpenAICompatStreamChunk = {
    content: string;
    reasoning?: string;
};
export type ToolExecutionSummaryInternal = {
    toolCallId: string;
    toolName: string;
    input: unknown;
    output?: unknown;
    error?: string;
    startTime: Date;
    endTime: Date;
};
export type StreamLoopArgs = {
    maxSteps: number;
    modelId: string;
    url: string;
    fetchImpl: typeof fetch;
    abortSignal: AbortSignal | undefined;
    options: StreamOptions;
    conversation: OpenAICompatChatMessage[];
    openAITools: OpenAICompatChatTool[] | undefined;
    openAIToolChoice: OpenAICompatToolChoiceWire | undefined;
    toolsRecord: Record<string, Tool>;
    /** Wire → registered tool-name map when sanitization was needed (see buildWireToolNameMaps). */
    toolNameFromWire?: Map<string, string>;
    emitter: TypedEventEmitter<NeuroLinkEvents> | undefined;
    toolsUsed: string[];
    toolExecutionSummaries: ToolExecutionSummaryInternal[];
    pushChunk: (chunk: OpenAICompatStreamChunk) => void;
    /** Signals the channel that no further chunks will arrive (success or error path alike). */
    closeChannel: () => void;
    resolveUsage: (u: {
        promptTokens: number;
        completionTokens: number;
        totalTokens: number;
    }) => void;
    resolveFinish: (reason: string) => void;
    /**
     * `response_format` for this turn's requests, computed once up front from
     * `options.schema` (see `suppressResponseFormatWithTools`). Absent when no
     * schema was requested, or when tools suppress it.
     */
    responseFormat?: OpenAICompatResponseFormat;
    /**
     * Fired once per step that echoes a `model` field on the wire (SSE
     * `chunk.model`, captured by `parseSSEStream` into `OpenAICompatSSEResult.model`).
     * Lets the caller learn what the SERVER actually served, distinct from the
     * pre-call resolved/requested `modelId` — a gateway or router can rewrite
     * an alias to a concrete model id. Not called when a step's response omits
     * `model` (some backends don't echo it), so the caller must keep its own
     * fallback.
     */
    onModelObserved?: (model: string) => void;
};
export type OpenAICompatBuildBodyArgs = {
    modelId: string;
    messages: OpenAICompatChatMessage[];
    options: {
        maxTokens?: number | null;
        temperature?: number | null;
        topP?: number | null;
        presencePenalty?: number | null;
        frequencyPenalty?: number | null;
        seed?: number | null;
        stopSequences?: string[];
        /**
         * Provider-specific extra wire fields, spread verbatim onto the final
         * request body by `buildBody` (after the standard fields). This is the
         * explicit channel for non-OpenAI knobs (e.g. NVIDIA NIM's `top_k` /
         * `chat_template_kwargs`) — loose unknown keys returned from
         * `adjustBuildBodyOptions` are intentionally NOT forwarded.
         */
        extraBody?: Record<string, unknown>;
    };
    tools?: OpenAICompatChatTool[];
    toolChoice?: OpenAICompatToolChoiceWire;
    streaming: boolean;
    responseFormat?: OpenAICompatResponseFormat;
};
/**
 * Per-stream lifecycle listeners returned from an OpenAIChatCompletionsProvider
 * subclass's `onStreamStart` hook. Every property is optional — provide only
 * what the subclass cares about. Used by LiteLLM to wire an OTel span around
 * the deferred analytics promises.
 */
export type OpenAICompatStreamLifecycleListeners = {
    /**
     * Fired once the deferred usage promise resolves with the final aggregated
     * token counts. promptTokens is the UNCACHED remainder; cacheReadTokens
     * carries the cached portion (non-overlapping convention), and
     * reasoningTokens is a subset of completionTokens.
     */
    onUsage?: (usage: DeferredUsage) => void;
    /**
     * Fired once the deferred finish promise resolves. `reason` is "stop",
     * "length", "tool-calls", "content-filter", or "error". When the loop
     * errored, the upstream cause is passed as `capturedError`.
     */
    onFinish?: (reason: string, capturedError?: unknown) => void;
};
