@cuylabs/agent-core 0.5.0 → 0.6.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
@@ -1,26 +1,40 @@
1
1
  # @cuylabs/agent-core
2
2
 
3
- Embeddable AI agent infrastructure using Vercel AI SDK. Core building blocks for AI agents with session management, tools, skills, sub-agents, and tracing.
4
-
5
- ## Features
6
-
7
- - **Named Agents** `name` field for identity in spans, runtime traces, and logging
8
- - **Agent Framework** Create AI agents with tool support and streaming responses
9
- - **OpenTelemetry Tracing** — Built-in tracing with a single `tracing` config — Zipkin, Phoenix, any OTLP backend
10
- - **Session Management** — Persistent conversation state with branching support
11
- - **Execution Streaming** — Real-time event streaming with proper backpressure handling
12
- - **Error Resilience** — Automatic retry with exponential backoff
13
- - **Context Management** — Token counting and automatic context pruning
14
- - **Tool Framework** Type-safe tool definitions with Zod schemas
15
- - **Middleware** — Composable lifecycle hooks for tool interception, prompt injection, logging, and guardrails
16
- - **Skills** Modular knowledge packs with progressive disclosure (L1 summary → L2 content → L3 resources)
17
- - **Approval System** Configurable tool approval via middleware (rules + interactive prompts)
18
- - **Checkpoint System** Undo/restore capabilities for file operations
19
- - **Model Capabilities** Runtime model capability detection
20
- - **MCP Support** — Extend agents with Model Context Protocol servers
21
- - **Sub-Agents** Fork agents with inherited config, run tasks in parallel, or let the LLM delegate via `invoke_agent`
22
- - **Presets** — Reusable agent configurations with tool filtering
23
- - **Runtime Integration** Extracted turn-runner phases for durable workflow integration
3
+ Embeddable AI agent infrastructure built on the AI SDK.
4
+
5
+ `@cuylabs/agent-core` is the in-process execution layer in this workspace. It
6
+ owns the `Agent` API, tool and model execution semantics, middleware, sessions,
7
+ prompt construction, tracing, and the reusable task/turn/workflow primitives
8
+ that higher layers build on.
9
+
10
+ ## Package Boundary
11
+
12
+ Use `@cuylabs/agent-core` when you want:
13
+
14
+ - `Agent` creation and `chat()` / `send()` APIs
15
+ - tool definition and execution
16
+ - model hooks, tool hooks, and lifecycle middleware
17
+ - sessions, storage, branching, and prompt construction
18
+ - tracing, MCP, skills, presets, and sub-agents
19
+ - runtime-facing task/turn/workflow helpers from `@cuylabs/agent-core/runtime`
20
+
21
+ This package does not own outer orchestration or hosting:
22
+
23
+ - use `@cuylabs/agent-runtime` for jobs, schedules, retries, and workload dispatch
24
+ - use `@cuylabs/agent-runtime-dapr` for Dapr-backed durability and workflow hosting
25
+ - use `@cuylabs/agent-http` for an AI SDK chat-stream HTTP adapter
26
+
27
+ ## Core Capabilities
28
+
29
+ - Streaming agent execution with structured events
30
+ - Type-safe tools with Zod schemas
31
+ - Middleware for model input/output, stream chunks, tool calls, and lifecycle hooks
32
+ - Session persistence with branching support
33
+ - Prompt pipeline and dynamic prompt sections
34
+ - Skills and built-in sub-agent delegation
35
+ - OpenTelemetry tracing
36
+ - MCP integration
37
+ - Runtime-facing task, turn, and workflow primitives for durable adapters
24
38
 
25
39
  ## Installation
26
40
 
@@ -30,14 +44,14 @@ npm install @cuylabs/agent-core
30
44
  pnpm add @cuylabs/agent-core
31
45
  ```
32
46
 
33
- You'll also need at least one AI SDK provider:
47
+ You will also need at least one AI SDK provider:
34
48
 
35
49
  ```bash
36
50
  npm install @ai-sdk/openai
37
51
  # or @ai-sdk/anthropic, @ai-sdk/google
38
52
  ```
39
53
 
40
- For OpenAI-compatible endpoints (local or hosted), add:
54
+ For OpenAI-compatible endpoints, add:
41
55
 
42
56
  ```bash
43
57
  npm install @ai-sdk/openai-compatible
@@ -45,33 +59,15 @@ npm install @ai-sdk/openai-compatible
45
59
 
