mirror of
https://github.com/nexu-io/open-design.git
synced 2026-10-27 09:51:12 +01:00
feat(daemon): add Grok Build (xAI's first-party CLI) as agent runtime
xAI shipped Grok Build (https://x.ai/cli) on 2026-05-19 — a first- party CLI agent that boxes their SuperGrok subscription into a Claude-Code-shaped headless mode (`grok -p <prompt>`, optional `--output-format streaming-json`, `--max-turns`, native subagent / plan / mcp subcommands). The OAuth flow it ships uses the same `auth.x.ai` issuer + `b1a00492-073a-47ea-816f-4c329264a828` client_id + `grok-cli:access api:access` scope that the existing OD xAI Settings panel already speaks, so once a user runs the install script and `grok login --oauth`, Grok Build is fully authenticated without OD doing anything. This runtime def lets OD detect a `grok` binary on PATH and surface it in the agent picker the same way Hermes / Claude Code / Codex are surfaced today. Headless invocations get: - `grok -p` (prompt via stdin to avoid Windows ENAMETOOLONG / Linux E2BIG on large composed prompts), with `--model` / `--effort` pass-through when the user picks one in the picker. - `grok models` for live model discovery (parsed line-by-line, matching the existing `parseLineSeparatedModels` helper opencode / cursor-agent already use). Falls back to a static list of grok-build / grok-4.3 / grok-4.20-{reasoning,non-reasoning, multi-agent} when probing fails (no Heavy entitlement, network blip, etc.). - `--effort` exposed as the standard reasoning-options dropdown. streamFormat is intentionally `plain` for this first cut. Grok Build's `streaming-json` output is a real NDJSON event stream, but the schema is xAI-specific and OD does not yet have a parser for it — shipping with `plain` now means the user can chat single-turn, and a follow-up `grok-stream-json` adapter can light up tool_use / plan-mode streaming once we've validated the shape against a live Heavy account. No test added for the def itself; the existing `tests/runtimes/registry-and-args.test.ts` and `agent-args.test.ts` iterate over `AGENT_DEFS` and now cover this entry by construction. All 126 runtime tests pass; daemon tsc + tsconfig.tests.json clean; pnpm guard clean.
This commit is contained in:
@@ -0,0 +1,76 @@
|
||||
import { parseLineSeparatedModels, DEFAULT_MODEL_OPTION } from './shared.js';
|
||||
import type { RuntimeAgentDef } from '../types.js';
|
||||
|
||||
// xAI's first-party CLI agent — https://x.ai/cli — distributed as the
|
||||
// `grok` binary. Installed via `curl -fsSL https://x.ai/cli/install.sh | bash`,
|
||||
// which symlinks `~/.grok/bin/grok` into PATH.
|
||||
//
|
||||
// `grok` ships its own SuperGrok OAuth dance (same `auth.x.ai` issuer +
|
||||
// loopback-redirect shape Open Design's xAI Settings panel uses), so it's
|
||||
// already authenticated by the time OD detects the binary; OD does not
|
||||
// need to inject credentials. Users authenticate once with `grok login
|
||||
// --oauth` and the resulting `~/.grok/auth.json` is what every spawned
|
||||
// invocation reads.
|
||||
//
|
||||
// Headless mode follows Claude Code's pattern (`-p <PROMPT>` for single-
|
||||
// turn, `--output-format streaming-json` for structured streaming), but
|
||||
// the streaming-json schema is xAI-specific and we do not yet have a
|
||||
// daemon-side parser for it. To ship the runtime now and let users at
|
||||
// least chat with grok inside OD, this defaults to `plain` streamFormat
|
||||
// (single-turn text reply, no tool_use streaming). Upgrading to a
|
||||
// `grok-stream-json` event parser is follow-up work once the format is
|
||||
// stable enough to lock in.
|
||||
export const grokBuildAgentDef = {
|
||||
id: 'grok-build',
|
||||
name: 'Grok Build',
|
||||
bin: 'grok',
|
||||
versionArgs: ['--version'],
|
||||
helpArgs: ['-p', '--help'],
|
||||
// `grok models` prints one model id per line, plus a `Default model:`
|
||||
// header line that parseLineSeparatedModels strips because it isn't
|
||||
// an id token. Falls back to the static list below when probing fails
|
||||
// (no SuperGrok Heavy entitlement on this machine, network blip, etc.).
|
||||
listModels: {
|
||||
args: ['models'],
|
||||
timeoutMs: 10_000,
|
||||
parse: parseLineSeparatedModels,
|
||||
},
|
||||
fallbackModels: [
|
||||
DEFAULT_MODEL_OPTION,
|
||||
{ id: 'grok-build', label: 'grok-build (xAI · default)' },
|
||||
{ id: 'grok-4.3', label: 'grok-4.3 (xAI)' },
|
||||
{ id: 'grok-4.20-reasoning', label: 'grok-4.20-reasoning (xAI · deep)' },
|
||||
{
|
||||
id: 'grok-4.20-non-reasoning',
|
||||
label: 'grok-4.20-non-reasoning (xAI · fast)',
|
||||
},
|
||||
{
|
||||
id: 'grok-4.20-multi-agent',
|
||||
label: 'grok-4.20-multi-agent (xAI · orchestration)',
|
||||
},
|
||||
],
|
||||
// Prompt delivered via stdin so Windows `spawn ENAMETOOLONG` and Linux
|
||||
// `spawn E2BIG` can't truncate large composed prompts. `grok -p` with
|
||||
// no positional argument reads from piped stdin.
|
||||
buildArgs: (_prompt, _imagePaths, _extra = [], options = {}) => {
|
||||
const args = ['-p'];
|
||||
if (options.model && options.model !== DEFAULT_MODEL_OPTION.id) {
|
||||
args.push('--model', options.model);
|
||||
}
|
||||
if (options.reasoning) {
|
||||
args.push('--effort', options.reasoning);
|
||||
}
|
||||
return args;
|
||||
},
|
||||
reasoningOptions: [
|
||||
{ id: 'low', label: 'low' },
|
||||
{ id: 'medium', label: 'medium' },
|
||||
{ id: 'high', label: 'high' },
|
||||
{ id: 'xhigh', label: 'xhigh' },
|
||||
{ id: 'max', label: 'max' },
|
||||
],
|
||||
promptViaStdin: true,
|
||||
streamFormat: 'plain',
|
||||
installUrl: 'https://x.ai/cli',
|
||||
docsUrl: 'https://x.ai/cli',
|
||||
} satisfies RuntimeAgentDef;
|
||||
@@ -4,6 +4,7 @@ import { devinAgentDef } from './defs/devin.js';
|
||||
import { geminiAgentDef } from './defs/gemini.js';
|
||||
import { opencodeAgentDef } from './defs/opencode.js';
|
||||
import { hermesAgentDef } from './defs/hermes.js';
|
||||
import { grokBuildAgentDef } from './defs/grok-build.js';
|
||||
import { kimiAgentDef } from './defs/kimi.js';
|
||||
import { cursorAgentDef } from './defs/cursor-agent.js';
|
||||
import { qwenAgentDef } from './defs/qwen.js';
|
||||
@@ -24,6 +25,7 @@ const BASE_AGENT_DEFS: RuntimeAgentDef[] = [
|
||||
geminiAgentDef,
|
||||
opencodeAgentDef,
|
||||
hermesAgentDef,
|
||||
grokBuildAgentDef,
|
||||
kimiAgentDef,
|
||||
cursorAgentDef,
|
||||
qwenAgentDef,
|
||||
|
||||
Reference in New Issue
Block a user