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.
Files changed (54) hide show
  1. package/README.md +247 -72
  2. package/dist/agent/agent.d.ts +4 -4
  3. package/dist/agent/hooks/index.d.ts +1 -1
  4. package/dist/agent/hooks/manager.d.ts +10 -3
  5. package/dist/agent/hooks/types.d.ts +95 -8
  6. package/dist/agent/index.d.ts +3 -2
  7. package/dist/agent/middleware.d.ts +31 -2
  8. package/dist/agent/tokenCounter.d.ts +48 -2
  9. package/dist/agent/types.d.ts +15 -1
  10. package/dist/index.d.ts +12 -4
  11. package/dist/index.js +618 -467
  12. package/dist/lib/access-control/index.d.ts +1 -1
  13. package/dist/lib/access-control/policies.d.ts +10 -0
  14. package/dist/lib/session-blob.d.ts +50 -0
  15. package/dist/mcp-client/manager.d.ts +2 -0
  16. package/dist/middleware/attachmentMiddleware.d.ts +34 -0
  17. package/dist/middleware/commitModeMiddleware.d.ts +1 -1
  18. package/dist/middleware/contextCompressionMiddleware.d.ts +28 -2
  19. package/dist/middleware/envInfoMiddleware.d.ts +6 -0
  20. package/dist/middleware/gitUtils.d.ts +4 -0
  21. package/dist/middleware/longRunningMiddleware.d.ts +100 -0
  22. package/dist/middleware/parallelSubagentMiddleware.d.ts +2 -2
  23. package/dist/middleware/planModeMiddleware.d.ts +3 -3
  24. package/dist/middleware/reviewMiddleware.d.ts +1 -1
  25. package/dist/middleware/skillsMiddleware.d.ts +8 -0
  26. package/dist/model/anthropic/createAnthropicAdapter.d.ts +1 -1
  27. package/dist/model/codex/createCodexAdapter.d.ts +1 -1
  28. package/dist/model/index.d.ts +2 -0
  29. package/dist/model/openai/createOpenAIResponsesAdapter.d.ts +28 -0
  30. package/dist/session/completion/composite.d.ts +25 -0
  31. package/dist/session/completion/index.d.ts +8 -0
  32. package/dist/session/completion/strategies/reflection-decision-tool.d.ts +51 -0
  33. package/dist/session/completion/strategies/rule-based.d.ts +16 -0
  34. package/dist/session/completion/strategies/self-reflection.d.ts +54 -0
  35. package/dist/session/completion/strategies/todo-based.d.ts +17 -0
  36. package/dist/session/completion/types.d.ts +53 -0
  37. package/dist/session/executors/ToolExecutor.d.ts +4 -4
  38. package/dist/session/session.d.ts +9 -0
  39. package/dist/state/types.d.ts +3 -2
  40. package/dist/subagent/index.d.ts +1 -0
  41. package/dist/subagent/self-reflection-critic.d.ts +35 -0
  42. package/dist/tool/builtin/bash.d.ts +24 -0
  43. package/dist/tool/builtin/edit.d.ts +12 -0
  44. package/dist/tool/builtin/index.d.ts +2 -2
  45. package/dist/tool/builtin/pathProtection.d.ts +25 -0
  46. package/dist/tool/builtin/read.d.ts +69 -112
  47. package/dist/tool/builtin/task.d.ts +8 -0
  48. package/dist/tool/builtin/webFetch.d.ts +27 -4
  49. package/dist/tool/builtin/write.d.ts +15 -0
  50. package/dist/tool/index.d.ts +2 -2
  51. package/dist/types/common.d.ts +35 -0
  52. package/dist/types/event.d.ts +55 -3
  53. package/dist/types/snapshot.d.ts +1 -1
  54. package/package.json +4 -2
