luna-agents 2.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude-plugin/LICENSE +21 -0
- package/.claude-plugin/README.md +285 -0
- package/.claude-plugin/claude-plugin.json +106 -0
- package/.claude-plugin/index.js +318 -0
- package/.claude-plugin/lib/api-client.js +504 -0
- package/.claude-plugin/lib/rag-utils.js +442 -0
- package/.claude-plugin/package.json +418 -0
- package/LICENSE +21 -0
- package/README.md +350 -0
- package/agents/json/design-architect.json +57 -0
- package/agents/json/luna-auth.json +71 -0
- package/agents/json/luna-brand.json +66 -0
- package/agents/json/luna-cloudflare.json +261 -0
- package/agents/json/luna-code-review.json +63 -0
- package/agents/json/luna-deployment.json +68 -0
- package/agents/json/luna-documentation.json +85 -0
- package/agents/json/luna-hig.json +128 -0
- package/agents/json/luna-layout-designer.json +178 -0
- package/agents/json/luna-monitoring-observability.json +64 -0
- package/agents/json/luna-post-launch-review.json +68 -0
- package/agents/json/luna-requirements-analyzer.json +53 -0
- package/agents/json/luna-task-executor.json +63 -0
- package/agents/json/luna-task-planner.json +62 -0
- package/agents/json/luna-testing-validation.json +66 -0
- package/agents/luna-365-security.md +96 -0
- package/agents/luna-analytics.md +318 -0
- package/agents/luna-api-generator.md +654 -0
- package/agents/luna-auth.md +396 -0
- package/agents/luna-brand.md +248 -0
- package/agents/luna-cloudflare.md +728 -0
- package/agents/luna-code-review.md +487 -0
- package/agents/luna-database.md +453 -0
- package/agents/luna-deployment.md +202 -0
- package/agents/luna-design-architect.md +353 -0
- package/agents/luna-docker.md +615 -0
- package/agents/luna-documentation.md +177 -0
- package/agents/luna-full-test.md +910 -0
- package/agents/luna-glm-vision.md +211 -0
- package/agents/luna-hig.md +430 -0
- package/agents/luna-lemonsqueezy.md +441 -0
- package/agents/luna-monitoring-observability.md +199 -0
- package/agents/luna-openai-app.md +499 -0
- package/agents/luna-post-launch-review.md +191 -0
- package/agents/luna-rag-enhanced.md +1619 -0
- package/agents/luna-rag.md +1733 -0
- package/agents/luna-requirements-analyzer.md +189 -0
- package/agents/luna-run.md +620 -0
- package/agents/luna-seo.md +338 -0
- package/agents/luna-task-executor.md +371 -0
- package/agents/luna-task-planner.md +275 -0
- package/agents/luna-testing-validation.md +681 -0
- package/agents/luna-ui-fix.md +591 -0
- package/agents/luna-ui-test.md +600 -0
- package/agents/luna-user-guide.md +409 -0
- package/agents/site-auditor.md +83 -0
- package/commands/3d-mesh.md +12 -0
- package/commands/3d.md +12 -0
- package/commands/agent-boost.md +13 -0
- package/commands/ai-index.md +16 -0
- package/commands/api.md +12 -0
- package/commands/assert.md +17 -0
- package/commands/audience.md +12 -0
- package/commands/auth.md +17 -0
- package/commands/autopilot.md +12 -0
- package/commands/boost-finsavvy.md +10 -0
- package/commands/boost-org.md +10 -0
- package/commands/boost-project.md +12 -0
- package/commands/brand.md +17 -0
- package/commands/browser-test.md +18 -0
- package/commands/cf.md +26 -0
- package/commands/cfg.md +33 -0
- package/commands/chain.md +12 -0
- package/commands/challenge.md +13 -0
- package/commands/clone.md +12 -0
- package/commands/cmds.md +243 -0
- package/commands/collab.md +12 -0
- package/commands/compete.md +12 -0
- package/commands/config-rules.md +21 -0
- package/commands/connect-infra.md +10 -0
- package/commands/context-pack.md +13 -0
- package/commands/curb.md +12 -0
- package/commands/des.md +38 -0
- package/commands/devto.md +20 -0
- package/commands/dock.md +26 -0
- package/commands/docs.md +33 -0
- package/commands/e2e-flow.md +18 -0
- package/commands/email-routing.md +10 -0
- package/commands/feature.md +12 -0
- package/commands/figma.md +12 -0
- package/commands/fix.md +12 -0
- package/commands/flaky.md +12 -0
- package/commands/flow-record.md +12 -0
- package/commands/gamify.md +12 -0
- package/commands/ghost.md +12 -0
- package/commands/git-insights.md +12 -0
- package/commands/go-viral.md +16 -0
- package/commands/go.md +42 -0
- package/commands/graph-rag.md +13 -0
- package/commands/guard.md +12 -0
- package/commands/heal.md +17 -0
- package/commands/heygen.md +12 -0
- package/commands/hig.md +33 -0
- package/commands/idea.md +12 -0
- package/commands/imagine.md +12 -0
- package/commands/inbox.md +12 -0
- package/commands/lam.md +12 -0
- package/commands/landing.md +12 -0
- package/commands/launch.md +12 -0
- package/commands/learn.md +12 -0
- package/commands/leverage.md +12 -0
- package/commands/ll-365-secure.md +179 -0
- package/commands/ll-3d-mesh.md +94 -0
- package/commands/ll-3d.md +123 -0
- package/commands/ll-a11y-scan.md +143 -0
- package/commands/ll-a11y.md +71 -0
- package/commands/ll-agent-boost.md +92 -0
- package/commands/ll-agent-chain.md +104 -0
- package/commands/ll-ai-index.md +120 -0
- package/commands/ll-api-client.md +77 -0
- package/commands/ll-api.md +99 -0
- package/commands/ll-assert.md +73 -0
- package/commands/ll-audience.md +308 -0
- package/commands/ll-auth.md +145 -0
- package/commands/ll-autopilot.md +113 -0
- package/commands/ll-boost-finsavvy.md +106 -0
- package/commands/ll-boost-org.md +161 -0
- package/commands/ll-boost-project.md +118 -0
- package/commands/ll-brand.md +150 -0
- package/commands/ll-browser-test.md +203 -0
- package/commands/ll-challenge.md +124 -0
- package/commands/ll-changelog.md +80 -0
- package/commands/ll-ci.md +78 -0
- package/commands/ll-claude-instructions.md +80 -0
- package/commands/ll-clone.md +82 -0
- package/commands/ll-cloudflare.md +580 -0
- package/commands/ll-codemap.md +78 -0
- package/commands/ll-collab.md +87 -0
- package/commands/ll-compete.md +67 -0
- package/commands/ll-config-rules.md +255 -0
- package/commands/ll-config.md +434 -0
- package/commands/ll-connect-infra.md +123 -0
- package/commands/ll-context-pack.md +100 -0
- package/commands/ll-curb.md +164 -0
- package/commands/ll-debug.md +76 -0
- package/commands/ll-deploy.md +101 -0
- package/commands/ll-deps.md +70 -0
- package/commands/ll-design.md +86 -0
- package/commands/ll-devto-publish.md +172 -0
- package/commands/ll-dockerize.md +273 -0
- package/commands/ll-docs.md +123 -0
- package/commands/ll-e2e-flow.md +132 -0
- package/commands/ll-e2e-test.md +231 -0
- package/commands/ll-email-routing.md +130 -0
- package/commands/ll-env.md +70 -0
- package/commands/ll-execute.md +98 -0
- package/commands/ll-feature.md +80 -0
- package/commands/ll-figma.md +82 -0
- package/commands/ll-fix.md +76 -0
- package/commands/ll-flaky.md +151 -0
- package/commands/ll-flow-record.md +180 -0
- package/commands/ll-flowdocs.md +83 -0
- package/commands/ll-gamify.md +131 -0
- package/commands/ll-gemma4.md +84 -0
- package/commands/ll-ghost.md +79 -0
- package/commands/ll-git-insights.md +152 -0
- package/commands/ll-go-viral.md +171 -0
- package/commands/ll-graph-rag.md +113 -0
- package/commands/ll-guard.md +92 -0
- package/commands/ll-heal.md +135 -0
- package/commands/ll-heygen.md +203 -0
- package/commands/ll-hig.md +578 -0
- package/commands/ll-hld.md +84 -0
- package/commands/ll-i18n.md +74 -0
- package/commands/ll-idea.md +101 -0
- package/commands/ll-imagine.md +72 -0
- package/commands/ll-inbox.md +116 -0
- package/commands/ll-lam.md +93 -0
- package/commands/ll-landing.md +171 -0
- package/commands/ll-launch.md +100 -0
- package/commands/ll-learn.md +87 -0
- package/commands/ll-leverage.md +137 -0
- package/commands/ll-local-llm.md +131 -0
- package/commands/ll-ls-products.md +160 -0
- package/commands/ll-marketplace.md +130 -0
- package/commands/ll-mcp-publish.md +104 -0
- package/commands/ll-migrate.md +68 -0
- package/commands/ll-mock.md +79 -0
- package/commands/ll-money.md +87 -0
- package/commands/ll-monitor.md +120 -0
- package/commands/ll-morph.md +117 -0
- package/commands/ll-multi-agent.md +170 -0
- package/commands/ll-native.md +93 -0
- package/commands/ll-nexa.md +79 -0
- package/commands/ll-onboarding.md +84 -0
- package/commands/ll-openhands.md +78 -0
- package/commands/ll-organic-promote.md +260 -0
- package/commands/ll-parallel.md +74 -0
- package/commands/ll-payments.md +83 -0
- package/commands/ll-perf-trace.md +147 -0
- package/commands/ll-perf.md +65 -0
- package/commands/ll-persona.md +280 -0
- package/commands/ll-pipe.md +296 -0
- package/commands/ll-plan-impl.js +570 -0
- package/commands/ll-plan-v2.md +297 -0
- package/commands/ll-plan.md +87 -0
- package/commands/ll-postlaunch.md +109 -0
- package/commands/ll-pr.md +84 -0
- package/commands/ll-present.md +110 -0
- package/commands/ll-product-map.md +152 -0
- package/commands/ll-promote.md +352 -0
- package/commands/ll-publish.md +124 -0
- package/commands/ll-pulse.md +96 -0
- package/commands/ll-rag-guided.md +345 -0
- package/commands/ll-rag-upgrade.md +504 -0
- package/commands/ll-rag.md +343 -0
- package/commands/ll-record.md +114 -0
- package/commands/ll-refactor.md +71 -0
- package/commands/ll-requirements.md +71 -0
- package/commands/ll-review.md +92 -0
- package/commands/ll-rollback.md +66 -0
- package/commands/ll-routemap.md +79 -0
- package/commands/ll-rules.md +90 -0
- package/commands/ll-shortcuts.md +229 -0
- package/commands/ll-sing.md +99 -0
- package/commands/ll-site-audit.md +228 -0
- package/commands/ll-smart-route.md +92 -0
- package/commands/ll-smart-search.md +58 -0
- package/commands/ll-storybook.md +86 -0
- package/commands/ll-swarm.md +101 -0
- package/commands/ll-test.md +97 -0
- package/commands/ll-time-machine.md +72 -0
- package/commands/ll-ui-convert.md +433 -0
- package/commands/ll-video.md +108 -0
- package/commands/ll-vision-pipeline.md +247 -0
- package/commands/ll-vision.md +74 -0
- package/commands/ll-visual-diff.md +118 -0
- package/commands/ll-visual-qa.md +204 -0
- package/commands/ll-visual-regression.md +96 -0
- package/commands/ll-voice.md +138 -0
- package/commands/ll-watch.md +65 -0
- package/commands/ll-workflow.md +108 -0
- package/commands/ll-zen.md +98 -0
- package/commands/local-llm.md +12 -0
- package/commands/marketplace.md +13 -0
- package/commands/mcp-publish.md +16 -0
- package/commands/migrate.md +12 -0
- package/commands/money.md +12 -0
- package/commands/morph.md +12 -0
- package/commands/multi-agent.md +12 -0
- package/commands/native.md +12 -0
- package/commands/nexa.md +12 -0
- package/commands/oh.md +12 -0
- package/commands/organic-promote.md +16 -0
- package/commands/perf-trace.md +12 -0
- package/commands/perf.md +12 -0
- package/commands/persona.md +12 -0
- package/commands/pipe.md +21 -0
- package/commands/plan.md +38 -0
- package/commands/pr.md +12 -0
- package/commands/present.md +12 -0
- package/commands/product-map.md +13 -0
- package/commands/promote.md +16 -0
- package/commands/publish.md +12 -0
- package/commands/pulse.md +12 -0
- package/commands/q.md +35 -0
- package/commands/record.md +12 -0
- package/commands/refactor.md +12 -0
- package/commands/req.md +40 -0
- package/commands/retro.md +33 -0
- package/commands/rev.md +39 -0
- package/commands/rules.md +19 -0
- package/commands/search.md +12 -0
- package/commands/sec.md +34 -0
- package/commands/ship.md +39 -0
- package/commands/sing.md +12 -0
- package/commands/site-audit.md +12 -0
- package/commands/smart-route.md +13 -0
- package/commands/swarm.md +12 -0
- package/commands/test.md +39 -0
- package/commands/time-machine.md +12 -0
- package/commands/ui.md +33 -0
- package/commands/video.md +12 -0
- package/commands/vision.md +12 -0
- package/commands/voice.md +12 -0
- package/commands/vr.md +18 -0
- package/commands/watch.md +39 -0
- package/commands/workflow.md +19 -0
- package/commands/zen.md +12 -0
- package/package.json +76 -0
- package/setup.sh +382 -0
|
@@ -0,0 +1,1733 @@
|
|
|
1
|
+
# Luna RAG - Retrieval-Augmented Generation Agent
|
|
2
|
+
|
|
3
|
+
## Role
|
|
4
|
+
You are an expert RAG (Retrieval-Augmented Generation) specialist with deep knowledge of context management, vector databases, token optimization, and intelligent content retrieval. Your task is to implement comprehensive RAG systems that provide AI agents with relevant context while optimizing for cost and performance.
|
|
5
|
+
|
|
6
|
+
## Initial Setup
|
|
7
|
+
|
|
8
|
+
### Project Analysis
|
|
9
|
+
**IMPORTANT**: When this agent is invoked, it MUST first analyze the project:
|
|
10
|
+
|
|
11
|
+
```
|
|
12
|
+
🧠 Luna RAG - Context Intelligence System
|
|
13
|
+
|
|
14
|
+
Analyzing project structure for RAG implementation...
|
|
15
|
+
Detected: [Project Type]
|
|
16
|
+
Codebase Size: [X files, Y lines of code]
|
|
17
|
+
Documentation: [Available/Not Available]
|
|
18
|
+
Existing Context: [Git history, README, docs/]
|
|
19
|
+
|
|
20
|
+
What would you like to do?
|
|
21
|
+
1. Complete RAG system setup (recommended)
|
|
22
|
+
2. Index project for intelligent context retrieval
|
|
23
|
+
3. Setup token optimization and budget management
|
|
24
|
+
4. Configure multi-provider AI integration
|
|
25
|
+
5. Migrate existing RAG to cloudflare deployment
|
|
26
|
+
|
|
27
|
+
Choice: _
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
### RAG Configuration
|
|
31
|
+
```
|
|
32
|
+
⚙️ RAG System Configuration
|
|
33
|
+
Select vector database:
|
|
34
|
+
1. Pinecone (managed, recommended)
|
|
35
|
+
2. Weaviate (self-hosted)
|
|
36
|
+
3. Qdrant (lightweight)
|
|
37
|
+
4. Chroma (local development)
|
|
38
|
+
|
|
39
|
+
Vector Database: _
|
|
40
|
+
|
|
41
|
+
Choose embedding model:
|
|
42
|
+
1. OpenAI text-embedding-3-small (fast, cost-effective)
|
|
43
|
+
2. OpenAI text-embedding-3-large (high quality)
|
|
44
|
+
3. Sentence Transformers (local, free)
|
|
45
|
+
4. Cohere embed-multilingual-v3.0 (multilingual)
|
|
46
|
+
|
|
47
|
+
Embedding Model: _
|
|
48
|
+
|
|
49
|
+
Token optimization strategy:
|
|
50
|
+
1. Maximum savings (aggressive compression)
|
|
51
|
+
2. Balanced (quality + savings)
|
|
52
|
+
3. Quality优先 (minimal compression)
|
|
53
|
+
4. Custom strategy
|
|
54
|
+
|
|
55
|
+
Strategy: _
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
## Workflow
|
|
59
|
+
|
|
60
|
+
### Phase 1: Context Extraction and Analysis
|
|
61
|
+
|
|
62
|
+
**Project Indexing System**:
|
|
63
|
+
```javascript
|
|
64
|
+
// lib/context-extractor.js
|
|
65
|
+
import fs from 'fs';
|
|
66
|
+
import path from 'path';
|
|
67
|
+
import { parse } from 'recast';
|
|
68
|
+
import * as babelParser from '@babel/parser';
|
|
69
|
+
import * as typescriptParser from '@typescript-eslint/typescript-estree';
|
|
70
|
+
|
|
71
|
+
export class ContextExtractor {
|
|
72
|
+
constructor(projectPath, config = {}) {
|
|
73
|
+
this.projectPath = projectPath;
|
|
74
|
+
this.config = {
|
|
75
|
+
includePatterns: config.includePatterns || ['**/*.{js,ts,jsx,tsx,py,java,go,rs}'],
|
|
76
|
+
excludePatterns: config.excludePatterns || ['node_modules/**', 'dist/**', 'build/**'],
|
|
77
|
+
maxFileSize: config.maxFileSize || 1024 * 1024, // 1MB
|
|
78
|
+
chunkSize: config.chunkSize || 1000,
|
|
79
|
+
overlap: config.overlap || 100,
|
|
80
|
+
...config
|
|
81
|
+
};
|
|
82
|
+
this.contexts = [];
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
async extractContexts() {
|
|
86
|
+
console.log('🔍 Extracting contexts from project...');
|
|
87
|
+
|
|
88
|
+
const files = await this.getProjectFiles();
|
|
89
|
+
console.log(`📁 Found ${files.length} files to process`);
|
|
90
|
+
|
|
91
|
+
for (const filePath of files) {
|
|
92
|
+
try {
|
|
93
|
+
const contexts = await this.extractFromFile(filePath);
|
|
94
|
+
this.contexts.push(...contexts);
|
|
95
|
+
} catch (error) {
|
|
96
|
+
console.warn(`⚠️ Failed to extract from ${filePath}: ${error.message}`);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
console.log(`✅ Extracted ${this.contexts.length} context chunks`);
|
|
101
|
+
return this.contexts;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
async getProjectFiles() {
|
|
105
|
+
const files = [];
|
|
106
|
+
|
|
107
|
+
const walkDir = (dir, basePath = '') => {
|
|
108
|
+
const items = fs.readdirSync(dir);
|
|
109
|
+
|
|
110
|
+
for (const item of items) {
|
|
111
|
+
const fullPath = path.join(dir, item);
|
|
112
|
+
const relativePath = path.join(basePath, item);
|
|
113
|
+
const stat = fs.statSync(fullPath);
|
|
114
|
+
|
|
115
|
+
if (stat.isDirectory()) {
|
|
116
|
+
// Skip excluded directories
|
|
117
|
+
if (!this.matchesExcludePatterns(relativePath)) {
|
|
118
|
+
walkDir(fullPath, relativePath);
|
|
119
|
+
}
|
|
120
|
+
} else if (stat.isFile()) {
|
|
121
|
+
// Check if file matches include patterns and size limit
|
|
122
|
+
if (this.matchesIncludePatterns(relativePath) && stat.size <= this.config.maxFileSize) {
|
|
123
|
+
files.push({
|
|
124
|
+
path: relativePath,
|
|
125
|
+
fullPath,
|
|
126
|
+
size: stat.size,
|
|
127
|
+
lastModified: stat.mtime
|
|
128
|
+
});
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
};
|
|
133
|
+
|
|
134
|
+
walkDir(this.projectPath);
|
|
135
|
+
return files;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
matchesIncludePatterns(filePath) {
|
|
139
|
+
return this.config.includePatterns.some(pattern =>
|
|
140
|
+
this.matchPattern(filePath, pattern)
|
|
141
|
+
);
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
matchesExcludePatterns(filePath) {
|
|
145
|
+
return this.config.excludePatterns.some(pattern =>
|
|
146
|
+
this.matchPattern(filePath, pattern)
|
|
147
|
+
);
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
matchPattern(filePath, pattern) {
|
|
151
|
+
// Convert glob pattern to regex
|
|
152
|
+
const regexPattern = pattern
|
|
153
|
+
.replace(/\*\*/g, '.*')
|
|
154
|
+
.replace(/\?/g, '.')
|
|
155
|
+
.replace(/\./g, '\\.');
|
|
156
|
+
|
|
157
|
+
const regex = new RegExp(`^${regexPattern}$`);
|
|
158
|
+
return regex.test(filePath);
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
async extractFromFile(filePath) {
|
|
162
|
+
const content = fs.readFileSync(filePath.fullPath, 'utf-8');
|
|
163
|
+
const extension = path.extname(filePath.path);
|
|
164
|
+
const language = this.detectLanguage(extension);
|
|
165
|
+
|
|
166
|
+
const contexts = [{
|
|
167
|
+
id: this.generateContextId(filePath.path, 0),
|
|
168
|
+
filePath: filePath.path,
|
|
169
|
+
content: content,
|
|
170
|
+
language,
|
|
171
|
+
type: 'file',
|
|
172
|
+
metadata: {
|
|
173
|
+
size: filePath.size,
|
|
174
|
+
lastModified: filePath.lastModified,
|
|
175
|
+
lines: content.split('\n').length
|
|
176
|
+
}
|
|
177
|
+
}];
|
|
178
|
+
|
|
179
|
+
// Extract code-specific contexts
|
|
180
|
+
if (['.js', '.jsx', '.ts', '.tsx'].includes(extension)) {
|
|
181
|
+
contexts.push(...await this.extractFromCode(content, filePath.path, language));
|
|
182
|
+
} else if (['.py'].includes(extension)) {
|
|
183
|
+
contexts.push(...await this.extractFromPython(content, filePath.path, language));
|
|
184
|
+
} else if (['.md', '.rst'].includes(extension)) {
|
|
185
|
+
contexts.push(...await this.extractFromDocumentation(content, filePath.path, language));
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
// Chunk large content
|
|
189
|
+
return this.chunkContexts(contexts);
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
async extractFromCode(content, filePath, language) {
|
|
193
|
+
const contexts = [];
|
|
194
|
+
|
|
195
|
+
try {
|
|
196
|
+
const ast = this.parseCode(content, language);
|
|
197
|
+
|
|
198
|
+
// Extract functions/classes
|
|
199
|
+
this.extractFunctions(ast, contexts, filePath, language);
|
|
200
|
+
this.extractClasses(ast, contexts, filePath, language);
|
|
201
|
+
this.extractComments(ast, contexts, filePath, language);
|
|
202
|
+
|
|
203
|
+
} catch (error) {
|
|
204
|
+
console.warn(`Failed to parse ${filePath}: ${error.message}`);
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
return contexts;
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
parseCode(content, language) {
|
|
211
|
+
if (language.includes('TypeScript') || language.includes('JavaScript')) {
|
|
212
|
+
return parse(content, {
|
|
213
|
+
parser: {
|
|
214
|
+
parse: (source) => {
|
|
215
|
+
if (language.includes('TypeScript')) {
|
|
216
|
+
return babelParser.parse(source, {
|
|
217
|
+
sourceType: 'module',
|
|
218
|
+
plugins: ['typescript', 'jsx']
|
|
219
|
+
});
|
|
220
|
+
} else {
|
|
221
|
+
return babelParser.parse(source, {
|
|
222
|
+
sourceType: 'module',
|
|
223
|
+
plugins: ['jsx']
|
|
224
|
+
});
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
});
|
|
229
|
+
}
|
|
230
|
+
// Add parsers for other languages as needed
|
|
231
|
+
return null;
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
extractFunctions(ast, contexts, filePath, language) {
|
|
235
|
+
if (!ast) return;
|
|
236
|
+
|
|
237
|
+
// Traverse AST to find functions
|
|
238
|
+
const traverse = require('@babel/traverse').default;
|
|
239
|
+
|
|
240
|
+
traverse(ast, {
|
|
241
|
+
FunctionDeclaration: (path) => {
|
|
242
|
+
const node = path.node;
|
|
243
|
+
contexts.push({
|
|
244
|
+
id: this.generateContextId(filePath, `function_${node.id?.name}`),
|
|
245
|
+
filePath,
|
|
246
|
+
content: this.getSourceCode(path),
|
|
247
|
+
language,
|
|
248
|
+
type: 'function',
|
|
249
|
+
name: node.id?.name || 'anonymous',
|
|
250
|
+
metadata: {
|
|
251
|
+
lineStart: node.loc?.start.line,
|
|
252
|
+
lineEnd: node.loc?.end.line,
|
|
253
|
+
parameters: node.params.length,
|
|
254
|
+
isAsync: node.async,
|
|
255
|
+
isGenerator: node.generator
|
|
256
|
+
}
|
|
257
|
+
});
|
|
258
|
+
},
|
|
259
|
+
|
|
260
|
+
ArrowFunctionExpression: (path) => {
|
|
261
|
+
const parent = path.parent;
|
|
262
|
+
let name = 'arrow_function';
|
|
263
|
+
|
|
264
|
+
if (parent.type === 'VariableDeclarator' && parent.id.name) {
|
|
265
|
+
name = parent.id.name;
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
contexts.push({
|
|
269
|
+
id: this.generateContextId(filePath, `arrow_${name}`),
|
|
270
|
+
filePath,
|
|
271
|
+
content: this.getSourceCode(path),
|
|
272
|
+
language,
|
|
273
|
+
type: 'arrow_function',
|
|
274
|
+
name,
|
|
275
|
+
metadata: {
|
|
276
|
+
lineStart: path.node.loc?.start.line,
|
|
277
|
+
lineEnd: path.node.loc?.end.line,
|
|
278
|
+
isAsync: path.node.async
|
|
279
|
+
}
|
|
280
|
+
});
|
|
281
|
+
}
|
|
282
|
+
});
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
extractClasses(ast, contexts, filePath, language) {
|
|
286
|
+
if (!ast) return;
|
|
287
|
+
|
|
288
|
+
const traverse = require('@babel/traverse').default;
|
|
289
|
+
|
|
290
|
+
traverse(ast, {
|
|
291
|
+
ClassDeclaration: (path) => {
|
|
292
|
+
const node = path.node;
|
|
293
|
+
const methods = [];
|
|
294
|
+
const properties = [];
|
|
295
|
+
|
|
296
|
+
// Extract methods and properties
|
|
297
|
+
node.body.body.forEach(member => {
|
|
298
|
+
if (member.type === 'MethodDefinition') {
|
|
299
|
+
methods.push({
|
|
300
|
+
name: member.key.name,
|
|
301
|
+
kind: member.kind,
|
|
302
|
+
static: member.static,
|
|
303
|
+
line: member.loc?.start.line
|
|
304
|
+
});
|
|
305
|
+
} else if (member.type === 'ClassProperty') {
|
|
306
|
+
properties.push({
|
|
307
|
+
name: member.key.name,
|
|
308
|
+
static: member.static,
|
|
309
|
+
line: member.loc?.start.line
|
|
310
|
+
});
|
|
311
|
+
}
|
|
312
|
+
});
|
|
313
|
+
|
|
314
|
+
contexts.push({
|
|
315
|
+
id: this.generateContextId(filePath, `class_${node.id?.name}`),
|
|
316
|
+
filePath,
|
|
317
|
+
content: this.getSourceCode(path),
|
|
318
|
+
language,
|
|
319
|
+
type: 'class',
|
|
320
|
+
name: node.id?.name || 'anonymous',
|
|
321
|
+
metadata: {
|
|
322
|
+
lineStart: node.loc?.start.line,
|
|
323
|
+
lineEnd: node.loc?.end.line,
|
|
324
|
+
methods,
|
|
325
|
+
properties,
|
|
326
|
+
superClass: node.superClass?.name
|
|
327
|
+
}
|
|
328
|
+
});
|
|
329
|
+
}
|
|
330
|
+
});
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
extractComments(ast, contexts, filePath, language) {
|
|
334
|
+
if (!ast) return;
|
|
335
|
+
|
|
336
|
+
// Extract comments from AST
|
|
337
|
+
ast.comments?.forEach((comment, index) => {
|
|
338
|
+
if (comment.value.trim().length > 10) { // Skip short comments
|
|
339
|
+
contexts.push({
|
|
340
|
+
id: this.generateContextId(filePath, `comment_${index}`),
|
|
341
|
+
filePath,
|
|
342
|
+
content: comment.value.trim(),
|
|
343
|
+
language,
|
|
344
|
+
type: 'comment',
|
|
345
|
+
metadata: {
|
|
346
|
+
lineStart: comment.loc?.start.line,
|
|
347
|
+
lineEnd: comment.loc?.end.line,
|
|
348
|
+
type: comment.type // 'CommentLine' or 'CommentBlock'
|
|
349
|
+
}
|
|
350
|
+
});
|
|
351
|
+
}
|
|
352
|
+
});
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
async extractFromPython(content, filePath, language) {
|
|
356
|
+
// Python-specific extraction logic
|
|
357
|
+
const contexts = [];
|
|
358
|
+
|
|
359
|
+
// Simple regex-based extraction for now
|
|
360
|
+
const functionRegex = /def\s+(\w+)\s*\([^)]*\):/g;
|
|
361
|
+
let match;
|
|
362
|
+
|
|
363
|
+
while ((match = functionRegex.exec(content)) !== null) {
|
|
364
|
+
const startPos = match.index;
|
|
365
|
+
const lines = content.substring(0, startPos).split('\n');
|
|
366
|
+
const lineStart = lines.length;
|
|
367
|
+
|
|
368
|
+
contexts.push({
|
|
369
|
+
id: this.generateContextId(filePath, `function_${match[1]}`),
|
|
370
|
+
filePath,
|
|
371
|
+
content: match[0],
|
|
372
|
+
language,
|
|
373
|
+
type: 'function',
|
|
374
|
+
name: match[1],
|
|
375
|
+
metadata: {
|
|
376
|
+
lineStart
|
|
377
|
+
}
|
|
378
|
+
});
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
return contexts;
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
async extractFromDocumentation(content, filePath, language) {
|
|
385
|
+
const contexts = [];
|
|
386
|
+
|
|
387
|
+
// Split documentation into sections
|
|
388
|
+
const sections = content.split(/^#{1,3}\s+/gm);
|
|
389
|
+
|
|
390
|
+
sections.forEach((section, index) => {
|
|
391
|
+
if (section.trim().length > 50) { // Skip very short sections
|
|
392
|
+
contexts.push({
|
|
393
|
+
id: this.generateContextId(filePath, `section_${index}`),
|
|
394
|
+
filePath,
|
|
395
|
+
content: section.trim(),
|
|
396
|
+
language,
|
|
397
|
+
type: 'documentation_section',
|
|
398
|
+
metadata: {
|
|
399
|
+
sectionIndex: index,
|
|
400
|
+
wordCount: section.split(/\s+/).length
|
|
401
|
+
}
|
|
402
|
+
});
|
|
403
|
+
}
|
|
404
|
+
});
|
|
405
|
+
|
|
406
|
+
return contexts;
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
chunkContexts(contexts) {
|
|
410
|
+
const chunked = [];
|
|
411
|
+
|
|
412
|
+
for (const context of contexts) {
|
|
413
|
+
if (context.content.length <= this.config.chunkSize) {
|
|
414
|
+
chunked.push(context);
|
|
415
|
+
} else {
|
|
416
|
+
// Split large content into chunks
|
|
417
|
+
const chunks = this.splitIntoChunks(context.content);
|
|
418
|
+
chunks.forEach((chunk, index) => {
|
|
419
|
+
chunked.push({
|
|
420
|
+
...context,
|
|
421
|
+
id: `${context.id}_chunk_${index}`,
|
|
422
|
+
content: chunk,
|
|
423
|
+
type: `${context.type}_chunk`,
|
|
424
|
+
metadata: {
|
|
425
|
+
...context.metadata,
|
|
426
|
+
chunkIndex: index,
|
|
427
|
+
totalChunks: chunks.length
|
|
428
|
+
}
|
|
429
|
+
});
|
|
430
|
+
});
|
|
431
|
+
}
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
return chunked;
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
splitIntoChunks(content) {
|
|
438
|
+
const chunks = [];
|
|
439
|
+
const words = content.split(/\s+/);
|
|
440
|
+
|
|
441
|
+
for (let i = 0; i < words.length; i += this.config.chunkSize - this.config.overlap) {
|
|
442
|
+
const chunk = words.slice(i, i + this.config.chunkSize).join(' ');
|
|
443
|
+
chunks.push(chunk);
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
return chunks;
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
detectLanguage(extension) {
|
|
450
|
+
const languageMap = {
|
|
451
|
+
'.js': 'JavaScript',
|
|
452
|
+
'.jsx': 'JavaScript (React)',
|
|
453
|
+
'.ts': 'TypeScript',
|
|
454
|
+
'.tsx': 'TypeScript (React)',
|
|
455
|
+
'.py': 'Python',
|
|
456
|
+
'.java': 'Java',
|
|
457
|
+
'.go': 'Go',
|
|
458
|
+
'.rs': 'Rust',
|
|
459
|
+
'.cpp': 'C++',
|
|
460
|
+
'.c': 'C',
|
|
461
|
+
'.cs': 'C#',
|
|
462
|
+
'.php': 'PHP',
|
|
463
|
+
'.rb': 'Ruby',
|
|
464
|
+
'.swift': 'Swift',
|
|
465
|
+
'.kt': 'Kotlin',
|
|
466
|
+
'.scala': 'Scala',
|
|
467
|
+
'.md': 'Markdown',
|
|
468
|
+
'.rst': 'reStructuredText',
|
|
469
|
+
'.txt': 'Plain Text',
|
|
470
|
+
'.json': 'JSON',
|
|
471
|
+
'.yaml': 'YAML',
|
|
472
|
+
'.yml': 'YAML',
|
|
473
|
+
'.xml': 'XML',
|
|
474
|
+
'.sql': 'SQL',
|
|
475
|
+
'.sh': 'Shell',
|
|
476
|
+
'.bash': 'Bash',
|
|
477
|
+
'.html': 'HTML',
|
|
478
|
+
'.css': 'CSS',
|
|
479
|
+
'.scss': 'SCSS'
|
|
480
|
+
};
|
|
481
|
+
|
|
482
|
+
return languageMap[extension] || 'Unknown';
|
|
483
|
+
}
|
|
484
|
+
|
|
485
|
+
generateContextId(filePath, identifier) {
|
|
486
|
+
const hash = require('crypto')
|
|
487
|
+
.createHash('md5')
|
|
488
|
+
.update(`${filePath}:${identifier}`)
|
|
489
|
+
.digest('hex');
|
|
490
|
+
return `ctx_${hash}`;
|
|
491
|
+
}
|
|
492
|
+
|
|
493
|
+
getSourceCode(path) {
|
|
494
|
+
// Extract source code from AST path
|
|
495
|
+
if (path.hub.file.code) {
|
|
496
|
+
return path.hub.file.code.slice(path.node.start, path.node.end);
|
|
497
|
+
}
|
|
498
|
+
return '';
|
|
499
|
+
}
|
|
500
|
+
}
|
|
501
|
+
```
|
|
502
|
+
|
|
503
|
+
### Phase 2: Vector Database Integration
|
|
504
|
+
|
|
505
|
+
**Vector Store Management**:
|
|
506
|
+
```javascript
|
|
507
|
+
// lib/vector-store.js
|
|
508
|
+
import { PineconeClient } from '@pinecone-database/pinecone';
|
|
509
|
+
import { WeaviateClient } from 'weaviate-ts-client';
|
|
510
|
+
import { QdrantClient } from 'qdrant-js';
|
|
511
|
+
import { ChromaClient } from 'chromadb';
|
|
512
|
+
|
|
513
|
+
export class VectorStoreManager {
|
|
514
|
+
constructor(config) {
|
|
515
|
+
this.config = config;
|
|
516
|
+
this.client = null;
|
|
517
|
+
this.indexName = config.indexName || 'rag-contexts';
|
|
518
|
+
}
|
|
519
|
+
|
|
520
|
+
async initialize() {
|
|
521
|
+
switch (this.config.provider) {
|
|
522
|
+
case 'pinecone':
|
|
523
|
+
await this.initializePinecone();
|
|
524
|
+
break;
|
|
525
|
+
case 'weaviate':
|
|
526
|
+
await this.initializeWeaviate();
|
|
527
|
+
break;
|
|
528
|
+
case 'qdrant':
|
|
529
|
+
await this.initializeQdrant();
|
|
530
|
+
break;
|
|
531
|
+
case 'chroma':
|
|
532
|
+
await this.initializeChroma();
|
|
533
|
+
break;
|
|
534
|
+
default:
|
|
535
|
+
throw new Error(`Unsupported vector database: ${this.config.provider}`);
|
|
536
|
+
}
|
|
537
|
+
}
|
|
538
|
+
|
|
539
|
+
async initializePinecone() {
|
|
540
|
+
const pinecone = new PineconeClient();
|
|
541
|
+
await pinecone.init({
|
|
542
|
+
apiKey: this.config.apiKey,
|
|
543
|
+
environment: this.config.environment
|
|
544
|
+
});
|
|
545
|
+
|
|
546
|
+
this.client = pinecone;
|
|
547
|
+
|
|
548
|
+
// Create index if it doesn't exist
|
|
549
|
+
const indexes = await pinecone.listIndexes();
|
|
550
|
+
if (!indexes.includes(this.indexName)) {
|
|
551
|
+
await pinecone.createIndex({
|
|
552
|
+
createRequest: {
|
|
553
|
+
name: this.indexName,
|
|
554
|
+
dimension: this.config.dimension || 1536,
|
|
555
|
+
metric: this.config.metric || 'cosine'
|
|
556
|
+
}
|
|
557
|
+
});
|
|
558
|
+
}
|
|
559
|
+
|
|
560
|
+
this.index = pinecone.Index(this.indexName);
|
|
561
|
+
console.log(`✅ Pinecone initialized with index: ${this.indexName}`);
|
|
562
|
+
}
|
|
563
|
+
|
|
564
|
+
async initializeWeaviate() {
|
|
565
|
+
this.client = new WeaviateClient({
|
|
566
|
+
scheme: this.config.scheme || 'https',
|
|
567
|
+
host: this.config.host,
|
|
568
|
+
apiKey: this.config.apiKey
|
|
569
|
+
});
|
|
570
|
+
|
|
571
|
+
// Check if class exists, create if not
|
|
572
|
+
const classExists = await this.checkWeaviateClass(this.indexName);
|
|
573
|
+
if (!classExists) {
|
|
574
|
+
await this.createWeaviateClass();
|
|
575
|
+
}
|
|
576
|
+
|
|
577
|
+
console.log(`✅ Weaviate initialized with class: ${this.indexName}`);
|
|
578
|
+
}
|
|
579
|
+
|
|
580
|
+
async initializeQdrant() {
|
|
581
|
+
this.client = new QdrantClient({
|
|
582
|
+
url: this.config.url,
|
|
583
|
+
apiKey: this.config.apiKey
|
|
584
|
+
});
|
|
585
|
+
|
|
586
|
+
// Create collection if it doesn't exist
|
|
587
|
+
const collections = await this.client.listCollections();
|
|
588
|
+
if (!collections.collections.some(c => c.name === this.indexName)) {
|
|
589
|
+
await this.client.createCollection(this.indexName, {
|
|
590
|
+
vectors: {
|
|
591
|
+
size: this.config.dimension || 1536,
|
|
592
|
+
distance: this.config.metric || 'Cosine'
|
|
593
|
+
}
|
|
594
|
+
});
|
|
595
|
+
}
|
|
596
|
+
|
|
597
|
+
console.log(`✅ Qdrant initialized with collection: ${this.indexName}`);
|
|
598
|
+
}
|
|
599
|
+
|
|
600
|
+
async initializeChroma() {
|
|
601
|
+
this.client = new ChromaClient({
|
|
602
|
+
path: this.config.path || 'http://localhost:8000'
|
|
603
|
+
});
|
|
604
|
+
|
|
605
|
+
// Get or create collection
|
|
606
|
+
try {
|
|
607
|
+
this.collection = await this.client.getCollection({
|
|
608
|
+
name: this.indexName
|
|
609
|
+
});
|
|
610
|
+
} catch (error) {
|
|
611
|
+
this.collection = await this.client.createCollection({
|
|
612
|
+
name: this.indexName,
|
|
613
|
+
metadata: {
|
|
614
|
+
dimension: this.config.dimension || 1536
|
|
615
|
+
}
|
|
616
|
+
});
|
|
617
|
+
}
|
|
618
|
+
|
|
619
|
+
console.log(`✅ Chroma initialized with collection: ${this.indexName}`);
|
|
620
|
+
}
|
|
621
|
+
|
|
622
|
+
async indexContexts(contexts, embeddings) {
|
|
623
|
+
console.log(`📝 Indexing ${contexts.length} contexts...`);
|
|
624
|
+
|
|
625
|
+
switch (this.config.provider) {
|
|
626
|
+
case 'pinecone':
|
|
627
|
+
return await this.indexPinecone(contexts, embeddings);
|
|
628
|
+
case 'weaviate':
|
|
629
|
+
return await this.indexWeaviate(contexts, embeddings);
|
|
630
|
+
case 'qdrant':
|
|
631
|
+
return await this.indexQdrant(contexts, embeddings);
|
|
632
|
+
case 'chroma':
|
|
633
|
+
return await this.indexChroma(contexts, embeddings);
|
|
634
|
+
default:
|
|
635
|
+
throw new Error(`Unsupported vector database: ${this.config.provider}`);
|
|
636
|
+
}
|
|
637
|
+
}
|
|
638
|
+
|
|
639
|
+
async indexPinecone(contexts, embeddings) {
|
|
640
|
+
const vectors = contexts.map((context, index) => ({
|
|
641
|
+
id: context.id,
|
|
642
|
+
values: embeddings[index],
|
|
643
|
+
metadata: {
|
|
644
|
+
filePath: context.filePath,
|
|
645
|
+
content: context.content.substring(0, 1000), // Truncate for metadata
|
|
646
|
+
language: context.language,
|
|
647
|
+
type: context.type,
|
|
648
|
+
name: context.name,
|
|
649
|
+
...context.metadata
|
|
650
|
+
}
|
|
651
|
+
}));
|
|
652
|
+
|
|
653
|
+
// Batch upsert to Pinecone
|
|
654
|
+
const batchSize = 100;
|
|
655
|
+
for (let i = 0; i < vectors.length; i += batchSize) {
|
|
656
|
+
const batch = vectors.slice(i, i + batchSize);
|
|
657
|
+
await this.index.upsert({
|
|
658
|
+
upsertRequest: {
|
|
659
|
+
vectors: batch
|
|
660
|
+
}
|
|
661
|
+
});
|
|
662
|
+
}
|
|
663
|
+
|
|
664
|
+
console.log(`✅ Indexed ${vectors.length} contexts in Pinecone`);
|
|
665
|
+
}
|
|
666
|
+
|
|
667
|
+
async queryRelevantContexts(queryEmbedding, topK = 5, filter = {}) {
|
|
668
|
+
switch (this.config.provider) {
|
|
669
|
+
case 'pinecone':
|
|
670
|
+
return await this.queryPinecone(queryEmbedding, topK, filter);
|
|
671
|
+
case 'weaviate':
|
|
672
|
+
return await this.queryWeaviate(queryEmbedding, topK, filter);
|
|
673
|
+
case 'qdrant':
|
|
674
|
+
return await this.queryQdrant(queryEmbedding, topK, filter);
|
|
675
|
+
case 'chroma':
|
|
676
|
+
return await this.queryChroma(queryEmbedding, topK, filter);
|
|
677
|
+
default:
|
|
678
|
+
throw new Error(`Unsupported vector database: ${this.config.provider}`);
|
|
679
|
+
}
|
|
680
|
+
}
|
|
681
|
+
|
|
682
|
+
async queryPinecone(queryEmbedding, topK, filter) {
|
|
683
|
+
const queryResponse = await this.index.query({
|
|
684
|
+
queryRequest: {
|
|
685
|
+
vector: queryEmbedding,
|
|
686
|
+
topK,
|
|
687
|
+
includeMetadata: true,
|
|
688
|
+
includeValues: true,
|
|
689
|
+
filter
|
|
690
|
+
}
|
|
691
|
+
});
|
|
692
|
+
|
|
693
|
+
return queryResponse.matches.map(match => ({
|
|
694
|
+
id: match.id,
|
|
695
|
+
score: match.score,
|
|
696
|
+
content: match.metadata.content,
|
|
697
|
+
filePath: match.metadata.filePath,
|
|
698
|
+
language: match.metadata.language,
|
|
699
|
+
type: match.metadata.type,
|
|
700
|
+
name: match.metadata.name,
|
|
701
|
+
metadata: match.metadata
|
|
702
|
+
}));
|
|
703
|
+
}
|
|
704
|
+
|
|
705
|
+
async deleteContext(contextIds) {
|
|
706
|
+
switch (this.config.provider) {
|
|
707
|
+
case 'pinecone':
|
|
708
|
+
return await this.index.delete1({
|
|
709
|
+
ids: contextIds
|
|
710
|
+
});
|
|
711
|
+
case 'qdrant':
|
|
712
|
+
return await this.client.delete(this.indexName, {
|
|
713
|
+
points: contextIds.map(id => ({ id }))
|
|
714
|
+
});
|
|
715
|
+
case 'chroma':
|
|
716
|
+
return await this.collection.delete({
|
|
717
|
+
ids: contextIds
|
|
718
|
+
});
|
|
719
|
+
default:
|
|
720
|
+
console.warn('Delete not implemented for this provider');
|
|
721
|
+
}
|
|
722
|
+
}
|
|
723
|
+
|
|
724
|
+
async getStats() {
|
|
725
|
+
switch (this.config.provider) {
|
|
726
|
+
case 'pinecone':
|
|
727
|
+
const stats = await this.index.describeIndexStats();
|
|
728
|
+
return {
|
|
729
|
+
totalVectors: stats.totalVectorCount,
|
|
730
|
+
dimension: stats.dimension,
|
|
731
|
+
indexFullness: stats.indexFullness
|
|
732
|
+
};
|
|
733
|
+
case 'qdrant':
|
|
734
|
+
const info = await this.client.getCollection(this.indexName);
|
|
735
|
+
return {
|
|
736
|
+
totalVectors: info.pointsCount,
|
|
737
|
+
dimension: info.config.params.vectors.size,
|
|
738
|
+
status: info.status
|
|
739
|
+
};
|
|
740
|
+
default:
|
|
741
|
+
return {};
|
|
742
|
+
}
|
|
743
|
+
}
|
|
744
|
+
}
|
|
745
|
+
```
|
|
746
|
+
|
|
747
|
+
### Phase 3: Token Optimization Engine
|
|
748
|
+
|
|
749
|
+
**Advanced Token Optimization**:
|
|
750
|
+
```javascript
|
|
751
|
+
// lib/token-optimizer.js
|
|
752
|
+
import { encode } from 'gpt-3-encoder';
|
|
753
|
+
import TurndownService from 'turndown';
|
|
754
|
+
|
|
755
|
+
export class TokenOptimizer {
|
|
756
|
+
constructor(config = {}) {
|
|
757
|
+
this.config = {
|
|
758
|
+
targetTokens: config.targetTokens || 4000,
|
|
759
|
+
strategy: config.strategy || 'balanced',
|
|
760
|
+
model: config.model || 'gpt-3.5-turbo',
|
|
761
|
+
maxCompression: config.maxCompression || 0.7, // Max 70% compression
|
|
762
|
+
...config
|
|
763
|
+
};
|
|
764
|
+
this.turndownService = new TurndownService();
|
|
765
|
+
}
|
|
766
|
+
|
|
767
|
+
async optimizeContexts(contexts, query = '', additionalContext = '') {
|
|
768
|
+
console.log(`⚡ Optimizing ${contexts.length} contexts for tokens...`);
|
|
769
|
+
|
|
770
|
+
// Calculate initial token count
|
|
771
|
+
const initialTokens = this.countTokens(JSON.stringify(contexts));
|
|
772
|
+
console.log(`📊 Initial token count: ${initialTokens}`);
|
|
773
|
+
|
|
774
|
+
let optimizedContexts = [...contexts];
|
|
775
|
+
let currentTokens = initialTokens;
|
|
776
|
+
|
|
777
|
+
// Apply optimization strategies
|
|
778
|
+
while (currentTokens > this.config.targetTokens) {
|
|
779
|
+
const strategy = this.selectOptimizationStrategy(currentTokens, initialTokens);
|
|
780
|
+
const result = await this.applyStrategy(optimizedContexts, strategy, query, additionalContext);
|
|
781
|
+
|
|
782
|
+
optimizedContexts = result.contexts;
|
|
783
|
+
currentTokens = result.tokens;
|
|
784
|
+
|
|
785
|
+
console.log(`🔄 Applied ${strategy}: ${result.tokens} tokens (${Math.round((result.tokens / initialTokens) * 100)}%)`);
|
|
786
|
+
|
|
787
|
+
// Prevent infinite loop
|
|
788
|
+
if (currentTokens >= initialTokens) {
|
|
789
|
+
console.warn('⚠️ Optimization failed to reduce tokens, breaking');
|
|
790
|
+
break;
|
|
791
|
+
}
|
|
792
|
+
}
|
|
793
|
+
|
|
794
|
+
const optimization = {
|
|
795
|
+
originalTokens: initialTokens,
|
|
796
|
+
optimizedTokens: currentTokens,
|
|
797
|
+
savings: initialTokens - currentTokens,
|
|
798
|
+
savingsPercentage: Math.round(((initialTokens - currentTokens) / initialTokens) * 100),
|
|
799
|
+
strategies: this.appliedStrategies || []
|
|
800
|
+
};
|
|
801
|
+
|
|
802
|
+
console.log(`✅ Optimization complete: ${optimization.savings} tokens saved (${optimization.savingsPercentage}%)`);
|
|
803
|
+
|
|
804
|
+
return {
|
|
805
|
+
contexts: optimizedContexts,
|
|
806
|
+
optimization
|
|
807
|
+
};
|
|
808
|
+
}
|
|
809
|
+
|
|
810
|
+
selectOptimizationStrategy(currentTokens, originalTokens) {
|
|
811
|
+
const compressionRatio = currentTokens / originalTokens;
|
|
812
|
+
|
|
813
|
+
if (compressionRatio > 0.8) {
|
|
814
|
+
return 'relevance_filtering'; // Remove low-relevance contexts
|
|
815
|
+
} else if (compressionRatio > 0.6) {
|
|
816
|
+
return 'content_compression'; // Compress content
|
|
817
|
+
} else if (compressionRatio > 0.4) {
|
|
818
|
+
return 'summarization'; // Summarize contexts
|
|
819
|
+
} else {
|
|
820
|
+
return 'chunk_merging'; // Merge similar chunks
|
|
821
|
+
}
|
|
822
|
+
}
|
|
823
|
+
|
|
824
|
+
async applyStrategy(contexts, strategy, query, additionalContext) {
|
|
825
|
+
this.appliedStrategies = this.appliedStrategies || [];
|
|
826
|
+
this.appliedStrategies.push(strategy);
|
|
827
|
+
|
|
828
|
+
switch (strategy) {
|
|
829
|
+
case 'relevance_filtering':
|
|
830
|
+
return await this.applyRelevanceFiltering(contexts, query);
|
|
831
|
+
case 'content_compression':
|
|
832
|
+
return await this.applyContentCompression(contexts);
|
|
833
|
+
case 'summarization':
|
|
834
|
+
return await this.applySummarization(contexts, query);
|
|
835
|
+
case 'chunk_merging':
|
|
836
|
+
return await this.applyChunkMerging(contexts);
|
|
837
|
+
case 'code_deduplication':
|
|
838
|
+
return await this.applyCodeDeduplication(contexts);
|
|
839
|
+
default:
|
|
840
|
+
return { contexts, tokens: this.countTokens(JSON.stringify(contexts)) };
|
|
841
|
+
}
|
|
842
|
+
}
|
|
843
|
+
|
|
844
|
+
async applyRelevanceFiltering(contexts, query) {
|
|
845
|
+
console.log('🎯 Applying relevance filtering...');
|
|
846
|
+
|
|
847
|
+
// Calculate relevance scores for each context
|
|
848
|
+
const scoredContexts = contexts.map(context => ({
|
|
849
|
+
...context,
|
|
850
|
+
relevanceScore: this.calculateRelevanceScore(context, query)
|
|
851
|
+
}));
|
|
852
|
+
|
|
853
|
+
// Sort by relevance score
|
|
854
|
+
scoredContexts.sort((a, b) => b.relevanceScore - a.relevanceScore);
|
|
855
|
+
|
|
856
|
+
// Keep only high-relevance contexts
|
|
857
|
+
const threshold = 0.3; // Keep contexts with 30%+ relevance
|
|
858
|
+
const filtered = scoredContexts.filter(ctx => ctx.relevanceScore >= threshold);
|
|
859
|
+
|
|
860
|
+
return {
|
|
861
|
+
contexts: filtered,
|
|
862
|
+
tokens: this.countTokens(JSON.stringify(filtered))
|
|
863
|
+
};
|
|
864
|
+
}
|
|
865
|
+
|
|
866
|
+
calculateRelevanceScore(context, query) {
|
|
867
|
+
const content = context.content.toLowerCase();
|
|
868
|
+
const queryTerms = query.toLowerCase().split(/\s+/);
|
|
869
|
+
|
|
870
|
+
let score = 0;
|
|
871
|
+
let totalTerms = queryTerms.length;
|
|
872
|
+
|
|
873
|
+
for (const term of queryTerms) {
|
|
874
|
+
if (content.includes(term)) {
|
|
875
|
+
score += 1;
|
|
876
|
+
|
|
877
|
+
// Boost score for exact phrase matches
|
|
878
|
+
if (content.includes(query.toLowerCase())) {
|
|
879
|
+
score += 0.5;
|
|
880
|
+
}
|
|
881
|
+
|
|
882
|
+
// Boost score for title/function/class names
|
|
883
|
+
if (context.name && context.name.toLowerCase().includes(term)) {
|
|
884
|
+
score += 0.3;
|
|
885
|
+
}
|
|
886
|
+
|
|
887
|
+
// Boost score for recent/important files
|
|
888
|
+
if (context.metadata?.lastModified) {
|
|
889
|
+
const daysSinceModified = (Date.now() - new Date(context.metadata.lastModified)) / (1000 * 60 * 60 * 24);
|
|
890
|
+
if (daysSinceModified < 7) {
|
|
891
|
+
score += 0.1; // Recent files
|
|
892
|
+
}
|
|
893
|
+
}
|
|
894
|
+
}
|
|
895
|
+
}
|
|
896
|
+
|
|
897
|
+
return Math.min(score / totalTerms, 1.0); // Normalize to 0-1
|
|
898
|
+
}
|
|
899
|
+
|
|
900
|
+
async applyContentCompression(contexts) {
|
|
901
|
+
console.log('🗜️ Applying content compression...');
|
|
902
|
+
|
|
903
|
+
const compressed = contexts.map(context => {
|
|
904
|
+
let compressedContent = context.content;
|
|
905
|
+
|
|
906
|
+
// Remove extra whitespace
|
|
907
|
+
compressedContent = compressedContent.replace(/\s+/g, ' ').trim();
|
|
908
|
+
|
|
909
|
+
// Remove comments (for code)
|
|
910
|
+
if (['JavaScript', 'TypeScript', 'Python', 'Java', 'Go'].includes(context.language)) {
|
|
911
|
+
compressedContent = this.removeCodeComments(compressedContent);
|
|
912
|
+
}
|
|
913
|
+
|
|
914
|
+
// Remove empty lines
|
|
915
|
+
compressedContent = compressedContent.replace(/\n\s*\n/g, '\n');
|
|
916
|
+
|
|
917
|
+
// Truncate very long content
|
|
918
|
+
const maxLength = 2000;
|
|
919
|
+
if (compressedContent.length > maxLength) {
|
|
920
|
+
compressedContent = compressedContent.substring(0, maxLength) + '...';
|
|
921
|
+
}
|
|
922
|
+
|
|
923
|
+
return {
|
|
924
|
+
...context,
|
|
925
|
+
content: compressedContent,
|
|
926
|
+
originalLength: context.content.length,
|
|
927
|
+
compressedLength: compressedContent.length
|
|
928
|
+
};
|
|
929
|
+
});
|
|
930
|
+
|
|
931
|
+
return {
|
|
932
|
+
contexts: compressed,
|
|
933
|
+
tokens: this.countTokens(JSON.stringify(compressed))
|
|
934
|
+
};
|
|
935
|
+
}
|
|
936
|
+
|
|
937
|
+
removeCodeComments(code) {
|
|
938
|
+
// Remove single-line comments
|
|
939
|
+
code = code.replace(/\/\/.*$/gm, '');
|
|
940
|
+
|
|
941
|
+
// Remove multi-line comments
|
|
942
|
+
code = code.replace(/\/\*[\s\S]*?\*\//g, '');
|
|
943
|
+
|
|
944
|
+
// Remove Python comments
|
|
945
|
+
code = code.replace(/#.*$/gm, '');
|
|
946
|
+
|
|
947
|
+
return code.trim();
|
|
948
|
+
}
|
|
949
|
+
|
|
950
|
+
async applySummarization(contexts, query) {
|
|
951
|
+
console.log('📝 Applying content summarization...');
|
|
952
|
+
|
|
953
|
+
// For now, implement simple extraction-based summarization
|
|
954
|
+
// In production, this would use an LLM for actual summarization
|
|
955
|
+
const summarized = contexts.map(context => {
|
|
956
|
+
if (context.content.length > 500) {
|
|
957
|
+
// Extract key sentences (simple heuristic)
|
|
958
|
+
const sentences = context.content.split(/[.!?]+/);
|
|
959
|
+
const keySentences = sentences
|
|
960
|
+
.filter(s => s.trim().length > 20)
|
|
961
|
+
.slice(0, 3); // Keep first 3 meaningful sentences
|
|
962
|
+
|
|
963
|
+
return {
|
|
964
|
+
...context,
|
|
965
|
+
content: keySentences.join('. ') + '.',
|
|
966
|
+
summarized: true,
|
|
967
|
+
originalLength: context.content.length,
|
|
968
|
+
summarizedLength: keySentences.join('. ').length
|
|
969
|
+
};
|
|
970
|
+
}
|
|
971
|
+
|
|
972
|
+
return context;
|
|
973
|
+
});
|
|
974
|
+
|
|
975
|
+
return {
|
|
976
|
+
contexts: summarized,
|
|
977
|
+
tokens: this.countTokens(JSON.stringify(summarized))
|
|
978
|
+
};
|
|
979
|
+
}
|
|
980
|
+
|
|
981
|
+
async applyChunkMerging(contexts) {
|
|
982
|
+
console.log('🔗 Applying chunk merging...');
|
|
983
|
+
|
|
984
|
+
// Group contexts by file path
|
|
985
|
+
const grouped = {};
|
|
986
|
+
contexts.forEach(context => {
|
|
987
|
+
if (!grouped[context.filePath]) {
|
|
988
|
+
grouped[context.filePath] = [];
|
|
989
|
+
}
|
|
990
|
+
grouped[context.filePath].push(context);
|
|
991
|
+
});
|
|
992
|
+
|
|
993
|
+
const merged = [];
|
|
994
|
+
|
|
995
|
+
for (const [filePath, fileContexts] of Object.entries(grouped)) {
|
|
996
|
+
if (fileContexts.length > 1) {
|
|
997
|
+
// Merge chunks from the same file
|
|
998
|
+
const sorted = fileContexts.sort((a, b) => {
|
|
999
|
+
const lineA = a.metadata?.lineStart || 0;
|
|
1000
|
+
const lineB = b.metadata?.lineStart || 0;
|
|
1001
|
+
return lineA - lineB;
|
|
1002
|
+
});
|
|
1003
|
+
|
|
1004
|
+
const mergedContent = sorted.map(ctx => ctx.content).join('\n...\n');
|
|
1005
|
+
|
|
1006
|
+
merged.push({
|
|
1007
|
+
id: `merged_${filePath}`,
|
|
1008
|
+
filePath,
|
|
1009
|
+
content: mergedContent,
|
|
1010
|
+
language: sorted[0].language,
|
|
1011
|
+
type: 'merged_chunks',
|
|
1012
|
+
metadata: {
|
|
1013
|
+
originalChunks: sorted.length,
|
|
1014
|
+
lineStart: Math.min(...sorted.map(c => c.metadata?.lineStart || 0)),
|
|
1015
|
+
lineEnd: Math.max(...sorted.map(c => c.metadata?.lineEnd || 0))
|
|
1016
|
+
}
|
|
1017
|
+
});
|
|
1018
|
+
} else {
|
|
1019
|
+
merged.push(fileContexts[0]);
|
|
1020
|
+
}
|
|
1021
|
+
}
|
|
1022
|
+
|
|
1023
|
+
return {
|
|
1024
|
+
contexts: merged,
|
|
1025
|
+
tokens: this.countTokens(JSON.stringify(merged))
|
|
1026
|
+
};
|
|
1027
|
+
}
|
|
1028
|
+
|
|
1029
|
+
async applyCodeDeduplication(contexts) {
|
|
1030
|
+
console.log('🔄 Applying code deduplication...');
|
|
1031
|
+
|
|
1032
|
+
// Group similar code contexts
|
|
1033
|
+
const deduplicated = [];
|
|
1034
|
+
const seen = new Set();
|
|
1035
|
+
|
|
1036
|
+
for (const context of contexts) {
|
|
1037
|
+
if (context.type === 'function' || context.type === 'class') {
|
|
1038
|
+
// Create a signature for deduplication
|
|
1039
|
+
const signature = this.createCodeSignature(context);
|
|
1040
|
+
|
|
1041
|
+
if (!seen.has(signature)) {
|
|
1042
|
+
seen.add(signature);
|
|
1043
|
+
deduplicated.push(context);
|
|
1044
|
+
}
|
|
1045
|
+
} else {
|
|
1046
|
+
deduplicated.push(context);
|
|
1047
|
+
}
|
|
1048
|
+
}
|
|
1049
|
+
|
|
1050
|
+
return {
|
|
1051
|
+
contexts: deduplicated,
|
|
1052
|
+
tokens: this.countTokens(JSON.stringify(deduplicated))
|
|
1053
|
+
};
|
|
1054
|
+
}
|
|
1055
|
+
|
|
1056
|
+
createCodeSignature(context) {
|
|
1057
|
+
// Create a normalized signature for code deduplication
|
|
1058
|
+
let signature = context.name || '';
|
|
1059
|
+
signature += `_${context.type}`;
|
|
1060
|
+
|
|
1061
|
+
// Add parameter count for functions
|
|
1062
|
+
if (context.metadata?.parameters !== undefined) {
|
|
1063
|
+
signature += `_${context.metadata.parameters}`;
|
|
1064
|
+
}
|
|
1065
|
+
|
|
1066
|
+
// Add method count for classes
|
|
1067
|
+
if (context.metadata?.methods) {
|
|
1068
|
+
signature += `_${context.metadata.methods.length}`;
|
|
1069
|
+
}
|
|
1070
|
+
|
|
1071
|
+
return signature.toLowerCase();
|
|
1072
|
+
}
|
|
1073
|
+
|
|
1074
|
+
countTokens(text) {
|
|
1075
|
+
try {
|
|
1076
|
+
return encode(text).length;
|
|
1077
|
+
} catch (error) {
|
|
1078
|
+
// Fallback estimation (roughly 4 characters per token)
|
|
1079
|
+
return Math.ceil(text.length / 4);
|
|
1080
|
+
}
|
|
1081
|
+
}
|
|
1082
|
+
|
|
1083
|
+
generateOptimizationReport(originalContexts, optimizedResult) {
|
|
1084
|
+
const report = {
|
|
1085
|
+
summary: {
|
|
1086
|
+
originalContexts: originalContexts.length,
|
|
1087
|
+
optimizedContexts: optimizedResult.contexts.length,
|
|
1088
|
+
originalTokens: optimizedResult.optimization.originalTokens,
|
|
1089
|
+
optimizedTokens: optimizedResult.optimization.optimizedTokens,
|
|
1090
|
+
tokensSaved: optimizedResult.optimization.savings,
|
|
1091
|
+
percentageSaved: optimizedResult.optimization.savingsPercentage,
|
|
1092
|
+
strategiesApplied: optimizedResult.optimization.strategies
|
|
1093
|
+
},
|
|
1094
|
+
contextBreakdown: optimizedResult.contexts.map(ctx => ({
|
|
1095
|
+
id: ctx.id,
|
|
1096
|
+
filePath: ctx.filePath,
|
|
1097
|
+
type: ctx.type,
|
|
1098
|
+
language: ctx.language,
|
|
1099
|
+
originalTokens: this.countTokens(ctx.content),
|
|
1100
|
+
compressed: ctx.compressed || false,
|
|
1101
|
+
summarized: ctx.summarized || false
|
|
1102
|
+
})),
|
|
1103
|
+
recommendations: this.generateRecommendations(optimizedResult)
|
|
1104
|
+
};
|
|
1105
|
+
|
|
1106
|
+
return report;
|
|
1107
|
+
}
|
|
1108
|
+
|
|
1109
|
+
generateRecommendations(result) {
|
|
1110
|
+
const recommendations = [];
|
|
1111
|
+
|
|
1112
|
+
if (result.optimization.savingsPercentage < 20) {
|
|
1113
|
+
recommendations.push('Consider increasing target token limit for better context retention');
|
|
1114
|
+
}
|
|
1115
|
+
|
|
1116
|
+
if (result.optimization.strategies.includes('summarization')) {
|
|
1117
|
+
recommendations.push('Some content was summarized. Consider reviewing summarized contexts for accuracy');
|
|
1118
|
+
}
|
|
1119
|
+
|
|
1120
|
+
if (result.optimization.strategies.length > 3) {
|
|
1121
|
+
recommendations.push('Multiple optimization strategies were applied. Consider reviewing content quality');
|
|
1122
|
+
}
|
|
1123
|
+
|
|
1124
|
+
return recommendations;
|
|
1125
|
+
}
|
|
1126
|
+
}
|
|
1127
|
+
```
|
|
1128
|
+
|
|
1129
|
+
### Phase 4: Multi-Provider AI Integration
|
|
1130
|
+
|
|
1131
|
+
**AI Provider Management**:
|
|
1132
|
+
```javascript
|
|
1133
|
+
// lib/ai-provider.js
|
|
1134
|
+
export class AIProviderManager {
|
|
1135
|
+
constructor(config) {
|
|
1136
|
+
this.config = config;
|
|
1137
|
+
this.providers = new Map();
|
|
1138
|
+
this.initializeProviders();
|
|
1139
|
+
}
|
|
1140
|
+
|
|
1141
|
+
initializeProviders() {
|
|
1142
|
+
// Initialize OpenAI
|
|
1143
|
+
if (this.config.openai) {
|
|
1144
|
+
this.providers.set('openai', new OpenAIProvider(this.config.openai));
|
|
1145
|
+
}
|
|
1146
|
+
|
|
1147
|
+
// Initialize Anthropic
|
|
1148
|
+
if (this.config.anthropic) {
|
|
1149
|
+
this.providers.set('anthropic', new AnthropicProvider(this.config.anthropic));
|
|
1150
|
+
}
|
|
1151
|
+
|
|
1152
|
+
// Initialize DeepSeek
|
|
1153
|
+
if (this.config.deepseek) {
|
|
1154
|
+
this.providers.set('deepseek', new DeepSeekProvider(this.config.deepseek));
|
|
1155
|
+
}
|
|
1156
|
+
|
|
1157
|
+
// Initialize Google
|
|
1158
|
+
if (this.config.google) {
|
|
1159
|
+
this.providers.set('google', new GoogleProvider(this.config.google));
|
|
1160
|
+
}
|
|
1161
|
+
}
|
|
1162
|
+
|
|
1163
|
+
async selectOptimalProvider(task, constraints = {}) {
|
|
1164
|
+
const availableProviders = Array.from(this.providers.keys());
|
|
1165
|
+
|
|
1166
|
+
// Filter providers based on constraints
|
|
1167
|
+
const suitableProviders = availableProviders.filter(provider => {
|
|
1168
|
+
const providerConfig = this.providers.get(provider).config;
|
|
1169
|
+
|
|
1170
|
+
// Check budget constraints
|
|
1171
|
+
if (constraints.maxCost && providerConfig.costPerToken > constraints.maxCost) {
|
|
1172
|
+
return false;
|
|
1173
|
+
}
|
|
1174
|
+
|
|
1175
|
+
// Check capability constraints
|
|
1176
|
+
if (constraints.capabilities) {
|
|
1177
|
+
const hasCapabilities = constraints.capabilities.every(cap =>
|
|
1178
|
+
providerConfig.capabilities.includes(cap)
|
|
1179
|
+
);
|
|
1180
|
+
if (!hasCapabilities) return false;
|
|
1181
|
+
}
|
|
1182
|
+
|
|
1183
|
+
return true;
|
|
1184
|
+
});
|
|
1185
|
+
|
|
1186
|
+
if (suitableProviders.length === 0) {
|
|
1187
|
+
throw new Error('No suitable providers found for given constraints');
|
|
1188
|
+
}
|
|
1189
|
+
|
|
1190
|
+
// Select provider based on optimization criteria
|
|
1191
|
+
return this.selectProviderByCriteria(suitableProviders, task, constraints);
|
|
1192
|
+
}
|
|
1193
|
+
|
|
1194
|
+
selectProviderByCriteria(providers, task, constraints) {
|
|
1195
|
+
let bestProvider = providers[0];
|
|
1196
|
+
let bestScore = 0;
|
|
1197
|
+
|
|
1198
|
+
for (const providerName of providers) {
|
|
1199
|
+
const provider = this.providers.get(providerName);
|
|
1200
|
+
const score = this.calculateProviderScore(provider, task, constraints);
|
|
1201
|
+
|
|
1202
|
+
if (score > bestScore) {
|
|
1203
|
+
bestScore = score;
|
|
1204
|
+
bestProvider = providerName;
|
|
1205
|
+
}
|
|
1206
|
+
}
|
|
1207
|
+
|
|
1208
|
+
return bestProvider;
|
|
1209
|
+
}
|
|
1210
|
+
|
|
1211
|
+
calculateProviderScore(provider, task, constraints) {
|
|
1212
|
+
let score = 0;
|
|
1213
|
+
|
|
1214
|
+
// Cost score (lower cost = higher score)
|
|
1215
|
+
const costScore = 100 - (provider.config.costPerToken * 1000);
|
|
1216
|
+
score += costScore * 0.3;
|
|
1217
|
+
|
|
1218
|
+
// Performance score (latency)
|
|
1219
|
+
const latencyScore = 100 - (provider.config.averageLatency / 10);
|
|
1220
|
+
score += latencyScore * 0.2;
|
|
1221
|
+
|
|
1222
|
+
// Quality score
|
|
1223
|
+
score += provider.config.qualityScore * 0.3;
|
|
1224
|
+
|
|
1225
|
+
// Task-specific score
|
|
1226
|
+
if (task.type && provider.config.taskScores[task.type]) {
|
|
1227
|
+
score += provider.config.taskScores[task.type] * 0.2;
|
|
1228
|
+
}
|
|
1229
|
+
|
|
1230
|
+
return score;
|
|
1231
|
+
}
|
|
1232
|
+
|
|
1233
|
+
async generateEmbeddings(texts, provider = null) {
|
|
1234
|
+
const selectedProvider = provider || await this.selectOptimalProvider({
|
|
1235
|
+
type: 'embedding'
|
|
1236
|
+
}, {
|
|
1237
|
+
capabilities: ['embedding']
|
|
1238
|
+
});
|
|
1239
|
+
|
|
1240
|
+
return await this.providers.get(selectedProvider).generateEmbeddings(texts);
|
|
1241
|
+
}
|
|
1242
|
+
|
|
1243
|
+
async generateCompletion(prompt, options = {}, provider = null) {
|
|
1244
|
+
const selectedProvider = provider || await this.selectOptimalProvider({
|
|
1245
|
+
type: 'completion',
|
|
1246
|
+
prompt
|
|
1247
|
+
}, options);
|
|
1248
|
+
|
|
1249
|
+
return await this.providers.get(selectedProvider).generateCompletion(prompt, options);
|
|
1250
|
+
}
|
|
1251
|
+
}
|
|
1252
|
+
|
|
1253
|
+
// OpenAI Provider
|
|
1254
|
+
class OpenAIProvider {
|
|
1255
|
+
constructor(config) {
|
|
1256
|
+
this.config = {
|
|
1257
|
+
apiKey: config.apiKey,
|
|
1258
|
+
model: config.model || 'gpt-3.5-turbo',
|
|
1259
|
+
costPerToken: 0.000002, // $0.002 per 1K tokens
|
|
1260
|
+
averageLatency: 1500, // ms
|
|
1261
|
+
qualityScore: 85,
|
|
1262
|
+
capabilities: ['completion', 'embedding', 'function-calling', 'vision'],
|
|
1263
|
+
taskScores: {
|
|
1264
|
+
'completion': 90,
|
|
1265
|
+
'embedding': 85,
|
|
1266
|
+
'code-generation': 88,
|
|
1267
|
+
'analysis': 87
|
|
1268
|
+
},
|
|
1269
|
+
...config
|
|
1270
|
+
};
|
|
1271
|
+
}
|
|
1272
|
+
|
|
1273
|
+
async generateEmbeddings(texts) {
|
|
1274
|
+
const OpenAI = require('openai');
|
|
1275
|
+
const openai = new OpenAI({ apiKey: this.config.apiKey });
|
|
1276
|
+
|
|
1277
|
+
const response = await openai.embeddings.create({
|
|
1278
|
+
model: 'text-embedding-3-small',
|
|
1279
|
+
input: texts
|
|
1280
|
+
});
|
|
1281
|
+
|
|
1282
|
+
return response.data.map(item => item.embedding);
|
|
1283
|
+
}
|
|
1284
|
+
|
|
1285
|
+
async generateCompletion(prompt, options = {}) {
|
|
1286
|
+
const OpenAI = require('openai');
|
|
1287
|
+
const openai = new OpenAI({ apiKey: this.config.apiKey });
|
|
1288
|
+
|
|
1289
|
+
const response = await openai.chat.completions.create({
|
|
1290
|
+
model: this.config.model,
|
|
1291
|
+
messages: [{ role: 'user', content: prompt }],
|
|
1292
|
+
max_tokens: options.maxTokens || 1000,
|
|
1293
|
+
temperature: options.temperature || 0.7,
|
|
1294
|
+
...options
|
|
1295
|
+
});
|
|
1296
|
+
|
|
1297
|
+
return {
|
|
1298
|
+
content: response.choices[0].message.content,
|
|
1299
|
+
usage: response.usage,
|
|
1300
|
+
model: this.config.model,
|
|
1301
|
+
provider: 'openai'
|
|
1302
|
+
};
|
|
1303
|
+
}
|
|
1304
|
+
}
|
|
1305
|
+
```
|
|
1306
|
+
|
|
1307
|
+
### Phase 5: Main RAG Service
|
|
1308
|
+
|
|
1309
|
+
**Luna RAG Service**:
|
|
1310
|
+
```javascript
|
|
1311
|
+
// lib/rag-service.js
|
|
1312
|
+
import { ContextExtractor } from './context-extractor.js';
|
|
1313
|
+
import { VectorStoreManager } from './vector-store.js';
|
|
1314
|
+
import { TokenOptimizer } from './token-optimizer.js';
|
|
1315
|
+
import { AIProviderManager } from './ai-provider.js';
|
|
1316
|
+
|
|
1317
|
+
export class LunaRAGService {
|
|
1318
|
+
constructor(config) {
|
|
1319
|
+
this.config = config;
|
|
1320
|
+
this.contextExtractor = new ContextExtractor(config.projectPath, config.extraction);
|
|
1321
|
+
this.vectorStore = new VectorStoreManager(config.vectorStore);
|
|
1322
|
+
this.tokenOptimizer = new TokenOptimizer(config.tokenOptimization);
|
|
1323
|
+
this.aiProvider = new AIProviderManager(config.aiProviders);
|
|
1324
|
+
this.isInitialized = false;
|
|
1325
|
+
}
|
|
1326
|
+
|
|
1327
|
+
async initialize() {
|
|
1328
|
+
console.log('🚀 Initializing Luna RAG Service...');
|
|
1329
|
+
|
|
1330
|
+
await this.vectorStore.initialize();
|
|
1331
|
+
await this.aiProvider.initializeProviders();
|
|
1332
|
+
|
|
1333
|
+
this.isInitialized = true;
|
|
1334
|
+
console.log('✅ Luna RAG Service initialized successfully');
|
|
1335
|
+
}
|
|
1336
|
+
|
|
1337
|
+
async indexProject(projectPath = null) {
|
|
1338
|
+
if (!this.isInitialized) {
|
|
1339
|
+
await this.initialize();
|
|
1340
|
+
}
|
|
1341
|
+
|
|
1342
|
+
const workingPath = projectPath || this.config.projectPath;
|
|
1343
|
+
console.log(`📚 Indexing project: ${workingPath}`);
|
|
1344
|
+
|
|
1345
|
+
// Extract contexts
|
|
1346
|
+
const contexts = await this.contextExtractor.extractContexts();
|
|
1347
|
+
|
|
1348
|
+
// Generate embeddings
|
|
1349
|
+
console.log('🔤 Generating embeddings...');
|
|
1350
|
+
const texts = contexts.map(ctx => ctx.content);
|
|
1351
|
+
const embeddings = await this.aiProvider.generateEmbeddings(texts);
|
|
1352
|
+
|
|
1353
|
+
// Index in vector store
|
|
1354
|
+
await this.vectorStore.indexContexts(contexts, embeddings);
|
|
1355
|
+
|
|
1356
|
+
// Generate index report
|
|
1357
|
+
const stats = await this.vectorStore.getStats();
|
|
1358
|
+
const report = {
|
|
1359
|
+
projectPath: workingPath,
|
|
1360
|
+
contextsIndexed: contexts.length,
|
|
1361
|
+
vectorStoreStats: stats,
|
|
1362
|
+
languages: this.getLanguageBreakdown(contexts),
|
|
1363
|
+
fileTypes: this.getFileTypeBreakdown(contexts),
|
|
1364
|
+
timestamp: new Date().toISOString()
|
|
1365
|
+
};
|
|
1366
|
+
|
|
1367
|
+
console.log(`✅ Project indexing complete`);
|
|
1368
|
+
return report;
|
|
1369
|
+
}
|
|
1370
|
+
|
|
1371
|
+
async queryContext(query, options = {}) {
|
|
1372
|
+
if (!this.isInitialized) {
|
|
1373
|
+
throw new Error('RAG service not initialized. Call initialize() first.');
|
|
1374
|
+
}
|
|
1375
|
+
|
|
1376
|
+
console.log(`🔍 Querying context for: "${query}"`);
|
|
1377
|
+
|
|
1378
|
+
// Generate query embedding
|
|
1379
|
+
const queryEmbedding = await this.aiProvider.generateEmbeddings([query]);
|
|
1380
|
+
|
|
1381
|
+
// Retrieve relevant contexts
|
|
1382
|
+
const relevantContexts = await this.vectorStore.queryRelevantContexts(
|
|
1383
|
+
queryEmbedding[0],
|
|
1384
|
+
options.topK || 10,
|
|
1385
|
+
options.filter
|
|
1386
|
+
);
|
|
1387
|
+
|
|
1388
|
+
console.log(`📊 Found ${relevantContexts.length} relevant contexts`);
|
|
1389
|
+
|
|
1390
|
+
// Optimize contexts for tokens
|
|
1391
|
+
const optimizedResult = await this.tokenOptimizer.optimizeContexts(
|
|
1392
|
+
relevantContexts,
|
|
1393
|
+
query,
|
|
1394
|
+
options.additionalContext
|
|
1395
|
+
);
|
|
1396
|
+
|
|
1397
|
+
// Generate optimization report
|
|
1398
|
+
const report = this.tokenOptimizer.generateOptimizationReport(
|
|
1399
|
+
relevantContexts,
|
|
1400
|
+
optimizedResult
|
|
1401
|
+
);
|
|
1402
|
+
|
|
1403
|
+
console.log(`⚡ Context optimization complete: ${report.summary.tokensSaved} tokens saved`);
|
|
1404
|
+
|
|
1405
|
+
return {
|
|
1406
|
+
query,
|
|
1407
|
+
originalContexts: relevantContexts,
|
|
1408
|
+
optimizedContexts: optimizedResult.contexts,
|
|
1409
|
+
optimization: report.summary,
|
|
1410
|
+
report
|
|
1411
|
+
};
|
|
1412
|
+
}
|
|
1413
|
+
|
|
1414
|
+
async generateEnhancedPrompt(query, options = {}) {
|
|
1415
|
+
const contextResult = await this.queryContext(query, options);
|
|
1416
|
+
|
|
1417
|
+
// Build enhanced prompt with context
|
|
1418
|
+
const contextText = contextResult.optimizedContexts
|
|
1419
|
+
.map(ctx => `File: ${ctx.filePath}\n${ctx.content}`)
|
|
1420
|
+
.join('\n\n---\n\n');
|
|
1421
|
+
|
|
1422
|
+
const enhancedPrompt = `
|
|
1423
|
+
CONTEXT:
|
|
1424
|
+
${contextText}
|
|
1425
|
+
|
|
1426
|
+
QUERY: ${query}
|
|
1427
|
+
|
|
1428
|
+
Please provide a comprehensive response based on the context provided above. If the context doesn't contain enough information, indicate what additional information might be helpful.
|
|
1429
|
+
`;
|
|
1430
|
+
|
|
1431
|
+
return {
|
|
1432
|
+
prompt: enhancedPrompt,
|
|
1433
|
+
contextResult,
|
|
1434
|
+
estimatedTokens: this.tokenOptimizer.countTokens(enhancedPrompt)
|
|
1435
|
+
};
|
|
1436
|
+
}
|
|
1437
|
+
|
|
1438
|
+
async chatWithContext(query, conversationHistory = [], options = {}) {
|
|
1439
|
+
const contextResult = await this.queryContext(query, options);
|
|
1440
|
+
|
|
1441
|
+
// Build messages for chat completion
|
|
1442
|
+
const messages = [
|
|
1443
|
+
{
|
|
1444
|
+
role: 'system',
|
|
1445
|
+
content: `You are a helpful AI assistant with access to relevant project context. Use the provided context to give accurate and helpful responses. Context information is up-to-date as of the last indexing.`
|
|
1446
|
+
},
|
|
1447
|
+
...conversationHistory,
|
|
1448
|
+
{
|
|
1449
|
+
role: 'system',
|
|
1450
|
+
content: `RELEVANT CONTEXT:\n${contextResult.optimizedContexts
|
|
1451
|
+
.map(ctx => `[${ctx.filePath}]: ${ctx.content}`)
|
|
1452
|
+
.join('\n\n')}`
|
|
1453
|
+
},
|
|
1454
|
+
{
|
|
1455
|
+
role: 'user',
|
|
1456
|
+
content: query
|
|
1457
|
+
}
|
|
1458
|
+
];
|
|
1459
|
+
|
|
1460
|
+
// Generate completion
|
|
1461
|
+
const completion = await this.aiProvider.generateCompletion(
|
|
1462
|
+
messages,
|
|
1463
|
+
{
|
|
1464
|
+
maxTokens: options.maxTokens || 1000,
|
|
1465
|
+
temperature: options.temperature || 0.7
|
|
1466
|
+
}
|
|
1467
|
+
);
|
|
1468
|
+
|
|
1469
|
+
return {
|
|
1470
|
+
response: completion.content,
|
|
1471
|
+
context: contextResult,
|
|
1472
|
+
usage: completion.usage,
|
|
1473
|
+
provider: completion.provider
|
|
1474
|
+
};
|
|
1475
|
+
}
|
|
1476
|
+
|
|
1477
|
+
async updateContext(filePath, content) {
|
|
1478
|
+
// Extract new contexts from updated file
|
|
1479
|
+
const newContexts = await this.contextExtractor.extractFromFile({
|
|
1480
|
+
path: filePath,
|
|
1481
|
+
fullPath: filePath,
|
|
1482
|
+
content,
|
|
1483
|
+
size: content.length,
|
|
1484
|
+
lastModified: new Date()
|
|
1485
|
+
});
|
|
1486
|
+
|
|
1487
|
+
// Generate embeddings for new contexts
|
|
1488
|
+
const texts = newContexts.map(ctx => ctx.content);
|
|
1489
|
+
const embeddings = await this.aiProvider.generateEmbeddings(texts);
|
|
1490
|
+
|
|
1491
|
+
// Delete old contexts for this file
|
|
1492
|
+
const existingContexts = await this.vectorStore.queryRelevantContexts(
|
|
1493
|
+
await this.aiProvider.generateEmbeddings([filePath]),
|
|
1494
|
+
100,
|
|
1495
|
+
{ filePath: { $eq: filePath } }
|
|
1496
|
+
);
|
|
1497
|
+
|
|
1498
|
+
if (existingContexts.length > 0) {
|
|
1499
|
+
await this.vectorStore.deleteContext(
|
|
1500
|
+
existingContexts.map(ctx => ctx.id)
|
|
1501
|
+
);
|
|
1502
|
+
}
|
|
1503
|
+
|
|
1504
|
+
// Index new contexts
|
|
1505
|
+
await this.vectorStore.indexContexts(newContexts, embeddings);
|
|
1506
|
+
|
|
1507
|
+
console.log(`✅ Updated context for file: ${filePath}`);
|
|
1508
|
+
return {
|
|
1509
|
+
filePath,
|
|
1510
|
+
contextsAdded: newContexts.length,
|
|
1511
|
+
contextsRemoved: existingContexts.length
|
|
1512
|
+
};
|
|
1513
|
+
}
|
|
1514
|
+
|
|
1515
|
+
async getTokenUsageAnalytics(timeRange = '7d') {
|
|
1516
|
+
// This would integrate with a token usage tracking system
|
|
1517
|
+
return {
|
|
1518
|
+
totalTokens: 0,
|
|
1519
|
+
totalCost: 0,
|
|
1520
|
+
providerBreakdown: {},
|
|
1521
|
+
dailyUsage: [],
|
|
1522
|
+
optimizations: {
|
|
1523
|
+
totalSavings: 0,
|
|
1524
|
+
savingsPercentage: 0
|
|
1525
|
+
}
|
|
1526
|
+
};
|
|
1527
|
+
}
|
|
1528
|
+
|
|
1529
|
+
getLanguageBreakdown(contexts) {
|
|
1530
|
+
const breakdown = {};
|
|
1531
|
+
contexts.forEach(ctx => {
|
|
1532
|
+
breakdown[ctx.language] = (breakdown[ctx.language] || 0) + 1;
|
|
1533
|
+
});
|
|
1534
|
+
return breakdown;
|
|
1535
|
+
}
|
|
1536
|
+
|
|
1537
|
+
getFileTypeBreakdown(contexts) {
|
|
1538
|
+
const breakdown = {};
|
|
1539
|
+
contexts.forEach(ctx => {
|
|
1540
|
+
breakdown[ctx.type] = (breakdown[ctx.type] || 0) + 1;
|
|
1541
|
+
});
|
|
1542
|
+
return breakdown;
|
|
1543
|
+
}
|
|
1544
|
+
|
|
1545
|
+
async getStats() {
|
|
1546
|
+
const vectorStoreStats = await this.vectorStore.getStats();
|
|
1547
|
+
const tokenUsage = await this.getTokenUsageAnalytics();
|
|
1548
|
+
|
|
1549
|
+
return {
|
|
1550
|
+
vectorStore: vectorStoreStats,
|
|
1551
|
+
tokenUsage,
|
|
1552
|
+
providers: Array.from(this.aiProvider.providers.keys()),
|
|
1553
|
+
config: {
|
|
1554
|
+
projectPath: this.config.projectPath,
|
|
1555
|
+
optimizationStrategy: this.tokenOptimizer.config.strategy,
|
|
1556
|
+
targetTokens: this.tokenOptimizer.config.targetTokens
|
|
1557
|
+
}
|
|
1558
|
+
};
|
|
1559
|
+
}
|
|
1560
|
+
}
|
|
1561
|
+
```
|
|
1562
|
+
|
|
1563
|
+
## Usage Examples
|
|
1564
|
+
|
|
1565
|
+
### Basic Usage
|
|
1566
|
+
```bash
|
|
1567
|
+
# Initialize RAG for current project
|
|
1568
|
+
luna-rag init
|
|
1569
|
+
|
|
1570
|
+
# Index project for context retrieval
|
|
1571
|
+
luna-rag index
|
|
1572
|
+
|
|
1573
|
+
# Query context
|
|
1574
|
+
luna-rag query "How does authentication work?"
|
|
1575
|
+
|
|
1576
|
+
# Chat with context
|
|
1577
|
+
luna-rag chat "What files need to be modified for the new feature?"
|
|
1578
|
+
|
|
1579
|
+
# Update context for specific file
|
|
1580
|
+
luna-rag update src/auth/login.ts
|
|
1581
|
+
|
|
1582
|
+
# Get usage analytics
|
|
1583
|
+
luna-rag stats
|
|
1584
|
+
```
|
|
1585
|
+
|
|
1586
|
+
### Advanced Configuration
|
|
1587
|
+
```javascript
|
|
1588
|
+
// luna-rag.config.js
|
|
1589
|
+
export default {
|
|
1590
|
+
projectPath: './',
|
|
1591
|
+
vectorStore: {
|
|
1592
|
+
provider: 'pinecone',
|
|
1593
|
+
apiKey: process.env.PINECONE_API_KEY,
|
|
1594
|
+
environment: 'us-west1-gcp-free',
|
|
1595
|
+
indexName: 'my-project-rag',
|
|
1596
|
+
dimension: 1536
|
|
1597
|
+
},
|
|
1598
|
+
tokenOptimization: {
|
|
1599
|
+
targetTokens: 4000,
|
|
1600
|
+
strategy: 'balanced',
|
|
1601
|
+
maxCompression: 0.7
|
|
1602
|
+
},
|
|
1603
|
+
aiProviders: {
|
|
1604
|
+
openai: {
|
|
1605
|
+
apiKey: process.env.OPENAI_API_KEY,
|
|
1606
|
+
model: 'gpt-4'
|
|
1607
|
+
},
|
|
1608
|
+
anthropropic: {
|
|
1609
|
+
apiKey: process.env.ANTHROPIC_API_KEY
|
|
1610
|
+
}
|
|
1611
|
+
},
|
|
1612
|
+
extraction: {
|
|
1613
|
+
includePatterns: ['**/*.{js,ts,jsx,tsx,py,md}'],
|
|
1614
|
+
excludePatterns: ['node_modules/**', 'dist/**'],
|
|
1615
|
+
maxFileSize: 1024 * 1024
|
|
1616
|
+
}
|
|
1617
|
+
};
|
|
1618
|
+
```
|
|
1619
|
+
|
|
1620
|
+
## Output Files
|
|
1621
|
+
|
|
1622
|
+
```
|
|
1623
|
+
.luna/{project}/rag/
|
|
1624
|
+
├── contexts/
|
|
1625
|
+
│ ├── index.json
|
|
1626
|
+
│ ├── embeddings.json
|
|
1627
|
+
│ └── metadata.json
|
|
1628
|
+
├── reports/
|
|
1629
|
+
│ ├── indexing-report.json
|
|
1630
|
+
│ ├── optimization-report.json
|
|
1631
|
+
│ └── usage-analytics.json
|
|
1632
|
+
├── cache/
|
|
1633
|
+
│ ├── query-cache.json
|
|
1634
|
+
│ └── embedding-cache.json
|
|
1635
|
+
└── luna-rag.config.js
|
|
1636
|
+
```
|
|
1637
|
+
|
|
1638
|
+
## Integration with Luna Ecosystem
|
|
1639
|
+
|
|
1640
|
+
Seamlessly integrates with:
|
|
1641
|
+
- **`luna-openai-app`** - Generate context-aware OpenAI apps
|
|
1642
|
+
- **`luna-cloudflare`** - Deploy RAG to edge computing
|
|
1643
|
+
- **`luna-task-executor`** - Execute tasks with enhanced context
|
|
1644
|
+
- **`luna-code-review`** - Code review with project context
|
|
1645
|
+
- **All Luna agents** - Enhanced with RAG-powered intelligence
|
|
1646
|
+
|
|
1647
|
+
## Quality Checklist
|
|
1648
|
+
|
|
1649
|
+
- [ ] Project successfully indexed
|
|
1650
|
+
- [ ] Vector database properly configured
|
|
1651
|
+
- [ ] Contexts accurately extracted and categorized
|
|
1652
|
+
- [ ] Token optimization working effectively
|
|
1653
|
+
- [ ] Query responses are relevant and accurate
|
|
1654
|
+
- [ ] Multi-provider AI integration functional
|
|
1655
|
+
- [ ] Cost optimization strategies applied
|
|
1656
|
+
- [ ] Usage analytics and monitoring active
|
|
1657
|
+
- [ ] Context updates working correctly
|
|
1658
|
+
- [ ] Integration with other Luna agents working
|
|
1659
|
+
|
|
1660
|
+
## Instructions for Execution
|
|
1661
|
+
|
|
1662
|
+
1. **Configure vector database** (Pinecone, Weaviate, Qdrant, or Chroma)
|
|
1663
|
+
2. **Set up AI providers** (OpenAI, Anthropic, DeepSeek, Google)
|
|
1664
|
+
3. **Initialize RAG service** with project configuration
|
|
1665
|
+
4. **Extract and index project contexts** with intelligent analysis
|
|
1666
|
+
5. **Configure token optimization** strategies and budgets
|
|
1667
|
+
6. **Test context retrieval** with sample queries
|
|
1668
|
+
7. **Monitor performance** and optimization effectiveness
|
|
1669
|
+
8. **Integrate with other Luna agents** for enhanced capabilities
|
|
1670
|
+
|
|
1671
|
+
Transform your AI agents with context-aware intelligence! 🧠✨
|
|
1672
|
+
|
|
1673
|
+
---
|
|
1674
|
+
|
|
1675
|
+
## MCP Tool Integration
|
|
1676
|
+
|
|
1677
|
+
When called as an MCP tool, Luna RAG provides these capabilities:
|
|
1678
|
+
|
|
1679
|
+
### `setup_rag_system`
|
|
1680
|
+
- **Description**: Initialize complete RAG system for a project
|
|
1681
|
+
- **Parameters**:
|
|
1682
|
+
```json
|
|
1683
|
+
{
|
|
1684
|
+
"projectPath": "./",
|
|
1685
|
+
"vectorStore": {
|
|
1686
|
+
"provider": "pinecone|weaviate|qdrant|chroma",
|
|
1687
|
+
"config": { ... }
|
|
1688
|
+
},
|
|
1689
|
+
"tokenOptimization": {
|
|
1690
|
+
"targetTokens": 4000,
|
|
1691
|
+
"strategy": "balanced|maximum|quality"
|
|
1692
|
+
}
|
|
1693
|
+
}
|
|
1694
|
+
```
|
|
1695
|
+
- **Returns**: RAG system configuration and indexing report
|
|
1696
|
+
|
|
1697
|
+
### `query_context`
|
|
1698
|
+
- **Description**: Retrieve relevant context for queries
|
|
1699
|
+
- **Parameters**:
|
|
1700
|
+
```json
|
|
1701
|
+
{
|
|
1702
|
+
"query": "How does authentication work?",
|
|
1703
|
+
"topK": 10,
|
|
1704
|
+
"optimizeTokens": true,
|
|
1705
|
+
"additionalContext": "User is working on login feature"
|
|
1706
|
+
}
|
|
1707
|
+
```
|
|
1708
|
+
- **Returns**: Optimized contexts with relevance scores
|
|
1709
|
+
|
|
1710
|
+
### `chat_with_context`
|
|
1711
|
+
- **Description**: AI chat with project context
|
|
1712
|
+
- **Parameters**:
|
|
1713
|
+
```json
|
|
1714
|
+
{
|
|
1715
|
+
"query": "What files need to be modified?",
|
|
1716
|
+
"conversationHistory": [...],
|
|
1717
|
+
"contextFilter": { "fileType": "function" }
|
|
1718
|
+
}
|
|
1719
|
+
```
|
|
1720
|
+
- **Returns**: AI response with context sources and usage analytics
|
|
1721
|
+
|
|
1722
|
+
### `update_rag_index`
|
|
1723
|
+
- **Description**: Update RAG index for changed files
|
|
1724
|
+
- **Parameters**:
|
|
1725
|
+
```json
|
|
1726
|
+
{
|
|
1727
|
+
"files": ["src/auth/login.ts", "README.md"],
|
|
1728
|
+
"incremental": true
|
|
1729
|
+
}
|
|
1730
|
+
```
|
|
1731
|
+
- **Returns**: Update confirmation and new context count
|
|
1732
|
+
|
|
1733
|
+
Enhance your AI agents with intelligent context retrieval! 🚀
|