46
60
  ## Quick Start
47
61
 
48
- Everything is available from the root import, plus focused subpath imports for clearer boundaries:
49
-
50
- ```typescript
51
- import { createAgent, Tool } from "@cuylabs/agent-core"; // full API
52
- import { defineTool } from "@cuylabs/agent-core/tool"; // tools only
53
- import { createSkillRegistry } from "@cuylabs/agent-core/skill"; // skill system
54
- import { createSubAgentTools } from "@cuylabs/agent-core/sub-agent"; // sub-agents
55
- import { createAgentTaskRunner } from "@cuylabs/agent-core/runtime"; // runtime
56
- import type { AgentMiddleware } from "@cuylabs/agent-core/middleware"; // middleware
57
- import { createPromptBuilder } from "@cuylabs/agent-core/prompt"; // prompts
58
- import { createMCPManager } from "@cuylabs/agent-core/mcp"; // MCP integration
59
- ```
60
-
61
- Additional focused entrypoints are available for `storage`, `context`, `reasoning`,
62
- `capabilities`, `models`, and `tracking` when you want imports to mirror the
63
- module layout.
64
-
65
62
  ```typescript
66
63
  import { createAgent, Tool } from "@cuylabs/agent-core";
67
64
  import { openai } from "@ai-sdk/openai";
68
65
  import { z } from "zod";
69
66
 
70
- // Define tools
71
67
  const greet = Tool.define("greet", {
72
68
  description: "Greet a user by name",
73
69
  parameters: z.object({
74
- name: z.string().describe("Name to greet"),
70
+ name: z.string(),
75
71
  }),
76
72
  execute: async ({ name }) => ({
77
73
  title: "Greeting",
@@ -80,371 +76,84 @@ const greet = Tool.define("greet", {
80
76
  }),
81
77
  });
82
78
 
83
- // Create agent
84
79
  const agent = createAgent({
85
- name: "my-assistant",
80
+ name: "assistant",
86
81
  model: openai("gpt-4o"),
87
82
  tools: [greet],
88
83
  systemPrompt: "You are a helpful assistant.",
89
84
  });
90
85
 
91
- // Stream responses
92
- for await (const event of agent.chat("session-1", "Hello!")) {
86
+ for await (const event of agent.chat("session-1", "Say hi to Ada")) {
93
87
  switch (event.type) {
94
88
  case "text-delta":
95
89
  process.stdout.write(event.text);
96
90
  break;
97
91
  case "tool-start":
98
- console.log(`Calling tool: ${event.toolName}`);
92
+ console.log(`calling ${event.toolName}`);
99
93
  break;
100
94
  case "tool-result":
101
- console.log(`Tool result: ${event.result}`);
95
+ console.log(`tool result:`, event.result);
102
96
  break;
103
97
  case "complete":
104
- console.log("\nDone!");
98
+ console.log("\ndone");
105
99
  break;
106
100
  }
107
101
  }
108
102
  ```
109
103
 
110
- ## API Reference
111
-
112
- ### Local Models (Ollama Example)
113
-
114
- ```typescript
115
- import { createAgent, createResolver } from "@cuylabs/agent-core";
116
-
117
- const resolveModel = createResolver({
118
- engines: {
119
- ollama: {
120
- adapter: "openai-compatible",
121
- settings: {
122
- baseUrl: "http://localhost:11434/v1",
123
- },
124
- },
125
- },
126
- });
127
-
128
- const agent = createAgent({
129
- model: resolveModel("ollama/llama3.1"),
130
- cwd: process.cwd(),
131
- });
132
- ```
133
-
134
- ### Agent
135
-
136
- ```typescript
137
- import { createAgent, Agent } from "@cuylabs/agent-core";
138
- import { openai } from "@ai-sdk/openai";
139
-
140
- const agent = createAgent({
141
- model: openai("gpt-4o"),
142
- cwd: "/path/to/project",
143
- tools: myTools,
144
- systemPrompt: "You are a helpful assistant.",
145
- temperature: 0.7,
146
- maxSteps: 10,
147
- });
148
-
149
- // Streaming chat
150
- for await (const event of agent.chat(sessionId, message)) {
151
- // Handle events
152
- }
153
- ```
154
-
155
- ### Session Management
104
+ ## Focused Imports
156
105
 
