open-agent-sdk-typescript
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseOpen Agent SDK (TypeScript)
Open Agent SDK(TypeScript)
Skill by ara.so — AI Agent Skills collection.
Open Agent SDK is a TypeScript library that runs full AI agent loops in-process without CLI dependencies or subprocesses. It supports both Anthropic and OpenAI-compatible APIs, provides 35+ built-in tools, MCP server integration, custom tool creation, skills system, subagents, and lifecycle hooks. Deploy anywhere: cloud, serverless, Docker, or CI/CD.
由ara.so提供的Skill —— AI Agent技能合集。
Open Agent SDK是一款TypeScript库,无需CLI依赖或子进程即可在进程内运行完整的AI Agent循环。它支持Anthropic和兼容OpenAI的API,提供35+内置工具、MCP服务器集成、自定义工具创建、技能系统、子Agent以及生命周期钩子。可部署在任意环境:云、无服务器、Docker或CI/CD中。
Installation
安装
bash
npm install @codeany/open-agent-sdkSet your API key as an environment variable:
bash
export CODEANY_API_KEY=your-api-key-hereFor OpenAI-compatible models:
bash
export CODEANY_API_TYPE=openai-completions
export CODEANY_API_KEY=sk-your-key
export CODEANY_BASE_URL=https://api.openai.com/v1
export CODEANY_MODEL=gpt-4oFor third-party Anthropic-compatible providers:
bash
export CODEANY_BASE_URL=https://openrouter.ai/api
export CODEANY_API_KEY=sk-or-your-key
export CODEANY_MODEL=anthropic/claude-sonnet-4bash
npm install @codeany/open-agent-sdk将你的API密钥设置为环境变量:
bash
export CODEANY_API_KEY=your-api-key-here对于兼容OpenAI的模型:
bash
export CODEANY_API_TYPE=openai-completions
export CODEANY_API_KEY=sk-your-key
export CODEANY_BASE_URL=https://api.openai.com/v1
export CODEANY_MODEL=gpt-4o对于第三方兼容Anthropic的提供商:
bash
export CODEANY_BASE_URL=https://openrouter.ai/api
export CODEANY_API_KEY=sk-or-your-key
export CODEANY_MODEL=anthropic/claude-sonnet-4Core Concepts
核心概念
API Types
API类型
The SDK supports two API types:
- : Anthropic Claude models (default)
anthropic-messages - : OpenAI, DeepSeek, Qwen, Mistral, or any OpenAI-compatible API
openai-completions
API type is auto-detected from model name. Models containing , , , , , or automatically use .
gpt-o1o3deepseekqwenmistralopenai-completionsSDK支持两种API类型:
- :Anthropic Claude模型(默认)
anthropic-messages - :OpenAI、DeepSeek、Qwen、Mistral或任何兼容OpenAI的API
openai-completions
API类型会根据模型名称自动检测。包含、、、、或的模型会自动使用。
gpt-o1o3deepseekqwenmistralopenai-completionsAgent vs Query
Agent与Query
- : One-shot streaming query, no session persistence
query() - : Reusable agent with multi-turn conversation history
createAgent()
- :单次流式查询,无会话持久化
query() - :可复用的Agent,支持多轮对话历史
createAgent()
Quick Start Examples
快速开始示例
One-Shot Streaming Query
单次流式查询
typescript
import { query } from "@codeany/open-agent-sdk";
for await (const message of query({
prompt: "Read package.json and tell me the project name.",
options: {
allowedTools: ["Read", "Glob"],
permissionMode: "bypassPermissions",
},
})) {
if (message.type === "assistant") {
for (const block of message.message.content) {
if ("text" in block) {
console.log(block.text);
}
}
}
if (message.type === "result") {
console.log(`Cost: $${message.total_cost_usd?.toFixed(4)}`);
console.log(`Turns: ${message.num_turns}`);
}
}typescript
import { query } from "@codeany/open-agent-sdk";
for await (const message of query({
prompt: "Read package.json and tell me the project name.",
options: {
allowedTools: ["Read", "Glob"],
permissionMode: "bypassPermissions",
},
})) {
if (message.type === "assistant") {
for (const block of message.message.content) {
if ("text" in block) {
console.log(block.text);
}
}
}
if (message.type === "result") {
console.log(`Cost: $${message.total_cost_usd?.toFixed(4)}`);
console.log(`Turns: ${message.num_turns}`);
}
}Simple Blocking Prompt
简单阻塞式提示词
typescript
import { createAgent } from "@codeany/open-agent-sdk";
const agent = createAgent({ model: "claude-sonnet-4-6" });
const result = await agent.prompt("What files are in this project?");
console.log(result.text);
console.log(`Turns: ${result.num_turns}`);
console.log(`Tokens: ${result.usage.input_tokens + result.usage.output_tokens}`);typescript
import { createAgent } from "@codeany/open-agent-sdk";
const agent = createAgent({ model: "claude-sonnet-4-6" });
const result = await agent.prompt("What files are in this project?");
console.log(result.text);
console.log(`Turns: ${result.num_turns}`);
console.log(`Tokens: ${result.usage.input_tokens + result.usage.output_tokens}`);OpenAI / GPT Models
OpenAI / GPT模型
typescript
import { createAgent } from "@codeany/open-agent-sdk";
const agent = createAgent({
apiType: "openai-completions",
model: "gpt-4o",
apiKey: process.env.OPENAI_API_KEY,
baseURL: "https://api.openai.com/v1",
});
const result = await agent.prompt("Analyze the code structure of this project");
console.log(result.text);typescript
import { createAgent } from "@codeany/open-agent-sdk";
const agent = createAgent({
apiType: "openai-completions",
model: "gpt-4o",
apiKey: process.env.OPENAI_API_KEY,
baseURL: "https://api.openai.com/v1",
});
const result = await agent.prompt("Analyze the code structure of this project");
console.log(result.text);Multi-Turn Conversation
多轮对话
typescript
import { createAgent } from "@codeany/open-agent-sdk";
const agent = createAgent({ maxTurns: 5 });
const r1 = await agent.prompt(
'Create a file /tmp/hello.txt with "Hello World"'
);
console.log("Response 1:", r1.text);
const r2 = await agent.prompt("Read back the file you just created");
console.log("Response 2:", r2.text);
const r3 = await agent.prompt("Delete the file");
console.log("Response 3:", r3.text);
console.log(`Total messages in session: ${agent.getMessages().length}`);
// Clean up
await agent.close();typescript
import { createAgent } from "@codeany/open-agent-sdk";
const agent = createAgent({ maxTurns: 5 });
const r1 = await agent.prompt(
'Create a file /tmp/hello.txt with "Hello World"'
);
console.log("Response 1:", r1.text);
const r2 = await agent.prompt("Read back the file you just created");
console.log("Response 2:", r2.text);
const r3 = await agent.prompt("Delete the file");
console.log("Response 3:", r3.text);
console.log(`Total messages in session: ${agent.getMessages().length}`);
// Clean up
await agent.close();Custom Tools
自定义工具
Using Zod Schema (Recommended)
使用Zod Schema(推荐)
typescript
import { z } from "zod";
import { query, tool, createSdkMcpServer } from "@codeany/open-agent-sdk";
const getWeather = tool(
"get_weather",
"Get the current weather for a city",
{
city: z.string().describe("City name"),
unit: z.enum(["celsius", "fahrenheit"]).optional().describe("Temperature unit"),
},
async ({ city, unit = "celsius" }) => {
// Simulate API call
const temp = unit === "celsius" ? 22 : 72;
return {
content: [
{
type: "text",
text: `Weather in ${city}: ${temp}°${unit === "celsius" ? "C" : "F"}, sunny`,
},
],
};
}
);
const calculator = tool(
"calculate",
"Perform mathematical calculations",
{
expression: z.string().describe("Mathematical expression to evaluate"),
},
async ({ expression }) => {
try {
const result = Function(`'use strict'; return (${expression})`)();
return {
content: [{ type: "text", text: `${expression} = ${result}` }],
};
} catch (error) {
return {
content: [{ type: "text", text: `Error: ${error.message}` }],
isError: true,
};
}
}
);
const server = createSdkMcpServer({
name: "custom-tools",
tools: [getWeather, calculator],
});
for await (const msg of query({
prompt: "What's the weather in Tokyo? Also calculate 2**16.",
options: { mcpServers: { "custom-tools": server } },
})) {
if (msg.type === "assistant") {
for (const block of msg.message.content) {
if ("text" in block) console.log(block.text);
}
}
}typescript
import { z } from "zod";
import { query, tool, createSdkMcpServer } from "@codeany/open-agent-sdk";
const getWeather = tool(
"get_weather",
"Get the current weather for a city",
{
city: z.string().describe("City name"),
unit: z.enum(["celsius", "fahrenheit"]).optional().describe("Temperature unit"),
},
async ({ city, unit = "celsius" }) => {
// Simulate API call
const temp = unit === "celsius" ? 22 : 72;
return {
content: [
{
type: "text",
text: `Weather in ${city}: ${temp}°${unit === "celsius" ? "C" : "F"}, sunny`,
},
],
};
}
);
const calculator = tool(
"calculate",
"Perform mathematical calculations",
{
expression: z.string().describe("Mathematical expression to evaluate"),
},
async ({ expression }) => {
try {
const result = Function(`'use strict'; return (${expression})`)();
return {
content: [{ type: "text", text: `${expression} = ${result}` }],
};
} catch (error) {
return {
content: [{ type: "text", text: `Error: ${error.message}` }],
isError: true,
};
}
}
);
const server = createSdkMcpServer({
name: "custom-tools",
tools: [getWeather, calculator],
});
for await (const msg of query({
prompt: "What's the weather in Tokyo? Also calculate 2**16.",
options: { mcpServers: { "custom-tools": server } },
})) {
if (msg.type === "assistant") {
for (const block of msg.message.content) {
if ("text" in block) console.log(block.text);
}
}
}Low-Level Tool Definition
底层工具定义
typescript
import { createAgent, getAllBaseTools, defineTool } from "@codeany/open-agent-sdk";
const databaseQuery = defineTool({
name: "DatabaseQuery",
description: "Execute SQL queries against the database",
inputSchema: {
type: "object",
properties: {
query: {
type: "string",
description: "SQL query to execute",
},
readonly: {
type: "boolean",
description: "Whether this is a read-only query",
},
},
required: ["query"],
},
isReadOnly: false,
async call(input) {
// Validate read-only
if (!input.readonly && /^\s*(SELECT|SHOW|DESCRIBE)/i.test(input.query)) {
return "Error: Use readonly=true for SELECT queries";
}
// Execute query (simulated)
return JSON.stringify({
rows: [{ id: 1, name: "Example" }],
rowCount: 1,
});
},
});
const agent = createAgent({
tools: [...getAllBaseTools(), databaseQuery],
});
const result = await agent.prompt(
"Query the users table and show me all records"
);
console.log(result.text);typescript
import { createAgent, getAllBaseTools, defineTool } from "@codeany/open-agent-sdk";
const databaseQuery = defineTool({
name: "DatabaseQuery",
description: "Execute SQL queries against the database",
inputSchema: {
type: "object",
properties: {
query: {
type: "string",
description: "SQL query to execute",
},
readonly: {
type: "boolean",
description: "Whether this is a read-only query",
},
},
required: ["query"],
},
isReadOnly: false,
async call(input) {
// Validate read-only
if (!input.readonly && /^\s*(SELECT|SHOW|DESCRIBE)/i.test(input.query)) {
return "Error: Use readonly=true for SELECT queries";
}
// Execute query (simulated)
return JSON.stringify({
rows: [{ id: 1, name: "Example" }],
rowCount: 1,
});
},
});
const agent = createAgent({
tools: [...getAllBaseTools(), databaseQuery],
});
const result = await agent.prompt(
"Query the users table and show me all records"
);
console.log(result.text);Built-in Tools
内置工具
The SDK includes 35+ built-in tools. Common ones include:
- File operations: ,
Read,Write,Edit,Delete,MoveRename - Search: ,
Glob,GrepSearch - Git: ,
GitStatus,GitDiff,GitLog,GitCommitGitCheckout - Analysis: ,
Lint,Symbols,CodeGraphDependencies - Shell: ,
BashBashSession - Utility: ,
Ask,Attempt,Skill(subagents)Agent
SDK包含35+内置工具,常见的有:
- 文件操作:、
Read、Write、Edit、Delete、MoveRename - 搜索:、
Glob、GrepSearch - Git:、
GitStatus、GitDiff、GitLog、GitCommitGitCheckout - 分析:、
Lint、Symbols、CodeGraphDependencies - Shell:、
BashBashSession - 实用工具:、
Ask、Attempt、Skill(子Agent)Agent
Restricting Tools
限制工具使用
typescript
import { createAgent } from "@codeany/open-agent-sdk";
// Read-only agent
const readOnlyAgent = createAgent({
allowedTools: ["Read", "Glob", "Grep", "Search"],
permissionMode: "dontAsk",
});
// Agent without shell access
const noShellAgent = createAgent({
disallowedTools: ["Bash", "BashSession"],
});
// Minimal tool set
const minimalAgent = createAgent({
tools: [], // No tools at all
});typescript
import { createAgent } from "@codeany/open-agent-sdk";
// 只读Agent
const readOnlyAgent = createAgent({
allowedTools: ["Read", "Glob", "Grep", "Search"],
permissionMode: "dontAsk",
});
// 无Shell权限的Agent
const noShellAgent = createAgent({
disallowedTools: ["Bash", "BashSession"],
});
// 极简工具集
const minimalAgent = createAgent({
tools: [], // 完全不使用工具
});Skills
技能系统
Skills are reusable prompt templates. Five built-in skills: , , , , .
simplifycommitreviewdebugtest技能是可复用的提示词模板。内置5种技能:、、、、。
simplifycommitreviewdebugtestUsing Built-in Skills
使用内置技能
typescript
import { createAgent } from "@codeany/open-agent-sdk";
const agent = createAgent();
// The agent can invoke skills via the Skill tool
const result = await agent.prompt(
'Use the "review" skill to review src/index.ts'
);
console.log(result.text);typescript
import { createAgent } from "@codeany/open-agent-sdk";
const agent = createAgent();
// Agent可通过Skill工具调用技能
const result = await agent.prompt(
'Use the "review" skill to review src/index.ts'
);
console.log(result.text);Creating Custom Skills
创建自定义技能
typescript
import { registerSkill, getAllSkills, createAgent } from "@codeany/open-agent-sdk";
registerSkill({
name: "explain",
description: "Explain a concept in simple terms",
userInvocable: true,
async getPrompt(args) {
return [
{
type: "text",
text: `Explain in simple terms: ${args || "Ask what to explain."}`,
},
];
},
});
registerSkill({
name: "optimize",
description: "Optimize code for performance",
userInvocable: true,
async getPrompt(args) {
return [
{
type: "text",
text: `Analyze and optimize the following for performance:\n${args}\n\nProvide specific improvements and benchmarks.`,
},
];
},
});
console.log(`${getAllSkills().length} skills registered`);
const agent = createAgent();
const result = await agent.prompt(
'Use the "optimize" skill on src/heavy-computation.ts'
);
console.log(result.text);typescript
import { registerSkill, getAllSkills, createAgent } from "@codeany/open-agent-sdk";
registerSkill({
name: "explain",
description: "Explain a concept in simple terms",
userInvocable: true,
async getPrompt(args) {
return [
{
type: "text",
text: `Explain in simple terms: ${args || "Ask what to explain."}`,
},
];
},
});
registerSkill({
name: "optimize",
description: "Optimize code for performance",
userInvocable: true,
async getPrompt(args) {
return [
{
type: "text",
text: `Analyze and optimize the following for performance:\n${args}\n\nProvide specific improvements and benchmarks.`,
},
];
},
});
console.log(`${getAllSkills().length} skills registered`);
const agent = createAgent();
const result = await agent.prompt(
'Use the "optimize" skill on src/heavy-computation.ts'
);
console.log(result.text);MCP Server Integration
MCP服务器集成
External MCP Servers
外部MCP服务器
typescript
import { createAgent } from "@codeany/open-agent-sdk";
const agent = createAgent({
mcpServers: {
filesystem: {
command: "npx",
args: ["-y", "@modelcontextprotocol/server-filesystem", "/tmp"],
},
postgres: {
command: "npx",
args: ["-y", "@modelcontextprotocol/server-postgres"],
env: {
DATABASE_URL: process.env.DATABASE_URL,
},
},
},
});
const result = await agent.prompt("List files in /tmp and query the database");
console.log(result.text);
await agent.close(); // Important: closes MCP connectionstypescript
import { createAgent } from "@codeany/open-agent-sdk";
const agent = createAgent({
mcpServers: {
filesystem: {
command: "npx",
args: ["-y", "@modelcontextprotocol/server-filesystem", "/tmp"],
},
postgres: {
command: "npx",
args: ["-y", "@modelcontextprotocol/server-postgres"],
env: {
DATABASE_URL: process.env.DATABASE_URL,
},
},
},
});
const result = await agent.prompt("List files in /tmp and query the database");
console.log(result.text);
await agent.close(); // 重要:关闭MCP连接In-Process MCP Servers
进程内MCP服务器
typescript
import { z } from "zod";
import { createAgent, tool, createSdkMcpServer } from "@codeany/open-agent-sdk";
const httpGet = tool(
"http_get",
"Make HTTP GET requests",
{
url: z.string().url().describe("URL to fetch"),
headers: z.record(z.string()).optional().describe("HTTP headers"),
},
async ({ url, headers }) => {
const response = await fetch(url, { headers });
const text = await response.text();
return {
content: [
{
type: "text",
text: `Status: ${response.status}\n\n${text}`,
},
],
};
}
);
const mcpServer = createSdkMcpServer({
name: "http-tools",
tools: [httpGet],
});
const agent = createAgent({
mcpServers: {
http: mcpServer,
},
});
const result = await agent.prompt("Fetch https://api.github.com/repos/codeany-ai/open-agent-sdk-typescript");
console.log(result.text);typescript
import { z } from "zod";
import { createAgent, tool, createSdkMcpServer } from "@codeany/open-agent-sdk";
const httpGet = tool(
"http_get",
"Make HTTP GET requests",
{
url: z.string().url().describe("URL to fetch"),
headers: z.record(z.string()).optional().describe("HTTP headers"),
},
async ({ url, headers }) => {
const response = await fetch(url, { headers });
const text = await response.text();
return {
content: [
{
type: "text",
text: `Status: ${response.status}\n\n${text}`,
},
],
};
}
);
const mcpServer = createSdkMcpServer({
name: "http-tools",
tools: [httpGet],
});
const agent = createAgent({
mcpServers: {
http: mcpServer,
},
});
const result = await agent.prompt("Fetch https://api.github.com/repos/codeany-ai/open-agent-sdk-typescript");
console.log(result.text);Subagents
子Agent
Subagents are specialized agents with restricted tools and custom prompts.
typescript
import { query } from "@codeany/open-agent-sdk";
for await (const msg of query({
prompt: "Use the security-reviewer to audit src/auth.ts for vulnerabilities",
options: {
agents: {
"security-reviewer": {
description: "Expert security code reviewer",
prompt: "You are a security expert. Analyze code for vulnerabilities, focusing on authentication, authorization, input validation, and data exposure.",
tools: ["Read", "Glob", "Grep", "Symbols"],
},
"performance-optimizer": {
description: "Performance optimization specialist",
prompt: "You optimize code for speed and efficiency. Identify bottlenecks, suggest algorithmic improvements, and recommend caching strategies.",
tools: ["Read", "Symbols", "Dependencies"],
},
},
},
})) {
if (msg.type === "assistant") {
for (const block of msg.message.content) {
if ("text" in block) console.log(block.text);
}
}
}子Agent是具备受限工具和自定义提示词的专业化Agent。
typescript
import { query } from "@codeany/open-agent-sdk";
for await (const msg of query({
prompt: "Use the security-reviewer to audit src/auth.ts for vulnerabilities",
options: {
agents: {
"security-reviewer": {
description: "Expert security code reviewer",
prompt: "You are a security expert. Analyze code for vulnerabilities, focusing on authentication, authorization, input validation, and data exposure.",
tools: ["Read", "Glob", "Grep", "Symbols"],
},
"performance-optimizer": {
description: "Performance optimization specialist",
prompt: "You optimize code for speed and efficiency. Identify bottlenecks, suggest algorithmic improvements, and recommend caching strategies.",
tools: ["Read", "Symbols", "Dependencies"],
},
},
},
})) {
if (msg.type === "assistant") {
for (const block of msg.message.content) {
if ("text" in block) console.log(block.text);
}
}
}Lifecycle Hooks
生命周期钩子
20 available hook events for observability and control.
typescript
import { createAgent, createHookRegistry } from "@codeany/open-agent-sdk";
const hooks = createHookRegistry({
PreToolUse: [
{
handler: async (input) => {
console.log(`[HOOK] About to use tool: ${input.toolName}`);
console.log(`[HOOK] Arguments:`, input.toolInput);
// Block dangerous operations
if (input.toolName === "Bash" && input.toolInput.command?.includes("rm -rf")) {
console.warn("[HOOK] Blocking dangerous command");
return { block: true };
}
},
},
],
PostToolUse: [
{
handler: async (input) => {
console.log(`[HOOK] Tool ${input.toolName} completed`);
console.log(`[HOOK] Result length:`, input.toolResult.length);
},
},
],
PostToolUseFailure: [
{
handler: async (input) => {
console.error(`[HOOK] Tool ${input.toolName} failed:`, input.error);
},
},
],
SessionStart: [
{
handler: async () => {
console.log("[HOOK] Session started");
},
},
],
SessionEnd: [
{
handler: async () => {
console.log("[HOOK] Session ended");
},
},
],
FileChanged: [
{
handler: async (input) => {
console.log(`[HOOK] File changed: ${input.path}`);
},
},
],
});
const agent = createAgent({
hooks,
model: "claude-sonnet-4-6",
});
const result = await agent.prompt("List files and create a new test file");
console.log(result.text);提供20种可用的钩子事件,用于可观测性和控制。
typescript
import { createAgent, createHookRegistry } from "@codeany/open-agent-sdk";
const hooks = createHookRegistry({
PreToolUse: [
{
handler: async (input) => {
console.log(`[HOOK] About to use tool: ${input.toolName}`);
console.log(`[HOOK] Arguments:`, input.toolInput);
// Block dangerous operations
if (input.toolName === "Bash" && input.toolInput.command?.includes("rm -rf")) {
console.warn("[HOOK] Blocking dangerous command");
return { block: true };
}
},
},
],
PostToolUse: [
{
handler: async (input) => {
console.log(`[HOOK] Tool ${input.toolName} completed`);
console.log(`[HOOK] Result length:`, input.toolResult.length);
},
},
],
PostToolUseFailure: [
{
handler: async (input) => {
console.error(`[HOOK] Tool ${input.toolName} failed:`, input.error);
},
},
],
SessionStart: [
{
handler: async () => {
console.log("[HOOK] Session started");
},
},
],
SessionEnd: [
{
handler: async () => {
console.log("[HOOK] Session ended");
},
},
],
FileChanged: [
{
handler: async (input) => {
console.log(`[HOOK] File changed: ${input.path}`);
},
},
],
});
const agent = createAgent({
hooks,
model: "claude-sonnet-4-6",
});
const result = await agent.prompt("List files and create a new test file");
console.log(result.text);Available Hook Events
可用钩子事件
- Tool lifecycle: ,
PreToolUse,PostToolUsePostToolUseFailure - Session: ,
SessionStart,SessionEndStop - Subagents: ,
SubagentStartSubagentStop - User interaction: ,
UserPromptSubmit,PermissionRequestPermissionDenied - Tasks: ,
TaskCreatedTaskCompleted - Config: ,
ConfigChangeCwdChanged - File system:
FileChanged - System: ,
Notification,PreCompact,PostCompactTeammateIdle
- 工具生命周期:、
PreToolUse、PostToolUsePostToolUseFailure - 会话:、
SessionStart、SessionEndStop - 子Agent:、
SubagentStartSubagentStop - 用户交互:、
UserPromptSubmit、PermissionRequestPermissionDenied - 任务:、
TaskCreatedTaskCompleted - 配置:、
ConfigChangeCwdChanged - 文件系统:
FileChanged - 系统:、
Notification、PreCompact、PostCompactTeammateIdle
Permission Modes
权限模式
Control how the agent handles permission requests:
typescript
import { createAgent } from "@codeany/open-agent-sdk";
// Bypass all permissions (default)
const autoAgent = createAgent({
permissionMode: "bypassPermissions",
});
// Never ask, deny if permission needed
const denyAgent = createAgent({
permissionMode: "dontAsk",
});
// Ask for permission (requires custom handler)
const askAgent = createAgent({
permissionMode: "ask",
// Implement permission handler via hooks
});
// Change mode mid-session
autoAgent.setPermissionMode("dontAsk");控制Agent处理权限请求的方式:
typescript
import { createAgent } from "@codeany/open-agent-sdk";
// 绕过所有权限(默认)
const autoAgent = createAgent({
permissionMode: "bypassPermissions",
});
// 从不询问,需要权限时直接拒绝
const denyAgent = createAgent({
permissionMode: "dontAsk",
});
// 请求权限(需要自定义处理器)
const askAgent = createAgent({
permissionMode: "ask",
// 通过钩子实现权限处理器
});
// 会话中途更改模式
autoAgent.setPermissionMode("dontAsk");Configuration Options
配置选项
Agent Options
Agent选项
typescript
import { createAgent } from "@codeany/open-agent-sdk";
const agent = createAgent({
// API configuration
apiType: "anthropic-messages", // or "openai-completions"
model: "claude-sonnet-4-6",
apiKey: process.env.CODEANY_API_KEY,
baseURL: "https://api.anthropic.com",
// Session
sessionId: "my-session-id",
maxTurns: 10,
// Working directory
cwd: process.cwd(),
// System prompt
systemPrompt: "You are a helpful coding assistant",
appendSystemPrompt: "\n\nAlways explain your reasoning.",
// Tools
tools: [], // Custom tool list
allowedTools: ["Read", "Write", "Glob"],
disallowedTools: ["Bash"],
// Permissions
permissionMode: "bypassPermissions",
// MCP servers
mcpServers: {},
// Subagents
agents: {},
// Hooks
hooks: createHookRegistry({}),
// Model parameters
temperature: 0.7,
maxTokens: 4096,
});typescript
import { createAgent } from "@codeany/open-agent-sdk";
const agent = createAgent({
// API配置
apiType: "anthropic-messages", // 或 "openai-completions"
model: "claude-sonnet-4-6",
apiKey: process.env.CODEANY_API_KEY,
baseURL: "https://api.anthropic.com",
// 会话
sessionId: "my-session-id",
maxTurns: 10,
// 工作目录
cwd: process.cwd(),
// 系统提示词
systemPrompt: "You are a helpful coding assistant",
appendSystemPrompt: "\n\nAlways explain your reasoning.",
// 工具
tools: [], // 自定义工具列表
allowedTools: ["Read", "Write", "Glob"],
disallowedTools: ["Bash"],
// 权限
permissionMode: "bypassPermissions",
// MCP服务器
mcpServers: {},
// 子Agent
agents: {},
// 钩子
hooks: createHookRegistry({}),
// 模型参数
temperature: 0.7,
maxTokens: 4096,
});Query Options
Query选项
typescript
import { query } from "@codeany/open-agent-sdk";
for await (const msg of query({
prompt: "Your prompt here",
options: {
model: "gpt-4o",
apiType: "openai-completions",
apiKey: process.env.OPENAI_API_KEY,
cwd: "/path/to/project",
allowedTools: ["Read", "Glob"],
permissionMode: "bypassPermissions",
maxTurns: 5,
temperature: 0.5,
},
})) {
// Handle messages
}typescript
import { query } from "@codeany/open-agent-sdk";
for await (const msg of query({
prompt: "Your prompt here",
options: {
model: "gpt-4o",
apiType: "openai-completions",
apiKey: process.env.OPENAI_API_KEY,
cwd: "/path/to/project",
allowedTools: ["Read", "Glob"],
permissionMode: "bypassPermissions",
maxTurns: 5,
temperature: 0.5,
},
})) {
// 处理消息
}Advanced Patterns
高级模式
Session Management
会话管理
typescript
import { createAgent, listSessions, forkSession } from "@codeany/open-agent-sdk";
// Create agent with persistent session
const agent = createAgent({
sessionId: "my-project-session",
});
await agent.prompt("Analyze the codebase structure");
await agent.prompt("Now suggest improvements");
// List all sessions
const sessions = await listSessions();
console.log("Saved sessions:", sessions);
// Fork a session for experimentation
const forkedId = await forkSession("my-project-session");
const forkedAgent = createAgent({ sessionId: forkedId });
await forkedAgent.prompt("Try refactoring with a different approach");typescript
import { createAgent, listSessions, forkSession } from "@codeany/open-agent-sdk";
// 创建带持久化会话的Agent
const agent = createAgent({
sessionId: "my-project-session",
});
await agent.prompt("Analyze the codebase structure");
await agent.prompt("Now suggest improvements");
// 列出所有会话
const sessions = await listSessions();
console.log("Saved sessions:", sessions);
// 复制会话用于实验
const forkedId = await forkSession("my-project-session");
const forkedAgent = createAgent({ sessionId: forkedId });
await forkedAgent.prompt("Try refactoring with a different approach");Interrupting Long-Running Queries
中断长时间运行的查询
typescript
import { createAgent } from "@codeany/open-agent-sdk";
const agent = createAgent();
// Start a long-running query
const queryPromise = agent.prompt("Analyze all files in the project");
// Interrupt after 5 seconds
setTimeout(() => {
agent.interrupt();
console.log("Query interrupted");
}, 5000);
try {
const result = await queryPromise;
console.log(result.text);
} catch (error) {
console.log("Query was interrupted");
}typescript
import { createAgent } from "@codeany/open-agent-sdk";
const agent = createAgent();
// 启动长时间运行的查询
const queryPromise = agent.prompt("Analyze all files in the project");
// 5秒后中断
setTimeout(() => {
agent.interrupt();
console.log("Query interrupted");
}, 5000);
try {
const result = await queryPromise;
console.log(result.text);
} catch (error) {
console.log("Query was interrupted");
}Model Switching
模型切换
typescript
import { createAgent } from "@codeany/open-agent-sdk";
const agent = createAgent({ model: "claude-sonnet-4-6" });
await agent.prompt("Quick analysis");
// Switch to more powerful model for complex task
agent.setModel("claude-opus-4");
await agent.prompt("Perform deep architectural analysis");
// Switch back to cheaper model
agent.setModel("claude-sonnet-4-6");
await agent.prompt("Summarize findings");typescript
import { createAgent } from "@codeany/open-agent-sdk";
const agent = createAgent({ model: "claude-sonnet-4-6" });
await agent.prompt("Quick analysis");
// 切换到更强大的模型处理复杂任务
agent.setModel("claude-opus-4");
await agent.prompt("Perform deep architectural analysis");
// 切换回更经济的模型
agent.setModel("claude-sonnet-4-6");
await agent.prompt("Summarize findings");Streaming with Full Control
完全可控的流式处理
typescript
import { createAgent } from "@codeany/open-agent-sdk";
const agent = createAgent();
for await (const message of agent.query("Analyze this codebase")) {
switch (message.type) {
case "assistant":
for (const block of message.message.content) {
if ("text" in block) {
process.stdout.write(block.text);
} else if ("tool_use" in block) {
console.log(`\n[Tool: ${block.tool_use.name}]`);
}
}
break;
case "tool_use":
console.log(`\nExecuting: ${message.toolName}`);
break;
case "tool_result":
console.log(`Tool result length: ${message.result.length} chars`);
break;
case "result":
console.log(`\n\nCompleted in ${message.num_turns} turns`);
console.log(`Cost: $${message.total_cost_usd?.toFixed(4)}`);
console.log(`Tokens: ${message.usage.input_tokens + message.usage.output_tokens}`);
break;
case "error":
console.error(`Error: ${message.error}`);
break;
}
}typescript
import { createAgent } from "@codeany/open-agent-sdk";
const agent = createAgent();
for await (const message of agent.query("Analyze this codebase")) {
switch (message.type) {
case "assistant":
for (const block of message.message.content) {
if ("text" in block) {
process.stdout.write(block.text);
} else if ("tool_use" in block) {
console.log(`\n[Tool: ${block.tool_use.name}]`);
}
}
break;
case "tool_use":
console.log(`\nExecuting: ${message.toolName}`);
break;
case "tool_result":
console.log(`Tool result length: ${message.result.length} chars`);
break;
case "result":
console.log(`\n\nCompleted in ${message.num_turns} turns`);
console.log(`Cost: $${message.total_cost_usd?.toFixed(4)}`);
console.log(`Tokens: ${message.usage.input_tokens + message.usage.output_tokens}`);
break;
case "error":
console.error(`Error: ${message.error}`);
break;
}
}Error Handling
错误处理
typescript
import { createAgent } from "@codeany/open-agent-sdk";
const agent = createAgent();
try {
const result = await agent.prompt("Your prompt here");
console.log(result.text);
} catch (error) {
if (error.message.includes("rate limit")) {
console.error("Rate limit exceeded, retry later");
} else if (error.message.includes("context length")) {
console.error("Prompt too long, try simplifying");
} else {
console.error("Agent error:", error.message);
}
} finally {
await agent.close();
}typescript
import { createAgent } from "@codeany/open-agent-sdk";
const agent = createAgent();
try {
const result = await agent.prompt("Your prompt here");
console.log(result.text);
} catch (error) {
if (error.message.includes("rate limit")) {
console.error("Rate limit exceeded, retry later");
} else if (error.message.includes("context length")) {
console.error("Prompt too long, try simplifying");
} else {
console.error("Agent error:", error.message);
}
} finally {
await agent.close();
}Troubleshooting
故障排查
API Key Not Found
API密钥未找到
Error: API key not foundSolution: Set the environment variable or pass in options:
CODEANY_API_KEYapiKeytypescript
const agent = createAgent({
apiKey: process.env.CODEANY_API_KEY,
});Error: API key not found解决方案:设置环境变量,或在选项中传入:
CODEANY_API_KEYapiKeytypescript
const agent = createAgent({
apiKey: process.env.CODEANY_API_KEY,
});Model Not Found / Invalid API Type
模型未找到/API类型无效
Error: Model not found: gpt-4oSolution: Explicitly set for OpenAI models:
apiTypetypescript
const agent = createAgent({
apiType: "openai-completions",
model: "gpt-4o",
baseURL: "https://api.openai.com/v1",
});Error: Model not found: gpt-4o解决方案:为OpenAI模型显式设置:
apiTypetypescript
const agent = createAgent({
apiType: "openai-completions",
model: "gpt-4o",
baseURL: "https://api.openai.com/v1",
});MCP Server Connection Failed
MCP服务器连接失败
Error: Failed to start MCP serverSolution: Ensure MCP server package is available and command is correct:
bash
npm install -g @modelcontextprotocol/server-filesystemtypescript
const agent = createAgent({
mcpServers: {
filesystem: {
command: "npx",
args: ["-y", "@modelcontextprotocol/server-filesystem", "/tmp"],
},
},
});Error: Failed to start MCP server解决方案:确保MCP服务器包可用且命令正确:
bash
npm install -g @modelcontextprotocol/server-filesystemtypescript
const agent = createAgent({
mcpServers: {
filesystem: {
command: "npx",
args: ["-y", "@modelcontextprotocol/server-filesystem", "/tmp"],
},
},
});Permission Denied Errors
权限拒绝错误
Permission denied: Cannot execute BashSolution: Adjust permission mode or allow specific tools:
typescript
const agent = createAgent({
permissionMode: "bypassPermissions",
allowedTools: ["Bash", "Read", "Write"],
});Permission denied: Cannot execute Bash解决方案:调整权限模式或允许特定工具:
typescript
const agent = createAgent({
permissionMode: "bypassPermissions",
allowedTools: ["Bash", "Read", "Write"],
});Session Persistence Issues
会话持久化问题
Sessions are stored in by default. Ensure write permissions exist.
.codeany/sessions/会话默认存储在目录下。确保具备写入权限。
.codeany/sessions/Rate Limiting
速率限制
Implement retry logic with exponential backoff:
typescript
async function queryWithRetry(agent, prompt, maxRetries = 3) {
for (let i = 0; i < maxRetries; i++) {
try {
return await agent.prompt(prompt);
} catch (error) {
if (error.message.includes("rate limit") && i < maxRetries - 1) {
const delay = Math.pow(2, i) * 1000;
console.log(`Rate limited, retrying in ${delay}ms...`);
await new Promise(resolve => setTimeout(resolve, delay));
} else {
throw error;
}
}
}
}实现带指数退避的重试逻辑:
typescript
async function queryWithRetry(agent, prompt, maxRetries = 3) {
for (let i = 0; i < maxRetries; i++) {
try {
return await agent.prompt(prompt);
} catch (error) {
if (error.message.includes("rate limit") && i < maxRetries - 1) {
const delay = Math.pow(2, i) * 1000;
console.log(`Rate limited, retrying in ${delay}ms...`);
await new Promise(resolve => setTimeout(resolve, delay));
} else {
throw error;
}
}
}
}Web UI
Web UI
The SDK includes a built-in web chat interface for testing:
bash
npx tsx examples/web/server.tsThen open in your browser.
http://localhost:8081SDK包含内置的网页聊天界面用于测试:
bash
npx tsx examples/web/server.ts然后在浏览器中打开。
http://localhost:8081Complete Example: Code Review Agent
完整示例:代码审查Agent
typescript
import { z } from "zod";
import { createAgent, tool, createSdkMcpServer, createHookRegistry } from "@codeany/open-agent-sdk";
// Custom tool for static analysis
const analyzeComplexity = tool(
"analyze_complexity",
"Analyze code complexity metrics",
{
filePath: z.string().describe("Path to file to analyze"),
},
async ({ filePath }) => {
// Simplified complexity analysis
return {
content: [
{
type: "text",
text: JSON.stringify({
cyclomaticComplexity: 12,
cognitiveComplexity: 8,
linesOfCode: 245,
}),
},
],
};
}
);
const mcpServer = createSdkMcpServer({
name: "code-analysis",
tools: [analyzeComplexity],
});
// Hook to log all tool usage
const hooks = createHookRegistry({
PreToolUse: [
{
handler: async (input) => {
console.log(`[Review] Using tool: ${input.toolName}`);
},
},
],
PostToolUse: [
{
handler: async (input) => {
console.log(`[Review] Tool ${input.toolName} completed`);
},
},
],
});
const agent = createAgent({
model: "claude-sonnet-4-6",
systemPrompt: "You are an expert code reviewer. Focus on code quality, security, performance, and maintainability.",
allowedTools: ["Read", "Glob", "Grep", "Symbols", "analyze_complexity"],
mcpServers: { analysis: mcpServer },
hooks,
permissionMode: "bypassPermissions",
});
async function reviewCode(pattern) {
console.log(`\n=== Starting code review for: ${pattern} ===\n`);
const result = await agent.prompt(`
Review all files matching ${pattern}. For each file:
1. Analyze code quality and structure
2. Check for security vulnerabilities
3. Assess performance implications
4. Suggest improvements
Use analyze_complexity to get metrics.
Provide a summary with prioritized recommendations.
`);
console.log("\n=== Review Results ===\n");
console.log(result.text);
console.log(`\n=== Stats: ${result.num_turns} turns, ${result.usage.input_tokens + result.usage.output_tokens} tokens ===`);
}
reviewCode("src/**/*.ts").then(() => agent.close());typescript
import { z } from "zod";
import { createAgent, tool, createSdkMcpServer, createHookRegistry } from "@codeany/open-agent-sdk";
// 用于静态分析的自定义工具
const analyzeComplexity = tool(
"analyze_complexity",
"Analyze code complexity metrics",
{
filePath: z.string().describe("Path to file to analyze"),
},
async ({ filePath }) => {
// 简化的复杂度分析
return {
content: [
{
type: "text",
text: JSON.stringify({
cyclomaticComplexity: 12,
cognitiveComplexity: 8,
linesOfCode: 245,
}),
},
],
};
}
);
const mcpServer = createSdkMcpServer({
name: "code-analysis",
tools: [analyzeComplexity],
});
// 记录所有工具使用情况的钩子
const hooks = createHookRegistry({
PreToolUse: [
{
handler: async (input) => {
console.log(`[Review] Using tool: ${input.toolName}`);
},
},
],
PostToolUse: [
{
handler: async (input) => {
console.log(`[Review] Tool ${input.toolName} completed`);
},
},
],
});
const agent = createAgent({
model: "claude-sonnet-4-6",
systemPrompt: "You are an expert code reviewer. Focus on code quality, security, performance, and maintainability.",
allowedTools: ["Read", "Glob", "Grep", "Symbols", "analyze_complexity"],
mcpServers: { analysis: mcpServer },
hooks,
permissionMode: "bypassPermissions",
});
async function reviewCode(pattern) {
console.log(`\n=== Starting code review for: ${pattern} ===\n`);
const result = await agent.prompt(`
Review all files matching ${pattern}. For each file:
1. Analyze code quality and structure
2. Check for security vulnerabilities
3. Assess performance implications
4. Suggest improvements
Use analyze_complexity to get metrics.
Provide a summary with prioritized recommendations.
`);
console.log("\n=== Review Results ===\n");
console.log(result.text);
console.log(`\n=== Stats: ${result.num_turns} turns, ${result.usage.input_tokens + result.usage.output_tokens} tokens ===`);
}
reviewCode("src/**/*.ts").then(() => agent.close());