open-agent-sdk-typescript

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Open 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-sdk
Set your API key as an environment variable:
bash
export CODEANY_API_KEY=your-api-key-here
For 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-4o
For 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-4
bash
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-4

Core Concepts

核心概念

API Types

API类型

The SDK supports two API types:
  • anthropic-messages
    : Anthropic Claude models (default)
  • openai-completions
    : OpenAI, DeepSeek, Qwen, Mistral, or any OpenAI-compatible API
API type is auto-detected from model name. Models containing
gpt-
,
o1
,
o3
,
deepseek
,
qwen
, or
mistral
automatically use
openai-completions
.
SDK支持两种API类型:
  • anthropic-messages
    :Anthropic Claude模型(默认)
  • openai-completions
    :OpenAI、DeepSeek、Qwen、Mistral或任何兼容OpenAI的API
API类型会根据模型名称自动检测。包含
gpt-
o1
o3
deepseek
qwen
mistral
的模型会自动使用
openai-completions

Agent vs Query

Agent与Query

  • query()
    : One-shot streaming query, no session persistence
  • createAgent()
    : Reusable agent with multi-turn conversation history
  • query()
    :单次流式查询,无会话持久化
  • createAgent()
    :可复用的Agent,支持多轮对话历史

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
    ,
    Move
    ,
    Rename
  • Search:
    Glob
    ,
    Grep
    ,
    Search
  • Git:
    GitStatus
    ,
    GitDiff
    ,
    GitLog
    ,
    GitCommit
    ,
    GitCheckout
  • Analysis:
    Lint
    ,
    Symbols
    ,
    CodeGraph
    ,
    Dependencies
  • Shell:
    Bash
    ,
    BashSession
  • Utility:
    Ask
    ,
    Attempt
    ,
    Skill
    ,
    Agent
    (subagents)
SDK包含35+内置工具,常见的有:
  • 文件操作
    Read
    Write
    Edit
    Delete
    Move
    Rename
  • 搜索
    Glob
    Grep
    Search
  • Git
    GitStatus
    GitDiff
    GitLog
    GitCommit
    GitCheckout
  • 分析
    Lint
    Symbols
    CodeGraph
    Dependencies
  • Shell
    Bash
    BashSession
  • 实用工具
    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:
simplify
,
commit
,
review
,
debug
,
test
.
技能是可复用的提示词模板。内置5种技能:
simplify
commit
review
debug
test

Using 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 connections
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(); // 重要:关闭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
    ,
    PostToolUse
    ,
    PostToolUseFailure
  • Session:
    SessionStart
    ,
    SessionEnd
    ,
    Stop
  • Subagents:
    SubagentStart
    ,
    SubagentStop
  • User interaction:
    UserPromptSubmit
    ,
    PermissionRequest
    ,
    PermissionDenied
  • Tasks:
    TaskCreated
    ,
    TaskCompleted
  • Config:
    ConfigChange
    ,
    CwdChanged
  • File system:
    FileChanged
  • System:
    Notification
    ,
    PreCompact
    ,
    PostCompact
    ,
    TeammateIdle
  • 工具生命周期
    PreToolUse
    PostToolUse
    PostToolUseFailure
  • 会话
    SessionStart
    SessionEnd
    Stop
  • 子Agent
    SubagentStart
    SubagentStop
  • 用户交互
    UserPromptSubmit
    PermissionRequest
    PermissionDenied
  • 任务
    TaskCreated
    TaskCompleted
  • 配置
    ConfigChange
    CwdChanged
  • 文件系统
    FileChanged
  • 系统
    Notification
    PreCompact
    PostCompact
    TeammateIdle

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 found
Solution: Set the
CODEANY_API_KEY
environment variable or pass
apiKey
in options:
typescript
const agent = createAgent({
  apiKey: process.env.CODEANY_API_KEY,
});
Error: API key not found
解决方案:设置
CODEANY_API_KEY
环境变量,或在选项中传入
apiKey
typescript
const agent = createAgent({
  apiKey: process.env.CODEANY_API_KEY,
});

Model Not Found / Invalid API Type

模型未找到/API类型无效

Error: Model not found: gpt-4o
Solution: Explicitly set
apiType
for OpenAI models:
typescript
const agent = createAgent({
  apiType: "openai-completions",
  model: "gpt-4o",
  baseURL: "https://api.openai.com/v1",
});
Error: Model not found: gpt-4o
解决方案:为OpenAI模型显式设置
apiType
typescript
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 server
Solution: Ensure MCP server package is available and command is correct:
bash
npm install -g @modelcontextprotocol/server-filesystem
typescript
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-filesystem
typescript
const agent = createAgent({
  mcpServers: {
    filesystem: {
      command: "npx",
      args: ["-y", "@modelcontextprotocol/server-filesystem", "/tmp"],
    },
  },
});

Permission Denied Errors

权限拒绝错误

Permission denied: Cannot execute Bash
Solution: 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
.codeany/sessions/
by default. Ensure write permissions exist.
会话默认存储在
.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.ts
Then open
http://localhost:8081
in your browser.
SDK包含内置的网页聊天界面用于测试:
bash
npx tsx examples/web/server.ts
然后在浏览器中打开
http://localhost:8081

Complete 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());