@@ -0,0 +1,53 @@
1
+ import type { AgentLoopState } from '../../agent/types';
2
+ import type { MessageContent } from '../../types';
3
+ import type { TodoItem } from '../../tool/builtin/todoWrite';
4
+ /**
5
+ * Result of a completion assessment.
6
+ *
7
+ * Returned by a `CompletionAssessor` to indicate whether the current task
8
+ * is complete or if the loop should continue with a follow-up message.
9
+ */
10
+ export interface CompletionAssessment {
11
+ /** Whether the task is considered complete */
12
+ isComplete: boolean;
13
+ /** Human-readable reason for the assessment */
14
+ reason?: string;
15
+ /** Message to inject as a user message if !isComplete */
16
+ followUpMessage?: string;
17
+ /** Confidence score (0-1) for the assessment */
18
+ confidence?: number;
19
+ }
20
+ /**
21
+ * Context provided to completion assessors.
22
+ *
23
+ * Contains everything an assessor needs to judge whether the task is complete.
24
+ */
25
+ export interface CompletionContext {
26
+ /** Current agent loop state (messages, response, iteration, etc.) */
27
+ state: AgentLoopState;
28
+ /** The original user input that started this session run */
29
+ originalInput: MessageContent;
30
+ /** Current todo items from TodoWriteTool (if available) */
31
+ todoItems?: TodoItem[];
32
+ /** Which follow-up round we are on (0 = first assessment) */
33
+ followUpRound: number;
34
+ /** Maximum follow-up rounds allowed */
35
+ maxFollowUpRounds: number;
36
+ }
37
+ /**
38
+ * Interface for completion assessment strategies.
39
+ *
40
+ * Implementations determine whether the agent's task is truly complete
41
+ * or if the loop should continue with additional instructions.
42
+ */
43
+ export interface CompletionAssessor {
44
+ /** Name of this assessor (for logging and events) */
45
+ readonly name: string;
46
+ /**
47
+ * Assess whether the task is complete.
48
+ *
49
+ * @param context - Assessment context with state, todos, etc.
50
+ * @returns Assessment result indicating completion status
51
+ */
52
+ assess(context: CompletionContext): Promise<CompletionAssessment>;
53
+ }
@@ -1,4 +1,4 @@
1
- import type { ToolHooks } from '../../agent/hooks';
1
+ import type { AgentHooks } from '../../agent/hooks';
2
2
  import type { AgentLoopState, ToolCallWithResult } from '../../agent/types';
3
3
  import type { ToolExecutionContext, ToolExecutionContextInput, ToolRegistry } from '../../tool';
4
4
  import type { AgentEvent, AgentLoopCheckpoint, CheckpointModelConfig, CheckpointRequestParams, ToolCall } from '../../types';
