klaus-agent 0.1.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 +685 -0
- package/dist/approval/approval.d.ts +18 -0
- package/dist/approval/approval.js +93 -0
- package/dist/approval/approval.js.map +1 -0
- package/dist/approval/types.d.ts +21 -0
- package/dist/approval/types.js +3 -0
- package/dist/approval/types.js.map +1 -0
- package/dist/background/task-manager.d.ts +14 -0
- package/dist/background/task-manager.js +89 -0
- package/dist/background/task-manager.js.map +1 -0
- package/dist/background/tools.d.ts +4 -0
- package/dist/background/tools.js +74 -0
- package/dist/background/tools.js.map +1 -0
- package/dist/background/types.d.ts +31 -0
- package/dist/background/types.js +3 -0
- package/dist/background/types.js.map +1 -0
- package/dist/checkpoint/checkpoint-manager.d.ts +19 -0
- package/dist/checkpoint/checkpoint-manager.js +49 -0
- package/dist/checkpoint/checkpoint-manager.js.map +1 -0
- package/dist/checkpoint/dmail.d.ts +10 -0
- package/dist/checkpoint/dmail.js +26 -0
- package/dist/checkpoint/dmail.js.map +1 -0
- package/dist/checkpoint/types.d.ts +12 -0
- package/dist/checkpoint/types.js +3 -0
- package/dist/checkpoint/types.js.map +1 -0
- package/dist/compaction/compaction.d.ts +6 -0
- package/dist/compaction/compaction.js +104 -0
- package/dist/compaction/compaction.js.map +1 -0
- package/dist/compaction/summarizer.d.ts +10 -0
- package/dist/compaction/summarizer.js +75 -0
- package/dist/compaction/summarizer.js.map +1 -0
- package/dist/compaction/types.d.ts +23 -0
- package/dist/compaction/types.js +3 -0
- package/dist/compaction/types.js.map +1 -0
- package/dist/core/agent-loop.d.ts +37 -0
- package/dist/core/agent-loop.js +337 -0
- package/dist/core/agent-loop.js.map +1 -0
- package/dist/core/agent.d.ts +97 -0
- package/dist/core/agent.js +335 -0
- package/dist/core/agent.js.map +1 -0
- package/dist/extensions/runner.d.ts +19 -0
- package/dist/extensions/runner.js +88 -0
- package/dist/extensions/runner.js.map +1 -0
- package/dist/extensions/types.d.ts +179 -0
- package/dist/extensions/types.js +3 -0
- package/dist/extensions/types.js.map +1 -0
- package/dist/index.d.ts +78 -0
- package/dist/index.js +53 -0
- package/dist/index.js.map +1 -0
- package/dist/injection/history-normalizer.d.ts +2 -0
- package/dist/injection/history-normalizer.js +34 -0
- package/dist/injection/history-normalizer.js.map +1 -0
- package/dist/injection/injection-manager.d.ts +8 -0
- package/dist/injection/injection-manager.js +28 -0
- package/dist/injection/injection-manager.js.map +1 -0
- package/dist/injection/types.d.ts +8 -0
- package/dist/injection/types.js +3 -0
- package/dist/injection/types.js.map +1 -0
- package/dist/llm/provider.d.ts +16 -0
- package/dist/llm/provider.js +233 -0
- package/dist/llm/provider.js.map +1 -0
- package/dist/llm/types.d.ts +110 -0
- package/dist/llm/types.js +3 -0
- package/dist/llm/types.js.map +1 -0
- package/dist/multi-agent/labor-market.d.ts +16 -0
- package/dist/multi-agent/labor-market.js +40 -0
- package/dist/multi-agent/labor-market.js.map +1 -0
- package/dist/multi-agent/task-executor.d.ts +12 -0
- package/dist/multi-agent/task-executor.js +38 -0
- package/dist/multi-agent/task-executor.js.map +1 -0
- package/dist/multi-agent/task-tool.d.ts +4 -0
- package/dist/multi-agent/task-tool.js +46 -0
- package/dist/multi-agent/task-tool.js.map +1 -0
- package/dist/multi-agent/types.d.ts +7 -0
- package/dist/multi-agent/types.js +3 -0
- package/dist/multi-agent/types.js.map +1 -0
- package/dist/session/session-context-builder.d.ts +2 -0
- package/dist/session/session-context-builder.js +52 -0
- package/dist/session/session-context-builder.js.map +1 -0
- package/dist/session/session-manager.d.ts +30 -0
- package/dist/session/session-manager.js +209 -0
- package/dist/session/session-manager.js.map +1 -0
- package/dist/session/types.d.ts +61 -0
- package/dist/session/types.js +3 -0
- package/dist/session/types.js.map +1 -0
- package/dist/skills/discovery.d.ts +2 -0
- package/dist/skills/discovery.js +29 -0
- package/dist/skills/discovery.js.map +1 -0
- package/dist/skills/loader.d.ts +3 -0
- package/dist/skills/loader.js +46 -0
- package/dist/skills/loader.js.map +1 -0
- package/dist/skills/skill-tool.d.ts +3 -0
- package/dist/skills/skill-tool.js +38 -0
- package/dist/skills/skill-tool.js.map +1 -0
- package/dist/skills/types.d.ts +14 -0
- package/dist/skills/types.js +3 -0
- package/dist/skills/types.js.map +1 -0
- package/dist/tools/executor.d.ts +37 -0
- package/dist/tools/executor.js +131 -0
- package/dist/tools/executor.js.map +1 -0
- package/dist/tools/mcp-adapter.d.ts +57 -0
- package/dist/tools/mcp-adapter.js +113 -0
- package/dist/tools/mcp-adapter.js.map +1 -0
- package/dist/tools/types.d.ts +43 -0
- package/dist/tools/types.js +2 -0
- package/dist/tools/types.js.map +1 -0
- package/dist/types.d.ts +96 -0
- package/dist/types.js +3 -0
- package/dist/types.js.map +1 -0
- package/dist/utils/id.d.ts +1 -0
- package/dist/utils/id.js +9 -0
- package/dist/utils/id.js.map +1 -0
- package/dist/utils/jsonl.d.ts +3 -0
- package/dist/utils/jsonl.js +17 -0
- package/dist/utils/jsonl.js.map +1 -0
- package/dist/wire/types.d.ts +10 -0
- package/dist/wire/types.js +3 -0
- package/dist/wire/types.js.map +1 -0
- package/dist/wire/wire.d.ts +20 -0
- package/dist/wire/wire.js +71 -0
- package/dist/wire/wire.js.map +1 -0
- package/package.json +26 -0
- package/src/approval/approval.ts +108 -0
- package/src/approval/types.ts +26 -0
- package/src/background/task-manager.ts +112 -0
- package/src/background/tools.ts +84 -0
- package/src/background/types.ts +29 -0
- package/src/checkpoint/checkpoint-manager.ts +60 -0
- package/src/checkpoint/dmail.ts +35 -0
- package/src/checkpoint/types.ts +16 -0
- package/src/compaction/compaction.ts +119 -0
- package/src/compaction/summarizer.ts +83 -0
- package/src/compaction/types.ts +29 -0
- package/src/core/agent-loop.ts +427 -0
- package/src/core/agent.ts +430 -0
- package/src/extensions/runner.ts +138 -0
- package/src/extensions/types.ts +177 -0
- package/src/index.ts +221 -0
- package/src/injection/history-normalizer.ts +44 -0
- package/src/injection/injection-manager.ts +34 -0
- package/src/injection/types.ts +12 -0
- package/src/llm/provider.ts +254 -0
- package/src/llm/types.ts +146 -0
- package/src/multi-agent/labor-market.ts +54 -0
- package/src/multi-agent/task-executor.ts +49 -0
- package/src/multi-agent/task-tool.ts +58 -0
- package/src/multi-agent/types.ts +10 -0
- package/src/session/session-context-builder.ts +65 -0
- package/src/session/session-manager.ts +258 -0
- package/src/session/types.ts +93 -0
- package/src/skills/discovery.ts +32 -0
- package/src/skills/loader.ts +54 -0
- package/src/skills/skill-tool.ts +50 -0
- package/src/skills/types.ts +18 -0
- package/src/tools/executor.ts +196 -0
- package/src/tools/mcp-adapter.ts +185 -0
- package/src/tools/types.ts +64 -0
- package/src/types.ts +96 -0
- package/src/utils/id.ts +8 -0
- package/src/utils/jsonl.ts +19 -0
- package/src/wire/types.ts +14 -0
- package/src/wire/wire.ts +79 -0
- package/tsconfig.json +19 -0
package/README.md
ADDED
|
@@ -0,0 +1,685 @@
|
|
|
1
|
+
# @klaus-ai/agent
|
|
2
|
+
|
|
3
|
+
Universal agent framework SDK. Inject tools, skills, and systemPrompt to build your agent — no wrapper needed.
|
|
4
|
+
|
|
5
|
+
通用 Agent 框架 SDK。注入 tools、skills、systemPrompt 即可构建 agent,无需再包一层。
|
|
6
|
+
|
|
7
|
+
## Install
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
npm install @klaus-ai/agent
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## Quick Start
|
|
14
|
+
|
|
15
|
+
```typescript
|
|
16
|
+
import { createAgent } from "@klaus-ai/agent";
|
|
17
|
+
import { Type } from "@sinclair/typebox";
|
|
18
|
+
|
|
19
|
+
const agent = createAgent({
|
|
20
|
+
model: { provider: "anthropic", model: "claude-sonnet-4-20250514", maxContextTokens: 200000 },
|
|
21
|
+
systemPrompt: "You are a helpful assistant.",
|
|
22
|
+
tools: [
|
|
23
|
+
{
|
|
24
|
+
name: "echo",
|
|
25
|
+
label: "Echo",
|
|
26
|
+
description: "Echo back the input",
|
|
27
|
+
parameters: Type.Object({ text: Type.String() }),
|
|
28
|
+
async execute(_id, params) {
|
|
29
|
+
return { content: [{ type: "text", text: params.text }] };
|
|
30
|
+
},
|
|
31
|
+
},
|
|
32
|
+
],
|
|
33
|
+
approval: { yolo: true },
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
// Subscribe to streaming events
|
|
37
|
+
agent.subscribe((event) => {
|
|
38
|
+
if (event.type === "message_update" && event.event.type === "text") {
|
|
39
|
+
process.stdout.write(event.event.text);
|
|
40
|
+
}
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
const messages = await agent.prompt("Say hello");
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
## Architecture
|
|
47
|
+
|
|
48
|
+
Single package, 14 modules, zero wrappers. All capabilities are built-in and opt-in via config.
|
|
49
|
+
|
|
50
|
+
单包架构,14 个模块,零包装层。所有能力内置,通过 config 按需启用。
|
|
51
|
+
|
|
52
|
+
```
|
|
53
|
+
src/
|
|
54
|
+
├── core/ Agent + AgentLoop (nested dual-loop runtime)
|
|
55
|
+
├── llm/ Provider abstraction + Anthropic implementation
|
|
56
|
+
├── tools/ Tool executor (sequential/parallel) + MCP adapter
|
|
57
|
+
├── approval/ Queue-based approval system
|
|
58
|
+
├── session/ JSONL tree persistence with branching
|
|
59
|
+
├── compaction/ Token estimation + LLM summarization
|
|
60
|
+
├── checkpoint/ Checkpoint + D-Mail time travel
|
|
61
|
+
├── injection/ Dynamic context injection + history normalization
|
|
62
|
+
├── multi-agent/ LaborMarket subagent registry + TaskExecutor
|
|
63
|
+
├── extensions/ Event-driven plugin system
|
|
64
|
+
├── skills/ Markdown skill discovery + template rendering
|
|
65
|
+
├── wire/ Typed async event channel with replay buffer
|
|
66
|
+
├── background/ In-process async task manager
|
|
67
|
+
└── utils/ ID generation + JSONL helpers
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
## Modules
|
|
71
|
+
|
|
72
|
+
### Core — Agent Loop
|
|
73
|
+
|
|
74
|
+
Nested dual-loop execution engine:
|
|
75
|
+
|
|
76
|
+
- Inner loop: LLM call → tool execution → steering messages → repeat until no more tool calls
|
|
77
|
+
- Outer loop: follow-up messages → re-enter inner loop
|
|
78
|
+
|
|
79
|
+
Each step integrates: checkpoint → compaction check → dynamic injection → history normalization → extension context hook → LLM stream → tool execution → D-Mail check → steering.
|
|
80
|
+
|
|
81
|
+
```typescript
|
|
82
|
+
const agent = createAgent({
|
|
83
|
+
model: { provider: "anthropic", model: "claude-sonnet-4-20250514", maxContextTokens: 200000 },
|
|
84
|
+
systemPrompt: "You are a helpful assistant.",
|
|
85
|
+
tools: [...],
|
|
86
|
+
maxStepsPerTurn: 50, // Max inner loop iterations (default: 50)
|
|
87
|
+
toolExecution: "parallel", // "sequential" | "parallel" (default: "parallel")
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
// Run a prompt
|
|
91
|
+
const messages = await agent.prompt("Hello");
|
|
92
|
+
|
|
93
|
+
// Continue without new input
|
|
94
|
+
const more = await agent.continue();
|
|
95
|
+
|
|
96
|
+
// Inject messages mid-run
|
|
97
|
+
agent.steer({ role: "user", content: "Focus on X" }); // Injected after current tool execution
|
|
98
|
+
agent.followUp({ role: "user", content: "Also do Y" }); // Injected after inner loop completes
|
|
99
|
+
|
|
100
|
+
// Abort
|
|
101
|
+
agent.abort();
|
|
102
|
+
|
|
103
|
+
// Cleanup
|
|
104
|
+
await agent.dispose();
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
### LLM Provider
|
|
108
|
+
|
|
109
|
+
Provider-agnostic abstraction. Built-in Anthropic provider with streaming, retry (3 attempts, exponential backoff), and extended thinking support.
|
|
110
|
+
|
|
111
|
+
```typescript
|
|
112
|
+
import { registerProvider, resolveProvider } from "@klaus-ai/agent";
|
|
113
|
+
|
|
114
|
+
// Register a custom provider
|
|
115
|
+
registerProvider("openai", (config) => new MyOpenAIProvider(config.apiKey));
|
|
116
|
+
|
|
117
|
+
// Use it
|
|
118
|
+
const agent = createAgent({
|
|
119
|
+
model: { provider: "openai", model: "gpt-4", maxContextTokens: 128000 },
|
|
120
|
+
...
|
|
121
|
+
});
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
Provider interface:
|
|
125
|
+
|
|
126
|
+
```typescript
|
|
127
|
+
interface LLMProvider {
|
|
128
|
+
stream(options: LLMRequestOptions): AsyncIterable<AssistantMessageEvent>;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
// Stream events: text | tool_call_start | tool_call_delta | thinking | done | error
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
### Canonical Message Format
|
|
135
|
+
|
|
136
|
+
Provider-agnostic message types used throughout the framework:
|
|
137
|
+
|
|
138
|
+
```typescript
|
|
139
|
+
type Message = UserMessage | AssistantMessage | ToolResultMessage;
|
|
140
|
+
|
|
141
|
+
interface UserMessage {
|
|
142
|
+
role: "user";
|
|
143
|
+
content: string | ContentBlock[]; // ContentBlock = TextContent | ImageContent
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
interface AssistantMessage {
|
|
147
|
+
role: "assistant";
|
|
148
|
+
content: AssistantContentBlock[]; // TextBlock | ToolCallBlock | ThinkingBlock
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
interface ToolResultMessage {
|
|
152
|
+
role: "tool_result";
|
|
153
|
+
toolCallId: string;
|
|
154
|
+
content: string | ContentBlock[];
|
|
155
|
+
isError?: boolean;
|
|
156
|
+
}
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
Extensible via `CustomAgentMessages` interface for framework consumers to add custom message types.
|
|
160
|
+
|
|
161
|
+
### Tools
|
|
162
|
+
|
|
163
|
+
Tools use TypeBox schemas for parameter validation. The executor supports sequential and parallel modes with approval gating.
|
|
164
|
+
|
|
165
|
+
```typescript
|
|
166
|
+
import { Type } from "@sinclair/typebox";
|
|
167
|
+
import type { AgentTool } from "@klaus-ai/agent";
|
|
168
|
+
|
|
169
|
+
const readFile: AgentTool = {
|
|
170
|
+
name: "read_file",
|
|
171
|
+
label: "Read File",
|
|
172
|
+
description: "Read a file from disk",
|
|
173
|
+
parameters: Type.Object({
|
|
174
|
+
path: Type.String({ description: "File path" }),
|
|
175
|
+
}),
|
|
176
|
+
approvalAction: "file:read", // Triggers approval unless yolo mode
|
|
177
|
+
|
|
178
|
+
async execute(toolCallId, params, context) {
|
|
179
|
+
// context.signal — AbortSignal
|
|
180
|
+
// context.onUpdate — stream partial results
|
|
181
|
+
// context.approval — approval interface
|
|
182
|
+
// context.agentName — parent agent name
|
|
183
|
+
const text = await fs.readFile(params.path, "utf-8");
|
|
184
|
+
return { content: [{ type: "text", text }] };
|
|
185
|
+
},
|
|
186
|
+
};
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
Parallel mode: approval and beforeToolCall hooks run sequentially (preflight), then all approved tools execute concurrently.
|
|
190
|
+
|
|
191
|
+
### Approval
|
|
192
|
+
|
|
193
|
+
Queue-based approval system with three modes:
|
|
194
|
+
|
|
195
|
+
```typescript
|
|
196
|
+
const agent = createAgent({
|
|
197
|
+
approval: {
|
|
198
|
+
yolo: true, // Auto-approve everything
|
|
199
|
+
autoApproveActions: ["file:read"], // Auto-approve specific actions
|
|
200
|
+
},
|
|
201
|
+
...
|
|
202
|
+
});
|
|
203
|
+
|
|
204
|
+
// UI integration — pull pending requests and resolve them
|
|
205
|
+
const request = await agent.approval.fetchRequest();
|
|
206
|
+
// request: { id, toolCallId, sender, action, description }
|
|
207
|
+
agent.approval.resolve(request.id, "approve"); // One-time approve
|
|
208
|
+
agent.approval.resolve(request.id, "approve_for_session"); // Auto-approve this action going forward
|
|
209
|
+
agent.approval.resolve(request.id, "reject");
|
|
210
|
+
|
|
211
|
+
// Subagents share yolo/autoApproveActions state via approval.share()
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
### Thinking
|
|
215
|
+
|
|
216
|
+
Six-level extended thinking budget:
|
|
217
|
+
|
|
218
|
+
```typescript
|
|
219
|
+
const agent = createAgent({
|
|
220
|
+
thinkingLevel: "medium", // "off" | "minimal" | "low" | "medium" | "high" | "xhigh"
|
|
221
|
+
model: {
|
|
222
|
+
provider: "anthropic",
|
|
223
|
+
model: "claude-sonnet-4-20250514",
|
|
224
|
+
maxContextTokens: 200000,
|
|
225
|
+
capabilities: { thinking: true },
|
|
226
|
+
},
|
|
227
|
+
...
|
|
228
|
+
});
|
|
229
|
+
|
|
230
|
+
// Change at runtime
|
|
231
|
+
agent.setThinkingLevel("high");
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
Token budgets: minimal=1024, low=4096, medium=10240, high=20480, xhigh=40960.
|
|
235
|
+
|
|
236
|
+
### Session Persistence
|
|
237
|
+
|
|
238
|
+
JSONL tree-based session storage with branching and restore.
|
|
239
|
+
|
|
240
|
+
```typescript
|
|
241
|
+
const agent = createAgent({
|
|
242
|
+
session: {
|
|
243
|
+
persist: true,
|
|
244
|
+
directory: "./sessions",
|
|
245
|
+
sessionId: "my-session", // Optional, auto-generated if omitted
|
|
246
|
+
},
|
|
247
|
+
...
|
|
248
|
+
});
|
|
249
|
+
|
|
250
|
+
// Access session tree
|
|
251
|
+
const tree = agent.session.getTree();
|
|
252
|
+
const branch = agent.session.getBranch();
|
|
253
|
+
|
|
254
|
+
// Branch from a specific entry
|
|
255
|
+
agent.session.branch(entryId);
|
|
256
|
+
|
|
257
|
+
// Entry types: message | compaction | branch_summary | model_change |
|
|
258
|
+
// thinking_level_change | checkpoint | custom
|
|
259
|
+
```
|
|
260
|
+
|
|
261
|
+
Session file format: first line is a header `{ type: "session", version: 1, id, timestamp }`, followed by one JSON entry per line, each with `{ type, id, parentId, timestamp, ... }`.
|
|
262
|
+
|
|
263
|
+
### Compaction
|
|
264
|
+
|
|
265
|
+
Automatic context compression when token count exceeds threshold.
|
|
266
|
+
|
|
267
|
+
```typescript
|
|
268
|
+
const agent = createAgent({
|
|
269
|
+
compaction: {
|
|
270
|
+
enabled: true,
|
|
271
|
+
maxContextTokens: 200000, // Defaults to model.maxContextTokens
|
|
272
|
+
reserveTokens: 16384, // Reserve for output
|
|
273
|
+
keepRecentTokens: 20000, // Keep recent messages
|
|
274
|
+
customSummarizer: mySummarizer, // Optional custom summarizer
|
|
275
|
+
},
|
|
276
|
+
...
|
|
277
|
+
});
|
|
278
|
+
```
|
|
279
|
+
|
|
280
|
+
Flow: estimate tokens → check threshold → find cut point (respects tool_result boundaries) → summarize discarded messages via LLM → replace with `<compaction-summary>` → persist to session.
|
|
281
|
+
|
|
282
|
+
Built-in `LLMSummarizer` uses the same provider to generate summaries. Supports incremental summarization with `previousSummary`.
|
|
283
|
+
|
|
284
|
+
### Checkpoint + D-Mail
|
|
285
|
+
|
|
286
|
+
Time-travel via the Steins;Gate-inspired D-Mail mechanism. Checkpoints are created before each agent loop step.
|
|
287
|
+
|
|
288
|
+
```typescript
|
|
289
|
+
const agent = createAgent({
|
|
290
|
+
session: { persist: true, directory: "./sessions" },
|
|
291
|
+
checkpoint: { enabled: true, enableDMail: true },
|
|
292
|
+
...
|
|
293
|
+
});
|
|
294
|
+
|
|
295
|
+
// Send a D-Mail — branches session tree back to target checkpoint
|
|
296
|
+
agent.checkpoints.denwaRenji.sendDMail("Try a different approach", checkpointId);
|
|
297
|
+
|
|
298
|
+
// The agent loop automatically:
|
|
299
|
+
// 1. Detects pending D-Mail after tool execution
|
|
300
|
+
// 2. Branches session tree to target checkpoint
|
|
301
|
+
// 3. Injects D-Mail content as <dmail> message
|
|
302
|
+
// 4. Continues execution from that point
|
|
303
|
+
```
|
|
304
|
+
|
|
305
|
+
### Dynamic Injection
|
|
306
|
+
|
|
307
|
+
Inject context into the message stream before each LLM call, without modifying the persistent history.
|
|
308
|
+
|
|
309
|
+
```typescript
|
|
310
|
+
const agent = createAgent({
|
|
311
|
+
injection: [
|
|
312
|
+
{
|
|
313
|
+
async getInjections(history) {
|
|
314
|
+
return [
|
|
315
|
+
{ type: "memory", content: "User prefers TypeScript" },
|
|
316
|
+
{ type: "context", content: `Current time: ${new Date().toISOString()}` },
|
|
317
|
+
];
|
|
318
|
+
},
|
|
319
|
+
},
|
|
320
|
+
],
|
|
321
|
+
...
|
|
322
|
+
});
|
|
323
|
+
```
|
|
324
|
+
|
|
325
|
+
Injections are wrapped as `<system-reminder type="...">` user messages. History normalization merges adjacent user messages to maintain valid message alternation.
|
|
326
|
+
|
|
327
|
+
### Multi-Agent
|
|
328
|
+
|
|
329
|
+
LaborMarket registry with fixed and dynamic subagents. The LLM delegates via the built-in `delegate_task` tool.
|
|
330
|
+
|
|
331
|
+
```typescript
|
|
332
|
+
const agent = createAgent({
|
|
333
|
+
subagents: {
|
|
334
|
+
researcher: {
|
|
335
|
+
name: "researcher",
|
|
336
|
+
systemPrompt: "You are a research assistant.",
|
|
337
|
+
description: "Handles research tasks",
|
|
338
|
+
tools: [searchTool],
|
|
339
|
+
},
|
|
340
|
+
writer: {
|
|
341
|
+
name: "writer",
|
|
342
|
+
systemPrompt: "You are a writing assistant.",
|
|
343
|
+
description: "Handles writing tasks",
|
|
344
|
+
},
|
|
345
|
+
},
|
|
346
|
+
...
|
|
347
|
+
});
|
|
348
|
+
|
|
349
|
+
// Dynamic subagent registration at runtime
|
|
350
|
+
agent.laborMarket.addDynamic("analyst", analystAgent, "Data analysis");
|
|
351
|
+
agent.laborMarket.removeDynamic("analyst");
|
|
352
|
+
```
|
|
353
|
+
|
|
354
|
+
Subagents share the parent's approval state (yolo, autoApproveActions) but have independent approval queues. Subagent events are forwarded to the parent's event stream.
|
|
355
|
+
|
|
356
|
+
### Extensions
|
|
357
|
+
|
|
358
|
+
Event-driven plugin system with 18 event types across agent lifecycle, tool execution, LLM requests, context, compaction, session, and background tasks.
|
|
359
|
+
|
|
360
|
+
```typescript
|
|
361
|
+
import type { ExtensionFactory } from "@klaus-ai/agent";
|
|
362
|
+
|
|
363
|
+
const myExtension: ExtensionFactory = (api) => {
|
|
364
|
+
// Register event handlers
|
|
365
|
+
api.on("before_agent_start", (event) => {
|
|
366
|
+
return { systemPrompt: event.systemPrompt + "\nExtra instructions." };
|
|
367
|
+
});
|
|
368
|
+
|
|
369
|
+
api.on("tool_call", (event) => {
|
|
370
|
+
if (event.toolName === "dangerous_tool") {
|
|
371
|
+
return { block: true, reason: "Not allowed" };
|
|
372
|
+
}
|
|
373
|
+
});
|
|
374
|
+
|
|
375
|
+
api.on("before_provider_request", (event) => {
|
|
376
|
+
return { messages: event.messages }; // Modify LLM request
|
|
377
|
+
});
|
|
378
|
+
|
|
379
|
+
api.on("context", (event) => {
|
|
380
|
+
return { messages: [...event.messages, extraMsg] };
|
|
381
|
+
});
|
|
382
|
+
|
|
383
|
+
api.on("before_compact", (event) => {
|
|
384
|
+
return { skip: true }; // Or provide custom summary
|
|
385
|
+
});
|
|
386
|
+
|
|
387
|
+
// Register tools
|
|
388
|
+
api.registerTool(myTool);
|
|
389
|
+
|
|
390
|
+
// Register commands
|
|
391
|
+
api.registerCommand("my-command", async (args) => { ... });
|
|
392
|
+
|
|
393
|
+
// Inject messages into the conversation
|
|
394
|
+
api.sendMessage({ role: "user", content: "Injected by extension" });
|
|
395
|
+
};
|
|
396
|
+
|
|
397
|
+
const agent = createAgent({ extensions: [myExtension], ... });
|
|
398
|
+
```
|
|
399
|
+
|
|
400
|
+
Interceptable events (return values modify behavior): `before_agent_start`, `before_provider_request`, `tool_call`, `tool_result`, `context`, `before_compact`.
|
|
401
|
+
|
|
402
|
+
Notification events (fire-and-forget): `agent_start`, `agent_end`, `turn_start`, `turn_end`, `message_start`, `message_end`, `after_compact`, `session_start`, `session_switch`, `session_fork`, `task_started`, `task_completed`, `task_failed`.
|
|
403
|
+
|
|
404
|
+
### Skills
|
|
405
|
+
|
|
406
|
+
Markdown-based skill discovery with frontmatter parsing and template rendering.
|
|
407
|
+
|
|
408
|
+
```typescript
|
|
409
|
+
const agent = createAgent({
|
|
410
|
+
skills: [{ directory: "./skills", pattern: ".md" }],
|
|
411
|
+
...
|
|
412
|
+
});
|
|
413
|
+
```
|
|
414
|
+
|
|
415
|
+
Skill file format (`./skills/review.md`):
|
|
416
|
+
|
|
417
|
+
```markdown
|
|
418
|
+
---
|
|
419
|
+
name: review
|
|
420
|
+
description: Code review checklist
|
|
421
|
+
---
|
|
422
|
+
|
|
423
|
+
Review the code for:
|
|
424
|
+
- Security: {{focus_area}}
|
|
425
|
+
- Performance issues
|
|
426
|
+
- Code style
|
|
427
|
+
```
|
|
428
|
+
|
|
429
|
+
The LLM invokes skills via the built-in `invoke_skill` tool with optional template variables.
|
|
430
|
+
|
|
431
|
+
### MCP (Model Context Protocol)
|
|
432
|
+
|
|
433
|
+
Connect to MCP servers and expose their tools to the agent.
|
|
434
|
+
|
|
435
|
+
```typescript
|
|
436
|
+
const agent = createAgent({
|
|
437
|
+
mcp: {
|
|
438
|
+
servers: [
|
|
439
|
+
{
|
|
440
|
+
name: "filesystem",
|
|
441
|
+
transport: { type: "stdio", command: "mcp-server-fs", args: ["--root", "/tmp"] },
|
|
442
|
+
timeout: 30000,
|
|
443
|
+
},
|
|
444
|
+
{
|
|
445
|
+
name: "web",
|
|
446
|
+
transport: { type: "sse", url: "http://localhost:3001/sse" },
|
|
447
|
+
},
|
|
448
|
+
],
|
|
449
|
+
clientFactory: (config) => new MyMCPClient(config),
|
|
450
|
+
},
|
|
451
|
+
...
|
|
452
|
+
});
|
|
453
|
+
|
|
454
|
+
// Check server statuses
|
|
455
|
+
const statuses = agent.mcpAdapter.getStatuses();
|
|
456
|
+
// [{ name: "filesystem", status: "connected", tools: [...] }]
|
|
457
|
+
```
|
|
458
|
+
|
|
459
|
+
MCP tools are namespaced as `{serverName}__{toolName}` and require approval via `mcp:{serverName}:{toolName}` action.
|
|
460
|
+
|
|
461
|
+
### Wire (Event Channel)
|
|
462
|
+
|
|
463
|
+
Typed async pub/sub event channel with optional replay buffer. All agent events are automatically published to the wire.
|
|
464
|
+
|
|
465
|
+
```typescript
|
|
466
|
+
const agent = createAgent({
|
|
467
|
+
wire: { bufferSize: 100 }, // Buffer last 100 messages for late subscribers
|
|
468
|
+
...
|
|
469
|
+
});
|
|
470
|
+
|
|
471
|
+
// Subscribe to specific event types
|
|
472
|
+
agent.wire.on("tool_execution_end", (msg) => {
|
|
473
|
+
console.log(`Tool ${msg.payload.toolName} completed`);
|
|
474
|
+
});
|
|
475
|
+
|
|
476
|
+
// Subscribe to all events
|
|
477
|
+
agent.wire.subscribe((msg) => {
|
|
478
|
+
console.log(msg.type, msg.payload);
|
|
479
|
+
}, { replay: true }); // Replay buffered messages
|
|
480
|
+
|
|
481
|
+
// Publish custom events
|
|
482
|
+
agent.wire.publish("custom_event", { data: "hello" });
|
|
483
|
+
```
|
|
484
|
+
|
|
485
|
+
### Background Tasks
|
|
486
|
+
|
|
487
|
+
In-process async task execution with lifecycle events. The LLM manages tasks via built-in tools.
|
|
488
|
+
|
|
489
|
+
```typescript
|
|
490
|
+
const agent = createAgent({
|
|
491
|
+
backgroundTasks: {
|
|
492
|
+
factories: {
|
|
493
|
+
build: async (args, signal) => {
|
|
494
|
+
// Long-running task with abort support
|
|
495
|
+
return { success: true };
|
|
496
|
+
},
|
|
497
|
+
},
|
|
498
|
+
},
|
|
499
|
+
...
|
|
500
|
+
});
|
|
501
|
+
|
|
502
|
+
// Programmatic access
|
|
503
|
+
const handle = agent.backgroundTasks.spawn("my-task", async (signal) => {
|
|
504
|
+
return await doWork(signal);
|
|
505
|
+
});
|
|
506
|
+
|
|
507
|
+
console.log(handle.status); // "running" | "completed" | "failed"
|
|
508
|
+
handle.abort();
|
|
509
|
+
```
|
|
510
|
+
|
|
511
|
+
Built-in tools: `start_background_task`, `check_task_status`, `get_task_result`.
|
|
512
|
+
|
|
513
|
+
### Hooks
|
|
514
|
+
|
|
515
|
+
User-level hooks for transforming context and intercepting tool calls:
|
|
516
|
+
|
|
517
|
+
```typescript
|
|
518
|
+
const agent = createAgent({
|
|
519
|
+
hooks: {
|
|
520
|
+
// Transform messages before sending to LLM
|
|
521
|
+
transformContext: async (messages) => {
|
|
522
|
+
return messages.filter(m => ...);
|
|
523
|
+
},
|
|
524
|
+
// Custom message format conversion
|
|
525
|
+
convertToLlm: (messages) => {
|
|
526
|
+
return messages.filter(m => m.role === "user" || m.role === "assistant" || m.role === "tool_result");
|
|
527
|
+
},
|
|
528
|
+
// Before/after tool execution
|
|
529
|
+
beforeToolCall: async (ctx) => {
|
|
530
|
+
// return { block: true, reason: "..." } to block
|
|
531
|
+
},
|
|
532
|
+
afterToolCall: async (ctx) => {
|
|
533
|
+
// return { content, details, isError } to modify result
|
|
534
|
+
},
|
|
535
|
+
},
|
|
536
|
+
...
|
|
537
|
+
});
|
|
538
|
+
```
|
|
539
|
+
|
|
540
|
+
## Events
|
|
541
|
+
|
|
542
|
+
Subscribe to the agent event stream for real-time updates:
|
|
543
|
+
|
|
544
|
+
```typescript
|
|
545
|
+
agent.subscribe((event) => {
|
|
546
|
+
switch (event.type) {
|
|
547
|
+
case "agent_start":
|
|
548
|
+
case "agent_end": // { messages }
|
|
549
|
+
case "turn_start":
|
|
550
|
+
case "turn_end": // { message, toolResults }
|
|
551
|
+
case "message_start": // { message }
|
|
552
|
+
case "message_update": // { message, event: text|tool_call_start|tool_call_delta|thinking|done }
|
|
553
|
+
case "message_end": // { message, usage }
|
|
554
|
+
case "tool_execution_start": // { toolCallId, toolName, args }
|
|
555
|
+
case "tool_execution_update": // { toolCallId, toolName, partialResult }
|
|
556
|
+
case "tool_execution_end": // { toolCallId, toolName, result, isError }
|
|
557
|
+
case "approval_request": // { request }
|
|
558
|
+
case "approval_response": // { requestId, response }
|
|
559
|
+
case "compaction_start":
|
|
560
|
+
case "compaction_end": // { summary }
|
|
561
|
+
case "checkpoint": // { id }
|
|
562
|
+
case "dmail_received": // { checkpoint, content }
|
|
563
|
+
case "task_started": // { taskId, taskName }
|
|
564
|
+
case "task_completed": // { taskId, taskName }
|
|
565
|
+
case "task_failed": // { taskId, taskName, error }
|
|
566
|
+
case "error": // { error }
|
|
567
|
+
}
|
|
568
|
+
});
|
|
569
|
+
```
|
|
570
|
+
|
|
571
|
+
## Full Example
|
|
572
|
+
|
|
573
|
+
```typescript
|
|
574
|
+
import { createAgent } from "@klaus-ai/agent";
|
|
575
|
+
import { Type } from "@sinclair/typebox";
|
|
576
|
+
|
|
577
|
+
const agent = createAgent({
|
|
578
|
+
model: {
|
|
579
|
+
provider: "anthropic",
|
|
580
|
+
model: "claude-sonnet-4-20250514",
|
|
581
|
+
maxContextTokens: 200000,
|
|
582
|
+
capabilities: { vision: true, thinking: true },
|
|
583
|
+
},
|
|
584
|
+
systemPrompt: "You are a coding assistant.",
|
|
585
|
+
tools: [readFileTool, writeFileTool, searchTool],
|
|
586
|
+
thinkingLevel: "medium",
|
|
587
|
+
toolExecution: "parallel",
|
|
588
|
+
maxStepsPerTurn: 30,
|
|
589
|
+
|
|
590
|
+
approval: { autoApproveActions: ["file:read", "search"] },
|
|
591
|
+
|
|
592
|
+
session: { persist: true, directory: "./sessions" },
|
|
593
|
+
compaction: { enabled: true, reserveTokens: 16384, keepRecentTokens: 20000 },
|
|
594
|
+
checkpoint: { enabled: true, enableDMail: true },
|
|
595
|
+
|
|
596
|
+
injection: [memoryProvider, contextProvider],
|
|
597
|
+
extensions: [loggingExtension, guardExtension],
|
|
598
|
+
|
|
599
|
+
subagents: {
|
|
600
|
+
researcher: {
|
|
601
|
+
name: "researcher",
|
|
602
|
+
systemPrompt: "You research topics thoroughly.",
|
|
603
|
+
description: "Research assistant",
|
|
604
|
+
tools: [searchTool],
|
|
605
|
+
},
|
|
606
|
+
},
|
|
607
|
+
|
|
608
|
+
skills: [{ directory: "./skills" }],
|
|
609
|
+
|
|
610
|
+
mcp: {
|
|
611
|
+
servers: [{ name: "fs", transport: { type: "stdio", command: "mcp-fs" } }],
|
|
612
|
+
clientFactory: (config) => new MCPClient(config),
|
|
613
|
+
},
|
|
614
|
+
|
|
615
|
+
wire: { bufferSize: 100 },
|
|
616
|
+
backgroundTasks: { factories: { build: buildTaskFactory } },
|
|
617
|
+
|
|
618
|
+
hooks: {
|
|
619
|
+
transformContext: async (msgs) => msgs,
|
|
620
|
+
beforeToolCall: async (ctx) => {},
|
|
621
|
+
afterToolCall: async (ctx) => {},
|
|
622
|
+
},
|
|
623
|
+
});
|
|
624
|
+
|
|
625
|
+
agent.subscribe((event) => {
|
|
626
|
+
if (event.type === "message_update" && event.event.type === "text") {
|
|
627
|
+
process.stdout.write(event.event.text);
|
|
628
|
+
}
|
|
629
|
+
});
|
|
630
|
+
|
|
631
|
+
await agent.prompt("Help me refactor the auth module");
|
|
632
|
+
await agent.dispose();
|
|
633
|
+
```
|
|
634
|
+
|
|
635
|
+
## API Reference
|
|
636
|
+
|
|
637
|
+
### `createAgent(config): Agent`
|
|
638
|
+
|
|
639
|
+
| Config | Type | Required | Default | Description |
|
|
640
|
+
|--------|------|----------|---------|-------------|
|
|
641
|
+
| `model` | `ModelConfig` | yes | — | Provider, model ID, maxContextTokens, capabilities |
|
|
642
|
+
| `systemPrompt` | `string \| () => string` | yes | — | Static or dynamic system prompt |
|
|
643
|
+
| `tools` | `AgentTool[]` | yes | — | Tool definitions with TypeBox schemas |
|
|
644
|
+
| `approval` | `ApprovalConfig` | no | `{}` | yolo, autoApproveActions |
|
|
645
|
+
| `thinkingLevel` | `ThinkingLevel` | no | `"off"` | Extended thinking budget |
|
|
646
|
+
| `toolExecution` | `"sequential" \| "parallel"` | no | `"parallel"` | Tool execution mode |
|
|
647
|
+
| `maxStepsPerTurn` | `number` | no | `50` | Max inner loop iterations |
|
|
648
|
+
| `hooks` | `AgentHooks` | no | — | transformContext, convertToLlm, beforeToolCall, afterToolCall |
|
|
649
|
+
| `session` | `SessionConfig` | no | — | persist, directory, sessionId |
|
|
650
|
+
| `compaction` | `CompactionConfig` | no | — | enabled, reserveTokens, keepRecentTokens, customSummarizer |
|
|
651
|
+
| `checkpoint` | `CheckpointConfig` | no | — | enabled, enableDMail |
|
|
652
|
+
| `injection` | `DynamicInjectionProvider[]` | no | — | Dynamic context providers |
|
|
653
|
+
| `extensions` | `ExtensionFactory[]` | no | — | Plugin factories |
|
|
654
|
+
| `subagents` | `Record<string, SubagentConfig>` | no | — | Named subagent configs |
|
|
655
|
+
| `skills` | `SkillSource[]` | no | — | Skill directories |
|
|
656
|
+
| `mcp` | `{ servers, clientFactory }` | no | — | MCP server configs |
|
|
657
|
+
| `wire` | `{ bufferSize }` | no | `{ bufferSize: 0 }` | Event channel config |
|
|
658
|
+
| `backgroundTasks` | `{ factories }` | no | — | Background task factories |
|
|
659
|
+
| `provider` | `LLMProvider` | no | — | Custom LLM provider (bypasses registry) |
|
|
660
|
+
|
|
661
|
+
### `Agent` Instance
|
|
662
|
+
|
|
663
|
+
| Method / Property | Description |
|
|
664
|
+
|-------------------|-------------|
|
|
665
|
+
| `prompt(input)` | Send input and run the agent loop. Returns all messages. |
|
|
666
|
+
| `continue()` | Re-enter the loop without new input. |
|
|
667
|
+
| `steer(message)` | Inject a message after current tool execution. |
|
|
668
|
+
| `followUp(message)` | Inject a message after inner loop completes. |
|
|
669
|
+
| `abort()` | Abort the current run. |
|
|
670
|
+
| `subscribe(fn)` | Subscribe to events. Returns unsubscribe function. |
|
|
671
|
+
| `dispose()` | Cleanup all resources. |
|
|
672
|
+
| `state` | Current `AgentState` (systemPrompt, model, tools, messages, isRunning). |
|
|
673
|
+
| `approval` | `Approval` instance. |
|
|
674
|
+
| `session` | `SessionManager` (if configured). |
|
|
675
|
+
| `checkpoints` | `CheckpointManager` (if configured). |
|
|
676
|
+
| `extensions` | `ExtensionRunner` (if configured). |
|
|
677
|
+
| `injections` | `InjectionManager` (if configured). |
|
|
678
|
+
| `laborMarket` | `LaborMarket` (if subagents configured). |
|
|
679
|
+
| `mcpAdapter` | `MCPAdapter` (if MCP configured). |
|
|
680
|
+
| `wire` | `Wire` event channel (always available). |
|
|
681
|
+
| `backgroundTasks` | `BackgroundTaskManager` (if configured). |
|
|
682
|
+
| `setSystemPrompt(prompt)` | Update system prompt. |
|
|
683
|
+
| `setModel(model)` | Update model config. |
|
|
684
|
+
| `setTools(tools)` | Replace tools (not while running). |
|
|
685
|
+
| `setThinkingLevel(level)` | Update thinking level (not while running). |
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { Approval, ApprovalConfig, ApprovalRequest, ApprovalResponse } from "./types.js";
|
|
2
|
+
export declare class ApprovalImpl implements Approval {
|
|
3
|
+
private _yolo;
|
|
4
|
+
private _autoApproveActions;
|
|
5
|
+
private _pending;
|
|
6
|
+
private _queue;
|
|
7
|
+
private _waiters;
|
|
8
|
+
constructor(config?: ApprovalConfig);
|
|
9
|
+
request(sender: string, action: string, description: string, toolCallId: string): Promise<boolean>;
|
|
10
|
+
fetchRequest(): Promise<ApprovalRequest>;
|
|
11
|
+
/** Cancel all pending waiters (e.g., on agent dispose) */
|
|
12
|
+
cancelPendingWaiters(): void;
|
|
13
|
+
resolve(requestId: string, response: ApprovalResponse): void;
|
|
14
|
+
setYolo(yolo: boolean): void;
|
|
15
|
+
isYolo(): boolean;
|
|
16
|
+
get autoApproveActions(): Set<string>;
|
|
17
|
+
share(): Approval;
|
|
18
|
+
}
|