UNPKG

@genkit-ai/googleai

Version:

Genkit AI framework plugin for Google AI APIs, including Gemini APIs.

1 lines 8.98 kB
{"version":3,"sources":["../../src/context-caching/utils.ts"],"sourcesContent":["/**\n * Copyright 2024 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport type { CachedContent, StartChatParams } from '@google/generative-ai';\nimport type { GoogleAICacheManager } from '@google/generative-ai/server';\nimport crypto from 'crypto';\nimport { GenkitError, type MessageData, type z } from 'genkit';\nimport type { GenerateRequest } from 'genkit/model';\nimport {\n CONTEXT_CACHE_SUPPORTED_MODELS,\n DEFAULT_TTL,\n INVALID_ARGUMENT_MESSAGES,\n} from './constants';\nimport {\n cacheConfigSchema,\n type CacheConfig,\n type CacheConfigDetails,\n} from './types';\n\n/**\n * Generates a SHA-256 hash to use as a cache key.\n * @param request CachedContent - request object to hash\n * @returns string - the generated cache key\n */\nexport function generateCacheKey(request: CachedContent): string {\n return crypto\n .createHash('sha256')\n .update(JSON.stringify(request))\n .digest('hex');\n}\n\n/**\n * Retrieves the content needed for the cache based on the chat history and config details.\n */\nexport function getContentForCache(\n request: GenerateRequest<z.ZodTypeAny>,\n chatRequest: StartChatParams,\n modelVersion: string,\n cacheConfigDetails: CacheConfigDetails\n): {\n cachedContent: CachedContent;\n chatRequest: StartChatParams;\n cacheConfig?: CacheConfig;\n} {\n // Ensure modelVersion is provided\n if (!modelVersion) {\n throw new Error('No model version provided for context caching');\n }\n\n // Ensure chatRequest has a history\n if (!chatRequest.history?.length) {\n throw new Error('No history provided for context caching');\n }\n\n // Validate the history length between request and chatRequest\n validateHistoryLength(request, chatRequest);\n\n // Extract relevant cached content based on cacheConfigDetails\n const { endOfCachedContents, cacheConfig } = cacheConfigDetails;\n const cachedContent: CachedContent = {\n model: modelVersion,\n contents: chatRequest.history.slice(0, endOfCachedContents + 1),\n };\n\n // Update the chatRequest history to only include non-cached parts\n chatRequest.history = chatRequest.history.slice(endOfCachedContents + 1);\n\n return { cachedContent, chatRequest, cacheConfig };\n}\n\n/**\n * Validates that the request and chat request history lengths align.\n * @throws GenkitError if lengths are mismatched\n */\nfunction validateHistoryLength(\n request: GenerateRequest<z.ZodTypeAny>,\n chatRequest: StartChatParams\n) {\n if (chatRequest.history?.length !== request.messages.length - 1) {\n throw new GenkitError({\n status: 'INTERNAL',\n message:\n 'Genkit request history and Gemini chat request history length do not match',\n });\n }\n}\n\n/**\n * Looks up context cache using a cache manager and returns the found item, if any.\n */\n/**\n * Looks up context cache using a cache manager and returns the found item, if any.\n */\nexport async function lookupContextCache(\n cacheManager: GoogleAICacheManager,\n cacheKey: string,\n maxPages = 100,\n pageSize = 100\n): Promise<CachedContent | null> {\n let currentPage = 0;\n let pageToken: string | undefined;\n\n try {\n while (currentPage < maxPages) {\n const { cachedContents, nextPageToken } = await cacheManager.list({\n pageSize,\n pageToken,\n });\n\n // Check for the cached content by key\n const found = cachedContents?.find(\n (content) => content.displayName === cacheKey\n );\n\n if (found) return found; // Return found content\n\n // Stop if there's no next page\n if (!nextPageToken) break;\n\n pageToken = nextPageToken;\n currentPage++;\n }\n } catch (error) {\n const message =\n error instanceof Error ? error.message : 'Unknown Network Error';\n\n throw new GenkitError({\n status: 'INTERNAL',\n message: `Error looking up context cache: ${message}`,\n });\n }\n\n return null; // Return null if not found or on error\n}\n\n/**\n * Extracts the cache configuration from the request if available.\n */\nexport const extractCacheConfig = (\n request: GenerateRequest<z.ZodTypeAny>\n): {\n cacheConfig: { ttlSeconds?: number } | boolean;\n endOfCachedContents: number;\n} | null => {\n const endOfCachedContents = findLastIndex<MessageData>(\n request.messages,\n (message) => !!message.metadata?.cache\n );\n\n return endOfCachedContents === -1\n ? null\n : {\n endOfCachedContents,\n cacheConfig: cacheConfigSchema.parse(\n request.messages[endOfCachedContents].metadata?.cache\n ),\n };\n};\n\n/**\n * Validates context caching request for compatibility with model and request configurations.\n */\nexport function validateContextCacheRequest(\n request: GenerateRequest<z.ZodTypeAny>,\n modelVersion: string\n): boolean {\n if (!modelVersion || !CONTEXT_CACHE_SUPPORTED_MODELS.includes(modelVersion)) {\n throw new GenkitError({\n status: 'INVALID_ARGUMENT',\n message: INVALID_ARGUMENT_MESSAGES.modelVersion,\n });\n }\n if (request.tools?.length)\n throw new GenkitError({\n status: 'INVALID_ARGUMENT',\n message: INVALID_ARGUMENT_MESSAGES.tools,\n });\n if (request.config?.codeExecution)\n throw new GenkitError({\n status: 'INVALID_ARGUMENT',\n message: INVALID_ARGUMENT_MESSAGES.codeExecution,\n });\n\n return true;\n}\n\n/**\n * Polyfill function for Array.prototype.findLastIndex for ES2015 compatibility.\n */\nexport function findLastIndex<T>(\n array: T[],\n callback: (element: T, index: number, array: T[]) => boolean\n): number {\n for (let i = array.length - 1; i >= 0; i--) {\n if (callback(array[i], i, array)) return i;\n }\n return -1;\n}\n\n/**\n * Calculates the TTL (Time-To-Live) for the cache based on cacheConfigDetails.\n * @param cacheConfig - The caching configuration details.\n * @returns The TTL in seconds.\n */\nexport function calculateTTL(cacheConfig: CacheConfigDetails): number {\n if (cacheConfig.cacheConfig === true) {\n return DEFAULT_TTL;\n }\n if (cacheConfig.cacheConfig === false) {\n return 0;\n }\n return cacheConfig.cacheConfig.ttlSeconds || DEFAULT_TTL;\n}\n"],"mappings":"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","names":[]}