@codebolt/agent 1.1.0 → 2.2.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.
Files changed (183) hide show
  1. package/README.md +157 -66
  2. package/dist/builderpattern/agent.d.ts +86 -0
  3. package/dist/builderpattern/agent.js +324 -0
  4. package/dist/builderpattern/followupquestionbuilder.d.ts +75 -0
  5. package/dist/builderpattern/followupquestionbuilder.js +197 -0
  6. package/dist/builderpattern/index.d.ts +14 -0
  7. package/dist/builderpattern/index.js +23 -0
  8. package/dist/builderpattern/llmoutputhandler.d.ts +102 -0
  9. package/dist/builderpattern/llmoutputhandler.js +452 -0
  10. package/dist/builderpattern/promptbuilder.d.ts +382 -0
  11. package/dist/builderpattern/promptbuilder.js +805 -0
  12. package/dist/builderpattern/systemprompt.d.ts +20 -0
  13. package/dist/builderpattern/systemprompt.js +48 -0
  14. package/dist/builderpattern/taskInstruction.d.ts +37 -0
  15. package/dist/builderpattern/taskInstruction.js +57 -0
  16. package/dist/builderpattern/usermessage.d.ts +70 -0
  17. package/dist/builderpattern/usermessage.js +123 -0
  18. package/dist/composablepattern/agent.d.ts +169 -0
  19. package/dist/composablepattern/agent.js +598 -0
  20. package/dist/composablepattern/codebolt-storage.d.ts +67 -0
  21. package/dist/composablepattern/codebolt-storage.js +320 -0
  22. package/dist/composablepattern/document.d.ts +149 -0
  23. package/dist/composablepattern/document.js +405 -0
  24. package/dist/composablepattern/examples/codebolt-integration-example.d.ts +12 -0
  25. package/dist/composablepattern/examples/codebolt-integration-example.js +218 -0
  26. package/dist/composablepattern/examples/codebolt-storage-example.d.ts +40 -0
  27. package/dist/composablepattern/examples/codebolt-storage-example.js +223 -0
  28. package/dist/composablepattern/examples/custom-steps-example.d.ts +20 -0
  29. package/dist/composablepattern/examples/custom-steps-example.js +455 -0
  30. package/dist/composablepattern/examples/document-agent.d.ts +17 -0
  31. package/dist/composablepattern/examples/document-agent.js +107 -0
  32. package/dist/composablepattern/examples/simple-codebolt-integration.d.ts +8 -0
  33. package/dist/composablepattern/examples/simple-codebolt-integration.js +164 -0
  34. package/dist/composablepattern/examples/weather-agent.d.ts +18 -0
  35. package/dist/composablepattern/examples/weather-agent.js +86 -0
  36. package/dist/composablepattern/examples/workflow-example.d.ts +12 -0
  37. package/dist/composablepattern/examples/workflow-example.js +463 -0
  38. package/dist/composablepattern/index.d.ts +63 -0
  39. package/dist/composablepattern/index.js +115 -0
  40. package/dist/composablepattern/memory.d.ts +89 -0
  41. package/dist/composablepattern/memory.js +141 -0
  42. package/dist/composablepattern/tool.d.ts +84 -0
  43. package/dist/composablepattern/tool.js +260 -0
  44. package/dist/composablepattern/types.d.ts +194 -0
  45. package/dist/composablepattern/types.js +6 -0
  46. package/dist/composablepattern/user-context.d.ts +214 -0
  47. package/dist/composablepattern/user-context.js +275 -0
  48. package/dist/composablepattern/workflow.d.ts +388 -0
  49. package/dist/composablepattern/workflow.js +562 -0
  50. package/dist/processor/agent/agentStep.d.ts +49 -0
  51. package/dist/processor/agent/agentStep.js +241 -0
  52. package/dist/processor/agent/toolExecutor.d.ts +19 -0
  53. package/dist/processor/agent/toolExecutor.js +90 -0
  54. package/dist/processor/index.d.ts +7 -0
  55. package/dist/processor/index.js +36 -0
  56. package/dist/processor/messageModifiers/baseMessageModifier.d.ts +20 -0
  57. package/dist/processor/messageModifiers/baseMessageModifier.js +55 -0
  58. package/dist/processor/processors/baseProcessor.d.ts +14 -0
  59. package/dist/processor/processors/baseProcessor.js +29 -0
  60. package/dist/processor/tools/baseTool.d.ts +10 -0
  61. package/dist/processor/tools/baseTool.js +20 -0
  62. package/dist/processor/tools/toolList.d.ts +9 -0
  63. package/dist/processor/tools/toolList.js +22 -0
  64. package/dist/processor/types/interfaces.d.ts +94 -0
  65. package/dist/processor/types/interfaces.js +2 -0
  66. package/dist/processor-pieces/base/baseMessageModifier.d.ts +12 -0
  67. package/dist/processor-pieces/base/baseMessageModifier.js +15 -0
  68. package/dist/processor-pieces/base/basePostInferenceProcessor.d.ts +13 -0
  69. package/dist/processor-pieces/base/basePostInferenceProcessor.js +18 -0
  70. package/dist/processor-pieces/base/basePostToolCallProcessor.d.ts +15 -0
  71. package/dist/processor-pieces/base/basePostToolCallProcessor.js +25 -0
  72. package/dist/processor-pieces/base/basePreInferenceProcessor.d.ts +12 -0
  73. package/dist/processor-pieces/base/basePreInferenceProcessor.js +17 -0
  74. package/dist/processor-pieces/base/basePreToolCallProcessor.d.ts +18 -0
  75. package/dist/processor-pieces/base/basePreToolCallProcessor.js +66 -0
  76. package/dist/processor-pieces/base/index.d.ts +9 -0
  77. package/dist/processor-pieces/base/index.js +18 -0
  78. package/dist/processor-pieces/index.d.ts +1 -0
  79. package/dist/processor-pieces/index.js +59 -0
  80. package/dist/processor-pieces/messageModifiers/addToolsListMessageModifier.d.ts +22 -0
  81. package/dist/processor-pieces/messageModifiers/addToolsListMessageModifier.js +144 -0
  82. package/dist/processor-pieces/messageModifiers/argumentProcessorModifier.d.ts +13 -0
  83. package/dist/processor-pieces/messageModifiers/argumentProcessorModifier.js +68 -0
  84. package/dist/processor-pieces/messageModifiers/atFileProcessorModifier.d.ts +25 -0
  85. package/dist/processor-pieces/messageModifiers/atFileProcessorModifier.js +453 -0
  86. package/dist/processor-pieces/messageModifiers/baseContextMessageModifier.d.ts +15 -0
  87. package/dist/processor-pieces/messageModifiers/baseContextMessageModifier.js +75 -0
  88. package/dist/processor-pieces/messageModifiers/baseSystemInstructionMessageModifier.d.ts +11 -0
  89. package/dist/processor-pieces/messageModifiers/baseSystemInstructionMessageModifier.js +46 -0
  90. package/dist/processor-pieces/messageModifiers/chatHistoryMessageModifier.d.ts +18 -0
  91. package/dist/processor-pieces/messageModifiers/chatHistoryMessageModifier.js +104 -0
  92. package/dist/processor-pieces/messageModifiers/chatRecordingModifier.d.ts +23 -0
  93. package/dist/processor-pieces/messageModifiers/chatRecordingModifier.js +173 -0
  94. package/dist/processor-pieces/messageModifiers/coreSystemPromptModifier.d.ts +14 -0
  95. package/dist/processor-pieces/messageModifiers/coreSystemPromptModifier.js +130 -0
  96. package/dist/processor-pieces/messageModifiers/directoryContextModifier.d.ts +36 -0
  97. package/dist/processor-pieces/messageModifiers/directoryContextModifier.js +418 -0
  98. package/dist/processor-pieces/messageModifiers/environmentContextModifier.d.ts +26 -0
  99. package/dist/processor-pieces/messageModifiers/environmentContextModifier.js +260 -0
  100. package/dist/processor-pieces/messageModifiers/handleUrlMessageModifier.d.ts +12 -0
  101. package/dist/processor-pieces/messageModifiers/handleUrlMessageModifier.js +60 -0
  102. package/dist/processor-pieces/messageModifiers/ideContextModifier.d.ts +34 -0
  103. package/dist/processor-pieces/messageModifiers/ideContextModifier.js +157 -0
  104. package/dist/processor-pieces/messageModifiers/imageAttachmentMessageModifier.d.ts +18 -0
  105. package/dist/processor-pieces/messageModifiers/imageAttachmentMessageModifier.js +222 -0
  106. package/dist/processor-pieces/messageModifiers/index.d.ts +11 -0
  107. package/dist/processor-pieces/messageModifiers/index.js +26 -0
  108. package/dist/processor-pieces/messageModifiers/memoryImportModifier.d.ts +15 -0
  109. package/dist/processor-pieces/messageModifiers/memoryImportModifier.js +129 -0
  110. package/dist/processor-pieces/messageModifiers/toolInjectionModifier.d.ts +20 -0
  111. package/dist/processor-pieces/messageModifiers/toolInjectionModifier.js +152 -0
  112. package/dist/processor-pieces/messageModifiers/workingDirectoryMessageModifier.d.ts +22 -0
  113. package/dist/processor-pieces/messageModifiers/workingDirectoryMessageModifier.js +194 -0
  114. package/dist/processor-pieces/postInferenceProcessors/loopDetectionModifier.d.ts +29 -0
  115. package/dist/processor-pieces/postInferenceProcessors/loopDetectionModifier.js +174 -0
  116. package/dist/processor-pieces/postToolCallProcessors/index.d.ts +1 -0
  117. package/dist/processor-pieces/postToolCallProcessors/index.js +2 -0
  118. package/dist/processor-pieces/postToolCallProcessors/shellProcessorModifier.d.ts +25 -0
  119. package/dist/processor-pieces/postToolCallProcessors/shellProcessorModifier.js +225 -0
  120. package/dist/processor-pieces/preInferenceProcessors/chatCompressionModifier.d.ts +35 -0
  121. package/dist/processor-pieces/preInferenceProcessors/chatCompressionModifier.js +255 -0
  122. package/dist/processor-pieces/preInferenceProcessors/index.d.ts +1 -0
  123. package/dist/processor-pieces/preInferenceProcessors/index.js +2 -0
  124. package/dist/processor-pieces/pretoolCallProcessors/index.d.ts +1 -0
  125. package/dist/processor-pieces/pretoolCallProcessors/index.js +2 -0
  126. package/dist/processor-pieces/processors/advancedLoopDetectionProcessor.d.ts +41 -0
  127. package/dist/processor-pieces/processors/advancedLoopDetectionProcessor.js +197 -0
  128. package/dist/processor-pieces/processors/chatCompressionProcessor.d.ts +26 -0
  129. package/dist/processor-pieces/processors/chatCompressionProcessor.js +90 -0
  130. package/dist/processor-pieces/processors/chatRecordingProcessor.d.ts +81 -0
  131. package/dist/processor-pieces/processors/chatRecordingProcessor.js +329 -0
  132. package/dist/processor-pieces/processors/contextManagementProcessor.d.ts +40 -0
  133. package/dist/processor-pieces/processors/contextManagementProcessor.js +305 -0
  134. package/dist/processor-pieces/processors/loopDetectionProcessor.d.ts +30 -0
  135. package/dist/processor-pieces/processors/loopDetectionProcessor.js +137 -0
  136. package/dist/processor-pieces/processors/responseValidationProcessor.d.ts +30 -0
  137. package/dist/processor-pieces/processors/responseValidationProcessor.js +228 -0
  138. package/dist/processor-pieces/processors/telemetryProcessor.d.ts +99 -0
  139. package/dist/processor-pieces/processors/telemetryProcessor.js +311 -0
  140. package/dist/processor-pieces/processors/tokenManagementProcessor.d.ts +37 -0
  141. package/dist/processor-pieces/processors/tokenManagementProcessor.js +178 -0
  142. package/dist/processor-pieces/processors/toolExecutionProcessor.d.ts +43 -0
  143. package/dist/processor-pieces/processors/toolExecutionProcessor.js +207 -0
  144. package/dist/processor-pieces/tools/fileTools.d.ts +26 -0
  145. package/dist/processor-pieces/tools/fileTools.js +162 -0
  146. package/dist/processor-pieces/utils/messageModifierHelper.d.ts +4 -0
  147. package/dist/processor-pieces/utils/messageModifierHelper.js +58 -0
  148. package/dist/types/commonTypes.d.ts +4 -0
  149. package/dist/types/processorTypes.d.ts +67 -0
  150. package/dist/types/processorTypes.js +58 -0
  151. package/dist/unified/agent/agent.d.ts +17 -0
  152. package/dist/unified/agent/agent.js +79 -0
  153. package/dist/unified/agent/team.d.ts +2 -0
  154. package/dist/unified/agent/team.js +6 -0
  155. package/dist/unified/agent/tools.d.ts +44 -0
  156. package/dist/unified/agent/tools.js +487 -0
  157. package/dist/unified/agent/workflow.d.ts +24 -0
  158. package/dist/unified/agent/workflow.js +275 -0
  159. package/dist/unified/agent/workflowControls.d.ts +11 -0
  160. package/dist/unified/agent/workflowControls.js +20 -0
  161. package/dist/unified/agent/workflowSteps.d.ts +63 -0
  162. package/dist/unified/agent/workflowSteps.js +284 -0
  163. package/dist/unified/base/agentStep.d.ts +32 -0
  164. package/dist/unified/base/agentStep.js +96 -0
  165. package/dist/unified/base/create/createInitialPromptGenerators.d.ts +5 -0
  166. package/dist/unified/base/create/createInitialPromptGenerators.js +17 -0
  167. package/dist/unified/base/index.d.ts +5 -0
  168. package/dist/unified/base/index.js +13 -0
  169. package/dist/unified/base/initialPromptGenerator.d.ts +48 -0
  170. package/dist/unified/base/initialPromptGenerator.js +118 -0
  171. package/dist/unified/base/responseExecutor.d.ts +36 -0
  172. package/dist/unified/base/responseExecutor.js +283 -0
  173. package/dist/unified/index.d.ts +18 -0
  174. package/dist/unified/index.js +42 -0
  175. package/dist/unified/team/team.d.ts +1 -0
  176. package/dist/unified/team/team.js +2 -0
  177. package/dist/unified/types/libTypes.d.ts +378 -0
  178. package/dist/unified/types/libTypes.js +6 -0
  179. package/dist/unified/types/types.d.ts +212 -0
  180. package/dist/unified/types/types.js +43 -0
  181. package/dist/unified/utils/utils.d.ts +40 -0
  182. package/dist/unified/utils/utils.js +219 -0
  183. package/package.json +29 -7
