@livekit/agents-plugin-google 1.2.3 → 1.2.5
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/README.md +15 -1
- package/dist/beta/realtime/realtime_api.cjs +26 -3
- package/dist/beta/realtime/realtime_api.cjs.map +1 -1
- package/dist/beta/realtime/realtime_api.d.cts +2 -2
- package/dist/beta/realtime/realtime_api.d.ts +2 -2
- package/dist/beta/realtime/realtime_api.d.ts.map +1 -1
- package/dist/beta/realtime/realtime_api.js +26 -3
- package/dist/beta/realtime/realtime_api.js.map +1 -1
- package/dist/index.cjs +1 -1
- package/dist/index.js +1 -1
- package/dist/llm.cjs +1 -1
- package/dist/llm.cjs.map +1 -1
- package/dist/llm.d.cts +1 -1
- package/dist/llm.d.ts +1 -1
- package/dist/llm.js +1 -1
- package/dist/llm.js.map +1 -1
- package/package.json +7 -7
- package/src/beta/realtime/realtime_api.ts +26 -4
- package/src/llm.ts +1 -1
package/dist/llm.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/llm.ts"],"sourcesContent":["// SPDX-FileCopyrightText: 2025 LiveKit, Inc.\n//\n// SPDX-License-Identifier: Apache-2.0\nimport type * as types from '@google/genai';\nimport { FunctionCallingConfigMode, type GenerateContentConfig, GoogleGenAI } from '@google/genai';\nimport type { APIConnectOptions } from '@livekit/agents';\nimport {\n APIConnectionError,\n APIStatusError,\n DEFAULT_API_CONNECT_OPTIONS,\n llm,\n shortuuid,\n} from '@livekit/agents';\nimport type { ChatModels } from './models.js';\nimport type { LLMTools } from './tools.js';\nimport { toFunctionDeclarations } from './utils.js';\n\ninterface GoogleFormatData {\n systemMessages: string[] | null;\n}\n\nexport interface LLMOptions {\n model: string | ChatModels;\n apiKey?: string;\n temperature?: number;\n toolChoice?: llm.ToolChoice;\n vertexai?: boolean;\n project?: string;\n location?: string;\n maxOutputTokens?: number;\n topP?: number;\n topK?: number;\n presencePenalty?: number;\n frequencyPenalty?: number;\n thinkingConfig?: types.ThinkingConfig;\n automaticFunctionCallingConfig?: types.AutomaticFunctionCallingConfig;\n geminiTools?: LLMTools;\n httpOptions?: types.HttpOptions;\n seed?: number;\n}\n\nexport class LLM extends llm.LLM {\n #opts: LLMOptions;\n #client: GoogleGenAI;\n\n label(): string {\n return 'google.LLM';\n }\n\n get model(): string {\n return this.#opts.model;\n }\n\n get provider(): string {\n if (this.#opts.vertexai) {\n return 'Vertex AI';\n }\n return 'Gemini';\n }\n\n /**\n * Create a new instance of Google GenAI LLM.\n *\n * Environment Requirements:\n * - For VertexAI: Set the `GOOGLE_APPLICATION_CREDENTIALS` environment variable to the path of the service account key file or use any of the other Google Cloud auth methods.\n * The Google Cloud project and location can be set via `project` and `location` arguments or the environment variables\n * `GOOGLE_CLOUD_PROJECT` and `GOOGLE_CLOUD_LOCATION`. By default, the project is inferred from the service account key file,\n * and the location defaults to \"us-central1\".\n * - For Google Gemini API: Set the `apiKey` argument or the `GOOGLE_API_KEY` environment variable.\n *\n * @param model - The model name to use. Defaults to \"gemini-2.0-flash-001\".\n * @param apiKey - The API key for Google Gemini. If not provided, it attempts to read from the `GOOGLE_API_KEY` environment variable.\n * @param vertexai - Whether to use VertexAI. If not provided, it attempts to read from the `GOOGLE_GENAI_USE_VERTEXAI` environment variable. Defaults to false.\n * @param project - The Google Cloud project to use (only for VertexAI). Defaults to undefined.\n * @param location - The location to use for VertexAI API requests. Default value is \"us-central1\".\n * @param temperature - Sampling temperature for response generation. Defaults to undefined.\n * @param maxOutputTokens - Maximum number of tokens to generate in the output. Defaults to undefined.\n * @param topP - The nucleus sampling probability for response generation. Defaults to undefined.\n * @param topK - The top-k sampling value for response generation. Defaults to undefined.\n * @param presencePenalty - Penalizes the model for generating previously mentioned concepts. Defaults to undefined.\n * @param frequencyPenalty - Penalizes the model for repeating words. Defaults to undefined.\n * @param toolChoice - Specifies whether to use tools during response generation. Defaults to \"auto\".\n * @param thinkingConfig - The thinking configuration for response generation. Defaults to undefined.\n * @param automaticFunctionCallingConfig - The automatic function calling configuration for response generation. Defaults to undefined.\n * @param geminiTools - The Gemini-specific tools to use for the session.\n * @param httpOptions - The HTTP options to use for the session.\n * @param seed - Random seed for reproducible results. Defaults to undefined.\n */\n constructor(\n {\n model,\n apiKey,\n vertexai,\n project,\n location,\n temperature,\n maxOutputTokens,\n topP,\n topK,\n presencePenalty,\n frequencyPenalty,\n toolChoice,\n thinkingConfig,\n automaticFunctionCallingConfig,\n geminiTools,\n httpOptions,\n seed,\n }: LLMOptions = {\n model: 'gemini-2.0-flash-001',\n },\n ) {\n super();\n\n const useVertexAI =\n vertexai ??\n (process.env.GOOGLE_GENAI_USE_VERTEXAI === 'true' ||\n process.env.GOOGLE_GENAI_USE_VERTEXAI === '1');\n\n let gcpProject: string | undefined = project ?? process.env.GOOGLE_CLOUD_PROJECT;\n let gcpLocation: string | undefined = location ?? process.env.GOOGLE_CLOUD_LOCATION;\n let geminiApiKey: string | undefined = apiKey ?? process.env.GOOGLE_API_KEY;\n\n if (useVertexAI) {\n if (!gcpProject) {\n // TODO(brian): use default_async to get the project ID\n throw new Error(\n 'Project ID is required for Vertex AI. Set via project option or GOOGLE_CLOUD_PROJECT environment variable',\n );\n }\n geminiApiKey = undefined;\n } else {\n gcpProject = undefined;\n gcpLocation = undefined;\n if (!geminiApiKey) {\n throw new Error(\n 'API key is required for Google API either via apiKey or GOOGLE_API_KEY environment variable',\n );\n }\n }\n\n // Validate thinkingConfig\n if (thinkingConfig?.thinkingBudget !== undefined) {\n const budget = thinkingConfig.thinkingBudget;\n if (budget < 0 || budget > 24576) {\n throw new Error('thinkingBudget inside thinkingConfig must be between 0 and 24576');\n }\n }\n\n const clientOptions: types.GoogleGenAIOptions = useVertexAI\n ? {\n vertexai: true,\n project: gcpProject,\n location: gcpLocation,\n }\n : {\n apiKey: geminiApiKey,\n };\n\n this.#client = new GoogleGenAI(clientOptions);\n\n this.#opts = {\n model,\n vertexai: useVertexAI,\n project: gcpProject,\n location: gcpLocation,\n temperature,\n maxOutputTokens,\n topP,\n topK,\n presencePenalty,\n frequencyPenalty,\n toolChoice,\n thinkingConfig,\n automaticFunctionCallingConfig,\n geminiTools,\n httpOptions,\n seed,\n apiKey,\n };\n }\n\n chat({\n chatCtx,\n toolCtx,\n connOptions = DEFAULT_API_CONNECT_OPTIONS,\n toolChoice,\n extraKwargs,\n geminiTools,\n }: {\n chatCtx: llm.ChatContext;\n toolCtx?: llm.ToolContext;\n connOptions?: APIConnectOptions;\n parallelToolCalls?: boolean;\n toolChoice?: llm.ToolChoice;\n extraKwargs?: Record<string, unknown>;\n geminiTools?: LLMTools;\n }): LLMStream {\n const extras: GenerateContentConfig = { ...extraKwargs } as GenerateContentConfig;\n\n toolChoice = toolChoice !== undefined ? toolChoice : this.#opts.toolChoice;\n\n if (toolChoice) {\n let geminiToolConfig: types.ToolConfig;\n\n if (typeof toolChoice === 'object' && toolChoice.type === 'function') {\n geminiToolConfig = {\n functionCallingConfig: {\n mode: FunctionCallingConfigMode.ANY,\n allowedFunctionNames: [toolChoice.function.name],\n },\n };\n } else if (toolChoice === 'required') {\n const toolNames = Object.entries(toolCtx || {}).map(([name]) => name);\n geminiToolConfig = {\n functionCallingConfig: {\n mode: FunctionCallingConfigMode.ANY,\n allowedFunctionNames: toolNames.length > 0 ? toolNames : undefined,\n },\n };\n } else if (toolChoice === 'auto') {\n geminiToolConfig = {\n functionCallingConfig: {\n mode: FunctionCallingConfigMode.AUTO,\n },\n };\n } else if (toolChoice === 'none') {\n geminiToolConfig = {\n functionCallingConfig: {\n mode: FunctionCallingConfigMode.NONE,\n },\n };\n } else {\n throw new Error(`Invalid tool choice: ${toolChoice}`);\n }\n\n extras.toolConfig = geminiToolConfig;\n }\n\n if (this.#opts.temperature !== undefined) {\n extras.temperature = this.#opts.temperature;\n }\n if (this.#opts.maxOutputTokens !== undefined) {\n extras.maxOutputTokens = this.#opts.maxOutputTokens;\n }\n if (this.#opts.topP !== undefined) {\n extras.topP = this.#opts.topP;\n }\n if (this.#opts.topK !== undefined) {\n extras.topK = this.#opts.topK;\n }\n if (this.#opts.presencePenalty !== undefined) {\n extras.presencePenalty = this.#opts.presencePenalty;\n }\n if (this.#opts.frequencyPenalty !== undefined) {\n extras.frequencyPenalty = this.#opts.frequencyPenalty;\n }\n if (this.#opts.seed !== undefined) {\n extras.seed = this.#opts.seed;\n }\n\n if (this.#opts.thinkingConfig !== undefined) {\n extras.thinkingConfig = this.#opts.thinkingConfig;\n }\n\n if (this.#opts.automaticFunctionCallingConfig !== undefined) {\n extras.automaticFunctionCalling = this.#opts.automaticFunctionCallingConfig;\n }\n\n geminiTools = geminiTools !== undefined ? geminiTools : this.#opts.geminiTools;\n\n return new LLMStream(this, {\n client: this.#client,\n model: this.#opts.model,\n chatCtx,\n toolCtx,\n connOptions,\n geminiTools,\n extraKwargs: extras,\n });\n }\n}\n\nconst BLOCKED_REASONS = [\n 'SAFETY',\n 'SPII',\n 'PROHIBITED_CONTENT',\n 'BLOCKLIST',\n 'LANGUAGE',\n 'RECITATION',\n];\n\nexport class LLMStream extends llm.LLMStream {\n #client: GoogleGenAI;\n #model: string;\n #geminiTools?: LLMTools;\n #extraKwargs: GenerateContentConfig;\n\n constructor(\n llm: LLM,\n {\n client,\n model,\n chatCtx,\n toolCtx,\n connOptions,\n geminiTools,\n extraKwargs,\n }: {\n client: GoogleGenAI;\n model: string;\n chatCtx: llm.ChatContext;\n toolCtx?: llm.ToolContext;\n connOptions: APIConnectOptions;\n geminiTools?: LLMTools;\n extraKwargs: GenerateContentConfig;\n },\n ) {\n // Call base constructor with dev 1.0 object parameter pattern\n super(llm, { chatCtx, toolCtx, connOptions });\n this.#client = client;\n this.#model = model;\n this.#geminiTools = geminiTools;\n this.#extraKwargs = extraKwargs;\n }\n\n protected async run(): Promise<void> {\n let retryable = true;\n const requestId = `google_${Date.now()}`;\n\n try {\n const [turns, extraData] = (await this.chatCtx.toProviderFormat('google')) as [\n Record<string, unknown>[],\n GoogleFormatData,\n ];\n\n const contents: types.Content[] = turns.map((turn: Record<string, unknown>) => ({\n role: turn.role as types.Content['role'],\n parts: turn.parts as types.Part[],\n }));\n\n const functionDeclarations = this.toolCtx ? toFunctionDeclarations(this.toolCtx) : undefined;\n const tools =\n functionDeclarations && functionDeclarations.length > 0\n ? [{ functionDeclarations }]\n : undefined;\n\n let systemInstruction: types.Content | undefined = undefined;\n if (extraData.systemMessages && extraData.systemMessages.length > 0) {\n systemInstruction = {\n parts: extraData.systemMessages.map((content: string) => ({ text: content })),\n };\n }\n\n const response = await this.#client.models.generateContentStream({\n model: this.#model,\n contents,\n config: {\n ...this.#extraKwargs,\n systemInstruction,\n httpOptions: this.#extraKwargs.httpOptions ?? {\n timeout: Math.floor(this.connOptions.timeoutMs),\n },\n tools,\n },\n });\n\n for await (const chunk of response) {\n if (chunk.promptFeedback) {\n throw new APIStatusError({\n message: `Prompt feedback error: ${JSON.stringify(chunk.promptFeedback)}`,\n options: {\n retryable: false,\n requestId,\n },\n });\n }\n\n // Check for blocked reasons first — safety-blocked responses often lack content.parts,\n // so this must run before the no-content guard to avoid wasting retries.\n if (\n chunk.candidates?.[0]?.finishReason &&\n BLOCKED_REASONS.includes(chunk.candidates[0].finishReason)\n ) {\n throw new APIStatusError({\n message: `Google LLM: generation blocked - ${chunk.candidates[0].finishReason}`,\n options: {\n retryable: false,\n requestId,\n },\n });\n }\n\n if (!chunk.candidates || !chunk.candidates[0]?.content?.parts) {\n this.logger.warn(`No content in the response: ${JSON.stringify(chunk)}`);\n if (retryable) {\n throw new APIStatusError({\n message: 'Google LLM: no content in the response',\n options: {\n retryable: true,\n requestId,\n },\n });\n }\n continue;\n }\n\n if (chunk.candidates.length > 1) {\n this.logger.warn(\n 'Google LLM: there are multiple candidates in the response, returning response from the first one.',\n );\n }\n\n const candidate = chunk.candidates[0];\n const finishReason = candidate.finishReason;\n\n let chunksYielded = false;\n for (const part of candidate.content!.parts!) {\n const chatChunk = this.#parsePart(requestId, part);\n if (chatChunk) {\n chunksYielded = true;\n retryable = false;\n this.queue.put(chatChunk);\n }\n }\n\n if (finishReason === 'STOP' && !chunksYielded && retryable) {\n throw new APIStatusError({\n message: 'Google LLM: no response generated',\n options: {\n retryable,\n requestId,\n },\n });\n }\n\n if (chunk.usageMetadata) {\n const usage = chunk.usageMetadata;\n this.queue.put({\n id: requestId,\n usage: {\n completionTokens: usage.candidatesTokenCount || 0,\n promptTokens: usage.promptTokenCount || 0,\n promptCachedTokens: usage.cachedContentTokenCount || 0,\n totalTokens: usage.totalTokenCount || 0,\n },\n });\n }\n }\n } catch (error: unknown) {\n if (error instanceof APIStatusError || error instanceof APIConnectionError) {\n throw error;\n }\n\n const err = error as {\n code?: number;\n message?: string;\n status?: string;\n type?: string;\n };\n\n if (err.code && err.code >= 400 && err.code < 500) {\n if (err.code === 429) {\n throw new APIStatusError({\n message: `Google LLM: Rate limit error - ${err.message || 'Unknown error'}`,\n options: {\n statusCode: 429,\n retryable: true,\n },\n });\n } else {\n throw new APIStatusError({\n message: `Google LLM: Client error (${err.code}) - ${err.message || 'Unknown error'}`,\n options: {\n statusCode: err.code,\n retryable: false,\n },\n });\n }\n }\n\n if (err.code && err.code >= 500) {\n throw new APIStatusError({\n message: `Google LLM: Server error (${err.code}) - ${err.message || 'Unknown error'}`,\n options: {\n statusCode: err.code,\n retryable,\n },\n });\n }\n\n throw new APIConnectionError({\n message: `Google LLM: API error - ${err.message || 'Unknown error'}`,\n options: {\n retryable,\n },\n });\n }\n }\n\n #parsePart(id: string, part: types.Part): llm.ChatChunk | null {\n if (part.functionCall) {\n return {\n id,\n delta: {\n role: 'assistant',\n toolCalls: [\n llm.FunctionCall.create({\n callId: part.functionCall.id || shortuuid('function_call_'),\n name: part.functionCall.name!,\n args: JSON.stringify(part.functionCall.args!),\n // Preserve thought signature for Gemini 3+ thinking mode\n thoughtSignature: part.thoughtSignature,\n }),\n ],\n },\n };\n }\n\n if (!part.text) {\n return null;\n }\n\n return {\n id,\n delta: {\n content: part.text,\n role: 'assistant',\n },\n };\n }\n}\n"],"mappings":"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","names":["llm"]}
|
|
1
|
+
{"version":3,"sources":["../src/llm.ts"],"sourcesContent":["// SPDX-FileCopyrightText: 2025 LiveKit, Inc.\n//\n// SPDX-License-Identifier: Apache-2.0\nimport type * as types from '@google/genai';\nimport { FunctionCallingConfigMode, type GenerateContentConfig, GoogleGenAI } from '@google/genai';\nimport type { APIConnectOptions } from '@livekit/agents';\nimport {\n APIConnectionError,\n APIStatusError,\n DEFAULT_API_CONNECT_OPTIONS,\n llm,\n shortuuid,\n} from '@livekit/agents';\nimport type { ChatModels } from './models.js';\nimport type { LLMTools } from './tools.js';\nimport { toFunctionDeclarations } from './utils.js';\n\ninterface GoogleFormatData {\n systemMessages: string[] | null;\n}\n\nexport interface LLMOptions {\n model: string | ChatModels;\n apiKey?: string;\n temperature?: number;\n toolChoice?: llm.ToolChoice;\n vertexai?: boolean;\n project?: string;\n location?: string;\n maxOutputTokens?: number;\n topP?: number;\n topK?: number;\n presencePenalty?: number;\n frequencyPenalty?: number;\n thinkingConfig?: types.ThinkingConfig;\n automaticFunctionCallingConfig?: types.AutomaticFunctionCallingConfig;\n geminiTools?: LLMTools;\n httpOptions?: types.HttpOptions;\n seed?: number;\n}\n\nexport class LLM extends llm.LLM {\n #opts: LLMOptions;\n #client: GoogleGenAI;\n\n label(): string {\n return 'google.LLM';\n }\n\n get model(): string {\n return this.#opts.model;\n }\n\n get provider(): string {\n if (this.#opts.vertexai) {\n return 'Vertex AI';\n }\n return 'Gemini';\n }\n\n /**\n * Create a new instance of Google GenAI LLM.\n *\n * Environment Requirements:\n * - For VertexAI: Set the `GOOGLE_APPLICATION_CREDENTIALS` environment variable to the path of the service account key file or use any of the other Google Cloud auth methods.\n * The Google Cloud project and location can be set via `project` and `location` arguments or the environment variables\n * `GOOGLE_CLOUD_PROJECT` and `GOOGLE_CLOUD_LOCATION`. By default, the project is inferred from the service account key file,\n * and the location defaults to \"us-central1\".\n * - For Google Gemini API: Set the `apiKey` argument or the `GOOGLE_API_KEY` environment variable.\n *\n * @param model - The model name to use. Defaults to \"gemini-2.0-flash-001\".\n * @param apiKey - The API key for Google Gemini. If not provided, it attempts to read from the `GOOGLE_API_KEY` environment variable.\n * @param vertexai - Whether to use VertexAI. If not provided, it attempts to read from the `GOOGLE_GENAI_USE_VERTEXAI` environment variable. Defaults to false.\n * @param project - The Google Cloud project to use (only for VertexAI). Defaults to undefined.\n * @param location - The location to use for VertexAI API requests. Default value is \"us-central1\".\n * @param temperature - Sampling temperature for response generation. Defaults to undefined.\n * @param maxOutputTokens - Maximum number of tokens to generate in the output. Defaults to undefined.\n * @param topP - The nucleus sampling probability for response generation. Defaults to undefined.\n * @param topK - The top-k sampling value for response generation. Defaults to undefined.\n * @param presencePenalty - Penalizes the model for generating previously mentioned concepts. Defaults to undefined.\n * @param frequencyPenalty - Penalizes the model for repeating words. Defaults to undefined.\n * @param toolChoice - Specifies whether to use tools during response generation. Defaults to \"auto\".\n * @param thinkingConfig - The thinking configuration for response generation. Gemini 3.1 models use `thinkingLevel`; Gemini 2.5 models use `thinkingBudget`. Defaults to undefined.\n * @param automaticFunctionCallingConfig - The automatic function calling configuration for response generation. Defaults to undefined.\n * @param geminiTools - The Gemini-specific tools to use for the session.\n * @param httpOptions - The HTTP options to use for the session.\n * @param seed - Random seed for reproducible results. Defaults to undefined.\n */\n constructor(\n {\n model,\n apiKey,\n vertexai,\n project,\n location,\n temperature,\n maxOutputTokens,\n topP,\n topK,\n presencePenalty,\n frequencyPenalty,\n toolChoice,\n thinkingConfig,\n automaticFunctionCallingConfig,\n geminiTools,\n httpOptions,\n seed,\n }: LLMOptions = {\n model: 'gemini-2.0-flash-001',\n },\n ) {\n super();\n\n const useVertexAI =\n vertexai ??\n (process.env.GOOGLE_GENAI_USE_VERTEXAI === 'true' ||\n process.env.GOOGLE_GENAI_USE_VERTEXAI === '1');\n\n let gcpProject: string | undefined = project ?? process.env.GOOGLE_CLOUD_PROJECT;\n let gcpLocation: string | undefined = location ?? process.env.GOOGLE_CLOUD_LOCATION;\n let geminiApiKey: string | undefined = apiKey ?? process.env.GOOGLE_API_KEY;\n\n if (useVertexAI) {\n if (!gcpProject) {\n // TODO(brian): use default_async to get the project ID\n throw new Error(\n 'Project ID is required for Vertex AI. Set via project option or GOOGLE_CLOUD_PROJECT environment variable',\n );\n }\n geminiApiKey = undefined;\n } else {\n gcpProject = undefined;\n gcpLocation = undefined;\n if (!geminiApiKey) {\n throw new Error(\n 'API key is required for Google API either via apiKey or GOOGLE_API_KEY environment variable',\n );\n }\n }\n\n // Validate thinkingConfig\n if (thinkingConfig?.thinkingBudget !== undefined) {\n const budget = thinkingConfig.thinkingBudget;\n if (budget < 0 || budget > 24576) {\n throw new Error('thinkingBudget inside thinkingConfig must be between 0 and 24576');\n }\n }\n\n const clientOptions: types.GoogleGenAIOptions = useVertexAI\n ? {\n vertexai: true,\n project: gcpProject,\n location: gcpLocation,\n }\n : {\n apiKey: geminiApiKey,\n };\n\n this.#client = new GoogleGenAI(clientOptions);\n\n this.#opts = {\n model,\n vertexai: useVertexAI,\n project: gcpProject,\n location: gcpLocation,\n temperature,\n maxOutputTokens,\n topP,\n topK,\n presencePenalty,\n frequencyPenalty,\n toolChoice,\n thinkingConfig,\n automaticFunctionCallingConfig,\n geminiTools,\n httpOptions,\n seed,\n apiKey,\n };\n }\n\n chat({\n chatCtx,\n toolCtx,\n connOptions = DEFAULT_API_CONNECT_OPTIONS,\n toolChoice,\n extraKwargs,\n geminiTools,\n }: {\n chatCtx: llm.ChatContext;\n toolCtx?: llm.ToolContext;\n connOptions?: APIConnectOptions;\n parallelToolCalls?: boolean;\n toolChoice?: llm.ToolChoice;\n extraKwargs?: Record<string, unknown>;\n geminiTools?: LLMTools;\n }): LLMStream {\n const extras: GenerateContentConfig = { ...extraKwargs } as GenerateContentConfig;\n\n toolChoice = toolChoice !== undefined ? toolChoice : this.#opts.toolChoice;\n\n if (toolChoice) {\n let geminiToolConfig: types.ToolConfig;\n\n if (typeof toolChoice === 'object' && toolChoice.type === 'function') {\n geminiToolConfig = {\n functionCallingConfig: {\n mode: FunctionCallingConfigMode.ANY,\n allowedFunctionNames: [toolChoice.function.name],\n },\n };\n } else if (toolChoice === 'required') {\n const toolNames = Object.entries(toolCtx || {}).map(([name]) => name);\n geminiToolConfig = {\n functionCallingConfig: {\n mode: FunctionCallingConfigMode.ANY,\n allowedFunctionNames: toolNames.length > 0 ? toolNames : undefined,\n },\n };\n } else if (toolChoice === 'auto') {\n geminiToolConfig = {\n functionCallingConfig: {\n mode: FunctionCallingConfigMode.AUTO,\n },\n };\n } else if (toolChoice === 'none') {\n geminiToolConfig = {\n functionCallingConfig: {\n mode: FunctionCallingConfigMode.NONE,\n },\n };\n } else {\n throw new Error(`Invalid tool choice: ${toolChoice}`);\n }\n\n extras.toolConfig = geminiToolConfig;\n }\n\n if (this.#opts.temperature !== undefined) {\n extras.temperature = this.#opts.temperature;\n }\n if (this.#opts.maxOutputTokens !== undefined) {\n extras.maxOutputTokens = this.#opts.maxOutputTokens;\n }\n if (this.#opts.topP !== undefined) {\n extras.topP = this.#opts.topP;\n }\n if (this.#opts.topK !== undefined) {\n extras.topK = this.#opts.topK;\n }\n if (this.#opts.presencePenalty !== undefined) {\n extras.presencePenalty = this.#opts.presencePenalty;\n }\n if (this.#opts.frequencyPenalty !== undefined) {\n extras.frequencyPenalty = this.#opts.frequencyPenalty;\n }\n if (this.#opts.seed !== undefined) {\n extras.seed = this.#opts.seed;\n }\n\n if (this.#opts.thinkingConfig !== undefined) {\n extras.thinkingConfig = this.#opts.thinkingConfig;\n }\n\n if (this.#opts.automaticFunctionCallingConfig !== undefined) {\n extras.automaticFunctionCalling = this.#opts.automaticFunctionCallingConfig;\n }\n\n geminiTools = geminiTools !== undefined ? geminiTools : this.#opts.geminiTools;\n\n return new LLMStream(this, {\n client: this.#client,\n model: this.#opts.model,\n chatCtx,\n toolCtx,\n connOptions,\n geminiTools,\n extraKwargs: extras,\n });\n }\n}\n\nconst BLOCKED_REASONS = [\n 'SAFETY',\n 'SPII',\n 'PROHIBITED_CONTENT',\n 'BLOCKLIST',\n 'LANGUAGE',\n 'RECITATION',\n];\n\nexport class LLMStream extends llm.LLMStream {\n #client: GoogleGenAI;\n #model: string;\n #geminiTools?: LLMTools;\n #extraKwargs: GenerateContentConfig;\n\n constructor(\n llm: LLM,\n {\n client,\n model,\n chatCtx,\n toolCtx,\n connOptions,\n geminiTools,\n extraKwargs,\n }: {\n client: GoogleGenAI;\n model: string;\n chatCtx: llm.ChatContext;\n toolCtx?: llm.ToolContext;\n connOptions: APIConnectOptions;\n geminiTools?: LLMTools;\n extraKwargs: GenerateContentConfig;\n },\n ) {\n // Call base constructor with dev 1.0 object parameter pattern\n super(llm, { chatCtx, toolCtx, connOptions });\n this.#client = client;\n this.#model = model;\n this.#geminiTools = geminiTools;\n this.#extraKwargs = extraKwargs;\n }\n\n protected async run(): Promise<void> {\n let retryable = true;\n const requestId = `google_${Date.now()}`;\n\n try {\n const [turns, extraData] = (await this.chatCtx.toProviderFormat('google')) as [\n Record<string, unknown>[],\n GoogleFormatData,\n ];\n\n const contents: types.Content[] = turns.map((turn: Record<string, unknown>) => ({\n role: turn.role as types.Content['role'],\n parts: turn.parts as types.Part[],\n }));\n\n const functionDeclarations = this.toolCtx ? toFunctionDeclarations(this.toolCtx) : undefined;\n const tools =\n functionDeclarations && functionDeclarations.length > 0\n ? [{ functionDeclarations }]\n : undefined;\n\n let systemInstruction: types.Content | undefined = undefined;\n if (extraData.systemMessages && extraData.systemMessages.length > 0) {\n systemInstruction = {\n parts: extraData.systemMessages.map((content: string) => ({ text: content })),\n };\n }\n\n const response = await this.#client.models.generateContentStream({\n model: this.#model,\n contents,\n config: {\n ...this.#extraKwargs,\n systemInstruction,\n httpOptions: this.#extraKwargs.httpOptions ?? {\n timeout: Math.floor(this.connOptions.timeoutMs),\n },\n tools,\n },\n });\n\n for await (const chunk of response) {\n if (chunk.promptFeedback) {\n throw new APIStatusError({\n message: `Prompt feedback error: ${JSON.stringify(chunk.promptFeedback)}`,\n options: {\n retryable: false,\n requestId,\n },\n });\n }\n\n // Check for blocked reasons first — safety-blocked responses often lack content.parts,\n // so this must run before the no-content guard to avoid wasting retries.\n if (\n chunk.candidates?.[0]?.finishReason &&\n BLOCKED_REASONS.includes(chunk.candidates[0].finishReason)\n ) {\n throw new APIStatusError({\n message: `Google LLM: generation blocked - ${chunk.candidates[0].finishReason}`,\n options: {\n retryable: false,\n requestId,\n },\n });\n }\n\n if (!chunk.candidates || !chunk.candidates[0]?.content?.parts) {\n this.logger.warn(`No content in the response: ${JSON.stringify(chunk)}`);\n if (retryable) {\n throw new APIStatusError({\n message: 'Google LLM: no content in the response',\n options: {\n retryable: true,\n requestId,\n },\n });\n }\n continue;\n }\n\n if (chunk.candidates.length > 1) {\n this.logger.warn(\n 'Google LLM: there are multiple candidates in the response, returning response from the first one.',\n );\n }\n\n const candidate = chunk.candidates[0];\n const finishReason = candidate.finishReason;\n\n let chunksYielded = false;\n for (const part of candidate.content!.parts!) {\n const chatChunk = this.#parsePart(requestId, part);\n if (chatChunk) {\n chunksYielded = true;\n retryable = false;\n this.queue.put(chatChunk);\n }\n }\n\n if (finishReason === 'STOP' && !chunksYielded && retryable) {\n throw new APIStatusError({\n message: 'Google LLM: no response generated',\n options: {\n retryable,\n requestId,\n },\n });\n }\n\n if (chunk.usageMetadata) {\n const usage = chunk.usageMetadata;\n this.queue.put({\n id: requestId,\n usage: {\n completionTokens: usage.candidatesTokenCount || 0,\n promptTokens: usage.promptTokenCount || 0,\n promptCachedTokens: usage.cachedContentTokenCount || 0,\n totalTokens: usage.totalTokenCount || 0,\n },\n });\n }\n }\n } catch (error: unknown) {\n if (error instanceof APIStatusError || error instanceof APIConnectionError) {\n throw error;\n }\n\n const err = error as {\n code?: number;\n message?: string;\n status?: string;\n type?: string;\n };\n\n if (err.code && err.code >= 400 && err.code < 500) {\n if (err.code === 429) {\n throw new APIStatusError({\n message: `Google LLM: Rate limit error - ${err.message || 'Unknown error'}`,\n options: {\n statusCode: 429,\n retryable: true,\n },\n });\n } else {\n throw new APIStatusError({\n message: `Google LLM: Client error (${err.code}) - ${err.message || 'Unknown error'}`,\n options: {\n statusCode: err.code,\n retryable: false,\n },\n });\n }\n }\n\n if (err.code && err.code >= 500) {\n throw new APIStatusError({\n message: `Google LLM: Server error (${err.code}) - ${err.message || 'Unknown error'}`,\n options: {\n statusCode: err.code,\n retryable,\n },\n });\n }\n\n throw new APIConnectionError({\n message: `Google LLM: API error - ${err.message || 'Unknown error'}`,\n options: {\n retryable,\n },\n });\n }\n }\n\n #parsePart(id: string, part: types.Part): llm.ChatChunk | null {\n if (part.functionCall) {\n return {\n id,\n delta: {\n role: 'assistant',\n toolCalls: [\n llm.FunctionCall.create({\n callId: part.functionCall.id || shortuuid('function_call_'),\n name: part.functionCall.name!,\n args: JSON.stringify(part.functionCall.args!),\n // Preserve thought signature for Gemini 3+ thinking mode\n thoughtSignature: part.thoughtSignature,\n }),\n ],\n },\n };\n }\n\n if (!part.text) {\n return null;\n }\n\n return {\n id,\n delta: {\n content: part.text,\n role: 'assistant',\n },\n };\n }\n}\n"],"mappings":"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","names":["llm"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@livekit/agents-plugin-google",
|
|
3
|
-
"version": "1.2.
|
|
3
|
+
"version": "1.2.5",
|
|
4
4
|
"description": "Google Gemini plugin for LiveKit Node Agents",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"require": "dist/index.cjs",
|
|
@@ -25,13 +25,13 @@
|
|
|
25
25
|
"README.md"
|
|
26
26
|
],
|
|
27
27
|
"devDependencies": {
|
|
28
|
-
"@livekit/rtc-node": "^0.13.
|
|
28
|
+
"@livekit/rtc-node": "^0.13.25",
|
|
29
29
|
"@microsoft/api-extractor": "^7.35.0",
|
|
30
30
|
"tsup": "^8.3.5",
|
|
31
31
|
"typescript": "^5.0.0",
|
|
32
|
-
"@livekit/agents": "1.2.
|
|
33
|
-
"@livekit/agents-plugin-openai": "1.2.
|
|
34
|
-
"@livekit/agents-plugins-test": "1.2.
|
|
32
|
+
"@livekit/agents": "1.2.5",
|
|
33
|
+
"@livekit/agents-plugin-openai": "1.2.5",
|
|
34
|
+
"@livekit/agents-plugins-test": "1.2.5"
|
|
35
35
|
},
|
|
36
36
|
"dependencies": {
|
|
37
37
|
"@google/genai": "^1.44.0",
|
|
@@ -40,8 +40,8 @@
|
|
|
40
40
|
"json-schema": "^0.4.0"
|
|
41
41
|
},
|
|
42
42
|
"peerDependencies": {
|
|
43
|
-
"@livekit/rtc-node": "^0.13.
|
|
44
|
-
"@livekit/agents": "1.2.
|
|
43
|
+
"@livekit/rtc-node": "^0.13.25",
|
|
44
|
+
"@livekit/agents": "1.2.5"
|
|
45
45
|
},
|
|
46
46
|
"scripts": {
|
|
47
47
|
"build": "tsup --onSuccess \"pnpm build:types\"",
|
|
@@ -288,8 +288,8 @@ export class RealtimeModel extends llm.RealtimeModel {
|
|
|
288
288
|
/**
|
|
289
289
|
* Thinking configuration for native audio models.
|
|
290
290
|
* If not set, the model's default thinking behavior is used.
|
|
291
|
-
*
|
|
292
|
-
*
|
|
291
|
+
* Gemini 3.1 live models use `thinkingLevel`.
|
|
292
|
+
* Gemini 2.5 live models use `thinkingBudget`.
|
|
293
293
|
*/
|
|
294
294
|
thinkingConfig?: types.ThinkingConfig;
|
|
295
295
|
} = {},
|
|
@@ -311,6 +311,10 @@ export class RealtimeModel extends llm.RealtimeModel {
|
|
|
311
311
|
autoToolReplyGeneration: true,
|
|
312
312
|
audioOutput: options.modalities?.includes(Modality.AUDIO) ?? true,
|
|
313
313
|
manualFunctionCalls: false,
|
|
314
|
+
midSessionChatCtxUpdate: false,
|
|
315
|
+
midSessionInstructionsUpdate: true,
|
|
316
|
+
midSessionToolsUpdate: false,
|
|
317
|
+
perResponseToolChoice: false,
|
|
314
318
|
});
|
|
315
319
|
|
|
316
320
|
// Environment variable fallbacks
|
|
@@ -543,6 +547,13 @@ export class RealtimeSession extends llm.RealtimeSession {
|
|
|
543
547
|
}
|
|
544
548
|
|
|
545
549
|
async updateInstructions(instructions: string): Promise<void> {
|
|
550
|
+
if (this.options.model === 'gemini-3.1-flash-live-preview') {
|
|
551
|
+
this.#logger.warn(
|
|
552
|
+
'updateInstructions is not compatible with gemini-3.1-flash-live-preview and will be ignored.',
|
|
553
|
+
);
|
|
554
|
+
this.options.instructions = instructions;
|
|
555
|
+
return;
|
|
556
|
+
}
|
|
546
557
|
if (this.options.instructions === undefined || this.options.instructions !== instructions) {
|
|
547
558
|
this.options.instructions = instructions;
|
|
548
559
|
this.markRestartNeeded();
|
|
@@ -550,6 +561,13 @@ export class RealtimeSession extends llm.RealtimeSession {
|
|
|
550
561
|
}
|
|
551
562
|
|
|
552
563
|
async updateChatCtx(chatCtx: llm.ChatContext): Promise<void> {
|
|
564
|
+
if (this.options.model === 'gemini-3.1-flash-live-preview') {
|
|
565
|
+
this.#logger.warn(
|
|
566
|
+
'updateChatCtx is not compatible with gemini-3.1-flash-live-preview and will be ignored.',
|
|
567
|
+
);
|
|
568
|
+
this._chatCtx = chatCtx.copy();
|
|
569
|
+
return;
|
|
570
|
+
}
|
|
553
571
|
const unlock = await this.sessionLock.lock();
|
|
554
572
|
try {
|
|
555
573
|
if (!this.activeSession) {
|
|
@@ -684,9 +702,11 @@ export class RealtimeSession extends llm.RealtimeSession {
|
|
|
684
702
|
async generateReply(instructions?: string): Promise<llm.GenerationCreatedEvent> {
|
|
685
703
|
if (this.options.model === 'gemini-3.1-flash-live-preview') {
|
|
686
704
|
this.#logger.warn(
|
|
687
|
-
'generateReply is not compatible with gemini-3.1-flash-live-preview
|
|
705
|
+
'generateReply is not compatible with gemini-3.1-flash-live-preview. Use a Gemini 2.5 live model for voice-agent flows that require programmatic reply generation.',
|
|
706
|
+
);
|
|
707
|
+
throw new Error(
|
|
708
|
+
"generateReply is not compatible with 'gemini-3.1-flash-live-preview'; use a Gemini 2.5 live model for voice-agent flows that require programmatic reply generation.",
|
|
688
709
|
);
|
|
689
|
-
throw new Error("generateReply is not compatible with 'gemini-3.1-flash-live-preview'");
|
|
690
710
|
}
|
|
691
711
|
|
|
692
712
|
if (this.pendingGenerationFut && !this.pendingGenerationFut.done) {
|
|
@@ -794,6 +814,7 @@ export class RealtimeSession extends llm.RealtimeSession {
|
|
|
794
814
|
this.#closed = true;
|
|
795
815
|
|
|
796
816
|
this.sessionShouldClose.set();
|
|
817
|
+
this.inputResampler?.close();
|
|
797
818
|
|
|
798
819
|
await this.closeActiveSession();
|
|
799
820
|
|
|
@@ -1644,6 +1665,7 @@ export class RealtimeSession extends llm.RealtimeSession {
|
|
|
1644
1665
|
if (this.inputResampler) {
|
|
1645
1666
|
if (frame.sampleRate !== this.inputResamplerInputRate) {
|
|
1646
1667
|
// input audio changed to a different sample rate
|
|
1668
|
+
this.inputResampler.close();
|
|
1647
1669
|
this.inputResampler = undefined;
|
|
1648
1670
|
this.inputResamplerInputRate = undefined;
|
|
1649
1671
|
}
|
package/src/llm.ts
CHANGED
|
@@ -80,7 +80,7 @@ export class LLM extends llm.LLM {
|
|
|
80
80
|
* @param presencePenalty - Penalizes the model for generating previously mentioned concepts. Defaults to undefined.
|
|
81
81
|
* @param frequencyPenalty - Penalizes the model for repeating words. Defaults to undefined.
|
|
82
82
|
* @param toolChoice - Specifies whether to use tools during response generation. Defaults to "auto".
|
|
83
|
-
* @param thinkingConfig - The thinking configuration for response generation. Defaults to undefined.
|
|
83
|
+
* @param thinkingConfig - The thinking configuration for response generation. Gemini 3.1 models use `thinkingLevel`; Gemini 2.5 models use `thinkingBudget`. Defaults to undefined.
|
|
84
84
|
* @param automaticFunctionCallingConfig - The automatic function calling configuration for response generation. Defaults to undefined.
|
|
85
85
|
* @param geminiTools - The Gemini-specific tools to use for the session.
|
|
86
86
|
* @param httpOptions - The HTTP options to use for the session.
|