# Open Agent SDK (TypeScript) [![npm version](https://img.shields.io/npm/v/@codeany/open-agent-sdk)](https://www.npmjs.com/package/@codeany/open-agent-sdk) [![Node.js](https://img.shields.io/badge/node-%3E%3D18-brightgreen)](https://nodejs.org) [![License: MIT](https://img.shields.io/badge/license-MIT-blue)](./LICENSE) Open-source Agent SDK that runs the full agent loop **in-process** — no subprocess or CLI required. Supports both **Anthropic** and **OpenAI-compatible** APIs. Deploy anywhere: cloud, serverless, Docker, CI/CD. Also available in **Go**: [open-agent-sdk-go](https://github.com/codeany-ai/open-agent-sdk-go) ## Get started ```bash npm install @codeany/open-agent-sdk ``` Set your API key: ```bash export CODEANY_API_KEY=your-api-key ``` ### OpenAI-compatible models Works with OpenAI, DeepSeek, Qwen, Mistral, or any OpenAI-compatible endpoint: ```bash export CODEANY_API_TYPE=openai-completions export CODEANY_API_KEY=sk-... export CODEANY_BASE_URL=https://api.openai.com/v1 export CODEANY_MODEL=gpt-4o ``` ### Third-party Anthropic-compatible providers ```bash export CODEANY_BASE_URL=https://openrouter.ai/api export CODEANY_API_KEY=sk-or-... export CODEANY_MODEL=anthropic/claude-sonnet-4 ``` ## Quick start ### One-shot query (streaming) ```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); } } } ``` ### 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}, Tokens: ${result.usage.input_tokens + result.usage.output_tokens}`, ); ``` ### OpenAI / GPT models ```typescript import { createAgent } from "@codeany/open-agent-sdk"; const agent = createAgent({ apiType: "openai-completions", model: "gpt-4o", apiKey: "sk-...", baseURL: "https://api.openai.com/v1", }); const result = await agent.prompt("What files are in this project?"); console.log(result.text); ``` The `apiType` is auto-detected from model name — models containing `gpt-`, `o1`, `o3`, `deepseek`, `qwen`, `mistral`, etc. automatically use `openai-completions`. ### 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(r1.text); const r2 = await agent.prompt("Read back the file you just created"); console.log(r2.text); console.log(`Session messages: ${agent.getMessages().length}`); ``` ### Custom tools (Zod schema) ```typescript import { z } from "zod"; import { query, tool, createSdkMcpServer } from "@codeany/open-agent-sdk"; const getWeather = tool( "get_weather", "Get the temperature for a city", { city: z.string().describe("City name") }, async ({ city }) => ({ content: [{ type: "text", text: `${city}: 22°C, sunny` }], }), ); const server = createSdkMcpServer({ name: "weather", tools: [getWeather] }); for await (const msg of query({ prompt: "What is the weather in Tokyo?", options: { mcpServers: { weather: server } }, })) { if (msg.type === "result") console.log(`Done: $${msg.total_cost_usd?.toFixed(4)}`); } ``` ### Custom tools (low-level) ```typescript import { createAgent, getAllBaseTools, defineTool, } from "@codeany/open-agent-sdk"; const calculator = defineTool({ name: "Calculator", description: "Evaluate a math expression", inputSchema: { type: "object", properties: { expression: { type: "string" } }, required: ["expression"], }, isReadOnly: true, async call(input) { const result = Function(`'use strict'; return (${input.expression})`)(); return `${input.expression} = ${result}`; }, }); const agent = createAgent({ tools: [...getAllBaseTools(), calculator] }); const r = await agent.prompt("Calculate 2**10 * 3"); console.log(r.text); ``` ### Skills Skills are reusable prompt templates that extend agent capabilities. Five bundled skills are included: `simplify`, `commit`, `review`, `debug`, `test`. ```typescript import { createAgent, registerSkill, getAllSkills, } from "@codeany/open-agent-sdk"; // Register a custom skill 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."}`, }, ]; }, }); console.log(`${getAllSkills().length} skills registered`); // The model can invoke skills via the Skill tool const agent = createAgent(); const result = await agent.prompt('Use the "explain" skill to explain git rebase'); console.log(result.text); ``` ### Hooks (lifecycle events) ```typescript import { createAgent, createHookRegistry } from "@codeany/open-agent-sdk"; const hooks = createHookRegistry({ PreToolUse: [ { handler: async (input) => { console.log(`About to use: ${input.toolName}`); // Return { block: true } to prevent tool execution }, }, ], PostToolUse: [ { handler: async (input) => { console.log(`Tool ${input.toolName} completed`); }, }, ], }); ``` 20 lifecycle events: `PreToolUse`, `PostToolUse`, `PostToolUseFailure`, `SessionStart`, `SessionEnd`, `Stop`, `SubagentStart`, `SubagentStop`, `UserPromptSubmit`, `PermissionRequest`, `PermissionDenied`, `TaskCreated`, `TaskCompleted`, `ConfigChange`, `CwdChanged`, `FileChanged`, `Notification`, `PreCompact`, `PostCompact`, `TeammateIdle`. ### MCP server integration ```typescript import { createAgent } from "@codeany/open-agent-sdk"; const agent = createAgent({ mcpServers: { filesystem: { command: "npx", args: ["-y", "@modelcontextprotocol/server-filesystem", "/tmp"], }, }, }); const result = await agent.prompt("List files in /tmp"); console.log(result.text); await agent.close(); ``` ### Subagents ```typescript import { query } from "@codeany/open-agent-sdk"; for await (const msg of query({ prompt: "Use the code-reviewer agent to review src/index.ts", options: { agents: { "code-reviewer": { description: "Expert code reviewer", prompt: "Analyze code quality. Focus on security and performance.", tools: ["Read", "Glob", "Grep"], }, }, }, })) { if (msg.type === "result") console.log("Done"); } ``` ### Permissions ```typescript import { query } from "@codeany/open-agent-sdk"; // Read-only agent — can only analyze, not modify for await (const msg of query({ prompt: "Review the code in src/ for best practices.", options: { allowedTools: ["Read", "Glob", "Grep"], permissionMode: "dontAsk", }, })) { // ... } ``` ### Web UI A built-in web chat interface is included for testing: ```bash npx tsx examples/web/server.ts # Open http://localhost:8081 ``` ## API reference ### Top-level functions | Function | Description | | ------------------------------------- | -------------------------------------------------------------- | | `query({ prompt, options })` | One-shot streaming query, returns `AsyncGenerator` | | `createAgent(options)` | Create a reusable agent with session persistence | | `tool(name, desc, schema, handler)` | Create a tool with Zod schema validation | | `createSdkMcpServer({ name, tools })` | Bundle tools into an in-process MCP server | | `defineTool(config)` | Low-level tool definition helper | | `getAllBaseTools()` | Get all 35+ built-in tools | | `registerSkill(definition)` | Register a custom skill | | `getAllSkills()` | Get all registered skills | | `createProvider(apiType, opts)` | Create an LLM provider directly | | `createHookRegistry(config)` | Create a hook registry for lifecycle events | | `listSessions()` | List persisted sessions | | `forkSession(id)` | Fork a session for branching | ### Agent methods | Method | Description | | ------------------------------- | ----------------------------------------------------- | | `agent.query(prompt)` | Streaming query, returns `AsyncGenerator` | | `agent.prompt(text)` | Blocking query, returns `Promise` | | `agent.getMessages()` | Get conversation history | | `agent.clear()` | Reset session | | `agent.interrupt()` | Abort current query | | `agent.setModel(model)` | Change model mid-session | | `agent.setPermissionMode(mode)` | Change permission mode | | `agent.getApiType()` | Get current API type | | `agent.close()` | Close MCP connections, persist session | ### Options | Option | Type | Default | Description | | -------------------- | --------------------------------------- | ---------------------- | -------------------------------------------------------------------- | | `apiType` | `string` | auto-detected | `'anthropic-messages'` or `'openai-completions'` | | `model` | `string` | `claude-sonnet-4-6` | LLM model ID | | `apiKey` | `string` | `CODEANY_API_KEY` | API key | | `baseURL` | `string` | — | Custom API endpoint | | `cwd` | `string` | `process.cwd()` | Working directory | | `systemPrompt` | `string` | — | System prompt override | | `appendSystemPrompt` | `string` | — | Append to default system prompt | | `tools` | `ToolDefinition[]` | All built-in | Available tools | | `allowedTools` | `string[]` | — | Tool allow-list | | `disallowedTools` | `string[]` | — | Tool deny-list | | `permissionMode` | `string` | `bypassPermissions` | `default` / `acceptEdits` / `dontAsk` / `bypassPermissions` / `plan` | | `canUseTool` | `function` | — | Custom permission callback | | `maxTurns` | `number` | `10` | Max agentic turns | | `maxBudgetUsd` | `number` | — | Spending cap | | `thinking` | `ThinkingConfig` | `{ type: 'adaptive' }` | Extended thinking | | `effort` | `string` | `high` | Reasoning effort: `low` / `medium` / `high` / `max` | | `mcpServers` | `Record` | — | MCP server connections | | `agents` | `Record` | — | Subagent definitions | | `hooks` | `Record` | — | Lifecycle hooks | | `resume` | `string` | — | Resume session by ID | | `continue` | `boolean` | `false` | Continue most recent session | | `persistSession` | `boolean` | `true` | Persist session to disk | | `sessionId` | `string` | auto | Explicit session ID | | `outputFormat` | `{ type: 'json_schema', schema }` | — | Structured output | | `sandbox` | `SandboxSettings` | — | Filesystem/network sandbox | | `settingSources` | `SettingSource[]` | — | Load AGENT.md, project settings | | `env` | `Record` | — | Environment variables | | `abortController` | `AbortController` | — | Cancellation controller | ### Environment variables | Variable | Description | | -------------------- | -------------------------------------------------------- | | `CODEANY_API_KEY` | API key (required) | | `CODEANY_API_TYPE` | `anthropic-messages` (default) or `openai-completions` | | `CODEANY_MODEL` | Default model override | | `CODEANY_BASE_URL` | Custom API endpoint | | `CODEANY_AUTH_TOKEN` | Alternative auth token | ## Built-in tools | Tool | Description | | ------------------------------------------ | -------------------------------------------- | | **Bash** | Execute shell commands | | **Read** | Read files with line numbers | | **Write** | Create / overwrite files | | **Edit** | Precise string replacement in files | | **Glob** | Find files by pattern | | **Grep** | Search file contents with regex | | **WebFetch** | Fetch and parse web content | | **WebSearch** | Search the web | | **NotebookEdit** | Edit Jupyter notebook cells | | **Agent** | Spawn subagents for parallel work | | **Skill** | Invoke registered skills | | **TaskCreate/List/Update/Get/Stop/Output** | Task management system | | **TeamCreate/Delete** | Multi-agent team coordination | | **SendMessage** | Inter-agent messaging | | **EnterWorktree/ExitWorktree** | Git worktree isolation | | **EnterPlanMode/ExitPlanMode** | Structured planning workflow | | **AskUserQuestion** | Ask the user for input | | **ToolSearch** | Discover lazy-loaded tools | | **ListMcpResources/ReadMcpResource** | MCP resource access | | **CronCreate/Delete/List** | Scheduled task management | | **RemoteTrigger** | Remote agent triggers | | **LSP** | Language Server Protocol (code intelligence) | | **Config** | Dynamic configuration | | **TodoWrite** | Session todo list | ## Bundled skills | Skill | Description | | ------------ | -------------------------------------------------------------- | | `simplify` | Review changed code for reuse, quality, and efficiency | | `commit` | Create a git commit with a well-crafted message | | `review` | Review code changes for correctness, security, and performance | | `debug` | Systematic debugging using structured investigation | | `test` | Run tests and analyze failures | Register custom skills with `registerSkill()`. ## Architecture ``` ┌──────────────────────────────────────────────────────┐ │ Your Application │ │ │ │ import { createAgent } from '@codeany/open-agent-sdk' │ └────────────────────────┬─────────────────────────────┘ │ ┌──────────▼──────────┐ │ Agent │ Session state, tool pool, │ query() / prompt() │ MCP connections, hooks └──────────┬──────────┘ │ ┌──────────▼──────────┐ │ QueryEngine │ Agentic loop: │ submitMessage() │ API call → tools → repeat └──────────┬──────────┘ │ ┌───────────────┼───────────────┐ │ │ │ ┌─────▼─────┐ ┌─────▼─────┐ ┌─────▼─────┐ │ Provider │ │ 35 Tools │ │ MCP │ │ Anthropic │ │ Bash,Read │ │ Servers │ │ OpenAI │ │ Edit,... │ │ stdio/SSE/ │ │ DeepSeek │ │ + Skills │ │ HTTP/SDK │ └───────────┘ └───────────┘ └───────────┘ ``` **Key internals:** | Component | Description | | --------------------- | ------------------------------------------------------------------ | | **Provider layer** | Abstracts Anthropic / OpenAI API differences | | **QueryEngine** | Core agentic loop with auto-compact, retry, tool orchestration | | **Skill system** | Reusable prompt templates with 5 bundled skills | | **Hook system** | 20 lifecycle events integrated into the engine | | **Auto-compact** | Summarizes conversation when context window fills up | | **Micro-compact** | Truncates oversized tool results | | **Retry** | Exponential backoff for rate limits and transient errors | | **Token estimation** | Rough token counting with pricing for Claude, GPT, DeepSeek models | | **File cache** | LRU cache (100 entries, 25 MB) for file reads | | **Session storage** | Persist / resume / fork sessions on disk | | **Context injection** | Git status + AGENT.md automatically injected into system prompt | ## Examples | # | File | Description | | --- | ------------------------------------- | -------------------------------------- | | 01 | `examples/01-simple-query.ts` | Streaming query with event handling | | 02 | `examples/02-multi-tool.ts` | Multi-tool orchestration (Glob + Bash) | | 03 | `examples/03-multi-turn.ts` | Multi-turn session persistence | | 04 | `examples/04-prompt-api.ts` | Blocking `prompt()` API | | 05 | `examples/05-custom-system-prompt.ts` | Custom system prompt | | 06 | `examples/06-mcp-server.ts` | MCP server integration | | 07 | `examples/07-custom-tools.ts` | Custom tools with `defineTool()` | | 08 | `examples/08-official-api-compat.ts` | `query()` API pattern | | 09 | `examples/09-subagents.ts` | Subagent delegation | | 10 | `examples/10-permissions.ts` | Read-only agent with tool restrictions | | 11 | `examples/11-custom-mcp-tools.ts` | `tool()` + `createSdkMcpServer()` | | 12 | `examples/12-skills.ts` | Skill system usage | | 13 | `examples/13-hooks.ts` | Lifecycle hooks | | 14 | `examples/14-openai-compat.ts` | OpenAI / DeepSeek models | | web | `examples/web/` | Web chat UI for testing | Run any example: ```bash npx tsx examples/01-simple-query.ts ``` Start the web UI: ```bash npx tsx examples/web/server.ts ``` ## Star History Star History Chart ## License MIT