@animus-labs/cortex 0.2.0
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/LICENSE +21 -0
- package/README.md +73 -0
- package/dist/budget-guard.d.ts +75 -0
- package/dist/budget-guard.d.ts.map +1 -0
- package/dist/budget-guard.js +142 -0
- package/dist/budget-guard.js.map +1 -0
- package/dist/compaction/compaction.d.ts +99 -0
- package/dist/compaction/compaction.d.ts.map +1 -0
- package/dist/compaction/compaction.js +302 -0
- package/dist/compaction/compaction.js.map +1 -0
- package/dist/compaction/failsafe.d.ts +57 -0
- package/dist/compaction/failsafe.d.ts.map +1 -0
- package/dist/compaction/failsafe.js +135 -0
- package/dist/compaction/failsafe.js.map +1 -0
- package/dist/compaction/index.d.ts +381 -0
- package/dist/compaction/index.d.ts.map +1 -0
- package/dist/compaction/index.js +979 -0
- package/dist/compaction/index.js.map +1 -0
- package/dist/compaction/microcompaction.d.ts +219 -0
- package/dist/compaction/microcompaction.d.ts.map +1 -0
- package/dist/compaction/microcompaction.js +536 -0
- package/dist/compaction/microcompaction.js.map +1 -0
- package/dist/compaction/observational/buffering.d.ts +225 -0
- package/dist/compaction/observational/buffering.d.ts.map +1 -0
- package/dist/compaction/observational/buffering.js +354 -0
- package/dist/compaction/observational/buffering.js.map +1 -0
- package/dist/compaction/observational/constants.d.ts +70 -0
- package/dist/compaction/observational/constants.d.ts.map +1 -0
- package/dist/compaction/observational/constants.js +507 -0
- package/dist/compaction/observational/constants.js.map +1 -0
- package/dist/compaction/observational/index.d.ts +219 -0
- package/dist/compaction/observational/index.d.ts.map +1 -0
- package/dist/compaction/observational/index.js +641 -0
- package/dist/compaction/observational/index.js.map +1 -0
- package/dist/compaction/observational/observer.d.ts +97 -0
- package/dist/compaction/observational/observer.d.ts.map +1 -0
- package/dist/compaction/observational/observer.js +424 -0
- package/dist/compaction/observational/observer.js.map +1 -0
- package/dist/compaction/observational/recall-tool.d.ts +27 -0
- package/dist/compaction/observational/recall-tool.d.ts.map +1 -0
- package/dist/compaction/observational/recall-tool.js +93 -0
- package/dist/compaction/observational/recall-tool.js.map +1 -0
- package/dist/compaction/observational/reflector.d.ts +94 -0
- package/dist/compaction/observational/reflector.d.ts.map +1 -0
- package/dist/compaction/observational/reflector.js +167 -0
- package/dist/compaction/observational/reflector.js.map +1 -0
- package/dist/compaction/observational/types.d.ts +271 -0
- package/dist/compaction/observational/types.d.ts.map +1 -0
- package/dist/compaction/observational/types.js +15 -0
- package/dist/compaction/observational/types.js.map +1 -0
- package/dist/context-manager.d.ts +134 -0
- package/dist/context-manager.d.ts.map +1 -0
- package/dist/context-manager.js +170 -0
- package/dist/context-manager.js.map +1 -0
- package/dist/cortex-agent.d.ts +1020 -0
- package/dist/cortex-agent.d.ts.map +1 -0
- package/dist/cortex-agent.js +3589 -0
- package/dist/cortex-agent.js.map +1 -0
- package/dist/error-classifier.d.ts +48 -0
- package/dist/error-classifier.d.ts.map +1 -0
- package/dist/error-classifier.js +152 -0
- package/dist/error-classifier.js.map +1 -0
- package/dist/event-bridge.d.ts +166 -0
- package/dist/event-bridge.d.ts.map +1 -0
- package/dist/event-bridge.js +381 -0
- package/dist/event-bridge.js.map +1 -0
- package/dist/index.d.ts +55 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +57 -0
- package/dist/index.js.map +1 -0
- package/dist/mcp-client.d.ts +119 -0
- package/dist/mcp-client.d.ts.map +1 -0
- package/dist/mcp-client.js +474 -0
- package/dist/mcp-client.js.map +1 -0
- package/dist/model-wrapper.d.ts +58 -0
- package/dist/model-wrapper.d.ts.map +1 -0
- package/dist/model-wrapper.js +86 -0
- package/dist/model-wrapper.js.map +1 -0
- package/dist/noop-logger.d.ts +4 -0
- package/dist/noop-logger.d.ts.map +1 -0
- package/dist/noop-logger.js +8 -0
- package/dist/noop-logger.js.map +1 -0
- package/dist/prompt-diagnostics.d.ts +47 -0
- package/dist/prompt-diagnostics.d.ts.map +1 -0
- package/dist/prompt-diagnostics.js +230 -0
- package/dist/prompt-diagnostics.js.map +1 -0
- package/dist/provider-manager.d.ts +224 -0
- package/dist/provider-manager.d.ts.map +1 -0
- package/dist/provider-manager.js +563 -0
- package/dist/provider-manager.js.map +1 -0
- package/dist/provider-registry.d.ts +115 -0
- package/dist/provider-registry.d.ts.map +1 -0
- package/dist/provider-registry.js +305 -0
- package/dist/provider-registry.js.map +1 -0
- package/dist/schema-converter.d.ts +20 -0
- package/dist/schema-converter.d.ts.map +1 -0
- package/dist/schema-converter.js +48 -0
- package/dist/schema-converter.js.map +1 -0
- package/dist/skill-preprocessor.d.ts +46 -0
- package/dist/skill-preprocessor.d.ts.map +1 -0
- package/dist/skill-preprocessor.js +237 -0
- package/dist/skill-preprocessor.js.map +1 -0
- package/dist/skill-registry.d.ts +107 -0
- package/dist/skill-registry.d.ts.map +1 -0
- package/dist/skill-registry.js +330 -0
- package/dist/skill-registry.js.map +1 -0
- package/dist/skill-tool.d.ts +54 -0
- package/dist/skill-tool.d.ts.map +1 -0
- package/dist/skill-tool.js +88 -0
- package/dist/skill-tool.js.map +1 -0
- package/dist/sub-agent-manager.d.ts +90 -0
- package/dist/sub-agent-manager.d.ts.map +1 -0
- package/dist/sub-agent-manager.js +192 -0
- package/dist/sub-agent-manager.js.map +1 -0
- package/dist/token-estimator.d.ts +23 -0
- package/dist/token-estimator.d.ts.map +1 -0
- package/dist/token-estimator.js +27 -0
- package/dist/token-estimator.js.map +1 -0
- package/dist/tool-contract.d.ts +68 -0
- package/dist/tool-contract.d.ts.map +1 -0
- package/dist/tool-contract.js +35 -0
- package/dist/tool-contract.js.map +1 -0
- package/dist/tool-result-persistence.d.ts +89 -0
- package/dist/tool-result-persistence.d.ts.map +1 -0
- package/dist/tool-result-persistence.js +152 -0
- package/dist/tool-result-persistence.js.map +1 -0
- package/dist/tools/bash/index.d.ts +71 -0
- package/dist/tools/bash/index.d.ts.map +1 -0
- package/dist/tools/bash/index.js +485 -0
- package/dist/tools/bash/index.js.map +1 -0
- package/dist/tools/bash/interactive.d.ts +47 -0
- package/dist/tools/bash/interactive.d.ts.map +1 -0
- package/dist/tools/bash/interactive.js +262 -0
- package/dist/tools/bash/interactive.js.map +1 -0
- package/dist/tools/bash/safety.d.ts +149 -0
- package/dist/tools/bash/safety.d.ts.map +1 -0
- package/dist/tools/bash/safety.js +1116 -0
- package/dist/tools/bash/safety.js.map +1 -0
- package/dist/tools/edit.d.ts +57 -0
- package/dist/tools/edit.d.ts.map +1 -0
- package/dist/tools/edit.js +310 -0
- package/dist/tools/edit.js.map +1 -0
- package/dist/tools/glob.d.ts +34 -0
- package/dist/tools/glob.d.ts.map +1 -0
- package/dist/tools/glob.js +268 -0
- package/dist/tools/glob.js.map +1 -0
- package/dist/tools/grep.d.ts +53 -0
- package/dist/tools/grep.d.ts.map +1 -0
- package/dist/tools/grep.js +673 -0
- package/dist/tools/grep.js.map +1 -0
- package/dist/tools/index.d.ts +62 -0
- package/dist/tools/index.d.ts.map +1 -0
- package/dist/tools/index.js +52 -0
- package/dist/tools/index.js.map +1 -0
- package/dist/tools/read.d.ts +43 -0
- package/dist/tools/read.d.ts.map +1 -0
- package/dist/tools/read.js +459 -0
- package/dist/tools/read.js.map +1 -0
- package/dist/tools/runtime.d.ts +62 -0
- package/dist/tools/runtime.d.ts.map +1 -0
- package/dist/tools/runtime.js +116 -0
- package/dist/tools/runtime.js.map +1 -0
- package/dist/tools/shared/cwd-tracker.d.ts +32 -0
- package/dist/tools/shared/cwd-tracker.d.ts.map +1 -0
- package/dist/tools/shared/cwd-tracker.js +44 -0
- package/dist/tools/shared/cwd-tracker.js.map +1 -0
- package/dist/tools/shared/edit-history.d.ts +55 -0
- package/dist/tools/shared/edit-history.d.ts.map +1 -0
- package/dist/tools/shared/edit-history.js +72 -0
- package/dist/tools/shared/edit-history.js.map +1 -0
- package/dist/tools/shared/edit-matcher.d.ts +83 -0
- package/dist/tools/shared/edit-matcher.d.ts.map +1 -0
- package/dist/tools/shared/edit-matcher.js +359 -0
- package/dist/tools/shared/edit-matcher.js.map +1 -0
- package/dist/tools/shared/file-mutation-lock.d.ts +22 -0
- package/dist/tools/shared/file-mutation-lock.d.ts.map +1 -0
- package/dist/tools/shared/file-mutation-lock.js +35 -0
- package/dist/tools/shared/file-mutation-lock.js.map +1 -0
- package/dist/tools/shared/gitignore.d.ts +17 -0
- package/dist/tools/shared/gitignore.d.ts.map +1 -0
- package/dist/tools/shared/gitignore.js +59 -0
- package/dist/tools/shared/gitignore.js.map +1 -0
- package/dist/tools/shared/pdf-extractor.d.ts +96 -0
- package/dist/tools/shared/pdf-extractor.d.ts.map +1 -0
- package/dist/tools/shared/pdf-extractor.js +196 -0
- package/dist/tools/shared/pdf-extractor.js.map +1 -0
- package/dist/tools/shared/read-registry.d.ts +66 -0
- package/dist/tools/shared/read-registry.d.ts.map +1 -0
- package/dist/tools/shared/read-registry.js +65 -0
- package/dist/tools/shared/read-registry.js.map +1 -0
- package/dist/tools/shared/safe-env.d.ts +18 -0
- package/dist/tools/shared/safe-env.d.ts.map +1 -0
- package/dist/tools/shared/safe-env.js +70 -0
- package/dist/tools/shared/safe-env.js.map +1 -0
- package/dist/tools/sub-agent.d.ts +91 -0
- package/dist/tools/sub-agent.d.ts.map +1 -0
- package/dist/tools/sub-agent.js +89 -0
- package/dist/tools/sub-agent.js.map +1 -0
- package/dist/tools/task-output.d.ts +38 -0
- package/dist/tools/task-output.d.ts.map +1 -0
- package/dist/tools/task-output.js +186 -0
- package/dist/tools/task-output.js.map +1 -0
- package/dist/tools/tool-search/index.d.ts +40 -0
- package/dist/tools/tool-search/index.d.ts.map +1 -0
- package/dist/tools/tool-search/index.js +110 -0
- package/dist/tools/tool-search/index.js.map +1 -0
- package/dist/tools/tool-search/registry.d.ts +82 -0
- package/dist/tools/tool-search/registry.d.ts.map +1 -0
- package/dist/tools/tool-search/registry.js +238 -0
- package/dist/tools/tool-search/registry.js.map +1 -0
- package/dist/tools/undo-edit.d.ts +51 -0
- package/dist/tools/undo-edit.d.ts.map +1 -0
- package/dist/tools/undo-edit.js +231 -0
- package/dist/tools/undo-edit.js.map +1 -0
- package/dist/tools/web-fetch/cache.d.ts +49 -0
- package/dist/tools/web-fetch/cache.d.ts.map +1 -0
- package/dist/tools/web-fetch/cache.js +89 -0
- package/dist/tools/web-fetch/cache.js.map +1 -0
- package/dist/tools/web-fetch/index.d.ts +53 -0
- package/dist/tools/web-fetch/index.d.ts.map +1 -0
- package/dist/tools/web-fetch/index.js +513 -0
- package/dist/tools/web-fetch/index.js.map +1 -0
- package/dist/tools/write.d.ts +59 -0
- package/dist/tools/write.d.ts.map +1 -0
- package/dist/tools/write.js +316 -0
- package/dist/tools/write.js.map +1 -0
- package/dist/types.d.ts +881 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +16 -0
- package/dist/types.js.map +1 -0
- package/dist/working-tags.d.ts +44 -0
- package/dist/working-tags.d.ts.map +1 -0
- package/dist/working-tags.js +103 -0
- package/dist/working-tags.js.map +1 -0
- package/package.json +87 -0
- package/src/budget-guard.ts +170 -0
- package/src/compaction/compaction.ts +386 -0
- package/src/compaction/failsafe.ts +185 -0
- package/src/compaction/index.ts +1199 -0
- package/src/compaction/microcompaction.ts +709 -0
- package/src/compaction/observational/buffering.ts +430 -0
- package/src/compaction/observational/constants.ts +532 -0
- package/src/compaction/observational/index.ts +837 -0
- package/src/compaction/observational/observer.ts +510 -0
- package/src/compaction/observational/recall-tool.ts +130 -0
- package/src/compaction/observational/reflector.ts +221 -0
- package/src/compaction/observational/types.ts +343 -0
- package/src/context-manager.ts +237 -0
- package/src/cortex-agent.ts +4297 -0
- package/src/error-classifier.ts +199 -0
- package/src/event-bridge.ts +508 -0
- package/src/index.ts +292 -0
- package/src/mcp-client.ts +582 -0
- package/src/model-wrapper.ts +128 -0
- package/src/noop-logger.ts +9 -0
- package/src/prompt-diagnostics.ts +296 -0
- package/src/provider-manager.ts +823 -0
- package/src/provider-registry.ts +386 -0
- package/src/schema-converter.ts +51 -0
- package/src/skill-preprocessor.ts +314 -0
- package/src/skill-registry.ts +378 -0
- package/src/skill-tool.ts +130 -0
- package/src/sub-agent-manager.ts +236 -0
- package/src/token-estimator.ts +26 -0
- package/src/tool-contract.ts +113 -0
- package/src/tool-result-persistence.ts +197 -0
- package/src/tools/bash/index.ts +633 -0
- package/src/tools/bash/interactive.ts +302 -0
- package/src/tools/bash/safety.ts +1297 -0
- package/src/tools/edit.ts +422 -0
- package/src/tools/glob.ts +330 -0
- package/src/tools/grep.ts +819 -0
- package/src/tools/index.ts +110 -0
- package/src/tools/read.ts +580 -0
- package/src/tools/runtime.ts +173 -0
- package/src/tools/shared/cwd-tracker.ts +50 -0
- package/src/tools/shared/edit-history.ts +96 -0
- package/src/tools/shared/edit-matcher.ts +457 -0
- package/src/tools/shared/file-mutation-lock.ts +40 -0
- package/src/tools/shared/gitignore.ts +61 -0
- package/src/tools/shared/pdf-extractor.ts +290 -0
- package/src/tools/shared/read-registry.ts +93 -0
- package/src/tools/shared/safe-env.ts +82 -0
- package/src/tools/sub-agent.ts +171 -0
- package/src/tools/task-output.ts +236 -0
- package/src/tools/tool-search/index.ts +167 -0
- package/src/tools/tool-search/registry.ts +278 -0
- package/src/tools/undo-edit.ts +314 -0
- package/src/tools/web-fetch/cache.ts +112 -0
- package/src/tools/web-fetch/index.ts +604 -0
- package/src/tools/write.ts +385 -0
- package/src/types.ts +1057 -0
- package/src/working-tags.ts +118 -0
|
@@ -0,0 +1,459 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Read tool: read file contents from the local filesystem.
|
|
3
|
+
*
|
|
4
|
+
* Returns file content with line numbers in `cat -n` format.
|
|
5
|
+
* Handles text files, images (base64 ImageContent), and
|
|
6
|
+
* detects binary files.
|
|
7
|
+
*
|
|
8
|
+
* Reference: docs/cortex/tools/read.md
|
|
9
|
+
*/
|
|
10
|
+
import * as crypto from 'node:crypto';
|
|
11
|
+
import * as fs from 'node:fs';
|
|
12
|
+
import * as path from 'node:path';
|
|
13
|
+
import { Type } from 'typebox';
|
|
14
|
+
import { attachRuntimeAwareTool } from './runtime.js';
|
|
15
|
+
import { estimateTokens } from '../token-estimator.js';
|
|
16
|
+
import { extractPdfText } from './shared/pdf-extractor.js';
|
|
17
|
+
// ---------------------------------------------------------------------------
|
|
18
|
+
// Schema
|
|
19
|
+
// ---------------------------------------------------------------------------
|
|
20
|
+
export const ReadParams = Type.Object({
|
|
21
|
+
file_path: Type.String({ description: 'Absolute path to the file to read' }),
|
|
22
|
+
offset: Type.Optional(Type.Number({ description: 'Line number to start reading from (1-based). Only provide if the file is too large to read at once.' })),
|
|
23
|
+
limit: Type.Optional(Type.Number({ description: 'Maximum number of lines to read. Only provide if the file is too large to read at once.' })),
|
|
24
|
+
pages: Type.Optional(Type.String({ description: 'Page range for PDF files (e.g., "1-5", "3", "10-20"). Only applicable to PDF files. Max 20 pages per request.' })),
|
|
25
|
+
});
|
|
26
|
+
// ---------------------------------------------------------------------------
|
|
27
|
+
// Constants
|
|
28
|
+
// ---------------------------------------------------------------------------
|
|
29
|
+
const DEFAULT_LIMIT = 2000;
|
|
30
|
+
const MAX_LINE_LENGTH = 2000;
|
|
31
|
+
/** Pre-read gate for full reads (no offset/limit provided). */
|
|
32
|
+
const MAX_FULL_READ_BYTES = 256 * 1024; // 256 KB
|
|
33
|
+
/** Hard ceiling even with offset/limit. Beyond this, use Bash. */
|
|
34
|
+
const MAX_READABLE_BYTES = 10 * 1024 * 1024; // 10 MB
|
|
35
|
+
/** Post-read token ceiling on formatted output. */
|
|
36
|
+
const MAX_OUTPUT_TOKENS = 25_000;
|
|
37
|
+
const IMAGE_EXTENSIONS = new Set(['.png', '.jpg', '.jpeg', '.gif', '.webp']);
|
|
38
|
+
const IMAGE_MIME_TYPES = {
|
|
39
|
+
'.png': 'image/png',
|
|
40
|
+
'.jpg': 'image/jpeg',
|
|
41
|
+
'.jpeg': 'image/jpeg',
|
|
42
|
+
'.gif': 'image/gif',
|
|
43
|
+
'.webp': 'image/webp',
|
|
44
|
+
};
|
|
45
|
+
/**
|
|
46
|
+
* Device files that would hang the process: infinite output or blocking input.
|
|
47
|
+
* Checked by path only (no I/O).
|
|
48
|
+
*/
|
|
49
|
+
const BLOCKED_DEVICE_PATHS = new Set([
|
|
50
|
+
// Infinite output
|
|
51
|
+
'/dev/zero',
|
|
52
|
+
'/dev/random',
|
|
53
|
+
'/dev/urandom',
|
|
54
|
+
'/dev/full',
|
|
55
|
+
// Blocks waiting for input
|
|
56
|
+
'/dev/stdin',
|
|
57
|
+
'/dev/tty',
|
|
58
|
+
'/dev/console',
|
|
59
|
+
// Nonsensical to read
|
|
60
|
+
'/dev/stdout',
|
|
61
|
+
'/dev/stderr',
|
|
62
|
+
// fd aliases for stdin/stdout/stderr
|
|
63
|
+
'/dev/fd/0',
|
|
64
|
+
'/dev/fd/1',
|
|
65
|
+
'/dev/fd/2',
|
|
66
|
+
]);
|
|
67
|
+
function isBlockedDevicePath(filePath) {
|
|
68
|
+
if (BLOCKED_DEVICE_PATHS.has(filePath))
|
|
69
|
+
return true;
|
|
70
|
+
// /proc/self/fd/0-2 and /proc/<pid>/fd/0-2 are Linux aliases for stdio
|
|
71
|
+
if (filePath.startsWith('/proc/') &&
|
|
72
|
+
(filePath.endsWith('/fd/0') ||
|
|
73
|
+
filePath.endsWith('/fd/1') ||
|
|
74
|
+
filePath.endsWith('/fd/2')))
|
|
75
|
+
return true;
|
|
76
|
+
return false;
|
|
77
|
+
}
|
|
78
|
+
// ---------------------------------------------------------------------------
|
|
79
|
+
// Helpers
|
|
80
|
+
// ---------------------------------------------------------------------------
|
|
81
|
+
/**
|
|
82
|
+
* Detect if a buffer contains binary content.
|
|
83
|
+
* A file is considered binary if it contains null bytes in the first 8KB.
|
|
84
|
+
*/
|
|
85
|
+
function isBinaryBuffer(buffer) {
|
|
86
|
+
const checkLength = Math.min(buffer.length, 8192);
|
|
87
|
+
for (let i = 0; i < checkLength; i++) {
|
|
88
|
+
if (buffer[i] === 0) {
|
|
89
|
+
return true;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
return false;
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Try to detect and decode file content with common encodings.
|
|
96
|
+
* Handles UTF-8, UTF-16 LE/BE (via BOM), and falls back to Latin-1.
|
|
97
|
+
*/
|
|
98
|
+
function decodeFileContent(buffer) {
|
|
99
|
+
// Check for UTF-16 BOM
|
|
100
|
+
if (buffer.length >= 2) {
|
|
101
|
+
if (buffer[0] === 0xff && buffer[1] === 0xfe) {
|
|
102
|
+
return buffer.toString('utf16le');
|
|
103
|
+
}
|
|
104
|
+
if (buffer[0] === 0xfe && buffer[1] === 0xff) {
|
|
105
|
+
// UTF-16 BE: swap bytes and decode as UTF-16 LE
|
|
106
|
+
const swapped = Buffer.alloc(buffer.length);
|
|
107
|
+
for (let i = 0; i < buffer.length - 1; i += 2) {
|
|
108
|
+
swapped[i] = buffer[i + 1];
|
|
109
|
+
swapped[i + 1] = buffer[i];
|
|
110
|
+
}
|
|
111
|
+
return swapped.toString('utf16le');
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
// Check for UTF-8 BOM
|
|
115
|
+
if (buffer.length >= 3 && buffer[0] === 0xef && buffer[1] === 0xbb && buffer[2] === 0xbf) {
|
|
116
|
+
return buffer.toString('utf8').slice(1); // Skip the BOM character
|
|
117
|
+
}
|
|
118
|
+
// Try UTF-8 first (most common)
|
|
119
|
+
const utf8 = buffer.toString('utf8');
|
|
120
|
+
// Check for replacement characters that suggest bad UTF-8 decoding
|
|
121
|
+
// Only fall back to Latin-1 if there are many replacement chars
|
|
122
|
+
const replacementCount = (utf8.match(/\ufffd/g) ?? []).length;
|
|
123
|
+
if (replacementCount > 0 && replacementCount > buffer.length * 0.01) {
|
|
124
|
+
return buffer.toString('latin1');
|
|
125
|
+
}
|
|
126
|
+
return utf8;
|
|
127
|
+
}
|
|
128
|
+
/**
|
|
129
|
+
* Format lines with `cat -n` style line numbers.
|
|
130
|
+
* Format: spaces + line_number + tab + content
|
|
131
|
+
*/
|
|
132
|
+
function formatWithLineNumbers(lines, startLine) {
|
|
133
|
+
const maxLineNum = startLine + lines.length - 1;
|
|
134
|
+
const width = String(maxLineNum).length;
|
|
135
|
+
return lines
|
|
136
|
+
.map((line, i) => {
|
|
137
|
+
const lineNum = startLine + i;
|
|
138
|
+
const paddedNum = String(lineNum).padStart(width + 2);
|
|
139
|
+
// Truncate long lines
|
|
140
|
+
const truncatedLine = line.length > MAX_LINE_LENGTH
|
|
141
|
+
? line.slice(0, MAX_LINE_LENGTH) + '... [truncated]'
|
|
142
|
+
: line;
|
|
143
|
+
return `${paddedNum}\t${truncatedLine}`;
|
|
144
|
+
})
|
|
145
|
+
.join('\n');
|
|
146
|
+
}
|
|
147
|
+
/**
|
|
148
|
+
* Format byte count as a human-readable string (KB or MB).
|
|
149
|
+
*/
|
|
150
|
+
function formatBytes(bytes) {
|
|
151
|
+
if (bytes >= 1024 * 1024) {
|
|
152
|
+
return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
|
|
153
|
+
}
|
|
154
|
+
return `${Math.round(bytes / 1024)} KB`;
|
|
155
|
+
}
|
|
156
|
+
/**
|
|
157
|
+
* Build a rejection result for size/token gate failures.
|
|
158
|
+
* Returns an error message as tool content with `rejected: true` in details.
|
|
159
|
+
*/
|
|
160
|
+
function makeRejection(filePath, byteSize, message) {
|
|
161
|
+
return {
|
|
162
|
+
content: [{ type: 'text', text: message }],
|
|
163
|
+
details: {
|
|
164
|
+
filePath,
|
|
165
|
+
totalLines: 0,
|
|
166
|
+
byteSize,
|
|
167
|
+
truncated: false,
|
|
168
|
+
truncatedLines: false,
|
|
169
|
+
truncatedChars: false,
|
|
170
|
+
startLine: 1,
|
|
171
|
+
rejected: true,
|
|
172
|
+
},
|
|
173
|
+
};
|
|
174
|
+
}
|
|
175
|
+
// ---------------------------------------------------------------------------
|
|
176
|
+
// Tool factory
|
|
177
|
+
// ---------------------------------------------------------------------------
|
|
178
|
+
export function createReadTool(config) {
|
|
179
|
+
const readRegistry = config.runtime?.readRegistry ?? config.readRegistry;
|
|
180
|
+
if (!readRegistry) {
|
|
181
|
+
throw new Error('createReadTool requires either runtime or readRegistry');
|
|
182
|
+
}
|
|
183
|
+
const tool = {
|
|
184
|
+
name: 'Read',
|
|
185
|
+
description: [
|
|
186
|
+
'Read file contents from the local filesystem.',
|
|
187
|
+
'Returns content with line numbers in cat -n format.',
|
|
188
|
+
'',
|
|
189
|
+
'Size limits:',
|
|
190
|
+
`- Files up to ${formatBytes(MAX_FULL_READ_BYTES)}: read in full (no offset/limit needed)`,
|
|
191
|
+
`- Files ${formatBytes(MAX_FULL_READ_BYTES)} to ${formatBytes(MAX_READABLE_BYTES)}: must provide offset and limit`,
|
|
192
|
+
`- Files over ${formatBytes(MAX_READABLE_BYTES)}: use Bash (head, tail, sed) instead`,
|
|
193
|
+
`- Output capped at ~${MAX_OUTPUT_TOKENS.toLocaleString()} tokens; reduce limit if exceeded`,
|
|
194
|
+
'',
|
|
195
|
+
'For searching file contents, use Grep instead of reading the whole file.',
|
|
196
|
+
].join('\n'),
|
|
197
|
+
parameters: ReadParams,
|
|
198
|
+
async execute(params) {
|
|
199
|
+
const filePath = path.resolve(params.file_path);
|
|
200
|
+
const offset = params.offset ?? 1;
|
|
201
|
+
const limit = params.limit ?? DEFAULT_LIMIT;
|
|
202
|
+
// Block device paths that would hang (infinite output or blocking input)
|
|
203
|
+
if (isBlockedDevicePath(filePath)) {
|
|
204
|
+
return {
|
|
205
|
+
content: [{ type: 'text', text: `Cannot read '${params.file_path}': this device file would block or produce infinite output.` }],
|
|
206
|
+
details: {
|
|
207
|
+
filePath,
|
|
208
|
+
totalLines: 0,
|
|
209
|
+
byteSize: 0,
|
|
210
|
+
truncated: false,
|
|
211
|
+
truncatedLines: false,
|
|
212
|
+
truncatedChars: false,
|
|
213
|
+
startLine: 1,
|
|
214
|
+
},
|
|
215
|
+
};
|
|
216
|
+
}
|
|
217
|
+
// Check if path exists
|
|
218
|
+
let stat;
|
|
219
|
+
try {
|
|
220
|
+
stat = await fs.promises.stat(filePath);
|
|
221
|
+
}
|
|
222
|
+
catch (err) {
|
|
223
|
+
const code = err.code;
|
|
224
|
+
if (code === 'ENOENT') {
|
|
225
|
+
return {
|
|
226
|
+
content: [{ type: 'text', text: `File does not exist: ${filePath}` }],
|
|
227
|
+
details: {
|
|
228
|
+
filePath,
|
|
229
|
+
totalLines: 0,
|
|
230
|
+
byteSize: 0,
|
|
231
|
+
truncated: false,
|
|
232
|
+
truncatedLines: false,
|
|
233
|
+
truncatedChars: false,
|
|
234
|
+
startLine: 1,
|
|
235
|
+
},
|
|
236
|
+
};
|
|
237
|
+
}
|
|
238
|
+
if (code === 'EACCES') {
|
|
239
|
+
return {
|
|
240
|
+
content: [{ type: 'text', text: `Permission denied: ${filePath}` }],
|
|
241
|
+
details: {
|
|
242
|
+
filePath,
|
|
243
|
+
totalLines: 0,
|
|
244
|
+
byteSize: 0,
|
|
245
|
+
truncated: false,
|
|
246
|
+
truncatedLines: false,
|
|
247
|
+
truncatedChars: false,
|
|
248
|
+
startLine: 1,
|
|
249
|
+
},
|
|
250
|
+
};
|
|
251
|
+
}
|
|
252
|
+
throw err;
|
|
253
|
+
}
|
|
254
|
+
// Cannot read directories
|
|
255
|
+
if (stat.isDirectory()) {
|
|
256
|
+
return {
|
|
257
|
+
content: [{ type: 'text', text: 'Cannot read a directory. Use `ls` via Bash.' }],
|
|
258
|
+
details: {
|
|
259
|
+
filePath,
|
|
260
|
+
totalLines: 0,
|
|
261
|
+
byteSize: 0,
|
|
262
|
+
truncated: false,
|
|
263
|
+
truncatedLines: false,
|
|
264
|
+
truncatedChars: false,
|
|
265
|
+
startLine: 1,
|
|
266
|
+
},
|
|
267
|
+
};
|
|
268
|
+
}
|
|
269
|
+
// Gate 1: Absolute size ceiling - reject files > 10 MB entirely
|
|
270
|
+
if (stat.size > MAX_READABLE_BYTES) {
|
|
271
|
+
return makeRejection(filePath, stat.size, `File is too large to read (${formatBytes(stat.size)}, limit ${formatBytes(MAX_READABLE_BYTES)}). Use Bash with head, tail, or sed to extract specific sections.`);
|
|
272
|
+
}
|
|
273
|
+
const ext = path.extname(filePath).toLowerCase();
|
|
274
|
+
// Handle image files
|
|
275
|
+
if (IMAGE_EXTENSIONS.has(ext)) {
|
|
276
|
+
const buffer = await fs.promises.readFile(filePath);
|
|
277
|
+
const mimeType = IMAGE_MIME_TYPES[ext] ?? 'application/octet-stream';
|
|
278
|
+
const base64 = buffer.toString('base64');
|
|
279
|
+
readRegistry.markRead(filePath, { timestamp: stat.mtimeMs });
|
|
280
|
+
return {
|
|
281
|
+
content: [{ type: 'image', data: base64, mimeType }],
|
|
282
|
+
details: {
|
|
283
|
+
filePath,
|
|
284
|
+
totalLines: 0,
|
|
285
|
+
byteSize: stat.size,
|
|
286
|
+
truncated: false,
|
|
287
|
+
truncatedLines: false,
|
|
288
|
+
truncatedChars: false,
|
|
289
|
+
startLine: 1,
|
|
290
|
+
},
|
|
291
|
+
};
|
|
292
|
+
}
|
|
293
|
+
// Handle PDF files. The extractor (shared/pdf-extractor.ts) wraps
|
|
294
|
+
// unpdf and returns a structured result: the Read tool's only
|
|
295
|
+
// responsibility is to decide how to surface each outcome.
|
|
296
|
+
if (ext === '.pdf') {
|
|
297
|
+
const pdfBuffer = await fs.promises.readFile(filePath);
|
|
298
|
+
const extraction = await extractPdfText({
|
|
299
|
+
data: pdfBuffer,
|
|
300
|
+
pagesSpec: params.pages,
|
|
301
|
+
});
|
|
302
|
+
if (extraction.kind === 'error' ||
|
|
303
|
+
extraction.kind === 'invalid-range' ||
|
|
304
|
+
extraction.kind === 'empty') {
|
|
305
|
+
// All three are read failures from the caller's perspective:
|
|
306
|
+
// there is no usable content to hand to the model. Flag as
|
|
307
|
+
// rejected so consumers can surface them uniformly and the
|
|
308
|
+
// model can retry (with a different pages spec, OCR, etc.).
|
|
309
|
+
return makeRejection(filePath, stat.size, extraction.message);
|
|
310
|
+
}
|
|
311
|
+
// Line-number the rendered output to match the cat -n style
|
|
312
|
+
// used for text files. Line numbers reset to 1 per call; PDFs
|
|
313
|
+
// don't map cleanly to the file-wide offset/limit model.
|
|
314
|
+
const renderedLines = extraction.rendered.split('\n');
|
|
315
|
+
const formatted = formatWithLineNumbers(renderedLines, 1);
|
|
316
|
+
// Gate 3: token ceiling on the formatted output.
|
|
317
|
+
const pdfTokenCount = estimateTokens(formatted);
|
|
318
|
+
if (pdfTokenCount > MAX_OUTPUT_TOKENS) {
|
|
319
|
+
const requestedPages = extraction.lastPage - extraction.firstPage + 1;
|
|
320
|
+
const suggestedPages = Math.max(1, Math.floor(requestedPages * MAX_OUTPUT_TOKENS / pdfTokenCount));
|
|
321
|
+
return makeRejection(filePath, stat.size, `PDF extraction too large (estimated ~${pdfTokenCount.toLocaleString()} tokens, limit ${MAX_OUTPUT_TOKENS.toLocaleString()}). ` +
|
|
322
|
+
`Narrow the \`pages\` range (try ~${suggestedPages} page${suggestedPages === 1 ? '' : 's'} per call).`);
|
|
323
|
+
}
|
|
324
|
+
readRegistry.markRead(filePath, { timestamp: stat.mtimeMs });
|
|
325
|
+
return {
|
|
326
|
+
content: [{ type: 'text', text: formatted }],
|
|
327
|
+
details: {
|
|
328
|
+
filePath,
|
|
329
|
+
totalLines: renderedLines.length,
|
|
330
|
+
byteSize: stat.size,
|
|
331
|
+
truncated: false,
|
|
332
|
+
truncatedLines: false,
|
|
333
|
+
truncatedChars: false,
|
|
334
|
+
startLine: 1,
|
|
335
|
+
},
|
|
336
|
+
};
|
|
337
|
+
}
|
|
338
|
+
// Gate 2: Full-read size gate - reject full reads of files > 256 KB
|
|
339
|
+
const hasExplicitRange = params.offset !== undefined || params.limit !== undefined;
|
|
340
|
+
if (!hasExplicitRange && stat.size > MAX_FULL_READ_BYTES) {
|
|
341
|
+
return makeRejection(filePath, stat.size, `File is too large to read in full (${formatBytes(stat.size)}, limit ${formatBytes(MAX_FULL_READ_BYTES)}). Provide offset and limit to read a specific range, or use Grep to search for specific content.`);
|
|
342
|
+
}
|
|
343
|
+
// File-unchanged dedup: if we already read this exact range and the
|
|
344
|
+
// file hasn't changed on disk, return a stub. The earlier Read result
|
|
345
|
+
// is still in context, so re-sending wastes tokens.
|
|
346
|
+
const existingState = readRegistry.getState(filePath);
|
|
347
|
+
if (existingState && existingState.offset !== undefined) {
|
|
348
|
+
const rangeMatch = existingState.offset === offset && existingState.limit === limit;
|
|
349
|
+
if (rangeMatch && stat.mtimeMs === existingState.timestamp) {
|
|
350
|
+
return {
|
|
351
|
+
content: [{ type: 'text', text: `[File unchanged since last read: ${filePath}]` }],
|
|
352
|
+
details: {
|
|
353
|
+
filePath,
|
|
354
|
+
totalLines: 0,
|
|
355
|
+
byteSize: stat.size,
|
|
356
|
+
truncated: false,
|
|
357
|
+
truncatedLines: false,
|
|
358
|
+
truncatedChars: false,
|
|
359
|
+
startLine: 1,
|
|
360
|
+
},
|
|
361
|
+
};
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
// Read the raw buffer
|
|
365
|
+
const buffer = await fs.promises.readFile(filePath);
|
|
366
|
+
// Binary detection (not image, not PDF)
|
|
367
|
+
if (isBinaryBuffer(buffer)) {
|
|
368
|
+
return {
|
|
369
|
+
content: [{ type: 'text', text: 'Binary file detected. Cannot display as text.' }],
|
|
370
|
+
details: {
|
|
371
|
+
filePath,
|
|
372
|
+
totalLines: 0,
|
|
373
|
+
byteSize: stat.size,
|
|
374
|
+
truncated: false,
|
|
375
|
+
truncatedLines: false,
|
|
376
|
+
truncatedChars: false,
|
|
377
|
+
startLine: 1,
|
|
378
|
+
},
|
|
379
|
+
};
|
|
380
|
+
}
|
|
381
|
+
// Decode and split into lines
|
|
382
|
+
const content = decodeFileContent(buffer);
|
|
383
|
+
const allLines = content.split('\n');
|
|
384
|
+
const totalLines = allLines.length;
|
|
385
|
+
// Handle empty file
|
|
386
|
+
if (totalLines === 0 || (totalLines === 1 && allLines[0] === '')) {
|
|
387
|
+
readRegistry.markRead(filePath, { timestamp: stat.mtimeMs, offset, limit });
|
|
388
|
+
return {
|
|
389
|
+
content: [{ type: 'text', text: `[File is empty: ${filePath}]` }],
|
|
390
|
+
details: {
|
|
391
|
+
filePath,
|
|
392
|
+
totalLines: 0,
|
|
393
|
+
byteSize: stat.size,
|
|
394
|
+
truncated: false,
|
|
395
|
+
truncatedLines: false,
|
|
396
|
+
truncatedChars: false,
|
|
397
|
+
startLine: 1,
|
|
398
|
+
},
|
|
399
|
+
};
|
|
400
|
+
}
|
|
401
|
+
// Apply offset and limit
|
|
402
|
+
const startIdx = Math.max(0, offset - 1); // Convert 1-based to 0-based
|
|
403
|
+
const endIdx = Math.min(totalLines, startIdx + limit);
|
|
404
|
+
const selectedLines = allLines.slice(startIdx, endIdx);
|
|
405
|
+
const truncatedLines = endIdx < totalLines;
|
|
406
|
+
const truncatedChars = selectedLines.some((line) => line.length > MAX_LINE_LENGTH);
|
|
407
|
+
// Format with line numbers
|
|
408
|
+
const formatted = formatWithLineNumbers(selectedLines, startIdx + 1);
|
|
409
|
+
// Gate 3: Post-read token estimation
|
|
410
|
+
const estimatedTokenCount = estimateTokens(formatted);
|
|
411
|
+
if (estimatedTokenCount > MAX_OUTPUT_TOKENS) {
|
|
412
|
+
const suggestedLimit = Math.floor(limit * MAX_OUTPUT_TOKENS / estimatedTokenCount);
|
|
413
|
+
return makeRejection(filePath, stat.size, `Read result too large (estimated ~${estimatedTokenCount.toLocaleString()} tokens, limit ${MAX_OUTPUT_TOKENS.toLocaleString()}). ` +
|
|
414
|
+
`The file has ${totalLines} lines. Use a smaller limit (try limit: ${Math.max(1, suggestedLimit)}) ` +
|
|
415
|
+
`or use Grep to find the specific content you need.`);
|
|
416
|
+
}
|
|
417
|
+
// Only mark as read after passing all gates, so rejected reads
|
|
418
|
+
// can be retried without hitting the dedup stub.
|
|
419
|
+
// For full, non-truncated reads, record a content hash so the
|
|
420
|
+
// Edit/Write tools can distinguish real file modifications from
|
|
421
|
+
// mtime-only changes (formatters, cloud sync, antivirus, etc.).
|
|
422
|
+
const isFullRead = !hasExplicitRange && !truncatedLines;
|
|
423
|
+
const contentHash = isFullRead
|
|
424
|
+
? crypto.createHash('sha256').update(buffer).digest('hex')
|
|
425
|
+
: undefined;
|
|
426
|
+
readRegistry.markRead(filePath, {
|
|
427
|
+
timestamp: stat.mtimeMs,
|
|
428
|
+
offset,
|
|
429
|
+
limit,
|
|
430
|
+
...(contentHash !== undefined ? { contentHash } : {}),
|
|
431
|
+
});
|
|
432
|
+
let text = formatted;
|
|
433
|
+
if (truncatedLines) {
|
|
434
|
+
text += `\n\n[Showing lines ${startIdx + 1}-${endIdx} of ${totalLines} total. Use offset/limit to read more.]`;
|
|
435
|
+
}
|
|
436
|
+
return {
|
|
437
|
+
content: [{ type: 'text', text }],
|
|
438
|
+
details: {
|
|
439
|
+
filePath,
|
|
440
|
+
totalLines,
|
|
441
|
+
byteSize: stat.size,
|
|
442
|
+
truncated: truncatedLines || truncatedChars,
|
|
443
|
+
truncatedLines,
|
|
444
|
+
truncatedChars,
|
|
445
|
+
startLine: offset,
|
|
446
|
+
},
|
|
447
|
+
};
|
|
448
|
+
},
|
|
449
|
+
};
|
|
450
|
+
return attachRuntimeAwareTool(tool, {
|
|
451
|
+
toolKind: 'Read',
|
|
452
|
+
cloneForRuntime: (runtime) => createReadTool({
|
|
453
|
+
...config,
|
|
454
|
+
runtime,
|
|
455
|
+
readRegistry: runtime.readRegistry,
|
|
456
|
+
}),
|
|
457
|
+
});
|
|
458
|
+
}
|
|
459
|
+
//# sourceMappingURL=read.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"read.js","sourceRoot":"","sources":["../../src/tools/read.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Per-agent runtime state for mutable built-in tool behavior.
|
|
3
|
+
*
|
|
4
|
+
* Cortex clones runtime-aware built-in tools into a fresh runtime for each
|
|
5
|
+
* agent so parent and child agents do not share mutable closures.
|
|
6
|
+
*/
|
|
7
|
+
import type * as child_process from 'node:child_process';
|
|
8
|
+
import { CwdTracker } from './shared/cwd-tracker.js';
|
|
9
|
+
import { EditHistory } from './shared/edit-history.js';
|
|
10
|
+
import { FileMutationLock } from './shared/file-mutation-lock.js';
|
|
11
|
+
import { ReadRegistry } from './shared/read-registry.js';
|
|
12
|
+
import { WebFetchCache } from './web-fetch/cache.js';
|
|
13
|
+
export interface BackgroundTask {
|
|
14
|
+
id: string;
|
|
15
|
+
/** The command that was executed (for status display). */
|
|
16
|
+
command: string;
|
|
17
|
+
process: child_process.ChildProcess;
|
|
18
|
+
stdout: string;
|
|
19
|
+
stderr: string;
|
|
20
|
+
exitCode: number | null;
|
|
21
|
+
completed: boolean;
|
|
22
|
+
startTime: number;
|
|
23
|
+
}
|
|
24
|
+
export declare class BackgroundTaskStore {
|
|
25
|
+
private readonly tasks;
|
|
26
|
+
private taskIdCounter;
|
|
27
|
+
nextTaskId(): string;
|
|
28
|
+
set(task: BackgroundTask): void;
|
|
29
|
+
get(taskId: string): BackgroundTask | undefined;
|
|
30
|
+
getAll(): Map<string, BackgroundTask>;
|
|
31
|
+
cleanupCompletedTasks(maxAgeMs?: number): void;
|
|
32
|
+
clear(): void;
|
|
33
|
+
}
|
|
34
|
+
export declare const globalBackgroundTaskStore: BackgroundTaskStore;
|
|
35
|
+
export declare class WebFetchRuntimeState {
|
|
36
|
+
private readonly cache;
|
|
37
|
+
private fetchesThisLoop;
|
|
38
|
+
getCache(): WebFetchCache;
|
|
39
|
+
get fetchCount(): number;
|
|
40
|
+
incrementFetchCount(): void;
|
|
41
|
+
resetLoop(): void;
|
|
42
|
+
destroy(): void;
|
|
43
|
+
}
|
|
44
|
+
export declare class CortexToolRuntime {
|
|
45
|
+
readonly cwdTracker: CwdTracker;
|
|
46
|
+
readonly readRegistry: ReadRegistry;
|
|
47
|
+
readonly fileMutationLock: FileMutationLock;
|
|
48
|
+
readonly editHistory: EditHistory;
|
|
49
|
+
readonly backgroundTasks: BackgroundTaskStore;
|
|
50
|
+
readonly webFetch: WebFetchRuntimeState;
|
|
51
|
+
constructor(workingDirectory: string);
|
|
52
|
+
resetForLoop(): void;
|
|
53
|
+
destroy(): void;
|
|
54
|
+
}
|
|
55
|
+
export interface RuntimeAwareToolMetadata<TTool> {
|
|
56
|
+
readonly toolKind: string;
|
|
57
|
+
cloneForRuntime: (runtime: CortexToolRuntime) => TTool;
|
|
58
|
+
}
|
|
59
|
+
export declare function attachRuntimeAwareTool<TTool extends object>(tool: TTool, metadata: RuntimeAwareToolMetadata<TTool>): TTool;
|
|
60
|
+
export declare function getRuntimeAwareToolMetadata<TTool>(tool: TTool): RuntimeAwareToolMetadata<TTool> | undefined;
|
|
61
|
+
export declare function cloneRuntimeAwareTool<TTool>(tool: TTool, runtime: CortexToolRuntime): TTool | null;
|
|
62
|
+
//# sourceMappingURL=runtime.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"runtime.d.ts","sourceRoot":"","sources":["../../src/tools/runtime.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,KAAK,aAAa,MAAM,oBAAoB,CAAC;AACzD,OAAO,EAAE,UAAU,EAAE,MAAM,yBAAyB,CAAC;AACrD,OAAO,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AACvD,OAAO,EAAE,gBAAgB,EAAE,MAAM,gCAAgC,CAAC;AAClE,OAAO,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAC;AACzD,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAMrD,MAAM,WAAW,cAAc;IAC7B,EAAE,EAAE,MAAM,CAAC;IACX,0DAA0D;IAC1D,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,aAAa,CAAC,YAAY,CAAC;IACpC,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,SAAS,EAAE,OAAO,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,qBAAa,mBAAmB;IAC9B,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAqC;IAC3D,OAAO,CAAC,aAAa,CAAK;IAE1B,UAAU,IAAI,MAAM;IAKpB,GAAG,CAAC,IAAI,EAAE,cAAc,GAAG,IAAI;IAI/B,GAAG,CAAC,MAAM,EAAE,MAAM,GAAG,cAAc,GAAG,SAAS;IAI/C,MAAM,IAAI,GAAG,CAAC,MAAM,EAAE,cAAc,CAAC;IAIrC,qBAAqB,CAAC,QAAQ,SAAiB,GAAG,IAAI;IAStD,KAAK,IAAI,IAAI;CAGd;AAED,eAAO,MAAM,yBAAyB,qBAA4B,CAAC;AAMnE,qBAAa,oBAAoB;IAC/B,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAuB;IAC7C,OAAO,CAAC,eAAe,CAAK;IAE5B,QAAQ,IAAI,aAAa;IAIzB,IAAI,UAAU,IAAI,MAAM,CAEvB;IAED,mBAAmB,IAAI,IAAI;IAI3B,SAAS,IAAI,IAAI;IAIjB,OAAO,IAAI,IAAI;CAGhB;AAMD,qBAAa,iBAAiB;IAC5B,QAAQ,CAAC,UAAU,EAAE,UAAU,CAAC;IAChC,QAAQ,CAAC,YAAY,EAAE,YAAY,CAAC;IACpC,QAAQ,CAAC,gBAAgB,EAAE,gBAAgB,CAAC;IAC5C,QAAQ,CAAC,WAAW,EAAE,WAAW,CAAC;IAClC,QAAQ,CAAC,eAAe,EAAE,mBAAmB,CAAC;IAC9C,QAAQ,CAAC,QAAQ,EAAE,oBAAoB,CAAC;gBAE5B,gBAAgB,EAAE,MAAM;IASpC,YAAY,IAAI,IAAI;IAQpB,OAAO,IAAI,IAAI;CAOhB;AAMD,MAAM,WAAW,wBAAwB,CAAC,KAAK;IAC7C,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,eAAe,EAAE,CAAC,OAAO,EAAE,iBAAiB,KAAK,KAAK,CAAC;CACxD;AAID,wBAAgB,sBAAsB,CAAC,KAAK,SAAS,MAAM,EACzD,IAAI,EAAE,KAAK,EACX,QAAQ,EAAE,wBAAwB,CAAC,KAAK,CAAC,GACxC,KAAK,CAQP;AAED,wBAAgB,2BAA2B,CAAC,KAAK,EAC/C,IAAI,EAAE,KAAK,GACV,wBAAwB,CAAC,KAAK,CAAC,GAAG,SAAS,CAI7C;AAED,wBAAgB,qBAAqB,CAAC,KAAK,EACzC,IAAI,EAAE,KAAK,EACX,OAAO,EAAE,iBAAiB,GACzB,KAAK,GAAG,IAAI,CAGd"}
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Per-agent runtime state for mutable built-in tool behavior.
|
|
3
|
+
*
|
|
4
|
+
* Cortex clones runtime-aware built-in tools into a fresh runtime for each
|
|
5
|
+
* agent so parent and child agents do not share mutable closures.
|
|
6
|
+
*/
|
|
7
|
+
import { CwdTracker } from './shared/cwd-tracker.js';
|
|
8
|
+
import { EditHistory } from './shared/edit-history.js';
|
|
9
|
+
import { FileMutationLock } from './shared/file-mutation-lock.js';
|
|
10
|
+
import { ReadRegistry } from './shared/read-registry.js';
|
|
11
|
+
import { WebFetchCache } from './web-fetch/cache.js';
|
|
12
|
+
export class BackgroundTaskStore {
|
|
13
|
+
tasks = new Map();
|
|
14
|
+
taskIdCounter = 0;
|
|
15
|
+
nextTaskId() {
|
|
16
|
+
this.taskIdCounter += 1;
|
|
17
|
+
return `task_${this.taskIdCounter}`;
|
|
18
|
+
}
|
|
19
|
+
set(task) {
|
|
20
|
+
this.tasks.set(task.id, task);
|
|
21
|
+
}
|
|
22
|
+
get(taskId) {
|
|
23
|
+
return this.tasks.get(taskId);
|
|
24
|
+
}
|
|
25
|
+
getAll() {
|
|
26
|
+
return this.tasks;
|
|
27
|
+
}
|
|
28
|
+
cleanupCompletedTasks(maxAgeMs = 30 * 60 * 1000) {
|
|
29
|
+
const now = Date.now();
|
|
30
|
+
for (const [id, task] of this.tasks) {
|
|
31
|
+
if (task.completed && now - task.startTime > maxAgeMs) {
|
|
32
|
+
this.tasks.delete(id);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
clear() {
|
|
37
|
+
this.tasks.clear();
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
export const globalBackgroundTaskStore = new BackgroundTaskStore();
|
|
41
|
+
// ---------------------------------------------------------------------------
|
|
42
|
+
// WebFetch runtime state
|
|
43
|
+
// ---------------------------------------------------------------------------
|
|
44
|
+
export class WebFetchRuntimeState {
|
|
45
|
+
cache = new WebFetchCache();
|
|
46
|
+
fetchesThisLoop = 0;
|
|
47
|
+
getCache() {
|
|
48
|
+
return this.cache;
|
|
49
|
+
}
|
|
50
|
+
get fetchCount() {
|
|
51
|
+
return this.fetchesThisLoop;
|
|
52
|
+
}
|
|
53
|
+
incrementFetchCount() {
|
|
54
|
+
this.fetchesThisLoop += 1;
|
|
55
|
+
}
|
|
56
|
+
resetLoop() {
|
|
57
|
+
this.fetchesThisLoop = 0;
|
|
58
|
+
}
|
|
59
|
+
destroy() {
|
|
60
|
+
this.cache.destroy();
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
// ---------------------------------------------------------------------------
|
|
64
|
+
// Per-agent runtime container
|
|
65
|
+
// ---------------------------------------------------------------------------
|
|
66
|
+
export class CortexToolRuntime {
|
|
67
|
+
cwdTracker;
|
|
68
|
+
readRegistry;
|
|
69
|
+
fileMutationLock;
|
|
70
|
+
editHistory;
|
|
71
|
+
backgroundTasks;
|
|
72
|
+
webFetch;
|
|
73
|
+
constructor(workingDirectory) {
|
|
74
|
+
this.cwdTracker = new CwdTracker(workingDirectory);
|
|
75
|
+
this.readRegistry = new ReadRegistry();
|
|
76
|
+
this.fileMutationLock = new FileMutationLock();
|
|
77
|
+
this.editHistory = new EditHistory();
|
|
78
|
+
this.backgroundTasks = new BackgroundTaskStore();
|
|
79
|
+
this.webFetch = new WebFetchRuntimeState();
|
|
80
|
+
}
|
|
81
|
+
resetForLoop() {
|
|
82
|
+
this.cwdTracker.reset();
|
|
83
|
+
this.readRegistry.clear();
|
|
84
|
+
this.fileMutationLock.clear();
|
|
85
|
+
this.editHistory.clear();
|
|
86
|
+
this.webFetch.resetLoop();
|
|
87
|
+
}
|
|
88
|
+
destroy() {
|
|
89
|
+
this.readRegistry.clear();
|
|
90
|
+
this.fileMutationLock.clear();
|
|
91
|
+
this.editHistory.clear();
|
|
92
|
+
this.backgroundTasks.clear();
|
|
93
|
+
this.webFetch.destroy();
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
const RUNTIME_AWARE_TOOL = Symbol.for('cortex.runtimeAwareTool');
|
|
97
|
+
export function attachRuntimeAwareTool(tool, metadata) {
|
|
98
|
+
Object.defineProperty(tool, RUNTIME_AWARE_TOOL, {
|
|
99
|
+
value: metadata,
|
|
100
|
+
enumerable: false,
|
|
101
|
+
configurable: false,
|
|
102
|
+
writable: false,
|
|
103
|
+
});
|
|
104
|
+
return tool;
|
|
105
|
+
}
|
|
106
|
+
export function getRuntimeAwareToolMetadata(tool) {
|
|
107
|
+
if (!tool || typeof tool !== 'object')
|
|
108
|
+
return undefined;
|
|
109
|
+
const record = tool;
|
|
110
|
+
return record[RUNTIME_AWARE_TOOL];
|
|
111
|
+
}
|
|
112
|
+
export function cloneRuntimeAwareTool(tool, runtime) {
|
|
113
|
+
const metadata = getRuntimeAwareToolMetadata(tool);
|
|
114
|
+
return metadata ? metadata.cloneForRuntime(runtime) : null;
|
|
115
|
+
}
|
|
116
|
+
//# sourceMappingURL=runtime.js.map
|