agent-nuvira 1.14.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/LICENSE +21 -0
- package/README.md +891 -0
- package/dist/agent-sdk/src/agent.d.ts +118 -0
- package/dist/agent-sdk/src/agent.d.ts.map +1 -0
- package/dist/agent-sdk/src/agent.js +88 -0
- package/dist/agent-sdk/src/agent.js.map +1 -0
- package/dist/agent-sdk/src/index.d.ts +33 -0
- package/dist/agent-sdk/src/index.d.ts.map +1 -0
- package/dist/agent-sdk/src/index.js +32 -0
- package/dist/agent-sdk/src/index.js.map +1 -0
- package/dist/agent-sdk/src/register.d.ts +70 -0
- package/dist/agent-sdk/src/register.d.ts.map +1 -0
- package/dist/agent-sdk/src/register.js +181 -0
- package/dist/agent-sdk/src/register.js.map +1 -0
- package/dist/agent-sdk/src/scaffold.d.ts +50 -0
- package/dist/agent-sdk/src/scaffold.d.ts.map +1 -0
- package/dist/agent-sdk/src/scaffold.js +291 -0
- package/dist/agent-sdk/src/scaffold.js.map +1 -0
- package/dist/agent-sdk/src/testing.d.ts +187 -0
- package/dist/agent-sdk/src/testing.d.ts.map +1 -0
- package/dist/agent-sdk/src/testing.js +243 -0
- package/dist/agent-sdk/src/testing.js.map +1 -0
- package/dist/agent-sdk/src/types.d.ts +202 -0
- package/dist/agent-sdk/src/types.d.ts.map +1 -0
- package/dist/agent-sdk/src/types.js +11 -0
- package/dist/agent-sdk/src/types.js.map +1 -0
- package/dist/agents/agent.d.ts +132 -0
- package/dist/agents/agent.d.ts.map +1 -0
- package/dist/agents/agent.js +19 -0
- package/dist/agents/agent.js.map +1 -0
- package/dist/agents/agents/context-gatherer.d.ts +42 -0
- package/dist/agents/agents/context-gatherer.d.ts.map +1 -0
- package/dist/agents/agents/context-gatherer.js +366 -0
- package/dist/agents/agents/context-gatherer.js.map +1 -0
- package/dist/agents/agents/debugger.d.ts +58 -0
- package/dist/agents/agents/debugger.d.ts.map +1 -0
- package/dist/agents/agents/debugger.js +257 -0
- package/dist/agents/agents/debugger.js.map +1 -0
- package/dist/agents/agents/git-agent.d.ts +34 -0
- package/dist/agents/agents/git-agent.d.ts.map +1 -0
- package/dist/agents/agents/git-agent.js +200 -0
- package/dist/agents/agents/git-agent.js.map +1 -0
- package/dist/agents/agents/github-release-agent.d.ts +65 -0
- package/dist/agents/agents/github-release-agent.d.ts.map +1 -0
- package/dist/agents/agents/github-release-agent.js +439 -0
- package/dist/agents/agents/github-release-agent.js.map +1 -0
- package/dist/agents/agents/package-agent.d.ts +33 -0
- package/dist/agents/agents/package-agent.d.ts.map +1 -0
- package/dist/agents/agents/package-agent.js +233 -0
- package/dist/agents/agents/package-agent.js.map +1 -0
- package/dist/agents/agents/planner.d.ts +26 -0
- package/dist/agents/agents/planner.d.ts.map +1 -0
- package/dist/agents/agents/planner.js +222 -0
- package/dist/agents/agents/planner.js.map +1 -0
- package/dist/agents/agents/reviewer.d.ts +34 -0
- package/dist/agents/agents/reviewer.d.ts.map +1 -0
- package/dist/agents/agents/reviewer.js +159 -0
- package/dist/agents/agents/reviewer.js.map +1 -0
- package/dist/agents/agents/runner.d.ts +73 -0
- package/dist/agents/agents/runner.d.ts.map +1 -0
- package/dist/agents/agents/runner.js +299 -0
- package/dist/agents/agents/runner.js.map +1 -0
- package/dist/agents/agents/security-agent.d.ts +33 -0
- package/dist/agents/agents/security-agent.d.ts.map +1 -0
- package/dist/agents/agents/security-agent.js +184 -0
- package/dist/agents/agents/security-agent.js.map +1 -0
- package/dist/agents/agents/tester.d.ts +96 -0
- package/dist/agents/agents/tester.d.ts.map +1 -0
- package/dist/agents/agents/tester.js +410 -0
- package/dist/agents/agents/tester.js.map +1 -0
- package/dist/agents/agents/writer.d.ts +51 -0
- package/dist/agents/agents/writer.d.ts.map +1 -0
- package/dist/agents/agents/writer.js +384 -0
- package/dist/agents/agents/writer.js.map +1 -0
- package/dist/agents/context-vault.d.ts +49 -0
- package/dist/agents/context-vault.d.ts.map +1 -0
- package/dist/agents/context-vault.js +134 -0
- package/dist/agents/context-vault.js.map +1 -0
- package/dist/agents/orchestrator.d.ts +97 -0
- package/dist/agents/orchestrator.d.ts.map +1 -0
- package/dist/agents/orchestrator.js +696 -0
- package/dist/agents/orchestrator.js.map +1 -0
- package/dist/agents/utils/file-tree.d.ts +28 -0
- package/dist/agents/utils/file-tree.d.ts.map +1 -0
- package/dist/agents/utils/file-tree.js +93 -0
- package/dist/agents/utils/file-tree.js.map +1 -0
- package/dist/cli/agent.d.ts +25 -0
- package/dist/cli/agent.d.ts.map +1 -0
- package/dist/cli/agent.js +374 -0
- package/dist/cli/agent.js.map +1 -0
- package/dist/cli/benchmark.d.ts +24 -0
- package/dist/cli/benchmark.d.ts.map +1 -0
- package/dist/cli/benchmark.js +235 -0
- package/dist/cli/benchmark.js.map +1 -0
- package/dist/cli/cache.d.ts +12 -0
- package/dist/cli/cache.d.ts.map +1 -0
- package/dist/cli/cache.js +58 -0
- package/dist/cli/cache.js.map +1 -0
- package/dist/cli/chat.d.ts +37 -0
- package/dist/cli/chat.d.ts.map +1 -0
- package/dist/cli/chat.js +393 -0
- package/dist/cli/chat.js.map +1 -0
- package/dist/cli/commands.d.ts +24 -0
- package/dist/cli/commands.d.ts.map +1 -0
- package/dist/cli/commands.js +18 -0
- package/dist/cli/commands.js.map +1 -0
- package/dist/cli/config.d.ts +19 -0
- package/dist/cli/config.d.ts.map +1 -0
- package/dist/cli/config.js +162 -0
- package/dist/cli/config.js.map +1 -0
- package/dist/cli/dashboard.d.ts +34 -0
- package/dist/cli/dashboard.d.ts.map +1 -0
- package/dist/cli/dashboard.js +126 -0
- package/dist/cli/dashboard.js.map +1 -0
- package/dist/cli/doctor.d.ts +68 -0
- package/dist/cli/doctor.d.ts.map +1 -0
- package/dist/cli/doctor.js +585 -0
- package/dist/cli/doctor.js.map +1 -0
- package/dist/cli/edit.d.ts +11 -0
- package/dist/cli/edit.d.ts.map +1 -0
- package/dist/cli/edit.js +86 -0
- package/dist/cli/edit.js.map +1 -0
- package/dist/cli/execute.d.ts +25 -0
- package/dist/cli/execute.d.ts.map +1 -0
- package/dist/cli/execute.js +186 -0
- package/dist/cli/execute.js.map +1 -0
- package/dist/cli/federation.d.ts +31 -0
- package/dist/cli/federation.d.ts.map +1 -0
- package/dist/cli/federation.js +387 -0
- package/dist/cli/federation.js.map +1 -0
- package/dist/cli/history.d.ts +22 -0
- package/dist/cli/history.d.ts.map +1 -0
- package/dist/cli/history.js +140 -0
- package/dist/cli/history.js.map +1 -0
- package/dist/cli/init.d.ts +49 -0
- package/dist/cli/init.d.ts.map +1 -0
- package/dist/cli/init.js +423 -0
- package/dist/cli/init.js.map +1 -0
- package/dist/cli/learn.d.ts +31 -0
- package/dist/cli/learn.d.ts.map +1 -0
- package/dist/cli/learn.js +320 -0
- package/dist/cli/learn.js.map +1 -0
- package/dist/cli/memory.d.ts +38 -0
- package/dist/cli/memory.d.ts.map +1 -0
- package/dist/cli/memory.js +295 -0
- package/dist/cli/memory.js.map +1 -0
- package/dist/cli/model-picker.d.ts +18 -0
- package/dist/cli/model-picker.d.ts.map +1 -0
- package/dist/cli/model-picker.js +225 -0
- package/dist/cli/model-picker.js.map +1 -0
- package/dist/cli/models.d.ts +11 -0
- package/dist/cli/models.d.ts.map +1 -0
- package/dist/cli/models.js +132 -0
- package/dist/cli/models.js.map +1 -0
- package/dist/cli/plan.d.ts +11 -0
- package/dist/cli/plan.d.ts.map +1 -0
- package/dist/cli/plan.js +94 -0
- package/dist/cli/plan.js.map +1 -0
- package/dist/cli/plugins.d.ts +15 -0
- package/dist/cli/plugins.d.ts.map +1 -0
- package/dist/cli/plugins.js +123 -0
- package/dist/cli/plugins.js.map +1 -0
- package/dist/cli/router.d.ts +20 -0
- package/dist/cli/router.d.ts.map +1 -0
- package/dist/cli/router.js +142 -0
- package/dist/cli/router.js.map +1 -0
- package/dist/cli/run.d.ts +22 -0
- package/dist/cli/run.d.ts.map +1 -0
- package/dist/cli/run.js +110 -0
- package/dist/cli/run.js.map +1 -0
- package/dist/cli/sandbox.d.ts +27 -0
- package/dist/cli/sandbox.d.ts.map +1 -0
- package/dist/cli/sandbox.js +264 -0
- package/dist/cli/sandbox.js.map +1 -0
- package/dist/cli/sdk.d.ts +27 -0
- package/dist/cli/sdk.d.ts.map +1 -0
- package/dist/cli/sdk.js +204 -0
- package/dist/cli/sdk.js.map +1 -0
- package/dist/cli/stats.d.ts +18 -0
- package/dist/cli/stats.d.ts.map +1 -0
- package/dist/cli/stats.js +78 -0
- package/dist/cli/stats.js.map +1 -0
- package/dist/cli/team.d.ts +42 -0
- package/dist/cli/team.d.ts.map +1 -0
- package/dist/cli/team.js +473 -0
- package/dist/cli/team.js.map +1 -0
- package/dist/cli/workflow.d.ts +27 -0
- package/dist/cli/workflow.d.ts.map +1 -0
- package/dist/cli/workflow.js +347 -0
- package/dist/cli/workflow.js.map +1 -0
- package/dist/config/manager.d.ts +37 -0
- package/dist/config/manager.d.ts.map +1 -0
- package/dist/config/manager.js +147 -0
- package/dist/config/manager.js.map +1 -0
- package/dist/config/types.d.ts +53 -0
- package/dist/config/types.d.ts.map +1 -0
- package/dist/config/types.js +2 -0
- package/dist/config/types.js.map +1 -0
- package/dist/context/cache.d.ts +27 -0
- package/dist/context/cache.d.ts.map +1 -0
- package/dist/context/cache.js +116 -0
- package/dist/context/cache.js.map +1 -0
- package/dist/context/history.d.ts +87 -0
- package/dist/context/history.d.ts.map +1 -0
- package/dist/context/history.js +249 -0
- package/dist/context/history.js.map +1 -0
- package/dist/context/parser.d.ts +61 -0
- package/dist/context/parser.d.ts.map +1 -0
- package/dist/context/parser.js +194 -0
- package/dist/context/parser.js.map +1 -0
- package/dist/federation/client.d.ts +49 -0
- package/dist/federation/client.d.ts.map +1 -0
- package/dist/federation/client.js +239 -0
- package/dist/federation/client.js.map +1 -0
- package/dist/federation/protocol.d.ts +155 -0
- package/dist/federation/protocol.d.ts.map +1 -0
- package/dist/federation/protocol.js +57 -0
- package/dist/federation/protocol.js.map +1 -0
- package/dist/federation/server.d.ts +25 -0
- package/dist/federation/server.d.ts.map +1 -0
- package/dist/federation/server.js +401 -0
- package/dist/federation/server.js.map +1 -0
- package/dist/index.d.ts +67 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +93 -0
- package/dist/index.js.map +1 -0
- package/dist/inference/factory.d.ts +20 -0
- package/dist/inference/factory.d.ts.map +1 -0
- package/dist/inference/factory.js +46 -0
- package/dist/inference/factory.js.map +1 -0
- package/dist/inference/gemini-adapter.d.ts +17 -0
- package/dist/inference/gemini-adapter.d.ts.map +1 -0
- package/dist/inference/gemini-adapter.js +176 -0
- package/dist/inference/gemini-adapter.js.map +1 -0
- package/dist/inference/groq-adapter.d.ts +17 -0
- package/dist/inference/groq-adapter.d.ts.map +1 -0
- package/dist/inference/groq-adapter.js +103 -0
- package/dist/inference/groq-adapter.js.map +1 -0
- package/dist/inference/interface.d.ts +49 -0
- package/dist/inference/interface.d.ts.map +1 -0
- package/dist/inference/interface.js +2 -0
- package/dist/inference/interface.js.map +1 -0
- package/dist/inference/local-adapter.d.ts +35 -0
- package/dist/inference/local-adapter.d.ts.map +1 -0
- package/dist/inference/local-adapter.js +311 -0
- package/dist/inference/local-adapter.js.map +1 -0
- package/dist/inference/model-catalog.d.ts +53 -0
- package/dist/inference/model-catalog.d.ts.map +1 -0
- package/dist/inference/model-catalog.js +306 -0
- package/dist/inference/model-catalog.js.map +1 -0
- package/dist/inference/nim-adapter.d.ts +17 -0
- package/dist/inference/nim-adapter.d.ts.map +1 -0
- package/dist/inference/nim-adapter.js +103 -0
- package/dist/inference/nim-adapter.js.map +1 -0
- package/dist/inference/openrouter-adapter.d.ts +17 -0
- package/dist/inference/openrouter-adapter.d.ts.map +1 -0
- package/dist/inference/openrouter-adapter.js +105 -0
- package/dist/inference/openrouter-adapter.js.map +1 -0
- package/dist/inference/sse.d.ts +20 -0
- package/dist/inference/sse.d.ts.map +1 -0
- package/dist/inference/sse.js +91 -0
- package/dist/inference/sse.js.map +1 -0
- package/dist/learning/agent-stats.d.ts +109 -0
- package/dist/learning/agent-stats.d.ts.map +1 -0
- package/dist/learning/agent-stats.js +240 -0
- package/dist/learning/agent-stats.js.map +1 -0
- package/dist/learning/benchmark.d.ts +161 -0
- package/dist/learning/benchmark.d.ts.map +1 -0
- package/dist/learning/benchmark.js +589 -0
- package/dist/learning/benchmark.js.map +1 -0
- package/dist/learning/cost-tracker.d.ts +101 -0
- package/dist/learning/cost-tracker.d.ts.map +1 -0
- package/dist/learning/cost-tracker.js +224 -0
- package/dist/learning/cost-tracker.js.map +1 -0
- package/dist/learning/feedback.d.ts +88 -0
- package/dist/learning/feedback.d.ts.map +1 -0
- package/dist/learning/feedback.js +169 -0
- package/dist/learning/feedback.js.map +1 -0
- package/dist/learning/hybrid-router.d.ts +201 -0
- package/dist/learning/hybrid-router.d.ts.map +1 -0
- package/dist/learning/hybrid-router.js +450 -0
- package/dist/learning/hybrid-router.js.map +1 -0
- package/dist/learning/model-compare.d.ts +76 -0
- package/dist/learning/model-compare.d.ts.map +1 -0
- package/dist/learning/model-compare.js +252 -0
- package/dist/learning/model-compare.js.map +1 -0
- package/dist/learning/model-router.d.ts +68 -0
- package/dist/learning/model-router.d.ts.map +1 -0
- package/dist/learning/model-router.js +140 -0
- package/dist/learning/model-router.js.map +1 -0
- package/dist/learning/pattern-extractor.d.ts +99 -0
- package/dist/learning/pattern-extractor.d.ts.map +1 -0
- package/dist/learning/pattern-extractor.js +310 -0
- package/dist/learning/pattern-extractor.js.map +1 -0
- package/dist/learning/scorer.d.ts +51 -0
- package/dist/learning/scorer.d.ts.map +1 -0
- package/dist/learning/scorer.js +64 -0
- package/dist/learning/scorer.js.map +1 -0
- package/dist/learning/self-improver.d.ts +48 -0
- package/dist/learning/self-improver.d.ts.map +1 -0
- package/dist/learning/self-improver.js +161 -0
- package/dist/learning/self-improver.js.map +1 -0
- package/dist/memory/embedder.d.ts +65 -0
- package/dist/memory/embedder.d.ts.map +1 -0
- package/dist/memory/embedder.js +424 -0
- package/dist/memory/embedder.js.map +1 -0
- package/dist/memory/memory-integration.d.ts +56 -0
- package/dist/memory/memory-integration.d.ts.map +1 -0
- package/dist/memory/memory-integration.js +95 -0
- package/dist/memory/memory-integration.js.map +1 -0
- package/dist/memory/trajectory-store.d.ts +149 -0
- package/dist/memory/trajectory-store.d.ts.map +1 -0
- package/dist/memory/trajectory-store.js +476 -0
- package/dist/memory/trajectory-store.js.map +1 -0
- package/dist/memory/vector-store.d.ts +78 -0
- package/dist/memory/vector-store.d.ts.map +1 -0
- package/dist/memory/vector-store.js +186 -0
- package/dist/memory/vector-store.js.map +1 -0
- package/dist/plugins/agent-plugin.d.ts +73 -0
- package/dist/plugins/agent-plugin.d.ts.map +1 -0
- package/dist/plugins/agent-plugin.js +199 -0
- package/dist/plugins/agent-plugin.js.map +1 -0
- package/dist/plugins/registry.d.ts +61 -0
- package/dist/plugins/registry.d.ts.map +1 -0
- package/dist/plugins/registry.js +67 -0
- package/dist/plugins/registry.js.map +1 -0
- package/dist/sandbox/images.d.ts +31 -0
- package/dist/sandbox/images.d.ts.map +1 -0
- package/dist/sandbox/images.js +129 -0
- package/dist/sandbox/images.js.map +1 -0
- package/dist/sandbox/manager.d.ts +134 -0
- package/dist/sandbox/manager.d.ts.map +1 -0
- package/dist/sandbox/manager.js +470 -0
- package/dist/sandbox/manager.js.map +1 -0
- package/dist/sandbox/types.d.ts +113 -0
- package/dist/sandbox/types.d.ts.map +1 -0
- package/dist/sandbox/types.js +107 -0
- package/dist/sandbox/types.js.map +1 -0
- package/dist/security/scanner.d.ts +53 -0
- package/dist/security/scanner.d.ts.map +1 -0
- package/dist/security/scanner.js +271 -0
- package/dist/security/scanner.js.map +1 -0
- package/dist/team/config.d.ts +50 -0
- package/dist/team/config.d.ts.map +1 -0
- package/dist/team/config.js +108 -0
- package/dist/team/config.js.map +1 -0
- package/dist/team/memory.d.ts +63 -0
- package/dist/team/memory.d.ts.map +1 -0
- package/dist/team/memory.js +282 -0
- package/dist/team/memory.js.map +1 -0
- package/dist/team/review.d.ts +123 -0
- package/dist/team/review.d.ts.map +1 -0
- package/dist/team/review.js +293 -0
- package/dist/team/review.js.map +1 -0
- package/dist/utils/env.d.ts +19 -0
- package/dist/utils/env.d.ts.map +1 -0
- package/dist/utils/env.js +250 -0
- package/dist/utils/env.js.map +1 -0
- package/dist/utils/logger.d.ts +11 -0
- package/dist/utils/logger.d.ts.map +1 -0
- package/dist/utils/logger.js +45 -0
- package/dist/utils/logger.js.map +1 -0
- package/dist/web-dashboard/server.d.ts +59 -0
- package/dist/web-dashboard/server.d.ts.map +1 -0
- package/dist/web-dashboard/server.js +418 -0
- package/dist/web-dashboard/server.js.map +1 -0
- package/dist/workflow/registry.d.ts +127 -0
- package/dist/workflow/registry.d.ts.map +1 -0
- package/dist/workflow/registry.js +482 -0
- package/dist/workflow/registry.js.map +1 -0
- package/dist/workflow/templates.d.ts +93 -0
- package/dist/workflow/templates.d.ts.map +1 -0
- package/dist/workflow/templates.js +481 -0
- package/dist/workflow/templates.js.map +1 -0
- package/package.json +78 -0
- package/src/web-dashboard/public/assets/index-B08nDkSB.css +1 -0
- package/src/web-dashboard/public/assets/index-BKL8YOFD.js +135 -0
- package/src/web-dashboard/public/assets/index-BKL8YOFD.js.map +1 -0
- package/src/web-dashboard/public/index.html +13 -0
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SelfImprover — The self-improvement loop that ties together scoring,
|
|
3
|
+
* agent performance tracking, pattern extraction, and model optimization.
|
|
4
|
+
*
|
|
5
|
+
* After each orchestration run (when `useMemory: true`), the SelfImprover:
|
|
6
|
+
* 1. Scores the trajectory (how well did we do?)
|
|
7
|
+
* 2. Records per-agent stats (which agents/models succeed/fail?)
|
|
8
|
+
* 3. Periodically extracts patterns from high-scoring trajectories
|
|
9
|
+
* 4. Provides optimization recommendations (best models per agent)
|
|
10
|
+
*
|
|
11
|
+
* The SelfImprover is called by the Orchestrator post-execution hook.
|
|
12
|
+
* Users can also interact with it via the `buff learn` CLI commands.
|
|
13
|
+
*/
|
|
14
|
+
import { getTrajectoryStore } from '../memory/trajectory-store.js';
|
|
15
|
+
import { getPatternStore } from './pattern-extractor.js';
|
|
16
|
+
import { getAgentStats } from './agent-stats.js';
|
|
17
|
+
import { scoreOrchestrationResult } from './scorer.js';
|
|
18
|
+
import { logger } from '../utils/logger.js';
|
|
19
|
+
// ─── Constants ──────────────────────────────────────────────────────────────
|
|
20
|
+
/** How many successful runs before auto-extracting patterns */
|
|
21
|
+
const PATTERN_EXTRACTION_INTERVAL = 5;
|
|
22
|
+
/** How many trajectories to pass for pattern extraction */
|
|
23
|
+
const TRAJECTORIES_FOR_EXTRACTION = 3;
|
|
24
|
+
/** Minimum score to consider a trajectory as "good" */
|
|
25
|
+
const GOOD_SCORE_THRESHOLD = 0.6;
|
|
26
|
+
// ─── SelfImprover ───────────────────────────────────────────────────────────
|
|
27
|
+
export class SelfImprover {
|
|
28
|
+
runCountSinceLastExtraction = 0;
|
|
29
|
+
/**
|
|
30
|
+
* Process a completed orchestration run through the self-improvement loop.
|
|
31
|
+
* Scores the result, tracks agent stats, and conditionally extracts patterns.
|
|
32
|
+
*
|
|
33
|
+
* @param result The completed orchestration result
|
|
34
|
+
* @param callLLM LLM function for pattern extraction
|
|
35
|
+
* @param agentModels The model map used for this run (for tracking model perf)
|
|
36
|
+
* @param verbose Whether to log details
|
|
37
|
+
*/
|
|
38
|
+
async processRun(result, callLLM, agentModels, verbose = false) {
|
|
39
|
+
// Step 1: Score the trajectory
|
|
40
|
+
const score = scoreOrchestrationResult(result);
|
|
41
|
+
if (verbose) {
|
|
42
|
+
logger.info(` Self-improvement: trajectory score = ${(score * 100).toFixed(0)}%`);
|
|
43
|
+
}
|
|
44
|
+
// Step 2: Record per-agent stats
|
|
45
|
+
const stats = getAgentStats();
|
|
46
|
+
stats.recordRuns(result.agentResults, agentModels);
|
|
47
|
+
// Step 3: Conditionally extract patterns from good trajectories
|
|
48
|
+
if (score >= GOOD_SCORE_THRESHOLD) {
|
|
49
|
+
this.runCountSinceLastExtraction++;
|
|
50
|
+
if (this.runCountSinceLastExtraction >= PATTERN_EXTRACTION_INTERVAL) {
|
|
51
|
+
this.runCountSinceLastExtraction = 0;
|
|
52
|
+
if (verbose) {
|
|
53
|
+
logger.info(' Extracting coding patterns from successful trajectories...');
|
|
54
|
+
}
|
|
55
|
+
await this.extractPatterns(callLLM, verbose);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Force pattern extraction from the best trajectories in the store.
|
|
61
|
+
*/
|
|
62
|
+
async extractPatterns(callLLM, verbose = false) {
|
|
63
|
+
try {
|
|
64
|
+
const store = getTrajectoryStore();
|
|
65
|
+
const allTrajectories = store.getAll();
|
|
66
|
+
// Get the highest-scoring trajectories
|
|
67
|
+
const best = allTrajectories
|
|
68
|
+
.filter((t) => t.score !== undefined)
|
|
69
|
+
.sort((a, b) => (b.score || 0) - (a.score || 0))
|
|
70
|
+
.slice(0, TRAJECTORIES_FOR_EXTRACTION);
|
|
71
|
+
if (best.length < 2) {
|
|
72
|
+
if (verbose) {
|
|
73
|
+
logger.info(' Not enough scored trajectories for pattern extraction');
|
|
74
|
+
}
|
|
75
|
+
return 0;
|
|
76
|
+
}
|
|
77
|
+
const patternStore = getPatternStore();
|
|
78
|
+
const count = await patternStore.extractFromTrajectories(best, callLLM);
|
|
79
|
+
if (verbose && count > 0) {
|
|
80
|
+
logger.success(` Extracted ${count} new pattern(s) from ${best.length} trajectories`);
|
|
81
|
+
}
|
|
82
|
+
return count;
|
|
83
|
+
}
|
|
84
|
+
catch (err) {
|
|
85
|
+
if (verbose) {
|
|
86
|
+
logger.debug(`Pattern extraction failed: ${err}`);
|
|
87
|
+
}
|
|
88
|
+
return 0;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Get optimization recommendations based on collected stats.
|
|
93
|
+
* Returns a recommended model map for the Orchestrator.
|
|
94
|
+
*/
|
|
95
|
+
getOptimizedModelMap() {
|
|
96
|
+
const stats = getAgentStats();
|
|
97
|
+
const allAgents = stats.getAllAgents();
|
|
98
|
+
const modelMap = {};
|
|
99
|
+
for (const agentType of Object.keys(allAgents)) {
|
|
100
|
+
const bestModel = stats.getBestModel(agentType);
|
|
101
|
+
if (bestModel) {
|
|
102
|
+
modelMap[agentType] = bestModel;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
return modelMap;
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* Get a human-readable summary of the self-improvement status.
|
|
109
|
+
*/
|
|
110
|
+
getStatus() {
|
|
111
|
+
const stats = getAgentStats();
|
|
112
|
+
const patternStore = getPatternStore();
|
|
113
|
+
const patterns = patternStore.getAll();
|
|
114
|
+
const store = getTrajectoryStore();
|
|
115
|
+
const allTrajectories = store.getAll();
|
|
116
|
+
const lines = [
|
|
117
|
+
'🔄 Self-Improvement Status',
|
|
118
|
+
'',
|
|
119
|
+
'── Trajectories ──',
|
|
120
|
+
` Total stored: ${allTrajectories.length}`,
|
|
121
|
+
` Scored: ${allTrajectories.filter((t) => t.score !== undefined).length}`,
|
|
122
|
+
` Avg score: ${this.averageScore(allTrajectories)}`,
|
|
123
|
+
'',
|
|
124
|
+
'── Patterns ──',
|
|
125
|
+
` Total patterns: ${patterns.length}`,
|
|
126
|
+
` Domains covered: ${[...new Set(patterns.flatMap((p) => p.applicableDomains))].join(', ') || 'none'}`,
|
|
127
|
+
'',
|
|
128
|
+
`── Performance ──`,
|
|
129
|
+
` Total runs tracked: ${stats.getRaw().totalRuns}`,
|
|
130
|
+
` Agents tracked: ${Object.keys(stats.getAllAgents()).length}`,
|
|
131
|
+
];
|
|
132
|
+
lines.push('');
|
|
133
|
+
lines.push(stats.formatStats());
|
|
134
|
+
lines.push('');
|
|
135
|
+
lines.push(stats.formatModelRecommendations());
|
|
136
|
+
return lines.join('\n');
|
|
137
|
+
}
|
|
138
|
+
/**
|
|
139
|
+
* Reset extraction counter (called when user manually extracts patterns).
|
|
140
|
+
*/
|
|
141
|
+
resetExtractionCounter() {
|
|
142
|
+
this.runCountSinceLastExtraction = 0;
|
|
143
|
+
}
|
|
144
|
+
// ── Private ────────────────────────────────────────────────────────────
|
|
145
|
+
averageScore(trajectories) {
|
|
146
|
+
const scored = trajectories.filter((t) => t.score !== undefined);
|
|
147
|
+
if (scored.length === 0)
|
|
148
|
+
return 'N/A';
|
|
149
|
+
const avg = scored.reduce((sum, t) => sum + (t.score || 0), 0) / scored.length;
|
|
150
|
+
return `${(avg * 100).toFixed(0)}%`;
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
// Singleton
|
|
154
|
+
let improverInstance = null;
|
|
155
|
+
export function getSelfImprover() {
|
|
156
|
+
if (!improverInstance) {
|
|
157
|
+
improverInstance = new SelfImprover();
|
|
158
|
+
}
|
|
159
|
+
return improverInstance;
|
|
160
|
+
}
|
|
161
|
+
//# sourceMappingURL=self-improver.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"self-improver.js","sourceRoot":"","sources":["../../src/learning/self-improver.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Embedder — Generates vector embeddings from text using a tiered approach.
|
|
3
|
+
*
|
|
4
|
+
* Embedding Tier Strategy:
|
|
5
|
+
* Tier 1: @huggingface/transformers (fast, local, 384-dim) — DEFAULT
|
|
6
|
+
* Tier 2: Python sentence-transformers via subprocess
|
|
7
|
+
* Tier 3: LLM-based (any configured InferenceProvider) — FALLBACK
|
|
8
|
+
*
|
|
9
|
+
* The embedder auto-selects the best available tier, caches results to avoid
|
|
10
|
+
* redundant computation, and gracefully degrades when tiers are unavailable.
|
|
11
|
+
*
|
|
12
|
+
* Dimensionality: 384 (all-MiniLM-L6-v2 default) — 6x more expressive than
|
|
13
|
+
* the previous 64-dim LLM-based embeddings while being 10x faster and free.
|
|
14
|
+
*/
|
|
15
|
+
import type { LLMCallFn } from '../agents/agent.js';
|
|
16
|
+
/** Dimensionality of the generated embeddings (all-MiniLM-L6-v2 default) */
|
|
17
|
+
export declare const EMBEDDING_DIM = 384;
|
|
18
|
+
/**
|
|
19
|
+
* Generate a vector embedding for the given text.
|
|
20
|
+
*
|
|
21
|
+
* Uses a tiered approach:
|
|
22
|
+
* 1. @huggingface/transformers (fast local embeddings) — preferred
|
|
23
|
+
* 2. Python sentence-transformers via subprocess
|
|
24
|
+
* 3. LLM-based embedding (requires callLLM function) — fallback
|
|
25
|
+
*
|
|
26
|
+
* @param text The text to embed (e.g., a user goal or task description)
|
|
27
|
+
* @param callLLM Optional LLM call function (only needed for Tier 3 fallback)
|
|
28
|
+
* @param forceLLM If true, skip native tiers and use LLM directly (useful for testing)
|
|
29
|
+
* @returns A promise that resolves to a number[] embedding vector (384-dim)
|
|
30
|
+
*/
|
|
31
|
+
export declare function embed(text: string, callLLM?: LLMCallFn, forceLLM?: boolean): Promise<number[]>;
|
|
32
|
+
/**
|
|
33
|
+
* Reset the tier availability cache.
|
|
34
|
+
* Call this when the environment changes (e.g., user installs a package)
|
|
35
|
+
* or in test setup to force re-detection.
|
|
36
|
+
*/
|
|
37
|
+
export declare function resetEmbeddingTierCache(): void;
|
|
38
|
+
/**
|
|
39
|
+
* Set the force-LLM mode for testing.
|
|
40
|
+
* When called with force=true, all native embedding tiers are disabled
|
|
41
|
+
* and only the LLM-based fallback (Tier 3) is used.
|
|
42
|
+
*/
|
|
43
|
+
export declare function setForceLLM(force: boolean): void;
|
|
44
|
+
/**
|
|
45
|
+
* Check if @huggingface/transformers is available.
|
|
46
|
+
* This is a lightweight check that doesn't load the model.
|
|
47
|
+
*/
|
|
48
|
+
export declare function isXenovaAvailable(): Promise<boolean>;
|
|
49
|
+
/**
|
|
50
|
+
* Check if Python sentence-transformers is available.
|
|
51
|
+
*/
|
|
52
|
+
export declare function isPythonAvailable(): Promise<boolean>;
|
|
53
|
+
/**
|
|
54
|
+
* Get the name of the currently active embedding tier.
|
|
55
|
+
*/
|
|
56
|
+
export declare function getActiveEmbeddingTier(): Promise<string>;
|
|
57
|
+
/**
|
|
58
|
+
* Clear the in-memory embedding cache.
|
|
59
|
+
*/
|
|
60
|
+
export declare function clearEmbeddingCache(): void;
|
|
61
|
+
/**
|
|
62
|
+
* Get the current size of the embedding cache.
|
|
63
|
+
*/
|
|
64
|
+
export declare function embeddingCacheSize(): number;
|
|
65
|
+
//# sourceMappingURL=embedder.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"embedder.d.ts","sourceRoot":"","sources":["../../src/memory/embedder.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAKH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAKpD,4EAA4E;AAC5E,eAAO,MAAM,aAAa,MAAM,CAAC;AAyEjC;;;;;;;;;;;;GAYG;AACH,wBAAsB,KAAK,CACzB,IAAI,EAAE,MAAM,EACZ,OAAO,CAAC,EAAE,SAAS,EACnB,QAAQ,CAAC,EAAE,OAAO,GACjB,OAAO,CAAC,MAAM,EAAE,CAAC,CAiDnB;AAyND;;;;GAIG;AACH,wBAAgB,uBAAuB,IAAI,IAAI,CAG9C;AAED;;;;GAIG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,OAAO,GAAG,IAAI,CAQhD;AAED;;;GAGG;AACH,wBAAsB,iBAAiB,IAAI,OAAO,CAAC,OAAO,CAAC,CAY1D;AAED;;GAEG;AACH,wBAAsB,iBAAiB,IAAI,OAAO,CAAC,OAAO,CAAC,CAmB1D;AAED;;GAEG;AACH,wBAAsB,sBAAsB,IAAI,OAAO,CAAC,MAAM,CAAC,CAI9D;AAID;;GAEG;AACH,wBAAgB,mBAAmB,IAAI,IAAI,CAE1C;AAED;;GAEG;AACH,wBAAgB,kBAAkB,IAAI,MAAM,CAE3C"}
|
|
@@ -0,0 +1,424 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Embedder — Generates vector embeddings from text using a tiered approach.
|
|
3
|
+
*
|
|
4
|
+
* Embedding Tier Strategy:
|
|
5
|
+
* Tier 1: @huggingface/transformers (fast, local, 384-dim) — DEFAULT
|
|
6
|
+
* Tier 2: Python sentence-transformers via subprocess
|
|
7
|
+
* Tier 3: LLM-based (any configured InferenceProvider) — FALLBACK
|
|
8
|
+
*
|
|
9
|
+
* The embedder auto-selects the best available tier, caches results to avoid
|
|
10
|
+
* redundant computation, and gracefully degrades when tiers are unavailable.
|
|
11
|
+
*
|
|
12
|
+
* Dimensionality: 384 (all-MiniLM-L6-v2 default) — 6x more expressive than
|
|
13
|
+
* the previous 64-dim LLM-based embeddings while being 10x faster and free.
|
|
14
|
+
*/
|
|
15
|
+
import { createHash } from 'node:crypto';
|
|
16
|
+
import { spawn } from 'node:child_process';
|
|
17
|
+
import { logger } from '../utils/logger.js';
|
|
18
|
+
// ─── Constants ──────────────────────────────────────────────────────────────
|
|
19
|
+
/** Dimensionality of the generated embeddings (all-MiniLM-L6-v2 default) */
|
|
20
|
+
export const EMBEDDING_DIM = 384;
|
|
21
|
+
/** Max text length for embedding (characters) */
|
|
22
|
+
const MAX_EMBEDDING_TEXT_LENGTH = 2000;
|
|
23
|
+
/** Default model for @huggingface/transformers */
|
|
24
|
+
const XENOVA_MODEL = 'Xenova/all-MiniLM-L6-v2';
|
|
25
|
+
/** LLM-based embedding system prompt (Tier 3 fallback) */
|
|
26
|
+
const EMBEDDING_PROMPT = `You are a semantic embedding generator. Given a piece of text, generate a dense vector representation that captures its semantic meaning.
|
|
27
|
+
|
|
28
|
+
Return ONLY a valid JSON array of ${EMBEDDING_DIM} floating-point numbers between -1 and 1.
|
|
29
|
+
No markdown, no explanations, no code blocks — just the raw JSON array.
|
|
30
|
+
|
|
31
|
+
The vector should encode:
|
|
32
|
+
- The main topic and domain (e.g., "authentication", "database", "CLI tool")
|
|
33
|
+
- The action being requested (e.g., "add", "fix", "refactor", "create")
|
|
34
|
+
- The technology stack or language if mentioned
|
|
35
|
+
- Key entities and concepts
|
|
36
|
+
|
|
37
|
+
Example output: [${Array(5).fill('0.0').join(', ')}, ...]`;
|
|
38
|
+
// ─── Tier Availability Cache ────────────────────────────────────────────────
|
|
39
|
+
let _xenovaAvailable = null;
|
|
40
|
+
let _pythonAvailable = null;
|
|
41
|
+
// ─── In-Memory Cache ────────────────────────────────────────────────────────
|
|
42
|
+
class EmbeddingCache {
|
|
43
|
+
cache = new Map();
|
|
44
|
+
maxSize;
|
|
45
|
+
constructor(maxSize = 200) {
|
|
46
|
+
this.maxSize = maxSize;
|
|
47
|
+
}
|
|
48
|
+
get(key) {
|
|
49
|
+
const value = this.cache.get(key);
|
|
50
|
+
if (value !== undefined) {
|
|
51
|
+
this.cache.delete(key);
|
|
52
|
+
this.cache.set(key, value);
|
|
53
|
+
}
|
|
54
|
+
return value;
|
|
55
|
+
}
|
|
56
|
+
set(key, value) {
|
|
57
|
+
if (this.cache.size >= this.maxSize) {
|
|
58
|
+
const firstKey = this.cache.keys().next().value;
|
|
59
|
+
if (firstKey !== undefined) {
|
|
60
|
+
this.cache.delete(firstKey);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
this.cache.set(key, value);
|
|
64
|
+
}
|
|
65
|
+
get size() {
|
|
66
|
+
return this.cache.size;
|
|
67
|
+
}
|
|
68
|
+
clear() {
|
|
69
|
+
this.cache.clear();
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
const cache = new EmbeddingCache();
|
|
73
|
+
// ─── Embedder ───────────────────────────────────────────────────────────────
|
|
74
|
+
function cacheKey(text) {
|
|
75
|
+
return createHash('md5').update(text.toLowerCase().trim()).digest('hex');
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Generate a vector embedding for the given text.
|
|
79
|
+
*
|
|
80
|
+
* Uses a tiered approach:
|
|
81
|
+
* 1. @huggingface/transformers (fast local embeddings) — preferred
|
|
82
|
+
* 2. Python sentence-transformers via subprocess
|
|
83
|
+
* 3. LLM-based embedding (requires callLLM function) — fallback
|
|
84
|
+
*
|
|
85
|
+
* @param text The text to embed (e.g., a user goal or task description)
|
|
86
|
+
* @param callLLM Optional LLM call function (only needed for Tier 3 fallback)
|
|
87
|
+
* @param forceLLM If true, skip native tiers and use LLM directly (useful for testing)
|
|
88
|
+
* @returns A promise that resolves to a number[] embedding vector (384-dim)
|
|
89
|
+
*/
|
|
90
|
+
export async function embed(text, callLLM, forceLLM) {
|
|
91
|
+
const key = cacheKey(text);
|
|
92
|
+
// Check cache first
|
|
93
|
+
const cached = cache.get(key);
|
|
94
|
+
if (cached)
|
|
95
|
+
return cached;
|
|
96
|
+
const truncatedText = text.slice(0, MAX_EMBEDDING_TEXT_LENGTH);
|
|
97
|
+
// When forceLLM is true, skip native tiers and go directly to LLM
|
|
98
|
+
// This is useful in test environments where mock LLMs are used
|
|
99
|
+
if (!forceLLM) {
|
|
100
|
+
// Tier 1: @huggingface/transformers (fast, local, free)
|
|
101
|
+
try {
|
|
102
|
+
const vector = await embedWithXenova(truncatedText);
|
|
103
|
+
if (vector) {
|
|
104
|
+
cache.set(key, vector);
|
|
105
|
+
return vector;
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
catch (err) {
|
|
109
|
+
logger.debug(`Tier 1 embedding (Xenova) failed: ${err}`);
|
|
110
|
+
}
|
|
111
|
+
// Tier 2: Python sentence-transformers via subprocess
|
|
112
|
+
try {
|
|
113
|
+
const vector = await embedWithPython(truncatedText);
|
|
114
|
+
if (vector) {
|
|
115
|
+
cache.set(key, vector);
|
|
116
|
+
return vector;
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
catch (err) {
|
|
120
|
+
logger.debug(`Tier 2 embedding (Python) failed: ${err}`);
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
// Tier 3: LLM-based embedding (requires callLLM)
|
|
124
|
+
if (callLLM) {
|
|
125
|
+
try {
|
|
126
|
+
const vector = await embedWithLLM(truncatedText, callLLM);
|
|
127
|
+
cache.set(key, vector);
|
|
128
|
+
return vector;
|
|
129
|
+
}
|
|
130
|
+
catch (err) {
|
|
131
|
+
logger.debug(`Tier 3 embedding (LLM) failed: ${err}`);
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
// All tiers failed — return zero vector (no meaningful matches)
|
|
135
|
+
logger.debug('All embedding tiers failed, returning zero vector');
|
|
136
|
+
return new Array(EMBEDDING_DIM).fill(0);
|
|
137
|
+
}
|
|
138
|
+
// ─── Tier 1: @huggingface/transformers ──────────────────────────────────────
|
|
139
|
+
/**
|
|
140
|
+
* Generate embedding using @huggingface/transformers (Xenova).
|
|
141
|
+
* This is the fastest and most reliable tier — runs locally with ONNX runtime.
|
|
142
|
+
* Returns null if the library is not installed or model fails to load.
|
|
143
|
+
*/
|
|
144
|
+
async function embedWithXenova(text) {
|
|
145
|
+
if (_xenovaAvailable === false)
|
|
146
|
+
return null;
|
|
147
|
+
try {
|
|
148
|
+
// Dynamic import — the package is optional (user may not have it installed)
|
|
149
|
+
const { pipeline } = await import('@huggingface/transformers');
|
|
150
|
+
// Use 'feature-extraction' pipeline with all-MiniLM-L6-v2
|
|
151
|
+
// This model produces 384-dimensional embeddings
|
|
152
|
+
const extractor = await pipeline('feature-extraction', XENOVA_MODEL);
|
|
153
|
+
const output = await extractor(text, {
|
|
154
|
+
pooling: 'mean',
|
|
155
|
+
normalize: true,
|
|
156
|
+
});
|
|
157
|
+
// Convert Tensor to plain JS array
|
|
158
|
+
const arr = output.tolist();
|
|
159
|
+
const vector = arr[0];
|
|
160
|
+
if (!vector || !Array.isArray(vector) || vector.length !== EMBEDDING_DIM) {
|
|
161
|
+
logger.debug(`Xenova embedding returned unexpected shape: ${vector?.length}`);
|
|
162
|
+
return null;
|
|
163
|
+
}
|
|
164
|
+
_xenovaAvailable = true;
|
|
165
|
+
return vector;
|
|
166
|
+
}
|
|
167
|
+
catch (err) {
|
|
168
|
+
_xenovaAvailable = false;
|
|
169
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
170
|
+
// Provide helpful messages for common issues
|
|
171
|
+
if (msg.includes('Cannot find package') || msg.includes('Cannot find module')) {
|
|
172
|
+
logger.debug('@huggingface/transformers not installed. Install with: npm install @huggingface/transformers');
|
|
173
|
+
}
|
|
174
|
+
else if (msg.includes('download')) {
|
|
175
|
+
logger.debug('Xenova model download failed. Will use fallback embedding.');
|
|
176
|
+
}
|
|
177
|
+
else {
|
|
178
|
+
logger.debug(`Xenova embedding error: ${msg}`);
|
|
179
|
+
}
|
|
180
|
+
return null;
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
// ─── Tier 2: Python sentence-transformers ───────────────────────────────────
|
|
184
|
+
/**
|
|
185
|
+
* Generate embedding using Python's sentence-transformers via subprocess.
|
|
186
|
+
* Second fallback — slower than Xenova but doesn't require npm package.
|
|
187
|
+
* Returns null if Python or sentence-transformers is not available.
|
|
188
|
+
*/
|
|
189
|
+
async function embedWithPython(text) {
|
|
190
|
+
if (_pythonAvailable === false)
|
|
191
|
+
return null;
|
|
192
|
+
// Escape the text for safe embedding in Python script
|
|
193
|
+
const escapedText = text
|
|
194
|
+
.replace(/\\/g, '\\\\')
|
|
195
|
+
.replace(/'/g, "\\'")
|
|
196
|
+
.replace(/\n/g, '\\n')
|
|
197
|
+
.replace(/\r/g, '\\r');
|
|
198
|
+
const pythonScript = `
|
|
199
|
+
import sys, json
|
|
200
|
+
try:
|
|
201
|
+
from sentence_transformers import SentenceTransformer
|
|
202
|
+
model = SentenceTransformer('all-MiniLM-L6-v2')
|
|
203
|
+
embedding = model.encode('${escapedText}').tolist()
|
|
204
|
+
# Ensure 384 dimensions
|
|
205
|
+
while len(embedding) < ${EMBEDDING_DIM}:
|
|
206
|
+
embedding.append(0.0)
|
|
207
|
+
embedding = embedding[:${EMBEDDING_DIM}]
|
|
208
|
+
print(json.dumps({"embedding": embedding}))
|
|
209
|
+
except ImportError:
|
|
210
|
+
print(json.dumps({"error": "sentence-transformers not installed. Run: pip install sentence-transformers"}))
|
|
211
|
+
sys.exit(1)
|
|
212
|
+
except Exception as e:
|
|
213
|
+
print(json.dumps({"error": str(e)}))
|
|
214
|
+
sys.exit(1)
|
|
215
|
+
`;
|
|
216
|
+
return new Promise((resolve) => {
|
|
217
|
+
const python = spawn('python3', ['-c', pythonScript], {
|
|
218
|
+
stdio: ['pipe', 'pipe', 'pipe'],
|
|
219
|
+
timeout: 30000, // 30 second timeout
|
|
220
|
+
});
|
|
221
|
+
let output = '';
|
|
222
|
+
let errorOutput = '';
|
|
223
|
+
python.stdout?.on('data', (chunk) => {
|
|
224
|
+
output += chunk.toString();
|
|
225
|
+
});
|
|
226
|
+
python.stderr?.on('data', (chunk) => {
|
|
227
|
+
errorOutput += chunk.toString();
|
|
228
|
+
});
|
|
229
|
+
python.on('error', (err) => {
|
|
230
|
+
_pythonAvailable = false;
|
|
231
|
+
if (err.code === 'ENOENT') {
|
|
232
|
+
logger.debug('Python 3 not found. Install sentence-transformers with: pip install sentence-transformers');
|
|
233
|
+
}
|
|
234
|
+
else {
|
|
235
|
+
logger.debug(`Python subprocess error: ${err.message}`);
|
|
236
|
+
}
|
|
237
|
+
resolve(null);
|
|
238
|
+
});
|
|
239
|
+
python.on('close', (exitCode) => {
|
|
240
|
+
if (exitCode === 0) {
|
|
241
|
+
try {
|
|
242
|
+
const parsed = JSON.parse(output);
|
|
243
|
+
if (parsed.error) {
|
|
244
|
+
logger.debug(`Python embedding error: ${parsed.error}`);
|
|
245
|
+
_pythonAvailable = false;
|
|
246
|
+
resolve(null);
|
|
247
|
+
}
|
|
248
|
+
else if (Array.isArray(parsed.embedding) && parsed.embedding.length === EMBEDDING_DIM) {
|
|
249
|
+
_pythonAvailable = true;
|
|
250
|
+
resolve(parsed.embedding);
|
|
251
|
+
}
|
|
252
|
+
else {
|
|
253
|
+
resolve(null);
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
catch {
|
|
257
|
+
resolve(null);
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
else {
|
|
261
|
+
_pythonAvailable = false;
|
|
262
|
+
if (errorOutput)
|
|
263
|
+
logger.debug(`Python embedding stderr: ${errorOutput.slice(0, 200)}`);
|
|
264
|
+
resolve(null);
|
|
265
|
+
}
|
|
266
|
+
});
|
|
267
|
+
});
|
|
268
|
+
}
|
|
269
|
+
// ─── Tier 3: LLM-based embedding ────────────────────────────────────────────
|
|
270
|
+
/**
|
|
271
|
+
* Generate embedding using an LLM via the InferenceProvider.
|
|
272
|
+
* This is the slowest and most expensive tier — fallback only.
|
|
273
|
+
* Requires a callLLM function (provided by the Orchestrator).
|
|
274
|
+
*/
|
|
275
|
+
async function embedWithLLM(text, callLLM) {
|
|
276
|
+
const prompt = `${EMBEDDING_PROMPT}\n\nText to embed:\n${text}`;
|
|
277
|
+
const response = await callLLM(prompt, {
|
|
278
|
+
temperature: 0.1,
|
|
279
|
+
maxTokens: 2048,
|
|
280
|
+
});
|
|
281
|
+
const vector = parseLLMEmbedding(response);
|
|
282
|
+
return vector;
|
|
283
|
+
}
|
|
284
|
+
/**
|
|
285
|
+
* Parse an embedding vector from the LLM's text response.
|
|
286
|
+
* Tries multiple strategies to extract a valid array of numbers.
|
|
287
|
+
*/
|
|
288
|
+
function parseLLMEmbedding(response) {
|
|
289
|
+
const trimmed = response.trim();
|
|
290
|
+
// Strategy 1: Direct JSON parse
|
|
291
|
+
try {
|
|
292
|
+
const parsed = JSON.parse(trimmed);
|
|
293
|
+
if (isValidEmbedding(parsed))
|
|
294
|
+
return parsed;
|
|
295
|
+
}
|
|
296
|
+
catch {
|
|
297
|
+
// Fall through
|
|
298
|
+
}
|
|
299
|
+
// Strategy 2: Extract from ```json code block
|
|
300
|
+
const jsonMatch = trimmed.match(/```(?:json)?\s*([\s\S]*?)```/);
|
|
301
|
+
if (jsonMatch) {
|
|
302
|
+
try {
|
|
303
|
+
const parsed = JSON.parse(jsonMatch[1].trim());
|
|
304
|
+
if (isValidEmbedding(parsed))
|
|
305
|
+
return parsed;
|
|
306
|
+
}
|
|
307
|
+
catch {
|
|
308
|
+
// Fall through
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
// Strategy 3: Find array pattern in text
|
|
312
|
+
const arrayMatch = trimmed.match(/\[[\s\S]*?\]/);
|
|
313
|
+
if (arrayMatch) {
|
|
314
|
+
try {
|
|
315
|
+
const parsed = JSON.parse(arrayMatch[0]);
|
|
316
|
+
if (isValidEmbedding(parsed))
|
|
317
|
+
return parsed;
|
|
318
|
+
}
|
|
319
|
+
catch {
|
|
320
|
+
// Fall through
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
// Fallback: return zero vector (no meaningful match)
|
|
324
|
+
logger.debug('Could not parse embedding from LLM response, using zero vector');
|
|
325
|
+
return new Array(EMBEDDING_DIM).fill(0);
|
|
326
|
+
}
|
|
327
|
+
/**
|
|
328
|
+
* Validate that a parsed value is a valid embedding vector.
|
|
329
|
+
*/
|
|
330
|
+
function isValidEmbedding(value) {
|
|
331
|
+
if (!Array.isArray(value))
|
|
332
|
+
return false;
|
|
333
|
+
if (value.length !== EMBEDDING_DIM)
|
|
334
|
+
return false;
|
|
335
|
+
return value.every((v) => typeof v === 'number' && isFinite(v));
|
|
336
|
+
}
|
|
337
|
+
// ─── Detection Helpers ──────────────────────────────────────────────────────
|
|
338
|
+
/**
|
|
339
|
+
* Reset the tier availability cache.
|
|
340
|
+
* Call this when the environment changes (e.g., user installs a package)
|
|
341
|
+
* or in test setup to force re-detection.
|
|
342
|
+
*/
|
|
343
|
+
export function resetEmbeddingTierCache() {
|
|
344
|
+
_xenovaAvailable = null;
|
|
345
|
+
_pythonAvailable = null;
|
|
346
|
+
}
|
|
347
|
+
/**
|
|
348
|
+
* Set the force-LLM mode for testing.
|
|
349
|
+
* When called with force=true, all native embedding tiers are disabled
|
|
350
|
+
* and only the LLM-based fallback (Tier 3) is used.
|
|
351
|
+
*/
|
|
352
|
+
export function setForceLLM(force) {
|
|
353
|
+
if (force) {
|
|
354
|
+
_xenovaAvailable = false;
|
|
355
|
+
_pythonAvailable = false;
|
|
356
|
+
}
|
|
357
|
+
else {
|
|
358
|
+
_xenovaAvailable = null;
|
|
359
|
+
_pythonAvailable = null;
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
/**
|
|
363
|
+
* Check if @huggingface/transformers is available.
|
|
364
|
+
* This is a lightweight check that doesn't load the model.
|
|
365
|
+
*/
|
|
366
|
+
export async function isXenovaAvailable() {
|
|
367
|
+
if (_xenovaAvailable !== null)
|
|
368
|
+
return _xenovaAvailable;
|
|
369
|
+
try {
|
|
370
|
+
// Try to resolve the package without loading it
|
|
371
|
+
await import('@huggingface/transformers');
|
|
372
|
+
_xenovaAvailable = true;
|
|
373
|
+
return true;
|
|
374
|
+
}
|
|
375
|
+
catch {
|
|
376
|
+
_xenovaAvailable = false;
|
|
377
|
+
return false;
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
/**
|
|
381
|
+
* Check if Python sentence-transformers is available.
|
|
382
|
+
*/
|
|
383
|
+
export async function isPythonAvailable() {
|
|
384
|
+
if (_pythonAvailable !== null)
|
|
385
|
+
return _pythonAvailable;
|
|
386
|
+
return new Promise((resolve) => {
|
|
387
|
+
const python = spawn('python3', ['-c', 'from sentence_transformers import SentenceTransformer; print("ok")'], {
|
|
388
|
+
stdio: ['pipe', 'pipe', 'pipe'],
|
|
389
|
+
timeout: 10000,
|
|
390
|
+
});
|
|
391
|
+
python.on('close', (code) => {
|
|
392
|
+
_pythonAvailable = code === 0;
|
|
393
|
+
resolve(code === 0);
|
|
394
|
+
});
|
|
395
|
+
python.on('error', () => {
|
|
396
|
+
_pythonAvailable = false;
|
|
397
|
+
resolve(false);
|
|
398
|
+
});
|
|
399
|
+
});
|
|
400
|
+
}
|
|
401
|
+
/**
|
|
402
|
+
* Get the name of the currently active embedding tier.
|
|
403
|
+
*/
|
|
404
|
+
export async function getActiveEmbeddingTier() {
|
|
405
|
+
if (await isXenovaAvailable())
|
|
406
|
+
return 'local (Xenova, 384-dim)';
|
|
407
|
+
if (await isPythonAvailable())
|
|
408
|
+
return 'python (sentence-transformers, 384-dim)';
|
|
409
|
+
return 'llm (fallback, 384-dim)';
|
|
410
|
+
}
|
|
411
|
+
// ─── Cache Management ───────────────────────────────────────────────────────
|
|
412
|
+
/**
|
|
413
|
+
* Clear the in-memory embedding cache.
|
|
414
|
+
*/
|
|
415
|
+
export function clearEmbeddingCache() {
|
|
416
|
+
cache.clear();
|
|
417
|
+
}
|
|
418
|
+
/**
|
|
419
|
+
* Get the current size of the embedding cache.
|
|
420
|
+
*/
|
|
421
|
+
export function embeddingCacheSize() {
|
|
422
|
+
return cache.size;
|
|
423
|
+
}
|
|
424
|
+
//# sourceMappingURL=embedder.js.map
|