agentic-flow 3.0.0 → 3.1.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.
Files changed (58) hide show
  1. package/.claude/skills/agentic-flow-quickstart/skill.md +6 -6
  2. package/.claude/skills/hooks-automation/skill.md +11 -11
  3. package/.claude/skills/memory-patterns/skill.md +7 -7
  4. package/.claude/skills/sparc-methodology/skill.md +13 -13
  5. package/.claude/skills/swarm-coordination/skill.md +5 -5
  6. package/.claude/skills/worker-benchmarks/skill.md +5 -5
  7. package/.claude/skills/worker-integration/skill.md +5 -5
  8. package/.claude/statusline.mjs +22 -5
  9. package/CHANGELOG.md +23 -0
  10. package/README.md +68 -71
  11. package/dist/.tsbuildinfo +1 -1
  12. package/dist/cli/commands/hooks.d.ts.map +1 -1
  13. package/dist/cli/commands/hooks.js +17 -17
  14. package/dist/cli/commands/hooks.js.map +1 -1
  15. package/dist/cli/commands/init.d.ts +2 -5
  16. package/dist/cli/commands/init.d.ts.map +1 -1
  17. package/dist/cli/commands/init.js +2 -15
  18. package/dist/cli/commands/init.js.map +1 -1
  19. package/dist/cli/commands/swarm.d.ts.map +1 -1
  20. package/dist/cli/commands/swarm.js +3 -2
  21. package/dist/cli/commands/swarm.js.map +1 -1
  22. package/dist/proxy/anthropic-to-gemini.d.ts.map +1 -1
  23. package/dist/proxy/anthropic-to-gemini.js +10 -14
  24. package/dist/proxy/anthropic-to-gemini.js.map +1 -1
  25. package/dist/proxy/anthropic-to-openrouter.d.ts.map +1 -1
  26. package/dist/proxy/anthropic-to-openrouter.js +6 -25
  27. package/dist/proxy/anthropic-to-openrouter.js.map +1 -1
  28. package/dist/proxy/anthropic-to-requesty.d.ts.map +1 -1
  29. package/dist/proxy/anthropic-to-requesty.js +8 -10
  30. package/dist/proxy/anthropic-to-requesty.js.map +1 -1
  31. package/dist/proxy/sse-lines.d.ts +9 -0
  32. package/dist/proxy/sse-lines.d.ts.map +1 -0
  33. package/dist/proxy/sse-lines.js +37 -0
  34. package/dist/proxy/sse-lines.js.map +1 -0
  35. package/dist/reasoningbank/index.d.ts +2 -1
  36. package/dist/reasoningbank/index.d.ts.map +1 -1
  37. package/dist/reasoningbank/index.js +1 -1
  38. package/dist/reasoningbank/index.js.map +1 -1
  39. package/dist/reasoningbank/utils/embeddings.d.ts +17 -0
  40. package/dist/reasoningbank/utils/embeddings.d.ts.map +1 -1
  41. package/dist/reasoningbank/utils/embeddings.js +48 -17
  42. package/dist/reasoningbank/utils/embeddings.js.map +1 -1
  43. package/dist/utils/package-version.d.ts +9 -0
  44. package/dist/utils/package-version.d.ts.map +1 -0
  45. package/dist/utils/package-version.js +39 -0
  46. package/dist/utils/package-version.js.map +1 -0
  47. package/docs/docker-tests/TEST-V1.7.8.Dockerfile +2 -2
  48. package/docs/docker-tests/TEST-V1.7.9-NODE20.Dockerfile +2 -2
  49. package/docs/docker-tests/TEST-V1.7.9.Dockerfile +2 -2
  50. package/docs/guides/CLAUDE-CODE-INTEGRATION.md +25 -8
  51. package/docs/guides/PROXY-ARCHITECTURE-AND-EXTENSION.md +22 -9
  52. package/docs/guides/STANDALONE_PROXY_GUIDE.md +16 -6
  53. package/docs/integrations/FASTMCP_CLI_INTEGRATION.md +1 -1
  54. package/docs/plans/requesty/02-architecture.md +5 -6
  55. package/docs/plans/requesty/03-implementation-phases.md +3 -4
  56. package/docs/plans/requesty/05-migration-guide.md +2 -2
  57. package/package.json +1 -1
  58. package/scripts/validate-providers.sh +7 -4
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sse-lines.d.ts","sourceRoot":"","sources":["../../src/proxy/sse-lines.ts"],"names":[],"mappings":"AAOA;;;;GAIG;AACH,wBAAsB,eAAe,CACnC,MAAM,EAAE,2BAA2B,CAAC,UAAU,CAAC,EAC/C,OAAO,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,GAC/B,OAAO,CAAC,MAAM,CAAC,CAoBjB;AAED,iEAAiE;AACjE,wBAAgB,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,CAE/C"}
@@ -0,0 +1,37 @@
1
+ // Shared SSE reader for the translation proxies.
2
+ //
3
+ // A network read can end anywhere: inside a data: line, or inside a multi-byte
4
+ // UTF-8 character. Decoding each read on its own and splitting on '\n' drops
5
+ // the split line and corrupts the character. This reader decodes with
6
+ // {stream:true} and holds back a partial line until its newline arrives.
7
+ /**
8
+ * Read `reader` to the end, calling `onLines` with text made only of complete
9
+ * lines (each ending in '\n'), then once more with any unterminated tail.
10
+ * Returns the number of reads.
11
+ */
12
+ export async function forEachSseLines(reader, onLines) {
13
+ const decoder = new TextDecoder();
14
+ let pending = '';
15
+ let reads = 0;
16
+ while (true) {
17
+ const { done, value } = await reader.read();
18
+ if (done)
19
+ break;
20
+ reads++;
21
+ pending += decoder.decode(value, { stream: true });
22
+ const lastNewline = pending.lastIndexOf('\n');
23
+ if (lastNewline === -1)
24
+ continue;
25
+ onLines(pending.slice(0, lastNewline + 1));
26
+ pending = pending.slice(lastNewline + 1);
27
+ }
28
+ pending += decoder.decode();
29
+ if (pending.trim())
30
+ onLines(pending);
31
+ return reads;
32
+ }
33
+ /** Non-empty lines of `text`, with any trailing '\r' removed. */
34
+ export function sseLines(text) {
35
+ return text.split('\n').map(line => line.replace(/\r$/, '')).filter(line => line.trim());
36
+ }
37
+ //# sourceMappingURL=sse-lines.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sse-lines.js","sourceRoot":"","sources":["../../src/proxy/sse-lines.ts"],"names":[],"mappings":"AAAA,iDAAiD;AACjD,EAAE;AACF,+EAA+E;AAC/E,6EAA6E;AAC7E,sEAAsE;AACtE,yEAAyE;AAEzE;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,eAAe,CACnC,MAA+C,EAC/C,OAAgC;IAEhC,MAAM,OAAO,GAAG,IAAI,WAAW,EAAE,CAAC;IAClC,IAAI,OAAO,GAAG,EAAE,CAAC;IACjB,IAAI,KAAK,GAAG,CAAC,CAAC;IAEd,OAAO,IAAI,EAAE,CAAC;QACZ,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,GAAG,MAAM,MAAM,CAAC,IAAI,EAAE,CAAC;QAC5C,IAAI,IAAI;YAAE,MAAM;QAChB,KAAK,EAAE,CAAC;QAER,OAAO,IAAI,OAAO,CAAC,MAAM,CAAC,KAAK,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC;QACnD,MAAM,WAAW,GAAG,OAAO,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC;QAC9C,IAAI,WAAW,KAAK,CAAC,CAAC;YAAE,SAAS;QACjC,OAAO,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,WAAW,GAAG,CAAC,CAAC,CAAC,CAAC;QAC3C,OAAO,GAAG,OAAO,CAAC,KAAK,CAAC,WAAW,GAAG,CAAC,CAAC,CAAC;IAC3C,CAAC;IAED,OAAO,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC;IAC5B,IAAI,OAAO,CAAC,IAAI,EAAE;QAAE,OAAO,CAAC,OAAO,CAAC,CAAC;IACrC,OAAO,KAAK,CAAC;AACf,CAAC;AAED,iEAAiE;AACjE,MAAM,UAAU,QAAQ,CAAC,IAAY;IACnC,OAAO,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC;AAC3F,CAAC","sourcesContent":["// Shared SSE reader for the translation proxies.\n//\n// A network read can end anywhere: inside a data: line, or inside a multi-byte\n// UTF-8 character. Decoding each read on its own and splitting on '\\n' drops\n// the split line and corrupts the character. This reader decodes with\n// {stream:true} and holds back a partial line until its newline arrives.\n\n/**\n * Read `reader` to the end, calling `onLines` with text made only of complete\n * lines (each ending in '\\n'), then once more with any unterminated tail.\n * Returns the number of reads.\n */\nexport async function forEachSseLines(\n reader: ReadableStreamDefaultReader<Uint8Array>,\n onLines: (lines: string) => void\n): Promise<number> {\n const decoder = new TextDecoder();\n let pending = '';\n let reads = 0;\n\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n reads++;\n\n pending += decoder.decode(value, { stream: true });\n const lastNewline = pending.lastIndexOf('\\n');\n if (lastNewline === -1) continue;\n onLines(pending.slice(0, lastNewline + 1));\n pending = pending.slice(lastNewline + 1);\n }\n\n pending += decoder.decode();\n if (pending.trim()) onLines(pending);\n return reads;\n}\n\n/** Non-empty lines of `text`, with any trailing '\\r' removed. */\nexport function sseLines(text: string): string[] {\n return text.split('\\n').map(line => line.replace(/\\r$/, '')).filter(line => line.trim());\n}\n"]}
@@ -21,7 +21,8 @@ export { consolidate, shouldConsolidate } from './core/consolidate.js';
21
21
  export type { ConsolidationResult } from './core/consolidate.js';