@@ -29,14 +29,14 @@ export declare class ToolExecutor {
29
29
  constructor(options: ToolExecutorOptions);
30
30
  private _log;
31
31
  createToolExecutionContext(state: AgentLoopState, signal?: AbortSignal, toolCallId?: string, toolName?: string): ToolExecutionContext;
32
- executeToolCall(tc: ToolCallWithResult, ctx: ToolExecutionContext, signal?: AbortSignal, hooks?: ToolHooks, preToolUseResult?: {
32
+ executeToolCall(tc: ToolCallWithResult, ctx: ToolExecutionContext, signal?: AbortSignal, hooks?: AgentHooks, permissionRequestResult?: {
33
33
  allow: boolean;
34
34
  modifiedToolCall?: ToolCall;
35
- }): Promise<AgentEvent>;
35
+ }, skipPreToolUseHook?: boolean): Promise<AgentEvent>;
36
36
  handleToolCalls(state: AgentLoopState, toolContext: ToolExecutionContext, options?: {
37
37
  signal?: AbortSignal;
38
38
  toolContextInput?: ToolExecutionContextInput;
39
- hooks?: ToolHooks;
39
+ hooks?: AgentHooks;
40
40
  checkpointModelConfig?: CheckpointModelConfig;
41
41
  requestParams?: CheckpointRequestParams;
42
42
  }): AsyncIterable<AgentEvent>;
@@ -63,6 +63,7 @@ export declare class Session extends EventEmitter {
63
63
  private readonly _requestParams?;
64
64
  private readonly _emitSessionCreatedEvent;
65
65
  private _sessionCreatedEventEmitted;
66
+ private _sessionStartHookEmitted;
66
67
  private _abortController;
67
68
  private readonly _enableLogging;
68
69
  private _checkpointOriginalMessages?;
@@ -163,8 +164,16 @@ export declare class Session extends EventEmitter {
163
164
  * Check if there's an assistant message containing the tool call
164
165
  */
165
166
  private hasAssistantToolCallMessage;
167
+ /**
168
+ * Get current todo items from the TodoWriteTool (if registered).
169
+ * Used to populate state.metadata._todoItems for middleware access.
170
+ * @internal
171
+ */
172
+ private _getTodoItems;
166
173
  private handleFinalResponse;
167
174
  private _finalizeRun;
175
+ private _executeStopHook;
176
+ private getStopReasonForModelResponse;
168
177
  /**
169
178
  * Get preview of the last message (truncated for display)
170
179
  *
@@ -81,9 +81,10 @@ export interface CompressionState {
81
81
  */
82
82
  compressedRange?: {
83
83
  /**
84
- * Index after first turn ends (messages before this are kept).
84
+ * Index where summarization starts (first non-system message).
85
+ * Messages before this index (system messages) are always kept.
85
86
  */
86
- firstTurnEnd: number;
87
+ summarizeStart: number;
87
88
  /**
88
89
  * Index where protected turns start (messages from this onward are kept).
89
90
  */
@@ -7,3 +7,4 @@
7
7
  export * from './bash-validator';
8
8
  export * from './explore';
9
9
  export * from './parallel-task-coordinator';
10
+ export * from './self-reflection-critic';
@@ -0,0 +1,35 @@
1
+ import type { SubagentDefinition } from '../tool/builtin/task';
2
+ /**
3
+ * System prompt for the Self-Reflection Critic subagent.
4
+ *
5
+ * This prompt defines the critic's role as the user's proxy / critical
6
+ * reviewer. It instructs the model to:
7
+ * 1. Act on behalf of the user
8
+ * 2. Search the codebase to verify the agent's claims
9
+ * 3. Identify potential issues, edge cases, and missing requirements
10
+ * 4. Generate follow-up questions the user would ask
11
+ * 5. Call the ReflectionDecision tool with its final verdict
12
+ * 6. Be progressively more lenient in later rounds to prevent infinite loops
13
+ */
14
+ export declare function buildCriticSystemPrompt(cwd: string, now?: Date): string;
15
+ export declare const criticSystemPrompt: string;
16
+ /**
17
+ * Self-Reflection Critic Subagent Definition
18
+ *
19
+ * A read-only reviewer agent that acts as the user's proxy.
20
+ * It verifies the main agent's work by searching the codebase,
21
+ * checking for issues, and generating follow-up questions the
22
+ * user would ask.
23
+ *
24
+ * Uses the ReflectionDecision tool to record a structured verdict.
25
+ *
26
+ * @example
27
+ * ```typescript
28
+ * Task({
29
+ * subagent_type: 'SelfReflectionCritic',
30
+ * description: 'Review agent work',
31
+ * prompt: '## Original User Request\n...\n## Agent Response\n...'
32
+ * })
33
+ * ```
34
+ */
35
+ export declare const selfReflectionCriticAgent: SubagentDefinition;
@@ -2,6 +2,7 @@ import type { ChildProcess } from 'node:child_process';
2
2
  import type { CallToolResult, ToolInputSchema } from '../../types';
3
3
  import type { ToolExecutionContext } from '../types';
4
4
  import { BaseTool } from '../base';
5
+ import { type ReadOnlyPathEntry } from './pathProtection';
5
6
  /**
6
7
  * Information about a tracked background process
7
8
  */
@@ -95,9 +96,12 @@ export declare class BashTool extends BaseTool {
95
96
  private cwd;
96
97
  /** Shell to use for command execution */
97
98
  private shell;
99
+ /** Optional read-only path rules */
100
+ private readOnlyPaths?;
98
101
  constructor(options?: {
99
102
  cwd?: string;
100
103
  shell?: string;
104
+ readOnlyPaths?: ReadOnlyPathEntry[];
101
105
  });
102
106
  /**
103
107
  * Set the current working directory
@@ -107,6 +111,14 @@ export declare class BashTool extends BaseTool {
107
111
  * Get the current working directory
108
112
  */
109
113
  getCwd(): string;
114
+ /**
115
+ * Set read-only paths for write-like shell commands.
116
+ */
117
+ setReadOnlyPaths(paths: ReadonlyArray<ReadOnlyPathEntry> | undefined): void;
118
+ /**
119
+ * Get configured read-only paths.
120
+ */
121
+ getReadOnlyPaths(): ReadonlyArray<ReadOnlyPathEntry> | undefined;
110
122
  /**
111
123
  * Execute a bash command
112
124
  *
@@ -123,6 +135,18 @@ export declare class BashTool extends BaseTool {
123
135
  * Validate and parse arguments
124
136
  */
125
137
  private validateArgs;
138
+ /**
139
+ * Validate read-only path policy for write-like shell commands.
140
+ *
141
+ * This is intentionally heuristic: commands that appear read-only are skipped.
142
+ * For write-like commands, we block when:
143
+ * 1) effective cwd is under a protected path, or
144
+ * 2) command text explicitly references a protected path.
145
+ */
146
+ private validateReadOnlyPathPolicy;
147
+ private findReferencedReadOnlyRule;
148
+ private buildCommandPathCandidates;
149
+ private commandMentionsPath;
126
150
  /**
127
151
  * Execute command synchronously with timeout
128
152
  */
@@ -1,6 +1,7 @@
1
1
  import type { CallToolResult, ToolInputSchema } from '../../types';
2
2
  import type { ToolExecutionContext } from '../types';
3
3
  import { BaseTool } from '../base';
4
+ import { type ReadOnlyPathEntry } from './pathProtection';
4
5
  /**
5
6
  * Result of an edit operation
6
7
  */
@@ -61,10 +62,13 @@ export declare class EditTool extends BaseTool {
61
62
  private fileBlacklist?;
62
63
  /** Disable file blacklist checks */
63
64
  private disableBlacklist;
65
+ /** Optional read-only path rules */
66
+ private readOnlyPaths?;
64
67
  constructor(options?: {
65
68
  cwd?: string;
66
69
  fileBlacklist?: string[];
67
70
  disableBlacklist?: boolean;
71
+ readOnlyPaths?: ReadOnlyPathEntry[];
68
72
  });
69
73
  /**
70
74
  * Set the current working directory
@@ -74,6 +78,14 @@ export declare class EditTool extends BaseTool {
74
78
  * Get the current working directory
75
79
  */
76
80
  getCwd(): string;
81
+ /**
82
+ * Set read-only paths for file operations.
83
+ */
84
+ setReadOnlyPaths(paths: ReadonlyArray<ReadOnlyPathEntry> | undefined): void;
85
+ /**
86
+ * Get configured read-only paths.
87
+ */
88
+ getReadOnlyPaths(): ReadonlyArray<ReadOnlyPathEntry> | undefined;
77
89
  /**
78
90
  * Execute file edit
79
91
  *
@@ -20,8 +20,8 @@ export { TodoPlanTool } from './todoPlan';
20
20
  export type { TodoPlanArgs, TodoPlanResult } from './todoPlan';
21
21
  export { TodoWriteTool } from './todoWrite';
22
22
  export type { TodoItem, TodoStatus, TodoWriteArgs, TodoWriteResult } from './todoWrite';
23
- export { WebFetchTool } from './webFetch';
24
- export type { FetchFormat, WebFetchArgs, WebFetchResult } from './webFetch';
23
+ export { softWrapLines, WebFetchTool } from './webFetch';
24
+ export type { DeliveryMode, FetchFormat, WebFetchArgs, WebFetchResult } from './webFetch';
25
25
  export { WebSearchTool } from './webSearch';
26
26
  export type { SearchResultItem, WebSearchArgs, WebSearchResult } from './webSearch';
27
27
  export { WriteTool } from './write';
@@ -0,0 +1,25 @@
1
+ export interface ReadOnlyPathRule {
2
+ path: string;
3
+ reason?: string;
4
+ }
5
+ export type ReadOnlyPathEntry = string | ReadOnlyPathRule;
6
+ export interface ResolvedReadOnlyPathRule {
7
+ path: string;
8
+ reason?: string;
9
+ absolutePath: string;
10
+ }
11
+ export interface ReadOnlyPathCheckOptions {
12
+ cwd?: string;
13
+ readOnlyPaths?: ReadonlyArray<ReadOnlyPathEntry>;
14
+ originalPath?: string;
15
+ action?: string;
16
+ }
17
+ export interface ReadOnlyPathCheckResult {
18
+ isBlocked: boolean;
19
+ rule?: ResolvedReadOnlyPathRule;
20
+ message?: string;
21
+ }
22
+ export declare function resolveReadOnlyPathRules(readOnlyPaths: ReadonlyArray<ReadOnlyPathEntry> | undefined, cwd?: string): ResolvedReadOnlyPathRule[];
23
+ export declare function findMatchingReadOnlyPath(targetPath: string, rules: ReadonlyArray<ResolvedReadOnlyPathRule>): ResolvedReadOnlyPathRule | undefined;
24
+ export declare function formatReadOnlyPathError(displayPath: string, rule?: Pick<ResolvedReadOnlyPathRule, 'path' | 'absolutePath' | 'reason'>, action?: string): string;
25
+ export declare function checkReadOnlyPath(targetPath: string, options?: ReadOnlyPathCheckOptions): Promise<ReadOnlyPathCheckResult>;
@@ -2,62 +2,33 @@ import type { CallToolResult, ToolInputSchema } from '../../types';
2
2
  import type { ConversionMetadata } from '../converters/types';
3
3
  import type { ToolExecutionContext } from '../types';
4
4
  import { BaseTool } from '../base';
5
- /**
6
- * Result of a file read operation
7
- */
5
+ /** Result of a file read operation (text path) */
8
6
  export interface ReadResult {
9
- /** File content with line numbers */
10
7
  content: string;
11
- /** Total number of lines in file */
12
8
  totalLines: number;
13
- /** Number of lines returned */
14
9
  linesReturned: number;
15
- /** Starting line number (1-based) */
16
10
  startLine: number;
17
- /** Whether any lines were truncated */
11
+ /** Whether any individual line was truncated (per-line length limit) */
18
12
  truncated: boolean;
19
- /** Whether the content was truncated due to character limit */
20
- contentTruncated?: boolean;
21
- /** Total characters in full content (before truncation) */
22
- totalChars?: number;
23
- /** Actual characters returned (after truncation) */
24
- charsReturned?: number;
25
- /** File size in bytes */
13
+ /** Whether output was truncated because byte budget was exceeded */
14
+ truncatedByBytes?: boolean;
26
15
  fileSize: number;
27
- /** Whether this is a binary/image file */
28
16
  isBinary: boolean;
29
- /** MIME type if detected */
30
17
  mimeType?: string;
31
- /** Conversion metadata if file was converted from binary format */
32
18
  conversionMetadata?: ConversionMetadata;
33
- /** Whether binary content was suppressed */
34
- binaryContentSuppressed?: boolean;
35
- /** Reason binary content was suppressed */
36
- binaryContentReason?: string;
37
19
  }
38
- /**
39
- * Arguments for the Read tool
40
- */
20
+ /** Arguments accepted by the Read tool */
41
21
  export interface ReadArgs {
42
- /** The path to the file to read (absolute or relative to cwd) */
43
- file_path: string;
44
- /** The line number to start reading from (1-based) */
22
+ file_path?: string;
23
+ file_id?: string;
45
24
  offset?: number;
46
- /** The number of lines to read */
47
25
  limit?: number;
48
- /** Enable automatic conversion of binary files to Markdown (default: true) */
49
- enable_conversion?: boolean;
50
- /** Conversion options for binary files */
51
- conversion_options?: Record<string, unknown>;
52
- /** Allow raw binary (base64) output for binary files (default: false) */
53
- allow_binary_content?: boolean;
26
+ start_line?: number;
27
+ end_line?: number;
54
28
  }
55
29
  /**
56
30
  * Tool for reading files from the filesystem.
57
31
  *
58
- * This tool reads files with line number formatting, supporting
59
- * offset/limit for large files and detecting binary content.
60
- *
61
32
  * @example
62
33
  * ```typescript
63
34
  * const readTool = new ReadTool()
@@ -67,106 +38,92 @@ export interface ReadArgs {
67
38
  * limit: 50
68
39
  * })
69
40
  * ```
70
- *
71
- * @example Restrict reads to a specific directory
72
- * ```typescript
73
- * const readTool = new ReadTool({
74
- * cwd: '/app/output',
75
- * restrictToDirectory: true
76
- * })
77
- * // All paths will be resolved relative to /app/output
78
- * // Absolute paths and path traversal (../) will be blocked
79
- * ```
80
41
  */
81
42
  export declare class ReadTool extends BaseTool {
82
43
  readonly name = "Read";
83
- /** Current working directory for resolving relative paths */
84
44
  private _cwd;
85
- /** Allowed directory for file operations (if set, restricts reads to this directory) */
86
45
  private _allowedDirectory?;
87
- /** Optional file blacklist override */
88
46
  private _fileBlacklist?;
89
- /** Disable file blacklist checks */
90
47
  private _disableBlacklist;
91
- /** Binary file processor for converting documents to Markdown */
92
48
  private _processor;
49
+ private _converterAllowList;
50
+ private _supportsVision;
51
+ private _supportsPdfs;
93
52
  constructor(options?: {
94
53
  cwd?: string;
95
- /** If set, restricts all file reads to this directory. Paths outside will be rejected. */
96
54
  allowedDirectory?: string;
97
- /** Optional file blacklist override (defaults to built-in blacklist). */
98
55
  fileBlacklist?: string[];
99
- /** Disable file blacklist checks entirely. */
100
56
  disableBlacklist?: boolean;
101
- /** Enable/disable binary file conversion (default: true) */
102
57
  enableConversion?: boolean;
103
- /** Custom binary file processor */
104
58
  processor?: any;
59
+ /**
60
+ * Extensions allowed through the converter pipeline (e.g. `['.docx', '.pptx']`).
61
+ * Binary files whose extension is NOT in this list will skip conversion and
62
+ * return a binary-info result suggesting to use the Bash tool instead.
63
+ *
64
+ * @default ['.docx', '.pptx', '.pages', '.numbers', '.key']
65
+ */
66
+ converterAllowList?: string[];
67
+ /**
68
+ * Model capabilities that determine how binary files are handled.
69
+ *
70
+ * - `vision` – whether the model can understand images (default: `false`)
71
+ * - `pdfs` – whether the model can read PDFs natively (default: `false`)
72
+ *
73
+ * When a capability is `false` the Read tool will **not** return native
74
+ * (base64) content for that file type. Instead it returns a short message
75
+ * explaining the file cannot be read by the current model, or attempts
76
+ * automatic conversion to Markdown (for PDFs).
77
+ */
78
+ modelCapabilities?: {
79
+ vision?: boolean;
80
+ pdfs?: boolean;
81
+ };
105
82
  });
106
- private createDefaultProcessor;
107
- /**
108
- * Dynamic description that includes allowed directory info if configured
109
- */
110
83
  get description(): string;
111
- /**
112
- * Dynamic parameters that include allowed directory info if configured
113
- */
114
84
  get parameters(): ToolInputSchema;
115
- /**
116
- * Set the current working directory
117
- */
118
85
  setCwd(cwd: string): void;
119
- /**
120
- * Get the current working directory
121
- */
122
86
  getCwd(): string;
123
- /**
124
- * Set the allowed directory for file operations
125
- */
126
87
  setAllowedDirectory(dir: string | undefined): void;
127
- /**
128
- * Get the allowed directory for file operations
129
- */
130
88
  getAllowedDirectory(): string | undefined;
131
- private isWithinDirectory;
132
89
  /**
133
- * Execute file read
134
- *
135
- * @param args - Read arguments
136
- * @param _ctx - Tool execution context (required, includes sessionId)
137
- * @returns MCP-compliant CallToolResult with file content
90
+ * Replace the converter allow-list at runtime.
91
+ * Pass extensions with or without leading dot (e.g. `'.xlsx'` or `'xlsx'`).
138
92
  */
139
- execute(args: Record<string, unknown>, _ctx: ToolExecutionContext): Promise<CallToolResult>;
93
+ setConverterAllowList(extensions: string[]): void;
94
+ /** Return a copy of the current converter allow-list. */
95
+ getConverterAllowList(): string[];
140
96
  /**
141
- * Validate and parse arguments
142
- */
143
- private validateArgs;
144
- /**
145
- * Handle image file (metadata only)
146
- */
147
- private handleImageFile;
148
- /**
149
- * Handle binary file (non-image)
150
- */
151
- private handleBinaryFile;
152
- /**
153
- * Handle binary file with conversion to Markdown
154
- */
155
- private handleBinaryFileWithConversion;
156
- /**
157
- * Handle Jupyter notebook file
158
- */
159
- private handleJupyterNotebook;
160
- /**
161
- * Handle text file
162
- */
163
- private handleTextFile;
164
- /**
165
- * Format output with line numbers and apply offset/limit
97
+ * Update model capabilities at runtime (e.g. when the user switches models).
98
+ *
99
+ * @example
100
+ * ```typescript
101
+ * readTool.setModelCapabilities({ vision: false, pdfs: false })
102
+ * ```
166
103
  */
167
- private formatOutput;
104
+ setModelCapabilities(caps: {
105
+ vision?: boolean;
106
+ pdfs?: boolean;
107
+ }): void;
108
+ /** Return the current model capability flags. */
109
+ getModelCapabilities(): {
110
+ vision: boolean;
111
+ pdfs: boolean;
112
+ };
113
+ execute(args: Record<string, unknown>, ctx: ToolExecutionContext): Promise<CallToolResult>;
114
+ private _validateArgs;
115
+ private _isWithin;
116
+ private _checkSymlinkEscape;
117
+ /** Read a text file, return byte-budgeted line-numbered output. */
118
+ private _readText;
119
+ /** Read a Jupyter notebook, flatten cells into lines, then format. */
120
+ private _readNotebook;
168
121
  /**
169
- * Format file size for display
122
+ * Handle a binary file that is not an image or PDF.
123
+ * Try to convert via processor; on failure return an info result with
124
+ * file type & size so the model knows what it's dealing with.
170
125
  */
171
- private formatSize;
126
+ private _readBinary;
127
+ private _wrapText;
128
+ private _createDefaultProcessor;
172
129
  }
@@ -14,6 +14,14 @@ export interface SubagentDefinition {
14
14
  accessPolicy: ToolAccessPolicy;
15
15
  /** System prompt for this subagent (optional) */
16
16
  systemPrompt?: string;
17
+ /**
18
+ * Extra tools to inject into this subagent (not sourced from global registry).
19
+ *
20
+ * Use this for subagent-specific tools that should not be registered
21
+ * globally. The middleware will add these tools to the subagent's registry
22
+ * after filtering global tools by the access policy.
23
+ */
24
+ extraTools?: import('../base').BaseTool[];
17
25
  /** Additional metadata (extensible for future use) */
18
26
  [key: string]: unknown;
19
27
  }
@@ -3,6 +3,8 @@ import type { ToolExecutionContext } from '../types';
3
3
  import { BaseTool } from '../base';
4
4
  /** Output format for web fetch */
5
5
  export type FetchFormat = 'markdown' | 'html' | 'json' | 'text';
6
+ /** Delivery mode: inline (small content) or blob (large content stored to disk) */
7
+ export type DeliveryMode = 'inline' | 'blob';
6
8
  /**
7
9
  * Result of a web fetch operation
8
10
  */
@@ -13,7 +15,7 @@ export interface WebFetchResult {
13
15
  url: string;
14
16
  /** The output format used */
15
17
  format: FetchFormat;
16
- /** The content text */
18
+ /** The content text (full for inline, preview for blob) */
17
19
  content: string;
18
20
  /** Original content length in characters */
19
21
  contentLength: number;
@@ -27,6 +29,16 @@ export interface WebFetchResult {
27
29
  truncated: boolean;
28
30
  /** Error message if fetch failed */
29
31
  error?: string;
32
+ /** Delivery mode: "inline" or "blob" */
33
+ delivery?: DeliveryMode;
34
+ /** Session blob file_id (only when delivery is "blob") */
35
+ file_id?: string;
36
+ /** Total line count in blob (only when delivery is "blob") */
37
+ lineCount?: number;
38
+ /** SHA-256 hash of full content (only when delivery is "blob") */
39
+ sha256?: string;
40
+ /** Instructions for reading the full blob content (only when delivery is "blob") */
41
+ readInstructions?: string;
30
42
  }
31
43
  /**
32
44
  * Arguments for the WebFetch tool
@@ -45,6 +57,12 @@ export interface WebFetchArgs {
45
57
  /** Whether to use Jina Reader as fallback if direct fetch fails. Defaults to true (programmatic use only). */
46
58
  use_jina_fallback?: boolean;
47
59
  }
60
+ /**
61
+ * Break lines longer than `maxLen` at word boundaries.
62
+ * Preserves content inside fenced code blocks (```) to avoid breaking
63
+ * indentation-sensitive code.
64
+ */
65
+ export declare function softWrapLines(text: string, maxLen?: number): string;
48
66
  /**
49
67
  * Tool for fetching and converting web content.
50
68
  *
@@ -64,7 +82,7 @@ export interface WebFetchArgs {
64
82
  */
65
83
  export declare class WebFetchTool extends BaseTool {
66
84
  readonly name = "WebFetch";
67
- readonly description = "Fetches content from a specified URL and converts it to various formats.\n\nUsage notes:\n- Takes a URL as input\n- Supports multiple output formats: markdown (recommended), html, json, text\n- Markdown format is recommended for LLM processing\n- The URL must be a fully-formed valid URL\n- Supports custom HTTP headers (programmatic use only)\n- Content length can be limited with max_length parameter (default: 5000)\n- Pagination supported with start_index parameter\n- Hard limit: 10MB to prevent OOM\n- Private IP addresses are blocked for security\n- 30 second timeout, maximum 5 redirects\n- Automatically falls back to Jina Reader (r.jina.ai) if direct fetch fails (cannot be disabled)";
85
+ readonly description = "Fetches content from a specified URL and converts it to various formats.\n\nUsage notes:\n- Takes a URL as input\n- Supports multiple output formats: markdown (recommended), html, json, text\n- Markdown format is recommended for LLM processing\n- The URL must be a fully-formed valid URL\n- Supports custom HTTP headers (programmatic use only)\n- Content length can be limited with max_length parameter (default: 5000)\n- Pagination supported with start_index parameter\n- Hard limit: 10MB to prevent OOM\n- Private IP addresses are blocked for security\n- 30 second timeout, maximum 5 redirects\n- Automatically falls back to Jina Reader (r.jina.ai) if direct fetch fails (cannot be disabled)\n- For large pages: content is automatically saved to a session blob and returned with a file_id. Use the Read tool with that file_id and start_line/end_line to access the full content in chunks of ~200 lines.";
68
86
  readonly parameters: ToolInputSchema;
69
87
  readonly riskLevel = "medium";
70
88
  private turndownService;
@@ -73,10 +91,15 @@ export declare class WebFetchTool extends BaseTool {
73
91
  * Execute web fetch
74
92
  *
75
93
  * @param args - WebFetch arguments
76
- * @param _ctx - Tool execution context
94
+ * @param ctx - Tool execution context
77
95
  * @returns MCP-compliant CallToolResult with fetched content
78
96
  */
79
- execute(args: Record<string, unknown>, _ctx: ToolExecutionContext): Promise<CallToolResult>;
97
+ execute(args: Record<string, unknown>, ctx: ToolExecutionContext): Promise<CallToolResult>;
98
+ /**
99
+ * Attempt to soft-wrap content and write to a session blob.
100
+ * Returns a CallToolResult with the blob reference on success, or null on failure.
101
+ */
102
+ private tryWriteBlob;
80
103
  /**
81
104
  * Validate and parse arguments
82
105
  */
@@ -1,6 +1,7 @@
1
1
  import type { CallToolResult, ToolInputSchema } from '../../types';
2
2
  import type { ToolExecutionContext } from '../types';
3
3
  import { BaseTool } from '../base';
4
+ import { type ReadOnlyPathEntry } from './pathProtection';
4
5
  /**
5
6
  * Result of a write operation
6
7
  */
@@ -11,6 +12,8 @@ export interface WriteResult {
11
12
  filePath: string;
12
13
  /** Number of bytes written */
13
14
  bytesWritten: number;
15
+ /** Number of lines written */
16
+ linesWritten: number;
14
17
  /** Whether an existing file was overwritten */
15
18
  overwritten: boolean;
16
19
  /** Optional revert payload for undo/redo */
@@ -68,6 +71,8 @@ export declare class WriteTool extends BaseTool {
68
71
  private _fileBlacklist?;
69
72
  /** Disable file blacklist checks */
70
73
  private _disableBlacklist;
74
+ /** Optional read-only path rules */
75
+ private _readOnlyPaths?;
71
76
  constructor(options?: {
72
77
  cwd?: string;
73
78
  /** If set, restricts all file writes to this directory. Paths outside will be rejected. */
@@ -76,6 +81,8 @@ export declare class WriteTool extends BaseTool {
76
81
  fileBlacklist?: string[];
77
82
  /** Disable file blacklist checks entirely. */
78
83
  disableBlacklist?: boolean;
84
+ /** Optional read-only path list. Writes into these paths will be rejected. */
85
+ readOnlyPaths?: ReadOnlyPathEntry[];
79
86
  });
80
87
  /**
81
88
  * Dynamic description that includes allowed directory info if configured
@@ -101,6 +108,14 @@ export declare class WriteTool extends BaseTool {
101
108
  * Get the allowed directory for file operations
102
109
  */
103
110
  getAllowedDirectory(): string | undefined;
111
+ /**
112
+ * Set read-only paths for file operations.
113
+ */
114
+ setReadOnlyPaths(paths: ReadonlyArray<ReadOnlyPathEntry> | undefined): void;
115
+ /**
116
+ * Get configured read-only paths.
117
+ */
118
+ getReadOnlyPaths(): ReadonlyArray<ReadOnlyPathEntry> | undefined;
104
119
  /**
105
120
  * Execute file write
106
121
  *