Skip to content
Draft
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
5 changes: 5 additions & 0 deletions .changeset/slimy-windows-count.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@ai-sdk/harness-eve": major
---

feat(harness-eve): add experimental eve harness
10 changes: 9 additions & 1 deletion .github/konsistent.json
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,6 @@
"from": "./${harnessId}-harness"
}
],
"exportConstants": ["${harnessId.toCamelCase()}"],
"exportTypes": [
{
"name": "${harnessId.toPascalCase()}HarnessSettings",
Expand All @@ -146,6 +145,14 @@
"haveFiles": ["${harnessId}-harness.ts"]
}
},
{
"name": "harness-package-must-export-default-harness-instance",
"description": "Every generic harness package must export a default harness instance.",
"excludeFiles": ["packages/harness-eve/src/index.ts"],
"must": {
"exportConstants": ["${harnessId.toCamelCase()}"]
}
},
{
"name": "harness-file-must-export-harness-creator-and-settings-type",
"description": "Every harness file must export a harness creator function and a harness settings type.",
Expand Down Expand Up @@ -211,6 +218,7 @@
"name": "harness-auth-file-must-export-relevant-symbols",
"description": "Every harness auth file must export the relevant symbols.",
"for": { "files": ["${harnessId}-auth.ts"] },
"excludeFiles": ["packages/harness-eve/src/eve-auth.ts"],
"must": {
"import": [
{
Expand Down
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`)
- [Deep Agents](/providers/ai-sdk-harnesses/deepagents) (`@ai-sdk/harness-deepagents`)
- [Eve](/providers/ai-sdk-harnesses/eve) (`@ai-sdk/harness-eve`)
- [OpenCode](/providers/ai-sdk-harnesses/opencode) (`@ai-sdk/harness-opencode`)
- [Pi](/providers/ai-sdk-harnesses/pi) (`@ai-sdk/harness-pi`)

Expand All @@ -33,5 +34,6 @@ 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} /> | <Check size={18} /> |
| [Codex](/providers/ai-sdk-harnesses/codex) | Sandbox bridge | <Check size={18} /> | <Check size={18} /> | <Cross size={18} /> | <Cross size={18} /> |
| [Deep Agents](/providers/ai-sdk-harnesses/deepagents) | Sandbox bridge | <Check size={18} /> | <Check size={18} /> | <Check size={18} /> | <Check size={18} /> via auto-rejection |
| [Eve](/providers/ai-sdk-harnesses/eve) | Remote Eve agent | <Cross size={18} /> | <Cross size={18} /> | <Check size={18} /> | <Check size={18} /> via auto-rejection |
| [OpenCode](/providers/ai-sdk-harnesses/opencode) | Sandbox bridge | <Check size={18} /> | <Check size={18} /> | <Check size={18} /> | <Check size={18} /> via auto-rejection |
| [Pi](/providers/ai-sdk-harnesses/pi) | Host process | <Check size={18} /> | <Check size={18} /> | <Check size={18} /> | <Check size={18} /> |
223 changes: 223 additions & 0 deletions content/providers/02-ai-sdk-harnesses/06-eve.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,223 @@
---
title: Eve
description: Learn how to use the Eve harness adapter.
---

# Eve Harness

The Eve harness adapter connects `HarnessAgent` to a specific remote
[Eve](https://eve.dev/) agent. Eve does not expose a generic harness process;
the harness is part of the Eve agent application, so the adapter requires the
URL of the Eve agent you want to run.

<Note>
Harness packages are **experimental**. The Eve adapter is especially
experimental because the remote Eve agent owns its tools, skills, model, and
sandbox.
</Note>

## Setup

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

## Import

```ts
import { createEve } from '@ai-sdk/harness-eve';
```

The package does not export an `eve` constant. Each harness instance needs a
specific Eve agent URL.

## Basic Usage

```ts
import { HarnessAgent } from '@ai-sdk/harness/agent';
import { createEve } from '@ai-sdk/harness-eve';
import { createJustBashSandbox } from '@ai-sdk/sandbox-just-bash';

const agent = new HarnessAgent({
harness: createEve({
url: process.env.EVE_AGENT_URL!,
}),
sandbox: createJustBashSandbox(),
});

const session = await agent.createSession();

try {
const result = await agent.stream({
session,
prompt: 'Check the test failures and explain the smallest fix.',
});

for await (const part of result.stream) {
if (part.type === 'text-delta') {
process.stdout.write(part.text);
}
}
} finally {
await session.destroy();
}
```

## Adapter Settings

Use `createEve()` to configure the remote agent connection:

```ts
const harness = createEve({
url: 'https://my-eve-agent.vercel.app',
auth: 'auto',
});
```

Settings:

- `url`: remote Eve agent URL.
- `auth`: Eve client auth mode. Defaults to `auto`.
- `headers`: additional headers for the Eve client.
- `redirect`: fetch redirect policy.
- `maxReconnectAttempts`: stream reconnect attempts.
- `preserveCompletedSessions`: whether Eve keeps continuation state after
completed turns. Defaults to `true`.

## Authentication

By default, remote Eve agent URLs use Eve's public Vercel OIDC auth helper.
That helper reads `VERCEL_OIDC_TOKEN` and refreshes development tokens when
needed. This matches the credential-bearing request path used by remote Eve
development clients.

```ts
const harness = createEve({
url: process.env.EVE_AGENT_URL!,
});
```

For a public Eve agent that does not require auth, opt out explicitly:

```ts
const harness = createEve({
url: process.env.EVE_AGENT_URL!,
auth: 'none',
});
```

Explicit credential modes are also available:

```ts
const harness = createEve({
url: process.env.EVE_AGENT_URL!,
auth: {
type: 'vercel-oidc',
token: process.env.VERCEL_OIDC_TOKEN,
},
});
```

If the resolver needs an explicit Vercel scope, pass `team` and `project`
instead of a static token:

```ts
const harness = createEve({
url: process.env.EVE_AGENT_URL!,
auth: {
type: 'vercel-oidc',
team: 'team_...',
project: 'prj_...',
},
});
```

When `VERCEL_AUTOMATION_BYPASS_SECRET` is set, the adapter forwards it as the
Vercel deployment protection bypass header.

Supported auth modes:

- `auto`: uses Eve's Vercel OIDC resolver for remote URLs; local URLs can run
without auth when no token is available.
- `none`: sends no Eve auth headers.
- `vercel-oidc`: sends a Vercel OIDC token.
- `bearer`: sends a bearer token.
- `basic`: sends basic auth credentials.

## Sandbox

`HarnessAgent` still requires a sandbox provider, but Eve does not use the AI
SDK sandbox. The remote Eve agent uses its own sandbox configuration and does
not expose a public API for the AI SDK adapter to replace it.

Use `@ai-sdk/sandbox-just-bash` when you only need a lightweight required
sandbox provider:

```ts
const agent = new HarnessAgent({
harness: createEve({
url: process.env.EVE_AGENT_URL!,
}),
sandbox: createJustBashSandbox(),
});
```

## Built-in Tools

The adapter exposes these Eve framework tools through `agent.tools`:

- `read`
- `write`
- `bash`
- `grep`
- `glob`
- `webSearch`
- `web_fetch`
- `todo`
- `agent`
- `load_skill`
- `connection_search`

Eve-authored tools and other agent-specific tools are surfaced as
provider-executed dynamic tool calls when the remote agent requests them.

Eve confirmation approvals are supported. `ask_question` and other non-
confirmation input requests are not supported by this adapter.

## Limitations

- Host-defined AI SDK tools are not supported.
- `activeTools` and `inactiveTools` are not supported.
- Host-provided skills are not supported.
- The AI SDK cannot provide or replace the remote Eve sandbox.
- Manual compaction is not supported.
- Eve `ask_question` requests are not supported.

## Related

- [HarnessAgent](/docs/ai-sdk-harnesses/harness-agent)
- [Harness tools](/docs/ai-sdk-harnesses/tools)
- [Harness adapters](/docs/ai-sdk-harnesses/harness-adapters)
6 changes: 6 additions & 0 deletions content/providers/02-ai-sdk-harnesses/index.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,12 @@ and response primitives.
description: 'Use Codex through the AI SDK harness abstraction.',
href: '/providers/ai-sdk-harnesses/codex',
},
{
title: 'Eve',
description:
'Use a remote Eve agent through the AI SDK harness abstraction.',
href: '/providers/ai-sdk-harnesses/eve',
},
{
title: 'OpenCode',
description: 'Use OpenCode through the AI SDK harness abstraction.',
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 @@ -31,6 +31,7 @@
"@ai-sdk/harness-claude-code": "workspace:*",
"@ai-sdk/harness-codex": "workspace:*",
"@ai-sdk/harness-deepagents": "workspace:*",
"@ai-sdk/harness-eve": "workspace:*",
"@ai-sdk/harness-opencode": "workspace:*",
"@ai-sdk/harness-pi": "workspace:*",
"@ai-sdk/huggingface": "workspace:*",
Expand Down
52 changes: 52 additions & 0 deletions examples/ai-functions/src/harness-agent/eve/active-tools.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import { HarnessAgent } from '@ai-sdk/harness/agent';
import { createEve } from '@ai-sdk/harness-eve';
import { createJustBashSandbox } from '@ai-sdk/sandbox-just-bash';
import { tool } from 'ai';
import { z } from 'zod';
import { printFullStream } from '../../lib/print-full-stream';
import { run } from '../../lib/run';

run(async () => {
const url = process.env.EVE_BASIC_AGENT_URL;
if (!url) {
throw new Error('Set EVE_BASIC_AGENT_URL to a remote Eve agent URL.');
}

const weather = tool({
description: 'Get the current temperature for a city.',
inputSchema: z.object({ city: z.string() }),
execute: async ({ city }: { city: string }) => {
const temps: Record<string, number> = {
Paris: 12,
Tokyo: 18,
Reykjavik: 3,
};
return { city, celsius: temps[city] ?? 20 };
},
});

const agent = new HarnessAgent({
harness: createEve({ url }),
sandbox: createJustBashSandbox(), // Ignored by eve harness.
tools: { weather },
activeTools: ['weather'],
});

let exitCode = 0;
const session = await agent.createSession();
try {
const result = await agent.stream({
session,
prompt:
'Use the `weather` tool for Paris, then read README.md and summarize both results in one sentence.',
});

await printFullStream({ result });
} catch (err) {
exitCode = 1;
console.error('[example] failed:', err);
} finally {
await session.destroy();
process.exit(exitCode);
}
});
29 changes: 29 additions & 0 deletions examples/ai-functions/src/harness-agent/eve/generate-text.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import { HarnessAgent } from '@ai-sdk/harness/agent';
import { createEve } from '@ai-sdk/harness-eve';
import { createJustBashSandbox } from '@ai-sdk/sandbox-just-bash';
import { run } from '../../lib/run';

run(async () => {
const url = process.env.EVE_BASIC_AGENT_URL;
if (!url) {
throw new Error('Set EVE_BASIC_AGENT_URL to a remote Eve agent URL.');
}

const agent = new HarnessAgent({
harness: createEve({ url }),
sandbox: createJustBashSandbox(), // Ignored by eve harness.
});

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);
} finally {
await session.destroy();
}
});
Loading
Loading