UNPKG

aiwrapper

Version:

A Universal AI Wrapper for JavaScript & TypeScript

325 lines (322 loc) 12 kB
var __defProp = Object.defineProperty; var __getOwnPropSymbols = Object.getOwnPropertySymbols; var __hasOwnProp = Object.prototype.hasOwnProperty; var __propIsEnum = Object.prototype.propertyIsEnumerable; var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value; var __spreadValues = (a, b) => { for (var prop in b || (b = {})) if (__hasOwnProp.call(b, prop)) __defNormalProp(a, prop, b[prop]); if (__getOwnPropSymbols) for (var prop of __getOwnPropSymbols(b)) { if (__propIsEnum.call(b, prop)) __defNormalProp(a, prop, b[prop]); } return a; }; var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value); import { LanguageProvider } from "../language-provider.js"; import { httpRequestWithRetry as fetch } from "../../http-request.js"; import { models } from "aimodels"; import { calculateModelResponseTokens } from "../utils/token-calculator.js"; import { LangMessage, LangMessages } from "../messages.js"; import { addInstructionAboutSchema } from "../prompt-for-json.js"; class GoogleLang extends LanguageProvider { constructor(options) { const modelName = options.model || "gemini-1.5-flash"; super(modelName); __publicField(this, "_apiKey"); __publicField(this, "_model"); __publicField(this, "_systemPrompt"); __publicField(this, "_maxTokens"); __publicField(this, "modelInfo"); const modelInfo = models.id(modelName); if (!modelInfo) { console.error(`Invalid Google model: ${modelName}. Model not found in aimodels database.`); } this.modelInfo = modelInfo; this._apiKey = options.apiKey; this._model = modelName; this._systemPrompt = options.systemPrompt || ""; this._maxTokens = options.maxTokens; } async ask(prompt, options) { const messages = new LangMessages(); if (this._systemPrompt) { messages.instructions = this._systemPrompt; } messages.addUserMessage(prompt); return await this.chat(messages, options); } async chat(messages, options) { var _a, _b; const messageCollection = messages instanceof LangMessages ? messages : new LangMessages(messages); const instructions = this.buildInstructions(messageCollection, options); const contents = this.transformMessagesForProvider(messageCollection); const maxOutputTokens = this.computeMaxTokens(messageCollection); const tools = this.buildTools(messageCollection.availableTools); const generationConfig = {}; if (typeof maxOutputTokens === "number") { generationConfig.max_output_tokens = maxOutputTokens; } const requestBody = __spreadValues(__spreadValues(__spreadValues(__spreadValues({ contents }, instructions ? { system_instruction: { role: "system", parts: [{ text: instructions }] } } : {}), Object.keys(generationConfig).length > 0 ? { generation_config: generationConfig } : {}), tools ? { tools } : {}), (_a = options == null ? void 0 : options.providerSpecificBody) != null ? _a : {}); try { const response = await fetch( `https://generativelanguage.googleapis.com/v1beta/models/${this._model}:generateContent?key=${this._apiKey}`, { method: "POST", headers: __spreadValues({ "Content-Type": "application/json", // Some setups still expect the header, so keep both "x-goog-api-key": this._apiKey }, (_b = options == null ? void 0 : options.providerSpecificHeaders) != null ? _b : {}), body: JSON.stringify(requestBody), signal: options == null ? void 0 : options.signal } ); if (!response.ok) { const body = await response.text().catch(() => ""); throw new Error( `Google API request failed with status ${response.status}${body ? `: ${body}` : ""}` ); } const data = await response.json(); this.applyCandidates(data == null ? void 0 : data.candidates, messageCollection, options == null ? void 0 : options.onResult); } catch (error) { if ((error == null ? void 0 : error.name) === "AbortError") { messageCollection.aborted = true; error.partialResult = messageCollection; } throw error; } messageCollection.finished = true; const toolsResults = await messageCollection.executeRequestedTools(); if ((options == null ? void 0 : options.onResult) && toolsResults) options.onResult(toolsResults); return messageCollection; } transformMessagesForProvider(messages) { var _a; const mapped = []; for (const msg of messages) { if (msg.role === "tool-results") { const parts2 = msg.toolResults.map((tr) => { let response; if (Array.isArray(tr.result)) { response = { result: tr.result }; } else if (typeof tr.result === "object" && tr.result !== null) { response = tr.result; } else { response = { result: tr.result }; } return { functionResponse: { name: tr.name, response } }; }); mapped.push({ role: "user", parts: parts2 }); continue; } if (msg.role !== "user" && msg.role !== "assistant") { continue; } const parts = []; const legacyContent = msg.content; if (Array.isArray(legacyContent)) { parts.push(...this.mapPartsToGemini(legacyContent)); } else { for (const item of msg.items) { if (item.type === "text") { parts.push({ text: item.text }); } else if (item.type === "image") { const imagePart = this.mapImageItemToGemini(item); if (imagePart) parts.push(imagePart); } else if (item.type === "tool") { const toolItem = item; const part = { function_call: { name: toolItem.name, args: (_a = toolItem.arguments) != null ? _a : {} } }; if (toolItem.thoughtSignature) { part.thoughtSignature = toolItem.thoughtSignature; } parts.push(part); } } } if (parts.length === 0) { parts.push({ text: "" }); } mapped.push({ role: msg.role === "assistant" ? "model" : "user", parts }); } return mapped; } mapPartsToGemini(parts) { const out = []; for (const p of parts) { if (p.type === "text") { out.push({ text: p.text }); } else if (p.type === "image") { const inlineData = this.imageInputToGeminiInlineData(p.image); out.push({ inlineData }); } } return out; } imageInputToGeminiInlineData(image) { const kind = image.kind; if (kind === "base64") { const base64 = image.base64; const mimeType = image.mimeType || "image/png"; return { mimeType, data: base64 }; } if (kind === "url") { const url = image.url; if (url.startsWith("data:")) { const match = url.match(/^data:([^;]+);base64,(.*)$/); if (!match) throw new Error("Invalid data URL for Gemini image"); const mimeType = match[1]; const data = match[2]; return { mimeType, data }; } throw new Error("Gemini inline image requires base64 or data URL. Provide base64+mimeType or a data: URL."); } if (kind === "bytes" || kind === "blob") { throw new Error("Gemini image input requires base64. Convert bytes/blob to base64 first."); } throw new Error("Unknown image input kind for Gemini"); } mapImageItemToGemini(image) { if (typeof image.base64 === "string" && image.base64.length > 0) { return { inlineData: { mimeType: image.mimeType || "image/png", data: image.base64 } }; } if (typeof image.url === "string" && image.url.length > 0) { if (image.url.startsWith("data:")) { const match = image.url.match(/^data:([^;]+);base64,(.*)$/); if (!match) return null; const mimeType = match[1]; const data = match[2]; return { inlineData: { mimeType, data } }; } return { fileData: { fileUri: image.url } }; } return null; } buildInstructions(messageCollection, options) { let instructions = messageCollection.instructions || ""; if (this._systemPrompt) { instructions = instructions ? `${this._systemPrompt} ${instructions}` : this._systemPrompt; } if (options == null ? void 0 : options.schema) { const baseInstruction = instructions !== "" ? `${instructions} ` : ""; instructions = baseInstruction + addInstructionAboutSchema(options.schema); messageCollection.instructions = instructions; } return instructions; } computeMaxTokens(messageCollection) { if (this._maxTokens !== void 0) return this._maxTokens; if (!this.modelInfo) return void 0; return calculateModelResponseTokens( this.modelInfo, messageCollection, this._maxTokens ); } buildTools(availableTools) { if (!availableTools || !Array.isArray(availableTools) || availableTools.length === 0) { return void 0; } const functionDeclarations = availableTools.map((tool) => ({ name: tool.name, description: tool.description || "", parameters: tool.parameters })); return functionDeclarations.length > 0 ? [{ function_declarations: functionDeclarations }] : void 0; } applyCandidates(candidates, result, onResult) { var _a, _b; if (!Array.isArray(candidates) || candidates.length === 0) { return; } const candidate = candidates[0]; const parts = (_a = candidate == null ? void 0 : candidate.content) == null ? void 0 : _a.parts; if (!Array.isArray(parts) || parts.length === 0) return; const assistantMessage = new LangMessage("assistant", []); let toolIndex = 0; for (const part of parts) { if (!part) continue; if (typeof part.text === "string" && part.text.length > 0) { assistantMessage.items.push({ type: "text", text: part.text }); } if (part.inlineData && (part.inlineData.data || part.inlineData.b64_json)) { const base64 = part.inlineData.data || part.inlineData.b64_json; const mimeType = part.inlineData.mimeType || "image/png"; assistantMessage.items.push({ type: "image", base64, mimeType }); } if ((_b = part.fileData) == null ? void 0 : _b.fileUri) { assistantMessage.items.push({ type: "image", url: part.fileData.fileUri }); } const funcCall = part.functionCall || part.function_call; if (funcCall) { const name = funcCall.name || `function_call_${toolIndex}`; const callId = `function_call_${toolIndex++}`; const rawArgs = funcCall.args || funcCall.arguments; const args = this.parseFunctionArgs(rawArgs); const toolItem = { type: "tool", callId, name, arguments: args }; const thoughtSignature = part.thoughtSignature || (funcCall == null ? void 0 : funcCall.thoughtSignature); if (thoughtSignature) { toolItem.thoughtSignature = thoughtSignature; } assistantMessage.items.push(toolItem); } } if (assistantMessage.items.length > 0) { result.push(assistantMessage); onResult == null ? void 0 : onResult(assistantMessage); } } parseFunctionArgs(rawArgs) { if (!rawArgs) return {}; if (typeof rawArgs === "object") return rawArgs; if (typeof rawArgs === "string") { try { return JSON.parse(rawArgs); } catch (e) { return {}; } } return {}; } } export { GoogleLang }; //# sourceMappingURL=google-lang.js.map