Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
48 commits
Select commit Hold shift + click to select a range
ac9d4d5
feat(harness-deepagents): add DeepAgents HarnessV1 adapter
mlekhi Jun 18, 2026
55ff849
test(harness-deepagents): cover factory, auth, and bootstrap
mlekhi Jun 18, 2026
fb72884
feat(harness-deepagents): drive JS deepagents via a Node bridge
mlekhi Jun 18, 2026
4a51784
adding changelog
mlekhi Jun 18, 2026
c7ba882
feat(harness-deepagents): align with maintainer conventions + add exa…
mlekhi Jun 18, 2026
585d0bb
fix(harness-deepagents): validate against live sandbox
mlekhi Jun 19, 2026
f2ab7a6
cleanup
mlekhi Jun 19, 2026
efde658
feat(harness-deepagents): add session lifecycle + e2e-next example
mlekhi Jun 19, 2026
f88416c
feat(harness-deepagents): provider-aware auth (anthropic + openai)
mlekhi Jun 19, 2026
46d50d2
supporting recursive JSON-schema→zod for custom tools
mlekhi Jun 19, 2026
f93b4f9
Merge branch 'main' into harness-deepagents
mlekhi Jun 19, 2026
cad12fa
bumping ws version
mlekhi Jun 22, 2026
b3121f4
adding full tool list
mlekhi Jun 22, 2026
aaab5c5
adding full test coverage for e2e-tui
mlekhi Jun 22, 2026
7d63a1f
adding examples for manual test coverage
mlekhi Jun 22, 2026
664ce01
adding test coverage for e2e-next
mlekhi Jun 22, 2026
82d6d4b
adding attach flag
mlekhi Jun 22, 2026
6f8d41a
adding endReasoningBlock()
mlekhi Jun 22, 2026
eab34b3
adding built in tool approvals
mlekhi Jun 23, 2026
4740f6c
fixing CI checks
mlekhi Jun 23, 2026
7262e2d
attempt to fix konsistent
mlekhi Jun 23, 2026
335517a
count model-call usage once in totalUsage
mlekhi Jun 23, 2026
7a46a5b
Merge branch 'main' into harness-deepagents
felixarntz Jun 23, 2026
c2655c2
remove unnecessary konsistent kebabToCamelMap entry
felixarntz Jun 23, 2026
b70ffe9
Merge branch 'main' into harness-deepagents
felixarntz Jun 23, 2026
380d096
use Deep Agents as user-facing name per official naming
felixarntz Jun 23, 2026
60631ce
Anthropic-only model routing
mlekhi Jun 23, 2026
131031e
correct step boundaries and suppress subagent leakage
mlekhi Jun 23, 2026
4f1e3fb
Merge branch 'harness-deepagents' of github.com:vercel/ai into harnes…
felixarntz Jun 23, 2026
dd75fbd
write skills to \$HOME and discover workdir skills
mlekhi Jun 23, 2026
68a1702
feat(harness-deepagents): add workflow-harness e2e and suspend-turn e…
mlekhi Jun 23, 2026
ecd1e52
Merge branch 'main' into harness-deepagents
felixarntz Jun 23, 2026
f309bb7
Merge branch 'main' into harness-deepagents
felixarntz Jun 23, 2026
c8346f7
Merge branch 'main' into harness-deepagents
felixarntz Jun 24, 2026
3374ba8
update docs
felixarntz Jun 24, 2026
3e09567
replace user-facing name DeepAgents with Deep Agents per their brand
felixarntz Jun 24, 2026
fa57170
setting optional recursion limit
mlekhi Jun 24, 2026
3a508fa
install verified ripgrep in the sandbox
mlekhi Jun 24, 2026
b1b8700
Merge branch 'main' into harness-deepagents
felixarntz Jun 25, 2026
3e001e0
update deepagents examples following a83a367fc399ad3a056510f963ca1e31…
felixarntz Jun 25, 2026
6717f45
ensure sandbox PATH reaches deepagents backend
felixarntz Jun 25, 2026
f9576d0
updating docs for accuracy
mlekhi Jun 25, 2026
eddb525
added logic to gracefully handle 'suspended' closure
mlekhi Jun 25, 2026
e7bc7c5
adding test for onclose handler
mlekhi Jun 25, 2026
813cb1f
remove beta tags from docs now that AI SDK v7 is stable
felixarntz Jun 25, 2026
92d4d71
Merge branch 'main' into harness-deepagents
felixarntz Jun 25, 2026
5289b70
remove native tool names from docs
felixarntz Jun 25, 2026
65e308f
changeset
felixarntz Jun 25, 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/deepagents-harness.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@ai-sdk/harness-deepagents': major
---

