fix: /help remove flickering and respect clear shortcut (ctr+l) (#3611)

Co-authored-by: Jacob Richman <jacob314@gmail.com>
Co-authored-by: Allen Hutchison <adh@google.com>
This commit is contained in:
Pyush Sinha 2025-08-04 09:53:50 -07:00 committed by GitHub
parent 83a04c4755
commit e506b40c27
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
10 changed files with 72 additions and 70 deletions

View File

@ -38,7 +38,6 @@ import { AuthInProgress } from './components/AuthInProgress.js';
import { EditorSettingsDialog } from './components/EditorSettingsDialog.js'; import { EditorSettingsDialog } from './components/EditorSettingsDialog.js';
import { ShellConfirmationDialog } from './components/ShellConfirmationDialog.js'; import { ShellConfirmationDialog } from './components/ShellConfirmationDialog.js';
import { Colors } from './colors.js'; import { Colors } from './colors.js';
import { Help } from './components/Help.js';
import { loadHierarchicalGeminiMemory } from '../config/config.js'; import { loadHierarchicalGeminiMemory } from '../config/config.js';
import { LoadedSettings } from '../config/settings.js'; import { LoadedSettings } from '../config/settings.js';
import { Tips } from './components/Tips.js'; import { Tips } from './components/Tips.js';
@ -146,7 +145,6 @@ const App = ({ config, settings, startupWarnings = [], version }: AppProps) => {
const [geminiMdFileCount, setGeminiMdFileCount] = useState<number>(0); const [geminiMdFileCount, setGeminiMdFileCount] = useState<number>(0);
const [debugMessage, setDebugMessage] = useState<string>(''); const [debugMessage, setDebugMessage] = useState<string>('');
const [showHelp, setShowHelp] = useState<boolean>(false);
const [themeError, setThemeError] = useState<string | null>(null); const [themeError, setThemeError] = useState<string | null>(null);
const [authError, setAuthError] = useState<string | null>(null); const [authError, setAuthError] = useState<string | null>(null);
const [editorError, setEditorError] = useState<string | null>(null); const [editorError, setEditorError] = useState<string | null>(null);
@ -473,7 +471,6 @@ const App = ({ config, settings, startupWarnings = [], version }: AppProps) => {
clearItems, clearItems,
loadHistory, loadHistory,
refreshStatic, refreshStatic,
setShowHelp,
setDebugMessage, setDebugMessage,
openThemeDialog, openThemeDialog,
openAuthDialog, openAuthDialog,
@ -495,7 +492,6 @@ const App = ({ config, settings, startupWarnings = [], version }: AppProps) => {
config.getGeminiClient(), config.getGeminiClient(),
history, history,
addItem, addItem,
setShowHelp,
config, config,
setDebugMessage, setDebugMessage,
handleSlashCommand, handleSlashCommand,
@ -802,6 +798,7 @@ const App = ({ config, settings, startupWarnings = [], version }: AppProps) => {
item={h} item={h}
isPending={false} isPending={false}
config={config} config={config}
commands={slashCommands}
/> />
)), )),
]} ]}
@ -829,8 +826,6 @@ const App = ({ config, settings, startupWarnings = [], version }: AppProps) => {
</Box> </Box>
</OverflowProvider> </OverflowProvider>
{showHelp && <Help commands={slashCommands} />}
<Box flexDirection="column" ref={mainControlsRef}> <Box flexDirection="column" ref={mainControlsRef}>
{/* Move UpdateNotification to render update notification above input area */} {/* Move UpdateNotification to render update notification above input area */}
{updateInfo && <UpdateNotification message={updateInfo.message} />} {updateInfo && <UpdateNotification message={updateInfo.message} />}

View File

@ -4,37 +4,49 @@
* SPDX-License-Identifier: Apache-2.0 * SPDX-License-Identifier: Apache-2.0
*/ */
import { vi, describe, it, expect, beforeEach } from 'vitest'; import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
import { helpCommand } from './helpCommand.js'; import { helpCommand } from './helpCommand.js';
import { type CommandContext } from './types.js'; import { type CommandContext } from './types.js';
import { createMockCommandContext } from '../../test-utils/mockCommandContext.js';
import { MessageType } from '../types.js';
import { CommandKind } from './types.js';
describe('helpCommand', () => { describe('helpCommand', () => {
let mockContext: CommandContext; let mockContext: CommandContext;
const originalEnv = { ...process.env };
beforeEach(() => { beforeEach(() => {
mockContext = {} as unknown as CommandContext; mockContext = createMockCommandContext({
ui: {
addItem: vi.fn(),
},
} as unknown as CommandContext);
}); });
it("should return a dialog action and log a debug message for '/help'", () => { afterEach(() => {
const consoleDebugSpy = vi process.env = { ...originalEnv };
.spyOn(console, 'debug') vi.clearAllMocks();
.mockImplementation(() => {}); });
it('should add a help message to the UI history', async () => {
if (!helpCommand.action) { if (!helpCommand.action) {
throw new Error('Help command has no action'); throw new Error('Help command has no action');
} }
const result = helpCommand.action(mockContext, '');
expect(result).toEqual({ await helpCommand.action(mockContext, '');
type: 'dialog',
dialog: 'help', expect(mockContext.ui.addItem).toHaveBeenCalledWith(
}); expect.objectContaining({
expect(consoleDebugSpy).toHaveBeenCalledWith('Opening help UI ...'); type: MessageType.HELP,
timestamp: expect.any(Date),
}),
expect.any(Number),
);
}); });
it("should also be triggered by its alternative name '?'", () => { it('should have the correct command properties', () => {
// This test is more conceptual. The routing of altNames to the command expect(helpCommand.name).toBe('help');
// is handled by the slash command processor, but we can assert the expect(helpCommand.kind).toBe(CommandKind.BUILT_IN);
// altNames is correctly defined on the command object itself. expect(helpCommand.description).toBe('for help on gemini-cli');
expect(helpCommand.altNames).toContain('?');
}); });
}); });

View File

@ -4,18 +4,20 @@
* SPDX-License-Identifier: Apache-2.0 * SPDX-License-Identifier: Apache-2.0
*/ */
import { CommandKind, OpenDialogActionReturn, SlashCommand } from './types.js'; import { CommandKind, SlashCommand } from './types.js';
import { MessageType, type HistoryItemHelp } from '../types.js';
export const helpCommand: SlashCommand = { export const helpCommand: SlashCommand = {
name: 'help', name: 'help',
altNames: ['?'], altNames: ['?'],
description: 'for help on gemini-cli',
kind: CommandKind.BUILT_IN, kind: CommandKind.BUILT_IN,
action: (_context, _args): OpenDialogActionReturn => { description: 'for help on gemini-cli',
console.debug('Opening help UI ...'); action: async (context) => {
return { const helpItem: Omit<HistoryItemHelp, 'id'> = {
type: 'dialog', type: MessageType.HELP,
dialog: 'help', timestamp: new Date(),
}; };
context.ui.addItem(helpItem, Date.now());
}, },
}; };

View File

@ -98,7 +98,7 @@ export interface MessageActionReturn {
*/ */
export interface OpenDialogActionReturn { export interface OpenDialogActionReturn {
type: 'dialog'; type: 'dialog';
dialog: 'help' | 'auth' | 'theme' | 'editor' | 'privacy'; dialog: 'auth' | 'theme' | 'editor' | 'privacy';
} }
/** /**

View File

@ -21,6 +21,8 @@ import { ModelStatsDisplay } from './ModelStatsDisplay.js';
import { ToolStatsDisplay } from './ToolStatsDisplay.js'; import { ToolStatsDisplay } from './ToolStatsDisplay.js';
import { SessionSummaryDisplay } from './SessionSummaryDisplay.js'; import { SessionSummaryDisplay } from './SessionSummaryDisplay.js';
import { Config } from '@google/gemini-cli-core'; import { Config } from '@google/gemini-cli-core';
import { Help } from './Help.js';
import { SlashCommand } from '../commands/types.js';
interface HistoryItemDisplayProps { interface HistoryItemDisplayProps {
item: HistoryItem; item: HistoryItem;
@ -29,6 +31,7 @@ interface HistoryItemDisplayProps {
isPending: boolean; isPending: boolean;
config?: Config; config?: Config;
isFocused?: boolean; isFocused?: boolean;
commands?: readonly SlashCommand[];
} }
export const HistoryItemDisplay: React.FC<HistoryItemDisplayProps> = ({ export const HistoryItemDisplay: React.FC<HistoryItemDisplayProps> = ({
@ -37,6 +40,7 @@ export const HistoryItemDisplay: React.FC<HistoryItemDisplayProps> = ({
terminalWidth, terminalWidth,
isPending, isPending,
config, config,
commands,
isFocused = true, isFocused = true,
}) => ( }) => (
<Box flexDirection="column" key={item.id}> <Box flexDirection="column" key={item.id}>
@ -71,6 +75,7 @@ export const HistoryItemDisplay: React.FC<HistoryItemDisplayProps> = ({
gcpProject={item.gcpProject} gcpProject={item.gcpProject}
/> />
)} )}
{item.type === 'help' && commands && <Help commands={commands} />}
{item.type === 'stats' && <StatsDisplay duration={item.duration} />} {item.type === 'stats' && <StatsDisplay duration={item.duration} />}
{item.type === 'model_stats' && <ModelStatsDisplay />} {item.type === 'model_stats' && <ModelStatsDisplay />}
{item.type === 'tool_stats' && <ToolStatsDisplay />} {item.type === 'tool_stats' && <ToolStatsDisplay />}

View File

@ -90,7 +90,7 @@ describe('useSlashCommandProcessor', () => {
const mockAddItem = vi.fn(); const mockAddItem = vi.fn();
const mockClearItems = vi.fn(); const mockClearItems = vi.fn();
const mockLoadHistory = vi.fn(); const mockLoadHistory = vi.fn();
const mockSetShowHelp = vi.fn(); const mockOpenThemeDialog = vi.fn();
const mockOpenAuthDialog = vi.fn(); const mockOpenAuthDialog = vi.fn();
const mockSetQuittingMessages = vi.fn(); const mockSetQuittingMessages = vi.fn();
@ -132,9 +132,8 @@ describe('useSlashCommandProcessor', () => {
mockClearItems, mockClearItems,
mockLoadHistory, mockLoadHistory,
vi.fn(), // refreshStatic vi.fn(), // refreshStatic
mockSetShowHelp,
vi.fn(), // onDebugMessage vi.fn(), // onDebugMessage
vi.fn(), // openThemeDialog mockOpenThemeDialog, // openThemeDialog
mockOpenAuthDialog, mockOpenAuthDialog,
vi.fn(), // openEditorDialog vi.fn(), // openEditorDialog
vi.fn(), // toggleCorgiMode vi.fn(), // toggleCorgiMode
@ -334,19 +333,19 @@ describe('useSlashCommandProcessor', () => {
}); });
describe('Action Result Handling', () => { describe('Action Result Handling', () => {
it('should handle "dialog: help" action', async () => { it('should handle "dialog: theme" action', async () => {
const command = createTestCommand({ const command = createTestCommand({
name: 'helpcmd', name: 'themecmd',
action: vi.fn().mockResolvedValue({ type: 'dialog', dialog: 'help' }), action: vi.fn().mockResolvedValue({ type: 'dialog', dialog: 'theme' }),
}); });
const result = setupProcessorHook([command]); const result = setupProcessorHook([command]);
await waitFor(() => expect(result.current.slashCommands).toHaveLength(1)); await waitFor(() => expect(result.current.slashCommands).toHaveLength(1));
await act(async () => { await act(async () => {
await result.current.handleSlashCommand('/helpcmd'); await result.current.handleSlashCommand('/themecmd');
}); });
expect(mockSetShowHelp).toHaveBeenCalledWith(true); expect(mockOpenThemeDialog).toHaveBeenCalled();
}); });
it('should handle "load_history" action', async () => { it('should handle "load_history" action', async () => {
@ -819,15 +818,15 @@ describe('useSlashCommandProcessor', () => {
mockClearItems, mockClearItems,
mockLoadHistory, mockLoadHistory,
vi.fn(), // refreshStatic vi.fn(), // refreshStatic
mockSetShowHelp,
vi.fn(), // onDebugMessage vi.fn(), // onDebugMessage
vi.fn(), // openThemeDialog vi.fn(), // openThemeDialog
mockOpenAuthDialog, mockOpenAuthDialog,
vi.fn(), // openEditorDialog, vi.fn(), // openEditorDialog
vi.fn(), // toggleCorgiMode vi.fn(), // toggleCorgiMode
mockSetQuittingMessages, mockSetQuittingMessages,
vi.fn(), // openPrivacyNotice vi.fn(), // openPrivacyNotice
vi.fn(), // toggleVimEnabled vi.fn().mockResolvedValue(false), // toggleVimEnabled
vi.fn(), // setIsProcessing
), ),
); );

View File

@ -42,7 +42,6 @@ export const useSlashCommandProcessor = (
clearItems: UseHistoryManagerReturn['clearItems'], clearItems: UseHistoryManagerReturn['clearItems'],
loadHistory: UseHistoryManagerReturn['loadHistory'], loadHistory: UseHistoryManagerReturn['loadHistory'],
refreshStatic: () => void, refreshStatic: () => void,
setShowHelp: React.Dispatch<React.SetStateAction<boolean>>,
onDebugMessage: (message: string) => void, onDebugMessage: (message: string) => void,
openThemeDialog: () => void, openThemeDialog: () => void,
openAuthDialog: () => void, openAuthDialog: () => void,
@ -105,6 +104,11 @@ export const useSlashCommandProcessor = (
selectedAuthType: message.selectedAuthType, selectedAuthType: message.selectedAuthType,
gcpProject: message.gcpProject, gcpProject: message.gcpProject,
}; };
} else if (message.type === MessageType.HELP) {
historyItemContent = {
type: 'help',
timestamp: message.timestamp,
};
} else if (message.type === MessageType.STATS) { } else if (message.type === MessageType.STATS) {
historyItemContent = { historyItemContent = {
type: 'stats', type: 'stats',
@ -138,7 +142,6 @@ export const useSlashCommandProcessor = (
}, },
[addItem], [addItem],
); );
const commandContext = useMemo( const commandContext = useMemo(
(): CommandContext => ({ (): CommandContext => ({
services: { services: {
@ -333,9 +336,6 @@ export const useSlashCommandProcessor = (
return { type: 'handled' }; return { type: 'handled' };
case 'dialog': case 'dialog':
switch (result.dialog) { switch (result.dialog) {
case 'help':
setShowHelp(true);
return { type: 'handled' };
case 'auth': case 'auth':
openAuthDialog(); openAuthDialog();
return { type: 'handled' }; return { type: 'handled' };
@ -462,7 +462,6 @@ export const useSlashCommandProcessor = (
[ [
config, config,
addItem, addItem,
setShowHelp,
openAuthDialog, openAuthDialog,
commands, commands,
commandContext, commandContext,

View File

@ -30,7 +30,6 @@ import {
SlashCommandProcessorResult, SlashCommandProcessorResult,
StreamingState, StreamingState,
} from '../types.js'; } from '../types.js';
import { Dispatch, SetStateAction } from 'react';
import { LoadedSettings } from '../../config/settings.js'; import { LoadedSettings } from '../../config/settings.js';
// --- MOCKS --- // --- MOCKS ---
@ -257,7 +256,6 @@ describe('mergePartListUnions', () => {
// --- Tests for useGeminiStream Hook --- // --- Tests for useGeminiStream Hook ---
describe('useGeminiStream', () => { describe('useGeminiStream', () => {
let mockAddItem: Mock; let mockAddItem: Mock;
let mockSetShowHelp: Mock;
let mockConfig: Config; let mockConfig: Config;
let mockOnDebugMessage: Mock; let mockOnDebugMessage: Mock;
let mockHandleSlashCommand: Mock; let mockHandleSlashCommand: Mock;
@ -269,7 +267,6 @@ describe('useGeminiStream', () => {
vi.clearAllMocks(); // Clear mocks before each test vi.clearAllMocks(); // Clear mocks before each test
mockAddItem = vi.fn(); mockAddItem = vi.fn();
mockSetShowHelp = vi.fn();
// Define the mock for getGeminiClient // Define the mock for getGeminiClient
const mockGetGeminiClient = vi.fn().mockImplementation(() => { const mockGetGeminiClient = vi.fn().mockImplementation(() => {
// MockedGeminiClientClass is defined in the module scope by the previous change. // MockedGeminiClientClass is defined in the module scope by the previous change.
@ -382,7 +379,6 @@ describe('useGeminiStream', () => {
client: any; client: any;
history: HistoryItem[]; history: HistoryItem[];
addItem: UseHistoryManagerReturn['addItem']; addItem: UseHistoryManagerReturn['addItem'];
setShowHelp: Dispatch<SetStateAction<boolean>>;
config: Config; config: Config;
onDebugMessage: (message: string) => void; onDebugMessage: (message: string) => void;
handleSlashCommand: ( handleSlashCommand: (
@ -400,7 +396,6 @@ describe('useGeminiStream', () => {
props.client, props.client,
props.history, props.history,
props.addItem, props.addItem,
props.setShowHelp,
props.config, props.config,
props.onDebugMessage, props.onDebugMessage,
props.handleSlashCommand, props.handleSlashCommand,
@ -417,7 +412,6 @@ describe('useGeminiStream', () => {
client, client,
history: [], history: [],
addItem: mockAddItem as unknown as UseHistoryManagerReturn['addItem'], addItem: mockAddItem as unknown as UseHistoryManagerReturn['addItem'],
setShowHelp: mockSetShowHelp,
config: mockConfig, config: mockConfig,
onDebugMessage: mockOnDebugMessage, onDebugMessage: mockOnDebugMessage,
handleSlashCommand: mockHandleSlashCommand as unknown as ( handleSlashCommand: mockHandleSlashCommand as unknown as (
@ -542,7 +536,6 @@ describe('useGeminiStream', () => {
new MockedGeminiClientClass(mockConfig), new MockedGeminiClientClass(mockConfig),
[], [],
mockAddItem, mockAddItem,
mockSetShowHelp,
mockConfig, mockConfig,
mockOnDebugMessage, mockOnDebugMessage,
mockHandleSlashCommand, mockHandleSlashCommand,
@ -610,7 +603,6 @@ describe('useGeminiStream', () => {
client, client,
[], [],
mockAddItem, mockAddItem,
mockSetShowHelp,
mockConfig, mockConfig,
mockOnDebugMessage, mockOnDebugMessage,
mockHandleSlashCommand, mockHandleSlashCommand,
@ -707,7 +699,6 @@ describe('useGeminiStream', () => {
client, client,
[], [],
mockAddItem, mockAddItem,
mockSetShowHelp,
mockConfig, mockConfig,
mockOnDebugMessage, mockOnDebugMessage,
mockHandleSlashCommand, mockHandleSlashCommand,
@ -810,7 +801,6 @@ describe('useGeminiStream', () => {
new MockedGeminiClientClass(mockConfig), new MockedGeminiClientClass(mockConfig),
[], [],
mockAddItem, mockAddItem,
mockSetShowHelp,
mockConfig, mockConfig,
mockOnDebugMessage, mockOnDebugMessage,
mockHandleSlashCommand, mockHandleSlashCommand,
@ -1161,7 +1151,6 @@ describe('useGeminiStream', () => {
new MockedGeminiClientClass(mockConfig), new MockedGeminiClientClass(mockConfig),
[], [],
mockAddItem, mockAddItem,
mockSetShowHelp,
mockConfig, mockConfig,
mockOnDebugMessage, mockOnDebugMessage,
mockHandleSlashCommand, mockHandleSlashCommand,
@ -1213,7 +1202,6 @@ describe('useGeminiStream', () => {
new MockedGeminiClientClass(testConfig), new MockedGeminiClientClass(testConfig),
[], [],
mockAddItem, mockAddItem,
mockSetShowHelp,
testConfig, testConfig,
mockOnDebugMessage, mockOnDebugMessage,
mockHandleSlashCommand, mockHandleSlashCommand,
@ -1262,7 +1250,6 @@ describe('useGeminiStream', () => {
new MockedGeminiClientClass(mockConfig), new MockedGeminiClientClass(mockConfig),
[], [],
mockAddItem, mockAddItem,
mockSetShowHelp,
mockConfig, mockConfig,
mockOnDebugMessage, mockOnDebugMessage,
mockHandleSlashCommand, mockHandleSlashCommand,
@ -1309,7 +1296,6 @@ describe('useGeminiStream', () => {
new MockedGeminiClientClass(mockConfig), new MockedGeminiClientClass(mockConfig),
[], [],
mockAddItem, mockAddItem,
mockSetShowHelp,
mockConfig, mockConfig,
mockOnDebugMessage, mockOnDebugMessage,
mockHandleSlashCommand, mockHandleSlashCommand,
@ -1357,7 +1343,6 @@ describe('useGeminiStream', () => {
new MockedGeminiClientClass(mockConfig), new MockedGeminiClientClass(mockConfig),
[], [],
mockAddItem, mockAddItem,
mockSetShowHelp,
mockConfig, mockConfig,
mockOnDebugMessage, mockOnDebugMessage,
mockHandleSlashCommand, mockHandleSlashCommand,
@ -1445,7 +1430,6 @@ describe('useGeminiStream', () => {
new MockedGeminiClientClass(mockConfig), new MockedGeminiClientClass(mockConfig),
[], [],
mockAddItem, mockAddItem,
mockSetShowHelp,
mockConfig, mockConfig,
mockOnDebugMessage, mockOnDebugMessage,
mockHandleSlashCommand, mockHandleSlashCommand,
@ -1500,7 +1484,6 @@ describe('useGeminiStream', () => {
new MockedGeminiClientClass(mockConfig), new MockedGeminiClientClass(mockConfig),
[], [],
mockAddItem, mockAddItem,
mockSetShowHelp,
mockConfig, mockConfig,
mockOnDebugMessage, mockOnDebugMessage,
mockHandleSlashCommand, mockHandleSlashCommand,
@ -1577,7 +1560,6 @@ describe('useGeminiStream', () => {
new MockedGeminiClientClass(mockConfig), new MockedGeminiClientClass(mockConfig),
[], [],
mockAddItem, mockAddItem,
mockSetShowHelp,
mockConfig, mockConfig,
mockOnDebugMessage, mockOnDebugMessage,
mockHandleSlashCommand, mockHandleSlashCommand,
@ -1630,7 +1612,6 @@ describe('useGeminiStream', () => {
new MockedGeminiClientClass(mockConfig), new MockedGeminiClientClass(mockConfig),
[], [],
mockAddItem, mockAddItem,
mockSetShowHelp,
mockConfig, mockConfig,
mockOnDebugMessage, mockOnDebugMessage,
mockHandleSlashCommand, mockHandleSlashCommand,

View File

@ -82,7 +82,6 @@ export const useGeminiStream = (
geminiClient: GeminiClient, geminiClient: GeminiClient,
history: HistoryItem[], history: HistoryItem[],
addItem: UseHistoryManagerReturn['addItem'], addItem: UseHistoryManagerReturn['addItem'],
setShowHelp: React.Dispatch<React.SetStateAction<boolean>>,
config: Config, config: Config,
onDebugMessage: (message: string) => void, onDebugMessage: (message: string) => void,
handleSlashCommand: ( handleSlashCommand: (
@ -610,7 +609,6 @@ export const useGeminiStream = (
return; return;
const userMessageTimestamp = Date.now(); const userMessageTimestamp = Date.now();
setShowHelp(false);
// Reset quota error flag when starting a new query (not a continuation) // Reset quota error flag when starting a new query (not a continuation)
if (!options?.isContinuation) { if (!options?.isContinuation) {
@ -693,7 +691,6 @@ export const useGeminiStream = (
}, },
[ [
streamingState, streamingState,
setShowHelp,
setModelSwitchedFromQuotaError, setModelSwitchedFromQuotaError,
prepareQueryForGemini, prepareQueryForGemini,
processGeminiStreamEvents, processGeminiStreamEvents,

View File

@ -97,6 +97,11 @@ export type HistoryItemAbout = HistoryItemBase & {
gcpProject: string; gcpProject: string;
}; };
export type HistoryItemHelp = HistoryItemBase & {
type: 'help';
timestamp: Date;
};
export type HistoryItemStats = HistoryItemBase & { export type HistoryItemStats = HistoryItemBase & {
type: 'stats'; type: 'stats';
duration: string; duration: string;
@ -142,6 +147,7 @@ export type HistoryItemWithoutId =
| HistoryItemInfo | HistoryItemInfo
| HistoryItemError | HistoryItemError
| HistoryItemAbout | HistoryItemAbout
| HistoryItemHelp
| HistoryItemToolGroup | HistoryItemToolGroup
| HistoryItemStats | HistoryItemStats
| HistoryItemModelStats | HistoryItemModelStats
@ -157,6 +163,7 @@ export enum MessageType {
ERROR = 'error', ERROR = 'error',
USER = 'user', USER = 'user',
ABOUT = 'about', ABOUT = 'about',
HELP = 'help',
STATS = 'stats', STATS = 'stats',
MODEL_STATS = 'model_stats', MODEL_STATS = 'model_stats',
TOOL_STATS = 'tool_stats', TOOL_STATS = 'tool_stats',
@ -183,6 +190,11 @@ export type Message =
gcpProject: string; gcpProject: string;
content?: string; // Optional content, not really used for ABOUT content?: string; // Optional content, not really used for ABOUT
} }
| {
type: MessageType.HELP;
timestamp: Date;
content?: string; // Optional content, not really used for HELP
}
| { | {
type: MessageType.STATS; type: MessageType.STATS;
timestamp: Date; timestamp: Date;