indusagi-coding-agent 0.1.25 → 0.1.27
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/CHANGELOG.md +87 -0
- package/dist/cli/file-processor.js +1 -1
- package/dist/cli/file-processor.js.map +1 -1
- package/dist/core/agent-session.d.ts +1 -1
- package/dist/core/agent-session.d.ts.map +1 -1
- package/dist/core/agent-session.js +3 -3
- package/dist/core/agent-session.js.map +1 -1
- package/dist/core/bash-executor.d.ts +1 -1
- package/dist/core/bash-executor.d.ts.map +1 -1
- package/dist/core/bash-executor.js +1 -1
- package/dist/core/bash-executor.js.map +1 -1
- package/dist/core/extensions/types.d.ts +1 -3
- package/dist/core/extensions/types.d.ts.map +1 -1
- package/dist/core/settings-manager.js +1 -1
- package/dist/core/settings-manager.js.map +1 -1
- package/dist/core/task-session-manager.d.ts.map +1 -1
- package/dist/core/task-session-manager.js +1 -7
- package/dist/core/task-session-manager.js.map +1 -1
- package/dist/core/tools/bg-process.d.ts +1 -1
- package/dist/core/tools/index.d.ts +60 -59
- package/dist/core/tools/index.d.ts.map +1 -1
- package/dist/core/tools/index.js +89 -24
- package/dist/core/tools/index.js.map +1 -1
- package/dist/core/tools/task.d.ts +21 -16
- package/dist/core/tools/task.d.ts.map +1 -1
- package/dist/core/tools/task.js +82 -43
- package/dist/core/tools/task.js.map +1 -1
- package/dist/core/tools/todo.d.ts +31 -20
- package/dist/core/tools/todo.d.ts.map +1 -1
- package/dist/core/tools/todo.js +67 -44
- package/dist/core/tools/todo.js.map +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/modes/interactive/components/bash-execution.d.ts +1 -1
- package/dist/modes/interactive/components/bash-execution.d.ts.map +1 -1
- package/dist/modes/interactive/components/bash-execution.js +1 -1
- package/dist/modes/interactive/components/bash-execution.js.map +1 -1
- package/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
- package/dist/modes/interactive/components/tool-execution.js +2 -2
- package/dist/modes/interactive/components/tool-execution.js.map +1 -1
- package/package.json +3 -3
- package/dist/core/todo-store.d.ts +0 -20
- package/dist/core/todo-store.d.ts.map +0 -1
- package/dist/core/todo-store.js +0 -55
- package/dist/core/todo-store.js.map +0 -1
- package/dist/core/tools/bash.d.ts +0 -428
- package/dist/core/tools/bash.d.ts.map +0 -1
- package/dist/core/tools/bash.js +0 -498
- package/dist/core/tools/bash.js.map +0 -1
- package/dist/core/tools/edit-diff.d.ts +0 -63
- package/dist/core/tools/edit-diff.d.ts.map +0 -1
- package/dist/core/tools/edit-diff.js +0 -243
- package/dist/core/tools/edit-diff.js.map +0 -1
- package/dist/core/tools/edit.d.ts +0 -315
- package/dist/core/tools/edit.d.ts.map +0 -1
- package/dist/core/tools/edit.js +0 -384
- package/dist/core/tools/edit.js.map +0 -1
- package/dist/core/tools/find.d.ts +0 -201
- package/dist/core/tools/find.d.ts.map +0 -1
- package/dist/core/tools/find.js +0 -342
- package/dist/core/tools/find.js.map +0 -1
- package/dist/core/tools/grep.d.ts +0 -323
- package/dist/core/tools/grep.d.ts.map +0 -1
- package/dist/core/tools/grep.js +0 -486
- package/dist/core/tools/grep.js.map +0 -1
- package/dist/core/tools/ls.d.ts +0 -44
- package/dist/core/tools/ls.d.ts.map +0 -1
- package/dist/core/tools/ls.js +0 -124
- package/dist/core/tools/ls.js.map +0 -1
- package/dist/core/tools/path-utils.d.ts +0 -8
- package/dist/core/tools/path-utils.d.ts.map +0 -1
- package/dist/core/tools/path-utils.js +0 -53
- package/dist/core/tools/path-utils.js.map +0 -1
- package/dist/core/tools/read.d.ts +0 -338
- package/dist/core/tools/read.d.ts.map +0 -1
- package/dist/core/tools/read.js +0 -397
- package/dist/core/tools/read.js.map +0 -1
- package/dist/core/tools/truncate.d.ts +0 -70
- package/dist/core/tools/truncate.d.ts.map +0 -1
- package/dist/core/tools/truncate.js +0 -205
- package/dist/core/tools/truncate.js.map +0 -1
- package/dist/core/tools/webfetch.d.ts +0 -174
- package/dist/core/tools/webfetch.d.ts.map +0 -1
- package/dist/core/tools/webfetch.js +0 -380
- package/dist/core/tools/webfetch.js.map +0 -1
- package/dist/core/tools/websearch.d.ts +0 -190
- package/dist/core/tools/websearch.d.ts.map +0 -1
- package/dist/core/tools/websearch.js +0 -267
- package/dist/core/tools/websearch.js.map +0 -1
- package/dist/core/tools/write.d.ts +0 -273
- package/dist/core/tools/write.d.ts.map +0 -1
- package/dist/core/tools/write.js +0 -288
- package/dist/core/tools/write.js.map +0 -1
package/dist/core/tools/read.js
DELETED
|
@@ -1,397 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Read Tool - Read file contents with automatic image handling
|
|
3
|
-
*
|
|
4
|
-
* @module core/tools/read
|
|
5
|
-
* @description
|
|
6
|
-
* Implements the read tool for the agent. Reads file contents with:
|
|
7
|
-
* - Support for line-based offset/limit
|
|
8
|
-
* - Automatic image detection and resizing
|
|
9
|
-
* - Large file truncation handling
|
|
10
|
-
* - Remote execution support (SSH, containers)
|
|
11
|
-
*
|
|
12
|
-
* Based on file reading tools from Anthropic's Claude API and common Unix utilities.
|
|
13
|
-
* Refactored for agent multimodal content handling.
|
|
14
|
-
* - Proper path resolution and validation
|
|
15
|
-
*
|
|
16
|
-
* ## Tool Interface
|
|
17
|
-
*
|
|
18
|
-
* **Input Parameters:**
|
|
19
|
-
* - `path` (required): File path to read (relative or absolute)
|
|
20
|
-
* - `offset` (optional): Starting line number (1-indexed)
|
|
21
|
-
* - `limit` (optional): Maximum number of lines to read
|
|
22
|
-
*
|
|
23
|
-
* **Output:**
|
|
24
|
-
* - Text files: Line content as text
|
|
25
|
-
* - Image files: Image data with metadata
|
|
26
|
-
* - Large files: Truncated with temp file path
|
|
27
|
-
*
|
|
28
|
-
* **Error Behavior:**
|
|
29
|
-
* - File not found → Tool error "ENOENT: no such file"
|
|
30
|
-
* - Permission denied → Tool error "EACCES: permission denied"
|
|
31
|
-
* - Invalid path → Tool error "Path outside working directory"
|
|
32
|
-
* - Large file not truncable → Tool error "File too large"
|
|
33
|
-
*
|
|
34
|
-
* ## Usage in Agent
|
|
35
|
-
*
|
|
36
|
-
* The agent uses this tool to:
|
|
37
|
-
* - Read source code files for analysis
|
|
38
|
-
* - Check configuration files
|
|
39
|
-
* - Read documentation and READMEs
|
|
40
|
-
* - View images and diagrams
|
|
41
|
-
* - Inspect logs and build output
|
|
42
|
-
*
|
|
43
|
-
* ## Features
|
|
44
|
-
*
|
|
45
|
-
* **Line-based Access:**
|
|
46
|
-
* - offset: Start reading from line N (1-indexed)
|
|
47
|
-
* - limit: Read at most N lines
|
|
48
|
-
* - Useful for large files
|
|
49
|
-
*
|
|
50
|
-
* **Image Handling:**
|
|
51
|
-
* - Auto-detect image MIME type
|
|
52
|
-
* - Resize large images (configurable)
|
|
53
|
-
* - Include dimension information
|
|
54
|
-
* - Provide helpful notes for vision models
|
|
55
|
-
*
|
|
56
|
-
* **Truncation:**
|
|
57
|
-
* - Truncate large files at front (keeps last N bytes)
|
|
58
|
-
* - Write full content to temp file if needed
|
|
59
|
-
* - Return truncation info for reference
|
|
60
|
-
*
|
|
61
|
-
* **Path Safety:**
|
|
62
|
-
* - Resolve relative paths relative to cwd
|
|
63
|
-
* - Prevent path traversal attacks (no ../../../etc/passwd)
|
|
64
|
-
* - Validate paths are accessible
|
|
65
|
-
*
|
|
66
|
-
* ## Security
|
|
67
|
-
*
|
|
68
|
-
* **Path validation:**
|
|
69
|
-
* - All paths resolved relative to cwd
|
|
70
|
-
* - No symlink following by default
|
|
71
|
-
* - Directory traversal prevented
|
|
72
|
-
*
|
|
73
|
-
* **Permission checks:**
|
|
74
|
-
* - File must be readable
|
|
75
|
-
* - Working directory must exist
|
|
76
|
-
* - Errors returned for permission denied
|
|
77
|
-
*
|
|
78
|
-
* **Data safety:**
|
|
79
|
-
* - Large files truncated (not read into memory)
|
|
80
|
-
* - Binary files handled gracefully
|
|
81
|
-
* - No automatic execution of file contents
|
|
82
|
-
*
|
|
83
|
-
* ## Customization
|
|
84
|
-
*
|
|
85
|
-
* **Image Resizing:**
|
|
86
|
-
* ```typescript
|
|
87
|
-
* const tool = createReadTool(cwd, {
|
|
88
|
-
* autoResizeImages: true,
|
|
89
|
-
* imageMaxBytes: 500 * 1024, // 500KB limit
|
|
90
|
-
* });
|
|
91
|
-
* ```
|
|
92
|
-
*
|
|
93
|
-
* **Remote Execution (SSH):**
|
|
94
|
-
* ```typescript
|
|
95
|
-
* const sshTool = createReadTool(cwd, {
|
|
96
|
-
* operations: {
|
|
97
|
-
* readFile: (path) => sshExec(`cat ${path}`),
|
|
98
|
-
* access: (path) => sshExec(`test -r ${path}`),
|
|
99
|
-
* },
|
|
100
|
-
* });
|
|
101
|
-
* ```
|
|
102
|
-
*
|
|
103
|
-
* ## Examples
|
|
104
|
-
*
|
|
105
|
-
* ### Read a source file
|
|
106
|
-
* ```typescript
|
|
107
|
-
* // Agent calls: read {path: "src/main.ts"}
|
|
108
|
-
* // Returns: Full file content or truncated with temp file path
|
|
109
|
-
* ```
|
|
110
|
-
*
|
|
111
|
-
* ### Read specific lines
|
|
112
|
-
* ```typescript
|
|
113
|
-
* // Agent calls: read {path: "test.txt", offset: 10, limit: 5}
|
|
114
|
-
* // Returns: Lines 10-14
|
|
115
|
-
* ```
|
|
116
|
-
*
|
|
117
|
-
* ### Auto-resized image
|
|
118
|
-
* ```typescript
|
|
119
|
-
* // Agent calls: read {path: "diagram.png"}
|
|
120
|
-
* // Returns: Image content, resized if > 2MB, with dimensions
|
|
121
|
-
* ```
|
|
122
|
-
*
|
|
123
|
-
* ## Attribution
|
|
124
|
-
*
|
|
125
|
-
* Based on: indusagi-agent read tool
|
|
126
|
-
* Modifications:
|
|
127
|
-
* - Added image auto-detection and resizing
|
|
128
|
-
* - Added line-based offset/limit support
|
|
129
|
-
* - Added custom operations interface
|
|
130
|
-
* - Improved truncation handling
|
|
131
|
-
*/
|
|
132
|
-
import { Type } from "@sinclair/typebox";
|
|
133
|
-
import { constants } from "fs";
|
|
134
|
-
import { access as fsAccess, readFile as fsReadFile } from "fs/promises";
|
|
135
|
-
import { formatDimensionNote, resizeImage } from "../../utils/image-resize.js";
|
|
136
|
-
import { detectSupportedImageMimeTypeFromFile } from "../../utils/mime.js";
|
|
137
|
-
import { resolveReadPath } from "./path-utils.js";
|
|
138
|
-
import { DEFAULT_MAX_BYTES, DEFAULT_MAX_LINES, formatSize, truncateHead } from "./truncate.js";
|
|
139
|
-
// ============================================================================
|
|
140
|
-
// Schema & Types
|
|
141
|
-
// ============================================================================
|
|
142
|
-
/**
|
|
143
|
-
* JSON Schema for read tool parameters
|
|
144
|
-
* @internal
|
|
145
|
-
*/
|
|
146
|
-
const readSchema = Type.Object({
|
|
147
|
-
path: Type.String({ description: "Path to the file to read (relative or absolute)" }),
|
|
148
|
-
offset: Type.Optional(Type.Number({ description: "Line number to start reading from (1-indexed)" })),
|
|
149
|
-
limit: Type.Optional(Type.Number({ description: "Maximum number of lines to read" })),
|
|
150
|
-
});
|
|
151
|
-
/**
|
|
152
|
-
* Default read operations using local filesystem
|
|
153
|
-
* @internal
|
|
154
|
-
*/
|
|
155
|
-
const defaultReadOperations = {
|
|
156
|
-
readFile: (path) => fsReadFile(path),
|
|
157
|
-
access: (path) => fsAccess(path, constants.R_OK),
|
|
158
|
-
detectImageMimeType: detectSupportedImageMimeTypeFromFile,
|
|
159
|
-
};
|
|
160
|
-
// ============================================================================
|
|
161
|
-
// Tool Factory & Exports
|
|
162
|
-
// ============================================================================
|
|
163
|
-
/**
|
|
164
|
-
* Create a read tool with custom configuration
|
|
165
|
-
*
|
|
166
|
-
* Creates an AgentTool that can read files with:
|
|
167
|
-
* - Line-based offset and limit
|
|
168
|
-
* - Automatic image detection and resizing
|
|
169
|
-
* - Large file truncation
|
|
170
|
-
* - Remote execution support
|
|
171
|
-
* - Proper path resolution
|
|
172
|
-
*
|
|
173
|
-
* **Tool Behavior:**
|
|
174
|
-
* - Resolves paths relative to working directory
|
|
175
|
-
* - Prevents path traversal (no ../../../etc/passwd)
|
|
176
|
-
* - Detects images and handles specially
|
|
177
|
-
* - Truncates large files at head (keeps tail)
|
|
178
|
-
* - Returns truncation info for reference
|
|
179
|
-
*
|
|
180
|
-
* **Tool Parameters:**
|
|
181
|
-
* - `path` (required): File to read
|
|
182
|
-
* - `offset` (optional): Starting line (1-indexed)
|
|
183
|
-
* - `limit` (optional): Maximum lines to read
|
|
184
|
-
*
|
|
185
|
-
* **Tool Output:**
|
|
186
|
-
* - Text files: File content (possibly truncated)
|
|
187
|
-
* - Image files: Image data with metadata
|
|
188
|
-
* - Details: Truncation info if file was too large
|
|
189
|
-
*
|
|
190
|
-
* **Error Handling:**
|
|
191
|
-
* - File not found: Tool error "ENOENT: no such file"
|
|
192
|
-
* - Permission denied: Tool error "EACCES: permission denied"
|
|
193
|
-
* - Invalid path: Tool error "Path outside working directory"
|
|
194
|
-
* - Other errors: Tool error with message
|
|
195
|
-
*
|
|
196
|
-
* @param cwd - Working directory for relative path resolution
|
|
197
|
-
* - All relative paths resolved from this directory
|
|
198
|
-
* - Prevents directory traversal attacks
|
|
199
|
-
* - Can be overridden per execution
|
|
200
|
-
*
|
|
201
|
-
* @param options - Optional configuration
|
|
202
|
-
* - autoResizeImages: Enable/disable image resizing (default: true)
|
|
203
|
-
* - operations: Custom file reading backend (default: filesystem)
|
|
204
|
-
*
|
|
205
|
-
* @returns AgentTool instance ready to use
|
|
206
|
-
*
|
|
207
|
-
* @example
|
|
208
|
-
* ```typescript
|
|
209
|
-
* // Basic tool
|
|
210
|
-
* const tool = createReadTool(process.cwd());
|
|
211
|
-
*
|
|
212
|
-
* // With image resizing disabled
|
|
213
|
-
* const noResizeTool = createReadTool(cwd, {
|
|
214
|
-
* autoResizeImages: false,
|
|
215
|
-
* });
|
|
216
|
-
*
|
|
217
|
-
* // With remote backend (SSH)
|
|
218
|
-
* const remoteTool = createReadTool(cwd, {
|
|
219
|
-
* operations: sshOperations,
|
|
220
|
-
* });
|
|
221
|
-
* ```
|
|
222
|
-
*
|
|
223
|
-
* @see ReadToolOptions for detailed configuration
|
|
224
|
-
* @see ReadOperations for custom backend interface
|
|
225
|
-
*/
|
|
226
|
-
export function createReadTool(cwd, options) {
|
|
227
|
-
const autoResizeImages = options?.autoResizeImages ?? true;
|
|
228
|
-
const ops = options?.operations ?? defaultReadOperations;
|
|
229
|
-
return {
|
|
230
|
-
name: "read",
|
|
231
|
-
label: "read",
|
|
232
|
-
description: `Read the contents of a file. Supports text files and images (jpg, png, gif, webp). Images are sent as attachments. For text files, output is truncated to ${DEFAULT_MAX_LINES} lines or ${DEFAULT_MAX_BYTES / 1024}KB (whichever is hit first). Use offset/limit for large files. When you need the full file, continue with offset until complete.`,
|
|
233
|
-
parameters: readSchema,
|
|
234
|
-
execute: async (_toolCallId, { path, offset, limit }, signal) => {
|
|
235
|
-
const absolutePath = resolveReadPath(path, cwd);
|
|
236
|
-
return new Promise((resolve, reject) => {
|
|
237
|
-
// Check if already aborted
|
|
238
|
-
if (signal?.aborted) {
|
|
239
|
-
reject(new Error("Operation aborted"));
|
|
240
|
-
return;
|
|
241
|
-
}
|
|
242
|
-
let aborted = false;
|
|
243
|
-
// Set up abort handler
|
|
244
|
-
const onAbort = () => {
|
|
245
|
-
aborted = true;
|
|
246
|
-
reject(new Error("Operation aborted"));
|
|
247
|
-
};
|
|
248
|
-
if (signal) {
|
|
249
|
-
signal.addEventListener("abort", onAbort, { once: true });
|
|
250
|
-
}
|
|
251
|
-
// Perform the read operation
|
|
252
|
-
(async () => {
|
|
253
|
-
try {
|
|
254
|
-
// Check if file exists
|
|
255
|
-
await ops.access(absolutePath);
|
|
256
|
-
// Check if aborted before reading
|
|
257
|
-
if (aborted) {
|
|
258
|
-
return;
|
|
259
|
-
}
|
|
260
|
-
const mimeType = ops.detectImageMimeType ? await ops.detectImageMimeType(absolutePath) : undefined;
|
|
261
|
-
// Read the file based on type
|
|
262
|
-
let content;
|
|
263
|
-
let details;
|
|
264
|
-
if (mimeType) {
|
|
265
|
-
// Read as image (binary)
|
|
266
|
-
const buffer = await ops.readFile(absolutePath);
|
|
267
|
-
const base64 = buffer.toString("base64");
|
|
268
|
-
if (autoResizeImages) {
|
|
269
|
-
// Resize image if needed
|
|
270
|
-
const resized = await resizeImage({ type: "image", data: base64, mimeType });
|
|
271
|
-
const dimensionNote = formatDimensionNote(resized);
|
|
272
|
-
let textNote = `Read image file [${resized.mimeType}]`;
|
|
273
|
-
if (dimensionNote) {
|
|
274
|
-
textNote += `\n${dimensionNote}`;
|
|
275
|
-
}
|
|
276
|
-
content = [
|
|
277
|
-
{ type: "text", text: textNote },
|
|
278
|
-
{ type: "image", data: resized.data, mimeType: resized.mimeType },
|
|
279
|
-
];
|
|
280
|
-
}
|
|
281
|
-
else {
|
|
282
|
-
const textNote = `Read image file [${mimeType}]`;
|
|
283
|
-
content = [
|
|
284
|
-
{ type: "text", text: textNote },
|
|
285
|
-
{ type: "image", data: base64, mimeType },
|
|
286
|
-
];
|
|
287
|
-
}
|
|
288
|
-
}
|
|
289
|
-
else {
|
|
290
|
-
// Read as text
|
|
291
|
-
const buffer = await ops.readFile(absolutePath);
|
|
292
|
-
const textContent = buffer.toString("utf-8");
|
|
293
|
-
const allLines = textContent.split("\n");
|
|
294
|
-
const totalFileLines = allLines.length;
|
|
295
|
-
// Apply offset if specified (1-indexed to 0-indexed)
|
|
296
|
-
const startLine = offset ? Math.max(0, offset - 1) : 0;
|
|
297
|
-
const startLineDisplay = startLine + 1; // For display (1-indexed)
|
|
298
|
-
// Check if offset is out of bounds
|
|
299
|
-
if (startLine >= allLines.length) {
|
|
300
|
-
throw new Error(`Offset ${offset} is beyond end of file (${allLines.length} lines total)`);
|
|
301
|
-
}
|
|
302
|
-
// If limit is specified by user, use it; otherwise we'll let truncateHead decide
|
|
303
|
-
let selectedContent;
|
|
304
|
-
let userLimitedLines;
|
|
305
|
-
if (limit !== undefined) {
|
|
306
|
-
const endLine = Math.min(startLine + limit, allLines.length);
|
|
307
|
-
selectedContent = allLines.slice(startLine, endLine).join("\n");
|
|
308
|
-
userLimitedLines = endLine - startLine;
|
|
309
|
-
}
|
|
310
|
-
else {
|
|
311
|
-
selectedContent = allLines.slice(startLine).join("\n");
|
|
312
|
-
}
|
|
313
|
-
// Apply truncation (respects both line and byte limits)
|
|
314
|
-
const truncation = truncateHead(selectedContent);
|
|
315
|
-
let outputText;
|
|
316
|
-
if (truncation.firstLineExceedsLimit) {
|
|
317
|
-
// First line at offset exceeds 30KB - tell model to use bash
|
|
318
|
-
const firstLineSize = formatSize(Buffer.byteLength(allLines[startLine], "utf-8"));
|
|
319
|
-
outputText = `[Line ${startLineDisplay} is ${firstLineSize}, exceeds ${formatSize(DEFAULT_MAX_BYTES)} limit. Use bash: sed -n '${startLineDisplay}p' ${path} | head -c ${DEFAULT_MAX_BYTES}]`;
|
|
320
|
-
details = { truncation };
|
|
321
|
-
}
|
|
322
|
-
else if (truncation.truncated) {
|
|
323
|
-
// Truncation occurred - build actionable notice
|
|
324
|
-
const endLineDisplay = startLineDisplay + truncation.outputLines - 1;
|
|
325
|
-
const nextOffset = endLineDisplay + 1;
|
|
326
|
-
outputText = truncation.content;
|
|
327
|
-
if (truncation.truncatedBy === "lines") {
|
|
328
|
-
outputText += `\n\n[Showing lines ${startLineDisplay}-${endLineDisplay} of ${totalFileLines}. Use offset=${nextOffset} to continue.]`;
|
|
329
|
-
}
|
|
330
|
-
else {
|
|
331
|
-
outputText += `\n\n[Showing lines ${startLineDisplay}-${endLineDisplay} of ${totalFileLines} (${formatSize(DEFAULT_MAX_BYTES)} limit). Use offset=${nextOffset} to continue.]`;
|
|
332
|
-
}
|
|
333
|
-
details = { truncation };
|
|
334
|
-
}
|
|
335
|
-
else if (userLimitedLines !== undefined && startLine + userLimitedLines < allLines.length) {
|
|
336
|
-
// User specified limit, there's more content, but no truncation
|
|
337
|
-
const remaining = allLines.length - (startLine + userLimitedLines);
|
|
338
|
-
const nextOffset = startLine + userLimitedLines + 1;
|
|
339
|
-
outputText = truncation.content;
|
|
340
|
-
outputText += `\n\n[${remaining} more lines in file. Use offset=${nextOffset} to continue.]`;
|
|
341
|
-
}
|
|
342
|
-
else {
|
|
343
|
-
// No truncation, no user limit exceeded
|
|
344
|
-
outputText = truncation.content;
|
|
345
|
-
}
|
|
346
|
-
content = [{ type: "text", text: outputText }];
|
|
347
|
-
}
|
|
348
|
-
// Check if aborted after reading
|
|
349
|
-
if (aborted) {
|
|
350
|
-
return;
|
|
351
|
-
}
|
|
352
|
-
// Clean up abort handler
|
|
353
|
-
if (signal) {
|
|
354
|
-
signal.removeEventListener("abort", onAbort);
|
|
355
|
-
}
|
|
356
|
-
resolve({ content, details });
|
|
357
|
-
}
|
|
358
|
-
catch (error) {
|
|
359
|
-
// Clean up abort handler
|
|
360
|
-
if (signal) {
|
|
361
|
-
signal.removeEventListener("abort", onAbort);
|
|
362
|
-
}
|
|
363
|
-
if (!aborted) {
|
|
364
|
-
reject(error);
|
|
365
|
-
}
|
|
366
|
-
}
|
|
367
|
-
})();
|
|
368
|
-
});
|
|
369
|
-
},
|
|
370
|
-
};
|
|
371
|
-
}
|
|
372
|
-
/** Default read tool using process.cwd() - for backwards compatibility */
|
|
373
|
-
/**
|
|
374
|
-
* Default read tool instance
|
|
375
|
-
*
|
|
376
|
-
* Pre-created read tool using current process working directory.
|
|
377
|
-
* Supports line-based reading, image resizing, and truncation.
|
|
378
|
-
*
|
|
379
|
-
* Equivalent to:
|
|
380
|
-
* ```typescript
|
|
381
|
-
* const readTool = createReadTool(process.cwd(), {
|
|
382
|
-
* autoResizeImages: true,
|
|
383
|
-
* });
|
|
384
|
-
* ```
|
|
385
|
-
*
|
|
386
|
-
* For custom configuration or remote backends, use createReadTool() directly.
|
|
387
|
-
*
|
|
388
|
-
* @example
|
|
389
|
-
* ```typescript
|
|
390
|
-
* import { readTool } from "./tools/read.js";
|
|
391
|
-
* const agent = new Agent({ tools: [readTool] });
|
|
392
|
-
* ```
|
|
393
|
-
*
|
|
394
|
-
* @see createReadTool for custom configuration
|
|
395
|
-
*/
|
|
396
|
-
export const readTool = createReadTool(process.cwd());
|
|
397
|
-
//# sourceMappingURL=read.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"read.js","sourceRoot":"","sources":["../../../src/core/tools/read.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,70 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Shared truncation utilities for tool outputs.
|
|
3
|
-
*
|
|
4
|
-
* Truncation is based on two independent limits - whichever is hit first wins:
|
|
5
|
-
* - Line limit (default: 2000 lines)
|
|
6
|
-
* - Byte limit (default: 50KB)
|
|
7
|
-
*
|
|
8
|
-
* Never returns partial lines (except bash tail truncation edge case).
|
|
9
|
-
*/
|
|
10
|
-
export declare const DEFAULT_MAX_LINES = 2000;
|
|
11
|
-
export declare const DEFAULT_MAX_BYTES: number;
|
|
12
|
-
export declare const GREP_MAX_LINE_LENGTH = 500;
|
|
13
|
-
export interface TruncationResult {
|
|
14
|
-
/** The truncated content */
|
|
15
|
-
content: string;
|
|
16
|
-
/** Whether truncation occurred */
|
|
17
|
-
truncated: boolean;
|
|
18
|
-
/** Which limit was hit: "lines", "bytes", or null if not truncated */
|
|
19
|
-
truncatedBy: "lines" | "bytes" | null;
|
|
20
|
-
/** Total number of lines in the original content */
|
|
21
|
-
totalLines: number;
|
|
22
|
-
/** Total number of bytes in the original content */
|
|
23
|
-
totalBytes: number;
|
|
24
|
-
/** Number of complete lines in the truncated output */
|
|
25
|
-
outputLines: number;
|
|
26
|
-
/** Number of bytes in the truncated output */
|
|
27
|
-
outputBytes: number;
|
|
28
|
-
/** Whether the last line was partially truncated (only for tail truncation edge case) */
|
|
29
|
-
lastLinePartial: boolean;
|
|
30
|
-
/** Whether the first line exceeded the byte limit (for head truncation) */
|
|
31
|
-
firstLineExceedsLimit: boolean;
|
|
32
|
-
/** The max lines limit that was applied */
|
|
33
|
-
maxLines: number;
|
|
34
|
-
/** The max bytes limit that was applied */
|
|
35
|
-
maxBytes: number;
|
|
36
|
-
}
|
|
37
|
-
export interface TruncationOptions {
|
|
38
|
-
/** Maximum number of lines (default: 2000) */
|
|
39
|
-
maxLines?: number;
|
|
40
|
-
/** Maximum number of bytes (default: 50KB) */
|
|
41
|
-
maxBytes?: number;
|
|
42
|
-
}
|
|
43
|
-
/**
|
|
44
|
-
* Format bytes as human-readable size.
|
|
45
|
-
*/
|
|
46
|
-
export declare function formatSize(bytes: number): string;
|
|
47
|
-
/**
|
|
48
|
-
* Truncate content from the head (keep first N lines/bytes).
|
|
49
|
-
* Suitable for file reads where you want to see the beginning.
|
|
50
|
-
*
|
|
51
|
-
* Never returns partial lines. If first line exceeds byte limit,
|
|
52
|
-
* returns empty content with firstLineExceedsLimit=true.
|
|
53
|
-
*/
|
|
54
|
-
export declare function truncateHead(content: string, options?: TruncationOptions): TruncationResult;
|
|
55
|
-
/**
|
|
56
|
-
* Truncate content from the tail (keep last N lines/bytes).
|
|
57
|
-
* Suitable for bash output where you want to see the end (errors, final results).
|
|
58
|
-
*
|
|
59
|
-
* May return partial first line if the last line of original content exceeds byte limit.
|
|
60
|
-
*/
|
|
61
|
-
export declare function truncateTail(content: string, options?: TruncationOptions): TruncationResult;
|
|
62
|
-
/**
|
|
63
|
-
* Truncate a single line to max characters, adding [truncated] suffix.
|
|
64
|
-
* Used for grep match lines.
|
|
65
|
-
*/
|
|
66
|
-
export declare function truncateLine(line: string, maxChars?: number): {
|
|
67
|
-
text: string;
|
|
68
|
-
wasTruncated: boolean;
|
|
69
|
-
};
|
|
70
|
-
//# sourceMappingURL=truncate.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"truncate.d.ts","sourceRoot":"","sources":["../../../src/core/tools/truncate.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,eAAO,MAAM,iBAAiB,OAAO,CAAC;AACtC,eAAO,MAAM,iBAAiB,QAAY,CAAC;AAC3C,eAAO,MAAM,oBAAoB,MAAM,CAAC;AAExC,MAAM,WAAW,gBAAgB;IAChC,4BAA4B;IAC5B,OAAO,EAAE,MAAM,CAAC;IAChB,kCAAkC;IAClC,SAAS,EAAE,OAAO,CAAC;IACnB,sEAAsE;IACtE,WAAW,EAAE,OAAO,GAAG,OAAO,GAAG,IAAI,CAAC;IACtC,oDAAoD;IACpD,UAAU,EAAE,MAAM,CAAC;IACnB,oDAAoD;IACpD,UAAU,EAAE,MAAM,CAAC;IACnB,uDAAuD;IACvD,WAAW,EAAE,MAAM,CAAC;IACpB,8CAA8C;IAC9C,WAAW,EAAE,MAAM,CAAC;IACpB,yFAAyF;IACzF,eAAe,EAAE,OAAO,CAAC;IACzB,2EAA2E;IAC3E,qBAAqB,EAAE,OAAO,CAAC;IAC/B,2CAA2C;IAC3C,QAAQ,EAAE,MAAM,CAAC;IACjB,2CAA2C;IAC3C,QAAQ,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,iBAAiB;IACjC,8CAA8C;IAC9C,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,8CAA8C;IAC9C,QAAQ,CAAC,EAAE,MAAM,CAAC;CAClB;AAED;;GAEG;AACH,wBAAgB,UAAU,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAQhD;AAED;;;;;;GAMG;AACH,wBAAgB,YAAY,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,GAAE,iBAAsB,GAAG,gBAAgB,CAkF/F;AAED;;;;;GAKG;AACH,wBAAgB,YAAY,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,GAAE,iBAAsB,GAAG,gBAAgB,CAyE/F;AAuBD;;;GAGG;AACH,wBAAgB,YAAY,CAC3B,IAAI,EAAE,MAAM,EACZ,QAAQ,GAAE,MAA6B,GACrC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,YAAY,EAAE,OAAO,CAAA;CAAE,CAKzC"}
|
|
@@ -1,205 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Shared truncation utilities for tool outputs.
|
|
3
|
-
*
|
|
4
|
-
* Truncation is based on two independent limits - whichever is hit first wins:
|
|
5
|
-
* - Line limit (default: 2000 lines)
|
|
6
|
-
* - Byte limit (default: 50KB)
|
|
7
|
-
*
|
|
8
|
-
* Never returns partial lines (except bash tail truncation edge case).
|
|
9
|
-
*/
|
|
10
|
-
export const DEFAULT_MAX_LINES = 2000;
|
|
11
|
-
export const DEFAULT_MAX_BYTES = 50 * 1024; // 50KB
|
|
12
|
-
export const GREP_MAX_LINE_LENGTH = 500; // Max chars per grep match line
|
|
13
|
-
/**
|
|
14
|
-
* Format bytes as human-readable size.
|
|
15
|
-
*/
|
|
16
|
-
export function formatSize(bytes) {
|
|
17
|
-
if (bytes < 1024) {
|
|
18
|
-
return `${bytes}B`;
|
|
19
|
-
}
|
|
20
|
-
else if (bytes < 1024 * 1024) {
|
|
21
|
-
return `${(bytes / 1024).toFixed(1)}KB`;
|
|
22
|
-
}
|
|
23
|
-
else {
|
|
24
|
-
return `${(bytes / (1024 * 1024)).toFixed(1)}MB`;
|
|
25
|
-
}
|
|
26
|
-
}
|
|
27
|
-
/**
|
|
28
|
-
* Truncate content from the head (keep first N lines/bytes).
|
|
29
|
-
* Suitable for file reads where you want to see the beginning.
|
|
30
|
-
*
|
|
31
|
-
* Never returns partial lines. If first line exceeds byte limit,
|
|
32
|
-
* returns empty content with firstLineExceedsLimit=true.
|
|
33
|
-
*/
|
|
34
|
-
export function truncateHead(content, options = {}) {
|
|
35
|
-
const maxLines = options.maxLines ?? DEFAULT_MAX_LINES;
|
|
36
|
-
const maxBytes = options.maxBytes ?? DEFAULT_MAX_BYTES;
|
|
37
|
-
const totalBytes = Buffer.byteLength(content, "utf-8");
|
|
38
|
-
const lines = content.split("\n");
|
|
39
|
-
const totalLines = lines.length;
|
|
40
|
-
// Check if no truncation needed
|
|
41
|
-
if (totalLines <= maxLines && totalBytes <= maxBytes) {
|
|
42
|
-
return {
|
|
43
|
-
content,
|
|
44
|
-
truncated: false,
|
|
45
|
-
truncatedBy: null,
|
|
46
|
-
totalLines,
|
|
47
|
-
totalBytes,
|
|
48
|
-
outputLines: totalLines,
|
|
49
|
-
outputBytes: totalBytes,
|
|
50
|
-
lastLinePartial: false,
|
|
51
|
-
firstLineExceedsLimit: false,
|
|
52
|
-
maxLines,
|
|
53
|
-
maxBytes,
|
|
54
|
-
};
|
|
55
|
-
}
|
|
56
|
-
// Check if first line alone exceeds byte limit
|
|
57
|
-
const firstLineBytes = Buffer.byteLength(lines[0], "utf-8");
|
|
58
|
-
if (firstLineBytes > maxBytes) {
|
|
59
|
-
return {
|
|
60
|
-
content: "",
|
|
61
|
-
truncated: true,
|
|
62
|
-
truncatedBy: "bytes",
|
|
63
|
-
totalLines,
|
|
64
|
-
totalBytes,
|
|
65
|
-
outputLines: 0,
|
|
66
|
-
outputBytes: 0,
|
|
67
|
-
lastLinePartial: false,
|
|
68
|
-
firstLineExceedsLimit: true,
|
|
69
|
-
maxLines,
|
|
70
|
-
maxBytes,
|
|
71
|
-
};
|
|
72
|
-
}
|
|
73
|
-
// Collect complete lines that fit
|
|
74
|
-
const outputLinesArr = [];
|
|
75
|
-
let outputBytesCount = 0;
|
|
76
|
-
let truncatedBy = "lines";
|
|
77
|
-
for (let i = 0; i < lines.length && i < maxLines; i++) {
|
|
78
|
-
const line = lines[i];
|
|
79
|
-
const lineBytes = Buffer.byteLength(line, "utf-8") + (i > 0 ? 1 : 0); // +1 for newline
|
|
80
|
-
if (outputBytesCount + lineBytes > maxBytes) {
|
|
81
|
-
truncatedBy = "bytes";
|
|
82
|
-
break;
|
|
83
|
-
}
|
|
84
|
-
outputLinesArr.push(line);
|
|
85
|
-
outputBytesCount += lineBytes;
|
|
86
|
-
}
|
|
87
|
-
// If we exited due to line limit
|
|
88
|
-
if (outputLinesArr.length >= maxLines && outputBytesCount <= maxBytes) {
|
|
89
|
-
truncatedBy = "lines";
|
|
90
|
-
}
|
|
91
|
-
const outputContent = outputLinesArr.join("\n");
|
|
92
|
-
const finalOutputBytes = Buffer.byteLength(outputContent, "utf-8");
|
|
93
|
-
return {
|
|
94
|
-
content: outputContent,
|
|
95
|
-
truncated: true,
|
|
96
|
-
truncatedBy,
|
|
97
|
-
totalLines,
|
|
98
|
-
totalBytes,
|
|
99
|
-
outputLines: outputLinesArr.length,
|
|
100
|
-
outputBytes: finalOutputBytes,
|
|
101
|
-
lastLinePartial: false,
|
|
102
|
-
firstLineExceedsLimit: false,
|
|
103
|
-
maxLines,
|
|
104
|
-
maxBytes,
|
|
105
|
-
};
|
|
106
|
-
}
|
|
107
|
-
/**
|
|
108
|
-
* Truncate content from the tail (keep last N lines/bytes).
|
|
109
|
-
* Suitable for bash output where you want to see the end (errors, final results).
|
|
110
|
-
*
|
|
111
|
-
* May return partial first line if the last line of original content exceeds byte limit.
|
|
112
|
-
*/
|
|
113
|
-
export function truncateTail(content, options = {}) {
|
|
114
|
-
const maxLines = options.maxLines ?? DEFAULT_MAX_LINES;
|
|
115
|
-
const maxBytes = options.maxBytes ?? DEFAULT_MAX_BYTES;
|
|
116
|
-
const totalBytes = Buffer.byteLength(content, "utf-8");
|
|
117
|
-
const lines = content.split("\n");
|
|
118
|
-
const totalLines = lines.length;
|
|
119
|
-
// Check if no truncation needed
|
|
120
|
-
if (totalLines <= maxLines && totalBytes <= maxBytes) {
|
|
121
|
-
return {
|
|
122
|
-
content,
|
|
123
|
-
truncated: false,
|
|
124
|
-
truncatedBy: null,
|
|
125
|
-
totalLines,
|
|
126
|
-
totalBytes,
|
|
127
|
-
outputLines: totalLines,
|
|
128
|
-
outputBytes: totalBytes,
|
|
129
|
-
lastLinePartial: false,
|
|
130
|
-
firstLineExceedsLimit: false,
|
|
131
|
-
maxLines,
|
|
132
|
-
maxBytes,
|
|
133
|
-
};
|
|
134
|
-
}
|
|
135
|
-
// Work backwards from the end
|
|
136
|
-
const outputLinesArr = [];
|
|
137
|
-
let outputBytesCount = 0;
|
|
138
|
-
let truncatedBy = "lines";
|
|
139
|
-
let lastLinePartial = false;
|
|
140
|
-
for (let i = lines.length - 1; i >= 0 && outputLinesArr.length < maxLines; i--) {
|
|
141
|
-
const line = lines[i];
|
|
142
|
-
const lineBytes = Buffer.byteLength(line, "utf-8") + (outputLinesArr.length > 0 ? 1 : 0); // +1 for newline
|
|
143
|
-
if (outputBytesCount + lineBytes > maxBytes) {
|
|
144
|
-
truncatedBy = "bytes";
|
|
145
|
-
// Edge case: if we haven't added ANY lines yet and this line exceeds maxBytes,
|
|
146
|
-
// take the end of the line (partial)
|
|
147
|
-
if (outputLinesArr.length === 0) {
|
|
148
|
-
const truncatedLine = truncateStringToBytesFromEnd(line, maxBytes);
|
|
149
|
-
outputLinesArr.unshift(truncatedLine);
|
|
150
|
-
outputBytesCount = Buffer.byteLength(truncatedLine, "utf-8");
|
|
151
|
-
lastLinePartial = true;
|
|
152
|
-
}
|
|
153
|
-
break;
|
|
154
|
-
}
|
|
155
|
-
outputLinesArr.unshift(line);
|
|
156
|
-
outputBytesCount += lineBytes;
|
|
157
|
-
}
|
|
158
|
-
// If we exited due to line limit
|
|
159
|
-
if (outputLinesArr.length >= maxLines && outputBytesCount <= maxBytes) {
|
|
160
|
-
truncatedBy = "lines";
|
|
161
|
-
}
|
|
162
|
-
const outputContent = outputLinesArr.join("\n");
|
|
163
|
-
const finalOutputBytes = Buffer.byteLength(outputContent, "utf-8");
|
|
164
|
-
return {
|
|
165
|
-
content: outputContent,
|
|
166
|
-
truncated: true,
|
|
167
|
-
truncatedBy,
|
|
168
|
-
totalLines,
|
|
169
|
-
totalBytes,
|
|
170
|
-
outputLines: outputLinesArr.length,
|
|
171
|
-
outputBytes: finalOutputBytes,
|
|
172
|
-
lastLinePartial,
|
|
173
|
-
firstLineExceedsLimit: false,
|
|
174
|
-
maxLines,
|
|
175
|
-
maxBytes,
|
|
176
|
-
};
|
|
177
|
-
}
|
|
178
|
-
/**
|
|
179
|
-
* Truncate a string to fit within a byte limit (from the end).
|
|
180
|
-
* Handles multi-byte UTF-8 characters correctly.
|
|
181
|
-
*/
|
|
182
|
-
function truncateStringToBytesFromEnd(str, maxBytes) {
|
|
183
|
-
const buf = Buffer.from(str, "utf-8");
|
|
184
|
-
if (buf.length <= maxBytes) {
|
|
185
|
-
return str;
|
|
186
|
-
}
|
|
187
|
-
// Start from the end, skip maxBytes back
|
|
188
|
-
let start = buf.length - maxBytes;
|
|
189
|
-
// Find a valid UTF-8 boundary (start of a character)
|
|
190
|
-
while (start < buf.length && (buf[start] & 0xc0) === 0x80) {
|
|
191
|
-
start++;
|
|
192
|
-
}
|
|
193
|
-
return buf.slice(start).toString("utf-8");
|
|
194
|
-
}
|
|
195
|
-
/**
|
|
196
|
-
* Truncate a single line to max characters, adding [truncated] suffix.
|
|
197
|
-
* Used for grep match lines.
|
|
198
|
-
*/
|
|
199
|
-
export function truncateLine(line, maxChars = GREP_MAX_LINE_LENGTH) {
|
|
200
|
-
if (line.length <= maxChars) {
|
|
201
|
-
return { text: line, wasTruncated: false };
|
|
202
|
-
}
|
|
203
|
-
return { text: `${line.slice(0, maxChars)}... [truncated]`, wasTruncated: true };
|
|
204
|
-
}
|
|
205
|
-
//# sourceMappingURL=truncate.js.map
|