157
- ```typescript
158
- import {
159
- SessionManager,
160
- MemoryStorage,
161
- FileStorage
162
- } from "@cuylabs/agent-core";
163
-
164
- // In-memory storage (default)
165
- const memoryStorage = new MemoryStorage();
166
-
167
- // File-based persistent storage
168
- const fileStorage = new FileStorage({
169
- directory: "/path/to/data",
170
- });
171
-
172
- const sessions = new SessionManager(fileStorage);
173
- await sessions.create({ id: "my-session", cwd: process.cwd() });
174
- ```
175
-
176
- ### Tool Framework
106
+ The root export is available, but focused subpath imports mirror the package
107
+ structure when you want clearer boundaries:
177
108
 
178
109
  ```typescript
179
- import { Tool } from "@cuylabs/agent-core";
180
- import { z } from "zod";
181
-
182
- const calculator = Tool.define("calculator", {
183
- description: "Evaluate a math expression",
184
- parameters: z.object({
185
- expression: z.string(),
186
- }),
187
- execute: async ({ expression }, ctx) => {
188
- // ctx provides sessionID, cwd, abort signal, host, etc.
189
- return {
190
- title: "Calculator",
191
- output: String(eval(expression)), // Don't actually do this!
192
- metadata: {},
193
- };
194
- },
195
- });
196
- ```
197
-
198
- ### Middleware
199
-
200
- Composable lifecycle hooks for tool interception, prompt injection, logging, and guardrails:
201
-
202
- ```typescript
203
- import { createAgent, type AgentMiddleware, approvalMiddleware } from "@cuylabs/agent-core";
204
-
205
- // Simple logging middleware
206
- const logger: AgentMiddleware = {
207
- name: "logger",
208
- async beforeToolCall(tool, args) {
209
- console.log(`→ ${tool}`, args);
210
- return { action: "allow" };
211
- },
212
- async afterToolCall(tool, _args, result) {
213
- console.log(`← ${tool}`, result.title);
214
- return result;
215
- },
216
- async onChatStart(sessionId, message) {
217
- console.log(`Chat started: ${sessionId}`);
218
- },
219
- async onChatEnd(sessionId, { usage, error }) {
220
- console.log(`Chat ended: ${usage?.totalTokens} tokens`);
221
- },
222
- };
223
-
224
- // Guardrail middleware — block dangerous tools
225
- const guardrail: AgentMiddleware = {
226
- name: "guardrail",
227
- async beforeToolCall(tool) {
228
- if (tool === "bash") {
229
- return { action: "deny", reason: "Shell commands are disabled." };
230
- }
231
- return { action: "allow" };
232
- },
233
- };
234
-
235
- const agent = createAgent({
236
- model: openai("gpt-4o"),
237
- tools: myTools,
238
- middleware: [
239
- logger,
240
- guardrail,
241
- approvalMiddleware({
242
- rules: [{ pattern: "*", tool: "read_file", action: "allow" }],
243
- onRequest: async (req) => {
244
- // Prompt user for approval
245
- return await askUser(req);
246
- },
247
- }),
248
- ],
249
- });
250
- ```
251
-
252
- Middleware hooks: `beforeToolCall`, `afterToolCall`, `promptSections`, `onEvent`, `onChatStart`, `onChatEnd`. Sub-agents inherit middleware via `fork()`.
253
-
254
- ### Tracing (OpenTelemetry)
255
-
256
- Enable full tracing with a single `tracing` field — no manual provider setup:
257
-
258
- ```typescript
259
- import { createAgent } from "@cuylabs/agent-core";
260
- import { openai } from "@ai-sdk/openai";
261
- import { SimpleSpanProcessor } from "@opentelemetry/sdk-trace-node";
262
- import { ZipkinExporter } from "@opentelemetry/exporter-zipkin";
263
-
264
- const agent = createAgent({
265
- name: "my-agent",
266
- model: openai("gpt-4o"),
267
- tools: [myTool],
268
- tracing: {
269
- spanProcessor: new SimpleSpanProcessor(
270
- new ZipkinExporter({ url: "http://localhost:9411/api/v2/spans" }),
271
- ),
272
- },
273
- });
274
-
275
- // ... use agent ...
276
-
277
- // Flush spans before exit
278
- await agent.close();
279
- ```
280
-
281
- This auto-creates agent-level, tool-level, and AI SDK LLM spans following the [GenAI Semantic Conventions](https://opentelemetry.io/docs/specs/semconv/gen-ai/). Works with Zipkin, Arize Phoenix, Jaeger, or any OTLP backend. See [docs/tracing.md](docs/tracing.md) for the full reference.
282
-
283
- ### Skills
284
-
285
- Modular knowledge packs with three-level progressive disclosure:
286
-
287
- ```typescript
288
- import { createAgent, createSkillRegistry, createSkillTools } from "@cuylabs/agent-core";
289
-
290
- // Discover skills from SKILL.md files
291
- const registry = await createSkillRegistry(process.cwd(), {
292
- externalDirs: [".agents", ".claude"],
293
- });
294
-
295
- // Create skill tools (skill + skill_resource)
296
- const skillTools = createSkillTools(registry);
297
-
298
- // Inject L1 summary into system prompt, give agent skill tools
299
- const agent = createAgent({
300
- model: openai("gpt-4o"),
301
- tools: [...myTools, ...skillTools],
302
- systemPrompt: `You are a coding assistant.\n\n${registry.formatSummary()}`,
303
- });
304
- ```
305
-
306
- Skills use the `SKILL.md` format with YAML frontmatter. See [examples/skills/](examples/skills/) for samples.
307
-
308
- ### Built-in Sub-Agent Tools
309
-
310
- Let the LLM delegate work to specialized sub-agents via tool calls:
311
-
312
- ```typescript
313
- import { createAgent, createSubAgentTools, Presets } from "@cuylabs/agent-core";
314
- import type { AgentProfile } from "@cuylabs/agent-core";
315
-
316
- const profiles: AgentProfile[] = [
317
- { name: "explorer", description: "Fast code search", preset: Presets.explore },
318
- { name: "reviewer", description: "Thorough code review", preset: Presets.review },
319
- ];
320
-
321
- const parent = createAgent({ model, tools: codeTools });
322
- const subTools = createSubAgentTools(parent, { profiles, async: true });
323
-
324
- const agent = createAgent({
325
- model,
326
- tools: [...codeTools, ...subTools],
327
- });
328
- // The LLM can now call invoke_agent, wait_agent, and close_agent
329
- ```
330
-
331
- 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).
332
-
333
- ### Error Handling & Retry
334
-
335
- ```typescript
336
- import {
337
- withRetry,
338
- LLMError,
339
- isRetryable,
340
- getRetryDelay
341
- } from "@cuylabs/agent-core";
342
-
343
- const result = await withRetry(
344
- async () => {
345
- // Your operation
346
- },
347
- {
348
- maxRetries: 3,
349
- initialDelay: 1000,
350
- maxDelay: 30000,
351
- }
352
- );
353
- ```
354
-
355
- ### Context Management
356
-
357
- ```typescript
358
- import {
359
- ContextManager,
360
- estimateTokens,
361
- pruneContext
362
- } from "@cuylabs/agent-core";
363
-
364
- const ctx = new ContextManager({
365
- maxInputTokens: 100000,
366
- pruneThreshold: 0.9,
367
- });
368
-
369
- const tokens = estimateTokens("Your text here");
370
- ```
371
-
372
- ### Model Capabilities
373
-
374
- ```typescript
375
- import {
376
- ModelCapabilityResolver,
377
- getDefaultResolver
378
- } from "@cuylabs/agent-core";
379
-
380
- const resolver = getDefaultResolver();
381
- const caps = await resolver.resolve("gpt-4o");
382
-
383
- console.log(caps.supportsImages);
384
- console.log(caps.supportsToolUse);
385
- console.log(caps.maxOutputTokens);
110
+ import { createAgent, Tool } from "@cuylabs/agent-core";
111
+ import type { AgentMiddleware } from "@cuylabs/agent-core/middleware";
112
+ import { createAgentTaskRunner } from "@cuylabs/agent-core/runtime";
113
+ import { createPromptBuilder } from "@cuylabs/agent-core/prompt";
114
+ import { createSkillRegistry } from "@cuylabs/agent-core/skill";
115
+ import { createSubAgentTools } from "@cuylabs/agent-core/sub-agent";
116
+ import { createMCPManager } from "@cuylabs/agent-core/mcp";
386
117
  ```
