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
16 changes: 9 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -114,16 +114,17 @@ This file stores **global settings** that apply across all projects. These setti

- **API Key**: Your Grok API key
- **Base URL**: Custom API endpoint (if needed)
- **Default Model**: Your preferred model (e.g., `grok-4-latest`)
- **Default Model**: Your preferred model (e.g., `grok-code-fast-1`)
- **Available Models**: List of models you can use

**Example:**
```json
{
"apiKey": "your_api_key_here",
"baseURL": "https://api.x.ai/v1",
"defaultModel": "grok-4-latest",
"defaultModel": "grok-code-fast-1",
"models": [
"grok-code-fast-1",
"grok-4-latest",
"grok-3-latest",
"grok-3-fast",
Expand Down Expand Up @@ -159,7 +160,7 @@ This file stores **project-specific settings** in your current working directory
1. **Global Defaults**: User-level settings provide your default preferences
2. **Project Override**: Project-level settings override defaults for specific projects
3. **Directory-Specific**: When you change directories, project settings are loaded automatically
4. **Fallback Logic**: Project model → User default model → System default (`grok-4-latest`)
4. **Fallback Logic**: Project model → User default model → System default (`grok-code-fast-1`)

This means you can have different models for different projects while maintaining consistent global settings like your API key.

Expand Down Expand Up @@ -245,6 +246,7 @@ You can specify which AI model to use with the `--model` parameter or `GROK_MODE
**Method 1: Command Line Flag**
```bash
# Use Grok models
grok --model grok-code-fast-1
grok --model grok-4-latest
grok --model grok-3-latest
grok --model grok-3-fast
Expand All @@ -256,7 +258,7 @@ grok --model claude-sonnet-4-20250514 --base-url https://api-endpoint.com/v1

**Method 2: Environment Variable**
```bash
export GROK_MODEL=grok-4-latest
export GROK_MODEL=grok-code-fast-1
grok
```

Expand All @@ -265,11 +267,11 @@ Add to `~/.grok/user-settings.json`:
```json
{
"apiKey": "your_api_key_here",
"defaultModel": "grok-4-latest"
"defaultModel": "grok-code-fast-1"
}
```

**Model Priority**: `--model` flag > `GROK_MODEL` environment variable > user default model > system default (grok-4-latest)
**Model Priority**: `--model` flag > `GROK_MODEL` environment variable > user default model > system default (grok-code-fast-1)

### Command Line Options

Expand All @@ -281,7 +283,7 @@ Options:
-d, --directory <dir> set working directory
-k, --api-key <key> Grok API key (or set GROK_API_KEY env var)
-u, --base-url <url> Grok API base URL (or set GROK_BASE_URL env var)
-m, --model <model> AI model to use (e.g., grok-4-latest, grok-3-latest) (or set GROK_MODEL env var)
-m, --model <model> AI model to use (e.g., grok-code-fast-1, grok-4-latest) (or set GROK_MODEL env var)
-p, --prompt <prompt> process a single prompt and exit (headless mode)
--max-tool-rounds <rounds> maximum number of tool execution rounds (default: 400)
-h, --help display help for command
Expand Down
10 changes: 5 additions & 5 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@vibe-kit/grok-cli",
"version": "0.0.23",
"version": "0.0.26",
"description": "An open-source AI agent that brings the power of Grok directly into your terminal.",
"main": "dist/index.js",
"bin": {
Expand Down
4 changes: 2 additions & 2 deletions src/agent/grok-agent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ export class GrokAgent extends EventEmitter {
super();
const manager = getSettingsManager();
const savedModel = manager.getCurrentModel();
const modelToUse = model || savedModel || "grok-4-latest";
const modelToUse = model || savedModel || "grok-code-fast-1";
this.maxToolRounds = maxToolRounds || 400;
this.grokClient = new GrokClient(apiKey, modelToUse, baseURL);
this.textEditor = new TextEditorTool();
Expand Down Expand Up @@ -160,7 +160,7 @@ Current working directory: ${process.cwd()}`,
await initializeMCPServers();
}
} catch (error) {
console.warn('MCP initialization failed:', error);
console.warn("MCP initialization failed:", error);
} finally {
this.mcpInitialized = true;
}
Expand Down
7 changes: 3 additions & 4 deletions src/grok/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ export interface GrokResponse {

export class GrokClient {
private client: OpenAI;
private currentModel: string = "grok-3-latest";
private currentModel: string = "grok-code-fast-1";

constructor(apiKey: string, model?: string, baseURL?: string) {
this.client = new OpenAI({
Expand Down Expand Up @@ -89,9 +89,8 @@ export class GrokClient {
requestPayload.search_parameters = searchOptions.search_parameters;
}

const response = await this.client.chat.completions.create(
requestPayload
);
const response =
await this.client.chat.completions.create(requestPayload);

return response as GrokResponse;
} catch (error: any) {
Expand Down
36 changes: 27 additions & 9 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -65,21 +65,27 @@ function loadBaseURL(): string {
}

// Save command line settings to user settings file
async function saveCommandLineSettings(apiKey?: string, baseURL?: string): Promise<void> {
async function saveCommandLineSettings(
apiKey?: string,
baseURL?: string
): Promise<void> {
try {
const manager = getSettingsManager();

// Update with command line values
if (apiKey) {
manager.updateUserSetting('apiKey', apiKey);
manager.updateUserSetting("apiKey", apiKey);
console.log("✅ API key saved to ~/.grok/user-settings.json");
}
if (baseURL) {
manager.updateUserSetting('baseURL', baseURL);
manager.updateUserSetting("baseURL", baseURL);
console.log("✅ Base URL saved to ~/.grok/user-settings.json");
}
} catch (error) {
console.warn("⚠️ Could not save settings to file:", error instanceof Error ? error.message : "Unknown error");
console.warn(
"⚠️ Could not save settings to file:",
error instanceof Error ? error.message : "Unknown error"
);
}
}

Expand Down Expand Up @@ -307,6 +313,7 @@ program
"A conversational AI CLI tool powered by Grok with text editor capabilities"
)
.version("1.0.1")
.argument("[message...]", "Initial message to send to Grok")
.option("-d, --directory <dir>", "set working directory", process.cwd())
.option("-k, --api-key <key>", "Grok API key (or set GROK_API_KEY env var)")
.option(
Expand All @@ -315,7 +322,7 @@ program
)
.option(
"-m, --model <model>",
"AI model to use (e.g., gemini-2.5-pro, grok-4-latest) (or set GROK_MODEL env var)"
"AI model to use (e.g., grok-code-fast-1, grok-4-latest) (or set GROK_MODEL env var)"
)
.option(
"-p, --prompt <prompt>",
Expand All @@ -326,7 +333,7 @@ program
"maximum number of tool execution rounds (default: 400)",
"400"
)
.action(async (options) => {
.action(async (message, options) => {
if (options.directory) {
try {
process.chdir(options.directory);
Expand Down Expand Up @@ -360,7 +367,13 @@ program

// Headless mode: process prompt and exit
if (options.prompt) {
await processPromptHeadless(options.prompt, apiKey, baseURL, model, maxToolRounds);
await processPromptHeadless(
options.prompt,
apiKey,
baseURL,
model,
maxToolRounds
);
return;
}

Expand All @@ -370,7 +383,12 @@ program

ensureUserSettingsDirectory();

render(React.createElement(ChatInterface, { agent }));
// Support variadic positional arguments for multi-word initial message
const initialMessage = Array.isArray(message)
? message.join(" ")
: message;

render(React.createElement(ChatInterface, { agent, initialMessage }));
} catch (error: any) {
console.error("❌ Error initializing Grok CLI:", error.message);
process.exit(1);
Expand All @@ -393,7 +411,7 @@ gitCommand
)
.option(
"-m, --model <model>",
"AI model to use (e.g., gemini-2.5-pro, grok-4-latest) (or set GROK_MODEL env var)"
"AI model to use (e.g., grok-code-fast-1, grok-4-latest) (or set GROK_MODEL env var)"
)
.option(
"--max-tool-rounds <rounds>",
Expand Down
52 changes: 47 additions & 5 deletions src/ui/components/chat-interface.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,17 @@ import cfonts from "cfonts";

interface ChatInterfaceProps {
agent?: GrokAgent;
initialMessage?: string;
}

// Main chat component that handles input when agent is available
function ChatInterfaceWithAgent({ agent }: { agent: GrokAgent }) {
function ChatInterfaceWithAgent({
agent,
initialMessage,
}: {
agent: GrokAgent;
initialMessage?: string;
}) {
const [chatHistory, setChatHistory] = useState<ChatEntry[]>([]);
const [isProcessing, setIsProcessing] = useState(false);
const [processingTime, setProcessingTime] = useState(0);
Expand Down Expand Up @@ -101,6 +108,29 @@ function ChatInterfaceWithAgent({ agent }: { agent: GrokAgent }) {
setChatHistory([]);
}, []);

// Process initial message if provided
useEffect(() => {
if (initialMessage && agent) {
// First, immediately add the user message to chat history
const userEntry: ChatEntry = {
type: "user",
content: initialMessage,
timestamp: new Date(),
};
setChatHistory([userEntry]);

// Then process the message asynchronously
const processInitialMessage = async () => {
setIsProcessing(true);
const entries = await agent.processUserMessage(initialMessage);
setChatHistory(entries);
setIsProcessing(false);
};

processInitialMessage();
}
}, [initialMessage, agent]);

useEffect(() => {
const handleConfirmationRequest = (options: ConfirmationOptions) => {
setConfirmationOptions(options);
Expand Down Expand Up @@ -178,7 +208,8 @@ function ChatInterfaceWithAgent({ agent }: { agent: GrokAgent }) {

<Box flexDirection="column" marginBottom={1}>
<Text color="gray">
Type your request in natural language. Ctrl+C to clear, 'exit' to quit.
Type your request in natural language. Ctrl+C to clear, 'exit' to
quit.
</Text>
</Box>

Expand Down Expand Up @@ -222,7 +253,10 @@ function ChatInterfaceWithAgent({ agent }: { agent: GrokAgent }) {
{autoEditEnabled ? "▶" : "⏸"} auto-edit:{" "}
{autoEditEnabled ? "on" : "off"}
</Text>
<Text color="gray" dimColor> (shift + tab)</Text>
<Text color="gray" dimColor>
{" "}
(shift + tab)
</Text>
</Box>
<Box marginRight={2}>
<Text color="yellow">≋ {agent.getCurrentModel()}</Text>
Expand Down Expand Up @@ -250,7 +284,10 @@ function ChatInterfaceWithAgent({ agent }: { agent: GrokAgent }) {
}

// Main component that handles API key input or chat interface
export default function ChatInterface({ agent }: ChatInterfaceProps) {
export default function ChatInterface({
agent,
initialMessage,
}: ChatInterfaceProps) {
const [currentAgent, setCurrentAgent] = useState<GrokAgent | null>(
agent || null
);
Expand All @@ -263,5 +300,10 @@ export default function ChatInterface({ agent }: ChatInterfaceProps) {
return <ApiKeyInput onApiKeySet={handleApiKeySet} />;
}

return <ChatInterfaceWithAgent agent={currentAgent} />;
return (
<ChatInterfaceWithAgent
agent={currentAgent}
initialMessage={initialMessage}
/>
);
}
Loading