feat(harness-deepagents): add Deep Agents harness adapter
1 change: 1 addition & 0 deletions .github/konsistent.json
Original file line number Diff line number Diff line change
Expand Up @@ -342,6 +342,7 @@
"kebabToPascalMap": {
"assemblyai": "AssemblyAI",
"bytedance": "ByteDance",
"deepagents": "DeepAgents",
"deepinfra": "DeepInfra",
"deepseek": "DeepSeek",
"elevenlabs": "ElevenLabs",
Expand Down
3 changes: 2 additions & 1 deletion content/docs/03-ai-sdk-harnesses/05-harness-adapters.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,13 @@ 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`)
- [OpenCode](/providers/ai-sdk-harnesses/opencode) (`@ai-sdk/harness-opencode`)
- [Pi](/providers/ai-sdk-harnesses/pi) (`@ai-sdk/harness-pi`)

### Coming Soon

- Amp (`@ai-sdk/harness-amp`)
- DeepAgents (`@ai-sdk/harness-deepagents`)
- Goose (`@ai-sdk/harness-goose`)
- Mastra (`@ai-sdk/harness-mastra`)

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

# Deep Agents Harness

The Deep Agents harness adapter connects `HarnessAgent` to
[Deep Agents](https://github.com/langchain-ai/deepagentsjs), a LangGraph-based agent
runtime. The adapter runs a Node bridge inside the sandbox that drives the
`deepagents` package and streams its `streamEvents` output 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 @ai-sdk/harness-deepagents @ai-sdk/sandbox-vercel"
dark
/>
</Tab>
<Tab>
<Snippet
text="npm install @ai-sdk/harness @ai-sdk/harness-deepagents @ai-sdk/sandbox-vercel"
dark
/>
</Tab>
<Tab>
<Snippet
text="yarn add @ai-sdk/harness @ai-sdk/harness-deepagents @ai-sdk/sandbox-vercel"
dark
/>
</Tab>
<Tab>
<Snippet
text="bun add @ai-sdk/harness @ai-sdk/harness-deepagents @ai-sdk/sandbox-vercel"
dark
/>
</Tab>
</Tabs>

The adapter bootstraps the bridge's Node dependencies (the `deepagents` package
and LangChain) inside the sandbox via `pnpm` when the first session starts.

## Import

```ts
import { deepAgents, createDeepAgents } from '@ai-sdk/harness-deepagents';
```

`deepAgents` is equivalent to `createDeepAgents()` with its default
configuration.

## Basic Usage

```ts
import { HarnessAgent } from '@ai-sdk/harness/agent';
import { deepAgents } from '@ai-sdk/harness-deepagents';
import { createVercelSandbox } from '@ai-sdk/sandbox-vercel';

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

const session = await agent.createSession();

let exitCode = 0;
try {
const result = await agent.stream({
session,
prompt: 'Analyze this codebase and suggest improvements.',
});

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 the model provider.

## Adapter Settings

Use `createDeepAgents()` to configure the runtime:

```ts
const harness = createDeepAgents({
model: 'claude-sonnet-4',
});
```

Settings:

- `auth`: Anthropic or AI Gateway authentication settings.
- `model`: model id passed to the Deep Agents (LangChain) runtime. Through AI
Gateway, use the `creator/model` slug (e.g. `anthropic/claude-sonnet-4-6`,
`google/gemini-2.5-flash`, `openai/gpt-4.1-mini`).
- `port`: bridge port override.
- `startupTimeoutMs`: maximum time to wait for the bridge to start.

## Authentication

Deep Agents always drives the Anthropic client. Non-Anthropic models reach it
through AI Gateway's Anthropic-compatible endpoint, which translates to any
model (Gemini, OpenAI, etc.), tool calls included. Authentication is resolved
from the host environment and forwarded to the sandbox bridge: explicit
Anthropic auth first, then AI Gateway credentials, then ambient Anthropic
credentials.

Supported environment variables:

- `AI_GATEWAY_API_KEY`
- `VERCEL_OIDC_TOKEN`
- `AI_GATEWAY_BASE_URL`
- `ANTHROPIC_API_KEY`
- `ANTHROPIC_AUTH_TOKEN`
- `ANTHROPIC_BASE_URL`

You can also pass explicit auth settings (`anthropic` or `gateway`). To run a
non-Anthropic model, route it through AI Gateway:

```ts
const harness = createDeepAgents({
model: 'google/gemini-2.5-flash',
auth: {
gateway: {
apiKey: process.env.AI_GATEWAY_API_KEY,
},
},
});
```

## Sandbox

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

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

## Skills

Skills passed to the session are materialized as native Deep Agents skill folders
(`<name>/SKILL.md` plus any attached files) under `$HOME/.agents/skills/` in the
sandbox (outside the work dir, so they can't clash with cloned code), and loaded
via Deep Agents' `skills` option — so the agent loads them on demand and skill
file references resolve. Skills already present under `<workDir>/.agents/skills/`
(e.g. in a cloned repo) are also discovered.

## Built-in Tools

The adapter exposes these Deep Agents built-ins through `agent.tools`:

- `read`
- `write`
- `edit`
- `bash`
- `grep`
- `glob`
- `ls`
- `task`
- `write_todos`

## Known Limitations

- **Resuming a stopped session's conversation** is not supported — after
`session.stop()`, Deep Agents' in-memory conversation state (LangGraph
`MemorySaver`) is gone; only the sandbox workspace persists via its snapshot.
Use `session.detach()` for cross-process handoff or `session.suspendTurn()` for
turn continuation while keeping the live bridge running.
- **Manual compaction** is 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)
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-deepagents": "workspace:*",
"@ai-sdk/harness-opencode": "workspace:*",
"@ai-sdk/harness-pi": "workspace:*",
"@ai-sdk/huggingface": "workspace:*",
Expand Down
55 changes: 55 additions & 0 deletions examples/ai-functions/src/harness-agent/deepagents/attach.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import {
HarnessAgent,
type HarnessAgentResumeSessionState,
} from '@ai-sdk/harness/agent';
import { deepAgents } from '@ai-sdk/harness-deepagents';
import { createVercelSandbox } from '@ai-sdk/sandbox-vercel';
import { printFullStream } from '../../lib/print-full-stream';
import { run } from '../../lib/run';

// Cross-process ATTACH: detach parks the live bridge + sandbox and returns
// coordinates; a fresh HarnessAgent reattaches and continues mid-conversation
// (the in-memory conversation survives because the bridge stays alive).
run(async () => {
const sandbox = createVercelSandbox({
runtime: 'node24',
ports: [4000],
timeout: 10 * 60 * 1000,
});

let sessionId: string;
let resumeState: HarnessAgentResumeSessionState;
{
const agent = new HarnessAgent({ harness: deepAgents, sandbox });
const session = await agent.createSession();
sessionId = session.sessionId;
console.log('--- turn 1 ---');
const result = await agent.stream({
session,
prompt: 'My name is Ada. Remember it.',
});
await printFullStream({ result });
resumeState = await session.detach();
console.log('[handle] live coords:', JSON.stringify(resumeState));
}

{
const agent = new HarnessAgent({ harness: deepAgents, sandbox });
const session = await agent.createSession({
sessionId,
resumeFrom: resumeState,
});
console.log('--- turn 2 ---');
if (!session.isResume) {
throw new Error('expected resumed session');
}
const result = await agent.stream({
session,
prompt: 'What is my name? Answer in one word.',
});
await printFullStream({ result });
await session.destroy();
}

process.exit(0);
});
30 changes: 30 additions & 0 deletions examples/ai-functions/src/harness-agent/deepagents/bash-shell.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import { HarnessAgent } from '@ai-sdk/harness/agent';
import { deepAgents } from '@ai-sdk/harness-deepagents';
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,
});
const agent = new HarnessAgent({ harness: deepAgents, sandbox });

