@compilr-dev/agents 0.0.1 → 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.
Files changed (44) hide show
  1. package/dist/agent.d.ts +188 -1
  2. package/dist/agent.js +284 -14
  3. package/dist/context/file-tracker.d.ts +156 -0
  4. package/dist/context/file-tracker.js +358 -0
  5. package/dist/context/file-tracking-hook.d.ts +29 -0
  6. package/dist/context/file-tracking-hook.js +103 -0
  7. package/dist/context/index.d.ts +5 -1
  8. package/dist/context/index.js +3 -0
  9. package/dist/context/manager.d.ts +69 -1
  10. package/dist/context/manager.js +304 -0
  11. package/dist/context/types.d.ts +95 -0
  12. package/dist/index.d.ts +13 -5
  13. package/dist/index.js +11 -3
  14. package/dist/messages/index.d.ts +13 -0
  15. package/dist/messages/index.js +51 -0
  16. package/dist/permissions/manager.js +6 -1
  17. package/dist/providers/gemini.d.ts +91 -0
  18. package/dist/providers/gemini.js +138 -0
  19. package/dist/providers/index.d.ts +8 -0
  20. package/dist/providers/index.js +7 -3
  21. package/dist/providers/mock.js +8 -0
  22. package/dist/providers/ollama.d.ts +87 -0
  23. package/dist/providers/ollama.js +133 -0
  24. package/dist/providers/openai-compatible.d.ts +182 -0
  25. package/dist/providers/openai-compatible.js +357 -0
  26. package/dist/providers/openai.d.ts +93 -0
  27. package/dist/providers/openai.js +133 -0
  28. package/dist/skills/index.js +691 -0
  29. package/dist/tools/builtin/glob.d.ts +11 -0
  30. package/dist/tools/builtin/glob.js +44 -2
  31. package/dist/tools/builtin/grep.d.ts +11 -1
  32. package/dist/tools/builtin/grep.js +38 -2
  33. package/dist/tools/builtin/index.d.ts +6 -1
  34. package/dist/tools/builtin/index.js +7 -0
  35. package/dist/tools/builtin/suggest.d.ts +57 -0
  36. package/dist/tools/builtin/suggest.js +99 -0
  37. package/dist/tools/builtin/task.js +13 -8
  38. package/dist/tools/builtin/tool-names.d.ts +44 -0
  39. package/dist/tools/builtin/tool-names.js +51 -0
  40. package/dist/tools/index.d.ts +2 -2
  41. package/dist/tools/index.js +5 -1
  42. package/dist/tools/registry.d.ts +4 -0
  43. package/dist/tools/registry.js +9 -0
  44. package/package.json +2 -2
