Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/gemini-3-flash-thinking.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@livekit/agents-plugin-google": patch
---

fix(plugin-google): default Gemini 3 Flash variants to minimal thinking.
6 changes: 6 additions & 0 deletions .changeset/neat-crabs-watch.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
"@livekit/agents": patch
"@livekit/agents-plugin-google": patch
---

fix(llm): log silent error from performLLMInference
3 changes: 3 additions & 0 deletions agents/src/voice/generation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -476,6 +476,7 @@ export function performLLMInference(
model?: string,
provider?: string,
): [Task<void>, _LLMGenerationData] {
const logger = log();
const textStream = new IdentityTransform<string | FlushSentinel>();
const toolCallStream = new IdentityTransform<FunctionCall>();

Expand Down Expand Up @@ -584,6 +585,8 @@ export function performLLMInference(
// Abort signal was triggered, handle gracefully
return;
}
// surface inference silent errors even when this task's rejection is never awaited
logger.error({ error }, 'error in llm node');
throw error;
} finally {
llmStreamReader?.releaseLock();
Expand Down
51 changes: 49 additions & 2 deletions plugins/google/src/llm.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,19 @@
//
// SPDX-License-Identifier: Apache-2.0
import type * as types from '@google/genai';
import { FunctionCallingConfigMode, type GenerateContentConfig, GoogleGenAI } from '@google/genai';
import {
FunctionCallingConfigMode,
type GenerateContentConfig,
GoogleGenAI,
ThinkingLevel,
} from '@google/genai';
import type { APIConnectOptions } from '@livekit/agents';
import {
APIConnectionError,
APIStatusError,
DEFAULT_API_CONNECT_OPTIONS,
llm,
log,
shortuuid,
} from '@livekit/agents';
import type { ChatModels } from './models.js';
Expand All @@ -19,6 +25,16 @@ interface GoogleFormatData {
systemMessages: string[] | null;
}

function isGemini3Model(model: string): boolean {
const modelLower = model.toLowerCase();
return modelLower.includes('gemini-3');
}

function isGemini3FlashModel(model: string): boolean {
const modelLower = model.toLowerCase();
return modelLower.includes('gemini-3') && modelLower.includes('flash');
}
Comment thread
devin-ai-integration[bot] marked this conversation as resolved.

export interface LLMOptions {
model: string | ChatModels;
apiKey?: string;
Expand Down Expand Up @@ -275,7 +291,38 @@ export class LLM extends llm.LLM {
}

if (this.#opts.thinkingConfig !== undefined) {
extras.thinkingConfig = this.#opts.thinkingConfig;
const { includeThoughts, thinkingBudget, thinkingLevel } = this.#opts.thinkingConfig;

if (isGemini3Model(this.#opts.model)) {
// Gemini 3: only supports thinkingLevel
if (thinkingBudget !== undefined && thinkingLevel === undefined) {
log().warn(
`Model ${this.#opts.model} is Gemini 3 which does not support thinkingBudget. ` +
`Please use thinkingLevel ('low' or 'high') instead. Ignoring thinkingBudget.`,
);
}
extras.thinkingConfig = {
includeThoughts,
thinkingLevel:
thinkingLevel ??
(isGemini3FlashModel(this.#opts.model) ? ThinkingLevel.MINIMAL : ThinkingLevel.LOW),
};
} else {
// Gemini 2.5 and earlier: only supports thinkingBudget
if (thinkingLevel !== undefined && thinkingBudget === undefined) {
log().warn(
`Model ${this.#opts.model} does not support thinkingLevel. ` +
`Please use thinkingBudget (number) instead for Gemini 2.5 and earlier models. ` +
`Ignoring thinkingLevel.`,
);
Comment thread
devin-ai-integration[bot] marked this conversation as resolved.
extras.thinkingConfig = { includeThoughts };
} else if (thinkingBudget !== undefined) {
// Preserve includeThoughts so callers relying on visible reasoning keep receiving it.
extras.thinkingConfig = { thinkingBudget, includeThoughts };
} else {
extras.thinkingConfig = this.#opts.thinkingConfig;
}
}
}
Comment thread
chenghao-mou marked this conversation as resolved.

if (this.#opts.automaticFunctionCallingConfig !== undefined) {
Expand Down
Loading