@codebolt/agent 6.0.0 → 6.1.2
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/README.md +118 -153
- package/dist/index.d.ts +2 -0
- package/dist/index.js +41 -0
- package/dist/processor-pieces/messageModifiers/chatHistoryMessageModifier.js +2 -4
- package/dist/processor-pieces/messageModifiers/contextAssemblyModifier.d.ts +81 -0
- package/dist/processor-pieces/messageModifiers/contextAssemblyModifier.js +316 -0
- package/dist/processor-pieces/messageModifiers/coreSystemPromptModifier.js +2 -19
- package/dist/processor-pieces/messageModifiers/directoryContextModifier.js +2 -6
- package/dist/processor-pieces/messageModifiers/environmentContextModifier.js +2 -7
- package/dist/processor-pieces/messageModifiers/ideContextModifier.js +2 -21
- package/dist/processor-pieces/messageModifiers/index.d.ts +3 -0
- package/dist/processor-pieces/messageModifiers/index.js +7 -1
- package/dist/processor-pieces/messageModifiers/toolInjectionModifier.js +2 -1
- package/dist/processor-pieces/postToolCallProcessors/conversationCompactorModifier.d.ts +34 -5
- package/dist/processor-pieces/postToolCallProcessors/conversationCompactorModifier.js +374 -89
- package/dist/processor-pieces/preInferenceProcessors/chatCompressionModifier.d.ts +3 -0
- package/dist/processor-pieces/preInferenceProcessors/chatCompressionModifier.js +50 -27
- package/dist/unified/agent/agent.d.ts +10 -0
- package/dist/unified/agent/agent.js +198 -10
- package/dist/unified/agent/codeboltAgent.d.ts +19 -100
- package/dist/unified/agent/codeboltAgent.js +209 -109
- package/dist/unified/base/agentStep.js +17 -17
- package/dist/unified/base/initialPromptGenerator.js +13 -31
- package/dist/unified/base/promptContext.d.ts +13 -0
- package/dist/unified/base/promptContext.js +213 -0
- package/dist/unified/base/responseExecutor.d.ts +7 -19
- package/dist/unified/base/responseExecutor.js +280 -259
- package/dist/unified/index.d.ts +9 -0
- package/dist/unified/index.js +20 -13
- package/dist/unified/services/CompressionCoordinator.d.ts +67 -0
- package/dist/unified/services/CompressionCoordinator.js +214 -0
- package/dist/unified/services/compaction/autoCompact.d.ts +52 -0
- package/dist/unified/services/compaction/autoCompact.js +294 -0
- package/dist/unified/services/compaction/compactionOrchestrator.d.ts +78 -0
- package/dist/unified/services/compaction/compactionOrchestrator.js +230 -0
- package/dist/unified/services/compaction/contextCollapse.d.ts +63 -0
- package/dist/unified/services/compaction/contextCollapse.js +291 -0
- package/dist/unified/services/compaction/microCompact.d.ts +34 -0
- package/dist/unified/services/compaction/microCompact.js +195 -0
- package/dist/unified/services/compaction/postCompactCleanup.d.ts +15 -0
- package/dist/unified/services/compaction/postCompactCleanup.js +37 -0
- package/dist/unified/services/compaction/reactiveCompact.d.ts +65 -0
- package/dist/unified/services/compaction/reactiveCompact.js +301 -0
- package/dist/unified/services/compaction/snipCompact.d.ts +31 -0
- package/dist/unified/services/compaction/snipCompact.js +124 -0
- package/dist/unified/services/compaction/types.d.ts +66 -0
- package/dist/unified/services/compaction/types.js +39 -0
- package/package.json +25 -29
package/dist/unified/index.js
CHANGED
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
* The framework is designed to be modular, extensible, and easy to use.
|
|
11
11
|
*/
|
|
12
12
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
13
|
-
exports.Workflow = exports.createTool = exports.Tool = exports.createCodeboltAgent = exports.CodeboltAgent = exports.Agent = exports.LoopType = exports.LoopDetectionService = exports.ResponseExecutor = exports.AgentStep = exports.InitialPromptGenerator = exports.createDefaultMessageProcessor = exports.UnifiedToolExecutionError = exports.UnifiedResponseExecutionError = exports.UnifiedStepExecutionError = exports.UnifiedMessageProcessingError = exports.UnifiedAgentError = void 0;
|
|
13
|
+
exports.TokenEstimator = exports.PostCompactCleanup = exports.ReactiveCompact = exports.AutoCompact = exports.ContextCollapse = exports.MicroCompact = exports.SnipCompact = exports.CompactionOrchestrator = exports.Workflow = exports.createTool = exports.Tool = exports.createCodeboltAgent = exports.CodeboltAgent = exports.Agent = exports.CompressionCoordinator = exports.LoopType = exports.LoopDetectionService = exports.ResponseExecutor = exports.AgentStep = exports.InitialPromptGenerator = exports.createDefaultMessageProcessor = exports.UnifiedToolExecutionError = exports.UnifiedResponseExecutionError = exports.UnifiedStepExecutionError = exports.UnifiedMessageProcessingError = exports.UnifiedAgentError = void 0;
|
|
14
14
|
// Error types
|
|
15
15
|
var types_1 = require("./types/types");
|
|
16
16
|
Object.defineProperty(exports, "UnifiedAgentError", { enumerable: true, get: function () { return types_1.UnifiedAgentError; } });
|
|
@@ -30,6 +30,8 @@ Object.defineProperty(exports, "ResponseExecutor", { enumerable: true, get: func
|
|
|
30
30
|
var LoopDetectionService_1 = require("./services/LoopDetectionService");
|
|
31
31
|
Object.defineProperty(exports, "LoopDetectionService", { enumerable: true, get: function () { return LoopDetectionService_1.LoopDetectionService; } });
|
|
32
32
|
Object.defineProperty(exports, "LoopType", { enumerable: true, get: function () { return LoopDetectionService_1.LoopType; } });
|
|
33
|
+
var CompressionCoordinator_1 = require("./services/CompressionCoordinator");
|
|
34
|
+
Object.defineProperty(exports, "CompressionCoordinator", { enumerable: true, get: function () { return CompressionCoordinator_1.CompressionCoordinator; } });
|
|
33
35
|
// Agent framework components
|
|
34
36
|
var agent_1 = require("./agent/agent");
|
|
35
37
|
Object.defineProperty(exports, "Agent", { enumerable: true, get: function () { return agent_1.Agent; } });
|
|
@@ -42,15 +44,20 @@ Object.defineProperty(exports, "createTool", { enumerable: true, get: function (
|
|
|
42
44
|
var workflow_1 = require("./agent/workflow");
|
|
43
45
|
Object.defineProperty(exports, "Workflow", { enumerable: true, get: function () { return workflow_1.Workflow; } });
|
|
44
46
|
// Workflow step factories
|
|
45
|
-
//
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
47
|
+
// Multi-layer compaction system
|
|
48
|
+
var compactionOrchestrator_1 = require("./services/compaction/compactionOrchestrator");
|
|
49
|
+
Object.defineProperty(exports, "CompactionOrchestrator", { enumerable: true, get: function () { return compactionOrchestrator_1.CompactionOrchestrator; } });
|
|
50
|
+
var snipCompact_1 = require("./services/compaction/snipCompact");
|
|
51
|
+
Object.defineProperty(exports, "SnipCompact", { enumerable: true, get: function () { return snipCompact_1.SnipCompact; } });
|
|
52
|
+
var microCompact_1 = require("./services/compaction/microCompact");
|
|
53
|
+
Object.defineProperty(exports, "MicroCompact", { enumerable: true, get: function () { return microCompact_1.MicroCompact; } });
|
|
54
|
+
var contextCollapse_1 = require("./services/compaction/contextCollapse");
|
|
55
|
+
Object.defineProperty(exports, "ContextCollapse", { enumerable: true, get: function () { return contextCollapse_1.ContextCollapse; } });
|
|
56
|
+
var autoCompact_1 = require("./services/compaction/autoCompact");
|
|
57
|
+
Object.defineProperty(exports, "AutoCompact", { enumerable: true, get: function () { return autoCompact_1.AutoCompact; } });
|
|
58
|
+
var reactiveCompact_1 = require("./services/compaction/reactiveCompact");
|
|
59
|
+
Object.defineProperty(exports, "ReactiveCompact", { enumerable: true, get: function () { return reactiveCompact_1.ReactiveCompact; } });
|
|
60
|
+
var postCompactCleanup_1 = require("./services/compaction/postCompactCleanup");
|
|
61
|
+
Object.defineProperty(exports, "PostCompactCleanup", { enumerable: true, get: function () { return postCompactCleanup_1.PostCompactCleanup; } });
|
|
62
|
+
var types_2 = require("./services/compaction/types");
|
|
63
|
+
Object.defineProperty(exports, "TokenEstimator", { enumerable: true, get: function () { return types_2.TokenEstimator; } });
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import type { ProcessedMessage } from '@codebolt/types/agent';
|
|
2
|
+
import type { FlatUserMessage } from '@codebolt/types/sdk';
|
|
3
|
+
import { ChatCompressionModifier, ConversationCompactorModifier } from '../../processor-pieces';
|
|
4
|
+
export type CompressionStage = 'pre_inference' | 'post_tool' | 'reactive_force_compact';
|
|
5
|
+
export interface CompressionCoordinatorOptions {
|
|
6
|
+
enabled?: boolean;
|
|
7
|
+
proactiveThreshold?: number;
|
|
8
|
+
postToolThreshold?: number;
|
|
9
|
+
preserveThreshold?: number;
|
|
10
|
+
toolResponseTokenBudget?: number;
|
|
11
|
+
truncateLines?: number;
|
|
12
|
+
reactiveRetryLimit?: number;
|
|
13
|
+
modelTokenLimit?: number;
|
|
14
|
+
compactStrategy?: 'simple' | 'smart' | 'summarize';
|
|
15
|
+
enableLogging?: boolean;
|
|
16
|
+
}
|
|
17
|
+
export interface CompressionMetadata {
|
|
18
|
+
status: string;
|
|
19
|
+
stage: CompressionStage;
|
|
20
|
+
originalTokenCount: number;
|
|
21
|
+
newTokenCount: number;
|
|
22
|
+
timestamp: string;
|
|
23
|
+
strategy: string;
|
|
24
|
+
messagesCompressed?: number;
|
|
25
|
+
messagesPreserved?: number;
|
|
26
|
+
toolOutputsTruncated?: boolean;
|
|
27
|
+
failedAttempts?: number;
|
|
28
|
+
reactiveRetryCount?: number;
|
|
29
|
+
reason?: string;
|
|
30
|
+
}
|
|
31
|
+
export interface CompressionDecision {
|
|
32
|
+
shouldCompress: boolean;
|
|
33
|
+
estimatedTokens: number;
|
|
34
|
+
threshold: number;
|
|
35
|
+
reason: string;
|
|
36
|
+
}
|
|
37
|
+
export interface CompressionRecoveryResult {
|
|
38
|
+
recoveredMessage: ProcessedMessage;
|
|
39
|
+
shouldRetry: boolean;
|
|
40
|
+
reason: string;
|
|
41
|
+
}
|
|
42
|
+
export declare class CompressionCoordinator {
|
|
43
|
+
private readonly options;
|
|
44
|
+
private readonly chatCompression;
|
|
45
|
+
private readonly conversationCompactor;
|
|
46
|
+
private reactiveRetryCount;
|
|
47
|
+
constructor(options?: CompressionCoordinatorOptions);
|
|
48
|
+
shouldCompressBeforeInference(message: ProcessedMessage): CompressionDecision;
|
|
49
|
+
compressBeforeInference(_originalRequest: FlatUserMessage, message: ProcessedMessage): Promise<ProcessedMessage>;
|
|
50
|
+
getPreInferenceProcessor(): ChatCompressionModifier;
|
|
51
|
+
getPostToolCallProcessor(): ConversationCompactorModifier;
|
|
52
|
+
compressAfterTools(input: {
|
|
53
|
+
llmMessageSent: ProcessedMessage;
|
|
54
|
+
rawLLMResponseMessage: any;
|
|
55
|
+
nextPrompt: ProcessedMessage;
|
|
56
|
+
toolResults: any[];
|
|
57
|
+
tokenLimit?: number;
|
|
58
|
+
maxOutputTokens?: number;
|
|
59
|
+
}): Promise<ProcessedMessage>;
|
|
60
|
+
recoverFromContextError(_originalRequest: FlatUserMessage, message: ProcessedMessage, error: unknown): Promise<CompressionRecoveryResult>;
|
|
61
|
+
resetReactiveRetries(): void;
|
|
62
|
+
getReactiveRetryCount(): number;
|
|
63
|
+
private countMessageTokens;
|
|
64
|
+
private withCompressionStage;
|
|
65
|
+
private withCompressionMetadata;
|
|
66
|
+
private isRecoverableContextError;
|
|
67
|
+
}
|
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.CompressionCoordinator = void 0;
|
|
4
|
+
const processor_pieces_1 = require("../../processor-pieces");
|
|
5
|
+
const DEFAULT_MODEL_TOKEN_LIMIT = 128000;
|
|
6
|
+
class CompressionCoordinator {
|
|
7
|
+
constructor(options = {}) {
|
|
8
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k;
|
|
9
|
+
this.reactiveRetryCount = 0;
|
|
10
|
+
this.options = {
|
|
11
|
+
enabled: (_a = options.enabled) !== null && _a !== void 0 ? _a : true,
|
|
12
|
+
proactiveThreshold: (_b = options.proactiveThreshold) !== null && _b !== void 0 ? _b : 0.7,
|
|
13
|
+
postToolThreshold: (_c = options.postToolThreshold) !== null && _c !== void 0 ? _c : 0.5,
|
|
14
|
+
preserveThreshold: (_d = options.preserveThreshold) !== null && _d !== void 0 ? _d : 0.3,
|
|
15
|
+
toolResponseTokenBudget: (_e = options.toolResponseTokenBudget) !== null && _e !== void 0 ? _e : 50000,
|
|
16
|
+
truncateLines: (_f = options.truncateLines) !== null && _f !== void 0 ? _f : 30,
|
|
17
|
+
reactiveRetryLimit: (_g = options.reactiveRetryLimit) !== null && _g !== void 0 ? _g : 1,
|
|
18
|
+
modelTokenLimit: (_h = options.modelTokenLimit) !== null && _h !== void 0 ? _h : DEFAULT_MODEL_TOKEN_LIMIT,
|
|
19
|
+
compactStrategy: (_j = options.compactStrategy) !== null && _j !== void 0 ? _j : 'summarize',
|
|
20
|
+
enableLogging: (_k = options.enableLogging) !== null && _k !== void 0 ? _k : false,
|
|
21
|
+
};
|
|
22
|
+
const chatCompressionOptions = {
|
|
23
|
+
enableCompression: this.options.enabled,
|
|
24
|
+
contextPercentageThreshold: this.options.proactiveThreshold,
|
|
25
|
+
modelTokenLimit: this.options.modelTokenLimit,
|
|
26
|
+
};
|
|
27
|
+
const conversationCompactorOptions = {
|
|
28
|
+
compressionTokenThreshold: this.options.postToolThreshold,
|
|
29
|
+
preserveThreshold: this.options.preserveThreshold,
|
|
30
|
+
toolResponseTokenBudget: this.options.toolResponseTokenBudget,
|
|
31
|
+
truncateLines: this.options.truncateLines,
|
|
32
|
+
compactStrategy: this.options.compactStrategy,
|
|
33
|
+
modelTokenLimit: this.options.modelTokenLimit,
|
|
34
|
+
enableLogging: this.options.enableLogging,
|
|
35
|
+
};
|
|
36
|
+
this.chatCompression = new processor_pieces_1.ChatCompressionModifier(chatCompressionOptions);
|
|
37
|
+
this.conversationCompactor = new processor_pieces_1.ConversationCompactorModifier(conversationCompactorOptions);
|
|
38
|
+
}
|
|
39
|
+
shouldCompressBeforeInference(message) {
|
|
40
|
+
const estimatedTokens = this.countMessageTokens(message.message.messages);
|
|
41
|
+
const threshold = this.options.proactiveThreshold * this.options.modelTokenLimit;
|
|
42
|
+
if (!this.options.enabled) {
|
|
43
|
+
return {
|
|
44
|
+
shouldCompress: false,
|
|
45
|
+
estimatedTokens,
|
|
46
|
+
threshold,
|
|
47
|
+
reason: 'Compression disabled',
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
if (estimatedTokens >= threshold) {
|
|
51
|
+
return {
|
|
52
|
+
shouldCompress: true,
|
|
53
|
+
estimatedTokens,
|
|
54
|
+
threshold,
|
|
55
|
+
reason: 'Proactive threshold reached',
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
return {
|
|
59
|
+
shouldCompress: false,
|
|
60
|
+
estimatedTokens,
|
|
61
|
+
threshold,
|
|
62
|
+
reason: 'Below proactive threshold',
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
async compressBeforeInference(_originalRequest, message) {
|
|
66
|
+
if (!this.options.enabled) {
|
|
67
|
+
return message;
|
|
68
|
+
}
|
|
69
|
+
return this.chatCompression.modify(_originalRequest, message);
|
|
70
|
+
}
|
|
71
|
+
getPreInferenceProcessor() {
|
|
72
|
+
return this.chatCompression;
|
|
73
|
+
}
|
|
74
|
+
getPostToolCallProcessor() {
|
|
75
|
+
return this.conversationCompactor;
|
|
76
|
+
}
|
|
77
|
+
async compressAfterTools(input) {
|
|
78
|
+
const result = await this.conversationCompactor.modify(input);
|
|
79
|
+
return this.withCompressionStage(result.nextPrompt, 'post_tool');
|
|
80
|
+
}
|
|
81
|
+
async recoverFromContextError(_originalRequest, message, error) {
|
|
82
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
83
|
+
if (!this.isRecoverableContextError(errorMessage)) {
|
|
84
|
+
return {
|
|
85
|
+
recoveredMessage: message,
|
|
86
|
+
shouldRetry: false,
|
|
87
|
+
reason: 'Error is not context-related',
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
if (this.reactiveRetryCount >= this.options.reactiveRetryLimit) {
|
|
91
|
+
return {
|
|
92
|
+
recoveredMessage: this.withCompressionMetadata(message, {
|
|
93
|
+
status: 'FAILED_REACTIVE_RETRY_LIMIT',
|
|
94
|
+
stage: 'reactive_force_compact',
|
|
95
|
+
originalTokenCount: this.countMessageTokens(message.message.messages),
|
|
96
|
+
newTokenCount: this.countMessageTokens(message.message.messages),
|
|
97
|
+
timestamp: new Date().toISOString(),
|
|
98
|
+
strategy: this.options.compactStrategy,
|
|
99
|
+
reactiveRetryCount: this.reactiveRetryCount,
|
|
100
|
+
reason: 'Reactive retry limit reached',
|
|
101
|
+
}),
|
|
102
|
+
shouldRetry: false,
|
|
103
|
+
reason: 'Reactive retry limit reached',
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
this.reactiveRetryCount++;
|
|
107
|
+
const proactiveCompression = await this.chatCompression.tryCompressChat(message.message.messages, true);
|
|
108
|
+
if (proactiveCompression.compressedMessages &&
|
|
109
|
+
proactiveCompression.compressionStatus === 1) {
|
|
110
|
+
return {
|
|
111
|
+
recoveredMessage: this.withCompressionMetadata({
|
|
112
|
+
...message,
|
|
113
|
+
message: {
|
|
114
|
+
...message.message,
|
|
115
|
+
messages: proactiveCompression.compressedMessages,
|
|
116
|
+
},
|
|
117
|
+
}, {
|
|
118
|
+
status: 'COMPRESSED',
|
|
119
|
+
stage: 'reactive_force_compact',
|
|
120
|
+
originalTokenCount: proactiveCompression.originalTokenCount,
|
|
121
|
+
newTokenCount: proactiveCompression.newTokenCount,
|
|
122
|
+
timestamp: new Date().toISOString(),
|
|
123
|
+
strategy: 'summarize',
|
|
124
|
+
reactiveRetryCount: this.reactiveRetryCount,
|
|
125
|
+
reason: 'Reactive pre-inference compression applied',
|
|
126
|
+
}),
|
|
127
|
+
shouldRetry: true,
|
|
128
|
+
reason: 'Reactive pre-inference compression applied',
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
const forceCompressed = await this.conversationCompactor.forceCompress(message.message.messages);
|
|
132
|
+
return {
|
|
133
|
+
recoveredMessage: this.withCompressionMetadata({
|
|
134
|
+
...message,
|
|
135
|
+
message: {
|
|
136
|
+
...message.message,
|
|
137
|
+
messages: forceCompressed.messages,
|
|
138
|
+
},
|
|
139
|
+
}, {
|
|
140
|
+
status: 'COMPRESSED',
|
|
141
|
+
stage: 'reactive_force_compact',
|
|
142
|
+
originalTokenCount: this.countMessageTokens(message.message.messages),
|
|
143
|
+
newTokenCount: this.countMessageTokens(forceCompressed.messages),
|
|
144
|
+
timestamp: new Date().toISOString(),
|
|
145
|
+
strategy: this.options.compactStrategy,
|
|
146
|
+
...(forceCompressed.metadata.messagesCompressed !==
|
|
147
|
+
undefined && {
|
|
148
|
+
messagesCompressed: forceCompressed.metadata.messagesCompressed,
|
|
149
|
+
}),
|
|
150
|
+
...(forceCompressed.metadata.messagesPreserved !==
|
|
151
|
+
undefined && {
|
|
152
|
+
messagesPreserved: forceCompressed.metadata.messagesPreserved,
|
|
153
|
+
}),
|
|
154
|
+
...(forceCompressed.metadata.toolOutputsTruncated !==
|
|
155
|
+
undefined && {
|
|
156
|
+
toolOutputsTruncated: forceCompressed.metadata.toolOutputsTruncated,
|
|
157
|
+
}),
|
|
158
|
+
reactiveRetryCount: this.reactiveRetryCount,
|
|
159
|
+
reason: 'Reactive post-tool compaction applied',
|
|
160
|
+
}),
|
|
161
|
+
shouldRetry: true,
|
|
162
|
+
reason: 'Reactive post-tool compaction applied',
|
|
163
|
+
};
|
|
164
|
+
}
|
|
165
|
+
resetReactiveRetries() {
|
|
166
|
+
this.reactiveRetryCount = 0;
|
|
167
|
+
}
|
|
168
|
+
getReactiveRetryCount() {
|
|
169
|
+
return this.reactiveRetryCount;
|
|
170
|
+
}
|
|
171
|
+
countMessageTokens(messages) {
|
|
172
|
+
return messages.reduce((totalTokens, message) => {
|
|
173
|
+
var _a;
|
|
174
|
+
const content = typeof message.content === 'string'
|
|
175
|
+
? message.content
|
|
176
|
+
: JSON.stringify((_a = message.content) !== null && _a !== void 0 ? _a : '');
|
|
177
|
+
return totalTokens + Math.ceil(content.length / 4) + 4;
|
|
178
|
+
}, 0);
|
|
179
|
+
}
|
|
180
|
+
withCompressionStage(message, stage) {
|
|
181
|
+
var _a;
|
|
182
|
+
const existingMetadata = (_a = message.metadata) === null || _a === void 0 ? void 0 : _a['compression'];
|
|
183
|
+
if (!existingMetadata) {
|
|
184
|
+
return message;
|
|
185
|
+
}
|
|
186
|
+
return this.withCompressionMetadata(message, {
|
|
187
|
+
...existingMetadata,
|
|
188
|
+
stage,
|
|
189
|
+
});
|
|
190
|
+
}
|
|
191
|
+
withCompressionMetadata(message, compression) {
|
|
192
|
+
return {
|
|
193
|
+
...message,
|
|
194
|
+
metadata: {
|
|
195
|
+
...message.metadata,
|
|
196
|
+
compression,
|
|
197
|
+
},
|
|
198
|
+
};
|
|
199
|
+
}
|
|
200
|
+
isRecoverableContextError(errorMessage) {
|
|
201
|
+
const contextErrorPatterns = [
|
|
202
|
+
/prompt too long/i,
|
|
203
|
+
/context length/i,
|
|
204
|
+
/maximum context/i,
|
|
205
|
+
/context window/i,
|
|
206
|
+
/too many tokens/i,
|
|
207
|
+
/token limit/i,
|
|
208
|
+
/request too large/i,
|
|
209
|
+
/input is too long/i,
|
|
210
|
+
];
|
|
211
|
+
return contextErrorPatterns.some(pattern => pattern.test(errorMessage));
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
exports.CompressionCoordinator = CompressionCoordinator;
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Layer 4: Auto Compact
|
|
3
|
+
*
|
|
4
|
+
* Full conversation summary via LLM when approaching the context window limit.
|
|
5
|
+
* Two sub-paths:
|
|
6
|
+
* 4a. Session memory compaction (using continuously-extracted memory)
|
|
7
|
+
* 4b. Legacy full summary (sends conversation to LLM for detailed summary)
|
|
8
|
+
*
|
|
9
|
+
* Key properties:
|
|
10
|
+
* - Triggers at effectiveContextWindow - bufferTokens (default 13K)
|
|
11
|
+
* - Circuit breaker: stops after N consecutive failures
|
|
12
|
+
* - Produces a CompactBoundaryMessage for boundary tracking
|
|
13
|
+
* - Post-compact cleanup resets all tracking state
|
|
14
|
+
* - When context collapse is active, auto-compact is suppressed
|
|
15
|
+
*/
|
|
16
|
+
import { type CompactionContext, type CompactionLayer, type CompactionLayerKind } from './types';
|
|
17
|
+
export interface AutoCompactOptions {
|
|
18
|
+
/** Buffer tokens below context window (default: 13000) */
|
|
19
|
+
bufferTokens?: number;
|
|
20
|
+
/** Max consecutive failures before circuit breaker (default: 3) */
|
|
21
|
+
maxConsecutiveFailures?: number;
|
|
22
|
+
/** Model token limit (default: 128000) */
|
|
23
|
+
modelTokenLimit?: number;
|
|
24
|
+
/** Fraction of recent history to preserve after compression (default: 0.3) */
|
|
25
|
+
preserveThreshold?: number;
|
|
26
|
+
/** LLM role for summarization calls (default: 'summarizer') */
|
|
27
|
+
llmRole?: string;
|
|
28
|
+
/** Enable logging (default: false) */
|
|
29
|
+
enableLogging?: boolean;
|
|
30
|
+
}
|
|
31
|
+
export interface AutoCompactTracking {
|
|
32
|
+
compacted: boolean;
|
|
33
|
+
turnId: string;
|
|
34
|
+
turnCounter: number;
|
|
35
|
+
consecutiveFailures: number;
|
|
36
|
+
}
|
|
37
|
+
export declare class AutoCompact implements CompactionLayer {
|
|
38
|
+
readonly name: CompactionLayerKind;
|
|
39
|
+
private readonly options;
|
|
40
|
+
private consecutiveFailures;
|
|
41
|
+
private tracking;
|
|
42
|
+
constructor(options?: AutoCompactOptions);
|
|
43
|
+
shouldApply(ctx: CompactionContext): boolean;
|
|
44
|
+
apply(ctx: CompactionContext): Promise<CompactionContext>;
|
|
45
|
+
reset(): void;
|
|
46
|
+
getTracking(): AutoCompactTracking | undefined;
|
|
47
|
+
getConsecutiveFailures(): number;
|
|
48
|
+
private compactConversation;
|
|
49
|
+
private findSplitIndex;
|
|
50
|
+
private generateSummary;
|
|
51
|
+
private isToolResponse;
|
|
52
|
+
}
|
|
@@ -0,0 +1,294 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Layer 4: Auto Compact
|
|
4
|
+
*
|
|
5
|
+
* Full conversation summary via LLM when approaching the context window limit.
|
|
6
|
+
* Two sub-paths:
|
|
7
|
+
* 4a. Session memory compaction (using continuously-extracted memory)
|
|
8
|
+
* 4b. Legacy full summary (sends conversation to LLM for detailed summary)
|
|
9
|
+
*
|
|
10
|
+
* Key properties:
|
|
11
|
+
* - Triggers at effectiveContextWindow - bufferTokens (default 13K)
|
|
12
|
+
* - Circuit breaker: stops after N consecutive failures
|
|
13
|
+
* - Produces a CompactBoundaryMessage for boundary tracking
|
|
14
|
+
* - Post-compact cleanup resets all tracking state
|
|
15
|
+
* - When context collapse is active, auto-compact is suppressed
|
|
16
|
+
*/
|
|
17
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
18
|
+
exports.AutoCompact = void 0;
|
|
19
|
+
const types_1 = require("./types");
|
|
20
|
+
/** Tokens below context window to trigger proactive auto-compact */
|
|
21
|
+
const DEFAULT_AUTOCOMPACT_BUFFER = 13000;
|
|
22
|
+
/** Max consecutive failures before circuit breaker trips */
|
|
23
|
+
const DEFAULT_MAX_CONSECUTIVE_FAILURES = 3;
|
|
24
|
+
/** Default model token limit */
|
|
25
|
+
const DEFAULT_MODEL_TOKEN_LIMIT = 128000;
|
|
26
|
+
class AutoCompact {
|
|
27
|
+
constructor(options) {
|
|
28
|
+
var _a, _b, _c, _d, _e, _f;
|
|
29
|
+
this.name = 'auto';
|
|
30
|
+
this.consecutiveFailures = 0;
|
|
31
|
+
this.options = {
|
|
32
|
+
bufferTokens: (_a = options === null || options === void 0 ? void 0 : options.bufferTokens) !== null && _a !== void 0 ? _a : DEFAULT_AUTOCOMPACT_BUFFER,
|
|
33
|
+
maxConsecutiveFailures: (_b = options === null || options === void 0 ? void 0 : options.maxConsecutiveFailures) !== null && _b !== void 0 ? _b : DEFAULT_MAX_CONSECUTIVE_FAILURES,
|
|
34
|
+
modelTokenLimit: (_c = options === null || options === void 0 ? void 0 : options.modelTokenLimit) !== null && _c !== void 0 ? _c : DEFAULT_MODEL_TOKEN_LIMIT,
|
|
35
|
+
preserveThreshold: (_d = options === null || options === void 0 ? void 0 : options.preserveThreshold) !== null && _d !== void 0 ? _d : 0.3,
|
|
36
|
+
llmRole: (_e = options === null || options === void 0 ? void 0 : options.llmRole) !== null && _e !== void 0 ? _e : 'summarizer',
|
|
37
|
+
enableLogging: (_f = options === null || options === void 0 ? void 0 : options.enableLogging) !== null && _f !== void 0 ? _f : false,
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
shouldApply(ctx) {
|
|
41
|
+
// Don't auto-compact if context collapse is handling it
|
|
42
|
+
if (ctx.contextCollapseEnabled) {
|
|
43
|
+
return false;
|
|
44
|
+
}
|
|
45
|
+
// Circuit breaker
|
|
46
|
+
if (this.consecutiveFailures >= this.options.maxConsecutiveFailures) {
|
|
47
|
+
return false;
|
|
48
|
+
}
|
|
49
|
+
// Check threshold
|
|
50
|
+
const estimator = new types_1.TokenEstimator();
|
|
51
|
+
const tokenCount = estimator.estimateForMessages(ctx.messages) - (ctx.snipTokensFreed || 0);
|
|
52
|
+
const threshold = this.options.modelTokenLimit - this.options.bufferTokens;
|
|
53
|
+
return tokenCount >= threshold;
|
|
54
|
+
}
|
|
55
|
+
async apply(ctx) {
|
|
56
|
+
const messages = ctx.messages;
|
|
57
|
+
const estimator = new types_1.TokenEstimator();
|
|
58
|
+
const originalTokens = estimator.estimateForMessages(messages) - (ctx.snipTokensFreed || 0);
|
|
59
|
+
try {
|
|
60
|
+
const result = await this.compactConversation(messages, ctx);
|
|
61
|
+
if (!result) {
|
|
62
|
+
this.consecutiveFailures++;
|
|
63
|
+
return ctx;
|
|
64
|
+
}
|
|
65
|
+
// Success — reset failure counter
|
|
66
|
+
this.consecutiveFailures = 0;
|
|
67
|
+
const newTokens = estimator.estimateForMessages(result);
|
|
68
|
+
const boundary = {
|
|
69
|
+
layer: 'auto',
|
|
70
|
+
tokensFreed: originalTokens - newTokens,
|
|
71
|
+
messagesRemoved: messages.length - result.length,
|
|
72
|
+
timestamp: new Date().toISOString(),
|
|
73
|
+
summaryIncluded: true,
|
|
74
|
+
};
|
|
75
|
+
this.tracking = {
|
|
76
|
+
compacted: true,
|
|
77
|
+
turnId: `auto-${Date.now()}`,
|
|
78
|
+
turnCounter: 0,
|
|
79
|
+
consecutiveFailures: 0,
|
|
80
|
+
};
|
|
81
|
+
if (this.options.enableLogging) {
|
|
82
|
+
console.log(`[AutoCompact] Compacted: ${originalTokens} -> ${newTokens} tokens (${boundary.tokensFreed} freed, ${boundary.messagesRemoved} messages removed)`);
|
|
83
|
+
}
|
|
84
|
+
return {
|
|
85
|
+
...ctx,
|
|
86
|
+
messages: result,
|
|
87
|
+
compactionHistory: [...(ctx.compactionHistory || []), boundary],
|
|
88
|
+
autoCompactTracking: this.tracking,
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
catch (error) {
|
|
92
|
+
this.consecutiveFailures++;
|
|
93
|
+
if (this.options.enableLogging) {
|
|
94
|
+
console.error('[AutoCompact] Compaction failed:', error);
|
|
95
|
+
}
|
|
96
|
+
return ctx;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
reset() {
|
|
100
|
+
this.consecutiveFailures = 0;
|
|
101
|
+
this.tracking = undefined;
|
|
102
|
+
}
|
|
103
|
+
getTracking() {
|
|
104
|
+
return this.tracking;
|
|
105
|
+
}
|
|
106
|
+
getConsecutiveFailures() {
|
|
107
|
+
return this.consecutiveFailures;
|
|
108
|
+
}
|
|
109
|
+
// ─── Core Compaction Logic ────────────────────────────────────────
|
|
110
|
+
async compactConversation(messages, ctx) {
|
|
111
|
+
const estimator = new types_1.TokenEstimator();
|
|
112
|
+
// Find split point: preserve the most recent portion of conversation
|
|
113
|
+
const splitIndex = this.findSplitIndex(messages);
|
|
114
|
+
if (splitIndex === 0) {
|
|
115
|
+
return null; // Nothing to compact
|
|
116
|
+
}
|
|
117
|
+
// Separate into history-to-compact and history-to-keep
|
|
118
|
+
const systemMessages = messages.filter(m => m.role === 'system');
|
|
119
|
+
const historyToCompress = messages
|
|
120
|
+
.slice(0, splitIndex)
|
|
121
|
+
.filter(m => m.role !== 'system');
|
|
122
|
+
const preservedMessages = messages.slice(splitIndex);
|
|
123
|
+
if (historyToCompress.length === 0) {
|
|
124
|
+
return null;
|
|
125
|
+
}
|
|
126
|
+
// Generate summary
|
|
127
|
+
const summary = await this.generateSummary(historyToCompress);
|
|
128
|
+
if (!summary || summary.trim().length === 0) {
|
|
129
|
+
return null;
|
|
130
|
+
}
|
|
131
|
+
// Build post-compact message array
|
|
132
|
+
const postCompactMessages = [
|
|
133
|
+
...systemMessages,
|
|
134
|
+
{
|
|
135
|
+
role: 'user',
|
|
136
|
+
content: `This session is being continued from a previous conversation that ran out of context. Below is a summary of the conversation so far.\n\n${summary}\n\nPlease continue from where the previous conversation left off. Do not ask the user to re-explain what they already told you — the summary above contains all the context you need.`,
|
|
137
|
+
},
|
|
138
|
+
{
|
|
139
|
+
role: 'assistant',
|
|
140
|
+
content: 'Understood. I have the summary of the previous conversation and will continue from where we left off.',
|
|
141
|
+
},
|
|
142
|
+
...preservedMessages,
|
|
143
|
+
];
|
|
144
|
+
// Verify compression was effective
|
|
145
|
+
const newTokens = estimator.estimateForMessages(postCompactMessages);
|
|
146
|
+
const originalTokens = estimator.estimateForMessages(messages) - (ctx.snipTokensFreed || 0);
|
|
147
|
+
if (newTokens >= originalTokens) {
|
|
148
|
+
if (this.options.enableLogging) {
|
|
149
|
+
console.warn(`[AutoCompact] Summary inflated token count: ${originalTokens} -> ${newTokens}`);
|
|
150
|
+
}
|
|
151
|
+
return null;
|
|
152
|
+
}
|
|
153
|
+
return postCompactMessages;
|
|
154
|
+
}
|
|
155
|
+
findSplitIndex(messages) {
|
|
156
|
+
var _a;
|
|
157
|
+
// Find turn boundaries (user messages that aren't tool responses)
|
|
158
|
+
const turnStarts = [];
|
|
159
|
+
for (let i = 0; i < messages.length; i++) {
|
|
160
|
+
const msg = messages[i];
|
|
161
|
+
if (!msg)
|
|
162
|
+
continue;
|
|
163
|
+
if (msg.role === 'user' &&
|
|
164
|
+
!msg.tool_call_id &&
|
|
165
|
+
!this.isToolResponse(msg)) {
|
|
166
|
+
turnStarts.push(i);
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
if (turnStarts.length <= 3) {
|
|
170
|
+
return 0; // Too few turns to compress
|
|
171
|
+
}
|
|
172
|
+
// Keep the last preserveThreshold fraction of turns
|
|
173
|
+
const turnsToKeep = Math.max(3, Math.ceil(turnStarts.length * this.options.preserveThreshold));
|
|
174
|
+
const turnsToRemove = turnStarts.length - turnsToKeep;
|
|
175
|
+
if (turnsToRemove <= 0) {
|
|
176
|
+
return 0;
|
|
177
|
+
}
|
|
178
|
+
// Adjust to avoid splitting in the middle of a tool-response chain
|
|
179
|
+
let splitIndex = (_a = turnStarts[turnsToRemove]) !== null && _a !== void 0 ? _a : messages.length;
|
|
180
|
+
// Walk forward to skip tool responses that belong to the previous turn
|
|
181
|
+
while (splitIndex < messages.length) {
|
|
182
|
+
const msg = messages[splitIndex];
|
|
183
|
+
if (!msg)
|
|
184
|
+
break;
|
|
185
|
+
if (msg.role === 'tool' || msg.tool_call_id) {
|
|
186
|
+
splitIndex++;
|
|
187
|
+
continue;
|
|
188
|
+
}
|
|
189
|
+
break;
|
|
190
|
+
}
|
|
191
|
+
return splitIndex;
|
|
192
|
+
}
|
|
193
|
+
async generateSummary(messages) {
|
|
194
|
+
var _a, _b, _c, _d, _e;
|
|
195
|
+
try {
|
|
196
|
+
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
197
|
+
const codebolt = require('@codebolt/codeboltjs');
|
|
198
|
+
// Build compression prompt
|
|
199
|
+
const historyText = messages
|
|
200
|
+
.map((msg, i) => {
|
|
201
|
+
var _a;
|
|
202
|
+
const content = typeof msg.content === 'string'
|
|
203
|
+
? msg.content
|
|
204
|
+
: JSON.stringify((_a = msg.content) !== null && _a !== void 0 ? _a : '');
|
|
205
|
+
// Truncate very long messages for the prompt
|
|
206
|
+
const truncated = content.length > 2000
|
|
207
|
+
? content.slice(0, 1000) +
|
|
208
|
+
`\n...[${content.length - 2000} chars truncated]...\n` +
|
|
209
|
+
content.slice(-1000)
|
|
210
|
+
: content;
|
|
211
|
+
return `[${i + 1}] ${msg.role}: ${truncated}`;
|
|
212
|
+
})
|
|
213
|
+
.join('\n\n');
|
|
214
|
+
const prompt = `You are a conversation compression assistant. Create a detailed, structured summary that preserves ALL critical context so work can continue seamlessly.
|
|
215
|
+
|
|
216
|
+
CONVERSATION HISTORY TO COMPRESS:
|
|
217
|
+
${historyText}
|
|
218
|
+
|
|
219
|
+
Generate the summary with ALL of the following sections:
|
|
220
|
+
|
|
221
|
+
<summary>
|
|
222
|
+
1. PRIMARY REQUEST
|
|
223
|
+
[The user's original, complete request]
|
|
224
|
+
|
|
225
|
+
2. TASK EVOLUTION
|
|
226
|
+
[How the task evolved. Include key user instructions that changed direction]
|
|
227
|
+
|
|
228
|
+
3. KEY TECHNICAL CONCEPTS
|
|
229
|
+
[Architecture decisions, design patterns, algorithms, data structures, API contracts]
|
|
230
|
+
|
|
231
|
+
4. FILES AND CODE
|
|
232
|
+
[Every file that was read, created, or modified. Include file paths and key changes]
|
|
233
|
+
|
|
234
|
+
5. PROBLEM SOLVING
|
|
235
|
+
[Errors encountered and solutions applied]
|
|
236
|
+
|
|
237
|
+
6. PENDING TASKS
|
|
238
|
+
[Tasks mentioned but NOT yet completed]
|
|
239
|
+
|
|
240
|
+
7. CURRENT WORK STATE
|
|
241
|
+
[Exactly where the work left off]
|
|
242
|
+
|
|
243
|
+
8. NEXT STEP
|
|
244
|
+
[The most logical next action]
|
|
245
|
+
</summary>
|
|
246
|
+
|
|
247
|
+
CRITICAL RULES:
|
|
248
|
+
- Preserve ALL file paths exactly
|
|
249
|
+
- Preserve ALL code snippets, function names, error messages verbatim
|
|
250
|
+
- Include the FULL original user request, not a paraphrase
|
|
251
|
+
- Do not summarize away technical details
|
|
252
|
+
- Focus on facts and specifics`;
|
|
253
|
+
const response = await codebolt.llm.inference({
|
|
254
|
+
messages: [
|
|
255
|
+
{
|
|
256
|
+
role: 'system',
|
|
257
|
+
content: 'You are a precise conversation compression assistant. Be comprehensive but concise.',
|
|
258
|
+
},
|
|
259
|
+
{ role: 'user', content: prompt },
|
|
260
|
+
],
|
|
261
|
+
});
|
|
262
|
+
// Extract summary from response
|
|
263
|
+
let summary;
|
|
264
|
+
if (typeof ((_a = response === null || response === void 0 ? void 0 : response.completion) === null || _a === void 0 ? void 0 : _a.content) === 'string') {
|
|
265
|
+
summary = response.completion.content;
|
|
266
|
+
}
|
|
267
|
+
else if ((_e = (_d = (_c = (_b = response === null || response === void 0 ? void 0 : response.completion) === null || _b === void 0 ? void 0 : _b.choices) === null || _c === void 0 ? void 0 : _c[0]) === null || _d === void 0 ? void 0 : _d.message) === null || _e === void 0 ? void 0 : _e.content) {
|
|
268
|
+
summary = response.completion.choices[0].message.content;
|
|
269
|
+
}
|
|
270
|
+
if (summary && summary.trim().length > 0) {
|
|
271
|
+
return summary.trim();
|
|
272
|
+
}
|
|
273
|
+
return '';
|
|
274
|
+
}
|
|
275
|
+
catch (error) {
|
|
276
|
+
console.error('[AutoCompact] Error generating summary:', error);
|
|
277
|
+
return '';
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
isToolResponse(msg) {
|
|
281
|
+
if (msg.role === 'tool')
|
|
282
|
+
return true;
|
|
283
|
+
if (msg.tool_call_id)
|
|
284
|
+
return true;
|
|
285
|
+
if (typeof msg.content === 'object' && msg.content !== null) {
|
|
286
|
+
if (Array.isArray(msg.content)) {
|
|
287
|
+
return msg.content.some((block) => block &&
|
|
288
|
+
(block.type === 'tool_result' || block.type === 'function_response'));
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
return false;
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
exports.AutoCompact = AutoCompact;
|