@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 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** - 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
- - **Approval System** - Configurable tool approval workflows
14
- - **Checkpoint System** - Undo/restore capabilities for file operations
15
- - **Model Capabilities** - Runtime model capability detection
16
- - **MCP Support** - Extend agents with Model Context Protocol servers
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 tools: Tool[] = [
48
- {
49
- name: "greet",
50
- description: "Greet a user by name",
51
- parameters: z.object({
52
- name: z.string().describe("Name to greet"),
53
- }),
54
- execute: async ({ name }) => `Hello, ${name}!`,
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
- cwd: process.cwd(),
62
- tools,
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-call":
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 { defineTool, Tool, ToolRegistry } from "@cuylabs/agent-core";
158
+ import { Tool } from "@cuylabs/agent-core";
154
159
  import { z } from "zod";
155
160
 
156
- const myTool = defineTool({
157
- name: "calculate",
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 sessionId, cwd, abort signal, etc.
164
- return eval(expression); // Don't actually do this!
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
- // Register tools
169
- const registry = new ToolRegistry();
170
- registry.register(myTool);
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
- | `tool-call` | Tool invocation started |
375
+ | `text-start` / `text-end` | Text generation boundaries |
376
+ | `tool-start` | Tool invocation started |
266
377
  | `tool-result` | Tool execution completed |
267
- | `reasoning` | Model reasoning (if supported) |
268
- | `message` | Complete assistant message |
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` | Error occurred |
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
- * Following OpenCode's Tool.define pattern for consistent tool creation.
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 - OpenCode-style tool definition
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 OpenCode-style patterns
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, Tool as a, type TurnTrackerContext as b, type ExecResult as c, type FileStat as d, MAX_LINES as e, TRUNCATE_DIR as f, TRUNCATE_GLOB as g, type ToolContext 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 };
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 };