open-agent-sdk
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseOpen Agent SDK
Open Agent SDK
Skill by ara.so — Daily 2026 Skills collection.
Open Agent SDK () is a fully open-source, in-process AI agent framework for TypeScript/Node.js. It runs the complete Claude Code agent engine directly — no local CLI subprocess required — making it suitable for cloud servers, serverless functions, Docker containers, and CI/CD pipelines. It is API-compatible with .
@shipany/open-agent-sdk@anthropic-ai/claude-agent-sdk由ara.so开发的Skill — 2026年度Skill合集。
Open Agent SDK()是面向TypeScript/Node.js的完全开源的进程内AI Agent框架。它直接运行完整的Claude Code Agent引擎,无需本地CLI子进程,因此适用于云服务器、Serverless函数、Docker容器和CI/CD流水线。它与的API完全兼容。
@shipany/open-agent-sdk@anthropic-ai/claude-agent-sdkInstallation
安装
sh
npm install @shipany/open-agent-sdkRequires Node.js 18+.
sh
npm install @shipany/open-agent-sdk需要Node.js 18及以上版本。
Authentication & Configuration
认证与配置
Set the Anthropic API key as an environment variable:
sh
export ANTHROPIC_API_KEY=your-api-keyOr use a third-party provider (e.g. OpenRouter):
sh
export ANTHROPIC_BASE_URL=https://openrouter.ai/api
export ANTHROPIC_API_KEY=your-openrouter-key
export ANTHROPIC_MODEL=anthropic/claude-sonnet-4-6These can also be passed programmatically via or / in .
options.envapiKeybaseURLcreateAgent()将Anthropic API密钥设置为环境变量:
sh
export ANTHROPIC_API_KEY=your-api-key也可以使用第三方服务商(例如OpenRouter):
sh
export ANTHROPIC_BASE_URL=https://openrouter.ai/api
export ANTHROPIC_API_KEY=your-openrouter-key
export ANTHROPIC_MODEL=anthropic/claude-sonnet-4-6你也可以通过或者中的/参数以编程方式传入这些配置。
options.envcreateAgent()apiKeybaseURLCore API
核心API
query({ prompt, options })
— Streaming, compatible with official SDK
query({ prompt, options })query({ prompt, options })
— 流式响应,与官方SDK兼容
query({ prompt, options })Returns an . Drop-in replacement for .
AsyncGenerator<SDKMessage>@anthropic-ai/claude-agent-sdktypescript
import { query } from '@shipany/open-agent-sdk'
for await (const message of query({
prompt: 'Find and fix the bug in auth.ts',
options: {
allowedTools: ['Read', 'Edit', 'Bash'],
permissionMode: 'acceptEdits',
},
})) {
if (message.type === 'assistant' && message.message?.content) {
for (const block of message.message.content) {
if ('text' in block) process.stdout.write(block.text)
else if ('name' in block) console.log(`\n[Tool used: ${block.name}]`)
}
} else if (message.type === 'result') {
console.log(`\nDone: ${message.subtype}`)
}
}返回,可直接替换的对应方法。
AsyncGenerator<SDKMessage>@anthropic-ai/claude-agent-sdktypescript
import { query } from '@shipany/open-agent-sdk'
for await (const message of query({
prompt: 'Find and fix the bug in auth.ts',
options: {
allowedTools: ['Read', 'Edit', 'Bash'],
permissionMode: 'acceptEdits',
},
})) {
if (message.type === 'assistant' && message.message?.content) {
for (const block of message.message.content) {
if ('text' in block) process.stdout.write(block.text)
else if ('name' in block) console.log(`\n[Tool used: ${block.name}]`)
}
} else if (message.type === 'result') {
console.log(`\nDone: ${message.subtype}`)
}
}createAgent(options)
— Reusable agent with session state
createAgent(options)createAgent(options)
— 带会话状态的可复用Agent
createAgent(options)typescript
import { createAgent } from '@shipany/open-agent-sdk'
const agent = createAgent({
model: 'claude-sonnet-4-6',
systemPrompt: 'You are a senior TypeScript engineer. Be concise.',
maxTurns: 20,
})
// Blocking call
const result = await agent.prompt('Read package.json and describe the project')
console.log(result.text)
console.log(`Tokens used: ${result.usage.input_tokens + result.usage.output_tokens}`)
// Streaming call
for await (const msg of agent.query('Now add JSDoc to all exported functions')) {
if (msg.type === 'assistant' && msg.message?.content) {
for (const block of msg.message.content) {
if ('text' in block) process.stdout.write(block.text)
}
}
}
// Session management
const history = agent.getMessages() // full conversation history
agent.clear() // reset sessiontypescript
import { createAgent } from '@shipany/open-agent-sdk'
const agent = createAgent({
model: 'claude-sonnet-4-6',
systemPrompt: 'You are a senior TypeScript engineer. Be concise.',
maxTurns: 20,
})
// 阻塞调用
const result = await agent.prompt('Read package.json and describe the project')
console.log(result.text)
console.log(`Tokens used: ${result.usage.input_tokens + result.usage.output_tokens}`)
// 流式调用
for await (const msg of agent.query('Now add JSDoc to all exported functions')) {
if (msg.type === 'assistant' && msg.message?.content) {
for (const block of msg.message.content) {
if ('text' in block) process.stdout.write(block.text)
}
}
}
// 会话管理
const history = agent.getMessages() // 完整对话历史
agent.clear() // 重置会话Options Reference
选项参考
| Option | Type | Default | Description |
|---|---|---|---|
| | | Claude model ID |
| | | API key |
| | Anthropic API | Override for third-party providers |
| | | Working directory for file/shell tools |
| | — | Custom system prompt prepended to agent |
| | All built-in | Override the full tool list |
| | all | Whitelist specific tools by name |
| | | |
| | | Maximum agentic loop iterations |
| | — | Spend cap in USD |
| | — | MCP server configs (stdio/SSE/HTTP) |
| | — | Named subagent definitions |
| | — | Lifecycle hooks: |
| | — | Extended thinking config |
| | — | Environment variables passed to tools |
| | — | Resume prior session by session ID |
| | — | Custom permission callback |
| | | Emit raw streaming events |
| 选项 | 类型 | 默认值 | 描述 |
|---|---|---|---|
| | | Claude模型ID |
| | | API密钥 |
| | Anthropic官方API地址 | 可覆写为第三方服务商的API地址 |
| | | 文件/Shell工具的工作目录 |
| | — | 为Agent添加的自定义系统提示词 |
| | 所有内置工具 | 覆写完整的工具列表 |
| | 所有工具 | 按名称白名单指定可用工具 |
| | | 可选值: |
| | | Agent循环执行的最大轮次 |
| | — | 最大花费上限,单位为美元 |
| | — | MCP服务器配置(stdio/SSE/HTTP) |
| | — | 命名子Agent定义 |
| | — | 生命周期钩子: |
| | — | 扩展思考配置 |
| | — | 传递给工具的环境变量 |
| | — | 通过会话ID恢复之前的会话 |
| | — | 自定义权限回调: |
| | | 输出原始流式事件 |
Common Patterns
常用模式
Multi-turn conversation with context
带上下文的多轮对话
typescript
import { createAgent } from '@shipany/open-agent-sdk'
const agent = createAgent({ model: 'claude-sonnet-4-6' })
const r1 = await agent.prompt('Read src/index.ts and explain the architecture')
console.log(r1.text)
// Context from r1 is preserved automatically
const r2 = await agent.prompt('Refactor the error handling to use a Result type')
console.log(r2.text)typescript
import { createAgent } from '@shipany/open-agent-sdk'
const agent = createAgent({ model: 'claude-sonnet-4-6' })
const r1 = await agent.prompt('Read src/index.ts and explain the architecture')
console.log(r1.text)
// r1的上下文会自动保留
const r2 = await agent.prompt('Refactor the error handling to use a Result type')
console.log(r2.text)Restrict to read-only tools
限制为只读工具
typescript
import { query } from '@shipany/open-agent-sdk'
for await (const message of query({
prompt: 'Review this codebase for security issues',
options: {
allowedTools: ['Read', 'Glob', 'Grep'],
// No Write, Edit, or Bash — agent cannot modify files
},
})) {
if (message.type === 'result') console.log('Review complete')
}typescript
import { query } from '@shipany/open-agent-sdk'
for await (const message of query({
prompt: 'Review this codebase for security issues',
options: {
allowedTools: ['Read', 'Glob', 'Grep'],
// 没有Write、Edit或Bash权限,Agent无法修改文件
},
})) {
if (message.type === 'result') console.log('Review complete')
}Custom tools
自定义工具
typescript
import { createAgent, getAllBaseTools } from '@shipany/open-agent-sdk'
const dbQueryTool = {
name: 'QueryDatabase',
description: 'Run a read-only SQL query and return results as JSON',
inputJSONSchema: {
type: 'object',
properties: {
sql: { type: 'string', description: 'The SQL query to run' },
},
required: ['sql'],
},
get inputSchema() {
return { safeParse: (v: unknown) => ({ success: true, data: v }) }
},
async prompt() { return this.description },
async call(input: { sql: string }) {
// Replace with your actual DB client
const rows = [{ id: 1, name: 'Example' }]
return { data: JSON.stringify(rows) }
},
userFacingName: () => 'QueryDatabase',
isReadOnly: () => true,
isConcurrencySafe: () => true,
mapToolResultToToolResultBlockParam: (data: string, id: string) => ({
type: 'tool_result' as const,
tool_use_id: id,
content: data,
}),
}
const agent = createAgent({
tools: [...getAllBaseTools(), dbQueryTool],
})
const result = await agent.prompt('How many users signed up in the last 7 days?')
console.log(result.text)typescript
import { createAgent, getAllBaseTools } from '@shipany/open-agent-sdk'
const dbQueryTool = {
name: 'QueryDatabase',
description: 'Run a read-only SQL query and return results as JSON',
inputJSONSchema: {
type: 'object',
properties: {
sql: { type: 'string', description: 'The SQL query to run' },
},
required: ['sql'],
},
get inputSchema() {
return { safeParse: (v: unknown) => ({ success: true, data: v }) }
},
async prompt() { return this.description },
async call(input: { sql: string }) {
// 替换为实际的数据库客户端
const rows = [{ id: 1, name: 'Example' }]
return { data: JSON.stringify(rows) }
},
userFacingName: () => 'QueryDatabase',
isReadOnly: () => true,
isConcurrencySafe: () => true,
mapToolResultToToolResultBlockParam: (data: string, id: string) => ({
type: 'tool_result' as const,
tool_use_id: id,
content: data,
}),
}
const agent = createAgent({
tools: [...getAllBaseTools(), dbQueryTool],
})
const result = await agent.prompt('How many users signed up in the last 7 days?')
console.log(result.text)MCP server integration
MCP服务器集成
typescript
import { createAgent } from '@shipany/open-agent-sdk'
const agent = createAgent({
mcpServers: {
filesystem: {
command: 'npx',
args: ['-y', '@modelcontextprotocol/server-filesystem', '/tmp'],
},
playwright: {
command: 'npx',
args: ['@playwright/mcp@latest'],
},
},
})
const result = await agent.prompt('List all .json files in /tmp')
console.log(result.text)typescript
import { createAgent } from '@shipany/open-agent-sdk'
const agent = createAgent({
mcpServers: {
filesystem: {
command: 'npx',
args: ['-y', '@modelcontextprotocol/server-filesystem', '/tmp'],
},
playwright: {
command: 'npx',
args: ['@playwright/mcp@latest'],
},
},
})
const result = await agent.prompt('List all .json files in /tmp')
console.log(result.text)Subagents for parallel / delegated work
用于并行/委派任务的子Agent
typescript
import { query } from '@shipany/open-agent-sdk'
for await (const message of query({
prompt: 'Use the security-auditor agent to audit src/ for vulnerabilities',
options: {
allowedTools: ['Read', 'Glob', 'Grep', 'Agent'],
agents: {
'security-auditor': {
description: 'Expert security auditor for TypeScript codebases.',
prompt: 'Identify OWASP Top 10 vulnerabilities and suggest fixes.',
tools: ['Read', 'Glob', 'Grep'],
},
},
},
})) {
if (message.type === 'assistant' && message.message?.content) {
for (const block of message.message.content) {
if ('text' in block) console.log(block.text)
}
}
}typescript
import { query } from '@shipany/open-agent-sdk'
for await (const message of query({
prompt: 'Use the security-auditor agent to audit src/ for vulnerabilities',
options: {
allowedTools: ['Read', 'Glob', 'Grep', 'Agent'],
agents: {
'security-auditor': {
description: 'Expert security auditor for TypeScript codebases.',
prompt: 'Identify OWASP Top 10 vulnerabilities and suggest fixes.',
tools: ['Read', 'Glob', 'Grep'],
},
},
},
})) {
if (message.type === 'assistant' && message.message?.content) {
for (const block of message.message.content) {
if ('text' in block) console.log(block.text)
}
}
}Custom permission callback
自定义权限回调
typescript
import { createAgent } from '@shipany/open-agent-sdk'
const agent = createAgent({
canUseTool: (toolName: string, input: unknown) => {
// Prevent deletion commands
if (toolName === 'Bash') {
const cmd = (input as { command?: string }).command ?? ''
if (cmd.includes('rm ') || cmd.includes('drop table')) return false
}
return true
},
})typescript
import { createAgent } from '@shipany/open-agent-sdk'
const agent = createAgent({
canUseTool: (toolName: string, input: unknown) => {
// 阻止删除命令
if (toolName === 'Bash') {
const cmd = (input as { command?: string }).command ?? ''
if (cmd.includes('rm ') || cmd.includes('drop table')) return false
}
return true
},
})Lifecycle hooks
生命周期钩子
typescript
import { createAgent } from '@shipany/open-agent-sdk'
const agent = createAgent({
hooks: {
PreToolUse: async ({ tool, input }) => {
console.log(`About to run tool: ${tool} with input:`, input)
},
PostToolUse: async ({ tool, output }) => {
console.log(`Tool ${tool} finished`)
},
Stop: async ({ result }) => {
console.log('Agent stopped. Final result:', result)
},
},
})typescript
import { createAgent } from '@shipany/open-agent-sdk'
const agent = createAgent({
hooks: {
PreToolUse: async ({ tool, input }) => {
console.log(`About to run tool: ${tool} with input:`, input)
},
PostToolUse: async ({ tool, output }) => {
console.log(`Tool ${tool} finished`)
},
Stop: async ({ result }) => {
console.log('Agent stopped. Final result:', result)
},
},
})Resume a previous session
恢复之前的会话
typescript
import { createAgent } from '@shipany/open-agent-sdk'
// First session
const agent1 = createAgent({ model: 'claude-sonnet-4-6' })
const r1 = await agent1.prompt('Read ARCHITECTURE.md')
const sessionId = r1.sessionId // save this
// Later — resume where you left off
const agent2 = createAgent({
model: 'claude-sonnet-4-6',
resume: sessionId,
})
const r2 = await agent2.prompt('Now implement the TODO in section 3')typescript
import { createAgent } from '@shipany/open-agent-sdk'
// 第一个会话
const agent1 = createAgent({ model: 'claude-sonnet-4-6' })
const r1 = await agent1.prompt('Read ARCHITECTURE.md')
const sessionId = r1.sessionId // 保存这个ID
// 后续可以从断开的位置恢复会话
const agent2 = createAgent({
model: 'claude-sonnet-4-6',
resume: sessionId,
})
const r2 = await agent2.prompt('Now implement the TODO in section 3')
console.log(r2.text)Built-in Tools Reference
内置工具参考
| Tool | Read-only | Description |
|---|---|---|
| ✅ | Read files, images, PDFs with line numbers |
| ✅ | Find files by glob pattern |
| ✅ | Search file contents with regex (uses ripgrep) |
| ✅ | Fetch and parse web pages |
| ✅ | Web search |
| ❌ | Create or overwrite files |
| ❌ | Precise string replacement in files |
| ❌ | Execute shell commands |
| — | Spawn subagents |
| ❌ | Manage todo lists |
| ❌ | Edit Jupyter notebooks |
| — | Task management |
| — | Agent team management |
| — | Plan approval workflow |
| — | Git worktree isolation |
| ✅ | MCP resource access |
| 工具 | 只读 | 描述 |
|---|---|---|
| ✅ | 读取文件、图片、PDF,带行号 |
| ✅ | 按glob模式查找文件 |
| ✅ | 用正则搜索文件内容(基于ripgrep) |
| ✅ | 抓取并解析网页 |
| ✅ | 网页搜索 |
| ❌ | 创建或覆盖文件 |
| ❌ | 精确替换文件中的字符串 |
| ❌ | 执行Shell命令 |
| — | 生成子Agent |
| ❌ | 管理待办列表 |
| ❌ | 编辑Jupyter笔记本 |
| — | 任务管理 |
| — | Agent团队管理 |
| — | 计划审批工作流 |
| — | Git工作树隔离 |
| ✅ | MCP资源访问 |
Architecture: How It Differs from Official SDK
架构:与官方SDK的差异
Official :
@anthropic-ai/claude-agent-sdkYour code → SDK → spawn cli.js subprocess → stdin/stdout JSON → Anthropic APIOpen Agent SDK:
Your code → SDK → QueryEngine (in-process) → Anthropic API (direct HTTP)This means:
- No CLI installation required in the deployment environment
- Works in serverless (AWS Lambda, Vercel, Cloudflare Workers with Node.js compat)
- Works in Docker with just
npm install - Works in CI/CD without CLI setup steps
- Programmatic access to the full agent engine
官方:
@anthropic-ai/claude-agent-sdk你的代码 → SDK → 启动cli.js子进程 → stdin/stdout传输JSON → Anthropic APIOpen Agent SDK:
你的代码 → SDK → QueryEngine(进程内) → 直接调用Anthropic API(HTTP)这种架构的优势:
- 部署环境无需安装CLI
- 可在Serverless环境运行(AWS Lambda、Vercel、兼容Node.js的Cloudflare Workers)
- 仅需即可在Docker中运行
npm install - 无需CLI配置步骤即可在CI/CD中运行
- 可通过编程方式访问完整的Agent引擎
Troubleshooting
问题排查
Error: ANTHROPIC_API_KEY is not setapiKeycreateAgent({ apiKey: process.env.MY_KEY })Agent exceeds without completing
→ Increase or narrow the task. Check in the result.
maxTurnsmaxTurnsmessage.subtype === 'max_turns'Tool not found / not working
→ Tool names are case-sensitive: , , , , , , etc.
allowedTools'Read''Edit''Bash''Glob''Grep''WebFetch'Using with OpenRouter or other providers
→ Set to the provider's base URL and use their model string format, e.g. for OpenRouter.
ANTHROPIC_BASE_URLanthropic/claude-sonnet-4-6Agent modifies files unexpectedly
→ Use to restrict to read-only tools, or set to require approval before edits.
allowedTools: ['Read', 'Glob', 'Grep']permissionMode: 'plan'MCP server fails to start
→ Ensure the MCP server package is installed or accessible via . Check and match what the MCP package expects.
npxcommandargsTypeScript types missing
→ The package ships its own types. Ensure or in and .
"moduleResolution": "bundler""node16"tsconfig.json"esModuleInterop": true错误:ANTHROPIC_API_KEY is not setcreateAgent({ apiKey: process.env.MY_KEY })apiKeyAgent未完成任务就超出限制
→ 调高的值,或者缩小任务范围。你可以在结果中检查来判断是否是因为超出轮次限制终止。
maxTurnsmaxTurnsmessage.subtype === 'max_turns'找不到工具 / 配置不生效
→ 工具名称区分大小写:、、、、、等。
allowedTools'Read''Edit''Bash''Glob''Grep''WebFetch'配合OpenRouter或其他服务商使用
→ 将设置为服务商的基础URL,并使用他们的模型字符串格式,例如OpenRouter使用。
ANTHROPIC_BASE_URLanthropic/claude-sonnet-4-6Agent意外修改文件
→ 使用限制为只读工具,或者设置要求编辑前先获得审批。
allowedTools: ['Read', 'Glob', 'Grep']permissionMode: 'plan'MCP服务器启动失败
→ 确保MCP服务器包已安装,或者可以通过访问。检查和是否与MCP包的要求一致。
npxcommandargs缺少TypeScript类型定义
→ 包本身自带类型定义。确保中设置了或,并且开启了。
tsconfig.json"moduleResolution": "bundler""node16""esModuleInterop": trueQuick Reference
快速参考
typescript
// Minimal one-shot agent
import { createAgent } from '@shipany/open-agent-sdk'
const agent = createAgent({ model: 'claude-sonnet-4-6' })
const { text } = await agent.prompt('Summarize README.md in 3 bullet points')
console.log(text)typescript
// 极简一次性Agent示例
import { createAgent } from '@shipany/open-agent-sdk'
const agent = createAgent({ model: 'claude-sonnet-4-6' })
const { text } = await agent.prompt('Summarize README.md in 3 bullet points')
console.log(text)