import consola from "consola" import { events } from "fetch-event-stream" import { copilotHeaders, copilotBaseUrl } from "~/lib/api-config" import { HTTPError } from "~/lib/error" import { state } from "~/lib/state" export const createChatCompletions = async ( payload: ChatCompletionsPayload, ) => { if (!state.copilotToken) throw new Error("Copilot token not found") const enableVision = payload.messages.some( (x) => typeof x.content !== "string" && x.content?.some((x) => x.type === "image_url"), ) // Agent/user check for X-Initiator header // Determine if any message is from an agent ("assistant" or "tool") const isAgentCall = payload.messages.some((msg) => ["assistant", "tool"].includes(msg.role), ) // Build headers and add X-Initiator const headers: Record = { ...copilotHeaders(state, enableVision), "X-Initiator": isAgentCall ? "agent" : "user", } const response = await fetch(`${copilotBaseUrl(state)}/chat/completions`, { method: "POST", headers, body: JSON.stringify(payload), }) if (!response.ok) { consola.error("Failed to create chat completions", response) throw new HTTPError("Failed to create chat completions", response) } if (payload.stream) { return events(response) } return (await response.json()) as ChatCompletionResponse } // Streaming types export interface ChatCompletionChunk { id: string object: "chat.completion.chunk" created: number model: string choices: Array system_fingerprint?: string usage?: { prompt_tokens: number completion_tokens: number total_tokens: number prompt_tokens_details?: { cached_tokens: number } completion_tokens_details?: { accepted_prediction_tokens: number rejected_prediction_tokens: number } } } interface Delta { content?: string | null role?: "user" | "assistant" | "system" | "tool" tool_calls?: Array<{ index: number id?: string type?: "function" function?: { name?: string arguments?: string } }> } interface Choice { index: number delta: Delta finish_reason: "stop" | "length" | "tool_calls" | "content_filter" | null logprobs: object | null } // Non-streaming types export interface ChatCompletionResponse { id: string object: "chat.completion" created: number model: string choices: Array system_fingerprint?: string usage?: { prompt_tokens: number completion_tokens: number total_tokens: number prompt_tokens_details?: { cached_tokens: number } } } interface ResponseMessage { role: "assistant" content: string | null tool_calls?: Array } interface ChoiceNonStreaming { index: number message: ResponseMessage logprobs: object | null finish_reason: "stop" | "length" | "tool_calls" | "content_filter" } // Payload types export interface ChatCompletionsPayload { messages: Array model: string temperature?: number | null top_p?: number | null max_tokens?: number | null stop?: string | Array | null n?: number | null stream?: boolean | null frequency_penalty?: number | null presence_penalty?: number | null logit_bias?: Record | null logprobs?: boolean | null response_format?: { type: "json_object" } | null seed?: number | null tools?: Array | null tool_choice?: | "none" | "auto" | "required" | { type: "function"; function: { name: string } } | null user?: string | null } export interface Tool { type: "function" function: { name: string description?: string parameters: Record } } export interface Message { role: "user" | "assistant" | "system" | "tool" | "developer" content: string | Array | null name?: string tool_calls?: Array tool_call_id?: string } export interface ToolCall { id: string type: "function" function: { name: string arguments: string } } export type ContentPart = TextPart | ImagePart export interface TextPart { type: "text" text: string } export interface ImagePart { type: "image_url" image_url: { url: string detail?: "low" | "high" | "auto" } }