diff --git a/.github/assets/architecture.svg b/.github/assets/architecture.svg deleted file mode 100644 index 2e00cf0..0000000 --- a/.github/assets/architecture.svg +++ /dev/null @@ -1,220 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - How It Works - - - - YOUR APPLICATION - - - - - Credentials - API keys, env vars - - - - Persistence - Session files, logs - - - - Hosted Tools - Your custom logic - - - - Hooks - 26 lifecycle points - - - - MCP Servers - stdio + HTTP - - - - - - - - createSession() - - - - GENERAL AGENT SDK - - - - - Session Factory - create · resume · fork - list · reset · history - - - - - - - - - - - Agent Execution Loop - - - - - User - - ’ - - - LLM - - ’ - - - Tool - - ’ - - - LLM - - ’ - - -  - - - - - - - Event Stream - assistant_delta · tool_call - hosted_tool_call · turn_complete - - - - TOOLS - - - - - - read - files - - -  - write - create - - - =' - edit - surgical - - - - exec - shell - - - = - web_search - search - - - < - web_fetch - pages - - - > - subagents - delegate - - - - apply_patch - diff - - - - RUNTIME - - - - Context Compaction - Auto-manage context window - - - - File Checkpoints - Auto-rollback on mutations - - - - Hook Runner - 19 SDK-native + 7 host-bridged - - - - LLM Providers - Claude · GPT · Gemini - - - - You own the boundary. The SDK owns the execution. - - diff --git a/.github/assets/event-flow.svg b/.github/assets/event-flow.svg deleted file mode 100644 index 1e6297b..0000000 --- a/.github/assets/event-flow.svg +++ /dev/null @@ -1,106 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - Event Stream Timeline - - - - - - - - - U - - streamTurn() - user message - - - - - - - reasoning - _delta - - - - -  - - assistant - _delta - - - - - =' - - tool_call - built-in or hosted - - - - -  - - tool_result - output returned - - - - loops until done - - - - - - - usage - _snapshot - - - - - - - turn - _complete - - - - - - - - - - - - - for await (const event of session.streamTurn(input)) { ... } - All events delivered via a single AsyncIterable  no callbacks, no observers - - diff --git a/.github/assets/features.svg b/.github/assets/features.svg deleted file mode 100644 index 87eee14..0000000 --- a/.github/assets/features.svg +++ /dev/null @@ -1,66 +0,0 @@ - - - - - - - - - - - - - - - - - - - - Real-time Streaming - Every token, tool call, result as events - - - - =' - 8 Built-in Tools - read · write · exec · web + more - - - - <― - Hosted Tools - Your code, suspend/resume safe - - - - - Multi-turn Memory - Automatic conversation history - - - - - - 26 Lifecycle Hooks - Intercept model, tools, sessions - - - - = - MCP Integration - stdio + HTTP, hot-pluggable - - - - > - Subagent Runtime - Scoped child agents with isolation - - - - =α - Production Ready - Compaction, checkpoints, restart-safe - - diff --git a/.github/assets/hero-banner.svg b/.github/assets/hero-banner.svg deleted file mode 100644 index ca27a1e..0000000 --- a/.github/assets/hero-banner.svg +++ /dev/null @@ -1,131 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - General Agent SDK - - - Build AI agents that actually do things. - - - - - - - - - Streaming - - - Tools - - - Sessions - - - Hooks - - - MCP - - - Subagents - - - - - - v0.1.0 · MIT - - - diff --git a/.github/assets/quick-start-header.svg b/.github/assets/quick-start-header.svg deleted file mode 100644 index 1503345..0000000 --- a/.github/assets/quick-start-header.svg +++ /dev/null @@ -1,21 +0,0 @@ - - - - - - - - - - - - - - - - - - - ‘ Get Started in 60 Seconds - - diff --git a/.github/assets/why-different.svg b/.github/assets/why-different.svg deleted file mode 100644 index e33741e..0000000 --- a/.github/assets/why-different.svg +++ /dev/null @@ -1,82 +0,0 @@ - - - - - - - - - - - - - - - - - - VS - - - Other Agent Frameworks - - - - -  - Chat completion wrappers - - - -  - Framework-owned state you can't control - - - -  - Manual tool loop management - - - -  - Restart = lost state - - - -  - Callback-heavy APIs, hard to reason about - - - - - General Agent SDK - - - - -  - Full autonomous execution engine - - - -  - Host-owned persistence & credentials - - - -  - Agent runs tools autonomously until done - - - -  - Restart-safe hosted tool suspend/resume - - - -  - Single for-await loop, zero callbacks - - - - diff --git a/README.md b/README.md index a6fdf07..75e1640 100644 --- a/README.md +++ b/README.md @@ -1,85 +1,108 @@
- - - - General Agent SDK - +# General Agent SDK -
+### Build AI agents that actually *do things*. -[![npm](https://img.shields.io/npm/v/general-agent-sdk?style=for-the-badge&logo=npm&logoColor=white&color=CB3837&label=)](https://www.npmjs.com/package/general-agent-sdk) -  -[![TypeScript](https://img.shields.io/badge/TypeScript-5.7-3178c6?style=for-the-badge&logo=typescript&logoColor=white)](https://www.typescriptlang.org/) -  -[![License](https://img.shields.io/badge/MIT-license-blue?style=for-the-badge)](./LICENSE) -  -[![Tests](https://img.shields.io/badge/133-tests_passing-22c55e?style=for-the-badge&logo=vitest&logoColor=white)](./tests) -  -[![Node](https://img.shields.io/badge/Node-%E2%89%A522-339933?style=for-the-badge&logo=nodedotjs&logoColor=white)](https://nodejs.org/) +**Stream responses. Call tools. Manage sessions. Ship to production.** -
+[![npm version](https://img.shields.io/npm/v/general-agent-sdk?style=flat-square&color=cb3837&label=npm)](https://www.npmjs.com/package/general-agent-sdk) +[![License: MIT](https://img.shields.io/badge/license-MIT-blue?style=flat-square)](./LICENSE) +[![TypeScript](https://img.shields.io/badge/TypeScript-5.7-3178c6?style=flat-square&logo=typescript&logoColor=white)](https://www.typescriptlang.org/) +[![Node.js](https://img.shields.io/badge/Node.js-%E2%89%A522.14-339933?style=flat-square&logo=nodedotjs&logoColor=white)](https://nodejs.org/) +[![Tests](https://img.shields.io/badge/tests-133%20passing-brightgreen?style=flat-square)](./tests) -**The TypeScript SDK for building AI agents that call tools, manage sessions, and ship to production.** +
-[Quick Start](#-get-started-in-60-seconds) Β· [Architecture](#-architecture) Β· [API Reference](./SDK%20DOCS/API-REFERENCE.md) Β· [Examples](./SDK%20DOCS/) +``` +npm install general-agent-sdk +```
+[Quick Start](#-quick-start) Β· [Examples](./SDK%20DOCS/) Β· [API Reference](./SDK%20DOCS/API-REFERENCE.md) Β· [Documentation](#-documentation) +
- +--- ## Why General Agent SDK? -Most agent frameworks give you **wrappers around chat completions** β€” you manage the tool loop, you track the state, you handle restarts. General Agent SDK gives you a **complete execution kernel**: +Most "agent frameworks" give you wrappers around chat completions. **General Agent SDK gives you a full execution kernel** β€” the agent runs tools autonomously, suspends for human input, resumes across restarts, and streams every event back to your app in real time. -
-
- -Comparison - -

-
- -> **The SDK runs the agent loop for you.** You send a message, the agent autonomously calls tools, reasons about results, calls more tools, and streams every event back β€” until it's done or needs your input. - -
+``` +β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” +β”‚ Your App (Host) β”‚ +β”‚ β”‚ +β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ +β”‚ β”‚ General Agent SDK β”‚ β”‚ +β”‚ β”‚ β”‚ β”‚ +β”‚ β”‚ User ──→ LLM ──→ Tool ──→ LLM ──→ Tool ──→ βœ… β”‚ β”‚ +β”‚ β”‚ β”‚ ↑ β”‚ ↑ β”‚ β”‚ +β”‚ β”‚ β”‚ built-in β”‚ hosted tool β”‚ β”‚ +β”‚ β”‚ β”‚ (read, exec, β”‚ (your code) β”‚ β”‚ +β”‚ β”‚ β”‚ web_search) β”‚ β”‚ β”‚ +β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ +β”‚ β”‚ └── stream events back to host ──→ β”‚ β”‚ +β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ +β”‚ β”‚ +β”‚ You control: credentials, persistence, tools, hooks β”‚ +β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ +``` - + + + + + +
-
+### What it does -Features +- **Autonomous tool loops** β€” agent calls tools and continues thinking until done +- **8 built-in tools** β€” `read`, `write`, `edit`, `exec`, `web_search`, `web_fetch`, `apply_patch`, `subagents` +- **Hosted tools** β€” define your own tools, SDK suspends & resumes +- **Multi-turn memory** β€” sessions remember across turns automatically +- **Real-time streaming** β€” every token, tool call, and result as events +- **MCP integration** β€” plug in any MCP server (stdio or HTTP) +- **26 lifecycle hooks** β€” intercept anything from model selection to tool execution +- **Subagent delegation** β€” spawn child agents with scoped instructions -
+
-
+### What makes it different - +- **Not a wrapper** β€” it's a complete agent execution engine +- **Host-owned** β€” you control persistence, credentials, and policy +- **Restart-safe** β€” hosted tool pauses survive process restarts +- **Production-ready** β€” context compaction, file checkpoints, error boundaries +- **Type-safe** β€” full TypeScript with zero `any` in public API +- **Tested** β€” 133 tests + real API E2E verification +- **Lightweight** β€” ~180KB packaged, 6 dependencies +- **Escape hatch friendly** β€” use as much or as little as you need -
+
-Quick Start +--- - +## ⚑ Quick Start -### Step 1 β€” Install +### 1. Install ```bash npm install general-agent-sdk ``` -### Step 2 β€” Set your API key +### 2. Set your API key ```bash export ANTHROPIC_API_KEY="sk-ant-..." -# Optional: use a custom endpoint +# Optional: use a proxy # export ANTHROPIC_BASE_URL="https://your-proxy.example.com" ``` -### Step 3 β€” Run your first agent +### 3. Build your first agent ```typescript import { createGeneralAgentSdk } from "general-agent-sdk"; @@ -87,14 +110,16 @@ import { randomUUID } from "node:crypto"; import path from "node:path"; import os from "node:os"; -// 1. Initialize +// Initialize the SDK const sdk = await createGeneralAgentSdk({ workspaceDir: process.cwd(), - stateDir: path.join(process.cwd(), ".agent-state"), - agentDir: path.join(process.cwd(), ".agent"), - profileId: "default", - pluginMode: "disabled", - logger: { onDebug() {}, onInfo() {}, onWarn() {}, onError() {} }, + stateDir: path.join(process.cwd(), ".agent-state"), + agentDir: path.join(process.cwd(), ".agent"), + profileId: "default", + pluginMode: "disabled", + logger: { + onDebug() {}, onInfo() {}, onWarn() {}, onError() {}, + }, sessionStore: { async load() { return null; }, async save() {}, @@ -104,225 +129,198 @@ const sdk = await createGeneralAgentSdk({ }, }); -// 2. Create a session +// Create a session const session = sdk.createSession({ - identity: { mode: "general", sessionId: randomUUID(), sessionKey: "demo" }, - systemPrompt: "You are a helpful assistant. Use tools when needed.", - modelRef: "claude-sonnet-4-20250514", - sessionFile: path.join(os.tmpdir(), "demo-session.jsonl"), + identity: { mode: "general", sessionId: randomUUID(), sessionKey: "my-app:default" }, + systemPrompt: "You are a helpful assistant.", + modelRef: "claude-sonnet-4-20250514", + sessionFile: path.join(os.tmpdir(), "session.jsonl"), }); -// 3. Stream a turn β€” the agent calls tools autonomously +// Stream a conversation for await (const event of session.streamTurn({ role: "user", - content: [{ type: "text", text: "List the files in the current directory" }], + content: [{ type: "text", text: "What files are in the current directory?" }], })) { switch (event.kind) { - case "assistant_delta": process.stdout.write(event.text); break; - case "tool_call": console.log(`\nπŸ”§ ${event.toolName}`); break; - case "tool_result": console.log(` βœ… done`); break; - case "turn_complete": console.log(`\n\n🏁 Turn complete (${event.stopReason})`); break; + case "assistant_delta": + process.stdout.write(event.text); + break; + case "tool_call": + console.log(`\nπŸ”§ ${event.toolName}(${JSON.stringify(event.input)})`); + break; + case "tool_result": + console.log(`βœ… Done`); + break; + case "turn_complete": + console.log(`\n\nβœ… Finished (${event.stopReason})`); + break; } } await sdk.shutdown(); ``` -> **That's it.** The agent autonomously reads the directory, reasons about the output, and streams a formatted answer β€” all in one `for await` loop. - -
+**That's it.** The agent will autonomously read the directory, think about the results, and give you a formatted answer β€” all streamed in real time. --- - - ## 🎯 Core Concepts ### The Event Stream -Every turn returns an `AsyncIterable`. No callbacks, no observers β€” one loop handles everything: - -
-
- -Event Flow - -

-
+Every interaction returns an `AsyncIterable`. No callbacks, no observers β€” just a `for await` loop: ```typescript for await (const event of session.streamTurn(input)) { - switch (event.kind) { - case "assistant_delta": // β†’ streaming text from the model - case "reasoning_delta": // β†’ model thinking (extended thinking) - case "tool_call": // β†’ built-in tool invoked - case "tool_result": // β†’ tool returned a result - case "hosted_tool_call": // β†’ YOUR tool was requested β€” SDK suspends ⏸️ - case "usage_snapshot": // β†’ token usage update - case "turn_complete": // β†’ this turn is done βœ… - } + // event.kind tells you what happened: + // + // "assistant_delta" β†’ streaming text chunk + // "reasoning_delta" β†’ model thinking (extended thinking) + // "tool_call" β†’ agent is calling a built-in tool + // "tool_result" β†’ tool returned a result + // "hosted_tool_call" β†’ YOUR tool was requested (SDK suspends) + // "usage_snapshot" β†’ token usage update + // "turn_complete" β†’ this turn is done } ``` ---- - -### 🎯 Hosted Tools β€” Your Code, The Model's Brain +### Hosted Tools β€” Your Code, Their Brain -Define tools the AI can call. You implement the logic; the SDK orchestrates the lifecycle: +Define tools that the AI can call. **You implement the logic**, the SDK handles the orchestration: ```typescript const sdk = await createGeneralAgentSdk({ - // ... - hostedTools: [{ - name: "get_weather", - description: "Get current weather for a city", - inputSchema: { - type: "object", - properties: { city: { type: "string" } }, - required: ["city"], + // ... other options ... + hostedTools: [ + { + name: "get_stock_price", + description: "Get real-time stock price", + inputSchema: { + type: "object", + properties: { symbol: { type: "string" } }, + required: ["symbol"], + }, }, - }], + ], }); -for await (const event of session.streamTurn(userMsg)) { +// Handle tool calls +for await (const event of session.streamTurn(userMessage)) { if (event.kind === "hosted_tool_call") { - // SDK suspends automatically ⏸️ - const weather = await getWeather(event.input.city); + // SDK automatically suspends here ⏸️ + + // You execute your logic + const price = await fetchStockPrice(event.input.symbol); - // Resume with your result ▢️ - for await (const e of session.submitHostedToolResult({ + // Resume the agent with the result ▢️ + for await (const resumed of session.submitHostedToolResult({ callId: event.callId, - output: weather, + output: { price, currency: "USD" }, })) { - if (e.kind === "assistant_delta") process.stdout.write(e.text); + if (resumed.kind === "assistant_delta") process.stdout.write(resumed.text); } break; } } ``` -> **Restart-safe:** Hosted tool pauses survive process restarts. The SDK snapshots context and resumes correctly β€” even with multi-tool parallel calls. - ---- - -### πŸ’¬ Multi-Turn Memory +### Multi-Turn Sessions -Sessions automatically maintain conversation history: +Sessions automatically maintain conversation history. The agent remembers everything: ```typescript // Turn 1 -for await (const e of session.streamTurn({ +await consume(session.streamTurn({ role: "user", - content: [{ type: "text", text: "My name is Alice. I'm building a TypeScript app." }], -})) { /* ... */ } + content: [{ type: "text", text: "My name is Alice and I like TypeScript." }], +})); -// Turn 2 β€” the agent remembers everything -for await (const e of session.streamTurn({ +// Turn 2 β€” the agent remembers! +await consume(session.streamTurn({ role: "user", - content: [{ type: "text", text: "What's my name and what am I building?" }], -})) { /* ... */ } -// ➜ "Your name is Alice and you're building a TypeScript app." + content: [{ type: "text", text: "What's my name and what do I like?" }], +})); +// β†’ "Your name is Alice and you like TypeScript." ``` ---- - -### πŸͺ Hooks β€” Intercept Everything +### Hooks β€” Intercept Everything -26 hooks let you observe, modify, or block any lifecycle event: +26 hooks let you observe, modify, or block any part of the agent lifecycle: ```typescript const sdk = await createGeneralAgentSdk({ + // ... hooks: [ - // πŸ”€ Dynamic model routing + // Dynamically switch models { pluginId: "my-app", hookName: "before_model_resolve", - handler: (ev) => ({ - modelOverride: needsPower(ev) ? "claude-opus-4-20250514" : "claude-sonnet-4-20250514", + handler: (event) => ({ + modelOverride: isComplexTask(event.prompt) + ? "claude-opus-4-20250514" + : "claude-sonnet-4-20250514", }), }, - - // πŸ›‘οΈ Safety guardrails + // Block dangerous tool calls { pluginId: "my-app", hookName: "before_tool_call", - handler: (ev) => { - if (ev.toolName === "exec" && ev.params.command?.includes("rm -rf")) + handler: (event) => { + if (event.toolName === "exec" && event.params.command?.includes("rm -rf")) { return { block: true, blockReason: "Dangerous command blocked" }; + } }, }, - - // πŸ“Š Usage audit trail + // Audit all LLM calls { pluginId: "my-app", hookName: "llm_output", - handler: (ev) => { - db.insert({ model: ev.model, tokens: ev.usage?.input + ev.usage?.output }); + handler: (event) => { + console.log(`[audit] ${event.model}: ${event.usage?.input}in/${event.usage?.output}out tokens`); }, }, ], }); ``` -
-πŸ“‹ Full hook reference (19 SDK-native + 7 host-bridged) - -
+--- -**SDK-native hooks** β€” auto-fired by the runtime: - -| Hook | Modifiable | Fires when... | -|:-----|:---:|:---| -| `before_model_resolve` | βœ… | Model selection begins | -| `before_prompt_build` | βœ… | System prompt is being assembled | -| `before_agent_start` | βœ… | Agent run is about to begin | -| `llm_input` | β€” | Request sent to LLM | -| `llm_output` | β€” | Response received from LLM | -| `agent_end` | β€” | Agent run completed | -| `before_tool_call` | βœ… | Tool is about to execute | -| `after_tool_call` | β€” | Tool execution finished | -| `tool_result_persist` | βœ… | Tool result being saved to transcript | -| `before_message_write` | βœ… | Message being written to history | -| `session_start` | β€” | Session first activated | -| `session_end` | β€” | Session completed | -| `before_compaction` | β€” | Context compaction starting | -| `after_compaction` | β€” | Context compaction finished | -| `before_reset` | β€” | Session about to clear | -| `subagent_spawning` | βœ… | Child agent creation requested | -| `subagent_delivery_target` | βœ… | Routing child agent delivery | -| `subagent_spawned` | β€” | Child agent created | -| `subagent_ended` | β€” | Child agent finished | +## 🧰 Built-in Tools -**Host-bridged hooks** β€” you trigger these via `sdk.emitHook()`: +The agent comes pre-loaded with powerful tools: -| Hook | Purpose | -|:-----|:--------| -| `inbound_claim` | Incoming message routing | -| `before_dispatch` | Pre-dispatch filtering | -| `message_received` | Message arrival notification | -| `message_sending` | Modify/cancel outgoing messages | -| `message_sent` | Delivery confirmation | -| `gateway_start` | Gateway lifecycle start | -| `gateway_stop` | Gateway shutdown | +| Tool | What it does | +|------|-------------| +| `read` | Read file contents (with line ranges) | +| `write` | Create or overwrite files | +| `edit` | Surgical file edits with diff | +| `apply_patch` | Apply unified diffs | +| `exec` | Run shell commands | +| `web_search` | Search the web (DuckDuckGo / Brave) | +| `web_fetch` | Fetch and parse web pages | +| `subagents` | Delegate tasks to child agents | -
+The agent decides which tools to use. You can restrict available tools per session, and every tool call flows through the `before_tool_call` / `after_tool_call` hooks. --- -### πŸ”Œ MCP Integration +## πŸ”Œ MCP Integration -Plug in any [Model Context Protocol](https://modelcontextprotocol.io/) server β€” tools appear alongside built-ins: +Plug in any [Model Context Protocol](https://modelcontextprotocol.io/) server: ```typescript +// Local process session.setDynamicMcpServers({ - // Local process (stdio) filesystem: { transport: "stdio", command: "npx", args: ["-y", "@modelcontextprotocol/server-filesystem", "/data"], }, +}); - // Remote endpoint (HTTP) +// Remote HTTP endpoint +session.setDynamicMcpServers({ my_api: { transport: "http", url: "https://mcp.example.com/api", @@ -331,190 +329,222 @@ session.setDynamicMcpServers({ }); ``` +MCP tools show up alongside built-in tools. The agent uses them seamlessly. + --- -### πŸ€– Subagents +## πŸ€– Subagents -The agent can spawn scoped child agents to divide and conquer complex tasks: +The agent can spawn child agents to divide and conquer: ```typescript const session = sdk.createSession({ - systemPrompt: `You are a tech lead. Delegate tasks using the subagents tool.`, // ... + systemPrompt: `You are a project manager. + Use the subagents tool to delegate tasks to specialists.`, }); // The agent will autonomously: -// 1. Analyze the task -// 2. Spawn child agents with scoped instructions + tools -// 3. Collect results from each child +// 1. Break the task into subtasks +// 2. Spawn child agents with scoped instructions +// 3. Collect results // 4. Synthesize a final answer ``` -Each child gets **independent message history** and **scoped tool access**. The `subagents` tool is excluded from children to prevent infinite recursion. Four lifecycle hooks fire automatically: `subagent_spawning` β†’ `subagent_spawned` β†’ `subagent_ended`. +Each subagent gets its own independent message history and scoped tool access. The `subagents` tool is excluded from children to prevent infinite recursion. --- -### πŸ“Š Session Management +## πŸ“Š Session Management ```typescript -const session = sdk.createSession({ ... }); // Create -const resumed = await sdk.resumeSession("sess-123"); // Resume -const forked = await sdk.forkSession("sess-123", { // Fork - identity: { ... }, -}); -const sessions = await sdk.listSessions(); // List all -const history = await sdk.readSessionHistory("id"); // Read transcript -await session.reset("context_overflow"); // Reset -const usage = session.getUsageSnapshot(); // Token usage +// Create +const session = sdk.createSession({ ... }); + +// Resume by ID +const resumed = await sdk.resumeSession("session-123"); + +// Fork (branch from existing conversation) +const forked = await sdk.forkSession("session-123", { ... }); + +// List all sessions +const sessions = await sdk.listSessions(); + +// Read transcript history +const history = await sdk.readSessionHistory("session-123"); + +// Reset (clear history, keep config) +await session.reset("starting_fresh"); + +// Check token usage +const usage = session.getUsageSnapshot(); +// β†’ { usedInputTokens: 1234, contextWindow: 200000, usedPct: 0.6 } ``` -**Context Compaction** β€” long conversations don't overflow: +### Context Compaction + +Long conversations don't overflow β€” the SDK compacts automatically: ```typescript await session.maybeCompactByTokens({ - usedPctThreshold: 85, // trigger at 85% context usage + usedPctThreshold: 85, // trigger at 85% usage cooldownMs: 60_000, // min 60s between compactions }); ``` -**File Checkpoints** β€” every write creates an automatic rollback point: +### File Checkpoints + +Every file write creates an automatic checkpoint. Roll back anytime: ```typescript const checkpoints = await session.listCheckpoints(); await session.restoreCheckpoint(checkpoints[0].id); ``` -
- --- - +## πŸ“– Documentation -## πŸ— Architecture +| Resource | Description | +|----------|-------------| +| [`SDK DOCS/README.md`](./SDK%20DOCS/README.md) | Full documentation index | +| [`SDK DOCS/API-REFERENCE.md`](./SDK%20DOCS/API-REFERENCE.md) | Complete API reference | +| [`SDK DOCS/01-hello-world.ts`](./SDK%20DOCS/01-hello-world.ts) | Your first agent | +| [`SDK DOCS/02-multi-turn-chat.ts`](./SDK%20DOCS/02-multi-turn-chat.ts) | Interactive multi-turn REPL | +| [`SDK DOCS/03-hosted-tools.ts`](./SDK%20DOCS/03-hosted-tools.ts) | Custom tool integration | +| [`SDK DOCS/04-session-lifecycle.ts`](./SDK%20DOCS/04-session-lifecycle.ts) | Session management | +| [`SDK DOCS/05-hooks.ts`](./SDK%20DOCS/05-hooks.ts) | Lifecycle hooks | +| [`SDK DOCS/06-mcp-servers.ts`](./SDK%20DOCS/06-mcp-servers.ts) | MCP server integration | +| [`SDK DOCS/07-compaction.ts`](./SDK%20DOCS/07-compaction.ts) | Context window management | +| [`SDK DOCS/08-subagents.ts`](./SDK%20DOCS/08-subagents.ts) | Subagent delegation | -
-
+All examples are **runnable** β€” just set your API key and go: -Architecture +```bash +export ANTHROPIC_API_KEY="sk-ant-..." +npx tsx "SDK DOCS/01-hello-world.ts" +``` -

-
+--- -
-πŸ“ Repository structure +## πŸ—οΈ Architecture ``` general-agent-sdk/ β”œβ”€β”€ src/ -β”‚ β”œβ”€β”€ index.ts β†’ Package entry point -β”‚ β”œβ”€β”€ public/ β†’ Stable public API surface -β”‚ β”‚ β”œβ”€β”€ sdk.ts β†’ createGeneralAgentSdk() -β”‚ β”‚ β”œβ”€β”€ session.ts β†’ GeneralAgentSession -β”‚ β”‚ β”œβ”€β”€ events.ts β†’ GeneralAgentStreamEvent -β”‚ β”‚ β”œβ”€β”€ hooks.ts β†’ 26 hook type definitions -β”‚ β”‚ β”œβ”€β”€ types.ts β†’ Shared types -β”‚ β”‚ β”œβ”€β”€ host-tools.ts β†’ Hosted tool definitions -β”‚ β”‚ └── persistence.ts β†’ Storage adapter interface -β”‚ β”œβ”€β”€ core/ -β”‚ β”‚ β”œβ”€β”€ embedded-runner/ β†’ Session factory + runtime -β”‚ β”‚ β”œβ”€β”€ compaction/ β†’ Context window compaction -β”‚ β”‚ β”œβ”€β”€ mcp/ β†’ MCP client (stdio + HTTP) -β”‚ β”‚ β”œβ”€β”€ model/ β†’ Model context window resolution -β”‚ β”‚ β”œβ”€β”€ plugins/ β†’ Hook runner engine -β”‚ β”‚ β”œβ”€β”€ sessions/ β†’ Metadata index + transcript repair -β”‚ β”‚ └── checkpoints/ β†’ File checkpoint manager -β”‚ β”œβ”€β”€ tools/ β†’ Built-in tool implementations -β”‚ β”œβ”€β”€ loop/ β†’ Agent execution loop -β”‚ └── providers/ β†’ LLM provider adapters -β”œβ”€β”€ SDK DOCS/ β†’ Runnable examples + API reference -β”œβ”€β”€ tests/ β†’ 133 tests (unit / integration / contract / e2e) -└── manifests/ β†’ Upstream provenance tracking +β”‚ β”œβ”€β”€ index.ts β†’ Package entry point +β”‚ β”œβ”€β”€ public/ β†’ Stable public API types +β”‚ β”‚ β”œβ”€β”€ sdk.ts β†’ createGeneralAgentSdk() +β”‚ β”‚ β”œβ”€β”€ session.ts β†’ GeneralAgentSession interface +β”‚ β”‚ β”œβ”€β”€ events.ts β†’ Stream event types +β”‚ β”‚ β”œβ”€β”€ hooks.ts β†’ 26 hook definitions +β”‚ β”‚ β”œβ”€β”€ types.ts β†’ Shared types +β”‚ β”‚ β”œβ”€β”€ host-tools.ts β†’ Hosted tool types +β”‚ β”‚ └── persistence.ts β†’ Storage adapter +β”‚ β”œβ”€β”€ core/ β†’ Runtime implementation +β”‚ β”‚ β”œβ”€β”€ embedded-runner/ β†’ Session + factory +β”‚ β”‚ β”œβ”€β”€ compaction/ β†’ Context compaction +β”‚ β”‚ β”œβ”€β”€ mcp/ β†’ MCP client (stdio + http) +β”‚ β”‚ β”œβ”€β”€ model/ β†’ Model context windows +β”‚ β”‚ β”œβ”€β”€ plugins/ β†’ Hook runner +β”‚ β”‚ β”œβ”€β”€ sessions/ β†’ Metadata + transcript repair +β”‚ β”‚ └── checkpoints/ β†’ File checkpoint manager +β”‚ β”œβ”€β”€ tools/ β†’ Built-in tool implementations +β”‚ β”œβ”€β”€ loop/ β†’ Agent execution loop +β”‚ └── providers/ β†’ LLM provider adapters +β”œβ”€β”€ SDK DOCS/ β†’ Examples + API reference +β”œβ”€β”€ tests/ β†’ 133 tests (unit/integration/contract/e2e) +└── manifests/ β†’ Upstream provenance tracking ``` -
- ---- - -## πŸ“‹ Event Reference - -| Event | Payload | Description | -|:------|:--------|:------------| -| `assistant_delta` | `{ text }` | Streaming text chunk from the model | -| `reasoning_delta` | `{ text }` | Extended thinking (chain-of-thought) | -| `reasoning_end` | β€” | Thinking phase complete | -| `tool_call` | `{ callId, toolName, input }` | Built-in tool invoked by the agent | -| `tool_result` | `{ callId, toolName, output }` | Tool execution result | -| `tool_error` | `{ callId, toolName, error }` | Tool execution failed | -| `hosted_tool_call` | `{ callId, toolName, input }` | **Your** tool requested β€” SDK suspends | -| `usage_snapshot` | `{ snapshot }` | Token usage update | -| `compaction_started` | `{ reason }` | Context compaction in progress | -| `compaction_finished` | `{ reason, tokensAfter? }` | Compaction complete | -| `turn_complete` | `{ stopReason }` | Turn finished | - --- -## 🧰 Built-in Tools +## πŸ”§ Development -| Tool | Description | Category | -|:-----|:------------|:---------| -| `read` | Read file contents with optional line ranges | File I/O | -| `write` | Create or overwrite files | File I/O | -| `edit` | Surgical string-replace edits | File I/O | -| `apply_patch` | Apply unified diff patches | File I/O | -| `exec` | Execute shell commands | System | -| `web_search` | Search the web (Brave / DuckDuckGo) | Web | -| `web_fetch` | Fetch and parse web pages | Web | -| `subagents` | Spawn scoped child agents | Orchestration | +```bash +# Install +pnpm install ---- +# Type check +pnpm run check -## πŸ“– Examples +# Build +pnpm run build -All examples are **runnable** TypeScript files: +# Run tests +pnpm run test # 133 unit + integration tests +pnpm run test:e2e # package smoke test -```bash -export ANTHROPIC_API_KEY="sk-ant-..." -npx tsx "SDK DOCS/01-hello-world.ts" +# Verify upstream provenance +node scripts/verify-upstream-snapshot.mjs ``` -| # | Example | What it covers | -|:--|:--------|:---------------| -| 01 | [`hello-world.ts`](./SDK%20DOCS/01-hello-world.ts) | Minimal agent, first `streamTurn()` call | -| 02 | [`multi-turn-chat.ts`](./SDK%20DOCS/02-multi-turn-chat.ts) | Interactive REPL with memory | -| 03 | [`hosted-tools.ts`](./SDK%20DOCS/03-hosted-tools.ts) | Custom tool with suspend/resume | -| 04 | [`session-lifecycle.ts`](./SDK%20DOCS/04-session-lifecycle.ts) | Create, resume, fork, reset | -| 05 | [`hooks.ts`](./SDK%20DOCS/05-hooks.ts) | Lifecycle hooks in action | -| 06 | [`mcp-servers.ts`](./SDK%20DOCS/06-mcp-servers.ts) | Dynamic MCP integration | -| 07 | [`compaction.ts`](./SDK%20DOCS/07-compaction.ts) | Context window management | -| 08 | [`subagents.ts`](./SDK%20DOCS/08-subagents.ts) | Child agent delegation | - -> πŸ“š Full API documentation: [`SDK DOCS/API-REFERENCE.md`](./SDK%20DOCS/API-REFERENCE.md) - --- -## πŸ”§ Development +## πŸ“‹ Event Reference -```bash -pnpm install # Install dependencies -pnpm run check # Type check -pnpm run build # Build -pnpm run test # 133 unit + integration tests -pnpm run test:e2e # Package smoke test -node scripts/verify-upstream-snapshot.mjs # Verify provenance -``` +| Event | Payload | When | +|-------|---------|------| +| `assistant_delta` | `{ text }` | Each streaming text chunk | +| `reasoning_delta` | `{ text }` | Model thinking (extended thinking) | +| `reasoning_end` | β€” | Thinking complete | +| `tool_call` | `{ callId, toolName, input }` | Built-in tool invoked | +| `tool_result` | `{ callId, toolName, output }` | Tool returned result | +| `tool_error` | `{ callId, toolName, error }` | Tool failed | +| `hosted_tool_call` | `{ callId, toolName, input }` | Your tool requested (SDK suspends) | +| `usage_snapshot` | `{ snapshot }` | Token usage update | +| `compaction_started` | `{ reason }` | Context compaction begins | +| `compaction_finished` | `{ reason, tokensAfter? }` | Compaction complete | +| `turn_complete` | `{ stopReason }` | Turn finished | --- -
+## πŸͺ Hook Reference -
+
+19 SDK-native hooks (auto-fired by runtime) + +| Hook | Can modify? | Description | +|------|:-----------:|-------------| +| `before_model_resolve` | βœ… | Override model selection | +| `before_prompt_build` | βœ… | Inject context into prompts | +| `before_agent_start` | βœ… | Final pre-run modifications | +| `llm_input` | β€” | Observe LLM request | +| `llm_output` | β€” | Observe LLM response + usage | +| `agent_end` | β€” | Run completed | +| `before_tool_call` | βœ… | Modify args or block execution | +| `after_tool_call` | β€” | Observe tool result | +| `tool_result_persist` | βœ… | Modify persisted tool result | +| `before_message_write` | βœ… | Modify or block transcript writes | +| `session_start` | β€” | Session first used | +| `session_end` | β€” | Session done | +| `before_compaction` | β€” | Compaction starting | +| `after_compaction` | β€” | Compaction finished | +| `before_reset` | β€” | Session about to reset | +| `subagent_spawning` | βœ… | Block subagent creation | +| `subagent_delivery_target` | βœ… | Override delivery routing | +| `subagent_spawned` | β€” | Child agent created | +| `subagent_ended` | β€” | Child agent finished | -**MIT** Β· Built by [BabelCloud](https://github.com/babelcloud) +
-
+
+7 Host-bridged hooks (triggered via sdk.emitHook()) + +| Hook | Description | +|------|-------------| +| `inbound_claim` | Incoming message routing | +| `before_dispatch` | Pre-dispatch filtering | +| `message_received` | Message received | +| `message_sending` | Modify/cancel outgoing messages | +| `message_sent` | Message delivery confirmation | +| `gateway_start` | Gateway lifecycle | +| `gateway_stop` | Gateway shutdown | -If this project helps you build something cool, give it a ⭐ β€” it helps others find it too. +
+ +--- -

+## License -
+[MIT](./LICENSE) β€” built by [BabelCloud](https://github.com/babelcloud)