@@ -0,0 +1,358 @@
1
+ /**
2
+ * File Access Tracker
3
+ *
4
+ * Tracks file accesses during agent sessions to provide context restoration
5
+ * hints after compaction. Inspired by Claude Code's post-compaction file
6
+ * reference display.
7
+ *
8
+ * Features:
9
+ * - Track read, referenced, and modified files
10
+ * - Deduplication (read supersedes reference)
11
+ * - Max entries with LRU eviction
12
+ * - Verbosity-aware formatting
13
+ *
14
+ * @see /workspace/project-docs/00-requirements/compilr-dev-agents/context-restoration-hints.md
15
+ */
16
+ import path from 'path';
17
+ // ============================================================================
18
+ // FileAccessTracker Class
19
+ // ============================================================================
20
+ /**
21
+ * Tracks file accesses during agent sessions for context restoration hints.
22
+ *
23
+ * @example
24
+ * ```typescript
25
+ * const tracker = new FileAccessTracker();
26
+ *
27
+ * // Track file accesses
28
+ * tracker.trackRead('/path/to/file.ts', 597);
29
+ * tracker.trackReference('/path/to/other.ts');
30
+ * tracker.trackModification('/path/to/file.ts', 'Added function');
31
+ *
32
+ * // Get restoration hints after compaction
33
+ * const hints = tracker.formatRestorationHints();
34
+ * console.log(hints);
35
+ * ```
36
+ */
37
+ export class FileAccessTracker {
38
+ accesses = new Map();
39
+ maxEntries;
40
+ deduplicateReferences;
41
+ constructor(options = {}) {
42
+ this.maxEntries = options.maxEntries ?? 100;
43
+ this.deduplicateReferences = options.deduplicateReferences ?? true;
44
+ }
45
+ // ==========================================================================
46
+ // Track Methods
47
+ // ==========================================================================
48
+ /**
49
+ * Track a file that was fully read
50
+ */
51
+ trackRead(filePath, lineCount, summary) {
52
+ const normalizedPath = this.normalizePath(filePath);
53
+ // Read supersedes reference - remove any existing reference
54
+ const existing = this.accesses.get(normalizedPath);
55
+ if (existing && existing.type === 'referenced') {
56
+ this.accesses.delete(normalizedPath);
57
+ }
58
+ // Update or create read entry
59
+ this.accesses.set(normalizedPath, {
60
+ path: normalizedPath,
61
+ type: 'read',
62
+ timestamp: Date.now(),
63
+ lineCount,
64
+ summary,
65
+ });
66
+ this.enforceMaxEntries();
67
+ }
68
+ /**
69
+ * Track a file that was referenced (e.g., appeared in grep/glob results)
70
+ */
71
+ trackReference(filePath) {
72
+ const normalizedPath = this.normalizePath(filePath);
73
+ // Don't downgrade read/modified to reference
74
+ const existing = this.accesses.get(normalizedPath);
75
+ if (existing && (existing.type === 'read' || existing.type === 'modified')) {
76
+ return;
77
+ }
78
+ // Deduplicate references
79
+ if (this.deduplicateReferences && existing && existing.type === 'referenced') {
80
+ // Update timestamp only
81
+ existing.timestamp = Date.now();
82
+ return;
83
+ }
84
+ this.accesses.set(normalizedPath, {
85
+ path: normalizedPath,
86
+ type: 'referenced',
87
+ timestamp: Date.now(),
88
+ });
89
+ this.enforceMaxEntries();
90
+ }
91
+ /**
92
+ * Track a file that was modified (written or edited)
93
+ */
94
+ trackModification(filePath, summary) {
95
+ const normalizedPath = this.normalizePath(filePath);
96
+ this.accesses.set(normalizedPath, {
97
+ path: normalizedPath,
98
+ type: 'modified',
99
+ timestamp: Date.now(),
100
+ summary,
101
+ });
102
+ this.enforceMaxEntries();
103
+ }
104
+ // ==========================================================================
105
+ // Query Methods
106
+ // ==========================================================================
107
+ /**
108
+ * Get all file accesses, optionally filtered
109
+ */
110
+ getAccesses(options) {
111
+ let accesses = Array.from(this.accesses.values());
112
+ if (options?.type) {
113
+ accesses = accesses.filter((a) => a.type === options.type);
114
+ }
115
+ if (options?.since !== undefined) {
116
+ const since = options.since;
117
+ accesses = accesses.filter((a) => a.timestamp >= since);
118
+ }
119
+ // Sort by timestamp descending (most recent first)
120
+ return accesses.sort((a, b) => b.timestamp - a.timestamp);
121
+ }
122
+ /**
123
+ * Get most recent file accesses
124
+ */
125
+ getRecentAccesses(limit = 10) {
126
+ return this.getAccesses().slice(0, limit);
127
+ }
128
+ /**
129
+ * Check if a file has been accessed
130
+ */
131
+ hasAccessed(filePath) {
132
+ return this.accesses.has(this.normalizePath(filePath));
133
+ }
134
+ /**
135
+ * Get access record for a specific file
136
+ */
137
+ getAccess(filePath) {
138
+ return this.accesses.get(this.normalizePath(filePath));
139
+ }
140
+ /**
141
+ * Get statistics about file accesses
142
+ */
143
+ getStats() {
144
+ const stats = { read: 0, referenced: 0, modified: 0, total: 0 };
145
+ for (const access of this.accesses.values()) {
146
+ stats[access.type]++;
147
+ stats.total++;
148
+ }
149
+ return stats;
150
+ }
151
+ // ==========================================================================
152
+ // Format Methods
153
+ // ==========================================================================
154
+ /**
155
+ * Format restoration hints for injection after compaction
156
+ */
157
+ formatRestorationHints(options = {}) {
158
+ const { includeLineCount = true, includeSummary = false, includeTimestamp = false, groupByType = true, maxFiles = 20, verbosityLevel = 'normal', } = options;
159
+ // Adjust based on verbosity
160
+ const effectiveMaxFiles = this.getEffectiveMaxFiles(maxFiles, verbosityLevel);
161
+ if (this.accesses.size === 0) {
162
+ return '';
163
+ }
164
+ const allAccesses = this.getAccesses();
165
+ // Apply limit
166
+ const limitedAccesses = allAccesses.slice(0, effectiveMaxFiles);
167
+ const hasMore = allAccesses.length > effectiveMaxFiles;
168
+ // Use compact format for tight context
169
+ if (verbosityLevel === 'minimal' || verbosityLevel === 'abbreviated') {
170
+ return this.formatCompact(limitedAccesses, hasMore);
171
+ }
172
+ // Full format with grouping
173
+ if (groupByType) {
174
+ return this.formatGrouped(limitedAccesses, hasMore, {
175
+ includeLineCount,
176
+ includeSummary,
177
+ includeTimestamp,
178
+ });
179
+ }
180
+ // Flat format (not grouped)
181
+ return this.formatFlat(limitedAccesses, hasMore, {
182
+ includeLineCount,
183
+ includeSummary,
184
+ includeTimestamp,
185
+ });
186
+ }
187
+ // ==========================================================================
188
+ // Lifecycle Methods
189
+ // ==========================================================================
190
+ /**
191
+ * Clear all tracked accesses
192
+ */
193
+ clear() {
194
+ this.accesses.clear();
195
+ }
196
+ /**
197
+ * Get the number of tracked files
198
+ */
199
+ get size() {
200
+ return this.accesses.size;
201
+ }
202
+ // ==========================================================================
203
+ // Private Helpers
204
+ // ==========================================================================
205
+ normalizePath(filePath) {
206
+ // Resolve to absolute path
207
+ return path.resolve(filePath);
208
+ }
209
+ enforceMaxEntries() {
210
+ if (this.accesses.size <= this.maxEntries) {
211
+ return;
212
+ }
213
+ // Evict oldest references first, then oldest reads
214
+ const sorted = this.getAccesses().reverse(); // Oldest first
215
+ // Separate by type for eviction priority
216
+ const references = sorted.filter((a) => a.type === 'referenced');
217
+ const reads = sorted.filter((a) => a.type === 'read');
218
+ const modified = sorted.filter((a) => a.type === 'modified');
219
+ // Build eviction order: references first, then reads, modified last
220
+ const evictionOrder = [...references, ...reads, ...modified];
221
+ // Evict until under limit
222
+ while (this.accesses.size > this.maxEntries && evictionOrder.length > 0) {
223
+ const toEvict = evictionOrder.shift();
224
+ if (toEvict) {
225
+ this.accesses.delete(toEvict.path);
226
+ }
227
+ }
228
+ }
229
+ getEffectiveMaxFiles(maxFiles, verbosityLevel) {
230
+ switch (verbosityLevel) {
231
+ case 'minimal':
232
+ return Math.min(maxFiles, 3);
233
+ case 'abbreviated':
234
+ return Math.min(maxFiles, 5);
235
+ case 'normal':
236
+ return Math.min(maxFiles, 10);
237
+ case 'full':
238
+ default:
239
+ return maxFiles;
240
+ }
241
+ }
242
+ formatCompact(accesses, hasMore) {
243
+ const byType = this.groupByType(accesses);
244
+ const parts = [];
245
+ if (byType.read.length > 0) {
246
+ const names = byType.read.map((a) => this.getDisplayName(a.path)).join(', ');
247
+ parts.push(`${names} (read)`);
248
+ }
249
+ if (byType.modified.length > 0) {
250
+ const names = byType.modified.map((a) => this.getDisplayName(a.path)).join(', ');
251
+ parts.push(`${names} (modified)`);
252
+ }
253
+ if (byType.referenced.length > 0) {
254
+ const count = byType.referenced.length;
255
+ if (count <= 2) {
256
+ const names = byType.referenced.map((a) => this.getDisplayName(a.path)).join(', ');
257
+ parts.push(`${names} (referenced)`);
258
+ }
259
+ else {
260
+ const first = this.getDisplayName(byType.referenced[0].path);
261
+ parts.push(`${first} +${String(count - 1)} more (referenced)`);
262
+ }
263
+ }
264
+ const moreNote = hasMore ? ' +more' : '';
265
+ return `[Previously accessed: ${parts.join('; ')}${moreNote}]`;
266
+ }
267
+ formatGrouped(accesses, hasMore, opts) {
268
+ const byType = this.groupByType(accesses);
269
+ const lines = ['[Context compacted. Previously accessed files:]', ''];
270
+ if (byType.read.length > 0) {
271
+ const count = byType.read.length;
272
+ lines.push(`Read (${String(count)} file${count > 1 ? 's' : ''}):`);
273
+ for (const access of byType.read) {
274
+ lines.push(this.formatAccessLine(access, opts));
275
+ }
276
+ lines.push('');
277
+ }
278
+ if (byType.modified.length > 0) {
279
+ const count = byType.modified.length;
280
+ lines.push(`Modified (${String(count)} file${count > 1 ? 's' : ''}):`);
281
+ for (const access of byType.modified) {
282
+ lines.push(this.formatAccessLine(access, opts));
283
+ }
284
+ lines.push('');
285
+ }
286
+ if (byType.referenced.length > 0) {
287
+ const count = byType.referenced.length;
288
+ lines.push(`Referenced (${String(count)} file${count > 1 ? 's' : ''}):`);
289
+ for (const access of byType.referenced) {
290
+ lines.push(this.formatAccessLine(access, opts));
291
+ }
292
+ lines.push('');
293
+ }
294
+ if (hasMore) {
295
+ lines.push('(Additional files truncated)');
296
+ lines.push('');
297
+ }
298
+ lines.push('[Use read_file to re-access content if needed.]');
299
+ return lines.join('\n');
300
+ }
301
+ formatFlat(accesses, hasMore, opts) {
302
+ const lines = ['[Context compacted. Previously accessed files:]', ''];
303
+ for (const access of accesses) {
304
+ const typeLabel = access.type === 'read' ? 'R' : access.type === 'modified' ? 'M' : 'ref';
305
+ lines.push(` [${typeLabel}] ${this.formatAccessLine(access, opts).trim()}`);
306
+ }
307
+ if (hasMore) {
308
+ lines.push('');
309
+ lines.push('(Additional files truncated)');
310
+ }
311
+ lines.push('');
312
+ lines.push('[Use read_file to re-access content if needed.]');
313
+ return lines.join('\n');
314
+ }
315
+ formatAccessLine(access, opts) {
316
+ const parts = [` • ${this.getDisplayPath(access.path)}`];
317
+ if (opts.includeLineCount && access.lineCount !== undefined) {
318
+ parts.push(`(${String(access.lineCount)} lines)`);
319
+ }
320
+ if (opts.includeSummary && access.summary) {
321
+ parts.push(`- ${access.summary}`);
322
+ }
323
+ if (opts.includeTimestamp) {
324
+ const date = new Date(access.timestamp);
325
+ parts.push(`@ ${date.toISOString().slice(11, 19)}`);
326
+ }
327
+ return parts.join(' ');
328
+ }
329
+ groupByType(accesses) {
330
+ const result = {
331
+ read: [],
332
+ referenced: [],
333
+ modified: [],
334
+ };
335
+ for (const access of accesses) {
336
+ result[access.type].push(access);
337
+ }
338
+ return result;
339
+ }
340
+ getDisplayName(filePath) {
341
+ return path.basename(filePath);
342
+ }
343
+ getDisplayPath(filePath) {
344
+ // Try to make path shorter for display
345
+ const cwd = process.cwd();
346
+ if (filePath.startsWith(cwd)) {
347
+ return filePath.slice(cwd.length + 1); // Remove cwd + leading slash
348
+ }
349
+ // Truncate long absolute paths
350
+ if (filePath.length > 60) {
351
+ const parts = filePath.split(path.sep);
352
+ if (parts.length > 4) {
353
+ return `...${path.sep}${parts.slice(-3).join(path.sep)}`;
354
+ }
355
+ }
356
+ return filePath;
357
+ }
358
+ }
@@ -0,0 +1,29 @@
1
+ /**
2
+ * File Tracking Hook
3
+ *
4
+ * An afterTool hook that automatically tracks file accesses based on tool calls.
5
+ * This approach is cleaner than modifying each tool directly.
6
+ *
7
+ * Usage:
8
+ * ```typescript
9
+ * const tracker = new FileAccessTracker();
10
+ * const agent = new Agent({
11
+ * hooks: {
12
+ * afterTool: [createFileTrackingHook(tracker)]
13
+ * }
14
+ * });
15
+ * ```
16
+ */
17
+ import type { AfterToolHook } from '../hooks/types.js';
18
+ import type { FileAccessTracker } from './file-tracker.js';
19
+ /**
20
+ * Create an afterTool hook that tracks file accesses
21
+ *
22
+ * @param tracker - FileAccessTracker instance to record accesses
23
+ * @returns An afterTool hook function
24
+ */
25
+ export declare function createFileTrackingHook(tracker: FileAccessTracker): AfterToolHook;
26
+ /**
27
+ * Tool names that this hook tracks
28
+ */
29
+ export declare const TRACKED_TOOLS: readonly ["read_file", "write_file", "edit", "grep", "glob"];
@@ -0,0 +1,103 @@
1
+ /**
2
+ * File Tracking Hook
3
+ *
4
+ * An afterTool hook that automatically tracks file accesses based on tool calls.
5
+ * This approach is cleaner than modifying each tool directly.
6
+ *
7
+ * Usage:
8
+ * ```typescript
9
+ * const tracker = new FileAccessTracker();
10
+ * const agent = new Agent({
11
+ * hooks: {
12
+ * afterTool: [createFileTrackingHook(tracker)]
13
+ * }
14
+ * });
15
+ * ```
16
+ */
17
+ import { TOOL_NAMES } from '../tools/builtin/tool-names.js';
18
+ /**
19
+ * Create an afterTool hook that tracks file accesses
20
+ *
21
+ * @param tracker - FileAccessTracker instance to record accesses
22
+ * @returns An afterTool hook function
23
+ */
24
+ export function createFileTrackingHook(tracker) {
25
+ return (context) => {
26
+ const { toolName, input, result } = context;
27
+ // Only track successful operations
28
+ if (!result.success) {
29
+ return undefined;
30
+ }
31
+ switch (toolName) {
32
+ case TOOL_NAMES.READ_FILE: {
33
+ const readInput = input;
34
+ const readResult = result;
35
+ const lineCount = readResult.result?.lineCount ?? 0;
36
+ tracker.trackRead(readInput.file_path, lineCount);
37
+ break;
38
+ }
39
+ case TOOL_NAMES.WRITE_FILE: {
40
+ const writeInput = input;
41
+ tracker.trackModification(writeInput.file_path, 'File written');
42
+ break;
43
+ }
44
+ case TOOL_NAMES.EDIT: {
45
+ const editInput = input;
46
+ tracker.trackModification(editInput.file_path, 'File edited');
47
+ break;
48
+ }
49
+ case TOOL_NAMES.GREP: {
50
+ const grepInput = input;
51
+ const grepResult = result;
52
+ // Track the search path if specified
53
+ if (grepInput.path) {
54
+ tracker.trackReference(grepInput.path);
55
+ }
56
+ // Track all files that matched
57
+ if (grepResult.result?.matches) {
58
+ const seenFiles = new Set();
59
+ for (const match of grepResult.result.matches) {
60
+ if (!seenFiles.has(match.file)) {
61
+ seenFiles.add(match.file);
62
+ tracker.trackReference(match.file);
63
+ }
64
+ }
65
+ }
66
+ if (grepResult.result?.files) {
67
+ for (const file of grepResult.result.files) {
68
+ tracker.trackReference(file);
69
+ }
70
+ }
71
+ break;
72
+ }
73
+ case TOOL_NAMES.GLOB: {
74
+ const globInput = input;
75
+ const globResult = result;
76
+ // Track the search path if specified
77
+ if (globInput.path) {
78
+ tracker.trackReference(globInput.path);
79
+ }
80
+ // Track all matched files
81
+ if (globResult.result?.files) {
82
+ for (const file of globResult.result.files) {
83
+ tracker.trackReference(file);
84
+ }
85
+ }
86
+ break;
87
+ }
88
+ // Note: bash tool could potentially be tracked for file operations,
89
+ // but it's complex to parse shell commands. Skip for now.
90
+ }
91
+ return undefined;
92
+ };
93
+ }
94
+ /**
95
+ * Tool names that this hook tracks
96
+ */
97
+ export const TRACKED_TOOLS = [
98
+ TOOL_NAMES.READ_FILE,
99
+ TOOL_NAMES.WRITE_FILE,
100
+ TOOL_NAMES.EDIT,
101
+ TOOL_NAMES.GREP,
102
+ TOOL_NAMES.GLOB,
103
+ ];
@@ -6,7 +6,11 @@
6
6
  * - Filtering (truncate large content)
