orchid-ai 1.0.0 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/server/index.d.ts +4 -0
- package/dist/server/index.esm.js +531 -1
- package/dist/server/index.js +534 -0
- package/dist/server/intent-detection.d.ts +118 -0
- package/dist/server/mongodb-rag.d.ts +106 -0
- package/dist/server/server/index.d.ts +4 -0
- package/dist/server/server/intent-detection.d.ts +118 -0
- package/dist/server/server/mongodb-rag.d.ts +106 -0
- package/dist/server/types/types.d.ts +6 -0
- package/dist/types/types.d.ts +6 -0
- package/package.json +1 -1
package/dist/server/index.d.ts
CHANGED
|
@@ -3,5 +3,9 @@ export type { ServerOptions, CommandServer, TrainingConfig, AIProvider, Contextu
|
|
|
3
3
|
export { setupCommandServer, createCommandConfig, formatErrorForUser, } from './server';
|
|
4
4
|
export { CommandService, } from './service';
|
|
5
5
|
export { ContextualCommandService, } from './contextual-service';
|
|
6
|
+
export { MongoDBRAGPlugin, enrichContextWithRAG, } from './mongodb-rag';
|
|
7
|
+
export type { MongoDBConnection, RAGConfig, RAGContext, LookupResult, FindOptions, VectorSearchOptions, } from './mongodb-rag';
|
|
8
|
+
export { IntentDetectionPlugin, enrichContextWithIntent, } from './intent-detection';
|
|
9
|
+
export type { IntentDetectionConfig, DetectedIntent, DataNeed, FieldOperation, } from './intent-detection';
|
|
6
10
|
export { getTrainingDataConfig, CommandTrainingCollector, } from './training';
|
|
7
11
|
export { createTrainingConfig, validateTrainingConfig, getExpectedFileStructure, } from './training-schema';
|
package/dist/server/index.esm.js
CHANGED
|
@@ -13902,6 +13902,536 @@ ${additionalContext}
|
|
|
13902
13902
|
}
|
|
13903
13903
|
}
|
|
13904
13904
|
|
|
13905
|
+
/**
|
|
13906
|
+
* MongoDB RAG (Retrieval-Augmented Generation) Plugin
|
|
13907
|
+
*
|
|
13908
|
+
* This plugin analyzes user queries and automatically retrieves relevant data
|
|
13909
|
+
* from MongoDB collections to enrich the AI context before generating responses.
|
|
13910
|
+
*
|
|
13911
|
+
* Features:
|
|
13912
|
+
* - Automatic query intent detection
|
|
13913
|
+
* - Dynamic collection lookups based on schema metadata
|
|
13914
|
+
* - Configurable search strategies (vector, text, filter)
|
|
13915
|
+
* - Database-agnostic interface (bring your own MongoDB connection)
|
|
13916
|
+
*/
|
|
13917
|
+
/**
|
|
13918
|
+
* MongoDB RAG Plugin for ContextualCommandService
|
|
13919
|
+
*/
|
|
13920
|
+
class MongoDBRAGPlugin {
|
|
13921
|
+
config;
|
|
13922
|
+
constructor(config) {
|
|
13923
|
+
this.config = {
|
|
13924
|
+
maxDocuments: 10,
|
|
13925
|
+
useVectorSearch: false,
|
|
13926
|
+
verboseLogging: false,
|
|
13927
|
+
...config,
|
|
13928
|
+
};
|
|
13929
|
+
}
|
|
13930
|
+
log(message, ...args) {
|
|
13931
|
+
if (this.config.verboseLogging) {
|
|
13932
|
+
console.log(`[MONGODB RAG]`, message, ...args);
|
|
13933
|
+
}
|
|
13934
|
+
}
|
|
13935
|
+
/**
|
|
13936
|
+
* Analyze user query and schema to determine what data needs to be retrieved
|
|
13937
|
+
*/
|
|
13938
|
+
async analyzeAndRetrieve(userQuery, schema, currentFormData) {
|
|
13939
|
+
this.log('🔍 Analyzing query for data retrieval needs...');
|
|
13940
|
+
const lookups = [];
|
|
13941
|
+
let queriesExecuted = 0;
|
|
13942
|
+
// Extract collections from schema
|
|
13943
|
+
const collectionsToQuery = this.extractCollectionsFromSchema(schema);
|
|
13944
|
+
if (collectionsToQuery.length === 0) {
|
|
13945
|
+
this.log('⚠️ No collections defined in schema');
|
|
13946
|
+
return {
|
|
13947
|
+
lookups: [],
|
|
13948
|
+
enrichedContext: '',
|
|
13949
|
+
queriesExecuted: 0,
|
|
13950
|
+
};
|
|
13951
|
+
}
|
|
13952
|
+
this.log(`📚 Found ${collectionsToQuery.length} collections in schema:`, collectionsToQuery.map(c => c.name));
|
|
13953
|
+
// Determine query intent and build MongoDB queries
|
|
13954
|
+
const queryIntents = this.determineQueryIntent(userQuery, collectionsToQuery, currentFormData);
|
|
13955
|
+
// Execute queries
|
|
13956
|
+
for (const intent of queryIntents) {
|
|
13957
|
+
try {
|
|
13958
|
+
this.log(`🔎 Querying collection: ${intent.collection}`, intent.query);
|
|
13959
|
+
const documents = await this.config.connection.find(intent.collection, intent.query, {
|
|
13960
|
+
limit: this.config.maxDocuments,
|
|
13961
|
+
sort: intent.sort,
|
|
13962
|
+
projection: intent.projection,
|
|
13963
|
+
});
|
|
13964
|
+
lookups.push({
|
|
13965
|
+
collection: intent.collection,
|
|
13966
|
+
documents,
|
|
13967
|
+
query: intent.query,
|
|
13968
|
+
count: documents.length,
|
|
13969
|
+
});
|
|
13970
|
+
queriesExecuted++;
|
|
13971
|
+
this.log(`✅ Retrieved ${documents.length} documents from ${intent.collection}`);
|
|
13972
|
+
}
|
|
13973
|
+
catch (error) {
|
|
13974
|
+
this.log(`❌ Error querying ${intent.collection}:`, error);
|
|
13975
|
+
}
|
|
13976
|
+
}
|
|
13977
|
+
// Build enriched context
|
|
13978
|
+
const enrichedContext = this.buildEnrichedContext(lookups, schema);
|
|
13979
|
+
return {
|
|
13980
|
+
lookups,
|
|
13981
|
+
enrichedContext,
|
|
13982
|
+
queriesExecuted,
|
|
13983
|
+
};
|
|
13984
|
+
}
|
|
13985
|
+
/**
|
|
13986
|
+
* Extract collections referenced in schema
|
|
13987
|
+
*/
|
|
13988
|
+
extractCollectionsFromSchema(schema) {
|
|
13989
|
+
const collections = new Map();
|
|
13990
|
+
const processProperty = (fieldName, property) => {
|
|
13991
|
+
if (property.collection) {
|
|
13992
|
+
if (!collections.has(property.collection)) {
|
|
13993
|
+
collections.set(property.collection, {
|
|
13994
|
+
name: property.collection,
|
|
13995
|
+
fields: [],
|
|
13996
|
+
searchable: property.searchable || false,
|
|
13997
|
+
vectorField: property.vectorField,
|
|
13998
|
+
});
|
|
13999
|
+
}
|
|
14000
|
+
collections.get(property.collection).fields.push(fieldName);
|
|
14001
|
+
}
|
|
14002
|
+
// Handle nested objects
|
|
14003
|
+
if (property.type === 'object' && property.properties) {
|
|
14004
|
+
for (const [nestedName, nestedProp] of Object.entries(property.properties)) {
|
|
14005
|
+
processProperty(`${fieldName}.${nestedName}`, nestedProp);
|
|
14006
|
+
}
|
|
14007
|
+
}
|
|
14008
|
+
// Handle arrays of objects
|
|
14009
|
+
if (property.type === 'array' && property.items && typeof property.items === 'object') {
|
|
14010
|
+
if (property.items.properties) {
|
|
14011
|
+
for (const [itemName, itemProp] of Object.entries(property.items.properties)) {
|
|
14012
|
+
processProperty(`${fieldName}.${itemName}`, itemProp);
|
|
14013
|
+
}
|
|
14014
|
+
}
|
|
14015
|
+
}
|
|
14016
|
+
};
|
|
14017
|
+
// Process all schema properties
|
|
14018
|
+
if (schema.properties) {
|
|
14019
|
+
for (const [fieldName, property] of Object.entries(schema.properties)) {
|
|
14020
|
+
processProperty(fieldName, property);
|
|
14021
|
+
}
|
|
14022
|
+
}
|
|
14023
|
+
return Array.from(collections.values());
|
|
14024
|
+
}
|
|
14025
|
+
/**
|
|
14026
|
+
* Determine query intent from user input
|
|
14027
|
+
*/
|
|
14028
|
+
determineQueryIntent(userQuery, collections, currentFormData) {
|
|
14029
|
+
const intents = [];
|
|
14030
|
+
const queryLower = userQuery.toLowerCase();
|
|
14031
|
+
for (const collection of collections) {
|
|
14032
|
+
// Build query based on current form data and user query
|
|
14033
|
+
const query = {};
|
|
14034
|
+
// Check if collection name is mentioned in query
|
|
14035
|
+
const collectionMentioned = queryLower.includes(collection.name.toLowerCase());
|
|
14036
|
+
// Check for specific keywords that indicate data lookup
|
|
14037
|
+
const needsLookup = queryLower.includes('show') ||
|
|
14038
|
+
queryLower.includes('list') ||
|
|
14039
|
+
queryLower.includes('find') ||
|
|
14040
|
+
queryLower.includes('get') ||
|
|
14041
|
+
queryLower.includes('search') ||
|
|
14042
|
+
queryLower.includes('available') ||
|
|
14043
|
+
queryLower.includes('options') ||
|
|
14044
|
+
collectionMentioned;
|
|
14045
|
+
if (!needsLookup && !collectionMentioned) {
|
|
14046
|
+
// Skip collections that aren't relevant to this query
|
|
14047
|
+
continue;
|
|
14048
|
+
}
|
|
14049
|
+
// Add filters based on current form data
|
|
14050
|
+
if (currentFormData) {
|
|
14051
|
+
for (const field of collection.fields) {
|
|
14052
|
+
if (currentFormData[field] && typeof currentFormData[field] === 'string') {
|
|
14053
|
+
// Add partial text match for string fields
|
|
14054
|
+
query[field] = { $regex: currentFormData[field], $options: 'i' };
|
|
14055
|
+
}
|
|
14056
|
+
}
|
|
14057
|
+
}
|
|
14058
|
+
// Extract potential search terms from query
|
|
14059
|
+
const searchTerms = this.extractSearchTerms(queryLower);
|
|
14060
|
+
if (searchTerms.length > 0 && collection.searchable) {
|
|
14061
|
+
// Build text search query
|
|
14062
|
+
query.$text = { $search: searchTerms.join(' ') };
|
|
14063
|
+
}
|
|
14064
|
+
// Add intent
|
|
14065
|
+
intents.push({
|
|
14066
|
+
collection: collection.name,
|
|
14067
|
+
query: Object.keys(query).length > 0 ? query : {}, // Empty query = get all
|
|
14068
|
+
sort: { _id: -1 }, // Most recent first
|
|
14069
|
+
projection: undefined, // Get all fields
|
|
14070
|
+
});
|
|
14071
|
+
}
|
|
14072
|
+
return intents;
|
|
14073
|
+
}
|
|
14074
|
+
/**
|
|
14075
|
+
* Extract search terms from user query
|
|
14076
|
+
*/
|
|
14077
|
+
extractSearchTerms(query) {
|
|
14078
|
+
// Remove common words
|
|
14079
|
+
const stopWords = ['the', 'a', 'an', 'in', 'on', 'at', 'for', 'to', 'of', 'with', 'show', 'me', 'list', 'find', 'get', 'search', 'available', 'options'];
|
|
14080
|
+
const words = query
|
|
14081
|
+
.toLowerCase()
|
|
14082
|
+
.replace(/[^\w\s]/g, ' ')
|
|
14083
|
+
.split(/\s+/)
|
|
14084
|
+
.filter(word => word.length > 2 && !stopWords.includes(word));
|
|
14085
|
+
return words;
|
|
14086
|
+
}
|
|
14087
|
+
/**
|
|
14088
|
+
* Build enriched context from retrieved documents
|
|
14089
|
+
*/
|
|
14090
|
+
buildEnrichedContext(lookups, schema) {
|
|
14091
|
+
if (lookups.length === 0) {
|
|
14092
|
+
return '';
|
|
14093
|
+
}
|
|
14094
|
+
let context = '\n## 📊 RETRIEVED DATA FROM DATABASE\n\n';
|
|
14095
|
+
context += 'The following data was retrieved from your database to help answer the query:\n\n';
|
|
14096
|
+
for (const lookup of lookups) {
|
|
14097
|
+
if (lookup.documents.length === 0)
|
|
14098
|
+
continue;
|
|
14099
|
+
context += `### Collection: ${lookup.collection}\n`;
|
|
14100
|
+
context += `Found ${lookup.documents.length} matching documents:\n\n`;
|
|
14101
|
+
// Format documents for AI consumption
|
|
14102
|
+
lookup.documents.forEach((doc, index) => {
|
|
14103
|
+
context += `**Document ${index + 1}:**\n`;
|
|
14104
|
+
context += '```json\n';
|
|
14105
|
+
context += JSON.stringify(doc, null, 2);
|
|
14106
|
+
context += '\n```\n\n';
|
|
14107
|
+
});
|
|
14108
|
+
}
|
|
14109
|
+
context += '**IMPORTANT:** Use this retrieved data to provide accurate, data-driven suggestions. ';
|
|
14110
|
+
context += 'Reference actual values from these documents rather than making up data.\n';
|
|
14111
|
+
return context;
|
|
14112
|
+
}
|
|
14113
|
+
/**
|
|
14114
|
+
* Generate embeddings for vector search (requires OpenAI API)
|
|
14115
|
+
*/
|
|
14116
|
+
async generateEmbedding(text) {
|
|
14117
|
+
if (!this.config.embeddingApiKey) {
|
|
14118
|
+
throw new Error('Embedding API key not configured');
|
|
14119
|
+
}
|
|
14120
|
+
// This would use OpenAI embeddings API
|
|
14121
|
+
// Implementation left as exercise - requires OpenAI SDK
|
|
14122
|
+
throw new Error('Vector search not yet implemented');
|
|
14123
|
+
}
|
|
14124
|
+
}
|
|
14125
|
+
/**
|
|
14126
|
+
* Helper function to create RAG-enhanced additional context
|
|
14127
|
+
*/
|
|
14128
|
+
async function enrichContextWithRAG(ragPlugin, userQuery, schema, currentFormData, existingContext) {
|
|
14129
|
+
const ragContext = await ragPlugin.analyzeAndRetrieve(userQuery, schema, currentFormData);
|
|
14130
|
+
let enrichedContext = existingContext || '';
|
|
14131
|
+
if (ragContext.enrichedContext) {
|
|
14132
|
+
enrichedContext = ragContext.enrichedContext + '\n\n' + enrichedContext;
|
|
14133
|
+
}
|
|
14134
|
+
return enrichedContext;
|
|
14135
|
+
}
|
|
14136
|
+
|
|
14137
|
+
/**
|
|
14138
|
+
* Intent Detection Plugin for ContextualCommandService
|
|
14139
|
+
*
|
|
14140
|
+
* Uses the AI model to analyze user queries and detect intent, entities,
|
|
14141
|
+
* and data retrieval needs before the main AI processing. This enables:
|
|
14142
|
+
* - Faster responses with pre-fetched relevant data
|
|
14143
|
+
* - More accurate AI suggestions based on real database values
|
|
14144
|
+
* - Context-aware data retrieval
|
|
14145
|
+
* - Automatic understanding of your domain without manual configuration
|
|
14146
|
+
*
|
|
14147
|
+
* The AI analyzes the query and schema to determine what data to retrieve.
|
|
14148
|
+
*/
|
|
14149
|
+
/**
|
|
14150
|
+
* Intent Detection Plugin (AI-Powered)
|
|
14151
|
+
*/
|
|
14152
|
+
class IntentDetectionPlugin {
|
|
14153
|
+
config;
|
|
14154
|
+
aiModel;
|
|
14155
|
+
constructor(config) {
|
|
14156
|
+
this.config = {
|
|
14157
|
+
verboseLogging: false,
|
|
14158
|
+
temperature: 0.3, // Low temperature for consistent intent detection
|
|
14159
|
+
...config,
|
|
14160
|
+
};
|
|
14161
|
+
// Create AI model instance
|
|
14162
|
+
this.aiModel = this.createModelInstance();
|
|
14163
|
+
}
|
|
14164
|
+
createModelInstance() {
|
|
14165
|
+
const { provider, apiKey, model } = this.config;
|
|
14166
|
+
switch (provider.toLowerCase()) {
|
|
14167
|
+
case 'openai':
|
|
14168
|
+
return {
|
|
14169
|
+
client: new OpenAI({ apiKey }),
|
|
14170
|
+
model: model || 'gpt-3.5-turbo',
|
|
14171
|
+
provider: 'openai',
|
|
14172
|
+
};
|
|
14173
|
+
case 'claude':
|
|
14174
|
+
return {
|
|
14175
|
+
client: new Anthropic({ apiKey }),
|
|
14176
|
+
model: model || 'claude-3-haiku-20240307',
|
|
14177
|
+
provider: 'claude',
|
|
14178
|
+
};
|
|
14179
|
+
case 'gemini':
|
|
14180
|
+
return {
|
|
14181
|
+
client: new GoogleGenerativeAI(apiKey),
|
|
14182
|
+
model: model || 'gemini-1.5-flash',
|
|
14183
|
+
provider: 'gemini',
|
|
14184
|
+
};
|
|
14185
|
+
default:
|
|
14186
|
+
throw new Error(`Unsupported provider: ${provider}`);
|
|
14187
|
+
}
|
|
14188
|
+
}
|
|
14189
|
+
log(message, ...args) {
|
|
14190
|
+
if (this.config.verboseLogging) {
|
|
14191
|
+
console.log(`[INTENT DETECTION]`, message, ...args);
|
|
14192
|
+
}
|
|
14193
|
+
}
|
|
14194
|
+
/**
|
|
14195
|
+
* Detect user intent from a query using AI
|
|
14196
|
+
*/
|
|
14197
|
+
async detectIntent(query, currentFormData = {}, schema) {
|
|
14198
|
+
this.log('🔍 AI Analyzing query:', query);
|
|
14199
|
+
// Build prompt for AI
|
|
14200
|
+
const systemPrompt = this.buildIntentAnalysisPrompt(schema);
|
|
14201
|
+
const userPrompt = this.buildUserPrompt(query, currentFormData, schema);
|
|
14202
|
+
try {
|
|
14203
|
+
// Call AI to analyze intent
|
|
14204
|
+
const response = await this.callAI(systemPrompt, userPrompt);
|
|
14205
|
+
// Parse AI response
|
|
14206
|
+
const intent = this.parseIntentResponse(response, query);
|
|
14207
|
+
this.log(' Action:', intent.actionType);
|
|
14208
|
+
this.log(' Entities:', intent.entities);
|
|
14209
|
+
this.log(' Data needs:', intent.dataNeeds.map(d => d.collection));
|
|
14210
|
+
this.log(' Confidence:', `${(intent.confidence * 100).toFixed(0)}%`);
|
|
14211
|
+
return intent;
|
|
14212
|
+
}
|
|
14213
|
+
catch (error) {
|
|
14214
|
+
this.log('❌ Error detecting intent:', error);
|
|
14215
|
+
// Fallback to empty intent
|
|
14216
|
+
return {
|
|
14217
|
+
actionType: 'unknown',
|
|
14218
|
+
entities: [],
|
|
14219
|
+
dataNeeds: [],
|
|
14220
|
+
fieldOperations: [],
|
|
14221
|
+
confidence: 0.3,
|
|
14222
|
+
query,
|
|
14223
|
+
};
|
|
14224
|
+
}
|
|
14225
|
+
}
|
|
14226
|
+
/**
|
|
14227
|
+
* Build system prompt for intent analysis
|
|
14228
|
+
*/
|
|
14229
|
+
buildIntentAnalysisPrompt(schema) {
|
|
14230
|
+
let prompt = `You are an intent analysis assistant. Analyze user queries to determine:
|
|
14231
|
+
1. What action they want to perform
|
|
14232
|
+
2. What entities/data they're referencing
|
|
14233
|
+
3. What database collections should be queried for relevant data
|
|
14234
|
+
|
|
14235
|
+
Common action types: create, update, search, view, delete, calculate, analyze, help
|
|
14236
|
+
|
|
14237
|
+
Return your analysis as JSON with this exact structure:
|
|
14238
|
+
{
|
|
14239
|
+
"actionType": "create|update|search|view|delete|calculate|analyze|help",
|
|
14240
|
+
"entities": ["entity1", "entity2"],
|
|
14241
|
+
"dataNeeds": [
|
|
14242
|
+
{
|
|
14243
|
+
"collection": "collection_name",
|
|
14244
|
+
"reason": "why this data is needed",
|
|
14245
|
+
"query": {},
|
|
14246
|
+
"limit": 20
|
|
14247
|
+
}
|
|
14248
|
+
],
|
|
14249
|
+
"fieldOperations": [
|
|
14250
|
+
{
|
|
14251
|
+
"operation": "set|add|remove",
|
|
14252
|
+
"field": "fieldName",
|
|
14253
|
+
"value": "optional value"
|
|
14254
|
+
}
|
|
14255
|
+
],
|
|
14256
|
+
"confidence": 0.8
|
|
14257
|
+
}`;
|
|
14258
|
+
if (schema) {
|
|
14259
|
+
prompt += `\n\nAvailable schema (use 'collection' properties to determine what data to retrieve):
|
|
14260
|
+
\`\`\`json
|
|
14261
|
+
${JSON.stringify(schema, null, 2)}
|
|
14262
|
+
\`\`\`
|
|
14263
|
+
|
|
14264
|
+
CRITICAL: For any field with a "collection" property, add it to dataNeeds if the user query references that field.`;
|
|
14265
|
+
}
|
|
14266
|
+
return prompt;
|
|
14267
|
+
}
|
|
14268
|
+
/**
|
|
14269
|
+
* Build user prompt with query and context
|
|
14270
|
+
*/
|
|
14271
|
+
buildUserPrompt(query, currentFormData, schema) {
|
|
14272
|
+
let prompt = `User Query: "${query}"`;
|
|
14273
|
+
if (Object.keys(currentFormData).length > 0) {
|
|
14274
|
+
prompt += `\n\nCurrent Form Data:
|
|
14275
|
+
\`\`\`json
|
|
14276
|
+
${JSON.stringify(currentFormData, null, 2)}
|
|
14277
|
+
\`\`\``;
|
|
14278
|
+
}
|
|
14279
|
+
prompt += `\n\nAnalyze this query and return the JSON intent analysis.`;
|
|
14280
|
+
return prompt;
|
|
14281
|
+
}
|
|
14282
|
+
/**
|
|
14283
|
+
* Call AI model to analyze intent
|
|
14284
|
+
*/
|
|
14285
|
+
async callAI(systemPrompt, userPrompt) {
|
|
14286
|
+
const { client, model, provider } = this.aiModel;
|
|
14287
|
+
switch (provider) {
|
|
14288
|
+
case 'openai': {
|
|
14289
|
+
const response = await client.chat.completions.create({
|
|
14290
|
+
model,
|
|
14291
|
+
messages: [
|
|
14292
|
+
{ role: 'system', content: systemPrompt },
|
|
14293
|
+
{ role: 'user', content: userPrompt },
|
|
14294
|
+
],
|
|
14295
|
+
temperature: this.config.temperature,
|
|
14296
|
+
max_tokens: 1000,
|
|
14297
|
+
});
|
|
14298
|
+
return response.choices[0]?.message?.content || '{}';
|
|
14299
|
+
}
|
|
14300
|
+
case 'claude': {
|
|
14301
|
+
const response = await client.messages.create({
|
|
14302
|
+
model,
|
|
14303
|
+
system: systemPrompt,
|
|
14304
|
+
messages: [{ role: 'user', content: userPrompt }],
|
|
14305
|
+
temperature: this.config.temperature,
|
|
14306
|
+
max_tokens: 1000,
|
|
14307
|
+
});
|
|
14308
|
+
const firstBlock = response.content[0];
|
|
14309
|
+
return firstBlock && firstBlock.type === 'text' ? firstBlock.text : '{}';
|
|
14310
|
+
}
|
|
14311
|
+
case 'gemini': {
|
|
14312
|
+
const geminiModel = client.getGenerativeModel({
|
|
14313
|
+
model,
|
|
14314
|
+
systemInstruction: systemPrompt,
|
|
14315
|
+
generationConfig: {
|
|
14316
|
+
temperature: this.config.temperature,
|
|
14317
|
+
maxOutputTokens: 1000,
|
|
14318
|
+
},
|
|
14319
|
+
});
|
|
14320
|
+
const result = await geminiModel.generateContent(userPrompt);
|
|
14321
|
+
return result.response?.text() || '{}';
|
|
14322
|
+
}
|
|
14323
|
+
default:
|
|
14324
|
+
throw new Error(`Unsupported provider: ${provider}`);
|
|
14325
|
+
}
|
|
14326
|
+
}
|
|
14327
|
+
/**
|
|
14328
|
+
* Parse AI response into DetectedIntent
|
|
14329
|
+
*/
|
|
14330
|
+
parseIntentResponse(response, query) {
|
|
14331
|
+
try {
|
|
14332
|
+
// Extract JSON from response
|
|
14333
|
+
const jsonMatch = response.match(/\{[\s\S]*\}/);
|
|
14334
|
+
if (!jsonMatch) {
|
|
14335
|
+
throw new Error('No JSON found in response');
|
|
14336
|
+
}
|
|
14337
|
+
const parsed = JSON.parse(jsonMatch[0]);
|
|
14338
|
+
return {
|
|
14339
|
+
actionType: parsed.actionType || 'unknown',
|
|
14340
|
+
entities: Array.isArray(parsed.entities) ? parsed.entities : [],
|
|
14341
|
+
dataNeeds: Array.isArray(parsed.dataNeeds) ? parsed.dataNeeds : [],
|
|
14342
|
+
fieldOperations: Array.isArray(parsed.fieldOperations) ? parsed.fieldOperations : [],
|
|
14343
|
+
confidence: typeof parsed.confidence === 'number' ? parsed.confidence : 0.5,
|
|
14344
|
+
query,
|
|
14345
|
+
};
|
|
14346
|
+
}
|
|
14347
|
+
catch (error) {
|
|
14348
|
+
this.log('Failed to parse AI response:', response);
|
|
14349
|
+
return {
|
|
14350
|
+
actionType: 'unknown',
|
|
14351
|
+
entities: [],
|
|
14352
|
+
dataNeeds: [],
|
|
14353
|
+
fieldOperations: [],
|
|
14354
|
+
confidence: 0.3,
|
|
14355
|
+
query,
|
|
14356
|
+
};
|
|
14357
|
+
}
|
|
14358
|
+
}
|
|
14359
|
+
/**
|
|
14360
|
+
* Build enhanced context for AI from intent and retrieved data
|
|
14361
|
+
*/
|
|
14362
|
+
buildContextFromIntent(intent, retrievedData) {
|
|
14363
|
+
let context = '';
|
|
14364
|
+
// Add user intent section
|
|
14365
|
+
context += `\n## 🎯 USER INTENT\n`;
|
|
14366
|
+
context += `The user wants to: **${intent.actionType}**\n`;
|
|
14367
|
+
if (intent.entities.length > 0) {
|
|
14368
|
+
context += `Entities mentioned: ${intent.entities.join(', ')}\n`;
|
|
14369
|
+
}
|
|
14370
|
+
context += `Confidence: ${(intent.confidence * 100).toFixed(0)}%\n`;
|
|
14371
|
+
// Add field operations if any
|
|
14372
|
+
if (intent.fieldOperations.length > 0) {
|
|
14373
|
+
context += `\n### Specific Field Operations:\n`;
|
|
14374
|
+
intent.fieldOperations.forEach(op => {
|
|
14375
|
+
context += `- ${op.operation} ${op.field}`;
|
|
14376
|
+
if (op.value)
|
|
14377
|
+
context += ` to "${op.value}"`;
|
|
14378
|
+
context += '\n';
|
|
14379
|
+
});
|
|
14380
|
+
}
|
|
14381
|
+
// Add retrieved data
|
|
14382
|
+
if (retrievedData && Object.keys(retrievedData).length > 0) {
|
|
14383
|
+
context += `\n## 📊 AVAILABLE DATA\n`;
|
|
14384
|
+
for (const [collection, data] of Object.entries(retrievedData)) {
|
|
14385
|
+
if (!data || data.length === 0)
|
|
14386
|
+
continue;
|
|
14387
|
+
context += `\n### ${collection.toUpperCase()} (${data.length} items):\n`;
|
|
14388
|
+
// Use custom formatter if available
|
|
14389
|
+
if (this.config.contextFormatters && this.config.contextFormatters[collection]) {
|
|
14390
|
+
context += this.config.contextFormatters[collection](data);
|
|
14391
|
+
}
|
|
14392
|
+
else {
|
|
14393
|
+
// Default formatting: JSON
|
|
14394
|
+
context += '```json\n';
|
|
14395
|
+
context += JSON.stringify(data.slice(0, 5), null, 2); // Limit to first 5 items
|
|
14396
|
+
context += '\n```\n';
|
|
14397
|
+
}
|
|
14398
|
+
}
|
|
14399
|
+
context += `\n**💡 TIP:** Use the actual data above in your suggestions instead of making up values.\n`;
|
|
14400
|
+
}
|
|
14401
|
+
return context;
|
|
14402
|
+
}
|
|
14403
|
+
}
|
|
14404
|
+
/**
|
|
14405
|
+
* Helper function to create intent-enhanced context (AI-Powered)
|
|
14406
|
+
*/
|
|
14407
|
+
async function enrichContextWithIntent(intentPlugin, dataRetriever, userQuery, schema, currentFormData, existingContext) {
|
|
14408
|
+
// AI analyzes the query to detect intent
|
|
14409
|
+
const intent = await intentPlugin.detectIntent(userQuery, currentFormData, schema);
|
|
14410
|
+
// Retrieve data based on AI-detected needs
|
|
14411
|
+
const retrievedData = {};
|
|
14412
|
+
for (const need of intent.dataNeeds) {
|
|
14413
|
+
try {
|
|
14414
|
+
const data = await dataRetriever(need);
|
|
14415
|
+
retrievedData[need.collection] = data;
|
|
14416
|
+
}
|
|
14417
|
+
catch (error) {
|
|
14418
|
+
console.error(`Failed to retrieve data for ${need.collection}:`, error);
|
|
14419
|
+
retrievedData[need.collection] = [];
|
|
14420
|
+
}
|
|
14421
|
+
}
|
|
14422
|
+
// Build context from intent
|
|
14423
|
+
const intentContext = intentPlugin.buildContextFromIntent(intent, retrievedData);
|
|
14424
|
+
// Merge with existing context
|
|
14425
|
+
let enrichedContext = existingContext || '';
|
|
14426
|
+
if (intentContext) {
|
|
14427
|
+
enrichedContext = intentContext + '\n\n' + enrichedContext;
|
|
14428
|
+
}
|
|
14429
|
+
return {
|
|
14430
|
+
context: enrichedContext,
|
|
14431
|
+
intent,
|
|
14432
|
+
};
|
|
14433
|
+
}
|
|
14434
|
+
|
|
13905
14435
|
/**
|
|
13906
14436
|
* Validate training configuration
|
|
13907
14437
|
*/
|
|
@@ -14004,5 +14534,5 @@ function getExpectedFileStructure() {
|
|
|
14004
14534
|
};
|
|
14005
14535
|
}
|
|
14006
14536
|
|
|
14007
|
-
export { CommandService, CommandTrainingCollector, ContextualCommandService, createCommandConfig, createTrainingConfig, formatErrorForUser, getExpectedFileStructure, getTrainingDataConfig, setupCommandServer, validateTrainingConfig };
|
|
14537
|
+
export { CommandService, CommandTrainingCollector, ContextualCommandService, IntentDetectionPlugin, MongoDBRAGPlugin, createCommandConfig, createTrainingConfig, enrichContextWithIntent, enrichContextWithRAG, formatErrorForUser, getExpectedFileStructure, getTrainingDataConfig, setupCommandServer, validateTrainingConfig };
|
|
14008
14538
|
//# sourceMappingURL=index.esm.js.map
|