MCPcopy Create free account
hub / github.com/QodeXcli/QodeX / buildRecommendations

Function buildRecommendations

src/diagnostics/token-analyzer.ts:235–313  ·  view source on GitHub ↗

* Data-driven recommendations. Each one fires only when its threshold is hit, so the * advice is calibrated to THIS session, not a generic checklist. * * Thresholds intentionally on the strict side — we don't want noise.

(args: {
  totals: TokenReport['totals'];
  breakdowns: TurnBreakdown[];
  toolHotspots: TokenReport['toolHotspots'];
  fileHotspots: TokenReport['fileHotspots'];
})

Source from the content-addressed store, hash-verified

233 * Thresholds intentionally on the strict side — we don't want noise.
234 */
235function buildRecommendations(args: {
236 totals: TokenReport['totals'];
237 breakdowns: TurnBreakdown[];
238 toolHotspots: TokenReport['toolHotspots'];
239 fileHotspots: TokenReport['fileHotspots'];
240}): string[] {
241 const recs: string[] = [];
242 const { totals, breakdowns, toolHotspots, fileHotspots } = args;
243 const turnCount = breakdowns.length;
244 if (turnCount === 0) return ['Session has no turns yet — run a task first.'];
245
246 // 1. Tool schemas dominate? Each turn reships them, so total = perTurn * turnCount
247 const schemasShare = totals.grandTotal > 0 ? totals.toolSchemas / totals.grandTotal : 0;
248 if (schemasShare > 0.4) {
249 recs.push(
250 `Tool schemas account for ${Math.round(schemasShare * 100)}% of all tokens ` +
251 `(${totals.toolSchemas.toLocaleString()} across ${turnCount} turns). ` +
252 `Highest-leverage fix: enable prompt caching (cloud) or KV-cache reuse (local Ollama/MLX), ` +
253 `OR slim tool descriptions. This is Lever 1 + Lever 2 in the optimization plan.`,
254 );
255 }
256
257 // 2. System prompt similar
258 const systemShare = totals.grandTotal > 0 ? totals.system / totals.grandTotal : 0;
259 if (systemShare > 0.2 && turnCount > 3) {
260 recs.push(
261 `System prompt is reshipped every turn (${totals.system.toLocaleString()} total = ` +
262 `${Math.round(systemShare * 100)}% of session). ` +
263 `Same caching strategy applies — system + tools should be a single cached prefix.`,
264 );
265 }
266
267 // 3. Repeated reads of the same file
268 const repeatedFiles = fileHotspots.filter(f => f.reads >= 3);
269 if (repeatedFiles.length > 0) {
270 const top = repeatedFiles.slice(0, 3).map(f => `${f.path} (${f.reads}×)`).join(', ');
271 recs.push(
272 `Repeated reads detected: ${top}. ` +
273 `Dedup with content hashing (Lever 3) would skip the redundant content. ` +
274 `Each repeat costs the full file body in tokens.`,
275 );
276 }
277
278 // 4. One tool dominates output
279 if (toolHotspots.length > 0) {
280 const top = toolHotspots[0]!;
281 const topShare = totals.toolResults > 0 ? top.outputTokens / totals.toolResults : 0;
282 if (topShare > 0.5 && top.outputTokens > 2000) {
283 recs.push(
284 `'${top.tool}' produced ${top.outputTokens.toLocaleString()} tokens of output ` +
285 `(${Math.round(topShare * 100)}% of all tool results), ` +
286 `avg ${top.avgPerCall.toLocaleString()} per call. ` +
287 `Consider truncation at the tool level (e.g. max bytes) or summarisation of older results in history.`,
288 );
289 }
290 }
291
292 // 5. Total trajectory — is the session about to blow past a typical 32K context?

Callers 1

analyzeMessagesFunction · 0.85

Calls 1

pushMethod · 0.45

Tested by

no test coverage detected