22
22
  export { mattsParallel, mattsSequential } from './core/matts.js';
23
23
  export type { MattsResult } from './core/matts.js';
24
- export { computeEmbedding, clearEmbeddingCache, isSemanticEmbedding } from './utils/embeddings.js';
24
+ export { computeEmbedding, clearEmbeddingCache, isSemanticEmbedding, getEmbeddingKind, resetEmbeddingBackend, } from './utils/embeddings.js';
25
+ export type { EmbeddingKind } from './utils/embeddings.js';
25
26
  export { mmrSelection, cosineSimilarity } from './utils/mmr.js';
26
27
  export { scrubPII, containsPII, scrubMemory } from './utils/pii-scrubber.js';
27
28
  export { loadConfig } from './utils/config.js';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/reasoningbank/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,mCAAmC,CAAC;AAG3C,OAAO,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AACzD,OAAO,EAAE,mBAAmB,IAAI,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAC1E,OAAO,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAC;AAC3D,YAAY,EAAE,WAAW,EAAE,gBAAgB,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACvF,YAAY,EAAE,eAAe,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AAG7E,OAAO,EACL,eAAe,EACf,YAAY,EACZ,iBAAiB,EACjB,YAAY,EACZ,cAAc,EACd,gBAAgB,EACjB,MAAM,SAAS,CAAC;AAGjB,OAAO,EAAE,gBAAgB,EAAE,uBAAuB,EAAE,MAAM,oBAAoB,CAAC;AAC/E,YAAY,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AAE1D,OAAO,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAClD,YAAY,EAAE,OAAO,EAAE,MAAM,iBAAiB,CAAC;AAE/C,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AACpD,YAAY,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAEzD,OAAO,EAAE,WAAW,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;AACvE,YAAY,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAC;AAEjE,OAAO,EAAE,aAAa,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AACjE,YAAY,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAEnD,OAAO,EAAE,gBAAgB,EAAE,mBAAmB,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAC;AACnG,OAAO,EAAE,YAAY,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAChE,OAAO,EAAE,QAAQ,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AAC7E,OAAO,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAG/C,OAAO,KAAK,EAAE,MAAM,iBAAiB,CAAC;AACtC,OAAO,EAAE,EAAE,EAAE,CAAC;AACd,YAAY,EACV,eAAe,EACf,gBAAgB,EAChB,WAAW,EACX,cAAc,EACd,QAAQ,EACR,gBAAgB,EAChB,UAAU,EACV,cAAc,EACf,MAAM,gBAAgB,CAAC;AASxB,wBAAsB,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC,CA0BhD;AAED,wBAAsB,OAAO,CAAC,OAAO,EAAE;IACrC,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,CAAC,QAAQ,EAAE,GAAG,EAAE,KAAK,OAAO,CAAC,GAAG,CAAC,CAAC;CAC9C,GAAG,OAAO,CAAC;IACV,OAAO,EAAE,GAAG,CAAC;IACb,YAAY,EAAE,GAAG,EAAE,CAAC;IACpB,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,YAAY,EAAE,OAAO,CAAC;CACvB,CAAC,CA6BD;AAED,eAAO,MAAM,OAAO,UAAU,CAAC;AAC/B,eAAO,MAAM,SAAS,wCAAwC,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/reasoningbank/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,mCAAmC,CAAC;AAG3C,OAAO,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AACzD,OAAO,EAAE,mBAAmB,IAAI,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAC1E,OAAO,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAC;AAC3D,YAAY,EAAE,WAAW,EAAE,gBAAgB,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACvF,YAAY,EAAE,eAAe,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AAG7E,OAAO,EACL,eAAe,EACf,YAAY,EACZ,iBAAiB,EACjB,YAAY,EACZ,cAAc,EACd,gBAAgB,EACjB,MAAM,SAAS,CAAC;AAGjB,OAAO,EAAE,gBAAgB,EAAE,uBAAuB,EAAE,MAAM,oBAAoB,CAAC;AAC/E,YAAY,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AAE1D,OAAO,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAClD,YAAY,EAAE,OAAO,EAAE,MAAM,iBAAiB,CAAC;AAE/C,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AACpD,YAAY,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAEzD,OAAO,EAAE,WAAW,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;AACvE,YAAY,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAC;AAEjE,OAAO,EAAE,aAAa,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AACjE,YAAY,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAEnD,OAAO,EACL,gBAAgB,EAChB,mBAAmB,EACnB,mBAAmB,EACnB,gBAAgB,EAChB,qBAAqB,GACtB,MAAM,uBAAuB,CAAC;AAC/B,YAAY,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AAC3D,OAAO,EAAE,YAAY,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAChE,OAAO,EAAE,QAAQ,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AAC7E,OAAO,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAG/C,OAAO,KAAK,EAAE,MAAM,iBAAiB,CAAC;AACtC,OAAO,EAAE,EAAE,EAAE,CAAC;AACd,YAAY,EACV,eAAe,EACf,gBAAgB,EAChB,WAAW,EACX,cAAc,EACd,QAAQ,EACR,gBAAgB,EAChB,UAAU,EACV,cAAc,EACf,MAAM,gBAAgB,CAAC;AASxB,wBAAsB,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC,CA0BhD;AAED,wBAAsB,OAAO,CAAC,OAAO,EAAE;IACrC,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,CAAC,QAAQ,EAAE,GAAG,EAAE,KAAK,OAAO,CAAC,GAAG,CAAC,CAAC;CAC9C,GAAG,OAAO,CAAC;IACV,OAAO,EAAE,GAAG,CAAC;IACb,YAAY,EAAE,GAAG,EAAE,CAAC;IACpB,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,YAAY,EAAE,OAAO,CAAC;CACvB,CAAC,CA6BD;AAED,eAAO,MAAM,OAAO,UAAU,CAAC;AAC/B,eAAO,MAAM,SAAS,wCAAwC,CAAC"}
@@ -18,7 +18,7 @@ export { judgeTrajectory } from './core/judge.js';
18
18
  export { distillMemories } from './core/distill.js';
19
19
  export { consolidate, shouldConsolidate } from './core/consolidate.js';
20
20
  export { mattsParallel, mattsSequential } from './core/matts.js';
21
- export { computeEmbedding, clearEmbeddingCache, isSemanticEmbedding } from './utils/embeddings.js';
21
+ export { computeEmbedding, clearEmbeddingCache, isSemanticEmbedding, getEmbeddingKind, resetEmbeddingBackend, } from './utils/embeddings.js';
22
22
  export { mmrSelection, cosineSimilarity } from './utils/mmr.js';
23
23
  export { scrubPII, containsPII, scrubMemory } from './utils/pii-scrubber.js';
