@supernal/interface 1.0.6 → 1.0.7
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/cjs/src/ai/AIInterface.js +183 -0
- package/dist/cjs/src/ai/AIInterface.js.map +1 -0
- package/dist/cjs/src/ai/ParameterExtractor.js +140 -0
- package/dist/cjs/src/ai/ParameterExtractor.js.map +1 -0
- package/dist/cjs/src/ai/SuggestionEngine.js +157 -0
- package/dist/cjs/src/ai/SuggestionEngine.js.map +1 -0
- package/dist/cjs/src/ai/ToolMatcher.js +20 -1
- package/dist/cjs/src/ai/ToolMatcher.js.map +1 -1
- package/dist/cjs/src/ai/index.js +5 -7
- package/dist/cjs/src/ai/index.js.map +1 -1
- package/dist/esm/src/ai/AIInterface.d.ts +79 -0
- package/dist/esm/src/ai/AIInterface.d.ts.map +1 -0
- package/dist/esm/src/ai/AIInterface.js +179 -0
- package/dist/esm/src/ai/AIInterface.js.map +1 -0
- package/dist/esm/src/ai/ParameterExtractor.d.ts +50 -0
- package/dist/esm/src/ai/ParameterExtractor.d.ts.map +1 -0
- package/dist/esm/src/ai/ParameterExtractor.js +136 -0
- package/dist/esm/src/ai/ParameterExtractor.js.map +1 -0
- package/dist/esm/src/ai/SuggestionEngine.d.ts +43 -0
- package/dist/esm/src/ai/SuggestionEngine.d.ts.map +1 -0
- package/dist/esm/src/ai/SuggestionEngine.js +153 -0
- package/dist/esm/src/ai/SuggestionEngine.js.map +1 -0
- package/dist/esm/src/ai/ToolMatcher.js +20 -1
- package/dist/esm/src/ai/ToolMatcher.js.map +1 -1
- package/dist/esm/src/ai/index.d.ts +5 -3
- package/dist/esm/src/ai/index.d.ts.map +1 -1
- package/dist/esm/src/ai/index.js +5 -7
- package/dist/esm/src/ai/index.js.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Generic AI Interface for Tool Command Processing
|
|
3
|
+
*
|
|
4
|
+
* Uses core abstractions:
|
|
5
|
+
* - ToolMatcher (pluggable matching strategies)
|
|
6
|
+
* - ParameterExtractor (declarative parameter extraction)
|
|
7
|
+
* - ToolExecutor (universal execution engine)
|
|
8
|
+
* - SuggestionEngine ("Did You Mean?" system)
|
|
9
|
+
*
|
|
10
|
+
* NO HARDCODED ROUTES - everything is inferred from NavigationGraph
|
|
11
|
+
*/
|
|
12
|
+
import type { ToolMetadata } from "../decorators/Tool";
|
|
13
|
+
import { ToolMatcher } from "./ToolMatcher";
|
|
14
|
+
import { ParameterExtractor } from "./ParameterExtractor";
|
|
15
|
+
import { ToolExecutor } from "./ToolExecutor";
|
|
16
|
+
import { SuggestionEngine } from "./SuggestionEngine";
|
|
17
|
+
export interface AICommand {
|
|
18
|
+
query: string;
|
|
19
|
+
tool?: ToolMetadata;
|
|
20
|
+
confidence: number;
|
|
21
|
+
requiresApproval: boolean;
|
|
22
|
+
parameters?: unknown[];
|
|
23
|
+
parsedIntent?: {
|
|
24
|
+
action: string;
|
|
25
|
+
target?: string;
|
|
26
|
+
value?: string;
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
export interface AIResponse {
|
|
30
|
+
success: boolean;
|
|
31
|
+
message: string;
|
|
32
|
+
executedTool?: string;
|
|
33
|
+
timestamp: string;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Generic AI Interface - works for ANY app with ZERO configuration
|
|
37
|
+
* Container detection is INFERRED from NavigationGraph
|
|
38
|
+
*
|
|
39
|
+
* Supports pluggable matching strategies via ToolMatcher.
|
|
40
|
+
* For LLM-based matching, see @supernalintelligence/interface-enterprise
|
|
41
|
+
*/
|
|
42
|
+
export declare class AIInterface {
|
|
43
|
+
protected matcher: ToolMatcher;
|
|
44
|
+
protected paramExtractor: ParameterExtractor;
|
|
45
|
+
protected executor: ToolExecutor;
|
|
46
|
+
protected suggestionEngine: SuggestionEngine;
|
|
47
|
+
constructor();
|
|
48
|
+
/**
|
|
49
|
+
* Register a custom matcher strategy (for BYOK LLM integration)
|
|
50
|
+
* @param strategy Custom matching strategy
|
|
51
|
+
*/
|
|
52
|
+
registerMatcherStrategy(strategy: any): void;
|
|
53
|
+
/**
|
|
54
|
+
* Get current container - INFERRED from NavigationGraph
|
|
55
|
+
* NO HARDCODED ROUTE MAPPINGS
|
|
56
|
+
*/
|
|
57
|
+
private getCurrentContext;
|
|
58
|
+
/**
|
|
59
|
+
* Find matching tools using ToolMatcher
|
|
60
|
+
*/
|
|
61
|
+
findToolsForCommand(query: string): Promise<AICommand[]>;
|
|
62
|
+
/**
|
|
63
|
+
* Execute a command using ToolExecutor
|
|
64
|
+
*/
|
|
65
|
+
executeCommand(commands: AICommand[], useFirstMatch?: boolean): Promise<AIResponse>;
|
|
66
|
+
/**
|
|
67
|
+
* CONVENIENCE: Process a text query end-to-end
|
|
68
|
+
*/
|
|
69
|
+
processQuery(query: string): Promise<AIResponse>;
|
|
70
|
+
/**
|
|
71
|
+
* Get all available commands for help/autocomplete
|
|
72
|
+
*/
|
|
73
|
+
getAvailableCommands(): string[];
|
|
74
|
+
/**
|
|
75
|
+
* Get suggestions for incomplete query (autocomplete)
|
|
76
|
+
*/
|
|
77
|
+
getSuggestions(partialQuery: string): Promise<string[]>;
|
|
78
|
+
}
|
|
79
|
+
//# sourceMappingURL=AIInterface.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AIInterface.d.ts","sourceRoot":"","sources":["../../../../src/ai/AIInterface.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAGH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAEvD,OAAO,EAAE,WAAW,EAAqB,MAAM,eAAe,CAAC;AAC/D,OAAO,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAC1D,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAC9C,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAEtD,MAAM,WAAW,SAAS;IACxB,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,YAAY,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC;IACnB,gBAAgB,EAAE,OAAO,CAAC;IAC1B,UAAU,CAAC,EAAE,OAAO,EAAE,CAAC;IACvB,YAAY,CAAC,EAAE;QACb,MAAM,EAAE,MAAM,CAAC;QACf,MAAM,CAAC,EAAE,MAAM,CAAC;QAChB,KAAK,CAAC,EAAE,MAAM,CAAC;KAChB,CAAC;CACH;AAED,MAAM,WAAW,UAAU;IACzB,OAAO,EAAE,OAAO,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED;;;;;;GAMG;AACH,qBAAa,WAAW;IAEtB,SAAS,CAAC,OAAO,EAAE,WAAW,CAAC;IAC/B,SAAS,CAAC,cAAc,EAAE,kBAAkB,CAAC;IAC7C,SAAS,CAAC,QAAQ,EAAE,YAAY,CAAC;IACjC,SAAS,CAAC,gBAAgB,EAAE,gBAAgB,CAAC;;IAU7C;;;OAGG;IACI,uBAAuB,CAAC,QAAQ,EAAE,GAAG,GAAG,IAAI;IAInD;;;OAGG;IACH,OAAO,CAAC,iBAAiB;IAmBzB;;OAEG;IACG,mBAAmB,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,EAAE,CAAC;IAiD9D;;OAEG;IACG,cAAc,CAAC,QAAQ,EAAE,SAAS,EAAE,EAAE,aAAa,GAAE,OAAc,GAAG,OAAO,CAAC,UAAU,CAAC;IA6D/F;;OAEG;IACG,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC;IAKtD;;OAEG;IACH,oBAAoB,IAAI,MAAM,EAAE;IAsBhC;;OAEG;IACG,cAAc,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC;CAM9D"}
|
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Generic AI Interface for Tool Command Processing
|
|
3
|
+
*
|
|
4
|
+
* Uses core abstractions:
|
|
5
|
+
* - ToolMatcher (pluggable matching strategies)
|
|
6
|
+
* - ParameterExtractor (declarative parameter extraction)
|
|
7
|
+
* - ToolExecutor (universal execution engine)
|
|
8
|
+
* - SuggestionEngine ("Did You Mean?" system)
|
|
9
|
+
*
|
|
10
|
+
* NO HARDCODED ROUTES - everything is inferred from NavigationGraph
|
|
11
|
+
*/
|
|
12
|
+
import { ToolRegistry } from '../background/registry/ToolRegistry.js';
|
|
13
|
+
import { NavigationGraph } from '../background/navigation/NavigationGraph.js';
|
|
14
|
+
import { ToolMatcher } from './ToolMatcher.js';
|
|
15
|
+
import { ParameterExtractor } from './ParameterExtractor.js';
|
|
16
|
+
import { ToolExecutor } from './ToolExecutor.js';
|
|
17
|
+
import { SuggestionEngine } from './SuggestionEngine.js';
|
|
18
|
+
/**
|
|
19
|
+
* Generic AI Interface - works for ANY app with ZERO configuration
|
|
20
|
+
* Container detection is INFERRED from NavigationGraph
|
|
21
|
+
*
|
|
22
|
+
* Supports pluggable matching strategies via ToolMatcher.
|
|
23
|
+
* For LLM-based matching, see @supernalintelligence/interface-enterprise
|
|
24
|
+
*/
|
|
25
|
+
export class AIInterface {
|
|
26
|
+
constructor() {
|
|
27
|
+
// Initialize core abstractions
|
|
28
|
+
this.matcher = new ToolMatcher();
|
|
29
|
+
this.paramExtractor = new ParameterExtractor();
|
|
30
|
+
this.executor = new ToolExecutor();
|
|
31
|
+
this.suggestionEngine = new SuggestionEngine();
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Register a custom matcher strategy (for BYOK LLM integration)
|
|
35
|
+
* @param strategy Custom matching strategy
|
|
36
|
+
*/
|
|
37
|
+
registerMatcherStrategy(strategy) {
|
|
38
|
+
this.matcher.registerStrategy(strategy);
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Get current container - INFERRED from NavigationGraph
|
|
42
|
+
* NO HARDCODED ROUTE MAPPINGS
|
|
43
|
+
*/
|
|
44
|
+
getCurrentContext() {
|
|
45
|
+
if (typeof window === 'undefined') {
|
|
46
|
+
return {
|
|
47
|
+
currentContainer: 'unknown',
|
|
48
|
+
currentPage: 'unknown'
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
// Use the context set by useContainer() hook, NOT route inference
|
|
52
|
+
// This ensures the context matches what the page component registered
|
|
53
|
+
const graph = NavigationGraph.getInstance();
|
|
54
|
+
const currentContainer = graph.getCurrentContext() || 'unknown';
|
|
55
|
+
return {
|
|
56
|
+
currentContainer,
|
|
57
|
+
currentPage: currentContainer
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Find matching tools using ToolMatcher
|
|
62
|
+
*/
|
|
63
|
+
async findToolsForCommand(query) {
|
|
64
|
+
console.log(`🔍 [AI] Finding tools for: "${query}"`);
|
|
65
|
+
// Get all available tools
|
|
66
|
+
const toolsMap = ToolRegistry.getAllTools();
|
|
67
|
+
const allTools = Array.from(toolsMap.values());
|
|
68
|
+
const context = this.getCurrentContext();
|
|
69
|
+
console.log(`📍 [AI] Current context:`, context);
|
|
70
|
+
// Filter tools by current container
|
|
71
|
+
// Priority: 1) Scoped to current container, 2) Global (no containerId), 3) Global navigation
|
|
72
|
+
const scopedTools = allTools.filter(tool => tool.containerId === context.currentContainer);
|
|
73
|
+
const globalTools = allTools.filter(tool => !tool.containerId);
|
|
74
|
+
const navigationTools = allTools.filter(tool => tool.containerId !== context.currentContainer && tool.category === 'navigation');
|
|
75
|
+
console.log(`📦 [AI] Scoped tools: ${scopedTools.length}, Global tools: ${globalTools.length}, Navigation tools: ${navigationTools.length}`);
|
|
76
|
+
// Combine: scoped first, then global, then navigation
|
|
77
|
+
const contextTools = [...scopedTools, ...globalTools, ...navigationTools];
|
|
78
|
+
console.log(`📦 [AI] Total filtered to ${contextTools.length} tools for context: ${context.currentContainer}`);
|
|
79
|
+
// Use ToolMatcher to find matches
|
|
80
|
+
const matches = await this.matcher.findMatches(query, contextTools, context, 5);
|
|
81
|
+
// Convert to AICommand format
|
|
82
|
+
const commands = matches.map(match => ({
|
|
83
|
+
query,
|
|
84
|
+
tool: match.tool,
|
|
85
|
+
confidence: match.confidence,
|
|
86
|
+
requiresApproval: match.tool.dangerLevel === 'dangerous' || match.tool.dangerLevel === 'destructive',
|
|
87
|
+
parameters: match.parameters || []
|
|
88
|
+
}));
|
|
89
|
+
console.log(`✅ [AI] Found ${commands.length} matching tools:`, commands.map(c => `${c.tool?.name} (${Math.round((c.confidence || 0) * 100)}%)`));
|
|
90
|
+
return commands;
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Execute a command using ToolExecutor
|
|
94
|
+
*/
|
|
95
|
+
async executeCommand(commands, useFirstMatch = true) {
|
|
96
|
+
if (commands.length === 0) {
|
|
97
|
+
// Use SuggestionEngine for helpful response
|
|
98
|
+
const toolsMap = ToolRegistry.getAllTools();
|
|
99
|
+
const allTools = Array.from(toolsMap.values());
|
|
100
|
+
const context = this.getCurrentContext();
|
|
101
|
+
// Get available commands for current context
|
|
102
|
+
const contextTools = allTools.filter(t => t.aiEnabled &&
|
|
103
|
+
(!t.containerId || t.containerId === context.currentContainer || t.category === 'navigation'));
|
|
104
|
+
const examples = contextTools.flatMap(t => t.examples || []).slice(0, 5);
|
|
105
|
+
return {
|
|
106
|
+
success: false,
|
|
107
|
+
message: `❓ No matching command found.\n\n💡 Try:\n${examples.map(ex => `• "${ex}"`).join('\n')}`,
|
|
108
|
+
timestamp: new Date().toISOString()
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
const command = commands[0]; // Use highest confidence match
|
|
112
|
+
if (!command.tool) {
|
|
113
|
+
return {
|
|
114
|
+
success: false,
|
|
115
|
+
message: `❌ No tool found for command`,
|
|
116
|
+
timestamp: new Date().toISOString()
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
console.log(`🎯 [AI] Executing: ${command.tool.name}`);
|
|
120
|
+
// Extract parameters using ParameterExtractor
|
|
121
|
+
const extraction = await this.paramExtractor.extract(command.query, command.tool);
|
|
122
|
+
const parameters = extraction.parameters.length > 0 ? extraction.parameters : command.parameters;
|
|
123
|
+
console.log(`📋 [AI] Parameters:`, parameters);
|
|
124
|
+
// Execute using ToolExecutor
|
|
125
|
+
try {
|
|
126
|
+
const result = await this.executor.execute(command.tool, parameters || []);
|
|
127
|
+
return {
|
|
128
|
+
success: result.success,
|
|
129
|
+
message: result.success ? `✅ ${result.message}` : `❌ ${result.message}`,
|
|
130
|
+
executedTool: command.tool.name,
|
|
131
|
+
timestamp: new Date().toISOString()
|
|
132
|
+
};
|
|
133
|
+
}
|
|
134
|
+
catch (error) {
|
|
135
|
+
const errorMsg = error instanceof Error ? error.message : String(error);
|
|
136
|
+
return {
|
|
137
|
+
success: false,
|
|
138
|
+
message: `❌ ${errorMsg}`,
|
|
139
|
+
timestamp: new Date().toISOString()
|
|
140
|
+
};
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
/**
|
|
144
|
+
* CONVENIENCE: Process a text query end-to-end
|
|
145
|
+
*/
|
|
146
|
+
async processQuery(query) {
|
|
147
|
+
const commands = await this.findToolsForCommand(query);
|
|
148
|
+
return this.executeCommand(commands, true);
|
|
149
|
+
}
|
|
150
|
+
/**
|
|
151
|
+
* Get all available commands for help/autocomplete
|
|
152
|
+
*/
|
|
153
|
+
getAvailableCommands() {
|
|
154
|
+
const toolsMap = ToolRegistry.getAllTools();
|
|
155
|
+
const allTools = Array.from(toolsMap.values());
|
|
156
|
+
const context = this.getCurrentContext();
|
|
157
|
+
// Filter by current context
|
|
158
|
+
const contextTools = allTools.filter(tool => !tool.containerId ||
|
|
159
|
+
tool.containerId === context.currentContainer ||
|
|
160
|
+
tool.category === 'navigation');
|
|
161
|
+
// Extract examples
|
|
162
|
+
const commands = [];
|
|
163
|
+
for (const tool of contextTools) {
|
|
164
|
+
const examples = tool.examples || [];
|
|
165
|
+
commands.push(...examples);
|
|
166
|
+
}
|
|
167
|
+
return commands;
|
|
168
|
+
}
|
|
169
|
+
/**
|
|
170
|
+
* Get suggestions for incomplete query (autocomplete)
|
|
171
|
+
*/
|
|
172
|
+
async getSuggestions(partialQuery) {
|
|
173
|
+
const toolsMap = ToolRegistry.getAllTools();
|
|
174
|
+
const allTools = Array.from(toolsMap.values());
|
|
175
|
+
const suggestions = this.suggestionEngine.getSuggestions(partialQuery, allTools, 5);
|
|
176
|
+
return suggestions.map(s => s.text);
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
//# sourceMappingURL=AIInterface.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AIInterface.js","sourceRoot":"","sources":["../../../../src/ai/AIInterface.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,qCAAqC,CAAC;AAEnE,OAAO,EAAE,eAAe,EAAE,MAAM,0CAA0C,CAAC;AAC3E,OAAO,EAAE,WAAW,EAAqB,MAAM,eAAe,CAAC;AAC/D,OAAO,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAC1D,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAC9C,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAsBtD;;;;;;GAMG;AACH,MAAM,OAAO,WAAW;IAOtB;QACE,+BAA+B;QAC/B,IAAI,CAAC,OAAO,GAAG,IAAI,WAAW,EAAE,CAAC;QACjC,IAAI,CAAC,cAAc,GAAG,IAAI,kBAAkB,EAAE,CAAC;QAC/C,IAAI,CAAC,QAAQ,GAAG,IAAI,YAAY,EAAE,CAAC;QACnC,IAAI,CAAC,gBAAgB,GAAG,IAAI,gBAAgB,EAAE,CAAC;IACjD,CAAC;IAED;;;OAGG;IACI,uBAAuB,CAAC,QAAa;QAC1C,IAAI,CAAC,OAAO,CAAC,gBAAgB,CAAC,QAAQ,CAAC,CAAC;IAC1C,CAAC;IAED;;;OAGG;IACK,iBAAiB;QACvB,IAAI,OAAO,MAAM,KAAK,WAAW,EAAE,CAAC;YAClC,OAAO;gBACL,gBAAgB,EAAE,SAAS;gBAC3B,WAAW,EAAE,SAAS;aACvB,CAAC;QACJ,CAAC;QAED,kEAAkE;QAClE,sEAAsE;QACtE,MAAM,KAAK,GAAG,eAAe,CAAC,WAAW,EAAE,CAAC;QAC5C,MAAM,gBAAgB,GAAG,KAAK,CAAC,iBAAiB,EAAE,IAAI,SAAS,CAAC;QAEhE,OAAO;YACL,gBAAgB;YAChB,WAAW,EAAE,gBAAgB;SAC9B,CAAC;IACJ,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,mBAAmB,CAAC,KAAa;QACrC,OAAO,CAAC,GAAG,CAAC,+BAA+B,KAAK,GAAG,CAAC,CAAC;QAErD,0BAA0B;QAC1B,MAAM,QAAQ,GAAG,YAAY,CAAC,WAAW,EAAE,CAAC;QAC5C,MAAM,QAAQ,GAAG,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,MAAM,EAAE,CAAC,CAAC;QAC/C,MAAM,OAAO,GAAG,IAAI,CAAC,iBAAiB,EAAE,CAAC;QAEzC,OAAO,CAAC,GAAG,CAAC,0BAA0B,EAAE,OAAO,CAAC,CAAC;QAEjD,oCAAoC;QACpC,6FAA6F;QAC7F,MAAM,WAAW,GAAG,QAAQ,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,CACzC,IAAI,CAAC,WAAW,KAAK,OAAO,CAAC,gBAAgB,CAC9C,CAAC;QAEF,MAAM,WAAW,GAAG,QAAQ,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,CACzC,CAAC,IAAI,CAAC,WAAW,CAClB,CAAC;QAEF,MAAM,eAAe,GAAG,QAAQ,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,CAC7C,IAAI,CAAC,WAAW,KAAK,OAAO,CAAC,gBAAgB,IAAI,IAAI,CAAC,QAAQ,KAAK,YAAY,CAChF,CAAC;QAEF,OAAO,CAAC,GAAG,CAAC,yBAAyB,WAAW,CAAC,MAAM,mBAAmB,WAAW,CAAC,MAAM,uBAAuB,eAAe,CAAC,MAAM,EAAE,CAAC,CAAC;QAE7I,sDAAsD;QACtD,MAAM,YAAY,GAAG,CAAC,GAAG,WAAW,EAAE,GAAG,WAAW,EAAE,GAAG,eAAe,CAAC,CAAC;QAE1E,OAAO,CAAC,GAAG,CAAC,6BAA6B,YAAY,CAAC,MAAM,uBAAuB,OAAO,CAAC,gBAAgB,EAAE,CAAC,CAAC;QAE/G,kCAAkC;QAClC,MAAM,OAAO,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,WAAW,CAAC,KAAK,EAAE,YAAY,EAAE,OAAO,EAAE,CAAC,CAAC,CAAC;QAEhF,8BAA8B;QAC9B,MAAM,QAAQ,GAAgB,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;YAClD,KAAK;YACL,IAAI,EAAE,KAAK,CAAC,IAAI;YAChB,UAAU,EAAE,KAAK,CAAC,UAAU;YAC5B,gBAAgB,EAAE,KAAK,CAAC,IAAI,CAAC,WAAW,KAAK,WAAW,IAAI,KAAK,CAAC,IAAI,CAAC,WAAW,KAAK,aAAa;YACpG,UAAU,EAAE,KAAK,CAAC,UAAU,IAAI,EAAE;SACnC,CAAC,CAAC,CAAC;QAEJ,OAAO,CAAC,GAAG,CAAC,gBAAgB,QAAQ,CAAC,MAAM,kBAAkB,EAC3D,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,IAAI,KAAK,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,UAAU,IAAI,CAAC,CAAC,GAAG,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC;QAEpF,OAAO,QAAQ,CAAC;IAClB,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,cAAc,CAAC,QAAqB,EAAE,gBAAyB,IAAI;QACvE,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAC1B,4CAA4C;YAC5C,MAAM,QAAQ,GAAG,YAAY,CAAC,WAAW,EAAE,CAAC;YAC5C,MAAM,QAAQ,GAAG,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,MAAM,EAAE,CAAC,CAAC;YAC/C,MAAM,OAAO,GAAG,IAAI,CAAC,iBAAiB,EAAE,CAAC;YAEzC,6CAA6C;YAC7C,MAAM,YAAY,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CACvC,CAAC,CAAC,SAAS;gBACX,CAAC,CAAC,CAAC,CAAC,WAAW,IAAI,CAAC,CAAC,WAAW,KAAK,OAAO,CAAC,gBAAgB,IAAI,CAAC,CAAC,QAAQ,KAAK,YAAY,CAAC,CAC9F,CAAC;YAEF,MAAM,QAAQ,GAAG,YAAY,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAE,CAAS,CAAC,QAAQ,IAAI,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;YAElF,OAAO;gBACL,OAAO,EAAE,KAAK;gBACd,OAAO,EAAE,4CAA4C,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE;gBACjG,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;aACpC,CAAC;QACJ,CAAC;QAED,MAAM,OAAO,GAAG,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,+BAA+B;QAE5D,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC;YAClB,OAAO;gBACL,OAAO,EAAE,KAAK;gBACd,OAAO,EAAE,6BAA6B;gBACtC,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;aACpC,CAAC;QACJ,CAAC;QAED,OAAO,CAAC,GAAG,CAAC,sBAAsB,OAAO,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC;QAEvD,8CAA8C;QAC9C,MAAM,UAAU,GAAG,MAAM,IAAI,CAAC,cAAc,CAAC,OAAO,CAAC,OAAO,CAAC,KAAK,EAAE,OAAO,CAAC,IAAI,CAAC,CAAC;QAClF,MAAM,UAAU,GAAG,UAAU,CAAC,UAAU,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,UAAU,CAAC,CAAC,CAAC,OAAO,CAAC,UAAU,CAAC;QAEjG,OAAO,CAAC,GAAG,CAAC,qBAAqB,EAAE,UAAU,CAAC,CAAC;QAE/C,6BAA6B;QAC7B,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,OAAO,CAAC,IAAI,EAAE,UAAU,IAAI,EAAE,CAAC,CAAC;YAE3E,OAAO;gBACL,OAAO,EAAE,MAAM,CAAC,OAAO;gBACvB,OAAO,EAAE,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,KAAK,MAAM,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,KAAK,MAAM,CAAC,OAAO,EAAE;gBACvE,YAAY,EAAE,OAAO,CAAC,IAAI,CAAC,IAAI;gBAC/B,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;aACpC,CAAC;QACJ,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,MAAM,QAAQ,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;YAExE,OAAO;gBACL,OAAO,EAAE,KAAK;gBACd,OAAO,EAAE,KAAK,QAAQ,EAAE;gBACxB,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;aACpC,CAAC;QACJ,CAAC;IACH,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,YAAY,CAAC,KAAa;QAC9B,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,mBAAmB,CAAC,KAAK,CAAC,CAAC;QACvD,OAAO,IAAI,CAAC,cAAc,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC;IAC7C,CAAC;IAED;;OAEG;IACH,oBAAoB;QAClB,MAAM,QAAQ,GAAG,YAAY,CAAC,WAAW,EAAE,CAAC;QAC5C,MAAM,QAAQ,GAAG,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,MAAM,EAAE,CAAC,CAAC;QAC/C,MAAM,OAAO,GAAG,IAAI,CAAC,iBAAiB,EAAE,CAAC;QAEzC,4BAA4B;QAC5B,MAAM,YAAY,GAAG,QAAQ,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,CAC1C,CAAC,IAAI,CAAC,WAAW;YACjB,IAAI,CAAC,WAAW,KAAK,OAAO,CAAC,gBAAgB;YAC7C,IAAI,CAAC,QAAQ,KAAK,YAAY,CAC/B,CAAC;QAEF,mBAAmB;QACnB,MAAM,QAAQ,GAAa,EAAE,CAAC;QAC9B,KAAK,MAAM,IAAI,IAAI,YAAY,EAAE,CAAC;YAChC,MAAM,QAAQ,GAAI,IAAY,CAAC,QAAQ,IAAI,EAAE,CAAC;YAC9C,QAAQ,CAAC,IAAI,CAAC,GAAG,QAAQ,CAAC,CAAC;QAC7B,CAAC;QAED,OAAO,QAAQ,CAAC;IAClB,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,cAAc,CAAC,YAAoB;QACvC,MAAM,QAAQ,GAAG,YAAY,CAAC,WAAW,EAAE,CAAC;QAC5C,MAAM,QAAQ,GAAG,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,MAAM,EAAE,CAAC,CAAC;QAC/C,MAAM,WAAW,GAAG,IAAI,CAAC,gBAAgB,CAAC,cAAc,CAAC,YAAY,EAAE,QAAQ,EAAE,CAAC,CAAC,CAAC;QACpF,OAAO,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;IACtC,CAAC;CACF"}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ParameterExtractor - Extract parameters from natural language queries
|
|
3
|
+
*
|
|
4
|
+
* Supports multiple extraction strategies:
|
|
5
|
+
* - Pattern-based (using tool examples)
|
|
6
|
+
* - Entity extraction (dates, numbers, names)
|
|
7
|
+
* - LLM-based extraction (structured JSON)
|
|
8
|
+
*/
|
|
9
|
+
import type { ToolMetadata } from '../decorators/Tool';
|
|
10
|
+
/**
|
|
11
|
+
* Extracted parameter with metadata
|
|
12
|
+
*/
|
|
13
|
+
export interface ExtractedParameter {
|
|
14
|
+
value: any;
|
|
15
|
+
type: 'string' | 'number' | 'boolean' | 'date' | 'object';
|
|
16
|
+
confidence: number;
|
|
17
|
+
source: 'pattern' | 'entity' | 'llm';
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Parameter extraction result
|
|
21
|
+
*/
|
|
22
|
+
export interface ExtractionResult {
|
|
23
|
+
parameters: any[];
|
|
24
|
+
confidence: number;
|
|
25
|
+
reasoning?: string;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Base interface for extraction strategies
|
|
29
|
+
*/
|
|
30
|
+
export interface ExtractorStrategy {
|
|
31
|
+
name: string;
|
|
32
|
+
priority: number;
|
|
33
|
+
extract(query: string, tool: ToolMetadata): Promise<ExtractionResult | null>;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Main ParameterExtractor orchestrator
|
|
37
|
+
*/
|
|
38
|
+
export declare class ParameterExtractor {
|
|
39
|
+
private strategies;
|
|
40
|
+
constructor();
|
|
41
|
+
/**
|
|
42
|
+
* Register a new extraction strategy
|
|
43
|
+
*/
|
|
44
|
+
registerStrategy(strategy: ExtractorStrategy): void;
|
|
45
|
+
/**
|
|
46
|
+
* Extract parameters from query for a specific tool
|
|
47
|
+
*/
|
|
48
|
+
extract(query: string, tool: ToolMetadata): Promise<ExtractionResult>;
|
|
49
|
+
}
|
|
50
|
+
//# sourceMappingURL=ParameterExtractor.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ParameterExtractor.d.ts","sourceRoot":"","sources":["../../../../src/ai/ParameterExtractor.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAEvD;;GAEG;AACH,MAAM,WAAW,kBAAkB;IACjC,KAAK,EAAE,GAAG,CAAC;IACX,IAAI,EAAE,QAAQ,GAAG,QAAQ,GAAG,SAAS,GAAG,MAAM,GAAG,QAAQ,CAAC;IAC1D,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,SAAS,GAAG,QAAQ,GAAG,KAAK,CAAC;CACtC;AAED;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B,UAAU,EAAE,GAAG,EAAE,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED;;GAEG;AACH,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IAEjB,OAAO,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,YAAY,GAAG,OAAO,CAAC,gBAAgB,GAAG,IAAI,CAAC,CAAC;CAC9E;AAED;;GAEG;AACH,qBAAa,kBAAkB;IAC7B,OAAO,CAAC,UAAU,CAA2B;;IAQ7C;;OAEG;IACH,gBAAgB,CAAC,QAAQ,EAAE,iBAAiB,GAAG,IAAI;IAKnD;;OAEG;IACG,OAAO,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,YAAY,GAAG,OAAO,CAAC,gBAAgB,CAAC;CAqB5E"}
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ParameterExtractor - Extract parameters from natural language queries
|
|
3
|
+
*
|
|
4
|
+
* Supports multiple extraction strategies:
|
|
5
|
+
* - Pattern-based (using tool examples)
|
|
6
|
+
* - Entity extraction (dates, numbers, names)
|
|
7
|
+
* - LLM-based extraction (structured JSON)
|
|
8
|
+
*/
|
|
9
|
+
/**
|
|
10
|
+
* Main ParameterExtractor orchestrator
|
|
11
|
+
*/
|
|
12
|
+
export class ParameterExtractor {
|
|
13
|
+
constructor() {
|
|
14
|
+
this.strategies = [];
|
|
15
|
+
// Register default strategies
|
|
16
|
+
this.registerStrategy(new PatternExtractor());
|
|
17
|
+
this.registerStrategy(new EntityExtractor());
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Register a new extraction strategy
|
|
21
|
+
*/
|
|
22
|
+
registerStrategy(strategy) {
|
|
23
|
+
this.strategies.push(strategy);
|
|
24
|
+
this.strategies.sort((a, b) => b.priority - a.priority);
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Extract parameters from query for a specific tool
|
|
28
|
+
*/
|
|
29
|
+
async extract(query, tool) {
|
|
30
|
+
// Try each strategy in priority order
|
|
31
|
+
for (const strategy of this.strategies) {
|
|
32
|
+
try {
|
|
33
|
+
const result = await strategy.extract(query, tool);
|
|
34
|
+
if (result && result.confidence >= 60) {
|
|
35
|
+
console.log(`✅ [ParamExtract] Used strategy: ${strategy.name}`, result);
|
|
36
|
+
return result;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
catch (error) {
|
|
40
|
+
console.warn(`[ParamExtract] Strategy ${strategy.name} failed:`, error);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
// No successful extraction
|
|
44
|
+
return {
|
|
45
|
+
parameters: [],
|
|
46
|
+
confidence: 0,
|
|
47
|
+
reasoning: 'No extraction strategy succeeded'
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Pattern-based extraction using tool examples
|
|
53
|
+
*/
|
|
54
|
+
class PatternExtractor {
|
|
55
|
+
constructor() {
|
|
56
|
+
this.name = 'pattern';
|
|
57
|
+
this.priority = 80;
|
|
58
|
+
}
|
|
59
|
+
async extract(query, tool) {
|
|
60
|
+
const examples = tool.examples || [];
|
|
61
|
+
if (examples.length === 0) {
|
|
62
|
+
return null;
|
|
63
|
+
}
|
|
64
|
+
const lowerQuery = query.toLowerCase().trim();
|
|
65
|
+
// Try to match each example pattern
|
|
66
|
+
for (const example of examples) {
|
|
67
|
+
const pattern = example.toLowerCase();
|
|
68
|
+
// Check if query starts with the pattern
|
|
69
|
+
if (lowerQuery.startsWith(pattern)) {
|
|
70
|
+
// Extract trailing text as parameter
|
|
71
|
+
const trailing = query.substring(example.length).trim();
|
|
72
|
+
if (trailing) {
|
|
73
|
+
console.log(`🔍 [PatternExtract] Matched: "${example}" → param: "${trailing}"`);
|
|
74
|
+
return {
|
|
75
|
+
parameters: [trailing],
|
|
76
|
+
confidence: 90,
|
|
77
|
+
reasoning: `Matched pattern: "${example}"`
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
// Check if pattern contains a placeholder (e.g., "open blog {title}")
|
|
82
|
+
const placeholderMatch = pattern.match(/\{(\w+)\}/);
|
|
83
|
+
if (placeholderMatch) {
|
|
84
|
+
// Create a regex from the pattern
|
|
85
|
+
const regexPattern = pattern.replace(/\{(\w+)\}/g, '(.+?)');
|
|
86
|
+
const regex = new RegExp(`^${regexPattern}$`, 'i');
|
|
87
|
+
const match = lowerQuery.match(regex);
|
|
88
|
+
if (match && match[1]) {
|
|
89
|
+
console.log(`🔍 [PatternExtract] Placeholder match: "${example}" → param: "${match[1]}"`);
|
|
90
|
+
return {
|
|
91
|
+
parameters: [match[1].trim()],
|
|
92
|
+
confidence: 95,
|
|
93
|
+
reasoning: `Matched placeholder in: "${example}"`
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
return null;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* Entity extraction for common types (numbers, dates, etc.)
|
|
103
|
+
*/
|
|
104
|
+
class EntityExtractor {
|
|
105
|
+
constructor() {
|
|
106
|
+
this.name = 'entity';
|
|
107
|
+
this.priority = 60;
|
|
108
|
+
}
|
|
109
|
+
async extract(query, tool) {
|
|
110
|
+
const parameters = [];
|
|
111
|
+
// Extract numbers
|
|
112
|
+
const numberMatch = query.match(/\d+/);
|
|
113
|
+
if (numberMatch) {
|
|
114
|
+
parameters.push(parseInt(numberMatch[0], 10));
|
|
115
|
+
}
|
|
116
|
+
// Extract quoted strings
|
|
117
|
+
const quotedMatch = query.match(/"([^"]+)"/);
|
|
118
|
+
if (quotedMatch) {
|
|
119
|
+
parameters.push(quotedMatch[1]);
|
|
120
|
+
}
|
|
121
|
+
// Extract common entities (colors, themes, etc.)
|
|
122
|
+
const colorMatch = query.match(/\b(red|blue|green|dark|light|black|white)\b/i);
|
|
123
|
+
if (colorMatch) {
|
|
124
|
+
parameters.push(colorMatch[1].toLowerCase());
|
|
125
|
+
}
|
|
126
|
+
if (parameters.length > 0) {
|
|
127
|
+
return {
|
|
128
|
+
parameters,
|
|
129
|
+
confidence: 70,
|
|
130
|
+
reasoning: `Extracted ${parameters.length} entities`
|
|
131
|
+
};
|
|
132
|
+
}
|
|
133
|
+
return null;
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
//# sourceMappingURL=ParameterExtractor.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ParameterExtractor.js","sourceRoot":"","sources":["../../../../src/ai/ParameterExtractor.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SuggestionEngine - "Did You Mean?" system for invalid queries
|
|
3
|
+
*
|
|
4
|
+
* Provides helpful suggestions when user queries don't match any tools:
|
|
5
|
+
* - Typo detection (Levenshtein distance)
|
|
6
|
+
* - Similar command suggestions
|
|
7
|
+
* - Available command list
|
|
8
|
+
*/
|
|
9
|
+
import type { ToolMetadata } from '../decorators/Tool';
|
|
10
|
+
/**
|
|
11
|
+
* Suggestion with confidence
|
|
12
|
+
*/
|
|
13
|
+
export interface Suggestion {
|
|
14
|
+
text: string;
|
|
15
|
+
confidence: number;
|
|
16
|
+
type: 'typo' | 'similar' | 'example' | 'category';
|
|
17
|
+
tool?: ToolMetadata;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* SuggestionEngine for generating "Did You Mean?" prompts
|
|
21
|
+
*/
|
|
22
|
+
export declare class SuggestionEngine {
|
|
23
|
+
/**
|
|
24
|
+
* Generate suggestions for an invalid/ambiguous query
|
|
25
|
+
* @param query User's query
|
|
26
|
+
* @param tools Available tools
|
|
27
|
+
* @param maxSuggestions Maximum number of suggestions to return
|
|
28
|
+
*/
|
|
29
|
+
getSuggestions(query: string, tools: ToolMetadata[], maxSuggestions?: number): Suggestion[];
|
|
30
|
+
/**
|
|
31
|
+
* Format suggestions into a user-friendly message
|
|
32
|
+
*/
|
|
33
|
+
formatSuggestions(suggestions: Suggestion[]): string;
|
|
34
|
+
/**
|
|
35
|
+
* Match query to a category
|
|
36
|
+
*/
|
|
37
|
+
private matchCategory;
|
|
38
|
+
/**
|
|
39
|
+
* Calculate Levenshtein distance between two strings
|
|
40
|
+
*/
|
|
41
|
+
private levenshtein;
|
|
42
|
+
}
|
|
43
|
+
//# sourceMappingURL=SuggestionEngine.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SuggestionEngine.d.ts","sourceRoot":"","sources":["../../../../src/ai/SuggestionEngine.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAEvD;;GAEG;AACH,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,EAAE,MAAM,GAAG,SAAS,GAAG,SAAS,GAAG,UAAU,CAAC;IAClD,IAAI,CAAC,EAAE,YAAY,CAAC;CACrB;AAED;;GAEG;AACH,qBAAa,gBAAgB;IAC3B;;;;;OAKG;IACH,cAAc,CACZ,KAAK,EAAE,MAAM,EACb,KAAK,EAAE,YAAY,EAAE,EACrB,cAAc,GAAE,MAAU,GACzB,UAAU,EAAE;IAgFf;;OAEG;IACH,iBAAiB,CAAC,WAAW,EAAE,UAAU,EAAE,GAAG,MAAM;IA4BpD;;OAEG;IACH,OAAO,CAAC,aAAa;IAkBrB;;OAEG;IACH,OAAO,CAAC,WAAW;CA2BpB"}
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SuggestionEngine - "Did You Mean?" system for invalid queries
|
|
3
|
+
*
|
|
4
|
+
* Provides helpful suggestions when user queries don't match any tools:
|
|
5
|
+
* - Typo detection (Levenshtein distance)
|
|
6
|
+
* - Similar command suggestions
|
|
7
|
+
* - Available command list
|
|
8
|
+
*/
|
|
9
|
+
/**
|
|
10
|
+
* SuggestionEngine for generating "Did You Mean?" prompts
|
|
11
|
+
*/
|
|
12
|
+
export class SuggestionEngine {
|
|
13
|
+
/**
|
|
14
|
+
* Generate suggestions for an invalid/ambiguous query
|
|
15
|
+
* @param query User's query
|
|
16
|
+
* @param tools Available tools
|
|
17
|
+
* @param maxSuggestions Maximum number of suggestions to return
|
|
18
|
+
*/
|
|
19
|
+
getSuggestions(query, tools, maxSuggestions = 5) {
|
|
20
|
+
const suggestions = [];
|
|
21
|
+
const lowerQuery = query.toLowerCase().trim();
|
|
22
|
+
// 1. Check for typos (Levenshtein distance ≤ 3)
|
|
23
|
+
for (const tool of tools) {
|
|
24
|
+
const examples = tool.examples || [];
|
|
25
|
+
const allPhrases = [tool.name, ...examples];
|
|
26
|
+
for (const phrase of allPhrases) {
|
|
27
|
+
const distance = this.levenshtein(lowerQuery, phrase.toLowerCase());
|
|
28
|
+
if (distance <= 3 && distance > 0) {
|
|
29
|
+
const confidence = Math.round((1 - distance / Math.max(lowerQuery.length, phrase.length)) * 100);
|
|
30
|
+
suggestions.push({
|
|
31
|
+
text: phrase,
|
|
32
|
+
confidence,
|
|
33
|
+
type: 'typo',
|
|
34
|
+
tool
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
// 2. Find similar commands (keyword overlap)
|
|
40
|
+
const queryWords = lowerQuery.split(/\s+/);
|
|
41
|
+
for (const tool of tools) {
|
|
42
|
+
const examples = tool.examples || [];
|
|
43
|
+
const toolWords = [
|
|
44
|
+
...tool.name.toLowerCase().split(/\s+/),
|
|
45
|
+
...(tool.description?.toLowerCase().split(/\s+/) || []),
|
|
46
|
+
...examples.flatMap((e) => e.toLowerCase().split(/\s+/))
|
|
47
|
+
];
|
|
48
|
+
const overlap = queryWords.filter(w => toolWords.includes(w)).length;
|
|
49
|
+
if (overlap > 0) {
|
|
50
|
+
const confidence = Math.round((overlap / queryWords.length) * 100);
|
|
51
|
+
// Use first example if available, otherwise tool name
|
|
52
|
+
const text = examples[0] || tool.name;
|
|
53
|
+
suggestions.push({
|
|
54
|
+
text,
|
|
55
|
+
confidence,
|
|
56
|
+
type: 'similar',
|
|
57
|
+
tool
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
// 3. Category-based suggestions
|
|
62
|
+
const categoryMatch = this.matchCategory(lowerQuery);
|
|
63
|
+
if (categoryMatch) {
|
|
64
|
+
const categoryTools = tools.filter(t => t.category === categoryMatch);
|
|
65
|
+
for (const tool of categoryTools.slice(0, 3)) {
|
|
66
|
+
const examples = tool.examples || [];
|
|
67
|
+
const text = examples[0] || tool.name;
|
|
68
|
+
suggestions.push({
|
|
69
|
+
text,
|
|
70
|
+
confidence: 60,
|
|
71
|
+
type: 'category',
|
|
72
|
+
tool
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
// Sort by confidence and deduplicate
|
|
77
|
+
const sorted = suggestions
|
|
78
|
+
.sort((a, b) => b.confidence - a.confidence)
|
|
79
|
+
.filter((s, i, arr) =>
|
|
80
|
+
// Remove duplicates (same text)
|
|
81
|
+
i === arr.findIndex(other => other.text === s.text))
|
|
82
|
+
.slice(0, maxSuggestions);
|
|
83
|
+
return sorted;
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Format suggestions into a user-friendly message
|
|
87
|
+
*/
|
|
88
|
+
formatSuggestions(suggestions) {
|
|
89
|
+
if (suggestions.length === 0) {
|
|
90
|
+
return 'No suggestions available. Try typing "help" to see all commands.';
|
|
91
|
+
}
|
|
92
|
+
const typos = suggestions.filter(s => s.type === 'typo');
|
|
93
|
+
const similar = suggestions.filter(s => s.type === 'similar' || s.type === 'category');
|
|
94
|
+
let message = '';
|
|
95
|
+
if (typos.length > 0) {
|
|
96
|
+
message += '❓ Did you mean?\n';
|
|
97
|
+
for (const typo of typos.slice(0, 3)) {
|
|
98
|
+
message += ` • "${typo.text}"\n`;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
if (similar.length > 0) {
|
|
102
|
+
if (message)
|
|
103
|
+
message += '\n';
|
|
104
|
+
message += '💡 Similar commands:\n';
|
|
105
|
+
for (const sim of similar.slice(0, 3)) {
|
|
106
|
+
message += ` • "${sim.text}"\n`;
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
return message.trim();
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* Match query to a category
|
|
113
|
+
*/
|
|
114
|
+
matchCategory(query) {
|
|
115
|
+
const categories = {
|
|
116
|
+
'navigation': ['go', 'open', 'navigate', 'show', 'view', 'page'],
|
|
117
|
+
'theme': ['theme', 'color', 'dark', 'light', 'appearance'],
|
|
118
|
+
'data': ['load', 'fetch', 'get', 'data', 'retrieve'],
|
|
119
|
+
'form': ['submit', 'save', 'form', 'input', 'enter'],
|
|
120
|
+
'state': ['set', 'change', 'update', 'modify', 'status']
|
|
121
|
+
};
|
|
122
|
+
for (const [category, keywords] of Object.entries(categories)) {
|
|
123
|
+
if (keywords.some(kw => query.includes(kw))) {
|
|
124
|
+
return category;
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
return null;
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
130
|
+
* Calculate Levenshtein distance between two strings
|
|
131
|
+
*/
|
|
132
|
+
levenshtein(a, b) {
|
|
133
|
+
const matrix = [];
|
|
134
|
+
for (let i = 0; i <= b.length; i++) {
|
|
135
|
+
matrix[i] = [i];
|
|
136
|
+
}
|
|
137
|
+
for (let j = 0; j <= a.length; j++) {
|
|
138
|
+
matrix[0][j] = j;
|
|
139
|
+
}
|
|
140
|
+
for (let i = 1; i <= b.length; i++) {
|
|
141
|
+
for (let j = 1; j <= a.length; j++) {
|
|
142
|
+
if (b.charAt(i - 1) === a.charAt(j - 1)) {
|
|
143
|
+
matrix[i][j] = matrix[i - 1][j - 1];
|
|
144
|
+
}
|
|
145
|
+
else {
|
|
146
|
+
matrix[i][j] = Math.min(matrix[i - 1][j - 1] + 1, matrix[i][j - 1] + 1, matrix[i - 1][j] + 1);
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
return matrix[b.length][a.length];
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
//# sourceMappingURL=SuggestionEngine.js.map
|