@@ -0,0 +1,35 @@
1
+ import { ProcessedMessage } from "@codebolt/types/agent";
2
+ import { BasePreInferenceProcessor } from "../base";
3
+ import { FlatUserMessage, MessageObject } from "@codebolt/types/sdk";
4
+ export declare enum CompressionStatus {
5
+ /** The compression was successful */
6
+ COMPRESSED = 1,
7
+ /** The compression failed due to the compression inflating the token count */
8
+ COMPRESSION_FAILED_INFLATED_TOKEN_COUNT = 2,
9
+ /** The compression failed due to an error counting tokens */
10
+ COMPRESSION_FAILED_TOKEN_COUNT_ERROR = 3,
11
+ /** The compression was not necessary and no action was taken */
12
+ NOOP = 4
13
+ }
14
+ export interface ChatCompressionInfo {
15
+ originalTokenCount: number;
16
+ newTokenCount: number;
17
+ compressionStatus: CompressionStatus;
18
+ }
19
+ export interface ChatCompressionOptions {
20
+ contextPercentageThreshold?: number;
21
+ enableCompression?: boolean;
22
+ force?: boolean;
23
+ }
24
+ export declare class ChatCompressionModifier extends BasePreInferenceProcessor {
25
+ private readonly options;
26
+ private hasFailedCompressionAttempt;
27
+ constructor(options?: ChatCompressionOptions);
28
+ modify(originalRequest: FlatUserMessage, createdMessage: ProcessedMessage): Promise<ProcessedMessage>;
29
+ tryCompressChat(messages: MessageObject[], force?: boolean): Promise<ChatCompressionInfo & {
30
+ compressedMessages?: MessageObject[];
31
+ }>;
32
+ private countTokens;
33
+ private generateCompressionSummary;
34
+ resetCompressionState(): void;
35
+ }
@@ -0,0 +1,255 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ChatCompressionModifier = exports.CompressionStatus = void 0;
4
+ const base_1 = require("../base");
5
+ /**
6
+ * Threshold for compression token count as a fraction of the model's token limit.
7
+ * If the chat history exceeds this threshold, it will be compressed.
8
+ */
9
+ const COMPRESSION_TOKEN_THRESHOLD = 0.7;
10
+ /**
11
+ * The fraction of the latest chat history to keep. A value of 0.3
12
+ * means that only the last 30% of the chat history will be kept after compression.
13
+ */
14
+ const COMPRESSION_PRESERVE_THRESHOLD = 0.3;
15
+ var CompressionStatus;
16
+ (function (CompressionStatus) {
17
+ /** The compression was successful */
18
+ CompressionStatus[CompressionStatus["COMPRESSED"] = 1] = "COMPRESSED";
19
+ /** The compression failed due to the compression inflating the token count */
20
+ CompressionStatus[CompressionStatus["COMPRESSION_FAILED_INFLATED_TOKEN_COUNT"] = 2] = "COMPRESSION_FAILED_INFLATED_TOKEN_COUNT";
21
+ /** The compression failed due to an error counting tokens */
22
+ CompressionStatus[CompressionStatus["COMPRESSION_FAILED_TOKEN_COUNT_ERROR"] = 3] = "COMPRESSION_FAILED_TOKEN_COUNT_ERROR";
23
+ /** The compression was not necessary and no action was taken */
24
+ CompressionStatus[CompressionStatus["NOOP"] = 4] = "NOOP";
25
+ })(CompressionStatus || (exports.CompressionStatus = CompressionStatus = {}));
26
+ /**
27
+ * Returns the index of the content after the fraction of the total characters in the history.
28
+ */
29
+ function findIndexAfterFraction(history, fraction) {
30
+ if (fraction <= 0 || fraction >= 1) {
31
+ throw new Error('Fraction must be between 0 and 1');
32
+ }
33
+ const contentLengths = history.map((content) => JSON.stringify(content).length);
34
+ const totalCharacters = contentLengths.reduce((sum, length) => sum + length, 0);
35
+ const targetCharacters = totalCharacters * fraction;
36
+ let charactersSoFar = 0;
37
+ for (let i = 0; i < contentLengths.length; i++) {
38
+ charactersSoFar += contentLengths[i];
39
+ if (charactersSoFar >= targetCharacters) {
40
+ return i;
41
+ }
42
+ }
43
+ return contentLengths.length;
44
+ }
45
+ function isFunctionResponse(message) {
46
+ // Check if message has function response content
47
+ if (typeof message.content === 'object' && message.content !== null) {
48
+ return 'functionResponse' in message.content;
49
+ }
50
+ return false;
51
+ }
52
+ // Mock token limit for different models (should be replaced with actual implementation)
53
+ function tokenLimit(model) {
54
+ // Default token limits for common models
55
+ if (model.includes('gemini-pro'))
56
+ return 30720;
57
+ if (model.includes('gemini-flash'))
58
+ return 1048576;
59
+ if (model.includes('gpt-4'))
60
+ return 8192;
61
+ if (model.includes('gpt-3.5'))
62
+ return 4096;
63
+ return 8192; // Default fallback
64
+ }
65
+ class ChatCompressionModifier extends base_1.BasePreInferenceProcessor {
66
+ constructor(options = {}) {
67
+ super();
68
+ this.hasFailedCompressionAttempt = false;
69
+ this.options = {
70
+ contextPercentageThreshold: options.contextPercentageThreshold || COMPRESSION_TOKEN_THRESHOLD,
71
+ enableCompression: options.enableCompression !== false,
72
+ force: options.force || false
73
+ };
74
+ }
75
+ async modify(originalRequest, createdMessage) {
76
+ try {
77
+ const compressionResult = await this.tryCompressChat(createdMessage.message.messages, this.options.force || false);
78
+ if (compressionResult.compressionStatus === CompressionStatus.COMPRESSED) {
79
+ return {
80
+ message: {
81
+ ...createdMessage.message,
82
+ messages: compressionResult.compressedMessages || createdMessage.message.messages
83
+ },
84
+ metadata: {
85
+ ...createdMessage.metadata,
86
+ chatCompressed: true,
87
+ originalTokenCount: compressionResult.originalTokenCount,
88
+ newTokenCount: compressionResult.newTokenCount,
89
+ compressionStatus: compressionResult.compressionStatus
90
+ }
91
+ };
92
+ }
93
+ return {
94
+ ...createdMessage,
95
+ metadata: {
96
+ ...createdMessage.metadata,
97
+ compressionStatus: compressionResult.compressionStatus,
98
+ originalTokenCount: compressionResult.originalTokenCount,
99
+ newTokenCount: compressionResult.newTokenCount
100
+ }
101
+ };
102
+ }
103
+ catch (error) {
104
+ console.error('Error in ChatCompressionModifier:', error);
105
+ this.hasFailedCompressionAttempt = true;
106
+ return createdMessage;
107
+ }
108
+ }
109
+ async tryCompressChat(messages, force = false) {
110
+ var _a;
111
+ const curatedHistory = messages;
112
+ // Regardless of `force`, don't do anything if the history is empty.
113
+ if (curatedHistory.length === 0 ||
114
+ (this.hasFailedCompressionAttempt && !force)) {
115
+ return {
116
+ originalTokenCount: 0,
117
+ newTokenCount: 0,
118
+ compressionStatus: CompressionStatus.NOOP,
119
+ };
120
+ }
121
+ // Mock model - should be replaced with actual model detection
122
+ const model = "gemini-pro";
123
+ const originalTokenCount = await this.countTokens(model, curatedHistory);
124
+ if (originalTokenCount === undefined) {
125
+ console.warn(`Could not determine token count for model ${model}.`);
126
+ this.hasFailedCompressionAttempt = !force && true;
127
+ return {
128
+ originalTokenCount: 0,
129
+ newTokenCount: 0,
130
+ compressionStatus: CompressionStatus.COMPRESSION_FAILED_TOKEN_COUNT_ERROR,
131
+ };
132
+ }
133
+ const contextPercentageThreshold = this.options.contextPercentageThreshold;
134
+ // Don't compress if not forced and we are under the limit.
135
+ if (!force) {
136
+ const threshold = contextPercentageThreshold !== null && contextPercentageThreshold !== void 0 ? contextPercentageThreshold : COMPRESSION_TOKEN_THRESHOLD;
137
+ if (originalTokenCount < threshold * tokenLimit(model)) {
138
+ return {
139
+ originalTokenCount,
140
+ newTokenCount: originalTokenCount,
141
+ compressionStatus: CompressionStatus.NOOP,
142
+ };
143
+ }
144
+ }
145
+ let compressBeforeIndex = findIndexAfterFraction(curatedHistory, 1 - COMPRESSION_PRESERVE_THRESHOLD);
146
+ // Find the first user message after the index. This is the start of the next turn.
147
+ while (compressBeforeIndex < curatedHistory.length &&
148
+ (((_a = curatedHistory[compressBeforeIndex]) === null || _a === void 0 ? void 0 : _a.role) === 'assistant' ||
149
+ isFunctionResponse(curatedHistory[compressBeforeIndex]))) {
150
+ compressBeforeIndex++;
151
+ }
152
+ const historyToCompress = curatedHistory.slice(0, compressBeforeIndex);
153
+ const historyToKeep = curatedHistory.slice(compressBeforeIndex);
154
+ // Generate AI summary using the compression prompt
155
+ const summary = await this.generateCompressionSummary(historyToCompress);
156
+ const compressedMessages = [
157
+ {
158
+ role: 'user',
159
+ content: summary
160
+ },
161
+ {
162
+ role: 'assistant',
163
+ content: 'Got it. Thanks for the additional context!'
164
+ },
165
+ ...historyToKeep,
166
+ ];
167
+ const newTokenCount = await this.countTokens(model, compressedMessages);
168
+ if (newTokenCount === undefined) {
169
+ console.warn('Could not determine compressed history token count.');
170
+ this.hasFailedCompressionAttempt = !force && true;
171
+ return {
172
+ originalTokenCount,
173
+ newTokenCount: originalTokenCount,
174
+ compressionStatus: CompressionStatus.COMPRESSION_FAILED_TOKEN_COUNT_ERROR,
175
+ };
176
+ }
177
+ if (newTokenCount > originalTokenCount) {
178
+ this.hasFailedCompressionAttempt = !force && true;
179
+ return {
180
+ originalTokenCount,
181
+ newTokenCount,
182
+ compressionStatus: CompressionStatus.COMPRESSION_FAILED_INFLATED_TOKEN_COUNT,
183
+ };
184
+ }
185
+ return {
186
+ originalTokenCount,
187
+ newTokenCount,
188
+ compressionStatus: CompressionStatus.COMPRESSED,
189
+ compressedMessages,
190
+ };
191
+ }
192
+ async countTokens(model, messages) {
193
+ // Mock token counting - should be replaced with actual API call
194
+ // Rough approximation: 4 characters per token
195
+ const totalCharacters = messages.reduce((sum, msg) => {
196
+ return sum + (typeof msg.content === 'string' ? msg.content.length : JSON.stringify(msg.content).length);
197
+ }, 0);
198
+ return Math.ceil(totalCharacters / 4);
199
+ }
200
+ async generateCompressionSummary(messages) {
201
+ // This should use the actual compression prompt and LLM call
202
+ // For now, using a simplified version similar to the original
203
+ const compressionPrompt = `You are tasked with creating a concise summary of a conversation history to preserve context while reducing token usage.
204
+
205
+ Please analyze the conversation and create a state snapshot that captures:
206
+ 1. Key topics discussed
207
+ 2. Important decisions made
208
+ 3. Current context and progress
209
+ 4. Any ongoing tasks or issues
210
+
211
+ Format your response as a clear, structured summary that maintains the essential information needed to continue the conversation effectively.`;
212
+ // Mock LLM call - should be replaced with actual LLM integration
213
+ const summaryParts = [];
214
+ let userQuestions = [];
215
+ let assistantResponses = [];
216
+ for (const message of messages) {
217
+ const content = typeof message.content === 'string' ? message.content : JSON.stringify(message.content);
218
+ if (message.role === 'user') {
219
+ if (content.length > 20) {
220
+ userQuestions.push(content.substring(0, 150) + (content.length > 150 ? '...' : ''));
221
+ }
222
+ }
223
+ else if (message.role === 'assistant') {
224
+ if (content.length > 20) {
225
+ assistantResponses.push(content.substring(0, 150) + (content.length > 150 ? '...' : ''));
226
+ }
227
+ }
228
+ }
229
+ summaryParts.push('<state_snapshot>');
230
+ summaryParts.push('This is a compressed summary of the previous conversation:');
231
+ summaryParts.push('');
232
+ if (userQuestions.length > 0) {
233
+ summaryParts.push('Key user requests and questions:');
234
+ userQuestions.slice(0, 5).forEach((q, i) => {
235
+ summaryParts.push(`${i + 1}. ${q}`);
236
+ });
237
+ summaryParts.push('');
238
+ }
239
+ if (assistantResponses.length > 0) {
240
+ summaryParts.push('Key assistant responses and actions:');
241
+ assistantResponses.slice(0, 5).forEach((r, i) => {
242
+ summaryParts.push(`${i + 1}. ${r}`);
243
+ });
244
+ summaryParts.push('');
245
+ }
246
+ summaryParts.push(`Total messages compressed: ${messages.length}`);
247
+ summaryParts.push('</state_snapshot>');
248
+ return summaryParts.join('\n');
249
+ }
250
+ resetCompressionState() {
251
+ this.hasFailedCompressionAttempt = false;
252
+ }
253
+ }
254
+ exports.ChatCompressionModifier = ChatCompressionModifier;
255
+ ////
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,41 @@
1
+ import { BaseProcessor, ProcessorInput, ProcessorOutput } from '../../processor';
2
+ export interface AdvancedLoopDetectionProcessorOptions {
3
+ toolCallThreshold?: number;
4
+ contentLoopThreshold?: number;
5
+ contentChunkSize?: number;
6
+ maxHistoryLength?: number;
7
+ enableLLMDetection?: boolean;
8
+ llmCheckAfterTurns?: number;
9
+ defaultLLMCheckInterval?: number;
10
+ }
11
+ export declare class AdvancedLoopDetectionProcessor extends BaseProcessor {
12
+ private readonly toolCallThreshold;
13
+ private readonly contentLoopThreshold;
14
+ private readonly contentChunkSize;
15
+ private readonly maxHistoryLength;
16
+ private readonly enableLLMDetection;
17
+ private readonly llmCheckAfterTurns;
18
+ private readonly defaultLLMCheckInterval;
19
+ private lastToolCallKey;
20
+ private toolCallRepetitionCount;
21
+ private streamContentHistory;
22
+ private contentStats;
23
+ private lastContentIndex;
24
+ private loopDetected;
25
+ private inCodeBlock;
26
+ private turnsInCurrentPrompt;
27
+ private llmCheckInterval;
28
+ private lastCheckTurn;
29
+ constructor(options?: AdvancedLoopDetectionProcessorOptions);
30
+ processInput(input: ProcessorInput): Promise<ProcessorOutput[]>;
31
+ private getToolCallKey;
32
+ private checkToolCallLoop;
33
+ private checkContentLoop;
34
+ private truncateAndUpdate;
35
+ private analyzeContentChunksForLoop;
36
+ private hasMoreChunksToProcess;
37
+ private isLoopDetectedForChunk;
38
+ private isActualContentMatch;
39
+ private resetContentTracking;
40
+ reset(): void;
41
+ }
@@ -0,0 +1,197 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.AdvancedLoopDetectionProcessor = void 0;
4
+ const processor_1 = require("../../processor");
5
+ const crypto_1 = require("crypto");
6
+ class AdvancedLoopDetectionProcessor extends processor_1.BaseProcessor {
7
+ constructor(options = {}) {
8
+ super();
9
+ // Tool call tracking
10
+ this.lastToolCallKey = null;
11
+ this.toolCallRepetitionCount = 0;
12
+ // Content streaming tracking
13
+ this.streamContentHistory = '';
14
+ this.contentStats = new Map();
15
+ this.lastContentIndex = 0;
16
+ this.loopDetected = false;
17
+ this.inCodeBlock = false;
18
+ // Turn tracking
19
+ this.turnsInCurrentPrompt = 0;
20
+ this.lastCheckTurn = 0;
21
+ this.toolCallThreshold = options.toolCallThreshold || 5;
22
+ this.contentLoopThreshold = options.contentLoopThreshold || 10;
23
+ this.contentChunkSize = options.contentChunkSize || 50;
24
+ this.maxHistoryLength = options.maxHistoryLength || 1000;
25
+ this.enableLLMDetection = options.enableLLMDetection || false;
26
+ this.llmCheckAfterTurns = options.llmCheckAfterTurns || 30;
27
+ this.defaultLLMCheckInterval = options.defaultLLMCheckInterval || 3;
28
+ this.llmCheckInterval = this.defaultLLMCheckInterval;
29
+ }
30
+ async processInput(input) {
31
+ const { message, context } = input;
32
+ // Increment turn counter
33
+ this.turnsInCurrentPrompt++;
34
+ // Check for tool call loops in the last message
35
+ const lastMessage = message.messages[message.messages.length - 1];
36
+ if (lastMessage.tool_calls && lastMessage.tool_calls.length > 0) {
37
+ for (const toolCall of lastMessage.tool_calls) {
38
+ const isLoop = this.checkToolCallLoop({
39
+ name: toolCall.function.name,
40
+ args: typeof toolCall.function.arguments === 'string'
41
+ ? JSON.parse(toolCall.function.arguments)
42
+ : toolCall.function.arguments
43
+ });
44
+ if (isLoop) {
45
+ this.loopDetected = true;
46
+ return [this.createEvent('LoopDetected', {
47
+ type: 'tool_call_loop',
48
+ toolCall: toolCall.function.name,
49
+ repetitionCount: this.toolCallRepetitionCount,
50
+ threshold: this.toolCallThreshold
51
+ })];
52
+ }
53
+ }
54
+ }
55
+ // Check for content loops
56
+ if (lastMessage.content && typeof lastMessage.content === 'string') {
57
+ const isContentLoop = this.checkContentLoop(lastMessage.content);
58
+ if (isContentLoop) {
59
+ this.loopDetected = true;
60
+ return [this.createEvent('LoopDetected', {
61
+ type: 'content_loop',
62
+ contentLength: this.streamContentHistory.length,
63
+ threshold: this.contentLoopThreshold
64
+ })];
65
+ }
66
+ }
67
+ // LLM-based loop detection (if enabled)
68
+ if (this.enableLLMDetection &&
69
+ this.turnsInCurrentPrompt >= this.llmCheckAfterTurns &&
70
+ this.turnsInCurrentPrompt - this.lastCheckTurn >= this.llmCheckInterval) {
71
+ this.lastCheckTurn = this.turnsInCurrentPrompt;
72
+ // For now, just log that LLM check would happen
73
+ // In a real implementation, this would call an LLM to analyze the conversation
74
+ console.log('[AdvancedLoopDetection] LLM-based loop check would be performed here');
75
+ }
76
+ return [this.createEvent('LoopCheckCompleted', {
77
+ loopDetected: this.loopDetected,
78
+ turnsInPrompt: this.turnsInCurrentPrompt,
79
+ toolCallCount: this.toolCallRepetitionCount
80
+ })];
81
+ }
82
+ getToolCallKey(toolCall) {
83
+ const argsString = JSON.stringify(toolCall.args);
84
+ const keyString = `${toolCall.name}:${argsString}`;
85
+ return (0, crypto_1.createHash)('sha256').update(keyString).digest('hex');
86
+ }
87
+ checkToolCallLoop(toolCall) {
88
+ const key = this.getToolCallKey(toolCall);
89
+ if (this.lastToolCallKey === key) {
90
+ this.toolCallRepetitionCount++;
91
+ }
92
+ else {
93
+ this.lastToolCallKey = key;
94
+ this.toolCallRepetitionCount = 1;
95
+ }
96
+ return this.toolCallRepetitionCount >= this.toolCallThreshold;
97
+ }
98
+ checkContentLoop(content) {
99
+ var _a;
100
+ // Different content elements can often contain repetitive syntax that is not indicative of a loop.
101
+ // To avoid false positives, we detect when we encounter different content types and
102
+ // reset tracking to avoid analyzing content that spans across different element boundaries.
103
+ const numFences = ((_a = content.match(/```/g)) !== null && _a !== void 0 ? _a : []).length;
104
+ const hasTable = /(^|\n)\s*(\|.*\||[|+-]{3,})/.test(content);
105
+ const hasListItem = /(^|\n)\s*[*-+]\s/.test(content) || /(^|\n)\s*\d+\.\s/.test(content);
106
+ const hasHeading = /(^|\n)#+\s/.test(content);
107
+ const hasBlockquote = /(^|\n)>\s/.test(content);
108
+ if (numFences || hasTable || hasListItem || hasHeading || hasBlockquote) {
109
+ // Reset tracking when different content elements are detected
110
+ this.resetContentTracking();
111
+ }
112
+ const wasInCodeBlock = this.inCodeBlock;
113
+ this.inCodeBlock = numFences % 2 === 0 ? this.inCodeBlock : !this.inCodeBlock;
114
+ if (wasInCodeBlock || this.inCodeBlock) {
115
+ return false;
116
+ }
117
+ this.streamContentHistory += content;
118
+ this.truncateAndUpdate();
119
+ return this.analyzeContentChunksForLoop();
120
+ }
121
+ truncateAndUpdate() {
122
+ if (this.streamContentHistory.length <= this.maxHistoryLength) {
123
+ return;
124
+ }
125
+ const truncationAmount = this.streamContentHistory.length - this.maxHistoryLength;
126
+ this.streamContentHistory = this.streamContentHistory.slice(truncationAmount);
127
+ this.lastContentIndex = Math.max(0, this.lastContentIndex - truncationAmount);
128
+ // Update all stored chunk indices to account for the truncation
129
+ for (const [hash, oldIndices] of this.contentStats.entries()) {
130
+ const adjustedIndices = oldIndices
131
+ .map((index) => index - truncationAmount)
132
+ .filter((index) => index >= 0);
133
+ if (adjustedIndices.length > 0) {
134
+ this.contentStats.set(hash, adjustedIndices);
135
+ }
136
+ else {
137
+ this.contentStats.delete(hash);
138
+ }
139
+ }
140
+ }
141
+ analyzeContentChunksForLoop() {
142
+ while (this.hasMoreChunksToProcess()) {
143
+ const currentChunk = this.streamContentHistory.substring(this.lastContentIndex, this.lastContentIndex + this.contentChunkSize);
144
+ const chunkHash = (0, crypto_1.createHash)('sha256').update(currentChunk).digest('hex');
145
+ if (this.isLoopDetectedForChunk(currentChunk, chunkHash)) {
146
+ return true;
147
+ }
148
+ this.lastContentIndex++;
149
+ }
150
+ return false;
151
+ }
152
+ hasMoreChunksToProcess() {
153
+ return this.lastContentIndex + this.contentChunkSize <= this.streamContentHistory.length;
154
+ }
155
+ isLoopDetectedForChunk(chunk, hash) {
156
+ const existingIndices = this.contentStats.get(hash);
157
+ if (!existingIndices) {
158
+ this.contentStats.set(hash, [this.lastContentIndex]);
159
+ return false;
160
+ }
161
+ if (!this.isActualContentMatch(chunk, existingIndices[0])) {
162
+ return false;
163
+ }
164
+ existingIndices.push(this.lastContentIndex);
165
+ if (existingIndices.length < this.contentLoopThreshold) {
166
+ return false;
167
+ }
168
+ // Analyze the most recent occurrences to see if they're clustered closely together
169
+ const recentIndices = existingIndices.slice(-this.contentLoopThreshold);
170
+ const totalDistance = recentIndices[recentIndices.length - 1] - recentIndices[0];
171
+ const averageDistance = totalDistance / (this.contentLoopThreshold - 1);
172
+ const maxAllowedDistance = this.contentChunkSize * 1.5;
173
+ return averageDistance <= maxAllowedDistance;
174
+ }
175
+ isActualContentMatch(currentChunk, originalIndex) {
176
+ const originalChunk = this.streamContentHistory.substring(originalIndex, originalIndex + this.contentChunkSize);
177
+ return originalChunk === currentChunk;
178
+ }
179
+ resetContentTracking(resetHistory = true) {
180
+ if (resetHistory) {
181
+ this.streamContentHistory = '';
182
+ }
183
+ this.contentStats.clear();
184
+ this.lastContentIndex = 0;
185
+ }
186
+ reset() {
187
+ this.lastToolCallKey = null;
188
+ this.toolCallRepetitionCount = 0;
189
+ this.resetContentTracking();
190
+ this.turnsInCurrentPrompt = 0;
191
+ this.llmCheckInterval = this.defaultLLMCheckInterval;
192
+ this.lastCheckTurn = 0;
193
+ this.loopDetected = false;
194
+ this.inCodeBlock = false;
195
+ }
196
+ }
197
+ exports.AdvancedLoopDetectionProcessor = AdvancedLoopDetectionProcessor;
@@ -0,0 +1,26 @@
1
+ import { BaseProcessor, ProcessorInput, ProcessorOutput } from '../../processor';
2
+ export interface ChatCompressionInfo {
3
+ originalTokenCount: number;
4
+ newTokenCount: number;
5
+ compressionRatio: number;
6
+ threshold: number;
7
+ }
8
+ export interface ChatCompressionProcessorOptions {
9
+ compressionThreshold?: number;
10
+ compressionPreserveThreshold?: number;
11
+ tokenLimit?: number;
12
+ enableCompression?: boolean;
13
+ }
14
+ export declare class ChatCompressionProcessor extends BaseProcessor {
15
+ private readonly compressionThreshold;
16
+ private readonly compressionPreserveThreshold;
17
+ private readonly tokenLimit;
18
+ private readonly enableCompression;
19
+ constructor(options?: ChatCompressionProcessorOptions);
20
+ processInput(input: ProcessorInput): Promise<ProcessorOutput[]>;
21
+ private estimateTokenCount;
22
+ setCompressionThreshold(threshold: number): void;
23
+ setTokenLimit(limit: number): void;
24
+ enableCompressionForSession(): void;
25
+ disableCompressionForSession(): void;
26
+ }
@@ -0,0 +1,90 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.ChatCompressionProcessor = void 0;
7
+ const processor_1 = require("../../processor");
8
+ const codeboltjs_1 = __importDefault(require("@codebolt/codeboltjs"));
9
+ class ChatCompressionProcessor extends processor_1.BaseProcessor {
10
+ constructor(options = {}) {
11
+ super(options);
12
+ this.compressionThreshold = options.compressionThreshold || 0.7;
13
+ this.compressionPreserveThreshold = options.compressionPreserveThreshold || 0.3;
14
+ this.tokenLimit = options.tokenLimit || 128000;
15
+ this.enableCompression = options.enableCompression !== false;
16
+ }
17
+ async processInput(input) {
18
+ try {
19
+ const { message, context } = input;
20
+ if (!this.enableCompression) {
21
+ return [this.createEvent('ChatCompressionDisabled', {
22
+ reason: 'Compression is disabled for this session'
23
+ })];
24
+ }
25
+ // Get chat history from CodeBolt
26
+ const chatHistory = await codeboltjs_1.default.chat.getChatHistory();
27
+ if (chatHistory.length === 0) {
28
+ return [this.createEvent('NoChatHistory', {
29
+ reason: 'No chat history available for compression'
30
+ })];
31
+ }
32
+ // Estimate token count (simple heuristic: 4 chars per token)
33
+ const estimatedTokens = this.estimateTokenCount(chatHistory);
34
+ const threshold = this.compressionThreshold * this.tokenLimit;
35
+ console.log(`[Compression] Estimated tokens: ${estimatedTokens}, threshold: ${threshold}`);
36
+ if (estimatedTokens < threshold) {
37
+ return [this.createEvent('ChatCompressionSkipped', {
38
+ estimatedTokens,
39
+ threshold,
40
+ reason: 'Below compression threshold'
41
+ })];
42
+ }
43
+ // Perform compression using CodeBolt's chatSummary
44
+ const compressionResult = await codeboltjs_1.default.chatSummary.summarizeAll();
45
+ if (compressionResult.success && compressionResult.data) {
46
+ const newTokenCount = this.estimateTokenCount(compressionResult.data);
47
+ const compressionInfo = {
48
+ originalTokenCount: estimatedTokens,
49
+ newTokenCount,
50
+ compressionRatio: newTokenCount / estimatedTokens,
51
+ threshold: this.compressionThreshold
52
+ };
53
+ // Send notification about compression
54
+ await codeboltjs_1.default.chat.sendNotificationEvent(`Chat compressed: ${estimatedTokens} → ${newTokenCount} tokens`, 'debug');
55
+ return [this.createEvent('ChatCompressed', compressionInfo)];
56
+ }
57
+ else {
58
+ return [this.createEvent('ChatCompressionFailed', {
59
+ error: compressionResult.message || 'Unknown compression error',
60
+ originalTokenCount: estimatedTokens
61
+ })];
62
+ }
63
+ }
64
+ catch (error) {
65
+ console.error('Error in ChatCompressionProcessor:', error);
66
+ return [this.createEvent('ChatCompressionError', {
67
+ error: error instanceof Error ? error.message : String(error)
68
+ })];
69
+ }
70
+ }
71
+ estimateTokenCount(data) {
72
+ // Simple heuristic: 4 characters per token
73
+ const totalContent = JSON.stringify(data);
74
+ return Math.ceil(totalContent.length / 4);
75
+ }
76
+ // Public methods for external control
77
+ setCompressionThreshold(threshold) {
78
+ this.compressionThreshold = Math.max(0.1, Math.min(0.9, threshold));
79
+ }
80
+ setTokenLimit(limit) {
81
+ this.tokenLimit = Math.max(1000, limit);
82
+ }
83
+ enableCompressionForSession() {
84
+ this.enableCompression = true;
85
+ }
86
+ disableCompressionForSession() {
87
+ this.enableCompression = false;
88
+ }
89
+ }
90
+ exports.ChatCompressionProcessor = ChatCompressionProcessor;