goatchain 0.0.16 → 0.0.18

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
@@ -74,9 +74,10 @@ const session = await agent.createSession({ id: 'my-session-id' })
74
74
 
75
75
  // Create session with configuration overrides
76
76
  const session = await agent.createSession({
77
- configOverride: {
78
- maxIterations: 10,
79
- maxConcurrentToolCalls: 3,
77
+ maxIterations: 10,
78
+ requestParams: {
79
+ temperature: 0.7,
80
+ maxTokens: 2000,
80
81
  },
81
82
  })
82
83
  ```
@@ -84,12 +85,14 @@ const session = await agent.createSession({
84
85
  ### Session Configuration Options
85
86
 
86
87
  ```typescript
87
- interface SessionConfigOverride {
88
+ interface CreateSessionOptions {
89
+ id?: string // Custom session ID
88
90
  maxIterations?: number // Max agent loop iterations (default: 5)
89
- maxConcurrentToolCalls?: number // Max parallel tool calls (default: 5)
90
- temperature?: number // Model temperature
91
- maxTokens?: number // Max output tokens
92
- topP?: number // Nucleus sampling parameter
91
+ requestParams?: {
92
+ temperature?: number // Model temperature
93
+ maxTokens?: number // Max output tokens
94
+ topP?: number // Nucleus sampling parameter
95
+ }
93
96
  }
94
97
  ```
95
98
 
@@ -103,12 +106,6 @@ session.send('What is the weather today?')
103
106
  session.send('First question')
104
107
  // Wait for response...
105
108
  session.send('Follow-up question')
106
-
107
- // Message with options
108
- session.send('Analyze this data', {
109
- temperature: 0.7,
110
- maxTokens: 2000,
111
- })
112
109
  ```
113
110
 
114
111
  ### Receiving Events
@@ -291,7 +288,7 @@ const agent = new Agent({
291
288
  name: 'MyAgent',
292
289
  systemPrompt: 'You are a helpful assistant.',
293
290
  model,
294
- tools: [], // Optional: custom tools
291
+ tools, // Optional: ToolRegistry instance
295
292
  stateStore, // Optional: for persistence
296
293
  maxIterations: 5, // Optional: max loop iterations
297
294
  maxConcurrentToolCalls: 5, // Optional: parallel tool calls
@@ -305,7 +302,7 @@ interface AgentOptions {
305
302
  name: string // Agent name
306
303
  systemPrompt: string // System instructions
307
304
  model: ModelClient | ModelRef // LLM client or reference
308
- tools?: BaseTool[] // Custom tools
305
+ tools?: ToolRegistry // Tool registry (not an array)
309
306
  stateStore?: StateStore // Persistence layer
310
307
  maxIterations?: number // Max agent loop iterations (default: 5)
311
308
  maxConcurrentToolCalls?: number // Max parallel tool calls (default: 5)
@@ -348,6 +345,8 @@ GoatChain includes 23 built-in tools:
348
345
 
349
346
  ```typescript
350
347
  import {
348
+ Agent,
349
+ ToolRegistry,
351
350
  ReadTool,
352
351
  WriteTool,
353
352
  EditTool,
@@ -358,27 +357,72 @@ import {
358
357
  WebFetchTool,
359
358
  } from 'goatchain'
360
359
 
360
+ // Create a tool registry and register tools
361
+ const tools = new ToolRegistry()
362
+ tools.register(new ReadTool())
363
+ tools.register(new WriteTool())
364
+ tools.register(new EditTool())
365
+ tools.register(new BashTool())
366
+ tools.register(new GrepTool())
367
+ tools.register(new GlobTool())
368
+ tools.register(new WebSearchTool({ apiKey: process.env.SERPER_API_KEY }))
369
+ tools.register(new WebFetchTool())
370
+
361
371
  const agent = new Agent({
362
372
  name: 'MyAgent',
363
373
  systemPrompt: 'You are helpful.',
364
374
  model,
365
- tools: [
366
- new ReadTool(),
367
- new WriteTool(),
368
- new EditTool(),
369
- new BashTool(),
370
- new GrepTool(),
371
- new GlobTool(),
372
- new WebSearchTool({ apiKey: process.env.SERPER_API_KEY }),
373
- new WebFetchTool(),
374
- ],
375
+ tools,
375
376
  })
376
377
  ```
377
378
 
379
+ ### Configuring File Tool Working Directory
380
+
381
+ File-related tools (`ReadTool`, `WriteTool`, `EditTool`, `GlobTool`, `GrepTool`, `BashTool`) support configuring the working directory:
382
+
383
+ ```typescript
384
+ import path from 'node:path'
385
+
386
+ // Define output directory
387
+ const OUTPUT_DIR = path.resolve(import.meta.dirname, 'output')
388
+
389
+ // Option 1: Set working directory only
390
+ const tools = new ToolRegistry()
391
+ tools.register(new ReadTool({ cwd: OUTPUT_DIR }))
392
+ tools.register(new WriteTool({ cwd: OUTPUT_DIR }))
393
+ tools.register(new GlobTool({ cwd: OUTPUT_DIR }))
394
+ tools.register(new GrepTool({ cwd: OUTPUT_DIR }))
395
+ tools.register(new BashTool({ cwd: OUTPUT_DIR }))
396
+
397
+ // Option 2: Restrict to specific directory (security sandbox)
398
+ // This prevents access to files outside the allowed directory
399
+ const tools = new ToolRegistry()
400
+ tools.register(new ReadTool({
401
+ cwd: OUTPUT_DIR,
402
+ allowedDirectory: OUTPUT_DIR // Only allow reads within OUTPUT_DIR
403
+ }))
404
+ tools.register(new WriteTool({
405
+ cwd: OUTPUT_DIR,
406
+ allowedDirectory: OUTPUT_DIR // Only allow writes within OUTPUT_DIR
407
+ }))
408
+ ```
409
+
410
+ **Directory Configuration Options:**
411
+
412
+ | Option | Description | Example |
413
+ |--------|-------------|---------|
414
+ | `cwd` | Working directory for resolving relative paths | `{ cwd: '/app/output' }` |
415
+ | `allowedDirectory` | Restrict file access to this directory only (blocks path traversal) | `{ allowedDirectory: '/app/output' }` |
416
+
417
+ **When to use `allowedDirectory`:**
418
+ - When you want to sandbox the agent to a specific directory
419
+ - To prevent accidental access to sensitive files
420
+ - For production environments with security requirements
421
+
378
422
  ### Creating Custom Tools
379
423
 
380
424
  ```typescript
381
- import { BaseTool } from 'goatchain'
425
+ import { BaseTool, ToolRegistry } from 'goatchain'
382
426
 
383
427
  class MyCustomTool extends BaseTool {
384
428
  name = 'my_tool'
@@ -402,11 +446,14 @@ class MyCustomTool extends BaseTool {
402
446
  }
403
447
 
404
448
  // Use it
449
+ const tools = new ToolRegistry()
450
+ tools.register(new MyCustomTool())
451
+
405
452
  const agent = new Agent({
406
453
  name: 'MyAgent',
407
454
  systemPrompt: 'You are helpful.',
408
455
  model,
409
- tools: [new MyCustomTool()],
456
+ tools,
410
457
  })
411
458
  ```
412
459
 
@@ -614,7 +661,7 @@ const model = createModel({
614
661
  adapter: createOpenAIAdapter({
615
662
  defaultModelId: 'gpt-4o',
616
663
  apiKey: process.env.OPENAI_API_KEY!,
617
- baseURL: 'https://api.openai.com/v1', // Optional
664
+ baseUrl: 'https://api.openai.com/v1', // Optional
618
665
  organization: 'org-xxx', // Optional
619
666
  }),
620
667
  })
@@ -626,7 +673,7 @@ const model = createModel({
626
673
  interface OpenAIAdapterOptions {
627
674
  defaultModelId?: string // Default model ID
628
675
  apiKey?: string // OpenAI API key
629
- baseURL?: string // Custom API endpoint
676
+ baseUrl?: string // Custom API endpoint (note: lowercase 'u')
630
677
  organization?: string // OpenAI organization ID
631
678
  defaultHeaders?: Record<string, string> // Custom headers
632
679
  timeout?: number // Request timeout (ms)
@@ -650,7 +697,7 @@ const deepseek = createModel({
650
697
  adapter: createOpenAIAdapter({
651
698
  defaultModelId: 'deepseek-chat',
652
699
  apiKey: process.env.DEEPSEEK_API_KEY!,
653
- baseURL: 'https://api.deepseek.com/v1',
700
+ baseUrl: 'https://api.deepseek.com/v1',
654
701
  }),
655
702
  })
656
703
  ```
@@ -799,6 +846,7 @@ import {
799
846
  Agent,
800
847
  createModel,
801
848
  createOpenAIAdapter,
849
+ ToolRegistry,
802
850
  ReadTool,
803
851
  WriteTool,
804
852
  BashTool,
@@ -811,11 +859,16 @@ const model = createModel({
811
859
  }),
812
860
  })
813
861
 
862
+ const tools = new ToolRegistry()
863
+ tools.register(new ReadTool())
864
+ tools.register(new WriteTool())
865
+ tools.register(new BashTool())
866
+
814
867
  const agent = new Agent({
815
868
  name: 'File Assistant',
816
869
  systemPrompt: 'You help users manage their files.',
817
870
  model,
818
- tools: [new ReadTool(), new WriteTool(), new BashTool()],
871
+ tools,
819
872
  })
820
873
 
821
874
  const session = await agent.createSession()
@@ -971,6 +1024,65 @@ console.log(`Total messages: ${session.messages.length}`)
971
1024
  console.log(`Total tokens: ${session.usage.totalTokens}`)
972
1025
  ```
973
1026
 
1027
+ ### Example 6: File Operations with Directory Configuration
1028
+
1029
+ ```typescript
1030
+ import path from 'node:path'
1031
+ import {
1032
+ Agent,
1033
+ createModel,
1034
+ createOpenAIAdapter,
1035
+ ToolRegistry,
1036
+ ReadTool,
1037
+ WriteTool,
1038
+ GlobTool,
1039
+ GrepTool,
1040
+ } from 'goatchain'
1041
+
1042
+ const model = createModel({
1043
+ adapter: createOpenAIAdapter({
1044
+ defaultModelId: 'gpt-4o',
1045
+ apiKey: process.env.OPENAI_API_KEY!,
1046
+ }),
1047
+ })
1048
+
1049
+ // Define output directory for agent's file operations
1050
+ const OUTPUT_DIR = path.resolve(process.cwd(), 'output')
1051
+
1052
+ // Configure tools with working directory and restrictions
1053
+ const tools = new ToolRegistry()
1054
+ tools.register(new ReadTool({
1055
+ cwd: OUTPUT_DIR,
1056
+ allowedDirectory: OUTPUT_DIR // Sandbox: only allow reads in OUTPUT_DIR
1057
+ }))
1058
+ tools.register(new WriteTool({
1059
+ cwd: OUTPUT_DIR,
1060
+ allowedDirectory: OUTPUT_DIR // Sandbox: only allow writes in OUTPUT_DIR
1061
+ }))
1062
+ tools.register(new GlobTool({ cwd: OUTPUT_DIR }))
1063
+ tools.register(new GrepTool({ cwd: OUTPUT_DIR }))
1064
+
1065
+ const agent = new Agent({
1066
+ name: 'Sandboxed File Agent',
1067
+ systemPrompt: `You are a file management assistant.
1068
+ All your file operations are restricted to the output directory.
1069
+ You can create, read, and modify files within this sandbox.`,
1070
+ model,
1071
+ tools,
1072
+ })
1073
+
1074
+ const session = await agent.createSession()
1075
+ session.send('Create a report.md file with a summary of today\'s tasks')
1076
+
1077
+ for await (const event of session.receive()) {
1078
+ if (event.type === 'text_delta') {
1079
+ process.stdout.write(event.delta)
1080
+ } else if (event.type === 'tool_call_start') {
1081
+ console.log(`\n[Tool] ${event.name}`)
1082
+ }
1083
+ }
1084
+ ```
1085
+
974
1086
  ## 📖 API Reference
975
1087
 
976
1088
  ### Agent Class
@@ -986,7 +1098,7 @@ new Agent(options: AgentOptions)
986
1098
  - `name: string` - Agent name (required)
987
1099
  - `systemPrompt: string` - System instructions (required)
988
1100
  - `model: ModelClient | ModelRef` - LLM client (required)
989
- - `tools?: BaseTool[]` - Custom tools
1101
+ - `tools?: ToolRegistry` - Tool registry (not an array)
990
1102
  - `stateStore?: StateStore` - Persistence layer
991
1103
  - `maxIterations?: number` - Max loop iterations (default: 5)
992
1104
  - `maxConcurrentToolCalls?: number` - Max parallel tools (default: 5)
@@ -1001,10 +1113,11 @@ Create a new session.
1001
1113
  ```typescript
1002
1114
  const session = await agent.createSession({
1003
1115
  id: 'custom-id', // Optional custom ID
1004
- configOverride: {
1005
- // Optional config overrides
1006
- maxIterations: 10,
1116
+ maxIterations: 10, // Optional max iterations
1117
+ requestParams: {
1118
+ // Optional request parameters
1007
1119
  temperature: 0.7,
1120
+ maxTokens: 2000,
1008
1121
  },
1009
1122
  })
1010
1123
  ```
@@ -1062,15 +1175,12 @@ agent.setModel({ type: 'ref', ref: 'the-model' })
1062
1175
 
1063
1176
  #### Methods
1064
1177
 
1065
- **`send(input, options?): void`**
1178
+ **`send(input): void`**
1066
1179
 
1067
1180
  Send a message to the session.
1068
1181
 
1069
1182
  ```typescript
1070
- session.send('Hello!', {
1071
- temperature: 0.8,
1072
- maxTokens: 1000,
1073
- })
1183
+ session.send('Hello!')
1074
1184
  ```
1075
1185
 
1076
1186
  **`receive(options?): AsyncGenerator<AgentEvent>`**
@@ -1124,7 +1234,6 @@ session.restoreFromSnapshot(snapshot)
1124
1234
  - `status: SessionStatus` - Session status ('idle' | 'running' | 'completed' | 'error')
1125
1235
  - `messages: Message[]` - Message history
1126
1236
  - `usage: Usage` - Token usage statistics
1127
- - `configOverride?: SessionConfigOverride` - Config overrides
1128
1237
  - `createdAt: number` - Creation timestamp
1129
1238
  - `updatedAt: number` - Last update timestamp
1130
1239