@exaudeus/workrail 0.1.0 → 0.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 +153 -189
- package/dist/application/services/classification-engine.d.ts +33 -0
- package/dist/application/services/classification-engine.js +258 -0
- package/dist/application/services/compression-service.d.ts +20 -0
- package/dist/application/services/compression-service.js +312 -0
- package/dist/application/services/context-management-service.d.ts +38 -0
- package/dist/application/services/context-management-service.js +301 -0
- package/dist/application/services/context-persistence-service.d.ts +45 -0
- package/dist/application/services/context-persistence-service.js +273 -0
- package/dist/cli/migrate-workflow.js +3 -2
- package/dist/infrastructure/storage/context-storage.d.ts +150 -0
- package/dist/infrastructure/storage/context-storage.js +40 -0
- package/dist/infrastructure/storage/filesystem-blob-storage.d.ts +27 -0
- package/dist/infrastructure/storage/filesystem-blob-storage.js +363 -0
- package/dist/infrastructure/storage/hybrid-context-storage.d.ts +29 -0
- package/dist/infrastructure/storage/hybrid-context-storage.js +400 -0
- package/dist/infrastructure/storage/migrations/001_initial_schema.sql +38 -0
- package/dist/infrastructure/storage/migrations/002_context_concurrency_enhancements.sql +234 -0
- package/dist/infrastructure/storage/migrations/003_classification_overrides.sql +20 -0
- package/dist/infrastructure/storage/sqlite-metadata-storage.d.ts +35 -0
- package/dist/infrastructure/storage/sqlite-metadata-storage.js +410 -0
- package/dist/infrastructure/storage/sqlite-migrator.d.ts +46 -0
- package/dist/infrastructure/storage/sqlite-migrator.js +293 -0
- package/dist/types/context-types.d.ts +236 -0
- package/dist/types/context-types.js +10 -0
- package/dist/utils/storage-security.js +1 -1
- package/package.json +4 -1
- package/workflows/coding-task-workflow-with-loops.json +434 -0
- package/workflows/mr-review-workflow.json +75 -26
- package/workflows/systemic-bug-investigation-with-loops.json +423 -0
|
@@ -0,0 +1,258 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ClassificationEngine = void 0;
|
|
4
|
+
const context_types_1 = require("../../types/context-types");
|
|
5
|
+
class ClassificationEngine {
|
|
6
|
+
constructor(initialRules) {
|
|
7
|
+
this.overrides = new Map();
|
|
8
|
+
this.rules = initialRules || this.getDefaultRules();
|
|
9
|
+
this.stats = {
|
|
10
|
+
totalClassifications: 0,
|
|
11
|
+
layerDistribution: {
|
|
12
|
+
[context_types_1.ContextLayer.CRITICAL]: 0,
|
|
13
|
+
[context_types_1.ContextLayer.IMPORTANT]: 0,
|
|
14
|
+
[context_types_1.ContextLayer.USEFUL]: 0,
|
|
15
|
+
[context_types_1.ContextLayer.EPHEMERAL]: 0
|
|
16
|
+
},
|
|
17
|
+
overrideCount: 0,
|
|
18
|
+
averageProcessingTime: 0
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
async classify(context, rules) {
|
|
22
|
+
const startTime = process.hrtime.bigint();
|
|
23
|
+
const activeRules = rules || this.rules;
|
|
24
|
+
const classified = {
|
|
25
|
+
[context_types_1.ContextLayer.CRITICAL]: {},
|
|
26
|
+
[context_types_1.ContextLayer.IMPORTANT]: {},
|
|
27
|
+
[context_types_1.ContextLayer.USEFUL]: {},
|
|
28
|
+
[context_types_1.ContextLayer.EPHEMERAL]: {}
|
|
29
|
+
};
|
|
30
|
+
for (const [key, value] of Object.entries(context)) {
|
|
31
|
+
const layer = this.classifyKeyValue(key, value, activeRules);
|
|
32
|
+
classified[layer][key] = value;
|
|
33
|
+
}
|
|
34
|
+
this.updateStats(startTime, classified);
|
|
35
|
+
return Object.freeze(classified);
|
|
36
|
+
}
|
|
37
|
+
async loadRules(config) {
|
|
38
|
+
if (config) {
|
|
39
|
+
this.rules = {
|
|
40
|
+
patterns: { ...this.rules.patterns, ...config.patterns },
|
|
41
|
+
heuristics: { ...this.rules.heuristics, ...config.heuristics },
|
|
42
|
+
overrides: { ...this.rules.overrides, ...config.overrides }
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
addOverride(sessionId, contextKey, layer) {
|
|
47
|
+
if (!this.overrides.has(sessionId)) {
|
|
48
|
+
this.overrides.set(sessionId, new Map());
|
|
49
|
+
}
|
|
50
|
+
const sessionOverrides = this.overrides.get(sessionId);
|
|
51
|
+
sessionOverrides.set(contextKey, layer);
|
|
52
|
+
this.stats.overrideCount++;
|
|
53
|
+
}
|
|
54
|
+
removeOverride(sessionId, contextKey) {
|
|
55
|
+
const sessionOverrides = this.overrides.get(sessionId);
|
|
56
|
+
if (sessionOverrides && sessionOverrides.has(contextKey)) {
|
|
57
|
+
sessionOverrides.delete(contextKey);
|
|
58
|
+
this.stats.overrideCount = Math.max(0, this.stats.overrideCount - 1);
|
|
59
|
+
if (sessionOverrides.size === 0) {
|
|
60
|
+
this.overrides.delete(sessionId);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
async markCritical(sessionId, contextKey) {
|
|
65
|
+
this.addOverride(sessionId, contextKey, context_types_1.ContextLayer.CRITICAL);
|
|
66
|
+
console.log(`✓ Marked key '${contextKey}' as CRITICAL for session '${sessionId}'`);
|
|
67
|
+
}
|
|
68
|
+
getStats() {
|
|
69
|
+
return { ...this.stats };
|
|
70
|
+
}
|
|
71
|
+
classifyKeyValue(key, value, rules, sessionId) {
|
|
72
|
+
if (sessionId) {
|
|
73
|
+
const sessionOverrides = this.overrides.get(sessionId);
|
|
74
|
+
const override = sessionOverrides?.get(key);
|
|
75
|
+
if (override) {
|
|
76
|
+
return override;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
if (rules.overrides[key]) {
|
|
80
|
+
return rules.overrides[key];
|
|
81
|
+
}
|
|
82
|
+
const patternLayer = this.applyPatternMatching(key, value, rules);
|
|
83
|
+
if (patternLayer) {
|
|
84
|
+
return patternLayer;
|
|
85
|
+
}
|
|
86
|
+
return this.applyHeuristics(key, value, rules);
|
|
87
|
+
}
|
|
88
|
+
applyPatternMatching(key, value, rules) {
|
|
89
|
+
let bestMatch = null;
|
|
90
|
+
for (const [layer, patterns] of Object.entries(rules.patterns)) {
|
|
91
|
+
for (const pattern of patterns) {
|
|
92
|
+
if (this.matchesPattern(key, value, pattern)) {
|
|
93
|
+
if (!bestMatch || pattern.weight > bestMatch.weight) {
|
|
94
|
+
bestMatch = { layer: layer, weight: pattern.weight };
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
return bestMatch?.layer || null;
|
|
100
|
+
}
|
|
101
|
+
matchesPattern(key, value, pattern) {
|
|
102
|
+
const keyRegex = new RegExp(pattern.keyPattern, 'i');
|
|
103
|
+
if (!keyRegex.test(key)) {
|
|
104
|
+
return false;
|
|
105
|
+
}
|
|
106
|
+
if (pattern.valuePattern) {
|
|
107
|
+
const valueStr = typeof value === 'string' ? value : JSON.stringify(value);
|
|
108
|
+
const valueRegex = new RegExp(pattern.valuePattern, 'i');
|
|
109
|
+
if (!valueRegex.test(valueStr)) {
|
|
110
|
+
return false;
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
return true;
|
|
114
|
+
}
|
|
115
|
+
applyHeuristics(key, value, rules) {
|
|
116
|
+
const heuristics = rules.heuristics;
|
|
117
|
+
const valueStr = typeof value === 'string' ? value :
|
|
118
|
+
value === undefined ? 'undefined' :
|
|
119
|
+
value === null ? 'null' :
|
|
120
|
+
JSON.stringify(value);
|
|
121
|
+
const contentLength = valueStr.length;
|
|
122
|
+
let keywordScore = 0;
|
|
123
|
+
for (const [keyword, weight] of Object.entries(heuristics.keywordWeights)) {
|
|
124
|
+
const regex = new RegExp(keyword, 'gi');
|
|
125
|
+
const matches = (key + ' ' + valueStr).match(regex);
|
|
126
|
+
if (matches) {
|
|
127
|
+
keywordScore += matches.length * weight;
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
if (keywordScore >= 10 || contentLength >= heuristics.lengthThresholds[context_types_1.ContextLayer.CRITICAL]) {
|
|
131
|
+
return context_types_1.ContextLayer.CRITICAL;
|
|
132
|
+
}
|
|
133
|
+
else if (keywordScore >= 5 || contentLength >= heuristics.lengthThresholds[context_types_1.ContextLayer.IMPORTANT]) {
|
|
134
|
+
return context_types_1.ContextLayer.IMPORTANT;
|
|
135
|
+
}
|
|
136
|
+
else if (contentLength >= heuristics.lengthThresholds[context_types_1.ContextLayer.USEFUL]) {
|
|
137
|
+
return context_types_1.ContextLayer.USEFUL;
|
|
138
|
+
}
|
|
139
|
+
else {
|
|
140
|
+
return heuristics.defaultLayer;
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
updateStats(startTime, classified) {
|
|
144
|
+
const endTime = process.hrtime.bigint();
|
|
145
|
+
const processingTime = Number(endTime - startTime) / 1000000;
|
|
146
|
+
this.stats.totalClassifications++;
|
|
147
|
+
this.stats.averageProcessingTime =
|
|
148
|
+
(this.stats.averageProcessingTime * (this.stats.totalClassifications - 1) + processingTime) /
|
|
149
|
+
this.stats.totalClassifications;
|
|
150
|
+
for (const [layer, content] of Object.entries(classified)) {
|
|
151
|
+
const itemCount = Object.keys(content).length;
|
|
152
|
+
this.stats.layerDistribution[layer] += itemCount;
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
getDefaultRules() {
|
|
156
|
+
return {
|
|
157
|
+
patterns: {
|
|
158
|
+
[context_types_1.ContextLayer.CRITICAL]: [
|
|
159
|
+
{
|
|
160
|
+
keyPattern: '^(goal|objective|target|requirement|result|answer|decision|conclusion)s?$',
|
|
161
|
+
weight: 100,
|
|
162
|
+
description: 'Core workflow objectives and final results'
|
|
163
|
+
},
|
|
164
|
+
{
|
|
165
|
+
keyPattern: '^(user|customer|client).*',
|
|
166
|
+
weight: 90,
|
|
167
|
+
description: 'User-related information and requirements'
|
|
168
|
+
},
|
|
169
|
+
{
|
|
170
|
+
keyPattern: '^(error|failure|critical|urgent|important).*',
|
|
171
|
+
weight: 85,
|
|
172
|
+
description: 'Critical errors and urgent items'
|
|
173
|
+
}
|
|
174
|
+
],
|
|
175
|
+
[context_types_1.ContextLayer.IMPORTANT]: [
|
|
176
|
+
{
|
|
177
|
+
keyPattern: '^(plan|strategy|approach|method|process|workflow)s?$',
|
|
178
|
+
weight: 80,
|
|
179
|
+
description: 'Planning and strategic information'
|
|
180
|
+
},
|
|
181
|
+
{
|
|
182
|
+
keyPattern: '^(config|settings|parameters).*',
|
|
183
|
+
weight: 70,
|
|
184
|
+
description: 'Configuration and settings'
|
|
185
|
+
},
|
|
186
|
+
{
|
|
187
|
+
keyPattern: '^(state|status|progress).*',
|
|
188
|
+
weight: 65,
|
|
189
|
+
description: 'Current state and progress tracking'
|
|
190
|
+
}
|
|
191
|
+
],
|
|
192
|
+
[context_types_1.ContextLayer.USEFUL]: [
|
|
193
|
+
{
|
|
194
|
+
keyPattern: '^(data|content|information|details).*',
|
|
195
|
+
weight: 50,
|
|
196
|
+
description: 'Supporting data and detailed information'
|
|
197
|
+
},
|
|
198
|
+
{
|
|
199
|
+
keyPattern: '^(example|sample|demo)s?.*',
|
|
200
|
+
weight: 45,
|
|
201
|
+
description: 'Examples and demonstrations'
|
|
202
|
+
},
|
|
203
|
+
{
|
|
204
|
+
keyPattern: '^(analysis|report|summary).*',
|
|
205
|
+
weight: 40,
|
|
206
|
+
description: 'Analysis results and reports'
|
|
207
|
+
}
|
|
208
|
+
],
|
|
209
|
+
[context_types_1.ContextLayer.EPHEMERAL]: [
|
|
210
|
+
{
|
|
211
|
+
keyPattern: '^(temp|temporary|cache|buffer).*',
|
|
212
|
+
weight: 20,
|
|
213
|
+
description: 'Temporary data and cache'
|
|
214
|
+
},
|
|
215
|
+
{
|
|
216
|
+
keyPattern: '.*(debug|log|trace|timestamp).*',
|
|
217
|
+
weight: 15,
|
|
218
|
+
description: 'Debug information and logs'
|
|
219
|
+
},
|
|
220
|
+
{
|
|
221
|
+
keyPattern: '^(_|internal).*',
|
|
222
|
+
weight: 10,
|
|
223
|
+
description: 'Internal system metadata'
|
|
224
|
+
}
|
|
225
|
+
]
|
|
226
|
+
},
|
|
227
|
+
heuristics: {
|
|
228
|
+
lengthThresholds: {
|
|
229
|
+
[context_types_1.ContextLayer.CRITICAL]: 1000,
|
|
230
|
+
[context_types_1.ContextLayer.IMPORTANT]: 500,
|
|
231
|
+
[context_types_1.ContextLayer.USEFUL]: 100,
|
|
232
|
+
[context_types_1.ContextLayer.EPHEMERAL]: 0
|
|
233
|
+
},
|
|
234
|
+
keywordWeights: {
|
|
235
|
+
'goal': 15,
|
|
236
|
+
'objective': 15,
|
|
237
|
+
'requirement': 12,
|
|
238
|
+
'critical': 10,
|
|
239
|
+
'important': 8,
|
|
240
|
+
'urgent': 8,
|
|
241
|
+
'user': 7,
|
|
242
|
+
'error': 7,
|
|
243
|
+
'failure': 7,
|
|
244
|
+
'plan': 6,
|
|
245
|
+
'strategy': 6,
|
|
246
|
+
'config': 5,
|
|
247
|
+
'data': 3,
|
|
248
|
+
'example': 2,
|
|
249
|
+
'debug': 1,
|
|
250
|
+
'temp': 1
|
|
251
|
+
},
|
|
252
|
+
defaultLayer: context_types_1.ContextLayer.USEFUL
|
|
253
|
+
},
|
|
254
|
+
overrides: {}
|
|
255
|
+
};
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
exports.ClassificationEngine = ClassificationEngine;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { ICompressionService, ClassifiedContext, CompressedBlob, RawContext, CompressionConfig, CompressionStats } from '../../types/context-types';
|
|
2
|
+
export declare class CompressionService implements ICompressionService {
|
|
3
|
+
private config;
|
|
4
|
+
private stats;
|
|
5
|
+
constructor(config?: Partial<CompressionConfig>);
|
|
6
|
+
compress(classified: ClassifiedContext): Promise<CompressedBlob>;
|
|
7
|
+
decompress(blob: CompressedBlob): Promise<RawContext>;
|
|
8
|
+
getStats(): CompressionStats;
|
|
9
|
+
resetStats(): void;
|
|
10
|
+
updateConfig(newConfig: Partial<CompressionConfig>): void;
|
|
11
|
+
private compressLayer;
|
|
12
|
+
private decompressLayer;
|
|
13
|
+
private applyLightCompression;
|
|
14
|
+
private applyMediumCompression;
|
|
15
|
+
private applyAggressiveCompression;
|
|
16
|
+
private applyAlgorithmCompression;
|
|
17
|
+
private applyAlgorithmDecompression;
|
|
18
|
+
private createUncompressedBlob;
|
|
19
|
+
private updateStats;
|
|
20
|
+
}
|
|
@@ -0,0 +1,312 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.CompressionService = void 0;
|
|
37
|
+
const zlib = __importStar(require("zlib"));
|
|
38
|
+
const util_1 = require("util");
|
|
39
|
+
const context_types_1 = require("../../types/context-types");
|
|
40
|
+
const gzip = (0, util_1.promisify)(zlib.gzip);
|
|
41
|
+
const gunzip = (0, util_1.promisify)(zlib.gunzip);
|
|
42
|
+
const deflate = (0, util_1.promisify)(zlib.deflate);
|
|
43
|
+
const inflate = (0, util_1.promisify)(zlib.inflate);
|
|
44
|
+
const LAYER_COMPRESSION_SETTINGS = {
|
|
45
|
+
[context_types_1.ContextLayer.CRITICAL]: {
|
|
46
|
+
enabled: false,
|
|
47
|
+
aggressiveness: 'none',
|
|
48
|
+
level: 0
|
|
49
|
+
},
|
|
50
|
+
[context_types_1.ContextLayer.IMPORTANT]: {
|
|
51
|
+
enabled: true,
|
|
52
|
+
aggressiveness: 'light',
|
|
53
|
+
level: 3
|
|
54
|
+
},
|
|
55
|
+
[context_types_1.ContextLayer.USEFUL]: {
|
|
56
|
+
enabled: true,
|
|
57
|
+
aggressiveness: 'medium',
|
|
58
|
+
level: 6
|
|
59
|
+
},
|
|
60
|
+
[context_types_1.ContextLayer.EPHEMERAL]: {
|
|
61
|
+
enabled: true,
|
|
62
|
+
aggressiveness: 'aggressive',
|
|
63
|
+
level: 9
|
|
64
|
+
}
|
|
65
|
+
};
|
|
66
|
+
const DEFAULT_COMPRESSION_CONFIG = {
|
|
67
|
+
enabled: true,
|
|
68
|
+
algorithm: 'gzip',
|
|
69
|
+
level: 6,
|
|
70
|
+
layerSettings: LAYER_COMPRESSION_SETTINGS
|
|
71
|
+
};
|
|
72
|
+
class CompressionService {
|
|
73
|
+
constructor(config = {}) {
|
|
74
|
+
this.config = { ...DEFAULT_COMPRESSION_CONFIG, ...config };
|
|
75
|
+
this.stats = {
|
|
76
|
+
totalOperations: 0,
|
|
77
|
+
averageRatio: 1.0,
|
|
78
|
+
totalSizeReduction: 0,
|
|
79
|
+
averageCompressionTime: 0
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
async compress(classified) {
|
|
83
|
+
const startTime = process.hrtime.bigint();
|
|
84
|
+
try {
|
|
85
|
+
const compressedLayers = {};
|
|
86
|
+
let totalOriginalSize = 0;
|
|
87
|
+
let totalCompressedSize = 0;
|
|
88
|
+
for (const [layerName, layerData] of Object.entries(classified)) {
|
|
89
|
+
const layer = layerName;
|
|
90
|
+
const layerConfig = this.config.layerSettings[layer];
|
|
91
|
+
if (!layerConfig.enabled || !this.config.enabled) {
|
|
92
|
+
const safeData = layerData || {};
|
|
93
|
+
compressedLayers[layer] = safeData;
|
|
94
|
+
const serialized = JSON.stringify(safeData);
|
|
95
|
+
totalOriginalSize += Buffer.byteLength(serialized, 'utf8');
|
|
96
|
+
totalCompressedSize += Buffer.byteLength(serialized, 'utf8');
|
|
97
|
+
continue;
|
|
98
|
+
}
|
|
99
|
+
const result = await this.compressLayer(layerData, layer, layerConfig.aggressiveness);
|
|
100
|
+
compressedLayers[layer] = result.data;
|
|
101
|
+
totalOriginalSize += result.originalSize;
|
|
102
|
+
totalCompressedSize += result.compressedSize;
|
|
103
|
+
}
|
|
104
|
+
const serializedData = JSON.stringify(compressedLayers);
|
|
105
|
+
let finalCompressedBuffer;
|
|
106
|
+
if (this.config.enabled) {
|
|
107
|
+
finalCompressedBuffer = await this.applyAlgorithmCompression(Buffer.from(serializedData, 'utf8'), this.config.level);
|
|
108
|
+
}
|
|
109
|
+
else {
|
|
110
|
+
finalCompressedBuffer = Buffer.from(serializedData, 'utf8');
|
|
111
|
+
}
|
|
112
|
+
const finalOriginalSize = Buffer.byteLength(serializedData, 'utf8');
|
|
113
|
+
const finalCompressedSize = finalCompressedBuffer.length;
|
|
114
|
+
if (!this.config.enabled) {
|
|
115
|
+
return {
|
|
116
|
+
data: finalCompressedBuffer,
|
|
117
|
+
originalSize: finalCompressedSize,
|
|
118
|
+
compressedSize: finalCompressedSize,
|
|
119
|
+
compressionRatio: 1.0,
|
|
120
|
+
algorithm: 'none'
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
const compressionRatio = totalOriginalSize > 0 ? totalOriginalSize / finalCompressedSize : 1.0;
|
|
124
|
+
const endTime = process.hrtime.bigint();
|
|
125
|
+
const compressionTimeMs = Number(endTime - startTime) / 1000000;
|
|
126
|
+
this.updateStats(compressionRatio, totalOriginalSize - finalCompressedSize, compressionTimeMs);
|
|
127
|
+
return {
|
|
128
|
+
data: finalCompressedBuffer,
|
|
129
|
+
originalSize: totalOriginalSize,
|
|
130
|
+
compressedSize: finalCompressedSize,
|
|
131
|
+
compressionRatio,
|
|
132
|
+
algorithm: this.config.enabled ? this.config.algorithm : 'none'
|
|
133
|
+
};
|
|
134
|
+
}
|
|
135
|
+
catch (error) {
|
|
136
|
+
console.warn('Compression failed, falling back to uncompressed data:', error);
|
|
137
|
+
return this.createUncompressedBlob(classified);
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
async decompress(blob) {
|
|
141
|
+
try {
|
|
142
|
+
if (blob.algorithm === 'none') {
|
|
143
|
+
return JSON.parse(blob.data.toString('utf8'));
|
|
144
|
+
}
|
|
145
|
+
const decompressedBuffer = await this.applyAlgorithmDecompression(blob.data);
|
|
146
|
+
const decompressedData = JSON.parse(decompressedBuffer.toString('utf8'));
|
|
147
|
+
const rawContext = {};
|
|
148
|
+
for (const [layerName, layerData] of Object.entries(decompressedData)) {
|
|
149
|
+
const layer = layerName;
|
|
150
|
+
const layerConfig = this.config.layerSettings[layer];
|
|
151
|
+
if (!layerConfig.enabled) {
|
|
152
|
+
Object.assign(rawContext, layerData);
|
|
153
|
+
}
|
|
154
|
+
else {
|
|
155
|
+
const decompressedLayerData = await this.decompressLayer(layerData, layer);
|
|
156
|
+
Object.assign(rawContext, decompressedLayerData);
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
return Object.freeze(rawContext);
|
|
160
|
+
}
|
|
161
|
+
catch (error) {
|
|
162
|
+
throw new Error(`Decompression failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
getStats() {
|
|
166
|
+
return { ...this.stats };
|
|
167
|
+
}
|
|
168
|
+
resetStats() {
|
|
169
|
+
this.stats = {
|
|
170
|
+
totalOperations: 0,
|
|
171
|
+
averageRatio: 1.0,
|
|
172
|
+
totalSizeReduction: 0,
|
|
173
|
+
averageCompressionTime: 0
|
|
174
|
+
};
|
|
175
|
+
}
|
|
176
|
+
updateConfig(newConfig) {
|
|
177
|
+
this.config = { ...this.config, ...newConfig };
|
|
178
|
+
}
|
|
179
|
+
async compressLayer(layerData, layer, aggressiveness) {
|
|
180
|
+
const safeLayerData = layerData || {};
|
|
181
|
+
const serialized = JSON.stringify(safeLayerData);
|
|
182
|
+
const originalSize = Buffer.byteLength(serialized, 'utf8');
|
|
183
|
+
if (aggressiveness === 'none') {
|
|
184
|
+
return {
|
|
185
|
+
data: safeLayerData,
|
|
186
|
+
originalSize,
|
|
187
|
+
compressedSize: originalSize
|
|
188
|
+
};
|
|
189
|
+
}
|
|
190
|
+
let processedData = safeLayerData;
|
|
191
|
+
switch (aggressiveness) {
|
|
192
|
+
case 'light':
|
|
193
|
+
processedData = this.applyLightCompression(layerData);
|
|
194
|
+
break;
|
|
195
|
+
case 'medium':
|
|
196
|
+
processedData = this.applyMediumCompression(layerData);
|
|
197
|
+
break;
|
|
198
|
+
case 'aggressive':
|
|
199
|
+
processedData = this.applyAggressiveCompression(layerData);
|
|
200
|
+
break;
|
|
201
|
+
}
|
|
202
|
+
const processedSerialized = JSON.stringify(processedData);
|
|
203
|
+
const compressedSize = Buffer.byteLength(processedSerialized, 'utf8');
|
|
204
|
+
return {
|
|
205
|
+
data: processedData,
|
|
206
|
+
originalSize,
|
|
207
|
+
compressedSize
|
|
208
|
+
};
|
|
209
|
+
}
|
|
210
|
+
async decompressLayer(layerData, layer) {
|
|
211
|
+
return layerData;
|
|
212
|
+
}
|
|
213
|
+
applyLightCompression(data) {
|
|
214
|
+
const compressed = {};
|
|
215
|
+
for (const [key, value] of Object.entries(data)) {
|
|
216
|
+
if (typeof value === 'string') {
|
|
217
|
+
compressed[key] = value.replace(/\s+/g, ' ').trim();
|
|
218
|
+
}
|
|
219
|
+
else {
|
|
220
|
+
compressed[key] = value;
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
return compressed;
|
|
224
|
+
}
|
|
225
|
+
applyMediumCompression(data) {
|
|
226
|
+
const compressed = {};
|
|
227
|
+
for (const [key, value] of Object.entries(data)) {
|
|
228
|
+
if (typeof value === 'string') {
|
|
229
|
+
let processedValue = value.replace(/\s+/g, ' ').trim();
|
|
230
|
+
if (processedValue.length > 1000) {
|
|
231
|
+
processedValue = processedValue.substring(0, 950) + '...[truncated]';
|
|
232
|
+
}
|
|
233
|
+
compressed[key] = processedValue;
|
|
234
|
+
}
|
|
235
|
+
else if (Array.isArray(value) && value.length > 50) {
|
|
236
|
+
compressed[key] = [...value.slice(0, 50), '...[truncated]'];
|
|
237
|
+
}
|
|
238
|
+
else {
|
|
239
|
+
compressed[key] = value;
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
return compressed;
|
|
243
|
+
}
|
|
244
|
+
applyAggressiveCompression(data) {
|
|
245
|
+
const compressed = {};
|
|
246
|
+
for (const [key, value] of Object.entries(data)) {
|
|
247
|
+
if (key.includes('debug') || key.includes('temp') || key.includes('timestamp')) {
|
|
248
|
+
continue;
|
|
249
|
+
}
|
|
250
|
+
if (typeof value === 'string') {
|
|
251
|
+
let processedValue = value.replace(/\s+/g, ' ').trim();
|
|
252
|
+
if (processedValue.length > 200) {
|
|
253
|
+
processedValue = processedValue.substring(0, 100) +
|
|
254
|
+
'...[compressed]...' +
|
|
255
|
+
processedValue.substring(processedValue.length - 50);
|
|
256
|
+
}
|
|
257
|
+
compressed[key] = processedValue;
|
|
258
|
+
}
|
|
259
|
+
else if (Array.isArray(value) && value.length > 10) {
|
|
260
|
+
compressed[key] = [...value.slice(0, 5), '...[compressed]', ...value.slice(-2)];
|
|
261
|
+
}
|
|
262
|
+
else if (typeof value === 'object' && value !== null) {
|
|
263
|
+
compressed[key] = this.applyAggressiveCompression(value);
|
|
264
|
+
}
|
|
265
|
+
else {
|
|
266
|
+
compressed[key] = value;
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
return compressed;
|
|
270
|
+
}
|
|
271
|
+
async applyAlgorithmCompression(data, level) {
|
|
272
|
+
const options = { level };
|
|
273
|
+
switch (this.config.algorithm) {
|
|
274
|
+
case 'gzip':
|
|
275
|
+
return await gzip(data, options);
|
|
276
|
+
case 'deflate':
|
|
277
|
+
return await deflate(data, options);
|
|
278
|
+
default:
|
|
279
|
+
throw new Error(`Unsupported compression algorithm: ${this.config.algorithm}`);
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
async applyAlgorithmDecompression(data) {
|
|
283
|
+
switch (this.config.algorithm) {
|
|
284
|
+
case 'gzip':
|
|
285
|
+
return await gunzip(data);
|
|
286
|
+
case 'deflate':
|
|
287
|
+
return await inflate(data);
|
|
288
|
+
default:
|
|
289
|
+
throw new Error(`Unsupported compression algorithm: ${this.config.algorithm}`);
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
createUncompressedBlob(classified) {
|
|
293
|
+
const serialized = JSON.stringify(classified);
|
|
294
|
+
const data = Buffer.from(serialized, 'utf8');
|
|
295
|
+
const size = data.length;
|
|
296
|
+
return {
|
|
297
|
+
data,
|
|
298
|
+
originalSize: size,
|
|
299
|
+
compressedSize: size,
|
|
300
|
+
compressionRatio: 1.0,
|
|
301
|
+
algorithm: 'none'
|
|
302
|
+
};
|
|
303
|
+
}
|
|
304
|
+
updateStats(ratio, sizeReduction, timeMs) {
|
|
305
|
+
const prevOps = this.stats.totalOperations;
|
|
306
|
+
this.stats.totalOperations += 1;
|
|
307
|
+
this.stats.averageRatio = (this.stats.averageRatio * prevOps + ratio) / this.stats.totalOperations;
|
|
308
|
+
this.stats.totalSizeReduction += sizeReduction;
|
|
309
|
+
this.stats.averageCompressionTime = (this.stats.averageCompressionTime * prevOps + timeMs) / this.stats.totalOperations;
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
exports.CompressionService = CompressionService;
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { IContextManagementService, IContextPersistenceService, SaveCheckpointParams, SaveCheckpointResult, LoadCheckpointParams, LoadCheckpointResult, ListCheckpointsParams, CheckpointMetadata, MarkCriticalParams, MarkCriticalResult } from '../../types/context-types';
|
|
2
|
+
import { IContextStorage } from '../../infrastructure/storage/context-storage';
|
|
3
|
+
interface ContextManagementMetrics {
|
|
4
|
+
totalSaveOperations: number;
|
|
5
|
+
totalLoadOperations: number;
|
|
6
|
+
totalListOperations: number;
|
|
7
|
+
totalMarkCriticalOperations: number;
|
|
8
|
+
averageSaveTime: number;
|
|
9
|
+
averageLoadTime: number;
|
|
10
|
+
lastOperationTime: number;
|
|
11
|
+
errorCount: number;
|
|
12
|
+
}
|
|
13
|
+
export declare class ContextManagementService implements IContextManagementService {
|
|
14
|
+
private readonly persistenceService;
|
|
15
|
+
private readonly storage;
|
|
16
|
+
private metrics;
|
|
17
|
+
constructor(persistenceService: IContextPersistenceService, storage: IContextStorage);
|
|
18
|
+
saveCheckpoint(params: SaveCheckpointParams): Promise<SaveCheckpointResult>;
|
|
19
|
+
loadCheckpoint(params: LoadCheckpointParams): Promise<LoadCheckpointResult>;
|
|
20
|
+
listCheckpoints(params: ListCheckpointsParams): Promise<CheckpointMetadata[]>;
|
|
21
|
+
markCritical(params: MarkCriticalParams): Promise<MarkCriticalResult>;
|
|
22
|
+
getMetrics(): ContextManagementMetrics;
|
|
23
|
+
resetMetrics(): void;
|
|
24
|
+
private generateSessionId;
|
|
25
|
+
private generateCheckpointId;
|
|
26
|
+
private isContextUnchanged;
|
|
27
|
+
private getLastCheckpointId;
|
|
28
|
+
private countLayers;
|
|
29
|
+
private upsertSessionInfo;
|
|
30
|
+
private updateSaveMetrics;
|
|
31
|
+
private updateLoadMetrics;
|
|
32
|
+
private updateListMetrics;
|
|
33
|
+
private updateMarkCriticalMetrics;
|
|
34
|
+
private calculateMovingAverage;
|
|
35
|
+
private hashContext;
|
|
36
|
+
private getLastCheckpointData;
|
|
37
|
+
}
|
|
38
|
+
export {};
|