claude-flow 3.32.18 → 3.32.20
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 +1 -1
- package/v3/@claude-flow/cli/catalog-manifest.json +2 -2
- package/v3/@claude-flow/cli/dist/src/commands/memory.js +59 -1
- package/v3/@claude-flow/cli/dist/src/commands/swarm.js +59 -1
- package/v3/@claude-flow/cli/dist/src/memory/oas-operator-selector.d.ts +74 -0
- package/v3/@claude-flow/cli/dist/src/memory/oas-operator-selector.js +117 -0
- package/v3/@claude-flow/cli/dist/src/swarm/message-compressor.d.ts +57 -0
- package/v3/@claude-flow/cli/dist/src/swarm/message-compressor.js +0 -0
- package/v3/@claude-flow/cli/package.json +1 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "claude-flow",
|
|
3
|
-
"version": "3.32.
|
|
3
|
+
"version": "3.32.20",
|
|
4
4
|
"description": "Ruflo - Enterprise AI agent orchestration for Claude Code. Deploy 60+ specialized agents in coordinated swarms with self-learning, fault-tolerant consensus, vector memory, and MCP integration",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"type": "module",
|
|
@@ -1632,6 +1632,64 @@ const initMemoryCommand = {
|
|
|
1632
1632
|
}
|
|
1633
1633
|
}
|
|
1634
1634
|
};
|
|
1635
|
+
// #2763 dream-cycle — OAS memory-operator selector. Standalone
|
|
1636
|
+
// subcommand that returns the highest-value consolidation operator
|
|
1637
|
+
// that fits the given budget for the given entry count. Advisory —
|
|
1638
|
+
// the caller decides whether to invoke that operator.
|
|
1639
|
+
const selectOperatorCommand = {
|
|
1640
|
+
name: 'select-operator',
|
|
1641
|
+
description: 'Pick the highest-value consolidation operator that fits a budget (OAS, dream-cycle #2763)',
|
|
1642
|
+
options: [
|
|
1643
|
+
{ name: 'budget', short: 'b', type: 'number', required: true, description: 'Budget in abstract operator points (1 point ≈ 1 Haiku call)' },
|
|
1644
|
+
{ name: 'entries', short: 'e', type: 'number', required: true, description: 'Number of entries to consolidate' },
|
|
1645
|
+
{ name: 'hint', type: 'string', choices: ['duplicates', 'verbose', 'patterns', 'general'], default: 'general', description: 'Entry-shape hint' },
|
|
1646
|
+
],
|
|
1647
|
+
examples: [
|
|
1648
|
+
{ command: 'claude-flow memory select-operator -b 50 -e 200', description: 'Pick operator for 200 entries within 50 points' },
|
|
1649
|
+
{ command: 'claude-flow memory select-operator -b 5 -e 100 --hint duplicates --format json', description: 'JSON for pipelines' },
|
|
1650
|
+
],
|
|
1651
|
+
action: async (ctx) => {
|
|
1652
|
+
const budget = ctx.flags.budget;
|
|
1653
|
+
const entries = ctx.flags.entries;
|
|
1654
|
+
const hint = ctx.flags.hint || 'general';
|
|
1655
|
+
if (budget === undefined || entries === undefined) {
|
|
1656
|
+
output.printError('Both --budget and --entries are required.');
|
|
1657
|
+
return { success: false, exitCode: 1 };
|
|
1658
|
+
}
|
|
1659
|
+
if (budget < 0 || entries < 0) {
|
|
1660
|
+
output.printError('Budget and entries must be non-negative.');
|
|
1661
|
+
return { success: false, exitCode: 1 };
|
|
1662
|
+
}
|
|
1663
|
+
const { selectOperator, OPERATORS } = await import('../memory/oas-operator-selector.js');
|
|
1664
|
+
const selection = selectOperator({ budget, entries, hint: hint });
|
|
1665
|
+
if (ctx.flags.format === 'json') {
|
|
1666
|
+
output.printJson(selection);
|
|
1667
|
+
return { success: true, data: selection };
|
|
1668
|
+
}
|
|
1669
|
+
const chosen = OPERATORS[selection.operator];
|
|
1670
|
+
output.writeln();
|
|
1671
|
+
output.printBox(`Budget: ${budget} points · Entries: ${entries}\n` +
|
|
1672
|
+
`Operator: ${selection.operator}\n` +
|
|
1673
|
+
`Description: ${chosen.description}\n` +
|
|
1674
|
+
`Estimated cost: ${selection.estimatedCost.toFixed(2)} points\n` +
|
|
1675
|
+
`Needs split: ${selection.needsSplit ? `YES — batch size ${selection.suggestedBatchSize}` : 'no'}`, 'OAS Operator Selection (#2763)');
|
|
1676
|
+
output.writeln();
|
|
1677
|
+
output.writeln(output.dim(selection.reason));
|
|
1678
|
+
if (selection.considered.length > 0) {
|
|
1679
|
+
output.writeln();
|
|
1680
|
+
output.writeln(output.bold('All operators considered'));
|
|
1681
|
+
output.printTable({
|
|
1682
|
+
columns: [
|
|
1683
|
+
{ key: 'id', header: 'Operator', width: 15 },
|
|
1684
|
+
{ key: 'cost', header: 'Est. Cost', width: 12, align: 'right', format: (v) => Number(v).toFixed(2) },
|
|
1685
|
+
{ key: 'fits', header: 'Fits Budget', width: 12, align: 'center', format: (v) => v ? '✓' : '—' },
|
|
1686
|
+
],
|
|
1687
|
+
data: selection.considered,
|
|
1688
|
+
});
|
|
1689
|
+
}
|
|
1690
|
+
return { success: true, data: selection };
|
|
1691
|
+
},
|
|
1692
|
+
};
|
|
1635
1693
|
// #2760 dream-cycle — SCM query classifier. Standalone subcommand so
|
|
1636
1694
|
// users can inspect what intent a query maps to and pipe the mapped
|
|
1637
1695
|
// namespaces into other tools (e.g. `memory search --namespace ...`).
|
|
@@ -1673,7 +1731,7 @@ const classifyCommand = {
|
|
|
1673
1731
|
export const memoryCommand = {
|
|
1674
1732
|
name: 'memory',
|
|
1675
1733
|
description: 'Memory management commands',
|
|
1676
|
-
subcommands: [initMemoryCommand, storeCommand, retrieveCommand, searchCommand, listCommand, deleteCommand, purgeCommand, statsCommand, configureCommand, cleanupCommand, compressCommand, exportCommand, importCommand, distillCommand, backupCommand, classifyCommand],
|
|
1734
|
+
subcommands: [initMemoryCommand, storeCommand, retrieveCommand, searchCommand, listCommand, deleteCommand, purgeCommand, statsCommand, configureCommand, cleanupCommand, compressCommand, exportCommand, importCommand, distillCommand, backupCommand, classifyCommand, selectOperatorCommand],
|
|
1677
1735
|
options: [],
|
|
1678
1736
|
examples: [
|
|
1679
1737
|
{ command: 'claude-flow memory store -k "key" -v "value"', description: 'Store data' },
|
|
@@ -843,10 +843,68 @@ const coordinateCommand = {
|
|
|
843
843
|
}
|
|
844
844
|
};
|
|
845
845
|
// Main swarm command
|
|
846
|
+
// #2727 dream-cycle — inter-agent message compressor (IB+VQ-inspired
|
|
847
|
+
// MVP). Advisory tool: takes a message + token budget, returns a
|
|
848
|
+
// compressed variant that preserves must-see spans (code, URLs, paths)
|
|
849
|
+
// and keeps the top-scored sentences by TF-IDF-ish keyword density.
|
|
850
|
+
// v2 wires a real VQ codec once a training pipeline exists.
|
|
851
|
+
const compressMessageCommand = {
|
|
852
|
+
name: 'compress-message',
|
|
853
|
+
description: 'Compress an inter-agent message to a token budget (IB+VQ-inspired, dream-cycle #2727)',
|
|
854
|
+
options: [
|
|
855
|
+
{ name: 'message', short: 'm', type: 'string', description: 'Message text (or use --message-file)' },
|
|
856
|
+
{ name: 'message-file', type: 'string', description: 'Path to a file whose contents will be compressed' },
|
|
857
|
+
{ name: 'budget-tokens', short: 'b', type: 'number', default: 200, description: 'Target token budget (approximate, ~4 chars per token)' },
|
|
858
|
+
{ name: 'mode', type: 'string', choices: ['keyword', 'sentence', 'hybrid'], default: 'hybrid', description: 'Scoring mode' },
|
|
859
|
+
],
|
|
860
|
+
examples: [
|
|
861
|
+
{ command: 'claude-flow swarm compress-message -m "…" --budget-tokens 100', description: 'Compress inline message to 100 tokens' },
|
|
862
|
+
{ command: 'claude-flow swarm compress-message --message-file ./msg.md -b 300 --format json', description: 'JSON for pipelines' },
|
|
863
|
+
],
|
|
864
|
+
action: async (ctx) => {
|
|
865
|
+
const inlineMsg = ctx.flags.message;
|
|
866
|
+
const msgFile = ctx.flags.messageFile;
|
|
867
|
+
const budgetTokens = ctx.flags.budgetTokens || 200;
|
|
868
|
+
const mode = ctx.flags.mode || 'hybrid';
|
|
869
|
+
let message = inlineMsg ?? '';
|
|
870
|
+
if (msgFile) {
|
|
871
|
+
try {
|
|
872
|
+
const fsMod = await import('node:fs');
|
|
873
|
+
const pathMod = await import('node:path');
|
|
874
|
+
message = fsMod.readFileSync(pathMod.resolve(msgFile), 'utf-8');
|
|
875
|
+
}
|
|
876
|
+
catch (err) {
|
|
877
|
+
output.printError(`Failed to read ${msgFile}: ${err instanceof Error ? err.message : String(err)}`);
|
|
878
|
+
return { success: false, exitCode: 1 };
|
|
879
|
+
}
|
|
880
|
+
}
|
|
881
|
+
if (!message) {
|
|
882
|
+
output.printError('No message provided. Use --message "..." or --message-file <path>.');
|
|
883
|
+
return { success: false, exitCode: 1 };
|
|
884
|
+
}
|
|
885
|
+
const { compressMessage } = await import('../swarm/message-compressor.js');
|
|
886
|
+
const result = compressMessage(message, { budgetTokens, mode: mode });
|
|
887
|
+
if (ctx.flags.format === 'json') {
|
|
888
|
+
output.printJson(result);
|
|
889
|
+
return { success: true, data: result };
|
|
890
|
+
}
|
|
891
|
+
output.writeln();
|
|
892
|
+
output.printBox(`Original: ${result.stats.originalTokens} tokens · Compressed: ${result.stats.compressedTokens} tokens\n` +
|
|
893
|
+
`Ratio: ${(result.stats.compressionRatio * 100).toFixed(1)}%\n` +
|
|
894
|
+
`Sentences kept: ${result.stats.sentencesKept}/${result.stats.sentencesTotal} · Preserved spans: ${result.stats.preservedSpans}\n` +
|
|
895
|
+
`Info retained (top-quartile): ${(result.stats.infoRetainedEstimate * 100).toFixed(1)}%`, 'Message Compressor (#2727 IB+VQ MVP)');
|
|
896
|
+
output.writeln();
|
|
897
|
+
output.writeln(output.bold('Compressed message'));
|
|
898
|
+
output.writeln(output.dim('─'.repeat(60)));
|
|
899
|
+
output.writeln(result.compressed);
|
|
900
|
+
output.writeln(output.dim('─'.repeat(60)));
|
|
901
|
+
return { success: true, data: result };
|
|
902
|
+
},
|
|
903
|
+
};
|
|
846
904
|
export const swarmCommand = {
|
|
847
905
|
name: 'swarm',
|
|
848
906
|
description: 'Swarm coordination commands',
|
|
849
|
-
subcommands: [initCommand, startCommand, statusCommand, stopCommand, scaleCommand, coordinateCommand],
|
|
907
|
+
subcommands: [initCommand, startCommand, statusCommand, stopCommand, scaleCommand, coordinateCommand, compressMessageCommand],
|
|
850
908
|
options: [],
|
|
851
909
|
examples: [
|
|
852
910
|
{ command: 'claude-flow swarm init --v3-mode', description: 'Initialize V3 swarm' },
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* OAS (Operator-Aware Selection) memory-consolidation operator picker
|
|
3
|
+
* (#2763 dream-cycle).
|
|
4
|
+
*
|
|
5
|
+
* Findings from the OAS paper referenced in dream-cycle #2763: memory-
|
|
6
|
+
* consolidation performance improves by +48% when the caller picks the
|
|
7
|
+
* RIGHT operator for the current budget + workload, instead of always
|
|
8
|
+
* applying the most-expensive one. Ruflo already has multiple
|
|
9
|
+
* consolidation operators (merge / summarize / compress / distill),
|
|
10
|
+
* but has no cost-aware selector — every `memory consolidate` call
|
|
11
|
+
* uses the same path.
|
|
12
|
+
*
|
|
13
|
+
* v1 MVP: rule-based selector. Cost-per-entry estimates are informed
|
|
14
|
+
* by ruflo's own measured performance targets in v3/@claude-flow/cli/
|
|
15
|
+
* CLAUDE.md — no external benchmark call needed. v2 will refine costs
|
|
16
|
+
* from routing-outcomes trajectories.
|
|
17
|
+
*/
|
|
18
|
+
/** The four consolidation operators ruflo can apply. */
|
|
19
|
+
export type OperatorId = 'merge' | 'summarize' | 'compress' | 'distill';
|
|
20
|
+
export interface OperatorSpec {
|
|
21
|
+
id: OperatorId;
|
|
22
|
+
/** Estimated cost per entry, in abstract "operator points" (1 point ≈ 1 Haiku call). */
|
|
23
|
+
costPerEntry: number;
|
|
24
|
+
/** Maximum recommended entry count per invocation (higher counts split). */
|
|
25
|
+
maxEntries: number;
|
|
26
|
+
/** What the operator does — human-readable. */
|
|
27
|
+
description: string;
|
|
28
|
+
/** Best when the entry set has this shape. */
|
|
29
|
+
bestWhen: string;
|
|
30
|
+
}
|
|
31
|
+
export declare const OPERATORS: Record<OperatorId, OperatorSpec>;
|
|
32
|
+
export interface OperatorSelection {
|
|
33
|
+
operator: OperatorId;
|
|
34
|
+
reason: string;
|
|
35
|
+
/** Estimated cost = costPerEntry × min(entries, maxEntries). */
|
|
36
|
+
estimatedCost: number;
|
|
37
|
+
/** True if entries > operator.maxEntries and caller should split into multiple invocations. */
|
|
38
|
+
needsSplit: boolean;
|
|
39
|
+
suggestedBatchSize: number;
|
|
40
|
+
/** All operators considered, in ranked order (best first). */
|
|
41
|
+
considered: Array<{
|
|
42
|
+
id: OperatorId;
|
|
43
|
+
cost: number;
|
|
44
|
+
fits: boolean;
|
|
45
|
+
}>;
|
|
46
|
+
}
|
|
47
|
+
export interface SelectOptions {
|
|
48
|
+
/** Budget in abstract operator points. */
|
|
49
|
+
budget: number;
|
|
50
|
+
/** Number of entries to consolidate. */
|
|
51
|
+
entries: number;
|
|
52
|
+
/**
|
|
53
|
+
* Optional hint about entry shape:
|
|
54
|
+
* 'duplicates' → strongly prefer merge (cheap wins first)
|
|
55
|
+
* 'verbose' → prefer summarize
|
|
56
|
+
* 'patterns' → prefer distill (small, high-signal)
|
|
57
|
+
* 'general' → let cost-fit decide (default)
|
|
58
|
+
*/
|
|
59
|
+
hint?: 'duplicates' | 'verbose' | 'patterns' | 'general';
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Select the highest-value operator that fits the budget.
|
|
63
|
+
*
|
|
64
|
+
* Selection rule (v1):
|
|
65
|
+
* 1. If a hint is provided AND the hinted operator fits the budget,
|
|
66
|
+
* pick it (hint is a strong signal about entry shape).
|
|
67
|
+
* 2. Else, rank operators by cost ascending; pick the most expensive
|
|
68
|
+
* operator that still fits budget × 1.0 (no over-spend). Idea:
|
|
69
|
+
* spend the whole budget on the most-fidelity operator we can afford.
|
|
70
|
+
* 3. If nothing fits, return merge (guaranteed cheapest) with
|
|
71
|
+
* needsSplit=true so caller batches.
|
|
72
|
+
*/
|
|
73
|
+
export declare function selectOperator(opts: SelectOptions): OperatorSelection;
|
|
74
|
+
//# sourceMappingURL=oas-operator-selector.d.ts.map
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* OAS (Operator-Aware Selection) memory-consolidation operator picker
|
|
3
|
+
* (#2763 dream-cycle).
|
|
4
|
+
*
|
|
5
|
+
* Findings from the OAS paper referenced in dream-cycle #2763: memory-
|
|
6
|
+
* consolidation performance improves by +48% when the caller picks the
|
|
7
|
+
* RIGHT operator for the current budget + workload, instead of always
|
|
8
|
+
* applying the most-expensive one. Ruflo already has multiple
|
|
9
|
+
* consolidation operators (merge / summarize / compress / distill),
|
|
10
|
+
* but has no cost-aware selector — every `memory consolidate` call
|
|
11
|
+
* uses the same path.
|
|
12
|
+
*
|
|
13
|
+
* v1 MVP: rule-based selector. Cost-per-entry estimates are informed
|
|
14
|
+
* by ruflo's own measured performance targets in v3/@claude-flow/cli/
|
|
15
|
+
* CLAUDE.md — no external benchmark call needed. v2 will refine costs
|
|
16
|
+
* from routing-outcomes trajectories.
|
|
17
|
+
*/
|
|
18
|
+
export const OPERATORS = {
|
|
19
|
+
merge: {
|
|
20
|
+
id: 'merge',
|
|
21
|
+
costPerEntry: 0.02, // near-free — deterministic near-duplicate merge
|
|
22
|
+
maxEntries: 5000,
|
|
23
|
+
description: 'Near-duplicate merge (deterministic, cosine ≥ 0.95)',
|
|
24
|
+
bestWhen: 'Many near-identical entries (e.g. duplicated command traces)',
|
|
25
|
+
},
|
|
26
|
+
summarize: {
|
|
27
|
+
id: 'summarize',
|
|
28
|
+
costPerEntry: 0.5, // one Haiku call per ~2 entries
|
|
29
|
+
maxEntries: 500,
|
|
30
|
+
description: 'Short-to-long consolidation via Haiku (1 call per ~2 entries)',
|
|
31
|
+
bestWhen: 'Verbose logs / trajectory steps that share a theme',
|
|
32
|
+
},
|
|
33
|
+
compress: {
|
|
34
|
+
id: 'compress',
|
|
35
|
+
costPerEntry: 1.5, // LoRA-style compression pass — heavier
|
|
36
|
+
maxEntries: 200,
|
|
37
|
+
description: 'LoRA/EWC-style compression preserving semantic embeddings',
|
|
38
|
+
bestWhen: 'High-fidelity pattern preservation across many entries',
|
|
39
|
+
},
|
|
40
|
+
distill: {
|
|
41
|
+
id: 'distill',
|
|
42
|
+
costPerEntry: 3, // full distillation — heaviest
|
|
43
|
+
maxEntries: 100,
|
|
44
|
+
description: 'Full pattern distillation (extracts high-value patterns for ReasoningBank)',
|
|
45
|
+
bestWhen: 'Extracting durable learnings from a small high-signal set',
|
|
46
|
+
},
|
|
47
|
+
};
|
|
48
|
+
/**
|
|
49
|
+
* Select the highest-value operator that fits the budget.
|
|
50
|
+
*
|
|
51
|
+
* Selection rule (v1):
|
|
52
|
+
* 1. If a hint is provided AND the hinted operator fits the budget,
|
|
53
|
+
* pick it (hint is a strong signal about entry shape).
|
|
54
|
+
* 2. Else, rank operators by cost ascending; pick the most expensive
|
|
55
|
+
* operator that still fits budget × 1.0 (no over-spend). Idea:
|
|
56
|
+
* spend the whole budget on the most-fidelity operator we can afford.
|
|
57
|
+
* 3. If nothing fits, return merge (guaranteed cheapest) with
|
|
58
|
+
* needsSplit=true so caller batches.
|
|
59
|
+
*/
|
|
60
|
+
export function selectOperator(opts) {
|
|
61
|
+
const { budget, entries, hint } = opts;
|
|
62
|
+
const considered = Object.keys(OPERATORS).map((id) => {
|
|
63
|
+
const spec = OPERATORS[id];
|
|
64
|
+
const effectiveEntries = Math.min(entries, spec.maxEntries);
|
|
65
|
+
const cost = spec.costPerEntry * effectiveEntries;
|
|
66
|
+
return { id, cost, fits: cost <= budget };
|
|
67
|
+
}).sort((a, b) => a.cost - b.cost);
|
|
68
|
+
// Rule 1: honor a shape hint if the hinted operator fits.
|
|
69
|
+
const hintMap = {
|
|
70
|
+
duplicates: 'merge',
|
|
71
|
+
verbose: 'summarize',
|
|
72
|
+
patterns: 'distill',
|
|
73
|
+
general: 'compress',
|
|
74
|
+
};
|
|
75
|
+
if (hint && hint !== 'general') {
|
|
76
|
+
const preferred = hintMap[hint];
|
|
77
|
+
const match = considered.find((c) => c.id === preferred);
|
|
78
|
+
if (match?.fits) {
|
|
79
|
+
const spec = OPERATORS[match.id];
|
|
80
|
+
return {
|
|
81
|
+
operator: match.id,
|
|
82
|
+
reason: `Hint "${hint}" → ${match.id} (cost ${match.cost.toFixed(2)} ≤ budget ${budget})`,
|
|
83
|
+
estimatedCost: match.cost,
|
|
84
|
+
needsSplit: entries > spec.maxEntries,
|
|
85
|
+
suggestedBatchSize: spec.maxEntries,
|
|
86
|
+
considered,
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
// Rule 2: pick the most-expensive operator that still fits.
|
|
91
|
+
const fitting = considered.filter((c) => c.fits);
|
|
92
|
+
if (fitting.length > 0) {
|
|
93
|
+
const best = fitting[fitting.length - 1]; // most expensive fitting
|
|
94
|
+
const spec = OPERATORS[best.id];
|
|
95
|
+
return {
|
|
96
|
+
operator: best.id,
|
|
97
|
+
reason: `Best-fit within budget: ${best.id} at cost ${best.cost.toFixed(2)} (budget ${budget}, entries ${entries})`,
|
|
98
|
+
estimatedCost: best.cost,
|
|
99
|
+
needsSplit: entries > spec.maxEntries,
|
|
100
|
+
suggestedBatchSize: spec.maxEntries,
|
|
101
|
+
considered,
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
// Rule 3: budget too small for any operator on the full entry set.
|
|
105
|
+
// Split via merge (cheapest) with the merge batch size.
|
|
106
|
+
const mergeSpec = OPERATORS.merge;
|
|
107
|
+
const batchSize = Math.max(1, Math.floor(budget / mergeSpec.costPerEntry));
|
|
108
|
+
return {
|
|
109
|
+
operator: 'merge',
|
|
110
|
+
reason: `Budget ${budget} too small for any operator across ${entries} entries — split via merge in batches of ${batchSize}`,
|
|
111
|
+
estimatedCost: budget,
|
|
112
|
+
needsSplit: true,
|
|
113
|
+
suggestedBatchSize: batchSize,
|
|
114
|
+
considered,
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
//# sourceMappingURL=oas-operator-selector.js.map
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Inter-agent message compressor (#2727 dream-cycle, IB+VQ inspired).
|
|
3
|
+
*
|
|
4
|
+
* Dream-cycle #2727 (IB+VQ messaging 181.8% task gain): variable-
|
|
5
|
+
* bandwidth compression at the inter-agent message boundary breaks the
|
|
6
|
+
* performance/bandwidth tradeoff. Real VQ needs a codebook trained on
|
|
7
|
+
* actual agent-to-agent traffic (own PR, own dataset). This v1 MVP
|
|
8
|
+
* delivers the SPIRIT of the finding with a deterministic pipeline:
|
|
9
|
+
*
|
|
10
|
+
* 1. Extract structured "must-preserve" spans (code fences, inline
|
|
11
|
+
* code, URLs, file paths, tool-call directives) — never compress
|
|
12
|
+
* those; they're load-bearing.
|
|
13
|
+
* 2. Score sentences by keyword density (TF-IDF against a domain
|
|
14
|
+
* stop-list) and keep the top-K sentences that fit `budgetTokens`.
|
|
15
|
+
* 3. Reassemble: preserved spans in original order + top scored
|
|
16
|
+
* sentences.
|
|
17
|
+
*
|
|
18
|
+
* v2 wires a real VQ codec once the training pipeline lands.
|
|
19
|
+
*
|
|
20
|
+
* SCOPE: advisory tool + library. Callers decide whether to use the
|
|
21
|
+
* compressed form. No auto-wire into SendMessage / hooks in v1.
|
|
22
|
+
*/
|
|
23
|
+
/** Result of a compression pass. */
|
|
24
|
+
export interface CompressionResult {
|
|
25
|
+
original: string;
|
|
26
|
+
compressed: string;
|
|
27
|
+
stats: {
|
|
28
|
+
originalTokens: number;
|
|
29
|
+
compressedTokens: number;
|
|
30
|
+
compressionRatio: number;
|
|
31
|
+
preservedSpans: number;
|
|
32
|
+
sentencesKept: number;
|
|
33
|
+
sentencesTotal: number;
|
|
34
|
+
/** Rough info-retention proxy: fraction of top-quartile-scored sentences kept. */
|
|
35
|
+
infoRetainedEstimate: number;
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
export interface CompressOptions {
|
|
39
|
+
/**
|
|
40
|
+
* Target token budget. The compressor keeps preserved spans first
|
|
41
|
+
* (they're mandatory) and then fills the remaining budget with the
|
|
42
|
+
* highest-scored sentences. Approximate — actual output may exceed
|
|
43
|
+
* budget by up to one sentence if a preserved span is very large.
|
|
44
|
+
*/
|
|
45
|
+
budgetTokens?: number;
|
|
46
|
+
/**
|
|
47
|
+
* Mode:
|
|
48
|
+
* 'keyword' → sentence score = sum(TF-IDF-approx) of unique keywords
|
|
49
|
+
* 'sentence' → sentence score = length + position penalty (favor lead)
|
|
50
|
+
* 'hybrid' → 0.7·keyword + 0.3·sentence (default)
|
|
51
|
+
*/
|
|
52
|
+
mode?: 'keyword' | 'sentence' | 'hybrid';
|
|
53
|
+
}
|
|
54
|
+
/** ~1 token per 4 chars — matches the OpenAI/Anthropic rule-of-thumb. */
|
|
55
|
+
export declare function estimateTokens(text: string): number;
|
|
56
|
+
export declare function compressMessage(message: string, options?: CompressOptions): CompressionResult;
|
|
57
|
+
//# sourceMappingURL=message-compressor.d.ts.map
|
|
Binary file
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@claude-flow/cli",
|
|
3
|
-
"version": "3.32.
|
|
3
|
+
"version": "3.32.20",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Ruflo CLI - Enterprise AI agent orchestration with 60+ specialized agents, swarm coordination, MCP server, self-learning hooks, and vector memory for Claude Code",
|
|
6
6
|
"main": "dist/src/index.js",
|