Patch 0.3.0 preview.4 (#7713)
Co-authored-by: gemini-cli-robot <gemini-cli-robot@google.com> Co-authored-by: christine betts <chrstn@uw.edu> Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com> Co-authored-by: Bryan Morgan <bryanmorgan@google.com> Co-authored-by: anthony bushong <agmsb@users.noreply.github.com>
This commit is contained in:
parent
52cc0f6feb
commit
7404949eff
21 changed files with 115 additions and 46 deletions
|
|
@ -8,7 +8,7 @@ import { describe, it, expect } from 'vitest';
|
||||||
import { TestRig, printDebugInfo, validateModelOutput } from './test-helper.js';
|
import { TestRig, printDebugInfo, validateModelOutput } from './test-helper.js';
|
||||||
|
|
||||||
describe('read_many_files', () => {
|
describe('read_many_files', () => {
|
||||||
it('should be able to read multiple files', async () => {
|
it.skip('should be able to read multiple files', async () => {
|
||||||
const rig = new TestRig();
|
const rig = new TestRig();
|
||||||
await rig.setup('should be able to read multiple files');
|
await rig.setup('should be able to read multiple files');
|
||||||
rig.createFile('file1.txt', 'file 1 content');
|
rig.createFile('file1.txt', 'file 1 content');
|
||||||
|
|
|
||||||
24
package-lock.json
generated
24
package-lock.json
generated
|
|
@ -1,12 +1,12 @@
|
||||||
{
|
{
|
||||||
"name": "@google/gemini-cli",
|
"name": "@google/gemini-cli",
|
||||||
"version": "0.3.0-preview.1",
|
"version": "0.3.0-preview.3",
|
||||||
"lockfileVersion": 3,
|
"lockfileVersion": 3,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "@google/gemini-cli",
|
"name": "@google/gemini-cli",
|
||||||
"version": "0.3.0-preview.1",
|
"version": "0.3.0-preview.3",
|
||||||
"workspaces": [
|
"workspaces": [
|
||||||
"packages/*"
|
"packages/*"
|
||||||
],
|
],
|
||||||
|
|
@ -8085,9 +8085,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/ink": {
|
"node_modules/ink": {
|
||||||
"version": "6.2.2",
|
"version": "6.2.3",
|
||||||
"resolved": "https://registry.npmjs.org/ink/-/ink-6.2.2.tgz",
|
"resolved": "https://registry.npmjs.org/ink/-/ink-6.2.3.tgz",
|
||||||
"integrity": "sha512-LN1f+/D8KKqMqRux08fIfA9wsEAJ9Bu9CiI3L6ih7bnqNSDUXT/JVJ0rUIc4NkjPiPaeI3BVNREcLYLz9ePSEg==",
|
"integrity": "sha512-fQkfEJjKbLXIcVWEE3MvpYSnwtbbmRsmeNDNz1pIuOFlwE+UF2gsy228J36OXKZGWJWZJKUigphBSqCNMcARtg==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@alcalzone/ansi-tokenize": "^0.2.0",
|
"@alcalzone/ansi-tokenize": "^0.2.0",
|
||||||
|
|
@ -8104,7 +8104,6 @@
|
||||||
"is-in-ci": "^2.0.0",
|
"is-in-ci": "^2.0.0",
|
||||||
"patch-console": "^2.0.0",
|
"patch-console": "^2.0.0",
|
||||||
"react-reconciler": "^0.32.0",
|
"react-reconciler": "^0.32.0",
|
||||||
"scheduler": "^0.26.0",
|
|
||||||
"signal-exit": "^3.0.7",
|
"signal-exit": "^3.0.7",
|
||||||
"slice-ansi": "^7.1.0",
|
"slice-ansi": "^7.1.0",
|
||||||
"stack-utils": "^2.0.6",
|
"stack-utils": "^2.0.6",
|
||||||
|
|
@ -14236,7 +14235,7 @@
|
||||||
},
|
},
|
||||||
"packages/a2a-server": {
|
"packages/a2a-server": {
|
||||||
"name": "@google/gemini-cli-a2a-server",
|
"name": "@google/gemini-cli-a2a-server",
|
||||||
"version": "0.3.0-preview.1",
|
"version": "0.3.0-preview.3",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@a2a-js/sdk": "^0.3.2",
|
"@a2a-js/sdk": "^0.3.2",
|
||||||
"@google-cloud/storage": "^7.16.0",
|
"@google-cloud/storage": "^7.16.0",
|
||||||
|
|
@ -14507,7 +14506,7 @@
|
||||||
},
|
},
|
||||||
"packages/cli": {
|
"packages/cli": {
|
||||||
"name": "@google/gemini-cli",
|
"name": "@google/gemini-cli",
|
||||||
"version": "0.3.0-preview.1",
|
"version": "0.3.0-preview.3",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@google/gemini-cli-core": "file:../core",
|
"@google/gemini-cli-core": "file:../core",
|
||||||
"@google/genai": "1.13.0",
|
"@google/genai": "1.13.0",
|
||||||
|
|
@ -14517,9 +14516,10 @@
|
||||||
"command-exists": "^1.2.9",
|
"command-exists": "^1.2.9",
|
||||||
"diff": "^7.0.0",
|
"diff": "^7.0.0",
|
||||||
"dotenv": "^17.1.0",
|
"dotenv": "^17.1.0",
|
||||||
|
"fzf": "^0.5.2",
|
||||||
"glob": "^10.4.1",
|
"glob": "^10.4.1",
|
||||||
"highlight.js": "^11.11.1",
|
"highlight.js": "^11.11.1",
|
||||||
"ink": "^6.1.1",
|
"ink": "^6.2.3",
|
||||||
"ink-gradient": "^3.0.0",
|
"ink-gradient": "^3.0.0",
|
||||||
"ink-spinner": "^5.0.0",
|
"ink-spinner": "^5.0.0",
|
||||||
"lodash-es": "^4.17.21",
|
"lodash-es": "^4.17.21",
|
||||||
|
|
@ -14690,7 +14690,7 @@
|
||||||
},
|
},
|
||||||
"packages/core": {
|
"packages/core": {
|
||||||
"name": "@google/gemini-cli-core",
|
"name": "@google/gemini-cli-core",
|
||||||
"version": "0.3.0-preview.1",
|
"version": "0.3.0-preview.3",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@google/genai": "1.13.0",
|
"@google/genai": "1.13.0",
|
||||||
"@lvce-editor/ripgrep": "^1.6.0",
|
"@lvce-editor/ripgrep": "^1.6.0",
|
||||||
|
|
@ -14812,7 +14812,7 @@
|
||||||
},
|
},
|
||||||
"packages/test-utils": {
|
"packages/test-utils": {
|
||||||
"name": "@google/gemini-cli-test-utils",
|
"name": "@google/gemini-cli-test-utils",
|
||||||
"version": "0.3.0-preview.1",
|
"version": "0.3.0-preview.3",
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"typescript": "^5.3.3"
|
"typescript": "^5.3.3"
|
||||||
|
|
@ -14823,7 +14823,7 @@
|
||||||
},
|
},
|
||||||
"packages/vscode-ide-companion": {
|
"packages/vscode-ide-companion": {
|
||||||
"name": "gemini-cli-vscode-ide-companion",
|
"name": "gemini-cli-vscode-ide-companion",
|
||||||
"version": "0.3.0-preview.1",
|
"version": "0.3.0-preview.3",
|
||||||
"license": "LICENSE",
|
"license": "LICENSE",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@modelcontextprotocol/sdk": "^1.15.1",
|
"@modelcontextprotocol/sdk": "^1.15.1",
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "@google/gemini-cli",
|
"name": "@google/gemini-cli",
|
||||||
"version": "0.3.0-preview.1",
|
"version": "0.3.0-preview.3",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=20.0.0"
|
"node": ">=20.0.0"
|
||||||
},
|
},
|
||||||
|
|
@ -14,7 +14,7 @@
|
||||||
"url": "git+https://github.com/google-gemini/gemini-cli.git"
|
"url": "git+https://github.com/google-gemini/gemini-cli.git"
|
||||||
},
|
},
|
||||||
"config": {
|
"config": {
|
||||||
"sandboxImageUri": "us-docker.pkg.dev/gemini-code-dev/gemini-cli/sandbox:0.3.0-preview.1"
|
"sandboxImageUri": "us-docker.pkg.dev/gemini-code-dev/gemini-cli/sandbox:0.3.0-preview.3"
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"start": "node scripts/start.js",
|
"start": "node scripts/start.js",
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "@google/gemini-cli-a2a-server",
|
"name": "@google/gemini-cli-a2a-server",
|
||||||
"version": "0.3.0-preview.1",
|
"version": "0.3.0-preview.3",
|
||||||
"private": true,
|
"private": true,
|
||||||
"description": "Gemini CLI A2A Server",
|
"description": "Gemini CLI A2A Server",
|
||||||
"repository": {
|
"repository": {
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "@google/gemini-cli",
|
"name": "@google/gemini-cli",
|
||||||
"version": "0.3.0-preview.1",
|
"version": "0.3.0-preview.3",
|
||||||
"description": "Gemini CLI",
|
"description": "Gemini CLI",
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
|
|
@ -25,7 +25,7 @@
|
||||||
"dist"
|
"dist"
|
||||||
],
|
],
|
||||||
"config": {
|
"config": {
|
||||||
"sandboxImageUri": "us-docker.pkg.dev/gemini-code-dev/gemini-cli/sandbox:0.3.0-preview.1"
|
"sandboxImageUri": "us-docker.pkg.dev/gemini-code-dev/gemini-cli/sandbox:0.3.0-preview.3"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@google/gemini-cli-core": "file:../core",
|
"@google/gemini-cli-core": "file:../core",
|
||||||
|
|
@ -36,9 +36,10 @@
|
||||||
"command-exists": "^1.2.9",
|
"command-exists": "^1.2.9",
|
||||||
"diff": "^7.0.0",
|
"diff": "^7.0.0",
|
||||||
"dotenv": "^17.1.0",
|
"dotenv": "^17.1.0",
|
||||||
|
"fzf": "^0.5.2",
|
||||||
"glob": "^10.4.1",
|
"glob": "^10.4.1",
|
||||||
"highlight.js": "^11.11.1",
|
"highlight.js": "^11.11.1",
|
||||||
"ink": "^6.1.1",
|
"ink": "^6.2.3",
|
||||||
"ink-gradient": "^3.0.0",
|
"ink-gradient": "^3.0.0",
|
||||||
"ink-spinner": "^5.0.0",
|
"ink-spinner": "^5.0.0",
|
||||||
"lodash-es": "^4.17.21",
|
"lodash-es": "^4.17.21",
|
||||||
|
|
|
||||||
|
|
@ -482,10 +482,10 @@ export async function loadCliConfig(
|
||||||
}
|
}
|
||||||
|
|
||||||
const sandboxConfig = await loadSandboxConfig(settings, argv);
|
const sandboxConfig = await loadSandboxConfig(settings, argv);
|
||||||
|
|
||||||
// The screen reader argument takes precedence over the accessibility setting.
|
|
||||||
const screenReader =
|
const screenReader =
|
||||||
argv.screenReader ?? settings.ui?.accessibility?.screenReader ?? false;
|
argv.screenReader !== undefined
|
||||||
|
? argv.screenReader
|
||||||
|
: (settings.ui?.accessibility?.screenReader ?? false);
|
||||||
return new Config({
|
return new Config({
|
||||||
sessionId,
|
sessionId,
|
||||||
embeddingModel: DEFAULT_GEMINI_EMBEDDING_MODEL,
|
embeddingModel: DEFAULT_GEMINI_EMBEDDING_MODEL,
|
||||||
|
|
|
||||||
|
|
@ -242,7 +242,7 @@ export const SETTINGS_SCHEMA = {
|
||||||
label: 'Screen Reader Mode',
|
label: 'Screen Reader Mode',
|
||||||
category: 'UI',
|
category: 'UI',
|
||||||
requiresRestart: true,
|
requiresRestart: true,
|
||||||
default: false,
|
default: undefined as boolean | undefined,
|
||||||
description:
|
description:
|
||||||
'Render output in plain-text to be more screen reader accessible',
|
'Render output in plain-text to be more screen reader accessible',
|
||||||
showInDialog: true,
|
showInDialog: true,
|
||||||
|
|
|
||||||
|
|
@ -5,11 +5,15 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import type React from 'react';
|
import type React from 'react';
|
||||||
import { Text } from 'ink';
|
import { Text, useIsScreenReaderEnabled } from 'ink';
|
||||||
import Spinner from 'ink-spinner';
|
import Spinner from 'ink-spinner';
|
||||||
import type { SpinnerName } from 'cli-spinners';
|
import type { SpinnerName } from 'cli-spinners';
|
||||||
import { useStreamingContext } from '../contexts/StreamingContext.js';
|
import { useStreamingContext } from '../contexts/StreamingContext.js';
|
||||||
import { StreamingState } from '../types.js';
|
import { StreamingState } from '../types.js';
|
||||||
|
import {
|
||||||
|
SCREEN_READER_LOADING,
|
||||||
|
SCREEN_READER_RESPONDING,
|
||||||
|
} from '../textConstants.js';
|
||||||
|
|
||||||
interface GeminiRespondingSpinnerProps {
|
interface GeminiRespondingSpinnerProps {
|
||||||
/**
|
/**
|
||||||
|
|
@ -24,11 +28,19 @@ export const GeminiRespondingSpinner: React.FC<
|
||||||
GeminiRespondingSpinnerProps
|
GeminiRespondingSpinnerProps
|
||||||
> = ({ nonRespondingDisplay, spinnerType = 'dots' }) => {
|
> = ({ nonRespondingDisplay, spinnerType = 'dots' }) => {
|
||||||
const streamingState = useStreamingContext();
|
const streamingState = useStreamingContext();
|
||||||
|
const isScreenReaderEnabled = useIsScreenReaderEnabled();
|
||||||
if (streamingState === StreamingState.Responding) {
|
if (streamingState === StreamingState.Responding) {
|
||||||
return <Spinner type={spinnerType} />;
|
return isScreenReaderEnabled ? (
|
||||||
|
<Text>{SCREEN_READER_RESPONDING}</Text>
|
||||||
|
) : (
|
||||||
|
<Spinner type={spinnerType} />
|
||||||
|
);
|
||||||
} else if (nonRespondingDisplay) {
|
} else if (nonRespondingDisplay) {
|
||||||
return <Text>{nonRespondingDisplay}</Text>;
|
return isScreenReaderEnabled ? (
|
||||||
|
<Text>{SCREEN_READER_LOADING}</Text>
|
||||||
|
) : (
|
||||||
|
<Text>{nonRespondingDisplay}</Text>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -29,7 +29,7 @@ import {
|
||||||
cleanupOldClipboardImages,
|
cleanupOldClipboardImages,
|
||||||
} from '../utils/clipboardUtils.js';
|
} from '../utils/clipboardUtils.js';
|
||||||
import * as path from 'node:path';
|
import * as path from 'node:path';
|
||||||
import { SCREEN_READER_USER_PREFIX } from '../constants.js';
|
import { SCREEN_READER_USER_PREFIX } from '../textConstants.js';
|
||||||
|
|
||||||
export interface InputPromptProps {
|
export interface InputPromptProps {
|
||||||
buffer: TextBuffer;
|
buffer: TextBuffer;
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,7 @@ import { Box, Text } from 'ink';
|
||||||
import type { CompressionProps } from '../../types.js';
|
import type { CompressionProps } from '../../types.js';
|
||||||
import Spinner from 'ink-spinner';
|
import Spinner from 'ink-spinner';
|
||||||
import { Colors } from '../../colors.js';
|
import { Colors } from '../../colors.js';
|
||||||
import { SCREEN_READER_MODEL_PREFIX } from '../../constants.js';
|
import { SCREEN_READER_MODEL_PREFIX } from '../../textConstants.js';
|
||||||
|
|
||||||
export interface CompressionDisplayProps {
|
export interface CompressionDisplayProps {
|
||||||
compression: CompressionProps;
|
compression: CompressionProps;
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import type React from 'react';
|
import type React from 'react';
|
||||||
import { Box, Text } from 'ink';
|
import { Box, Text, useIsScreenReaderEnabled } from 'ink';
|
||||||
import { Colors } from '../../colors.js';
|
import { Colors } from '../../colors.js';
|
||||||
import crypto from 'node:crypto';
|
import crypto from 'node:crypto';
|
||||||
import { colorizeCode, colorizeLine } from '../../utils/CodeColorizer.js';
|
import { colorizeCode, colorizeLine } from '../../utils/CodeColorizer.js';
|
||||||
|
|
@ -107,6 +107,7 @@ export const DiffRenderer: React.FC<DiffRendererProps> = ({
|
||||||
terminalWidth,
|
terminalWidth,
|
||||||
theme,
|
theme,
|
||||||
}) => {
|
}) => {
|
||||||
|
const screenReaderEnabled = useIsScreenReaderEnabled();
|
||||||
if (!diffContent || typeof diffContent !== 'string') {
|
if (!diffContent || typeof diffContent !== 'string') {
|
||||||
return <Text color={Colors.AccentYellow}>No diff content.</Text>;
|
return <Text color={Colors.AccentYellow}>No diff content.</Text>;
|
||||||
}
|
}
|
||||||
|
|
@ -120,6 +121,17 @@ export const DiffRenderer: React.FC<DiffRendererProps> = ({
|
||||||
</Box>
|
</Box>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
if (screenReaderEnabled) {
|
||||||
|
return (
|
||||||
|
<Box flexDirection="column">
|
||||||
|
{parsedLines.map((line, index) => (
|
||||||
|
<Text key={index}>
|
||||||
|
{line.type}: {line.content}
|
||||||
|
</Text>
|
||||||
|
))}
|
||||||
|
</Box>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
// Check if the diff represents a new file (only additions and header lines)
|
// Check if the diff represents a new file (only additions and header lines)
|
||||||
const isNewFile = parsedLines.every(
|
const isNewFile = parsedLines.every(
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,7 @@ import type React from 'react';
|
||||||
import { Text, Box } from 'ink';
|
import { Text, Box } from 'ink';
|
||||||
import { MarkdownDisplay } from '../../utils/MarkdownDisplay.js';
|
import { MarkdownDisplay } from '../../utils/MarkdownDisplay.js';
|
||||||
import { Colors } from '../../colors.js';
|
import { Colors } from '../../colors.js';
|
||||||
import { SCREEN_READER_MODEL_PREFIX } from '../../constants.js';
|
import { SCREEN_READER_MODEL_PREFIX } from '../../textConstants.js';
|
||||||
|
|
||||||
interface GeminiMessageProps {
|
interface GeminiMessageProps {
|
||||||
text: string;
|
text: string;
|
||||||
|
|
|
||||||
|
|
@ -129,18 +129,22 @@ const ToolStatusIndicator: React.FC<ToolStatusIndicatorProps> = ({
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
{status === ToolCallStatus.Success && (
|
{status === ToolCallStatus.Success && (
|
||||||
<Text color={Colors.AccentGreen}>{TOOL_STATUS.SUCCESS}</Text>
|
<Text color={Colors.AccentGreen} aria-label={'Success:'}>
|
||||||
|
{TOOL_STATUS.SUCCESS}
|
||||||
|
</Text>
|
||||||
)}
|
)}
|
||||||
{status === ToolCallStatus.Confirming && (
|
{status === ToolCallStatus.Confirming && (
|
||||||
<Text color={Colors.AccentYellow}>{TOOL_STATUS.CONFIRMING}</Text>
|
<Text color={Colors.AccentYellow} aria-label={'Confirming:'}>
|
||||||
|
{TOOL_STATUS.CONFIRMING}
|
||||||
|
</Text>
|
||||||
)}
|
)}
|
||||||
{status === ToolCallStatus.Canceled && (
|
{status === ToolCallStatus.Canceled && (
|
||||||
<Text color={Colors.AccentYellow} bold>
|
<Text color={Colors.AccentYellow} aria-label={'Canceled:'} bold>
|
||||||
{TOOL_STATUS.CANCELED}
|
{TOOL_STATUS.CANCELED}
|
||||||
</Text>
|
</Text>
|
||||||
)}
|
)}
|
||||||
{status === ToolCallStatus.Error && (
|
{status === ToolCallStatus.Error && (
|
||||||
<Text color={Colors.AccentRed} bold>
|
<Text color={Colors.AccentRed} aria-label={'Error:'} bold>
|
||||||
{TOOL_STATUS.ERROR}
|
{TOOL_STATUS.ERROR}
|
||||||
</Text>
|
</Text>
|
||||||
)}
|
)}
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@
|
||||||
import type React from 'react';
|
import type React from 'react';
|
||||||
import { Text, Box } from 'ink';
|
import { Text, Box } from 'ink';
|
||||||
import { Colors } from '../../colors.js';
|
import { Colors } from '../../colors.js';
|
||||||
import { SCREEN_READER_USER_PREFIX } from '../../constants.js';
|
import { SCREEN_READER_USER_PREFIX } from '../../textConstants.js';
|
||||||
import { isSlashCommand as checkIsSlashCommand } from '../../utils/commandUtils.js';
|
import { isSlashCommand as checkIsSlashCommand } from '../../utils/commandUtils.js';
|
||||||
|
|
||||||
interface UserMessageProps {
|
interface UserMessageProps {
|
||||||
|
|
|
||||||
|
|
@ -65,7 +65,6 @@ export function RadioButtonSelect<T>({
|
||||||
const [scrollOffset, setScrollOffset] = useState(0);
|
const [scrollOffset, setScrollOffset] = useState(0);
|
||||||
const [numberInput, setNumberInput] = useState('');
|
const [numberInput, setNumberInput] = useState('');
|
||||||
const numberInputTimer = useRef<NodeJS.Timeout | null>(null);
|
const numberInputTimer = useRef<NodeJS.Timeout | null>(null);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const newScrollOffset = Math.max(
|
const newScrollOffset = Math.max(
|
||||||
0,
|
0,
|
||||||
|
|
@ -195,7 +194,10 @@ export function RadioButtonSelect<T>({
|
||||||
return (
|
return (
|
||||||
<Box key={item.label} alignItems="center">
|
<Box key={item.label} alignItems="center">
|
||||||
<Box minWidth={2} flexShrink={0}>
|
<Box minWidth={2} flexShrink={0}>
|
||||||
<Text color={isSelected ? Colors.AccentGreen : Colors.Foreground}>
|
<Text
|
||||||
|
color={isSelected ? Colors.AccentGreen : Colors.Foreground}
|
||||||
|
aria-hidden
|
||||||
|
>
|
||||||
{isSelected ? '●' : ' '}
|
{isSelected ? '●' : ' '}
|
||||||
</Text>
|
</Text>
|
||||||
</Box>
|
</Box>
|
||||||
|
|
@ -203,6 +205,7 @@ export function RadioButtonSelect<T>({
|
||||||
marginRight={1}
|
marginRight={1}
|
||||||
flexShrink={0}
|
flexShrink={0}
|
||||||
minWidth={itemNumberText.length}
|
minWidth={itemNumberText.length}
|
||||||
|
aria-state={{ checked: isSelected }}
|
||||||
>
|
>
|
||||||
<Text color={numberColor}>{itemNumberText}</Text>
|
<Text color={numberColor}>{itemNumberText}</Text>
|
||||||
</Box>
|
</Box>
|
||||||
|
|
|
||||||
|
|
@ -16,10 +16,6 @@ export const STREAM_DEBOUNCE_MS = 100;
|
||||||
|
|
||||||
export const SHELL_COMMAND_NAME = 'Shell Command';
|
export const SHELL_COMMAND_NAME = 'Shell Command';
|
||||||
|
|
||||||
export const SCREEN_READER_USER_PREFIX = 'User: ';
|
|
||||||
|
|
||||||
export const SCREEN_READER_MODEL_PREFIX = 'Model: ';
|
|
||||||
|
|
||||||
// Tool status symbols used in ToolMessage component
|
// Tool status symbols used in ToolMessage component
|
||||||
export const TOOL_STATUS = {
|
export const TOOL_STATUS = {
|
||||||
SUCCESS: '✓',
|
SUCCESS: '✓',
|
||||||
|
|
|
||||||
13
packages/cli/src/ui/textConstants.ts
Normal file
13
packages/cli/src/ui/textConstants.ts
Normal file
|
|
@ -0,0 +1,13 @@
|
||||||
|
/**
|
||||||
|
* @license
|
||||||
|
* Copyright 2025 Google LLC
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
export const SCREEN_READER_USER_PREFIX = 'User: ';
|
||||||
|
|
||||||
|
export const SCREEN_READER_MODEL_PREFIX = 'Model: ';
|
||||||
|
|
||||||
|
export const SCREEN_READER_LOADING = 'loading';
|
||||||
|
|
||||||
|
export const SCREEN_READER_RESPONDING = 'responding';
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "@google/gemini-cli-core",
|
"name": "@google/gemini-cli-core",
|
||||||
"version": "0.3.0-preview.1",
|
"version": "0.3.0-preview.3",
|
||||||
"description": "Gemini CLI Core",
|
"description": "Gemini CLI Core",
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import type { Content } from '@google/genai';
|
||||||
import { createHash } from 'node:crypto';
|
import { createHash } from 'node:crypto';
|
||||||
import type { ServerGeminiStreamEvent } from '../core/turn.js';
|
import type { ServerGeminiStreamEvent } from '../core/turn.js';
|
||||||
import { GeminiEventType } from '../core/turn.js';
|
import { GeminiEventType } from '../core/turn.js';
|
||||||
|
|
@ -11,6 +12,10 @@ import { logLoopDetected } from '../telemetry/loggers.js';
|
||||||
import { LoopDetectedEvent, LoopType } from '../telemetry/types.js';
|
import { LoopDetectedEvent, LoopType } from '../telemetry/types.js';
|
||||||
import type { Config } from '../config/config.js';
|
import type { Config } from '../config/config.js';
|
||||||
import { DEFAULT_GEMINI_FLASH_MODEL } from '../config/config.js';
|
import { DEFAULT_GEMINI_FLASH_MODEL } from '../config/config.js';
|
||||||
|
import {
|
||||||
|
isFunctionCall,
|
||||||
|
isFunctionResponse,
|
||||||
|
} from '../utils/messageInspectors.js';
|
||||||
|
|
||||||
const TOOL_CALL_LOOP_THRESHOLD = 5;
|
const TOOL_CALL_LOOP_THRESHOLD = 5;
|
||||||
const CONTENT_LOOP_THRESHOLD = 10;
|
const CONTENT_LOOP_THRESHOLD = 10;
|
||||||
|
|
@ -328,12 +333,35 @@ export class LoopDetectionService {
|
||||||
return originalChunk === currentChunk;
|
return originalChunk === currentChunk;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private trimRecentHistory(recentHistory: Content[]): Content[] {
|
||||||
|
// A function response must be preceded by a function call.
|
||||||
|
// Continuously removes dangling function calls from the end of the history
|
||||||
|
// until the last turn is not a function call.
|
||||||
|
while (
|
||||||
|
recentHistory.length > 0 &&
|
||||||
|
isFunctionCall(recentHistory[recentHistory.length - 1])
|
||||||
|
) {
|
||||||
|
recentHistory.pop();
|
||||||
|
}
|
||||||
|
|
||||||
|
// A function response should follow a function call.
|
||||||
|
// Continuously removes leading function responses from the beginning of history
|
||||||
|
// until the first turn is not a function response.
|
||||||
|
while (recentHistory.length > 0 && isFunctionResponse(recentHistory[0])) {
|
||||||
|
recentHistory.shift();
|
||||||
|
}
|
||||||
|
|
||||||
|
return recentHistory;
|
||||||
|
}
|
||||||
|
|
||||||
private async checkForLoopWithLLM(signal: AbortSignal) {
|
private async checkForLoopWithLLM(signal: AbortSignal) {
|
||||||
const recentHistory = this.config
|
const recentHistory = this.config
|
||||||
.getGeminiClient()
|
.getGeminiClient()
|
||||||
.getHistory()
|
.getHistory()
|
||||||
.slice(-LLM_LOOP_CHECK_HISTORY_COUNT);
|
.slice(-LLM_LOOP_CHECK_HISTORY_COUNT);
|
||||||
|
|
||||||
|
const trimmedHistory = this.trimRecentHistory(recentHistory);
|
||||||
|
|
||||||
const prompt = `You are a sophisticated AI diagnostic agent specializing in identifying when a conversational AI is stuck in an unproductive state. Your task is to analyze the provided conversation history and determine if the assistant has ceased to make meaningful progress.
|
const prompt = `You are a sophisticated AI diagnostic agent specializing in identifying when a conversational AI is stuck in an unproductive state. Your task is to analyze the provided conversation history and determine if the assistant has ceased to make meaningful progress.
|
||||||
|
|
||||||
An unproductive state is characterized by one or more of the following patterns over the last 5 or more assistant turns:
|
An unproductive state is characterized by one or more of the following patterns over the last 5 or more assistant turns:
|
||||||
|
|
@ -347,7 +375,7 @@ For example, a series of 'tool_A' or 'tool_B' tool calls that make small, distin
|
||||||
|
|
||||||
Please analyze the conversation history to determine the possibility that the conversation is stuck in a repetitive, non-productive state.`;
|
Please analyze the conversation history to determine the possibility that the conversation is stuck in a repetitive, non-productive state.`;
|
||||||
const contents = [
|
const contents = [
|
||||||
...recentHistory,
|
...trimmedHistory,
|
||||||
{ role: 'user', parts: [{ text: prompt }] },
|
{ role: 'user', parts: [{ text: prompt }] },
|
||||||
];
|
];
|
||||||
const schema: Record<string, unknown> = {
|
const schema: Record<string, unknown> = {
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "@google/gemini-cli-test-utils",
|
"name": "@google/gemini-cli-test-utils",
|
||||||
"version": "0.3.0-preview.1",
|
"version": "0.3.0-preview.3",
|
||||||
"private": true,
|
"private": true,
|
||||||
"main": "src/index.ts",
|
"main": "src/index.ts",
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
"name": "gemini-cli-vscode-ide-companion",
|
"name": "gemini-cli-vscode-ide-companion",
|
||||||
"displayName": "Gemini CLI Companion",
|
"displayName": "Gemini CLI Companion",
|
||||||
"description": "Enable Gemini CLI with direct access to your IDE workspace.",
|
"description": "Enable Gemini CLI with direct access to your IDE workspace.",
|
||||||
"version": "0.3.0-preview.1",
|
"version": "0.3.0-preview.3",
|
||||||
"publisher": "google",
|
"publisher": "google",
|
||||||
"icon": "assets/icon.png",
|
"icon": "assets/icon.png",
|
||||||
"repository": {
|
"repository": {
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue