| | |
| | |
| | |
| | import { fetchAndEncode } from './remoteimage'; |
| | import { z } from 'zod'; |
| | import { ToolRegistry } from '@google/gemini-cli-core/dist/src/tools/tool-registry.js'; |
| |
|
| | |
| | type Part = { text?: string; inlineData?: { mimeType: string; data: string } }; |
| |
|
| | |
| | async function callLocalFunction(_name: string, _args: unknown) { |
| | return { ok: true }; |
| | } |
| |
|
| | |
| | |
| | |
| | export async function mapRequest(body: any) { |
| | const parts: Part[] = []; |
| |
|
| | |
| | for (const m of body.messages) { |
| | if (Array.isArray(m.content)) { |
| | for (const item of m.content) { |
| | if (item.type === 'image_url') { |
| | parts.push({ inlineData: await fetchAndEncode(item.image_url.url) }); |
| | } else if (item.type === 'text') { |
| | parts.push({ text: item.text }); |
| | } |
| | } |
| | } else { |
| | parts.push({ text: m.content }); |
| | } |
| | } |
| |
|
| | |
| | const generationConfig: Record<string, unknown> = { |
| | temperature: body.temperature, |
| | maxOutputTokens: body.max_tokens, |
| | topP: body.top_p, |
| | ...(body.generationConfig ?? {}), |
| | }; |
| | if (body.include_reasoning === true) { |
| | generationConfig.enable_thoughts = true; |
| | generationConfig.thinking_budget ??= 2048; |
| | } |
| |
|
| | |
| | if (body.include_reasoning === true && generationConfig.thinking !== true) { |
| | generationConfig.thinking = true; |
| | generationConfig.thinking_budget ??= 2048; |
| | } |
| | generationConfig.maxInputTokens ??= 1_000_000; |
| |
|
| | const geminiReq = { |
| | contents: [{ role: 'user', parts }], |
| | generationConfig, |
| | stream: body.stream, |
| | }; |
| |
|
| | |
| | const tools = new ToolRegistry({} as any); |
| |
|
| | if (body.functions?.length) { |
| | const reg = tools as any; |
| | body.functions.forEach((fn: any) => |
| | reg.registerTool( |
| | fn.name, |
| | { |
| | title: fn.name, |
| | description: fn.description ?? '', |
| | inputSchema: z.object(fn.parameters?.properties ?? {}), |
| | }, |
| | async (args: unknown) => callLocalFunction(fn.name, args), |
| | ), |
| | ); |
| | } |
| |
|
| | return { geminiReq, tools }; |
| | } |
| |
|
| | |
| | |
| | |
| | export function mapResponse(gResp: any) { |
| | const usage = gResp.usageMetadata ?? {}; |
| | return { |
| | id: `chatcmpl-${Date.now()}`, |
| | object: 'chat.completion', |
| | created: Math.floor(Date.now() / 1000), |
| | model: 'gemini-2.5-pro-latest', |
| | choices: [ |
| | { |
| | index: 0, |
| | message: { role: 'assistant', content: gResp.text }, |
| | finish_reason: 'stop', |
| | }, |
| | ], |
| | usage: { |
| | prompt_tokens: usage.promptTokens ?? 0, |
| | completion_tokens: usage.candidatesTokens ?? 0, |
| | total_tokens: usage.totalTokens ?? 0, |
| | }, |
| | }; |
| | } |
| |
|
| | |
| | |
| | |
| |
|
| | export function mapStreamChunk(chunk: any) { |
| | const part = chunk?.candidates?.[0]?.content?.parts?.[0] ?? {}; |
| | const delta: any = { role: 'assistant' }; |
| |
|
| | if (part.thought === true) { |
| | delta.content = `<think>${part.text ?? ''}`; |
| | } else if (typeof part.text === 'string') { |
| | delta.content = part.text; |
| | } |
| | return { choices: [ { delta, index: 0 } ] }; |
| | } |
| |
|
| |
|
| |
|