387
118
 
388
- ### MCP (Model Context Protocol)
119
+ Additional focused entrypoints are available for `tool`, `tracking`, `storage`,
120
+ `context`, `reasoning`, `capabilities`, and `models`.
389
121
 
390
- ```typescript
391
- import {
392
- createAgent,
393
- createMCPManager,
394
- stdioServer
395
- } from "@cuylabs/agent-core";
396
- import { anthropic } from "@ai-sdk/anthropic";
397
-
398
- // Create MCP manager with servers
399
- const mcp = createMCPManager({
400
- filesystem: stdioServer("npx", [
401
- "-y", "@modelcontextprotocol/server-filesystem", "/tmp"
402
- ]),
403
- });
122
+ ## Relationship To The Runtime Packages
404
123
 
405
- // Create agent with MCP tools
406
- const agent = createAgent({
407
- model: anthropic("claude-sonnet-4-20250514"),
408
- mcp,
409
- });
410
-
411
- // MCP tools are automatically available
412
- const result = await agent.send("session", "List files in /tmp");
124
+ The layering is:
413
125
 
414
- // Clean up
415
- await agent.close();
126
+ ```text
127
+ agent-core
128
+ -> agent-runtime
129
+ -> agent-runtime-dapr
416
130
  ```
417
131
 
418
- ## Event Types
419
-
420
- The `chat()` method yields these event types:
132
+ - `agent-core` owns live agent execution
133
+ - `agent-runtime` owns generic workload scheduling and dispatch
134
+ - `agent-runtime-dapr` adds Dapr-backed durability and host integration
421
135
 
422
- | Event Type | Description |
423
- |------------|-------------|
424
- | `text-delta` | Streaming text chunk |
425
- | `text-start` / `text-end` | Text generation boundaries |
426
- | `tool-start` | Tool invocation started |
427
- | `tool-result` | Tool execution completed |
428
- | `tool-error` | Tool execution failed |
429
- | `step-start` / `step-finish` | LLM step boundaries with usage stats |
430
- | `reasoning-delta` | Model reasoning chunk (if supported) |
431
- | `status` | Agent state changes (thinking, calling-tool, etc.) |
432
- | `doom-loop` | Repeated tool call pattern detected |
433
- | `context-overflow` | Context window exceeded |
434
- | `message` | Complete user/assistant message |
435
- | `complete` | Stream finished with usage stats |
436
- | `error` | Unrecoverable error |
136
+ If you need durable orchestration, `agent-core` already exposes the task and
137
+ turn surfaces those packages build on:
437
138
 
438
- See [examples/03-streaming.ts](examples/03-streaming.ts) for a complete event handling example.
139
+ - `createAgentTaskRunner(...)`
140
+ - task execution observers and checkpoints
141
+ - turn-step helpers such as `prepareModelStep(...)` and `runToolBatch(...)`
142
+ - workflow-safe state/planning helpers
439
143
 
440
- ## Concurrency Note
144
+ ## Learn More
441
145
 
442
- 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.
146
+ Start with the package docs:
443
147
 
444
- ## Examples
148
+ - [docs/README.md](./docs/README.md) for the learning path
149
+ - [docs/agent.md](./docs/agent.md) for the main `Agent` API
150
+ - [docs/middleware.md](./docs/middleware.md) for model/tool hooks and lifecycle middleware
151
+ - [docs/tools.md](./docs/tools.md) for tool definition and execution
152
+ - [docs/runtime-integration.md](./docs/runtime-integration.md) for task/turn/workflow runtime integration
153
+ - [docs/tracing.md](./docs/tracing.md) for tracing setup
445
154
 
446
- See [examples/](examples/) for 20 runnable examples covering every feature — from basic chat to middleware, skills, tracing, and Docker execution. The [examples README](examples/README.md) has setup instructions and run commands.
155
+ Runnable examples live in [examples/README.md](./examples/README.md).
447
156
 
448
- ## Documentation
157
+ ## License
449
158
 
450
- See [docs/](docs/) for in-depth guides on each subsystem.
159
+ Apache-2.0
@@ -1,4 +1,4 @@
1
- import { P as PromptConfig, a as PromptBuildContext, M as MiddlewareRunner, b as PromptSection, c as ModelFamily } from './runner-C7aMP_x3.js';
1
+ import { P as PromptConfig, a as PromptBuildContext, M as MiddlewareRunner, b as PromptSection, c as ModelFamily } from './runner-G1wxEgac.js';
2
2
  import { S as SkillRegistry } from './registry-CuRWWtcT.js';
3
3
 
4
4
  interface PromptSectionPreview {