24
24
  export { loadConfig } from './utils/config.js';
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/reasoningbank/index.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * ReasoningBank - Closed-loop memory system for AI agents\n * Based on arXiv:2509.25140 (Google DeepMind)\n *\n * @since v1.7.0 - Integrated AgentDB for optimal performance\n */\n\n// Apply AgentDB runtime patch before any AgentDB imports\nimport '../utils/agentdb-runtime-patch.js';\n\n// New hybrid backend (recommended for new code)\nexport { HybridReasoningBank } from './HybridBackend.js';\nexport { HybridReasoningBank as ReasoningBank } from './HybridBackend.js'; // Alias for backwards compat\nexport { AdvancedMemorySystem } from './AdvancedMemory.js';\nexport type { PatternData, RetrievalOptions, CausalInsight } from './HybridBackend.js';\nexport type { FailureAnalysis, SkillComposition } from './AdvancedMemory.js';\n\n// Re-export AgentDB controllers for advanced usage\nexport {\n ReflexionMemory,\n SkillLibrary,\n CausalMemoryGraph,\n CausalRecall,\n NightlyLearner,\n EmbeddingService\n} from 'agentdb';\n\n// Original ReasoningBank implementations (backwards compatibility)\nexport { retrieveMemories, formatMemoriesForPrompt } from './core/retrieve.js';\nexport type { RetrievedMemory } from './core/retrieve.js';\n\nexport { judgeTrajectory } from './core/judge.js';\nexport type { Verdict } from './core/judge.js';\n\nexport { distillMemories } from './core/distill.js';\nexport type { DistilledMemory } from './core/distill.js';\n\nexport { consolidate, shouldConsolidate } from './core/consolidate.js';\nexport type { ConsolidationResult } from './core/consolidate.js';\n\nexport { mattsParallel, mattsSequential } from './core/matts.js';\nexport type { MattsResult } from './core/matts.js';\n\nexport { computeEmbedding, clearEmbeddingCache, isSemanticEmbedding } from './utils/embeddings.js';\nexport { mmrSelection, cosineSimilarity } from './utils/mmr.js';\nexport { scrubPII, containsPII, scrubMemory } from './utils/pii-scrubber.js';\nexport { loadConfig } from './utils/config.js';\n\n// Re-export database utilities\nimport * as db from './db/queries.js';\nexport { db };\nexport type {\n ReasoningMemory,\n PatternEmbedding,\n PatternLink,\n TaskTrajectory,\n MattsRun,\n ConsolidationRun,\n Trajectory,\n TrajectoryStep\n} from './db/schema.js';\n\n// Original functions (backwards compatibility)\nimport { loadConfig } from './utils/config.js';\nimport { retrieveMemories } from './core/retrieve.js';\nimport { judgeTrajectory } from './core/judge.js';\nimport { distillMemories } from './core/distill.js';\nimport { shouldConsolidate as shouldCons, consolidate as cons } from './core/consolidate.js';\n\nexport async function initialize(): Promise<void> {\n const config = loadConfig();\n console.error('[ReasoningBank] Initializing...');\n console.error('[ReasoningBank] Enabled: true (initializing...)');\n console.error(`[ReasoningBank] Database: ${process.env.CLAUDE_FLOW_DB_PATH || '.swarm/memory.db'}`);\n console.error(`[ReasoningBank] Embeddings: ${config.embeddings.provider}`);\n console.error(`[ReasoningBank] Retrieval k: ${config.retrieve.k}`);\n\n try {\n await db.runMigrations();\n console.error(`[ReasoningBank] Database migrated successfully`);\n } catch (error) {\n console.error('[ReasoningBank] Migration error:', error);\n throw new Error('ReasoningBank initialization failed: could not run migrations');\n }\n\n try {\n const dbConn = db.getDb();\n const tables = dbConn.prepare(\"SELECT name FROM sqlite_master WHERE type='table' AND name LIKE 'pattern%'\").all();\n console.error(`[ReasoningBank] Database OK: ${tables.length} tables found`);\n } catch (error) {\n console.error('[ReasoningBank] Database error:', error);\n throw new Error('ReasoningBank initialization failed: database not accessible');\n }\n\n console.error('[ReasoningBank] Initialization complete');\n}\n\nexport async function runTask(options: {\n taskId: string;\n agentId: string;\n query: string;\n domain?: string;\n executeFn: (memories: any[]) => Promise<any>;\n}): Promise<{\n verdict: any;\n usedMemories: any[];\n newMemories: string[];\n consolidated: boolean;\n}> {\n console.error(`[ReasoningBank] Running task: ${options.taskId}`);\n const memories = await retrieveMemories(options.query, {\n domain: options.domain,\n agent: options.agentId\n });\n console.error(`[ReasoningBank] Retrieved ${memories.length} memories`);\n const trajectory = await options.executeFn(memories);\n const verdict = await judgeTrajectory(trajectory, options.query);\n console.error(`[ReasoningBank] Verdict: ${verdict.label} (${verdict.confidence})`);\n // Close the loop: the memories this task used share its outcome.\n db.applyOutcomeToMemories(\n memories.map(m => m.id),\n verdict.label === 'Success',\n verdict.confidence\n );\n const newMemories = await distillMemories(trajectory, verdict, options.query, {\n taskId: options.taskId,\n agentId: options.agentId,\n domain: options.domain\n });\n console.error(`[ReasoningBank] Distilled ${newMemories.length} new memories`);\n let consolidated = false;\n if (shouldCons()) {\n console.error('[ReasoningBank] Running consolidation...');\n await cons();\n consolidated = true;\n }\n return { verdict, usedMemories: memories, newMemories, consolidated };\n}\n\nexport const VERSION = '1.7.1';\nexport const PAPER_URL = 'https://arxiv.org/html/2509.25140v1';\n"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/reasoningbank/index.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * ReasoningBank - Closed-loop memory system for AI agents\n * Based on arXiv:2509.25140 (Google DeepMind)\n *\n * @since v1.7.0 - Integrated AgentDB for optimal performance\n */\n\n// Apply AgentDB runtime patch before any AgentDB imports\nimport '../utils/agentdb-runtime-patch.js';\n\n// New hybrid backend (recommended for new code)\nexport { HybridReasoningBank } from './HybridBackend.js';\nexport { HybridReasoningBank as ReasoningBank } from './HybridBackend.js'; // Alias for backwards compat\nexport { AdvancedMemorySystem } from './AdvancedMemory.js';\nexport type { PatternData, RetrievalOptions, CausalInsight } from './HybridBackend.js';\nexport type { FailureAnalysis, SkillComposition } from './AdvancedMemory.js';\n\n// Re-export AgentDB controllers for advanced usage\nexport {\n ReflexionMemory,\n SkillLibrary,\n CausalMemoryGraph,\n CausalRecall,\n NightlyLearner,\n EmbeddingService\n} from 'agentdb';\n\n// Original ReasoningBank implementations (backwards compatibility)\nexport { retrieveMemories, formatMemoriesForPrompt } from './core/retrieve.js';\nexport type { RetrievedMemory } from './core/retrieve.js';\n\nexport { judgeTrajectory } from './core/judge.js';\nexport type { Verdict } from './core/judge.js';\n\nexport { distillMemories } from './core/distill.js';\nexport type { DistilledMemory } from './core/distill.js';\n\nexport { consolidate, shouldConsolidate } from './core/consolidate.js';\nexport type { ConsolidationResult } from './core/consolidate.js';\n\nexport { mattsParallel, mattsSequential } from './core/matts.js';\nexport type { MattsResult } from './core/matts.js';\n\nexport {\n computeEmbedding,\n clearEmbeddingCache,\n isSemanticEmbedding,\n getEmbeddingKind,\n resetEmbeddingBackend,\n} from './utils/embeddings.js';\nexport type { EmbeddingKind } from './utils/embeddings.js';\nexport { mmrSelection, cosineSimilarity } from './utils/mmr.js';\nexport { scrubPII, containsPII, scrubMemory } from './utils/pii-scrubber.js';\nexport { loadConfig } from './utils/config.js';\n\n// Re-export database utilities\nimport * as db from './db/queries.js';\nexport { db };\nexport type {\n ReasoningMemory,\n PatternEmbedding,\n PatternLink,\n TaskTrajectory,\n MattsRun,\n ConsolidationRun,\n Trajectory,\n TrajectoryStep\n} from './db/schema.js';\n\n// Original functions (backwards compatibility)\nimport { loadConfig } from './utils/config.js';\nimport { retrieveMemories } from './core/retrieve.js';\nimport { judgeTrajectory } from './core/judge.js';\nimport { distillMemories } from './core/distill.js';\nimport { shouldConsolidate as shouldCons, consolidate as cons } from './core/consolidate.js';\n\nexport async function initialize(): Promise<void> {\n const config = loadConfig();\n console.error('[ReasoningBank] Initializing...');\n console.error('[ReasoningBank] Enabled: true (initializing...)');\n console.error(`[ReasoningBank] Database: ${process.env.CLAUDE_FLOW_DB_PATH || '.swarm/memory.db'}`);\n console.error(`[ReasoningBank] Embeddings: ${config.embeddings.provider}`);\n console.error(`[ReasoningBank] Retrieval k: ${config.retrieve.k}`);\n\n try {\n await db.runMigrations();\n console.error(`[ReasoningBank] Database migrated successfully`);\n } catch (error) {\n console.error('[ReasoningBank] Migration error:', error);\n throw new Error('ReasoningBank initialization failed: could not run migrations');\n }\n\n try {\n const dbConn = db.getDb();\n const tables = dbConn.prepare(\"SELECT name FROM sqlite_master WHERE type='table' AND name LIKE 'pattern%'\").all();\n console.error(`[ReasoningBank] Database OK: ${tables.length} tables found`);\n } catch (error) {\n console.error('[ReasoningBank] Database error:', error);\n throw new Error('ReasoningBank initialization failed: database not accessible');\n }\n\n console.error('[ReasoningBank] Initialization complete');\n}\n\nexport async function runTask(options: {\n taskId: string;\n agentId: string;\n query: string;\n domain?: string;\n executeFn: (memories: any[]) => Promise<any>;\n}): Promise<{\n verdict: any;\n usedMemories: any[];\n newMemories: string[];\n consolidated: boolean;\n}> {\n console.error(`[ReasoningBank] Running task: ${options.taskId}`);\n const memories = await retrieveMemories(options.query, {\n domain: options.domain,\n agent: options.agentId\n });\n console.error(`[ReasoningBank] Retrieved ${memories.length} memories`);\n const trajectory = await options.executeFn(memories);\n const verdict = await judgeTrajectory(trajectory, options.query);\n console.error(`[ReasoningBank] Verdict: ${verdict.label} (${verdict.confidence})`);\n // Close the loop: the memories this task used share its outcome.\n db.applyOutcomeToMemories(\n memories.map(m => m.id),\n verdict.label === 'Success',\n verdict.confidence\n );\n const newMemories = await distillMemories(trajectory, verdict, options.query, {\n taskId: options.taskId,\n agentId: options.agentId,\n domain: options.domain\n });\n console.error(`[ReasoningBank] Distilled ${newMemories.length} new memories`);\n let consolidated = false;\n if (shouldCons()) {\n console.error('[ReasoningBank] Running consolidation...');\n await cons();\n consolidated = true;\n }\n return { verdict, usedMemories: memories, newMemories, consolidated };\n}\n\nexport const VERSION = '1.7.1';\nexport const PAPER_URL = 'https://arxiv.org/html/2509.25140v1';\n"]}
@@ -5,6 +5,12 @@
5
5
  * Logs go to stderr so that stdout stays clean for callers that pipe
