goatchain 0.0.11 β†’ 0.0.13

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,37 +1,37 @@
1
- # GoatChain 🐐
1
+ # GoatChain SDK Developer Guide 🐐
2
2
 
3
- > A lightweight, extensible TypeScript SDK for building AI agents with streaming support, tool calling, and middleware pattern.
3
+ > A TypeScript SDK for building AI agents with streaming support, tool calling, and middleware pattern.
4
4
 
5
5
  [![npm version](https://badge.fury.io/js/goatchain.svg)](https://badge.fury.io/js/goatchain)
6
6
  [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
7
7
 
8
- [δΈ­ζ–‡ζ–‡ζ‘£ (Chinese Documentation)](README.zh.md)
9
-
10
- ## ✨ Features
11
-
12
- - **πŸ”„ Agentic Loop** - Automatic tool calling loop with configurable max iterations
13
- - **πŸ“‘ Streaming First** - Real-time streaming responses with detailed events
14
- - **πŸ§… Middleware Pattern** - Koa-style onion model for extensible hooks
15
- - **πŸ”§ Tool System** - Easy-to-use tool registration and execution
16
- - **πŸ’Ύ State Management** - Two-level state store (Agent + Session level)
17
- - **πŸ“Έ Snapshot/Restore** - Full persistence support for agents and sessions
18
- - **🎯 TypeScript Native** - Full type safety with comprehensive type exports
19
-
20
8
  ## πŸ“¦ Installation
21
9
 
22
10
  ```bash
23
11
  pnpm add goatchain
12
+ # or
13
+ npm install goatchain
14
+ # or
15
+ bun add goatchain
24
16
  ```
25
17
 
18
+ ## 🎯 Core Concepts
19
+
20
+ GoatChain SDK is built around three core components:
21
+
22
+ - **Agent** - The main orchestrator that manages the agent loop, middleware, and tools
23
+ - **Session** - A conversation context that handles message history and streaming
24
+ - **ModelClient** - Abstraction layer for LLM providers (OpenAI, Anthropic, etc.)
25
+
26
26
  ## πŸš€ Quick Start
27
27
 
28
- Simple Agent Loop example:
28
+ ### Basic Usage
29
29
 
30
30
  ```typescript
31
31
  import process from 'node:process'
32
32
  import { Agent, createModel, createOpenAIAdapter } from 'goatchain'
33
33
 
34
- // Create model
34
+ // 1. Create model client
35
35
  const model = createModel({
36
36
  adapter: createOpenAIAdapter({
37
37
  defaultModelId: 'gpt-4o',
@@ -39,16 +39,18 @@ const model = createModel({
39
39
  }),
40
40
  })
41
41
 
42
- // Create Agent
42
+ // 2. Create agent
43
43
  const agent = new Agent({
44
44
  name: 'Simple Assistant',
45
45
  systemPrompt: 'You are a helpful assistant.',
46
46
  model,
47
47
  })
48
48
 
49
- // Stream responses
49
+ // 3. Create session and interact
50
50
  const session = await agent.createSession()
51
51
  session.send('Hello!')
52
+
53
+ // 4. Stream responses
52
54
  for await (const event of session.receive()) {
53
55
  if (event.type === 'text_delta') {
54
56
  process.stdout.write(event.delta)
@@ -58,182 +60,381 @@ for await (const event of session.receive()) {
58
60
  }
59
61
  ```
60
62
 
61
- πŸ“– **Full Documentation**: See [docs/getting-started.md](./docs/getting-started.md) for more examples and complete guide.
63
+ ## πŸ“‘ Session Management
62
64
 
63
- ## 🧰 CLI
65
+ Session is the core component for managing conversations. It handles message history, state persistence, and event streaming.
64
66
 
65
- GoatChain CLI is a terminal UI (TUI) built on `@simon_he/vue-tui`.
67
+ ### Creating Sessions
66
68
 
67
- ### Installation
69
+ ```typescript
70
+ // Create a new session
71
+ const session = await agent.createSession()
68
72
 
69
- **Global installation (recommended):**
73
+ // Create session with custom ID
74
+ const session = await agent.createSession({ id: 'my-session-id' })
70
75
 
71
- ```bash
72
- npm install -g goatchain-cli@latest
76
+ // Create session with configuration overrides
77
+ const session = await agent.createSession({
78
+ configOverride: {
79
+ maxIterations: 10,
80
+ maxConcurrentToolCalls: 3,
81
+ },
82
+ })
73
83
  ```
74
84
 
75
- **Or use npx without installation:**
85
+ ### Session Configuration Options
76
86
 
77
- ```bash
78
- npx goatchain-cli@latest
87
+ ```typescript
88
+ interface SessionConfigOverride {
89
+ maxIterations?: number // Max agent loop iterations (default: 5)
90
+ maxConcurrentToolCalls?: number // Max parallel tool calls (default: 5)
91
+ temperature?: number // Model temperature
92
+ maxTokens?: number // Max output tokens
93
+ topP?: number // Nucleus sampling parameter
94
+ }
79
95
  ```
80
96
 
81
- ### Usage
97
+ ### Sending Messages
82
98
 
83
- After installation, simply run:
84
-
85
- ```bash
86
- goatchain
99
+ ```typescript
100
+ // Simple text message
101
+ session.send('What is the weather today?')
102
+
103
+ // Multiple messages in sequence
104
+ session.send('First question')
105
+ // Wait for response...
106
+ session.send('Follow-up question')
107
+
108
+ // Message with options
109
+ session.send('Analyze this data', {
110
+ temperature: 0.7,
111
+ maxTokens: 2000,
112
+ })
87
113
  ```
88
114
 
89
- Inside the TUI:
115
+ ### Receiving Events
90
116
 
91
- - `Ctrl+P` opens the command palette (Sessions / New Session / Settings / Tool Approvals; Chat also has Theme)
92
- - Slash commands in the input: `/settings`, `/approvals`, `/sessions`, `/new` (Chat also supports `/redo`)
117
+ The `receive()` method returns an async generator that streams events:
93
118
 
94
- ### Development
119
+ ```typescript
120
+ for await (const event of session.receive()) {
121
+ switch (event.type) {
122
+ case 'text_delta':
123
+ // Partial text from LLM
124
+ process.stdout.write(event.delta)
125
+ break
126
+
127
+ case 'tool_call_start':
128
+ console.log(`\nCalling tool: ${event.name}`)
129
+ break
130
+
131
+ case 'tool_result':
132
+ console.log(`Tool result: ${event.result}`)
133
+ break
134
+
135
+ case 'iteration_end':
136
+ console.log(`\nIteration ${event.iteration} complete`)
137
+ console.log(`Tokens used: ${event.usage?.totalTokens}`)
138
+ break
139
+
140
+ case 'done':
141
+ console.log(`\nConversation done: ${event.stopReason}`)
142
+ console.log(`Total tokens: ${event.usage?.totalTokens}`)
143
+ break
144
+
145
+ case 'error':
146
+ console.error(`Error: ${event.error}`)
147
+ break
148
+ }
149
+ }
150
+ ```
95
151
 
96
- Run it from this repo:
152
+ ### Session Event Types
153
+
154
+ | Event Type | Description | Key Fields |
155
+ |------------|-------------|------------|
156
+ | `iteration_start` | Agent loop iteration begins | `iteration` |
157
+ | `text_delta` | Partial text response | `delta` |
158
+ | `thinking_start` | Reasoning phase begins | - |
159
+ | `thinking_delta` | Reasoning content | `delta` |
160
+ | `thinking_end` | Reasoning phase ends | - |
161
+ | `tool_call_start` | Tool invocation begins | `name`, `id` |
162
+ | `tool_call_delta` | Tool arguments stream | `delta` |
163
+ | `tool_call_end` | Tool call complete | `name`, `args` |
164
+ | `tool_result` | Tool execution result | `result`, `error` |
165
+ | `iteration_end` | Iteration complete | `usage`, `iteration` |
166
+ | `done` | Stream finished | `stopReason`, `usage` |
167
+ | `error` | Error occurred | `error` |
168
+
169
+ ### Session State Management
97
170
 
98
- ```bash
99
- bun run cli
171
+ ```typescript
172
+ // Access message history
173
+ console.log(session.messages) // Message[]
174
+
175
+ // Check session status
176
+ console.log(session.status) // 'idle' | 'running' | 'completed' | 'error'
177
+
178
+ // Get token usage
179
+ console.log(session.usage)
180
+ // {
181
+ // promptTokens: 150,
182
+ // completionTokens: 80,
183
+ // totalTokens: 230
184
+ // }
185
+
186
+ // Session metadata
187
+ console.log(session.id) // Session ID
188
+ console.log(session.createdAt) // Creation timestamp
189
+ console.log(session.updatedAt) // Last update timestamp
100
190
  ```
101
191
 
102
- See `docs/cli.md` for the full feature list and flowcharts.
192
+ ### Session Persistence
103
193
 
104
- ## πŸ”Œ ACP Server
194
+ Sessions can be saved and restored:
105
195
 
106
- GoatChain can be exposed as an ACP (Agent Client Protocol) server for integration with editors like Zed.
196
+ ```typescript
197
+ // Save session to snapshot
198
+ const snapshot = session.toSnapshot()
199
+ // Store snapshot to database, file, etc.
107
200
 
108
- ```bash
109
- bun run acp-server
201
+ // Restore session from snapshot
202
+ session.restoreFromSnapshot(snapshot)
203
+
204
+ // Or create a new session from snapshot
205
+ const restored = await agent.createSession()
206
+ restored.restoreFromSnapshot(snapshot)
110
207
  ```
111
208
 
112
- **Configuration for Zed** (`settings.json`):
209
+ ### Multi-turn Conversations
113
210
 
114
- ```json
115
- {
116
- "agent_servers": {
117
- "goatchain": {
118
- "command": "pnpm",
119
- "args": ["--dir", "/path/to/GoatChain", "acp-server"]
120
- }
211
+ ```typescript
212
+ const session = await agent.createSession()
213
+
214
+ // Turn 1
215
+ session.send('What is 2 + 2?')
216
+ for await (const event of session.receive()) {
217
+ if (event.type === 'text_delta') {
218
+ process.stdout.write(event.delta)
219
+ }
220
+ }
221
+
222
+ // Turn 2 (maintains context)
223
+ session.send('What about multiplying that by 3?')
224
+ for await (const event of session.receive()) {
225
+ if (event.type === 'text_delta') {
226
+ process.stdout.write(event.delta)
121
227
  }
122
228
  }
229
+
230
+ // Session now contains full conversation history
231
+ console.log(session.messages.length) // 4 (2 user, 2 assistant)
123
232
  ```
124
233
 
125
- **Features:**
126
- - File operations (read, write, edit)
127
- - Search tools (glob, grep, ast-grep)
128
- - Web search and task management
129
- - Same tool set as CLI agent mode
234
+ ### Resuming Sessions
130
235
 
131
- **Available servers:**
132
- - `pnpm acp-server` - Simple agent (recommended)
133
- - `pnpm acp-server:plan` - With plan mode (experimental)
236
+ Resume interrupted sessions using checkpoints:
134
237
 
135
- πŸ“– **Full Documentation**: See [docs/acp-server.md](./docs/acp-server.md) for configuration and troubleshooting.
238
+ ```typescript
239
+ import { FileStateStore } from 'goatchain'
136
240
 
137
- ## πŸ—οΈ Architecture
241
+ // Create agent with state store
242
+ const stateStore = new FileStateStore({
243
+ dir: './checkpoints',
244
+ deleteOnComplete: true,
245
+ })
138
246
 
139
- ```mermaid
140
- classDiagram
141
- direction TB
247
+ const agent = new Agent({
248
+ name: 'MyAgent',
249
+ systemPrompt: 'You are helpful.',
250
+ model,
251
+ stateStore,
252
+ })
253
+
254
+ // Start session (automatically checkpointed)
255
+ const session = await agent.createSession({ id: 'session-123' })
256
+ session.send('Start a long task')
257
+ for await (const event of session.receive()) {
258
+ // Process events...
259
+ }
142
260
 
143
- class Agent {
144
- +id: string
145
- +name: string
146
- +systemPrompt: string
147
- +model: ModelClient
148
- +tools: ToolRegistry
149
- +stateStore: StateStore
150
- +sessionManager: BaseSessionManager
151
- +stats: AgentStats
152
- +use(middleware): this
153
- +createSession(options): BaseSession
154
- +resumeSession(sessionId, options): BaseSession
155
- +setModel(modelOrRef): void
156
- }
157
-
158
- class ModelClient {
159
- <<interface>>
160
- +modelId: string
161
- +stream(request): AsyncIterable~ModelStreamEvent~
162
- +run?(request): Promise~ModelRunResult~
163
- }
261
+ // Later, resume from checkpoint
262
+ const resumed = await agent.resumeSession('session-123')
263
+ for await (const event of resumed.receive()) {
264
+ // Continue from where it left off
265
+ }
266
+ ```
164
267
 
165
- class StateStore {
166
- <<interface>>
167
- +deleteOnComplete: boolean
168
- +saveCheckpoint(checkpoint): Promise~void~
169
- +loadCheckpoint(sessionId): Promise~AgentLoopCheckpoint~
170
- +deleteCheckpoint(sessionId): Promise~void~
171
- +listCheckpoints(): Promise~AgentLoopCheckpoint[]~
172
- }
268
+ ### Session Lifecycle Hooks
173
269
 
174
- class BaseTool {
175
- <<abstract>>
176
- +name: string
177
- +description: string
178
- +parameters: JSONSchema
179
- +execute(args, ctx?): Promise~unknown~
180
- }
270
+ ```typescript
271
+ // Add message manually
272
+ session.addMessage({
273
+ role: 'user',
274
+ content: 'Custom message',
275
+ })
181
276
 
182
- class ToolRegistry {
183
- +register(tool): void
184
- +unregister(name): boolean
185
- +get(name): BaseTool
186
- +list(): BaseTool[]
187
- +toOpenAIFormat(): OpenAITool[]
188
- }
277
+ // Save session state manually
278
+ await session.save()
189
279
 
190
- class BaseSession {
191
- <<abstract>>
192
- +id: string
193
- +status: SessionStatus
194
- +messages: Message[]
195
- +usage: Usage
196
- +configOverride: SessionConfigOverride
197
- +addMessage(message): void
198
- +save(): Promise~void~
199
- +toSnapshot(): SessionSnapshot
200
- +restoreFromSnapshot(snapshot): void
201
- }
280
+ // Clear session history
281
+ session.messages = []
282
+ ```
202
283
 
203
- class BaseSessionManager {
204
- <<abstract>>
205
- +create(sessionId?): Promise~BaseSession~
206
- +get(sessionId): Promise~BaseSession~
207
- +list(): Promise~BaseSession[]~
208
- +destroy(sessionId): Promise~void~
209
- }
284
+ ## πŸ€– Agent Configuration
210
285
 
211
- class Middleware {
212
- <<function>>
213
- (ctx: AgentLoopState, next: NextFunction) => Promise~void~
214
- }
286
+ ### Creating an Agent
215
287
 
216
- class AgentLoopState {
217
- +sessionId: string
218
- +messages: Message[]
219
- +iteration: number
220
- +pendingToolCalls: ToolCallWithResult[]
221
- +currentResponse: string
222
- +shouldContinue: boolean
223
- +usage: Usage
224
- }
288
+ ```typescript
289
+ import { Agent, createModel, createOpenAIAdapter } from 'goatchain'
225
290
 
226
- Agent --> ModelClient : uses
227
- Agent --> ToolRegistry : uses
228
- Agent --> StateStore : uses
229
- Agent --> BaseSessionManager : uses
230
- Agent ..> Middleware : applies
231
- Agent ..> AgentLoopState : manages
232
- ToolRegistry --> BaseTool : contains
233
- BaseSessionManager --> BaseSession : manages
291
+ const agent = new Agent({
292
+ name: 'MyAgent',
293
+ systemPrompt: 'You are a helpful assistant.',
294
+ model,
295
+ tools: [], // Optional: custom tools
296
+ stateStore, // Optional: for persistence
297
+ maxIterations: 5, // Optional: max loop iterations
298
+ maxConcurrentToolCalls: 5, // Optional: parallel tool calls
299
+ })
300
+ ```
301
+
302
+ ### Agent Options
303
+
304
+ ```typescript
305
+ interface AgentOptions {
306
+ name: string // Agent name
307
+ systemPrompt: string // System instructions
308
+ model: ModelClient | ModelRef // LLM client or reference
309
+ tools?: BaseTool[] // Custom tools
310
+ stateStore?: StateStore // Persistence layer
311
+ maxIterations?: number // Max agent loop iterations (default: 5)
312
+ maxConcurrentToolCalls?: number // Max parallel tool calls (default: 5)
313
+ modelSwapWhitelist?: string[] // Allowed model IDs for runtime switching
314
+ }
315
+ ```
316
+
317
+ ### Runtime Model Switching
318
+
319
+ ```typescript
320
+ // Pin to specific model
321
+ agent.setModel('gpt-4o-mini')
322
+
323
+ // Allow model to switch back
324
+ agent.setModel({ type: 'ref', ref: 'the-model' })
325
+ ```
326
+
327
+ ### Session Manager
328
+
329
+ Manage multiple sessions:
330
+
331
+ ```typescript
332
+ const sessionManager = agent.sessionManager
333
+
334
+ // List all sessions
335
+ const sessions = await sessionManager.list()
336
+
337
+ // Get specific session
338
+ const session = await sessionManager.get('session-id')
339
+
340
+ // Destroy session
341
+ await sessionManager.destroy('session-id')
342
+ ```
343
+
344
+ ## πŸ”§ Tool System
345
+
346
+ ### Using Built-in Tools
347
+
348
+ GoatChain includes 23 built-in tools:
349
+
350
+ ```typescript
351
+ import {
352
+ ReadTool,
353
+ WriteTool,
354
+ EditTool,
355
+ BashTool,
356
+ GrepTool,
357
+ GlobTool,
358
+ WebSearchTool,
359
+ WebFetchTool,
360
+ } from 'goatchain'
361
+
362
+ const agent = new Agent({
363
+ name: 'MyAgent',
364
+ systemPrompt: 'You are helpful.',
365
+ model,
366
+ tools: [
367
+ new ReadTool(),
368
+ new WriteTool(),
369
+ new EditTool(),
370
+ new BashTool(),
371
+ new GrepTool(),
372
+ new GlobTool(),
373
+ new WebSearchTool({ apiKey: process.env.SERPER_API_KEY }),
374
+ new WebFetchTool(),
375
+ ],
376
+ })
377
+ ```
378
+
379
+ ### Creating Custom Tools
380
+
381
+ ```typescript
382
+ import { BaseTool } from 'goatchain'
383
+
384
+ class MyCustomTool extends BaseTool {
385
+ name = 'my_tool'
386
+ description = 'Does something useful'
387
+
388
+ parameters = {
389
+ type: 'object',
390
+ properties: {
391
+ input: {
392
+ type: 'string',
393
+ description: 'Input parameter',
394
+ },
395
+ },
396
+ required: ['input'],
397
+ }
398
+
399
+ async execute(args: { input: string }) {
400
+ // Your tool logic here
401
+ return `Processed: ${args.input}`
402
+ }
403
+ }
404
+
405
+ // Use it
406
+ const agent = new Agent({
407
+ name: 'MyAgent',
408
+ systemPrompt: 'You are helpful.',
409
+ model,
410
+ tools: [new MyCustomTool()],
411
+ })
412
+ ```
413
+
414
+ ### Tool Registry
415
+
416
+ Dynamically manage tools:
417
+
418
+ ```typescript
419
+ const registry = agent.tools
420
+
421
+ // Register new tool
422
+ registry.register(new MyCustomTool())
423
+
424
+ // Unregister tool
425
+ registry.unregister('my_tool')
426
+
427
+ // Get tool
428
+ const tool = registry.get('my_tool')
429
+
430
+ // List all tools
431
+ const allTools = registry.list()
432
+
433
+ // Convert to OpenAI format
434
+ const openaiTools = registry.toOpenAIFormat()
234
435
  ```
235
436
 
236
- ## πŸ§… Middleware Pattern
437
+ ## πŸ§… Middleware System
237
438
 
238
439
  GoatChain uses a Koa-style onion model for middleware. Each middleware wraps around the core execution:
239
440
 
@@ -241,16 +442,16 @@ GoatChain uses a Koa-style onion model for middleware. Each middleware wraps aro
241
442
  outer:before β†’ inner:before β†’ exec (model.stream) β†’ inner:after β†’ outer:after
242
443
  ```
243
444
 
244
- ### Named Middleware
245
-
246
- Middlewares can be named for easier management and removal:
445
+ ### Adding Middleware
247
446
 
248
447
  ```typescript
249
448
  // Add named middleware (recommended)
250
449
  agent.use(async (state, next) => {
251
450
  const start = Date.now()
252
451
  console.log(`[${state.iteration}] Before model call`)
253
- const nextState = await next(state)
452
+
453
+ const nextState = await next(state) // Execute next middleware/model
454
+
254
455
  console.log(`[${state.iteration}] After model call (${Date.now() - start}ms)`)
255
456
  return nextState
256
457
  }, 'logging')
@@ -266,169 +467,857 @@ const unsubscribe = agent.use(middleware, 'temp')
266
467
  unsubscribe() // Remove middleware
267
468
  ```
268
469
 
269
- ### Built-in Middleware Default Names
470
+ ### Built-in Middleware
270
471
 
271
- GoatChain's built-in middleware factories automatically provide default names:
472
+ #### Plan Mode Middleware
473
+
474
+ Adds planning phase before execution:
272
475
 
273
476
  ```typescript
274
- // Plan mode middleware - automatically named 'plan-mode'
477
+ import { createPlanModeMiddleware } from 'goatchain'
478
+
479
+ // Automatically named 'plan-mode'
275
480
  agent.use(createPlanModeMiddleware())
276
481
 
277
- // Context compression middleware - automatically named 'context-compression'
278
- agent.use(createContextCompressionMiddleware({
279
- maxTokens: 128000,
482
+ // With custom configuration
483
+ agent.use(createPlanModeMiddleware({
484
+ name: 'my-plan', // Custom name
485
+ planPrompt: 'Create a detailed plan...', // Custom prompt
280
486
  }))
487
+ ```
488
+
489
+ #### Context Compression Middleware
281
490
 
282
- // View all middleware
283
- console.log(agent.middlewareNames)
284
- // Output: ['plan-mode', 'context-compression']
491
+ Automatically compresses context when token limit is reached using a two-stage strategy:
285
492
 
286
- // Remove by default name
287
- agent.removeMiddleware('plan-mode')
493
+ ```typescript
494
+ import { createContextCompressionMiddleware } from 'goatchain'
288
495
 
289
- // Or customize the name
290
- agent.use(createPlanModeMiddleware({ name: 'my-plan' }))
496
+ // Automatically named 'context-compression'
291
497
  agent.use(createContextCompressionMiddleware({
292
498
  maxTokens: 128000,
293
- }), 'my-compression') // Override default name
499
+ protectedTurns: 2, // Keep last 2 conversation turns
500
+ model: model,
501
+ stateStore: agent.stateStore,
502
+ toolCompressionTarget: 0.45, // Compress to 45% of maxTokens
503
+ minKeepToolResults: 5, // Keep last 5 tool results
504
+ // Optional: Enable detailed logging
505
+ enableLogging: true,
506
+ logFilePath: 'compression-logs.jsonl',
507
+ }))
294
508
  ```
295
509
 
296
- ### Middleware Examples
510
+ See [Context Compression Logging Guide](./docs/context-compression-logging.md) for details on monitoring compression behavior.
511
+
512
+ ### Custom Middleware Examples
513
+
514
+ #### Logging Middleware
297
515
 
298
516
  ```typescript
299
- // Logging middleware
300
517
  agent.use(async (state, next) => {
301
- const start = Date.now()
302
- console.log(`[${state.iteration}] Before model call`)
303
-
304
- const nextState = await next(state) // Execute model stream
518
+ console.log(`Iteration ${state.iteration}:`, {
519
+ messages: state.messages.length,
520
+ pendingTools: state.pendingToolCalls.length,
521
+ })
522
+
523
+ const result = await next(state)
524
+
525
+ console.log(`Completed iteration ${state.iteration}:`, {
526
+ shouldContinue: result.shouldContinue,
527
+ usage: result.usage,
528
+ })
529
+
530
+ return result
531
+ }, 'logger')
532
+ ```
305
533
 
306
- console.log(`[${state.iteration}] After model call (${Date.now() - start}ms)`)
307
- return nextState
308
- }, 'logging')
534
+ #### Error Handling Middleware
309
535
 
310
- // Error handling middleware
536
+ ```typescript
311
537
  agent.use(async (state, next) => {
312
538
  try {
313
539
  return await next(state)
314
- }
315
- catch (error) {
540
+ } catch (error) {
541
+ console.error('Agent error:', error)
316
542
  state.shouldContinue = false
317
543
  state.stopReason = 'error'
318
544
  state.error = error
319
545
  return state
320
546
  }
321
547
  }, 'error-handler')
548
+ ```
549
+
550
+ #### Rate Limiting Middleware
551
+
552
+ ```typescript
553
+ import { RateLimiter } from 'some-rate-limiter'
554
+
555
+ const limiter = new RateLimiter({ requestsPerMinute: 60 })
322
556
 
323
- // Rate limiting middleware
324
557
  agent.use(async (state, next) => {
325
- await rateLimiter.acquire()
558
+ await limiter.acquire()
326
559
  return next(state)
327
560
  }, 'rate-limiter')
328
561
  ```
329
562
 
330
- ## πŸ“‘ Event Types
331
-
332
- The session receive stream emits the following events:
333
-
334
- | Event | Description |
335
- | ----------------- | ------------------------------------- |
336
- | `iteration_start` | Beginning of a loop iteration |
337
- | `text_delta` | Partial text response from LLM |
338
- | `thinking_start` | Thinking phase begins (if supported) |
339
- | `thinking_delta` | Thinking content delta (if supported) |
340
- | `thinking_end` | Thinking phase ends (if supported) |
341
- | `tool_call_start` | Tool call begins |
342
- | `tool_call_delta` | Tool call arguments delta |
343
- | `tool_call_end` | Tool call is complete |
344
- | `tool_result` | Tool execution completed |
345
- | `iteration_end` | End of a loop iteration (includes usage) |
346
- | `done` | Stream completed (includes usage) |
347
- | `error` | Error occurred |
348
-
349
- ```typescript
350
- interface AgentEvent {
351
- type:
352
- | 'text_delta'
353
- | 'tool_call_start'
354
- | 'tool_call_delta'
355
- | 'tool_call_end'
356
- | 'tool_result'
357
- | 'thinking_start'
358
- | 'thinking_delta'
359
- | 'thinking_end'
360
- | 'error'
361
- | 'done'
362
- | 'iteration_start'
363
- | 'iteration_end'
364
- // ... event-specific fields
563
+ #### Custom Retry Middleware
564
+
565
+ ```typescript
566
+ agent.use(async (state, next) => {
567
+ let retries = 3
568
+
569
+ while (retries > 0) {
570
+ try {
571
+ return await next(state)
572
+ } catch (error) {
573
+ retries--
574
+ if (retries === 0) throw error
575
+
576
+ console.log(`Retrying... (${retries} attempts left)`)
577
+ await new Promise(resolve => setTimeout(resolve, 1000))
578
+ }
579
+ }
580
+
581
+ return state
582
+ }, 'retry')
583
+ ```
584
+
585
+ ### Middleware State
586
+
587
+ The `AgentLoopState` object passed to middleware:
588
+
589
+ ```typescript
590
+ interface AgentLoopState {
591
+ sessionId: string // Current session ID
592
+ messages: Message[] // Conversation history
593
+ iteration: number // Current iteration number
594
+ pendingToolCalls: ToolCallWithResult[] // Pending tool executions
595
+ currentResponse: string // Current LLM response
596
+ shouldContinue: boolean // Whether to continue loop
597
+ stopReason?: string // Reason for stopping
598
+ usage?: Usage // Token usage
599
+ error?: Error // Error if any
600
+ }
601
+ ```
602
+
603
+ ## πŸ”Œ Model Client
604
+
605
+ ### Creating a Model Client
606
+
607
+ ```typescript
608
+ import { createModel, createOpenAIAdapter } from 'goatchain'
609
+
610
+ const model = createModel({
611
+ adapter: createOpenAIAdapter({
612
+ defaultModelId: 'gpt-4o',
613
+ apiKey: process.env.OPENAI_API_KEY!,
614
+ baseURL: 'https://api.openai.com/v1', // Optional
615
+ organization: 'org-xxx', // Optional
616
+ }),
617
+ })
618
+ ```
619
+
620
+ ### OpenAI Adapter Options
621
+
622
+ ```typescript
623
+ interface OpenAIAdapterOptions {
624
+ defaultModelId?: string // Default model ID
625
+ apiKey?: string // OpenAI API key
626
+ baseURL?: string // Custom API endpoint
627
+ organization?: string // OpenAI organization ID
628
+ defaultHeaders?: Record<string, string> // Custom headers
629
+ timeout?: number // Request timeout (ms)
630
+ maxRetries?: number // Max retry attempts (default: 2)
631
+ }
632
+ ```
633
+
634
+ ### Using Different Models
635
+
636
+ ```typescript
637
+ // OpenAI
638
+ const openai = createModel({
639
+ adapter: createOpenAIAdapter({
640
+ defaultModelId: 'gpt-4o',
641
+ apiKey: process.env.OPENAI_API_KEY!,
642
+ }),
643
+ })
644
+
645
+ // OpenAI-compatible endpoints
646
+ const deepseek = createModel({
647
+ adapter: createOpenAIAdapter({
648
+ defaultModelId: 'deepseek-chat',
649
+ apiKey: process.env.DEEPSEEK_API_KEY!,
650
+ baseURL: 'https://api.deepseek.com/v1',
651
+ }),
652
+ })
653
+ ```
654
+
655
+ ### Model Interface
656
+
657
+ Implement custom model adapters:
658
+
659
+ ```typescript
660
+ interface ModelClient {
661
+ modelId: string
662
+
663
+ // Streaming API (required)
664
+ stream(request: ModelRequest): AsyncIterable<ModelStreamEvent>
665
+
666
+ // Non-streaming API (optional)
667
+ run?(request: ModelRequest): Promise<ModelRunResult>
668
+ }
669
+
670
+ interface ModelRequest {
671
+ messages: Message[]
672
+ tools?: OpenAITool[]
673
+ temperature?: number
674
+ maxTokens?: number
675
+ topP?: number
676
+ stopSequences?: string[]
365
677
  }
366
678
  ```
367
679
 
368
- `iteration_end` and `done` events include optional `usage: Usage` with cumulative token counts.
680
+ ## πŸ’Ύ State Management
369
681
 
370
- ## πŸ’Ύ Checkpoint & Resume
682
+ ### File State Store
371
683
 
372
- Built-in checkpoint support for resuming interrupted agent executions:
684
+ Persist agent state to filesystem:
373
685
 
374
686
  ```typescript
375
- import { Agent, FileStateStore } from 'goatchain'
687
+ import { FileStateStore } from 'goatchain'
376
688
 
377
- // Create state store with configuration
378
689
  const stateStore = new FileStateStore({
379
- dir: './checkpoints',
380
- deleteOnComplete: true, // Clean up after successful completion
690
+ dir: './checkpoints', // Storage directory
691
+ deleteOnComplete: true, // Auto-delete successful completions
381
692
  })
382
693
 
383
- // Agent automatically saves checkpoints when stateStore is provided
384
694
  const agent = new Agent({
385
695
  name: 'MyAgent',
386
696
  systemPrompt: 'You are helpful.',
387
697
  model,
388
698
  stateStore,
389
699
  })
700
+ ```
390
701
 
391
- // Run agent - checkpoints are saved automatically
392
- const session = await agent.createSession()
393
- session.send('Hello')
394
- for await (const event of session.receive()) {
395
- console.log(event)
702
+ ### In-Memory State Store
703
+
704
+ For testing or temporary state:
705
+
706
+ ```typescript
707
+ import { InMemoryStateStore } from 'goatchain'
708
+
709
+ const stateStore = new InMemoryStateStore({
710
+ deleteOnComplete: false,
711
+ })
712
+ ```
713
+
714
+ ### State Store Interface
715
+
716
+ Implement custom state stores:
717
+
718
+ ```typescript
719
+ interface StateStore {
720
+ deleteOnComplete: boolean
721
+
722
+ saveCheckpoint(checkpoint: AgentLoopCheckpoint): Promise<void>
723
+ loadCheckpoint(sessionId: string): Promise<AgentLoopCheckpoint | null>
724
+ deleteCheckpoint(sessionId: string): Promise<void>
725
+ listCheckpoints(): Promise<AgentLoopCheckpoint[]>
396
726
  }
397
727
 
398
- // If interrupted, resume from checkpoint
399
- const checkpoint = await stateStore.loadCheckpoint(session.id)
400
- if (checkpoint) {
401
- const resumed = await agent.resumeSession(session.id)
402
- for await (const event of resumed.receive()) {
403
- console.log(event)
404
- }
728
+ interface AgentLoopCheckpoint {
729
+ sessionId: string
730
+ messages: Message[]
731
+ iteration: number
732
+ usage: Usage
733
+ createdAt: number
734
+ updatedAt: number
405
735
  }
406
736
  ```
407
737
 
408
- Available state stores:
738
+ ### Manual Checkpoint Management
409
739
 
410
- - `FileStateStore` - File-based persistence
411
- - `InMemoryStateStore` - In-memory (for testing)
740
+ ```typescript
741
+ // Save checkpoint manually
742
+ await stateStore.saveCheckpoint({
743
+ sessionId: session.id,
744
+ messages: session.messages,
745
+ iteration: 3,
746
+ usage: session.usage,
747
+ createdAt: Date.now(),
748
+ updatedAt: Date.now(),
749
+ })
750
+
751
+ // Load checkpoint
752
+ const checkpoint = await stateStore.loadCheckpoint('session-id')
753
+
754
+ // List all checkpoints
755
+ const checkpoints = await stateStore.listCheckpoints()
756
+
757
+ // Delete checkpoint
758
+ await stateStore.deleteCheckpoint('session-id')
759
+ ```
760
+
761
+ ## πŸ“š Complete Examples
762
+
763
+ ### Example 1: Simple Q&A Bot
764
+
765
+ ```typescript
766
+ import process from 'node:process'
767
+ import { Agent, createModel, createOpenAIAdapter } from 'goatchain'
768
+
769
+ const model = createModel({
770
+ adapter: createOpenAIAdapter({
771
+ defaultModelId: 'gpt-4o',
772
+ apiKey: process.env.OPENAI_API_KEY!,
773
+ }),
774
+ })
775
+
776
+ const agent = new Agent({
777
+ name: 'Q&A Bot',
778
+ systemPrompt: 'You are a helpful assistant that answers questions concisely.',
779
+ model,
780
+ })
781
+
782
+ const session = await agent.createSession()
783
+ session.send('What is the capital of France?')
784
+
785
+ for await (const event of session.receive()) {
786
+ if (event.type === 'text_delta') {
787
+ process.stdout.write(event.delta)
788
+ }
789
+ }
790
+ ```
791
+
792
+ ### Example 2: Agent with Tools
793
+
794
+ ```typescript
795
+ import {
796
+ Agent,
797
+ createModel,
798
+ createOpenAIAdapter,
799
+ ReadTool,
800
+ WriteTool,
801
+ BashTool,
802
+ } from 'goatchain'
803
+
804
+ const model = createModel({
805
+ adapter: createOpenAIAdapter({
806
+ defaultModelId: 'gpt-4o',
807
+ apiKey: process.env.OPENAI_API_KEY!,
808
+ }),
809
+ })
810
+
811
+ const agent = new Agent({
812
+ name: 'File Assistant',
813
+ systemPrompt: 'You help users manage their files.',
814
+ model,
815
+ tools: [
816
+ new ReadTool(),
817
+ new WriteTool(),
818
+ new BashTool(),
819
+ ],
820
+ })
821
+
822
+ const session = await agent.createSession()
823
+ session.send('Read the package.json file and tell me the version')
824
+
825
+ for await (const event of session.receive()) {
826
+ if (event.type === 'text_delta') {
827
+ process.stdout.write(event.delta)
828
+ } else if (event.type === 'tool_call_start') {
829
+ console.log(`\nCalling: ${event.name}`)
830
+ } else if (event.type === 'tool_result') {
831
+ console.log(`Result: ${JSON.stringify(event.result).slice(0, 100)}...`)
832
+ }
833
+ }
834
+ ```
835
+
836
+ ### Example 3: Persistent Sessions
837
+
838
+ ```typescript
839
+ import {
840
+ Agent,
841
+ createModel,
842
+ createOpenAIAdapter,
843
+ FileStateStore,
844
+ } from 'goatchain'
845
+
846
+ const model = createModel({
847
+ adapter: createOpenAIAdapter({
848
+ defaultModelId: 'gpt-4o',
849
+ apiKey: process.env.OPENAI_API_KEY!,
850
+ }),
851
+ })
852
+
853
+ const stateStore = new FileStateStore({
854
+ dir: './agent-state',
855
+ deleteOnComplete: false, // Keep history
856
+ })
857
+
858
+ const agent = new Agent({
859
+ name: 'Persistent Agent',
860
+ systemPrompt: 'You are a helpful assistant.',
861
+ model,
862
+ stateStore,
863
+ })
864
+
865
+ // Create or resume session
866
+ let session
867
+ const sessionId = 'my-conversation'
868
+
869
+ try {
870
+ session = await agent.resumeSession(sessionId)
871
+ console.log('Resumed existing session')
872
+ } catch {
873
+ session = await agent.createSession({ id: sessionId })
874
+ console.log('Created new session')
875
+ }
876
+
877
+ session.send('Remember this: My favorite color is blue')
878
+
879
+ for await (const event of session.receive()) {
880
+ if (event.type === 'text_delta') {
881
+ process.stdout.write(event.delta)
882
+ }
883
+ }
884
+ ```
885
+
886
+ ### Example 4: Session with Middleware
887
+
888
+ ```typescript
889
+ import {
890
+ Agent,
891
+ createModel,
892
+ createOpenAIAdapter,
893
+ createPlanModeMiddleware,
894
+ } from 'goatchain'
895
+
896
+ const model = createModel({
897
+ adapter: createOpenAIAdapter({
898
+ defaultModelId: 'gpt-4o',
899
+ apiKey: process.env.OPENAI_API_KEY!,
900
+ }),
901
+ })
902
+
903
+ const agent = new Agent({
904
+ name: 'Planning Agent',
905
+ systemPrompt: 'You are a helpful assistant.',
906
+ model,
907
+ })
908
+
909
+ // Add logging middleware
910
+ agent.use(async (state, next) => {
911
+ console.log(`\n=== Iteration ${state.iteration} ===`)
912
+ const result = await next(state)
913
+ console.log(`Tokens used: ${result.usage?.totalTokens || 0}`)
914
+ return result
915
+ }, 'logger')
916
+
917
+ // Add plan mode
918
+ agent.use(createPlanModeMiddleware())
919
+
920
+ const session = await agent.createSession()
921
+ session.send('Create a todo list app with React and TypeScript')
922
+
923
+ for await (const event of session.receive()) {
924
+ if (event.type === 'text_delta') {
925
+ process.stdout.write(event.delta)
926
+ }
927
+ }
928
+ ```
929
+
930
+ ### Example 5: Multi-turn Conversation
931
+
932
+ ```typescript
933
+ import { Agent, createModel, createOpenAIAdapter } from 'goatchain'
934
+
935
+ const model = createModel({
936
+ adapter: createOpenAIAdapter({
937
+ defaultModelId: 'gpt-4o',
938
+ apiKey: process.env.OPENAI_API_KEY!,
939
+ }),
940
+ })
941
+
942
+ const agent = new Agent({
943
+ name: 'Conversational Agent',
944
+ systemPrompt: 'You are a helpful assistant.',
945
+ model,
946
+ })
947
+
948
+ const session = await agent.createSession()
949
+
950
+ async function chat(message: string) {
951
+ console.log(`\nUser: ${message}`)
952
+ console.log('Assistant: ')
953
+
954
+ session.send(message)
955
+
956
+ for await (const event of session.receive()) {
957
+ if (event.type === 'text_delta') {
958
+ process.stdout.write(event.delta)
959
+ }
960
+ }
961
+
962
+ console.log('\n')
963
+ }
964
+
965
+ // Multi-turn conversation
966
+ await chat('My name is Alice')
967
+ await chat('What is 2 + 2?')
968
+ await chat('What is my name?') // Should remember "Alice"
969
+ await chat('Multiply the previous result by 3') // Should remember "4"
970
+
971
+ console.log(`Total messages: ${session.messages.length}`)
972
+ console.log(`Total tokens: ${session.usage.totalTokens}`)
973
+ ```
412
974
 
413
975
  ## πŸ“– API Reference
414
976
 
415
- ### Agent
977
+ ### Agent Class
978
+
979
+ #### Constructor
980
+
981
+ ```typescript
982
+ new Agent(options: AgentOptions)
983
+ ```
984
+
985
+ **Options:**
986
+ - `name: string` - Agent name (required)
987
+ - `systemPrompt: string` - System instructions (required)
988
+ - `model: ModelClient | ModelRef` - LLM client (required)
989
+ - `tools?: BaseTool[]` - Custom tools
990
+ - `stateStore?: StateStore` - Persistence layer
991
+ - `maxIterations?: number` - Max loop iterations (default: 5)
992
+ - `maxConcurrentToolCalls?: number` - Max parallel tools (default: 5)
993
+ - `modelSwapWhitelist?: string[]` - Allowed model IDs
994
+
995
+ #### Methods
996
+
997
+ **`createSession(options?): Promise<BaseSession>`**
998
+
999
+ Create a new session.
1000
+
1001
+ ```typescript
1002
+ const session = await agent.createSession({
1003
+ id: 'custom-id', // Optional custom ID
1004
+ configOverride: { // Optional config overrides
1005
+ maxIterations: 10,
1006
+ temperature: 0.7,
1007
+ },
1008
+ })
1009
+ ```
1010
+
1011
+ **`resumeSession(sessionId, options?): Promise<BaseSession>`**
1012
+
1013
+ Resume an existing session from checkpoint.
1014
+
1015
+ ```typescript
1016
+ const session = await agent.resumeSession('session-123')
1017
+ ```
1018
+
1019
+ **`use(middleware, name?): () => void`**
1020
+
1021
+ Add middleware. Returns unsubscribe function.
1022
+
1023
+ ```typescript
1024
+ const unsubscribe = agent.use(myMiddleware, 'my-middleware')
1025
+ unsubscribe() // Remove middleware
1026
+ ```
1027
+
1028
+ **`removeMiddleware(name): boolean`**
1029
+
1030
+ Remove middleware by name.
1031
+
1032
+ ```typescript
1033
+ agent.removeMiddleware('my-middleware')
1034
+ ```
1035
+
1036
+ **`setModel(modelOrRef): void`**
1037
+
1038
+ Switch or pin model at runtime.
1039
+
1040
+ ```typescript
1041
+ // Pin to specific model
1042
+ agent.setModel('gpt-4o-mini')
1043
+
1044
+ // Use dynamic reference
1045
+ agent.setModel({ type: 'ref', ref: 'the-model' })
1046
+ ```
1047
+
1048
+ #### Properties
1049
+
1050
+ - `id: string` - Agent ID
1051
+ - `name: string` - Agent name
1052
+ - `systemPrompt: string` - System prompt
1053
+ - `model: ModelClient` - Current model client
1054
+ - `tools: ToolRegistry` - Tool registry
1055
+ - `stateStore?: StateStore` - State store
1056
+ - `sessionManager: BaseSessionManager` - Session manager
1057
+ - `middlewareNames: string[]` - List of middleware names
1058
+ - `stats: AgentStats` - Usage statistics
1059
+
1060
+ ### Session Class
1061
+
1062
+ #### Methods
1063
+
1064
+ **`send(input, options?): void`**
1065
+
1066
+ Send a message to the session.
1067
+
1068
+ ```typescript
1069
+ session.send('Hello!', {
1070
+ temperature: 0.8,
1071
+ maxTokens: 1000,
1072
+ })
1073
+ ```
1074
+
1075
+ **`receive(options?): AsyncGenerator<AgentEvent>`**
1076
+
1077
+ Stream agent events.
1078
+
1079
+ ```typescript
1080
+ for await (const event of session.receive()) {
1081
+ console.log(event)
1082
+ }
1083
+ ```
1084
+
1085
+ **`addMessage(message): void`**
1086
+
1087
+ Manually add a message.
1088
+
1089
+ ```typescript
1090
+ session.addMessage({
1091
+ role: 'user',
1092
+ content: 'Hello',
1093
+ })
1094
+ ```
1095
+
1096
+ **`save(): Promise<void>`**
1097
+
1098
+ Manually save session state.
1099
+
1100
+ ```typescript
1101
+ await session.save()
1102
+ ```
1103
+
1104
+ **`toSnapshot(): SessionSnapshot`**
1105
+
1106
+ Export session to snapshot.
1107
+
1108
+ ```typescript
1109
+ const snapshot = session.toSnapshot()
1110
+ ```
1111
+
1112
+ **`restoreFromSnapshot(snapshot): void`**
1113
+
1114
+ Restore session from snapshot.
1115
+
1116
+ ```typescript
1117
+ session.restoreFromSnapshot(snapshot)
1118
+ ```
1119
+
1120
+ #### Properties
1121
+
1122
+ - `id: string` - Session ID
1123
+ - `status: SessionStatus` - Session status ('idle' | 'running' | 'completed' | 'error')
1124
+ - `messages: Message[]` - Message history
1125
+ - `usage: Usage` - Token usage statistics
1126
+ - `configOverride?: SessionConfigOverride` - Config overrides
1127
+ - `createdAt: number` - Creation timestamp
1128
+ - `updatedAt: number` - Last update timestamp
1129
+
1130
+ ### Message Type
1131
+
1132
+ ```typescript
1133
+ interface Message {
1134
+ role: 'system' | 'user' | 'assistant' | 'tool'
1135
+ content: string | ToolCall[] | ToolResult[]
1136
+ name?: string // For tool messages
1137
+ toolCallId?: string // For tool messages
1138
+ }
1139
+ ```
1140
+
1141
+ ### Usage Type
1142
+
1143
+ ```typescript
1144
+ interface Usage {
1145
+ promptTokens: number
1146
+ completionTokens: number
1147
+ totalTokens: number
1148
+ }
1149
+ ```
1150
+
1151
+ ### AgentEvent Types
1152
+
1153
+ ```typescript
1154
+ type AgentEvent =
1155
+ | TextDeltaEvent
1156
+ | ToolCallStartEvent
1157
+ | ToolCallDeltaEvent
1158
+ | ToolCallEndEvent
1159
+ | ToolResultEvent
1160
+ | ThinkingStartEvent
1161
+ | ThinkingDeltaEvent
1162
+ | ThinkingEndEvent
1163
+ | IterationStartEvent
1164
+ | IterationEndEvent
1165
+ | DoneEvent
1166
+ | ErrorEvent
1167
+
1168
+ interface TextDeltaEvent {
1169
+ type: 'text_delta'
1170
+ delta: string
1171
+ }
1172
+
1173
+ interface ToolCallStartEvent {
1174
+ type: 'tool_call_start'
1175
+ id: string
1176
+ name: string
1177
+ }
1178
+
1179
+ interface ToolResultEvent {
1180
+ type: 'tool_result'
1181
+ id: string
1182
+ name: string
1183
+ result: unknown
1184
+ error?: string
1185
+ }
1186
+
1187
+ interface DoneEvent {
1188
+ type: 'done'
1189
+ stopReason: 'stop' | 'max_iterations' | 'error' | 'cancel'
1190
+ usage?: Usage
1191
+ }
1192
+ ```
1193
+
1194
+ ## πŸ—οΈ Architecture
1195
+
1196
+ ```mermaid
1197
+ classDiagram
1198
+ direction TB
1199
+
1200
+ class Agent {
1201
+ +id: string
1202
+ +name: string
1203
+ +systemPrompt: string
1204
+ +model: ModelClient
1205
+ +tools: ToolRegistry
1206
+ +stateStore: StateStore
1207
+ +sessionManager: BaseSessionManager
1208
+ +use(middleware): this
1209
+ +createSession(): Promise~BaseSession~
1210
+ +resumeSession(id): Promise~BaseSession~
1211
+ }
1212
+
1213
+ class ModelClient {
1214
+ <<interface>>
1215
+ +modelId: string
1216
+ +stream(request): AsyncIterable~ModelStreamEvent~
1217
+ }
1218
+
1219
+ class StateStore {
1220
+ <<interface>>
1221
+ +saveCheckpoint(): Promise~void~
1222
+ +loadCheckpoint(): Promise~Checkpoint~
1223
+ +deleteCheckpoint(): Promise~void~
1224
+ +listCheckpoints(): Promise~Checkpoint[]~
1225
+ }
1226
+
1227
+ class BaseTool {
1228
+ <<abstract>>
1229
+ +name: string
1230
+ +description: string
1231
+ +parameters: JSONSchema
1232
+ +execute(args): Promise~unknown~
1233
+ }
1234
+
1235
+ class ToolRegistry {
1236
+ +register(tool): void
1237
+ +unregister(name): boolean
1238
+ +get(name): BaseTool
1239
+ +list(): BaseTool[]
1240
+ }
1241
+
1242
+ class BaseSession {
1243
+ <<abstract>>
1244
+ +id: string
1245
+ +status: SessionStatus
1246
+ +messages: Message[]
1247
+ +usage: Usage
1248
+ +send(input): void
1249
+ +receive(): AsyncGenerator~AgentEvent~
1250
+ +save(): Promise~void~
1251
+ }
1252
+
1253
+ class Middleware {
1254
+ <<function>>
1255
+ (state, next) => Promise~AgentLoopState~
1256
+ }
1257
+
1258
+ Agent --> ModelClient : uses
1259
+ Agent --> ToolRegistry : uses
1260
+ Agent --> StateStore : uses
1261
+ Agent --> BaseSession : creates
1262
+ Agent ..> Middleware : applies
1263
+ ToolRegistry --> BaseTool : contains
1264
+ ```
1265
+
1266
+ ## 🧰 Additional Tools
1267
+
1268
+ ### CLI
1269
+
1270
+ DimCode includes a terminal UI (TUI) for interactive agent sessions:
1271
+
1272
+ ```bash
1273
+ # Install globally
1274
+ npm install -g dimcode@latest
1275
+
1276
+ # Run
1277
+ dim
1278
+ ```
1279
+
1280
+ **Features:**
1281
+ - Interactive chat interface
1282
+ - Session management
1283
+ - Tool approval system
1284
+ - Settings configuration
1285
+
1286
+ See [docs/cli.md](./docs/cli.md) for details.
1287
+
1288
+ ### ACP Server
1289
+
1290
+ Expose DimCode as an Agent Client Protocol server for editor integrations:
1291
+
1292
+ ```bash
1293
+ bun run acp-server
1294
+ ```
1295
+
1296
+ **Configuration for Zed** (`settings.json`):
1297
+
1298
+ ```json
1299
+ {
1300
+ "agent_servers": {
1301
+ "dimcode": {
1302
+ "command": "pnpm",
1303
+ "args": ["--dir", "/path/to/DimCode", "acp-server"]
1304
+ }
1305
+ }
1306
+ }
1307
+ ```
1308
+
1309
+ See [docs/acp-server.md](./docs/acp-server.md) for details.
1310
+
1311
+ ## πŸ“š Documentation
416
1312
 
417
- | Method | Description |
418
- | ------------------------------- | ----------------------- |
419
- | `constructor(options)` | Create a new agent |
420
- | `use(middleware)` | Add middleware |
421
- | `createSession(options)` | Create a session |
422
- | `resumeSession(sessionId, options)` | Resume a session |
423
- | `setModel(modelOrRef)` | Switch/pin model at runtime |
1313
+ - [Getting Started Guide](./docs/getting-started.md) - Comprehensive tutorial
1314
+ - [CLI Documentation](./docs/cli.md) - Terminal UI features and usage
1315
+ - [ACP Server Guide](./docs/acp-server.md) - Editor integration setup
1316
+ - [Examples](./examples/) - Sample implementations
424
1317
 
425
- ### Session
1318
+ ## 🀝 Contributing
426
1319
 
427
- | Method | Description |
428
- | ----------------------- | -------------------------------------------- |
429
- | `send(input, options?)` | Queue input for the session |
430
- | `receive(options?)` | Stream events, resuming from checkpoint if present |
431
- | `messages` | Conversation history |
1320
+ Contributions are welcome! Please read our contributing guidelines before submitting PRs.
432
1321
 
433
1322
  ## πŸ“„ License
434
1323