@claude-flow/cli 3.66.2 → 3.68.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/.claude/helpers/helpers.manifest.json +2 -2
- package/.claude/memory.db +0 -0
- package/README.md +2 -0
- package/catalog-manifest.json +3 -3
- package/dist/src/init/executor.js +1 -1
- package/dist/src/mcp-tools/agentdb-tools.d.ts +1 -0
- package/dist/src/mcp-tools/agentdb-tools.js +57 -1
- package/dist/src/mcp-tools/neural-tools.js +3 -1
- package/dist/src/memory/memory-bridge.d.ts +44 -0
- package/dist/src/memory/memory-bridge.js +143 -40
- package/dist/src/missions/schemas.d.ts +134 -134
- package/dist/src/mods/command-registry/schema.d.ts +189 -189
- package/dist/src/services/agentic-flow-bridge.d.ts +1 -1
- package/dist/src/update/validator.js +1 -1
- package/node_modules/@claude-flow/codex/dist/cli.js +0 -0
- package/node_modules/@claude-flow/plugin-agent-federation/dist/bin.js +0 -0
- package/node_modules/@claude-flow/security/dist/input-validator.d.ts +6 -6
- package/package.json +6 -6
- package/plugins/ruflo-console/dist/tui.mjs +32 -32
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"manifest": {
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.68.0",
|
|
4
4
|
"files": {
|
|
5
5
|
"auto-memory-hook.mjs": "631fac9d518835e2852a406888316bbbddddb49e7ed8e406d2e971f46833df9a",
|
|
6
6
|
"hook-handler.cjs": "0ce70981aa33f76d008b6f49626effaf4269918c4094f1a28c1ef6fceb097d6f",
|
|
@@ -10,6 +10,6 @@
|
|
|
10
10
|
"learning-loop.cjs": "d046cd6f8efb7dd40e1d2451516c181fc8b26477aefb1124c0df5f52a23f9190"
|
|
11
11
|
}
|
|
12
12
|
},
|
|
13
|
-
"signature": "
|
|
13
|
+
"signature": "hlbaMRRdeS+x8RDQSG0gdJuZhV7d1pJKr+ut6Gy3w4y72vxS2tbe/R1G+zs5WUtCfX5/bkzh/U9YBDqsMiovCA==",
|
|
14
14
|
"algorithm": "ed25519"
|
|
15
15
|
}
|
|
Binary file
|
package/README.md
CHANGED
|
@@ -245,6 +245,8 @@ This adds slash commands and agent definitions. `ruflo-core` (installed above) d
|
|
|
245
245
|
| [**ruflo-jujutsu**](plugins/ruflo-jujutsu/README.md) | Analyze git diffs, score risk, suggest reviewers |
|
|
246
246
|
| [**ruflo-docs**](plugins/ruflo-docs/README.md) | Generate and maintain documentation automatically |
|
|
247
247
|
| [**agentic-qe-fleet**](https://github.com/proffesor-for-testing/agentic-qe/tree/v3.15.17/plugins/agentic-qe-fleet) | External, maintained by [Agentic QE](https://github.com/proffesor-for-testing/agentic-qe): 11 QE agents, test generation, coverage, chaos and TDD skills, the `agentic-qe` MCP server, and a guard for AQE learning data (`/plugin install agentic-qe-fleet@ruflo`). Install it from one marketplace only, `agentic-qe` or `ruflo`: enabled from both, its mod and commands load twice |
|
|
248
|
+
| [**agentdb**](https://github.com/ruvnet/agentdb/tree/plugin-v3.2.0/plugins/agentdb) | External, maintained in [ruvnet/agentdb](https://github.com/ruvnet/agentdb): agentdb's own MCP server (pinned `agentdb@3.2.0`: hybrid keyword + vector search, opt-in cross-encoder rerank), a memory-specialist agent, vector-memory / learning / diagnostics skills, `/agentdb-status`, and a guard that keeps secrets out of memory and refuses delete/reset unless allowed (`/plugin install agentdb@ruflo`). Use `ruflo-agentdb` instead if you want AgentDB through ruflo's server; the two can coexist. Install it from one marketplace only, `agentdb` or `ruflo` |
|
|
249
|
+
| [**agentic-flow**](https://github.com/ruvnet/agentic-flow/tree/plugin-v3.1.0/plugins/agentic-flow) | External, maintained in [ruvnet/agentic-flow](https://github.com/ruvnet/agentic-flow): the agentic-flow MCP server (pinned `agentic-flow@3.1.0`, `readonly` profile by default, nothing pre-approved), ReasoningBank and model-router agents, routing / learning / autopilot skills, `/agentic-flow-status`, and a guard on `agentic_flow_agent` (`/plugin install agentic-flow@ruflo`). Install it from one marketplace only, `agentic-flow` or `ruflo` |
|
|
248
250
|
|
|
249
251
|
#### Security & Compliance
|
|
250
252
|
|
package/catalog-manifest.json
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
{
|
|
2
2
|
"schemaVersion": 1,
|
|
3
3
|
"generation": 7,
|
|
4
|
-
"generatedAt": "2026-
|
|
5
|
-
"gitSha": "
|
|
4
|
+
"generatedAt": "2026-11-01T04:34:21.063Z",
|
|
5
|
+
"gitSha": "2b1a3927",
|
|
6
6
|
"catalog": {
|
|
7
7
|
"agents": 177,
|
|
8
|
-
"tools":
|
|
8
|
+
"tools": 446,
|
|
9
9
|
"skills": 34
|
|
10
10
|
},
|
|
11
11
|
"benchmark": null
|
|
@@ -2022,7 +2022,7 @@ npx @claude-flow/cli@latest hive-mind consensus --propose "task"
|
|
|
2022
2022
|
### Integrated Packages
|
|
2023
2023
|
| Package | Version | Purpose |
|
|
2024
2024
|
|---------|---------|---------|
|
|
2025
|
-
| agentic-flow | 3.0.0
|
|
2025
|
+
| agentic-flow | 3.0.0 | Core coordination + ReasoningBank + Router |
|
|
2026
2026
|
| agentdb | 3.0.0-alpha.10 | Vector database + 8 controllers |
|
|
2027
2027
|
| @ruvector/attention | 0.1.3 | Flash attention |
|
|
2028
2028
|
| @ruvector/sona | 0.1.5 | Neural learning |
|
|
@@ -20,6 +20,7 @@ export declare const agentdbCausalEdge: MCPTool;
|
|
|
20
20
|
export declare const agentdbRoute: MCPTool;
|
|
21
21
|
export declare const agentdbSessionStart: MCPTool;
|
|
22
22
|
export declare const agentdbSessionEnd: MCPTool;
|
|
23
|
+
export declare const agentdbEpisodeRecall: MCPTool;
|
|
23
24
|
export declare const agentdbHierarchicalStore: MCPTool;
|
|
24
25
|
export declare const agentdbHierarchicalRecall: MCPTool;
|
|
25
26
|
export declare const agentdbConsolidate: MCPTool;
|
|
@@ -633,12 +633,16 @@ export const agentdbRoute = {
|
|
|
633
633
|
// ===== agentdb_session_start — Session with ReflexionMemory =====
|
|
634
634
|
export const agentdbSessionStart = {
|
|
635
635
|
name: 'agentdb_session-start',
|
|
636
|
-
description: 'Start a session with ReflexionMemory episodic replay Use when generic memory_* tools are wrong because you need AgentDB-specific controllers (HNSW vector search, hierarchical tiers, causal-graph links, pattern store/recall, RaBitQ quantization). For simple key-value persistence, memory_store/memory_retrieve are simpler. For unrelated file work, native Read/Write are fine.',
|
|
636
|
+
description: 'Start a session with ReflexionMemory episodic replay. Set recall=true with a context to get back past session episodes relevant to it (keyword + vector search; rerank=true adds a local cross-encoder, ~200 ms). Use when generic memory_* tools are wrong because you need AgentDB-specific controllers (HNSW vector search, hierarchical tiers, causal-graph links, pattern store/recall, RaBitQ quantization). For simple key-value persistence, memory_store/memory_retrieve are simpler. For unrelated file work, native Read/Write are fine.',
|
|
637
637
|
inputSchema: {
|
|
638
638
|
type: 'object',
|
|
639
639
|
properties: {
|
|
640
640
|
sessionId: { type: 'string', description: 'Session identifier' },
|
|
641
641
|
context: { type: 'string', description: 'Session context for pattern retrieval' },
|
|
642
|
+
recall: { type: 'boolean', description: 'Also return past session episodes relevant to context', default: false },
|
|
643
|
+
k: { type: 'number', description: 'Episodes to recall (1-50)', default: 5 },
|
|
644
|
+
hybrid: { type: 'boolean', description: 'Keyword + vector search; false = vector only', default: true },
|
|
645
|
+
rerank: { type: 'boolean', description: 'Rerank with a local cross-encoder (~200 ms, 23 MB model on first use)', default: false },
|
|
642
646
|
},
|
|
643
647
|
required: ['sessionId'],
|
|
644
648
|
},
|
|
@@ -659,6 +663,10 @@ export const agentdbSessionStart = {
|
|
|
659
663
|
const result = await bridge.bridgeSessionStart({
|
|
660
664
|
sessionId,
|
|
661
665
|
context: validateString(params.context, 'context', 10_000) ?? undefined,
|
|
666
|
+
recall: params.recall === true,
|
|
667
|
+
k: validatePositiveInt(params.k, 5, 50),
|
|
668
|
+
hybrid: params.hybrid !== false,
|
|
669
|
+
rerank: params.rerank === true,
|
|
662
670
|
});
|
|
663
671
|
return result ?? { success: false, error: 'AgentDB bridge not available. Use memory_store/memory_search instead.' };
|
|
664
672
|
}
|
|
@@ -706,6 +714,53 @@ export const agentdbSessionEnd = {
|
|
|
706
714
|
}
|
|
707
715
|
},
|
|
708
716
|
};
|
|
717
|
+
// ===== agentdb_episode-recall — agentdb 3.2 hybrid episode retrieval (ADR-519) =====
|
|
718
|
+
export const agentdbEpisodeRecall = {
|
|
719
|
+
name: 'agentdb_episode-recall',
|
|
720
|
+
description: 'Recall past episodes (session summaries, distilled trajectories) relevant to a task, ranked by keyword + vector search. rerank=true adds a local cross-encoder for better ordering at ~200 ms per call. Use when you want what happened last time on similar work; for key-value entries use memory_search.',
|
|
721
|
+
inputSchema: {
|
|
722
|
+
type: 'object',
|
|
723
|
+
properties: {
|
|
724
|
+
query: { type: 'string', description: 'What you are about to work on' },
|
|
725
|
+
k: { type: 'number', description: 'Episodes to return (1-50)', default: 5 },
|
|
726
|
+
hybrid: { type: 'boolean', description: 'Keyword + vector search; false = vector only', default: true },
|
|
727
|
+
rerank: { type: 'boolean', description: 'Rerank with a local cross-encoder (~200 ms, 23 MB model on first use)', default: false },
|
|
728
|
+
onlySuccesses: { type: 'boolean', description: 'Only episodes recorded as successes' },
|
|
729
|
+
onlyFailures: { type: 'boolean', description: 'Only episodes recorded as failures' },
|
|
730
|
+
minReward: { type: 'number', description: 'Minimum reward (0-1)' },
|
|
731
|
+
timeWindowDays: { type: 'number', description: 'Only episodes from the last N days' },
|
|
732
|
+
},
|
|
733
|
+
required: ['query'],
|
|
734
|
+
},
|
|
735
|
+
handler: async (params) => {
|
|
736
|
+
try {
|
|
737
|
+
const vQuery = validateText(params.query, 'query', 10_000);
|
|
738
|
+
if (!vQuery.valid)
|
|
739
|
+
return { success: false, error: vQuery.error };
|
|
740
|
+
const query = validateString(params.query, 'query', 10_000);
|
|
741
|
+
if (!query || !query.trim())
|
|
742
|
+
return { success: false, error: 'query is required (non-empty string)' };
|
|
743
|
+
if (params.onlySuccesses === true && params.onlyFailures === true) {
|
|
744
|
+
return { success: false, error: 'onlySuccesses and onlyFailures are mutually exclusive' };
|
|
745
|
+
}
|
|
746
|
+
const bridge = await getBridge();
|
|
747
|
+
const result = await bridge.bridgeRecallEpisodes({
|
|
748
|
+
task: query,
|
|
749
|
+
k: validatePositiveInt(params.k, 5, 50),
|
|
750
|
+
hybrid: params.hybrid !== false,
|
|
751
|
+
rerank: params.rerank === true,
|
|
752
|
+
onlySuccesses: params.onlySuccesses === true,
|
|
753
|
+
onlyFailures: params.onlyFailures === true,
|
|
754
|
+
...(typeof params.minReward === 'number' && Number.isFinite(params.minReward) ? { minReward: validateScore(params.minReward, 0) } : {}),
|
|
755
|
+
...(params.timeWindowDays !== undefined ? { timeWindowDays: validatePositiveInt(params.timeWindowDays, 30, 3650) } : {}),
|
|
756
|
+
});
|
|
757
|
+
return result ?? { success: false, error: 'AgentDB ReflexionMemory not available. Use memory_search instead.' };
|
|
758
|
+
}
|
|
759
|
+
catch (error) {
|
|
760
|
+
return { success: false, error: sanitizeError(error) };
|
|
761
|
+
}
|
|
762
|
+
},
|
|
763
|
+
};
|
|
709
764
|
// ===== agentdb_hierarchical_store — Store to hierarchical memory =====
|
|
710
765
|
export const agentdbHierarchicalStore = {
|
|
711
766
|
name: 'agentdb_hierarchical-store',
|
|
@@ -1547,6 +1602,7 @@ export const agentdbTools = [
|
|
|
1547
1602
|
agentdbRoute,
|
|
1548
1603
|
agentdbSessionStart,
|
|
1549
1604
|
agentdbSessionEnd,
|
|
1605
|
+
agentdbEpisodeRecall, // ADR-519
|
|
1550
1606
|
agentdbHierarchicalStore,
|
|
1551
1607
|
agentdbHierarchicalRecall,
|
|
1552
1608
|
agentdbHierarchicalDelete,
|
|
@@ -145,7 +145,9 @@ function ensureEmbeddings() {
|
|
|
145
145
|
if (!realEmbeddings) {
|
|
146
146
|
const rb = await import('agentic-flow/reasoningbank').catch(() => null);
|
|
147
147
|
if (rb?.computeEmbedding) {
|
|
148
|
-
|
|
148
|
+
// computeEmbedding returns a Float32Array; JSON.stringify writes that as
|
|
149
|
+
// {"0":…,"1":…}, so convert before it reaches the neural store.
|
|
150
|
+
realEmbeddings = { embed: async (text) => Array.from(await rb.computeEmbedding(text)) };
|
|
149
151
|
embeddingServiceName = 'agentic-flow/reasoningbank';
|
|
150
152
|
}
|
|
151
153
|
}
|
|
@@ -507,6 +507,43 @@ export declare function bridgeDeleteCausalNode(options: {
|
|
|
507
507
|
guarded?: boolean;
|
|
508
508
|
error?: string;
|
|
509
509
|
} | null>;
|
|
510
|
+
export interface RecalledEpisode {
|
|
511
|
+
id?: number;
|
|
512
|
+
sessionId: string;
|
|
513
|
+
task: string;
|
|
514
|
+
critique?: string;
|
|
515
|
+
reward: number;
|
|
516
|
+
success: boolean;
|
|
517
|
+
similarity?: number;
|
|
518
|
+
tags?: string[];
|
|
519
|
+
ts?: number;
|
|
520
|
+
}
|
|
521
|
+
export interface EpisodeRecallOptions {
|
|
522
|
+
task: string;
|
|
523
|
+
k?: number;
|
|
524
|
+
/** Keyword + vector fusion. Default true (agentdb's own default). */
|
|
525
|
+
hybrid?: boolean;
|
|
526
|
+
/** Cross-encoder rerank. Default false: ~200 ms on CPU, 23 MB model on first use. */
|
|
527
|
+
rerank?: boolean;
|
|
528
|
+
onlySuccesses?: boolean;
|
|
529
|
+
onlyFailures?: boolean;
|
|
530
|
+
minReward?: number;
|
|
531
|
+
timeWindowDays?: number;
|
|
532
|
+
}
|
|
533
|
+
/**
|
|
534
|
+
* Recall past episodes relevant to a task. Episodes come from session ends
|
|
535
|
+
* and from `memory distill`. Ranking is agentdb's keyword + vector fusion,
|
|
536
|
+
* optionally reranked by a local cross-encoder.
|
|
537
|
+
*/
|
|
538
|
+
export declare function bridgeRecallEpisodes(options: EpisodeRecallOptions & {
|
|
539
|
+
dbPath?: string;
|
|
540
|
+
}): Promise<{
|
|
541
|
+
success: boolean;
|
|
542
|
+
controller: string;
|
|
543
|
+
episodes: RecalledEpisode[];
|
|
544
|
+
hybrid: boolean;
|
|
545
|
+
rerank: boolean;
|
|
546
|
+
} | null>;
|
|
510
547
|
/**
|
|
511
548
|
* Start a session with ReflexionMemory episodic replay.
|
|
512
549
|
* Loads relevant past session patterns for the new session.
|
|
@@ -515,11 +552,17 @@ export declare function bridgeSessionStart(options: {
|
|
|
515
552
|
sessionId: string;
|
|
516
553
|
context?: string;
|
|
517
554
|
dbPath?: string;
|
|
555
|
+
/** Recall past session episodes relevant to `context`. Default false. */
|
|
556
|
+
recall?: boolean;
|
|
557
|
+
k?: number;
|
|
558
|
+
hybrid?: boolean;
|
|
559
|
+
rerank?: boolean;
|
|
518
560
|
}): Promise<{
|
|
519
561
|
success: boolean;
|
|
520
562
|
controller: string;
|
|
521
563
|
restoredPatterns: number;
|
|
522
564
|
sessionId: string;
|
|
565
|
+
episodes?: RecalledEpisode[];
|
|
523
566
|
} | null>;
|
|
524
567
|
/**
|
|
525
568
|
* End a session and persist episodic summary to ReflexionMemory.
|
|
@@ -534,6 +577,7 @@ export declare function bridgeSessionEnd(options: {
|
|
|
534
577
|
success: boolean;
|
|
535
578
|
controller: string;
|
|
536
579
|
persisted: boolean;
|
|
580
|
+
episodeId?: number;
|
|
537
581
|
} | null>;
|
|
538
582
|
/**
|
|
539
583
|
* Route a task via AgentDB's SemanticRouter.
|
|
@@ -2952,6 +2952,64 @@ export async function bridgeDeleteCausalNode(options) {
|
|
|
2952
2952
|
return null;
|
|
2953
2953
|
}
|
|
2954
2954
|
}
|
|
2955
|
+
// ===== Episode recall (agentdb 3.2 hybrid retrieval, ADR-519) =====
|
|
2956
|
+
const EPISODE_TASK_MAX = 4_000;
|
|
2957
|
+
const EPISODE_TEXT_MAX = 2_000;
|
|
2958
|
+
const EPISODE_RECALL_MAX = 50;
|
|
2959
|
+
/** Null when the registry has no ReflexionMemory with retrieveRelevant. */
|
|
2960
|
+
async function recallEpisodesFrom(registry, options) {
|
|
2961
|
+
const reflexion = registry.get('reflexion');
|
|
2962
|
+
if (!reflexion || typeof reflexion.retrieveRelevant !== 'function')
|
|
2963
|
+
return null;
|
|
2964
|
+
const k = Math.min(Math.max(Math.trunc(options.k ?? 5), 1), EPISODE_RECALL_MAX);
|
|
2965
|
+
const rows = await reflexion.retrieveRelevant({
|
|
2966
|
+
task: options.task,
|
|
2967
|
+
k,
|
|
2968
|
+
hybrid: options.hybrid !== false,
|
|
2969
|
+
rerank: options.rerank === true,
|
|
2970
|
+
...(options.onlySuccesses ? { onlySuccesses: true } : {}),
|
|
2971
|
+
...(options.onlyFailures ? { onlyFailures: true } : {}),
|
|
2972
|
+
...(typeof options.minReward === 'number' ? { minReward: options.minReward } : {}),
|
|
2973
|
+
...(typeof options.timeWindowDays === 'number' ? { timeWindowDays: options.timeWindowDays } : {}),
|
|
2974
|
+
});
|
|
2975
|
+
if (!Array.isArray(rows))
|
|
2976
|
+
return [];
|
|
2977
|
+
// Drop the embedding (1.5 KB of floats per row) and bound the text fields:
|
|
2978
|
+
// this goes back over MCP.
|
|
2979
|
+
return rows.slice(0, k).map(r => ({
|
|
2980
|
+
...(typeof r.id === 'number' ? { id: r.id } : {}),
|
|
2981
|
+
sessionId: String(r.sessionId ?? ''),
|
|
2982
|
+
task: String(r.task ?? '').slice(0, EPISODE_TEXT_MAX),
|
|
2983
|
+
...(r.critique ? { critique: String(r.critique).slice(0, EPISODE_TEXT_MAX) } : {}),
|
|
2984
|
+
reward: Number(r.reward ?? 0),
|
|
2985
|
+
success: !!r.success,
|
|
2986
|
+
...(typeof r.similarity === 'number' ? { similarity: Math.round(r.similarity * 1e4) / 1e4 } : {}),
|
|
2987
|
+
...(Array.isArray(r.tags) ? { tags: r.tags.slice(0, 20) } : {}),
|
|
2988
|
+
...(typeof r.ts === 'number' ? { ts: r.ts } : {}),
|
|
2989
|
+
}));
|
|
2990
|
+
}
|
|
2991
|
+
/**
|
|
2992
|
+
* Recall past episodes relevant to a task. Episodes come from session ends
|
|
2993
|
+
* and from `memory distill`. Ranking is agentdb's keyword + vector fusion,
|
|
2994
|
+
* optionally reranked by a local cross-encoder.
|
|
2995
|
+
*/
|
|
2996
|
+
export async function bridgeRecallEpisodes(options) {
|
|
2997
|
+
if (!operationContext.getStore()?.active)
|
|
2998
|
+
return withBridgeOperation(() => bridgeRecallEpisodes(options));
|
|
2999
|
+
const registry = await getRegistry(options.dbPath);
|
|
3000
|
+
if (!registry)
|
|
3001
|
+
return null;
|
|
3002
|
+
const episodes = await recallEpisodesFrom(registry, options);
|
|
3003
|
+
if (!episodes)
|
|
3004
|
+
return null;
|
|
3005
|
+
return {
|
|
3006
|
+
success: true,
|
|
3007
|
+
controller: 'reflexion',
|
|
3008
|
+
episodes,
|
|
3009
|
+
hybrid: options.hybrid !== false,
|
|
3010
|
+
rerank: options.rerank === true,
|
|
3011
|
+
};
|
|
3012
|
+
}
|
|
2955
3013
|
// ===== Phase 5: ReflexionMemory session lifecycle =====
|
|
2956
3014
|
/**
|
|
2957
3015
|
* Start a session with ReflexionMemory episodic replay.
|
|
@@ -2966,20 +3024,36 @@ export async function bridgeSessionStart(options) {
|
|
|
2966
3024
|
try {
|
|
2967
3025
|
let restoredPatterns = 0;
|
|
2968
3026
|
let controller = 'none';
|
|
2969
|
-
//
|
|
2970
|
-
|
|
2971
|
-
|
|
2972
|
-
|
|
2973
|
-
|
|
2974
|
-
|
|
2975
|
-
|
|
2976
|
-
|
|
2977
|
-
|
|
2978
|
-
|
|
2979
|
-
|
|
2980
|
-
|
|
2981
|
-
|
|
2982
|
-
}
|
|
3027
|
+
// Episodic replay: past session episodes relevant to this session's
|
|
3028
|
+
// context, ranked by agentdb's keyword + vector search (agentdb ADR-016).
|
|
3029
|
+
// Opt-in, because a recall costs an embedding call and a generic context
|
|
3030
|
+
// ("new session") matches nothing in particular.
|
|
3031
|
+
let episodes;
|
|
3032
|
+
if (options.recall && options.context) {
|
|
3033
|
+
const recalled = await recallEpisodesFrom(registry, {
|
|
3034
|
+
task: options.context, k: options.k, hybrid: options.hybrid, rerank: options.rerank,
|
|
3035
|
+
});
|
|
3036
|
+
if (recalled) {
|
|
3037
|
+
episodes = recalled;
|
|
3038
|
+
controller = 'reflexion';
|
|
3039
|
+
}
|
|
3040
|
+
}
|
|
3041
|
+
// Load recent patterns from past sessions. A failure here must not
|
|
3042
|
+
// discard episodes already recalled above.
|
|
3043
|
+
let searchResult = null;
|
|
3044
|
+
try {
|
|
3045
|
+
searchResult = await bridgeSearchEntries({
|
|
3046
|
+
query: options.context || 'session patterns',
|
|
3047
|
+
namespace: 'session',
|
|
3048
|
+
limit: 10,
|
|
3049
|
+
threshold: 0.2,
|
|
3050
|
+
dbPath: options.dbPath,
|
|
3051
|
+
});
|
|
3052
|
+
}
|
|
3053
|
+
catch (err) {
|
|
3054
|
+
if (!episodes)
|
|
3055
|
+
throw err;
|
|
3056
|
+
}
|
|
2983
3057
|
if (searchResult?.results) {
|
|
2984
3058
|
restoredPatterns = searchResult.results.length;
|
|
2985
3059
|
}
|
|
@@ -2988,6 +3062,7 @@ export async function bridgeSessionStart(options) {
|
|
|
2988
3062
|
controller: controller === 'none' ? 'bridge-search' : controller,
|
|
2989
3063
|
restoredPatterns,
|
|
2990
3064
|
sessionId: options.sessionId,
|
|
3065
|
+
...(episodes ? { episodes } : {}),
|
|
2991
3066
|
};
|
|
2992
3067
|
}
|
|
2993
3068
|
catch {
|
|
@@ -3006,35 +3081,63 @@ export async function bridgeSessionEnd(options) {
|
|
|
3006
3081
|
try {
|
|
3007
3082
|
let controller = 'none';
|
|
3008
3083
|
let persisted = false;
|
|
3009
|
-
//
|
|
3084
|
+
// Store the session summary as a ReflexionMemory episode so a later
|
|
3085
|
+
// session can recall it. Only a real summary is worth recalling. The
|
|
3086
|
+
// outcome is unverified, so it is stored neutral (reward 0, not a success)
|
|
3087
|
+
// and can never count as evidence that an approach worked (ADR-171).
|
|
3088
|
+
let episodeId;
|
|
3010
3089
|
const reflexion = registry.get('reflexion');
|
|
3011
|
-
if (reflexion && typeof reflexion.
|
|
3012
|
-
|
|
3013
|
-
|
|
3014
|
-
|
|
3015
|
-
|
|
3090
|
+
if (options.summary && reflexion && typeof reflexion.storeEpisode === 'function') {
|
|
3091
|
+
try {
|
|
3092
|
+
const id = await reflexion.storeEpisode({
|
|
3093
|
+
sessionId: options.sessionId,
|
|
3094
|
+
task: options.summary.slice(0, EPISODE_TASK_MAX),
|
|
3095
|
+
reward: 0,
|
|
3096
|
+
success: false,
|
|
3097
|
+
tags: ['session-end'],
|
|
3098
|
+
metadata: {
|
|
3099
|
+
source: 'session-end',
|
|
3100
|
+
provenance: 'session-summary',
|
|
3101
|
+
tasksCompleted: options.tasksCompleted ?? 0,
|
|
3102
|
+
patternsLearned: options.patternsLearned ?? 0,
|
|
3103
|
+
},
|
|
3104
|
+
});
|
|
3105
|
+
if (typeof id === 'number' && Number.isFinite(id)) {
|
|
3106
|
+
episodeId = id;
|
|
3107
|
+
controller = 'reflexion';
|
|
3108
|
+
persisted = true;
|
|
3109
|
+
}
|
|
3110
|
+
}
|
|
3111
|
+
catch { /* non-fatal: the memory entry below still records the session */ }
|
|
3112
|
+
}
|
|
3113
|
+
// Persist session summary as memory entry. A failure here must not hide
|
|
3114
|
+
// an episode that was already stored above.
|
|
3115
|
+
let entryStored = false;
|
|
3116
|
+
try {
|
|
3117
|
+
await bridgeStoreEntry({
|
|
3118
|
+
key: `session-${options.sessionId}`,
|
|
3119
|
+
value: JSON.stringify({
|
|
3120
|
+
sessionId: options.sessionId,
|
|
3121
|
+
summary: options.summary || 'Session ended',
|
|
3122
|
+
tasksCompleted: options.tasksCompleted ?? 0,
|
|
3123
|
+
patternsLearned: options.patternsLearned ?? 0,
|
|
3124
|
+
endedAt: new Date().toISOString(),
|
|
3125
|
+
}),
|
|
3126
|
+
namespace: 'session',
|
|
3127
|
+
tags: ['session-end'],
|
|
3128
|
+
upsert: true,
|
|
3129
|
+
dbPath: options.dbPath,
|
|
3016
3130
|
});
|
|
3017
|
-
|
|
3131
|
+
entryStored = true;
|
|
3132
|
+
}
|
|
3133
|
+
catch (err) {
|
|
3134
|
+
if (episodeId === undefined)
|
|
3135
|
+
throw err;
|
|
3136
|
+
}
|
|
3137
|
+
if (entryStored) {
|
|
3138
|
+
controller = controller === 'none' ? 'bridge-store' : controller + '+bridge-store';
|
|
3018
3139
|
persisted = true;
|
|
3019
3140
|
}
|
|
3020
|
-
// Persist session summary as memory entry
|
|
3021
|
-
await bridgeStoreEntry({
|
|
3022
|
-
key: `session-${options.sessionId}`,
|
|
3023
|
-
value: JSON.stringify({
|
|
3024
|
-
sessionId: options.sessionId,
|
|
3025
|
-
summary: options.summary || 'Session ended',
|
|
3026
|
-
tasksCompleted: options.tasksCompleted ?? 0,
|
|
3027
|
-
patternsLearned: options.patternsLearned ?? 0,
|
|
3028
|
-
endedAt: new Date().toISOString(),
|
|
3029
|
-
}),
|
|
3030
|
-
namespace: 'session',
|
|
3031
|
-
tags: ['session-end'],
|
|
3032
|
-
upsert: true,
|
|
3033
|
-
dbPath: options.dbPath,
|
|
3034
|
-
});
|
|
3035
|
-
if (controller === 'none')
|
|
3036
|
-
controller = 'bridge-store';
|
|
3037
|
-
persisted = true;
|
|
3038
3141
|
// Phase 3: Trigger NightlyLearner consolidation if available
|
|
3039
3142
|
const nightlyLearner = registry.get('nightlyLearner');
|
|
3040
3143
|
if (nightlyLearner && typeof nightlyLearner.consolidate === 'function') {
|
|
@@ -3044,7 +3147,7 @@ export async function bridgeSessionEnd(options) {
|
|
|
3044
3147
|
}
|
|
3045
3148
|
catch { /* non-fatal */ }
|
|
3046
3149
|
}
|
|
3047
|
-
return { success: true, controller, persisted };
|
|
3150
|
+
return { success: true, controller, persisted, ...(episodeId !== undefined ? { episodeId } : {}) };
|
|
3048
3151
|
}
|
|
3049
3152
|
catch {
|
|
3050
3153
|
return null;
|