experimental-agent
v0.8.0
Published
An LLM running in a loop, with access to a sandbox, tools, and session management. Nothing more.
Readme
Agent
An LLM running in a loop, with access to a sandbox, tools, and session management. Nothing more.
pnpm i experimental-agentWhy
- AI SDK compatible — Built on
ai. UsesUIMessage,GatewayModelId, streams the same way. If you know AI SDK, you know this. - Opt-in durability — Works in-process by default. Add a
"use workflow"wrapper for full durability that survives crashes, timeouts, and deploys. - Bring your own storage — Implement a flat handler map backed by any database. Built-in
localStorage()for dev. - Managed sandbox — Auto-starts on first use, auto-snapshots when idle, auto-resumes. You don't manage the VM.
- Built-in tools — Read, Grep, List, Bash, Write, Edit, Skill, JavaScript. No setup.
Quick Start
// lib/agent.ts
import { agent } from "experimental-agent";
export const myAgent = agent("my-agent", {
model: "anthropic/claude-opus-4.6",
system: "You are a helpful coding assistant.",
skills: [
{ type: "sandbox", path: ".agent/skills/project" },
{ type: "host", path: "./skills/company" },
{
type: "git",
repo: "https://github.com/acme/agent-skills.git",
ref: "v1.2.0",
path: "skills",
},
{
type: "inline",
name: "incident-triage",
description: "Triage incidents safely",
instructions: "1. Gather context\n2. Confirm blast radius\n3. Propose mitigations",
},
],
});// app/api/chat/[chatId]/route.ts
import { myAgent } from "@/lib/agent";
import { createUIMessageStreamResponse } from "ai";
export async function POST(req: Request, { params }: { params: { chatId: string } }) {
const { chatId } = await params;
const { message } = await req.json();
const session = myAgent.session(chatId);
await session.send(message);
const stream = await session.stream();
return createUIMessageStreamResponse({ stream });
}
export async function GET(req: Request, { params }: { params: { chatId: string } }) {
const { chatId } = await params;
const session = myAgent.session(chatId);
try {
const stream = await session.stream();
return createUIMessageStreamResponse({ stream });
} catch {
return Response.json(await session.history());
}
}Adding Workflow
Everything works without workflow. To add durability:
// workflow.ts
import { myAgent } from "@/lib/agent";
import type { SessionSendArgs } from "experimental-agent";
export async function agentWorkflow(
sessionId: string,
...args: SessionSendArgs<typeof myAgent>
) {
"use workflow";
return await myAgent.session(sessionId).send(...args);
}// route.ts
import { start } from "workflow/api";
import { agentWorkflow } from "./workflow";
const result = await start(agentWorkflow, [chatId, message, opts]);
const stream = await session.stream(result);
return createUIMessageStreamResponse({ stream });Storage
// Dev — built-in filesystem storage
import { localStorage } from "experimental-agent/storage";
agent("my-agent", { storage: localStorage() })
// Prod — your own database
agent("my-agent", {
async storage(store) {
return await store.on({
"session.get": async ({ id }) => await db.sessions.findById(id),
"session.set": async ({ id, value }) => await db.sessions.upsert(id, value),
// ... all handlers
});
},
})
// To add workflow durability, just add "use step" at the top:
agent("my-agent", {
async storage(store) {
"use step";
return await store.on({ /* same handlers */ });
},
})The SDK stores Session, Message, Part, Sandbox. Everything else — users, titles, access control — belongs in your database. Session ID is your join key.
Skills
skills is the canonical skills API for both agent(...) defaults and session.update(...) overrides.
{ type: "sandbox", path: "..." }reads skills already present in sandbox{ type: "host", path: "..." }copies skills from host filesystem into sandbox materialized dirs{ type: "git", ... }clones a git repo into sandbox materialized dirs (optionally withref,path,name){ type: "inline", ... }writes an inlineSKILL.mdinto sandbox materialized dirs
const session = myAgent.session("chat-123");
await session.update({
skills: [
{
type: "git",
repo: "https://github.com/acme/agent-skills.git",
ref: "main",
path: "skills",
name: "release-playbook",
},
],
});Migration
Legacy skillsDir configuration is deprecated. Migrate to skills:
// before
agent("my-agent", {
skillsDir: [".agent/skills", ".agent/skills/shared"],
});
// after
agent("my-agent", {
skills: [
{ type: "sandbox", path: ".agent/skills" },
{ type: "sandbox", path: ".agent/skills/shared" },
],
});Documentation
Full docs at packages/agent/docs.
Development
From the repo root:
pnpm agent # tsup --watch
pnpm test # vitest run
pnpm test:watch # vitest watch
pnpm typecheck # tsc --noEmit