Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions packages/cli/src/config/args.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
import yargs from 'yargs/yargs';
import { hideBin } from 'yargs/helpers';

const DEFAULT_GEMINI_MODEL = 'gemini-2.5-flash-preview-04-17';

export interface CliArgs {
target_dir: string | undefined;
model: string | undefined;
_: (string | number)[]; // Captures positional arguments
// Add other expected args here if needed
// e.g., verbose?: boolean;
Expand All @@ -16,6 +19,12 @@ export async function parseArguments(): Promise<CliArgs> {
description:
'The target directory for Gemini operations. Defaults to the current working directory.',
})
.option('model', {
alias: 'm',
type: 'string',
description: `The Gemini model to use. Defaults to ${DEFAULT_GEMINI_MODEL}.`,
default: DEFAULT_GEMINI_MODEL,
})
.help()
.alias('h', 'help')
.strict() // Keep strict mode to error on unknown options
Expand Down
50 changes: 50 additions & 0 deletions packages/cli/src/config/globalConfig.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import { CliArgs } from './args.js'; // Assuming CliArgs contains the needed fields
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should merge config into a single module.

Introduce a loadConfig that parses args, loads from environment, etc.

We should also avoid global state. Just pass a config type.


interface GlobalConfig {
model: string;
// Add other global config values here if needed
// e.g., targetDir?: string;
}

let config: GlobalConfig | null = null;

/**
* Initializes the global configuration. Should only be called once at application startup.
* @param args The parsed command-line arguments.
*/
export function initializeConfig(args: Pick<CliArgs, 'model'>): void {
if (config) {
console.warn('Global configuration already initialized.');
return;
}
if (!args.model) {
// This shouldn't happen if default is set correctly in args.ts
throw new Error('Model not provided during config initialization.');
}
config = {
model: args.model,
// Initialize other config values from args here
};
}

/**
* Retrieves the globally stored configuration.
* Throws an error if the configuration has not been initialized.
* @returns The global configuration object.
*/
export function getConfig(): GlobalConfig {
if (!config) {
throw new Error(
'Global configuration accessed before initialization. Call initializeConfig() first.',
);
}
return config;
}

/**
* Helper function to get the configured Gemini model name.
* @returns The model name string.
*/
export function getModel(): string {
return getConfig().model;
}
7 changes: 5 additions & 2 deletions packages/cli/src/core/gemini-client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import {
Content,
} from '@google/genai';
import { getApiKey } from '../config/env.js';
import { getModel } from '../config/globalConfig.js';
import { CoreSystemPrompt } from './prompts.js';
import {
type ToolCallEvent,
Expand Down Expand Up @@ -45,6 +46,7 @@ export class GeminiClient {

public async startChat(): Promise<Chat> {
const tools = toolRegistry.getToolSchemas();
const model = getModel();

// --- Get environmental information ---
const cwd = process.cwd();
Expand Down Expand Up @@ -73,7 +75,7 @@ ${folderStructure}

try {
const chat = this.ai.chats.create({
model: 'gemini-2.0-flash', //'gemini-2.0-flash',
model: model,
config: {
systemInstruction: CoreSystemPrompt,
...this.defaultHyperParameters,
Expand Down Expand Up @@ -446,9 +448,10 @@ Respond *only* in JSON format according to the following schema. Do not include
contents: Content[],
schema: SchemaUnion,
): Promise<any> {
const model = getModel();
try {
const result = await this.ai.models.generateContent({
model: 'gemini-2.0-flash', // Using flash for potentially faster structured output
model: model,
config: {
...this.defaultHyperParameters,
systemInstruction: CoreSystemPrompt,
Expand Down
10 changes: 8 additions & 2 deletions packages/cli/src/gemini.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { render } from 'ink';
import App from './ui/App.js';
import { parseArguments } from './config/args.js';
import { loadEnvironment } from './config/env.js';
import { initializeConfig } from './config/globalConfig.js';
import { getTargetDirectory } from './utils/paths.js';
import { toolRegistry } from './tools/tool-registry.js';
import { LSTool } from './tools/ls.tool.js';
Expand All @@ -16,14 +17,19 @@ import { WriteFileTool } from './tools/write-file.tool.js';
async function main() {
// 1. Configuration
loadEnvironment();
const argv = await parseArguments(); // Ensure args.ts imports printWarning from ui/display
const argv = await parseArguments();
initializeConfig({ model: argv.model as string });
const targetDir = getTargetDirectory(argv.target_dir);

// 2. Configure tools
registerTools(targetDir);

// 3. Render UI
render(React.createElement(App, { directory: targetDir }));
render(
React.createElement(App, {
directory: targetDir,
}),
);
}

// --- Global Unhandled Rejection Handler ---
Expand Down
5 changes: 4 additions & 1 deletion packages/cli/src/tools/terminal.tool.ts
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,10 @@ export class TerminalTool extends BaseTool<
private rejectShellReady: ((reason?: any) => void) | undefined; // Definite assignment assertion
private readonly backgroundTerminalAnalyzer: BackgroundTerminalAnalyzer;

constructor(rootDirectory: string, outputLimit: number = MAX_OUTPUT_LENGTH) {
constructor(
rootDirectory: string,
outputLimit: number = MAX_OUTPUT_LENGTH,
) {
const toolDisplayName = 'Terminal';
// --- LLM-Facing Description ---
// Updated description for background tasks to mention polling and LLM analysis
Expand Down
5 changes: 4 additions & 1 deletion packages/cli/src/ui/components/InputPrompt.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import React from 'react';
import { Box, Text } from 'ink';
import TextInput from 'ink-text-input';
import { getModel } from '../../config/globalConfig.js';

interface InputPromptProps {
query: string;
Expand All @@ -14,6 +15,8 @@ const InputPrompt: React.FC<InputPromptProps> = ({
setQuery,
onSubmit,
}) => {
const model = getModel();

return (
<Box marginTop={1} borderStyle="round" borderColor={'white'} paddingX={1}>
<Text color={'white'}>&gt; </Text>
Expand All @@ -24,7 +27,7 @@ const InputPrompt: React.FC<InputPromptProps> = ({
onSubmit={onSubmit}
showCursor={true}
focus={true}
placeholder={'Ask Gemini... (try "/init" or "/help")'}
placeholder={`Ask Gemini (${model})... (try "/init" or "/help")`}
/>
</Box>
</Box>
Expand Down
2 changes: 1 addition & 1 deletion packages/cli/src/utils/BackgroundTerminalAnalyzer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ export class BackgroundTerminalAnalyzer {
initialDelayMs?: number;
} = {}, // Provide default options
) {
this.ai = aiClient || new GeminiClient(); // Use injected client or default
this.ai = aiClient || new GeminiClient(); // Call constructor without model
this.pollIntervalMs = options.pollIntervalMs ?? 5000; // Default 5 seconds
this.maxAttempts = options.maxAttempts ?? 6; // Default 6 attempts (approx 30s total)
this.initialDelayMs = options.initialDelayMs ?? 500; // Default 0.5s initial delay
Expand Down