goatchain 0.0.2 → 0.0.3
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 +173 -236
- package/README.zh.md +430 -0
- package/dist/index.d.ts +2958 -1802
- package/dist/index.js +270 -136
- package/package.json +13 -8
package/README.md
CHANGED
|
@@ -5,6 +5,8 @@
|
|
|
5
5
|
[](https://badge.fury.io/js/goatchain)
|
|
6
6
|
[](https://opensource.org/licenses/MIT)
|
|
7
7
|
|
|
8
|
+
[中文文档 (Chinese Documentation)](README.zh.md)
|
|
9
|
+
|
|
8
10
|
## ✨ Features
|
|
9
11
|
|
|
10
12
|
- **🔄 Agentic Loop** - Automatic tool calling loop with configurable max iterations
|
|
@@ -21,12 +23,42 @@
|
|
|
21
23
|
pnpm add goatchain
|
|
22
24
|
```
|
|
23
25
|
|
|
24
|
-
##
|
|
26
|
+
## 🚀 Quick Start
|
|
27
|
+
|
|
28
|
+
Simple Agent Loop example:
|
|
25
29
|
|
|
26
|
-
|
|
30
|
+
```typescript
|
|
31
|
+
import process from 'node:process'
|
|
32
|
+
import { Agent, createModel, createOpenAIAdapter } from 'goatchain'
|
|
27
33
|
|
|
28
|
-
|
|
29
|
-
|
|
34
|
+
// Create model
|
|
35
|
+
const model = createModel({
|
|
36
|
+
adapter: createOpenAIAdapter({
|
|
37
|
+
defaultModelId: 'gpt-4o',
|
|
38
|
+
apiKey: process.env.OPENAI_API_KEY!,
|
|
39
|
+
}),
|
|
40
|
+
})
|
|
41
|
+
|
|
42
|
+
// Create Agent
|
|
43
|
+
const agent = new Agent({
|
|
44
|
+
name: 'Simple Assistant',
|
|
45
|
+
systemPrompt: 'You are a helpful assistant.',
|
|
46
|
+
model,
|
|
47
|
+
})
|
|
48
|
+
|
|
49
|
+
// Stream responses
|
|
50
|
+
const session = await agent.createSession()
|
|
51
|
+
session.send('Hello!')
|
|
52
|
+
for await (const event of session.receive()) {
|
|
53
|
+
if (event.type === 'text_delta') {
|
|
54
|
+
process.stdout.write(event.delta)
|
|
55
|
+
} else if (event.type === 'done') {
|
|
56
|
+
console.log('\nDone:', event.stopReason)
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
📖 **Full Documentation**: See [docs/getting-started.md](./docs/getting-started.md) for more examples and complete guide.
|
|
30
62
|
|
|
31
63
|
## 🧰 CLI
|
|
32
64
|
|
|
@@ -48,11 +80,14 @@ Commands:
|
|
|
48
80
|
|
|
49
81
|
- `/help` help
|
|
50
82
|
- `/model <id>` switch model id (OpenAI)
|
|
51
|
-
- `/
|
|
83
|
+
- `/plan [on|off|toggle]` toggle plan mode (plan → confirm → execute)
|
|
84
|
+
- `/approvals` select approval mode (interactive)
|
|
85
|
+
- `/set <k> <v>` set request params (e.g. `temperature`, `maxTokens`)
|
|
52
86
|
- `/unset <k>` clear a request param
|
|
53
87
|
- `/params` show current request params
|
|
54
88
|
- `/base-url <url>` set base URL
|
|
55
89
|
- `/api-key <key>` set API key (not printed)
|
|
90
|
+
- `/web-search-key <key>` set Serper API key for WebSearch tool (not printed)
|
|
56
91
|
- `/tools` list enabled tools (Read/Write/Edit/Glob/Grep/WebSearch*)
|
|
57
92
|
- `/sessions` list and pick a saved session
|
|
58
93
|
- `/use <sessionId>` restore a saved session (prints recent history)
|
|
@@ -65,9 +100,21 @@ Requires `OPENAI_API_KEY` in the environment.
|
|
|
65
100
|
Web search (optional):
|
|
66
101
|
|
|
67
102
|
- Set `SERPER_API_KEY` (or `GOATCHAIN_SERPER_API_KEY`) to enable the builtin `WebSearch` tool for up-to-date info like weather.
|
|
103
|
+
- In interactive mode, you can also run `/web-search-key <key>` to persist the key into the workspace config.
|
|
68
104
|
- You can also set it in `./.goatchain/config.json` (workspace-scoped, gitignored):
|
|
69
105
|
- `{"tools":{"webSearch":{"apiKey":"...","apiEndpoint":"...","numResults":10}}}`
|
|
70
106
|
|
|
107
|
+
Plan mode (interactive planning):
|
|
108
|
+
|
|
109
|
+
- Enable with `/plan on` to enter a plan-first workflow:
|
|
110
|
+
1. Agent explores the codebase and researches your request
|
|
111
|
+
2. Agent may ask clarifying questions using the `AskUserQuestion` tool to understand your preferences (e.g., library choices, architectural decisions)
|
|
112
|
+
3. Agent creates a structured plan using `TodoPlan` (3-8 steps)
|
|
113
|
+
4. You review and approve the plan
|
|
114
|
+
5. Agent executes the approved plan
|
|
115
|
+
- During planning, file modifications are blocked (read-only phase)
|
|
116
|
+
- Set `GOATCHAIN_PLAN_MODE=1` or configure in `.goatchain/config.json` to enable by default
|
|
117
|
+
|
|
71
118
|
Local persistence (workspace-scoped):
|
|
72
119
|
|
|
73
120
|
- Config and sessions are saved under `./.goatchain/` (auto-created).
|
|
@@ -76,7 +123,42 @@ Local persistence (workspace-scoped):
|
|
|
76
123
|
DeepSeek thinking mode compatibility:
|
|
77
124
|
|
|
78
125
|
- Some OpenAI-compatible gateways (e.g. DeepSeek thinking mode) require `reasoning_content` to be present on assistant messages that contain `tool_calls` (and may reject empty strings). GoatChain will attach the accumulated thinking content when available.
|
|
79
|
-
- If you use DeepSeek via a proxy where GoatChain can't detect it from `baseUrl`/`modelId`,
|
|
126
|
+
- If you use DeepSeek via a proxy where GoatChain can't detect it from `baseUrl`/`modelId`, you can enable this explicitly:
|
|
127
|
+
- Interactive: Run `/settings` and toggle "Interleaved Thinking"
|
|
128
|
+
- Config file: Set `openai.compat.interleavedThinking=true` in `./.goatchain/config.json`
|
|
129
|
+
|
|
130
|
+
## 🔌 ACP Server
|
|
131
|
+
|
|
132
|
+
GoatChain can be exposed as an ACP (Agent Client Protocol) server for integration with editors like Zed.
|
|
133
|
+
|
|
134
|
+
```bash
|
|
135
|
+
pnpm acp-server
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
**Configuration for Zed** (`settings.json`):
|
|
139
|
+
|
|
140
|
+
```json
|
|
141
|
+
{
|
|
142
|
+
"agent_servers": {
|
|
143
|
+
"goatchain": {
|
|
144
|
+
"command": "pnpm",
|
|
145
|
+
"args": ["--dir", "/path/to/GoatChain", "acp-server"]
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
**Features:**
|
|
152
|
+
- File operations (read, write, edit)
|
|
153
|
+
- Search tools (glob, grep, ast-grep)
|
|
154
|
+
- Web search and task management
|
|
155
|
+
- Same tool set as CLI agent mode
|
|
156
|
+
|
|
157
|
+
**Available servers:**
|
|
158
|
+
- `pnpm acp-server` - Simple agent (recommended)
|
|
159
|
+
- `pnpm acp-server:plan` - With plan mode (experimental)
|
|
160
|
+
|
|
161
|
+
📖 **Full Documentation**: See [docs/acp-server.md](./docs/acp-server.md) for configuration and troubleshooting.
|
|
80
162
|
|
|
81
163
|
## 🏗️ Architecture
|
|
82
164
|
|
|
@@ -84,27 +166,27 @@ DeepSeek thinking mode compatibility:
|
|
|
84
166
|
classDiagram
|
|
85
167
|
direction TB
|
|
86
168
|
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
169
|
+
class Agent {
|
|
170
|
+
+id: string
|
|
171
|
+
+name: string
|
|
172
|
+
+systemPrompt: string
|
|
173
|
+
+model: ModelClient
|
|
174
|
+
+tools: ToolRegistry
|
|
175
|
+
+stateStore: StateStore
|
|
176
|
+
+sessionManager: BaseSessionManager
|
|
177
|
+
+stats: AgentStats
|
|
178
|
+
+use(middleware): this
|
|
179
|
+
+createSession(options): BaseSession
|
|
180
|
+
+resumeSession(sessionId, options): BaseSession
|
|
181
|
+
+setModel(modelOrRef): void
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
class ModelClient {
|
|
185
|
+
<<interface>>
|
|
186
|
+
+modelId: string
|
|
187
|
+
+stream(request): AsyncIterable~ModelStreamEvent~
|
|
188
|
+
+run?(request): Promise~ModelRunResult~
|
|
189
|
+
}
|
|
108
190
|
|
|
109
191
|
class StateStore {
|
|
110
192
|
<<interface>>
|
|
@@ -113,7 +195,7 @@ classDiagram
|
|
|
113
195
|
+saveCheckpoint(checkpoint): Promise~void~
|
|
114
196
|
+loadCheckpoint(sessionId): Promise~AgentLoopCheckpoint~
|
|
115
197
|
+deleteCheckpoint(sessionId): Promise~void~
|
|
116
|
-
+listCheckpoints(
|
|
198
|
+
+listCheckpoints(): Promise~AgentLoopCheckpoint[]~
|
|
117
199
|
}
|
|
118
200
|
|
|
119
201
|
class BaseTool {
|
|
@@ -135,7 +217,6 @@ classDiagram
|
|
|
135
217
|
class BaseSession {
|
|
136
218
|
<<abstract>>
|
|
137
219
|
+id: string
|
|
138
|
-
+agentId: string
|
|
139
220
|
+status: SessionStatus
|
|
140
221
|
+messages: Message[]
|
|
141
222
|
+usage: Usage
|
|
@@ -148,9 +229,9 @@ classDiagram
|
|
|
148
229
|
|
|
149
230
|
class BaseSessionManager {
|
|
150
231
|
<<abstract>>
|
|
151
|
-
+create(
|
|
232
|
+
+create(sessionId?): Promise~BaseSession~
|
|
152
233
|
+get(sessionId): Promise~BaseSession~
|
|
153
|
-
+list(
|
|
234
|
+
+list(): Promise~BaseSession[]~
|
|
154
235
|
+destroy(sessionId): Promise~void~
|
|
155
236
|
}
|
|
156
237
|
|
|
@@ -161,7 +242,6 @@ classDiagram
|
|
|
161
242
|
|
|
162
243
|
class AgentLoopState {
|
|
163
244
|
+sessionId: string
|
|
164
|
-
+agentId: string
|
|
165
245
|
+messages: Message[]
|
|
166
246
|
+iteration: number
|
|
167
247
|
+pendingToolCalls: ToolCallWithResult[]
|
|
@@ -170,7 +250,7 @@ classDiagram
|
|
|
170
250
|
+usage: Usage
|
|
171
251
|
}
|
|
172
252
|
|
|
173
|
-
Agent -->
|
|
253
|
+
Agent --> ModelClient : uses
|
|
174
254
|
Agent --> ToolRegistry : uses
|
|
175
255
|
Agent --> StateStore : uses
|
|
176
256
|
Agent --> BaseSessionManager : uses
|
|
@@ -180,80 +260,98 @@ classDiagram
|
|
|
180
260
|
BaseSessionManager --> BaseSession : manages
|
|
181
261
|
```
|
|
182
262
|
|
|
183
|
-
##
|
|
263
|
+
## 🧅 Middleware Pattern
|
|
264
|
+
|
|
265
|
+
GoatChain uses a Koa-style onion model for middleware. Each middleware wraps around the core execution:
|
|
266
|
+
|
|
267
|
+
```
|
|
268
|
+
outer:before → inner:before → exec (model.stream) → inner:after → outer:after
|
|
269
|
+
```
|
|
184
270
|
|
|
185
|
-
|
|
271
|
+
### Named Middleware
|
|
272
|
+
|
|
273
|
+
Middlewares can be named for easier management and removal:
|
|
186
274
|
|
|
187
275
|
```typescript
|
|
188
|
-
|
|
189
|
-
|
|
276
|
+
// Add named middleware (recommended)
|
|
277
|
+
agent.use(async (state, next) => {
|
|
278
|
+
const start = Date.now()
|
|
279
|
+
console.log(`[${state.iteration}] Before model call`)
|
|
280
|
+
const nextState = await next(state)
|
|
281
|
+
console.log(`[${state.iteration}] After model call (${Date.now() - start}ms)`)
|
|
282
|
+
return nextState
|
|
283
|
+
}, 'logging')
|
|
190
284
|
|
|
191
|
-
//
|
|
192
|
-
|
|
193
|
-
adapters: [
|
|
194
|
-
createOpenAIAdapter({
|
|
195
|
-
defaultModelId: 'gpt-4o',
|
|
196
|
-
apiKey: process.env.OPENAI_API_KEY!,
|
|
197
|
-
}),
|
|
198
|
-
],
|
|
199
|
-
})
|
|
285
|
+
// Remove by name
|
|
286
|
+
agent.removeMiddleware('logging')
|
|
200
287
|
|
|
201
|
-
//
|
|
202
|
-
|
|
203
|
-
name: 'Simple Assistant',
|
|
204
|
-
systemPrompt: 'You are a helpful assistant.',
|
|
205
|
-
model,
|
|
206
|
-
})
|
|
288
|
+
// View all middleware names
|
|
289
|
+
console.log(agent.middlewareNames) // ['logging', 'compression', ...]
|
|
207
290
|
|
|
208
|
-
//
|
|
209
|
-
const
|
|
210
|
-
|
|
211
|
-
for await (const event of session.receive()) {
|
|
212
|
-
if (event.type === 'text_delta') {
|
|
213
|
-
process.stdout.write(event.delta)
|
|
214
|
-
} else if (event.type === 'done') {
|
|
215
|
-
console.log('\n完成:', event.stopReason)
|
|
216
|
-
}
|
|
217
|
-
}
|
|
291
|
+
// Use unsubscribe function
|
|
292
|
+
const unsubscribe = agent.use(middleware, 'temp')
|
|
293
|
+
unsubscribe() // Remove middleware
|
|
218
294
|
```
|
|
219
295
|
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
## 🧅 Middleware Pattern
|
|
296
|
+
### Built-in Middleware Default Names
|
|
223
297
|
|
|
224
|
-
GoatChain
|
|
298
|
+
GoatChain's built-in middleware factories automatically provide default names:
|
|
225
299
|
|
|
226
|
-
```
|
|
227
|
-
|
|
300
|
+
```typescript
|
|
301
|
+
// Plan mode middleware - automatically named 'plan-mode'
|
|
302
|
+
agent.use(createPlanModeMiddleware())
|
|
303
|
+
|
|
304
|
+
// Context compression middleware - automatically named 'context-compression'
|
|
305
|
+
agent.use(createContextCompressionMiddleware({
|
|
306
|
+
maxTokens: 128000,
|
|
307
|
+
}))
|
|
308
|
+
|
|
309
|
+
// View all middleware
|
|
310
|
+
console.log(agent.middlewareNames)
|
|
311
|
+
// Output: ['plan-mode', 'context-compression']
|
|
312
|
+
|
|
313
|
+
// Remove by default name
|
|
314
|
+
agent.removeMiddleware('plan-mode')
|
|
315
|
+
|
|
316
|
+
// Or customize the name
|
|
317
|
+
agent.use(createPlanModeMiddleware({ name: 'my-plan' }))
|
|
318
|
+
agent.use(createContextCompressionMiddleware({
|
|
319
|
+
maxTokens: 128000,
|
|
320
|
+
}), 'my-compression') // Override default name
|
|
228
321
|
```
|
|
229
322
|
|
|
323
|
+
### Middleware Examples
|
|
324
|
+
|
|
230
325
|
```typescript
|
|
231
326
|
// Logging middleware
|
|
232
327
|
agent.use(async (state, next) => {
|
|
233
328
|
const start = Date.now()
|
|
234
329
|
console.log(`[${state.iteration}] Before model call`)
|
|
235
330
|
|
|
236
|
-
await next() // Execute model stream
|
|
331
|
+
const nextState = await next(state) // Execute model stream
|
|
237
332
|
|
|
238
333
|
console.log(`[${state.iteration}] After model call (${Date.now() - start}ms)`)
|
|
239
|
-
|
|
334
|
+
return nextState
|
|
335
|
+
}, 'logging')
|
|
240
336
|
|
|
241
337
|
// Error handling middleware
|
|
242
338
|
agent.use(async (state, next) => {
|
|
243
339
|
try {
|
|
244
|
-
await next()
|
|
245
|
-
}
|
|
340
|
+
return await next(state)
|
|
341
|
+
}
|
|
342
|
+
catch (error) {
|
|
246
343
|
state.shouldContinue = false
|
|
247
344
|
state.stopReason = 'error'
|
|
248
345
|
state.error = error
|
|
346
|
+
return state
|
|
249
347
|
}
|
|
250
|
-
})
|
|
348
|
+
}, 'error-handler')
|
|
251
349
|
|
|
252
350
|
// Rate limiting middleware
|
|
253
351
|
agent.use(async (state, next) => {
|
|
254
352
|
await rateLimiter.acquire()
|
|
255
|
-
|
|
256
|
-
})
|
|
353
|
+
return next(state)
|
|
354
|
+
}, 'rate-limiter')
|
|
257
355
|
```
|
|
258
356
|
|
|
259
357
|
## 📡 Event Types
|
|
@@ -340,92 +438,6 @@ Available state stores:
|
|
|
340
438
|
- `FileStateStore` - File-based persistence
|
|
341
439
|
- `InMemoryStateStore` - In-memory (for testing)
|
|
342
440
|
|
|
343
|
-
## 🔧 Session Management
|
|
344
|
-
|
|
345
|
-
Sessions represent individual conversations with per-session configuration overrides:
|
|
346
|
-
|
|
347
|
-
```typescript
|
|
348
|
-
// Create session
|
|
349
|
-
const session = await sessionManager.create(agent.id, {
|
|
350
|
-
customField: 'value',
|
|
351
|
-
})
|
|
352
|
-
|
|
353
|
-
// Session-level overrides
|
|
354
|
-
session.setModelOverride({ modelId: 'gpt-4o-mini' })
|
|
355
|
-
session.setSystemPromptOverride('You are a concise assistant.')
|
|
356
|
-
session.disableTools(['dangerous_tool'])
|
|
357
|
-
|
|
358
|
-
// Track session activity
|
|
359
|
-
session.addMessage({ role: 'user', content: 'Hello!' })
|
|
360
|
-
session.addUsage({ promptTokens: 10, completionTokens: 5, totalTokens: 15 })
|
|
361
|
-
session.recordResponse(1500) // ms
|
|
362
|
-
|
|
363
|
-
// Get session snapshot for persistence
|
|
364
|
-
const snapshot = session.toSnapshot()
|
|
365
|
-
```
|
|
366
|
-
|
|
367
|
-
## 📁 Project Structure
|
|
368
|
-
|
|
369
|
-
```
|
|
370
|
-
src/
|
|
371
|
-
├── index.ts # Public exports
|
|
372
|
-
├── types/
|
|
373
|
-
│ ├── index.ts # Re-export all types
|
|
374
|
-
│ ├── message.ts # Message types (User, Assistant, Tool, System)
|
|
375
|
-
│ ├── event.ts # Stream event types
|
|
376
|
-
│ ├── common.ts # Shared types (ToolCall, Usage, JSONSchema)
|
|
377
|
-
│ └── snapshot.ts # Snapshot types (Agent, Session)
|
|
378
|
-
├── model/
|
|
379
|
-
│ ├── index.ts
|
|
380
|
-
│ ├── base.ts # BaseModel abstract class
|
|
381
|
-
│ └── types.ts # Model-specific types
|
|
382
|
-
├── state/
|
|
383
|
-
│ ├── index.ts
|
|
384
|
-
│ ├── stateStore.ts # StateStore interface
|
|
385
|
-
│ ├── FileStateStore.ts # File-based state storage
|
|
386
|
-
│ └── InMemoryStateStore.ts # In-memory state storage
|
|
387
|
-
├── tool/
|
|
388
|
-
│ ├── index.ts
|
|
389
|
-
│ ├── base.ts # BaseTool abstract class
|
|
390
|
-
│ └── registry.ts # ToolRegistry class
|
|
391
|
-
├── session/
|
|
392
|
-
│ ├── index.ts
|
|
393
|
-
│ ├── base.ts # BaseSession abstract class
|
|
394
|
-
│ └── manager.ts # BaseSessionManager abstract class
|
|
395
|
-
└── agent/
|
|
396
|
-
├── index.ts
|
|
397
|
-
├── agent.ts # Agent class
|
|
398
|
-
├── types.ts # Agent types (AgentLoopState, AgentInput, etc.)
|
|
399
|
-
├── middleware.ts # Middleware compose function
|
|
400
|
-
└── errors.ts # Agent-specific errors
|
|
401
|
-
```
|
|
402
|
-
|
|
403
|
-
## 🛡️ Error Handling
|
|
404
|
-
|
|
405
|
-
```typescript
|
|
406
|
-
import { AgentAbortError, AgentMaxIterationsError } from 'goatchain'
|
|
407
|
-
|
|
408
|
-
// Cancellation support
|
|
409
|
-
const controller = new AbortController()
|
|
410
|
-
|
|
411
|
-
try {
|
|
412
|
-
const session = await agent.createSession({ maxIterations: 5 })
|
|
413
|
-
session.send('Hello', { signal: controller.signal })
|
|
414
|
-
for await (const event of session.receive()) {
|
|
415
|
-
// Handle events...
|
|
416
|
-
}
|
|
417
|
-
} catch (error) {
|
|
418
|
-
if (error instanceof AgentAbortError) {
|
|
419
|
-
console.log('Agent was cancelled')
|
|
420
|
-
} else if (error instanceof AgentMaxIterationsError) {
|
|
421
|
-
console.log('Max iterations reached')
|
|
422
|
-
}
|
|
423
|
-
}
|
|
424
|
-
|
|
425
|
-
// Cancel from another context
|
|
426
|
-
controller.abort()
|
|
427
|
-
```
|
|
428
|
-
|
|
429
441
|
## 📖 API Reference
|
|
430
442
|
|
|
431
443
|
### Agent
|
|
@@ -446,81 +458,6 @@ controller.abort()
|
|
|
446
458
|
| `receive(options?)` | Stream events, resuming from checkpoint if present |
|
|
447
459
|
| `messages` | Conversation history |
|
|
448
460
|
|
|
449
|
-
### CreateSessionOptions
|
|
450
|
-
|
|
451
|
-
| Property | Type | Description |
|
|
452
|
-
| ---------------- | ------------- | ---------------------------------------- |
|
|
453
|
-
| `model?` | `ModelRef` | Optional model override for this session |
|
|
454
|
-
| `maxIterations?` | `number` | Max loop iterations (default: 10) |
|
|
455
|
-
| `hooks?` | `ToolHooks` | Tool execution hooks |
|
|
456
|
-
| `requestParams?` | `object` | Model request parameters |
|
|
457
|
-
|
|
458
|
-
### SendOptions
|
|
459
|
-
|
|
460
|
-
| Property | Type | Description |
|
|
461
|
-
| ---------------- | ------------- | ---------------------------------------- |
|
|
462
|
-
| `signal?` | `AbortSignal` | Cancellation support |
|
|
463
|
-
| `toolContext?` | `object` | Tool execution context input |
|
|
464
|
-
|
|
465
|
-
## 🔄 Model Switching
|
|
466
|
-
|
|
467
|
-
### Per-Request Model Override
|
|
468
|
-
|
|
469
|
-
Temporarily use a different model for a single request:
|
|
470
|
-
|
|
471
|
-
```typescript
|
|
472
|
-
const session = await agent.createSession({
|
|
473
|
-
model: { provider: 'openai', modelId: 'gpt-4' }, // Use GPT-4 for this session
|
|
474
|
-
})
|
|
475
|
-
session.send('Explain quantum physics')
|
|
476
|
-
for await (const event of session.receive()) {
|
|
477
|
-
// ...
|
|
478
|
-
}
|
|
479
|
-
```
|
|
480
|
-
|
|
481
|
-
### Persistent Model Switch
|
|
482
|
-
|
|
483
|
-
Change the default model for all subsequent requests:
|
|
484
|
-
|
|
485
|
-
```typescript
|
|
486
|
-
// Switch model at runtime
|
|
487
|
-
model.setModelId('gpt-4')
|
|
488
|
-
|
|
489
|
-
// All subsequent requests will use the new model
|
|
490
|
-
const session = await agent.createSession()
|
|
491
|
-
session.send('Hello')
|
|
492
|
-
for await (const event of session.receive()) {
|
|
493
|
-
// Uses gpt-4
|
|
494
|
-
}
|
|
495
|
-
```
|
|
496
|
-
|
|
497
|
-
### Pin Default Model (Overrides Routing)
|
|
498
|
-
|
|
499
|
-
If your `ModelClient` supports routing (e.g. created via `createModel()`), you can pin a specific default model at the agent level:
|
|
500
|
-
|
|
501
|
-
```typescript
|
|
502
|
-
agent.setModel({ provider: 'openai', modelId: 'gpt-4' })
|
|
503
|
-
```
|
|
504
|
-
|
|
505
|
-
### Multi-Provider Fallback
|
|
506
|
-
|
|
507
|
-
Configure multiple models with automatic fallback:
|
|
508
|
-
|
|
509
|
-
```typescript
|
|
510
|
-
const model = createModel({
|
|
511
|
-
adapters: [
|
|
512
|
-
createOpenAIAdapter({ defaultModelId: 'gpt-4' }),
|
|
513
|
-
createAnthropicAdapter({ defaultModelId: 'claude-3' }),
|
|
514
|
-
],
|
|
515
|
-
routing: {
|
|
516
|
-
fallbackOrder: [
|
|
517
|
-
{ provider: 'openai', modelId: 'gpt-4' }, // Try first
|
|
518
|
-
{ provider: 'anthropic', modelId: 'claude-3' }, // Fallback if first fails
|
|
519
|
-
],
|
|
520
|
-
},
|
|
521
|
-
})
|
|
522
|
-
```
|
|
523
|
-
|
|
524
461
|
## 📄 License
|
|
525
462
|
|
|
526
463
|
MIT © [Simon He](https://github.com/Simon-He95)
|