@@ -2,9 +2,11 @@ import chalk from 'chalk';
22import { WatchableSchema } from '../models/analyzer' ;
33import { VectorSearch } from '../rag/vector-search' ;
44import { OpenRouterClient , ChatMessage } from '../llm/openrouter' ;
5+ import { HybridRetrieval } from '../rag/hybrid-retrieval' ;
56import * as readline from 'readline' ;
67
78const vectorSearch = new VectorSearch ( ) ;
9+ let hybridRetrieval : HybridRetrieval ;
810
911export async function runChat ( watchableSchema : WatchableSchema ) : Promise < void > {
1012 console . log (
@@ -17,6 +19,7 @@ export async function runChat(watchableSchema: WatchableSchema): Promise<void> {
1719 console . log ( ) ;
1820
1921 await vectorSearch . initialize ( watchableSchema . models ) ;
22+ hybridRetrieval = new HybridRetrieval ( vectorSearch , watchableSchema . models ) ;
2023
2124 const apiKey = process . env . OPENROUTER_API_KEY ;
2225 if ( ! apiKey ) {
@@ -100,9 +103,17 @@ export async function runChat(watchableSchema: WatchableSchema): Promise<void> {
100103 } catch ( error ) {
101104 console . log ( chalk . red ( '❌ Failed to reload schema\n' ) ) ;
102105 }
103- } else if ( userInput . startsWith ( '/debug ' ) ) {
104- const query = userInput . substring ( 7 ) . trim ( ) ;
105- await debugSimilarity ( query , vectorSearch ) ;
106+ } else if ( userInput . startsWith ( '/explain ' ) ) {
107+ const query = userInput . substring ( 9 ) . trim ( ) ;
108+ const explanation = await hybridRetrieval . explainSelection ( query ) ;
109+
110+ console . log ( chalk . yellow ( '\n🔍 Selection Explanation:' ) ) ;
111+ console . log ( chalk . gray ( '─' . repeat ( 60 ) ) ) ;
112+ explanation . slice ( 0 , 10 ) . forEach ( ( item , i ) => {
113+ console . log ( chalk . cyan ( `${ i + 1 } . ${ item . model } ` ) ) ;
114+ console . log ( chalk . gray ( ` ${ item . reason } ` ) ) ;
115+ } ) ;
116+ console . log ( chalk . gray ( '─' . repeat ( 60 ) + '\n' ) ) ;
106117 } else if ( userInput . startsWith ( '/model ' ) ) {
107118 const modelName = userInput . substring ( 7 ) . trim ( ) ;
108119 try {
@@ -118,13 +129,7 @@ export async function runChat(watchableSchema: WatchableSchema): Promise<void> {
118129 console . log ( chalk . red ( `❌ Unknown command: ${ userInput } ` ) ) ;
119130 console . log ( chalk . gray ( 'Type /help for available commands.\n' ) ) ;
120131 } else {
121- await handleQuery (
122- userInput ,
123- llm ,
124- watchableSchema ,
125- chatHistory ,
126- vectorSearch
127- ) ;
132+ await handleQuery ( userInput , llm , watchableSchema , chatHistory ) ;
128133 }
129134
130135 rl . prompt ( ) ;
@@ -147,34 +152,36 @@ async function handleQuery(
147152 query : string ,
148153 llm : OpenRouterClient ,
149154 watchableSchema : WatchableSchema ,
150- chatHistory : ChatMessage [ ] ,
151- vectorSearch : VectorSearch
155+ chatHistory : ChatMessage [ ]
152156) : Promise < void > {
153157 try {
154158 process . stdout . write ( chalk . blue ( '🤔 Thinking... ' ) ) ;
155159
156- // Find relevant models using vector search
157- const relevantModels = await vectorSearch . findRelevant ( query , 5 , 0.25 ) ;
160+ const relevantModels = await hybridRetrieval . findRelevant ( query , {
161+ topK : 5 ,
162+ threshold : 0.25 ,
163+ includeRelated : true ,
164+ } ) ;
158165
159166 readline . clearLine ( process . stdout , 0 ) ;
160167 readline . cursorTo ( process . stdout , 0 ) ;
161168
162- // Show which models were selected
163169 if ( relevantModels . length > 0 ) {
164170 console . log (
165171 chalk . magenta (
166172 `📊 Using ${ relevantModels . length } /${ watchableSchema . models . length } relevant table(s):`
167173 )
168174 ) ;
169- relevantModels . forEach ( ( m ) => console . log ( chalk . gray ( ` • ${ m . name } ` ) ) ) ;
175+ relevantModels . forEach ( ( m ) =>
176+ console . log ( chalk . gray ( ` • ${ m . name } (${ m . tableName } )` ) )
177+ ) ;
170178 console . log ( ) ;
171179 } else {
172180 console . log (
173181 chalk . yellow ( '⚠️ No relevant tables found, using all models\n' )
174182 ) ;
175183 }
176184
177- // Generate SQL with filtered models
178185 const modelsToUse =
179186 relevantModels . length > 0 ? relevantModels : watchableSchema . models ;
180187 const response = await llm . generateSQL ( query , modelsToUse , chatHistory ) ;
@@ -203,33 +210,6 @@ async function handleQuery(
203210 }
204211}
205212
206- async function debugSimilarity (
207- query : string ,
208- vectorSearch : VectorSearch
209- ) : Promise < void > {
210- try {
211- const scores = await vectorSearch . getScores ( query ) ;
212- console . log (
213- chalk . yellow ( '\n🔍 Similarity scores for:' ) ,
214- chalk . white ( query )
215- ) ;
216- console . log ( chalk . gray ( '─' . repeat ( 60 ) ) ) ;
217- scores . slice ( 0 , 10 ) . forEach ( ( s , i ) => {
218- const percentage = ( s . score * 100 ) . toFixed ( 1 ) ;
219- const bar = '█' . repeat ( Math . floor ( s . score * 20 ) ) ;
220- console . log (
221- `${ i + 1 } . ${ chalk . cyan ( s . name . padEnd ( 20 ) ) } ${ bar } ${ percentage } %`
222- ) ;
223- } ) ;
224- console . log ( chalk . gray ( '─' . repeat ( 60 ) + '\n' ) ) ;
225- } catch ( error ) {
226- console . log (
227- chalk . red ( '❌ Error:' ) ,
228- error instanceof Error ? error . message : 'Failed to get scores'
229- ) ;
230- }
231- }
232-
233213function displayHelp ( ) : void {
234214 console . log ( chalk . yellow ( '📚 Available commands:' ) ) ;
235215 console . log ( chalk . gray ( '─' . repeat ( 60 ) ) ) ;
@@ -244,8 +224,8 @@ function displayHelp(): void {
244224 chalk . gray ( '- List all available models with details' )
245225 ) ;
246226 console . log (
247- chalk . cyan ( ' /debug ' ) +
248- chalk . gray ( '- Debug similarity scores (e.g., /debug show users)' )
227+ chalk . cyan ( ' /explain ' ) +
228+ chalk . gray ( '- Explain similarity scores (e.g., /explain show users)' )
249229 ) ;
250230 console . log ( chalk . cyan ( ' /history ' ) + chalk . gray ( '- Show chat history' ) ) ;
251231 console . log (
0 commit comments