Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
9141f62
chore(harness-grok-build): scaffold package and build configs
mlekhi Jun 17, 2026
325cb05
chore(harness-grok-build): add root tsconfig reference and grok devDe…
mlekhi Jun 17, 2026
1217577
feat(harness-grok-build): add auth resolver
mlekhi Jun 17, 2026
9506844
refactor(harness-grok-build): always forward gateway base url in auth…
mlekhi Jun 17, 2026
a4348d1
feat(harness-grok-build): add bridge protocol start schema
mlekhi Jun 17, 2026
69ee112
Add GROK_BUILD_BUILTIN_TOOLS (read/write/edit/bash/glob/grep/webSearch)
mlekhi Jun 17, 2026
c7f7127
feat(harness-grok-build): add createGrokBuild factory and bootstrap r…
mlekhi Jun 17, 2026
918cd4c
feat(harness-grok-build): map streaming-json output to harness stream…
mlekhi Jun 18, 2026
9096156
add bridge turn driver and doStart
mlekhi Jun 18, 2026
ad747c6
add local generate-text smoke test
mlekhi Jun 18, 2026
692088b
adding vercel sandbox to smoke test
mlekhi Jun 18, 2026
a4e6cf6
setting changeset to major
mlekhi Jun 18, 2026
0c67b1a
cutting
mlekhi Jun 18, 2026
604a372
adding robustness + cleaning
mlekhi Jun 18, 2026
bec5953
wire into e2e-tui and e2e-next apps
mlekhi Jun 18, 2026
d7473b0
feat(harness-grok-build): conditionally forward bridge stderr based o…
mlekhi Jun 18, 2026
45d2b83
fix(harness-grok-build): continue thread on resume and apply turn ins…
mlekhi Jun 18, 2026
f23f83b
adding changelog
mlekhi Jun 18, 2026
65439bb
docs(harness-grok-build): add README, provider docs, and examples
mlekhi Jun 18, 2026
1b61e11
security bump
mlekhi Jun 18, 2026
0c12f4c
refactor(harness-grok-build): remove debug option and enhance gateway…
mlekhi Jun 19, 2026
b1e71ca
adding attach/resume
mlekhi Jun 19, 2026
4c5c738
cutting planning
mlekhi Jun 29, 2026
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
5 changes: 5 additions & 0 deletions .changeset/grok-build-turn-driver.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@ai-sdk/harness-grok-build': major
---

feat(harness-grok-build): implement bridge turn driver and doStart
2 changes: 2 additions & 0 deletions content/docs/03-ai-sdk-harnesses/05-harness-adapters.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ The AI SDK includes the following harness adapters:
- [Claude Code](/providers/ai-sdk-harnesses/claude-code) (`@ai-sdk/harness-claude-code`)
- [Codex](/providers/ai-sdk-harnesses/codex) (`@ai-sdk/harness-codex`)
- [Pi](/providers/ai-sdk-harnesses/pi) (`@ai-sdk/harness-pi`)
- [Grok Build](/providers/ai-sdk-harnesses/grok-build) (`@ai-sdk/harness-grok-build`)

### Coming Soon

Expand All @@ -33,3 +34,4 @@ The AI SDK includes the following harness adapters:
| [Claude Code](/providers/ai-sdk-harnesses/claude-code) | Sandbox bridge | <Check size={18} /> | <Check size={18} /> | <Check size={18} /> |
| [Codex](/providers/ai-sdk-harnesses/codex) | Sandbox bridge | <Check size={18} /> | <Check size={18} /> | <Cross size={18} /> |
| [Pi](/providers/ai-sdk-harnesses/pi) | Host process | <Check size={18} /> | <Check size={18} /> | <Check size={18} /> |
| [Grok Build](/providers/ai-sdk-harnesses/grok-build) | Sandbox bridge | <Cross size={18} /> | <Cross size={18} /> | <Cross size={18} /> |
4 changes: 2 additions & 2 deletions content/docs/03-ai-sdk-harnesses/index.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ description: Use established agent harnesses through the AI SDK.
# AI SDK Harnesses

The harness section covers the AI SDK harness abstraction: a uniform API for
running established agent harnesses such as Claude Code, Codex, and Pi.
running established agent harnesses such as Claude Code, Codex, Pi, and Grok Build.