7
7
  * - Compaction (save to files, replace with references)
8
8
  * - Summarization (compress history when near limit)
9
+ * - File access tracking (for context restoration hints)
9
10
  */
10
11
  export { ContextManager, DEFAULT_CONTEXT_CONFIG } from './manager.js';
11
12
  export type { ContextManagerOptions } from './manager.js';
12
- export type { ContextCategory, BudgetAllocation, CategoryBudgetInfo, PreflightResult, VerbosityLevel, VerbosityConfig, ContextConfig, FilteringConfig, CompactionConfig, SummarizationConfig, CompactionResult, SummarizationResult, FilteringResult, ContextEvent, ContextEventHandler, ContextStats, } from './types.js';
13
+ export { FileAccessTracker } from './file-tracker.js';
14
+ export type { FileAccessType, FileAccess, FileAccessTrackerOptions, FormatHintsOptions, FileAccessStats, } from './file-tracker.js';
15
+ export { createFileTrackingHook, TRACKED_TOOLS } from './file-tracking-hook.js';
16
+ export type { ContextCategory, BudgetAllocation, CategoryBudgetInfo, PreflightResult, VerbosityLevel, VerbosityConfig, ContextConfig, FilteringConfig, CompactionConfig, SummarizationConfig, CompactionResult, SummarizationResult, FilteringResult, ContextEvent, ContextEventHandler, ContextStats, CategorizedMessages, SmartCompactOptions, SmartCompactionResult, } from './types.js';
@@ -6,5 +6,8 @@
6
6
  * - Filtering (truncate large content)
