mirror of
https://github.com/google-gemini/gemini-cli.git
synced 2026-05-13 05:12:55 -07:00
fix(cli): correct initial history length handling for chat commands (#15223)
This commit is contained in:
@@ -163,7 +163,6 @@ describe('chatCommand', () => {
|
|||||||
|
|
||||||
mockGetHistory.mockReturnValue([
|
mockGetHistory.mockReturnValue([
|
||||||
{ role: 'user', parts: [{ text: 'context for our chat' }] },
|
{ role: 'user', parts: [{ text: 'context for our chat' }] },
|
||||||
{ role: 'model', parts: [{ text: 'Got it. Thanks for the context!' }] },
|
|
||||||
]);
|
]);
|
||||||
result = await saveCommand?.action?.(mockContext, tag);
|
result = await saveCommand?.action?.(mockContext, tag);
|
||||||
expect(result).toEqual({
|
expect(result).toEqual({
|
||||||
@@ -208,9 +207,7 @@ describe('chatCommand', () => {
|
|||||||
it('should save the conversation if overwrite is confirmed', async () => {
|
it('should save the conversation if overwrite is confirmed', async () => {
|
||||||
const history: Content[] = [
|
const history: Content[] = [
|
||||||
{ role: 'user', parts: [{ text: 'context for our chat' }] },
|
{ role: 'user', parts: [{ text: 'context for our chat' }] },
|
||||||
{ role: 'model', parts: [{ text: 'Got it. Thanks for the context!' }] },
|
|
||||||
{ role: 'user', parts: [{ text: 'hello' }] },
|
{ role: 'user', parts: [{ text: 'hello' }] },
|
||||||
{ role: 'model', parts: [{ text: 'Hi there!' }] },
|
|
||||||
];
|
];
|
||||||
mockGetHistory.mockReturnValue(history);
|
mockGetHistory.mockReturnValue(history);
|
||||||
mockContext.overwriteConfirmed = true;
|
mockContext.overwriteConfirmed = true;
|
||||||
@@ -263,6 +260,7 @@ describe('chatCommand', () => {
|
|||||||
|
|
||||||
it('should resume a conversation with matching authType', async () => {
|
it('should resume a conversation with matching authType', async () => {
|
||||||
const conversation: Content[] = [
|
const conversation: Content[] = [
|
||||||
|
{ role: 'user', parts: [{ text: 'system setup' }] },
|
||||||
{ role: 'user', parts: [{ text: 'hello gemini' }] },
|
{ role: 'user', parts: [{ text: 'hello gemini' }] },
|
||||||
{ role: 'model', parts: [{ text: 'hello world' }] },
|
{ role: 'model', parts: [{ text: 'hello world' }] },
|
||||||
];
|
];
|
||||||
@@ -285,6 +283,7 @@ describe('chatCommand', () => {
|
|||||||
|
|
||||||
it('should block resuming a conversation with mismatched authType', async () => {
|
it('should block resuming a conversation with mismatched authType', async () => {
|
||||||
const conversation: Content[] = [
|
const conversation: Content[] = [
|
||||||
|
{ role: 'user', parts: [{ text: 'system setup' }] },
|
||||||
{ role: 'user', parts: [{ text: 'hello gemini' }] },
|
{ role: 'user', parts: [{ text: 'hello gemini' }] },
|
||||||
{ role: 'model', parts: [{ text: 'hello world' }] },
|
{ role: 'model', parts: [{ text: 'hello world' }] },
|
||||||
];
|
];
|
||||||
@@ -304,6 +303,7 @@ describe('chatCommand', () => {
|
|||||||
|
|
||||||
it('should resume a legacy conversation without authType', async () => {
|
it('should resume a legacy conversation without authType', async () => {
|
||||||
const conversation: Content[] = [
|
const conversation: Content[] = [
|
||||||
|
{ role: 'user', parts: [{ text: 'system setup' }] },
|
||||||
{ role: 'user', parts: [{ text: 'hello gemini' }] },
|
{ role: 'user', parts: [{ text: 'hello gemini' }] },
|
||||||
{ role: 'model', parts: [{ text: 'hello world' }] },
|
{ role: 'model', parts: [{ text: 'hello world' }] },
|
||||||
];
|
];
|
||||||
@@ -521,7 +521,6 @@ Hi there!`;
|
|||||||
it('should inform if there is no conversation to share', async () => {
|
it('should inform if there is no conversation to share', async () => {
|
||||||
mockGetHistory.mockReturnValue([
|
mockGetHistory.mockReturnValue([
|
||||||
{ role: 'user', parts: [{ text: 'context' }] },
|
{ role: 'user', parts: [{ text: 'context' }] },
|
||||||
{ role: 'model', parts: [{ text: 'context response' }] },
|
|
||||||
]);
|
]);
|
||||||
const result = await shareCommand?.action?.(mockContext, 'my-chat.json');
|
const result = await shareCommand?.action?.(mockContext, 'my-chat.json');
|
||||||
expect(mockFs.writeFile).not.toHaveBeenCalled();
|
expect(mockFs.writeFile).not.toHaveBeenCalled();
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ import { CommandKind } from './types.js';
|
|||||||
import {
|
import {
|
||||||
decodeTagName,
|
decodeTagName,
|
||||||
type MessageActionReturn,
|
type MessageActionReturn,
|
||||||
|
INITIAL_HISTORY_LENGTH,
|
||||||
} from '@google/gemini-cli-core';
|
} from '@google/gemini-cli-core';
|
||||||
import path from 'node:path';
|
import path from 'node:path';
|
||||||
import type {
|
import type {
|
||||||
@@ -131,7 +132,7 @@ const saveCommand: SlashCommand = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const history = chat.getHistory();
|
const history = chat.getHistory();
|
||||||
if (history.length > 2) {
|
if (history.length > INITIAL_HISTORY_LENGTH) {
|
||||||
const authType = config?.getContentGeneratorConfig()?.authType;
|
const authType = config?.getContentGeneratorConfig()?.authType;
|
||||||
await logger.saveCheckpoint({ history, authType }, tag);
|
await logger.saveCheckpoint({ history, authType }, tag);
|
||||||
return {
|
return {
|
||||||
@@ -200,11 +201,8 @@ const resumeCommand: SlashCommand = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const uiHistory: HistoryItemWithoutId[] = [];
|
const uiHistory: HistoryItemWithoutId[] = [];
|
||||||
let hasSystemPrompt = false;
|
|
||||||
let i = 0;
|
|
||||||
|
|
||||||
for (const item of conversation) {
|
for (const item of conversation.slice(INITIAL_HISTORY_LENGTH)) {
|
||||||
i += 1;
|
|
||||||
const text =
|
const text =
|
||||||
item.parts
|
item.parts
|
||||||
?.filter((m) => !!m.text)
|
?.filter((m) => !!m.text)
|
||||||
@@ -213,15 +211,11 @@ const resumeCommand: SlashCommand = {
|
|||||||
if (!text) {
|
if (!text) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (i === 1 && text.match(/context for our chat/)) {
|
|
||||||
hasSystemPrompt = true;
|
uiHistory.push({
|
||||||
}
|
type: (item.role && rolemap[item.role]) || MessageType.GEMINI,
|
||||||
if (i > 2 || !hasSystemPrompt) {
|
text,
|
||||||
uiHistory.push({
|
} as HistoryItemWithoutId);
|
||||||
type: (item.role && rolemap[item.role]) || MessageType.GEMINI,
|
|
||||||
text,
|
|
||||||
} as HistoryItemWithoutId);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return {
|
return {
|
||||||
type: 'load_history',
|
type: 'load_history',
|
||||||
@@ -343,10 +337,10 @@ const shareCommand: SlashCommand = {
|
|||||||
|
|
||||||
const history = chat.getHistory();
|
const history = chat.getHistory();
|
||||||
|
|
||||||
// An empty conversation has two hidden messages that setup the context for
|
// An empty conversation has a hidden message that sets up the context for
|
||||||
// the chat. Thus, to check whether a conversation has been started, we
|
// the chat. Thus, to check whether a conversation has been started, we
|
||||||
// can't check for length 0.
|
// can't check for length 0.
|
||||||
if (history.length <= 2) {
|
if (history.length <= INITIAL_HISTORY_LENGTH) {
|
||||||
return {
|
return {
|
||||||
type: 'message',
|
type: 'message',
|
||||||
messageType: 'info',
|
messageType: 'info',
|
||||||
|
|||||||
@@ -73,6 +73,7 @@ export * from './utils/generateContentResponseUtilities.js';
|
|||||||
export * from './utils/filesearch/fileSearch.js';
|
export * from './utils/filesearch/fileSearch.js';
|
||||||
export * from './utils/errorParsing.js';
|
export * from './utils/errorParsing.js';
|
||||||
export * from './utils/workspaceContext.js';
|
export * from './utils/workspaceContext.js';
|
||||||
|
export * from './utils/environmentContext.js';
|
||||||
export * from './utils/ignorePatterns.js';
|
export * from './utils/ignorePatterns.js';
|
||||||
export * from './utils/partUtils.js';
|
export * from './utils/partUtils.js';
|
||||||
export * from './utils/promptIdContext.js';
|
export * from './utils/promptIdContext.js';
|
||||||
|
|||||||
@@ -8,6 +8,8 @@ import type { Part, Content } from '@google/genai';
|
|||||||
import type { Config } from '../config/config.js';
|
import type { Config } from '../config/config.js';
|
||||||
import { getFolderStructure } from './getFolderStructure.js';
|
import { getFolderStructure } from './getFolderStructure.js';
|
||||||
|
|
||||||
|
export const INITIAL_HISTORY_LENGTH = 1;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generates a string describing the current workspace directories and their structures.
|
* Generates a string describing the current workspace directories and their structures.
|
||||||
* @param {Config} config - The runtime configuration and services.
|
* @param {Config} config - The runtime configuration and services.
|
||||||
|
|||||||
Reference in New Issue
Block a user