From 07ec1540c3e1049c8b5653f73af1a2d7e620aba6 Mon Sep 17 00:00:00 2001 From: z23cc Date: Tue, 22 Jul 2025 11:21:00 +0800 Subject: [PATCH] feat: add configurable base URL support (#19) --- README.md | 31 +++++++++++++++++++++++++++++++ src/agent/grok-agent.ts | 4 ++-- src/grok/client.ts | 4 ++-- src/index.ts | 27 ++++++++++++++++++++++++++- 4 files changed, 61 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index c0723dd..be21b30 100644 --- a/README.md +++ b/README.md @@ -55,6 +55,37 @@ cp .env.example .env grok --api-key your_api_key_here ``` +**Method 4: User Settings File** +Create `~/.grok/user-settings.json`: +```json +{ + "apiKey": "your_api_key_here" +} +``` + +### Custom Base URL (Optional) + +You can configure a custom Grok API endpoint (choose one method): + +**Method 1: Environment Variable** +```bash +export GROK_BASE_URL=https://your-custom-endpoint.com/v1 +``` + +**Method 2: Command Line Flag** +```bash +grok --api-key your_api_key_here --baseurl https://your-custom-endpoint.com/v1 +``` + +**Method 3: User Settings File** +Add to `~/.grok/user-settings.json`: +```json +{ + "apiKey": "your_api_key_here", + "baseURL": "https://your-custom-endpoint.com/v1" +} +``` + ## Usage Start the conversational AI assistant: diff --git a/src/agent/grok-agent.ts b/src/agent/grok-agent.ts index eb0353e..c35dae0 100644 --- a/src/agent/grok-agent.ts +++ b/src/agent/grok-agent.ts @@ -36,9 +36,9 @@ export class GrokAgent extends EventEmitter { private tokenCounter: TokenCounter; private abortController: AbortController | null = null; - constructor(apiKey: string) { + constructor(apiKey: string, baseURL?: string) { super(); - this.grokClient = new GrokClient(apiKey); + this.grokClient = new GrokClient(apiKey, undefined, baseURL); this.textEditor = new TextEditorTool(); this.bash = new BashTool(); this.todoTool = new TodoTool(); diff --git a/src/grok/client.ts b/src/grok/client.ts index 7241f0d..307ca14 100644 --- a/src/grok/client.ts +++ b/src/grok/client.ts @@ -40,10 +40,10 @@ export class GrokClient { private client: OpenAI; private currentModel: string = 'grok-3-latest'; - constructor(apiKey: string, model?: string) { + constructor(apiKey: string, model?: string, baseURL?: string) { this.client = new OpenAI({ apiKey, - baseURL: 'https://api.x.ai/v1', + baseURL: baseURL || process.env.GROK_BASE_URL || 'https://api.x.ai/v1', timeout: 360000, }); if (model) { diff --git a/src/index.ts b/src/index.ts index e2dae80..cc83e16 100755 --- a/src/index.ts +++ b/src/index.ts @@ -36,6 +36,29 @@ function loadApiKey(): string | undefined { return apiKey; } +// Load base URL from user settings if not in environment +function loadBaseURL(): string | undefined { + // First check environment variables + let baseURL = process.env.GROK_BASE_URL; + + if (!baseURL) { + // Try to load from user settings file + try { + const homeDir = os.homedir(); + const settingsFile = path.join(homeDir, '.grok', 'user-settings.json'); + + if (fs.existsSync(settingsFile)) { + const settings = JSON.parse(fs.readFileSync(settingsFile, 'utf8')); + baseURL = settings.baseURL; + } + } catch (error) { + // Ignore errors, baseURL will remain undefined + } + } + + return baseURL; +} + program .name("grok") .description( @@ -44,6 +67,7 @@ program .version("1.0.0") .option("-d, --directory ", "set working directory", process.cwd()) .option("-k, --api-key ", "Grok API key (or set GROK_API_KEY env var)") + .option("-u, --base-url ", "Grok API base URL (or set GROK_BASE_URL env var)") .action((options) => { if (options.directory) { try { @@ -60,7 +84,8 @@ program try { // Get API key from options, environment, or user settings const apiKey = options.apiKey || loadApiKey(); - const agent = apiKey ? new GrokAgent(apiKey) : undefined; + const baseURL = options.baseUrl || loadBaseURL(); + const agent = apiKey ? new GrokAgent(apiKey, baseURL) : undefined; console.log("🤖 Starting Grok CLI Conversational Assistant...\n");