goatchain 0.0.24 → 0.0.26
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 +247 -72
- package/dist/agent/agent.d.ts +4 -4
- package/dist/agent/hooks/index.d.ts +1 -1
- package/dist/agent/hooks/manager.d.ts +10 -3
- package/dist/agent/hooks/types.d.ts +95 -8
- package/dist/agent/index.d.ts +3 -2
- package/dist/agent/middleware.d.ts +31 -2
- package/dist/agent/tokenCounter.d.ts +48 -2
- package/dist/agent/types.d.ts +15 -1
- package/dist/index.d.ts +12 -4
- package/dist/index.js +618 -467
- package/dist/lib/access-control/index.d.ts +1 -1
- package/dist/lib/access-control/policies.d.ts +10 -0
- package/dist/lib/session-blob.d.ts +50 -0
- package/dist/mcp-client/manager.d.ts +2 -0
- package/dist/middleware/attachmentMiddleware.d.ts +34 -0
- package/dist/middleware/commitModeMiddleware.d.ts +1 -1
- package/dist/middleware/contextCompressionMiddleware.d.ts +28 -2
- package/dist/middleware/envInfoMiddleware.d.ts +6 -0
- package/dist/middleware/gitUtils.d.ts +4 -0
- package/dist/middleware/longRunningMiddleware.d.ts +100 -0
- package/dist/middleware/parallelSubagentMiddleware.d.ts +2 -2
- package/dist/middleware/planModeMiddleware.d.ts +3 -3
- package/dist/middleware/reviewMiddleware.d.ts +1 -1
- package/dist/middleware/skillsMiddleware.d.ts +8 -0
- package/dist/model/anthropic/createAnthropicAdapter.d.ts +1 -1
- package/dist/model/codex/createCodexAdapter.d.ts +1 -1
- package/dist/model/index.d.ts +2 -0
- package/dist/model/openai/createOpenAIResponsesAdapter.d.ts +28 -0
- package/dist/session/completion/composite.d.ts +25 -0
- package/dist/session/completion/index.d.ts +8 -0
- package/dist/session/completion/strategies/reflection-decision-tool.d.ts +51 -0
- package/dist/session/completion/strategies/rule-based.d.ts +16 -0
- package/dist/session/completion/strategies/self-reflection.d.ts +54 -0
- package/dist/session/completion/strategies/todo-based.d.ts +17 -0
- package/dist/session/completion/types.d.ts +53 -0
- package/dist/session/executors/ToolExecutor.d.ts +4 -4
- package/dist/session/session.d.ts +9 -0
- package/dist/state/types.d.ts +3 -2
- package/dist/subagent/index.d.ts +1 -0
- package/dist/subagent/self-reflection-critic.d.ts +35 -0
- package/dist/tool/builtin/bash.d.ts +24 -0
- package/dist/tool/builtin/edit.d.ts +12 -0
- package/dist/tool/builtin/index.d.ts +2 -2
- package/dist/tool/builtin/pathProtection.d.ts +25 -0
- package/dist/tool/builtin/read.d.ts +69 -112
- package/dist/tool/builtin/task.d.ts +8 -0
- package/dist/tool/builtin/webFetch.d.ts +27 -4
- package/dist/tool/builtin/write.d.ts +15 -0
- package/dist/tool/index.d.ts +2 -2
- package/dist/types/common.d.ts +35 -0
- package/dist/types/event.d.ts +55 -3
- package/dist/types/snapshot.d.ts +1 -1
- package/package.json +4 -2
package/README.md
CHANGED
|
@@ -4,6 +4,33 @@
|
|
|
4
4
|
|
|
5
5
|
[](https://badge.fury.io/js/goatchain)
|
|
6
6
|
|
|
7
|
+
## ⚠️ Breaking Change: `preToolUse` vs `permissionRequest`
|
|
8
|
+
|
|
9
|
+
`preToolUse` is now only for mutating tool calls (`modifiedToolCall`).
|
|
10
|
+
Permission decisions (`allow` / `deny`) must be handled in `permissionRequest`.
|
|
11
|
+
|
|
12
|
+
### Migration
|
|
13
|
+
|
|
14
|
+
Before (old pattern):
|
|
15
|
+
|
|
16
|
+
```typescript
|
|
17
|
+
hooks: {
|
|
18
|
+
preToolUse: async () => ({ allow: true }),
|
|
19
|
+
}
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
After (current pattern):
|
|
23
|
+
|
|
24
|
+
```typescript
|
|
25
|
+
hooks: {
|
|
26
|
+
permissionRequest: async () => ({ allow: true }),
|
|
27
|
+
}
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
If you need both, use:
|
|
31
|
+
- `preToolUse` to rewrite tool arguments/tool call
|
|
32
|
+
- `permissionRequest` to allow or block execution
|
|
33
|
+
|
|
7
34
|
## 📦 Installation
|
|
8
35
|
|
|
9
36
|
```bash
|
|
@@ -360,8 +387,9 @@ const agent = new Agent({
|
|
|
360
387
|
model,
|
|
361
388
|
tools, // Optional: ToolRegistry instance
|
|
362
389
|
stateStore, // Optional: for persistence
|
|
363
|
-
|
|
364
|
-
|
|
390
|
+
middleware: [], // Optional: middlewares to register on startup
|
|
391
|
+
mcpServers: [], // Optional: MCP server configs
|
|
392
|
+
enableLogging: false, // Optional: internal logs
|
|
365
393
|
})
|
|
366
394
|
```
|
|
367
395
|
|
|
@@ -369,14 +397,15 @@ const agent = new Agent({
|
|
|
369
397
|
|
|
370
398
|
```typescript
|
|
371
399
|
interface AgentOptions {
|
|
400
|
+
id?: string // Optional custom agent ID
|
|
372
401
|
name: string // Agent name
|
|
373
402
|
systemPrompt: string // System instructions
|
|
374
|
-
model: ModelClient
|
|
403
|
+
model: ModelClient // LLM client
|
|
375
404
|
tools?: ToolRegistry // Tool registry (not an array)
|
|
376
405
|
stateStore?: StateStore // Persistence layer
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
406
|
+
middleware?: Middleware[] // Optional middleware list
|
|
407
|
+
mcpServers?: MCPServerConfig[] // Optional MCP server configs
|
|
408
|
+
enableLogging?: boolean // Internal debug logs
|
|
380
409
|
}
|
|
381
410
|
```
|
|
382
411
|
|
|
@@ -384,10 +413,11 @@ interface AgentOptions {
|
|
|
384
413
|
|
|
385
414
|
```typescript
|
|
386
415
|
// Pin to specific model
|
|
387
|
-
agent.setModel('gpt-4o-mini')
|
|
416
|
+
agent.setModel({ provider: 'openai', modelId: 'gpt-4o-mini' })
|
|
388
417
|
|
|
389
|
-
//
|
|
390
|
-
|
|
418
|
+
// Switch to another concrete model client instance
|
|
419
|
+
const otherModelClient = createModel({ adapter: createOpenAIAdapter({ defaultModelId: 'gpt-4o' }) })
|
|
420
|
+
agent.setModel(otherModelClient)
|
|
391
421
|
```
|
|
392
422
|
|
|
393
423
|
### Session Manager
|
|
@@ -411,7 +441,23 @@ await sessionManager.destroy('session-id')
|
|
|
411
441
|
|
|
412
442
|
### Using Built-in Tools
|
|
413
443
|
|
|
414
|
-
GoatChain
|
|
444
|
+
GoatChain SDK exports the following built-in tools:
|
|
445
|
+
|
|
446
|
+
| Tool Class | Runtime Name | Category | Purpose |
|
|
447
|
+
| --- | --- | --- | --- |
|
|
448
|
+
| `ReadTool` | `Read` | File | Read file content (text, binary metadata, and selected converted formats) |
|
|
449
|
+
| `WriteTool` | `Write` | File | Create or overwrite files |
|
|
450
|
+
| `EditTool` | `Edit` | File | In-place text replacement edits |
|
|
451
|
+
| `GlobTool` | `Glob` | File/Search | Find files by glob pattern |
|
|
452
|
+
| `GrepTool` | `Grep` | File/Search | Search file contents by pattern |
|
|
453
|
+
| `BashTool` | `Bash` | Command | Execute shell commands |
|
|
454
|
+
| `WebSearchTool` | `WebSearch` | Web | Search the web (e.g. via Serper API) |
|
|
455
|
+
| `WebFetchTool` | `WebFetch` | Web | Fetch and extract content from a specific URL |
|
|
456
|
+
| `TodoWriteTool` | `TodoWrite` | Planning | Manage structured todo lists |
|
|
457
|
+
| `TodoPlanTool` | `TodoPlan` | Planning | Create/update planning todos for plan flows |
|
|
458
|
+
| `AskUserTool` | `AskUserQuestion` | Interaction | Ask the user structured follow-up questions |
|
|
459
|
+
| `EnterPlanModeTool` | `EnterPlanMode` | Mode | Enter plan mode |
|
|
460
|
+
| `ExitPlanModeTool` | `ExitPlanMode` | Mode | Exit plan mode |
|
|
415
461
|
|
|
416
462
|
```typescript
|
|
417
463
|
import {
|
|
@@ -490,6 +536,7 @@ const OUTPUT_DIR = path.resolve(import.meta.dirname, 'output')
|
|
|
490
536
|
const tools = new ToolRegistry()
|
|
491
537
|
tools.register(new ReadTool({ cwd: OUTPUT_DIR }))
|
|
492
538
|
tools.register(new WriteTool({ cwd: OUTPUT_DIR }))
|
|
539
|
+
tools.register(new EditTool({ cwd: OUTPUT_DIR }))
|
|
493
540
|
tools.register(new GlobTool({ cwd: OUTPUT_DIR }))
|
|
494
541
|
tools.register(new GrepTool({ cwd: OUTPUT_DIR }))
|
|
495
542
|
tools.register(new BashTool({ cwd: OUTPUT_DIR }))
|
|
@@ -511,12 +558,41 @@ tools.register(
|
|
|
511
558
|
)
|
|
512
559
|
```
|
|
513
560
|
|
|
514
|
-
**
|
|
561
|
+
**How each file tool uses `cwd`:**
|
|
562
|
+
|
|
563
|
+
| Tool | What it does | How `cwd` is applied | Per-call override | Extra sandbox options |
|
|
564
|
+
| --- | --- | --- | --- | --- |
|
|
565
|
+
| `ReadTool` | Reads files (and some converted formats) | Relative `file_path` resolves from `cwd` | `file_path` can be absolute | `allowedDirectory`, `fileBlacklist`, `disableBlacklist` |
|
|
566
|
+
| `WriteTool` | Writes/overwrites files | Relative `file_path` resolves from `cwd` | `file_path` can be absolute | `allowedDirectory`, `readOnlyPaths`, `fileBlacklist`, `disableBlacklist` |
|
|
567
|
+
| `EditTool` | Replaces `old_string` with `new_string` in a file | Relative `file_path` resolves from `cwd` | `file_path` can be absolute | `readOnlyPaths`, `fileBlacklist`, `disableBlacklist` |
|
|
568
|
+
| `GlobTool` | Finds files by pattern | Search root defaults to `cwd` | `path` argument can change search root | `fileBlacklist`, `disableBlacklist` |
|
|
569
|
+
| `GrepTool` | Searches text content in files | Search runs under `cwd` | `path` argument narrows search scope | `fileBlacklist`, `disableBlacklist` |
|
|
570
|
+
| `BashTool` | Runs shell commands | Commands execute in `cwd` | `workdir` argument overrides per call | `readOnlyPaths` |
|
|
571
|
+
|
|
572
|
+
**Directory & Protection Options:**
|
|
515
573
|
|
|
516
574
|
| Option | Description | Example |
|
|
517
575
|
| ------------------ | ------------------------------------------------------------------- | ------------------------------------- |
|
|
518
576
|
| `cwd` | Working directory for resolving relative paths | `{ cwd: '/app/output' }` |
|
|
519
577
|
| `allowedDirectory` | Restrict file access to this directory only (blocks path traversal) | `{ allowedDirectory: '/app/output' }` |
|
|
578
|
+
| `readOnlyPaths` | Mark paths/directories as read-only for write-like operations | `{ readOnlyPaths: ['docs', { path: '.env', reason: 'secrets' }] }` |
|
|
579
|
+
|
|
580
|
+
`readOnlyPaths` is supported by `WriteTool`, `EditTool`, and `BashTool`.
|
|
581
|
+
Use it to protect specific directories/files from modifications while still allowing reads/searches.
|
|
582
|
+
|
|
583
|
+
```typescript
|
|
584
|
+
const tools = new ToolRegistry()
|
|
585
|
+
|
|
586
|
+
const readOnlyPaths = [
|
|
587
|
+
'docs', // relative to cwd
|
|
588
|
+
{ path: '.env', reason: 'Secrets file must not be modified' },
|
|
589
|
+
{ path: '/absolute/path/to/protected-dir', reason: 'Managed by another system' },
|
|
590
|
+
]
|
|
591
|
+
|
|
592
|
+
tools.register(new WriteTool({ cwd: OUTPUT_DIR, readOnlyPaths }))
|
|
593
|
+
tools.register(new EditTool({ cwd: OUTPUT_DIR, readOnlyPaths }))
|
|
594
|
+
tools.register(new BashTool({ cwd: OUTPUT_DIR, readOnlyPaths }))
|
|
595
|
+
```
|
|
520
596
|
|
|
521
597
|
**When to use `allowedDirectory`:**
|
|
522
598
|
|
|
@@ -587,44 +663,60 @@ const openaiTools = registry.toOpenAIFormat()
|
|
|
587
663
|
|
|
588
664
|
## 🎣 Tool Approval & Hooks
|
|
589
665
|
|
|
590
|
-
Sessions support lifecycle hooks that let you intercept tool calls
|
|
666
|
+
Sessions support lifecycle hooks that let you intercept user input, tool calls, and session/subagent lifecycle events.
|
|
591
667
|
|
|
592
668
|
### Key Concepts
|
|
593
669
|
|
|
594
|
-
GoatChain has
|
|
670
|
+
GoatChain has three relevant mechanisms for tool execution control:
|
|
595
671
|
|
|
596
|
-
1. **preToolUse Hook** - For
|
|
597
|
-
-
|
|
598
|
-
-
|
|
672
|
+
1. **preToolUse Hook** - For tool-call mutation before permission/approval
|
|
673
|
+
- Can modify tool name/arguments with `modifiedToolCall`
|
|
674
|
+
- Runs before `permissionRequest`
|
|
675
|
+
|
|
676
|
+
2. **permissionRequest Hook** - For programmatic auto-approval/blocking
|
|
677
|
+
- Runs after `preToolUse`, so it sees the modified tool call
|
|
678
|
+
- `allow: true` → skips approval flow (execution still goes through normal middleware/disabled checks)
|
|
679
|
+
- `allow: false` → tool is blocked
|
|
599
680
|
- Use this for automated scenarios where you want to programmatically approve/deny tools
|
|
600
681
|
|
|
601
|
-
|
|
682
|
+
3. **Approval System** (via `toolContext.approval`) - For interactive user approval
|
|
602
683
|
- Pauses execution on high-risk tools
|
|
603
684
|
- Shows `requires_action` event
|
|
604
685
|
- Resumes with user's approval decisions
|
|
605
686
|
- Use this for interactive UIs where users manually approve tools
|
|
606
687
|
|
|
607
|
-
**These are independent**: If
|
|
688
|
+
**These are independent**: If `permissionRequest` returns `allow: true`, the approval system is bypassed.
|
|
608
689
|
|
|
609
690
|
### Hook Types
|
|
610
691
|
|
|
611
692
|
```typescript
|
|
612
|
-
interface
|
|
613
|
-
//
|
|
614
|
-
|
|
615
|
-
|
|
693
|
+
interface AgentHooks {
|
|
694
|
+
// Session lifecycle
|
|
695
|
+
sessionStart?: (ctx: SessionStartContext) => Promise<void>
|
|
696
|
+
sessionEnd?: (ctx: SessionEndContext) => Promise<void>
|
|
697
|
+
stop?: (ctx: StopContext) => Promise<void>
|
|
698
|
+
userPromptSubmit?: (ctx: UserPromptSubmitContext) => Promise<UserPromptSubmitResult>
|
|
699
|
+
|
|
700
|
+
// Tool lifecycle
|
|
616
701
|
// - Can modify tool call with modifiedToolCall
|
|
617
|
-
preToolUse?: (ctx:
|
|
702
|
+
preToolUse?: (ctx: ToolHookContext) => Promise<PreToolUseResult | void>
|
|
703
|
+
permissionRequest?: (ctx: ToolHookContext) => Promise<PermissionRequestResult>
|
|
704
|
+
postToolUse?: (ctx: ToolHookContext, result: unknown) => Promise<void>
|
|
705
|
+
postToolUseFailure?: (ctx: ToolHookContext, error: Error) => Promise<void>
|
|
706
|
+
|
|
707
|
+
// Subagent lifecycle (used by parallel task/subagent middleware)
|
|
708
|
+
subagentStart?: (ctx: SubagentStartContext) => Promise<void>
|
|
709
|
+
subagentStop?: (ctx: SubagentStopContext) => Promise<void>
|
|
710
|
+
}
|
|
618
711
|
|
|
619
|
-
|
|
620
|
-
|
|
712
|
+
// Backward-compatible alias
|
|
713
|
+
type ToolHooks = AgentHooks
|
|
621
714
|
|
|
622
|
-
|
|
623
|
-
|
|
715
|
+
interface BaseHookContext {
|
|
716
|
+
sessionId: string
|
|
624
717
|
}
|
|
625
718
|
|
|
626
|
-
interface
|
|
627
|
-
sessionId: string
|
|
719
|
+
interface ToolHookContext extends BaseHookContext {
|
|
628
720
|
toolCall: {
|
|
629
721
|
id: string
|
|
630
722
|
type: 'function'
|
|
@@ -636,15 +728,94 @@ interface HookContext {
|
|
|
636
728
|
toolContext: ToolExecutionContext
|
|
637
729
|
}
|
|
638
730
|
|
|
639
|
-
|
|
640
|
-
|
|
731
|
+
// `HookContext` is kept as a backward-compatible alias of ToolHookContext
|
|
732
|
+
type HookContext = ToolHookContext
|
|
733
|
+
|
|
734
|
+
interface PermissionRequestResult {
|
|
735
|
+
// If true, passes permission checks and skips approval flow
|
|
736
|
+
// (tool still goes through normal middleware/disabled checks)
|
|
641
737
|
// If false, blocks tool execution immediately
|
|
642
738
|
allow: boolean
|
|
643
739
|
// Optional: Modify the tool call before execution
|
|
644
740
|
modifiedToolCall?: ToolCall
|
|
645
741
|
}
|
|
742
|
+
|
|
743
|
+
interface PreToolUseResult {
|
|
744
|
+
// Optional: Modify the tool call before permission/approval/execution
|
|
745
|
+
modifiedToolCall?: ToolCall
|
|
746
|
+
}
|
|
747
|
+
|
|
748
|
+
interface UserPromptSubmitResult {
|
|
749
|
+
allow: boolean
|
|
750
|
+
modifiedInput?: MessageContent
|
|
751
|
+
}
|
|
752
|
+
|
|
753
|
+
interface SessionStartContext extends BaseHookContext {
|
|
754
|
+
startReason: 'new' | 'resume'
|
|
755
|
+
messages: Message[]
|
|
756
|
+
}
|
|
757
|
+
|
|
758
|
+
interface StopContext extends BaseHookContext {
|
|
759
|
+
stopReason:
|
|
760
|
+
| 'max_iterations'
|
|
761
|
+
| 'final_response'
|
|
762
|
+
| 'error'
|
|
763
|
+
| 'cancelled'
|
|
764
|
+
| 'approval_required'
|
|
765
|
+
| 'max_follow_ups'
|
|
766
|
+
// Stop reason reported by the latest model response, when available
|
|
767
|
+
// (e.g. 'tool_call' | 'final' | 'length' | 'error' | 'cancelled')
|
|
768
|
+
modelStopReason?: 'tool_call' | 'final' | 'length' | 'error' | 'cancelled'
|
|
769
|
+
finalResponse?: string
|
|
770
|
+
usage: Usage
|
|
771
|
+
error?: { code?: string; message: string }
|
|
772
|
+
messages: Message[]
|
|
773
|
+
}
|
|
774
|
+
|
|
775
|
+
interface SessionEndContext extends BaseHookContext {
|
|
776
|
+
stopReason: StopContext['stopReason']
|
|
777
|
+
finalResponse?: string
|
|
778
|
+
usage: Usage
|
|
779
|
+
durationMs: number
|
|
780
|
+
error?: { code?: string; message: string }
|
|
781
|
+
messages: Message[]
|
|
782
|
+
}
|
|
783
|
+
|
|
784
|
+
interface UserPromptSubmitContext extends BaseHookContext {
|
|
785
|
+
input: MessageContent
|
|
786
|
+
}
|
|
787
|
+
|
|
788
|
+
interface SubagentStartContext extends BaseHookContext {
|
|
789
|
+
subagentId: string
|
|
790
|
+
subagentType: string
|
|
791
|
+
taskDescription?: string
|
|
792
|
+
prompt: string
|
|
793
|
+
}
|
|
794
|
+
|
|
795
|
+
interface SubagentStopContext extends BaseHookContext {
|
|
796
|
+
subagentId: string
|
|
797
|
+
subagentType: string
|
|
798
|
+
result?: unknown
|
|
799
|
+
error?: Error
|
|
800
|
+
durationMs: number
|
|
801
|
+
usage?: Usage
|
|
802
|
+
messages: Message[]
|
|
803
|
+
}
|
|
646
804
|
```
|
|
647
805
|
|
|
806
|
+
### Hook Execution Order
|
|
807
|
+
|
|
808
|
+
Typical order in one run:
|
|
809
|
+
|
|
810
|
+
1. `sessionStart` (once, on the first `receive()` for this session)
|
|
811
|
+
2. `userPromptSubmit` (before a user message enters the loop; can block or rewrite input)
|
|
812
|
+
3. `preToolUse` (runs first for each tool call; can rewrite tool call)
|
|
813
|
+
4. `permissionRequest` (runs after `preToolUse`; allow/block decision before approval check)
|
|
814
|
+
5. Approval flow (`toolContext.approval`) if still required
|
|
815
|
+
6. `postToolUse` or `postToolUseFailure`
|
|
816
|
+
7. `stop` (after each LLM response completes; for no-LLM termination points, it runs before `done`)
|
|
817
|
+
8. `sessionEnd` (when a run fully finishes; not emitted at `approval_required` pause)
|
|
818
|
+
|
|
648
819
|
### Basic Hook Usage
|
|
649
820
|
|
|
650
821
|
```typescript
|
|
@@ -661,10 +832,17 @@ const agent = new Agent({
|
|
|
661
832
|
const session = await agent.createSession({
|
|
662
833
|
hooks: {
|
|
663
834
|
preToolUse: async (ctx) => {
|
|
835
|
+
// Pre-mutate tool call before permission/approval
|
|
836
|
+
const toolName = ctx.toolCall.function.name
|
|
837
|
+
console.log(`PreToolUse: ${toolName}`)
|
|
838
|
+
},
|
|
839
|
+
|
|
840
|
+
permissionRequest: async (ctx) => {
|
|
664
841
|
const toolName = ctx.toolCall.function.name
|
|
665
842
|
console.log(`Tool requested: ${toolName}`)
|
|
666
843
|
|
|
667
|
-
// Returning { allow: true } skips approval flow
|
|
844
|
+
// Returning { allow: true } skips approval flow
|
|
845
|
+
// (tool still goes through normal middleware/disabled checks before execution)
|
|
668
846
|
// Returning { allow: false } blocks tool execution
|
|
669
847
|
return { allow: true }
|
|
670
848
|
},
|
|
@@ -680,9 +858,9 @@ const session = await agent.createSession({
|
|
|
680
858
|
})
|
|
681
859
|
```
|
|
682
860
|
|
|
683
|
-
### Auto-Approval with
|
|
861
|
+
### Auto-Approval with permissionRequest Hook
|
|
684
862
|
|
|
685
|
-
The `
|
|
863
|
+
The `permissionRequest` hook is powerful because `allow: true` **bypasses the approval flow entirely**, even for high-risk tools. This is useful for automated scenarios:
|
|
686
864
|
|
|
687
865
|
```typescript
|
|
688
866
|
import type { RiskLevel } from 'goatchain'
|
|
@@ -706,7 +884,7 @@ function shouldAutoApprove(toolName: string, riskLevel: RiskLevel): boolean {
|
|
|
706
884
|
|
|
707
885
|
const session = await agent.createSession({
|
|
708
886
|
hooks: {
|
|
709
|
-
|
|
887
|
+
permissionRequest: async (ctx) => {
|
|
710
888
|
const tool = agent.tools.get(ctx.toolCall.function.name)
|
|
711
889
|
const riskLevel = tool?.riskLevel ?? 'safe'
|
|
712
890
|
const allow = shouldAutoApprove(ctx.toolCall.function.name, riskLevel)
|
|
@@ -769,12 +947,12 @@ session.send('Your task', {
|
|
|
769
947
|
|
|
770
948
|
### Interactive Approval with Pause/Resume
|
|
771
949
|
|
|
772
|
-
**Important**: The `
|
|
950
|
+
**Important**: The `permissionRequest` hook with `allow: true` **skips approval**. For interactive approval flows where you want to pause and ask the user, use `toolContext.approval` instead:
|
|
773
951
|
|
|
774
952
|
```typescript
|
|
775
953
|
import type { AgentLoopCheckpoint } from 'goatchain'
|
|
776
954
|
|
|
777
|
-
// Step 1: Start session WITHOUT
|
|
955
|
+
// Step 1: Start session WITHOUT permissionRequest hook (to use approval system)
|
|
778
956
|
const session = await agent.createSession()
|
|
779
957
|
|
|
780
958
|
let checkpoint: AgentLoopCheckpoint | undefined
|
|
@@ -872,12 +1050,9 @@ const session = await agent.createSession({
|
|
|
872
1050
|
}
|
|
873
1051
|
|
|
874
1052
|
return {
|
|
875
|
-
allow: true,
|
|
876
1053
|
modifiedToolCall,
|
|
877
1054
|
}
|
|
878
1055
|
}
|
|
879
|
-
|
|
880
|
-
return { allow: true }
|
|
881
1056
|
},
|
|
882
1057
|
},
|
|
883
1058
|
})
|
|
@@ -946,7 +1121,7 @@ Adds planning phase before execution:
|
|
|
946
1121
|
```typescript
|
|
947
1122
|
import { createPlanModeMiddleware } from 'goatchain'
|
|
948
1123
|
|
|
949
|
-
// Automatically named '
|
|
1124
|
+
// Automatically named 'plan_mode'
|
|
950
1125
|
agent.use(createPlanModeMiddleware())
|
|
951
1126
|
|
|
952
1127
|
// With custom configuration
|
|
@@ -965,7 +1140,7 @@ Automatically compresses context when token limit is reached using a two-stage s
|
|
|
965
1140
|
```typescript
|
|
966
1141
|
import { createContextCompressionMiddleware } from 'goatchain'
|
|
967
1142
|
|
|
968
|
-
// Automatically named '
|
|
1143
|
+
// Automatically named 'context_compression'
|
|
969
1144
|
agent.use(
|
|
970
1145
|
createContextCompressionMiddleware({
|
|
971
1146
|
maxTokens: 128000,
|
|
@@ -1597,22 +1772,22 @@ new Agent(options: AgentOptions)
|
|
|
1597
1772
|
|
|
1598
1773
|
- `name: string` - Agent name (required)
|
|
1599
1774
|
- `systemPrompt: string` - System instructions (required)
|
|
1600
|
-
- `model: ModelClient
|
|
1775
|
+
- `model: ModelClient` - LLM client (required)
|
|
1601
1776
|
- `tools?: ToolRegistry` - Tool registry (not an array)
|
|
1602
1777
|
- `stateStore?: StateStore` - Persistence layer
|
|
1603
|
-
- `
|
|
1604
|
-
- `
|
|
1605
|
-
- `
|
|
1778
|
+
- `middleware?: Middleware[]` - Middleware list to register at startup
|
|
1779
|
+
- `mcpServers?: MCPServerConfig[]` - MCP server configuration list
|
|
1780
|
+
- `enableLogging?: boolean` - Enable internal logs
|
|
1606
1781
|
|
|
1607
1782
|
#### Methods
|
|
1608
1783
|
|
|
1609
|
-
**`createSession(options?): Promise<
|
|
1784
|
+
**`createSession(options?): Promise<Session>`**
|
|
1610
1785
|
|
|
1611
1786
|
Create a new session.
|
|
1612
1787
|
|
|
1613
1788
|
```typescript
|
|
1614
1789
|
const session = await agent.createSession({
|
|
1615
|
-
|
|
1790
|
+
sessionId: 'custom-id', // Optional custom session ID
|
|
1616
1791
|
maxIterations: 10, // Optional max iterations
|
|
1617
1792
|
requestParams: {
|
|
1618
1793
|
// Optional request parameters
|
|
@@ -1622,7 +1797,7 @@ const session = await agent.createSession({
|
|
|
1622
1797
|
})
|
|
1623
1798
|
```
|
|
1624
1799
|
|
|
1625
|
-
**`resumeSession(sessionId, options?): Promise<
|
|
1800
|
+
**`resumeSession(sessionId, options?): Promise<Session>`**
|
|
1626
1801
|
|
|
1627
1802
|
Resume an existing session from checkpoint.
|
|
1628
1803
|
|
|
@@ -1630,21 +1805,21 @@ Resume an existing session from checkpoint.
|
|
|
1630
1805
|
const session = await agent.resumeSession('session-123')
|
|
1631
1806
|
```
|
|
1632
1807
|
|
|
1633
|
-
**`use(middleware, name?): () => void
|
|
1808
|
+
**`use(middleware, name?): Promise<() => void>`**
|
|
1634
1809
|
|
|
1635
1810
|
Add middleware. Returns unsubscribe function.
|
|
1636
1811
|
|
|
1637
1812
|
```typescript
|
|
1638
|
-
const unsubscribe = agent.use(myMiddleware, '
|
|
1813
|
+
const unsubscribe = await agent.use(myMiddleware, 'my_middleware')
|
|
1639
1814
|
unsubscribe() // Remove middleware
|
|
1640
1815
|
```
|
|
1641
1816
|
|
|
1642
|
-
**`removeMiddleware(
|
|
1817
|
+
**`removeMiddleware(nameOrFn): boolean`**
|
|
1643
1818
|
|
|
1644
|
-
Remove middleware by name.
|
|
1819
|
+
Remove middleware by name or function reference.
|
|
1645
1820
|
|
|
1646
1821
|
```typescript
|
|
1647
|
-
agent.removeMiddleware('
|
|
1822
|
+
agent.removeMiddleware('my_middleware')
|
|
1648
1823
|
```
|
|
1649
1824
|
|
|
1650
1825
|
**`setModel(modelOrRef): void`**
|
|
@@ -1652,11 +1827,7 @@ agent.removeMiddleware('my-middleware')
|
|
|
1652
1827
|
Switch or pin model at runtime.
|
|
1653
1828
|
|
|
1654
1829
|
```typescript
|
|
1655
|
-
|
|
1656
|
-
agent.setModel('gpt-4o-mini')
|
|
1657
|
-
|
|
1658
|
-
// Use dynamic reference
|
|
1659
|
-
agent.setModel({ type: 'ref', ref: 'the-model' })
|
|
1830
|
+
agent.setModel({ provider: 'openai', modelId: 'gpt-4o-mini' })
|
|
1660
1831
|
```
|
|
1661
1832
|
|
|
1662
1833
|
#### Properties
|
|
@@ -1665,11 +1836,10 @@ agent.setModel({ type: 'ref', ref: 'the-model' })
|
|
|
1665
1836
|
- `name: string` - Agent name
|
|
1666
1837
|
- `systemPrompt: string` - System prompt
|
|
1667
1838
|
- `model: ModelClient` - Current model client
|
|
1668
|
-
- `tools
|
|
1839
|
+
- `tools?: ToolRegistry` - Tool registry
|
|
1669
1840
|
- `stateStore?: StateStore` - State store
|
|
1670
|
-
- `sessionManager
|
|
1841
|
+
- `sessionManager?: BaseSessionManager` - Session manager
|
|
1671
1842
|
- `middlewareNames: string[]` - List of middleware names
|
|
1672
|
-
- `stats: AgentStats` - Usage statistics
|
|
1673
1843
|
|
|
1674
1844
|
### Session Class
|
|
1675
1845
|
|
|
@@ -1802,15 +1972,20 @@ interface ToolCallStartEvent {
|
|
|
1802
1972
|
|
|
1803
1973
|
interface ToolResultEvent {
|
|
1804
1974
|
type: 'tool_result'
|
|
1805
|
-
|
|
1806
|
-
name: string
|
|
1975
|
+
tool_call_id: string
|
|
1807
1976
|
result: unknown
|
|
1808
|
-
|
|
1977
|
+
isError?: boolean
|
|
1809
1978
|
}
|
|
1810
1979
|
|
|
1811
1980
|
interface DoneEvent {
|
|
1812
1981
|
type: 'done'
|
|
1813
|
-
stopReason:
|
|
1982
|
+
stopReason:
|
|
1983
|
+
| 'max_iterations'
|
|
1984
|
+
| 'final_response'
|
|
1985
|
+
| 'error'
|
|
1986
|
+
| 'cancelled'
|
|
1987
|
+
| 'approval_required'
|
|
1988
|
+
| 'max_follow_ups'
|
|
1814
1989
|
usage?: Usage
|
|
1815
1990
|
}
|
|
1816
1991
|
```
|
|
@@ -1826,12 +2001,12 @@ classDiagram
|
|
|
1826
2001
|
+name: string
|
|
1827
2002
|
+systemPrompt: string
|
|
1828
2003
|
+model: ModelClient
|
|
1829
|
-
+tools: ToolRegistry
|
|
1830
|
-
+stateStore: StateStore
|
|
1831
|
-
+sessionManager: BaseSessionManager
|
|
1832
|
-
+use(middleware):
|
|
1833
|
-
+createSession(): Promise~
|
|
1834
|
-
+resumeSession(id): Promise~
|
|
2004
|
+
+tools: ToolRegistry?
|
|
2005
|
+
+stateStore: StateStore?
|
|
2006
|
+
+sessionManager: BaseSessionManager?
|
|
2007
|
+
+use(middleware): Promise~function~
|
|
2008
|
+
+createSession(): Promise~Session~
|
|
2009
|
+
+resumeSession(id): Promise~Session~
|
|
1835
2010
|
}
|
|
1836
2011
|
|
|
1837
2012
|
class ModelClient {
|
package/dist/agent/agent.d.ts
CHANGED
|
@@ -115,17 +115,17 @@ export declare class Agent {
|
|
|
115
115
|
* }, 'logging');
|
|
116
116
|
*
|
|
117
117
|
* // Built-in middleware with default name
|
|
118
|
-
* await agent.use(createContextCompressionMiddleware({ ... })); // auto-named '
|
|
118
|
+
* await agent.use(createContextCompressionMiddleware({ ... })); // auto-named 'context_compression'
|
|
119
119
|
*
|
|
120
120
|
* // Override default name
|
|
121
|
-
* await agent.use(createPlanModeMiddleware(), '
|
|
121
|
+
* await agent.use(createPlanModeMiddleware(), 'my_plan_mode');
|
|
122
122
|
*
|
|
123
123
|
* // Middleware with tools (auto-registers tools with namespace)
|
|
124
124
|
* const middleware: Middleware = async (state, next) => next(state);
|
|
125
|
-
* middleware.__middlewareName = '
|
|
125
|
+
* middleware.__middlewareName = 'plan_mode';
|
|
126
126
|
* middleware.__createTools = async () => [new EnterPlanModeTool()];
|
|
127
127
|
* await agent.use(middleware);
|
|
128
|
-
* // Tool registered as: '
|
|
128
|
+
* // Tool registered as: 'plan_mode_EnterPlanMode'
|
|
129
129
|
*
|
|
130
130
|
* // Anonymous middleware (auto-named)
|
|
131
131
|
* const unsubscribe = await agent.use(async (state, next) => {
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
export { HookManager } from './manager';
|
|
2
|
-
export type { HookContext, PostToolUseFailureHook, PostToolUseHook, PreToolUseHook, PreToolUseResult, ToolHooks, } from './types';
|
|
2
|
+
export type { AgentHooks, BaseHookContext, HookContext, PermissionRequestHook, PermissionRequestResult, PostToolUseFailureHook, PostToolUseHook, PreToolUseHook, PreToolUseResult, SessionEndContext, SessionEndHook, SessionStartContext, SessionStartHook, StopContext, StopHook, SubagentStartContext, SubagentStartHook, SubagentStopContext, SubagentStopHook, ToolHookContext, ToolHooks, UserPromptSubmitContext, UserPromptSubmitHook, UserPromptSubmitResult, } from './types';
|
|
@@ -1,8 +1,15 @@
|
|
|
1
|
-
import type { HookContext, PreToolUseResult,
|
|
1
|
+
import type { AgentHooks, HookContext, PermissionRequestResult, PreToolUseResult, SessionEndContext, SessionStartContext, SubagentStartContext, StopContext, SubagentStopContext, UserPromptSubmitContext, UserPromptSubmitResult } from './types';
|
|
2
2
|
export declare class HookManager {
|
|
3
3
|
private readonly hooks;
|
|
4
|
-
constructor(hooks?:
|
|
5
|
-
|
|
4
|
+
constructor(hooks?: AgentHooks);
|
|
5
|
+
executePermissionRequest(context: HookContext): Promise<PermissionRequestResult>;
|
|
6
|
+
executePreToolUse(context: HookContext): Promise<PreToolUseResult | void>;
|
|
7
|
+
executeUserPromptSubmit(context: UserPromptSubmitContext): Promise<UserPromptSubmitResult>;
|
|
8
|
+
executeSessionStart(context: SessionStartContext): Promise<void>;
|
|
9
|
+
executeSessionEnd(context: SessionEndContext): Promise<void>;
|
|
6
10
|
executePostToolUse(context: HookContext, result: unknown): Promise<void>;
|
|
7
11
|
executePostToolUseFailure(context: HookContext, error: Error): Promise<void>;
|
|
12
|
+
executeStop(context: StopContext): Promise<void>;
|
|
13
|
+
executeSubagentStart(context: SubagentStartContext): Promise<void>;
|
|
14
|
+
executeSubagentStop(context: SubagentStopContext): Promise<void>;
|
|
8
15
|
}
|