UNPKG

@genkit-ai/vertexai

Version:

Genkit AI framework plugin for Google Cloud Vertex AI APIs including Gemini APIs, Imagen, and more.

308 lines 10.8 kB
"use strict"; var __defProp = Object.defineProperty; var __getOwnPropDesc = Object.getOwnPropertyDescriptor; var __getOwnPropNames = Object.getOwnPropertyNames; var __hasOwnProp = Object.prototype.hasOwnProperty; var __export = (target, all) => { for (var name2 in all) __defProp(target, name2, { get: all[name2], enumerable: true }); }; var __copyProps = (to, from, except, desc) => { if (from && typeof from === "object" || typeof from === "function") { for (let key of __getOwnPropNames(from)) if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); } return to; }; var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); var openai_compatibility_exports = {}; __export(openai_compatibility_exports, { OpenAIConfigSchema: () => OpenAIConfigSchema, fromOpenAiChoice: () => fromOpenAiChoice, fromOpenAiChunkChoice: () => fromOpenAiChunkChoice, fromOpenAiToolCall: () => fromOpenAiToolCall, openaiCompatibleModel: () => openaiCompatibleModel, toOpenAIRole: () => toOpenAIRole, toOpenAiMessages: () => toOpenAiMessages, toOpenAiTextAndMedia: () => toOpenAiTextAndMedia, toRequestBody: () => toRequestBody }); module.exports = __toCommonJS(openai_compatibility_exports); var import_genkit = require("genkit"); var import_model = require("genkit/model"); const OpenAIConfigSchema = import_model.GenerationCommonConfigSchema.extend({ // TODO: topK is not supported and some of the other common config options // have different names in the above doc. Eg: max_completion_tokens. // Update to use the parameters in above doc. frequencyPenalty: import_genkit.z.number().min(-2).max(2).describe( "Positive values penalize new tokens based on their existing frequency in the text so far, decreasing the model's likelihood to repeat the same line verbatim." ).optional(), logitBias: import_genkit.z.record( import_genkit.z.string().describe("Token string."), import_genkit.z.number().min(-100).max(100).describe("Associated bias value.") ).describe( "Controls the likelihood of specified tokens appearing in the generated output. Map of tokens to an associated bias value from -100 (which will in most cases block that token from being generated) to 100 (exclusive selection of the token which makes it more likely to be generated). Moderate values like -1 and 1 will change the probability of a token being selected to a lesser degree." ).optional(), logProbs: import_genkit.z.boolean().describe( "Whether to return log probabilities of the output tokens or not." ).optional(), presencePenalty: import_genkit.z.number().min(-2).max(2).describe( "Positive values penalize new tokens based on whether they appear in the text so far, increasing the model's likelihood to talk about new topics." ).optional(), seed: import_genkit.z.number().int().describe( "If specified, the system will make a best effort to sample deterministically, such that repeated requests with the same seed and parameters should return the same result. Determinism is not guaranteed, and you should refer to the system_fingerprint response parameter to monitor changes in the backend." ).optional(), topLogProbs: import_genkit.z.number().int().min(0).max(20).describe( "An integer specifying the number of most likely tokens to return at each token position, each with an associated log probability. logprobs must be set to true if this parameter is used." ).optional(), user: import_genkit.z.string().describe( "A unique identifier representing your end-user to monitor and detect abuse." ).optional() }); 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) { return { type: "function", function: { name: tool.name, parameters: tool.inputSchema || void 0 } }; } function toOpenAiTextAndMedia(part) { if (part.text) { return { type: "text", text: part.text }; } else if (part.media) { return { type: "image_url", image_url: { url: part.media.url } }; } throw Error( `Unsupported genkit part fields encountered for current message role: ${JSON.stringify(part)}.` ); } function toOpenAiMessages(messages) { const openAiMsgs = []; for (const message of messages) { const msg = new import_genkit.Message(message); const role = toOpenAIRole(message.role); switch (role) { case "user": openAiMsgs.push({ role, content: msg.content.map((part) => toOpenAiTextAndMedia(part)) }); break; case "system": openAiMsgs.push({ role, content: msg.text }); break; case "assistant": { const toolCalls = msg.content.filter( (part) => Boolean(part.toolRequest) ).map((part) => ({ 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; } } } return openAiMsgs; } const finishReasonMap = { length: "length", stop: "stop", tool_calls: "stop", content_filter: "blocked" }; function fromOpenAiToolCall(toolCall) { if (!toolCall.function) { throw Error( `Unexpected openAI chunk choice. tool_calls was provided but one or more tool_calls is missing.` ); } const f = toolCall.function; return { toolRequest: { name: f.name, ref: toolCall.id, input: f.arguments ? JSON.parse(f.arguments) : f.arguments } }; } function fromOpenAiChoice(choice, jsonMode = false) { const toolRequestParts = choice.message.tool_calls?.map(fromOpenAiToolCall); 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(fromOpenAiToolCall); return { index: choice.index, finishReason: choice.finish_reason ? finishReasonMap[choice.finish_reason] || "other" : "unknown", message: { role: "model", content: toolRequestParts ? toolRequestParts : [ jsonMode ? { data: JSON.parse(choice.delta.content) } : { text: choice.delta.content } ] }, custom: {} }; } function toRequestBody(model, request) { const openAiMessages = toOpenAiMessages(request.messages); const mappedModelName = request.config?.version || model.version || model.name; const body = { model: mappedModelName, messages: openAiMessages, temperature: request.config?.temperature, max_tokens: request.config?.maxOutputTokens, top_p: request.config?.topP, stop: request.config?.stopSequences, frequency_penalty: request.config?.frequencyPenalty, logit_bias: request.config?.logitBias, logprobs: request.config?.logProbs, presence_penalty: request.config?.presencePenalty, seed: request.config?.seed, top_logprobs: request.config?.topLogProbs, user: request.config?.user, tools: request.tools?.map(toOpenAiTool), n: request.candidates }; const response_format = request.output?.format; if (response_format) { 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")) { } else { throw new Error(`${response_format} format is not supported currently`); } } for (const key in body) { if (!body[key] || Array.isArray(body[key]) && !body[key].length) delete body[key]; } return body; } function openaiCompatibleModel(ai, model, clientFactory) { const modelId = model.name; if (!model) throw new Error(`Unsupported model: ${name}`); return ai.defineModel( { name: modelId, ...model.info, configSchema: model.configSchema }, async (request, sendChunk) => { let response; const client = await clientFactory(request); const body = toRequestBody(model, request); if (sendChunk) { const stream = client.beta.chat.completions.stream({ ...body, stream: true }); for await (const chunk of stream) { chunk.choices?.forEach((chunk2) => { const c = fromOpenAiChunkChoice(chunk2); sendChunk({ 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 }; } ); } // Annotate the CommonJS export names for ESM import in node: 0 && (module.exports = { OpenAIConfigSchema, fromOpenAiChoice, fromOpenAiChunkChoice, fromOpenAiToolCall, openaiCompatibleModel, toOpenAIRole, toOpenAiMessages, toOpenAiTextAndMedia, toRequestBody }); //# sourceMappingURL=openai_compatibility.js.map