mirror of
https://github.com/google-gemini/gemini-cli.git
synced 2026-05-19 08:14:35 -07:00
feat(acp): extract and stream plan events from agent thoughts
- Updated default model configurations (Gemini 3/3.1) to enforce `includeThoughts: true` and `ThinkingLevel.HIGH` and updated schema, doc and tests to reflect this. - Extended the code assist converters to safely extract and format the `thought` field, preventing type errors during `CountToken` API calls. - Implemented real-time `extractPlanEntries` parsing using regex that gracefully extracts markdown task lists (e.g., `[TODO]`, `[x]`, `[]`) while safely ignoring content inside code blocks. - Added logic in the ACP client that incrementally reads the agent's thought buffer and emits `sessionUpdate: 'plan'` events directly to the IDE whenever the tracked tasks change. - Formatted `agent_thought_chunk` outputs to replace escaped literal newlines (`\n`) with actual native newlines, ensuring the IDE chat displays main thought sections cleanly without visual artifacts. - Added comprehensive unit tests for the plan parser and ACP integration.
This commit is contained in:
@@ -444,9 +444,6 @@ their corresponding top-level category object in your `settings.json` file.
|
||||
"extends": "base",
|
||||
"modelConfig": {
|
||||
"generateContentConfig": {
|
||||
"thinkingConfig": {
|
||||
"includeThoughts": true
|
||||
},
|
||||
"temperature": 1,
|
||||
"topP": 0.95,
|
||||
"topK": 64
|
||||
@@ -458,6 +455,7 @@ their corresponding top-level category object in your `settings.json` file.
|
||||
"modelConfig": {
|
||||
"generateContentConfig": {
|
||||
"thinkingConfig": {
|
||||
"includeThoughts": true,
|
||||
"thinkingBudget": 8192
|
||||
}
|
||||
}
|
||||
@@ -468,6 +466,31 @@ their corresponding top-level category object in your `settings.json` file.
|
||||
"modelConfig": {
|
||||
"generateContentConfig": {
|
||||
"thinkingConfig": {
|
||||
"includeThoughts": true,
|
||||
"thinkingLevel": "HIGH"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"gemini-3.1-pro-preview": {
|
||||
"extends": "chat-base-3",
|
||||
"modelConfig": {
|
||||
"model": "gemini-3.1-pro-preview",
|
||||
"generateContentConfig": {
|
||||
"thinkingConfig": {
|
||||
"includeThoughts": true,
|
||||
"thinkingLevel": "HIGH"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"gemini-3.1-pro-preview-customtools": {
|
||||
"extends": "chat-base-3",
|
||||
"modelConfig": {
|
||||
"model": "gemini-3.1-pro-preview-customtools",
|
||||
"generateContentConfig": {
|
||||
"thinkingConfig": {
|
||||
"includeThoughts": true,
|
||||
"thinkingLevel": "HIGH"
|
||||
}
|
||||
}
|
||||
@@ -476,13 +499,37 @@ their corresponding top-level category object in your `settings.json` file.
|
||||
"gemini-3-pro-preview": {
|
||||
"extends": "chat-base-3",
|
||||
"modelConfig": {
|
||||
"model": "gemini-3-pro-preview"
|
||||
"model": "gemini-3-pro-preview",
|
||||
"generateContentConfig": {
|
||||
"thinkingConfig": {
|
||||
"includeThoughts": true,
|
||||
"thinkingLevel": "HIGH"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"gemini-3-flash-preview": {
|
||||
"extends": "chat-base-3",
|
||||
"modelConfig": {
|
||||
"model": "gemini-3-flash-preview"
|
||||
"model": "gemini-3-flash-preview",
|
||||
"generateContentConfig": {
|
||||
"thinkingConfig": {
|
||||
"includeThoughts": true,
|
||||
"thinkingLevel": "HIGH"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"gemini-3.1-flash-lite-preview": {
|
||||
"extends": "chat-base-3",
|
||||
"modelConfig": {
|
||||
"model": "gemini-3.1-flash-lite-preview",
|
||||
"generateContentConfig": {
|
||||
"thinkingConfig": {
|
||||
"includeThoughts": true,
|
||||
"thinkingLevel": "HIGH"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"gemini-2.5-pro": {
|
||||
@@ -512,7 +559,13 @@ their corresponding top-level category object in your `settings.json` file.
|
||||
"gemini-3-flash-base": {
|
||||
"extends": "base",
|
||||
"modelConfig": {
|
||||
"model": "gemini-3-flash-preview"
|
||||
"model": "gemini-3-flash-preview",
|
||||
"generateContentConfig": {
|
||||
"thinkingConfig": {
|
||||
"includeThoughts": true,
|
||||
"thinkingLevel": "HIGH"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"classifier": {
|
||||
|
||||
@@ -91,52 +91,44 @@ vi.mock('../ui/commands/initCommand.js', () => ({
|
||||
action: vi.fn(),
|
||||
},
|
||||
}));
|
||||
vi.mock(
|
||||
'@google/gemini-cli-core',
|
||||
async (
|
||||
importOriginal: () => Promise<typeof import('@google/gemini-cli-core')>,
|
||||
) => {
|
||||
const actual = await importOriginal();
|
||||
return {
|
||||
...actual,
|
||||
ReadManyFilesTool: vi.fn().mockImplementation(() => ({
|
||||
name: 'read_many_files',
|
||||
kind: 'read',
|
||||
build: vi.fn().mockReturnValue({
|
||||
getDescription: () => 'Read files',
|
||||
toolLocations: () => [],
|
||||
execute: vi.fn().mockResolvedValue({
|
||||
llmContent: ['--- file.txt ---\n\nFile content\n\n'],
|
||||
}),
|
||||
}),
|
||||
})),
|
||||
logToolCall: vi.fn(),
|
||||
isWithinRoot: vi.fn().mockReturnValue(true),
|
||||
LlmRole: {
|
||||
MAIN: 'main',
|
||||
SUBAGENT: 'subagent',
|
||||
UTILITY_TOOL: 'utility_tool',
|
||||
UTILITY_COMPRESSOR: 'utility_compressor',
|
||||
UTILITY_SUMMARIZER: 'utility_summarizer',
|
||||
UTILITY_ROUTER: 'utility_router',
|
||||
UTILITY_LOOP_DETECTOR: 'utility_loop_detector',
|
||||
UTILITY_NEXT_SPEAKER: 'utility_next_speaker',
|
||||
UTILITY_EDIT_CORRECTOR: 'utility_edit_corrector',
|
||||
UTILITY_AUTOCOMPLETE: 'utility_autocomplete',
|
||||
UTILITY_FAST_ACK_HELPER: 'utility_fast_ack_helper',
|
||||
},
|
||||
CoreToolCallStatus: {
|
||||
Validating: 'validating',
|
||||
Scheduled: 'scheduled',
|
||||
Error: 'error',
|
||||
Success: 'success',
|
||||
Executing: 'executing',
|
||||
Cancelled: 'cancelled',
|
||||
AwaitingApproval: 'awaiting_approval',
|
||||
},
|
||||
};
|
||||
const { actualCore } = await vi.hoisted(async () => {
|
||||
const actual = await import('@google/gemini-cli-core');
|
||||
return { actualCore: actual };
|
||||
});
|
||||
|
||||
vi.mock('@google/gemini-cli-core', () => ({
|
||||
...actualCore,
|
||||
ReadManyFilesTool: vi.fn().mockImplementation(() => ({
|
||||
name: 'read_many_files',
|
||||
kind: 'read',
|
||||
build: vi.fn().mockReturnValue({
|
||||
getDescription: () => 'Read files',
|
||||
toolLocations: () => [],
|
||||
execute: vi.fn().mockResolvedValue({
|
||||
llmContent: ['--- file.txt ---\n\nFile content\n\n'],
|
||||
}),
|
||||
}),
|
||||
})),
|
||||
logToolCall: vi.fn(),
|
||||
isWithinRoot: vi.fn().mockReturnValue(true),
|
||||
// Ensure critical enums/objects are present if they were overridden
|
||||
LlmRole: {
|
||||
...actualCore.LlmRole,
|
||||
MAIN: 'main',
|
||||
SUBAGENT: 'subagent',
|
||||
UTILITY_TOOL: 'utility_tool',
|
||||
},
|
||||
);
|
||||
CoreToolCallStatus: {
|
||||
...actualCore.CoreToolCallStatus,
|
||||
Validating: 'validating',
|
||||
Scheduled: 'scheduled',
|
||||
Error: 'error',
|
||||
Success: 'success',
|
||||
Executing: 'executing',
|
||||
Cancelled: 'cancelled',
|
||||
AwaitingApproval: 'awaiting_approval',
|
||||
},
|
||||
}));
|
||||
|
||||
// Helper to create mock streams
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
@@ -1588,4 +1580,43 @@ describe('Session', () => {
|
||||
|
||||
expect(handleCommandSpy).toHaveBeenCalledWith('/memory', expect.anything());
|
||||
});
|
||||
|
||||
it('should extract and emit plan events from thought chunks', async () => {
|
||||
const stream = createMockStream([
|
||||
{
|
||||
type: StreamEventType.CHUNK,
|
||||
value: {
|
||||
candidates: [
|
||||
{
|
||||
content: {
|
||||
parts: [
|
||||
{
|
||||
thought: '- [TODO] First task\n- [x] Done task',
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
]);
|
||||
mockChat.sendMessageStream.mockResolvedValue(stream);
|
||||
|
||||
await session.prompt({
|
||||
sessionId: 'session-1',
|
||||
prompt: [{ type: 'text', text: 'Hi' }],
|
||||
});
|
||||
|
||||
expect(mockConnection.sessionUpdate).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
update: expect.objectContaining({
|
||||
sessionUpdate: 'plan',
|
||||
entries: [
|
||||
{ content: 'First task', status: 'pending', priority: 'medium' },
|
||||
{ content: 'Done task', status: 'completed', priority: 'medium' },
|
||||
],
|
||||
}),
|
||||
}),
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -49,6 +49,8 @@ import {
|
||||
getDisplayString,
|
||||
} from '@google/gemini-cli-core';
|
||||
import * as acp from '@agentclientprotocol/sdk';
|
||||
import { z } from 'zod';
|
||||
import { extractPlanEntries } from './planParser.js';
|
||||
import { AcpFileSystemService } from './fileSystemService.js';
|
||||
import { getAcpErrorMessage } from './acpErrors.js';
|
||||
import { Readable, Writable } from 'node:stream';
|
||||
@@ -64,7 +66,6 @@ import {
|
||||
} from '../config/settings.js';
|
||||
import * as fs from 'node:fs/promises';
|
||||
import * as path from 'node:path';
|
||||
import { z } from 'zod';
|
||||
|
||||
import { randomUUID } from 'node:crypto';
|
||||
import { loadCliConfig, type CliArgs } from '../config/config.js';
|
||||
@@ -716,7 +717,7 @@ export class Session {
|
||||
(await this.config.getGemini31Launched?.()) ?? false,
|
||||
);
|
||||
const responseStream = await chat.sendMessageStream(
|
||||
{ model },
|
||||
{ model, isChatModel: true },
|
||||
nextMessage?.parts ?? [],
|
||||
promptId,
|
||||
pendingSend.signal,
|
||||
@@ -724,6 +725,9 @@ export class Session {
|
||||
);
|
||||
nextMessage = null;
|
||||
|
||||
let currentThoughtTextBuffer = '';
|
||||
let currentTurnPlanStr = '';
|
||||
|
||||
for await (const resp of responseStream) {
|
||||
if (pendingSend.signal.aborted) {
|
||||
return { stopReason: CoreToolCallStatus.Cancelled };
|
||||
@@ -736,13 +740,52 @@ export class Session {
|
||||
) {
|
||||
const candidate = resp.value.candidates[0];
|
||||
for (const part of candidate.content?.parts ?? []) {
|
||||
if (!part.text) {
|
||||
const thoughtValue = (part as { thought?: unknown }).thought;
|
||||
debugLogger.log(
|
||||
`[ACP] Received part: thought=${
|
||||
thoughtValue ? typeof thoughtValue : 'undefined'
|
||||
}, text=${part.text ? 'present' : 'empty'}`,
|
||||
);
|
||||
if (typeof thoughtValue === 'string') {
|
||||
debugLogger.log(
|
||||
`[ACP] Thought content: ${thoughtValue.substring(0, 50)}...`,
|
||||
);
|
||||
}
|
||||
|
||||
if (part.thought) {
|
||||
const thoughtSubText =
|
||||
typeof part.thought === 'string'
|
||||
? part.thought
|
||||
: (part.text ?? '');
|
||||
currentThoughtTextBuffer += thoughtSubText;
|
||||
const entries = extractPlanEntries(currentThoughtTextBuffer);
|
||||
if (entries) {
|
||||
const newPlanStr = JSON.stringify(entries);
|
||||
if (newPlanStr !== currentTurnPlanStr) {
|
||||
currentTurnPlanStr = newPlanStr;
|
||||
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
||||
this.sendUpdate({
|
||||
sessionUpdate: 'plan',
|
||||
entries,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const textToStream =
|
||||
typeof part.thought === 'string'
|
||||
? part.thought
|
||||
: (part.text ?? '');
|
||||
|
||||
if (!textToStream) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const content: acp.ContentBlock = {
|
||||
type: 'text',
|
||||
text: part.text,
|
||||
text: part.thought
|
||||
? textToStream.replace(/\\n/g, '\n')
|
||||
: textToStream,
|
||||
};
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright 2026 Google LLC
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
import { describe, it, expect } from 'vitest';
|
||||
import { extractPlanEntries } from './planParser.js';
|
||||
|
||||
describe('planParser', () => {
|
||||
it('should extract simple tasks', () => {
|
||||
const text = `
|
||||
- [ ] Task 1
|
||||
- [x] Task 2
|
||||
- [/] Task 3
|
||||
`;
|
||||
const entries = extractPlanEntries(text);
|
||||
expect(entries).toEqual([
|
||||
{ content: 'Task 1', status: 'pending', priority: 'medium' },
|
||||
{ content: 'Task 2', status: 'completed', priority: 'medium' },
|
||||
{ content: 'Task 3', status: 'in_progress', priority: 'medium' },
|
||||
]);
|
||||
});
|
||||
|
||||
it('should ignore tasks in code blocks', () => {
|
||||
const text = `
|
||||
- [ ] Valid task
|
||||
\`\`\`
|
||||
- [ ] Ignored task
|
||||
\`\`\`
|
||||
`;
|
||||
const entries = extractPlanEntries(text);
|
||||
expect(entries).toEqual([
|
||||
{ content: 'Valid task', status: 'pending', priority: 'medium' },
|
||||
]);
|
||||
});
|
||||
|
||||
it('should handle alternative status labels', () => {
|
||||
const text = `
|
||||
1. [TODO] Task 1
|
||||
2. [DONE] Task 2
|
||||
3. [IN_PROGRESS] Task 3
|
||||
`;
|
||||
const entries = extractPlanEntries(text);
|
||||
expect(entries).toEqual([
|
||||
{ content: 'Task 1', status: 'pending', priority: 'medium' },
|
||||
{ content: 'Task 2', status: 'completed', priority: 'medium' },
|
||||
{ content: 'Task 3', status: 'in_progress', priority: 'medium' },
|
||||
]);
|
||||
});
|
||||
|
||||
it('should return null if no tasks are found', () => {
|
||||
const text = 'Just some text without tasks.';
|
||||
expect(extractPlanEntries(text)).toBeNull();
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,56 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright 2026 Google LLC
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
import { type PlanEntry } from '@agentclientprotocol/sdk';
|
||||
|
||||
/**
|
||||
* Extracts plan entries from the provided markdown text.
|
||||
* It ignores content within triple-backtick code blocks.
|
||||
*/
|
||||
export function extractPlanEntries(text: string): PlanEntry[] | null {
|
||||
// 1. Strip triple-backtick code blocks to avoid false positives.
|
||||
const textWithoutCodeBlocks = text.replace(/```[\s\S]*?(?:```|$)/g, '');
|
||||
|
||||
// 2. Match markdown list items with task indicators.
|
||||
// Supports: - [ ], - [x], - [/], 1. [TODO], 2. [DONE], - [] etc.
|
||||
const taskRegex =
|
||||
/^\s*(?:[-*]|\d+\.)\s*\[\s*(x|X|\/| |DONE|TODO|IN_PROGRESS|IN PROGRESS|PENDING|COMPLETED)?\s*\]\s+(.*?)$/gm;
|
||||
|
||||
const entries: PlanEntry[] = [];
|
||||
let match;
|
||||
|
||||
while ((match = taskRegex.exec(textWithoutCodeBlocks)) !== null) {
|
||||
const rawStatus = (match[1] || '').toUpperCase().trim();
|
||||
const content = match[2].trim();
|
||||
|
||||
if (!content) continue;
|
||||
|
||||
let status: 'pending' | 'in_progress' | 'completed' = 'pending';
|
||||
|
||||
switch (rawStatus) {
|
||||
case 'X':
|
||||
case 'DONE':
|
||||
case 'COMPLETED':
|
||||
status = 'completed';
|
||||
break;
|
||||
case '/':
|
||||
case 'IN_PROGRESS':
|
||||
case 'IN PROGRESS':
|
||||
status = 'in_progress';
|
||||
break;
|
||||
case '':
|
||||
case 'TODO':
|
||||
case 'PENDING':
|
||||
default:
|
||||
status = 'pending';
|
||||
break;
|
||||
}
|
||||
|
||||
entries.push({ content, status, priority: 'medium' });
|
||||
}
|
||||
|
||||
return entries.length > 0 ? entries : null;
|
||||
}
|
||||
@@ -18,20 +18,8 @@ Spinner Connecting to MCP servers... (0/5) - Waiting for: s1, s2, s3, +2 more
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`ConfigInitDisplay > truncates list of waiting servers if too many 2`] = `
|
||||
"
|
||||
Spinner Connecting to MCP servers... (0/5) - Waiting for: s1, s2, s3, +2 more
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`ConfigInitDisplay > updates message on McpClientUpdate event 1`] = `
|
||||
"
|
||||
Spinner Connecting to MCP servers... (1/2) - Waiting for: server2
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`ConfigInitDisplay > updates message on McpClientUpdate event 2`] = `
|
||||
"
|
||||
Spinner Connecting to MCP servers... (1/2) - Waiting for: server2
|
||||
"
|
||||
`;
|
||||
|
||||
@@ -221,6 +221,15 @@ describe('converter', () => {
|
||||
frequencyPenalty: 0.8,
|
||||
seed: 9,
|
||||
responseMimeType: 'application/json',
|
||||
responseSchema: undefined,
|
||||
responseJsonSchema: undefined,
|
||||
routingConfig: undefined,
|
||||
modelSelectionConfig: undefined,
|
||||
responseModalities: undefined,
|
||||
mediaResolution: undefined,
|
||||
speechConfig: undefined,
|
||||
audioTimestamp: undefined,
|
||||
thinkingConfig: undefined,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -164,6 +164,7 @@ function toVertexGenerateContentRequest(
|
||||
req: GenerateContentParameters,
|
||||
sessionId?: string,
|
||||
): VertexGenerateContentRequest {
|
||||
const generationConfig = toVertexGenerationConfig(req.config);
|
||||
return {
|
||||
contents: toContents(req.contents),
|
||||
systemInstruction: maybeToContent(req.config?.systemInstruction),
|
||||
@@ -172,7 +173,7 @@ function toVertexGenerateContentRequest(
|
||||
toolConfig: req.config?.toolConfig,
|
||||
labels: req.config?.labels,
|
||||
safetySettings: req.config?.safetySettings,
|
||||
generationConfig: toVertexGenerationConfig(req.config),
|
||||
generationConfig,
|
||||
session_id: sessionId,
|
||||
};
|
||||
}
|
||||
@@ -247,8 +248,9 @@ function toPart(part: PartUnion): Part {
|
||||
// Handle thought parts for CountToken API compatibility
|
||||
// The CountToken API expects parts to have certain required "oneof" fields initialized,
|
||||
// but thought parts don't conform to this schema and cause API failures
|
||||
if ('thought' in part && part.thought) {
|
||||
const thoughtText = `[Thought: ${part.thought}]`;
|
||||
const thoughtValue = (part as { thought?: unknown }).thought;
|
||||
if ('thought' in part && thoughtValue) {
|
||||
const thoughtText = `[Thought: ${String(thoughtValue)}]`;
|
||||
|
||||
const newPart = { ...part };
|
||||
delete (newPart as Record<string, unknown>)['thought'];
|
||||
@@ -287,6 +289,7 @@ function toVertexGenerationConfig(
|
||||
if (!config) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
return {
|
||||
temperature: config.temperature,
|
||||
topP: config.topP,
|
||||
|
||||
@@ -25,9 +25,6 @@ export const DEFAULT_MODEL_CONFIGS: ModelConfigServiceConfig = {
|
||||
extends: 'base',
|
||||
modelConfig: {
|
||||
generateContentConfig: {
|
||||
thinkingConfig: {
|
||||
includeThoughts: true,
|
||||
},
|
||||
temperature: 1,
|
||||
topP: 0.95,
|
||||
topK: 64,
|
||||
@@ -39,6 +36,7 @@ export const DEFAULT_MODEL_CONFIGS: ModelConfigServiceConfig = {
|
||||
modelConfig: {
|
||||
generateContentConfig: {
|
||||
thinkingConfig: {
|
||||
includeThoughts: true,
|
||||
thinkingBudget: DEFAULT_THINKING_MODE,
|
||||
},
|
||||
},
|
||||
@@ -49,6 +47,7 @@ export const DEFAULT_MODEL_CONFIGS: ModelConfigServiceConfig = {
|
||||
modelConfig: {
|
||||
generateContentConfig: {
|
||||
thinkingConfig: {
|
||||
includeThoughts: true,
|
||||
thinkingLevel: ThinkingLevel.HIGH,
|
||||
},
|
||||
},
|
||||
@@ -59,16 +58,64 @@ export const DEFAULT_MODEL_CONFIGS: ModelConfigServiceConfig = {
|
||||
// ensure these model configs can be used interactively.
|
||||
// TODO(joshualitt): Introduce internal base configs for the various models,
|
||||
// note: we will have to think carefully about names.
|
||||
'gemini-3.1-pro-preview': {
|
||||
extends: 'chat-base-3',
|
||||
modelConfig: {
|
||||
model: 'gemini-3.1-pro-preview',
|
||||
generateContentConfig: {
|
||||
thinkingConfig: {
|
||||
includeThoughts: true,
|
||||
thinkingLevel: ThinkingLevel.HIGH,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
'gemini-3.1-pro-preview-customtools': {
|
||||
extends: 'chat-base-3',
|
||||
modelConfig: {
|
||||
model: 'gemini-3.1-pro-preview-customtools',
|
||||
generateContentConfig: {
|
||||
thinkingConfig: {
|
||||
includeThoughts: true,
|
||||
thinkingLevel: ThinkingLevel.HIGH,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
'gemini-3-pro-preview': {
|
||||
extends: 'chat-base-3',
|
||||
modelConfig: {
|
||||
model: 'gemini-3-pro-preview',
|
||||
generateContentConfig: {
|
||||
thinkingConfig: {
|
||||
includeThoughts: true,
|
||||
thinkingLevel: ThinkingLevel.HIGH,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
'gemini-3-flash-preview': {
|
||||
extends: 'chat-base-3',
|
||||
modelConfig: {
|
||||
model: 'gemini-3-flash-preview',
|
||||
generateContentConfig: {
|
||||
thinkingConfig: {
|
||||
includeThoughts: true,
|
||||
thinkingLevel: ThinkingLevel.HIGH,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
'gemini-3.1-flash-lite-preview': {
|
||||
extends: 'chat-base-3',
|
||||
modelConfig: {
|
||||
model: 'gemini-3.1-flash-lite-preview',
|
||||
generateContentConfig: {
|
||||
thinkingConfig: {
|
||||
includeThoughts: true,
|
||||
thinkingLevel: ThinkingLevel.HIGH,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
'gemini-2.5-pro': {
|
||||
@@ -100,6 +147,12 @@ export const DEFAULT_MODEL_CONFIGS: ModelConfigServiceConfig = {
|
||||
extends: 'base',
|
||||
modelConfig: {
|
||||
model: 'gemini-3-flash-preview',
|
||||
generateContentConfig: {
|
||||
thinkingConfig: {
|
||||
includeThoughts: true,
|
||||
thinkingLevel: ThinkingLevel.HIGH,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
classifier: {
|
||||
|
||||
@@ -1039,9 +1039,13 @@ export class GeminiChat {
|
||||
}
|
||||
|
||||
const thoughtPart = content.parts[0];
|
||||
if (thoughtPart.text) {
|
||||
const rawText =
|
||||
typeof thoughtPart.thought === 'string'
|
||||
? thoughtPart.thought
|
||||
: thoughtPart.text;
|
||||
|
||||
if (rawText) {
|
||||
// Extract subject and description using the same logic as turn.ts
|
||||
const rawText = thoughtPart.text;
|
||||
const subjectStringMatches = rawText.match(/\*\*(.*?)\*\*/s);
|
||||
const subject = subjectStringMatches
|
||||
? subjectStringMatches[1].trim()
|
||||
|
||||
@@ -9,9 +9,6 @@
|
||||
"generateContentConfig": {
|
||||
"temperature": 1,
|
||||
"topP": 0.95,
|
||||
"thinkingConfig": {
|
||||
"includeThoughts": true
|
||||
},
|
||||
"topK": 64
|
||||
}
|
||||
},
|
||||
@@ -19,22 +16,46 @@
|
||||
"generateContentConfig": {
|
||||
"temperature": 1,
|
||||
"topP": 0.95,
|
||||
"topK": 64,
|
||||
"thinkingConfig": {
|
||||
"includeThoughts": true,
|
||||
"thinkingBudget": 8192
|
||||
},
|
||||
"topK": 64
|
||||
}
|
||||
}
|
||||
},
|
||||
"chat-base-3": {
|
||||
"generateContentConfig": {
|
||||
"temperature": 1,
|
||||
"topP": 0.95,
|
||||
"topK": 64,
|
||||
"thinkingConfig": {
|
||||
"includeThoughts": true,
|
||||
"thinkingLevel": "HIGH"
|
||||
},
|
||||
"topK": 64
|
||||
}
|
||||
}
|
||||
},
|
||||
"gemini-3.1-pro-preview": {
|
||||
"model": "gemini-3.1-pro-preview",
|
||||
"generateContentConfig": {
|
||||
"temperature": 1,
|
||||
"topP": 0.95,
|
||||
"topK": 64,
|
||||
"thinkingConfig": {
|
||||
"includeThoughts": true,
|
||||
"thinkingLevel": "HIGH"
|
||||
}
|
||||
}
|
||||
},
|
||||
"gemini-3.1-pro-preview-customtools": {
|
||||
"model": "gemini-3.1-pro-preview-customtools",
|
||||
"generateContentConfig": {
|
||||
"temperature": 1,
|
||||
"topP": 0.95,
|
||||
"topK": 64,
|
||||
"thinkingConfig": {
|
||||
"includeThoughts": true,
|
||||
"thinkingLevel": "HIGH"
|
||||
}
|
||||
}
|
||||
},
|
||||
"gemini-3-pro-preview": {
|
||||
@@ -42,11 +63,11 @@
|
||||
"generateContentConfig": {
|
||||
"temperature": 1,
|
||||
"topP": 0.95,
|
||||
"topK": 64,
|
||||
"thinkingConfig": {
|
||||
"includeThoughts": true,
|
||||
"thinkingLevel": "HIGH"
|
||||
},
|
||||
"topK": 64
|
||||
}
|
||||
}
|
||||
},
|
||||
"gemini-3-flash-preview": {
|
||||
@@ -54,11 +75,23 @@
|
||||
"generateContentConfig": {
|
||||
"temperature": 1,
|
||||
"topP": 0.95,
|
||||
"topK": 64,
|
||||
"thinkingConfig": {
|
||||
"includeThoughts": true,
|
||||
"thinkingLevel": "HIGH"
|
||||
},
|
||||
"topK": 64
|
||||
}
|
||||
}
|
||||
},
|
||||
"gemini-3.1-flash-lite-preview": {
|
||||
"model": "gemini-3.1-flash-lite-preview",
|
||||
"generateContentConfig": {
|
||||
"temperature": 1,
|
||||
"topP": 0.95,
|
||||
"topK": 64,
|
||||
"thinkingConfig": {
|
||||
"includeThoughts": true,
|
||||
"thinkingLevel": "HIGH"
|
||||
}
|
||||
}
|
||||
},
|
||||
"gemini-2.5-pro": {
|
||||
@@ -66,11 +99,11 @@
|
||||
"generateContentConfig": {
|
||||
"temperature": 1,
|
||||
"topP": 0.95,
|
||||
"topK": 64,
|
||||
"thinkingConfig": {
|
||||
"includeThoughts": true,
|
||||
"thinkingBudget": 8192
|
||||
},
|
||||
"topK": 64
|
||||
}
|
||||
}
|
||||
},
|
||||
"gemini-2.5-flash": {
|
||||
@@ -78,11 +111,11 @@
|
||||
"generateContentConfig": {
|
||||
"temperature": 1,
|
||||
"topP": 0.95,
|
||||
"topK": 64,
|
||||
"thinkingConfig": {
|
||||
"includeThoughts": true,
|
||||
"thinkingBudget": 8192
|
||||
},
|
||||
"topK": 64
|
||||
}
|
||||
}
|
||||
},
|
||||
"gemini-2.5-flash-lite": {
|
||||
@@ -90,11 +123,11 @@
|
||||
"generateContentConfig": {
|
||||
"temperature": 1,
|
||||
"topP": 0.95,
|
||||
"topK": 64,
|
||||
"thinkingConfig": {
|
||||
"includeThoughts": true,
|
||||
"thinkingBudget": 8192
|
||||
},
|
||||
"topK": 64
|
||||
}
|
||||
}
|
||||
},
|
||||
"gemini-2.5-flash-base": {
|
||||
@@ -108,7 +141,11 @@
|
||||
"model": "gemini-3-flash-preview",
|
||||
"generateContentConfig": {
|
||||
"temperature": 0,
|
||||
"topP": 1
|
||||
"topP": 1,
|
||||
"thinkingConfig": {
|
||||
"includeThoughts": true,
|
||||
"thinkingLevel": "HIGH"
|
||||
}
|
||||
}
|
||||
},
|
||||
"classifier": {
|
||||
@@ -175,6 +212,10 @@
|
||||
"generateContentConfig": {
|
||||
"temperature": 0,
|
||||
"topP": 1,
|
||||
"thinkingConfig": {
|
||||
"includeThoughts": true,
|
||||
"thinkingLevel": "HIGH"
|
||||
},
|
||||
"tools": [
|
||||
{
|
||||
"googleSearch": {}
|
||||
@@ -187,6 +228,10 @@
|
||||
"generateContentConfig": {
|
||||
"temperature": 0,
|
||||
"topP": 1,
|
||||
"thinkingConfig": {
|
||||
"includeThoughts": true,
|
||||
"thinkingLevel": "HIGH"
|
||||
},
|
||||
"tools": [
|
||||
{
|
||||
"urlContext": {}
|
||||
@@ -198,14 +243,22 @@
|
||||
"model": "gemini-3-flash-preview",
|
||||
"generateContentConfig": {
|
||||
"temperature": 0,
|
||||
"topP": 1
|
||||
"topP": 1,
|
||||
"thinkingConfig": {
|
||||
"includeThoughts": true,
|
||||
"thinkingLevel": "HIGH"
|
||||
}
|
||||
}
|
||||
},
|
||||
"loop-detection": {
|
||||
"model": "gemini-3-flash-preview",
|
||||
"generateContentConfig": {
|
||||
"temperature": 0,
|
||||
"topP": 1
|
||||
"topP": 1,
|
||||
"thinkingConfig": {
|
||||
"includeThoughts": true,
|
||||
"thinkingLevel": "HIGH"
|
||||
}
|
||||
}
|
||||
},
|
||||
"loop-detection-double-check": {
|
||||
@@ -219,14 +272,22 @@
|
||||
"model": "gemini-3-flash-preview",
|
||||
"generateContentConfig": {
|
||||
"temperature": 0,
|
||||
"topP": 1
|
||||
"topP": 1,
|
||||
"thinkingConfig": {
|
||||
"includeThoughts": true,
|
||||
"thinkingLevel": "HIGH"
|
||||
}
|
||||
}
|
||||
},
|
||||
"next-speaker-checker": {
|
||||
"model": "gemini-3-flash-preview",
|
||||
"generateContentConfig": {
|
||||
"temperature": 0,
|
||||
"topP": 1
|
||||
"topP": 1,
|
||||
"thinkingConfig": {
|
||||
"includeThoughts": true,
|
||||
"thinkingLevel": "HIGH"
|
||||
}
|
||||
}
|
||||
},
|
||||
"chat-compression-3-pro": {
|
||||
|
||||
@@ -9,9 +9,6 @@
|
||||
"generateContentConfig": {
|
||||
"temperature": 1,
|
||||
"topP": 0.95,
|
||||
"thinkingConfig": {
|
||||
"includeThoughts": true
|
||||
},
|
||||
"topK": 64
|
||||
}
|
||||
},
|
||||
@@ -19,22 +16,46 @@
|
||||
"generateContentConfig": {
|
||||
"temperature": 1,
|
||||
"topP": 0.95,
|
||||
"topK": 64,
|
||||
"thinkingConfig": {
|
||||
"includeThoughts": true,
|
||||
"thinkingBudget": 8192
|
||||
},
|
||||
"topK": 64
|
||||
}
|
||||
}
|
||||
},
|
||||
"chat-base-3": {
|
||||
"generateContentConfig": {
|
||||
"temperature": 1,
|
||||
"topP": 0.95,
|
||||
"topK": 64,
|
||||
"thinkingConfig": {
|
||||
"includeThoughts": true,
|
||||
"thinkingLevel": "HIGH"
|
||||
},
|
||||
"topK": 64
|
||||
}
|
||||
}
|
||||
},
|
||||
"gemini-3.1-pro-preview": {
|
||||
"model": "gemini-3.1-pro-preview",
|
||||
"generateContentConfig": {
|
||||
"temperature": 1,
|
||||
"topP": 0.95,
|
||||
"topK": 64,
|
||||
"thinkingConfig": {
|
||||
"includeThoughts": true,
|
||||
"thinkingLevel": "HIGH"
|
||||
}
|
||||
}
|
||||
},
|
||||
"gemini-3.1-pro-preview-customtools": {
|
||||
"model": "gemini-3.1-pro-preview-customtools",
|
||||
"generateContentConfig": {
|
||||
"temperature": 1,
|
||||
"topP": 0.95,
|
||||
"topK": 64,
|
||||
"thinkingConfig": {
|
||||
"includeThoughts": true,
|
||||
"thinkingLevel": "HIGH"
|
||||
}
|
||||
}
|
||||
},
|
||||
"gemini-3-pro-preview": {
|
||||
@@ -42,11 +63,11 @@
|
||||
"generateContentConfig": {
|
||||
"temperature": 1,
|
||||
"topP": 0.95,
|
||||
"topK": 64,
|
||||
"thinkingConfig": {
|
||||
"includeThoughts": true,
|
||||
"thinkingLevel": "HIGH"
|
||||
},
|
||||
"topK": 64
|
||||
}
|
||||
}
|
||||
},
|
||||
"gemini-3-flash-preview": {
|
||||
@@ -54,11 +75,23 @@
|
||||
"generateContentConfig": {
|
||||
"temperature": 1,
|
||||
"topP": 0.95,
|
||||
"topK": 64,
|
||||
"thinkingConfig": {
|
||||
"includeThoughts": true,
|
||||
"thinkingLevel": "HIGH"
|
||||
},
|
||||
"topK": 64
|
||||
}
|
||||
}
|
||||
},
|
||||
"gemini-3.1-flash-lite-preview": {
|
||||
"model": "gemini-3.1-flash-lite-preview",
|
||||
"generateContentConfig": {
|
||||
"temperature": 1,
|
||||
"topP": 0.95,
|
||||
"topK": 64,
|
||||
"thinkingConfig": {
|
||||
"includeThoughts": true,
|
||||
"thinkingLevel": "HIGH"
|
||||
}
|
||||
}
|
||||
},
|
||||
"gemini-2.5-pro": {
|
||||
@@ -66,11 +99,11 @@
|
||||
"generateContentConfig": {
|
||||
"temperature": 1,
|
||||
"topP": 0.95,
|
||||
"topK": 64,
|
||||
"thinkingConfig": {
|
||||
"includeThoughts": true,
|
||||
"thinkingBudget": 8192
|
||||
},
|
||||
"topK": 64
|
||||
}
|
||||
}
|
||||
},
|
||||
"gemini-2.5-flash": {
|
||||
@@ -78,11 +111,11 @@
|
||||
"generateContentConfig": {
|
||||
"temperature": 1,
|
||||
"topP": 0.95,
|
||||
"topK": 64,
|
||||
"thinkingConfig": {
|
||||
"includeThoughts": true,
|
||||
"thinkingBudget": 8192
|
||||
},
|
||||
"topK": 64
|
||||
}
|
||||
}
|
||||
},
|
||||
"gemini-2.5-flash-lite": {
|
||||
@@ -90,11 +123,11 @@
|
||||
"generateContentConfig": {
|
||||
"temperature": 1,
|
||||
"topP": 0.95,
|
||||
"topK": 64,
|
||||
"thinkingConfig": {
|
||||
"includeThoughts": true,
|
||||
"thinkingBudget": 8192
|
||||
},
|
||||
"topK": 64
|
||||
}
|
||||
}
|
||||
},
|
||||
"gemini-2.5-flash-base": {
|
||||
@@ -108,7 +141,11 @@
|
||||
"model": "gemini-3-flash-preview",
|
||||
"generateContentConfig": {
|
||||
"temperature": 0,
|
||||
"topP": 1
|
||||
"topP": 1,
|
||||
"thinkingConfig": {
|
||||
"includeThoughts": true,
|
||||
"thinkingLevel": "HIGH"
|
||||
}
|
||||
}
|
||||
},
|
||||
"classifier": {
|
||||
@@ -175,6 +212,10 @@
|
||||
"generateContentConfig": {
|
||||
"temperature": 0,
|
||||
"topP": 1,
|
||||
"thinkingConfig": {
|
||||
"includeThoughts": true,
|
||||
"thinkingLevel": "HIGH"
|
||||
},
|
||||
"tools": [
|
||||
{
|
||||
"googleSearch": {}
|
||||
@@ -187,6 +228,10 @@
|
||||
"generateContentConfig": {
|
||||
"temperature": 0,
|
||||
"topP": 1,
|
||||
"thinkingConfig": {
|
||||
"includeThoughts": true,
|
||||
"thinkingLevel": "HIGH"
|
||||
},
|
||||
"tools": [
|
||||
{
|
||||
"urlContext": {}
|
||||
@@ -198,14 +243,22 @@
|
||||
"model": "gemini-3-flash-preview",
|
||||
"generateContentConfig": {
|
||||
"temperature": 0,
|
||||
"topP": 1
|
||||
"topP": 1,
|
||||
"thinkingConfig": {
|
||||
"includeThoughts": true,
|
||||
"thinkingLevel": "HIGH"
|
||||
}
|
||||
}
|
||||
},
|
||||
"loop-detection": {
|
||||
"model": "gemini-3-flash-preview",
|
||||
"generateContentConfig": {
|
||||
"temperature": 0,
|
||||
"topP": 1
|
||||
"topP": 1,
|
||||
"thinkingConfig": {
|
||||
"includeThoughts": true,
|
||||
"thinkingLevel": "HIGH"
|
||||
}
|
||||
}
|
||||
},
|
||||
"loop-detection-double-check": {
|
||||
@@ -219,14 +272,22 @@
|
||||
"model": "gemini-3-flash-preview",
|
||||
"generateContentConfig": {
|
||||
"temperature": 0,
|
||||
"topP": 1
|
||||
"topP": 1,
|
||||
"thinkingConfig": {
|
||||
"includeThoughts": true,
|
||||
"thinkingLevel": "HIGH"
|
||||
}
|
||||
}
|
||||
},
|
||||
"next-speaker-checker": {
|
||||
"model": "gemini-3-flash-preview",
|
||||
"generateContentConfig": {
|
||||
"temperature": 0,
|
||||
"topP": 1
|
||||
"topP": 1,
|
||||
"thinkingConfig": {
|
||||
"includeThoughts": true,
|
||||
"thinkingLevel": "HIGH"
|
||||
}
|
||||
}
|
||||
},
|
||||
"chat-compression-3-pro": {
|
||||
|
||||
+120
-14
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user