let exitCode = 0;
const session = await agent.createSession();
try {
const result = await agent.stream({
session,
prompt: 'Run `uname -a` and tell me what kernel this sandbox is running.',
});
await printFullStream({ result });
} catch (err) {
exitCode = 1;
console.error('[example] failed:', err);
} finally {
await session.destroy();
process.exit(exitCode);
}
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import { HarnessAgent } from '@ai-sdk/harness/agent';
import { deepAgents } from '@ai-sdk/harness-deepagents';
import { printFullStream } from '../../lib/print-full-stream';
import { run } from '../../lib/run';
import {
createToolApprovalResponseMessages,
printFullStreamAndCaptureToolApproval,
} from '../../lib/harness-tool-approval';
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: deepAgents,
sandbox,
permissionMode: 'allow-edits',
});

let exitCode = 0;
const session = await agent.createSession();
try {
const first = await agent.stream({
session,
prompt: 'Run `pwd` with the bash tool and tell me the working directory.',
});
const approval = await printFullStreamAndCaptureToolApproval({
result: first,
});
if (approval == null) {
throw new Error('Expected a built-in bash tool approval request.');
}

const second = await agent.stream({
session,
messages: createToolApprovalResponseMessages({
approval,
approved: true,
}),
});
await printFullStream({ result: second });
} catch (err) {
exitCode = 1;
console.error('[example] failed:', err);
} finally {
await session.destroy();
process.exit(exitCode);
}
});
Loading
Loading