mirror of
https://github.com/google-gemini/gemini-cli.git
synced 2026-04-25 20:44:46 -07:00
feat(cli): add streamlined gemini gemma local model setup (#25498)
Co-authored-by: Abhijit Balaji <abhijitbalaji@google.com> Co-authored-by: Samee Zahid <sameez@google.com> Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
This commit is contained in:
@@ -0,0 +1,41 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright 2026 Google LLC
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
import { CommandKind, type SlashCommand } from './types.js';
|
||||
import { MessageType, type HistoryItemGemmaStatus } from '../types.js';
|
||||
import { checkGemmaStatus } from '../../commands/gemma/status.js';
|
||||
import { GEMMA_MODEL_NAME } from '../../commands/gemma/constants.js';
|
||||
|
||||
export const gemmaStatusCommand: SlashCommand = {
|
||||
name: 'gemma',
|
||||
description: 'Check local Gemma model routing status',
|
||||
kind: CommandKind.BUILT_IN,
|
||||
autoExecute: true,
|
||||
isSafeConcurrent: true,
|
||||
action: async (context) => {
|
||||
const port =
|
||||
parseInt(
|
||||
context.services.settings.merged.experimental?.gemmaModelRouter?.classifier?.host?.match(
|
||||
/:(\d+)/,
|
||||
)?.[1] ?? '',
|
||||
10,
|
||||
) || undefined;
|
||||
const status = await checkGemmaStatus(port);
|
||||
const item: Omit<HistoryItemGemmaStatus, 'id'> = {
|
||||
type: MessageType.GEMMA_STATUS,
|
||||
binaryInstalled: status.binaryInstalled,
|
||||
binaryPath: status.binaryPath,
|
||||
modelName: GEMMA_MODEL_NAME,
|
||||
modelDownloaded: status.modelDownloaded,
|
||||
serverRunning: status.serverRunning,
|
||||
serverPid: status.serverPid,
|
||||
serverPort: status.port,
|
||||
settingsEnabled: status.settingsEnabled,
|
||||
allPassing: status.allPassing,
|
||||
};
|
||||
context.ui.addItem(item);
|
||||
},
|
||||
};
|
||||
@@ -32,6 +32,7 @@ import { ToolsList } from './views/ToolsList.js';
|
||||
import { SkillsList } from './views/SkillsList.js';
|
||||
import { AgentsStatus } from './views/AgentsStatus.js';
|
||||
import { McpStatus } from './views/McpStatus.js';
|
||||
import { GemmaStatus } from './views/GemmaStatus.js';
|
||||
import { ChatList } from './views/ChatList.js';
|
||||
import { ModelMessage } from './messages/ModelMessage.js';
|
||||
import { ThinkingMessage } from './messages/ThinkingMessage.js';
|
||||
@@ -228,6 +229,9 @@ export const HistoryItemDisplay: React.FC<HistoryItemDisplayProps> = ({
|
||||
{itemForDisplay.type === 'mcp_status' && (
|
||||
<McpStatus {...itemForDisplay} serverStatus={getMCPServerStatus} />
|
||||
)}
|
||||
{itemForDisplay.type === 'gemma_status' && (
|
||||
<GemmaStatus {...itemForDisplay} />
|
||||
)}
|
||||
{itemForDisplay.type === 'chat_list' && (
|
||||
<ChatList chats={itemForDisplay.chats} />
|
||||
)}
|
||||
|
||||
@@ -0,0 +1,120 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright 2026 Google LLC
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
import { Box, Text } from 'ink';
|
||||
import type React from 'react';
|
||||
import { theme } from '../../semantic-colors.js';
|
||||
import type { HistoryItemGemmaStatus } from '../../types.js';
|
||||
|
||||
type GemmaStatusProps = Omit<HistoryItemGemmaStatus, 'id' | 'type'>;
|
||||
|
||||
const StatusDot: React.FC<{ ok: boolean }> = ({ ok }) => (
|
||||
<Text color={ok ? theme.status.success : theme.status.error}>
|
||||
{ok ? '\u25CF' : '\u25CB'}
|
||||
</Text>
|
||||
);
|
||||
|
||||
export const GemmaStatus: React.FC<GemmaStatusProps> = ({
|
||||
binaryInstalled,
|
||||
binaryPath,
|
||||
modelName,
|
||||
modelDownloaded,
|
||||
serverRunning,
|
||||
serverPid,
|
||||
serverPort,
|
||||
settingsEnabled,
|
||||
allPassing,
|
||||
}) => (
|
||||
<Box flexDirection="column">
|
||||
<Text bold>Gemma Local Model Routing</Text>
|
||||
<Box height={1} />
|
||||
|
||||
<Box>
|
||||
<StatusDot ok={binaryInstalled} />
|
||||
<Text>
|
||||
{' '}
|
||||
<Text bold>Binary: </Text>
|
||||
{binaryInstalled ? (
|
||||
<Text color={theme.text.secondary}>{binaryPath}</Text>
|
||||
) : (
|
||||
<Text color={theme.status.error}>Not installed</Text>
|
||||
)}
|
||||
</Text>
|
||||
</Box>
|
||||
|
||||
<Box>
|
||||
<StatusDot ok={modelDownloaded} />
|
||||
<Text>
|
||||
{' '}
|
||||
<Text bold>Model: </Text>
|
||||
{modelDownloaded ? (
|
||||
<Text>{modelName}</Text>
|
||||
) : (
|
||||
<Text color={theme.status.error}>{modelName} not found</Text>
|
||||
)}
|
||||
</Text>
|
||||
</Box>
|
||||
|
||||
<Box>
|
||||
<StatusDot ok={serverRunning} />
|
||||
<Text>
|
||||
{' '}
|
||||
<Text bold>Server: </Text>
|
||||
{serverRunning ? (
|
||||
<Text>
|
||||
port {serverPort}
|
||||
{serverPid ? (
|
||||
<Text color={theme.text.secondary}> (PID {serverPid})</Text>
|
||||
) : null}
|
||||
</Text>
|
||||
) : (
|
||||
<Text color={theme.status.error}>
|
||||
not running on port {serverPort}
|
||||
</Text>
|
||||
)}
|
||||
</Text>
|
||||
</Box>
|
||||
|
||||
<Box>
|
||||
<StatusDot ok={settingsEnabled} />
|
||||
<Text>
|
||||
{' '}
|
||||
<Text bold>Settings: </Text>
|
||||
{settingsEnabled ? (
|
||||
<Text>enabled</Text>
|
||||
) : (
|
||||
<Text color={theme.status.error}>not enabled</Text>
|
||||
)}
|
||||
</Text>
|
||||
</Box>
|
||||
|
||||
<Box marginTop={1}>
|
||||
<Text bold>Active for: </Text>
|
||||
{allPassing ? (
|
||||
<Text color={theme.status.success}>[routing]</Text>
|
||||
) : (
|
||||
<Text color={theme.text.secondary}>none</Text>
|
||||
)}
|
||||
</Box>
|
||||
|
||||
<Box marginTop={1}>
|
||||
{allPassing ? (
|
||||
<Box flexDirection="column">
|
||||
<Text color={theme.text.secondary}>
|
||||
Simple requests route to Flash, complex requests to Pro.
|
||||
</Text>
|
||||
<Text color={theme.text.secondary}>
|
||||
This happens automatically on every request.
|
||||
</Text>
|
||||
</Box>
|
||||
) : (
|
||||
<Text color={theme.status.warning}>
|
||||
Run "gemini gemma setup" to install and configure.
|
||||
</Text>
|
||||
)}
|
||||
</Box>
|
||||
</Box>
|
||||
);
|
||||
@@ -355,6 +355,19 @@ export interface JsonMcpResource {
|
||||
description?: string;
|
||||
}
|
||||
|
||||
export type HistoryItemGemmaStatus = HistoryItemBase & {
|
||||
type: 'gemma_status';
|
||||
binaryInstalled: boolean;
|
||||
binaryPath: string | null;
|
||||
modelName: string;
|
||||
modelDownloaded: boolean;
|
||||
serverRunning: boolean;
|
||||
serverPid: number | null;
|
||||
serverPort: number;
|
||||
settingsEnabled: boolean;
|
||||
allPassing: boolean;
|
||||
};
|
||||
|
||||
export type HistoryItemMcpStatus = HistoryItemBase & {
|
||||
type: 'mcp_status';
|
||||
servers: Record<string, MCPServerConfig>;
|
||||
@@ -404,6 +417,7 @@ export type HistoryItemWithoutId =
|
||||
| HistoryItemSkillsList
|
||||
| HistoryItemAgentsList
|
||||
| HistoryItemMcpStatus
|
||||
| HistoryItemGemmaStatus
|
||||
| HistoryItemChatList
|
||||
| HistoryItemThinking
|
||||
| HistoryItemHint
|
||||
@@ -430,6 +444,7 @@ export enum MessageType {
|
||||
SKILLS_LIST = 'skills_list',
|
||||
AGENTS_LIST = 'agents_list',
|
||||
MCP_STATUS = 'mcp_status',
|
||||
GEMMA_STATUS = 'gemma_status',
|
||||
CHAT_LIST = 'chat_list',
|
||||
HINT = 'hint',
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user