mirror of
https://github.com/codeany-ai/open-agent-sdk-typescript.git
synced 2026-04-25 07:00:49 +09:00
85dff47d74
- Add skill system with types, registry, SkillTool, and 5 bundled skills
(simplify, commit, review, debug, test)
- Integrate hooks into QueryEngine at 9 lifecycle points (SessionStart,
UserPromptSubmit, PreToolUse, PostToolUse, PostToolUseFailure,
PreCompact, PostCompact, Stop, SessionEnd)
- Add LLM provider abstraction supporting both Anthropic Messages API
and OpenAI Chat Completions API (works with GPT, DeepSeek, Qwen, etc.)
- Add CODEANY_API_TYPE env var ('anthropic-messages' | 'openai-completions')
with auto-detection from model name
- Remove all ANTHROPIC_* env var references, only support CODEANY_* prefix
- Add model pricing and context windows for OpenAI/DeepSeek models
- Remove direct @anthropic-ai/sdk dependency from all files except the
Anthropic provider (types.ts, engine.ts, etc. are now provider-agnostic)
- Add PermissionBehavior type export
- Bump version to 0.2.0
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
502 lines
24 KiB
Markdown
502 lines
24 KiB
Markdown
# Open Agent SDK (TypeScript)
|
|
|
|
[](https://www.npmjs.com/package/@codeany/open-agent-sdk)
|
|
[](https://nodejs.org)
|
|
[](./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<SDKMessage>` |
|
|
| `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<SDKMessage>` |
|
|
| `agent.prompt(text)` | Blocking query, returns `Promise<QueryResult>` |
|
|
| `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<string, McpServerConfig>` | — | MCP server connections |
|
|
| `agents` | `Record<string, AgentDefinition>` | — | Subagent definitions |
|
|
| `hooks` | `Record<string, HookCallbackMatcher[]>` | — | 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<string, string>` | — | 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
|
|
|
|
<a href="https://www.star-history.com/?repos=codeany-ai%2Fopen-agent-sdk-typescript&type=timeline&legend=top-left">
|
|
<picture>
|
|
<source media="(prefers-color-scheme: dark)" srcset="https://api.star-history.com/image?repos=codeany-ai/open-agent-sdk-typescript&type=timeline&theme=dark&legend=top-left" />
|
|
<source media="(prefers-color-scheme: light)" srcset="https://api.star-history.com/image?repos=codeany-ai/open-agent-sdk-typescript&type=timeline&legend=top-left" />
|
|
<img alt="Star History Chart" src="https://api.star-history.com/image?repos=codeany-ai/open-agent-sdk-typescript&type=timeline&legend=top-left" />
|
|
</picture>
|
|
</a>
|
|
|
|
## License
|
|
|
|
MIT
|