7
7
  * - Compaction (save to files, replace with references)
8
8
  * - Summarization (compress history when near limit)
9
+ * - File access tracking (for context restoration hints)
9
10
  */
10
11
  export { ContextManager, DEFAULT_CONTEXT_CONFIG } from './manager.js';
12
+ export { FileAccessTracker } from './file-tracker.js';
13
+ export { createFileTrackingHook, TRACKED_TOOLS } from './file-tracking-hook.js';
@@ -18,7 +18,8 @@
18
18
  * ```
19
19
  */
20
20
  import type { Message, LLMProvider } from '../providers/types.js';
21
- import type { ContextConfig, ContextStats, CompactionResult, SummarizationResult, ContextEventHandler, ContextCategory, CategoryBudgetInfo, BudgetAllocation, PreflightResult, VerbosityLevel } from './types.js';
21
+ import type { ContextConfig, ContextStats, CompactionResult, SummarizationResult, ContextEventHandler, ContextCategory, CategoryBudgetInfo, BudgetAllocation, PreflightResult, VerbosityLevel, CategorizedMessages, SmartCompactOptions, SmartCompactionResult } from './types.js';
22
+ import type { FileAccessTracker } from './file-tracker.js';
22
23
  /**
23
24
  * Default budget allocation
24
25
  */
@@ -43,6 +44,12 @@ export interface ContextManagerOptions {
43
44
  * Event handler for context events
44
45
  */
45
46
  onEvent?: ContextEventHandler;
47
+ /**
48
+ * File access tracker for context restoration hints.
49
+ * When provided, compaction/summarization will inject hints
50
+ * about previously accessed files.
51
+ */
52
+ fileTracker?: FileAccessTracker;
46
53
  }
47
54
  /**
48
55
  * ContextManager tracks and manages context window usage
@@ -51,6 +58,7 @@ export declare class ContextManager {
51
58
  private readonly provider;
52
59
  private readonly config;
53
60
  private readonly onEvent?;
61
+ private readonly fileTracker?;
54
62
  private cachedTokenCount;
55
63
  private turnCount;
56
64
  private compactionCount;
@@ -110,6 +118,23 @@ export declare class ContextManager {
110
118
  * Get the current configuration
111
119
  */
112
120
  getConfig(): ContextConfig;
121
+ /**
122
+ * Get the file access tracker (if configured)
123
+ */
124
+ getFileTracker(): FileAccessTracker | undefined;
125
+ /**
126
+ * Format context restoration hints based on current verbosity level.
127
+ * Returns empty string if no file tracker is configured or no files have been accessed.
128
+ */
129
+ formatRestorationHints(): string;
130
+ /**
131
+ * Create a system message with context restoration hints.
132
+ * Returns undefined if no hints are available.
133
+ *
134
+ * The caller (Agent) is responsible for injecting this message
135
+ * after compaction or summarization.
136
+ */
137
+ createRestorationHintMessage(): Message | undefined;
113
138
  /**
114
139
  * Get budget information for a specific category
115
140
  */
@@ -144,6 +169,49 @@ export declare class ContextManager {
144
169
  * Determine which category a message belongs to
145
170
  */
146
171
  private categorizeMessage;
172
+ /**
173
+ * Categorize all messages by type for smart compaction
174
+ *
175
+ * This method:
176
+ * 1. Identifies system messages
177
+ * 2. Separates recent messages (last N turns) that should never be compacted
178
+ * 3. Identifies tool results in older messages
179
+ * 4. Classifies remaining older messages as history
180
+ *
181
+ * @param messages All messages to categorize
182
+ * @param preserveRecentTurns Number of recent turns to preserve (default: config value)
183
+ */
184
+ categorizeMessages(messages: Message[], preserveRecentTurns?: number): Promise<CategorizedMessages>;
185
+ /**
186
+ * Find which categories are over their budget allocation
187
+ *
188
+ * @param categorized Categorized messages from categorizeMessages()
189
+ * @returns Array of categories that exceed their budget, sorted by how much they exceed
190
+ */
191
+ findOverBudgetCategories(categorized: CategorizedMessages): ContextCategory[];
192
+ /**
193
+ * Smart compaction that respects category budgets
194
+ *
195
+ * Strategy:
196
+ * 1. System messages: Never compacted (critical for agent behavior)
197
+ * 2. Recent messages: Never compacted (needed for conversation continuity)
198
+ * 3. Tool results: Save large results to files, replace with references
199
+ * 4. History: Summarize with LLM
200
+ *
201
+ * The method compacts categories in order of how much they exceed their budget.
202
+ */
203
+ smartCompact(messages: Message[], options: SmartCompactOptions): Promise<{
204
+ messages: Message[];
205
+ result: SmartCompactionResult;
206
+ }>;
207
+ /**
208
+ * Compact tool results by saving large ones to files
209
+ */
210
+ private compactToolResults;
211
+ /**
212
+ * Calculate utilization given a token count
213
+ */
214
+ private calculateUtilization;
147
215
  /**
148
216
  * Estimate tokens for a string content
149
217
  */