goatchain 0.0.2
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 +526 -0
- package/dist/index.d.ts +3328 -0
- package/dist/index.js +181 -0
- package/package.json +65 -0
package/README.md
ADDED
|
@@ -0,0 +1,526 @@
|
|
|
1
|
+
# GoatChain ๐
|
|
2
|
+
|
|
3
|
+
> A lightweight, extensible TypeScript SDK for building AI agents with streaming support, tool calling, and middleware pattern.
|
|
4
|
+
|
|
5
|
+
[](https://badge.fury.io/js/goatchain)
|
|
6
|
+
[](https://opensource.org/licenses/MIT)
|
|
7
|
+
|
|
8
|
+
## โจ Features
|
|
9
|
+
|
|
10
|
+
- **๐ Agentic Loop** - Automatic tool calling loop with configurable max iterations
|
|
11
|
+
- **๐ก Streaming First** - Real-time streaming responses with detailed events
|
|
12
|
+
- **๐ง
Middleware Pattern** - Koa-style onion model for extensible hooks
|
|
13
|
+
- **๐ง Tool System** - Easy-to-use tool registration and execution
|
|
14
|
+
- **๐พ State Management** - Two-level state store (Agent + Session level)
|
|
15
|
+
- **๐ธ Snapshot/Restore** - Full persistence support for agents and sessions
|
|
16
|
+
- **๐ฏ TypeScript Native** - Full type safety with comprehensive type exports
|
|
17
|
+
|
|
18
|
+
## ๐ฆ Installation
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
pnpm add goatchain
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
## ๐ Documentation
|
|
25
|
+
|
|
26
|
+
ๅฎๆด็ๆๆกฃ่ฏทๆฅ็ [docs/](./docs/) ็ฎๅฝ๏ผ
|
|
27
|
+
|
|
28
|
+
- [ๅฟซ้ๅผๅง](./docs/getting-started.md) - ๅๅปบไฝ ็็ฌฌไธไธช Agent Loop
|
|
29
|
+
- [ๆๆกฃ็ดขๅผ](./docs/README.md) - ๆๆๆๆกฃ็ๅฎๆดๅ่กจ
|
|
30
|
+
|
|
31
|
+
## ๐งฐ CLI
|
|
32
|
+
|
|
33
|
+
After installing `goatchain-cli` globally (or using `pnpm -s cli` in this repo), run:
|
|
34
|
+
|
|
35
|
+
```bash
|
|
36
|
+
goatchain
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
Common options:
|
|
40
|
+
|
|
41
|
+
- `-k, --api-key <key>` (or set `OPENAI_API_KEY`)
|
|
42
|
+
- `-m, --model <id>`
|
|
43
|
+
- `--base-url <url>`
|
|
44
|
+
- `--max-tokens <n>`
|
|
45
|
+
- `--temperature <n>`
|
|
46
|
+
|
|
47
|
+
Commands:
|
|
48
|
+
|
|
49
|
+
- `/help` help
|
|
50
|
+
- `/model <id>` switch model id (OpenAI)
|
|
51
|
+
- `/set <k> <v>` set request params (e.g. `temperature`, `maxTokens`, `topP`)
|
|
52
|
+
- `/unset <k>` clear a request param
|
|
53
|
+
- `/params` show current request params
|
|
54
|
+
- `/base-url <url>` set base URL
|
|
55
|
+
- `/api-key <key>` set API key (not printed)
|
|
56
|
+
- `/tools` list enabled tools (Read/Write/Edit/Glob/Grep/WebSearch*)
|
|
57
|
+
- `/sessions` list and pick a saved session
|
|
58
|
+
- `/use <sessionId>` restore a saved session (prints recent history)
|
|
59
|
+
- `/save` persist current config/session
|
|
60
|
+
- `/status` show current model/session info
|
|
61
|
+
- `/new` start a new conversation (clears history)
|
|
62
|
+
|
|
63
|
+
Requires `OPENAI_API_KEY` in the environment.
|
|
64
|
+
|
|
65
|
+
Web search (optional):
|
|
66
|
+
|
|
67
|
+
- Set `SERPER_API_KEY` (or `GOATCHAIN_SERPER_API_KEY`) to enable the builtin `WebSearch` tool for up-to-date info like weather.
|
|
68
|
+
- You can also set it in `./.goatchain/config.json` (workspace-scoped, gitignored):
|
|
69
|
+
- `{"tools":{"webSearch":{"apiKey":"...","apiEndpoint":"...","numResults":10}}}`
|
|
70
|
+
|
|
71
|
+
Local persistence (workspace-scoped):
|
|
72
|
+
|
|
73
|
+
- Config and sessions are saved under `./.goatchain/` (auto-created).
|
|
74
|
+
- `.goatchain/` is gitignored to avoid accidentally committing secrets.
|
|
75
|
+
|
|
76
|
+
DeepSeek thinking mode compatibility:
|
|
77
|
+
|
|
78
|
+
- 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`, set `openai.compat.requireReasoningContentForToolCalls=true` in `./.goatchain/config.json`.
|
|
80
|
+
|
|
81
|
+
## ๐๏ธ Architecture
|
|
82
|
+
|
|
83
|
+
```mermaid
|
|
84
|
+
classDiagram
|
|
85
|
+
direction TB
|
|
86
|
+
|
|
87
|
+
class Agent {
|
|
88
|
+
+id: string
|
|
89
|
+
+name: string
|
|
90
|
+
+systemPrompt: string
|
|
91
|
+
+model: BaseModel
|
|
92
|
+
+tools: ToolRegistry
|
|
93
|
+
+stateStore: StateStore
|
|
94
|
+
+sessionManager: BaseSessionManager
|
|
95
|
+
+stats: AgentStats
|
|
96
|
+
+use(middleware): this
|
|
97
|
+
+createSession(options): BaseSession
|
|
98
|
+
+resumeSession(sessionId, options): BaseSession
|
|
99
|
+
+setModel(modelOrRef): void
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
class BaseModel {
|
|
103
|
+
<<abstract>>
|
|
104
|
+
+modelId: string
|
|
105
|
+
+invoke(messages, options): Promise~ChatResponse~
|
|
106
|
+
+stream(messages, options): AsyncIterable~StreamEvent~
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
class StateStore {
|
|
110
|
+
<<interface>>
|
|
111
|
+
+savePoint: string
|
|
112
|
+
+deleteOnComplete: boolean
|
|
113
|
+
+saveCheckpoint(checkpoint): Promise~void~
|
|
114
|
+
+loadCheckpoint(sessionId): Promise~AgentLoopCheckpoint~
|
|
115
|
+
+deleteCheckpoint(sessionId): Promise~void~
|
|
116
|
+
+listCheckpoints(agentId): Promise~AgentLoopCheckpoint[]~
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
class BaseTool {
|
|
120
|
+
<<abstract>>
|
|
121
|
+
+name: string
|
|
122
|
+
+description: string
|
|
123
|
+
+parameters: JSONSchema
|
|
124
|
+
+execute(args, ctx?): Promise~unknown~
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
class ToolRegistry {
|
|
128
|
+
+register(tool): void
|
|
129
|
+
+unregister(name): boolean
|
|
130
|
+
+get(name): BaseTool
|
|
131
|
+
+list(): BaseTool[]
|
|
132
|
+
+toOpenAIFormat(): OpenAITool[]
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
class BaseSession {
|
|
136
|
+
<<abstract>>
|
|
137
|
+
+id: string
|
|
138
|
+
+agentId: string
|
|
139
|
+
+status: SessionStatus
|
|
140
|
+
+messages: Message[]
|
|
141
|
+
+usage: Usage
|
|
142
|
+
+configOverride: SessionConfigOverride
|
|
143
|
+
+addMessage(message): void
|
|
144
|
+
+save(): Promise~void~
|
|
145
|
+
+toSnapshot(): SessionSnapshot
|
|
146
|
+
+restoreFromSnapshot(snapshot): void
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
class BaseSessionManager {
|
|
150
|
+
<<abstract>>
|
|
151
|
+
+create(agentId, metadata): Promise~BaseSession~
|
|
152
|
+
+get(sessionId): Promise~BaseSession~
|
|
153
|
+
+list(agentId): Promise~BaseSession[]~
|
|
154
|
+
+destroy(sessionId): Promise~void~
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
class Middleware {
|
|
158
|
+
<<function>>
|
|
159
|
+
(ctx: AgentLoopState, next: NextFunction) => Promise~void~
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
class AgentLoopState {
|
|
163
|
+
+sessionId: string
|
|
164
|
+
+agentId: string
|
|
165
|
+
+messages: Message[]
|
|
166
|
+
+iteration: number
|
|
167
|
+
+pendingToolCalls: ToolCallWithResult[]
|
|
168
|
+
+currentResponse: string
|
|
169
|
+
+shouldContinue: boolean
|
|
170
|
+
+usage: Usage
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
Agent --> BaseModel : uses
|
|
174
|
+
Agent --> ToolRegistry : uses
|
|
175
|
+
Agent --> StateStore : uses
|
|
176
|
+
Agent --> BaseSessionManager : uses
|
|
177
|
+
Agent ..> Middleware : applies
|
|
178
|
+
Agent ..> AgentLoopState : manages
|
|
179
|
+
ToolRegistry --> BaseTool : contains
|
|
180
|
+
BaseSessionManager --> BaseSession : manages
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
## ๐ Quick Start
|
|
184
|
+
|
|
185
|
+
ๆ็ฎๅ็ Agent Loop ็คบไพ๏ผ
|
|
186
|
+
|
|
187
|
+
```typescript
|
|
188
|
+
import process from 'node:process'
|
|
189
|
+
import { Agent, createModel, createOpenAIAdapter } from 'goatchain'
|
|
190
|
+
|
|
191
|
+
// ๅๅปบๆจกๅ
|
|
192
|
+
const model = createModel({
|
|
193
|
+
adapters: [
|
|
194
|
+
createOpenAIAdapter({
|
|
195
|
+
defaultModelId: 'gpt-4o',
|
|
196
|
+
apiKey: process.env.OPENAI_API_KEY!,
|
|
197
|
+
}),
|
|
198
|
+
],
|
|
199
|
+
})
|
|
200
|
+
|
|
201
|
+
// ๅๅปบ Agent
|
|
202
|
+
const agent = new Agent({
|
|
203
|
+
name: 'Simple Assistant',
|
|
204
|
+
systemPrompt: 'You are a helpful assistant.',
|
|
205
|
+
model,
|
|
206
|
+
})
|
|
207
|
+
|
|
208
|
+
// ๆตๅผๅค็ๅๅบ
|
|
209
|
+
const session = await agent.createSession()
|
|
210
|
+
session.send('Hello!')
|
|
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
|
+
}
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
๐ **่ฏฆ็ปๆๆกฃ**: ๆฅ็ [docs/getting-started.md](./docs/getting-started.md) ไบ่งฃๆดๅค็คบไพๅๅฎๆดๆๅใ
|
|
221
|
+
|
|
222
|
+
## ๐ง
Middleware Pattern
|
|
223
|
+
|
|
224
|
+
GoatChain uses a Koa-style onion model for middleware. Each middleware wraps around the core execution:
|
|
225
|
+
|
|
226
|
+
```
|
|
227
|
+
outer:before โ inner:before โ exec (model.stream) โ inner:after โ outer:after
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
```typescript
|
|
231
|
+
// Logging middleware
|
|
232
|
+
agent.use(async (state, next) => {
|
|
233
|
+
const start = Date.now()
|
|
234
|
+
console.log(`[${state.iteration}] Before model call`)
|
|
235
|
+
|
|
236
|
+
await next() // Execute model stream
|
|
237
|
+
|
|
238
|
+
console.log(`[${state.iteration}] After model call (${Date.now() - start}ms)`)
|
|
239
|
+
})
|
|
240
|
+
|
|
241
|
+
// Error handling middleware
|
|
242
|
+
agent.use(async (state, next) => {
|
|
243
|
+
try {
|
|
244
|
+
await next()
|
|
245
|
+
} catch (error) {
|
|
246
|
+
state.shouldContinue = false
|
|
247
|
+
state.stopReason = 'error'
|
|
248
|
+
state.error = error
|
|
249
|
+
}
|
|
250
|
+
})
|
|
251
|
+
|
|
252
|
+
// Rate limiting middleware
|
|
253
|
+
agent.use(async (state, next) => {
|
|
254
|
+
await rateLimiter.acquire()
|
|
255
|
+
await next()
|
|
256
|
+
})
|
|
257
|
+
```
|
|
258
|
+
|
|
259
|
+
## ๐ก Event Types
|
|
260
|
+
|
|
261
|
+
The session receive stream emits the following events:
|
|
262
|
+
|
|
263
|
+
| Event | Description |
|
|
264
|
+
| ----------------- | ------------------------------------- |
|
|
265
|
+
| `iteration_start` | Beginning of a loop iteration |
|
|
266
|
+
| `text_delta` | Partial text response from LLM |
|
|
267
|
+
| `thinking_start` | Thinking phase begins (if supported) |
|
|
268
|
+
| `thinking_delta` | Thinking content delta (if supported) |
|
|
269
|
+
| `thinking_end` | Thinking phase ends (if supported) |
|
|
270
|
+
| `tool_call_start` | Tool call begins |
|
|
271
|
+
| `tool_call_delta` | Tool call arguments delta |
|
|
272
|
+
| `tool_call_end` | Tool call is complete |
|
|
273
|
+
| `tool_result` | Tool execution completed |
|
|
274
|
+
| `iteration_end` | End of a loop iteration (includes usage) |
|
|
275
|
+
| `done` | Stream completed (includes usage) |
|
|
276
|
+
| `error` | Error occurred |
|
|
277
|
+
|
|
278
|
+
```typescript
|
|
279
|
+
interface AgentEvent {
|
|
280
|
+
type:
|
|
281
|
+
| 'text_delta'
|
|
282
|
+
| 'tool_call_start'
|
|
283
|
+
| 'tool_call_delta'
|
|
284
|
+
| 'tool_call_end'
|
|
285
|
+
| 'tool_result'
|
|
286
|
+
| 'thinking_start'
|
|
287
|
+
| 'thinking_delta'
|
|
288
|
+
| 'thinking_end'
|
|
289
|
+
| 'error'
|
|
290
|
+
| 'done'
|
|
291
|
+
| 'iteration_start'
|
|
292
|
+
| 'iteration_end'
|
|
293
|
+
// ... event-specific fields
|
|
294
|
+
}
|
|
295
|
+
```
|
|
296
|
+
|
|
297
|
+
`iteration_end` and `done` events include optional `usage: Usage` with cumulative token counts.
|
|
298
|
+
|
|
299
|
+
## ๐พ Checkpoint & Resume
|
|
300
|
+
|
|
301
|
+
Built-in checkpoint support for resuming interrupted agent executions:
|
|
302
|
+
|
|
303
|
+
```typescript
|
|
304
|
+
import { Agent, FileStateStore } from 'goatchain'
|
|
305
|
+
|
|
306
|
+
// Create state store with configuration
|
|
307
|
+
const stateStore = new FileStateStore({
|
|
308
|
+
dir: './checkpoints',
|
|
309
|
+
savePoint: 'before', // Save before each iteration
|
|
310
|
+
deleteOnComplete: true, // Clean up after successful completion
|
|
311
|
+
})
|
|
312
|
+
|
|
313
|
+
// Agent automatically saves checkpoints when stateStore is provided
|
|
314
|
+
const agent = new Agent({
|
|
315
|
+
name: 'MyAgent',
|
|
316
|
+
systemPrompt: 'You are helpful.',
|
|
317
|
+
model,
|
|
318
|
+
stateStore,
|
|
319
|
+
})
|
|
320
|
+
|
|
321
|
+
// Run agent - checkpoints are saved automatically
|
|
322
|
+
const session = await agent.createSession()
|
|
323
|
+
session.send('Hello')
|
|
324
|
+
for await (const event of session.receive()) {
|
|
325
|
+
console.log(event)
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
// If interrupted, resume from checkpoint
|
|
329
|
+
const checkpoint = await stateStore.loadCheckpoint(session.id)
|
|
330
|
+
if (checkpoint) {
|
|
331
|
+
const resumed = await agent.resumeSession(session.id)
|
|
332
|
+
for await (const event of resumed.receive()) {
|
|
333
|
+
console.log(event)
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
```
|
|
337
|
+
|
|
338
|
+
Available state stores:
|
|
339
|
+
|
|
340
|
+
- `FileStateStore` - File-based persistence
|
|
341
|
+
- `InMemoryStateStore` - In-memory (for testing)
|
|
342
|
+
|
|
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
|
+
## ๐ API Reference
|
|
430
|
+
|
|
431
|
+
### Agent
|
|
432
|
+
|
|
433
|
+
| Method | Description |
|
|
434
|
+
| ------------------------------- | ----------------------- |
|
|
435
|
+
| `constructor(options)` | Create a new agent |
|
|
436
|
+
| `use(middleware)` | Add middleware |
|
|
437
|
+
| `createSession(options)` | Create a session |
|
|
438
|
+
| `resumeSession(sessionId, options)` | Resume a session |
|
|
439
|
+
| `setModel(modelOrRef)` | Switch/pin model at runtime |
|
|
440
|
+
|
|
441
|
+
### Session
|
|
442
|
+
|
|
443
|
+
| Method | Description |
|
|
444
|
+
| ----------------------- | -------------------------------------------- |
|
|
445
|
+
| `send(input, options?)` | Queue input for the session |
|
|
446
|
+
| `receive(options?)` | Stream events, resuming from checkpoint if present |
|
|
447
|
+
| `messages` | Conversation history |
|
|
448
|
+
|
|
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
|
+
## ๐ License
|
|
525
|
+
|
|
526
|
+
MIT ยฉ [Simon He](https://github.com/Simon-He95)
|