claude-flow 3.20.0 → 3.21.1
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/doctor.js +56 -0
- package/v3/@claude-flow/cli/dist/src/commands/neural.js +309 -1
- package/v3/@claude-flow/cli/dist/src/init/executor.js +17 -0
- package/v3/@claude-flow/cli/dist/src/init/helpers-generator.js +26 -2
- package/v3/@claude-flow/cli/dist/src/init/memory-package-resolver.d.ts +53 -0
- package/v3/@claude-flow/cli/dist/src/init/memory-package-resolver.js +118 -0
- 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/memory/memory-bridge.js +49 -8
- 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
|
@@ -224,6 +224,8 @@ export const agentTools = [
|
|
|
224
224
|
description: 'Claude model alias (haiku=fast/cheap, sonnet=balanced, opus=current Opus 4.8, opus-4.7=prior Opus pin)'
|
|
225
225
|
},
|
|
226
226
|
task: { type: 'string', description: 'Task description for intelligent model routing' },
|
|
227
|
+
memoryBase: { type: 'string', description: 'Opt-in: base .rvf memory file to fork a per-agent Copy-On-Write branch from (agenticow). When set, the agent gets an isolated ~162-byte COW branch instead of a full copy — promote on success, discard on terminate. Requires the optional `agenticow` dep; degrades to a no-op when absent or when CLAUDE_FLOW_NO_COW_MEMORY=1.' },
|
|
228
|
+
memoryDimension: { type: 'integer', description: 'Vector dimension for the COW base (required only when memoryBase does not exist yet)' },
|
|
227
229
|
},
|
|
228
230
|
required: ['agentType'],
|
|
229
231
|
},
|
|
@@ -295,6 +297,31 @@ export const agentTools = [
|
|
|
295
297
|
await addNode({ id: agentId, type: 'agent', name: agentType });
|
|
296
298
|
}
|
|
297
299
|
catch { /* graph-node not available */ }
|
|
300
|
+
// ACOW — opt-in per-agent COW memory branch. Only when the caller
|
|
301
|
+
// supplies `memoryBase` does the agent get an isolated 162-byte branch
|
|
302
|
+
// (vs a full .rvf copy). Lazy-imported so agenticow stays off the
|
|
303
|
+
// startup path. Non-fatal: a branch failure never blocks the spawn —
|
|
304
|
+
// the agent is already registered above.
|
|
305
|
+
let memoryBranch;
|
|
306
|
+
if (input.memoryBase) {
|
|
307
|
+
try {
|
|
308
|
+
const { SwarmMemoryBranches } = await import('../services/swarm-memory-branches.js');
|
|
309
|
+
const svc = new SwarmMemoryBranches();
|
|
310
|
+
const br = await svc.branchForAgent(String(input.memoryBase), agentId, {
|
|
311
|
+
dimension: typeof input.memoryDimension === 'number' ? input.memoryDimension : undefined,
|
|
312
|
+
});
|
|
313
|
+
if (br.branchPath) {
|
|
314
|
+
memoryBranch = br.branchPath;
|
|
315
|
+
agent.memoryBranch = br.branchPath;
|
|
316
|
+
agent.memoryBase = br.basePath;
|
|
317
|
+
store.agents[agentId] = agent;
|
|
318
|
+
saveAgentStore(store);
|
|
319
|
+
}
|
|
320
|
+
// else: degraded (agenticow missing / kill-switched) — agent stands
|
|
321
|
+
// without an isolated branch; callers see no memoryBranch field.
|
|
322
|
+
}
|
|
323
|
+
catch { /* COW branch is best-effort; agent already registered */ }
|
|
324
|
+
}
|
|
298
325
|
// Include deterministic codemod routing info if applicable
|
|
299
326
|
const response = {
|
|
300
327
|
success: true,
|
|
@@ -307,6 +334,7 @@ export const agentTools = [
|
|
|
307
334
|
...(routingResult.openrouterModel ? { openrouterModel: routingResult.openrouterModel } : {}),
|
|
308
335
|
status: 'registered',
|
|
309
336
|
createdAt: agent.createdAt,
|
|
337
|
+
...(memoryBranch ? { memoryBranch, memoryBase: agent.memoryBase } : {}),
|
|
310
338
|
note: 'Agent registered for coordination. Three execution paths: ' +
|
|
311
339
|
'(1) call agent_execute(agentId, prompt) — direct LLM call via Anthropic Messages API (requires ANTHROPIC_API_KEY); ' +
|
|
312
340
|
'(2) Claude Code Task tool — spawns a real subagent; ' +
|
|
@@ -375,6 +403,7 @@ export const agentTools = [
|
|
|
375
403
|
properties: {
|
|
376
404
|
agentId: { type: 'string', description: 'ID of agent to terminate' },
|
|
377
405
|
force: { type: 'boolean', description: 'Force immediate termination' },
|
|
406
|
+
promoteMemory: { type: 'boolean', description: 'When the agent has a per-agent COW memory branch (spawned with memoryBase), promote (merge) its edits into the shared base on terminate. Default false → discard the branch (throw its edits away). No-op when the agent has no branch.' },
|
|
378
407
|
},
|
|
379
408
|
required: ['agentId'],
|
|
380
409
|
},
|
|
@@ -385,13 +414,30 @@ export const agentTools = [
|
|
|
385
414
|
const store = loadAgentStore();
|
|
386
415
|
const agentId = input.agentId;
|
|
387
416
|
if (store.agents[agentId]) {
|
|
388
|
-
store.agents[agentId]
|
|
417
|
+
const rec = store.agents[agentId];
|
|
418
|
+
rec.status = 'terminated';
|
|
389
419
|
saveAgentStore(store);
|
|
420
|
+
// ACOW — resolve the agent's COW memory branch on teardown: promote
|
|
421
|
+
// (merge into base) when asked, else discard. Non-fatal — a failure
|
|
422
|
+
// here never blocks termination. Discard needs no agenticow (pure fs),
|
|
423
|
+
// so cleanup still works in the degraded path.
|
|
424
|
+
let memory;
|
|
425
|
+
if (rec.memoryBranch) {
|
|
426
|
+
try {
|
|
427
|
+
const { SwarmMemoryBranches } = await import('../services/swarm-memory-branches.js');
|
|
428
|
+
const svc = new SwarmMemoryBranches();
|
|
429
|
+
memory = input.promoteMemory
|
|
430
|
+
? (await svc.promoteAgent(agentId))
|
|
431
|
+
: (await svc.discardAgent(agentId));
|
|
432
|
+
}
|
|
433
|
+
catch { /* best-effort teardown */ }
|
|
434
|
+
}
|
|
390
435
|
return {
|
|
391
436
|
success: true,
|
|
392
437
|
agentId,
|
|
393
438
|
terminated: true,
|
|
394
439
|
terminatedAt: new Date().toISOString(),
|
|
440
|
+
...(memory ? { memory } : {}),
|
|
395
441
|
};
|
|
396
442
|
}
|
|
397
443
|
return {
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Agenticow shared loader + helpers.
|
|
3
|
+
*
|
|
4
|
+
* Extracted from `agenticow-tools.ts` so both the MCP tool surface AND the
|
|
5
|
+
* `SwarmMemoryBranches` service (src/services/swarm-memory-branches.ts) share
|
|
6
|
+
* one loader, one degradation contract, and one set of path/lineage helpers —
|
|
7
|
+
* rather than duplicating the optional-dep dance in two places.
|
|
8
|
+
*
|
|
9
|
+
* Architectural constraint (ADR-150, mirrors metaharness-tools.ts):
|
|
10
|
+
* - `agenticow` lives in `optionalDependencies` — never a hard runtime dep.
|
|
11
|
+
* - When the package is missing, callers get `null` from `loadAgenticow()`
|
|
12
|
+
* (or a `{degraded:true}` result via `degradedResult`) and MUST fall back
|
|
13
|
+
* gracefully — never throw a MODULE_NOT_FOUND.
|
|
14
|
+
*
|
|
15
|
+
* @module @claude-flow/cli/mcp-tools/agenticow-loader
|
|
16
|
+
*/
|
|
17
|
+
export declare const PACKAGE_NAME = "agenticow";
|
|
18
|
+
export interface AgenticowApi {
|
|
19
|
+
open: (file: string, opts?: {
|
|
20
|
+
dimension?: number;
|
|
21
|
+
metric?: string;
|
|
22
|
+
}) => Promise<any>;
|
|
23
|
+
openBase?: (file: string, opts?: any) => Promise<any>;
|
|
24
|
+
AgenticMemory: any;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Lazily import `agenticow`. Returns the module on success, or `null` when the
|
|
28
|
+
* package is not installed (the optional-dep degraded path). Any OTHER load
|
|
29
|
+
* error (e.g. a corrupt install) is re-thrown so it is not silently masked.
|
|
30
|
+
*/
|
|
31
|
+
export declare function loadAgenticow(): Promise<AgenticowApi | null>;
|
|
32
|
+
/** Reset the module-level load cache. Test-only seam. */
|
|
33
|
+
export declare function __resetAgenticowCache(): void;
|
|
34
|
+
export declare function degradedResult(reason: string): {
|
|
35
|
+
success: true;
|
|
36
|
+
degraded: true;
|
|
37
|
+
reason: string;
|
|
38
|
+
};
|
|
39
|
+
/**
|
|
40
|
+
* Resolve a user-supplied memory path against the project cwd, rejecting path
|
|
41
|
+
* traversal and NUL bytes (D-2 style hardening — same rule the MCP verbs use).
|
|
42
|
+
*/
|
|
43
|
+
export declare function resolveMemoryPath(path: string): string;
|
|
44
|
+
/**
|
|
45
|
+
* Lineage manifest companion path. agenticow persists the COW chain
|
|
46
|
+
* (working → checkpoints → base) into `<file>.agenticow.json` next to the
|
|
47
|
+
* `.rvf` data file. Without it, forks/checkpoints are in-memory only and
|
|
48
|
+
* disappear when the AgenticMemory handle closes.
|
|
49
|
+
*/
|
|
50
|
+
export declare function manifestFor(file: string): string;
|
|
51
|
+
/** Validate a COW branch/checkpoint label (alnum + a small safe symbol set). */
|
|
52
|
+
export declare function validateLabel(label: string): string;
|
|
53
|
+
/**
|
|
54
|
+
* Open (or create) a memory file, restoring its COW chain from the lineage
|
|
55
|
+
* manifest when one exists. When neither the `.rvf` nor the manifest exists,
|
|
56
|
+
* `dimension` is required to create a fresh base.
|
|
57
|
+
*/
|
|
58
|
+
export declare function openWithLineage(api: AgenticowApi, file: string, dimension?: number): Promise<any>;
|
|
59
|
+
//# sourceMappingURL=agenticow-loader.d.ts.map
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Agenticow shared loader + helpers.
|
|
3
|
+
*
|
|
4
|
+
* Extracted from `agenticow-tools.ts` so both the MCP tool surface AND the
|
|
5
|
+
* `SwarmMemoryBranches` service (src/services/swarm-memory-branches.ts) share
|
|
6
|
+
* one loader, one degradation contract, and one set of path/lineage helpers —
|
|
7
|
+
* rather than duplicating the optional-dep dance in two places.
|
|
8
|
+
*
|
|
9
|
+
* Architectural constraint (ADR-150, mirrors metaharness-tools.ts):
|
|
10
|
+
* - `agenticow` lives in `optionalDependencies` — never a hard runtime dep.
|
|
11
|
+
* - When the package is missing, callers get `null` from `loadAgenticow()`
|
|
12
|
+
* (or a `{degraded:true}` result via `degradedResult`) and MUST fall back
|
|
13
|
+
* gracefully — never throw a MODULE_NOT_FOUND.
|
|
14
|
+
*
|
|
15
|
+
* @module @claude-flow/cli/mcp-tools/agenticow-loader
|
|
16
|
+
*/
|
|
17
|
+
import { existsSync } from 'node:fs';
|
|
18
|
+
import { resolve, isAbsolute } from 'node:path';
|
|
19
|
+
import { getProjectCwd } from './types.js';
|
|
20
|
+
export const PACKAGE_NAME = 'agenticow';
|
|
21
|
+
// Cache: module load is expensive enough to amortize across handler calls.
|
|
22
|
+
// null = not yet attempted; false = attempted and unavailable; module = loaded.
|
|
23
|
+
let _agenticowMod = null;
|
|
24
|
+
let _loadAttempted = false;
|
|
25
|
+
/**
|
|
26
|
+
* Lazily import `agenticow`. Returns the module on success, or `null` when the
|
|
27
|
+
* package is not installed (the optional-dep degraded path). Any OTHER load
|
|
28
|
+
* error (e.g. a corrupt install) is re-thrown so it is not silently masked.
|
|
29
|
+
*/
|
|
30
|
+
export async function loadAgenticow() {
|
|
31
|
+
if (_loadAttempted)
|
|
32
|
+
return _agenticowMod || null;
|
|
33
|
+
_loadAttempted = true;
|
|
34
|
+
try {
|
|
35
|
+
_agenticowMod = await import(PACKAGE_NAME);
|
|
36
|
+
return _agenticowMod;
|
|
37
|
+
}
|
|
38
|
+
catch (err) {
|
|
39
|
+
if (err && (err.code === 'ERR_MODULE_NOT_FOUND' || err.code === 'MODULE_NOT_FOUND' ||
|
|
40
|
+
/Cannot find (module|package)/i.test(String(err.message)))) {
|
|
41
|
+
_agenticowMod = false;
|
|
42
|
+
return null;
|
|
43
|
+
}
|
|
44
|
+
throw err;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
/** Reset the module-level load cache. Test-only seam. */
|
|
48
|
+
export function __resetAgenticowCache() {
|
|
49
|
+
_agenticowMod = null;
|
|
50
|
+
_loadAttempted = false;
|
|
51
|
+
}
|
|
52
|
+
export function degradedResult(reason) {
|
|
53
|
+
return { success: true, degraded: true, reason };
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Resolve a user-supplied memory path against the project cwd, rejecting path
|
|
57
|
+
* traversal and NUL bytes (D-2 style hardening — same rule the MCP verbs use).
|
|
58
|
+
*/
|
|
59
|
+
export function resolveMemoryPath(path) {
|
|
60
|
+
if (!path || typeof path !== 'string')
|
|
61
|
+
throw new Error('memory path is required');
|
|
62
|
+
if (/\.\.[\\/]|\0/.test(path))
|
|
63
|
+
throw new Error('memory path contains disallowed characters');
|
|
64
|
+
return isAbsolute(path) ? path : resolve(getProjectCwd(), path);
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Lineage manifest companion path. agenticow persists the COW chain
|
|
68
|
+
* (working → checkpoints → base) into `<file>.agenticow.json` next to the
|
|
69
|
+
* `.rvf` data file. Without it, forks/checkpoints are in-memory only and
|
|
70
|
+
* disappear when the AgenticMemory handle closes.
|
|
71
|
+
*/
|
|
72
|
+
export function manifestFor(file) {
|
|
73
|
+
return `${file}.agenticow.json`;
|
|
74
|
+
}
|
|
75
|
+
/** Validate a COW branch/checkpoint label (alnum + a small safe symbol set). */
|
|
76
|
+
export function validateLabel(label) {
|
|
77
|
+
if (!label || typeof label !== 'string')
|
|
78
|
+
throw new Error('label is required');
|
|
79
|
+
if (label.length > 256)
|
|
80
|
+
throw new Error('label exceeds 256 chars');
|
|
81
|
+
if (!/^[A-Za-z0-9_.\-:/@]+$/.test(label)) {
|
|
82
|
+
throw new Error('label may only contain [A-Za-z0-9_.\\-:/@]');
|
|
83
|
+
}
|
|
84
|
+
return label;
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Open (or create) a memory file, restoring its COW chain from the lineage
|
|
88
|
+
* manifest when one exists. When neither the `.rvf` nor the manifest exists,
|
|
89
|
+
* `dimension` is required to create a fresh base.
|
|
90
|
+
*/
|
|
91
|
+
export async function openWithLineage(api, file, dimension) {
|
|
92
|
+
const manifest = manifestFor(file);
|
|
93
|
+
if (existsSync(manifest)) {
|
|
94
|
+
return api.AgenticMemory.load(manifest);
|
|
95
|
+
}
|
|
96
|
+
const opts = {};
|
|
97
|
+
if (typeof dimension === 'number' && Number.isInteger(dimension) && dimension > 0) {
|
|
98
|
+
opts.dimension = dimension;
|
|
99
|
+
}
|
|
100
|
+
else if (!existsSync(file)) {
|
|
101
|
+
throw new Error('dimension is required when creating a new memory file');
|
|
102
|
+
}
|
|
103
|
+
return api.open(file, opts);
|
|
104
|
+
}
|
|
105
|
+
//# sourceMappingURL=agenticow-loader.js.map
|
|
@@ -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
|