@llm-ports/adapter-google 0.1.0-alpha.5 → 0.1.0-alpha.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -177,6 +177,7 @@ function createPort(ctx, modelId, alias) {
177
177
  };
178
178
  return {
179
179
  async generateText(options) {
180
+ core.throwIfAborted(options.signal);
180
181
  validateContent(options.prompt);
181
182
  const start = Date.now();
182
183
  try {
@@ -187,7 +188,8 @@ function createPort(ctx, modelId, alias) {
187
188
  config: {
188
189
  ...options.instructions !== void 0 ? { systemInstruction: options.instructions } : {},
189
190
  ...options.temperature !== void 0 ? { temperature: options.temperature } : {},
190
- ...options.maxOutputTokens !== void 0 ? { maxOutputTokens: options.maxOutputTokens } : {}
191
+ ...options.maxOutputTokens !== void 0 ? { maxOutputTokens: options.maxOutputTokens } : {},
192
+ ...options.signal ? { abortSignal: options.signal } : {}
191
193
  }
192
194
  });
193
195
  const candidate = response.candidates?.[0];
@@ -206,6 +208,7 @@ function createPort(ctx, modelId, alias) {
206
208
  }
207
209
  },
208
210
  async generateStructured(options) {
211
+ core.throwIfAborted(options.signal);
209
212
  validateContent(options.prompt);
210
213
  const start = Date.now();
211
214
  let attempts = 0;
@@ -228,7 +231,8 @@ Reply with a single JSON object only. No prose, no code fences.`;
228
231
  ...options.instructions !== void 0 ? { systemInstruction: options.instructions } : {},
229
232
  temperature: options.temperature ?? 0,
230
233
  ...options.maxOutputTokens !== void 0 ? { maxOutputTokens: options.maxOutputTokens } : {},
231
- responseMimeType: "application/json"
234
+ responseMimeType: "application/json",
235
+ ...options.signal ? { abortSignal: options.signal } : {}
232
236
  }
233
237
  });
234
238
  const candidate = response.candidates?.[0];
@@ -269,6 +273,7 @@ Reply with a single corrected JSON object only.`;
269
273
  throw new Error("generateStructured exhausted attempts");
270
274
  },
271
275
  async *streamText(options) {
276
+ core.throwIfAborted(options.signal);
272
277
  validateContent(options.prompt);
273
278
  try {
274
279
  const parts = toGeminiParts2(options.prompt);
@@ -278,7 +283,8 @@ Reply with a single corrected JSON object only.`;
278
283
  config: {
279
284
  ...options.instructions !== void 0 ? { systemInstruction: options.instructions } : {},
280
285
  ...options.temperature !== void 0 ? { temperature: options.temperature } : {},
281
- ...options.maxOutputTokens !== void 0 ? { maxOutputTokens: options.maxOutputTokens } : {}
286
+ ...options.maxOutputTokens !== void 0 ? { maxOutputTokens: options.maxOutputTokens } : {},
287
+ ...options.signal ? { abortSignal: options.signal } : {}
282
288
  }
283
289
  });
284
290
  for await (const chunk of stream) {
@@ -292,6 +298,7 @@ Reply with a single corrected JSON object only.`;
292
298
  }
293
299
  },
294
300
  async *streamStructured(options) {
301
+ core.throwIfAborted(options.signal);
295
302
  validateContent(options.prompt);
296
303
  try {
297
304
  const stream = await ctx.client.models.generateContentStream({
@@ -312,7 +319,8 @@ Reply with a single JSON object only. Stream the JSON progressively.`
312
319
  ...options.instructions !== void 0 ? { systemInstruction: options.instructions } : {},
313
320
  temperature: options.temperature ?? 0,
314
321
  ...options.maxOutputTokens !== void 0 ? { maxOutputTokens: options.maxOutputTokens } : {},
315
- responseMimeType: "application/json"
322
+ responseMimeType: "application/json",
323
+ ...options.signal ? { abortSignal: options.signal } : {}
316
324
  }
317
325
  });
318
326
  let buffer = "";
@@ -330,6 +338,7 @@ Reply with a single JSON object only. Stream the JSON progressively.`
330
338
  }
331
339
  },
332
340
  async runAgent(options) {
341
+ core.throwIfAborted(options.signal);
333
342
  validateMessages(options.messages);
334
343
  const start = Date.now();
335
344
  try {
@@ -339,7 +348,8 @@ Reply with a single JSON object only. Stream the JSON progressively.`
339
348
  contents,
340
349
  config: {
341
350
  ...systemInstruction !== void 0 ? { systemInstruction } : {},
342
- ...options.instructions !== void 0 ? { systemInstruction: options.instructions } : {}
351
+ ...options.instructions !== void 0 ? { systemInstruction: options.instructions } : {},
352
+ ...options.signal ? { abortSignal: options.signal } : {}
343
353
  }
344
354
  });
345
355
  const candidate = response.candidates?.[0];
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/content.ts","../src/pricing.ts","../src/adapter.ts"],"names":["ContentBlockUnsupportedError","GoogleGenAI","validateImageBlocks","computeChatCost","wrapProviderError","stringifyContentBlocks","extractJSON","attemptValidationRepair","failValidation","tryParsePartialJSON"],"mappings":"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","file":"index.cjs","sourcesContent":["/**\r\n * Content translation between llm-ports ContentBlock[] and Gemini's\r\n * Content + Part shapes.\r\n *\r\n * Gemini's content model:\r\n * Content = { role: \"user\" | \"model\" | \"function\", parts: Part[] }\r\n * Part shapes (the ones we care about):\r\n * - { text: string }\r\n * - { inlineData: { mimeType: string, data: string (base64) } }\r\n * - { fileData: { mimeType: string, fileUri: string } }\r\n * - { functionCall: { name: string, args: object } }\r\n * - { functionResponse: { name: string, response: object } }\r\n *\r\n * Notes:\r\n * - System messages map to a top-level `systemInstruction` field on the\r\n * request, NOT a Content with role: \"system\". `toGeminiRequest` handles\r\n * this split.\r\n * - The assistant role is `\"model\"` in Gemini's vocabulary.\r\n * - Tool results are mapped to `functionResponse` parts.\r\n */\r\n\r\nimport {\r\n ContentBlockUnsupportedError,\r\n type ContentBlock,\r\n type LLMMessage,\r\n type MessageContent,\r\n} from \"@llm-ports/core\";\r\n\r\nconst ADAPTER_NAME = \"google\";\r\n\r\n// ─── Outgoing: ContentBlock[] → Gemini Part[] ────────────────────────\r\n\r\ninterface GeminiTextPart {\r\n text: string;\r\n}\r\ninterface GeminiInlineDataPart {\r\n inlineData: { mimeType: string; data: string };\r\n}\r\ninterface GeminiFileDataPart {\r\n fileData: { mimeType: string; fileUri: string };\r\n}\r\ninterface GeminiFunctionCallPart {\r\n functionCall: { name: string; args: Record<string, unknown> };\r\n}\r\ninterface GeminiFunctionResponsePart {\r\n functionResponse: { name: string; response: Record<string, unknown> };\r\n}\r\nexport type GeminiPart =\r\n | GeminiTextPart\r\n | GeminiInlineDataPart\r\n | GeminiFileDataPart\r\n | GeminiFunctionCallPart\r\n | GeminiFunctionResponsePart;\r\n\r\nexport interface GeminiContent {\r\n role: \"user\" | \"model\" | \"function\";\r\n parts: GeminiPart[];\r\n}\r\n\r\n/** Translate a single ContentBlock to one or more GeminiParts. */\r\nfunction toGeminiParts(block: ContentBlock): GeminiPart[] {\r\n switch (block.type) {\r\n case \"text\":\r\n return [{ text: block.text }];\r\n case \"image\": {\r\n if (block.source.kind === \"base64\") {\r\n return [\r\n {\r\n inlineData: {\r\n mimeType: block.source.mediaType,\r\n data: block.source.data,\r\n },\r\n },\r\n ];\r\n }\r\n // URL form\r\n return [\r\n {\r\n fileData: {\r\n // Gemini infers mimeType from URL extension when not provided.\r\n // We pass image/jpeg as a sane default; users wanting tighter\r\n // control should pass base64 with explicit mediaType.\r\n mimeType: \"image/jpeg\",\r\n fileUri: block.source.url,\r\n },\r\n },\r\n ];\r\n }\r\n case \"audio\": {\r\n if (block.source.kind === \"base64\") {\r\n return [\r\n {\r\n inlineData: {\r\n mimeType: block.source.mediaType,\r\n data: block.source.data,\r\n },\r\n },\r\n ];\r\n }\r\n throw new ContentBlockUnsupportedError(ADAPTER_NAME, \"audio (url; Gemini accepts base64 or fileData with fileUri)\");\r\n }\r\n case \"tool_use\": {\r\n // Gemini's tool-call shape has args as a plain object; we pass the input\r\n // through if it's already an object, else wrap.\r\n const args =\r\n block.input !== null && typeof block.input === \"object\"\r\n ? (block.input as Record<string, unknown>)\r\n : { value: block.input };\r\n return [{ functionCall: { name: block.name, args } }];\r\n }\r\n case \"tool_result\": {\r\n // Gemini's functionResponse expects a `response` object. If the\r\n // ContentBlock.tool_result.content is a string, wrap it.\r\n const response: Record<string, unknown> =\r\n typeof block.content === \"string\"\r\n ? { result: block.content }\r\n : { result: extractTextOnly(block.content) };\r\n return [\r\n {\r\n functionResponse: {\r\n // Gemini's API requires the tool name; we use toolUseId since\r\n // llm-ports' ToolResultBlock doesn't carry the name. Adapters\r\n // that need the name can plumb it through a separate channel.\r\n name: block.toolUseId,\r\n response,\r\n },\r\n },\r\n ];\r\n }\r\n }\r\n}\r\n\r\nfunction extractTextOnly(blocks: ContentBlock[]): string {\r\n return blocks\r\n .filter((b): b is Extract<ContentBlock, { type: \"text\" }> => b.type === \"text\")\r\n .map((b) => b.text)\r\n .join(\"\\n\");\r\n}\r\n\r\n/** Translate a MessageContent to Gemini Parts. */\r\nexport function toGeminiParts2(content: MessageContent): GeminiPart[] {\r\n if (typeof content === \"string\") {\r\n return [{ text: content }];\r\n }\r\n return content.flatMap(toGeminiParts);\r\n}\r\n\r\n/**\r\n * Translate an array of LLMMessages into:\r\n * - `systemInstruction`: the concatenated system messages (Gemini puts\r\n * these at the top level of the request, not in `contents`).\r\n * - `contents`: the user + assistant + tool messages, with roles mapped.\r\n */\r\nexport function toGeminiRequest(messages: LLMMessage[]): {\r\n systemInstruction?: string;\r\n contents: GeminiContent[];\r\n} {\r\n let systemInstruction: string | undefined;\r\n const contents: GeminiContent[] = [];\r\n for (const msg of messages) {\r\n if (msg.role === \"system\") {\r\n const text =\r\n typeof msg.content === \"string\" ? msg.content : extractTextOnly(msg.content);\r\n systemInstruction = systemInstruction === undefined ? text : `${systemInstruction}\\n\\n${text}`;\r\n continue;\r\n }\r\n const role: GeminiContent[\"role\"] =\r\n msg.role === \"tool\" ? \"function\" : msg.role === \"assistant\" ? \"model\" : \"user\";\r\n contents.push({\r\n role,\r\n parts: toGeminiParts2(msg.content),\r\n });\r\n }\r\n return systemInstruction !== undefined\r\n ? { systemInstruction, contents }\r\n : { contents };\r\n}\r\n\r\n// ─── Incoming: Gemini response → ContentBlock[] ──────────────────────\r\n\r\ninterface GeminiResponseCandidate {\r\n content?: {\r\n role?: string;\r\n parts?: GeminiPart[];\r\n };\r\n finishReason?: string;\r\n}\r\n\r\n/**\r\n * Extract the assistant text from a Gemini response. Used by generateText\r\n * and by the structured-output path before JSON parsing.\r\n */\r\nexport function extractGeminiText(parts: GeminiPart[] | undefined): string {\r\n if (!parts) return \"\";\r\n return parts\r\n .filter((p): p is GeminiTextPart => \"text\" in p)\r\n .map((p) => p.text)\r\n .join(\"\");\r\n}\r\n\r\n/**\r\n * Translate a Gemini response candidate's parts back into ContentBlock[].\r\n * Used by runAgent to reconstruct the model's tool_use blocks.\r\n */\r\nexport function fromGeminiCandidate(candidate: GeminiResponseCandidate): ContentBlock[] {\r\n const out: ContentBlock[] = [];\r\n const parts = candidate.content?.parts ?? [];\r\n for (const part of parts) {\r\n if (\"text\" in part && part.text.length > 0) {\r\n out.push({ type: \"text\", text: part.text });\r\n } else if (\"functionCall\" in part) {\r\n out.push({\r\n type: \"tool_use\",\r\n id: `gemini-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`,\r\n name: part.functionCall.name,\r\n input: part.functionCall.args,\r\n });\r\n } else if (\"inlineData\" in part) {\r\n // Inline (base64) image in assistant response. Decode if media type\r\n // is one we support, else drop (consistent with adapter-openai's\r\n // unknown-media-type behavior).\r\n const mt = part.inlineData.mimeType;\r\n if (\r\n mt === \"image/jpeg\" ||\r\n mt === \"image/png\" ||\r\n mt === \"image/gif\" ||\r\n mt === \"image/webp\"\r\n ) {\r\n out.push({\r\n type: \"image\",\r\n source: { kind: \"base64\", mediaType: mt, data: part.inlineData.data },\r\n });\r\n }\r\n }\r\n // fileData / functionResponse in assistant responses: not currently observed.\r\n }\r\n return out;\r\n}\r\n","/**\r\n * Bundled pricing for Google Gemini models.\r\n *\r\n * Source: https://ai.google.dev/gemini-api/docs/pricing (verified 2026-05).\r\n * Override per model via `pricingOverrides` on the adapter options.\r\n *\r\n * Gemini pricing has separate tiers for prompts under 200k tokens vs over\r\n * 200k tokens (the \"long-context premium\"). The bundled values are the\r\n * UNDER-200k-token rates, which dominate typical usage. For long-context\r\n * workloads, supply `pricingOverrides` with the over-200k rates.\r\n */\r\n\r\nimport type { ModelPricing } from \"@llm-ports/core\";\r\n\r\nexport const GEMINI_PRICING: Record<string, ModelPricing> = {\r\n // Gemini 2.5 family (2026-05 GA pricing)\r\n \"gemini-2.5-pro\": {\r\n inputPer1M: 1.25,\r\n outputPer1M: 5.0,\r\n cacheReadPer1M: 0.3125,\r\n },\r\n \"gemini-2.5-flash\": {\r\n inputPer1M: 0.075,\r\n outputPer1M: 0.3,\r\n cacheReadPer1M: 0.01875,\r\n },\r\n \"gemini-2.5-flash-lite\": {\r\n inputPer1M: 0.0375,\r\n outputPer1M: 0.15,\r\n cacheReadPer1M: 0.009375,\r\n },\r\n // Gemini 2.0 family (still available)\r\n \"gemini-2.0-flash\": {\r\n inputPer1M: 0.1,\r\n outputPer1M: 0.4,\r\n cacheReadPer1M: 0.025,\r\n },\r\n \"gemini-2.0-flash-lite\": {\r\n inputPer1M: 0.075,\r\n outputPer1M: 0.3,\r\n },\r\n};\r\n\r\nexport function lookupGeminiPricing(modelId: string): ModelPricing | undefined {\r\n return GEMINI_PRICING[modelId];\r\n}\r\n","/**\r\n * Google Gemini adapter for llm-ports.\r\n *\r\n * Wraps @google/genai (the unified Gemini + Vertex SDK as of 2026) to\r\n * implement LLMPort. Provides:\r\n *\r\n * - Native multimodal: image content blocks pass through as inlineData\r\n * (base64) or fileData (URL). NO degradation, unlike OpenAI-compat\r\n * baseURL where image_url.detail is silently ignored.\r\n * - Native streaming via generateContentStream\r\n * - Structured output via prompted-JSON + Zod retry-with-feedback\r\n * + alpha.5 programmatic repair. Native Gemini responseSchema lands\r\n * in v0.2.\r\n * - Image-block boundary validation (size + URL scheme) — same shape\r\n * as adapter-anthropic and adapter-openai (alpha.5).\r\n *\r\n * Out of scope for v0.1 alpha:\r\n * - Embeddings (Gemini's embedding API is separate; lands in v0.2)\r\n * - Multi-turn runAgent through Gemini's native automatic tool calling\r\n * (v0.1 ships a single-turn shim consistent with adapter-vercel)\r\n * - Caching API (Gemini supports explicit context caching; lands in v0.2)\r\n * - Code execution tool (Gemini's built-in code interpreter; lands in v0.2)\r\n */\r\n\r\nimport { GoogleGenAI } from \"@google/genai\";\r\nimport {\r\n attemptValidationRepair,\r\n computeChatCost,\r\n extractJSON,\r\n failValidation,\r\n stringifyContentBlocks,\r\n tryParsePartialJSON,\r\n validateImageBlocks,\r\n wrapProviderError,\r\n type AgentResult,\r\n type ContentBlock,\r\n type GenerateStructuredOptions,\r\n type GenerateStructuredResult,\r\n type GenerateTextOptions,\r\n type GenerateTextResult,\r\n type LLMPort,\r\n type MessageContent,\r\n type ModelPricing,\r\n type RunAgentOptions,\r\n type StreamStructuredOptions,\r\n type StreamTextOptions,\r\n type TokenUsage,\r\n type ValidationStrategy,\r\n} from \"@llm-ports/core\";\r\nimport {\r\n extractGeminiText,\r\n toGeminiParts2,\r\n toGeminiRequest,\r\n type GeminiPart,\r\n} from \"./content.js\";\r\nimport { GEMINI_PRICING } from \"./pricing.js\";\r\n\r\n// ─── Adapter options ─────────────────────────────────────────────────\r\n\r\nexport interface GoogleAdapterOptions {\r\n /** Google AI API key (https://aistudio.google.com/apikey). */\r\n apiKey: string;\r\n /** Override Gemini pricing for any model id. Falls back to the bundled table. */\r\n pricingOverrides?: Record<string, ModelPricing>;\r\n /** Default validation strategy if the registry doesn't override per-call. */\r\n validationStrategy?: ValidationStrategy;\r\n /**\r\n * Maximum bytes per base64 image. Defaults to 20MB (Gemini accepts up to\r\n * 20MB inlined; fileData URLs are unconstrained but provider-fetched).\r\n * Set to 0 or a negative number to disable size validation.\r\n */\r\n imageSizeLimitBytes?: number;\r\n}\r\n\r\n// ─── Internal context ────────────────────────────────────────────────\r\n\r\ninterface AdapterContext {\r\n client: GoogleGenAI;\r\n validationStrategy: ValidationStrategy;\r\n pricingOverrides: Record<string, ModelPricing>;\r\n imageSizeLimitBytes: number;\r\n}\r\n\r\nfunction pricingFor(ctx: AdapterContext, modelId: string): ModelPricing {\r\n const pricing = ctx.pricingOverrides[modelId] ?? GEMINI_PRICING[modelId];\r\n if (!pricing) {\r\n throw new Error(\r\n `No pricing entry for Google Gemini model \"${modelId}\". Provide pricingOverrides or update src/pricing.ts.`,\r\n );\r\n }\r\n return pricing;\r\n}\r\n\r\n// ─── Public factory ──────────────────────────────────────────────────\r\n\r\nexport interface GoogleAdapter {\r\n name: \"google\";\r\n pricing: Record<string, ModelPricing>;\r\n createLLMPort: (modelId: string, alias: string) => LLMPort;\r\n}\r\n\r\nexport function createGoogleAdapter(opts: GoogleAdapterOptions): GoogleAdapter {\r\n const mergedPricing: Record<string, ModelPricing> = {\r\n ...GEMINI_PRICING,\r\n ...(opts.pricingOverrides ?? {}),\r\n };\r\n const ctx: AdapterContext = {\r\n client: new GoogleGenAI({ apiKey: opts.apiKey }),\r\n validationStrategy: opts.validationStrategy ?? {\r\n kind: \"retry-with-feedback\",\r\n maxAttempts: 2,\r\n includeOriginalError: true,\r\n },\r\n pricingOverrides: opts.pricingOverrides ?? {},\r\n imageSizeLimitBytes: opts.imageSizeLimitBytes ?? 20 * 1024 * 1024,\r\n };\r\n return {\r\n name: \"google\",\r\n pricing: mergedPricing,\r\n createLLMPort: (modelId, alias) => createPort(ctx, modelId, alias),\r\n };\r\n}\r\n\r\n// ─── Port implementation ─────────────────────────────────────────────\r\n\r\nfunction createPort(ctx: AdapterContext, modelId: string, alias: string): LLMPort {\r\n const pricing = pricingFor(ctx, modelId);\r\n\r\n // Image-block validation closure: throws ImageTooLargeError or\r\n // InvalidImageUrlError before the SDK call.\r\n const validateContent = (content: MessageContent): void => {\r\n if (Array.isArray(content)) {\r\n validateImageBlocks(content, {\r\n alias,\r\n ...(ctx.imageSizeLimitBytes > 0 ? { limitBytes: ctx.imageSizeLimitBytes } : {}),\r\n });\r\n }\r\n };\r\n const validateMessages = (messages: ReadonlyArray<{ content: MessageContent }>): void => {\r\n for (const msg of messages) validateContent(msg.content);\r\n };\r\n\r\n return {\r\n async generateText(options: GenerateTextOptions): Promise<GenerateTextResult> {\r\n validateContent(options.prompt);\r\n const start = Date.now();\r\n try {\r\n const parts = toGeminiParts2(options.prompt);\r\n const response = await ctx.client.models.generateContent({\r\n model: modelId,\r\n contents: [{ role: \"user\", parts }],\r\n config: {\r\n ...(options.instructions !== undefined\r\n ? { systemInstruction: options.instructions }\r\n : {}),\r\n ...(options.temperature !== undefined ? { temperature: options.temperature } : {}),\r\n ...(options.maxOutputTokens !== undefined\r\n ? { maxOutputTokens: options.maxOutputTokens }\r\n : {}),\r\n },\r\n });\r\n const candidate = response.candidates?.[0];\r\n const text = extractGeminiText(candidate?.content?.parts as GeminiPart[] | undefined);\r\n const usage = parseUsage(response);\r\n return {\r\n text,\r\n usage,\r\n cost: computeChatCost(usage, pricing),\r\n modelId: response.modelVersion ?? modelId,\r\n providerAlias: alias,\r\n latencyMs: Date.now() - start,\r\n };\r\n } catch (err) {\r\n throw wrapProviderError(alias, err);\r\n }\r\n },\r\n\r\n async generateStructured<T>(\r\n options: GenerateStructuredOptions<T>,\r\n ): Promise<GenerateStructuredResult<T>> {\r\n validateContent(options.prompt);\r\n const start = Date.now();\r\n let attempts = 0;\r\n const maxAttempts =\r\n ctx.validationStrategy.kind === \"retry-with-feedback\"\r\n ? ctx.validationStrategy.maxAttempts\r\n : 1;\r\n\r\n let correctionPrompt: string | null = null;\r\n let lastUsage: TokenUsage = { inputTokens: 0, outputTokens: 0, totalTokens: 0 };\r\n let lastModelId = modelId;\r\n\r\n while (attempts < maxAttempts) {\r\n attempts++;\r\n const userText = correctionPrompt\r\n ? `${stringifyContentBlocks(options.prompt)}\\n\\n${correctionPrompt}`\r\n : `${stringifyContentBlocks(options.prompt)}\\n\\nReply with a single JSON object only. No prose, no code fences.`;\r\n\r\n try {\r\n const response = await ctx.client.models.generateContent({\r\n model: modelId,\r\n contents: [{ role: \"user\", parts: [{ text: userText }] }],\r\n config: {\r\n ...(options.instructions !== undefined\r\n ? { systemInstruction: options.instructions }\r\n : {}),\r\n temperature: options.temperature ?? 0,\r\n ...(options.maxOutputTokens !== undefined\r\n ? { maxOutputTokens: options.maxOutputTokens }\r\n : {}),\r\n responseMimeType: \"application/json\",\r\n },\r\n });\r\n const candidate = response.candidates?.[0];\r\n const raw = extractGeminiText(candidate?.content?.parts as GeminiPart[] | undefined);\r\n lastUsage = parseUsage(response);\r\n lastModelId = response.modelVersion ?? modelId;\r\n\r\n const decoded = extractJSON(raw);\r\n let parsed = options.schema.safeParse(decoded);\r\n if (!parsed.success) {\r\n const repaired = attemptValidationRepair(decoded, parsed.error);\r\n const reparsed = options.schema.safeParse(repaired);\r\n if (reparsed.success) parsed = reparsed;\r\n }\r\n if (parsed.success) {\r\n return {\r\n data: parsed.data as T,\r\n usage: lastUsage,\r\n cost: computeChatCost(lastUsage, pricing),\r\n modelId: lastModelId,\r\n providerAlias: alias,\r\n latencyMs: Date.now() - start,\r\n validationAttempts: attempts,\r\n };\r\n }\r\n if (\r\n ctx.validationStrategy.kind === \"retry-with-feedback\" &&\r\n attempts < maxAttempts\r\n ) {\r\n const issues = parsed.error.issues\r\n .map((i) => `- ${i.path.join(\".\") || \"<root>\"}: ${i.message}`)\r\n .join(\"\\n\");\r\n correctionPrompt = `Your previous response failed validation:\\n${issues}\\n\\nReply with a single corrected JSON object only.`;\r\n continue;\r\n }\r\n failValidation(parsed.error.issues, attempts);\r\n } catch (err) {\r\n throw wrapProviderError(alias, err);\r\n }\r\n }\r\n throw new Error(\"generateStructured exhausted attempts\");\r\n },\r\n\r\n async *streamText(options: StreamTextOptions): AsyncIterable<string> {\r\n validateContent(options.prompt);\r\n try {\r\n const parts = toGeminiParts2(options.prompt);\r\n const stream = await ctx.client.models.generateContentStream({\r\n model: modelId,\r\n contents: [{ role: \"user\", parts }],\r\n config: {\r\n ...(options.instructions !== undefined\r\n ? { systemInstruction: options.instructions }\r\n : {}),\r\n ...(options.temperature !== undefined ? { temperature: options.temperature } : {}),\r\n ...(options.maxOutputTokens !== undefined\r\n ? { maxOutputTokens: options.maxOutputTokens }\r\n : {}),\r\n },\r\n });\r\n for await (const chunk of stream) {\r\n const text = extractGeminiText(\r\n chunk.candidates?.[0]?.content?.parts as GeminiPart[] | undefined,\r\n );\r\n if (text.length > 0) yield text;\r\n }\r\n } catch (err) {\r\n throw wrapProviderError(alias, err);\r\n }\r\n },\r\n\r\n async *streamStructured<T>(options: StreamStructuredOptions<T>): AsyncIterable<Partial<T>> {\r\n validateContent(options.prompt);\r\n try {\r\n const stream = await ctx.client.models.generateContentStream({\r\n model: modelId,\r\n contents: [\r\n {\r\n role: \"user\",\r\n parts: [\r\n {\r\n text: `${stringifyContentBlocks(options.prompt)}\\n\\nReply with a single JSON object only. Stream the JSON progressively.`,\r\n },\r\n ],\r\n },\r\n ],\r\n config: {\r\n ...(options.instructions !== undefined\r\n ? { systemInstruction: options.instructions }\r\n : {}),\r\n temperature: options.temperature ?? 0,\r\n ...(options.maxOutputTokens !== undefined\r\n ? { maxOutputTokens: options.maxOutputTokens }\r\n : {}),\r\n responseMimeType: \"application/json\",\r\n },\r\n });\r\n let buffer = \"\";\r\n for await (const chunk of stream) {\r\n const text = extractGeminiText(\r\n chunk.candidates?.[0]?.content?.parts as GeminiPart[] | undefined,\r\n );\r\n if (text.length === 0) continue;\r\n buffer += text;\r\n const partial = tryParsePartialJSON(buffer);\r\n if (partial !== null) yield partial as Partial<T>;\r\n }\r\n } catch (err) {\r\n throw wrapProviderError(alias, err);\r\n }\r\n },\r\n\r\n async runAgent(options: RunAgentOptions): Promise<AgentResult> {\r\n validateMessages(options.messages);\r\n // v0.1: single-turn agent loop. Gemini's native automatic-function-calling\r\n // multi-turn runAgent ships in v0.2 (matches adapter-vercel's v0.1 shape).\r\n const start = Date.now();\r\n try {\r\n const { systemInstruction, contents } = toGeminiRequest(options.messages);\r\n const response = await ctx.client.models.generateContent({\r\n model: modelId,\r\n contents,\r\n config: {\r\n ...(systemInstruction !== undefined ? { systemInstruction } : {}),\r\n ...(options.instructions !== undefined\r\n ? { systemInstruction: options.instructions }\r\n : {}),\r\n },\r\n });\r\n const candidate = response.candidates?.[0];\r\n const text = extractGeminiText(candidate?.content?.parts as GeminiPart[] | undefined);\r\n const usage = parseUsage(response);\r\n const toolCalls: AgentResult[\"toolCalls\"] = [];\r\n // v0.1 stub: we surface no tool calls. Real tool-use is v0.2 scope.\r\n return {\r\n text,\r\n messages: [\r\n ...options.messages,\r\n { role: \"assistant\" as const, content: text },\r\n ],\r\n usage,\r\n cost: computeChatCost(usage, pricing),\r\n modelId: response.modelVersion ?? modelId,\r\n providerAlias: alias,\r\n latencyMs: Date.now() - start,\r\n toolCalls,\r\n stepsTaken: 1,\r\n terminationReason: \"completed\",\r\n };\r\n } catch (err) {\r\n throw wrapProviderError(alias, err);\r\n }\r\n },\r\n };\r\n}\r\n\r\n// ─── Helpers ─────────────────────────────────────────────────────────\r\n\r\ninterface GeminiUsageMetadata {\r\n promptTokenCount?: number;\r\n candidatesTokenCount?: number;\r\n totalTokenCount?: number;\r\n cachedContentTokenCount?: number;\r\n}\r\n\r\ninterface GeminiResponseShape {\r\n usageMetadata?: GeminiUsageMetadata;\r\n}\r\n\r\nfunction parseUsage(response: GeminiResponseShape): TokenUsage {\r\n const m = response.usageMetadata ?? {};\r\n const inputTokens = m.promptTokenCount ?? 0;\r\n const outputTokens = m.candidatesTokenCount ?? 0;\r\n const totalTokens = m.totalTokenCount ?? inputTokens + outputTokens;\r\n const usage: TokenUsage = { inputTokens, outputTokens, totalTokens };\r\n if (m.cachedContentTokenCount !== undefined && m.cachedContentTokenCount > 0) {\r\n usage.cacheReadTokens = m.cachedContentTokenCount;\r\n }\r\n return usage;\r\n}\r\n\r\n// Re-export ContentBlock for the rare adapter user that wants to type-check\r\n// outside of @llm-ports/core. Keeps the import surface symmetric with the\r\n// other adapters.\r\nexport type { ContentBlock };\r\n"]}
1
+ {"version":3,"sources":["../src/content.ts","../src/pricing.ts","../src/adapter.ts"],"names":["ContentBlockUnsupportedError","GoogleGenAI","validateImageBlocks","throwIfAborted","computeChatCost","wrapProviderError","stringifyContentBlocks","extractJSON","attemptValidationRepair","failValidation","tryParsePartialJSON"],"mappings":"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","file":"index.cjs","sourcesContent":["/**\r\n * Content translation between llm-ports ContentBlock[] and Gemini's\r\n * Content + Part shapes.\r\n *\r\n * Gemini's content model:\r\n * Content = { role: \"user\" | \"model\" | \"function\", parts: Part[] }\r\n * Part shapes (the ones we care about):\r\n * - { text: string }\r\n * - { inlineData: { mimeType: string, data: string (base64) } }\r\n * - { fileData: { mimeType: string, fileUri: string } }\r\n * - { functionCall: { name: string, args: object } }\r\n * - { functionResponse: { name: string, response: object } }\r\n *\r\n * Notes:\r\n * - System messages map to a top-level `systemInstruction` field on the\r\n * request, NOT a Content with role: \"system\". `toGeminiRequest` handles\r\n * this split.\r\n * - The assistant role is `\"model\"` in Gemini's vocabulary.\r\n * - Tool results are mapped to `functionResponse` parts.\r\n */\r\n\r\nimport {\r\n ContentBlockUnsupportedError,\r\n type ContentBlock,\r\n type LLMMessage,\r\n type MessageContent,\r\n} from \"@llm-ports/core\";\r\n\r\nconst ADAPTER_NAME = \"google\";\r\n\r\n// ─── Outgoing: ContentBlock[] → Gemini Part[] ────────────────────────\r\n\r\ninterface GeminiTextPart {\r\n text: string;\r\n}\r\ninterface GeminiInlineDataPart {\r\n inlineData: { mimeType: string; data: string };\r\n}\r\ninterface GeminiFileDataPart {\r\n fileData: { mimeType: string; fileUri: string };\r\n}\r\ninterface GeminiFunctionCallPart {\r\n functionCall: { name: string; args: Record<string, unknown> };\r\n}\r\ninterface GeminiFunctionResponsePart {\r\n functionResponse: { name: string; response: Record<string, unknown> };\r\n}\r\nexport type GeminiPart =\r\n | GeminiTextPart\r\n | GeminiInlineDataPart\r\n | GeminiFileDataPart\r\n | GeminiFunctionCallPart\r\n | GeminiFunctionResponsePart;\r\n\r\nexport interface GeminiContent {\r\n role: \"user\" | \"model\" | \"function\";\r\n parts: GeminiPart[];\r\n}\r\n\r\n/** Translate a single ContentBlock to one or more GeminiParts. */\r\nfunction toGeminiParts(block: ContentBlock): GeminiPart[] {\r\n switch (block.type) {\r\n case \"text\":\r\n return [{ text: block.text }];\r\n case \"image\": {\r\n if (block.source.kind === \"base64\") {\r\n return [\r\n {\r\n inlineData: {\r\n mimeType: block.source.mediaType,\r\n data: block.source.data,\r\n },\r\n },\r\n ];\r\n }\r\n // URL form\r\n return [\r\n {\r\n fileData: {\r\n // Gemini infers mimeType from URL extension when not provided.\r\n // We pass image/jpeg as a sane default; users wanting tighter\r\n // control should pass base64 with explicit mediaType.\r\n mimeType: \"image/jpeg\",\r\n fileUri: block.source.url,\r\n },\r\n },\r\n ];\r\n }\r\n case \"audio\": {\r\n if (block.source.kind === \"base64\") {\r\n return [\r\n {\r\n inlineData: {\r\n mimeType: block.source.mediaType,\r\n data: block.source.data,\r\n },\r\n },\r\n ];\r\n }\r\n throw new ContentBlockUnsupportedError(ADAPTER_NAME, \"audio (url; Gemini accepts base64 or fileData with fileUri)\");\r\n }\r\n case \"tool_use\": {\r\n // Gemini's tool-call shape has args as a plain object; we pass the input\r\n // through if it's already an object, else wrap.\r\n const args =\r\n block.input !== null && typeof block.input === \"object\"\r\n ? (block.input as Record<string, unknown>)\r\n : { value: block.input };\r\n return [{ functionCall: { name: block.name, args } }];\r\n }\r\n case \"tool_result\": {\r\n // Gemini's functionResponse expects a `response` object. If the\r\n // ContentBlock.tool_result.content is a string, wrap it.\r\n const response: Record<string, unknown> =\r\n typeof block.content === \"string\"\r\n ? { result: block.content }\r\n : { result: extractTextOnly(block.content) };\r\n return [\r\n {\r\n functionResponse: {\r\n // Gemini's API requires the tool name; we use toolUseId since\r\n // llm-ports' ToolResultBlock doesn't carry the name. Adapters\r\n // that need the name can plumb it through a separate channel.\r\n name: block.toolUseId,\r\n response,\r\n },\r\n },\r\n ];\r\n }\r\n }\r\n}\r\n\r\nfunction extractTextOnly(blocks: ContentBlock[]): string {\r\n return blocks\r\n .filter((b): b is Extract<ContentBlock, { type: \"text\" }> => b.type === \"text\")\r\n .map((b) => b.text)\r\n .join(\"\\n\");\r\n}\r\n\r\n/** Translate a MessageContent to Gemini Parts. */\r\nexport function toGeminiParts2(content: MessageContent): GeminiPart[] {\r\n if (typeof content === \"string\") {\r\n return [{ text: content }];\r\n }\r\n return content.flatMap(toGeminiParts);\r\n}\r\n\r\n/**\r\n * Translate an array of LLMMessages into:\r\n * - `systemInstruction`: the concatenated system messages (Gemini puts\r\n * these at the top level of the request, not in `contents`).\r\n * - `contents`: the user + assistant + tool messages, with roles mapped.\r\n */\r\nexport function toGeminiRequest(messages: LLMMessage[]): {\r\n systemInstruction?: string;\r\n contents: GeminiContent[];\r\n} {\r\n let systemInstruction: string | undefined;\r\n const contents: GeminiContent[] = [];\r\n for (const msg of messages) {\r\n if (msg.role === \"system\") {\r\n const text =\r\n typeof msg.content === \"string\" ? msg.content : extractTextOnly(msg.content);\r\n systemInstruction = systemInstruction === undefined ? text : `${systemInstruction}\\n\\n${text}`;\r\n continue;\r\n }\r\n const role: GeminiContent[\"role\"] =\r\n msg.role === \"tool\" ? \"function\" : msg.role === \"assistant\" ? \"model\" : \"user\";\r\n contents.push({\r\n role,\r\n parts: toGeminiParts2(msg.content),\r\n });\r\n }\r\n return systemInstruction !== undefined\r\n ? { systemInstruction, contents }\r\n : { contents };\r\n}\r\n\r\n// ─── Incoming: Gemini response → ContentBlock[] ──────────────────────\r\n\r\ninterface GeminiResponseCandidate {\r\n content?: {\r\n role?: string;\r\n parts?: GeminiPart[];\r\n };\r\n finishReason?: string;\r\n}\r\n\r\n/**\r\n * Extract the assistant text from a Gemini response. Used by generateText\r\n * and by the structured-output path before JSON parsing.\r\n */\r\nexport function extractGeminiText(parts: GeminiPart[] | undefined): string {\r\n if (!parts) return \"\";\r\n return parts\r\n .filter((p): p is GeminiTextPart => \"text\" in p)\r\n .map((p) => p.text)\r\n .join(\"\");\r\n}\r\n\r\n/**\r\n * Translate a Gemini response candidate's parts back into ContentBlock[].\r\n * Used by runAgent to reconstruct the model's tool_use blocks.\r\n */\r\nexport function fromGeminiCandidate(candidate: GeminiResponseCandidate): ContentBlock[] {\r\n const out: ContentBlock[] = [];\r\n const parts = candidate.content?.parts ?? [];\r\n for (const part of parts) {\r\n if (\"text\" in part && part.text.length > 0) {\r\n out.push({ type: \"text\", text: part.text });\r\n } else if (\"functionCall\" in part) {\r\n out.push({\r\n type: \"tool_use\",\r\n id: `gemini-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`,\r\n name: part.functionCall.name,\r\n input: part.functionCall.args,\r\n });\r\n } else if (\"inlineData\" in part) {\r\n // Inline (base64) image in assistant response. Decode if media type\r\n // is one we support, else drop (consistent with adapter-openai's\r\n // unknown-media-type behavior).\r\n const mt = part.inlineData.mimeType;\r\n if (\r\n mt === \"image/jpeg\" ||\r\n mt === \"image/png\" ||\r\n mt === \"image/gif\" ||\r\n mt === \"image/webp\"\r\n ) {\r\n out.push({\r\n type: \"image\",\r\n source: { kind: \"base64\", mediaType: mt, data: part.inlineData.data },\r\n });\r\n }\r\n }\r\n // fileData / functionResponse in assistant responses: not currently observed.\r\n }\r\n return out;\r\n}\r\n","/**\r\n * Bundled pricing for Google Gemini models.\r\n *\r\n * Source: https://ai.google.dev/gemini-api/docs/pricing (verified 2026-05).\r\n * Override per model via `pricingOverrides` on the adapter options.\r\n *\r\n * Gemini pricing has separate tiers for prompts under 200k tokens vs over\r\n * 200k tokens (the \"long-context premium\"). The bundled values are the\r\n * UNDER-200k-token rates, which dominate typical usage. For long-context\r\n * workloads, supply `pricingOverrides` with the over-200k rates.\r\n */\r\n\r\nimport type { ModelPricing } from \"@llm-ports/core\";\r\n\r\nexport const GEMINI_PRICING: Record<string, ModelPricing> = {\r\n // Gemini 2.5 family (2026-05 GA pricing)\r\n \"gemini-2.5-pro\": {\r\n inputPer1M: 1.25,\r\n outputPer1M: 5.0,\r\n cacheReadPer1M: 0.3125,\r\n },\r\n \"gemini-2.5-flash\": {\r\n inputPer1M: 0.075,\r\n outputPer1M: 0.3,\r\n cacheReadPer1M: 0.01875,\r\n },\r\n \"gemini-2.5-flash-lite\": {\r\n inputPer1M: 0.0375,\r\n outputPer1M: 0.15,\r\n cacheReadPer1M: 0.009375,\r\n },\r\n // Gemini 2.0 family (still available)\r\n \"gemini-2.0-flash\": {\r\n inputPer1M: 0.1,\r\n outputPer1M: 0.4,\r\n cacheReadPer1M: 0.025,\r\n },\r\n \"gemini-2.0-flash-lite\": {\r\n inputPer1M: 0.075,\r\n outputPer1M: 0.3,\r\n },\r\n};\r\n\r\nexport function lookupGeminiPricing(modelId: string): ModelPricing | undefined {\r\n return GEMINI_PRICING[modelId];\r\n}\r\n","/**\r\n * Google Gemini adapter for llm-ports.\r\n *\r\n * Wraps @google/genai (the unified Gemini + Vertex SDK as of 2026) to\r\n * implement LLMPort. Provides:\r\n *\r\n * - Native multimodal: image content blocks pass through as inlineData\r\n * (base64) or fileData (URL). NO degradation, unlike OpenAI-compat\r\n * baseURL where image_url.detail is silently ignored.\r\n * - Native streaming via generateContentStream\r\n * - Structured output via prompted-JSON + Zod retry-with-feedback\r\n * + alpha.5 programmatic repair. Native Gemini responseSchema lands\r\n * in v0.2.\r\n * - Image-block boundary validation (size + URL scheme) — same shape\r\n * as adapter-anthropic and adapter-openai (alpha.5).\r\n *\r\n * Out of scope for v0.1 alpha:\r\n * - Embeddings (Gemini's embedding API is separate; lands in v0.2)\r\n * - Multi-turn runAgent through Gemini's native automatic tool calling\r\n * (v0.1 ships a single-turn shim consistent with adapter-vercel)\r\n * - Caching API (Gemini supports explicit context caching; lands in v0.2)\r\n * - Code execution tool (Gemini's built-in code interpreter; lands in v0.2)\r\n */\r\n\r\nimport { GoogleGenAI } from \"@google/genai\";\r\nimport {\r\n attemptValidationRepair,\r\n computeChatCost,\r\n extractJSON,\r\n failValidation,\r\n stringifyContentBlocks,\r\n throwIfAborted,\r\n tryParsePartialJSON,\r\n validateImageBlocks,\r\n wrapProviderError,\r\n type AgentResult,\r\n type ContentBlock,\r\n type GenerateStructuredOptions,\r\n type GenerateStructuredResult,\r\n type GenerateTextOptions,\r\n type GenerateTextResult,\r\n type LLMPort,\r\n type MessageContent,\r\n type ModelPricing,\r\n type RunAgentOptions,\r\n type StreamStructuredOptions,\r\n type StreamTextOptions,\r\n type TokenUsage,\r\n type ValidationStrategy,\r\n} from \"@llm-ports/core\";\r\nimport {\r\n extractGeminiText,\r\n toGeminiParts2,\r\n toGeminiRequest,\r\n type GeminiPart,\r\n} from \"./content.js\";\r\nimport { GEMINI_PRICING } from \"./pricing.js\";\r\n\r\n// ─── Adapter options ─────────────────────────────────────────────────\r\n\r\nexport interface GoogleAdapterOptions {\r\n /** Google AI API key (https://aistudio.google.com/apikey). */\r\n apiKey: string;\r\n /** Override Gemini pricing for any model id. Falls back to the bundled table. */\r\n pricingOverrides?: Record<string, ModelPricing>;\r\n /** Default validation strategy if the registry doesn't override per-call. */\r\n validationStrategy?: ValidationStrategy;\r\n /**\r\n * Maximum bytes per base64 image. Defaults to 20MB (Gemini accepts up to\r\n * 20MB inlined; fileData URLs are unconstrained but provider-fetched).\r\n * Set to 0 or a negative number to disable size validation.\r\n */\r\n imageSizeLimitBytes?: number;\r\n}\r\n\r\n// ─── Internal context ────────────────────────────────────────────────\r\n\r\ninterface AdapterContext {\r\n client: GoogleGenAI;\r\n validationStrategy: ValidationStrategy;\r\n pricingOverrides: Record<string, ModelPricing>;\r\n imageSizeLimitBytes: number;\r\n}\r\n\r\nfunction pricingFor(ctx: AdapterContext, modelId: string): ModelPricing {\r\n const pricing = ctx.pricingOverrides[modelId] ?? GEMINI_PRICING[modelId];\r\n if (!pricing) {\r\n throw new Error(\r\n `No pricing entry for Google Gemini model \"${modelId}\". Provide pricingOverrides or update src/pricing.ts.`,\r\n );\r\n }\r\n return pricing;\r\n}\r\n\r\n// ─── Public factory ──────────────────────────────────────────────────\r\n\r\nexport interface GoogleAdapter {\r\n name: \"google\";\r\n pricing: Record<string, ModelPricing>;\r\n createLLMPort: (modelId: string, alias: string) => LLMPort;\r\n}\r\n\r\nexport function createGoogleAdapter(opts: GoogleAdapterOptions): GoogleAdapter {\r\n const mergedPricing: Record<string, ModelPricing> = {\r\n ...GEMINI_PRICING,\r\n ...(opts.pricingOverrides ?? {}),\r\n };\r\n const ctx: AdapterContext = {\r\n client: new GoogleGenAI({ apiKey: opts.apiKey }),\r\n validationStrategy: opts.validationStrategy ?? {\r\n kind: \"retry-with-feedback\",\r\n maxAttempts: 2,\r\n includeOriginalError: true,\r\n },\r\n pricingOverrides: opts.pricingOverrides ?? {},\r\n imageSizeLimitBytes: opts.imageSizeLimitBytes ?? 20 * 1024 * 1024,\r\n };\r\n return {\r\n name: \"google\",\r\n pricing: mergedPricing,\r\n createLLMPort: (modelId, alias) => createPort(ctx, modelId, alias),\r\n };\r\n}\r\n\r\n// ─── Port implementation ─────────────────────────────────────────────\r\n\r\nfunction createPort(ctx: AdapterContext, modelId: string, alias: string): LLMPort {\r\n const pricing = pricingFor(ctx, modelId);\r\n\r\n // Image-block validation closure: throws ImageTooLargeError or\r\n // InvalidImageUrlError before the SDK call.\r\n const validateContent = (content: MessageContent): void => {\r\n if (Array.isArray(content)) {\r\n validateImageBlocks(content, {\r\n alias,\r\n ...(ctx.imageSizeLimitBytes > 0 ? { limitBytes: ctx.imageSizeLimitBytes } : {}),\r\n });\r\n }\r\n };\r\n const validateMessages = (messages: ReadonlyArray<{ content: MessageContent }>): void => {\r\n for (const msg of messages) validateContent(msg.content);\r\n };\r\n\r\n return {\r\n async generateText(options: GenerateTextOptions): Promise<GenerateTextResult> {\r\n throwIfAborted(options.signal);\r\n validateContent(options.prompt);\r\n const start = Date.now();\r\n try {\r\n const parts = toGeminiParts2(options.prompt);\r\n const response = await ctx.client.models.generateContent({\r\n model: modelId,\r\n contents: [{ role: \"user\", parts }],\r\n config: {\r\n ...(options.instructions !== undefined\r\n ? { systemInstruction: options.instructions }\r\n : {}),\r\n ...(options.temperature !== undefined ? { temperature: options.temperature } : {}),\r\n ...(options.maxOutputTokens !== undefined\r\n ? { maxOutputTokens: options.maxOutputTokens }\r\n : {}),\r\n ...(options.signal ? { abortSignal: options.signal } : {}),\r\n },\r\n });\r\n const candidate = response.candidates?.[0];\r\n const text = extractGeminiText(candidate?.content?.parts as GeminiPart[] | undefined);\r\n const usage = parseUsage(response);\r\n return {\r\n text,\r\n usage,\r\n cost: computeChatCost(usage, pricing),\r\n modelId: response.modelVersion ?? modelId,\r\n providerAlias: alias,\r\n latencyMs: Date.now() - start,\r\n };\r\n } catch (err) {\r\n throw wrapProviderError(alias, err);\r\n }\r\n },\r\n\r\n async generateStructured<T>(\r\n options: GenerateStructuredOptions<T>,\r\n ): Promise<GenerateStructuredResult<T>> {\r\n throwIfAborted(options.signal);\r\n validateContent(options.prompt);\r\n const start = Date.now();\r\n let attempts = 0;\r\n const maxAttempts =\r\n ctx.validationStrategy.kind === \"retry-with-feedback\"\r\n ? ctx.validationStrategy.maxAttempts\r\n : 1;\r\n\r\n let correctionPrompt: string | null = null;\r\n let lastUsage: TokenUsage = { inputTokens: 0, outputTokens: 0, totalTokens: 0 };\r\n let lastModelId = modelId;\r\n\r\n while (attempts < maxAttempts) {\r\n attempts++;\r\n const userText = correctionPrompt\r\n ? `${stringifyContentBlocks(options.prompt)}\\n\\n${correctionPrompt}`\r\n : `${stringifyContentBlocks(options.prompt)}\\n\\nReply with a single JSON object only. No prose, no code fences.`;\r\n\r\n try {\r\n const response = await ctx.client.models.generateContent({\r\n model: modelId,\r\n contents: [{ role: \"user\", parts: [{ text: userText }] }],\r\n config: {\r\n ...(options.instructions !== undefined\r\n ? { systemInstruction: options.instructions }\r\n : {}),\r\n temperature: options.temperature ?? 0,\r\n ...(options.maxOutputTokens !== undefined\r\n ? { maxOutputTokens: options.maxOutputTokens }\r\n : {}),\r\n responseMimeType: \"application/json\",\r\n ...(options.signal ? { abortSignal: options.signal } : {}),\r\n },\r\n });\r\n const candidate = response.candidates?.[0];\r\n const raw = extractGeminiText(candidate?.content?.parts as GeminiPart[] | undefined);\r\n lastUsage = parseUsage(response);\r\n lastModelId = response.modelVersion ?? modelId;\r\n\r\n const decoded = extractJSON(raw);\r\n let parsed = options.schema.safeParse(decoded);\r\n if (!parsed.success) {\r\n const repaired = attemptValidationRepair(decoded, parsed.error);\r\n const reparsed = options.schema.safeParse(repaired);\r\n if (reparsed.success) parsed = reparsed;\r\n }\r\n if (parsed.success) {\r\n return {\r\n data: parsed.data as T,\r\n usage: lastUsage,\r\n cost: computeChatCost(lastUsage, pricing),\r\n modelId: lastModelId,\r\n providerAlias: alias,\r\n latencyMs: Date.now() - start,\r\n validationAttempts: attempts,\r\n };\r\n }\r\n if (\r\n ctx.validationStrategy.kind === \"retry-with-feedback\" &&\r\n attempts < maxAttempts\r\n ) {\r\n const issues = parsed.error.issues\r\n .map((i) => `- ${i.path.join(\".\") || \"<root>\"}: ${i.message}`)\r\n .join(\"\\n\");\r\n correctionPrompt = `Your previous response failed validation:\\n${issues}\\n\\nReply with a single corrected JSON object only.`;\r\n continue;\r\n }\r\n failValidation(parsed.error.issues, attempts);\r\n } catch (err) {\r\n throw wrapProviderError(alias, err);\r\n }\r\n }\r\n throw new Error(\"generateStructured exhausted attempts\");\r\n },\r\n\r\n async *streamText(options: StreamTextOptions): AsyncIterable<string> {\r\n throwIfAborted(options.signal);\r\n validateContent(options.prompt);\r\n try {\r\n const parts = toGeminiParts2(options.prompt);\r\n const stream = await ctx.client.models.generateContentStream({\r\n model: modelId,\r\n contents: [{ role: \"user\", parts }],\r\n config: {\r\n ...(options.instructions !== undefined\r\n ? { systemInstruction: options.instructions }\r\n : {}),\r\n ...(options.temperature !== undefined ? { temperature: options.temperature } : {}),\r\n ...(options.maxOutputTokens !== undefined\r\n ? { maxOutputTokens: options.maxOutputTokens }\r\n : {}),\r\n ...(options.signal ? { abortSignal: options.signal } : {}),\r\n },\r\n });\r\n for await (const chunk of stream) {\r\n const text = extractGeminiText(\r\n chunk.candidates?.[0]?.content?.parts as GeminiPart[] | undefined,\r\n );\r\n if (text.length > 0) yield text;\r\n }\r\n } catch (err) {\r\n throw wrapProviderError(alias, err);\r\n }\r\n },\r\n\r\n async *streamStructured<T>(options: StreamStructuredOptions<T>): AsyncIterable<Partial<T>> {\r\n throwIfAborted(options.signal);\r\n validateContent(options.prompt);\r\n try {\r\n const stream = await ctx.client.models.generateContentStream({\r\n model: modelId,\r\n contents: [\r\n {\r\n role: \"user\",\r\n parts: [\r\n {\r\n text: `${stringifyContentBlocks(options.prompt)}\\n\\nReply with a single JSON object only. Stream the JSON progressively.`,\r\n },\r\n ],\r\n },\r\n ],\r\n config: {\r\n ...(options.instructions !== undefined\r\n ? { systemInstruction: options.instructions }\r\n : {}),\r\n temperature: options.temperature ?? 0,\r\n ...(options.maxOutputTokens !== undefined\r\n ? { maxOutputTokens: options.maxOutputTokens }\r\n : {}),\r\n responseMimeType: \"application/json\",\r\n ...(options.signal ? { abortSignal: options.signal } : {}),\r\n },\r\n });\r\n let buffer = \"\";\r\n for await (const chunk of stream) {\r\n const text = extractGeminiText(\r\n chunk.candidates?.[0]?.content?.parts as GeminiPart[] | undefined,\r\n );\r\n if (text.length === 0) continue;\r\n buffer += text;\r\n const partial = tryParsePartialJSON(buffer);\r\n if (partial !== null) yield partial as Partial<T>;\r\n }\r\n } catch (err) {\r\n throw wrapProviderError(alias, err);\r\n }\r\n },\r\n\r\n async runAgent(options: RunAgentOptions): Promise<AgentResult> {\r\n throwIfAborted(options.signal);\r\n validateMessages(options.messages);\r\n // v0.1: single-turn agent loop. Gemini's native automatic-function-calling\r\n // multi-turn runAgent ships in v0.2 (matches adapter-vercel's v0.1 shape).\r\n const start = Date.now();\r\n try {\r\n const { systemInstruction, contents } = toGeminiRequest(options.messages);\r\n const response = await ctx.client.models.generateContent({\r\n model: modelId,\r\n contents,\r\n config: {\r\n ...(systemInstruction !== undefined ? { systemInstruction } : {}),\r\n ...(options.instructions !== undefined\r\n ? { systemInstruction: options.instructions }\r\n : {}),\r\n ...(options.signal ? { abortSignal: options.signal } : {}),\r\n },\r\n });\r\n const candidate = response.candidates?.[0];\r\n const text = extractGeminiText(candidate?.content?.parts as GeminiPart[] | undefined);\r\n const usage = parseUsage(response);\r\n const toolCalls: AgentResult[\"toolCalls\"] = [];\r\n // v0.1 stub: we surface no tool calls. Real tool-use is v0.2 scope.\r\n return {\r\n text,\r\n messages: [\r\n ...options.messages,\r\n { role: \"assistant\" as const, content: text },\r\n ],\r\n usage,\r\n cost: computeChatCost(usage, pricing),\r\n modelId: response.modelVersion ?? modelId,\r\n providerAlias: alias,\r\n latencyMs: Date.now() - start,\r\n toolCalls,\r\n stepsTaken: 1,\r\n terminationReason: \"completed\",\r\n };\r\n } catch (err) {\r\n throw wrapProviderError(alias, err);\r\n }\r\n },\r\n };\r\n}\r\n\r\n// ─── Helpers ─────────────────────────────────────────────────────────\r\n\r\ninterface GeminiUsageMetadata {\r\n promptTokenCount?: number;\r\n candidatesTokenCount?: number;\r\n totalTokenCount?: number;\r\n cachedContentTokenCount?: number;\r\n}\r\n\r\ninterface GeminiResponseShape {\r\n usageMetadata?: GeminiUsageMetadata;\r\n}\r\n\r\nfunction parseUsage(response: GeminiResponseShape): TokenUsage {\r\n const m = response.usageMetadata ?? {};\r\n const inputTokens = m.promptTokenCount ?? 0;\r\n const outputTokens = m.candidatesTokenCount ?? 0;\r\n const totalTokens = m.totalTokenCount ?? inputTokens + outputTokens;\r\n const usage: TokenUsage = { inputTokens, outputTokens, totalTokens };\r\n if (m.cachedContentTokenCount !== undefined && m.cachedContentTokenCount > 0) {\r\n usage.cacheReadTokens = m.cachedContentTokenCount;\r\n }\r\n return usage;\r\n}\r\n\r\n// Re-export ContentBlock for the rare adapter user that wants to type-check\r\n// outside of @llm-ports/core. Keeps the import surface symmetric with the\r\n// other adapters.\r\nexport type { ContentBlock };\r\n"]}
package/dist/index.mjs CHANGED
@@ -1,5 +1,5 @@
1
1
  import { GoogleGenAI } from '@google/genai';
2
- import { computeChatCost, wrapProviderError, stringifyContentBlocks, tryParsePartialJSON, extractJSON, attemptValidationRepair, failValidation, validateImageBlocks, ContentBlockUnsupportedError } from '@llm-ports/core';
2
+ import { throwIfAborted, computeChatCost, wrapProviderError, stringifyContentBlocks, tryParsePartialJSON, extractJSON, attemptValidationRepair, failValidation, validateImageBlocks, ContentBlockUnsupportedError } from '@llm-ports/core';
3
3
 
4
4
  // src/adapter.ts
5
5
  var ADAPTER_NAME = "google";
@@ -175,6 +175,7 @@ function createPort(ctx, modelId, alias) {
175
175
  };
176
176
  return {
177
177
  async generateText(options) {
178
+ throwIfAborted(options.signal);
178
179
  validateContent(options.prompt);
179
180
  const start = Date.now();
180
181
  try {
@@ -185,7 +186,8 @@ function createPort(ctx, modelId, alias) {
185
186
  config: {
186
187
  ...options.instructions !== void 0 ? { systemInstruction: options.instructions } : {},
187
188
  ...options.temperature !== void 0 ? { temperature: options.temperature } : {},
188
- ...options.maxOutputTokens !== void 0 ? { maxOutputTokens: options.maxOutputTokens } : {}
189
+ ...options.maxOutputTokens !== void 0 ? { maxOutputTokens: options.maxOutputTokens } : {},
190
+ ...options.signal ? { abortSignal: options.signal } : {}
189
191
  }
190
192
  });
191
193
  const candidate = response.candidates?.[0];
@@ -204,6 +206,7 @@ function createPort(ctx, modelId, alias) {
204
206
  }
205
207
  },
206
208
  async generateStructured(options) {
209
+ throwIfAborted(options.signal);
207
210
  validateContent(options.prompt);
208
211
  const start = Date.now();
209
212
  let attempts = 0;
@@ -226,7 +229,8 @@ Reply with a single JSON object only. No prose, no code fences.`;
226
229
  ...options.instructions !== void 0 ? { systemInstruction: options.instructions } : {},
227
230
  temperature: options.temperature ?? 0,
228
231
  ...options.maxOutputTokens !== void 0 ? { maxOutputTokens: options.maxOutputTokens } : {},
229
- responseMimeType: "application/json"
232
+ responseMimeType: "application/json",
233
+ ...options.signal ? { abortSignal: options.signal } : {}
230
234
  }
231
235
  });
232
236
  const candidate = response.candidates?.[0];
@@ -267,6 +271,7 @@ Reply with a single corrected JSON object only.`;
267
271
  throw new Error("generateStructured exhausted attempts");
268
272
  },
269
273
  async *streamText(options) {
274
+ throwIfAborted(options.signal);
270
275
  validateContent(options.prompt);
271
276
  try {
272
277
  const parts = toGeminiParts2(options.prompt);
@@ -276,7 +281,8 @@ Reply with a single corrected JSON object only.`;
276
281
  config: {
277
282
  ...options.instructions !== void 0 ? { systemInstruction: options.instructions } : {},
278
283
  ...options.temperature !== void 0 ? { temperature: options.temperature } : {},
279
- ...options.maxOutputTokens !== void 0 ? { maxOutputTokens: options.maxOutputTokens } : {}
284
+ ...options.maxOutputTokens !== void 0 ? { maxOutputTokens: options.maxOutputTokens } : {},
285
+ ...options.signal ? { abortSignal: options.signal } : {}
280
286
  }
281
287
  });
282
288
  for await (const chunk of stream) {
@@ -290,6 +296,7 @@ Reply with a single corrected JSON object only.`;
290
296
  }
291
297
  },
292
298
  async *streamStructured(options) {
299
+ throwIfAborted(options.signal);
293
300
  validateContent(options.prompt);
294
301
  try {
295
302
  const stream = await ctx.client.models.generateContentStream({
@@ -310,7 +317,8 @@ Reply with a single JSON object only. Stream the JSON progressively.`
310
317
  ...options.instructions !== void 0 ? { systemInstruction: options.instructions } : {},
311
318
  temperature: options.temperature ?? 0,
312
319
  ...options.maxOutputTokens !== void 0 ? { maxOutputTokens: options.maxOutputTokens } : {},
313
- responseMimeType: "application/json"
320
+ responseMimeType: "application/json",
321
+ ...options.signal ? { abortSignal: options.signal } : {}
314
322
  }
315
323
  });
316
324
  let buffer = "";
@@ -328,6 +336,7 @@ Reply with a single JSON object only. Stream the JSON progressively.`
328
336
  }
329
337
  },
330
338
  async runAgent(options) {
339
+ throwIfAborted(options.signal);
331
340
  validateMessages(options.messages);
332
341
  const start = Date.now();
333
342
  try {
@@ -337,7 +346,8 @@ Reply with a single JSON object only. Stream the JSON progressively.`
337
346
  contents,
338
347
  config: {
339
348
  ...systemInstruction !== void 0 ? { systemInstruction } : {},
340
- ...options.instructions !== void 0 ? { systemInstruction: options.instructions } : {}
349
+ ...options.instructions !== void 0 ? { systemInstruction: options.instructions } : {},
350
+ ...options.signal ? { abortSignal: options.signal } : {}
341
351
  }
342
352
  });
343
353
  const candidate = response.candidates?.[0];
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/content.ts","../src/pricing.ts","../src/adapter.ts"],"names":[],"mappings":"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","file":"index.mjs","sourcesContent":["/**\r\n * Content translation between llm-ports ContentBlock[] and Gemini's\r\n * Content + Part shapes.\r\n *\r\n * Gemini's content model:\r\n * Content = { role: \"user\" | \"model\" | \"function\", parts: Part[] }\r\n * Part shapes (the ones we care about):\r\n * - { text: string }\r\n * - { inlineData: { mimeType: string, data: string (base64) } }\r\n * - { fileData: { mimeType: string, fileUri: string } }\r\n * - { functionCall: { name: string, args: object } }\r\n * - { functionResponse: { name: string, response: object } }\r\n *\r\n * Notes:\r\n * - System messages map to a top-level `systemInstruction` field on the\r\n * request, NOT a Content with role: \"system\". `toGeminiRequest` handles\r\n * this split.\r\n * - The assistant role is `\"model\"` in Gemini's vocabulary.\r\n * - Tool results are mapped to `functionResponse` parts.\r\n */\r\n\r\nimport {\r\n ContentBlockUnsupportedError,\r\n type ContentBlock,\r\n type LLMMessage,\r\n type MessageContent,\r\n} from \"@llm-ports/core\";\r\n\r\nconst ADAPTER_NAME = \"google\";\r\n\r\n// ─── Outgoing: ContentBlock[] → Gemini Part[] ────────────────────────\r\n\r\ninterface GeminiTextPart {\r\n text: string;\r\n}\r\ninterface GeminiInlineDataPart {\r\n inlineData: { mimeType: string; data: string };\r\n}\r\ninterface GeminiFileDataPart {\r\n fileData: { mimeType: string; fileUri: string };\r\n}\r\ninterface GeminiFunctionCallPart {\r\n functionCall: { name: string; args: Record<string, unknown> };\r\n}\r\ninterface GeminiFunctionResponsePart {\r\n functionResponse: { name: string; response: Record<string, unknown> };\r\n}\r\nexport type GeminiPart =\r\n | GeminiTextPart\r\n | GeminiInlineDataPart\r\n | GeminiFileDataPart\r\n | GeminiFunctionCallPart\r\n | GeminiFunctionResponsePart;\r\n\r\nexport interface GeminiContent {\r\n role: \"user\" | \"model\" | \"function\";\r\n parts: GeminiPart[];\r\n}\r\n\r\n/** Translate a single ContentBlock to one or more GeminiParts. */\r\nfunction toGeminiParts(block: ContentBlock): GeminiPart[] {\r\n switch (block.type) {\r\n case \"text\":\r\n return [{ text: block.text }];\r\n case \"image\": {\r\n if (block.source.kind === \"base64\") {\r\n return [\r\n {\r\n inlineData: {\r\n mimeType: block.source.mediaType,\r\n data: block.source.data,\r\n },\r\n },\r\n ];\r\n }\r\n // URL form\r\n return [\r\n {\r\n fileData: {\r\n // Gemini infers mimeType from URL extension when not provided.\r\n // We pass image/jpeg as a sane default; users wanting tighter\r\n // control should pass base64 with explicit mediaType.\r\n mimeType: \"image/jpeg\",\r\n fileUri: block.source.url,\r\n },\r\n },\r\n ];\r\n }\r\n case \"audio\": {\r\n if (block.source.kind === \"base64\") {\r\n return [\r\n {\r\n inlineData: {\r\n mimeType: block.source.mediaType,\r\n data: block.source.data,\r\n },\r\n },\r\n ];\r\n }\r\n throw new ContentBlockUnsupportedError(ADAPTER_NAME, \"audio (url; Gemini accepts base64 or fileData with fileUri)\");\r\n }\r\n case \"tool_use\": {\r\n // Gemini's tool-call shape has args as a plain object; we pass the input\r\n // through if it's already an object, else wrap.\r\n const args =\r\n block.input !== null && typeof block.input === \"object\"\r\n ? (block.input as Record<string, unknown>)\r\n : { value: block.input };\r\n return [{ functionCall: { name: block.name, args } }];\r\n }\r\n case \"tool_result\": {\r\n // Gemini's functionResponse expects a `response` object. If the\r\n // ContentBlock.tool_result.content is a string, wrap it.\r\n const response: Record<string, unknown> =\r\n typeof block.content === \"string\"\r\n ? { result: block.content }\r\n : { result: extractTextOnly(block.content) };\r\n return [\r\n {\r\n functionResponse: {\r\n // Gemini's API requires the tool name; we use toolUseId since\r\n // llm-ports' ToolResultBlock doesn't carry the name. Adapters\r\n // that need the name can plumb it through a separate channel.\r\n name: block.toolUseId,\r\n response,\r\n },\r\n },\r\n ];\r\n }\r\n }\r\n}\r\n\r\nfunction extractTextOnly(blocks: ContentBlock[]): string {\r\n return blocks\r\n .filter((b): b is Extract<ContentBlock, { type: \"text\" }> => b.type === \"text\")\r\n .map((b) => b.text)\r\n .join(\"\\n\");\r\n}\r\n\r\n/** Translate a MessageContent to Gemini Parts. */\r\nexport function toGeminiParts2(content: MessageContent): GeminiPart[] {\r\n if (typeof content === \"string\") {\r\n return [{ text: content }];\r\n }\r\n return content.flatMap(toGeminiParts);\r\n}\r\n\r\n/**\r\n * Translate an array of LLMMessages into:\r\n * - `systemInstruction`: the concatenated system messages (Gemini puts\r\n * these at the top level of the request, not in `contents`).\r\n * - `contents`: the user + assistant + tool messages, with roles mapped.\r\n */\r\nexport function toGeminiRequest(messages: LLMMessage[]): {\r\n systemInstruction?: string;\r\n contents: GeminiContent[];\r\n} {\r\n let systemInstruction: string | undefined;\r\n const contents: GeminiContent[] = [];\r\n for (const msg of messages) {\r\n if (msg.role === \"system\") {\r\n const text =\r\n typeof msg.content === \"string\" ? msg.content : extractTextOnly(msg.content);\r\n systemInstruction = systemInstruction === undefined ? text : `${systemInstruction}\\n\\n${text}`;\r\n continue;\r\n }\r\n const role: GeminiContent[\"role\"] =\r\n msg.role === \"tool\" ? \"function\" : msg.role === \"assistant\" ? \"model\" : \"user\";\r\n contents.push({\r\n role,\r\n parts: toGeminiParts2(msg.content),\r\n });\r\n }\r\n return systemInstruction !== undefined\r\n ? { systemInstruction, contents }\r\n : { contents };\r\n}\r\n\r\n// ─── Incoming: Gemini response → ContentBlock[] ──────────────────────\r\n\r\ninterface GeminiResponseCandidate {\r\n content?: {\r\n role?: string;\r\n parts?: GeminiPart[];\r\n };\r\n finishReason?: string;\r\n}\r\n\r\n/**\r\n * Extract the assistant text from a Gemini response. Used by generateText\r\n * and by the structured-output path before JSON parsing.\r\n */\r\nexport function extractGeminiText(parts: GeminiPart[] | undefined): string {\r\n if (!parts) return \"\";\r\n return parts\r\n .filter((p): p is GeminiTextPart => \"text\" in p)\r\n .map((p) => p.text)\r\n .join(\"\");\r\n}\r\n\r\n/**\r\n * Translate a Gemini response candidate's parts back into ContentBlock[].\r\n * Used by runAgent to reconstruct the model's tool_use blocks.\r\n */\r\nexport function fromGeminiCandidate(candidate: GeminiResponseCandidate): ContentBlock[] {\r\n const out: ContentBlock[] = [];\r\n const parts = candidate.content?.parts ?? [];\r\n for (const part of parts) {\r\n if (\"text\" in part && part.text.length > 0) {\r\n out.push({ type: \"text\", text: part.text });\r\n } else if (\"functionCall\" in part) {\r\n out.push({\r\n type: \"tool_use\",\r\n id: `gemini-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`,\r\n name: part.functionCall.name,\r\n input: part.functionCall.args,\r\n });\r\n } else if (\"inlineData\" in part) {\r\n // Inline (base64) image in assistant response. Decode if media type\r\n // is one we support, else drop (consistent with adapter-openai's\r\n // unknown-media-type behavior).\r\n const mt = part.inlineData.mimeType;\r\n if (\r\n mt === \"image/jpeg\" ||\r\n mt === \"image/png\" ||\r\n mt === \"image/gif\" ||\r\n mt === \"image/webp\"\r\n ) {\r\n out.push({\r\n type: \"image\",\r\n source: { kind: \"base64\", mediaType: mt, data: part.inlineData.data },\r\n });\r\n }\r\n }\r\n // fileData / functionResponse in assistant responses: not currently observed.\r\n }\r\n return out;\r\n}\r\n","/**\r\n * Bundled pricing for Google Gemini models.\r\n *\r\n * Source: https://ai.google.dev/gemini-api/docs/pricing (verified 2026-05).\r\n * Override per model via `pricingOverrides` on the adapter options.\r\n *\r\n * Gemini pricing has separate tiers for prompts under 200k tokens vs over\r\n * 200k tokens (the \"long-context premium\"). The bundled values are the\r\n * UNDER-200k-token rates, which dominate typical usage. For long-context\r\n * workloads, supply `pricingOverrides` with the over-200k rates.\r\n */\r\n\r\nimport type { ModelPricing } from \"@llm-ports/core\";\r\n\r\nexport const GEMINI_PRICING: Record<string, ModelPricing> = {\r\n // Gemini 2.5 family (2026-05 GA pricing)\r\n \"gemini-2.5-pro\": {\r\n inputPer1M: 1.25,\r\n outputPer1M: 5.0,\r\n cacheReadPer1M: 0.3125,\r\n },\r\n \"gemini-2.5-flash\": {\r\n inputPer1M: 0.075,\r\n outputPer1M: 0.3,\r\n cacheReadPer1M: 0.01875,\r\n },\r\n \"gemini-2.5-flash-lite\": {\r\n inputPer1M: 0.0375,\r\n outputPer1M: 0.15,\r\n cacheReadPer1M: 0.009375,\r\n },\r\n // Gemini 2.0 family (still available)\r\n \"gemini-2.0-flash\": {\r\n inputPer1M: 0.1,\r\n outputPer1M: 0.4,\r\n cacheReadPer1M: 0.025,\r\n },\r\n \"gemini-2.0-flash-lite\": {\r\n inputPer1M: 0.075,\r\n outputPer1M: 0.3,\r\n },\r\n};\r\n\r\nexport function lookupGeminiPricing(modelId: string): ModelPricing | undefined {\r\n return GEMINI_PRICING[modelId];\r\n}\r\n","/**\r\n * Google Gemini adapter for llm-ports.\r\n *\r\n * Wraps @google/genai (the unified Gemini + Vertex SDK as of 2026) to\r\n * implement LLMPort. Provides:\r\n *\r\n * - Native multimodal: image content blocks pass through as inlineData\r\n * (base64) or fileData (URL). NO degradation, unlike OpenAI-compat\r\n * baseURL where image_url.detail is silently ignored.\r\n * - Native streaming via generateContentStream\r\n * - Structured output via prompted-JSON + Zod retry-with-feedback\r\n * + alpha.5 programmatic repair. Native Gemini responseSchema lands\r\n * in v0.2.\r\n * - Image-block boundary validation (size + URL scheme) — same shape\r\n * as adapter-anthropic and adapter-openai (alpha.5).\r\n *\r\n * Out of scope for v0.1 alpha:\r\n * - Embeddings (Gemini's embedding API is separate; lands in v0.2)\r\n * - Multi-turn runAgent through Gemini's native automatic tool calling\r\n * (v0.1 ships a single-turn shim consistent with adapter-vercel)\r\n * - Caching API (Gemini supports explicit context caching; lands in v0.2)\r\n * - Code execution tool (Gemini's built-in code interpreter; lands in v0.2)\r\n */\r\n\r\nimport { GoogleGenAI } from \"@google/genai\";\r\nimport {\r\n attemptValidationRepair,\r\n computeChatCost,\r\n extractJSON,\r\n failValidation,\r\n stringifyContentBlocks,\r\n tryParsePartialJSON,\r\n validateImageBlocks,\r\n wrapProviderError,\r\n type AgentResult,\r\n type ContentBlock,\r\n type GenerateStructuredOptions,\r\n type GenerateStructuredResult,\r\n type GenerateTextOptions,\r\n type GenerateTextResult,\r\n type LLMPort,\r\n type MessageContent,\r\n type ModelPricing,\r\n type RunAgentOptions,\r\n type StreamStructuredOptions,\r\n type StreamTextOptions,\r\n type TokenUsage,\r\n type ValidationStrategy,\r\n} from \"@llm-ports/core\";\r\nimport {\r\n extractGeminiText,\r\n toGeminiParts2,\r\n toGeminiRequest,\r\n type GeminiPart,\r\n} from \"./content.js\";\r\nimport { GEMINI_PRICING } from \"./pricing.js\";\r\n\r\n// ─── Adapter options ─────────────────────────────────────────────────\r\n\r\nexport interface GoogleAdapterOptions {\r\n /** Google AI API key (https://aistudio.google.com/apikey). */\r\n apiKey: string;\r\n /** Override Gemini pricing for any model id. Falls back to the bundled table. */\r\n pricingOverrides?: Record<string, ModelPricing>;\r\n /** Default validation strategy if the registry doesn't override per-call. */\r\n validationStrategy?: ValidationStrategy;\r\n /**\r\n * Maximum bytes per base64 image. Defaults to 20MB (Gemini accepts up to\r\n * 20MB inlined; fileData URLs are unconstrained but provider-fetched).\r\n * Set to 0 or a negative number to disable size validation.\r\n */\r\n imageSizeLimitBytes?: number;\r\n}\r\n\r\n// ─── Internal context ────────────────────────────────────────────────\r\n\r\ninterface AdapterContext {\r\n client: GoogleGenAI;\r\n validationStrategy: ValidationStrategy;\r\n pricingOverrides: Record<string, ModelPricing>;\r\n imageSizeLimitBytes: number;\r\n}\r\n\r\nfunction pricingFor(ctx: AdapterContext, modelId: string): ModelPricing {\r\n const pricing = ctx.pricingOverrides[modelId] ?? GEMINI_PRICING[modelId];\r\n if (!pricing) {\r\n throw new Error(\r\n `No pricing entry for Google Gemini model \"${modelId}\". Provide pricingOverrides or update src/pricing.ts.`,\r\n );\r\n }\r\n return pricing;\r\n}\r\n\r\n// ─── Public factory ──────────────────────────────────────────────────\r\n\r\nexport interface GoogleAdapter {\r\n name: \"google\";\r\n pricing: Record<string, ModelPricing>;\r\n createLLMPort: (modelId: string, alias: string) => LLMPort;\r\n}\r\n\r\nexport function createGoogleAdapter(opts: GoogleAdapterOptions): GoogleAdapter {\r\n const mergedPricing: Record<string, ModelPricing> = {\r\n ...GEMINI_PRICING,\r\n ...(opts.pricingOverrides ?? {}),\r\n };\r\n const ctx: AdapterContext = {\r\n client: new GoogleGenAI({ apiKey: opts.apiKey }),\r\n validationStrategy: opts.validationStrategy ?? {\r\n kind: \"retry-with-feedback\",\r\n maxAttempts: 2,\r\n includeOriginalError: true,\r\n },\r\n pricingOverrides: opts.pricingOverrides ?? {},\r\n imageSizeLimitBytes: opts.imageSizeLimitBytes ?? 20 * 1024 * 1024,\r\n };\r\n return {\r\n name: \"google\",\r\n pricing: mergedPricing,\r\n createLLMPort: (modelId, alias) => createPort(ctx, modelId, alias),\r\n };\r\n}\r\n\r\n// ─── Port implementation ─────────────────────────────────────────────\r\n\r\nfunction createPort(ctx: AdapterContext, modelId: string, alias: string): LLMPort {\r\n const pricing = pricingFor(ctx, modelId);\r\n\r\n // Image-block validation closure: throws ImageTooLargeError or\r\n // InvalidImageUrlError before the SDK call.\r\n const validateContent = (content: MessageContent): void => {\r\n if (Array.isArray(content)) {\r\n validateImageBlocks(content, {\r\n alias,\r\n ...(ctx.imageSizeLimitBytes > 0 ? { limitBytes: ctx.imageSizeLimitBytes } : {}),\r\n });\r\n }\r\n };\r\n const validateMessages = (messages: ReadonlyArray<{ content: MessageContent }>): void => {\r\n for (const msg of messages) validateContent(msg.content);\r\n };\r\n\r\n return {\r\n async generateText(options: GenerateTextOptions): Promise<GenerateTextResult> {\r\n validateContent(options.prompt);\r\n const start = Date.now();\r\n try {\r\n const parts = toGeminiParts2(options.prompt);\r\n const response = await ctx.client.models.generateContent({\r\n model: modelId,\r\n contents: [{ role: \"user\", parts }],\r\n config: {\r\n ...(options.instructions !== undefined\r\n ? { systemInstruction: options.instructions }\r\n : {}),\r\n ...(options.temperature !== undefined ? { temperature: options.temperature } : {}),\r\n ...(options.maxOutputTokens !== undefined\r\n ? { maxOutputTokens: options.maxOutputTokens }\r\n : {}),\r\n },\r\n });\r\n const candidate = response.candidates?.[0];\r\n const text = extractGeminiText(candidate?.content?.parts as GeminiPart[] | undefined);\r\n const usage = parseUsage(response);\r\n return {\r\n text,\r\n usage,\r\n cost: computeChatCost(usage, pricing),\r\n modelId: response.modelVersion ?? modelId,\r\n providerAlias: alias,\r\n latencyMs: Date.now() - start,\r\n };\r\n } catch (err) {\r\n throw wrapProviderError(alias, err);\r\n }\r\n },\r\n\r\n async generateStructured<T>(\r\n options: GenerateStructuredOptions<T>,\r\n ): Promise<GenerateStructuredResult<T>> {\r\n validateContent(options.prompt);\r\n const start = Date.now();\r\n let attempts = 0;\r\n const maxAttempts =\r\n ctx.validationStrategy.kind === \"retry-with-feedback\"\r\n ? ctx.validationStrategy.maxAttempts\r\n : 1;\r\n\r\n let correctionPrompt: string | null = null;\r\n let lastUsage: TokenUsage = { inputTokens: 0, outputTokens: 0, totalTokens: 0 };\r\n let lastModelId = modelId;\r\n\r\n while (attempts < maxAttempts) {\r\n attempts++;\r\n const userText = correctionPrompt\r\n ? `${stringifyContentBlocks(options.prompt)}\\n\\n${correctionPrompt}`\r\n : `${stringifyContentBlocks(options.prompt)}\\n\\nReply with a single JSON object only. No prose, no code fences.`;\r\n\r\n try {\r\n const response = await ctx.client.models.generateContent({\r\n model: modelId,\r\n contents: [{ role: \"user\", parts: [{ text: userText }] }],\r\n config: {\r\n ...(options.instructions !== undefined\r\n ? { systemInstruction: options.instructions }\r\n : {}),\r\n temperature: options.temperature ?? 0,\r\n ...(options.maxOutputTokens !== undefined\r\n ? { maxOutputTokens: options.maxOutputTokens }\r\n : {}),\r\n responseMimeType: \"application/json\",\r\n },\r\n });\r\n const candidate = response.candidates?.[0];\r\n const raw = extractGeminiText(candidate?.content?.parts as GeminiPart[] | undefined);\r\n lastUsage = parseUsage(response);\r\n lastModelId = response.modelVersion ?? modelId;\r\n\r\n const decoded = extractJSON(raw);\r\n let parsed = options.schema.safeParse(decoded);\r\n if (!parsed.success) {\r\n const repaired = attemptValidationRepair(decoded, parsed.error);\r\n const reparsed = options.schema.safeParse(repaired);\r\n if (reparsed.success) parsed = reparsed;\r\n }\r\n if (parsed.success) {\r\n return {\r\n data: parsed.data as T,\r\n usage: lastUsage,\r\n cost: computeChatCost(lastUsage, pricing),\r\n modelId: lastModelId,\r\n providerAlias: alias,\r\n latencyMs: Date.now() - start,\r\n validationAttempts: attempts,\r\n };\r\n }\r\n if (\r\n ctx.validationStrategy.kind === \"retry-with-feedback\" &&\r\n attempts < maxAttempts\r\n ) {\r\n const issues = parsed.error.issues\r\n .map((i) => `- ${i.path.join(\".\") || \"<root>\"}: ${i.message}`)\r\n .join(\"\\n\");\r\n correctionPrompt = `Your previous response failed validation:\\n${issues}\\n\\nReply with a single corrected JSON object only.`;\r\n continue;\r\n }\r\n failValidation(parsed.error.issues, attempts);\r\n } catch (err) {\r\n throw wrapProviderError(alias, err);\r\n }\r\n }\r\n throw new Error(\"generateStructured exhausted attempts\");\r\n },\r\n\r\n async *streamText(options: StreamTextOptions): AsyncIterable<string> {\r\n validateContent(options.prompt);\r\n try {\r\n const parts = toGeminiParts2(options.prompt);\r\n const stream = await ctx.client.models.generateContentStream({\r\n model: modelId,\r\n contents: [{ role: \"user\", parts }],\r\n config: {\r\n ...(options.instructions !== undefined\r\n ? { systemInstruction: options.instructions }\r\n : {}),\r\n ...(options.temperature !== undefined ? { temperature: options.temperature } : {}),\r\n ...(options.maxOutputTokens !== undefined\r\n ? { maxOutputTokens: options.maxOutputTokens }\r\n : {}),\r\n },\r\n });\r\n for await (const chunk of stream) {\r\n const text = extractGeminiText(\r\n chunk.candidates?.[0]?.content?.parts as GeminiPart[] | undefined,\r\n );\r\n if (text.length > 0) yield text;\r\n }\r\n } catch (err) {\r\n throw wrapProviderError(alias, err);\r\n }\r\n },\r\n\r\n async *streamStructured<T>(options: StreamStructuredOptions<T>): AsyncIterable<Partial<T>> {\r\n validateContent(options.prompt);\r\n try {\r\n const stream = await ctx.client.models.generateContentStream({\r\n model: modelId,\r\n contents: [\r\n {\r\n role: \"user\",\r\n parts: [\r\n {\r\n text: `${stringifyContentBlocks(options.prompt)}\\n\\nReply with a single JSON object only. Stream the JSON progressively.`,\r\n },\r\n ],\r\n },\r\n ],\r\n config: {\r\n ...(options.instructions !== undefined\r\n ? { systemInstruction: options.instructions }\r\n : {}),\r\n temperature: options.temperature ?? 0,\r\n ...(options.maxOutputTokens !== undefined\r\n ? { maxOutputTokens: options.maxOutputTokens }\r\n : {}),\r\n responseMimeType: \"application/json\",\r\n },\r\n });\r\n let buffer = \"\";\r\n for await (const chunk of stream) {\r\n const text = extractGeminiText(\r\n chunk.candidates?.[0]?.content?.parts as GeminiPart[] | undefined,\r\n );\r\n if (text.length === 0) continue;\r\n buffer += text;\r\n const partial = tryParsePartialJSON(buffer);\r\n if (partial !== null) yield partial as Partial<T>;\r\n }\r\n } catch (err) {\r\n throw wrapProviderError(alias, err);\r\n }\r\n },\r\n\r\n async runAgent(options: RunAgentOptions): Promise<AgentResult> {\r\n validateMessages(options.messages);\r\n // v0.1: single-turn agent loop. Gemini's native automatic-function-calling\r\n // multi-turn runAgent ships in v0.2 (matches adapter-vercel's v0.1 shape).\r\n const start = Date.now();\r\n try {\r\n const { systemInstruction, contents } = toGeminiRequest(options.messages);\r\n const response = await ctx.client.models.generateContent({\r\n model: modelId,\r\n contents,\r\n config: {\r\n ...(systemInstruction !== undefined ? { systemInstruction } : {}),\r\n ...(options.instructions !== undefined\r\n ? { systemInstruction: options.instructions }\r\n : {}),\r\n },\r\n });\r\n const candidate = response.candidates?.[0];\r\n const text = extractGeminiText(candidate?.content?.parts as GeminiPart[] | undefined);\r\n const usage = parseUsage(response);\r\n const toolCalls: AgentResult[\"toolCalls\"] = [];\r\n // v0.1 stub: we surface no tool calls. Real tool-use is v0.2 scope.\r\n return {\r\n text,\r\n messages: [\r\n ...options.messages,\r\n { role: \"assistant\" as const, content: text },\r\n ],\r\n usage,\r\n cost: computeChatCost(usage, pricing),\r\n modelId: response.modelVersion ?? modelId,\r\n providerAlias: alias,\r\n latencyMs: Date.now() - start,\r\n toolCalls,\r\n stepsTaken: 1,\r\n terminationReason: \"completed\",\r\n };\r\n } catch (err) {\r\n throw wrapProviderError(alias, err);\r\n }\r\n },\r\n };\r\n}\r\n\r\n// ─── Helpers ─────────────────────────────────────────────────────────\r\n\r\ninterface GeminiUsageMetadata {\r\n promptTokenCount?: number;\r\n candidatesTokenCount?: number;\r\n totalTokenCount?: number;\r\n cachedContentTokenCount?: number;\r\n}\r\n\r\ninterface GeminiResponseShape {\r\n usageMetadata?: GeminiUsageMetadata;\r\n}\r\n\r\nfunction parseUsage(response: GeminiResponseShape): TokenUsage {\r\n const m = response.usageMetadata ?? {};\r\n const inputTokens = m.promptTokenCount ?? 0;\r\n const outputTokens = m.candidatesTokenCount ?? 0;\r\n const totalTokens = m.totalTokenCount ?? inputTokens + outputTokens;\r\n const usage: TokenUsage = { inputTokens, outputTokens, totalTokens };\r\n if (m.cachedContentTokenCount !== undefined && m.cachedContentTokenCount > 0) {\r\n usage.cacheReadTokens = m.cachedContentTokenCount;\r\n }\r\n return usage;\r\n}\r\n\r\n// Re-export ContentBlock for the rare adapter user that wants to type-check\r\n// outside of @llm-ports/core. Keeps the import surface symmetric with the\r\n// other adapters.\r\nexport type { ContentBlock };\r\n"]}
1
+ {"version":3,"sources":["../src/content.ts","../src/pricing.ts","../src/adapter.ts"],"names":[],"mappings":"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","file":"index.mjs","sourcesContent":["/**\r\n * Content translation between llm-ports ContentBlock[] and Gemini's\r\n * Content + Part shapes.\r\n *\r\n * Gemini's content model:\r\n * Content = { role: \"user\" | \"model\" | \"function\", parts: Part[] }\r\n * Part shapes (the ones we care about):\r\n * - { text: string }\r\n * - { inlineData: { mimeType: string, data: string (base64) } }\r\n * - { fileData: { mimeType: string, fileUri: string } }\r\n * - { functionCall: { name: string, args: object } }\r\n * - { functionResponse: { name: string, response: object } }\r\n *\r\n * Notes:\r\n * - System messages map to a top-level `systemInstruction` field on the\r\n * request, NOT a Content with role: \"system\". `toGeminiRequest` handles\r\n * this split.\r\n * - The assistant role is `\"model\"` in Gemini's vocabulary.\r\n * - Tool results are mapped to `functionResponse` parts.\r\n */\r\n\r\nimport {\r\n ContentBlockUnsupportedError,\r\n type ContentBlock,\r\n type LLMMessage,\r\n type MessageContent,\r\n} from \"@llm-ports/core\";\r\n\r\nconst ADAPTER_NAME = \"google\";\r\n\r\n// ─── Outgoing: ContentBlock[] → Gemini Part[] ────────────────────────\r\n\r\ninterface GeminiTextPart {\r\n text: string;\r\n}\r\ninterface GeminiInlineDataPart {\r\n inlineData: { mimeType: string; data: string };\r\n}\r\ninterface GeminiFileDataPart {\r\n fileData: { mimeType: string; fileUri: string };\r\n}\r\ninterface GeminiFunctionCallPart {\r\n functionCall: { name: string; args: Record<string, unknown> };\r\n}\r\ninterface GeminiFunctionResponsePart {\r\n functionResponse: { name: string; response: Record<string, unknown> };\r\n}\r\nexport type GeminiPart =\r\n | GeminiTextPart\r\n | GeminiInlineDataPart\r\n | GeminiFileDataPart\r\n | GeminiFunctionCallPart\r\n | GeminiFunctionResponsePart;\r\n\r\nexport interface GeminiContent {\r\n role: \"user\" | \"model\" | \"function\";\r\n parts: GeminiPart[];\r\n}\r\n\r\n/** Translate a single ContentBlock to one or more GeminiParts. */\r\nfunction toGeminiParts(block: ContentBlock): GeminiPart[] {\r\n switch (block.type) {\r\n case \"text\":\r\n return [{ text: block.text }];\r\n case \"image\": {\r\n if (block.source.kind === \"base64\") {\r\n return [\r\n {\r\n inlineData: {\r\n mimeType: block.source.mediaType,\r\n data: block.source.data,\r\n },\r\n },\r\n ];\r\n }\r\n // URL form\r\n return [\r\n {\r\n fileData: {\r\n // Gemini infers mimeType from URL extension when not provided.\r\n // We pass image/jpeg as a sane default; users wanting tighter\r\n // control should pass base64 with explicit mediaType.\r\n mimeType: \"image/jpeg\",\r\n fileUri: block.source.url,\r\n },\r\n },\r\n ];\r\n }\r\n case \"audio\": {\r\n if (block.source.kind === \"base64\") {\r\n return [\r\n {\r\n inlineData: {\r\n mimeType: block.source.mediaType,\r\n data: block.source.data,\r\n },\r\n },\r\n ];\r\n }\r\n throw new ContentBlockUnsupportedError(ADAPTER_NAME, \"audio (url; Gemini accepts base64 or fileData with fileUri)\");\r\n }\r\n case \"tool_use\": {\r\n // Gemini's tool-call shape has args as a plain object; we pass the input\r\n // through if it's already an object, else wrap.\r\n const args =\r\n block.input !== null && typeof block.input === \"object\"\r\n ? (block.input as Record<string, unknown>)\r\n : { value: block.input };\r\n return [{ functionCall: { name: block.name, args } }];\r\n }\r\n case \"tool_result\": {\r\n // Gemini's functionResponse expects a `response` object. If the\r\n // ContentBlock.tool_result.content is a string, wrap it.\r\n const response: Record<string, unknown> =\r\n typeof block.content === \"string\"\r\n ? { result: block.content }\r\n : { result: extractTextOnly(block.content) };\r\n return [\r\n {\r\n functionResponse: {\r\n // Gemini's API requires the tool name; we use toolUseId since\r\n // llm-ports' ToolResultBlock doesn't carry the name. Adapters\r\n // that need the name can plumb it through a separate channel.\r\n name: block.toolUseId,\r\n response,\r\n },\r\n },\r\n ];\r\n }\r\n }\r\n}\r\n\r\nfunction extractTextOnly(blocks: ContentBlock[]): string {\r\n return blocks\r\n .filter((b): b is Extract<ContentBlock, { type: \"text\" }> => b.type === \"text\")\r\n .map((b) => b.text)\r\n .join(\"\\n\");\r\n}\r\n\r\n/** Translate a MessageContent to Gemini Parts. */\r\nexport function toGeminiParts2(content: MessageContent): GeminiPart[] {\r\n if (typeof content === \"string\") {\r\n return [{ text: content }];\r\n }\r\n return content.flatMap(toGeminiParts);\r\n}\r\n\r\n/**\r\n * Translate an array of LLMMessages into:\r\n * - `systemInstruction`: the concatenated system messages (Gemini puts\r\n * these at the top level of the request, not in `contents`).\r\n * - `contents`: the user + assistant + tool messages, with roles mapped.\r\n */\r\nexport function toGeminiRequest(messages: LLMMessage[]): {\r\n systemInstruction?: string;\r\n contents: GeminiContent[];\r\n} {\r\n let systemInstruction: string | undefined;\r\n const contents: GeminiContent[] = [];\r\n for (const msg of messages) {\r\n if (msg.role === \"system\") {\r\n const text =\r\n typeof msg.content === \"string\" ? msg.content : extractTextOnly(msg.content);\r\n systemInstruction = systemInstruction === undefined ? text : `${systemInstruction}\\n\\n${text}`;\r\n continue;\r\n }\r\n const role: GeminiContent[\"role\"] =\r\n msg.role === \"tool\" ? \"function\" : msg.role === \"assistant\" ? \"model\" : \"user\";\r\n contents.push({\r\n role,\r\n parts: toGeminiParts2(msg.content),\r\n });\r\n }\r\n return systemInstruction !== undefined\r\n ? { systemInstruction, contents }\r\n : { contents };\r\n}\r\n\r\n// ─── Incoming: Gemini response → ContentBlock[] ──────────────────────\r\n\r\ninterface GeminiResponseCandidate {\r\n content?: {\r\n role?: string;\r\n parts?: GeminiPart[];\r\n };\r\n finishReason?: string;\r\n}\r\n\r\n/**\r\n * Extract the assistant text from a Gemini response. Used by generateText\r\n * and by the structured-output path before JSON parsing.\r\n */\r\nexport function extractGeminiText(parts: GeminiPart[] | undefined): string {\r\n if (!parts) return \"\";\r\n return parts\r\n .filter((p): p is GeminiTextPart => \"text\" in p)\r\n .map((p) => p.text)\r\n .join(\"\");\r\n}\r\n\r\n/**\r\n * Translate a Gemini response candidate's parts back into ContentBlock[].\r\n * Used by runAgent to reconstruct the model's tool_use blocks.\r\n */\r\nexport function fromGeminiCandidate(candidate: GeminiResponseCandidate): ContentBlock[] {\r\n const out: ContentBlock[] = [];\r\n const parts = candidate.content?.parts ?? [];\r\n for (const part of parts) {\r\n if (\"text\" in part && part.text.length > 0) {\r\n out.push({ type: \"text\", text: part.text });\r\n } else if (\"functionCall\" in part) {\r\n out.push({\r\n type: \"tool_use\",\r\n id: `gemini-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`,\r\n name: part.functionCall.name,\r\n input: part.functionCall.args,\r\n });\r\n } else if (\"inlineData\" in part) {\r\n // Inline (base64) image in assistant response. Decode if media type\r\n // is one we support, else drop (consistent with adapter-openai's\r\n // unknown-media-type behavior).\r\n const mt = part.inlineData.mimeType;\r\n if (\r\n mt === \"image/jpeg\" ||\r\n mt === \"image/png\" ||\r\n mt === \"image/gif\" ||\r\n mt === \"image/webp\"\r\n ) {\r\n out.push({\r\n type: \"image\",\r\n source: { kind: \"base64\", mediaType: mt, data: part.inlineData.data },\r\n });\r\n }\r\n }\r\n // fileData / functionResponse in assistant responses: not currently observed.\r\n }\r\n return out;\r\n}\r\n","/**\r\n * Bundled pricing for Google Gemini models.\r\n *\r\n * Source: https://ai.google.dev/gemini-api/docs/pricing (verified 2026-05).\r\n * Override per model via `pricingOverrides` on the adapter options.\r\n *\r\n * Gemini pricing has separate tiers for prompts under 200k tokens vs over\r\n * 200k tokens (the \"long-context premium\"). The bundled values are the\r\n * UNDER-200k-token rates, which dominate typical usage. For long-context\r\n * workloads, supply `pricingOverrides` with the over-200k rates.\r\n */\r\n\r\nimport type { ModelPricing } from \"@llm-ports/core\";\r\n\r\nexport const GEMINI_PRICING: Record<string, ModelPricing> = {\r\n // Gemini 2.5 family (2026-05 GA pricing)\r\n \"gemini-2.5-pro\": {\r\n inputPer1M: 1.25,\r\n outputPer1M: 5.0,\r\n cacheReadPer1M: 0.3125,\r\n },\r\n \"gemini-2.5-flash\": {\r\n inputPer1M: 0.075,\r\n outputPer1M: 0.3,\r\n cacheReadPer1M: 0.01875,\r\n },\r\n \"gemini-2.5-flash-lite\": {\r\n inputPer1M: 0.0375,\r\n outputPer1M: 0.15,\r\n cacheReadPer1M: 0.009375,\r\n },\r\n // Gemini 2.0 family (still available)\r\n \"gemini-2.0-flash\": {\r\n inputPer1M: 0.1,\r\n outputPer1M: 0.4,\r\n cacheReadPer1M: 0.025,\r\n },\r\n \"gemini-2.0-flash-lite\": {\r\n inputPer1M: 0.075,\r\n outputPer1M: 0.3,\r\n },\r\n};\r\n\r\nexport function lookupGeminiPricing(modelId: string): ModelPricing | undefined {\r\n return GEMINI_PRICING[modelId];\r\n}\r\n","/**\r\n * Google Gemini adapter for llm-ports.\r\n *\r\n * Wraps @google/genai (the unified Gemini + Vertex SDK as of 2026) to\r\n * implement LLMPort. Provides:\r\n *\r\n * - Native multimodal: image content blocks pass through as inlineData\r\n * (base64) or fileData (URL). NO degradation, unlike OpenAI-compat\r\n * baseURL where image_url.detail is silently ignored.\r\n * - Native streaming via generateContentStream\r\n * - Structured output via prompted-JSON + Zod retry-with-feedback\r\n * + alpha.5 programmatic repair. Native Gemini responseSchema lands\r\n * in v0.2.\r\n * - Image-block boundary validation (size + URL scheme) — same shape\r\n * as adapter-anthropic and adapter-openai (alpha.5).\r\n *\r\n * Out of scope for v0.1 alpha:\r\n * - Embeddings (Gemini's embedding API is separate; lands in v0.2)\r\n * - Multi-turn runAgent through Gemini's native automatic tool calling\r\n * (v0.1 ships a single-turn shim consistent with adapter-vercel)\r\n * - Caching API (Gemini supports explicit context caching; lands in v0.2)\r\n * - Code execution tool (Gemini's built-in code interpreter; lands in v0.2)\r\n */\r\n\r\nimport { GoogleGenAI } from \"@google/genai\";\r\nimport {\r\n attemptValidationRepair,\r\n computeChatCost,\r\n extractJSON,\r\n failValidation,\r\n stringifyContentBlocks,\r\n throwIfAborted,\r\n tryParsePartialJSON,\r\n validateImageBlocks,\r\n wrapProviderError,\r\n type AgentResult,\r\n type ContentBlock,\r\n type GenerateStructuredOptions,\r\n type GenerateStructuredResult,\r\n type GenerateTextOptions,\r\n type GenerateTextResult,\r\n type LLMPort,\r\n type MessageContent,\r\n type ModelPricing,\r\n type RunAgentOptions,\r\n type StreamStructuredOptions,\r\n type StreamTextOptions,\r\n type TokenUsage,\r\n type ValidationStrategy,\r\n} from \"@llm-ports/core\";\r\nimport {\r\n extractGeminiText,\r\n toGeminiParts2,\r\n toGeminiRequest,\r\n type GeminiPart,\r\n} from \"./content.js\";\r\nimport { GEMINI_PRICING } from \"./pricing.js\";\r\n\r\n// ─── Adapter options ─────────────────────────────────────────────────\r\n\r\nexport interface GoogleAdapterOptions {\r\n /** Google AI API key (https://aistudio.google.com/apikey). */\r\n apiKey: string;\r\n /** Override Gemini pricing for any model id. Falls back to the bundled table. */\r\n pricingOverrides?: Record<string, ModelPricing>;\r\n /** Default validation strategy if the registry doesn't override per-call. */\r\n validationStrategy?: ValidationStrategy;\r\n /**\r\n * Maximum bytes per base64 image. Defaults to 20MB (Gemini accepts up to\r\n * 20MB inlined; fileData URLs are unconstrained but provider-fetched).\r\n * Set to 0 or a negative number to disable size validation.\r\n */\r\n imageSizeLimitBytes?: number;\r\n}\r\n\r\n// ─── Internal context ────────────────────────────────────────────────\r\n\r\ninterface AdapterContext {\r\n client: GoogleGenAI;\r\n validationStrategy: ValidationStrategy;\r\n pricingOverrides: Record<string, ModelPricing>;\r\n imageSizeLimitBytes: number;\r\n}\r\n\r\nfunction pricingFor(ctx: AdapterContext, modelId: string): ModelPricing {\r\n const pricing = ctx.pricingOverrides[modelId] ?? GEMINI_PRICING[modelId];\r\n if (!pricing) {\r\n throw new Error(\r\n `No pricing entry for Google Gemini model \"${modelId}\". Provide pricingOverrides or update src/pricing.ts.`,\r\n );\r\n }\r\n return pricing;\r\n}\r\n\r\n// ─── Public factory ──────────────────────────────────────────────────\r\n\r\nexport interface GoogleAdapter {\r\n name: \"google\";\r\n pricing: Record<string, ModelPricing>;\r\n createLLMPort: (modelId: string, alias: string) => LLMPort;\r\n}\r\n\r\nexport function createGoogleAdapter(opts: GoogleAdapterOptions): GoogleAdapter {\r\n const mergedPricing: Record<string, ModelPricing> = {\r\n ...GEMINI_PRICING,\r\n ...(opts.pricingOverrides ?? {}),\r\n };\r\n const ctx: AdapterContext = {\r\n client: new GoogleGenAI({ apiKey: opts.apiKey }),\r\n validationStrategy: opts.validationStrategy ?? {\r\n kind: \"retry-with-feedback\",\r\n maxAttempts: 2,\r\n includeOriginalError: true,\r\n },\r\n pricingOverrides: opts.pricingOverrides ?? {},\r\n imageSizeLimitBytes: opts.imageSizeLimitBytes ?? 20 * 1024 * 1024,\r\n };\r\n return {\r\n name: \"google\",\r\n pricing: mergedPricing,\r\n createLLMPort: (modelId, alias) => createPort(ctx, modelId, alias),\r\n };\r\n}\r\n\r\n// ─── Port implementation ─────────────────────────────────────────────\r\n\r\nfunction createPort(ctx: AdapterContext, modelId: string, alias: string): LLMPort {\r\n const pricing = pricingFor(ctx, modelId);\r\n\r\n // Image-block validation closure: throws ImageTooLargeError or\r\n // InvalidImageUrlError before the SDK call.\r\n const validateContent = (content: MessageContent): void => {\r\n if (Array.isArray(content)) {\r\n validateImageBlocks(content, {\r\n alias,\r\n ...(ctx.imageSizeLimitBytes > 0 ? { limitBytes: ctx.imageSizeLimitBytes } : {}),\r\n });\r\n }\r\n };\r\n const validateMessages = (messages: ReadonlyArray<{ content: MessageContent }>): void => {\r\n for (const msg of messages) validateContent(msg.content);\r\n };\r\n\r\n return {\r\n async generateText(options: GenerateTextOptions): Promise<GenerateTextResult> {\r\n throwIfAborted(options.signal);\r\n validateContent(options.prompt);\r\n const start = Date.now();\r\n try {\r\n const parts = toGeminiParts2(options.prompt);\r\n const response = await ctx.client.models.generateContent({\r\n model: modelId,\r\n contents: [{ role: \"user\", parts }],\r\n config: {\r\n ...(options.instructions !== undefined\r\n ? { systemInstruction: options.instructions }\r\n : {}),\r\n ...(options.temperature !== undefined ? { temperature: options.temperature } : {}),\r\n ...(options.maxOutputTokens !== undefined\r\n ? { maxOutputTokens: options.maxOutputTokens }\r\n : {}),\r\n ...(options.signal ? { abortSignal: options.signal } : {}),\r\n },\r\n });\r\n const candidate = response.candidates?.[0];\r\n const text = extractGeminiText(candidate?.content?.parts as GeminiPart[] | undefined);\r\n const usage = parseUsage(response);\r\n return {\r\n text,\r\n usage,\r\n cost: computeChatCost(usage, pricing),\r\n modelId: response.modelVersion ?? modelId,\r\n providerAlias: alias,\r\n latencyMs: Date.now() - start,\r\n };\r\n } catch (err) {\r\n throw wrapProviderError(alias, err);\r\n }\r\n },\r\n\r\n async generateStructured<T>(\r\n options: GenerateStructuredOptions<T>,\r\n ): Promise<GenerateStructuredResult<T>> {\r\n throwIfAborted(options.signal);\r\n validateContent(options.prompt);\r\n const start = Date.now();\r\n let attempts = 0;\r\n const maxAttempts =\r\n ctx.validationStrategy.kind === \"retry-with-feedback\"\r\n ? ctx.validationStrategy.maxAttempts\r\n : 1;\r\n\r\n let correctionPrompt: string | null = null;\r\n let lastUsage: TokenUsage = { inputTokens: 0, outputTokens: 0, totalTokens: 0 };\r\n let lastModelId = modelId;\r\n\r\n while (attempts < maxAttempts) {\r\n attempts++;\r\n const userText = correctionPrompt\r\n ? `${stringifyContentBlocks(options.prompt)}\\n\\n${correctionPrompt}`\r\n : `${stringifyContentBlocks(options.prompt)}\\n\\nReply with a single JSON object only. No prose, no code fences.`;\r\n\r\n try {\r\n const response = await ctx.client.models.generateContent({\r\n model: modelId,\r\n contents: [{ role: \"user\", parts: [{ text: userText }] }],\r\n config: {\r\n ...(options.instructions !== undefined\r\n ? { systemInstruction: options.instructions }\r\n : {}),\r\n temperature: options.temperature ?? 0,\r\n ...(options.maxOutputTokens !== undefined\r\n ? { maxOutputTokens: options.maxOutputTokens }\r\n : {}),\r\n responseMimeType: \"application/json\",\r\n ...(options.signal ? { abortSignal: options.signal } : {}),\r\n },\r\n });\r\n const candidate = response.candidates?.[0];\r\n const raw = extractGeminiText(candidate?.content?.parts as GeminiPart[] | undefined);\r\n lastUsage = parseUsage(response);\r\n lastModelId = response.modelVersion ?? modelId;\r\n\r\n const decoded = extractJSON(raw);\r\n let parsed = options.schema.safeParse(decoded);\r\n if (!parsed.success) {\r\n const repaired = attemptValidationRepair(decoded, parsed.error);\r\n const reparsed = options.schema.safeParse(repaired);\r\n if (reparsed.success) parsed = reparsed;\r\n }\r\n if (parsed.success) {\r\n return {\r\n data: parsed.data as T,\r\n usage: lastUsage,\r\n cost: computeChatCost(lastUsage, pricing),\r\n modelId: lastModelId,\r\n providerAlias: alias,\r\n latencyMs: Date.now() - start,\r\n validationAttempts: attempts,\r\n };\r\n }\r\n if (\r\n ctx.validationStrategy.kind === \"retry-with-feedback\" &&\r\n attempts < maxAttempts\r\n ) {\r\n const issues = parsed.error.issues\r\n .map((i) => `- ${i.path.join(\".\") || \"<root>\"}: ${i.message}`)\r\n .join(\"\\n\");\r\n correctionPrompt = `Your previous response failed validation:\\n${issues}\\n\\nReply with a single corrected JSON object only.`;\r\n continue;\r\n }\r\n failValidation(parsed.error.issues, attempts);\r\n } catch (err) {\r\n throw wrapProviderError(alias, err);\r\n }\r\n }\r\n throw new Error(\"generateStructured exhausted attempts\");\r\n },\r\n\r\n async *streamText(options: StreamTextOptions): AsyncIterable<string> {\r\n throwIfAborted(options.signal);\r\n validateContent(options.prompt);\r\n try {\r\n const parts = toGeminiParts2(options.prompt);\r\n const stream = await ctx.client.models.generateContentStream({\r\n model: modelId,\r\n contents: [{ role: \"user\", parts }],\r\n config: {\r\n ...(options.instructions !== undefined\r\n ? { systemInstruction: options.instructions }\r\n : {}),\r\n ...(options.temperature !== undefined ? { temperature: options.temperature } : {}),\r\n ...(options.maxOutputTokens !== undefined\r\n ? { maxOutputTokens: options.maxOutputTokens }\r\n : {}),\r\n ...(options.signal ? { abortSignal: options.signal } : {}),\r\n },\r\n });\r\n for await (const chunk of stream) {\r\n const text = extractGeminiText(\r\n chunk.candidates?.[0]?.content?.parts as GeminiPart[] | undefined,\r\n );\r\n if (text.length > 0) yield text;\r\n }\r\n } catch (err) {\r\n throw wrapProviderError(alias, err);\r\n }\r\n },\r\n\r\n async *streamStructured<T>(options: StreamStructuredOptions<T>): AsyncIterable<Partial<T>> {\r\n throwIfAborted(options.signal);\r\n validateContent(options.prompt);\r\n try {\r\n const stream = await ctx.client.models.generateContentStream({\r\n model: modelId,\r\n contents: [\r\n {\r\n role: \"user\",\r\n parts: [\r\n {\r\n text: `${stringifyContentBlocks(options.prompt)}\\n\\nReply with a single JSON object only. Stream the JSON progressively.`,\r\n },\r\n ],\r\n },\r\n ],\r\n config: {\r\n ...(options.instructions !== undefined\r\n ? { systemInstruction: options.instructions }\r\n : {}),\r\n temperature: options.temperature ?? 0,\r\n ...(options.maxOutputTokens !== undefined\r\n ? { maxOutputTokens: options.maxOutputTokens }\r\n : {}),\r\n responseMimeType: \"application/json\",\r\n ...(options.signal ? { abortSignal: options.signal } : {}),\r\n },\r\n });\r\n let buffer = \"\";\r\n for await (const chunk of stream) {\r\n const text = extractGeminiText(\r\n chunk.candidates?.[0]?.content?.parts as GeminiPart[] | undefined,\r\n );\r\n if (text.length === 0) continue;\r\n buffer += text;\r\n const partial = tryParsePartialJSON(buffer);\r\n if (partial !== null) yield partial as Partial<T>;\r\n }\r\n } catch (err) {\r\n throw wrapProviderError(alias, err);\r\n }\r\n },\r\n\r\n async runAgent(options: RunAgentOptions): Promise<AgentResult> {\r\n throwIfAborted(options.signal);\r\n validateMessages(options.messages);\r\n // v0.1: single-turn agent loop. Gemini's native automatic-function-calling\r\n // multi-turn runAgent ships in v0.2 (matches adapter-vercel's v0.1 shape).\r\n const start = Date.now();\r\n try {\r\n const { systemInstruction, contents } = toGeminiRequest(options.messages);\r\n const response = await ctx.client.models.generateContent({\r\n model: modelId,\r\n contents,\r\n config: {\r\n ...(systemInstruction !== undefined ? { systemInstruction } : {}),\r\n ...(options.instructions !== undefined\r\n ? { systemInstruction: options.instructions }\r\n : {}),\r\n ...(options.signal ? { abortSignal: options.signal } : {}),\r\n },\r\n });\r\n const candidate = response.candidates?.[0];\r\n const text = extractGeminiText(candidate?.content?.parts as GeminiPart[] | undefined);\r\n const usage = parseUsage(response);\r\n const toolCalls: AgentResult[\"toolCalls\"] = [];\r\n // v0.1 stub: we surface no tool calls. Real tool-use is v0.2 scope.\r\n return {\r\n text,\r\n messages: [\r\n ...options.messages,\r\n { role: \"assistant\" as const, content: text },\r\n ],\r\n usage,\r\n cost: computeChatCost(usage, pricing),\r\n modelId: response.modelVersion ?? modelId,\r\n providerAlias: alias,\r\n latencyMs: Date.now() - start,\r\n toolCalls,\r\n stepsTaken: 1,\r\n terminationReason: \"completed\",\r\n };\r\n } catch (err) {\r\n throw wrapProviderError(alias, err);\r\n }\r\n },\r\n };\r\n}\r\n\r\n// ─── Helpers ─────────────────────────────────────────────────────────\r\n\r\ninterface GeminiUsageMetadata {\r\n promptTokenCount?: number;\r\n candidatesTokenCount?: number;\r\n totalTokenCount?: number;\r\n cachedContentTokenCount?: number;\r\n}\r\n\r\ninterface GeminiResponseShape {\r\n usageMetadata?: GeminiUsageMetadata;\r\n}\r\n\r\nfunction parseUsage(response: GeminiResponseShape): TokenUsage {\r\n const m = response.usageMetadata ?? {};\r\n const inputTokens = m.promptTokenCount ?? 0;\r\n const outputTokens = m.candidatesTokenCount ?? 0;\r\n const totalTokens = m.totalTokenCount ?? inputTokens + outputTokens;\r\n const usage: TokenUsage = { inputTokens, outputTokens, totalTokens };\r\n if (m.cachedContentTokenCount !== undefined && m.cachedContentTokenCount > 0) {\r\n usage.cacheReadTokens = m.cachedContentTokenCount;\r\n }\r\n return usage;\r\n}\r\n\r\n// Re-export ContentBlock for the rare adapter user that wants to type-check\r\n// outside of @llm-ports/core. Keeps the import surface symmetric with the\r\n// other adapters.\r\nexport type { ContentBlock };\r\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@llm-ports/adapter-google",
3
- "version": "0.1.0-alpha.5",
3
+ "version": "0.1.0-alpha.7",
4
4
  "description": "Google Gemini adapter for llm-ports — native @google/genai SDK integration with bundled pricing, content-block translation, validation repair, and image-size + URL validation.",
5
5
  "license": "MIT",
6
6
  "author": "Babak Abbaschian",
@@ -20,7 +20,7 @@
20
20
  "README.md"
21
21
  ],
22
22
  "dependencies": {
23
- "@llm-ports/core": "0.1.0-alpha.5"
23
+ "@llm-ports/core": "0.1.0-alpha.7"
24
24
  },
25
25
  "peerDependencies": {
26
26
  "@google/genai": "^2.0.0",