<IndexCards
cards={[
Expand Down Expand Up @@ -36,7 +36,7 @@ running established agent harnesses such as Claude Code, Codex, and Pi.
{
title: 'Harness Adapters',
description:
'Choose from the implemented Claude Code, Codex, and Pi harness adapters.',
'Choose from the implemented Claude Code, Codex, Pi, and Grok Build harness adapters.',
href: '/docs/ai-sdk-harnesses/harness-adapters',
},
{
Expand Down
168 changes: 168 additions & 0 deletions content/providers/02-ai-sdk-harnesses/04-grok-build.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,168 @@
---
title: Grok Build
description: Learn how to use the Grok Build harness adapter.
---

# Grok Build Harness

The Grok Build harness adapter connects `HarnessAgent` to the `grok` CLI. The
adapter runs a bridge inside the sandbox and streams the CLI's
`--output-format streaming-json` events back to the host over a sandbox-exposed
WebSocket.

<Note>
Harness packages are **experimental**. Expect breaking changes between
releases as this early API gets further refined.
</Note>

## Setup

<Tabs items={['pnpm', 'npm', 'yarn', 'bun']}>
<Tab>
<Snippet
text="pnpm add @ai-sdk/harness@beta @ai-sdk/harness-grok-build@beta @ai-sdk/sandbox-vercel@beta"
dark
/>
</Tab>
<Tab>
<Snippet
text="npm install @ai-sdk/harness@beta @ai-sdk/harness-grok-build@beta @ai-sdk/sandbox-vercel@beta"
dark
/>
</Tab>
<Tab>
<Snippet
text="yarn add @ai-sdk/harness@beta @ai-sdk/harness-grok-build@beta @ai-sdk/sandbox-vercel@beta"
dark
/>
</Tab>
<Tab>
<Snippet
text="bun add @ai-sdk/harness@beta @ai-sdk/harness-grok-build@beta @ai-sdk/sandbox-vercel@beta"
dark
/>
</Tab>
</Tabs>

The adapter installs the `grok` CLI inside the sandbox when the first session
starts. This requires network egress for the bootstrap install.

## Import

```ts
import { grokBuild, createGrokBuild } from '@ai-sdk/harness-grok-build';
```

`grokBuild` is equivalent to `createGrokBuild()` with its default configuration.

## Basic Usage

```ts
import { HarnessAgent } from '@ai-sdk/harness/agent';
import { grokBuild } from '@ai-sdk/harness-grok-build';
import { createVercelSandbox } from '@ai-sdk/sandbox-vercel';

const agent = new HarnessAgent({
harness: grokBuild,
sandbox: createVercelSandbox({
runtime: 'node24',
ports: [4000],
}),
});

const session = await agent.createSession();

let exitCode = 0;
try {
const result = await agent.stream({
session,
prompt: 'In one sentence, what is the capital of France?',
});

for await (const part of result.stream) {
if (part.type === 'text-delta') {
process.stdout.write(part.text);
}
}
} catch (err) {
exitCode = 1;
console.error(err);
} finally {
await session.destroy();
process.exit(exitCode);
}
```

To use this agent, ensure environment variables include `VERCEL_OIDC_TOKEN` for
Vercel Sandbox, and one of the variables listed under [authentication](#authentication)
for Grok.

## Adapter Settings

Use `createGrokBuild()` to configure the runtime:

```ts
const harness = createGrokBuild({
model: 'grok-code-fast-1',
});
```

Settings:

- `auth`: xAI or AI Gateway authentication settings.
- `model`: Grok model id. If omitted, the adapter uses its pinned default.
- `port`: bridge port override.
- `startupTimeoutMs`: maximum time to wait for the bridge to start.

## Authentication

By default, authentication is resolved from the host environment and forwarded
to the sandbox bridge. The adapter checks for AI Gateway and xAI credentials.

Supported environment variables:

- `XAI_API_KEY` (direct)
- `AI_GATEWAY_API_KEY` (AI Gateway)
- `VERCEL_OIDC_TOKEN` (AI Gateway)

The CLI maps these internally to `GROK_MODELS_BASE_URL` / `GROK_CODE_XAI_API_KEY`.

You can also pass explicit auth settings:

```ts
const harness = createGrokBuild({
auth: {
xai: {
apiKey: process.env.XAI_API_KEY,
},
},
});
```

## Sandbox

Grok Build requires a network sandbox with at least one exposed TCP port,
e.g. `@ai-sdk/sandbox-vercel`:

```ts
const sandbox = createVercelSandbox({
runtime: 'node24',
ports: [4000],
});
```

## Known limitations

The grok CLI's `--output-format streaming-json` surface is narrow:

- Streams reasoning and text only — no tool-call, tool-result, or file-change
events, and no token usage.
- Allow-all permission mode only. The CLI runs with `--always-approve` and
executes tools itself; use `permissionMode: 'allow-all'`.
- No compaction.

## Related

- [HarnessAgent](/docs/ai-sdk-harnesses/harness-agent)
- [Harness tools](/docs/ai-sdk-harnesses/tools)
- [Harness adapters](/docs/ai-sdk-harnesses/harness-adapters)
5 changes: 5 additions & 0 deletions content/providers/02-ai-sdk-harnesses/index.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,11 @@ and response primitives.
description: 'Use Pi through the AI SDK harness abstraction.',
href: '/providers/ai-sdk-harnesses/pi',
},
{
title: 'Grok Build',
description: 'Use Grok Build through the AI SDK harness abstraction.',
href: '/providers/ai-sdk-harnesses/grok-build',
},
]}
/>

Expand Down
1 change: 1 addition & 0 deletions examples/ai-functions/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
"@ai-sdk/harness": "workspace:*",
"@ai-sdk/harness-claude-code": "workspace:*",
"@ai-sdk/harness-codex": "workspace:*",
"@ai-sdk/harness-grok-build": "workspace:*",
"@ai-sdk/harness-pi": "workspace:*",
"@ai-sdk/huggingface": "workspace:*",
"@ai-sdk/hume": "workspace:*",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import { HarnessAgent } from '@ai-sdk/harness/agent';
import { grokBuild } from '@ai-sdk/harness-grok-build';
import { createVercelSandbox } from '@ai-sdk/sandbox-vercel';
import { run } from '../../lib/run';

// End-to-end smoke test against the Vercel Sandbox (required: grok-build is
// bridge-backed and needs a port, which the local just-bash sandbox cannot
// expose). Requires Vercel Sandbox credentials (OIDC token / `vercel` auth)
// and XAI_API_KEY (or AI Gateway env) in examples/ai-functions/.env.
run(async () => {
const sandbox = createVercelSandbox({
runtime: 'node24',
ports: [4000],
timeout: 10 * 60 * 1000,
});
const agent = new HarnessAgent({
harness: grokBuild,
sandbox,
});

let exitCode = 0;
const session = await agent.createSession();
try {
const result = await agent.generate({
session,
prompt: 'In one sentence, what is the capital of France?',
});
console.log('text:', result.text);
console.log('finishReason:', result.finishReason);
console.log('usage:', result.usage);
} catch (err) {
exitCode = 1;
console.error('[example] failed:', err);
} finally {
await session.destroy();
process.exit(exitCode);
}
});
41 changes: 41 additions & 0 deletions examples/ai-functions/src/harness-agent/grok-build/multi-turn.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import { HarnessAgent } from '@ai-sdk/harness/agent';
import { grokBuild } from '@ai-sdk/harness-grok-build';
import { printFullStream } from '../../lib/print-full-stream';
import { run } from '../../lib/run';
import { createVercelSandbox } from '@ai-sdk/sandbox-vercel';

run(async () => {
const sandbox = createVercelSandbox({
runtime: 'node24',
ports: [4000],
timeout: 10 * 60 * 1000,
});
const agent = new HarnessAgent({
harness: grokBuild,
sandbox,
});

let exitCode = 0;
const session = await agent.createSession();
try {
console.log('--- turn 1 ---');
const first = await agent.stream({
session,
prompt: 'My name is Felix. Remember it.',
});
await printFullStream({ result: first });

console.log('--- turn 2 ---');
const second = await agent.stream({
session,
prompt: 'What is my name? Answer in one word.',
});
await printFullStream({ result: second });
} catch (err) {
exitCode = 1;
console.error('[example] failed:', err);
} finally {
await session.destroy();
process.exit(exitCode);
}
});
61 changes: 61 additions & 0 deletions examples/ai-functions/src/harness-agent/grok-build/resume.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
/*
* Cross-process resume smoke test for the Grok Build harness.
*
* Within a single Node process this simulates the REST-server flow: turn 1
* runs, the session is stopped, the agent reference is dropped, and a fresh
* `HarnessAgent` instance picks the conversation back up using the persisted
* `HarnessAgentResumeSessionState`. The resume payload carries the grok CLI
* session id, which feeds `--resume` on the second turn so the model
* remembers the name from turn 1.
*/
import {
HarnessAgent,
type HarnessAgentResumeSessionState,
} from '@ai-sdk/harness/agent';
import { grokBuild } from '@ai-sdk/harness-grok-build';
import { createVercelSandbox } from '@ai-sdk/sandbox-vercel';
import { printFullStream } from '../../lib/print-full-stream';
import { run } from '../../lib/run';

run(async () => {
const sandbox = createVercelSandbox({
runtime: 'node24',
ports: [4000],
timeout: 10 * 60 * 1000,
});

// Turn 1: introduce the name.
let sessionId: string;
let resumeState: HarnessAgentResumeSessionState;
{
const agent = new HarnessAgent({ harness: grokBuild, sandbox });
const session = await agent.createSession();
sessionId = session.sessionId;
console.log('--- turn 1 ---');
const result = await agent.stream({
session,
prompt: 'My name is Maya. Remember it.',
});
await printFullStream({ result });
resumeState = await session.stop();
console.log('[stopped] resume state:', JSON.stringify(resumeState));
}

// Turn 2: brand-new agent instance, only the persisted state survives.
{
const agent = new HarnessAgent({ harness: grokBuild, sandbox });
const session = await agent.createSession({
sessionId,
resumeFrom: resumeState,
});
console.log('--- turn 2 (resumed) ---');
const result = await agent.stream({
session,
prompt: 'What is my name? Answer in one word.',
});
await printFullStream({ result });
await session.destroy();
}

process.exit(0);
});
Loading