6
6
  * structured output (CLIs, MCP stdio servers).
7
7
  */
8
+ /**
9
+ * The space every vector in this process belongs to. Set by the first
10
+ * embedding and kept until resetEmbeddingBackend(): model vectors and hash
11
+ * vectors are not comparable, so a process never mixes them (issue #246).
12
+ */
13
+ export type EmbeddingKind = 'local' | 'hash';
8
14
  /**
9
15
  * True when embeddings come from the transformer model; false when they come
10
16
  * from the deterministic hash fallback, whose vectors carry no semantic
@@ -12,6 +18,17 @@
12
18
  * model.
13
19
  */
14
20
  export declare function isSemanticEmbedding(): boolean;
21
+ /**
22
+ * The space this process's embeddings are in, or null before the first one.
23
+ * Vectors of different kinds must never be compared.
24
+ */
25
+ export declare function getEmbeddingKind(): EmbeddingKind | null;
26
+ /**
27
+ * Forget the backend choice and the cache, so the next embedding tries to load
28
+ * the model again. Vectors produced before the reset may be in a different
29
+ * space from those produced after it; re-embed anything you keep.
30
+ */
31
+ export declare function resetEmbeddingBackend(): void;
15
32
  /**
16
33
  * Compute embedding for text using local model
17
34
  */
