88 "strings"
99 "sync"
1010
11+ "github.com/ethpandaops/xcli/pkg/ai"
1112 "github.com/ethpandaops/xcli/pkg/config"
1213 "github.com/ethpandaops/xcli/pkg/constants"
1314 "github.com/ethpandaops/xcli/pkg/seeddata"
@@ -307,112 +308,117 @@ func runGenerateTransformationTest(
307308 return fmt .Errorf ("failed to detect range columns: %w" , err )
308309 }
309310
310- discoveryResult , err = seeddata .FallbackRangeDiscovery (ctx , gen , externalModels , network , rangeInfos , duration , labCfg .Repos .XatuCBT )
311- if err != nil {
312- return fmt .Errorf ("fallback range discovery failed: %w" , err )
313- }
314- } else if discoveryClient , discoveryErr := seeddata .NewClaudeDiscoveryClient (log , gen ); discoveryErr != nil {
315- ui .Warning (fmt .Sprintf ("Claude CLI not available: %v" , discoveryErr ))
316- ui .Info ("Falling back to heuristic range detection" )
317-
318- // Fallback to heuristic detection
319- var rangeInfos map [string ]* seeddata.RangeColumnInfo
320-
321- rangeInfos , err = seeddata .DetectRangeColumnsForModels (externalModels , labCfg .Repos .XatuCBT )
322- if err != nil {
323- return fmt .Errorf ("failed to detect range columns: %w" , err )
324- }
325-
326311 discoveryResult , err = seeddata .FallbackRangeDiscovery (ctx , gen , externalModels , network , rangeInfos , duration , labCfg .Repos .XatuCBT )
327312 if err != nil {
328313 return fmt .Errorf ("fallback range discovery failed: %w" , err )
329314 }
330315 } else {
331- // Gather schema information
332- schemaSpinner := ui .NewSpinner ("Gathering schema information" )
316+ engine , engineErr := ai .NewEngine (ai .DefaultProvider , log )
333317
334- schemaInfo , schemaErr := discoveryClient .GatherSchemaInfo (ctx , externalModels , network , labCfg .Repos .XatuCBT )
335- if schemaErr != nil {
336- schemaSpinner .Fail ("Failed to gather schema info" )
318+ discoveryClient := seeddata .NewClaudeDiscoveryClient (log , gen , engine )
319+ if engineErr != nil || ! discoveryClient .IsAvailable () {
320+ ui .Warning ("AI engine not available" )
321+ ui .Info ("Falling back to heuristic range detection" )
337322
338- return fmt . Errorf ( "failed to gather schema info: %w" , schemaErr )
339- }
323+ // Fallback to heuristic detection
324+ var rangeInfos map [ string ] * seeddata. RangeColumnInfo
340325
341- schemaSpinner .Success (fmt .Sprintf ("Schema info gathered for %d models" , len (schemaInfo )))
326+ rangeInfos , err = seeddata .DetectRangeColumnsForModels (externalModels , labCfg .Repos .XatuCBT )
327+ if err != nil {
328+ return fmt .Errorf ("failed to detect range columns: %w" , err )
329+ }
342330
343- // Display detected range info
344- for _ , schema := range schemaInfo {
345- if schema . RangeInfo != nil {
346- status := "detected"
347- if ! schema . RangeInfo . Detected {
348- status = "default"
349- }
331+ discoveryResult , err = seeddata . FallbackRangeDiscovery ( ctx , gen , externalModels , network , rangeInfos , duration , labCfg . Repos . XatuCBT )
332+ if err != nil {
333+ return fmt . Errorf ( "fallback range discovery failed: %w" , err )
334+ }
335+ } else {
336+ // Gather schema information
337+ schemaSpinner := ui . NewSpinner ( "Gathering schema information" )
350338
351- rangeStr := ""
352- if schema .RangeInfo .MinValue != "" && schema .RangeInfo .MaxValue != "" {
353- rangeStr = fmt .Sprintf (" [%s → %s]" , schema .RangeInfo .MinValue , schema .RangeInfo .MaxValue )
354- }
339+ schemaInfo , schemaErr := discoveryClient .GatherSchemaInfo (ctx , externalModels , network , labCfg .Repos .XatuCBT )
340+ if schemaErr != nil {
341+ schemaSpinner .Fail ("Failed to gather schema info" )
355342
356- ui . Info ( fmt .Sprintf ( " • %s : %s (%s)%s " , schema . Model , schema . RangeInfo . Column , status , rangeStr ) )
343+ return fmt .Errorf ( "failed to gather schema info : %w " , schemaErr )
357344 }
358- }
359345
360- // Read transformation SQL
361- transformationSQL , sqlErr := seeddata .ReadTransformationSQL (model , labCfg .Repos .XatuCBT )
362- if sqlErr != nil {
363- return fmt .Errorf ("failed to read transformation SQL: %w" , sqlErr )
364- }
346+ schemaSpinner .Success (fmt .Sprintf ("Schema info gathered for %d models" , len (schemaInfo )))
365347
366- // Read intermediate dependency SQL (for WHERE clause analysis)
367- intermediateSQL , intErr := seeddata .ReadIntermediateSQL (tree , labCfg .Repos .XatuCBT )
368- if intErr != nil {
369- ui .Warning (fmt .Sprintf ("Could not read intermediate SQL: %v" , intErr ))
370- // Continue without intermediate SQL - not critical
371- }
348+ // Display detected range info
349+ for _ , schema := range schemaInfo {
350+ if schema .RangeInfo != nil {
351+ status := "detected"
352+ if ! schema .RangeInfo .Detected {
353+ status = "default"
354+ }
372355
373- // Convert to IntermediateSQL slice
374- var intermediateModels []seeddata.IntermediateSQL
375- for modelName , sql := range intermediateSQL {
376- intermediateModels = append (intermediateModels , seeddata.IntermediateSQL {
377- Model : modelName ,
378- SQL : sql ,
379- })
380- }
356+ rangeStr := ""
357+ if schema .RangeInfo .MinValue != "" && schema .RangeInfo .MaxValue != "" {
358+ rangeStr = fmt .Sprintf (" [%s → %s]" , schema .RangeInfo .MinValue , schema .RangeInfo .MaxValue )
359+ }
381360
382- if len ( intermediateModels ) > 0 {
383- ui . Info ( fmt . Sprintf ( "Including %d intermediate model(s) for WHERE clause analysis" , len ( intermediateModels )))
384- }
361+ ui . Info ( fmt . Sprintf ( " • %s: %s (%s)%s" , schema . Model , schema . RangeInfo . Column , status , rangeStr ))
362+ }
363+ }
385364
386- // Invoke Claude for analysis
387- ui .Blank ()
365+ // Read transformation SQL
366+ transformationSQL , sqlErr := seeddata .ReadTransformationSQL (model , labCfg .Repos .XatuCBT )
367+ if sqlErr != nil {
368+ return fmt .Errorf ("failed to read transformation SQL: %w" , sqlErr )
369+ }
388370
389- analysisSpinner := ui .NewSpinner ("Analyzing correlation strategy with Claude" )
371+ // Read intermediate dependency SQL (for WHERE clause analysis)
372+ intermediateSQL , intErr := seeddata .ReadIntermediateSQL (tree , labCfg .Repos .XatuCBT )
373+ if intErr != nil {
374+ ui .Warning (fmt .Sprintf ("Could not read intermediate SQL: %v" , intErr ))
375+ // Continue without intermediate SQL - not critical
376+ }
390377
391- discoveryResult , err = discoveryClient .AnalyzeRanges (ctx , seeddata.DiscoveryInput {
392- TransformationModel : model ,
393- TransformationSQL : transformationSQL ,
394- IntermediateModels : intermediateModels ,
395- Network : network ,
396- Duration : duration ,
397- ExternalModels : schemaInfo ,
398- })
399- if err != nil {
400- analysisSpinner .Fail ("AI analysis failed" )
401- ui .Warning (fmt .Sprintf ("Claude analysis failed: %v" , err ))
402- ui .Info ("Falling back to heuristic range detection" )
378+ // Convert to IntermediateSQL slice
379+ var intermediateModels []seeddata.IntermediateSQL
380+ for modelName , sql := range intermediateSQL {
381+ intermediateModels = append (intermediateModels , seeddata.IntermediateSQL {
382+ Model : modelName ,
383+ SQL : sql ,
384+ })
385+ }
403386
404- // Fallback to heuristic detection
405- rangeInfos , rangeErr := seeddata .DetectRangeColumnsForModels (externalModels , labCfg .Repos .XatuCBT )
406- if rangeErr != nil {
407- return fmt .Errorf ("failed to detect range columns: %w" , rangeErr )
387+ if len (intermediateModels ) > 0 {
388+ ui .Info (fmt .Sprintf ("Including %d intermediate model(s) for WHERE clause analysis" , len (intermediateModels )))
408389 }
409390
410- discoveryResult , err = seeddata .FallbackRangeDiscovery (ctx , gen , externalModels , network , rangeInfos , duration , labCfg .Repos .XatuCBT )
391+ // Invoke Claude for analysis
392+ ui .Blank ()
393+
394+ analysisSpinner := ui .NewSpinner ("Analyzing correlation strategy with Claude" )
395+
396+ discoveryResult , err = discoveryClient .AnalyzeRanges (ctx , seeddata.DiscoveryInput {
397+ TransformationModel : model ,
398+ TransformationSQL : transformationSQL ,
399+ IntermediateModels : intermediateModels ,
400+ Network : network ,
401+ Duration : duration ,
402+ ExternalModels : schemaInfo ,
403+ })
411404 if err != nil {
412- return fmt .Errorf ("fallback range discovery failed: %w" , err )
405+ analysisSpinner .Fail ("AI analysis failed" )
406+ ui .Warning (fmt .Sprintf ("Claude analysis failed: %v" , err ))
407+ ui .Info ("Falling back to heuristic range detection" )
408+
409+ // Fallback to heuristic detection
410+ rangeInfos , rangeErr := seeddata .DetectRangeColumnsForModels (externalModels , labCfg .Repos .XatuCBT )
411+ if rangeErr != nil {
412+ return fmt .Errorf ("failed to detect range columns: %w" , rangeErr )
413+ }
414+
415+ discoveryResult , err = seeddata .FallbackRangeDiscovery (ctx , gen , externalModels , network , rangeInfos , duration , labCfg .Repos .XatuCBT )
416+ if err != nil {
417+ return fmt .Errorf ("fallback range discovery failed: %w" , err )
418+ }
419+ } else {
420+ analysisSpinner .Success (fmt .Sprintf ("Strategy generated (confidence: %.0f%%)" , discoveryResult .OverallConfidence * 100 ))
413421 }
414- } else {
415- analysisSpinner .Success (fmt .Sprintf ("Strategy generated (confidence: %.0f%%)" , discoveryResult .OverallConfidence * 100 ))
416422 }
417423 }
418424
@@ -995,11 +1001,18 @@ func promptForTransformationModel(xatuCBTPath string) (string, error) {
9951001func generateAIAssertions (ctx context.Context , log logrus.FieldLogger , model string , externalModels []string , xatuCBTPath string ) ([]seeddata.Assertion , error ) {
9961002 aiSpinner := ui .NewSpinner ("Analyzing transformation SQL with Claude" )
9971003
998- client , err := seeddata .NewClaudeAssertionClient (log )
999- if err != nil {
1000- aiSpinner .Fail ("Claude CLI not available" )
1004+ engine , engineErr := ai .NewEngine (ai .DefaultProvider , log )
1005+ if engineErr != nil {
1006+ aiSpinner .Fail ("AI engine not available" )
1007+
1008+ return nil , fmt .Errorf ("AI engine not available: %w" , engineErr )
1009+ }
10011010
1002- return nil , fmt .Errorf ("claude CLI not available: %w" , err )
1011+ client := seeddata .NewClaudeAssertionClient (log , engine )
1012+ if ! client .IsAvailable () {
1013+ aiSpinner .Fail ("AI engine not available" )
1014+
1015+ return nil , fmt .Errorf ("AI engine is not available" )
10031016 }
10041017
10051018 // Read transformation SQL
@@ -1185,58 +1198,17 @@ func runSingleModelGeneration(
11851198 return fmt .Errorf ("failed to detect range columns: %w" , rangeErr )
11861199 }
11871200
1188- discoveryResult , err = seeddata .FallbackRangeDiscovery (ctx , gen , externalModels , network , rangeInfos , duration , labCfg .Repos .XatuCBT )
1189- if err != nil {
1190- return fmt .Errorf ("fallback range discovery failed: %w" , err )
1191- }
1192- } else if discoveryClient , discoveryErr := seeddata .NewClaudeDiscoveryClient (log , gen ); discoveryErr != nil {
1193- // Claude not available, use heuristics
1194- logInfo ("Claude unavailable, using heuristic range detection" )
1195-
1196- rangeInfos , rangeErr := seeddata .DetectRangeColumnsForModels (externalModels , labCfg .Repos .XatuCBT )
1197- if rangeErr != nil {
1198- return fmt .Errorf ("failed to detect range columns: %w" , rangeErr )
1199- }
1200-
12011201 discoveryResult , err = seeddata .FallbackRangeDiscovery (ctx , gen , externalModels , network , rangeInfos , duration , labCfg .Repos .XatuCBT )
12021202 if err != nil {
12031203 return fmt .Errorf ("fallback range discovery failed: %w" , err )
12041204 }
12051205 } else {
1206- // Use Claude for analysis
1207- logInfo ("Analyzing with Claude AI" )
1208-
1209- schemaInfo , schemaErr := discoveryClient .GatherSchemaInfo (ctx , externalModels , network , labCfg .Repos .XatuCBT )
1210- if schemaErr != nil {
1211- return fmt .Errorf ("failed to gather schema info: %w" , schemaErr )
1212- }
1213-
1214- transformationSQL , sqlErr := seeddata .ReadTransformationSQL (model , labCfg .Repos .XatuCBT )
1215- if sqlErr != nil {
1216- return fmt .Errorf ("failed to read transformation SQL: %w" , sqlErr )
1217- }
1218-
1219- intermediateSQL , _ := seeddata .ReadIntermediateSQL (tree , labCfg .Repos .XatuCBT )
1220-
1221- var intermediateModels []seeddata.IntermediateSQL
1222- for modelName , sql := range intermediateSQL {
1223- intermediateModels = append (intermediateModels , seeddata.IntermediateSQL {
1224- Model : modelName ,
1225- SQL : sql ,
1226- })
1227- }
1206+ engine , engineErr := ai .NewEngine (ai .DefaultProvider , log )
12281207
1229- discoveryResult , err = discoveryClient .AnalyzeRanges (ctx , seeddata.DiscoveryInput {
1230- TransformationModel : model ,
1231- TransformationSQL : transformationSQL ,
1232- IntermediateModels : intermediateModels ,
1233- Network : network ,
1234- Duration : duration ,
1235- ExternalModels : schemaInfo ,
1236- })
1237- if err != nil {
1238- // Fallback to heuristics
1239- logInfo ("Claude analysis failed, falling back to heuristics" )
1208+ discoveryClient := seeddata .NewClaudeDiscoveryClient (log , gen , engine )
1209+ if engineErr != nil || ! discoveryClient .IsAvailable () {
1210+ // AI not available, use heuristics
1211+ logInfo ("AI engine unavailable, using heuristic range detection" )
12401212
12411213 rangeInfos , rangeErr := seeddata .DetectRangeColumnsForModels (externalModels , labCfg .Repos .XatuCBT )
12421214 if rangeErr != nil {
@@ -1248,7 +1220,53 @@ func runSingleModelGeneration(
12481220 return fmt .Errorf ("fallback range discovery failed: %w" , err )
12491221 }
12501222 } else {
1251- logInfo (fmt .Sprintf ("Claude strategy generated (confidence: %.0f%%)" , discoveryResult .OverallConfidence * 100 ))
1223+ // Use AI for analysis
1224+ logInfo ("Analyzing with Claude AI" )
1225+
1226+ schemaInfo , schemaErr := discoveryClient .GatherSchemaInfo (ctx , externalModels , network , labCfg .Repos .XatuCBT )
1227+ if schemaErr != nil {
1228+ return fmt .Errorf ("failed to gather schema info: %w" , schemaErr )
1229+ }
1230+
1231+ transformationSQL , sqlErr := seeddata .ReadTransformationSQL (model , labCfg .Repos .XatuCBT )
1232+ if sqlErr != nil {
1233+ return fmt .Errorf ("failed to read transformation SQL: %w" , sqlErr )
1234+ }
1235+
1236+ intermediateSQL , _ := seeddata .ReadIntermediateSQL (tree , labCfg .Repos .XatuCBT )
1237+
1238+ var intermediateModels []seeddata.IntermediateSQL
1239+ for modelName , sql := range intermediateSQL {
1240+ intermediateModels = append (intermediateModels , seeddata.IntermediateSQL {
1241+ Model : modelName ,
1242+ SQL : sql ,
1243+ })
1244+ }
1245+
1246+ discoveryResult , err = discoveryClient .AnalyzeRanges (ctx , seeddata.DiscoveryInput {
1247+ TransformationModel : model ,
1248+ TransformationSQL : transformationSQL ,
1249+ IntermediateModels : intermediateModels ,
1250+ Network : network ,
1251+ Duration : duration ,
1252+ ExternalModels : schemaInfo ,
1253+ })
1254+ if err != nil {
1255+ // Fallback to heuristics
1256+ logInfo ("Claude analysis failed, falling back to heuristics" )
1257+
1258+ rangeInfos , rangeErr := seeddata .DetectRangeColumnsForModels (externalModels , labCfg .Repos .XatuCBT )
1259+ if rangeErr != nil {
1260+ return fmt .Errorf ("failed to detect range columns: %w" , rangeErr )
1261+ }
1262+
1263+ discoveryResult , err = seeddata .FallbackRangeDiscovery (ctx , gen , externalModels , network , rangeInfos , duration , labCfg .Repos .XatuCBT )
1264+ if err != nil {
1265+ return fmt .Errorf ("fallback range discovery failed: %w" , err )
1266+ }
1267+ } else {
1268+ logInfo (fmt .Sprintf ("Claude strategy generated (confidence: %.0f%%)" , discoveryResult .OverallConfidence * 100 ))
1269+ }
12521270 }
12531271 }
12541272
0 commit comments