claude-flow 3.20.0 → 3.21.0
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/dist/src/agenticow/speculative-exploration.d.ts +148 -0
- package/v3/@claude-flow/cli/dist/src/agenticow/speculative-exploration.js +218 -0
- package/v3/@claude-flow/cli/dist/src/commands/autopilot.js +45 -0
- package/v3/@claude-flow/cli/dist/src/commands/neural.js +309 -1
- package/v3/@claude-flow/cli/dist/src/mcp-client.js +6 -1
- package/v3/@claude-flow/cli/dist/src/mcp-tools/agent-execute-core.js +33 -0
- package/v3/@claude-flow/cli/dist/src/mcp-tools/agent-tools.js +47 -1
- package/v3/@claude-flow/cli/dist/src/mcp-tools/agenticow-loader.d.ts +59 -0
- package/v3/@claude-flow/cli/dist/src/mcp-tools/agenticow-loader.js +105 -0
- package/v3/@claude-flow/cli/dist/src/mcp-tools/agenticow-speculate-tools.d.ts +24 -0
- package/v3/@claude-flow/cli/dist/src/mcp-tools/agenticow-speculate-tools.js +202 -0
- package/v3/@claude-flow/cli/dist/src/mcp-tools/agenticow-tools.js +9 -82
- package/v3/@claude-flow/cli/dist/src/mcp-tools/index.d.ts +1 -0
- package/v3/@claude-flow/cli/dist/src/mcp-tools/index.js +2 -0
- package/v3/@claude-flow/cli/dist/src/ruvector/router-trajectory.d.ts +33 -0
- package/v3/@claude-flow/cli/dist/src/ruvector/router-trajectory.js +31 -0
- package/v3/@claude-flow/cli/dist/src/ruvector/run-transcript-recorder.d.ts +154 -0
- package/v3/@claude-flow/cli/dist/src/ruvector/run-transcript-recorder.js +209 -0
- package/v3/@claude-flow/cli/dist/src/services/checkpoint-gate.d.ts +140 -0
- package/v3/@claude-flow/cli/dist/src/services/checkpoint-gate.js +223 -0
- package/v3/@claude-flow/cli/dist/src/services/distill-oracle.d.ts +190 -0
- package/v3/@claude-flow/cli/dist/src/services/distill-oracle.js +349 -0
- package/v3/@claude-flow/cli/dist/src/services/fable-harness.d.ts +168 -0
- package/v3/@claude-flow/cli/dist/src/services/fable-harness.js +347 -0
- package/v3/@claude-flow/cli/dist/src/services/swarm-memory-branches.d.ts +135 -0
- package/v3/@claude-flow/cli/dist/src/services/swarm-memory-branches.js +213 -0
- package/v3/@claude-flow/cli/dist/src/services/weight-eft.d.ts +305 -0
- package/v3/@claude-flow/cli/dist/src/services/weight-eft.js +296 -0
- package/v3/@claude-flow/cli/package.json +5 -4
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* agenticow speculate — MCP surface for speculative branch-and-promote
|
|
3
|
+
* (agenticow step 4).
|
|
4
|
+
*
|
|
5
|
+
* Exposes the `SpeculativeExploration` module as a single MCP tool
|
|
6
|
+
* `agenticow_speculate` so agents can drive parallel A/B memory exploration:
|
|
7
|
+
* fan out N candidate ingest-sets, each on its own 162-byte COW branch of a
|
|
8
|
+
* shared base `.rvf`, score them by a probe query, PROMOTE the winner into
|
|
9
|
+
* base, and DISCARD the losers (delete their branch files).
|
|
10
|
+
*
|
|
11
|
+
* Because MCP inputs are JSON (not JS functions), candidates are DECLARATIVE:
|
|
12
|
+
* each candidate is a label + a set of vectors to ingest, and scoring is a
|
|
13
|
+
* probe query (`nearest`) or an ingest count (`count`). The generic
|
|
14
|
+
* `explore(base, {label, fn}[], score)` core does the real work.
|
|
15
|
+
*
|
|
16
|
+
* Optional-dep contract (mirrors agenticow-tools.ts): when `agenticow` is not
|
|
17
|
+
* installed the tool returns `{success:true, degraded:true,
|
|
18
|
+
* reason:'agenticow-not-found'}` and never throws for that reason.
|
|
19
|
+
*
|
|
20
|
+
* @module @claude-flow/cli/mcp-tools/agenticow-speculate
|
|
21
|
+
*/
|
|
22
|
+
import type { MCPTool } from './types.js';
|
|
23
|
+
export declare const agenticowSpeculateTools: MCPTool[];
|
|
24
|
+
//# sourceMappingURL=agenticow-speculate-tools.d.ts.map
|
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* agenticow speculate — MCP surface for speculative branch-and-promote
|
|
3
|
+
* (agenticow step 4).
|
|
4
|
+
*
|
|
5
|
+
* Exposes the `SpeculativeExploration` module as a single MCP tool
|
|
6
|
+
* `agenticow_speculate` so agents can drive parallel A/B memory exploration:
|
|
7
|
+
* fan out N candidate ingest-sets, each on its own 162-byte COW branch of a
|
|
8
|
+
* shared base `.rvf`, score them by a probe query, PROMOTE the winner into
|
|
9
|
+
* base, and DISCARD the losers (delete their branch files).
|
|
10
|
+
*
|
|
11
|
+
* Because MCP inputs are JSON (not JS functions), candidates are DECLARATIVE:
|
|
12
|
+
* each candidate is a label + a set of vectors to ingest, and scoring is a
|
|
13
|
+
* probe query (`nearest`) or an ingest count (`count`). The generic
|
|
14
|
+
* `explore(base, {label, fn}[], score)` core does the real work.
|
|
15
|
+
*
|
|
16
|
+
* Optional-dep contract (mirrors agenticow-tools.ts): when `agenticow` is not
|
|
17
|
+
* installed the tool returns `{success:true, degraded:true,
|
|
18
|
+
* reason:'agenticow-not-found'}` and never throws for that reason.
|
|
19
|
+
*
|
|
20
|
+
* @module @claude-flow/cli/mcp-tools/agenticow-speculate
|
|
21
|
+
*/
|
|
22
|
+
import { loadAgenticow, degradedResult, resolveMemoryPath, openWithLineage, manifestFor, validateLabel, } from './agenticow-loader.js';
|
|
23
|
+
import { explore, } from '../agenticow/speculative-exploration.js';
|
|
24
|
+
/** Turn a validated label into a filesystem-safe branch filename segment. */
|
|
25
|
+
function safeSegment(label) {
|
|
26
|
+
return label.replace(/[^A-Za-z0-9_-]+/g, '_').slice(0, 64) || 'branch';
|
|
27
|
+
}
|
|
28
|
+
export const agenticowSpeculateTools = [
|
|
29
|
+
{
|
|
30
|
+
name: 'agenticow_speculate',
|
|
31
|
+
description: "agenticow — speculative branch-and-promote for parallel A/B memory exploration. " +
|
|
32
|
+
"Forks a 162-byte COW branch per candidate off a shared base .rvf, ingests each candidate's " +
|
|
33
|
+
"vectors into its OWN isolated branch, scores every branch (probe-query 'nearest' distance or " +
|
|
34
|
+
"ingest 'count'), PROMOTES the winning branch's edits into base, and DISCARDS the losers by " +
|
|
35
|
+
"deleting their branch files. Use when you want to try N competing memory-write strategies and " +
|
|
36
|
+
"keep only the best — the memory-state analogue of worktree-per-agent code exploration. " +
|
|
37
|
+
"Copying the base per candidate is wrong (full-copy snapshots grow linearly, the 3.3 GB Darwin " +
|
|
38
|
+
"bloat); COW forks are constant-size and losers cost ~162 B to throw away. Optional dep — " +
|
|
39
|
+
"degrades to {degraded:true} when agenticow is missing.",
|
|
40
|
+
category: 'memory',
|
|
41
|
+
tags: ['agenticow', 'memory', 'cow', 'speculative', 'branch', 'promote', 'ab'],
|
|
42
|
+
inputSchema: {
|
|
43
|
+
type: 'object',
|
|
44
|
+
properties: {
|
|
45
|
+
basePath: {
|
|
46
|
+
type: 'string',
|
|
47
|
+
description: 'Path to base .rvf memory file (absolute or relative to cwd)',
|
|
48
|
+
},
|
|
49
|
+
dimension: {
|
|
50
|
+
type: 'integer',
|
|
51
|
+
description: 'Vector dimension (required only when basePath does not exist yet)',
|
|
52
|
+
},
|
|
53
|
+
candidates: {
|
|
54
|
+
type: 'array',
|
|
55
|
+
description: 'The A/B candidates. Each explores its own COW branch.',
|
|
56
|
+
items: {
|
|
57
|
+
type: 'object',
|
|
58
|
+
properties: {
|
|
59
|
+
label: { type: 'string', description: 'Branch label (alnum + _.-:/@ only)' },
|
|
60
|
+
ingest: {
|
|
61
|
+
type: 'array',
|
|
62
|
+
description: 'Vectors to ingest into this candidate branch',
|
|
63
|
+
items: {
|
|
64
|
+
type: 'object',
|
|
65
|
+
properties: {
|
|
66
|
+
id: { type: 'integer', description: 'Explicit vector id (auto when omitted)' },
|
|
67
|
+
vector: { type: 'array', items: { type: 'number' }, description: 'Dense vector' },
|
|
68
|
+
text: { type: 'string', description: 'Optional payload text' },
|
|
69
|
+
},
|
|
70
|
+
required: ['vector'],
|
|
71
|
+
},
|
|
72
|
+
},
|
|
73
|
+
branchPath: {
|
|
74
|
+
type: 'string',
|
|
75
|
+
description: 'Optional explicit path for this branch file (default: alongside base)',
|
|
76
|
+
},
|
|
77
|
+
},
|
|
78
|
+
required: ['label', 'ingest'],
|
|
79
|
+
},
|
|
80
|
+
},
|
|
81
|
+
probe: {
|
|
82
|
+
type: 'array',
|
|
83
|
+
items: { type: 'number' },
|
|
84
|
+
description: "Probe vector for scoreBy='nearest' (scores each branch by best-hit similarity)",
|
|
85
|
+
},
|
|
86
|
+
k: { type: 'integer', description: 'Nearest-neighbours to fetch per probe (default 1)' },
|
|
87
|
+
scoreBy: {
|
|
88
|
+
type: 'string',
|
|
89
|
+
enum: ['nearest', 'count'],
|
|
90
|
+
description: "'nearest' = closest probe distance wins; 'count' = most accepted ingests wins. Default 'nearest'.",
|
|
91
|
+
},
|
|
92
|
+
requireClearance: {
|
|
93
|
+
type: 'boolean',
|
|
94
|
+
description: 'ADR-171 fail-closed gate. When true, the top-scored winner is NOT promoted (base stays unchanged) and a provenance-tagged receipt is emitted — score alone cannot graduate work. Use when speculating over TASK outcomes rather than pure memory A/B. Default false (score-only promotion, tagged `unverified`).',
|
|
95
|
+
default: false,
|
|
96
|
+
},
|
|
97
|
+
},
|
|
98
|
+
required: ['basePath', 'candidates'],
|
|
99
|
+
},
|
|
100
|
+
handler: async (input) => {
|
|
101
|
+
const api = await loadAgenticow();
|
|
102
|
+
if (!api)
|
|
103
|
+
return degradedResult('agenticow-not-found');
|
|
104
|
+
const basePath = resolveMemoryPath(String(input.basePath));
|
|
105
|
+
const dimension = input.dimension;
|
|
106
|
+
const scoreBy = input.scoreBy === 'count' ? 'count' : 'nearest';
|
|
107
|
+
const k = Number.isInteger(input.k) && input.k > 0 ? input.k : 1;
|
|
108
|
+
const probe = Array.isArray(input.probe) ? input.probe : null;
|
|
109
|
+
const rawCandidates = input.candidates;
|
|
110
|
+
if (!Array.isArray(rawCandidates) || rawCandidates.length === 0) {
|
|
111
|
+
throw new Error('at least one candidate is required');
|
|
112
|
+
}
|
|
113
|
+
if (scoreBy === 'nearest' && !probe) {
|
|
114
|
+
throw new Error("scoreBy='nearest' requires a probe vector");
|
|
115
|
+
}
|
|
116
|
+
// Build the generic {label, fn} candidates. Each fn ingests into its own
|
|
117
|
+
// branch handle, then (for 'nearest') probes it so we can score.
|
|
118
|
+
const candidates = rawCandidates.map((c) => {
|
|
119
|
+
const label = validateLabel(String(c.label));
|
|
120
|
+
if (!Array.isArray(c.ingest) || c.ingest.length === 0) {
|
|
121
|
+
throw new Error(`candidate ${label} must ingest at least one vector`);
|
|
122
|
+
}
|
|
123
|
+
const records = c.ingest.map((r) => ({
|
|
124
|
+
...(Number.isInteger(r.id) ? { id: r.id } : {}),
|
|
125
|
+
vector: r.vector,
|
|
126
|
+
...(typeof r.text === 'string' ? { text: r.text } : {}),
|
|
127
|
+
}));
|
|
128
|
+
return {
|
|
129
|
+
label,
|
|
130
|
+
fn: (branch) => {
|
|
131
|
+
const res = branch.ingest(records);
|
|
132
|
+
const accepted = Number(res?.accepted ?? records.length);
|
|
133
|
+
let hits = [];
|
|
134
|
+
if (probe) {
|
|
135
|
+
hits = (branch.query(probe, k) || []).map((h) => ({
|
|
136
|
+
id: h.id,
|
|
137
|
+
distance: h.distance,
|
|
138
|
+
}));
|
|
139
|
+
}
|
|
140
|
+
const bestDistance = hits.length ? hits[0].distance : null;
|
|
141
|
+
return { accepted, bestDistance, hits };
|
|
142
|
+
},
|
|
143
|
+
};
|
|
144
|
+
});
|
|
145
|
+
const score = (r) => {
|
|
146
|
+
if (scoreBy === 'count')
|
|
147
|
+
return r.accepted;
|
|
148
|
+
// nearest: smaller distance = better. Map to a higher-is-better score.
|
|
149
|
+
if (r.bestDistance === null)
|
|
150
|
+
return -Infinity;
|
|
151
|
+
return 1 / (1 + Math.max(0, r.bestDistance));
|
|
152
|
+
};
|
|
153
|
+
const branchPath = (label) => {
|
|
154
|
+
const explicit = rawCandidates.find((c) => validateLabel(String(c.label)) === label)?.branchPath;
|
|
155
|
+
if (explicit)
|
|
156
|
+
return resolveMemoryPath(String(explicit));
|
|
157
|
+
return `${basePath}.spec-${safeSegment(label)}.rvf`;
|
|
158
|
+
};
|
|
159
|
+
// ADR-171 promotion gate. For pure memory A/B the `score` IS the chosen
|
|
160
|
+
// metric (not a proxy for task correctness), so score-only promotion is
|
|
161
|
+
// legitimate and stays the default (tagged `unverified`, never
|
|
162
|
+
// masquerading as ground truth). Callers grafting this onto TASK work
|
|
163
|
+
// pass requireClearance:true to fail-closed — the winner is then
|
|
164
|
+
// ineligible unless a real clearance mechanism graduates it.
|
|
165
|
+
const requireClearance = input.requireClearance === true;
|
|
166
|
+
const exploreOpts = { branchPath, persist: true };
|
|
167
|
+
if (requireClearance)
|
|
168
|
+
exploreOpts.requireClearance = true;
|
|
169
|
+
// Open base, run the speculative exploration, persist base with the winner promoted.
|
|
170
|
+
const base = await openWithLineage(api, basePath, dimension);
|
|
171
|
+
try {
|
|
172
|
+
const result = await explore(base, candidates, score, exploreOpts);
|
|
173
|
+
base.save?.(manifestFor(basePath));
|
|
174
|
+
return {
|
|
175
|
+
success: true,
|
|
176
|
+
basePath,
|
|
177
|
+
scoreBy,
|
|
178
|
+
winner: result.winner,
|
|
179
|
+
scores: result.scores,
|
|
180
|
+
promoted: result.promoted,
|
|
181
|
+
promotedBy: result.promotedBy,
|
|
182
|
+
promotionDecision: result.promotionDecision,
|
|
183
|
+
promoteStats: result.promoteStats,
|
|
184
|
+
discarded: result.discarded,
|
|
185
|
+
receipts: result.receipts,
|
|
186
|
+
branches: result.branches.map((b) => ({
|
|
187
|
+
label: b.label,
|
|
188
|
+
path: b.path,
|
|
189
|
+
score: b.score,
|
|
190
|
+
kept: b.kept,
|
|
191
|
+
accepted: b.result.accepted,
|
|
192
|
+
bestDistance: b.result.bestDistance,
|
|
193
|
+
})),
|
|
194
|
+
};
|
|
195
|
+
}
|
|
196
|
+
finally {
|
|
197
|
+
await base.close?.();
|
|
198
|
+
}
|
|
199
|
+
},
|
|
200
|
+
},
|
|
201
|
+
];
|
|
202
|
+
//# sourceMappingURL=agenticow-speculate-tools.js.map
|
|
@@ -31,83 +31,10 @@
|
|
|
31
31
|
*
|
|
32
32
|
* @module @claude-flow/cli/mcp-tools/agenticow
|
|
33
33
|
*/
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
// Cache: module load is expensive enough to amortize across handler calls.
|
|
39
|
-
// null = not yet attempted; false = attempted and unavailable; module = loaded.
|
|
40
|
-
let _agenticowMod = null;
|
|
41
|
-
let _loadAttempted = false;
|
|
42
|
-
async function loadAgenticow() {
|
|
43
|
-
if (_loadAttempted)
|
|
44
|
-
return _agenticowMod;
|
|
45
|
-
_loadAttempted = true;
|
|
46
|
-
try {
|
|
47
|
-
_agenticowMod = await import(PACKAGE_NAME);
|
|
48
|
-
return _agenticowMod;
|
|
49
|
-
}
|
|
50
|
-
catch (err) {
|
|
51
|
-
if (err && (err.code === 'ERR_MODULE_NOT_FOUND' || err.code === 'MODULE_NOT_FOUND' ||
|
|
52
|
-
/Cannot find (module|package)/i.test(String(err.message)))) {
|
|
53
|
-
_agenticowMod = false;
|
|
54
|
-
return null;
|
|
55
|
-
}
|
|
56
|
-
throw err;
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
function degradedResult(reason) {
|
|
60
|
-
return { success: true, degraded: true, reason };
|
|
61
|
-
}
|
|
62
|
-
function resolveMemoryPath(path) {
|
|
63
|
-
if (!path || typeof path !== 'string')
|
|
64
|
-
throw new Error('memory path is required');
|
|
65
|
-
// D-2 style: reject path traversal in user-supplied paths
|
|
66
|
-
if (/\.\.[\\/]|\0/.test(path))
|
|
67
|
-
throw new Error('memory path contains disallowed characters');
|
|
68
|
-
return isAbsolute(path) ? path : resolve(getProjectCwd(), path);
|
|
69
|
-
}
|
|
70
|
-
/**
|
|
71
|
-
* Lineage manifest companion path. agenticow persists the COW chain
|
|
72
|
-
* (working → checkpoints → base) into `<file>.agenticow.json` next to the
|
|
73
|
-
* `.rvf` data file. Without this, checkpoints and forks are in-memory only
|
|
74
|
-
* and disappear when the AgenticMemory handle closes. Mirrors the bin
|
|
75
|
-
* CLI's `manifestFor(file)` helper.
|
|
76
|
-
*/
|
|
77
|
-
function manifestFor(file) {
|
|
78
|
-
return `${file}.agenticow.json`;
|
|
79
|
-
}
|
|
80
|
-
function validateLabel(label) {
|
|
81
|
-
if (!label || typeof label !== 'string')
|
|
82
|
-
throw new Error('label is required');
|
|
83
|
-
if (label.length > 256)
|
|
84
|
-
throw new Error('label exceeds 256 chars');
|
|
85
|
-
if (!/^[A-Za-z0-9_.\-:/@]+$/.test(label)) {
|
|
86
|
-
throw new Error('label may only contain [A-Za-z0-9_.\\-:/@]');
|
|
87
|
-
}
|
|
88
|
-
return label;
|
|
89
|
-
}
|
|
90
|
-
/**
|
|
91
|
-
* Open (or create) a base memory file. When a lineage manifest exists at
|
|
92
|
-
* `<file>.agenticow.json`, we load that to restore the COW chain (checkpoints,
|
|
93
|
-
* ancestors). When only the `.rvf` exists, fresh-open it. When neither exists,
|
|
94
|
-
* dimension is required to create. Mirrors the bin CLI's `loadMem()` helper.
|
|
95
|
-
*/
|
|
96
|
-
async function openWithLineage(api, file, dimension) {
|
|
97
|
-
const manifest = manifestFor(file);
|
|
98
|
-
if (existsSync(manifest)) {
|
|
99
|
-
// The class-level static method `load` reconstructs the full chain.
|
|
100
|
-
return api.AgenticMemory.load(manifest);
|
|
101
|
-
}
|
|
102
|
-
const opts = {};
|
|
103
|
-
if (typeof dimension === 'number' && Number.isInteger(dimension) && dimension > 0) {
|
|
104
|
-
opts.dimension = dimension;
|
|
105
|
-
}
|
|
106
|
-
else if (!existsSync(file)) {
|
|
107
|
-
throw new Error('dimension is required when creating a new memory file');
|
|
108
|
-
}
|
|
109
|
-
return api.open(file, opts);
|
|
110
|
-
}
|
|
34
|
+
// Loader + path/lineage helpers are shared with the SwarmMemoryBranches
|
|
35
|
+
// service (src/services/swarm-memory-branches.ts) via one module so the
|
|
36
|
+
// optional-dep dance and the COW open/fork semantics live in exactly one place.
|
|
37
|
+
import { loadAgenticow, degradedResult, resolveMemoryPath, manifestFor, validateLabel, openWithLineage, } from './agenticow-loader.js';
|
|
111
38
|
export const agenticowTools = [
|
|
112
39
|
{
|
|
113
40
|
name: 'agenticow_branch',
|
|
@@ -157,7 +84,7 @@ export const agenticowTools = [
|
|
|
157
84
|
},
|
|
158
85
|
{
|
|
159
86
|
name: 'agenticow_ingest',
|
|
160
|
-
description: 'agenticow — write vectors (with optional text payloads) into an .rvf memory branch or base. Records: [{id?, vector, text?}] — id auto-assigns when omitted. This is the write half that makes a branch usable: agenticow_branch creates an empty COW child, but without ingest it has nothing to read back. Use
|
|
87
|
+
description: 'agenticow — write vectors (with optional text payloads) into an .rvf memory branch or base. Records: [{id?, vector, text?}] — id auto-assigns when omitted. This is the write half that makes a branch usable: agenticow_branch creates an empty COW child, but without ingest it has nothing to read back. Use when you have branched and must populate the branch (agenticow_branch alone leaves it empty). Editing the base directly is wrong when the writes are speculative — ingest into a branch, then promote only if validated. Persists via .agenticow.json lineage manifest.',
|
|
161
88
|
category: 'memory',
|
|
162
89
|
tags: ['agenticow', 'memory', 'cow', 'ingest', 'write'],
|
|
163
90
|
inputSchema: {
|
|
@@ -213,7 +140,7 @@ export const agenticowTools = [
|
|
|
213
140
|
},
|
|
214
141
|
{
|
|
215
142
|
name: 'agenticow_query',
|
|
216
|
-
description: 'agenticow — k-NN read across an .rvf memory branch\'s full COW lineage (parent ∪ edits, child wins), returning {id, distance, branch, text}. Read-only (no manifest write). The `branch` field on each hit tells you which lineage node the result came from — the read-through semantics that make branching useful. Use to
|
|
143
|
+
description: 'agenticow — k-NN read across an .rvf memory branch\'s full COW lineage (parent ∪ edits, child wins), returning {id, distance, branch, text}. Read-only (no manifest write). The `branch` field on each hit tells you which lineage node the result came from — the read-through semantics that make branching useful. Use when you need to read from an agent/session branch without materializing a full copy. Re-opening the base and manually merging edits is wrong: query already spans the chain (and uses the single-call Rust path when the branch was forked with nativeAnn).',
|
|
217
144
|
category: 'memory',
|
|
218
145
|
tags: ['agenticow', 'memory', 'cow', 'query', 'read', 'search'],
|
|
219
146
|
inputSchema: {
|
|
@@ -251,7 +178,7 @@ export const agenticowTools = [
|
|
|
251
178
|
},
|
|
252
179
|
{
|
|
253
180
|
name: 'agenticow_diff',
|
|
254
|
-
description: 'agenticow — show what a branch changed relative to its lineage: {added, overridden, deleted} vector-id lists. Use
|
|
181
|
+
description: 'agenticow — show what a branch changed relative to its lineage: {added, overridden, deleted} vector-id lists. Use when you are about to promote and want to preview the exact merge, or when auditing what a branch actually wrote. Diffing by re-querying is wrong because deletions (tombstones) are invisible to a read — diff() surfaces them explicitly. Requires the branch was opened with edit tracking (default on).',
|
|
255
182
|
category: 'memory',
|
|
256
183
|
tags: ['agenticow', 'memory', 'cow', 'diff'],
|
|
257
184
|
inputSchema: {
|
|
@@ -278,7 +205,7 @@ export const agenticowTools = [
|
|
|
278
205
|
},
|
|
279
206
|
{
|
|
280
207
|
name: 'agenticow_lineage',
|
|
281
|
-
description: 'agenticow — walk the COW chain of an .rvf memory file: an ordered list of nodes (role working|checkpoint|base, id, label, parent, createdAt, mutations, tombstones). Use
|
|
208
|
+
description: 'agenticow — walk the COW chain of an .rvf memory file: an ordered list of nodes (role working|checkpoint|base, id, label, parent, createdAt, mutations, tombstones). Use when you need branch history — to find checkpoint ids for a targeted rollback, or to debug a promote. Guessing the chain from filenames is wrong — lineage is the authoritative structure the store maintains.',
|
|
282
209
|
category: 'memory',
|
|
283
210
|
tags: ['agenticow', 'memory', 'cow', 'lineage', 'history'],
|
|
284
211
|
inputSchema: {
|
|
@@ -305,7 +232,7 @@ export const agenticowTools = [
|
|
|
305
232
|
},
|
|
306
233
|
{
|
|
307
234
|
name: 'agenticow_status',
|
|
308
|
-
description: 'agenticow — health/geometry of an .rvf memory file: {totalVectors, totalSegments, fileSize, currentEpoch, deadSpaceRatio, readOnly, chainDepth, dimension, metric}. Use to check vector count before/after ingest, spot compaction pressure (deadSpaceRatio), or confirm the dimension before ingesting into a shared base. Pure read.',
|
|
235
|
+
description: 'agenticow — health/geometry of an .rvf memory file: {totalVectors, totalSegments, fileSize, currentEpoch, deadSpaceRatio, readOnly, chainDepth, dimension, metric}. Use when you need to check vector count before/after ingest, spot compaction pressure (deadSpaceRatio), or confirm the dimension before ingesting into a shared base. Pure read.',
|
|
309
236
|
category: 'memory',
|
|
310
237
|
tags: ['agenticow', 'memory', 'cow', 'status'],
|
|
311
238
|
inputSchema: {
|
|
@@ -27,6 +27,7 @@ export { autopilotTools } from './autopilot-tools.js';
|
|
|
27
27
|
export { metaharnessTools } from './metaharness-tools.js';
|
|
28
28
|
export { testgenTools } from './testgen-tools.js';
|
|
29
29
|
export { agenticowTools } from './agenticow-tools.js';
|
|
30
|
+
export { agenticowSpeculateTools } from './agenticow-speculate-tools.js';
|
|
30
31
|
export { agentbbsTools } from './agentbbs-tools.js';
|
|
31
32
|
export { businessPodTools } from './business-pod-tools.js';
|
|
32
33
|
export { httpFetchTools } from './http-fetch-tools.js';
|
|
@@ -29,6 +29,8 @@ export { metaharnessTools } from './metaharness-tools.js';
|
|
|
29
29
|
export { testgenTools } from './testgen-tools.js';
|
|
30
30
|
// agenticow@~0.2.3 — Copy-On-Write memory branching (162-byte branches)
|
|
31
31
|
export { agenticowTools } from './agenticow-tools.js';
|
|
32
|
+
// agenticow step 4 — speculative branch-and-promote (A/B memory exploration)
|
|
33
|
+
export { agenticowSpeculateTools } from './agenticow-speculate-tools.js';
|
|
32
34
|
// ADR-164 — AgentBBS federated business-domain BBS rooms (Phase 1)
|
|
33
35
|
export { agentbbsTools } from './agentbbs-tools.js';
|
|
34
36
|
// ADR-164 Phase 2 — Business-pod template validation
|
|
@@ -13,6 +13,19 @@
|
|
|
13
13
|
* Schema is versioned (`"v": 1`). New required fields bump the version;
|
|
14
14
|
* additive optional fields do not.
|
|
15
15
|
*
|
|
16
|
+
* COMPANION: run-transcript-recorder.ts (weight-eft capture path)
|
|
17
|
+
* --------------------------------------------------------------
|
|
18
|
+
* This recorder captures the routing DECISION only (task, embedding, scalar
|
|
19
|
+
* quality, tokens, cost) — enough to retrain the router. It deliberately does
|
|
20
|
+
* NOT carry the full message transcript, the produced patch, or a resolved
|
|
21
|
+
* boolean. `@metaharness/weight-eft` needs those to build SFT/DPO training
|
|
22
|
+
* rows, so a SEPARATE opt-in recorder — `run-transcript-recorder.ts` — captures
|
|
23
|
+
* the full run transcript to `.swarm/run-transcripts.jsonl`. Both share the
|
|
24
|
+
* `taskHash()` below as their join key, and both are off-by-default for the
|
|
25
|
+
* same PII/retention reason. Use `unifiedRecorderStatus()` (bottom of this
|
|
26
|
+
* file) to inspect both at once. Keeping them as two files keeps the routing
|
|
27
|
+
* hot path free of the heavier transcript payload.
|
|
28
|
+
*
|
|
16
29
|
* @module router-trajectory
|
|
17
30
|
*/
|
|
18
31
|
import type { ClaudeModel } from './model-router.js';
|
|
@@ -158,4 +171,24 @@ export declare function pairTrajectoryRows(rows: TrajectoryRow[]): {
|
|
|
158
171
|
};
|
|
159
172
|
/** Test seam — reset cached config so unit tests can change env vars between cases. */
|
|
160
173
|
export declare function __resetTrajectoryRecorderForTests(): void;
|
|
174
|
+
/**
|
|
175
|
+
* Unified status for BOTH the routing-decision recorder (this module) and the
|
|
176
|
+
* companion run-transcript recorder (the weight-eft capture path). The
|
|
177
|
+
* run-transcript recorder is loaded dynamically so this module has no static
|
|
178
|
+
* dependency on it (the reverse edge — run-transcript-recorder → taskHash —
|
|
179
|
+
* is the only static link, keeping the import acyclic).
|
|
180
|
+
*/
|
|
181
|
+
export declare function unifiedRecorderStatus(): Promise<{
|
|
182
|
+
routerTrajectory: {
|
|
183
|
+
enabled: boolean;
|
|
184
|
+
path: string;
|
|
185
|
+
taskCharLimit: number;
|
|
186
|
+
};
|
|
187
|
+
runTranscripts: {
|
|
188
|
+
enabled: boolean;
|
|
189
|
+
path: string;
|
|
190
|
+
} | {
|
|
191
|
+
unavailable: true;
|
|
192
|
+
};
|
|
193
|
+
}>;
|
|
161
194
|
//# sourceMappingURL=router-trajectory.d.ts.map
|
|
@@ -13,6 +13,19 @@
|
|
|
13
13
|
* Schema is versioned (`"v": 1`). New required fields bump the version;
|
|
14
14
|
* additive optional fields do not.
|
|
15
15
|
*
|
|
16
|
+
* COMPANION: run-transcript-recorder.ts (weight-eft capture path)
|
|
17
|
+
* --------------------------------------------------------------
|
|
18
|
+
* This recorder captures the routing DECISION only (task, embedding, scalar
|
|
19
|
+
* quality, tokens, cost) — enough to retrain the router. It deliberately does
|
|
20
|
+
* NOT carry the full message transcript, the produced patch, or a resolved
|
|
21
|
+
* boolean. `@metaharness/weight-eft` needs those to build SFT/DPO training
|
|
22
|
+
* rows, so a SEPARATE opt-in recorder — `run-transcript-recorder.ts` — captures
|
|
23
|
+
* the full run transcript to `.swarm/run-transcripts.jsonl`. Both share the
|
|
24
|
+
* `taskHash()` below as their join key, and both are off-by-default for the
|
|
25
|
+
* same PII/retention reason. Use `unifiedRecorderStatus()` (bottom of this
|
|
26
|
+
* file) to inspect both at once. Keeping them as two files keeps the routing
|
|
27
|
+
* hot path free of the heavier transcript payload.
|
|
28
|
+
*
|
|
16
29
|
* @module router-trajectory
|
|
17
30
|
*/
|
|
18
31
|
import { appendFileSync, mkdirSync, existsSync, statSync, renameSync, unlinkSync } from 'node:fs';
|
|
@@ -247,4 +260,22 @@ export function __resetTrajectoryRecorderForTests() {
|
|
|
247
260
|
_cfg = null;
|
|
248
261
|
_cachedSize = -1;
|
|
249
262
|
}
|
|
263
|
+
/**
|
|
264
|
+
* Unified status for BOTH the routing-decision recorder (this module) and the
|
|
265
|
+
* companion run-transcript recorder (the weight-eft capture path). The
|
|
266
|
+
* run-transcript recorder is loaded dynamically so this module has no static
|
|
267
|
+
* dependency on it (the reverse edge — run-transcript-recorder → taskHash —
|
|
268
|
+
* is the only static link, keeping the import acyclic).
|
|
269
|
+
*/
|
|
270
|
+
export async function unifiedRecorderStatus() {
|
|
271
|
+
const routerTrajectory = trajectoryRecorderStatus();
|
|
272
|
+
try {
|
|
273
|
+
const mod = await import('./run-transcript-recorder.js');
|
|
274
|
+
const s = mod.runTranscriptRecorderStatus();
|
|
275
|
+
return { routerTrajectory, runTranscripts: { enabled: s.enabled, path: s.path } };
|
|
276
|
+
}
|
|
277
|
+
catch {
|
|
278
|
+
return { routerTrajectory, runTranscripts: { unavailable: true } };
|
|
279
|
+
}
|
|
280
|
+
}
|
|
250
281
|
//# sourceMappingURL=router-trajectory.js.map
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* run-transcript-recorder.ts — Opt-in FULL run-transcript recorder for the
|
|
3
|
+
* weight-eft training-data export path (agenticow / ADR-150 weight-eft slice).
|
|
4
|
+
*
|
|
5
|
+
* WHY THIS EXISTS
|
|
6
|
+
* ---------------
|
|
7
|
+
* The existing `router-trajectory.ts` recorder captures only the ROUTING
|
|
8
|
+
* DECISION for a task: task text, embedding, scalar quality, tokens, cost.
|
|
9
|
+
* `@metaharness/weight-eft` needs something the routing recorder never had —
|
|
10
|
+
* the full ReAct message TRANSCRIPT, the produced patch, and a resolved
|
|
11
|
+
* boolean — to build SFT/DPO training rows. This module is that missing
|
|
12
|
+
* capture surface. It writes one JSON-line per completed run to
|
|
13
|
+
* `.swarm/run-transcripts.jsonl`, in a shape the archive-builder in
|
|
14
|
+
* `services/weight-eft.ts` maps directly to `DarwinTrajectory[]`.
|
|
15
|
+
*
|
|
16
|
+
* OFF BY DEFAULT (PII / RETENTION SURFACE)
|
|
17
|
+
* ----------------------------------------
|
|
18
|
+
* Rows carry the FULL prompt + assistant transcript + patch — a much larger
|
|
19
|
+
* PII/retention surface than the routing recorder. Mirroring why
|
|
20
|
+
* router-trajectory.ts is off-by-default, every write goes through the
|
|
21
|
+
* `CLAUDE_FLOW_RUN_TRANSCRIPTS=1` env gate. When unset (the default),
|
|
22
|
+
* `recordRunTranscript()` is a no-op. There is no way to enable it implicitly.
|
|
23
|
+
*
|
|
24
|
+
* HONESTY: `resolved` IS A PROXY
|
|
25
|
+
* ------------------------------
|
|
26
|
+
* `DarwinTrajectory.resolved` is meant to be GOLD-resolved status from the
|
|
27
|
+
* official SWE-bench harness. Ruflo has NO SWE-bench oracle. Every record
|
|
28
|
+
* therefore stamps `resolved_source` describing where the boolean actually
|
|
29
|
+
* came from, so no downstream consumer can mistake a proxy for gold:
|
|
30
|
+
* - 'gold-oracle' — a real conformant gold eval supplied it (never
|
|
31
|
+
* ruflo today; reserved for an external caller)
|
|
32
|
+
* - 'output-verifier' — ruflo's structural output-verifier confidence,
|
|
33
|
+
* thresholded — an EXPLICIT proxy
|
|
34
|
+
* - 'api-success' — the model returned without an API error — the
|
|
35
|
+
* weakest proxy (says nothing about correctness)
|
|
36
|
+
* - 'external' — supplied verbatim by the caller, provenance unknown
|
|
37
|
+
*
|
|
38
|
+
* ARCHITECTURAL CONSTRAINTS (mirror router-trajectory.ts / ADR-150)
|
|
39
|
+
* -----------------------------------------------------------------
|
|
40
|
+
* 1. OPT-IN — gated behind CLAUDE_FLOW_RUN_TRANSCRIPTS=1; default off.
|
|
41
|
+
* 2. NEVER THROWS — every fs op is try/caught at the append boundary; a
|
|
42
|
+
* failed write is silent (DEBUG-logged) and never breaks the run.
|
|
43
|
+
* 3. NO metaharness COUPLING — this module imports nothing from
|
|
44
|
+
* `@metaharness/*`; it only defines a portable record shape. The
|
|
45
|
+
* services/weight-eft.ts archive-builder does the (optional) mapping.
|
|
46
|
+
*
|
|
47
|
+
* SCHEMA (versioned, additive) — one JSONL row per completed run:
|
|
48
|
+
* { v, ts, instance_id, task_hash, model, tier, resolved, resolved_source,
|
|
49
|
+
* messages[], model_patch, sample?, source?, tokens?, cost_usd? }
|
|
50
|
+
*
|
|
51
|
+
* @module run-transcript-recorder
|
|
52
|
+
*/
|
|
53
|
+
/** An OpenAI-style tool call (the ReAct action). Mirrors weight-eft's ToolCall. */
|
|
54
|
+
export interface ToolCallLite {
|
|
55
|
+
id: string;
|
|
56
|
+
type: 'function';
|
|
57
|
+
function: {
|
|
58
|
+
name: string;
|
|
59
|
+
arguments: string;
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
/** A chat message in an OpenAI-compatible transcript. Mirrors weight-eft's ChatMessage. */
|
|
63
|
+
export interface ChatMessageLite {
|
|
64
|
+
role: 'system' | 'user' | 'assistant' | 'tool';
|
|
65
|
+
content: string | null;
|
|
66
|
+
tool_calls?: ToolCallLite[];
|
|
67
|
+
tool_call_id?: string;
|
|
68
|
+
name?: string;
|
|
69
|
+
}
|
|
70
|
+
/** Where a `resolved` boolean actually came from (never silently "gold"). */
|
|
71
|
+
export type ResolvedSource = 'gold-oracle' | 'output-verifier' | 'api-success' | 'external';
|
|
72
|
+
/** Ruflo's cascade tier. haiku → 'cheap' (first tier), sonnet/opus → 'frontier'. */
|
|
73
|
+
export type RunTier = 'cheap' | 'frontier';
|
|
74
|
+
/** One persisted run transcript. Maps 1:1 to a DarwinTrajectory (+ provenance). */
|
|
75
|
+
export interface RunTranscriptRecord {
|
|
76
|
+
v: 1;
|
|
77
|
+
ts: string;
|
|
78
|
+
instance_id: string;
|
|
79
|
+
task_hash: string;
|
|
80
|
+
model: string;
|
|
81
|
+
tier: RunTier;
|
|
82
|
+
resolved: boolean;
|
|
83
|
+
resolved_source: ResolvedSource;
|
|
84
|
+
messages: ChatMessageLite[];
|
|
85
|
+
model_patch: string;
|
|
86
|
+
sample?: number;
|
|
87
|
+
source?: string;
|
|
88
|
+
tokens?: {
|
|
89
|
+
input: number;
|
|
90
|
+
output: number;
|
|
91
|
+
};
|
|
92
|
+
cost_usd?: number;
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Record one completed run transcript. Cheap — a single appendFileSync of a
|
|
96
|
+
* JSONL row. No-op when CLAUDE_FLOW_RUN_TRANSCRIPTS is unset (the default).
|
|
97
|
+
* Never throws.
|
|
98
|
+
*
|
|
99
|
+
* `resolvedSource` is REQUIRED so a proxy can never masquerade as gold. If you
|
|
100
|
+
* only have "the API returned", pass 'api-success' — the honest weakest label.
|
|
101
|
+
*/
|
|
102
|
+
export declare function recordRunTranscript(args: {
|
|
103
|
+
/** Task/issue text — used for the FNV hash + default instance id. */
|
|
104
|
+
task: string;
|
|
105
|
+
/** Concrete model id that produced the run (e.g. "claude-haiku-4"). */
|
|
106
|
+
model: string;
|
|
107
|
+
/** Ruflo cascade tier of `model`. */
|
|
108
|
+
tier: RunTier;
|
|
109
|
+
/** The resolved boolean (see resolvedSource for what it actually means). */
|
|
110
|
+
resolved: boolean;
|
|
111
|
+
/** Provenance of `resolved`. Never omit — honesty is the point. */
|
|
112
|
+
resolvedSource: ResolvedSource;
|
|
113
|
+
/** OpenAI-shaped message transcript (system/user/assistant/tool). */
|
|
114
|
+
messages: ChatMessageLite[];
|
|
115
|
+
/** Unified diff the run produced. '' when the path produces no patch. */
|
|
116
|
+
modelPatch?: string;
|
|
117
|
+
/** Override the default "run-<hash>" instance id (contamination key). */
|
|
118
|
+
instanceId?: string;
|
|
119
|
+
/** Best-of-N sample index on the same instance (default 0). */
|
|
120
|
+
sample?: number;
|
|
121
|
+
/** Provenance tag, e.g. "agent-execute", "autopilot". */
|
|
122
|
+
source?: string;
|
|
123
|
+
tokens?: {
|
|
124
|
+
input: number;
|
|
125
|
+
output: number;
|
|
126
|
+
};
|
|
127
|
+
costUsd?: number;
|
|
128
|
+
}): {
|
|
129
|
+
recorded: boolean;
|
|
130
|
+
instanceId: string;
|
|
131
|
+
taskHash: string;
|
|
132
|
+
};
|
|
133
|
+
/**
|
|
134
|
+
* Read + parse the run-transcript JSONL back into records. Used by the
|
|
135
|
+
* archive-builder (`services/weight-eft.ts`). Malformed lines are skipped and
|
|
136
|
+
* counted, never thrown. Returns `[]` if the file is absent.
|
|
137
|
+
*/
|
|
138
|
+
export declare function readRunTranscripts(path?: string): {
|
|
139
|
+
records: RunTranscriptRecord[];
|
|
140
|
+
malformed: number;
|
|
141
|
+
path: string;
|
|
142
|
+
};
|
|
143
|
+
/** Map a ruflo model tier label to the weight-eft policy tier. */
|
|
144
|
+
export declare function tierForModel(model: string | undefined): RunTier;
|
|
145
|
+
/** Diagnostic for status/CLI. */
|
|
146
|
+
export declare function runTranscriptRecorderStatus(): {
|
|
147
|
+
enabled: boolean;
|
|
148
|
+
path: string;
|
|
149
|
+
maxSizeBytes: number;
|
|
150
|
+
maxRotations: number;
|
|
151
|
+
};
|
|
152
|
+
/** @internal — test seam: reset cached config so tests can flip env vars. */
|
|
153
|
+
export declare function __resetRunTranscriptRecorderForTests(): void;
|
|
154
|
+
//# sourceMappingURL=run-transcript-recorder.d.ts.map
|