@codeany/open-agent-sdk 0.1.0 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +144 -31
- package/examples/12-skills.ts +88 -0
- package/examples/13-hooks.ts +88 -0
- package/examples/14-openai-compat.ts +71 -0
- package/package.json +1 -1
- package/src/agent.ts +106 -15
- package/src/engine.ts +169 -59
- package/src/index.ts +51 -1
- package/src/providers/anthropic.ts +60 -0
- package/src/providers/index.ts +34 -0
- package/src/providers/openai.ts +315 -0
- package/src/providers/types.ts +85 -0
- package/src/session.ts +5 -5
- package/src/skills/bundled/commit.ts +38 -0
- package/src/skills/bundled/debug.ts +48 -0
- package/src/skills/bundled/index.ts +28 -0
- package/src/skills/bundled/review.ts +41 -0
- package/src/skills/bundled/simplify.ts +51 -0
- package/src/skills/bundled/test.ts +43 -0
- package/src/skills/index.ts +25 -0
- package/src/skills/registry.ts +133 -0
- package/src/skills/types.ts +99 -0
- package/src/tools/agent-tool.ts +13 -2
- package/src/tools/index.ts +8 -0
- package/src/tools/skill-tool.ts +133 -0
- package/src/tools/types.ts +7 -3
- package/src/types.ts +35 -8
- package/src/utils/compact.ts +18 -17
- package/src/utils/messages.ts +12 -13
- package/src/utils/tokens.ts +29 -6
package/README.md
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
[](https://nodejs.org)
|
|
5
5
|
[](./LICENSE)
|
|
6
6
|
|
|
7
|
-
Open-source Agent SDK that runs the full agent loop **in-process** — no subprocess or CLI required. Deploy anywhere: cloud, serverless, Docker, CI/CD.
|
|
7
|
+
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.
|
|
8
8
|
|
|
9
9
|
Also available in **Go**: [open-agent-sdk-go](https://github.com/codeany-ai/open-agent-sdk-go)
|
|
10
10
|
|
|
@@ -20,7 +20,18 @@ Set your API key:
|
|
|
20
20
|
export CODEANY_API_KEY=your-api-key
|
|
21
21
|
```
|
|
22
22
|
|
|
23
|
-
|
|
23
|
+
### OpenAI-compatible models
|
|
24
|
+
|
|
25
|
+
Works with OpenAI, DeepSeek, Qwen, Mistral, or any OpenAI-compatible endpoint:
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
export CODEANY_API_TYPE=openai-completions
|
|
29
|
+
export CODEANY_API_KEY=sk-...
|
|
30
|
+
export CODEANY_BASE_URL=https://api.openai.com/v1
|
|
31
|
+
export CODEANY_MODEL=gpt-4o
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
### Third-party Anthropic-compatible providers
|
|
24
35
|
|
|
25
36
|
```bash
|
|
26
37
|
export CODEANY_BASE_URL=https://openrouter.ai/api
|
|
@@ -64,6 +75,24 @@ console.log(
|
|
|
64
75
|
);
|
|
65
76
|
```
|
|
66
77
|
|
|
78
|
+
### OpenAI / GPT models
|
|
79
|
+
|
|
80
|
+
```typescript
|
|
81
|
+
import { createAgent } from "@codeany/open-agent-sdk";
|
|
82
|
+
|
|
83
|
+
const agent = createAgent({
|
|
84
|
+
apiType: "openai-completions",
|
|
85
|
+
model: "gpt-4o",
|
|
86
|
+
apiKey: "sk-...",
|
|
87
|
+
baseURL: "https://api.openai.com/v1",
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
const result = await agent.prompt("What files are in this project?");
|
|
91
|
+
console.log(result.text);
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
The `apiType` is auto-detected from model name — models containing `gpt-`, `o1`, `o3`, `deepseek`, `qwen`, `mistral`, etc. automatically use `openai-completions`.
|
|
95
|
+
|
|
67
96
|
### Multi-turn conversation
|
|
68
97
|
|
|
69
98
|
```typescript
|
|
@@ -137,6 +166,66 @@ const r = await agent.prompt("Calculate 2**10 * 3");
|
|
|
137
166
|
console.log(r.text);
|
|
138
167
|
```
|
|
139
168
|
|
|
169
|
+
### Skills
|
|
170
|
+
|
|
171
|
+
Skills are reusable prompt templates that extend agent capabilities. Five bundled skills are included: `simplify`, `commit`, `review`, `debug`, `test`.
|
|
172
|
+
|
|
173
|
+
```typescript
|
|
174
|
+
import {
|
|
175
|
+
createAgent,
|
|
176
|
+
registerSkill,
|
|
177
|
+
getAllSkills,
|
|
178
|
+
} from "@codeany/open-agent-sdk";
|
|
179
|
+
|
|
180
|
+
// Register a custom skill
|
|
181
|
+
registerSkill({
|
|
182
|
+
name: "explain",
|
|
183
|
+
description: "Explain a concept in simple terms",
|
|
184
|
+
userInvocable: true,
|
|
185
|
+
async getPrompt(args) {
|
|
186
|
+
return [
|
|
187
|
+
{
|
|
188
|
+
type: "text",
|
|
189
|
+
text: `Explain in simple terms: ${args || "Ask what to explain."}`,
|
|
190
|
+
},
|
|
191
|
+
];
|
|
192
|
+
},
|
|
193
|
+
});
|
|
194
|
+
|
|
195
|
+
console.log(`${getAllSkills().length} skills registered`);
|
|
196
|
+
|
|
197
|
+
// The model can invoke skills via the Skill tool
|
|
198
|
+
const agent = createAgent();
|
|
199
|
+
const result = await agent.prompt('Use the "explain" skill to explain git rebase');
|
|
200
|
+
console.log(result.text);
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
### Hooks (lifecycle events)
|
|
204
|
+
|
|
205
|
+
```typescript
|
|
206
|
+
import { createAgent, createHookRegistry } from "@codeany/open-agent-sdk";
|
|
207
|
+
|
|
208
|
+
const hooks = createHookRegistry({
|
|
209
|
+
PreToolUse: [
|
|
210
|
+
{
|
|
211
|
+
handler: async (input) => {
|
|
212
|
+
console.log(`About to use: ${input.toolName}`);
|
|
213
|
+
// Return { block: true } to prevent tool execution
|
|
214
|
+
},
|
|
215
|
+
},
|
|
216
|
+
],
|
|
217
|
+
PostToolUse: [
|
|
218
|
+
{
|
|
219
|
+
handler: async (input) => {
|
|
220
|
+
console.log(`Tool ${input.toolName} completed`);
|
|
221
|
+
},
|
|
222
|
+
},
|
|
223
|
+
],
|
|
224
|
+
});
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
20 lifecycle events: `PreToolUse`, `PostToolUse`, `PostToolUseFailure`, `SessionStart`, `SessionEnd`, `Stop`, `SubagentStart`, `SubagentStop`, `UserPromptSubmit`, `PermissionRequest`, `PermissionDenied`, `TaskCreated`, `TaskCompleted`, `ConfigChange`, `CwdChanged`, `FileChanged`, `Notification`, `PreCompact`, `PostCompact`, `TeammateIdle`.
|
|
228
|
+
|
|
140
229
|
### MCP server integration
|
|
141
230
|
|
|
142
231
|
```typescript
|
|
@@ -214,9 +303,12 @@ npx tsx examples/web/server.ts
|
|
|
214
303
|
| `tool(name, desc, schema, handler)` | Create a tool with Zod schema validation |
|
|
215
304
|
| `createSdkMcpServer({ name, tools })` | Bundle tools into an in-process MCP server |
|
|
216
305
|
| `defineTool(config)` | Low-level tool definition helper |
|
|
217
|
-
| `getAllBaseTools()` | Get all
|
|
306
|
+
| `getAllBaseTools()` | Get all 35+ built-in tools |
|
|
307
|
+
| `registerSkill(definition)` | Register a custom skill |
|
|
308
|
+
| `getAllSkills()` | Get all registered skills |
|
|
309
|
+
| `createProvider(apiType, opts)` | Create an LLM provider directly |
|
|
310
|
+
| `createHookRegistry(config)` | Create a hook registry for lifecycle events |
|
|
218
311
|
| `listSessions()` | List persisted sessions |
|
|
219
|
-
| `getSessionMessages(id)` | Retrieve messages from a session |
|
|
220
312
|
| `forkSession(id)` | Fork a session for branching |
|
|
221
313
|
|
|
222
314
|
### Agent methods
|
|
@@ -230,12 +322,14 @@ npx tsx examples/web/server.ts
|
|
|
230
322
|
| `agent.interrupt()` | Abort current query |
|
|
231
323
|
| `agent.setModel(model)` | Change model mid-session |
|
|
232
324
|
| `agent.setPermissionMode(mode)` | Change permission mode |
|
|
325
|
+
| `agent.getApiType()` | Get current API type |
|
|
233
326
|
| `agent.close()` | Close MCP connections, persist session |
|
|
234
327
|
|
|
235
328
|
### Options
|
|
236
329
|
|
|
237
330
|
| Option | Type | Default | Description |
|
|
238
331
|
| -------------------- | --------------------------------------- | ---------------------- | -------------------------------------------------------------------- |
|
|
332
|
+
| `apiType` | `string` | auto-detected | `'anthropic-messages'` or `'openai-completions'` |
|
|
239
333
|
| `model` | `string` | `claude-sonnet-4-6` | LLM model ID |
|
|
240
334
|
| `apiKey` | `string` | `CODEANY_API_KEY` | API key |
|
|
241
335
|
| `baseURL` | `string` | — | Custom API endpoint |
|
|
@@ -266,12 +360,13 @@ npx tsx examples/web/server.ts
|
|
|
266
360
|
|
|
267
361
|
### Environment variables
|
|
268
362
|
|
|
269
|
-
| Variable | Description
|
|
270
|
-
| -------------------- |
|
|
271
|
-
| `CODEANY_API_KEY` | API key (required)
|
|
272
|
-
| `
|
|
273
|
-
| `
|
|
274
|
-
| `
|
|
363
|
+
| Variable | Description |
|
|
364
|
+
| -------------------- | -------------------------------------------------------- |
|
|
365
|
+
| `CODEANY_API_KEY` | API key (required) |
|
|
366
|
+
| `CODEANY_API_TYPE` | `anthropic-messages` (default) or `openai-completions` |
|
|
367
|
+
| `CODEANY_MODEL` | Default model override |
|
|
368
|
+
| `CODEANY_BASE_URL` | Custom API endpoint |
|
|
369
|
+
| `CODEANY_AUTH_TOKEN` | Alternative auth token |
|
|
275
370
|
|
|
276
371
|
## Built-in tools
|
|
277
372
|
|
|
@@ -287,6 +382,7 @@ npx tsx examples/web/server.ts
|
|
|
287
382
|
| **WebSearch** | Search the web |
|
|
288
383
|
| **NotebookEdit** | Edit Jupyter notebook cells |
|
|
289
384
|
| **Agent** | Spawn subagents for parallel work |
|
|
385
|
+
| **Skill** | Invoke registered skills |
|
|
290
386
|
| **TaskCreate/List/Update/Get/Stop/Output** | Task management system |
|
|
291
387
|
| **TeamCreate/Delete** | Multi-agent team coordination |
|
|
292
388
|
| **SendMessage** | Inter-agent messaging |
|
|
@@ -301,6 +397,18 @@ npx tsx examples/web/server.ts
|
|
|
301
397
|
| **Config** | Dynamic configuration |
|
|
302
398
|
| **TodoWrite** | Session todo list |
|
|
303
399
|
|
|
400
|
+
## Bundled skills
|
|
401
|
+
|
|
402
|
+
| Skill | Description |
|
|
403
|
+
| ------------ | -------------------------------------------------------------- |
|
|
404
|
+
| `simplify` | Review changed code for reuse, quality, and efficiency |
|
|
405
|
+
| `commit` | Create a git commit with a well-crafted message |
|
|
406
|
+
| `review` | Review code changes for correctness, security, and performance |
|
|
407
|
+
| `debug` | Systematic debugging using structured investigation |
|
|
408
|
+
| `test` | Run tests and analyze failures |
|
|
409
|
+
|
|
410
|
+
Register custom skills with `registerSkill()`.
|
|
411
|
+
|
|
304
412
|
## Architecture
|
|
305
413
|
|
|
306
414
|
```
|
|
@@ -312,7 +420,7 @@ npx tsx examples/web/server.ts
|
|
|
312
420
|
│
|
|
313
421
|
┌──────────▼──────────┐
|
|
314
422
|
│ Agent │ Session state, tool pool,
|
|
315
|
-
│ query() / prompt() │ MCP connections
|
|
423
|
+
│ query() / prompt() │ MCP connections, hooks
|
|
316
424
|
└──────────┬──────────┘
|
|
317
425
|
│
|
|
318
426
|
┌──────────▼──────────┐
|
|
@@ -323,26 +431,28 @@ npx tsx examples/web/server.ts
|
|
|
323
431
|
┌───────────────┼───────────────┐
|
|
324
432
|
│ │ │
|
|
325
433
|
┌─────▼─────┐ ┌─────▼─────┐ ┌─────▼─────┐
|
|
326
|
-
│
|
|
327
|
-
│
|
|
328
|
-
│
|
|
329
|
-
|
|
330
|
-
|
|
434
|
+
│ Provider │ │ 35 Tools │ │ MCP │
|
|
435
|
+
│ Anthropic │ │ Bash,Read │ │ Servers │
|
|
436
|
+
│ OpenAI │ │ Edit,... │ │ stdio/SSE/ │
|
|
437
|
+
│ DeepSeek │ │ + Skills │ │ HTTP/SDK │
|
|
438
|
+
└───────────┘ └───────────┘ └───────────┘
|
|
331
439
|
```
|
|
332
440
|
|
|
333
441
|
**Key internals:**
|
|
334
442
|
|
|
335
|
-
| Component | Description
|
|
336
|
-
| --------------------- |
|
|
337
|
-
| **
|
|
338
|
-
| **
|
|
339
|
-
| **
|
|
340
|
-
| **
|
|
341
|
-
| **
|
|
342
|
-
| **
|
|
343
|
-
| **
|
|
344
|
-
| **
|
|
345
|
-
| **
|
|
443
|
+
| Component | Description |
|
|
444
|
+
| --------------------- | ------------------------------------------------------------------ |
|
|
445
|
+
| **Provider layer** | Abstracts Anthropic / OpenAI API differences |
|
|
446
|
+
| **QueryEngine** | Core agentic loop with auto-compact, retry, tool orchestration |
|
|
447
|
+
| **Skill system** | Reusable prompt templates with 5 bundled skills |
|
|
448
|
+
| **Hook system** | 20 lifecycle events integrated into the engine |
|
|
449
|
+
| **Auto-compact** | Summarizes conversation when context window fills up |
|
|
450
|
+
| **Micro-compact** | Truncates oversized tool results |
|
|
451
|
+
| **Retry** | Exponential backoff for rate limits and transient errors |
|
|
452
|
+
| **Token estimation** | Rough token counting with pricing for Claude, GPT, DeepSeek models |
|
|
453
|
+
| **File cache** | LRU cache (100 entries, 25 MB) for file reads |
|
|
454
|
+
| **Session storage** | Persist / resume / fork sessions on disk |
|
|
455
|
+
| **Context injection** | Git status + AGENT.md automatically injected into system prompt |
|
|
346
456
|
|
|
347
457
|
## Examples
|
|
348
458
|
|
|
@@ -359,6 +469,9 @@ npx tsx examples/web/server.ts
|
|
|
359
469
|
| 09 | `examples/09-subagents.ts` | Subagent delegation |
|
|
360
470
|
| 10 | `examples/10-permissions.ts` | Read-only agent with tool restrictions |
|
|
361
471
|
| 11 | `examples/11-custom-mcp-tools.ts` | `tool()` + `createSdkMcpServer()` |
|
|
472
|
+
| 12 | `examples/12-skills.ts` | Skill system usage |
|
|
473
|
+
| 13 | `examples/13-hooks.ts` | Lifecycle hooks |
|
|
474
|
+
| 14 | `examples/14-openai-compat.ts` | OpenAI / DeepSeek models |
|
|
362
475
|
| web | `examples/web/` | Web chat UI for testing |
|
|
363
476
|
|
|
364
477
|
Run any example:
|
|
@@ -375,11 +488,11 @@ npx tsx examples/web/server.ts
|
|
|
375
488
|
|
|
376
489
|
## Star History
|
|
377
490
|
|
|
378
|
-
<a href="https://www.star-history.com/?repos=
|
|
491
|
+
<a href="https://www.star-history.com/?repos=codeany-ai%2Fopen-agent-sdk-typescript&type=timeline&legend=top-left">
|
|
379
492
|
<picture>
|
|
380
|
-
<source media="(prefers-color-scheme: dark)" srcset="https://api.star-history.com/image?repos=
|
|
381
|
-
<source media="(prefers-color-scheme: light)" srcset="https://api.star-history.com/image?repos=
|
|
382
|
-
<img alt="Star History Chart" src="https://api.star-history.com/image?repos=
|
|
493
|
+
<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" />
|
|
494
|
+
<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" />
|
|
495
|
+
<img alt="Star History Chart" src="https://api.star-history.com/image?repos=codeany-ai/open-agent-sdk-typescript&type=timeline&legend=top-left" />
|
|
383
496
|
</picture>
|
|
384
497
|
</a>
|
|
385
498
|
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Example 12: Skills
|
|
3
|
+
*
|
|
4
|
+
* Shows how to use the skill system: bundled skills, custom skills,
|
|
5
|
+
* and invoking skills programmatically.
|
|
6
|
+
*
|
|
7
|
+
* Run: npx tsx examples/12-skills.ts
|
|
8
|
+
*/
|
|
9
|
+
import {
|
|
10
|
+
createAgent,
|
|
11
|
+
registerSkill,
|
|
12
|
+
getAllSkills,
|
|
13
|
+
getUserInvocableSkills,
|
|
14
|
+
getSkill,
|
|
15
|
+
initBundledSkills,
|
|
16
|
+
} from '../src/index.js'
|
|
17
|
+
import type { SkillContentBlock } from '../src/index.js'
|
|
18
|
+
|
|
19
|
+
async function main() {
|
|
20
|
+
console.log('--- Example 12: Skills ---\n')
|
|
21
|
+
|
|
22
|
+
// Bundled skills are auto-initialized when creating an Agent,
|
|
23
|
+
// but you can also init them explicitly:
|
|
24
|
+
initBundledSkills()
|
|
25
|
+
|
|
26
|
+
// List all registered skills
|
|
27
|
+
const all = getAllSkills()
|
|
28
|
+
console.log(`Registered skills (${all.length}):`)
|
|
29
|
+
for (const skill of all) {
|
|
30
|
+
console.log(` - ${skill.name}: ${skill.description.slice(0, 80)}...`)
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// Register a custom skill
|
|
34
|
+
registerSkill({
|
|
35
|
+
name: 'explain',
|
|
36
|
+
description: 'Explain a concept or piece of code in simple terms.',
|
|
37
|
+
aliases: ['eli5'],
|
|
38
|
+
userInvocable: true,
|
|
39
|
+
async getPrompt(args): Promise<SkillContentBlock[]> {
|
|
40
|
+
return [{
|
|
41
|
+
type: 'text',
|
|
42
|
+
text: `Explain the following in simple, clear terms that a beginner could understand. Use analogies where helpful.\n\nTopic: ${args || 'Ask the user what they want explained.'}`,
|
|
43
|
+
}]
|
|
44
|
+
},
|
|
45
|
+
})
|
|
46
|
+
|
|
47
|
+
console.log(`\nAfter registering custom skill: ${getAllSkills().length} total`)
|
|
48
|
+
console.log(`User-invocable: ${getUserInvocableSkills().length}`)
|
|
49
|
+
|
|
50
|
+
// Get a specific skill
|
|
51
|
+
const commitSkill = getSkill('commit')
|
|
52
|
+
if (commitSkill) {
|
|
53
|
+
const blocks = await commitSkill.getPrompt('', { cwd: process.cwd() })
|
|
54
|
+
console.log(`\nCommit skill prompt (first 200 chars):`)
|
|
55
|
+
console.log(blocks[0]?.type === 'text' ? blocks[0].text.slice(0, 200) + '...' : '(non-text)')
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// Use skills with an agent - the model can invoke them via the Skill tool
|
|
59
|
+
console.log('\n--- Using skills with an agent ---\n')
|
|
60
|
+
|
|
61
|
+
const agent = createAgent({
|
|
62
|
+
model: process.env.CODEANY_MODEL || 'claude-sonnet-4-6',
|
|
63
|
+
maxTurns: 5,
|
|
64
|
+
})
|
|
65
|
+
|
|
66
|
+
for await (const event of agent.query(
|
|
67
|
+
'Use the "explain" skill to explain what git rebase does.',
|
|
68
|
+
)) {
|
|
69
|
+
const msg = event as any
|
|
70
|
+
if (msg.type === 'assistant') {
|
|
71
|
+
for (const block of msg.message?.content || []) {
|
|
72
|
+
if (block.type === 'tool_use') {
|
|
73
|
+
console.log(`[Tool: ${block.name}] ${JSON.stringify(block.input)}`)
|
|
74
|
+
}
|
|
75
|
+
if (block.type === 'text' && block.text.trim()) {
|
|
76
|
+
console.log(block.text)
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
if (msg.type === 'result') {
|
|
81
|
+
console.log(`\n--- ${msg.subtype} ---`)
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
await agent.close()
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
main().catch(console.error)
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Example 13: Hooks
|
|
3
|
+
*
|
|
4
|
+
* Shows how to use lifecycle hooks to intercept agent behavior.
|
|
5
|
+
* Hooks fire at key points: session start/end, before/after tool use,
|
|
6
|
+
* compaction, etc.
|
|
7
|
+
*
|
|
8
|
+
* Run: npx tsx examples/13-hooks.ts
|
|
9
|
+
*/
|
|
10
|
+
import { createAgent, createHookRegistry } from '../src/index.js'
|
|
11
|
+
import type { HookInput } from '../src/index.js'
|
|
12
|
+
|
|
13
|
+
async function main() {
|
|
14
|
+
console.log('--- Example 13: Hooks ---\n')
|
|
15
|
+
|
|
16
|
+
// Create a hook registry with custom handlers
|
|
17
|
+
const registry = createHookRegistry({
|
|
18
|
+
SessionStart: [{
|
|
19
|
+
handler: async (input: HookInput) => {
|
|
20
|
+
console.log(`[Hook] Session started: ${input.sessionId}`)
|
|
21
|
+
},
|
|
22
|
+
}],
|
|
23
|
+
PreToolUse: [{
|
|
24
|
+
handler: async (input: HookInput) => {
|
|
25
|
+
console.log(`[Hook] About to use tool: ${input.toolName}`)
|
|
26
|
+
// You can block a tool by returning { block: true }
|
|
27
|
+
// return { block: true, message: 'Tool blocked by hook' }
|
|
28
|
+
},
|
|
29
|
+
}],
|
|
30
|
+
PostToolUse: [{
|
|
31
|
+
handler: async (input: HookInput) => {
|
|
32
|
+
const output = typeof input.toolOutput === 'string'
|
|
33
|
+
? input.toolOutput.slice(0, 100)
|
|
34
|
+
: JSON.stringify(input.toolOutput).slice(0, 100)
|
|
35
|
+
console.log(`[Hook] Tool ${input.toolName} completed: ${output}...`)
|
|
36
|
+
},
|
|
37
|
+
}],
|
|
38
|
+
PostToolUseFailure: [{
|
|
39
|
+
handler: async (input: HookInput) => {
|
|
40
|
+
console.log(`[Hook] Tool ${input.toolName} FAILED: ${input.error}`)
|
|
41
|
+
},
|
|
42
|
+
}],
|
|
43
|
+
Stop: [{
|
|
44
|
+
handler: async () => {
|
|
45
|
+
console.log('[Hook] Agent loop completed')
|
|
46
|
+
},
|
|
47
|
+
}],
|
|
48
|
+
SessionEnd: [{
|
|
49
|
+
handler: async () => {
|
|
50
|
+
console.log('[Hook] Session ended')
|
|
51
|
+
},
|
|
52
|
+
}],
|
|
53
|
+
})
|
|
54
|
+
|
|
55
|
+
// Create agent with hook registry
|
|
56
|
+
// Note: For direct HookRegistry usage, we pass hooks via the engine config.
|
|
57
|
+
// The AgentOptions.hooks format also works (see below).
|
|
58
|
+
const agent = createAgent({
|
|
59
|
+
model: process.env.CODEANY_MODEL || 'claude-sonnet-4-6',
|
|
60
|
+
maxTurns: 5,
|
|
61
|
+
// Alternative: use AgentOptions.hooks format
|
|
62
|
+
hooks: {
|
|
63
|
+
PreToolUse: [{
|
|
64
|
+
hooks: [async (input: any, toolUseId: string) => {
|
|
65
|
+
console.log(`[AgentHook] PreToolUse: ${input.toolName} (${toolUseId})`)
|
|
66
|
+
}],
|
|
67
|
+
}],
|
|
68
|
+
},
|
|
69
|
+
})
|
|
70
|
+
|
|
71
|
+
for await (const event of agent.query('What files are in the current directory? Be brief.')) {
|
|
72
|
+
const msg = event as any
|
|
73
|
+
if (msg.type === 'assistant') {
|
|
74
|
+
for (const block of msg.message?.content || []) {
|
|
75
|
+
if (block.type === 'text' && block.text.trim()) {
|
|
76
|
+
console.log(`\nAssistant: ${block.text.slice(0, 200)}`)
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
if (msg.type === 'result') {
|
|
81
|
+
console.log(`\n--- ${msg.subtype} ---`)
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
await agent.close()
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
main().catch(console.error)
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Example 14: OpenAI-Compatible Models
|
|
3
|
+
*
|
|
4
|
+
* Shows how to use the SDK with OpenAI's API or any OpenAI-compatible
|
|
5
|
+
* endpoint (e.g., DeepSeek, Qwen, vLLM, Ollama).
|
|
6
|
+
*
|
|
7
|
+
* Environment variables:
|
|
8
|
+
* CODEANY_API_KEY=sk-... # Your OpenAI API key
|
|
9
|
+
* CODEANY_BASE_URL=https://api.openai.com/v1 # Optional, defaults to OpenAI
|
|
10
|
+
* CODEANY_API_TYPE=openai-completions # Optional, auto-detected from model name
|
|
11
|
+
*
|
|
12
|
+
* Run: npx tsx examples/14-openai-compat.ts
|
|
13
|
+
*/
|
|
14
|
+
import { createAgent } from '../src/index.js'
|
|
15
|
+
|
|
16
|
+
async function main() {
|
|
17
|
+
console.log('--- Example 14: OpenAI-Compatible Models ---\n')
|
|
18
|
+
|
|
19
|
+
// Option 1: Explicit apiType
|
|
20
|
+
const agent = createAgent({
|
|
21
|
+
apiType: 'openai-completions',
|
|
22
|
+
model: process.env.CODEANY_MODEL || 'gpt-4o',
|
|
23
|
+
apiKey: process.env.CODEANY_API_KEY,
|
|
24
|
+
baseURL: process.env.CODEANY_BASE_URL || 'https://api.openai.com/v1',
|
|
25
|
+
maxTurns: 5,
|
|
26
|
+
})
|
|
27
|
+
|
|
28
|
+
console.log(`API Type: ${agent.getApiType()}`)
|
|
29
|
+
console.log(`Model: ${process.env.CODEANY_MODEL || 'gpt-4o'}\n`)
|
|
30
|
+
|
|
31
|
+
// Option 2: Auto-detected from model name (uncomment to try)
|
|
32
|
+
// const agent = createAgent({
|
|
33
|
+
// model: 'gpt-4o', // Auto-detects 'openai-completions'
|
|
34
|
+
// apiKey: process.env.CODEANY_API_KEY,
|
|
35
|
+
// })
|
|
36
|
+
|
|
37
|
+
// Option 3: DeepSeek example (uncomment to try)
|
|
38
|
+
// const agent = createAgent({
|
|
39
|
+
// model: 'deepseek-chat',
|
|
40
|
+
// apiKey: process.env.CODEANY_API_KEY,
|
|
41
|
+
// baseURL: 'https://api.deepseek.com/v1',
|
|
42
|
+
// })
|
|
43
|
+
|
|
44
|
+
// Option 4: Via environment variables only
|
|
45
|
+
// CODEANY_API_TYPE=openai-completions
|
|
46
|
+
// CODEANY_MODEL=gpt-4o
|
|
47
|
+
// CODEANY_API_KEY=sk-...
|
|
48
|
+
// CODEANY_BASE_URL=https://api.openai.com/v1
|
|
49
|
+
// const agent = createAgent()
|
|
50
|
+
|
|
51
|
+
for await (const event of agent.query('What is 2+2? Reply in one sentence.')) {
|
|
52
|
+
const msg = event as any
|
|
53
|
+
if (msg.type === 'assistant') {
|
|
54
|
+
for (const block of msg.message?.content || []) {
|
|
55
|
+
if (block.type === 'text' && block.text.trim()) {
|
|
56
|
+
console.log(`Assistant: ${block.text}`)
|
|
57
|
+
}
|
|
58
|
+
if (block.type === 'tool_use') {
|
|
59
|
+
console.log(`[Tool: ${block.name}] ${JSON.stringify(block.input)}`)
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
if (msg.type === 'result') {
|
|
64
|
+
console.log(`\n--- ${msg.subtype} (${msg.usage?.input_tokens}+${msg.usage?.output_tokens} tokens) ---`)
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
await agent.close()
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
main().catch(console.error)
|
package/package.json
CHANGED
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
"bugs": {
|
|
13
13
|
"url": "https://github.com/codeany-ai/open-agent-sdk-typescript/issues"
|
|
14
14
|
},
|
|
15
|
-
"version": "0.
|
|
15
|
+
"version": "0.2.0",
|
|
16
16
|
"description": "Open-source Agent SDK. Runs the full agent loop in-process — no local CLI required. Deploy anywhere: cloud, serverless, Docker, CI/CD.",
|
|
17
17
|
"type": "module",
|
|
18
18
|
"main": "./dist/index.js",
|