@compilr-dev/agents 0.3.11 → 0.3.12
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/dist/agent.d.ts +23 -0
- package/dist/agent.js +41 -7
- package/dist/anchors/manager.js +3 -2
- package/dist/context/delegated-result-store.d.ts +67 -0
- package/dist/context/delegated-result-store.js +99 -0
- package/dist/context/delegation-types.d.ts +82 -0
- package/dist/context/delegation-types.js +18 -0
- package/dist/context/index.d.ts +6 -0
- package/dist/context/index.js +4 -0
- package/dist/context/manager.js +12 -32
- package/dist/context/tool-result-delegator.d.ts +63 -0
- package/dist/context/tool-result-delegator.js +305 -0
- package/dist/index.d.ts +5 -5
- package/dist/index.js +9 -3
- package/dist/memory/loader.js +2 -1
- package/dist/memory/types.d.ts +1 -1
- package/dist/providers/claude.d.ts +1 -5
- package/dist/providers/claude.js +3 -28
- package/dist/providers/gemini-native.d.ts +1 -1
- package/dist/providers/gemini-native.js +3 -24
- package/dist/providers/mock.d.ts +1 -1
- package/dist/providers/mock.js +3 -24
- package/dist/providers/openai-compatible.d.ts +1 -5
- package/dist/providers/openai-compatible.js +3 -28
- package/dist/rate-limit/provider-wrapper.d.ts +1 -1
- package/dist/rate-limit/provider-wrapper.js +3 -27
- package/dist/tools/builtin/index.d.ts +2 -0
- package/dist/tools/builtin/index.js +2 -0
- package/dist/tools/builtin/recall-result.d.ts +29 -0
- package/dist/tools/builtin/recall-result.js +48 -0
- package/dist/tools/index.d.ts +2 -2
- package/dist/tools/index.js +2 -0
- package/dist/utils/index.d.ts +1 -0
- package/dist/utils/index.js +2 -0
- package/dist/utils/tokenizer.d.ts +18 -0
- package/dist/utils/tokenizer.js +56 -0
- package/package.json +3 -2
package/dist/agent.d.ts
CHANGED
|
@@ -11,6 +11,7 @@ import type { ToolPermission, PermissionLevel, PermissionManagerOptions } from '
|
|
|
11
11
|
import type { ProjectMemoryOptions, ProjectMemory } from './memory/types.js';
|
|
12
12
|
import type { UsageTrackerOptions, UsageStats, BudgetStatus, TokenUsage } from './costs/types.js';
|
|
13
13
|
import type { HooksConfig } from './hooks/types.js';
|
|
14
|
+
import type { DelegationConfig } from './context/delegation-types.js';
|
|
14
15
|
import { PermissionManager } from './permissions/manager.js';
|
|
15
16
|
import { ContextManager } from './context/manager.js';
|
|
16
17
|
import { FileAccessTracker } from './context/file-tracker.js';
|
|
@@ -528,6 +529,28 @@ export interface AgentConfig {
|
|
|
528
529
|
* ```
|
|
529
530
|
*/
|
|
530
531
|
hooks?: HooksConfig;
|
|
532
|
+
/**
|
|
533
|
+
* Tool result delegation config. When set and enabled, large tool results
|
|
534
|
+
* are automatically summarized to conserve context tokens. Full results are
|
|
535
|
+
* stored in-memory for optional recall via `recall_full_result`.
|
|
536
|
+
*
|
|
537
|
+
* @example
|
|
538
|
+
* ```typescript
|
|
539
|
+
* const agent = new Agent({
|
|
540
|
+
* provider,
|
|
541
|
+
* delegation: {
|
|
542
|
+
* enabled: true,
|
|
543
|
+
* delegationThreshold: 8000, // tokens above which to delegate
|
|
544
|
+
* strategy: 'auto', // try LLM, fall back to extractive
|
|
545
|
+
* toolOverrides: {
|
|
546
|
+
* bash: { threshold: 12000 },
|
|
547
|
+
* grep: { threshold: 4000 },
|
|
548
|
+
* },
|
|
549
|
+
* },
|
|
550
|
+
* });
|
|
551
|
+
* ```
|
|
552
|
+
*/
|
|
553
|
+
delegation?: DelegationConfig;
|
|
531
554
|
/**
|
|
532
555
|
* Enable file access tracking for context restoration hints.
|
|
533
556
|
*
|
package/dist/agent.js
CHANGED
|
@@ -9,6 +9,8 @@ import { DefaultToolRegistry } from './tools/registry.js';
|
|
|
9
9
|
import { ContextManager } from './context/manager.js';
|
|
10
10
|
import { FileAccessTracker } from './context/file-tracker.js';
|
|
11
11
|
import { createFileTrackingHook } from './context/file-tracking-hook.js';
|
|
12
|
+
import { ToolResultDelegator, DELEGATION_SYSTEM_PROMPT } from './context/tool-result-delegator.js';
|
|
13
|
+
import { createRecallResultTool } from './tools/builtin/recall-result.js';
|
|
12
14
|
import { AnchorManager } from './anchors/manager.js';
|
|
13
15
|
import { GuardrailManager } from './guardrails/manager.js';
|
|
14
16
|
import { MaxIterationsError, ToolLoopError, ProviderError } from './errors.js';
|
|
@@ -177,19 +179,50 @@ export class Agent {
|
|
|
177
179
|
}
|
|
178
180
|
});
|
|
179
181
|
}
|
|
182
|
+
// Build hooks config (may be extended by file tracking and delegation)
|
|
183
|
+
const hooksConfig = config.hooks ? { ...config.hooks } : {};
|
|
184
|
+
let needsHooksManager = config.hooks !== undefined;
|
|
185
|
+
// Tool result delegation — auto-summarize large results
|
|
186
|
+
if (config.delegation?.enabled) {
|
|
187
|
+
const delegator = new ToolResultDelegator({
|
|
188
|
+
provider: config.provider,
|
|
189
|
+
config: config.delegation,
|
|
190
|
+
onEvent: (event) => {
|
|
191
|
+
this.onEvent?.({
|
|
192
|
+
type: 'custom',
|
|
193
|
+
name: event.type,
|
|
194
|
+
data: event,
|
|
195
|
+
});
|
|
196
|
+
},
|
|
197
|
+
});
|
|
198
|
+
hooksConfig.afterTool = hooksConfig.afterTool ?? [];
|
|
199
|
+
hooksConfig.afterTool.push(delegator.createHook());
|
|
200
|
+
needsHooksManager = true;
|
|
201
|
+
// Register recall_full_result tool
|
|
202
|
+
this.registerTool(createRecallResultTool({
|
|
203
|
+
store: delegator.getStore(),
|
|
204
|
+
onEvent: (event) => {
|
|
205
|
+
this.onEvent?.({
|
|
206
|
+
type: 'custom',
|
|
207
|
+
name: event.type,
|
|
208
|
+
data: event,
|
|
209
|
+
});
|
|
210
|
+
},
|
|
211
|
+
}));
|
|
212
|
+
// Append delegation instructions to system prompt
|
|
213
|
+
this.systemPrompt += DELEGATION_SYSTEM_PROMPT;
|
|
214
|
+
}
|
|
180
215
|
// File tracking for context restoration hints
|
|
181
216
|
if (config.enableFileTracking && config.contextManager) {
|
|
182
217
|
this.fileTracker = new FileAccessTracker();
|
|
183
218
|
const trackingHook = createFileTrackingHook(this.fileTracker);
|
|
184
|
-
// Merge with existing hooks or create new hooks config
|
|
185
|
-
const hooksConfig = config.hooks ?? {};
|
|
186
219
|
hooksConfig.afterTool = hooksConfig.afterTool ?? [];
|
|
187
220
|
hooksConfig.afterTool.push(trackingHook);
|
|
188
|
-
|
|
221
|
+
needsHooksManager = true;
|
|
189
222
|
}
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
this.hooksManager = new HooksManager({ hooks:
|
|
223
|
+
// Create hooks manager if any hooks were configured
|
|
224
|
+
if (needsHooksManager) {
|
|
225
|
+
this.hooksManager = new HooksManager({ hooks: hooksConfig });
|
|
193
226
|
}
|
|
194
227
|
// Retry configuration with defaults
|
|
195
228
|
this.retryConfig = {
|
|
@@ -2098,7 +2131,8 @@ export class Agent {
|
|
|
2098
2131
|
throw new MaxIterationsError(maxIterations);
|
|
2099
2132
|
}
|
|
2100
2133
|
}
|
|
2101
|
-
if (!aborted &&
|
|
2134
|
+
if (!aborted &&
|
|
2135
|
+
!(iterations >= maxIterations && this.iterationLimitBehavior === 'summarize')) {
|
|
2102
2136
|
emit({ type: 'done', response: finalResponse });
|
|
2103
2137
|
}
|
|
2104
2138
|
}
|
package/dist/anchors/manager.js
CHANGED
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
import * as fs from 'node:fs';
|
|
5
5
|
import * as path from 'node:path';
|
|
6
6
|
import { generateId } from '../utils/index.js';
|
|
7
|
+
import { countTokens } from '../utils/tokenizer.js';
|
|
7
8
|
import { getDefaultAnchors, isBuiltinAnchor } from './builtin.js';
|
|
8
9
|
/**
|
|
9
10
|
* Default options for AnchorManager
|
|
@@ -14,10 +15,10 @@ const DEFAULT_OPTIONS = {
|
|
|
14
15
|
includeDefaults: true,
|
|
15
16
|
};
|
|
16
17
|
/**
|
|
17
|
-
* Default token estimator
|
|
18
|
+
* Default token estimator using tiktoken (cl100k_base encoding)
|
|
18
19
|
*/
|
|
19
20
|
function defaultEstimateTokens(content) {
|
|
20
|
-
return
|
|
21
|
+
return countTokens(content);
|
|
21
22
|
}
|
|
22
23
|
/**
|
|
23
24
|
* AnchorManager - Manages critical information that survives context compaction
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* In-memory store for delegated tool results.
|
|
3
|
+
*
|
|
4
|
+
* Stores full tool results that were replaced by summaries, allowing
|
|
5
|
+
* the agent to recall them via `recall_full_result`. Implements TTL
|
|
6
|
+
* expiration and LRU eviction.
|
|
7
|
+
*/
|
|
8
|
+
import type { StoredResult } from './delegation-types.js';
|
|
9
|
+
/**
|
|
10
|
+
* Statistics about the delegation store.
|
|
11
|
+
*/
|
|
12
|
+
export interface DelegatedResultStoreStats {
|
|
13
|
+
/** Number of currently stored results */
|
|
14
|
+
size: number;
|
|
15
|
+
/** Maximum capacity (LRU limit) */
|
|
16
|
+
maxSize: number;
|
|
17
|
+
/** Total results stored since creation */
|
|
18
|
+
totalStored: number;
|
|
19
|
+
/** Total results evicted (TTL or LRU) */
|
|
20
|
+
totalEvicted: number;
|
|
21
|
+
/** Total results successfully recalled */
|
|
22
|
+
totalRecalled: number;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* In-memory store for delegated results with TTL expiration and LRU eviction.
|
|
26
|
+
*/
|
|
27
|
+
export declare class DelegatedResultStore {
|
|
28
|
+
private readonly results;
|
|
29
|
+
private readonly maxSize;
|
|
30
|
+
private readonly defaultTTL;
|
|
31
|
+
private counter;
|
|
32
|
+
private totalStored;
|
|
33
|
+
private totalEvicted;
|
|
34
|
+
private totalRecalled;
|
|
35
|
+
constructor(options?: {
|
|
36
|
+
maxSize?: number;
|
|
37
|
+
defaultTTL?: number;
|
|
38
|
+
});
|
|
39
|
+
/**
|
|
40
|
+
* Generate a unique delegation ID.
|
|
41
|
+
*/
|
|
42
|
+
generateId(): string;
|
|
43
|
+
/**
|
|
44
|
+
* Store a delegated result. Evicts oldest entries if at capacity.
|
|
45
|
+
*/
|
|
46
|
+
add(result: StoredResult): void;
|
|
47
|
+
/**
|
|
48
|
+
* Get a stored result by ID. Returns undefined if not found or expired.
|
|
49
|
+
*/
|
|
50
|
+
get(id: string): StoredResult | undefined;
|
|
51
|
+
/**
|
|
52
|
+
* Remove all expired entries.
|
|
53
|
+
*/
|
|
54
|
+
cleanup(): void;
|
|
55
|
+
/**
|
|
56
|
+
* Clear all stored results.
|
|
57
|
+
*/
|
|
58
|
+
clear(): void;
|
|
59
|
+
/**
|
|
60
|
+
* Get the default TTL for this store.
|
|
61
|
+
*/
|
|
62
|
+
getDefaultTTL(): number;
|
|
63
|
+
/**
|
|
64
|
+
* Get store statistics.
|
|
65
|
+
*/
|
|
66
|
+
getStats(): DelegatedResultStoreStats;
|
|
67
|
+
}
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* In-memory store for delegated tool results.
|
|
3
|
+
*
|
|
4
|
+
* Stores full tool results that were replaced by summaries, allowing
|
|
5
|
+
* the agent to recall them via `recall_full_result`. Implements TTL
|
|
6
|
+
* expiration and LRU eviction.
|
|
7
|
+
*/
|
|
8
|
+
/**
|
|
9
|
+
* In-memory store for delegated results with TTL expiration and LRU eviction.
|
|
10
|
+
*/
|
|
11
|
+
export class DelegatedResultStore {
|
|
12
|
+
results = new Map();
|
|
13
|
+
maxSize;
|
|
14
|
+
defaultTTL;
|
|
15
|
+
counter = 0;
|
|
16
|
+
totalStored = 0;
|
|
17
|
+
totalEvicted = 0;
|
|
18
|
+
totalRecalled = 0;
|
|
19
|
+
constructor(options) {
|
|
20
|
+
this.maxSize = options?.maxSize ?? 50;
|
|
21
|
+
this.defaultTTL = options?.defaultTTL ?? 600_000;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Generate a unique delegation ID.
|
|
25
|
+
*/
|
|
26
|
+
generateId() {
|
|
27
|
+
return `dr_${String(Date.now())}_${String(this.counter++)}`;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Store a delegated result. Evicts oldest entries if at capacity.
|
|
31
|
+
*/
|
|
32
|
+
add(result) {
|
|
33
|
+
// Evict expired entries first
|
|
34
|
+
this.cleanup();
|
|
35
|
+
// LRU eviction: remove oldest entries if at capacity
|
|
36
|
+
while (this.results.size >= this.maxSize) {
|
|
37
|
+
const oldestKey = this.results.keys().next().value;
|
|
38
|
+
this.results.delete(oldestKey);
|
|
39
|
+
this.totalEvicted++;
|
|
40
|
+
}
|
|
41
|
+
this.results.set(result.id, result);
|
|
42
|
+
this.totalStored++;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Get a stored result by ID. Returns undefined if not found or expired.
|
|
46
|
+
*/
|
|
47
|
+
get(id) {
|
|
48
|
+
const result = this.results.get(id);
|
|
49
|
+
if (!result)
|
|
50
|
+
return undefined;
|
|
51
|
+
// Check TTL
|
|
52
|
+
if (Date.now() > result.expiresAt) {
|
|
53
|
+
this.results.delete(id);
|
|
54
|
+
this.totalEvicted++;
|
|
55
|
+
return undefined;
|
|
56
|
+
}
|
|
57
|
+
// Move to end for LRU (delete + re-insert)
|
|
58
|
+
this.results.delete(id);
|
|
59
|
+
this.results.set(id, result);
|
|
60
|
+
this.totalRecalled++;
|
|
61
|
+
return result;
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Remove all expired entries.
|
|
65
|
+
*/
|
|
66
|
+
cleanup() {
|
|
67
|
+
const now = Date.now();
|
|
68
|
+
for (const [id, result] of this.results) {
|
|
69
|
+
if (now > result.expiresAt) {
|
|
70
|
+
this.results.delete(id);
|
|
71
|
+
this.totalEvicted++;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Clear all stored results.
|
|
77
|
+
*/
|
|
78
|
+
clear() {
|
|
79
|
+
this.results.clear();
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Get the default TTL for this store.
|
|
83
|
+
*/
|
|
84
|
+
getDefaultTTL() {
|
|
85
|
+
return this.defaultTTL;
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Get store statistics.
|
|
89
|
+
*/
|
|
90
|
+
getStats() {
|
|
91
|
+
return {
|
|
92
|
+
size: this.results.size,
|
|
93
|
+
maxSize: this.maxSize,
|
|
94
|
+
totalStored: this.totalStored,
|
|
95
|
+
totalEvicted: this.totalEvicted,
|
|
96
|
+
totalRecalled: this.totalRecalled,
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Types for tool result auto-delegation.
|
|
3
|
+
*
|
|
4
|
+
* When large tool results exceed a token threshold, they are automatically
|
|
5
|
+
* summarized and stored for optional recall. This conserves context tokens
|
|
6
|
+
* while preserving access to the full data.
|
|
7
|
+
*/
|
|
8
|
+
/**
|
|
9
|
+
* Configuration for tool result delegation.
|
|
10
|
+
* Controls when and how large tool results are summarized.
|
|
11
|
+
*/
|
|
12
|
+
export interface DelegationConfig {
|
|
13
|
+
/** Whether delegation is enabled. Default: false (opt-in) */
|
|
14
|
+
enabled: boolean;
|
|
15
|
+
/** Token count above which results are delegated. Default: 8000 */
|
|
16
|
+
delegationThreshold: number;
|
|
17
|
+
/** Maximum tokens for the summary. Default: 800 */
|
|
18
|
+
summaryMaxTokens: number;
|
|
19
|
+
/** Milliseconds before stored results expire. Default: 600_000 (10 min) */
|
|
20
|
+
resultTTL: number;
|
|
21
|
+
/** Maximum number of stored results (LRU eviction). Default: 50 */
|
|
22
|
+
maxStoredResults: number;
|
|
23
|
+
/** Summarization strategy. Default: 'auto' */
|
|
24
|
+
strategy: 'llm' | 'extractive' | 'auto';
|
|
25
|
+
/** Per-tool threshold/strategy overrides */
|
|
26
|
+
toolOverrides?: Record<string, {
|
|
27
|
+
enabled?: boolean;
|
|
28
|
+
threshold?: number;
|
|
29
|
+
strategy?: 'llm' | 'extractive' | 'auto';
|
|
30
|
+
}>;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* A stored full result that was replaced by a summary.
|
|
34
|
+
*/
|
|
35
|
+
export interface StoredResult {
|
|
36
|
+
/** Unique delegation ID, e.g., 'dr_1707900000_0' */
|
|
37
|
+
id: string;
|
|
38
|
+
/** Name of the tool that produced the result */
|
|
39
|
+
toolName: string;
|
|
40
|
+
/** Input parameters passed to the tool */
|
|
41
|
+
toolInput: Record<string, unknown>;
|
|
42
|
+
/** The full serialized result content */
|
|
43
|
+
fullContent: string;
|
|
44
|
+
/** Token count of the full content */
|
|
45
|
+
fullTokens: number;
|
|
46
|
+
/** The generated summary */
|
|
47
|
+
summary: string;
|
|
48
|
+
/** Token count of the summary */
|
|
49
|
+
summaryTokens: number;
|
|
50
|
+
/** Timestamp when stored */
|
|
51
|
+
storedAt: number;
|
|
52
|
+
/** Timestamp when this result expires */
|
|
53
|
+
expiresAt: number;
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Events emitted during the delegation lifecycle.
|
|
57
|
+
*/
|
|
58
|
+
export type DelegationEvent = {
|
|
59
|
+
type: 'delegation:started';
|
|
60
|
+
toolName: string;
|
|
61
|
+
originalTokens: number;
|
|
62
|
+
delegationId: string;
|
|
63
|
+
} | {
|
|
64
|
+
type: 'delegation:completed';
|
|
65
|
+
toolName: string;
|
|
66
|
+
originalTokens: number;
|
|
67
|
+
summaryTokens: number;
|
|
68
|
+
delegationId: string;
|
|
69
|
+
strategy: 'llm' | 'extractive';
|
|
70
|
+
} | {
|
|
71
|
+
type: 'delegation:failed';
|
|
72
|
+
toolName: string;
|
|
73
|
+
error: string;
|
|
74
|
+
} | {
|
|
75
|
+
type: 'delegation:recall';
|
|
76
|
+
delegationId: string;
|
|
77
|
+
found: boolean;
|
|
78
|
+
};
|
|
79
|
+
/**
|
|
80
|
+
* Default delegation configuration values.
|
|
81
|
+
*/
|
|
82
|
+
export declare const DEFAULT_DELEGATION_CONFIG: DelegationConfig;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Types for tool result auto-delegation.
|
|
3
|
+
*
|
|
4
|
+
* When large tool results exceed a token threshold, they are automatically
|
|
5
|
+
* summarized and stored for optional recall. This conserves context tokens
|
|
6
|
+
* while preserving access to the full data.
|
|
7
|
+
*/
|
|
8
|
+
/**
|
|
9
|
+
* Default delegation configuration values.
|
|
10
|
+
*/
|
|
11
|
+
export const DEFAULT_DELEGATION_CONFIG = {
|
|
12
|
+
enabled: false,
|
|
13
|
+
delegationThreshold: 8000,
|
|
14
|
+
summaryMaxTokens: 800,
|
|
15
|
+
resultTTL: 600_000,
|
|
16
|
+
maxStoredResults: 50,
|
|
17
|
+
strategy: 'auto',
|
|
18
|
+
};
|
package/dist/context/index.d.ts
CHANGED
|
@@ -14,3 +14,9 @@ export { FileAccessTracker } from './file-tracker.js';
|
|
|
14
14
|
export type { FileAccessType, FileAccess, FileAccessTrackerOptions, FormatHintsOptions, FileAccessStats, } from './file-tracker.js';
|
|
15
15
|
export { createFileTrackingHook, TRACKED_TOOLS } from './file-tracking-hook.js';
|
|
16
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';
|
|
17
|
+
export { DelegatedResultStore } from './delegated-result-store.js';
|
|
18
|
+
export type { DelegatedResultStoreStats } from './delegated-result-store.js';
|
|
19
|
+
export { ToolResultDelegator, DELEGATION_SYSTEM_PROMPT } from './tool-result-delegator.js';
|
|
20
|
+
export type { ToolResultDelegatorOptions } from './tool-result-delegator.js';
|
|
21
|
+
export { DEFAULT_DELEGATION_CONFIG } from './delegation-types.js';
|
|
22
|
+
export type { DelegationConfig, StoredResult, DelegationEvent } from './delegation-types.js';
|
package/dist/context/index.js
CHANGED
|
@@ -11,3 +11,7 @@
|
|
|
11
11
|
export { ContextManager, DEFAULT_CONTEXT_CONFIG } from './manager.js';
|
|
12
12
|
export { FileAccessTracker } from './file-tracker.js';
|
|
13
13
|
export { createFileTrackingHook, TRACKED_TOOLS } from './file-tracking-hook.js';
|
|
14
|
+
// Tool Result Delegation
|
|
15
|
+
export { DelegatedResultStore } from './delegated-result-store.js';
|
|
16
|
+
export { ToolResultDelegator, DELEGATION_SYSTEM_PROMPT } from './tool-result-delegator.js';
|
|
17
|
+
export { DEFAULT_DELEGATION_CONFIG } from './delegation-types.js';
|
package/dist/context/manager.js
CHANGED
|
@@ -18,6 +18,7 @@
|
|
|
18
18
|
* ```
|
|
19
19
|
*/
|
|
20
20
|
import { repairToolPairing } from '../messages/index.js';
|
|
21
|
+
import { countTokens, countMessageTokens } from '../utils/tokenizer.js';
|
|
21
22
|
/**
|
|
22
23
|
* Default budget allocation
|
|
23
24
|
*/
|
|
@@ -122,29 +123,8 @@ export class ContextManager {
|
|
|
122
123
|
if (this.provider.countTokens) {
|
|
123
124
|
return this.provider.countTokens(messages);
|
|
124
125
|
}
|
|
125
|
-
// Fallback:
|
|
126
|
-
|
|
127
|
-
for (const msg of messages) {
|
|
128
|
-
if (typeof msg.content === 'string') {
|
|
129
|
-
charCount += msg.content.length;
|
|
130
|
-
}
|
|
131
|
-
else {
|
|
132
|
-
for (const block of msg.content) {
|
|
133
|
-
switch (block.type) {
|
|
134
|
-
case 'text':
|
|
135
|
-
charCount += block.text.length;
|
|
136
|
-
break;
|
|
137
|
-
case 'tool_use':
|
|
138
|
-
charCount += JSON.stringify(block.input).length;
|
|
139
|
-
break;
|
|
140
|
-
case 'tool_result':
|
|
141
|
-
charCount += block.content.length;
|
|
142
|
-
break;
|
|
143
|
-
}
|
|
144
|
-
}
|
|
145
|
-
}
|
|
146
|
-
}
|
|
147
|
-
return Math.ceil(charCount / 4);
|
|
126
|
+
// Fallback: count tokens using tiktoken
|
|
127
|
+
return countMessageTokens(messages);
|
|
148
128
|
}
|
|
149
129
|
/**
|
|
150
130
|
* Update token count for messages
|
|
@@ -351,7 +331,7 @@ export class ContextManager {
|
|
|
351
331
|
}
|
|
352
332
|
// Compact this message
|
|
353
333
|
if (typeof msg.content === 'string') {
|
|
354
|
-
const tokens =
|
|
334
|
+
const tokens = countTokens(msg.content);
|
|
355
335
|
if (tokens >= this.config.compaction.minTokensToCompact) {
|
|
356
336
|
const filePath = await saveToFile(msg.content, compactedIndex++);
|
|
357
337
|
filesCreated.push(filePath);
|
|
@@ -369,7 +349,7 @@ export class ContextManager {
|
|
|
369
349
|
const compactedBlocks = [];
|
|
370
350
|
for (const block of msg.content) {
|
|
371
351
|
if (block.type === 'tool_result' && category === 'toolResults') {
|
|
372
|
-
const tokens =
|
|
352
|
+
const tokens = countTokens(block.content);
|
|
373
353
|
if (tokens >= this.config.compaction.minTokensToCompact) {
|
|
374
354
|
const filePath = await saveToFile(block.content, compactedIndex++);
|
|
375
355
|
filesCreated.push(filePath);
|
|
@@ -702,7 +682,7 @@ export class ContextManager {
|
|
|
702
682
|
* Estimate tokens for a string content
|
|
703
683
|
*/
|
|
704
684
|
estimateTokens(content) {
|
|
705
|
-
return
|
|
685
|
+
return countTokens(content);
|
|
706
686
|
}
|
|
707
687
|
/**
|
|
708
688
|
* Check if content can be added to a category
|
|
@@ -822,13 +802,13 @@ export class ContextManager {
|
|
|
822
802
|
maxLines = this.config.filtering.maxErrorLines;
|
|
823
803
|
break;
|
|
824
804
|
default: {
|
|
825
|
-
// For tool results, check token count
|
|
826
|
-
const estimatedTokens =
|
|
805
|
+
// For tool results, check token count
|
|
806
|
+
const estimatedTokens = countTokens(content);
|
|
827
807
|
if (estimatedTokens <= this.config.filtering.maxToolResultTokens) {
|
|
828
808
|
return { content, filtered: false, originalLength };
|
|
829
809
|
}
|
|
830
|
-
// Truncate to roughly maxToolResultTokens
|
|
831
|
-
const maxChars = this.config.filtering.maxToolResultTokens *
|
|
810
|
+
// Truncate to roughly maxToolResultTokens (~3 chars per token)
|
|
811
|
+
const maxChars = this.config.filtering.maxToolResultTokens * 3;
|
|
832
812
|
const truncated = content.slice(0, maxChars);
|
|
833
813
|
return {
|
|
834
814
|
content: truncated + '\n\n[Content truncated - see file for full output]',
|
|
@@ -877,7 +857,7 @@ export class ContextManager {
|
|
|
877
857
|
for (const msg of oldMessages) {
|
|
878
858
|
if (typeof msg.content === 'string') {
|
|
879
859
|
// Check if string content is large enough to compact
|
|
880
|
-
const tokens =
|
|
860
|
+
const tokens = countTokens(msg.content);
|
|
881
861
|
if (tokens >= this.config.compaction.minTokensToCompact) {
|
|
882
862
|
const filePath = await saveToFile(msg.content, compactedIndex++);
|
|
883
863
|
filesCreated.push(filePath);
|
|
@@ -895,7 +875,7 @@ export class ContextManager {
|
|
|
895
875
|
const compactedBlocks = [];
|
|
896
876
|
for (const block of msg.content) {
|
|
897
877
|
if (block.type === 'tool_result') {
|
|
898
|
-
const tokens =
|
|
878
|
+
const tokens = countTokens(block.content);
|
|
899
879
|
if (tokens >= this.config.compaction.minTokensToCompact) {
|
|
900
880
|
const filePath = await saveToFile(block.content, compactedIndex++);
|
|
901
881
|
filesCreated.push(filePath);
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tool Result Delegator
|
|
3
|
+
*
|
|
4
|
+
* Intercepts large tool results via the AfterToolHook mechanism,
|
|
5
|
+
* stores the full result for optional recall, and replaces it
|
|
6
|
+
* with a compact summary to conserve context tokens.
|
|
7
|
+
*/
|
|
8
|
+
import type { LLMProvider } from '../providers/types.js';
|
|
9
|
+
import type { AfterToolHook } from '../hooks/types.js';
|
|
10
|
+
import type { DelegationConfig, DelegationEvent } from './delegation-types.js';
|
|
11
|
+
import { DelegatedResultStore } from './delegated-result-store.js';
|
|
12
|
+
/**
|
|
13
|
+
* Options for creating a ToolResultDelegator.
|
|
14
|
+
*/
|
|
15
|
+
export interface ToolResultDelegatorOptions {
|
|
16
|
+
/** LLM provider for summarization (small/medium tier preferred) */
|
|
17
|
+
provider: LLMProvider;
|
|
18
|
+
/** Delegation configuration (merged with defaults) */
|
|
19
|
+
config?: Partial<DelegationConfig>;
|
|
20
|
+
/** Event callback for delegation lifecycle events */
|
|
21
|
+
onEvent?: (event: DelegationEvent) => void;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Core class that creates an AfterToolHook for auto-delegating large tool results.
|
|
25
|
+
*/
|
|
26
|
+
export declare class ToolResultDelegator {
|
|
27
|
+
private readonly store;
|
|
28
|
+
private readonly config;
|
|
29
|
+
private readonly provider;
|
|
30
|
+
private readonly onEvent?;
|
|
31
|
+
constructor(options: ToolResultDelegatorOptions);
|
|
32
|
+
/**
|
|
33
|
+
* Returns an AfterToolHook to register with HooksManager.
|
|
34
|
+
*/
|
|
35
|
+
createHook(): AfterToolHook;
|
|
36
|
+
/**
|
|
37
|
+
* Perform the actual delegation (async path).
|
|
38
|
+
*/
|
|
39
|
+
private delegateResult;
|
|
40
|
+
/**
|
|
41
|
+
* Access the store (needed by recall_full_result tool).
|
|
42
|
+
*/
|
|
43
|
+
getStore(): DelegatedResultStore;
|
|
44
|
+
/**
|
|
45
|
+
* Get the resolved config for a specific tool.
|
|
46
|
+
*/
|
|
47
|
+
private getToolConfig;
|
|
48
|
+
/**
|
|
49
|
+
* Extractive summarization: first/last lines + prioritized structural markers.
|
|
50
|
+
* No LLM cost, fast, preserves actual code signatures.
|
|
51
|
+
*/
|
|
52
|
+
private summarizeExtractive;
|
|
53
|
+
/**
|
|
54
|
+
* LLM-based summarization using the provider.
|
|
55
|
+
* Returns null if the LLM call fails.
|
|
56
|
+
*/
|
|
57
|
+
private summarizeLLM;
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* System prompt addition when delegation is enabled.
|
|
61
|
+
* Append to the agent's system prompt.
|
|
62
|
+
*/
|
|
63
|
+
export declare const DELEGATION_SYSTEM_PROMPT: string;
|