@cuylabs/agent-core 0.3.0 → 0.4.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 +162 -36
- package/dist/{index-QR704uRr.d.ts → index-BlSTfS-W.d.ts} +4 -6
- package/dist/index.d.ts +2432 -1037
- package/dist/index.js +1571 -61
- package/dist/tool/index.d.ts +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -4,16 +4,20 @@ Embeddable AI agent infrastructure using Vercel AI SDK. Core building blocks for
|
|
|
4
4
|
|
|
5
5
|
## Features
|
|
6
6
|
|
|
7
|
-
- **Agent Framework**
|
|
8
|
-
- **Session Management**
|
|
9
|
-
- **LLM Streaming**
|
|
10
|
-
- **Error Resilience**
|
|
11
|
-
- **Context Management**
|
|
12
|
-
- **Tool Framework**
|
|
13
|
-
- **
|
|
14
|
-
- **
|
|
15
|
-
- **
|
|
16
|
-
- **
|
|
7
|
+
- **Agent Framework** — Create AI agents with tool support and streaming responses
|
|
8
|
+
- **Session Management** — Persistent conversation state with branching support
|
|
9
|
+
- **LLM Streaming** — Real-time streaming with proper backpressure handling
|
|
10
|
+
- **Error Resilience** — Automatic retry with exponential backoff
|
|
11
|
+
- **Context Management** — Token counting and automatic context pruning
|
|
12
|
+
- **Tool Framework** — Type-safe tool definitions with Zod schemas
|
|
13
|
+
- **Middleware** — Composable lifecycle hooks for tool interception, prompt injection, logging, and guardrails
|
|
14
|
+
- **Skills** — Modular knowledge packs with progressive disclosure (L1 summary → L2 content → L3 resources)
|
|
15
|
+
- **Approval System** — Configurable tool approval via middleware (rules + interactive prompts)
|
|
16
|
+
- **Checkpoint System** — Undo/restore capabilities for file operations
|
|
17
|
+
- **Model Capabilities** — Runtime model capability detection
|
|
18
|
+
- **MCP Support** — Extend agents with Model Context Protocol servers
|
|
19
|
+
- **Sub-Agents** — Fork agents with inherited config, run tasks in parallel, or let the LLM delegate via `invoke_agent`
|
|
20
|
+
- **Presets** — Reusable agent configurations with tool filtering
|
|
17
21
|
|
|
18
22
|
## Installation
|
|
19
23
|
|
|
@@ -44,22 +48,23 @@ import { openai } from "@ai-sdk/openai";
|
|
|
44
48
|
import { z } from "zod";
|
|
45
49
|
|
|
46
50
|
// Define tools
|
|
47
|
-
const
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
51
|
+
const greet = Tool.define("greet", {
|
|
52
|
+
description: "Greet a user by name",
|
|
53
|
+
parameters: z.object({
|
|
54
|
+
name: z.string().describe("Name to greet"),
|
|
55
|
+
}),
|
|
56
|
+
execute: async ({ name }) => ({
|
|
57
|
+
title: "Greeting",
|
|
58
|
+
output: `Hello, ${name}!`,
|
|
59
|
+
metadata: {},
|
|
60
|
+
}),
|
|
61
|
+
});
|
|
57
62
|
|
|
58
63
|
// Create agent
|
|
59
64
|
const agent = createAgent({
|
|
60
65
|
model: openai("gpt-4o"),
|
|
61
|
-
|
|
62
|
-
|
|
66
|
+
tools: [greet],
|
|
67
|
+
systemPrompt: "You are a helpful assistant.",
|
|
63
68
|
});
|
|
64
69
|
|
|
65
70
|
// Stream responses
|
|
@@ -68,7 +73,7 @@ for await (const event of agent.chat("session-1", "Hello!")) {
|
|
|
68
73
|
case "text-delta":
|
|
69
74
|
process.stdout.write(event.text);
|
|
70
75
|
break;
|
|
71
|
-
case "tool-
|
|
76
|
+
case "tool-start":
|
|
72
77
|
console.log(`Calling tool: ${event.toolName}`);
|
|
73
78
|
break;
|
|
74
79
|
case "tool-result":
|
|
@@ -150,26 +155,131 @@ await sessions.createSession({ id: "my-session" });
|
|
|
150
155
|
### Tool Framework
|
|
151
156
|
|
|
152
157
|
```typescript
|
|
153
|
-
import {
|
|
158
|
+
import { Tool } from "@cuylabs/agent-core";
|
|
154
159
|
import { z } from "zod";
|
|
155
160
|
|
|
156
|
-
const
|
|
157
|
-
|
|
158
|
-
description: "Perform a calculation",
|
|
161
|
+
const calculator = Tool.define("calculator", {
|
|
162
|
+
description: "Evaluate a math expression",
|
|
159
163
|
parameters: z.object({
|
|
160
164
|
expression: z.string(),
|
|
161
165
|
}),
|
|
162
166
|
execute: async ({ expression }, ctx) => {
|
|
163
|
-
// ctx provides
|
|
164
|
-
return
|
|
167
|
+
// ctx provides sessionID, cwd, abort signal, host, etc.
|
|
168
|
+
return {
|
|
169
|
+
title: "Calculator",
|
|
170
|
+
output: String(eval(expression)), // Don't actually do this!
|
|
171
|
+
metadata: {},
|
|
172
|
+
};
|
|
165
173
|
},
|
|
166
174
|
});
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
### Middleware
|
|
167
178
|
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
179
|
+
Composable lifecycle hooks for tool interception, prompt injection, logging, and guardrails:
|
|
180
|
+
|
|
181
|
+
```typescript
|
|
182
|
+
import { createAgent, type AgentMiddleware, approvalMiddleware } from "@cuylabs/agent-core";
|
|
183
|
+
|
|
184
|
+
// Simple logging middleware
|
|
185
|
+
const logger: AgentMiddleware = {
|
|
186
|
+
name: "logger",
|
|
187
|
+
async beforeToolCall(tool, args) {
|
|
188
|
+
console.log(`→ ${tool}`, args);
|
|
189
|
+
return { action: "allow" };
|
|
190
|
+
},
|
|
191
|
+
async afterToolCall(tool, _args, result) {
|
|
192
|
+
console.log(`← ${tool}`, result.title);
|
|
193
|
+
return result;
|
|
194
|
+
},
|
|
195
|
+
async onChatStart(sessionId, message) {
|
|
196
|
+
console.log(`Chat started: ${sessionId}`);
|
|
197
|
+
},
|
|
198
|
+
async onChatEnd(sessionId, { usage, error }) {
|
|
199
|
+
console.log(`Chat ended: ${usage?.totalTokens} tokens`);
|
|
200
|
+
},
|
|
201
|
+
};
|
|
202
|
+
|
|
203
|
+
// Guardrail middleware — block dangerous tools
|
|
204
|
+
const guardrail: AgentMiddleware = {
|
|
205
|
+
name: "guardrail",
|
|
206
|
+
async beforeToolCall(tool) {
|
|
207
|
+
if (tool === "bash") {
|
|
208
|
+
return { action: "deny", reason: "Shell commands are disabled." };
|
|
209
|
+
}
|
|
210
|
+
return { action: "allow" };
|
|
211
|
+
},
|
|
212
|
+
};
|
|
213
|
+
|
|
214
|
+
const agent = createAgent({
|
|
215
|
+
model: openai("gpt-4o"),
|
|
216
|
+
tools: myTools,
|
|
217
|
+
middleware: [
|
|
218
|
+
logger,
|
|
219
|
+
guardrail,
|
|
220
|
+
approvalMiddleware({
|
|
221
|
+
rules: [{ pattern: "*", tool: "read_file", action: "allow" }],
|
|
222
|
+
onRequest: async (req) => {
|
|
223
|
+
// Prompt user for approval
|
|
224
|
+
return await askUser(req);
|
|
225
|
+
},
|
|
226
|
+
}),
|
|
227
|
+
],
|
|
228
|
+
});
|
|
171
229
|
```
|
|
172
230
|
|
|
231
|
+
Middleware hooks: `beforeToolCall`, `afterToolCall`, `promptSections`, `onEvent`, `onChatStart`, `onChatEnd`. Sub-agents inherit middleware via `fork()`.
|
|
232
|
+
|
|
233
|
+
### Skills
|
|
234
|
+
|
|
235
|
+
Modular knowledge packs with three-level progressive disclosure:
|
|
236
|
+
|
|
237
|
+
```typescript
|
|
238
|
+
import { createAgent, createSkillRegistry, createSkillTools } from "@cuylabs/agent-core";
|
|
239
|
+
|
|
240
|
+
// Discover skills from SKILL.md files
|
|
241
|
+
const registry = await createSkillRegistry(process.cwd(), {
|
|
242
|
+
externalDirs: [".agents", ".claude"],
|
|
243
|
+
});
|
|
244
|
+
|
|
245
|
+
// Create skill tools (skill + skill_resource)
|
|
246
|
+
const skillTools = createSkillTools(registry);
|
|
247
|
+
|
|
248
|
+
// Inject L1 summary into system prompt, give agent skill tools
|
|
249
|
+
const agent = createAgent({
|
|
250
|
+
model: openai("gpt-4o"),
|
|
251
|
+
tools: [...myTools, ...skillTools],
|
|
252
|
+
systemPrompt: `You are a coding assistant.\n\n${registry.formatSummary()}`,
|
|
253
|
+
});
|
|
254
|
+
```
|
|
255
|
+
|
|
256
|
+
Skills use the `SKILL.md` format with YAML frontmatter. See [examples/skills/](examples/skills/) for samples.
|
|
257
|
+
|
|
258
|
+
### Built-in Sub-Agent Tools
|
|
259
|
+
|
|
260
|
+
Let the LLM delegate work to specialized sub-agents via tool calls:
|
|
261
|
+
|
|
262
|
+
```typescript
|
|
263
|
+
import { createAgent, createSubAgentTools, Presets } from "@cuylabs/agent-core";
|
|
264
|
+
import type { AgentProfile } from "@cuylabs/agent-core";
|
|
265
|
+
|
|
266
|
+
const profiles: AgentProfile[] = [
|
|
267
|
+
{ name: "explorer", description: "Fast code search", preset: Presets.explore },
|
|
268
|
+
{ name: "reviewer", description: "Thorough code review", preset: Presets.review },
|
|
269
|
+
];
|
|
270
|
+
|
|
271
|
+
const parent = createAgent({ model, tools: codeTools });
|
|
272
|
+
const subTools = createSubAgentTools(parent, { profiles, async: true });
|
|
273
|
+
|
|
274
|
+
const agent = createAgent({
|
|
275
|
+
model,
|
|
276
|
+
tools: [...codeTools, ...subTools],
|
|
277
|
+
});
|
|
278
|
+
// The LLM can now call invoke_agent, wait_agent, and close_agent
|
|
279
|
+
```
|
|
280
|
+
|
|
281
|
+
Tools: `invoke_agent` (spawn), `wait_agent` (collect results), `close_agent` (cancel). Supports sync and async modes, depth limiting, and concurrency control. See [docs/subagents.md](docs/subagents.md#built-in-sub-agent-tools-llm-callable).
|
|
282
|
+
|
|
173
283
|
### Error Handling & Retry
|
|
174
284
|
|
|
175
285
|
```typescript
|
|
@@ -262,14 +372,30 @@ The `chat()` method yields these event types:
|
|
|
262
372
|
| Event Type | Description |
|
|
263
373
|
|------------|-------------|
|
|
264
374
|
| `text-delta` | Streaming text chunk |
|
|
265
|
-
| `
|
|
375
|
+
| `text-start` / `text-end` | Text generation boundaries |
|
|
376
|
+
| `tool-start` | Tool invocation started |
|
|
266
377
|
| `tool-result` | Tool execution completed |
|
|
267
|
-
| `
|
|
268
|
-
| `
|
|
378
|
+
| `tool-error` | Tool execution failed |
|
|
379
|
+
| `step-start` / `step-finish` | LLM step boundaries with usage stats |
|
|
380
|
+
| `reasoning-delta` | Model reasoning chunk (if supported) |
|
|
381
|
+
| `status` | Agent state changes (thinking, calling-tool, etc.) |
|
|
382
|
+
| `doom-loop` | Repeated tool call pattern detected |
|
|
383
|
+
| `context-overflow` | Context window exceeded |
|
|
384
|
+
| `message` | Complete user/assistant message |
|
|
269
385
|
| `complete` | Stream finished with usage stats |
|
|
270
|
-
| `error` |
|
|
386
|
+
| `error` | Unrecoverable error |
|
|
387
|
+
|
|
388
|
+
See [examples/03-streaming.ts](examples/03-streaming.ts) for a complete event handling example.
|
|
271
389
|
|
|
272
390
|
## Concurrency Note
|
|
273
391
|
|
|
274
392
|
When using `runConcurrent()` to run multiple tasks in parallel, be aware that all tasks share the same `SessionManager` instance. For independent conversations, create separate `Agent` instances or use distinct session IDs.
|
|
275
393
|
|
|
394
|
+
## Examples
|
|
395
|
+
|
|
396
|
+
See [examples/](examples/) for 17 runnable examples covering every feature — from basic chat to middleware, skills, and Docker execution. The [examples README](examples/README.md) has setup instructions and run commands.
|
|
397
|
+
|
|
398
|
+
## Documentation
|
|
399
|
+
|
|
400
|
+
See [docs/](docs/) for in-depth guides on each subsystem.
|
|
401
|
+
|
|
@@ -203,7 +203,7 @@ interface ToolMetadata {
|
|
|
203
203
|
/**
|
|
204
204
|
* Tool definition namespace for @cuylabs/agent-core
|
|
205
205
|
*
|
|
206
|
-
*
|
|
206
|
+
* Provides consistent tool creation via Tool.define.
|
|
207
207
|
*/
|
|
208
208
|
|
|
209
209
|
/**
|
|
@@ -233,7 +233,7 @@ interface CompatibleSchema<T = any> {
|
|
|
233
233
|
*/
|
|
234
234
|
type InferSchemaOutput<T extends CompatibleSchema> = T["_output"];
|
|
235
235
|
/**
|
|
236
|
-
* Tool namespace -
|
|
236
|
+
* Tool namespace - tool definition utilities
|
|
237
237
|
*/
|
|
238
238
|
declare namespace Tool {
|
|
239
239
|
/**
|
|
@@ -298,7 +298,7 @@ declare namespace Tool {
|
|
|
298
298
|
metadata: TMeta;
|
|
299
299
|
}
|
|
300
300
|
/**
|
|
301
|
-
* Define a tool with
|
|
301
|
+
* Define a tool with standard patterns
|
|
302
302
|
*
|
|
303
303
|
* @example
|
|
304
304
|
* ```typescript
|
|
@@ -438,8 +438,6 @@ declare const defaultRegistry: ToolRegistry;
|
|
|
438
438
|
|
|
439
439
|
/**
|
|
440
440
|
* Output truncation utilities for @cuylabs/agent-core
|
|
441
|
-
*
|
|
442
|
-
* Based on OpenCode's tool/truncation.ts
|
|
443
441
|
*/
|
|
444
442
|
/** Maximum lines before truncation */
|
|
445
443
|
declare const MAX_LINES = 2000;
|
|
@@ -469,4 +467,4 @@ declare function truncateOutput(output: string, options?: {
|
|
|
469
467
|
*/
|
|
470
468
|
declare function formatSize(bytes: number): string;
|
|
471
469
|
|
|
472
|
-
export { type CompatibleSchema as C, type DirEntry as D, type ExecOptions as E, type FileOperationMeta as F, type InferSchemaOutput as I, MAX_BYTES as M, type ToolHost as T,
|
|
470
|
+
export { type CompatibleSchema as C, type DirEntry as D, type ExecOptions as E, type FileOperationMeta as F, type InferSchemaOutput as I, MAX_BYTES as M, type ToolHost as T, type ToolContext as a, Tool as b, type TurnTrackerContext as c, type ExecResult as d, type FileStat as e, MAX_LINES as f, TRUNCATE_DIR as g, TRUNCATE_GLOB as h, type ToolMetadata as i, ToolRegistry as j, type ToolResult as k, type ToolSpec as l, type TruncateResult as m, defaultRegistry as n, defineTool as o, formatSize as p, truncateOutput as t };
|