aiwf 0.3.21 → 0.3.23
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/package.json +3 -2
- package/src/cli/index.js +39 -336
- package/src/lib/installer.js +310 -90
- package/src/utils/messages.js +24 -0
- package/src/DEPENDENCY_MAP.md +0 -90
- package/src/cli/cache-cli.js +0 -459
- package/src/cli/checkpoint-cli.js +0 -417
- package/src/cli/language-cli.js +0 -286
- package/src/cli/sprint-cli.js +0 -287
- package/src/commands/ai-tool.js +0 -383
- package/src/commands/compress.js +0 -60
- package/src/commands/create-project.js +0 -160
- package/src/commands/evaluate.js +0 -459
- package/src/commands/persona.js +0 -309
- package/src/commands/sprint-task.js +0 -262
- package/src/commands/token.js +0 -312
- package/src/lib/ai-persona-manager.js +0 -711
- package/src/lib/cache-system.js +0 -332
- package/src/lib/context-engine.js +0 -568
- package/src/lib/github-integration.js +0 -402
- package/src/lib/memory-profiler.js +0 -471
- package/src/lib/metrics-collector.js +0 -885
- package/src/lib/offline-detector.js +0 -386
- package/src/lib/resource-loader-enhanced.js +0 -399
- package/src/lib/resource-loader.js +0 -250
- package/src/lib/resources/commands/ai-persona.js +0 -602
- package/src/lib/resources/commands/compress-context.js +0 -389
- package/src/lib/resources/commands/evaluate.js +0 -246
- package/src/lib/resources/commands/persona-context-apply.js +0 -562
- package/src/lib/resources/commands/token-tracking.js +0 -443
- package/src/lib/resources/config/commit-patterns.js +0 -103
- package/src/lib/resources/config/language.json +0 -6
- package/src/lib/resources/personas/PERSONA_INDEX.md +0 -57
- package/src/lib/resources/personas/analyst.json +0 -44
- package/src/lib/resources/personas/architect/best_practices.md +0 -136
- package/src/lib/resources/personas/architect/knowledge_base.md +0 -377
- package/src/lib/resources/personas/architect.json +0 -44
- package/src/lib/resources/personas/backend/best_practices.md +0 -766
- package/src/lib/resources/personas/backend/knowledge_base.md +0 -1070
- package/src/lib/resources/personas/data_analyst/best_practices.md +0 -594
- package/src/lib/resources/personas/data_analyst/knowledge_base.md +0 -1057
- package/src/lib/resources/personas/developer.json +0 -44
- package/src/lib/resources/personas/developer.md +0 -37
- package/src/lib/resources/personas/evaluation_criteria.json +0 -137
- package/src/lib/resources/personas/frontend/best_practices.md +0 -445
- package/src/lib/resources/personas/frontend/knowledge_base.md +0 -729
- package/src/lib/resources/personas/persona-index.json +0 -31
- package/src/lib/resources/personas/reviewer.json +0 -44
- package/src/lib/resources/personas/security/best_practices.md +0 -307
- package/src/lib/resources/personas/security/knowledge_base.md +0 -498
- package/src/lib/resources/personas/tester.json +0 -44
- package/src/lib/resources/templates/README.md +0 -78
- package/src/lib/resources/templates/api-server/config.json +0 -64
- package/src/lib/resources/templates/api-server/template/.aiwf/config.json +0 -56
- package/src/lib/resources/templates/api-server/template/.aiwf/feature-ledger.json +0 -42
- package/src/lib/resources/templates/api-server/template/.aiwf/personas/backend-engineer.json +0 -40
- package/src/lib/resources/templates/api-server/template/.aiwf/scripts/cli.js +0 -111
- package/src/lib/resources/templates/api-server/template/.env.example +0 -29
- package/src/lib/resources/templates/api-server/template/.eslintrc.json +0 -23
- package/src/lib/resources/templates/api-server/template/README.md +0 -171
- package/src/lib/resources/templates/api-server/template/jest.config.js +0 -26
- package/src/lib/resources/templates/api-server/template/nodemon.json +0 -9
- package/src/lib/resources/templates/api-server/template/package.json +0 -61
- package/src/lib/resources/templates/api-server/template/src/app.ts +0 -60
- package/src/lib/resources/templates/api-server/template/src/config/swagger.ts +0 -38
- package/src/lib/resources/templates/api-server/template/src/controllers/aiwfController.ts +0 -54
- package/src/lib/resources/templates/api-server/template/src/controllers/authController.ts +0 -128
- package/src/lib/resources/templates/api-server/template/src/controllers/statusController.ts +0 -28
- package/src/lib/resources/templates/api-server/template/src/index.ts +0 -28
- package/src/lib/resources/templates/api-server/template/src/middleware/aiwfMiddleware.ts +0 -50
- package/src/lib/resources/templates/api-server/template/src/middleware/authMiddleware.ts +0 -41
- package/src/lib/resources/templates/api-server/template/src/middleware/errorHandler.ts +0 -42
- package/src/lib/resources/templates/api-server/template/src/middleware/notFoundHandler.ts +0 -14
- package/src/lib/resources/templates/api-server/template/src/middleware/requestLogger.ts +0 -20
- package/src/lib/resources/templates/api-server/template/src/routes/aiwf.ts +0 -31
- package/src/lib/resources/templates/api-server/template/src/routes/index.ts +0 -13
- package/src/lib/resources/templates/api-server/template/src/routes/v1/index.ts +0 -67
- package/src/lib/resources/templates/api-server/template/src/utils/logger.ts +0 -37
- package/src/lib/resources/templates/api-server/template/tests/app.test.ts +0 -40
- package/src/lib/resources/templates/api-server/template/tsconfig.json +0 -43
- package/src/lib/resources/templates/npm-library/config.json +0 -61
- package/src/lib/resources/templates/npm-library/template/LICENSE +0 -21
- package/src/lib/resources/templates/npm-library/template/README.md +0 -201
- package/src/lib/resources/templates/npm-library/template/package.json +0 -78
- package/src/lib/resources/templates/web-app/config.json +0 -53
- package/src/lib/resources/templates/web-app/template/.aiwf/config.json +0 -54
- package/src/lib/resources/templates/web-app/template/.aiwf/feature-ledger.json +0 -37
- package/src/lib/resources/templates/web-app/template/.aiwf/personas/fullstack-developer.json +0 -40
- package/src/lib/resources/templates/web-app/template/.aiwf/scripts/cli.js +0 -110
- package/src/lib/resources/templates/web-app/template/.eslintrc.cjs +0 -20
- package/src/lib/resources/templates/web-app/template/README.md +0 -151
- package/src/lib/resources/templates/web-app/template/index.html +0 -14
- package/src/lib/resources/templates/web-app/template/package.json +0 -44
- package/src/lib/resources/templates/web-app/template/postcss.config.js +0 -6
- package/src/lib/resources/templates/web-app/template/public/vite.svg +0 -1
- package/src/lib/resources/templates/web-app/template/src/App.tsx +0 -21
- package/src/lib/resources/templates/web-app/template/src/components/Layout.tsx +0 -57
- package/src/lib/resources/templates/web-app/template/src/components/aiwf/ContextStatus.tsx +0 -107
- package/src/lib/resources/templates/web-app/template/src/components/aiwf/TokenUsage.tsx +0 -71
- package/src/lib/resources/templates/web-app/template/src/index.css +0 -60
- package/src/lib/resources/templates/web-app/template/src/main.tsx +0 -10
- package/src/lib/resources/templates/web-app/template/src/pages/AiwfDashboard.tsx +0 -57
- package/src/lib/resources/templates/web-app/template/src/pages/HomePage.tsx +0 -89
- package/src/lib/resources/templates/web-app/template/src/pages/NotFound.tsx +0 -25
- package/src/lib/resources/templates/web-app/template/src/stores/aiwfStore.ts +0 -126
- package/src/lib/resources/templates/web-app/template/src/types/global.d.ts +0 -9
- package/src/lib/resources/templates/web-app/template/src/vite-env.d.ts +0 -1
- package/src/lib/resources/templates/web-app/template/tailwind.config.js +0 -30
- package/src/lib/resources/templates/web-app/template/tsconfig.json +0 -37
- package/src/lib/resources/templates/web-app/template/tsconfig.node.json +0 -10
- package/src/lib/resources/templates/web-app/template/vite.config.ts +0 -23
- package/src/lib/resources/utils/background-monitor.js +0 -223
- package/src/lib/resources/utils/compression-metrics.js +0 -1031
- package/src/lib/resources/utils/compression-strategies.js +0 -557
- package/src/lib/resources/utils/content-normalizer.js +0 -455
- package/src/lib/resources/utils/context-compressor.js +0 -583
- package/src/lib/resources/utils/context-rule-parser.js +0 -180
- package/src/lib/resources/utils/context-token-monitor.js +0 -463
- package/src/lib/resources/utils/context-update-manager.js +0 -502
- package/src/lib/resources/utils/git-utils.js +0 -220
- package/src/lib/resources/utils/importance-classifier.js +0 -645
- package/src/lib/resources/utils/information-filter.js +0 -710
- package/src/lib/resources/utils/persona-aware-compressor.js +0 -598
- package/src/lib/resources/utils/prompt-injector.js +0 -242
- package/src/lib/resources/utils/simplified-evaluator.js +0 -119
- package/src/lib/resources/utils/text-summarizer.js +0 -492
- package/src/lib/resources/utils/token-counter.js +0 -177
- package/src/lib/resources/utils/token-monitor.js +0 -484
- package/src/lib/resources/utils/token-reporter.js +0 -452
- package/src/lib/resources/utils/token-storage.js +0 -433
- package/src/lib/resources/utils/token-tracker.js +0 -283
- package/src/lib/state/priority-calculator.js +0 -217
- package/src/lib/state/state-index.js +0 -155
- package/src/lib/state/task-scanner.js +0 -328
- package/src/lib/task-analyzer.js +0 -599
- package/src/lib/template-cache-system.js +0 -559
- package/src/lib/template-downloader.js +0 -467
- package/src/lib/template-version-manager.js +0 -491
- package/src/lib/token-optimizer.js +0 -517
- package/src/utils/engineering-guard.js +0 -399
|
@@ -1,517 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Token Optimizer
|
|
3
|
-
* Optimizes token usage for AI persona contexts
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
import { EventEmitter } from 'events';
|
|
7
|
-
|
|
8
|
-
class TokenOptimizer extends EventEmitter {
|
|
9
|
-
constructor(options = {}) {
|
|
10
|
-
super();
|
|
11
|
-
|
|
12
|
-
this.options = {
|
|
13
|
-
maxTokens: options.maxTokens || 100000,
|
|
14
|
-
compressionStrategies: options.compressionStrategies || ['summarize', 'filter', 'truncate'],
|
|
15
|
-
preserveImportant: options.preserveImportant !== false,
|
|
16
|
-
qualityThreshold: options.qualityThreshold || 0.8,
|
|
17
|
-
...options
|
|
18
|
-
};
|
|
19
|
-
|
|
20
|
-
// Token estimation factors
|
|
21
|
-
this.tokenFactors = {
|
|
22
|
-
charToToken: 4, // Approximate: 1 token ≈ 4 characters
|
|
23
|
-
lineOverhead: 1, // Additional tokens per line
|
|
24
|
-
structureOverhead: 0.1 // 10% overhead for JSON structure
|
|
25
|
-
};
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
/**
|
|
29
|
-
* Optimize context based on persona token allocation
|
|
30
|
-
*/
|
|
31
|
-
async optimize(baseContext, personaOverlay, tokenAllocation) {
|
|
32
|
-
try {
|
|
33
|
-
// Calculate current token usage
|
|
34
|
-
const currentTokens = this.estimateTokens(baseContext) +
|
|
35
|
-
this.estimateTokens(personaOverlay);
|
|
36
|
-
|
|
37
|
-
// Calculate target tokens
|
|
38
|
-
const targetTokens = Math.floor(this.options.maxTokens * (tokenAllocation.context || 0.4));
|
|
39
|
-
|
|
40
|
-
// If already within limits, return as-is
|
|
41
|
-
if (currentTokens <= targetTokens) {
|
|
42
|
-
return this.mergeContexts(baseContext, personaOverlay);
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
// Apply optimization strategies
|
|
46
|
-
let optimizedContext = baseContext;
|
|
47
|
-
let optimizedOverlay = personaOverlay;
|
|
48
|
-
|
|
49
|
-
for (const strategy of this.options.compressionStrategies) {
|
|
50
|
-
const result = await this.applyStrategy(
|
|
51
|
-
strategy,
|
|
52
|
-
optimizedContext,
|
|
53
|
-
optimizedOverlay,
|
|
54
|
-
targetTokens
|
|
55
|
-
);
|
|
56
|
-
|
|
57
|
-
optimizedContext = result.context;
|
|
58
|
-
optimizedOverlay = result.overlay;
|
|
59
|
-
|
|
60
|
-
// Check if we've reached target
|
|
61
|
-
const newTokens = this.estimateTokens(optimizedContext) +
|
|
62
|
-
this.estimateTokens(optimizedOverlay);
|
|
63
|
-
|
|
64
|
-
if (newTokens <= targetTokens) {
|
|
65
|
-
break;
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
const finalContext = this.mergeContexts(optimizedContext, optimizedOverlay);
|
|
70
|
-
|
|
71
|
-
this.emit('optimized', {
|
|
72
|
-
originalTokens: currentTokens,
|
|
73
|
-
optimizedTokens: this.estimateTokens(finalContext),
|
|
74
|
-
reduction: ((currentTokens - this.estimateTokens(finalContext)) / currentTokens) * 100
|
|
75
|
-
});
|
|
76
|
-
|
|
77
|
-
return finalContext;
|
|
78
|
-
} catch (error) {
|
|
79
|
-
this.emit('error', { error, phase: 'optimization' });
|
|
80
|
-
throw error;
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
/**
|
|
85
|
-
* Apply optimization strategy
|
|
86
|
-
*/
|
|
87
|
-
async applyStrategy(strategy, context, overlay, targetTokens) {
|
|
88
|
-
switch (strategy) {
|
|
89
|
-
case 'summarize':
|
|
90
|
-
return await this.applySummarization(context, overlay, targetTokens);
|
|
91
|
-
|
|
92
|
-
case 'filter':
|
|
93
|
-
return await this.applyFiltering(context, overlay, targetTokens);
|
|
94
|
-
|
|
95
|
-
case 'truncate':
|
|
96
|
-
return await this.applyTruncation(context, overlay, targetTokens);
|
|
97
|
-
|
|
98
|
-
default:
|
|
99
|
-
return { context, overlay };
|
|
100
|
-
}
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
/**
|
|
104
|
-
* Apply summarization strategy
|
|
105
|
-
*/
|
|
106
|
-
async applySummarization(context, overlay, targetTokens) {
|
|
107
|
-
const optimized = {
|
|
108
|
-
context: { ...context },
|
|
109
|
-
overlay: { ...overlay }
|
|
110
|
-
};
|
|
111
|
-
|
|
112
|
-
// Summarize project files
|
|
113
|
-
if (context.projectFiles) {
|
|
114
|
-
optimized.context.projectFiles = this.summarizeProjectFiles(context.projectFiles);
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
// Summarize environment (keep as-is, already minimal)
|
|
118
|
-
|
|
119
|
-
// Summarize recent changes
|
|
120
|
-
if (context.recentChanges) {
|
|
121
|
-
optimized.context.recentChanges = this.summarizeRecentChanges(context.recentChanges);
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
return optimized;
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
/**
|
|
128
|
-
* Summarize project files
|
|
129
|
-
*/
|
|
130
|
-
summarizeProjectFiles(projectFiles) {
|
|
131
|
-
const summarized = {
|
|
132
|
-
structure: this.summarizeFileStructure(projectFiles.structure || []),
|
|
133
|
-
recentFiles: (projectFiles.recentFiles || []).slice(0, 5), // Keep only top 5
|
|
134
|
-
importantFiles: projectFiles.importantFiles || []
|
|
135
|
-
};
|
|
136
|
-
|
|
137
|
-
return summarized;
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
/**
|
|
141
|
-
* Summarize file structure
|
|
142
|
-
*/
|
|
143
|
-
summarizeFileStructure(structure, maxDepth = 2, currentDepth = 0) {
|
|
144
|
-
if (currentDepth >= maxDepth) {
|
|
145
|
-
return { type: 'truncated', count: this.countItems(structure) };
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
return structure.map(item => {
|
|
149
|
-
if (item.type === 'directory' && item.children) {
|
|
150
|
-
// Summarize large directories
|
|
151
|
-
if (item.children.length > 10) {
|
|
152
|
-
return {
|
|
153
|
-
...item,
|
|
154
|
-
children: [
|
|
155
|
-
...item.children.slice(0, 5),
|
|
156
|
-
{ type: 'truncated', count: item.children.length - 5 }
|
|
157
|
-
]
|
|
158
|
-
};
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
return {
|
|
162
|
-
...item,
|
|
163
|
-
children: this.summarizeFileStructure(item.children, maxDepth, currentDepth + 1)
|
|
164
|
-
};
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
return item;
|
|
168
|
-
});
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
/**
|
|
172
|
-
* Count items in structure
|
|
173
|
-
*/
|
|
174
|
-
countItems(structure) {
|
|
175
|
-
let count = 0;
|
|
176
|
-
|
|
177
|
-
for (const item of structure) {
|
|
178
|
-
count++;
|
|
179
|
-
if (item.children) {
|
|
180
|
-
count += this.countItems(item.children);
|
|
181
|
-
}
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
return count;
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
/**
|
|
188
|
-
* Summarize recent changes
|
|
189
|
-
*/
|
|
190
|
-
summarizeRecentChanges(changes) {
|
|
191
|
-
return {
|
|
192
|
-
gitStatus: changes.gitStatus,
|
|
193
|
-
recentCommits: (changes.recentCommits || []).slice(0, 3), // Keep only 3 most recent
|
|
194
|
-
hasUncommittedChanges: changes.uncommittedChanges?.length > 0
|
|
195
|
-
};
|
|
196
|
-
}
|
|
197
|
-
|
|
198
|
-
/**
|
|
199
|
-
* Apply filtering strategy
|
|
200
|
-
*/
|
|
201
|
-
async applyFiltering(context, overlay, targetTokens) {
|
|
202
|
-
const optimized = {
|
|
203
|
-
context: { ...context },
|
|
204
|
-
overlay: { ...overlay }
|
|
205
|
-
};
|
|
206
|
-
|
|
207
|
-
// Apply persona-specific filtering
|
|
208
|
-
if (overlay.exclusionPatterns?.length > 0) {
|
|
209
|
-
optimized.context = this.filterByPatterns(
|
|
210
|
-
optimized.context,
|
|
211
|
-
overlay.exclusionPatterns,
|
|
212
|
-
'exclude'
|
|
213
|
-
);
|
|
214
|
-
}
|
|
215
|
-
|
|
216
|
-
if (overlay.priorityPatterns?.length > 0) {
|
|
217
|
-
optimized.context = this.filterByPatterns(
|
|
218
|
-
optimized.context,
|
|
219
|
-
overlay.priorityPatterns,
|
|
220
|
-
'include'
|
|
221
|
-
);
|
|
222
|
-
}
|
|
223
|
-
|
|
224
|
-
return optimized;
|
|
225
|
-
}
|
|
226
|
-
|
|
227
|
-
/**
|
|
228
|
-
* Filter context by patterns
|
|
229
|
-
*/
|
|
230
|
-
filterByPatterns(context, patterns, mode = 'exclude') {
|
|
231
|
-
const filtered = { ...context };
|
|
232
|
-
|
|
233
|
-
// Filter project files
|
|
234
|
-
if (filtered.projectFiles) {
|
|
235
|
-
filtered.projectFiles = {
|
|
236
|
-
...filtered.projectFiles,
|
|
237
|
-
structure: this.filterFileStructure(
|
|
238
|
-
filtered.projectFiles.structure || [],
|
|
239
|
-
patterns,
|
|
240
|
-
mode
|
|
241
|
-
),
|
|
242
|
-
recentFiles: this.filterFileList(
|
|
243
|
-
filtered.projectFiles.recentFiles || [],
|
|
244
|
-
patterns,
|
|
245
|
-
mode
|
|
246
|
-
)
|
|
247
|
-
};
|
|
248
|
-
}
|
|
249
|
-
|
|
250
|
-
return filtered;
|
|
251
|
-
}
|
|
252
|
-
|
|
253
|
-
/**
|
|
254
|
-
* Filter file structure by patterns
|
|
255
|
-
*/
|
|
256
|
-
filterFileStructure(structure, patterns, mode) {
|
|
257
|
-
return structure
|
|
258
|
-
.map(item => {
|
|
259
|
-
const matches = this.matchesPatterns(item.path, patterns);
|
|
260
|
-
|
|
261
|
-
if (mode === 'exclude' && matches) {
|
|
262
|
-
return null;
|
|
263
|
-
}
|
|
264
|
-
|
|
265
|
-
if (mode === 'include' && !matches) {
|
|
266
|
-
return null;
|
|
267
|
-
}
|
|
268
|
-
|
|
269
|
-
if (item.type === 'directory' && item.children) {
|
|
270
|
-
const filteredChildren = this.filterFileStructure(item.children, patterns, mode);
|
|
271
|
-
|
|
272
|
-
// Remove empty directories
|
|
273
|
-
if (filteredChildren.length === 0) {
|
|
274
|
-
return null;
|
|
275
|
-
}
|
|
276
|
-
|
|
277
|
-
return {
|
|
278
|
-
...item,
|
|
279
|
-
children: filteredChildren
|
|
280
|
-
};
|
|
281
|
-
}
|
|
282
|
-
|
|
283
|
-
return item;
|
|
284
|
-
})
|
|
285
|
-
.filter(Boolean);
|
|
286
|
-
}
|
|
287
|
-
|
|
288
|
-
/**
|
|
289
|
-
* Filter file list by patterns
|
|
290
|
-
*/
|
|
291
|
-
filterFileList(files, patterns, mode) {
|
|
292
|
-
return files.filter(file => {
|
|
293
|
-
const path = typeof file === 'string' ? file : file.path;
|
|
294
|
-
const matches = this.matchesPatterns(path, patterns);
|
|
295
|
-
|
|
296
|
-
if (mode === 'exclude') {
|
|
297
|
-
return !matches;
|
|
298
|
-
}
|
|
299
|
-
|
|
300
|
-
return matches;
|
|
301
|
-
});
|
|
302
|
-
}
|
|
303
|
-
|
|
304
|
-
/**
|
|
305
|
-
* Check if path matches any pattern
|
|
306
|
-
*/
|
|
307
|
-
matchesPatterns(path, patterns) {
|
|
308
|
-
return patterns.some(pattern => {
|
|
309
|
-
const regex = pattern
|
|
310
|
-
.replace(/\*\*/g, '.*')
|
|
311
|
-
.replace(/\*/g, '[^/]*')
|
|
312
|
-
.replace(/\?/g, '.')
|
|
313
|
-
.replace(/\./g, '\\.');
|
|
314
|
-
|
|
315
|
-
return new RegExp(regex).test(path);
|
|
316
|
-
});
|
|
317
|
-
}
|
|
318
|
-
|
|
319
|
-
/**
|
|
320
|
-
* Apply truncation strategy
|
|
321
|
-
*/
|
|
322
|
-
async applyTruncation(context, overlay, targetTokens) {
|
|
323
|
-
const optimized = {
|
|
324
|
-
context: { ...context },
|
|
325
|
-
overlay: { ...overlay }
|
|
326
|
-
};
|
|
327
|
-
|
|
328
|
-
// Calculate how much we need to reduce
|
|
329
|
-
const currentTokens = this.estimateTokens(context) + this.estimateTokens(overlay);
|
|
330
|
-
const reductionRatio = targetTokens / currentTokens;
|
|
331
|
-
|
|
332
|
-
// Truncate various sections proportionally
|
|
333
|
-
if (context.projectFiles?.structure) {
|
|
334
|
-
const maxItems = Math.floor(10 * reductionRatio);
|
|
335
|
-
optimized.context.projectFiles.structure =
|
|
336
|
-
this.truncateStructure(context.projectFiles.structure, maxItems);
|
|
337
|
-
}
|
|
338
|
-
|
|
339
|
-
if (context.projectFiles?.recentFiles) {
|
|
340
|
-
const maxFiles = Math.floor(context.projectFiles.recentFiles.length * reductionRatio);
|
|
341
|
-
optimized.context.projectFiles.recentFiles =
|
|
342
|
-
context.projectFiles.recentFiles.slice(0, Math.max(maxFiles, 3));
|
|
343
|
-
}
|
|
344
|
-
|
|
345
|
-
// Truncate system prompt if needed
|
|
346
|
-
if (overlay.systemPrompt) {
|
|
347
|
-
const maxLength = Math.floor(overlay.systemPrompt.length * reductionRatio);
|
|
348
|
-
optimized.overlay.systemPrompt = this.truncateText(
|
|
349
|
-
overlay.systemPrompt,
|
|
350
|
-
maxLength,
|
|
351
|
-
true // preserve important parts
|
|
352
|
-
);
|
|
353
|
-
}
|
|
354
|
-
|
|
355
|
-
return optimized;
|
|
356
|
-
}
|
|
357
|
-
|
|
358
|
-
/**
|
|
359
|
-
* Truncate structure to maximum items
|
|
360
|
-
*/
|
|
361
|
-
truncateStructure(structure, maxItems, currentCount = 0) {
|
|
362
|
-
const truncated = [];
|
|
363
|
-
let count = currentCount;
|
|
364
|
-
|
|
365
|
-
for (const item of structure) {
|
|
366
|
-
if (count >= maxItems) {
|
|
367
|
-
truncated.push({ type: 'truncated', count: structure.length - truncated.length });
|
|
368
|
-
break;
|
|
369
|
-
}
|
|
370
|
-
|
|
371
|
-
if (item.type === 'directory' && item.children) {
|
|
372
|
-
const remainingItems = maxItems - count - 1;
|
|
373
|
-
const truncatedChildren = this.truncateStructure(
|
|
374
|
-
item.children,
|
|
375
|
-
remainingItems,
|
|
376
|
-
0
|
|
377
|
-
);
|
|
378
|
-
|
|
379
|
-
truncated.push({
|
|
380
|
-
...item,
|
|
381
|
-
children: truncatedChildren
|
|
382
|
-
});
|
|
383
|
-
|
|
384
|
-
count += 1 + this.countItems(truncatedChildren);
|
|
385
|
-
} else {
|
|
386
|
-
truncated.push(item);
|
|
387
|
-
count++;
|
|
388
|
-
}
|
|
389
|
-
}
|
|
390
|
-
|
|
391
|
-
return truncated;
|
|
392
|
-
}
|
|
393
|
-
|
|
394
|
-
/**
|
|
395
|
-
* Truncate text while preserving important parts
|
|
396
|
-
*/
|
|
397
|
-
truncateText(text, maxLength, preserveImportant = false) {
|
|
398
|
-
if (text.length <= maxLength) {
|
|
399
|
-
return text;
|
|
400
|
-
}
|
|
401
|
-
|
|
402
|
-
if (!preserveImportant) {
|
|
403
|
-
return text.substring(0, maxLength - 3) + '...';
|
|
404
|
-
}
|
|
405
|
-
|
|
406
|
-
// Try to preserve complete sentences
|
|
407
|
-
const sentences = text.split(/\. |\n/);
|
|
408
|
-
let truncated = '';
|
|
409
|
-
|
|
410
|
-
for (const sentence of sentences) {
|
|
411
|
-
if (truncated.length + sentence.length + 2 > maxLength) {
|
|
412
|
-
break;
|
|
413
|
-
}
|
|
414
|
-
truncated += sentence + '. ';
|
|
415
|
-
}
|
|
416
|
-
|
|
417
|
-
return truncated.trim() || text.substring(0, maxLength - 3) + '...';
|
|
418
|
-
}
|
|
419
|
-
|
|
420
|
-
/**
|
|
421
|
-
* Estimate token count
|
|
422
|
-
*/
|
|
423
|
-
estimateTokens(obj) {
|
|
424
|
-
if (!obj) return 0;
|
|
425
|
-
|
|
426
|
-
const jsonString = JSON.stringify(obj);
|
|
427
|
-
const charCount = jsonString.length;
|
|
428
|
-
const lineCount = jsonString.split('\n').length;
|
|
429
|
-
|
|
430
|
-
// Base token count from characters
|
|
431
|
-
let tokens = Math.ceil(charCount / this.tokenFactors.charToToken);
|
|
432
|
-
|
|
433
|
-
// Add line overhead
|
|
434
|
-
tokens += lineCount * this.tokenFactors.lineOverhead;
|
|
435
|
-
|
|
436
|
-
// Add structure overhead
|
|
437
|
-
tokens *= (1 + this.tokenFactors.structureOverhead);
|
|
438
|
-
|
|
439
|
-
return Math.ceil(tokens);
|
|
440
|
-
}
|
|
441
|
-
|
|
442
|
-
/**
|
|
443
|
-
* Merge contexts
|
|
444
|
-
*/
|
|
445
|
-
mergeContexts(context, overlay) {
|
|
446
|
-
return {
|
|
447
|
-
...context,
|
|
448
|
-
personaOverlay: overlay,
|
|
449
|
-
size: this.estimateTokens({ ...context, personaOverlay: overlay })
|
|
450
|
-
};
|
|
451
|
-
}
|
|
452
|
-
|
|
453
|
-
/**
|
|
454
|
-
* Validate optimization quality
|
|
455
|
-
*/
|
|
456
|
-
validateQuality(original, optimized) {
|
|
457
|
-
// Check that important information is preserved
|
|
458
|
-
const quality = {
|
|
459
|
-
score: 1.0,
|
|
460
|
-
issues: []
|
|
461
|
-
};
|
|
462
|
-
|
|
463
|
-
// Check if environment is preserved
|
|
464
|
-
if (!optimized.environment) {
|
|
465
|
-
quality.score -= 0.2;
|
|
466
|
-
quality.issues.push('Missing environment information');
|
|
467
|
-
}
|
|
468
|
-
|
|
469
|
-
// Check if important files are preserved
|
|
470
|
-
if (original.projectFiles?.importantFiles &&
|
|
471
|
-
(!optimized.projectFiles?.importantFiles ||
|
|
472
|
-
optimized.projectFiles.importantFiles.length === 0)) {
|
|
473
|
-
quality.score -= 0.1;
|
|
474
|
-
quality.issues.push('Important files removed');
|
|
475
|
-
}
|
|
476
|
-
|
|
477
|
-
// Check if persona overlay is preserved
|
|
478
|
-
if (!optimized.personaOverlay?.systemPrompt) {
|
|
479
|
-
quality.score -= 0.3;
|
|
480
|
-
quality.issues.push('Missing persona system prompt');
|
|
481
|
-
}
|
|
482
|
-
|
|
483
|
-
return quality;
|
|
484
|
-
}
|
|
485
|
-
|
|
486
|
-
/**
|
|
487
|
-
* Get optimization statistics
|
|
488
|
-
*/
|
|
489
|
-
getOptimizationStats() {
|
|
490
|
-
// This would track optimization performance over time
|
|
491
|
-
return {
|
|
492
|
-
averageReduction: 0.3, // 30% average reduction
|
|
493
|
-
strategyEffectiveness: {
|
|
494
|
-
summarize: 0.2,
|
|
495
|
-
filter: 0.3,
|
|
496
|
-
truncate: 0.5
|
|
497
|
-
}
|
|
498
|
-
};
|
|
499
|
-
}
|
|
500
|
-
|
|
501
|
-
/**
|
|
502
|
-
* Reset optimizer
|
|
503
|
-
*/
|
|
504
|
-
reset() {
|
|
505
|
-
this.removeAllListeners();
|
|
506
|
-
}
|
|
507
|
-
|
|
508
|
-
/**
|
|
509
|
-
* Cleanup resources
|
|
510
|
-
*/
|
|
511
|
-
cleanup() {
|
|
512
|
-
this.reset();
|
|
513
|
-
}
|
|
514
|
-
}
|
|
515
|
-
|
|
516
|
-
export default TokenOptimizer;
|
|
517
|
-
export { TokenOptimizer };
|