本页还没有译文
本页 54 段还没译成简体中文,下面显示的是英文原文。Pi
还没翻译译自英文(ai-sdk.dev)本页 54 段都还没译
The Pi harness adapter connects HarnessAgent to
@earendil-works/pi-coding-agent. Pi runs in the host Node.js process and uses
the sandbox as a remote filesystem and shell. It does not install a bridge
inside the sandbox.
Note
Harness packages are experimental. Expect breaking changes between releases as this early API gets further refined.
Setup
pnpm add @ai-sdk/harness @ai-sdk/harness-pi @ai-sdk/sandbox-vercelnpm install @ai-sdk/harness @ai-sdk/harness-pi @ai-sdk/sandbox-vercelyarn add @ai-sdk/harness @ai-sdk/harness-pi @ai-sdk/sandbox-vercelbun add @ai-sdk/harness @ai-sdk/harness-pi @ai-sdk/sandbox-vercelImport
import { pi, createPi } from '@ai-sdk/harness-pi';pi is equivalent to createPi() with its default configuration.
Basic Usage
import { HarnessAgent } from '@ai-sdk/harness/agent';
import { pi } from '@ai-sdk/harness-pi';
import { createVercelNetworkSandboxSession } from '@ai-sdk/sandbox-vercel';
const agent = new HarnessAgent({
harness: pi,
model: 'anthropic/claude-sonnet-4.6',
});
const sandboxSession = await createVercelNetworkSandboxSession({
runtime: 'node24',
template: await agent.getSandboxTemplate(),
});
const session = await agent.createSession({ sandboxSession });
let exitCode = 0;
try {
const result = await agent.stream({
session,
prompt: 'Check the test failures and fix the production code.',
});
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();
await sandboxSession.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
for Pi.
Adapter Settings
Use createPi() to configure the runtime:
const harness = createPi({
thinkingLevel: 'medium',
});Settings:
auth: authentication mode (auto,openai,anthropic,custom, orai-gateway) or an isolated authentication environment.cacheRetention: default prompt cache retention for model requests (none,short, orlong). For Anthropic models,longuses the 1-hour cache instead of the 5-minute default.credentials: application-owned Pi credential storage. This replaces the file-backedauth.jsonstore and supports persistent database-backed credentials.extensionFactories: trusted inline Pi extension factories that run in the host Node.js process.fileToolPathPolicy: extra sandbox roots Pi's native file tools can read or write, and roots they must refuse. See File Tool Paths.mcpServers: MCP servers keyed by server name, served by Pi's native MCP support. Each entry is Pi's MCP server configuration, either stdio (command,args,env,cwd) or streamable HTTP (url,headers). Tools are namedmcp__<server>__<tool>, with-in either name replaced by_.exposuredefaults todirect, which declares a server's tools to the model; withdeferred, the model finds them through Pi'stool_searchtool first. Pi'scodemodeexposure is not supported. An entry that uses it, or that Pi rejects, fails session start. Pi truncates text results over 20 KB and writes the full text to the host temp directory. The harness has no sign-in flow, so an HTTP server that requires authentication must carry anAuthorizationheader orauth.provider.mcpSettings: deprecated. Pi's native MCP has no tool prefix or output guard settings, so atoolPrefixother thanmcp, oroutputGuard: false, fails session start.providers: explicit Pi provider configurations for custom models.reattachInProcess: whether a suspended turn can reuse its live Pi session in the current process. Defaults totrue.thinkingLevel: Pi thinking level (off,minimal,low,medium,high,xhigh, ormax).
File Tool Paths
By default, Pi's native file tools (read, write, edit, ls, find, and
grep) are limited to the session workspace, and the read-only tools can also
read the harness skill directory. Use fileToolPathPolicy to change what they
can reach:
const harness = createPi({
fileToolPathPolicy: {
readableRoots: ['/home/vercel-sandbox'],
writableRoots: ['/tmp', '/mnt/artifacts'],
deniedRoots: ['/home/vercel-sandbox/.credentials'],
},
});readableRoots: absolute sandbox directories thatread,ls,find, andgrepcan reach in addition to the defaults. They do not become writable.writableRoots: absolute sandbox directories thatwriteandeditcan reach in addition to the workspace. Writable roots are also readable.deniedRoots: absolute sandbox directories that every native file tool refuses, even inside the workspace or a readable root. Both requested paths and denied roots are resolved in the sandbox, so symlinks pointing to or from a denied root are refused. Configured roots are resolved again for each file operation; canonical denied roots captured at session startup remain denied.findandgrepprune exact denied paths without following directory symlinks, andlshides directly denied entries. Other directories with the same name remain accessible.
Every configured root must be an absolute sandbox path. Denied roots take
precedence over the workspace, harness skill directory, and allowed roots.
Writes outside the workspace do not emit workspace file-change events.
When the setting is present, a leading ~ in a tool path expands to the
sandbox home directory.
The policy applies to Pi's native file tools only. The bash tool is not
restricted by it, so do not treat deniedRoots as a security boundary for
commands the agent runs.
Inline Extensions
Use extensionFactories to load trusted inline Pi extensions for each harness
session:
const harness = createPi({
extensionFactories: [
pi => {
pi.on('agent_start', () => {
console.log('Pi agent started');
});
},
],
});Each factory also receives the harness session it runs in as a second argument:
sandboxSession: the session's sandbox, restricted to the operations harness tools may use.sessionWorkDir: the sandbox directory the session works in.instructions(): the instructions of the current turn. Instructions arrive with each turn, so call it while a turn runs, not when the factory runs.
const harness = createPi({
extensionFactories: [
(pi, session) => {
pi.on('agent_start', async () => {
const { stdout } = await session.sandboxSession.run({
command: `git -C ${session.sessionWorkDir} status --short`,
});
console.log(session.instructions(), stdout);
});
},
],
});Factories that take only the Pi API keep working unchanged.
Routine resource refreshes between turns reuse the active extension runtime and do not reinitialize factories. If the underlying Pi session is rebuilt, the factories initialize again for the new Pi runtime.
Extension factories execute in the host Node.js process with access to the host environment, so only pass factories you trust. This setting enables only the factories you explicitly provide. Filesystem extension discovery remains disabled, including user, project, and settings-based extensions. Themes and prompt templates also remain disabled.
Session Reattachment
Pi keeps its live session journal in a host temporary directory. On detach,
stop, or suspension, the adapter copies the journal to
$HOME/.ai-sdk-harness/.agent-runs/<encoded-sessionId>/pi/<session-file>.jsonl.
Here, $HOME belongs to the sandbox; the saved journal is outside
sessionWorkDir. A future process restores that journal after the caller
reattaches the sandbox and supplies the saved lifecycle state.
By default, Pi keeps a suspended turn alive for an efficient continuation in the same process when the incoming request has compatible settings and runtime resources. Changed request-scoped settings or sandbox handles cause a cold restore from persisted lifecycle state.
For stateless or multi-replica applications, disable in-process reattachment so every continuation restores the persisted lifecycle state with the current request's settings:
const harness = createPi({
reattachInProcess: false,
});An incoming completed resume-session state always takes precedence over an
older live suspended turn in the process.
Authentication
The auth setting selects which credentials Pi reads from the host environment:
auto(default): use AI Gateway credentials when available, then fall back to all provider credentials found in the environment.openai: useOPENAI_API_KEYand the optionalOPENAI_BASE_URL.anthropic: useANTHROPIC_API_KEYand the optionalANTHROPIC_AUTH_TOKENandANTHROPIC_BASE_URL.custom: register all providers configured through environment variables.ai-gateway: useAI_GATEWAY_API_KEYorVERCEL_OIDC_TOKENand the optionalAI_GATEWAY_BASE_URL.
If no applicable credential environment variable is set, the adapter attempts to resolve a native subscription from the host system unless AI Gateway authentication is selected.
const harness = createPi({ auth: 'ai-gateway' });Pass an authentication environment to use programmatically resolved
credentials without reading process.env:
const harness = createPi({
auth: {
MISTRAL_API_KEY: await resolveMistralToken(),
MISTRAL_BASE_URL: 'https://api.mistral.ai',
},
});The supplied record replaces the host environment for authentication discovery. Pi parses provider API keys and base URLs from that record.
For credentials managed outside environment variables or files, inject an application-owned credential store. Pi performs credential reads, refreshes, and updates through this interface:
import { createPi, type PiCredentialStore } from '@ai-sdk/harness-pi';
declare const credentials: PiCredentialStore;
const harness = createPi({
credentials,
reattachInProcess: false,
});credentials replaces Pi's auth.json storage. In request-scoped or
multi-replica deployments, pair it with reattachInProcess: false so each
continuation constructs a model runtime from the current request.
With custom, standard providers use environment variables such as
OPENAI_API_KEY, OPENAI_BASE_URL, ANTHROPIC_API_KEY, and
ANTHROPIC_BASE_URL. Other providers use a <PREFIX>_API_KEY and matching
<PREFIX>_BASE_URL pair.
Authentication variables do not identify a provider's API protocol or models. Register that metadata explicitly when using a custom model:
const harness = createPi({
auth: {
MYPROVIDER_API_KEY: await resolveMyProviderToken(),
MYPROVIDER_BASE_URL: 'https://api.example.com/v1',
},
providers: {
myprovider: {
api: 'openai-completions',
models: [
{
id: 'my-custom-model',
name: 'My Custom Model',
reasoning: false,
input: ['text'],
cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
contextWindow: 128_000,
maxTokens: 16_384,
},
],
},
},
});Sandbox
Pi needs a sandbox session but does not require exposed ports. You can create a Vercel network session or a local just-bash session:
const sandboxSession = await createVercelNetworkSandboxSession({
runtime: 'node24',
template: await agent.getSandboxTemplate(),
});Built-in Tools
The adapter exposes these common Pi built-ins through agent.tools:
readwriteeditbashgrepglobls
Additional Pi built-ins may also appear in agent.tools when they do not fit a
common tool shape.
Pi supports built-in tool approval requests when permissionMode is
allow-reads or allow-edits.
Known Limitations
Pi does not support structured output. Supplying output to HarnessAgent
causes the turn to throw HarnessCapabilityUnsupportedError.
Pi does not support user messages with text parts after image parts; all text must appear before the first image.