@providerprotocol/ai 0.0.11 → 0.0.13

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.
Files changed (104) hide show
  1. package/dist/anthropic/index.d.ts +51 -15
  2. package/dist/anthropic/index.js +54 -19
  3. package/dist/anthropic/index.js.map +1 -1
  4. package/dist/{chunk-SUNYWHTH.js → chunk-MOU4U3PO.js} +55 -3
  5. package/dist/chunk-MOU4U3PO.js.map +1 -0
  6. package/dist/{chunk-Y6Q7JCNP.js → chunk-MSR5P65T.js} +1 -1
  7. package/dist/chunk-MSR5P65T.js.map +1 -0
  8. package/dist/{chunk-W4BB4BG2.js → chunk-SVYROCLD.js} +31 -11
  9. package/dist/chunk-SVYROCLD.js.map +1 -0
  10. package/dist/chunk-U4JJC2YX.js +234 -0
  11. package/dist/chunk-U4JJC2YX.js.map +1 -0
  12. package/dist/{chunk-X5G4EHL7.js → chunk-Z7RBRCRN.js} +1 -1
  13. package/dist/chunk-Z7RBRCRN.js.map +1 -0
  14. package/dist/google/index.d.ts +376 -7
  15. package/dist/google/index.js +127 -15
  16. package/dist/google/index.js.map +1 -1
  17. package/dist/http/index.d.ts +222 -25
  18. package/dist/http/index.js +3 -3
  19. package/dist/index.d.ts +1482 -198
  20. package/dist/index.js +233 -49
  21. package/dist/index.js.map +1 -1
  22. package/dist/ollama/index.d.ts +92 -20
  23. package/dist/ollama/index.js +17 -7
  24. package/dist/ollama/index.js.map +1 -1
  25. package/dist/openai/index.d.ts +340 -61
  26. package/dist/openai/index.js +57 -15
  27. package/dist/openai/index.js.map +1 -1
  28. package/dist/openrouter/index.d.ts +107 -51
  29. package/dist/openrouter/index.js +36 -8
  30. package/dist/openrouter/index.js.map +1 -1
  31. package/dist/provider-mKkz7Q9U.d.ts +488 -0
  32. package/dist/retry-Dh70lgr0.d.ts +508 -0
  33. package/dist/xai/index.d.ts +97 -22
  34. package/dist/xai/index.js +55 -19
  35. package/dist/xai/index.js.map +1 -1
  36. package/package.json +8 -12
  37. package/dist/chunk-CUCRF5W6.js +0 -136
  38. package/dist/chunk-CUCRF5W6.js.map +0 -1
  39. package/dist/chunk-SUNYWHTH.js.map +0 -1
  40. package/dist/chunk-W4BB4BG2.js.map +0 -1
  41. package/dist/chunk-X5G4EHL7.js.map +0 -1
  42. package/dist/chunk-Y6Q7JCNP.js.map +0 -1
  43. package/dist/provider-CUJWjgNl.d.ts +0 -192
  44. package/dist/retry-I2661_rv.d.ts +0 -118
  45. package/src/anthropic/index.ts +0 -3
  46. package/src/core/image.ts +0 -188
  47. package/src/core/llm.ts +0 -650
  48. package/src/core/provider.ts +0 -92
  49. package/src/google/index.ts +0 -3
  50. package/src/http/errors.ts +0 -112
  51. package/src/http/fetch.ts +0 -210
  52. package/src/http/index.ts +0 -31
  53. package/src/http/keys.ts +0 -136
  54. package/src/http/retry.ts +0 -205
  55. package/src/http/sse.ts +0 -136
  56. package/src/index.ts +0 -32
  57. package/src/ollama/index.ts +0 -3
  58. package/src/openai/index.ts +0 -39
  59. package/src/openrouter/index.ts +0 -11
  60. package/src/providers/anthropic/index.ts +0 -17
  61. package/src/providers/anthropic/llm.ts +0 -196
  62. package/src/providers/anthropic/transform.ts +0 -434
  63. package/src/providers/anthropic/types.ts +0 -213
  64. package/src/providers/google/index.ts +0 -17
  65. package/src/providers/google/llm.ts +0 -203
  66. package/src/providers/google/transform.ts +0 -447
  67. package/src/providers/google/types.ts +0 -214
  68. package/src/providers/ollama/index.ts +0 -43
  69. package/src/providers/ollama/llm.ts +0 -272
  70. package/src/providers/ollama/transform.ts +0 -434
  71. package/src/providers/ollama/types.ts +0 -260
  72. package/src/providers/openai/index.ts +0 -186
  73. package/src/providers/openai/llm.completions.ts +0 -201
  74. package/src/providers/openai/llm.responses.ts +0 -211
  75. package/src/providers/openai/transform.completions.ts +0 -561
  76. package/src/providers/openai/transform.responses.ts +0 -708
  77. package/src/providers/openai/types.ts +0 -1249
  78. package/src/providers/openrouter/index.ts +0 -177
  79. package/src/providers/openrouter/llm.completions.ts +0 -201
  80. package/src/providers/openrouter/llm.responses.ts +0 -211
  81. package/src/providers/openrouter/transform.completions.ts +0 -538
  82. package/src/providers/openrouter/transform.responses.ts +0 -742
  83. package/src/providers/openrouter/types.ts +0 -717
  84. package/src/providers/xai/index.ts +0 -223
  85. package/src/providers/xai/llm.completions.ts +0 -201
  86. package/src/providers/xai/llm.messages.ts +0 -195
  87. package/src/providers/xai/llm.responses.ts +0 -211
  88. package/src/providers/xai/transform.completions.ts +0 -565
  89. package/src/providers/xai/transform.messages.ts +0 -448
  90. package/src/providers/xai/transform.responses.ts +0 -678
  91. package/src/providers/xai/types.ts +0 -938
  92. package/src/types/content.ts +0 -133
  93. package/src/types/errors.ts +0 -85
  94. package/src/types/index.ts +0 -105
  95. package/src/types/llm.ts +0 -211
  96. package/src/types/messages.ts +0 -205
  97. package/src/types/provider.ts +0 -195
  98. package/src/types/schema.ts +0 -58
  99. package/src/types/stream.ts +0 -188
  100. package/src/types/thread.ts +0 -226
  101. package/src/types/tool.ts +0 -88
  102. package/src/types/turn.ts +0 -118
  103. package/src/utils/id.ts +0 -28
  104. package/src/xai/index.ts +0 -41
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/providers/google/transform.ts","../../src/providers/google/llm.ts","../../src/providers/google/index.ts"],"sourcesContent":["import type { LLMRequest, LLMResponse } from '../../types/llm.ts';\nimport type { Message } from '../../types/messages.ts';\nimport type { StreamEvent } from '../../types/stream.ts';\nimport type { Tool, ToolCall } from '../../types/tool.ts';\nimport type { TokenUsage } from '../../types/turn.ts';\nimport type { ContentBlock, TextBlock, ImageBlock } from '../../types/content.ts';\nimport {\n AssistantMessage,\n isUserMessage,\n isAssistantMessage,\n isToolResultMessage,\n} from '../../types/messages.ts';\nimport type {\n GoogleLLMParams,\n GoogleRequest,\n GoogleContent,\n GooglePart,\n GoogleTool,\n GoogleResponse,\n GoogleStreamChunk,\n GoogleFunctionCallPart,\n} from './types.ts';\n\n/**\n * Transform UPP request to Google format\n *\n * Params are spread into generationConfig to allow pass-through of any Google API fields,\n * even those not explicitly defined in our type. This enables developers to\n * use new API features without waiting for library updates.\n */\nexport function transformRequest<TParams extends GoogleLLMParams>(\n request: LLMRequest<TParams>,\n modelId: string\n): GoogleRequest {\n const params = (request.params ?? {}) as GoogleLLMParams;\n\n const googleRequest: GoogleRequest = {\n contents: transformMessages(request.messages),\n };\n\n // System instruction (separate from contents in Google)\n if (request.system) {\n googleRequest.systemInstruction = {\n parts: [{ text: request.system }],\n };\n }\n\n // Spread params into generationConfig to pass through all fields\n const generationConfig: NonNullable<GoogleRequest['generationConfig']> = {\n ...params,\n };\n\n // Protocol-level structured output (overrides provider-specific settings)\n if (request.structure) {\n generationConfig.responseMimeType = 'application/json';\n generationConfig.responseSchema = request.structure as unknown as Record<string, unknown>;\n }\n\n if (Object.keys(generationConfig).length > 0) {\n googleRequest.generationConfig = generationConfig;\n }\n\n // Tools come from request, not params\n if (request.tools && request.tools.length > 0) {\n googleRequest.tools = [\n {\n functionDeclarations: request.tools.map(transformTool),\n },\n ];\n }\n\n return googleRequest;\n}\n\n/**\n * Filter to only valid content blocks with a type property\n */\nfunction filterValidContent<T extends { type?: string }>(content: T[]): T[] {\n return content.filter((c) => c && typeof c.type === 'string');\n}\n\n/**\n * Transform UPP Messages to Google contents\n */\nfunction transformMessages(messages: Message[]): GoogleContent[] {\n const contents: GoogleContent[] = [];\n\n for (const msg of messages) {\n if (isUserMessage(msg)) {\n const validContent = filterValidContent(msg.content);\n const parts = validContent.map(transformContentBlock);\n // Google requires at least one part - add placeholder if empty\n if (parts.length === 0) {\n parts.push({ text: '' });\n }\n contents.push({\n role: 'user',\n parts,\n });\n } else if (isAssistantMessage(msg)) {\n const validContent = filterValidContent(msg.content);\n const parts: GooglePart[] = validContent.map(transformContentBlock);\n\n // Add function calls - use stored parts with thought signatures if available\n const googleMeta = msg.metadata?.google as {\n functionCallParts?: Array<{\n name: string;\n args: Record<string, unknown>;\n thoughtSignature?: string;\n }>;\n } | undefined;\n\n if (googleMeta?.functionCallParts && googleMeta.functionCallParts.length > 0) {\n // Use stored function call parts with thought signatures\n for (const fc of googleMeta.functionCallParts) {\n const part: GoogleFunctionCallPart = {\n functionCall: {\n name: fc.name,\n args: fc.args,\n },\n };\n if (fc.thoughtSignature) {\n part.thoughtSignature = fc.thoughtSignature;\n }\n parts.push(part);\n }\n } else if (msg.toolCalls) {\n // Fallback: reconstruct from tool calls (no thought signatures)\n for (const call of msg.toolCalls) {\n parts.push({\n functionCall: {\n name: call.toolName,\n args: call.arguments,\n },\n });\n }\n }\n\n // Google requires at least one part - add placeholder if empty\n if (parts.length === 0) {\n parts.push({ text: '' });\n }\n\n contents.push({\n role: 'model',\n parts,\n });\n } else if (isToolResultMessage(msg)) {\n // Function results are sent as user messages in Google\n contents.push({\n role: 'user',\n parts: msg.results.map((result) => ({\n functionResponse: {\n name: result.toolCallId, // Google uses the function name, but we store it in toolCallId\n response:\n typeof result.result === 'object'\n ? (result.result as Record<string, unknown>)\n : { result: result.result },\n },\n })),\n });\n }\n }\n\n return contents;\n}\n\n/**\n * Transform a content block to Google format\n */\nfunction transformContentBlock(block: ContentBlock): GooglePart {\n switch (block.type) {\n case 'text':\n return { text: block.text };\n\n case 'image': {\n const imageBlock = block as ImageBlock;\n let data: string;\n\n if (imageBlock.source.type === 'base64') {\n data = imageBlock.source.data;\n } else if (imageBlock.source.type === 'bytes') {\n data = btoa(\n Array.from(imageBlock.source.data)\n .map((b) => String.fromCharCode(b))\n .join('')\n );\n } else {\n throw new Error('Google API does not support URL image sources directly');\n }\n\n return {\n inlineData: {\n mimeType: imageBlock.mimeType,\n data,\n },\n };\n }\n\n default:\n throw new Error(`Unsupported content type: ${block.type}`);\n }\n}\n\n/**\n * Transform a UPP Tool to Google format\n */\nfunction transformTool(tool: Tool): GoogleTool['functionDeclarations'][0] {\n return {\n name: tool.name,\n description: tool.description,\n parameters: {\n type: 'object',\n properties: tool.parameters.properties,\n required: tool.parameters.required,\n },\n };\n}\n\n/**\n * Transform Google response to UPP LLMResponse\n */\nexport function transformResponse(data: GoogleResponse): LLMResponse {\n const candidate = data.candidates?.[0];\n if (!candidate) {\n throw new Error('No candidates in Google response');\n }\n\n const textContent: TextBlock[] = [];\n const toolCalls: ToolCall[] = [];\n let structuredData: unknown;\n // Store original function call parts with thought signatures for echoing back\n const functionCallParts: Array<{\n name: string;\n args: Record<string, unknown>;\n thoughtSignature?: string;\n }> = [];\n\n for (const part of candidate.content.parts) {\n if ('text' in part) {\n textContent.push({ type: 'text', text: part.text });\n // Try to parse as JSON for structured output (native JSON mode)\n if (structuredData === undefined) {\n try {\n structuredData = JSON.parse(part.text);\n } catch {\n // Not valid JSON - that's fine, might not be structured output\n }\n }\n } else if ('functionCall' in part) {\n const fc = part as GoogleFunctionCallPart;\n toolCalls.push({\n toolCallId: fc.functionCall.name, // Google doesn't have call IDs, use name\n toolName: fc.functionCall.name,\n arguments: fc.functionCall.args,\n });\n // Store the full part including thought signature\n functionCallParts.push({\n name: fc.functionCall.name,\n args: fc.functionCall.args,\n thoughtSignature: fc.thoughtSignature,\n });\n }\n }\n\n const message = new AssistantMessage(\n textContent,\n toolCalls.length > 0 ? toolCalls : undefined,\n {\n metadata: {\n google: {\n finishReason: candidate.finishReason,\n safetyRatings: candidate.safetyRatings,\n // Store function call parts with thought signatures for multi-turn\n functionCallParts: functionCallParts.length > 0 ? functionCallParts : undefined,\n },\n },\n }\n );\n\n const usage: TokenUsage = {\n inputTokens: data.usageMetadata?.promptTokenCount ?? 0,\n outputTokens: data.usageMetadata?.candidatesTokenCount ?? 0,\n totalTokens: data.usageMetadata?.totalTokenCount ?? 0,\n };\n\n return {\n message,\n usage,\n stopReason: candidate.finishReason ?? 'STOP',\n data: structuredData,\n };\n}\n\n/**\n * State for accumulating streaming response\n */\nexport interface StreamState {\n content: string;\n toolCalls: Array<{ name: string; args: Record<string, unknown>; thoughtSignature?: string }>;\n finishReason: string | null;\n inputTokens: number;\n outputTokens: number;\n isFirstChunk: boolean;\n}\n\n/**\n * Create initial stream state\n */\nexport function createStreamState(): StreamState {\n return {\n content: '',\n toolCalls: [],\n finishReason: null,\n inputTokens: 0,\n outputTokens: 0,\n isFirstChunk: true,\n };\n}\n\n/**\n * Transform Google stream chunk to UPP StreamEvents\n */\nexport function transformStreamChunk(\n chunk: GoogleStreamChunk,\n state: StreamState\n): StreamEvent[] {\n const events: StreamEvent[] = [];\n\n // First chunk - emit message start\n if (state.isFirstChunk) {\n events.push({ type: 'message_start', index: 0, delta: {} });\n state.isFirstChunk = false;\n }\n\n // Usage metadata\n if (chunk.usageMetadata) {\n state.inputTokens = chunk.usageMetadata.promptTokenCount;\n state.outputTokens = chunk.usageMetadata.candidatesTokenCount;\n }\n\n const candidate = chunk.candidates?.[0];\n if (!candidate) {\n return events;\n }\n\n // Process parts\n for (const part of candidate.content?.parts ?? []) {\n if ('text' in part) {\n state.content += part.text;\n events.push({\n type: 'text_delta',\n index: 0,\n delta: { text: part.text },\n });\n } else if ('functionCall' in part) {\n const fc = part as GoogleFunctionCallPart;\n // Store with thought signature for echoing back\n state.toolCalls.push({\n name: fc.functionCall.name,\n args: fc.functionCall.args,\n thoughtSignature: fc.thoughtSignature,\n });\n events.push({\n type: 'tool_call_delta',\n index: state.toolCalls.length - 1,\n delta: {\n toolCallId: fc.functionCall.name,\n toolName: fc.functionCall.name,\n argumentsJson: JSON.stringify(fc.functionCall.args),\n },\n });\n }\n }\n\n // Finish reason\n if (candidate.finishReason) {\n state.finishReason = candidate.finishReason;\n events.push({ type: 'message_stop', index: 0, delta: {} });\n }\n\n return events;\n}\n\n/**\n * Build LLMResponse from accumulated stream state\n */\nexport function buildResponseFromState(state: StreamState): LLMResponse {\n const textContent: TextBlock[] = [];\n const toolCalls: ToolCall[] = [];\n let structuredData: unknown;\n const functionCallParts: Array<{\n name: string;\n args: Record<string, unknown>;\n thoughtSignature?: string;\n }> = [];\n\n if (state.content) {\n textContent.push({ type: 'text', text: state.content });\n // Try to parse as JSON for structured output (native JSON mode)\n try {\n structuredData = JSON.parse(state.content);\n } catch {\n // Not valid JSON - that's fine, might not be structured output\n }\n }\n\n for (const tc of state.toolCalls) {\n toolCalls.push({\n toolCallId: tc.name,\n toolName: tc.name,\n arguments: tc.args,\n });\n functionCallParts.push({\n name: tc.name,\n args: tc.args,\n thoughtSignature: tc.thoughtSignature,\n });\n }\n\n const message = new AssistantMessage(\n textContent,\n toolCalls.length > 0 ? toolCalls : undefined,\n {\n metadata: {\n google: {\n finishReason: state.finishReason,\n // Store function call parts with thought signatures for multi-turn\n functionCallParts: functionCallParts.length > 0 ? functionCallParts : undefined,\n },\n },\n }\n );\n\n const usage: TokenUsage = {\n inputTokens: state.inputTokens,\n outputTokens: state.outputTokens,\n totalTokens: state.inputTokens + state.outputTokens,\n };\n\n return {\n message,\n usage,\n stopReason: state.finishReason ?? 'STOP',\n data: structuredData,\n };\n}\n","import type { LLMHandler, BoundLLMModel, LLMRequest, LLMResponse, LLMStreamResult, LLMCapabilities } from '../../types/llm.ts';\nimport type { StreamEvent } from '../../types/stream.ts';\nimport type { LLMProvider } from '../../types/provider.ts';\nimport { UPPError } from '../../types/errors.ts';\nimport { resolveApiKey } from '../../http/keys.ts';\nimport { doFetch, doStreamFetch } from '../../http/fetch.ts';\nimport { parseSSEStream } from '../../http/sse.ts';\nimport { normalizeHttpError } from '../../http/errors.ts';\nimport type { GoogleLLMParams, GoogleResponse, GoogleStreamChunk } from './types.ts';\nimport {\n transformRequest,\n transformResponse,\n transformStreamChunk,\n createStreamState,\n buildResponseFromState,\n} from './transform.ts';\n\nconst GOOGLE_API_BASE = 'https://generativelanguage.googleapis.com/v1beta';\n\n/**\n * Google API capabilities\n */\nconst GOOGLE_CAPABILITIES: LLMCapabilities = {\n streaming: true,\n tools: true,\n structuredOutput: true,\n imageInput: true,\n videoInput: true,\n audioInput: true,\n};\n\n/**\n * Build Google API URL for a model\n */\nfunction buildUrl(modelId: string, action: 'generateContent' | 'streamGenerateContent', apiKey: string): string {\n const base = `${GOOGLE_API_BASE}/models/${modelId}:${action}`;\n return `${base}?key=${apiKey}`;\n}\n\n/**\n * Create Google LLM handler\n */\nexport function createLLMHandler(): LLMHandler<GoogleLLMParams> {\n // Provider reference injected by createProvider() after construction\n let providerRef: LLMProvider<GoogleLLMParams> | null = null;\n\n return {\n _setProvider(provider: LLMProvider<GoogleLLMParams>) {\n providerRef = provider;\n },\n\n bind(modelId: string): BoundLLMModel<GoogleLLMParams> {\n // Use the injected provider reference (set by createProvider)\n if (!providerRef) {\n throw new UPPError(\n 'Provider reference not set. Handler must be used with createProvider().',\n 'INVALID_REQUEST',\n 'google',\n 'llm'\n );\n }\n\n const model: BoundLLMModel<GoogleLLMParams> = {\n modelId,\n capabilities: GOOGLE_CAPABILITIES,\n\n get provider(): LLMProvider<GoogleLLMParams> {\n return providerRef!;\n },\n\n async complete(request: LLMRequest<GoogleLLMParams>): Promise<LLMResponse> {\n const apiKey = await resolveApiKey(\n request.config,\n 'GOOGLE_API_KEY',\n 'google',\n 'llm'\n );\n\n const url = request.config.baseUrl\n ? `${request.config.baseUrl}/models/${modelId}:generateContent?key=${apiKey}`\n : buildUrl(modelId, 'generateContent', apiKey);\n\n const body = transformRequest(request, modelId);\n\n const response = await doFetch(\n url,\n {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify(body),\n signal: request.signal,\n },\n request.config,\n 'google',\n 'llm'\n );\n\n const data = (await response.json()) as GoogleResponse;\n return transformResponse(data);\n },\n\n stream(request: LLMRequest<GoogleLLMParams>): LLMStreamResult {\n const state = createStreamState();\n let responseResolve: (value: LLMResponse) => void;\n let responseReject: (error: Error) => void;\n\n const responsePromise = new Promise<LLMResponse>((resolve, reject) => {\n responseResolve = resolve;\n responseReject = reject;\n });\n\n async function* generateEvents(): AsyncGenerator<StreamEvent, void, unknown> {\n try {\n const apiKey = await resolveApiKey(\n request.config,\n 'GOOGLE_API_KEY',\n 'google',\n 'llm'\n );\n\n const url = request.config.baseUrl\n ? `${request.config.baseUrl}/models/${modelId}:streamGenerateContent?alt=sse&key=${apiKey}`\n : `${buildUrl(modelId, 'streamGenerateContent', apiKey)}&alt=sse`;\n\n const body = transformRequest(request, modelId);\n\n const response = await doStreamFetch(\n url,\n {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify(body),\n signal: request.signal,\n },\n request.config,\n 'google',\n 'llm'\n );\n\n if (!response.ok) {\n const error = await normalizeHttpError(response, 'google', 'llm');\n responseReject(error);\n throw error;\n }\n\n if (!response.body) {\n const error = new UPPError(\n 'No response body for streaming request',\n 'PROVIDER_ERROR',\n 'google',\n 'llm'\n );\n responseReject(error);\n throw error;\n }\n\n for await (const data of parseSSEStream(response.body)) {\n if (typeof data === 'object' && data !== null) {\n const chunk = data as GoogleStreamChunk;\n\n // Check for error\n if ('error' in chunk) {\n const error = new UPPError(\n (chunk as any).error.message,\n 'PROVIDER_ERROR',\n 'google',\n 'llm'\n );\n responseReject(error);\n throw error;\n }\n\n const events = transformStreamChunk(chunk, state);\n for (const event of events) {\n yield event;\n }\n }\n }\n\n responseResolve(buildResponseFromState(state));\n } catch (error) {\n responseReject(error as Error);\n throw error;\n }\n }\n\n return {\n [Symbol.asyncIterator]() {\n return generateEvents();\n },\n response: responsePromise,\n };\n },\n };\n\n return model;\n },\n };\n}\n","import { createProvider } from '../../core/provider.ts';\nimport { createLLMHandler } from './llm.ts';\n\n/**\n * Google Gemini provider\n * Supports LLM modality with Gemini models\n */\nexport const google = createProvider({\n name: 'google',\n version: '1.0.0',\n modalities: {\n llm: createLLMHandler(),\n },\n});\n\n// Re-export types\nexport type { GoogleLLMParams } from './types.ts';\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../src/providers/google/transform.ts","../../src/providers/google/llm.ts","../../src/providers/google/cache.ts","../../src/providers/google/index.ts"],"sourcesContent":["/**\n * @fileoverview Transformation functions between UPP format and Google Gemini API format.\n *\n * This module handles the bidirectional conversion of requests, responses, and\n * streaming chunks between the Unified Provider Protocol (UPP) format and\n * Google's Generative Language API format.\n *\n * Key transformations:\n * - UPP messages with content blocks to Google's parts-based content structure\n * - UPP tools to Google's functionDeclarations format\n * - Google responses back to UPP LLMResponse with proper message types\n * - Streaming chunks to UPP StreamEvents\n */\n\nimport type { LLMRequest, LLMResponse } from '../../types/llm.ts';\nimport type { Message } from '../../types/messages.ts';\nimport type { StreamEvent } from '../../types/stream.ts';\nimport type { Tool, ToolCall } from '../../types/tool.ts';\nimport type { TokenUsage } from '../../types/turn.ts';\nimport type { ContentBlock, TextBlock, ImageBlock } from '../../types/content.ts';\nimport {\n AssistantMessage,\n isUserMessage,\n isAssistantMessage,\n isToolResultMessage,\n} from '../../types/messages.ts';\nimport type {\n GoogleLLMParams,\n GoogleRequest,\n GoogleContent,\n GooglePart,\n GoogleTool,\n GoogleResponse,\n GoogleStreamChunk,\n GoogleFunctionCallPart,\n} from './types.ts';\n\n/**\n * Transforms a UPP LLM request into Google Gemini API format.\n *\n * Converts the UPP message structure, system prompt, tools, and generation\n * parameters into Google's expected request body format. Provider-specific\n * parameters are passed through to `generationConfig` to support new API\n * features without library updates.\n *\n * @typeParam TParams - Type extending GoogleLLMParams for provider-specific options\n * @param request - The UPP-formatted LLM request\n * @param modelId - The target Gemini model identifier\n * @returns Google API request body ready for submission\n *\n * @example\n * ```typescript\n * const googleRequest = transformRequest({\n * messages: [{ role: 'user', content: [{ type: 'text', text: 'Hello' }] }],\n * system: 'You are a helpful assistant',\n * params: { temperature: 0.7 },\n * config: { apiKey: '...' },\n * }, 'gemini-1.5-pro');\n * ```\n */\nexport function transformRequest<TParams extends GoogleLLMParams>(\n request: LLMRequest<TParams>,\n modelId: string\n): GoogleRequest {\n const params = (request.params ?? {}) as GoogleLLMParams;\n const { cachedContent, ...generationParams } = params;\n\n const googleRequest: GoogleRequest = {\n contents: transformMessages(request.messages),\n };\n\n if (request.system) {\n if (typeof request.system === 'string') {\n googleRequest.systemInstruction = {\n parts: [{ text: request.system }],\n };\n } else {\n // Array format - pass through as parts: [{text: '...'}, {text: '...'}]\n googleRequest.systemInstruction = {\n parts: request.system as GooglePart[],\n };\n }\n }\n\n const generationConfig: NonNullable<GoogleRequest['generationConfig']> = {\n ...generationParams,\n };\n\n if (request.structure) {\n generationConfig.responseMimeType = 'application/json';\n generationConfig.responseSchema = request.structure as unknown as Record<string, unknown>;\n }\n\n if (Object.keys(generationConfig).length > 0) {\n googleRequest.generationConfig = generationConfig;\n }\n\n if (request.tools && request.tools.length > 0) {\n googleRequest.tools = [\n {\n functionDeclarations: request.tools.map(transformTool),\n },\n ];\n }\n\n if (cachedContent) {\n googleRequest.cachedContent = cachedContent;\n }\n\n return googleRequest;\n}\n\n/**\n * Filters content blocks to only those with a valid type property.\n *\n * @typeParam T - Content block type with optional type property\n * @param content - Array of content blocks to filter\n * @returns Filtered array containing only blocks with string type property\n */\nfunction filterValidContent<T extends { type?: string }>(content: T[]): T[] {\n return content.filter((c) => c && typeof c.type === 'string');\n}\n\n/**\n * Transforms UPP message array to Google's content format.\n *\n * Handles the conversion of user messages, assistant messages (including\n * tool calls), and tool result messages to Google's role-based content\n * structure with parts arrays.\n *\n * @param messages - Array of UPP-formatted messages\n * @returns Array of Google content objects with role and parts\n */\nfunction transformMessages(messages: Message[]): GoogleContent[] {\n const contents: GoogleContent[] = [];\n\n for (const msg of messages) {\n if (isUserMessage(msg)) {\n const validContent = filterValidContent(msg.content);\n const parts = validContent.map(transformContentBlock);\n if (parts.length === 0) {\n parts.push({ text: '' });\n }\n contents.push({\n role: 'user',\n parts,\n });\n } else if (isAssistantMessage(msg)) {\n const validContent = filterValidContent(msg.content);\n const parts: GooglePart[] = validContent.map(transformContentBlock);\n\n const googleMeta = msg.metadata?.google as {\n functionCallParts?: Array<{\n name: string;\n args: Record<string, unknown>;\n thoughtSignature?: string;\n }>;\n } | undefined;\n\n if (googleMeta?.functionCallParts && googleMeta.functionCallParts.length > 0) {\n for (const fc of googleMeta.functionCallParts) {\n const part: GoogleFunctionCallPart = {\n functionCall: {\n name: fc.name,\n args: fc.args,\n },\n };\n if (fc.thoughtSignature) {\n part.thoughtSignature = fc.thoughtSignature;\n }\n parts.push(part);\n }\n } else if (msg.toolCalls) {\n for (const call of msg.toolCalls) {\n parts.push({\n functionCall: {\n name: call.toolName,\n args: call.arguments,\n },\n });\n }\n }\n\n if (parts.length === 0) {\n parts.push({ text: '' });\n }\n\n contents.push({\n role: 'model',\n parts,\n });\n } else if (isToolResultMessage(msg)) {\n contents.push({\n role: 'user',\n parts: msg.results.map((result) => ({\n functionResponse: {\n name: result.toolCallId,\n response:\n typeof result.result === 'object'\n ? (result.result as Record<string, unknown>)\n : { result: result.result },\n },\n })),\n });\n }\n }\n\n return contents;\n}\n\n/**\n * Transforms a UPP content block to a Google part.\n *\n * Supports text and image content types. Images must be base64 or bytes\n * encoded; URL sources are not supported by Google's API directly.\n *\n * @param block - The UPP content block to transform\n * @returns Google-formatted part object\n * @throws Error if the content type is unsupported or if an image uses URL source\n */\nfunction transformContentBlock(block: ContentBlock): GooglePart {\n switch (block.type) {\n case 'text':\n return { text: block.text };\n\n case 'image': {\n const imageBlock = block as ImageBlock;\n let data: string;\n\n if (imageBlock.source.type === 'base64') {\n data = imageBlock.source.data;\n } else if (imageBlock.source.type === 'bytes') {\n data = btoa(\n Array.from(imageBlock.source.data)\n .map((b) => String.fromCharCode(b))\n .join('')\n );\n } else {\n throw new Error('Google API does not support URL image sources directly');\n }\n\n return {\n inlineData: {\n mimeType: imageBlock.mimeType,\n data,\n },\n };\n }\n\n default:\n throw new Error(`Unsupported content type: ${block.type}`);\n }\n}\n\n/**\n * Transforms a UPP tool definition to Google's function declaration format.\n *\n * @param tool - The UPP tool definition with name, description, and parameters\n * @returns Google function declaration object\n */\nfunction transformTool(tool: Tool): GoogleTool['functionDeclarations'][0] {\n return {\n name: tool.name,\n description: tool.description,\n parameters: {\n type: 'object',\n properties: tool.parameters.properties,\n required: tool.parameters.required,\n },\n };\n}\n\n/**\n * Transforms a Google API response to UPP LLMResponse format.\n *\n * Extracts text content, tool calls, structured data, and usage metadata\n * from Google's response format. Preserves Google-specific metadata like\n * finish reason, safety ratings, and thought signatures for multi-turn\n * tool call conversations.\n *\n * @param data - The raw Google API response\n * @returns Normalized UPP LLMResponse with message, usage, and stop reason\n * @throws Error if response contains no candidates\n *\n * @example\n * ```typescript\n * const response = await fetch(googleApiUrl, options);\n * const data = await response.json();\n * const uppResponse = transformResponse(data);\n * console.log(uppResponse.message.content);\n * ```\n */\nexport function transformResponse(data: GoogleResponse): LLMResponse {\n const candidate = data.candidates?.[0];\n if (!candidate) {\n throw new Error('No candidates in Google response');\n }\n\n const textContent: TextBlock[] = [];\n const toolCalls: ToolCall[] = [];\n let structuredData: unknown;\n const functionCallParts: Array<{\n name: string;\n args: Record<string, unknown>;\n thoughtSignature?: string;\n }> = [];\n\n for (const part of candidate.content.parts) {\n if ('text' in part) {\n textContent.push({ type: 'text', text: part.text });\n if (structuredData === undefined) {\n try {\n structuredData = JSON.parse(part.text);\n } catch {\n // Not JSON - may not be structured output\n }\n }\n } else if ('functionCall' in part) {\n const fc = part as GoogleFunctionCallPart;\n toolCalls.push({\n toolCallId: fc.functionCall.name,\n toolName: fc.functionCall.name,\n arguments: fc.functionCall.args,\n });\n functionCallParts.push({\n name: fc.functionCall.name,\n args: fc.functionCall.args,\n thoughtSignature: fc.thoughtSignature,\n });\n }\n }\n\n const message = new AssistantMessage(\n textContent,\n toolCalls.length > 0 ? toolCalls : undefined,\n {\n metadata: {\n google: {\n finishReason: candidate.finishReason,\n safetyRatings: candidate.safetyRatings,\n functionCallParts: functionCallParts.length > 0 ? functionCallParts : undefined,\n },\n },\n }\n );\n\n const usage: TokenUsage = {\n inputTokens: data.usageMetadata?.promptTokenCount ?? 0,\n outputTokens: data.usageMetadata?.candidatesTokenCount ?? 0,\n totalTokens: data.usageMetadata?.totalTokenCount ?? 0,\n cacheReadTokens: data.usageMetadata?.cachedContentTokenCount ?? 0,\n cacheWriteTokens: 0,\n };\n\n return {\n message,\n usage,\n stopReason: candidate.finishReason ?? 'STOP',\n data: structuredData,\n };\n}\n\n/**\n * Accumulator state for streaming responses.\n *\n * Tracks partial content, tool calls, token counts, and stream lifecycle\n * as chunks arrive from the Google streaming API.\n */\nexport interface StreamState {\n /** Accumulated text content from all chunks. */\n content: string;\n /** Accumulated tool calls with their arguments and optional thought signatures. */\n toolCalls: Array<{ name: string; args: Record<string, unknown>; thoughtSignature?: string }>;\n /** The finish reason from the final chunk, if received. */\n finishReason: string | null;\n /** Total input tokens reported by the API. */\n inputTokens: number;\n /** Total output tokens reported by the API. */\n outputTokens: number;\n /** Number of tokens read from cached content. */\n cacheReadTokens: number;\n /** Flag indicating whether this is the first chunk (for message_start event). */\n isFirstChunk: boolean;\n}\n\n/**\n * Creates a fresh stream state for accumulating streaming responses.\n *\n * @returns Initialized StreamState with empty content and default values\n */\nexport function createStreamState(): StreamState {\n return {\n content: '',\n toolCalls: [],\n finishReason: null,\n inputTokens: 0,\n outputTokens: 0,\n cacheReadTokens: 0,\n isFirstChunk: true,\n };\n}\n\n/**\n * Transforms a Google streaming chunk to UPP StreamEvent array.\n *\n * Processes each streaming chunk, updating the accumulator state and\n * generating appropriate stream events for text deltas, tool calls,\n * and message lifecycle (start/stop).\n *\n * @param chunk - The Google streaming response chunk\n * @param state - Mutable accumulator state updated by this function\n * @returns Array of UPP StreamEvents generated from this chunk\n */\nexport function transformStreamChunk(\n chunk: GoogleStreamChunk,\n state: StreamState\n): StreamEvent[] {\n const events: StreamEvent[] = [];\n\n if (state.isFirstChunk) {\n events.push({ type: 'message_start', index: 0, delta: {} });\n state.isFirstChunk = false;\n }\n\n if (chunk.usageMetadata) {\n state.inputTokens = chunk.usageMetadata.promptTokenCount;\n state.outputTokens = chunk.usageMetadata.candidatesTokenCount;\n state.cacheReadTokens = chunk.usageMetadata.cachedContentTokenCount ?? 0;\n }\n\n const candidate = chunk.candidates?.[0];\n if (!candidate) {\n return events;\n }\n\n for (const part of candidate.content?.parts ?? []) {\n if ('text' in part) {\n state.content += part.text;\n events.push({\n type: 'text_delta',\n index: 0,\n delta: { text: part.text },\n });\n } else if ('functionCall' in part) {\n const fc = part as GoogleFunctionCallPart;\n state.toolCalls.push({\n name: fc.functionCall.name,\n args: fc.functionCall.args,\n thoughtSignature: fc.thoughtSignature,\n });\n events.push({\n type: 'tool_call_delta',\n index: state.toolCalls.length - 1,\n delta: {\n toolCallId: fc.functionCall.name,\n toolName: fc.functionCall.name,\n argumentsJson: JSON.stringify(fc.functionCall.args),\n },\n });\n }\n }\n\n if (candidate.finishReason) {\n state.finishReason = candidate.finishReason;\n events.push({ type: 'message_stop', index: 0, delta: {} });\n }\n\n return events;\n}\n\n/**\n * Constructs a complete LLMResponse from accumulated stream state.\n *\n * Called after streaming completes to build the final response object\n * with all accumulated content, tool calls, usage statistics, and metadata.\n *\n * @param state - The final accumulated stream state\n * @returns Complete UPP LLMResponse\n */\nexport function buildResponseFromState(state: StreamState): LLMResponse {\n const textContent: TextBlock[] = [];\n const toolCalls: ToolCall[] = [];\n let structuredData: unknown;\n const functionCallParts: Array<{\n name: string;\n args: Record<string, unknown>;\n thoughtSignature?: string;\n }> = [];\n\n if (state.content) {\n textContent.push({ type: 'text', text: state.content });\n try {\n structuredData = JSON.parse(state.content);\n } catch {\n // Not JSON - may not be structured output\n }\n }\n\n for (const tc of state.toolCalls) {\n toolCalls.push({\n toolCallId: tc.name,\n toolName: tc.name,\n arguments: tc.args,\n });\n functionCallParts.push({\n name: tc.name,\n args: tc.args,\n thoughtSignature: tc.thoughtSignature,\n });\n }\n\n const message = new AssistantMessage(\n textContent,\n toolCalls.length > 0 ? toolCalls : undefined,\n {\n metadata: {\n google: {\n finishReason: state.finishReason,\n functionCallParts: functionCallParts.length > 0 ? functionCallParts : undefined,\n },\n },\n }\n );\n\n const usage: TokenUsage = {\n inputTokens: state.inputTokens,\n outputTokens: state.outputTokens,\n totalTokens: state.inputTokens + state.outputTokens,\n cacheReadTokens: state.cacheReadTokens,\n cacheWriteTokens: 0,\n };\n\n return {\n message,\n usage,\n stopReason: state.finishReason ?? 'STOP',\n data: structuredData,\n };\n}\n","import type { LLMHandler, BoundLLMModel, LLMRequest, LLMResponse, LLMStreamResult, LLMCapabilities } from '../../types/llm.ts';\nimport type { StreamEvent } from '../../types/stream.ts';\nimport type { LLMProvider } from '../../types/provider.ts';\nimport { UPPError } from '../../types/errors.ts';\nimport { resolveApiKey } from '../../http/keys.ts';\nimport { doFetch, doStreamFetch } from '../../http/fetch.ts';\nimport { parseSSEStream } from '../../http/sse.ts';\nimport { normalizeHttpError } from '../../http/errors.ts';\nimport type { GoogleLLMParams, GoogleResponse, GoogleStreamChunk } from './types.ts';\nimport {\n transformRequest,\n transformResponse,\n transformStreamChunk,\n createStreamState,\n buildResponseFromState,\n} from './transform.ts';\n\n/** Base URL for the Google Generative Language API (v1beta). */\nconst GOOGLE_API_BASE = 'https://generativelanguage.googleapis.com/v1beta';\n\n/**\n * Capability flags for the Google Gemini API.\n *\n * Gemini models support streaming responses, function/tool calling,\n * structured JSON output, and multimodal inputs including images,\n * video, and audio.\n */\nconst GOOGLE_CAPABILITIES: LLMCapabilities = {\n streaming: true,\n tools: true,\n structuredOutput: true,\n imageInput: true,\n videoInput: true,\n audioInput: true,\n};\n\n/**\n * Constructs the Google API endpoint URL for a specific model and action.\n *\n * @param modelId - The Gemini model identifier (e.g., 'gemini-1.5-pro')\n * @param action - The API action to perform\n * @param apiKey - The Google API key for authentication\n * @returns Fully qualified URL with API key as query parameter\n */\nfunction buildUrl(modelId: string, action: 'generateContent' | 'streamGenerateContent', apiKey: string): string {\n const base = `${GOOGLE_API_BASE}/models/${modelId}:${action}`;\n return `${base}?key=${apiKey}`;\n}\n\n/**\n * Creates an LLM handler for Google Gemini models.\n *\n * The handler implements the UPP LLMHandler interface, providing `bind()`\n * to create model instances that support both synchronous completion and\n * streaming responses.\n *\n * @returns An LLMHandler configured for Google Gemini API\n *\n * @example\n * ```typescript\n * const handler = createLLMHandler();\n * const model = handler.bind('gemini-1.5-pro');\n *\n * const response = await model.complete({\n * messages: [...],\n * config: { apiKey: 'your-api-key' },\n * });\n * ```\n */\nexport function createLLMHandler(): LLMHandler<GoogleLLMParams> {\n let providerRef: LLMProvider<GoogleLLMParams> | null = null;\n\n return {\n _setProvider(provider: LLMProvider<GoogleLLMParams>) {\n providerRef = provider;\n },\n\n bind(modelId: string): BoundLLMModel<GoogleLLMParams> {\n if (!providerRef) {\n throw new UPPError(\n 'Provider reference not set. Handler must be used with createProvider().',\n 'INVALID_REQUEST',\n 'google',\n 'llm'\n );\n }\n\n const model: BoundLLMModel<GoogleLLMParams> = {\n modelId,\n capabilities: GOOGLE_CAPABILITIES,\n\n get provider(): LLMProvider<GoogleLLMParams> {\n return providerRef!;\n },\n\n async complete(request: LLMRequest<GoogleLLMParams>): Promise<LLMResponse> {\n const apiKey = await resolveApiKey(\n request.config,\n 'GOOGLE_API_KEY',\n 'google',\n 'llm'\n );\n\n const url = request.config.baseUrl\n ? `${request.config.baseUrl}/models/${modelId}:generateContent?key=${apiKey}`\n : buildUrl(modelId, 'generateContent', apiKey);\n\n const body = transformRequest(request, modelId);\n\n const response = await doFetch(\n url,\n {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify(body),\n signal: request.signal,\n },\n request.config,\n 'google',\n 'llm'\n );\n\n const data = (await response.json()) as GoogleResponse;\n return transformResponse(data);\n },\n\n stream(request: LLMRequest<GoogleLLMParams>): LLMStreamResult {\n const state = createStreamState();\n let responseResolve: (value: LLMResponse) => void;\n let responseReject: (error: Error) => void;\n\n const responsePromise = new Promise<LLMResponse>((resolve, reject) => {\n responseResolve = resolve;\n responseReject = reject;\n });\n\n async function* generateEvents(): AsyncGenerator<StreamEvent, void, unknown> {\n try {\n const apiKey = await resolveApiKey(\n request.config,\n 'GOOGLE_API_KEY',\n 'google',\n 'llm'\n );\n\n const url = request.config.baseUrl\n ? `${request.config.baseUrl}/models/${modelId}:streamGenerateContent?alt=sse&key=${apiKey}`\n : `${buildUrl(modelId, 'streamGenerateContent', apiKey)}&alt=sse`;\n\n const body = transformRequest(request, modelId);\n\n const response = await doStreamFetch(\n url,\n {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify(body),\n signal: request.signal,\n },\n request.config,\n 'google',\n 'llm'\n );\n\n if (!response.ok) {\n const error = await normalizeHttpError(response, 'google', 'llm');\n responseReject(error);\n throw error;\n }\n\n if (!response.body) {\n const error = new UPPError(\n 'No response body for streaming request',\n 'PROVIDER_ERROR',\n 'google',\n 'llm'\n );\n responseReject(error);\n throw error;\n }\n\n for await (const data of parseSSEStream(response.body)) {\n if (typeof data === 'object' && data !== null) {\n const chunk = data as GoogleStreamChunk;\n\n if ('error' in chunk) {\n const error = new UPPError(\n (chunk as any).error.message,\n 'PROVIDER_ERROR',\n 'google',\n 'llm'\n );\n responseReject(error);\n throw error;\n }\n\n const events = transformStreamChunk(chunk, state);\n for (const event of events) {\n yield event;\n }\n }\n }\n\n responseResolve(buildResponseFromState(state));\n } catch (error) {\n responseReject(error as Error);\n throw error;\n }\n }\n\n return {\n [Symbol.asyncIterator]() {\n return generateEvents();\n },\n response: responsePromise,\n };\n },\n };\n\n return model;\n },\n };\n}\n","/**\n * @fileoverview Google Gemini caching utilities.\n *\n * Provides functions for creating and managing cached content entries\n * that can be reused across multiple Gemini API requests to reduce\n * costs and latency for repeated context.\n *\n * @see {@link https://ai.google.dev/api/caching Google Caching API docs}\n * @module providers/google/cache\n */\n\nimport type {\n GoogleCacheCreateRequest,\n GoogleCacheResponse,\n GoogleCacheUpdateRequest,\n GoogleCacheListResponse,\n GoogleContent,\n GoogleTool,\n} from './types.ts';\n\nconst CACHE_API_BASE = 'https://generativelanguage.googleapis.com/v1beta/cachedContents';\n\n/**\n * Options for creating a cached content entry.\n */\nexport interface CacheCreateOptions {\n /** API key for authentication */\n apiKey: string;\n /** Model to associate with this cache (e.g., \"gemini-1.5-flash-001\") */\n model: string;\n /** Optional display name for the cache (max 128 chars) */\n displayName?: string;\n /** Content messages to cache */\n contents?: GoogleContent[];\n /** System instruction text to cache */\n systemInstruction?: string;\n /** Tool declarations to cache */\n tools?: GoogleTool[];\n /** Time-to-live duration (e.g., \"3600s\" for 1 hour) */\n ttl?: string;\n /** Absolute expiration time (RFC 3339 format, alternative to ttl) */\n expireTime?: string;\n}\n\n/**\n * Options for listing cached content entries.\n */\nexport interface CacheListOptions {\n /** API key for authentication */\n apiKey: string;\n /** Maximum number of caches to return per page */\n pageSize?: number;\n /** Token for fetching the next page of results */\n pageToken?: string;\n}\n\n/**\n * Creates a new cached content entry.\n *\n * Caches can contain system instructions, conversation content, and tool\n * declarations that are reused across multiple requests. This reduces\n * token costs and processing time for repeated context.\n *\n * @param options - Cache creation options\n * @returns The created cache entry with its name/ID for use in requests\n *\n * @example\n * ```typescript\n * import { google } from '@anthropic/provider-protocol';\n *\n * // Create a cache with system instruction and large context\n * const cache = await google.cache.create({\n * apiKey: process.env.GOOGLE_API_KEY,\n * model: 'gemini-1.5-flash-001',\n * displayName: 'Code Review Context',\n * systemInstruction: 'You are an expert code reviewer...',\n * contents: [\n * { role: 'user', parts: [{ text: largeCodebaseContent }] }\n * ],\n * ttl: '3600s', // 1 hour\n * });\n *\n * // Use the cache in subsequent requests\n * const response = await model.complete({\n * messages: [userMessage('Review this function')],\n * params: { cachedContent: cache.name },\n * });\n * ```\n */\nexport async function create(options: CacheCreateOptions): Promise<GoogleCacheResponse> {\n const {\n apiKey,\n model,\n displayName,\n contents,\n systemInstruction,\n tools,\n ttl,\n expireTime,\n } = options;\n\n const requestBody: GoogleCacheCreateRequest = {\n model: model.startsWith('models/') ? model : `models/${model}`,\n };\n\n if (displayName) {\n requestBody.displayName = displayName;\n }\n\n if (contents && contents.length > 0) {\n requestBody.contents = contents;\n }\n\n if (systemInstruction) {\n requestBody.systemInstruction = {\n parts: [{ text: systemInstruction }],\n };\n }\n\n if (tools && tools.length > 0) {\n requestBody.tools = tools;\n }\n\n if (ttl) {\n requestBody.ttl = ttl;\n } else if (expireTime) {\n requestBody.expireTime = expireTime;\n }\n\n const response = await fetch(`${CACHE_API_BASE}?key=${apiKey}`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify(requestBody),\n });\n\n if (!response.ok) {\n const error = await response.text();\n throw new Error(`Failed to create cache: ${response.status} ${error}`);\n }\n\n return response.json() as Promise<GoogleCacheResponse>;\n}\n\n/**\n * Retrieves a cached content entry by name.\n *\n * @param name - The cache name (format: \"cachedContents/{id}\")\n * @param apiKey - API key for authentication\n * @returns The cache entry details\n *\n * @example\n * ```typescript\n * const cache = await google.cache.get('cachedContents/abc123', apiKey);\n * console.log(`Cache expires at: ${cache.expireTime}`);\n * ```\n */\nexport async function get(name: string, apiKey: string): Promise<GoogleCacheResponse> {\n const cacheName = name.startsWith('cachedContents/') ? name : `cachedContents/${name}`;\n const url = `https://generativelanguage.googleapis.com/v1beta/${cacheName}?key=${apiKey}`;\n\n const response = await fetch(url, { method: 'GET' });\n\n if (!response.ok) {\n const error = await response.text();\n throw new Error(`Failed to get cache: ${response.status} ${error}`);\n }\n\n return response.json() as Promise<GoogleCacheResponse>;\n}\n\n/**\n * Lists all cached content entries.\n *\n * @param options - List options including API key and pagination\n * @returns Array of cache entries and optional next page token\n *\n * @example\n * ```typescript\n * const { cachedContents, nextPageToken } = await google.cache.list({\n * apiKey: process.env.GOOGLE_API_KEY,\n * pageSize: 10,\n * });\n *\n * for (const cache of cachedContents ?? []) {\n * console.log(`${cache.displayName}: ${cache.name}`);\n * }\n * ```\n */\nexport async function list(options: CacheListOptions): Promise<GoogleCacheListResponse> {\n const { apiKey, pageSize, pageToken } = options;\n\n const params = new URLSearchParams({ key: apiKey });\n if (pageSize) params.set('pageSize', String(pageSize));\n if (pageToken) params.set('pageToken', pageToken);\n\n const response = await fetch(`${CACHE_API_BASE}?${params}`, { method: 'GET' });\n\n if (!response.ok) {\n const error = await response.text();\n throw new Error(`Failed to list caches: ${response.status} ${error}`);\n }\n\n return response.json() as Promise<GoogleCacheListResponse>;\n}\n\n/**\n * Updates a cached content entry's expiration time.\n *\n * Only the expiration time can be updated; all other fields\n * (contents, systemInstruction, tools) are immutable after creation.\n *\n * @param name - The cache name (format: \"cachedContents/{id}\")\n * @param update - The update to apply (ttl or expireTime)\n * @param apiKey - API key for authentication\n * @returns The updated cache entry\n *\n * @example\n * ```typescript\n * // Extend cache expiration by 2 hours\n * const updated = await google.cache.update(\n * 'cachedContents/abc123',\n * { ttl: '7200s' },\n * apiKey\n * );\n * ```\n */\nexport async function update(\n name: string,\n updateRequest: GoogleCacheUpdateRequest,\n apiKey: string\n): Promise<GoogleCacheResponse> {\n const cacheName = name.startsWith('cachedContents/') ? name : `cachedContents/${name}`;\n const url = `https://generativelanguage.googleapis.com/v1beta/${cacheName}?key=${apiKey}`;\n\n const response = await fetch(url, {\n method: 'PATCH',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify(updateRequest),\n });\n\n if (!response.ok) {\n const error = await response.text();\n throw new Error(`Failed to update cache: ${response.status} ${error}`);\n }\n\n return response.json() as Promise<GoogleCacheResponse>;\n}\n\n/**\n * Deletes a cached content entry.\n *\n * @param name - The cache name (format: \"cachedContents/{id}\")\n * @param apiKey - API key for authentication\n *\n * @example\n * ```typescript\n * await google.cache.delete('cachedContents/abc123', apiKey);\n * ```\n */\nasync function deleteCache(name: string, apiKey: string): Promise<void> {\n const cacheName = name.startsWith('cachedContents/') ? name : `cachedContents/${name}`;\n const url = `https://generativelanguage.googleapis.com/v1beta/${cacheName}?key=${apiKey}`;\n\n const response = await fetch(url, { method: 'DELETE' });\n\n if (!response.ok) {\n const error = await response.text();\n throw new Error(`Failed to delete cache: ${response.status} ${error}`);\n }\n}\n\n/**\n * Cache utilities namespace.\n *\n * Provides functions for creating and managing Google Gemini cached content\n * entries. Use cached content to reduce costs and latency when repeatedly\n * sending the same context (system instructions, large documents, etc.)\n * across multiple requests.\n *\n * @example\n * ```typescript\n * import { google } from '@anthropic/provider-protocol';\n *\n * // Create a cache\n * const cache = await google.cache.create({\n * apiKey: process.env.GOOGLE_API_KEY,\n * model: 'gemini-1.5-flash-001',\n * systemInstruction: 'You are an expert assistant...',\n * contents: [{ role: 'user', parts: [{ text: largeDocument }] }],\n * ttl: '3600s',\n * });\n *\n * // Use cache.name in requests via params.cachedContent\n * const response = await model.complete({\n * messages: [userMessage('Summarize the document')],\n * params: { cachedContent: cache.name },\n * });\n *\n * // Manage caches\n * const caches = await google.cache.list({ apiKey });\n * await google.cache.update(cache.name, { ttl: '7200s' }, apiKey);\n * await google.cache.delete(cache.name, apiKey);\n * ```\n */\nexport const cache = {\n create,\n get,\n list,\n update,\n delete: deleteCache,\n};\n","import { createProvider } from '../../core/provider.ts';\nimport { createLLMHandler } from './llm.ts';\nimport { cache } from './cache.ts';\n\nconst baseProvider = createProvider({\n name: 'google',\n version: '1.0.0',\n modalities: {\n llm: createLLMHandler(),\n },\n});\n\n/**\n * Google Gemini provider for the Unified Provider Protocol (UPP).\n *\n * Provides access to Google's Gemini family of large language models through\n * a standardized interface. Supports text generation, multimodal inputs\n * (images, video, audio), tool/function calling, and structured output.\n *\n * @example\n * ```typescript\n * import { google } from './providers/google';\n *\n * // Create a model instance\n * const gemini = google.llm.bind('gemini-1.5-pro');\n *\n * // Simple completion\n * const response = await gemini.complete({\n * messages: [{ role: 'user', content: [{ type: 'text', text: 'Hello!' }] }],\n * config: { apiKey: process.env.GOOGLE_API_KEY },\n * });\n *\n * // Streaming completion\n * const stream = gemini.stream({\n * messages: [{ role: 'user', content: [{ type: 'text', text: 'Tell me a story' }] }],\n * config: { apiKey: process.env.GOOGLE_API_KEY },\n * });\n *\n * for await (const event of stream) {\n * if (event.type === 'text_delta') {\n * process.stdout.write(event.delta.text);\n * }\n * }\n * ```\n *\n * @example Caching\n * ```typescript\n * // Create a cache for repeated context\n * const cacheEntry = await google.cache.create({\n * apiKey: process.env.GOOGLE_API_KEY,\n * model: 'gemini-1.5-flash-001',\n * systemInstruction: 'You are an expert code reviewer...',\n * contents: [{ role: 'user', parts: [{ text: largeCodebase }] }],\n * ttl: '3600s',\n * });\n *\n * // Use cache in requests\n * const response = await gemini.complete({\n * messages: [userMessage('Review this function')],\n * config: { apiKey: process.env.GOOGLE_API_KEY },\n * params: { cachedContent: cacheEntry.name },\n * });\n *\n * // Manage caches\n * await google.cache.update(cacheEntry.name, { ttl: '7200s' }, apiKey);\n * await google.cache.delete(cacheEntry.name, apiKey);\n * ```\n *\n * @see {@link GoogleLLMParams} for provider-specific configuration options\n * @see {@link cache} for caching utilities\n */\nexport const google = Object.assign(baseProvider, { cache });\n\nexport { cache } from './cache.ts';\nexport type { CacheCreateOptions, CacheListOptions } from './cache.ts';\nexport type {\n GoogleLLMParams,\n GoogleCacheCreateRequest,\n GoogleCacheResponse,\n GoogleCacheUpdateRequest,\n GoogleCacheListResponse,\n} from './types.ts';\n"],"mappings":"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","names":[]}
@@ -1,60 +1,257 @@
1
- export { D as DynamicKey, E as ExponentialBackoff, L as LinearBackoff, N as NoRetry, a as RetryAfterStrategy, R as RoundRobinKeys, T as TokenBucket, W as WeightedKeys, r as resolveApiKey } from '../retry-I2661_rv.js';
2
- import { P as ProviderConfig, d as Modality, U as UPPError, c as ErrorCode } from '../provider-CUJWjgNl.js';
1
+ export { D as DynamicKey, E as ExponentialBackoff, L as LinearBackoff, N as NoRetry, a as RetryAfterStrategy, R as RoundRobinKeys, T as TokenBucket, W as WeightedKeys, r as resolveApiKey } from '../retry-Dh70lgr0.js';
2
+ import { P as ProviderConfig, d as Modality, U as UPPError, c as ErrorCode } from '../provider-mKkz7Q9U.js';
3
3
 
4
4
  /**
5
- * Execute fetch with retry, timeout, and error normalization
5
+ * HTTP fetch utilities with retry, timeout, and error normalization.
6
+ * @module http/fetch
7
+ */
8
+
9
+ /**
10
+ * Executes an HTTP fetch request with automatic retry, timeout handling, and error normalization.
11
+ *
12
+ * This function wraps the standard fetch API with additional capabilities:
13
+ * - Configurable timeout with automatic request cancellation
14
+ * - Retry strategy support (exponential backoff, linear, token bucket, etc.)
15
+ * - Pre-request delay support for rate limiting strategies
16
+ * - Automatic Retry-After header parsing and handling
17
+ * - Error normalization to UPPError format
18
+ *
19
+ * @param url - The URL to fetch
20
+ * @param init - Standard fetch RequestInit options (method, headers, body, etc.)
21
+ * @param config - Provider configuration containing fetch customization, timeout, and retry strategy
22
+ * @param provider - Provider identifier for error context (e.g., 'openai', 'anthropic')
23
+ * @param modality - Request modality for error context (e.g., 'llm', 'embedding', 'image')
24
+ * @returns The successful Response object
6
25
  *
7
- * @param url - Request URL
8
- * @param init - Fetch init options
9
- * @param config - Provider config
10
- * @param provider - Provider name for error messages
11
- * @param modality - Modality for error messages
26
+ * @throws {UPPError} RATE_LIMITED - When rate limited and retries exhausted
27
+ * @throws {UPPError} NETWORK_ERROR - When a network failure occurs
28
+ * @throws {UPPError} TIMEOUT - When the request times out
29
+ * @throws {UPPError} CANCELLED - When the request is aborted via signal
30
+ * @throws {UPPError} Various codes based on HTTP status (see statusToErrorCode)
31
+ *
32
+ * @example
33
+ * ```typescript
34
+ * const response = await doFetch(
35
+ * 'https://api.openai.com/v1/chat/completions',
36
+ * {
37
+ * method: 'POST',
38
+ * headers: { 'Authorization': 'Bearer sk-...' },
39
+ * body: JSON.stringify({ model: 'gpt-4', messages: [] })
40
+ * },
41
+ * { timeout: 30000, retryStrategy: new ExponentialBackoff() },
42
+ * 'openai',
43
+ * 'llm'
44
+ * );
45
+ * ```
12
46
  */
13
47
  declare function doFetch(url: string, init: RequestInit, config: ProviderConfig, provider: string, modality: Modality): Promise<Response>;
14
48
  /**
15
- * Streaming fetch - returns response without checking ok status
16
- * Used when we need to read the stream for SSE
49
+ * Executes an HTTP fetch request for streaming responses.
50
+ *
51
+ * Unlike {@link doFetch}, this function returns the response immediately without
52
+ * checking the HTTP status. This is necessary for Server-Sent Events (SSE) and
53
+ * other streaming protocols where error information may be embedded in the stream.
54
+ *
55
+ * The caller is responsible for:
56
+ * - Checking response.ok and handling HTTP errors
57
+ * - Parsing the response stream (e.g., using parseSSEStream)
58
+ * - Handling stream-specific error conditions
59
+ *
60
+ * Retries are not performed for streaming requests since partial data may have
61
+ * already been consumed by the caller.
62
+ *
63
+ * @param url - The URL to fetch
64
+ * @param init - Standard fetch RequestInit options
65
+ * @param config - Provider configuration containing fetch customization and timeout
66
+ * @param provider - Provider identifier for error context
67
+ * @param modality - Request modality for error context
68
+ * @returns The Response object (may have non-2xx status)
69
+ *
70
+ * @throws {UPPError} NETWORK_ERROR - When a network failure occurs
71
+ * @throws {UPPError} TIMEOUT - When the request times out
72
+ * @throws {UPPError} CANCELLED - When the request is aborted via signal
73
+ *
74
+ * @example
75
+ * ```typescript
76
+ * const response = await doStreamFetch(
77
+ * 'https://api.openai.com/v1/chat/completions',
78
+ * {
79
+ * method: 'POST',
80
+ * headers: { 'Authorization': 'Bearer sk-...' },
81
+ * body: JSON.stringify({ model: 'gpt-4', messages: [], stream: true })
82
+ * },
83
+ * { timeout: 120000 },
84
+ * 'openai',
85
+ * 'llm'
86
+ * );
87
+ *
88
+ * if (!response.ok) {
89
+ * throw await normalizeHttpError(response, 'openai', 'llm');
90
+ * }
91
+ *
92
+ * for await (const event of parseSSEStream(response.body!)) {
93
+ * console.log(event);
94
+ * }
95
+ * ```
17
96
  */
18
97
  declare function doStreamFetch(url: string, init: RequestInit, config: ProviderConfig, provider: string, modality: Modality): Promise<Response>;
19
98
 
20
99
  /**
21
- * Server-Sent Events (SSE) stream parser
100
+ * Server-Sent Events (SSE) stream parsing utilities.
101
+ * @module http/sse
22
102
  */
23
103
  /**
24
- * Parse a Server-Sent Events stream into JSON objects
25
- * Handles standard SSE format with "data:" prefix
26
- * Yields parsed JSON for each event
27
- * Terminates on "[DONE]" message (OpenAI style)
104
+ * Parses a Server-Sent Events stream into JSON objects.
105
+ *
106
+ * This async generator handles the standard SSE wire format:
107
+ * - Lines prefixed with "data:" contain event data
108
+ * - Lines prefixed with "event:" specify event types
109
+ * - Lines prefixed with ":" are comments (used for keep-alive)
110
+ * - Events are separated by double newlines
111
+ * - Stream terminates on "[DONE]" message (OpenAI convention)
28
112
  *
29
- * @param body - ReadableStream from fetch response
113
+ * Also handles non-standard formats used by some providers:
114
+ * - Raw JSON without "data:" prefix (Google)
115
+ * - Multi-line data fields
116
+ *
117
+ * @param body - ReadableStream from fetch response body
118
+ * @yields Parsed JSON objects from each SSE event
119
+ *
120
+ * @example
121
+ * ```typescript
122
+ * const response = await doStreamFetch(url, init, config, 'openai', 'llm');
123
+ *
124
+ * for await (const event of parseSSEStream(response.body!)) {
125
+ * // event is parsed JSON from each SSE data field
126
+ * const chunk = event as OpenAIStreamChunk;
127
+ * const delta = chunk.choices[0]?.delta?.content;
128
+ * if (delta) {
129
+ * process.stdout.write(delta);
130
+ * }
131
+ * }
132
+ * ```
30
133
  */
31
134
  declare function parseSSEStream(body: ReadableStream<Uint8Array>): AsyncGenerator<unknown, void, unknown>;
32
135
  /**
33
- * Create a simple SSE reader that handles basic text streaming
34
- * For providers that just stream text deltas
136
+ * Parses a simple text stream without SSE formatting.
137
+ *
138
+ * This is a simpler alternative to {@link parseSSEStream} for providers
139
+ * that stream raw text deltas without SSE event wrappers. Each chunk
140
+ * from the response body is decoded and yielded as-is.
141
+ *
142
+ * Use this for:
143
+ * - Plain text streaming responses
144
+ * - Providers with custom streaming formats
145
+ * - Testing and debugging stream handling
146
+ *
147
+ * @param body - ReadableStream from fetch response body
148
+ * @yields Decoded text strings from each stream chunk
149
+ *
150
+ * @example
151
+ * ```typescript
152
+ * const response = await doStreamFetch(url, init, config, 'custom', 'llm');
153
+ *
154
+ * for await (const text of parseSimpleTextStream(response.body!)) {
155
+ * process.stdout.write(text);
156
+ * }
157
+ * ```
35
158
  */
36
159
  declare function parseSimpleTextStream(body: ReadableStream<Uint8Array>): AsyncGenerator<string, void, unknown>;
37
160
 
38
161
  /**
39
- * Map HTTP status codes to UPP error codes
162
+ * HTTP error handling and normalization utilities.
163
+ * @module http/errors
164
+ */
165
+
166
+ /**
167
+ * Maps HTTP status codes to standardized UPP error codes.
168
+ *
169
+ * This function provides consistent error categorization across all providers:
170
+ * - 400 -> INVALID_REQUEST (bad request format or parameters)
171
+ * - 401, 403 -> AUTHENTICATION_FAILED (invalid or missing credentials)
172
+ * - 404 -> MODEL_NOT_FOUND (requested model does not exist)
173
+ * - 408 -> TIMEOUT (request timed out)
174
+ * - 413 -> CONTEXT_LENGTH_EXCEEDED (input too long)
175
+ * - 429 -> RATE_LIMITED (too many requests)
176
+ * - 5xx -> PROVIDER_ERROR (server-side issues)
177
+ *
178
+ * @param status - HTTP status code from the response
179
+ * @returns The corresponding UPP ErrorCode
180
+ *
181
+ * @example
182
+ * ```typescript
183
+ * const errorCode = statusToErrorCode(429);
184
+ * // Returns 'RATE_LIMITED'
185
+ *
186
+ * const serverError = statusToErrorCode(503);
187
+ * // Returns 'PROVIDER_ERROR'
188
+ * ```
40
189
  */
41
190
  declare function statusToErrorCode(status: number): ErrorCode;
42
191
  /**
43
- * Normalize HTTP error responses to UPPError
44
- * Maps HTTP status codes to appropriate ErrorCode values
45
- * Extracts error message from response body when available
192
+ * Normalizes HTTP error responses into standardized UPPError objects.
193
+ *
194
+ * This function performs several operations:
195
+ * 1. Maps the HTTP status code to an appropriate ErrorCode
196
+ * 2. Attempts to extract a meaningful error message from the response body
197
+ * 3. Handles various provider-specific error response formats
198
+ *
199
+ * Supported error message formats:
200
+ * - `{ error: { message: "..." } }` (OpenAI, Anthropic)
201
+ * - `{ message: "..." }` (simple format)
202
+ * - `{ error: { error: { message: "..." } } }` (nested format)
203
+ * - `{ detail: "..." }` (FastAPI style)
204
+ * - Plain text body (if under 200 characters)
205
+ *
206
+ * @param response - The HTTP Response object with non-2xx status
207
+ * @param provider - Provider identifier for error context
208
+ * @param modality - Request modality for error context
209
+ * @returns A UPPError with normalized code and message
210
+ *
211
+ * @example
212
+ * ```typescript
213
+ * if (!response.ok) {
214
+ * const error = await normalizeHttpError(response, 'openai', 'llm');
215
+ * // error.code might be 'RATE_LIMITED' for 429
216
+ * // error.message contains provider's error message
217
+ * throw error;
218
+ * }
219
+ * ```
46
220
  */
47
221
  declare function normalizeHttpError(response: Response, provider: string, modality: Modality): Promise<UPPError>;
48
222
  /**
49
- * Create a network error
223
+ * Creates a UPPError for network failures (DNS, connection, etc.).
224
+ *
225
+ * Use this when the request fails before receiving any HTTP response,
226
+ * such as DNS resolution failures, connection refused, or network unreachable.
227
+ *
228
+ * @param error - The underlying Error that caused the failure
229
+ * @param provider - Provider identifier for error context
230
+ * @param modality - Request modality for error context
231
+ * @returns A UPPError with NETWORK_ERROR code and the original error attached
50
232
  */
51
233
  declare function networkError(error: Error, provider: string, modality: Modality): UPPError;
52
234
  /**
53
- * Create a timeout error
235
+ * Creates a UPPError for request timeout.
236
+ *
237
+ * Use this when the request exceeds the configured timeout duration
238
+ * and is aborted by the AbortController.
239
+ *
240
+ * @param timeout - The timeout duration in milliseconds that was exceeded
241
+ * @param provider - Provider identifier for error context
242
+ * @param modality - Request modality for error context
243
+ * @returns A UPPError with TIMEOUT code
54
244
  */
55
245
  declare function timeoutError(timeout: number, provider: string, modality: Modality): UPPError;
56
246
  /**
57
- * Create a cancelled error
247
+ * Creates a UPPError for user-initiated request cancellation.
248
+ *
249
+ * Use this when the request is aborted via a user-provided AbortSignal,
250
+ * distinct from timeout-based cancellation.
251
+ *
252
+ * @param provider - Provider identifier for error context
253
+ * @param modality - Request modality for error context
254
+ * @returns A UPPError with CANCELLED code
58
255
  */
59
256
  declare function cancelledError(provider: string, modality: Modality): UPPError;
60
257
 
@@ -4,11 +4,11 @@ import {
4
4
  NoRetry,
5
5
  RetryAfterStrategy,
6
6
  TokenBucket
7
- } from "../chunk-CUCRF5W6.js";
7
+ } from "../chunk-U4JJC2YX.js";
8
8
  import {
9
9
  parseSSEStream,
10
10
  parseSimpleTextStream
11
- } from "../chunk-X5G4EHL7.js";
11
+ } from "../chunk-Z7RBRCRN.js";
12
12
  import {
13
13
  DynamicKey,
14
14
  RoundRobinKeys,
@@ -21,7 +21,7 @@ import {
21
21
  resolveApiKey,
22
22
  statusToErrorCode,
23
23
  timeoutError
24
- } from "../chunk-SUNYWHTH.js";
24
+ } from "../chunk-MOU4U3PO.js";
25
25
  export {
26
26
  DynamicKey,
27
27
  ExponentialBackoff,