@@ -1 +1 @@
1
- {"version":3,"file":"embeddings.d.ts","sourceRoot":"","sources":["../../../src/reasoningbank/utils/embeddings.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AA8FH;;;;;GAKG;AACH,wBAAgB,mBAAmB,IAAI,OAAO,CAE7C;AAED;;GAEG;AACH,wBAAsB,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC,CA8B1E;AAED;;;GAGG;AACH,wBAAsB,qBAAqB,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,YAAY,EAAE,CAAC,CA8CpF;AAED;;GAEG;AACH,wBAAgB,sBAAsB,IAAI,MAAM,CAE/C;AA+CD;;GAEG;AACH,wBAAgB,mBAAmB,IAAI,IAAI,CAE1C"}
1
+ {"version":3,"file":"embeddings.d.ts","sourceRoot":"","sources":["../../../src/reasoningbank/utils/embeddings.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAyBH;;;;GAIG;AACH,MAAM,MAAM,aAAa,GAAG,OAAO,GAAG,MAAM,CAAC;AAyE7C;;;;;GAKG;AACH,wBAAgB,mBAAmB,IAAI,OAAO,CAE7C;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,IAAI,aAAa,GAAG,IAAI,CAEvD;AAED;;;;GAIG;AACH,wBAAgB,qBAAqB,IAAI,IAAI,CAK5C;AAkBD;;GAEG;AACH,wBAAsB,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC,CA4B1E;AAED;;;GAGG;AACH,wBAAsB,qBAAqB,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,YAAY,EAAE,CAAC,CA6CpF;AAED;;GAEG;AACH,wBAAgB,sBAAsB,IAAI,MAAM,CAE/C;AA+CD;;GAEG;AACH,wBAAgB,mBAAmB,IAAI,IAAI,CAE1C"}
@@ -24,6 +24,7 @@ const CACHE_MAX_ENTRIES = 1000;
24
24
  const BATCH_CHUNK_SIZE = 32;
25
25
  let embeddingPipeline = null;
26
26
  let initializationPromise = null;
27
+ let embeddingKind = null;
27
28
  const embeddingCache = new Map();
28
29
  function cacheGet(key) {
29
30
  const entry = embeddingCache.get(key);
@@ -72,8 +73,9 @@ async function initializeEmbeddings() {
72
73
  catch (error) {
73
74
  console.error('[Embeddings] Failed to initialize:', error?.message || error);
74
75
  console.error('[Embeddings] Falling back to hash-based embeddings (not semantic)');
75
- // Reset promise so retry is possible
76
- initializationPromise = null;
76
+ // No automatic retry: a later successful load would put new vectors in a
77
+ // different space from the hash vectors already handed out. Call
78
+ // resetEmbeddingBackend() to try the model again.
77
79
  }
78
80
  })();
79
81
  return initializationPromise;
@@ -85,20 +87,50 @@ async function initializeEmbeddings() {
85
87
  * model.
86
88
  */
87
89
  export function isSemanticEmbedding() {
88
- return embeddingPipeline !== null;
90
+ return embeddingKind === 'local' || (embeddingKind === null && embeddingPipeline !== null);
91
+ }
92
+ /**
93
+ * The space this process's embeddings are in, or null before the first one.
94
+ * Vectors of different kinds must never be compared.
95
+ */
96
+ export function getEmbeddingKind() {
97
+ return embeddingKind;
98
+ }
99
+ /**
100
+ * Forget the backend choice and the cache, so the next embedding tries to load
101
+ * the model again. Vectors produced before the reset may be in a different
102
+ * space from those produced after it; re-embed anything you keep.
103
+ */
104
+ export function resetEmbeddingBackend() {
105
+ embeddingPipeline = null;
106
+ initializationPromise = null;
107
+ embeddingKind = null;
108
+ embeddingCache.clear();
109
+ }
110
+ /** Fix the process to one space on first use; refuse to switch afterwards. */
111
+ function commitKind(kind) {
112
+ if (embeddingKind === null)
113
+ embeddingKind = kind;
114
+ else if (embeddingKind !== kind) {
115
+ throw new Error(`[Embeddings] refusing to produce a ${kind} vector: this process already embeds with ${embeddingKind}`);
116
+ }
117
+ }
118
+ function modelFailure(error) {
119
+ return new Error(`[Embeddings] model failed (${error?.message || error}); not substituting a hash vector, which would not be comparable with the model vectors already produced`);
89
120
  }
90
121
  /**
91
122
  * Compute embedding for text using local model
92
123
  */
93
124
  export async function computeEmbedding(text) {
94
- const cached = cacheGet(`local:${text}`) ?? cacheGet(`hash:${text}`);
125
+ const cached = cacheGet(text);
95
126
  if (cached)
96
127
  return cached;
97
- // Initialize if needed
98
- await initializeEmbeddings();
128
+ // A process already in the hash space stays there; don't load the model.
129
+ if (embeddingKind !== 'hash')
130
+ await initializeEmbeddings();
99
131
  let embedding;
100
- let kind = 'local';
101
132
  if (embeddingPipeline) {
133
+ commitKind('local');
102
134
  try {
103
135
  const output = await embeddingPipeline(text, {
104
136
  pooling: 'mean',
@@ -108,16 +140,15 @@ export async function computeEmbedding(text) {
108
140
  }
109
141
  catch (error) {
110
142
  console.error('[Embeddings] Generation failed:', error?.message || error);
111
- embedding = hashEmbed(text, MODEL_DIMS);
112
- kind = 'hash';
143
+ throw modelFailure(error);
113
144
  }
114
145
  }
115
146
  else {
147
+ commitKind('hash');
116
148
  const dims = loadConfig()?.embeddings?.dimensions || MODEL_DIMS;
117
149
  embedding = hashEmbed(text, dims);
118
- kind = 'hash';
119
150
  }
120
- cacheSet(`${kind}:${text}`, embedding, cacheTtlSeconds());
151
+ cacheSet(text, embedding, cacheTtlSeconds());
121
152
  return embedding;
122
153
  }
123
154
  /**
@@ -125,14 +156,16 @@ export async function computeEmbedding(text) {
125
156
  * per chunk of texts rather than one call per text.
126
157
  */
127
158
  export async function computeEmbeddingBatch(texts) {
128
- await initializeEmbeddings();
159
+ if (embeddingKind !== 'hash')
160
+ await initializeEmbeddings();
129
161
  if (!embeddingPipeline) {
130
162
  return Promise.all(texts.map(text => computeEmbedding(text)));
131
163
  }
164
+ commitKind('local');
132
165
  const results = new Array(texts.length);
133
166
  const missing = new Map(); // text -> result indices
134
167
  texts.forEach((text, i) => {
135
- const cached = cacheGet(`local:${text}`);
168
+ const cached = cacheGet(text);
136
169
  if (cached) {
137
170
  results[i] = cached;
138
171
  return;
@@ -148,7 +181,6 @@ export async function computeEmbeddingBatch(texts) {
148
181
  for (let start = 0; start < uniqueTexts.length; start += BATCH_CHUNK_SIZE) {
149
182
  const chunk = uniqueTexts.slice(start, start + BATCH_CHUNK_SIZE);
150
183
  let vectors;
151
- let kind = 'local';
152
184
  try {
153
185
  const output = await embeddingPipeline(chunk, { pooling: 'mean', normalize: true });
154
186
  const dims = output.dims[output.dims.length - 1];
@@ -157,11 +189,10 @@ export async function computeEmbeddingBatch(texts) {
157
189
  }
158
190
  catch (error) {
159
191
  console.error('[Embeddings] Batch generation failed:', error?.message || error);
160
- vectors = chunk.map(text => hashEmbed(text, MODEL_DIMS));
161
- kind = 'hash';
192
+ throw modelFailure(error);
162
193
  }
163
194
  chunk.forEach((text, j) => {
164
- cacheSet(`${kind}:${text}`, vectors[j], ttl);
195
+ cacheSet(text, vectors[j], ttl);
165
196
  for (const i of missing.get(text))
166
197
  results[i] = vectors[j];
167
198
  });
@@ -1 +1 @@
1
- {"version":3,"file":"embeddings.js","sourceRoot":"","sources":["../../../src/reasoningbank/utils/embeddings.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Embedding generation for semantic similarity\n * Uses local transformers.js - no API key required!\n *\n * Logs go to stderr so that stdout stays clean for callers that pipe\n * structured output (CLIs, MCP stdio servers).\n */\n\nimport { pipeline, env } from '@huggingface/transformers';\nimport { loadConfig } from './config.js';\n\n// Configure transformers.js to use WASM backend only (avoid ONNX runtime issues)\n// The native ONNX runtime causes \"DefaultLogger not registered\" errors in Node.js\nenv.backends.onnx.wasm.proxy = false; // Disable ONNX runtime proxy\nenv.backends.onnx.wasm.numThreads = 1; // Single thread for stability\n\nconst MODEL_ID = 'Xenova/all-MiniLM-L6-v2';\nconst MODEL_DIMS = 384;\nconst CACHE_MAX_ENTRIES = 1000;\n// Texts per pipeline call in computeEmbeddingBatch. Bounds padding waste and\n// peak memory when a batch mixes short and long texts.\n//\n// The q8 model quantizes activations dynamically with one scale per tensor, so\n// a batched vector depends slightly on its batch-mates: cosine vs. the same\n// text embedded alone is ~0.99 (min ~0.985 measured). fp32 weights are exact\n// but slower for single texts and change every stored vector.\nconst BATCH_CHUNK_SIZE = 32;\n\nlet embeddingPipeline: any = null;\nlet initializationPromise: Promise<void> | null = null;\n\n/**\n * LRU cache with lazy TTL expiry. No timers: an expired entry is dropped when\n * it is next read, so the cache never keeps the event loop alive.\n */\ninterface CacheEntry {\n vector: Float32Array;\n expiresAt: number;\n}\nconst embeddingCache = new Map<string, CacheEntry>();\n\nfunction cacheGet(key: string): Float32Array | undefined {\n const entry = embeddingCache.get(key);\n if (!entry) return undefined;\n embeddingCache.delete(key);\n if (entry.expiresAt <= Date.now()) return undefined;\n embeddingCache.set(key, entry); // move to most-recently-used\n return entry.vector;\n}\n\nfunction cacheSet(key: string, vector: Float32Array, ttlSeconds: number): void {\n embeddingCache.delete(key);\n embeddingCache.set(key, { vector, expiresAt: Date.now() + ttlSeconds * 1000 });\n while (embeddingCache.size > CACHE_MAX_ENTRIES) {\n const oldest = embeddingCache.keys().next().value;\n if (oldest === undefined) break;\n embeddingCache.delete(oldest);\n }\n}\n\nfunction cacheTtlSeconds(): number {\n return loadConfig()?.embeddings?.cache_ttl_seconds || 3600;\n}\n\n/**\n * Initialize the embedding pipeline (lazy load)\n * RACE CONDITION FIX: Use promise-based initialization instead of busy-wait\n */\nasync function initializeEmbeddings(): Promise<void> {\n // Already initialized\n if (embeddingPipeline) return;\n\n // Initialization in progress - await existing promise\n if (initializationPromise) {\n return initializationPromise;\n }\n\n // RACE CONDITION FIX: Create promise for concurrent callers to await\n initializationPromise = (async () => {\n console.error(`[Embeddings] Initializing local embedding model (${MODEL_ID})...`);\n console.error('[Embeddings] First run will download ~23MB model...');\n\n try {\n embeddingPipeline = await pipeline(\n 'feature-extraction',\n MODEL_ID,\n { dtype: 'q8' } // quantized weights\n );\n console.error(`[Embeddings] Local model ready! (${MODEL_DIMS} dimensions)`);\n } catch (error: any) {\n console.error('[Embeddings] Failed to initialize:', error?.message || error);\n console.error('[Embeddings] Falling back to hash-based embeddings (not semantic)');\n // Reset promise so retry is possible\n initializationPromise = null;\n }\n })();\n\n return initializationPromise;\n}\n\n/**\n * True when embeddings come from the transformer model; false when they come\n * from the deterministic hash fallback, whose vectors carry no semantic\n * similarity. Returns false until the first embedding call has initialized the\n * model.\n */\nexport function isSemanticEmbedding(): boolean {\n return embeddingPipeline !== null;\n}\n\n/**\n * Compute embedding for text using local model\n */\nexport async function computeEmbedding(text: string): Promise<Float32Array> {\n const cached = cacheGet(`local:${text}`) ?? cacheGet(`hash:${text}`);\n if (cached) return cached;\n\n // Initialize if needed\n await initializeEmbeddings();\n\n let embedding: Float32Array;\n let kind: 'local' | 'hash' = 'local';\n\n if (embeddingPipeline) {\n try {\n const output = await embeddingPipeline(text, {\n pooling: 'mean',\n normalize: true\n });\n embedding = new Float32Array(output.data);\n } catch (error: any) {\n console.error('[Embeddings] Generation failed:', error?.message || error);\n embedding = hashEmbed(text, MODEL_DIMS);\n kind = 'hash';\n }\n } else {\n const dims = loadConfig()?.embeddings?.dimensions || MODEL_DIMS;\n embedding = hashEmbed(text, dims);\n kind = 'hash';\n }\n\n cacheSet(`${kind}:${text}`, embedding, cacheTtlSeconds());\n return embedding;\n}\n\n/**\n * Batch compute embeddings. Cache misses are embedded with one pipeline call\n * per chunk of texts rather than one call per text.\n */\nexport async function computeEmbeddingBatch(texts: string[]): Promise<Float32Array[]> {\n await initializeEmbeddings();\n if (!embeddingPipeline) {\n return Promise.all(texts.map(text => computeEmbedding(text)));\n }\n\n const results: Float32Array[] = new Array(texts.length);\n const missing = new Map<string, number[]>(); // text -> result indices\n\n texts.forEach((text, i) => {\n const cached = cacheGet(`local:${text}`);\n if (cached) {\n results[i] = cached;\n return;\n }\n const indices = missing.get(text);\n if (indices) indices.push(i);\n else missing.set(text, [i]);\n });\n\n const ttl = cacheTtlSeconds();\n const uniqueTexts = Array.from(missing.keys());\n\n for (let start = 0; start < uniqueTexts.length; start += BATCH_CHUNK_SIZE) {\n const chunk = uniqueTexts.slice(start, start + BATCH_CHUNK_SIZE);\n let vectors: Float32Array[];\n let kind: 'local' | 'hash' = 'local';\n\n try {\n const output = await embeddingPipeline(chunk, { pooling: 'mean', normalize: true });\n const dims = output.dims[output.dims.length - 1];\n const data = output.data as Float32Array;\n vectors = chunk.map((_, j) => new Float32Array(data.subarray(j * dims, (j + 1) * dims)));\n } catch (error: any) {\n console.error('[Embeddings] Batch generation failed:', error?.message || error);\n vectors = chunk.map(text => hashEmbed(text, MODEL_DIMS));\n kind = 'hash';\n }\n\n chunk.forEach((text, j) => {\n cacheSet(`${kind}:${text}`, vectors[j], ttl);\n for (const i of missing.get(text)!) results[i] = vectors[j];\n });\n }\n\n return results;\n}\n\n/**\n * Get embedding dimensions\n */\nexport function getEmbeddingDimensions(): number {\n return MODEL_DIMS; // all-MiniLM-L6-v2 uses 384 dimensions\n}\n\n/**\n * Deterministic hash-based embedding (fallback)\n */\nfunction hashEmbed(text: string, dims: number): Float32Array {\n const hash = simpleHash(text);\n const vec = new Float32Array(dims);\n\n // Generate deterministic pseudo-random vector from hash\n for (let i = 0; i < dims; i++) {\n vec[i] = Math.sin(hash * (i + 1) * 0.01) + Math.cos(hash * i * 0.02);\n }\n\n return normalize(vec);\n}\n\n/**\n * Simple string hash function\n */\nfunction simpleHash(str: string): number {\n let hash = 0;\n for (let i = 0; i < str.length; i++) {\n hash = ((hash << 5) - hash) + str.charCodeAt(i);\n hash |= 0;\n }\n return Math.abs(hash);\n}\n\n/**\n * Normalize vector to unit length\n */\nfunction normalize(vec: Float32Array): Float32Array {\n let mag = 0;\n for (let i = 0; i < vec.length; i++) {\n mag += vec[i] * vec[i];\n }\n mag = Math.sqrt(mag);\n\n if (mag === 0) return vec;\n\n for (let i = 0; i < vec.length; i++) {\n vec[i] /= mag;\n }\n return vec;\n}\n\n/**\n * Clear embedding cache\n */\nexport function clearEmbeddingCache(): void {\n embeddingCache.clear();\n}\n"]}
1
+ {"version":3,"file":"embeddings.js","sourceRoot":"","sources":["../../../src/reasoningbank/utils/embeddings.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Embedding generation for semantic similarity\n * Uses local transformers.js - no API key required!\n *\n * Logs go to stderr so that stdout stays clean for callers that pipe\n * structured output (CLIs, MCP stdio servers).\n */\n\nimport { pipeline, env } from '@huggingface/transformers';\nimport { loadConfig } from './config.js';\n\n// Configure transformers.js to use WASM backend only (avoid ONNX runtime issues)\n// The native ONNX runtime causes \"DefaultLogger not registered\" errors in Node.js\nenv.backends.onnx.wasm.proxy = false; // Disable ONNX runtime proxy\nenv.backends.onnx.wasm.numThreads = 1; // Single thread for stability\n\nconst MODEL_ID = 'Xenova/all-MiniLM-L6-v2';\nconst MODEL_DIMS = 384;\nconst CACHE_MAX_ENTRIES = 1000;\n// Texts per pipeline call in computeEmbeddingBatch. Bounds padding waste and\n// peak memory when a batch mixes short and long texts.\n//\n// The q8 model quantizes activations dynamically with one scale per tensor, so\n// a batched vector depends slightly on its batch-mates: cosine vs. the same\n// text embedded alone is ~0.99 (min ~0.985 measured). fp32 weights are exact\n// but slower for single texts and change every stored vector.\nconst BATCH_CHUNK_SIZE = 32;\n\nlet embeddingPipeline: any = null;\nlet initializationPromise: Promise<void> | null = null;\n\n/**\n * The space every vector in this process belongs to. Set by the first\n * embedding and kept until resetEmbeddingBackend(): model vectors and hash\n * vectors are not comparable, so a process never mixes them (issue #246).\n */\nexport type EmbeddingKind = 'local' | 'hash';\nlet embeddingKind: EmbeddingKind | null = null;\n\n/**\n * LRU cache with lazy TTL expiry. No timers: an expired entry is dropped when\n * it is next read, so the cache never keeps the event loop alive.\n */\ninterface CacheEntry {\n vector: Float32Array;\n expiresAt: number;\n}\nconst embeddingCache = new Map<string, CacheEntry>();\n\nfunction cacheGet(key: string): Float32Array | undefined {\n const entry = embeddingCache.get(key);\n if (!entry) return undefined;\n embeddingCache.delete(key);\n if (entry.expiresAt <= Date.now()) return undefined;\n embeddingCache.set(key, entry); // move to most-recently-used\n return entry.vector;\n}\n\nfunction cacheSet(key: string, vector: Float32Array, ttlSeconds: number): void {\n embeddingCache.delete(key);\n embeddingCache.set(key, { vector, expiresAt: Date.now() + ttlSeconds * 1000 });\n while (embeddingCache.size > CACHE_MAX_ENTRIES) {\n const oldest = embeddingCache.keys().next().value;\n if (oldest === undefined) break;\n embeddingCache.delete(oldest);\n }\n}\n\nfunction cacheTtlSeconds(): number {\n return loadConfig()?.embeddings?.cache_ttl_seconds || 3600;\n}\n\n/**\n * Initialize the embedding pipeline (lazy load)\n * RACE CONDITION FIX: Use promise-based initialization instead of busy-wait\n */\nasync function initializeEmbeddings(): Promise<void> {\n // Already initialized\n if (embeddingPipeline) return;\n\n // Initialization in progress - await existing promise\n if (initializationPromise) {\n return initializationPromise;\n }\n\n // RACE CONDITION FIX: Create promise for concurrent callers to await\n initializationPromise = (async () => {\n console.error(`[Embeddings] Initializing local embedding model (${MODEL_ID})...`);\n console.error('[Embeddings] First run will download ~23MB model...');\n\n try {\n embeddingPipeline = await pipeline(\n 'feature-extraction',\n MODEL_ID,\n { dtype: 'q8' } // quantized weights\n );\n console.error(`[Embeddings] Local model ready! (${MODEL_DIMS} dimensions)`);\n } catch (error: any) {\n console.error('[Embeddings] Failed to initialize:', error?.message || error);\n console.error('[Embeddings] Falling back to hash-based embeddings (not semantic)');\n // No automatic retry: a later successful load would put new vectors in a\n // different space from the hash vectors already handed out. Call\n // resetEmbeddingBackend() to try the model again.\n }\n })();\n\n return initializationPromise;\n}\n\n/**\n * True when embeddings come from the transformer model; false when they come\n * from the deterministic hash fallback, whose vectors carry no semantic\n * similarity. Returns false until the first embedding call has initialized the\n * model.\n */\nexport function isSemanticEmbedding(): boolean {\n return embeddingKind === 'local' || (embeddingKind === null && embeddingPipeline !== null);\n}\n\n/**\n * The space this process's embeddings are in, or null before the first one.\n * Vectors of different kinds must never be compared.\n */\nexport function getEmbeddingKind(): EmbeddingKind | null {\n return embeddingKind;\n}\n\n/**\n * Forget the backend choice and the cache, so the next embedding tries to load\n * the model again. Vectors produced before the reset may be in a different\n * space from those produced after it; re-embed anything you keep.\n */\nexport function resetEmbeddingBackend(): void {\n embeddingPipeline = null;\n initializationPromise = null;\n embeddingKind = null;\n embeddingCache.clear();\n}\n\n/** Fix the process to one space on first use; refuse to switch afterwards. */\nfunction commitKind(kind: EmbeddingKind): void {\n if (embeddingKind === null) embeddingKind = kind;\n else if (embeddingKind !== kind) {\n throw new Error(\n `[Embeddings] refusing to produce a ${kind} vector: this process already embeds with ${embeddingKind}`\n );\n }\n}\n\nfunction modelFailure(error: any): Error {\n return new Error(\n `[Embeddings] model failed (${error?.message || error}); not substituting a hash vector, which would not be comparable with the model vectors already produced`\n );\n}\n\n/**\n * Compute embedding for text using local model\n */\nexport async function computeEmbedding(text: string): Promise<Float32Array> {\n const cached = cacheGet(text);\n if (cached) return cached;\n\n // A process already in the hash space stays there; don't load the model.\n if (embeddingKind !== 'hash') await initializeEmbeddings();\n\n let embedding: Float32Array;\n if (embeddingPipeline) {\n commitKind('local');\n try {\n const output = await embeddingPipeline(text, {\n pooling: 'mean',\n normalize: true\n });\n embedding = new Float32Array(output.data);\n } catch (error: any) {\n console.error('[Embeddings] Generation failed:', error?.message || error);\n throw modelFailure(error);\n }\n } else {\n commitKind('hash');\n const dims = loadConfig()?.embeddings?.dimensions || MODEL_DIMS;\n embedding = hashEmbed(text, dims);\n }\n\n cacheSet(text, embedding, cacheTtlSeconds());\n return embedding;\n}\n\n/**\n * Batch compute embeddings. Cache misses are embedded with one pipeline call\n * per chunk of texts rather than one call per text.\n */\nexport async function computeEmbeddingBatch(texts: string[]): Promise<Float32Array[]> {\n if (embeddingKind !== 'hash') await initializeEmbeddings();\n if (!embeddingPipeline) {\n return Promise.all(texts.map(text => computeEmbedding(text)));\n }\n commitKind('local');\n\n const results: Float32Array[] = new Array(texts.length);\n const missing = new Map<string, number[]>(); // text -> result indices\n\n texts.forEach((text, i) => {\n const cached = cacheGet(text);\n if (cached) {\n results[i] = cached;\n return;\n }\n const indices = missing.get(text);\n if (indices) indices.push(i);\n else missing.set(text, [i]);\n });\n\n const ttl = cacheTtlSeconds();\n const uniqueTexts = Array.from(missing.keys());\n\n for (let start = 0; start < uniqueTexts.length; start += BATCH_CHUNK_SIZE) {\n const chunk = uniqueTexts.slice(start, start + BATCH_CHUNK_SIZE);\n let vectors: Float32Array[];\n\n try {\n const output = await embeddingPipeline(chunk, { pooling: 'mean', normalize: true });\n const dims = output.dims[output.dims.length - 1];\n const data = output.data as Float32Array;\n vectors = chunk.map((_, j) => new Float32Array(data.subarray(j * dims, (j + 1) * dims)));\n } catch (error: any) {\n console.error('[Embeddings] Batch generation failed:', error?.message || error);\n throw modelFailure(error);\n }\n\n chunk.forEach((text, j) => {\n cacheSet(text, vectors[j], ttl);\n for (const i of missing.get(text)!) results[i] = vectors[j];\n });\n }\n\n return results;\n}\n\n/**\n * Get embedding dimensions\n */\nexport function getEmbeddingDimensions(): number {\n return MODEL_DIMS; // all-MiniLM-L6-v2 uses 384 dimensions\n}\n\n/**\n * Deterministic hash-based embedding (fallback)\n */\nfunction hashEmbed(text: string, dims: number): Float32Array {\n const hash = simpleHash(text);\n const vec = new Float32Array(dims);\n\n // Generate deterministic pseudo-random vector from hash\n for (let i = 0; i < dims; i++) {\n vec[i] = Math.sin(hash * (i + 1) * 0.01) + Math.cos(hash * i * 0.02);\n }\n\n return normalize(vec);\n}\n\n/**\n * Simple string hash function\n */\nfunction simpleHash(str: string): number {\n let hash = 0;\n for (let i = 0; i < str.length; i++) {\n hash = ((hash << 5) - hash) + str.charCodeAt(i);\n hash |= 0;\n }\n return Math.abs(hash);\n}\n\n/**\n * Normalize vector to unit length\n */\nfunction normalize(vec: Float32Array): Float32Array {\n let mag = 0;\n for (let i = 0; i < vec.length; i++) {\n mag += vec[i] * vec[i];\n }\n mag = Math.sqrt(mag);\n\n if (mag === 0) return vec;\n\n for (let i = 0; i < vec.length; i++) {\n vec[i] /= mag;\n }\n return vec;\n}\n\n/**\n * Clear embedding cache\n */\nexport function clearEmbeddingCache(): void {\n embeddingCache.clear();\n}\n"]}
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Version from this package's package.json, found by walking up from this
3
+ * file (src/utils under tsx, dist/utils when built). Throws if it is missing,
4
+ * which only happens in a broken install, rather than falling back to a tag.
5
+ */
6
+ export declare function readPackageVersion(): string;
7
+ /** `agentic-flow@<installed version>`, for npx commands. */
8
+ export declare function packageSpec(): string;
9
+ //# sourceMappingURL=package-version.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"package-version.d.ts","sourceRoot":"","sources":["../../src/utils/package-version.ts"],"names":[],"mappings":"AAYA;;;;GAIG;AACH,wBAAgB,kBAAkB,IAAI,MAAM,CAgB3C;AAED,4DAA4D;AAC5D,wBAAgB,WAAW,IAAI,MAAM,CAEpC"}
@@ -0,0 +1,39 @@
1
+ // The installed agentic-flow version, for commands we write or print.
2
+ //
3
+ // Generated hooks, statuslines and help text run `npx agentic-flow@<this>`,
4
+ // never a dist-tag: @alpha still resolves to the deprecated March 3.0.0-alpha
5
+ // line, and @latest changes under an installed project without notice.
6
+ import * as fs from 'fs';
7
+ import * as path from 'path';
8
+ import { fileURLToPath } from 'url';
9
+ const VERSION_RE = /^\d+\.\d+\.\d+[\w.+-]*$/;
10
+ let cached;
11
+ /**
12
+ * Version from this package's package.json, found by walking up from this
13
+ * file (src/utils under tsx, dist/utils when built). Throws if it is missing,
14
+ * which only happens in a broken install, rather than falling back to a tag.
15
+ */
16
+ export function readPackageVersion() {
17
+ if (cached)
18
+ return cached;
19
+ let dir = path.dirname(fileURLToPath(import.meta.url));
20
+ for (;;) {
21
+ const file = path.join(dir, 'package.json');
22
+ if (fs.existsSync(file)) {
23
+ const pkg = JSON.parse(fs.readFileSync(file, 'utf-8'));
24
+ if (pkg.name === 'agentic-flow' && typeof pkg.version === 'string' && VERSION_RE.test(pkg.version)) {
25
+ cached = pkg.version;
26
+ return cached;
27
+ }
28
+ }
29
+ const parent = path.dirname(dir);
30
+ if (parent === dir)
31
+ throw new Error('agentic-flow: cannot find its own package.json to pin the version');
32
+ dir = parent;
33
+ }
34
+ }
35
+ /** `agentic-flow@<installed version>`, for npx commands. */
36
+ export function packageSpec() {
37
+ return `agentic-flow@${readPackageVersion()}`;
38
+ }
39
+ //# sourceMappingURL=package-version.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"package-version.js","sourceRoot":"","sources":["../../src/utils/package-version.ts"],"names":[],"mappings":"AAAA,sEAAsE;AACtE,EAAE;AACF,4EAA4E;AAC5E,8EAA8E;AAC9E,uEAAuE;AACvE,OAAO,KAAK,EAAE,MAAM,IAAI,CAAC;AACzB,OAAO,KAAK,IAAI,MAAM,MAAM,CAAC;AAC7B,OAAO,EAAE,aAAa,EAAE,MAAM,KAAK,CAAC;AAEpC,MAAM,UAAU,GAAG,yBAAyB,CAAC;AAC7C,IAAI,MAA0B,CAAC;AAE/B;;;;GAIG;AACH,MAAM,UAAU,kBAAkB;IAChC,IAAI,MAAM;QAAE,OAAO,MAAM,CAAC;IAC1B,IAAI,GAAG,GAAG,IAAI,CAAC,OAAO,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;IACvD,SAAS,CAAC;QACR,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,cAAc,CAAC,CAAC;QAC5C,IAAI,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC;YACxB,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,YAAY,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC,CAAC;YACvD,IAAI,GAAG,CAAC,IAAI,KAAK,cAAc,IAAI,OAAO,GAAG,CAAC,OAAO,KAAK,QAAQ,IAAI,UAAU,CAAC,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC;gBACnG,MAAM,GAAG,GAAG,CAAC,OAAiB,CAAC;gBAC/B,OAAO,MAAM,CAAC;YAChB,CAAC;QACH,CAAC;QACD,MAAM,MAAM,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;QACjC,IAAI,MAAM,KAAK,GAAG;YAAE,MAAM,IAAI,KAAK,CAAC,mEAAmE,CAAC,CAAC;QACzG,GAAG,GAAG,MAAM,CAAC;IACf,CAAC;AACH,CAAC;AAED,4DAA4D;AAC5D,MAAM,UAAU,WAAW;IACzB,OAAO,gBAAgB,kBAAkB,EAAE,EAAE,CAAC;AAChD,CAAC","sourcesContent":["// The installed agentic-flow version, for commands we write or print.\n//\n// Generated hooks, statuslines and help text run `npx agentic-flow@<this>`,\n// never a dist-tag: @alpha still resolves to the deprecated March 3.0.0-alpha\n// line, and @latest changes under an installed project without notice.\nimport * as fs from 'fs';\nimport * as path from 'path';\nimport { fileURLToPath } from 'url';\n\nconst VERSION_RE = /^\\d+\\.\\d+\\.\\d+[\\w.+-]*$/;\nlet cached: string | undefined;\n\n/**\n * Version from this package's package.json, found by walking up from this\n * file (src/utils under tsx, dist/utils when built). Throws if it is missing,\n * which only happens in a broken install, rather than falling back to a tag.\n */\nexport function readPackageVersion(): string {\n if (cached) return cached;\n let dir = path.dirname(fileURLToPath(import.meta.url));\n for (;;) {\n const file = path.join(dir, 'package.json');\n if (fs.existsSync(file)) {\n const pkg = JSON.parse(fs.readFileSync(file, 'utf-8'));\n if (pkg.name === 'agentic-flow' && typeof pkg.version === 'string' && VERSION_RE.test(pkg.version)) {\n cached = pkg.version as string;\n return cached;\n }\n }\n const parent = path.dirname(dir);\n if (parent === dir) throw new Error('agentic-flow: cannot find its own package.json to pin the version');\n dir = parent;\n }\n}\n\n/** `agentic-flow@<installed version>`, for npx commands. */\nexport function packageSpec(): string {\n return `agentic-flow@${readPackageVersion()}`;\n}\n"]}
@@ -6,8 +6,8 @@ RUN apk add --no-cache python3 make g++ sqlite sqlite-dev
6
6
  WORKDIR /test
7
7
 
8
8
  RUN echo "========================================" && \
9
- echo "Testing npx agentic-flow@latest" && \
9
+ echo "Testing npx agentic-flow@1.7.8" && \
10
10
  echo "========================================" && \
11
- npx agentic-flow@latest --version 2>&1 | head -20
11
+ npx agentic-flow@1.7.8 --version 2>&1 | head -20
12
12
 
13
13
  CMD ["echo", "✅ Test complete"]
@@ -6,8 +6,8 @@ RUN apk add --no-cache python3 make g++ sqlite sqlite-dev
6
6
  WORKDIR /test
7
7
 
8
8
  RUN echo "========================================" && \
9
- echo "Testing npx agentic-flow@latest with Node 20" && \
9
+ echo "Testing npx agentic-flow@1.7.9 with Node 20" && \
10
10
  echo "========================================" && \
11
- npx agentic-flow@latest --version 2>&1
11
+ npx agentic-flow@1.7.9 --version 2>&1
12
12
 
13
13
  CMD ["echo", "✅ Test complete"]
@@ -6,9 +6,9 @@ RUN apk add --no-cache python3 make g++ sqlite sqlite-dev
6
6
  WORKDIR /test
7
7
 
8
8
  RUN echo "========================================" && \
9
- echo "Testing npx agentic-flow@latest" && \
9
+ echo "Testing npx agentic-flow@1.7.9" && \
10
10
  echo "Expecting v1.7.9 with better-sqlite3 v11.x" && \
11
11
  echo "========================================" && \
12
- npx agentic-flow@latest --version 2>&1 | head -20
12
+ npx agentic-flow@1.7.9 --version 2>&1 | head -20
13
13
 
14
14
  CMD ["echo", "✅ Test complete"]
@@ -31,18 +31,29 @@ This command:
31
31
 
32
32
  **Terminal 1 - Start Proxy:**
33
33
  ```bash
34
+ export OPENROUTER_API_KEY=sk-or-v1-...
34
35
  npx agentic-flow proxy --provider openrouter --port 3000
36
+ # Prints: export ANTHROPIC_API_KEY=sk-ant-proxy-... (a new token every run)
35
37
  ```
36
38
 
37
39
  **Terminal 2 - Use Claude Code:**
38
40
  ```bash
39
41
  # Inline environment variables (cleanest native approach)
40
42
  ANTHROPIC_BASE_URL=http://localhost:3000 \
41
- ANTHROPIC_API_KEY=sk-ant-proxy-dummy \
42
- OPENROUTER_API_KEY=$OPENROUTER_API_KEY \
43
+ ANTHROPIC_API_KEY='<token printed by the proxy>' \
43
44
  claude "Write a Python function to sort a list"
44
45
  ```
45
46
 
47
+ The provider key stays with the proxy; Claude Code only needs the proxy token.
48
+
49
+ **Authentication (3.0.0+).** The proxy binds `127.0.0.1` and rejects any
50
+ `/v1/messages` request without its token, so nobody else on your network can
51
+ spend your provider key. On start it prints a random per-run token; pass it as
52
+ `ANTHROPIC_API_KEY` (sent as `x-api-key`) or as `Authorization: Bearer`. To
53
+ keep the same token across restarts, set `AGENTIC_FLOW_PROXY_TOKEN` before
54
+ starting the proxy and use that value. `AGENTIC_FLOW_PROXY_HOST` changes the
55
+ bind address; only widen it on a network you trust. `/health` needs no token.
56
+
46
57
  ---
47
58
 
48
59
  ### Option 3: Bash Wrapper Script
@@ -232,8 +243,7 @@ npx agentic-flow claude-code \
232
243
  4. **Wrapper spawns Claude Code with env:**
233
244
  ```bash
234
245
  ANTHROPIC_BASE_URL=http://localhost:3000
235
- ANTHROPIC_API_KEY=sk-ant-proxy-dummy
236
- OPENROUTER_API_KEY=sk-or-v1-xxxxx
246
+ ANTHROPIC_API_KEY=<the proxy's per-run token>
237
247
  claude "task"
238
248
  ```
239
249
 
@@ -309,7 +319,7 @@ VERBOSE=true npx agentic-flow proxy --provider openrouter
309
319
  # In another terminal, test with curl
310
320
  curl -X POST http://localhost:3000/v1/messages \
311
321
  -H "Content-Type: application/json" \
312
- -H "x-api-key: sk-ant-proxy-dummy" \
322
+ -H "x-api-key: <token printed by the proxy>" \
313
323
  -d '{"model":"claude-3-5-sonnet-20241022","messages":[{"role":"user","content":"hello"}],"max_tokens":100}'
314
324
  ```
315
325
 
@@ -361,14 +371,21 @@ proxy.start(3000);
361
371
 
362
372
  ### Environment Variable Presets
363
373
 
364
- Create `~/.agentic-flow-presets`:
374
+ Create `~/.agentic-flow-presets`. The proxies require a token, so give each
375
+ one a fixed token with `AGENTIC_FLOW_PROXY_TOKEN` when you start it and reuse
376
+ it here:
365
377
 
366
378
  ```bash
379
+ # Start the proxies with a stable token, e.g.
380
+ # AGENTIC_FLOW_PROXY_TOKEN=$AF_PROXY_TOKEN npx agentic-flow proxy --provider openrouter --port 3000
381
+ # AGENTIC_FLOW_PROXY_TOKEN=$AF_PROXY_TOKEN npx agentic-flow proxy --provider gemini --port 3001
382
+ export AF_PROXY_TOKEN="sk-ant-proxy-$(openssl rand -hex 32)"
383
+
367
384
  # OpenRouter preset
368
- alias claude-openrouter='ANTHROPIC_BASE_URL=http://localhost:3000 ANTHROPIC_API_KEY=dummy claude'
385
+ alias claude-openrouter='ANTHROPIC_BASE_URL=http://localhost:3000 ANTHROPIC_API_KEY=$AF_PROXY_TOKEN claude'
369
386
 
370
387
  # Gemini preset
371
- alias claude-gemini='ANTHROPIC_BASE_URL=http://localhost:3001 ANTHROPIC_API_KEY=dummy claude'
388
+ alias claude-gemini='ANTHROPIC_BASE_URL=http://localhost:3001 ANTHROPIC_API_KEY=$AF_PROXY_TOKEN claude'
372
389
 
373
390
  # Usage
374
391
  claude-openrouter "Write code"