UNPKG

genkitx-azure-openai

Version:
912 lines 21.5 kB
import { GenerationCommonConfigSchema, Message, z } from "genkit"; import { modelRef } from "genkit/model"; const MODELS_SUPPORTING_OPENAI_RESPONSE_FORMAT = [ "gpt-4", "gpt-4-32k", "gpt-4o", "gpt-4o-mini", "gpt-o1", "gpt-o1-mini", "gpt-o1-preview", "gpt-3.5-turbo", "gpt-3.5-turbo-instruct", "gpt-3.5-turbo-26k", "gpt-4.5", "gpt-4.1-mini", "gpt-4.1-nano", "gpt-4.1", "gpt-5", "gpt-5-mini", "gpt-5-nano", "gpt-5-chat", "gpt-5-codex", "gpt-5-pro", "gpt-5.1", "gpt-5.1-chat", "gpt-5.1-codex", "gpt-5.1-codex-mini", "gpt-5.1-codex-max", "gpt-5.2", "gpt-5.2-chat", "gpt-5.2-codex", "gpt-oss-120b", "gpt-oss-20b", "o3", "o3-mini", "o3-pro", "o4-mini", "o1", "o1-mini", "o1-preview", "codex-mini" ]; const OpenAiConfigSchema = GenerationCommonConfigSchema.extend({ frequencyPenalty: z.number().min(-2).max(2).optional(), logitBias: z.record(z.string(), z.number().min(-100).max(100)).optional(), logProbs: z.boolean().optional(), presencePenalty: z.number().min(-2).max(2).optional(), seed: z.number().int().optional(), topLogProbs: z.number().int().min(0).max(20).optional(), user: z.string().optional(), visualDetailLevel: z.enum(["auto", "low", "high"]).optional() }); const gpt4o = modelRef({ name: "azure-openai/gpt-4o", info: { versions: ["gpt-4o"], label: "OpenAI - GPT-4o", supports: { multiturn: true, tools: true, media: true, systemRole: true, output: ["text", "json"] } }, configSchema: OpenAiConfigSchema }); const gpt4oMini = modelRef({ name: "azure-openai/gpt-4o-mini", info: { versions: ["gpt-4o-mini"], label: "OpenAI - GPT-4o Mini", supports: { multiturn: true, tools: true, media: true, systemRole: true, output: ["text", "json"] } }, configSchema: OpenAiConfigSchema }); const gpt4 = modelRef({ name: "azure-openai/gpt-4", info: { versions: ["gpt-4", "gpt-4-32k"], label: "OpenAI - GPT-4", supports: { multiturn: true, tools: true, media: true, systemRole: true, output: ["text", "json"] } }, configSchema: OpenAiConfigSchema }); const gpt45 = modelRef({ name: "azure-openai/gpt-4.5", info: { versions: ["gpt-4.5-preview"], label: "OpenAI - GPT-4.5", supports: { multiturn: true, tools: true, media: true, systemRole: true, output: ["text", "json"] } }, configSchema: OpenAiConfigSchema }); const gpt5 = modelRef({ name: "azure-openai/gpt-5", info: { versions: ["gpt-5"], label: "OpenAI - GPT-5", supports: { multiturn: true, tools: true, media: true, systemRole: true, output: ["text", "json"] } }, configSchema: OpenAiConfigSchema }); const gpt5Mini = modelRef({ name: "azure-openai/gpt-5-mini", info: { versions: ["gpt-5-mini"], label: "OpenAI - GPT-5 Mini", supports: { multiturn: true, tools: true, media: true, systemRole: true, output: ["text", "json"] } }, configSchema: OpenAiConfigSchema }); const gpt5Nano = modelRef({ name: "azure-openai/gpt-5-nano", info: { versions: ["gpt-5-nano"], label: "OpenAI - GPT-5 Nano", supports: { multiturn: true, tools: true, media: true, systemRole: true, output: ["text", "json"] } }, configSchema: OpenAiConfigSchema }); const gpt5Chat = modelRef({ name: "azure-openai/gpt-5-chat", info: { versions: ["gpt-5-chat"], label: "OpenAI - GPT-5 Chat", supports: { multiturn: true, tools: true, media: true, systemRole: true, output: ["text"] } }, configSchema: OpenAiConfigSchema }); const gpt5Codex = modelRef({ name: "azure-openai/gpt-5-codex", info: { versions: ["gpt-5-codex"], label: "OpenAI - GPT-5 Codex", supports: { multiturn: true, tools: true, media: true, systemRole: true, output: ["text", "json"] } }, configSchema: OpenAiConfigSchema }); const gpt5Pro = modelRef({ name: "azure-openai/gpt-5-pro", info: { versions: ["gpt-5-pro"], label: "OpenAI - GPT-5 Pro", supports: { multiturn: true, tools: true, media: true, systemRole: true, output: ["text", "json"] } }, configSchema: OpenAiConfigSchema }); const gpt51 = modelRef({ name: "azure-openai/gpt-5.1", info: { versions: ["gpt-5.1"], label: "OpenAI - GPT-5.1", supports: { multiturn: true, tools: true, media: true, systemRole: true, output: ["text", "json"] } }, configSchema: OpenAiConfigSchema }); const gpt51Chat = modelRef({ name: "azure-openai/gpt-5.1-chat", info: { versions: ["gpt-5.1-chat"], label: "OpenAI - GPT-5.1 Chat", supports: { multiturn: true, tools: true, media: false, systemRole: true, output: ["text", "json"] } }, configSchema: OpenAiConfigSchema }); const gpt51Codex = modelRef({ name: "azure-openai/gpt-5.1-codex", info: { versions: ["gpt-5.1-codex"], label: "OpenAI - GPT-5.1 Codex", supports: { multiturn: true, tools: true, media: true, systemRole: true, output: ["text", "json"] } }, configSchema: OpenAiConfigSchema }); const gpt51CodexMini = modelRef({ name: "azure-openai/gpt-5.1-codex-mini", info: { versions: ["gpt-5.1-codex-mini"], label: "OpenAI - GPT-5.1 Codex Mini", supports: { multiturn: true, tools: true, media: true, systemRole: true, output: ["text", "json"] } }, configSchema: OpenAiConfigSchema }); const gpt51CodexMax = modelRef({ name: "azure-openai/gpt-5.1-codex-max", info: { versions: ["gpt-5.1-codex-max"], label: "OpenAI - GPT-5.1 Codex Max", supports: { multiturn: true, tools: true, media: true, systemRole: true, output: ["text", "json"] } }, configSchema: OpenAiConfigSchema }); const gpt52 = modelRef({ name: "azure-openai/gpt-5.2", info: { versions: ["gpt-5.2"], label: "OpenAI - GPT-5.2", supports: { multiturn: true, tools: true, media: true, systemRole: true, output: ["text", "json"] } }, configSchema: OpenAiConfigSchema }); const gpt52Chat = modelRef({ name: "azure-openai/gpt-5.2-chat", info: { versions: ["gpt-5.2-chat"], label: "OpenAI - GPT-5.2 Chat", supports: { multiturn: true, tools: true, media: false, systemRole: true, output: ["text", "json"] } }, configSchema: OpenAiConfigSchema }); const gpt52Codex = modelRef({ name: "azure-openai/gpt-5.2-codex", info: { versions: ["gpt-5.2-codex"], label: "OpenAI - GPT-5.2 Codex", supports: { multiturn: true, tools: true, media: true, systemRole: true, output: ["text", "json"] } }, configSchema: OpenAiConfigSchema }); const gptOss120b = modelRef({ name: "azure-openai/gpt-oss-120b", info: { versions: ["gpt-oss-120b"], label: "OpenAI - GPT-OSS 120B", supports: { multiturn: true, tools: true, media: false, systemRole: true, output: ["text", "json"] } }, configSchema: OpenAiConfigSchema }); const gptOss20b = modelRef({ name: "azure-openai/gpt-oss-20b", info: { versions: ["gpt-oss-20b"], label: "OpenAI - GPT-OSS 20B", supports: { multiturn: true, tools: true, media: false, systemRole: true, output: ["text", "json"] } }, configSchema: OpenAiConfigSchema }); const gpt41 = modelRef({ name: "azure-openai/gpt-4.1", info: { versions: ["gpt-4.1"], label: "OpenAI - GPT-4.1", supports: { multiturn: true, tools: true, media: true, systemRole: true, output: ["text", "json"] } }, configSchema: OpenAiConfigSchema }); const gpt41Mini = modelRef({ name: "azure-openai/gpt-4.1-mini", info: { versions: ["gpt-4.1-mini"], label: "OpenAI - GPT-4.1 Mini", supports: { multiturn: true, tools: true, media: true, systemRole: true, output: ["text", "json"] } }, configSchema: OpenAiConfigSchema }); const gpt41Nano = modelRef({ name: "azure-openai/gpt-4.1-nano", info: { versions: ["gpt-4.1-nano"], label: "OpenAI - GPT-4.1 Nano", supports: { multiturn: true, tools: true, media: true, systemRole: true, output: ["text", "json"] } }, configSchema: OpenAiConfigSchema }); const o1 = modelRef({ name: "azure-openai/o1", info: { versions: ["o1"], label: "OpenAI - o1", supports: { multiturn: true, tools: false, media: true, systemRole: true, output: ["text"] } }, configSchema: OpenAiConfigSchema }); const o1Mini = modelRef({ name: "azure-openai/o1-mini", info: { versions: ["o1-mini"], label: "OpenAI - o1 Mini", supports: { multiturn: true, tools: true, media: false, systemRole: true, output: ["text"] } }, configSchema: OpenAiConfigSchema }); const o1Preview = modelRef({ name: "azure-openai/o1-preview", info: { versions: ["o1-preview"], label: "OpenAI - o1 Preview", supports: { multiturn: true, tools: true, media: true, systemRole: true, output: ["text"] } }, configSchema: OpenAiConfigSchema }); const o3 = modelRef({ name: "azure-openai/o3", info: { versions: ["o3"], label: "OpenAI - o3", supports: { multiturn: true, tools: true, media: true, systemRole: true, output: ["text"] } }, configSchema: OpenAiConfigSchema }); const o4Mini = modelRef({ name: "azure-openai/o4-mini", info: { versions: ["o4-mini"], label: "OpenAI - o4 Mini", supports: { multiturn: true, tools: true, media: true, systemRole: true, output: ["text"] } }, configSchema: OpenAiConfigSchema }); const o3Mini = modelRef({ name: "azure-openai/o3-mini", info: { versions: ["o3-mini"], label: "OpenAI - o3 Mini", supports: { multiturn: true, tools: true, media: false, systemRole: true, output: ["text"] } }, configSchema: OpenAiConfigSchema }); const o3Pro = modelRef({ name: "azure-openai/o3-pro", info: { versions: ["o3-pro"], label: "OpenAI - o3 Pro", supports: { multiturn: true, tools: true, media: true, systemRole: true, output: ["text"] } }, configSchema: OpenAiConfigSchema }); const codexMini = modelRef({ name: "azure-openai/codex-mini", info: { versions: ["codex-mini"], label: "OpenAI - Codex Mini", supports: { multiturn: true, tools: true, media: true, systemRole: true, output: ["text"] } }, configSchema: OpenAiConfigSchema }); const gpt35Turbo = modelRef({ name: "azure-openai/gpt-3.5-turbo", info: { versions: ["gpt-3.5-turbo", "gpt-35-turbo-instruct", "gpt-35-turbo-16k"], label: "OpenAI - GPT-3.5 Turbo", supports: { multiturn: true, tools: true, media: false, systemRole: true, output: ["json", "text"] } }, configSchema: OpenAiConfigSchema }); const SUPPORTED_GPT_MODELS = { "o1-mini": o1Mini, "o1-preview": o1Preview, o1, o3, "o3-mini": o3Mini, "o3-pro": o3Pro, "o4-mini": o4Mini, "codex-mini": codexMini, "gpt-4.1": gpt41, "gpt-4.1-mini": gpt41Mini, "gpt-4.1-nano": gpt41Nano, "gpt-4": gpt4, "gpt-4o": gpt4o, "gpt-4o-mini": gpt4oMini, "gpt-4.5": gpt45, "gpt-5": gpt5, "gpt-5-mini": gpt5Mini, "gpt-5-nano": gpt5Nano, "gpt-5-chat": gpt5Chat, "gpt-5-codex": gpt5Codex, "gpt-5-pro": gpt5Pro, "gpt-5.1": gpt51, "gpt-5.1-chat": gpt51Chat, "gpt-5.1-codex": gpt51Codex, "gpt-5.1-codex-mini": gpt51CodexMini, "gpt-5.1-codex-max": gpt51CodexMax, "gpt-5.2": gpt52, "gpt-5.2-chat": gpt52Chat, "gpt-5.2-codex": gpt52Codex, "gpt-oss-120b": gptOss120b, "gpt-oss-20b": gptOss20b, "gpt-3.5-turbo": gpt35Turbo }; function toOpenAIRole(role) { switch (role) { case "user": return "user"; case "model": return "assistant"; case "system": return "system"; case "tool": return "tool"; default: throw new Error(`role ${role} doesn't map to an OpenAI role.`); } } function toOpenAiTool(tool) { let parameters; if (tool.inputSchema !== null) { if (typeof tool.inputSchema === "string") { try { parameters = JSON.parse(tool.inputSchema); } catch (error) { const errorMessage = error instanceof Error ? error.message : "Unknown parsing error"; throw new Error( `Invalid JSON schema for function '${tool.name}': ${errorMessage}` ); } } else { parameters = tool.inputSchema; } parameters.type = "object"; parameters.properties = { ...tool.inputSchema.properties }; } return { type: "function", function: { name: tool.name, parameters } }; } function toOpenAiTextAndMedia(part, visualDetailLevel) { if (part.text) { return { type: "text", text: part.text }; } else if (part.media) { return { type: "image_url", image_url: { url: part.media.url, detail: visualDetailLevel } }; } throw Error( `Unsupported genkit part fields encountered for current message role: ${part}.` ); } function toOpenAiMessages(messages, visualDetailLevel = "auto") { const openAiMsgs = []; for (const message of messages) { const msg = new Message(message); const role = toOpenAIRole(message.role); switch (role) { case "user": openAiMsgs.push({ role, content: msg.content.map( (part) => toOpenAiTextAndMedia(part, visualDetailLevel) ) }); break; case "system": openAiMsgs.push({ role, content: msg.text }); break; case "assistant": { const toolCalls = msg.content.filter((part) => part.toolRequest).map((part) => { if (!part.toolRequest) { throw Error( "Mapping genkit message to openai tool call content part but message.toolRequest not provided." ); } return { id: part.toolRequest.ref || "", type: "function", function: { name: part.toolRequest.name, arguments: JSON.stringify(part.toolRequest.input) } }; }); if (toolCalls?.length > 0) { openAiMsgs.push({ role, tool_calls: toolCalls }); } else { openAiMsgs.push({ role, content: msg.text }); } break; } case "tool": { const toolResponseParts = msg.toolResponseParts(); toolResponseParts.map((part) => { openAiMsgs.push({ role, tool_call_id: part.toolResponse.ref || "", content: typeof part.toolResponse.output === "string" ? part.toolResponse.output : JSON.stringify(part.toolResponse.output) }); }); break; } default: { throw new Error("unrecognized role"); } } } return openAiMsgs; } const finishReasonMap = { length: "length", stop: "stop", tool_calls: "stop", content_filter: "blocked", function_call: "stop" }; function fromOpenAiToolCall(toolCall, choice) { if (!("function" in toolCall && toolCall.function && typeof toolCall.function === "object")) { throw Error( `Unexpected openAI chunk choice. tool_calls was provided but one or more tool_calls is missing function property.` ); } const f = toolCall.function; if (choice.finish_reason === "tool_calls") { return { toolRequest: { name: f.name, ref: toolCall.id, input: f.arguments ? JSON.parse(f.arguments) : f.arguments } }; } else { return { toolRequest: { name: f.name, ref: toolCall.id, input: "" } }; } } function fromOpenAiChoice(choice, jsonMode = false) { const toolRequestParts = choice.message.tool_calls?.map( (toolCall) => fromOpenAiToolCall(toolCall, choice) ); return { index: choice.index, finishReason: finishReasonMap[choice.finish_reason] || "other", message: { role: "model", content: toolRequestParts ? ( // Note: Not sure why I have to cast here exactly. // Otherwise it thinks toolRequest must be 'undefined' if provided toolRequestParts ) : [ jsonMode ? { data: JSON.parse(choice.message.content) } : { text: choice.message.content } ] }, custom: {} }; } function fromOpenAiChunkChoice(choice, jsonMode = false) { const toolRequestParts = choice.delta.tool_calls?.map( (toolCall) => fromOpenAiToolCall(toolCall, choice) ); return { index: choice.index, finishReason: choice.finish_reason ? finishReasonMap[choice.finish_reason] || "other" : "unknown", message: { role: "model", content: toolRequestParts ? ( // Note: Not sure why I have to cast here exactly. // Otherwise it thinks toolRequest must be 'undefined' if provided toolRequestParts ) : [ jsonMode ? { data: JSON.parse(choice.delta.content) } : { text: choice.delta.content } ] }, custom: {} }; } function toOpenAiRequestBody(modelName, request) { const mapToSnakeCase = (obj) => { return Object.entries(obj).reduce( (acc, [key, value]) => { const snakeCaseKey = key.replace( /[A-Z]/g, (letter) => `_${letter.toLowerCase()}` ); acc[snakeCaseKey] = value; return acc; }, {} ); }; const model = SUPPORTED_GPT_MODELS[modelName]; if (!model) throw new Error(`Unsupported model: ${modelName}`); const openAiMessages = toOpenAiMessages( request.messages, request.config?.visualDetailLevel ); const mappedModelName = request.config?.version || modelName; const body = { messages: openAiMessages, tools: request.tools?.map(toOpenAiTool), model: mappedModelName, max_tokens: request.config?.maxOutputTokens, temperature: request.config?.temperature, top_p: request.config?.topP, n: request.candidates, stop: request.config?.stopSequences, ...mapToSnakeCase(request.config?.custom || {}) }; const response_format = request.output?.format; if (response_format && MODELS_SUPPORTING_OPENAI_RESPONSE_FORMAT.includes(mappedModelName)) { if (response_format === "json" && model.info?.supports?.output?.includes("json")) { body.response_format = { type: "json_object" }; } else if (response_format === "text" && model.info?.supports?.output?.includes("text")) { body.response_format = { type: "text" }; } else { throw new Error( `${response_format} format is not supported for GPT models currently` ); } } for (const key in body) { const typedKey = key; if (!body[typedKey] || Array.isArray(body[typedKey]) && !body[typedKey].length) delete body[typedKey]; } return body; } function gptModel(ai, name, client) { const modelId = `azure-openai/${name}`; const model = SUPPORTED_GPT_MODELS[name]; if (!model) throw new Error(`Unsupported model: ${name}`); return ai.defineModel( { name: modelId, ...model.info, configSchema: SUPPORTED_GPT_MODELS[name].configSchema }, async (request, streamingCallback) => { let response; const body = toOpenAiRequestBody(name, request); if (streamingCallback) { const stream = client.chat.completions.stream({ ...body, stream: true, stream_options: { include_usage: true } }); for await (const chunk of stream) { chunk.choices?.forEach((chunk2) => { const c = fromOpenAiChunkChoice(chunk2); streamingCallback({ index: c.index, content: c.message.content }); }); } response = await stream.finalChatCompletion(); } else { response = await client.chat.completions.create(body); } return { candidates: response.choices.map( (c) => fromOpenAiChoice(c, request.output?.format === "json") ), usage: { inputTokens: response.usage?.prompt_tokens, outputTokens: response.usage?.completion_tokens, totalTokens: response.usage?.total_tokens }, custom: response }; } ); } export { OpenAiConfigSchema, SUPPORTED_GPT_MODELS, codexMini, gpt35Turbo, gpt4, gpt41, gpt41Mini, gpt41Nano, gpt45, gpt4o, gpt4oMini, gpt5, gpt51, gpt51Chat, gpt51Codex, gpt51CodexMax, gpt51CodexMini, gpt52, gpt52Chat, gpt52Codex, gpt5Chat, gpt5Codex, gpt5Mini, gpt5Nano, gpt5Pro, gptModel, gptOss120b, gptOss20b, o1, o1Mini, o1Preview, o3, o3Mini, o3Pro, o4Mini, toOpenAiMessages, toOpenAiRequestBody, toOpenAiTextAndMedia }; //# sourceMappingURL=gpt.mjs.map