goatchain 0.0.18 → 0.0.20

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
@@ -70,7 +70,7 @@ Session is the core component for managing conversations. It handles message his
70
70
  const session = await agent.createSession()
71
71
 
72
72
  // Create session with custom ID
73
- const session = await agent.createSession({ id: 'my-session-id' })
73
+ const session = await agent.createSession({ sessionId: 'my-session-id' })
74
74
 
75
75
  // Create session with configuration overrides
76
76
  const session = await agent.createSession({
@@ -86,8 +86,10 @@ const session = await agent.createSession({
86
86
 
87
87
  ```typescript
88
88
  interface CreateSessionOptions {
89
- id?: string // Custom session ID
90
- maxIterations?: number // Max agent loop iterations (default: 5)
89
+ sessionId?: string // Custom session ID
90
+ model?: ModelRef // Optional model override
91
+ maxIterations?: number // Max agent loop iterations (default: 1000)
92
+ cwd?: string // Working directory for file operations
91
93
  requestParams?: {
92
94
  temperature?: number // Model temperature
93
95
  maxTokens?: number // Max output tokens
@@ -96,6 +98,33 @@ interface CreateSessionOptions {
96
98
  }
97
99
  ```
98
100
 
101
+ ### Working Directory (CWD) Configuration
102
+
103
+ You can set a working directory for the session, which will be automatically applied to all file operation tools (Read, Write, Edit, Glob, Grep, Bash, AstGrepSearch, AstGrepReplace):
104
+
105
+ ```typescript
106
+ // Set CWD when creating a session
107
+ const session = await agent.createSession({
108
+ cwd: '/path/to/project',
109
+ })
110
+
111
+ // Get the current working directory
112
+ const cwd = session.getCwd()
113
+ console.log('Current directory:', cwd)
114
+
115
+ // Change the working directory at runtime
116
+ session.setCwd('/path/to/another/project')
117
+
118
+ // All file operations now use the new directory
119
+ session.send('Read the README.md file')
120
+ ```
121
+
122
+ **Benefits:**
123
+ - Automatically sets the working directory for all tools that support it
124
+ - Persisted across session saves and restores
125
+ - Can be changed at runtime with `session.setCwd()`
126
+ - Simplifies file path management in multi-project environments
127
+
99
128
  ### Sending Messages
100
129
 
101
130
  ```typescript
@@ -108,6 +137,40 @@ session.send('First question')
108
137
  session.send('Follow-up question')
109
138
  ```
110
139
 
140
+ #### Send Options
141
+
142
+ You can pass options to `send()` to control tool execution, approval, and more:
143
+
144
+ ```typescript
145
+ // Auto-approve all tools for this request
146
+ session.send('Create files and search the web', {
147
+ toolContext: {
148
+ approval: {
149
+ autoApprove: true, // Skip approval for all tools
150
+ },
151
+ },
152
+ })
153
+
154
+ // Require approval only for high-risk tools
155
+ session.send('Analyze the codebase', {
156
+ toolContext: {
157
+ approval: {
158
+ strategy: 'high_risk', // Only prompt for high/critical risk tools
159
+ },
160
+ },
161
+ })
162
+
163
+ // Combine with session-level CWD
164
+ session.setCwd('/path/to/project')
165
+ session.send('Read and analyze all TypeScript files', {
166
+ toolContext: {
167
+ approval: { autoApprove: true },
168
+ },
169
+ })
170
+ // Tools will use /path/to/project as working directory
171
+ // and execute without requiring approval
172
+ ```
173
+
111
174
  ### Receiving Events
112
175
 
113
176
  The `receive()` method returns an async generator that streams events:
@@ -187,7 +250,7 @@ console.log(session.updatedAt) // Last update timestamp
187
250
 
188
251
  ### Session Persistence
189
252
 
190
- Sessions can be saved and restored:
253
+ Sessions can be saved and restored. All session state including message history, configuration, and working directory (cwd) are preserved:
191
254
 
192
255
  ```typescript
193
256
  // Save session to snapshot
@@ -200,6 +263,12 @@ session.restoreFromSnapshot(snapshot)
200
263
  // Or create a new session from snapshot
201
264
  const restored = await agent.createSession()
202
265
  restored.restoreFromSnapshot(snapshot)
266
+
267
+ // The restored session maintains all state including:
268
+ // - Message history
269
+ // - Configuration overrides
270
+ // - Working directory (cwd)
271
+ // - Usage statistics
203
272
  ```
204
273
 
205
274
  ### Multi-turn Conversations
@@ -248,7 +317,7 @@ const agent = new Agent({
248
317
  })
249
318
 
250
319
  // Start session (automatically checkpointed)
251
- const session = await agent.createSession({ id: 'session-123' })
320
+ const session = await agent.createSession({ sessionId: 'session-123' })
252
321
  session.send('Start a long task')
253
322
  for await (const event of session.receive()) {
254
323
  // Process events...
@@ -376,6 +445,36 @@ const agent = new Agent({
376
445
  })
377
446
  ```
378
447
 
448
+ ### MCP Servers (HTTP + stdio)
449
+
450
+ GoatChain can connect MCP servers and register their remote tools automatically:
451
+
452
+ ```typescript
453
+ const agent = new Agent({
454
+ name: 'MCP Assistant',
455
+ systemPrompt: 'You are helpful.',
456
+ model,
457
+ mcpServers: [
458
+ {
459
+ id: 'weather',
460
+ name: 'Weather API',
461
+ transport: 'http',
462
+ url: 'https://example.com/mcp',
463
+ auth: { type: 'bearer', token: process.env.WEATHER_API_KEY! },
464
+ },
465
+ {
466
+ id: 'local-tools',
467
+ name: 'Local Tools',
468
+ transport: 'stdio',
469
+ command: 'node',
470
+ args: ['./mcp-servers/tools.js'],
471
+ },
472
+ ],
473
+ })
474
+ ```
475
+
476
+ See `docs/mcp.md` for details.
477
+
379
478
  ### Configuring File Tool Working Directory
380
479
 
381
480
  File-related tools (`ReadTool`, `WriteTool`, `EditTool`, `GlobTool`, `GrepTool`, `BashTool`) support configuring the working directory:
@@ -397,24 +496,29 @@ tools.register(new BashTool({ cwd: OUTPUT_DIR }))
397
496
  // Option 2: Restrict to specific directory (security sandbox)
398
497
  // This prevents access to files outside the allowed directory
399
498
  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
- }))
499
+ tools.register(
500
+ new ReadTool({
501
+ cwd: OUTPUT_DIR,
502
+ allowedDirectory: OUTPUT_DIR, // Only allow reads within OUTPUT_DIR
503
+ }),
504
+ )
505
+ tools.register(
506
+ new WriteTool({
507
+ cwd: OUTPUT_DIR,
508
+ allowedDirectory: OUTPUT_DIR, // Only allow writes within OUTPUT_DIR
509
+ }),
510
+ )
408
511
  ```
409
512
 
410
513
  **Directory Configuration Options:**
411
514
 
412
- | Option | Description | Example |
413
- |--------|-------------|---------|
414
- | `cwd` | Working directory for resolving relative paths | `{ cwd: '/app/output' }` |
515
+ | Option | Description | Example |
516
+ | ------------------ | ------------------------------------------------------------------- | ------------------------------------- |
517
+ | `cwd` | Working directory for resolving relative paths | `{ cwd: '/app/output' }` |
415
518
  | `allowedDirectory` | Restrict file access to this directory only (blocks path traversal) | `{ allowedDirectory: '/app/output' }` |
416
519
 
417
520
  **When to use `allowedDirectory`:**
521
+
418
522
  - When you want to sandbox the agent to a specific directory
419
523
  - To prevent accidental access to sensitive files
420
524
  - For production environments with security requirements
@@ -480,6 +584,324 @@ const allTools = registry.list()
480
584
  const openaiTools = registry.toOpenAIFormat()
481
585
  ```
482
586
 
587
+ ## 🎣 Tool Approval & Hooks
588
+
589
+ Sessions support lifecycle hooks that let you intercept tool calls for approval, logging, or custom logic.
590
+
591
+ ### Key Concepts
592
+
593
+ GoatChain has two separate mechanisms for controlling tool execution:
594
+
595
+ 1. **preToolUse Hook** - For programmatic auto-approval/blocking
596
+ - `allow: true` → Tool executes immediately, **skips approval flow**
597
+ - `allow: false` → Tool is blocked
598
+ - Use this for automated scenarios where you want to programmatically approve/deny tools
599
+
600
+ 2. **Approval System** (via `toolContext.approval`) - For interactive user approval
601
+ - Pauses execution on high-risk tools
602
+ - Shows `requires_action` event
603
+ - Resumes with user's approval decisions
604
+ - Use this for interactive UIs where users manually approve tools
605
+
606
+ **These are independent**: If you use `preToolUse` with `allow: true`, the approval system is bypassed entirely.
607
+
608
+ ### Hook Types
609
+
610
+ ```typescript
611
+ interface ToolHooks {
612
+ // Called before tool execution
613
+ // - If allow: true, tool executes immediately and skips approval flow
614
+ // - If allow: false, tool is blocked
615
+ // - Can modify tool call with modifiedToolCall
616
+ preToolUse?: (ctx: HookContext) => Promise<PreToolUseResult>
617
+
618
+ // Called after successful tool execution
619
+ postToolUse?: (ctx: HookContext, result: unknown) => Promise<void>
620
+
621
+ // Called after tool execution failure
622
+ postToolUseFailure?: (ctx: HookContext, error: Error) => Promise<void>
623
+ }
624
+
625
+ interface HookContext {
626
+ sessionId: string
627
+ toolCall: {
628
+ id: string
629
+ type: 'function'
630
+ function: {
631
+ name: string
632
+ arguments: string
633
+ }
634
+ }
635
+ toolContext: ToolExecutionContext
636
+ }
637
+
638
+ interface PreToolUseResult {
639
+ // If true, allows tool to execute and skips approval flow
640
+ // If false, blocks tool execution immediately
641
+ allow: boolean
642
+ // Optional: Modify the tool call before execution
643
+ modifiedToolCall?: ToolCall
644
+ }
645
+ ```
646
+
647
+ ### Basic Hook Usage
648
+
649
+ ```typescript
650
+ import { Agent, ToolRegistry, ReadTool, WriteTool } from 'goatchain'
651
+
652
+ const agent = new Agent({
653
+ name: 'MyAgent',
654
+ systemPrompt: 'You are helpful.',
655
+ model,
656
+ tools: new ToolRegistry()
657
+ .register(new ReadTool())
658
+ .register(new WriteTool()),
659
+ })
660
+
661
+ // Create session with hooks
662
+ const session = await agent.createSession({
663
+ hooks: {
664
+ preToolUse: async (ctx) => {
665
+ const toolName = ctx.toolCall.function.name
666
+ console.log(`Tool requested: ${toolName}`)
667
+
668
+ // Returning { allow: true } skips approval flow and executes tool immediately
669
+ // Returning { allow: false } blocks tool execution
670
+ return { allow: true }
671
+ },
672
+
673
+ postToolUse: async (ctx, result) => {
674
+ console.log(`Tool ${ctx.toolCall.function.name} completed successfully`)
675
+ },
676
+
677
+ postToolUseFailure: async (ctx, error) => {
678
+ console.error(`Tool ${ctx.toolCall.function.name} failed:`, error)
679
+ },
680
+ },
681
+ })
682
+ ```
683
+
684
+ ### Auto-Approval with preToolUse Hook
685
+
686
+ The `preToolUse` hook is powerful because `allow: true` **bypasses the approval flow entirely**, even for high-risk tools. This is useful for automated scenarios:
687
+
688
+ ```typescript
689
+ import type { RiskLevel } from 'goatchain'
690
+
691
+ // Define auto-approval policy
692
+ function shouldAutoApprove(toolName: string, riskLevel: RiskLevel): boolean {
693
+ // Auto-approve safe and low risk tools
694
+ if (riskLevel === 'safe' || riskLevel === 'low') {
695
+ return true
696
+ }
697
+
698
+ // Block critical tools
699
+ if (riskLevel === 'critical') {
700
+ return false
701
+ }
702
+
703
+ // For medium/high risk, you can implement custom logic
704
+ // e.g., check environment, user permissions, etc.
705
+ return process.env.AUTO_APPROVE_ALL === 'true'
706
+ }
707
+
708
+ const session = await agent.createSession({
709
+ hooks: {
710
+ preToolUse: async (ctx) => {
711
+ const tool = agent.tools.get(ctx.toolCall.function.name)
712
+ const riskLevel = tool?.riskLevel ?? 'safe'
713
+ const allow = shouldAutoApprove(ctx.toolCall.function.name, riskLevel)
714
+
715
+ if (allow) {
716
+ console.log(`✓ Auto-approved: ${ctx.toolCall.function.name}`)
717
+ } else {
718
+ console.log(`✗ Blocked: ${ctx.toolCall.function.name}`)
719
+ }
720
+
721
+ return { allow }
722
+ },
723
+ },
724
+ })
725
+ ```
726
+
727
+ ### Auto-Approve All Tools with toolContext
728
+
729
+ The simplest way to bypass approval for a specific request is using `toolContext.approval.autoApprove`:
730
+
731
+ ```typescript
732
+ // Auto-approve all tools for this specific send() call
733
+ session.send('Create a file and search the web', {
734
+ toolContext: {
735
+ approval: {
736
+ autoApprove: true, // Bypasses approval for ALL tools in this request
737
+ },
738
+ },
739
+ })
740
+
741
+ for await (const event of session.receive()) {
742
+ // All tools execute without requiring approval
743
+ if (event.type === 'text_delta') {
744
+ process.stdout.write(event.delta)
745
+ }
746
+ }
747
+ ```
748
+
749
+ **Use cases:**
750
+ - **Automated workflows**: Scripts that run without user interaction
751
+ - **Testing**: E2E tests that need tools to execute automatically
752
+ - **Trusted environments**: When you trust the agent's tool usage completely
753
+
754
+ **Approval strategies:**
755
+
756
+ ```typescript
757
+ session.send('Your task', {
758
+ toolContext: {
759
+ approval: {
760
+ autoApprove: true, // Approve all tools automatically
761
+ // OR
762
+ strategy: 'high_risk', // Only require approval for high/critical risk tools
763
+ // OR
764
+ strategy: 'all', // Require approval for every tool call
765
+ },
766
+ },
767
+ })
768
+ ```
769
+
770
+ ### Interactive Approval with Pause/Resume
771
+
772
+ **Important**: The `preToolUse` hook with `allow: true` **skips approval**. For interactive approval flows where you want to pause and ask the user, use `toolContext.approval` instead:
773
+
774
+ ```typescript
775
+ import type { AgentLoopCheckpoint } from 'goatchain'
776
+
777
+ // Step 1: Start session WITHOUT preToolUse hook (to use approval system)
778
+ const session = await agent.createSession()
779
+
780
+ let checkpoint: AgentLoopCheckpoint | undefined
781
+
782
+ session.send('Create a file and delete it', {
783
+ toolContext: {
784
+ approval: { strategy: 'high_risk' }, // Pause on high-risk tools for user approval
785
+ },
786
+ })
787
+
788
+ // Collect checkpoint when requires_action event is emitted
789
+ for await (const event of session.receive()) {
790
+ if (event.type === 'requires_action') {
791
+ // Save checkpoint
792
+ checkpoint = event.checkpoint ||
793
+ await agent.stateStore?.loadCheckpoint(event.checkpointRef?.sessionId)
794
+ break // Pause here
795
+ }
796
+ }
797
+
798
+ // Step 2: Resume with approval decisions
799
+ if (checkpoint) {
800
+ // Build approval decisions for pending tools
801
+ const decisions = Object.fromEntries(
802
+ checkpoint.pendingToolCalls.map((pending) => {
803
+ const toolName = pending.toolCall.function.name
804
+ const approved = confirm(`Approve ${toolName}?`)
805
+
806
+ return [
807
+ pending.toolCall.id,
808
+ { approved, reason: approved ? undefined : 'User denied' },
809
+ ]
810
+ })
811
+ )
812
+
813
+ // Resume session with decisions
814
+ for await (const event of session.receive({
815
+ toolContext: {
816
+ approval: { decisions },
817
+ },
818
+ })) {
819
+ // Process events...
820
+ }
821
+ }
822
+ ```
823
+
824
+ ### Complete Example: Interactive Approval System
825
+
826
+ See `examples/tool-approval-session.ts` for a full example demonstrating:
827
+
828
+ - **Sync approval** - Real-time approval during tool execution
829
+ - **Async approval** - Pause/resume pattern for user interaction
830
+ - **Blocked tools** - Denying high-risk tools automatically
831
+ - **Risk-based policies** - Different approval rules per risk level
832
+
833
+ ```bash
834
+ # Run the example
835
+ bun run examples/tool-approval-session.ts
836
+ ```
837
+
838
+ **Key features shown:**
839
+ - Creating custom tools with risk levels
840
+ - Implementing approval hooks with async delays
841
+ - Pausing execution on `requires_action` events
842
+ - Resuming sessions with approval decisions
843
+ - Pretty-printed logging with colors and symbols
844
+
845
+ ### Modifying Tool Calls with preToolUse
846
+
847
+ The `preToolUse` hook can also modify tool calls before execution:
848
+
849
+ ```typescript
850
+ const session = await agent.createSession({
851
+ hooks: {
852
+ preToolUse: async (ctx) => {
853
+ const toolName = ctx.toolCall.function.name
854
+
855
+ // Example: Add safety constraints to file writes
856
+ if (toolName === 'Write') {
857
+ const args = JSON.parse(ctx.toolCall.function.arguments)
858
+
859
+ // Modify the tool call to add restrictions
860
+ const modifiedToolCall = {
861
+ ...ctx.toolCall,
862
+ function: {
863
+ ...ctx.toolCall.function,
864
+ arguments: JSON.stringify({
865
+ ...args,
866
+ // Force files to be written in a safe directory
867
+ file_path: `/safe-dir/${args.file_path}`,
868
+ }),
869
+ },
870
+ }
871
+
872
+ return {
873
+ allow: true,
874
+ modifiedToolCall,
875
+ }
876
+ }
877
+
878
+ return { allow: true }
879
+ },
880
+ },
881
+ })
882
+ ```
883
+
884
+ ### Tool Context
885
+
886
+ The `toolContext` parameter in `send()` and `receive()` allows passing additional context:
887
+
888
+ ```typescript
889
+ session.send('Do something risky', {
890
+ toolContext: {
891
+ approval: {
892
+ strategy: 'high_risk', // Pause on high-risk tools
893
+ // or
894
+ decisions: {
895
+ 'tool_call_id_123': { approved: true },
896
+ 'tool_call_id_456': { approved: false, reason: 'Too dangerous' },
897
+ },
898
+ },
899
+ // Your custom context
900
+ custom: { userId: '123', environment: 'production' },
901
+ },
902
+ })
903
+ ```
904
+
483
905
  ## 🧅 Middleware System
484
906
 
485
907
  GoatChain uses a Koa-style onion model for middleware. Each middleware wraps around the core execution:
@@ -922,7 +1344,7 @@ try {
922
1344
  session = await agent.resumeSession(sessionId)
923
1345
  console.log('Resumed existing session')
924
1346
  } catch {
925
- session = await agent.createSession({ id: sessionId })
1347
+ session = await agent.createSession({ sessionId })
926
1348
  console.log('Created new session')
927
1349
  }
928
1350
 
@@ -1024,7 +1446,74 @@ console.log(`Total messages: ${session.messages.length}`)
1024
1446
  console.log(`Total tokens: ${session.usage.totalTokens}`)
1025
1447
  ```
1026
1448
 
1027
- ### Example 6: File Operations with Directory Configuration
1449
+ ### Example 6: Working Directory with Auto-Approval
1450
+
1451
+ Combine session-level working directory with auto-approval for automated file operations:
1452
+
1453
+ ```typescript
1454
+ import { Agent, createModel, createOpenAIAdapter, createBuiltinTools } from 'goatchain'
1455
+
1456
+ const model = createModel({
1457
+ adapter: createOpenAIAdapter({
1458
+ defaultModelId: 'gpt-4o',
1459
+ apiKey: process.env.OPENAI_API_KEY!,
1460
+ }),
1461
+ })
1462
+
1463
+ const agent = new Agent({
1464
+ name: 'File Agent',
1465
+ systemPrompt: 'You are a file management assistant.',
1466
+ model,
1467
+ tools: createBuiltinTools(), // All file tools included
1468
+ })
1469
+
1470
+ // Set working directory at session creation
1471
+ const session = await agent.createSession({
1472
+ cwd: '/path/to/project',
1473
+ })
1474
+
1475
+ // Auto-approve all file operations for automated workflow
1476
+ session.send('List all TypeScript files, then create a summary.md file', {
1477
+ toolContext: {
1478
+ approval: {
1479
+ autoApprove: true, // No approval prompts - fully automated
1480
+ },
1481
+ },
1482
+ })
1483
+
1484
+ for await (const event of session.receive()) {
1485
+ if (event.type === 'text_delta') {
1486
+ process.stdout.write(event.delta)
1487
+ }
1488
+ else if (event.type === 'tool_call_start') {
1489
+ console.log(`\nExecuting: ${event.toolName}`)
1490
+ }
1491
+ }
1492
+
1493
+ // Change directory and continue with auto-approval
1494
+ session.setCwd('/path/to/another/project')
1495
+ session.send('Analyze the project structure and create a report', {
1496
+ toolContext: {
1497
+ approval: { autoApprove: true },
1498
+ },
1499
+ })
1500
+
1501
+ for await (const event of session.receive()) {
1502
+ if (event.type === 'text_delta') {
1503
+ process.stdout.write(event.delta)
1504
+ }
1505
+ }
1506
+ ```
1507
+
1508
+ **Perfect for:**
1509
+ - CI/CD pipelines that need file analysis
1510
+ - Automated code review bots
1511
+ - Project documentation generators
1512
+ - Bulk file operations without manual intervention
1513
+
1514
+ ### Example 7: Tool-level Working Directory (Advanced)
1515
+
1516
+ For more control, you can configure individual tools with specific directories and restrictions:
1028
1517
 
1029
1518
  ```typescript
1030
1519
  import path from 'node:path'
@@ -1051,14 +1540,18 @@ const OUTPUT_DIR = path.resolve(process.cwd(), 'output')
1051
1540
 
1052
1541
  // Configure tools with working directory and restrictions
1053
1542
  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
- }))
1543
+ tools.register(
1544
+ new ReadTool({
1545
+ cwd: OUTPUT_DIR,
1546
+ allowedDirectory: OUTPUT_DIR, // Sandbox: only allow reads in OUTPUT_DIR
1547
+ }),
1548
+ )
1549
+ tools.register(
1550
+ new WriteTool({
1551
+ cwd: OUTPUT_DIR,
1552
+ allowedDirectory: OUTPUT_DIR, // Sandbox: only allow writes in OUTPUT_DIR
1553
+ }),
1554
+ )
1062
1555
  tools.register(new GlobTool({ cwd: OUTPUT_DIR }))
1063
1556
  tools.register(new GrepTool({ cwd: OUTPUT_DIR }))
1064
1557
 
@@ -1072,7 +1565,7 @@ You can create, read, and modify files within this sandbox.`,
1072
1565
  })
1073
1566
 
1074
1567
  const session = await agent.createSession()
1075
- session.send('Create a report.md file with a summary of today\'s tasks')
1568
+ session.send("Create a report.md file with a summary of today's tasks")
1076
1569
 
1077
1570
  for await (const event of session.receive()) {
1078
1571
  if (event.type === 'text_delta') {
@@ -1224,8 +1717,22 @@ const snapshot = session.toSnapshot()
1224
1717
 
1225
1718
  Restore session from snapshot.
1226
1719
 
1720
+ **`getCwd(): string | undefined`**
1721
+
1722
+ Get the current working directory for this session.
1723
+
1227
1724
  ```typescript
1228
- session.restoreFromSnapshot(snapshot)
1725
+ const cwd = session.getCwd()
1726
+ console.log('Working directory:', cwd)
1727
+ ```
1728
+
1729
+ **`setCwd(cwd: string): void`**
1730
+
1731
+ Set the current working directory for this session. This automatically syncs the new directory to all tools that support it.
1732
+
1733
+ ```typescript
1734
+ session.setCwd('/path/to/project')
1735
+ // All file operation tools now use this directory
1229
1736
  ```
1230
1737
 
1231
1738
  #### Properties
@@ -1,10 +1,11 @@
1
1
  import type { ModelClient, ModelRef } from '../model';
2
2
  import type { BaseSessionManager } from '../session';
3
3
  import type { StateStore } from '../state';
4
- import type { ToolRegistry } from '../tool';
5
4
  import type { Middleware, NamedMiddleware } from './middleware';
6
5
  import type { AgentLoopState, AgentOptions, CreateSessionOptions, SessionHandleOptions } from './types';
6
+ import { McpServerManager } from '../mcp-client';
7
7
  import { Session } from '../session';
8
+ import { ToolRegistry } from '../tool';
8
9
  /**
9
10
  * Agent class - the main orchestrator.
10
11
  *
@@ -29,12 +30,15 @@ export declare class Agent {
29
30
  private _enableLogging;
30
31
  private _initializationPromise;
31
32
  private _initialized;
33
+ private _mcpManager?;
32
34
  constructor(options: AgentOptions);
33
35
  /**
34
36
  * Initialize middleware asynchronously (internal helper for constructor)
35
37
  * @private
36
38
  */
37
39
  private _initializeMiddleware;
40
+ private _initializeMcpServers;
41
+ private _initializeAll;
38
42
  /**
39
43
  * Ensure agent is initialized (all middleware registered)
40
44
  * @private
@@ -64,6 +68,10 @@ export declare class Agent {
64
68
  * Get the tool registry
65
69
  */
66
70
  get tools(): ToolRegistry | undefined;
71
+ /**
72
+ * Get MCP server manager, if configured.
73
+ */
74
+ get mcpManager(): McpServerManager | undefined;
67
75
  /**
68
76
  * Get the state store
69
77
  */