@memberjunction/query-gen 6.1.4 → 6.2.0-edge.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/.turbo/turbo-build.log +1 -1
- package/CHANGELOG.md +119 -69
- package/dist/cli/commands/export.d.ts +2 -0
- package/dist/cli/commands/export.d.ts.map +1 -1
- package/dist/cli/commands/export.js +10 -6
- package/dist/cli/commands/export.js.map +1 -1
- package/dist/cli/commands/generate.d.ts +2 -0
- package/dist/cli/commands/generate.d.ts.map +1 -1
- package/dist/cli/commands/generate.js +19 -15
- package/dist/cli/commands/generate.js.map +1 -1
- package/dist/cli/commands/validate.d.ts +2 -0
- package/dist/cli/commands/validate.d.ts.map +1 -1
- package/dist/cli/commands/validate.js +12 -8
- package/dist/cli/commands/validate.js.map +1 -1
- package/dist/cli/config.d.ts +2 -0
- package/dist/cli/config.d.ts.map +1 -1
- package/dist/cli/config.js +5 -1
- package/dist/cli/config.js.map +1 -1
- package/dist/cli/index.js +6 -6
- package/dist/core/EntityGrouper.d.ts +2 -0
- package/dist/core/EntityGrouper.d.ts.map +1 -1
- package/dist/core/EntityGrouper.js +13 -9
- package/dist/core/EntityGrouper.js.map +1 -1
- package/dist/core/MetadataExporter.d.ts +2 -0
- package/dist/core/MetadataExporter.d.ts.map +1 -1
- package/dist/core/MetadataExporter.js +5 -1
- package/dist/core/MetadataExporter.js.map +1 -1
- package/dist/core/QueryDatabaseWriter.d.ts +2 -0
- package/dist/core/QueryDatabaseWriter.d.ts.map +1 -1
- package/dist/core/QueryDatabaseWriter.js +7 -3
- package/dist/core/QueryDatabaseWriter.js.map +1 -1
- package/dist/core/QueryFixer.d.ts +2 -0
- package/dist/core/QueryFixer.d.ts.map +1 -1
- package/dist/core/QueryFixer.js +9 -5
- package/dist/core/QueryFixer.js.map +1 -1
- package/dist/core/QueryRefiner.d.ts +2 -0
- package/dist/core/QueryRefiner.d.ts.map +1 -1
- package/dist/core/QueryRefiner.js +12 -8
- package/dist/core/QueryRefiner.js.map +1 -1
- package/dist/core/QueryTester.d.ts +2 -0
- package/dist/core/QueryTester.d.ts.map +1 -1
- package/dist/core/QueryTester.js +9 -5
- package/dist/core/QueryTester.js.map +1 -1
- package/dist/core/QueryWriter.d.ts +2 -0
- package/dist/core/QueryWriter.d.ts.map +1 -1
- package/dist/core/QueryWriter.js +9 -5
- package/dist/core/QueryWriter.js.map +1 -1
- package/dist/core/QuestionGenerator.d.ts +2 -0
- package/dist/core/QuestionGenerator.d.ts.map +1 -1
- package/dist/core/QuestionGenerator.js +11 -7
- package/dist/core/QuestionGenerator.js.map +1 -1
- package/dist/index.d.ts +6 -6
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +6 -6
- package/dist/index.js.map +1 -1
- package/dist/utils/category-builder.d.ts +4 -0
- package/dist/utils/category-builder.d.ts.map +1 -1
- package/dist/utils/category-builder.js +10 -2
- package/dist/utils/category-builder.js.map +1 -1
- package/dist/utils/entity-helpers.d.ts +14 -0
- package/dist/utils/entity-helpers.d.ts.map +1 -1
- package/dist/utils/entity-helpers.js +36 -8
- package/dist/utils/entity-helpers.js.map +1 -1
- package/dist/utils/error-handlers.d.ts +6 -0
- package/dist/utils/error-handlers.d.ts.map +1 -1
- package/dist/utils/error-handlers.js +15 -3
- package/dist/utils/error-handlers.js.map +1 -1
- package/dist/utils/graph-helpers.d.ts +6 -0
- package/dist/utils/graph-helpers.d.ts.map +1 -1
- package/dist/utils/graph-helpers.js +15 -3
- package/dist/utils/graph-helpers.js.map +1 -1
- package/dist/utils/prompt-helpers.d.ts +6 -0
- package/dist/utils/prompt-helpers.d.ts.map +1 -1
- package/dist/utils/prompt-helpers.js +5 -1
- package/dist/utils/prompt-helpers.js.map +1 -1
- package/dist/utils/user-helpers.d.ts +2 -0
- package/dist/utils/user-helpers.d.ts.map +1 -1
- package/dist/utils/user-helpers.js +5 -1
- package/dist/utils/user-helpers.js.map +1 -1
- package/dist/vectors/EmbeddingService.d.ts +14 -0
- package/dist/vectors/EmbeddingService.d.ts.map +1 -1
- package/dist/vectors/EmbeddingService.js +17 -5
- package/dist/vectors/EmbeddingService.js.map +1 -1
- package/dist/vectors/SimilaritySearch.d.ts +2 -0
- package/dist/vectors/SimilaritySearch.d.ts.map +1 -1
- package/dist/vectors/SimilaritySearch.js +5 -1
- package/dist/vectors/SimilaritySearch.js.map +1 -1
- package/package.json +11 -11
- package/src/__tests__/QueryGen.test.ts +22 -22
- package/src/cli/commands/export.ts +11 -6
- package/src/cli/commands/generate.ts +20 -15
- package/src/cli/commands/validate.ts +13 -8
- package/src/cli/config.ts +6 -1
- package/src/cli/index.ts +6 -6
- package/src/core/EntityGrouper.ts +17 -9
- package/src/core/MetadataExporter.ts +10 -1
- package/src/core/QueryDatabaseWriter.ts +11 -3
- package/src/core/QueryFixer.ts +15 -5
- package/src/core/QueryRefiner.ts +18 -8
- package/src/core/QueryTester.ts +13 -5
- package/src/core/QueryWriter.ts +14 -5
- package/src/core/QuestionGenerator.ts +12 -7
- package/src/index.ts +12 -12
- package/src/utils/category-builder.ts +15 -2
- package/src/utils/entity-helpers.ts +44 -9
- package/src/utils/error-handlers.ts +22 -3
- package/src/utils/graph-helpers.ts +18 -3
- package/src/utils/prompt-helpers.ts +11 -1
- package/src/utils/user-helpers.ts +6 -1
- package/src/vectors/EmbeddingService.ts +30 -5
- package/src/vectors/SimilaritySearch.ts +10 -1
|
@@ -13,8 +13,8 @@
|
|
|
13
13
|
import ora from 'ora';
|
|
14
14
|
import chalk from 'chalk';
|
|
15
15
|
import { Metadata, DatabaseProviderBase, EntityInfo, LogStatus } from '@memberjunction/core';
|
|
16
|
-
import {
|
|
17
|
-
import {
|
|
16
|
+
import { LoadConfig } from '../config';
|
|
17
|
+
import { GetSystemUser } from '../../utils/user-helpers';
|
|
18
18
|
import { EntityGrouper } from '../../core/EntityGrouper';
|
|
19
19
|
import { QuestionGenerator } from '../../core/QuestionGenerator';
|
|
20
20
|
import { QueryWriter } from '../../core/QueryWriter';
|
|
@@ -24,9 +24,9 @@ import { MetadataExporter } from '../../core/MetadataExporter';
|
|
|
24
24
|
import { QueryDatabaseWriter } from '../../core/QueryDatabaseWriter';
|
|
25
25
|
import { EmbeddingService } from '../../vectors/EmbeddingService';
|
|
26
26
|
import { SimilaritySearch } from '../../vectors/SimilaritySearch';
|
|
27
|
-
import {
|
|
28
|
-
import {
|
|
29
|
-
import {
|
|
27
|
+
import { FormatEntityMetadataForPrompt } from '../../utils/entity-helpers';
|
|
28
|
+
import { ExtractErrorMessage } from '../../utils/error-handlers';
|
|
29
|
+
import { BuildQueryCategory, ExtractUniqueCategories } from '../../utils/category-builder';
|
|
30
30
|
import { ValidatedQuery, GoldenQuery, EntityGroup, QueryCategoryInfo } from '../../data/schema';
|
|
31
31
|
import { readFileSync } from 'fs';
|
|
32
32
|
import { dirname, join } from 'path';
|
|
@@ -38,13 +38,13 @@ import { fileURLToPath } from 'url';
|
|
|
38
38
|
* Full orchestration of query generation workflow with progress reporting.
|
|
39
39
|
* Uses ora for spinners and chalk for colored output.
|
|
40
40
|
*/
|
|
41
|
-
export async function
|
|
41
|
+
export async function GenerateCommand(options: Record<string, unknown>): Promise<void> {
|
|
42
42
|
const spinner = ora('Initializing query generation...').start();
|
|
43
43
|
|
|
44
44
|
try {
|
|
45
45
|
// 1. Load configuration
|
|
46
46
|
spinner.text = 'Loading configuration...';
|
|
47
|
-
const config =
|
|
47
|
+
const config = LoadConfig(options);
|
|
48
48
|
|
|
49
49
|
// Show model/vendor overrides if configured
|
|
50
50
|
if (config.modelOverride || config.vendorOverride) {
|
|
@@ -60,7 +60,7 @@ export async function generateCommand(options: Record<string, unknown>): Promise
|
|
|
60
60
|
}
|
|
61
61
|
|
|
62
62
|
// 2. Get system user from UserCache (populated by provider initialization)
|
|
63
|
-
const contextUser =
|
|
63
|
+
const contextUser = GetSystemUser();
|
|
64
64
|
|
|
65
65
|
// 3. Verify database connection and metadata
|
|
66
66
|
spinner.text = 'Loading metadata...';
|
|
@@ -150,11 +150,11 @@ export async function generateCommand(options: Record<string, unknown>): Promise
|
|
|
150
150
|
spinner.start('Building category structure...');
|
|
151
151
|
const categoryMap = new Map<string, QueryCategoryInfo>();
|
|
152
152
|
for (const group of entityGroups) {
|
|
153
|
-
const category =
|
|
153
|
+
const category = BuildQueryCategory(config, group);
|
|
154
154
|
// Use primary entity name as key for lookup during query generation
|
|
155
155
|
categoryMap.set(group.primaryEntity.Name, category);
|
|
156
156
|
}
|
|
157
|
-
const uniqueCategories =
|
|
157
|
+
const uniqueCategories = ExtractUniqueCategories(Array.from(categoryMap.values()));
|
|
158
158
|
spinner.succeed(chalk.green(`Created ${uniqueCategories.length} ${uniqueCategories.length === 1 ? 'category' : 'categories'}`));
|
|
159
159
|
|
|
160
160
|
// 6. Generate queries for each entity group
|
|
@@ -202,14 +202,14 @@ export async function generateCommand(options: Record<string, unknown>): Promise
|
|
|
202
202
|
const queryWriter = new QueryWriter(contextUser, config);
|
|
203
203
|
const generatedQuery = await queryWriter.generateQuery(
|
|
204
204
|
question,
|
|
205
|
-
group.entities.map((e: EntityInfo) =>
|
|
205
|
+
group.entities.map((e: EntityInfo) => FormatEntityMetadataForPrompt(e, group.entities)),
|
|
206
206
|
fewShotExamples
|
|
207
207
|
);
|
|
208
208
|
|
|
209
209
|
// Test and fix query
|
|
210
210
|
// Access the database provider through Metadata.Provider
|
|
211
211
|
const dataProvider = Metadata.Provider as DatabaseProviderBase; // global-provider-ok: CLI tool, single-provider context
|
|
212
|
-
const entityMetadata = group.entities.map((e: EntityInfo) =>
|
|
212
|
+
const entityMetadata = group.entities.map((e: EntityInfo) => FormatEntityMetadataForPrompt(e, group.entities));
|
|
213
213
|
const queryTester = new QueryTester(
|
|
214
214
|
dataProvider,
|
|
215
215
|
entityMetadata,
|
|
@@ -277,7 +277,7 @@ export async function generateCommand(options: Record<string, unknown>): Promise
|
|
|
277
277
|
|
|
278
278
|
spinner.warn(
|
|
279
279
|
chalk.yellow(
|
|
280
|
-
`${groupPrefix} Error processing ${entityDisplay}: ${
|
|
280
|
+
`${groupPrefix} Error processing ${entityDisplay}: ${ExtractErrorMessage(error, 'Query Generation')}`
|
|
281
281
|
)
|
|
282
282
|
);
|
|
283
283
|
}
|
|
@@ -313,11 +313,16 @@ export async function generateCommand(options: Record<string, unknown>): Promise
|
|
|
313
313
|
|
|
314
314
|
} catch (error: unknown) {
|
|
315
315
|
spinner.fail(chalk.red('Query generation failed'));
|
|
316
|
-
console.error(chalk.red(
|
|
316
|
+
console.error(chalk.red(ExtractErrorMessage(error, 'Query Generation')));
|
|
317
317
|
process.exit(1);
|
|
318
318
|
}
|
|
319
319
|
}
|
|
320
320
|
|
|
321
|
+
/** @deprecated Use {@link GenerateCommand}. */
|
|
322
|
+
export async function generateCommand(options: Record<string, unknown>): Promise<void> {
|
|
323
|
+
return GenerateCommand(options);
|
|
324
|
+
}
|
|
325
|
+
|
|
321
326
|
/**
|
|
322
327
|
* Load golden queries from compile-time imported JSON data
|
|
323
328
|
*
|
|
@@ -353,7 +358,7 @@ async function loadGoldenQueries(config: { verbose: boolean }): Promise<GoldenQu
|
|
|
353
358
|
return goldenQueries;
|
|
354
359
|
} catch (error: unknown) {
|
|
355
360
|
if (config.verbose) {
|
|
356
|
-
LogStatus(`[Warning] Failed to load golden queries: ${
|
|
361
|
+
LogStatus(`[Warning] Failed to load golden queries: ${ExtractErrorMessage(error, 'loadGoldenQueries')}`);
|
|
357
362
|
}
|
|
358
363
|
return [];
|
|
359
364
|
}
|
|
@@ -13,11 +13,11 @@ import chalk from 'chalk';
|
|
|
13
13
|
import * as fs from 'fs';
|
|
14
14
|
import * as path from 'path';
|
|
15
15
|
import { Metadata, DatabaseProviderBase } from '@memberjunction/core';
|
|
16
|
-
import {
|
|
16
|
+
import { GetSystemUser } from '../../utils/user-helpers';
|
|
17
17
|
import { QueryTester } from '../../core/QueryTester';
|
|
18
|
-
import {
|
|
18
|
+
import { ExtractErrorMessage } from '../../utils/error-handlers';
|
|
19
19
|
import { GeneratedQuery, QueryMetadataRecord } from '../../data/schema';
|
|
20
|
-
import {
|
|
20
|
+
import { LoadConfig } from '../config';
|
|
21
21
|
|
|
22
22
|
/**
|
|
23
23
|
* Execute the validate command
|
|
@@ -25,7 +25,7 @@ import { loadConfig } from '../config';
|
|
|
25
25
|
* Loads query metadata files and validates each query template.
|
|
26
26
|
* Reports success/failure statistics.
|
|
27
27
|
*/
|
|
28
|
-
export async function
|
|
28
|
+
export async function ValidateCommand(options: Record<string, unknown>): Promise<void> {
|
|
29
29
|
const spinner = ora('Initializing validation...').start();
|
|
30
30
|
|
|
31
31
|
try {
|
|
@@ -33,10 +33,10 @@ export async function validateCommand(options: Record<string, unknown>): Promise
|
|
|
33
33
|
const verbose = Boolean(options.verbose);
|
|
34
34
|
|
|
35
35
|
// Load configuration
|
|
36
|
-
const config =
|
|
36
|
+
const config = LoadConfig(options);
|
|
37
37
|
|
|
38
38
|
// 1. Get system user from UserCache (populated by provider initialization)
|
|
39
|
-
const contextUser =
|
|
39
|
+
const contextUser = GetSystemUser();
|
|
40
40
|
|
|
41
41
|
// 2. Verify database connection and load metadata
|
|
42
42
|
spinner.text = 'Loading metadata...';
|
|
@@ -98,7 +98,7 @@ export async function validateCommand(options: Record<string, unknown>): Promise
|
|
|
98
98
|
}
|
|
99
99
|
} catch (error: unknown) {
|
|
100
100
|
failCount++;
|
|
101
|
-
const errorMsg =
|
|
101
|
+
const errorMsg = ExtractErrorMessage(error, 'Query Validation');
|
|
102
102
|
errors.push({ file, error: `${queryRecord.fields.Name}: ${errorMsg}` });
|
|
103
103
|
if (verbose) {
|
|
104
104
|
spinner.warn(`${filePrefix} ${chalk.red('✗')} ${queryRecord.fields.Name}: ${errorMsg}`);
|
|
@@ -137,11 +137,16 @@ export async function validateCommand(options: Record<string, unknown>): Promise
|
|
|
137
137
|
|
|
138
138
|
} catch (error: unknown) {
|
|
139
139
|
spinner.fail(chalk.red('Validation failed'));
|
|
140
|
-
console.error(chalk.red(
|
|
140
|
+
console.error(chalk.red(ExtractErrorMessage(error, 'Query Validation')));
|
|
141
141
|
process.exit(1);
|
|
142
142
|
}
|
|
143
143
|
}
|
|
144
144
|
|
|
145
|
+
/** @deprecated Use {@link ValidateCommand}. */
|
|
146
|
+
export async function validateCommand(options: Record<string, unknown>): Promise<void> {
|
|
147
|
+
return ValidateCommand(options);
|
|
148
|
+
}
|
|
149
|
+
|
|
145
150
|
/**
|
|
146
151
|
* Load all query metadata files from the specified directory
|
|
147
152
|
*/
|
package/src/cli/config.ts
CHANGED
|
@@ -116,7 +116,7 @@ const DEFAULT_CONFIG: QueryGenConfig = {
|
|
|
116
116
|
* @param cliOptions - Options provided via command line
|
|
117
117
|
* @returns Merged configuration ready for use
|
|
118
118
|
*/
|
|
119
|
-
export function
|
|
119
|
+
export function LoadConfig(cliOptions: Record<string, unknown>): QueryGenConfig {
|
|
120
120
|
// Start with defaults
|
|
121
121
|
const config: QueryGenConfig = { ...DEFAULT_CONFIG };
|
|
122
122
|
|
|
@@ -173,6 +173,11 @@ export function loadConfig(cliOptions: Record<string, unknown>): QueryGenConfig
|
|
|
173
173
|
return config;
|
|
174
174
|
}
|
|
175
175
|
|
|
176
|
+
/** @deprecated Use {@link LoadConfig}. */
|
|
177
|
+
export function loadConfig(cliOptions: Record<string, unknown>): QueryGenConfig {
|
|
178
|
+
return LoadConfig(cliOptions);
|
|
179
|
+
}
|
|
180
|
+
|
|
176
181
|
/**
|
|
177
182
|
* Load mj.config.cjs from current working directory
|
|
178
183
|
* Returns null if file doesn't exist or can't be loaded
|
package/src/cli/index.ts
CHANGED
|
@@ -12,9 +12,9 @@
|
|
|
12
12
|
|
|
13
13
|
import { Command } from 'commander';
|
|
14
14
|
import { createRequire } from 'node:module';
|
|
15
|
-
import {
|
|
16
|
-
import {
|
|
17
|
-
import {
|
|
15
|
+
import { GenerateCommand } from './commands/generate';
|
|
16
|
+
import { ValidateCommand } from './commands/validate';
|
|
17
|
+
import { ExportCommand } from './commands/export';
|
|
18
18
|
|
|
19
19
|
// Use createRequire to import JSON (compatible with ESM)
|
|
20
20
|
const require = createRequire(import.meta.url);
|
|
@@ -41,21 +41,21 @@ program
|
|
|
41
41
|
.option('-o, --output <path>', 'Output directory')
|
|
42
42
|
.option('--mode <mode>', 'Output mode: metadata|database|both')
|
|
43
43
|
.option('-v, --verbose', 'Verbose output')
|
|
44
|
-
.action(
|
|
44
|
+
.action(GenerateCommand);
|
|
45
45
|
|
|
46
46
|
program
|
|
47
47
|
.command('validate')
|
|
48
48
|
.description('Validate existing query templates')
|
|
49
49
|
.option('-p, --path <path>', 'Path to queries metadata file', './metadata/queries')
|
|
50
50
|
.option('-v, --verbose', 'Verbose output')
|
|
51
|
-
.action(
|
|
51
|
+
.action(ValidateCommand);
|
|
52
52
|
|
|
53
53
|
program
|
|
54
54
|
.command('export')
|
|
55
55
|
.description('Export queries from database to metadata files')
|
|
56
56
|
.option('-o, --output <path>', 'Output directory')
|
|
57
57
|
.option('-v, --verbose', 'Verbose output')
|
|
58
|
-
.action(
|
|
58
|
+
.action(ExportCommand);
|
|
59
59
|
|
|
60
60
|
// Parse command line arguments
|
|
61
61
|
program.parse();
|
|
@@ -10,9 +10,9 @@ import { EntityInfo, EntityRelationshipInfo, UserInfo, LogStatus } from '@member
|
|
|
10
10
|
import { AIEngine } from '@memberjunction/aiengine';
|
|
11
11
|
import { EntityGroup } from '../data/schema';
|
|
12
12
|
import { QueryGenConfig } from '../cli/config';
|
|
13
|
-
import {
|
|
14
|
-
import {
|
|
15
|
-
import {
|
|
13
|
+
import { GenerateRelationshipGraph, FormatEntitiesForPrompt } from '../utils/graph-helpers';
|
|
14
|
+
import { ExtractErrorMessage } from '../utils/error-handlers';
|
|
15
|
+
import { ExecutePromptWithOverrides } from '../utils/prompt-helpers';
|
|
16
16
|
|
|
17
17
|
/**
|
|
18
18
|
* LLM response format from Entity Group Generator prompt
|
|
@@ -54,7 +54,7 @@ export class EntityGrouper {
|
|
|
54
54
|
* @param contextUser - User context for server-side operations
|
|
55
55
|
* @returns Array of validated entity groups with business context
|
|
56
56
|
*/
|
|
57
|
-
async
|
|
57
|
+
async GenerateEntityGroups(
|
|
58
58
|
entities: EntityInfo[],
|
|
59
59
|
contextUser: UserInfo
|
|
60
60
|
): Promise<EntityGroup[]> {
|
|
@@ -109,10 +109,18 @@ export class EntityGrouper {
|
|
|
109
109
|
|
|
110
110
|
return deduplicatedGroups;
|
|
111
111
|
} catch (error: unknown) {
|
|
112
|
-
throw new Error(
|
|
112
|
+
throw new Error(ExtractErrorMessage(error, 'EntityGrouper.generateEntityGroups'));
|
|
113
113
|
}
|
|
114
114
|
}
|
|
115
115
|
|
|
116
|
+
/** @deprecated Use {@link GenerateEntityGroups}. */
|
|
117
|
+
async generateEntityGroups(
|
|
118
|
+
entities: EntityInfo[],
|
|
119
|
+
contextUser: UserInfo
|
|
120
|
+
): Promise<EntityGroup[]> {
|
|
121
|
+
return this.GenerateEntityGroups(entities, contextUser);
|
|
122
|
+
}
|
|
123
|
+
|
|
116
124
|
/**
|
|
117
125
|
* Group entities by schema name
|
|
118
126
|
*/
|
|
@@ -139,8 +147,8 @@ export class EntityGrouper {
|
|
|
139
147
|
* @param schemaName - Name of the schema being processed
|
|
140
148
|
*/
|
|
141
149
|
private prepareSchemaData(entities: EntityInfo[], schemaName: string): Record<string, unknown> {
|
|
142
|
-
const formattedEntities =
|
|
143
|
-
const relationshipGraph =
|
|
150
|
+
const formattedEntities = FormatEntitiesForPrompt(entities);
|
|
151
|
+
const relationshipGraph = GenerateRelationshipGraph(entities);
|
|
144
152
|
|
|
145
153
|
// Calculate target group count using graph theory metrics
|
|
146
154
|
// This approach uses actual schema connectivity instead of arbitrary thresholds
|
|
@@ -217,7 +225,7 @@ export class EntityGrouper {
|
|
|
217
225
|
}
|
|
218
226
|
|
|
219
227
|
// Execute with model/vendor overrides if specified in config
|
|
220
|
-
const result = await
|
|
228
|
+
const result = await ExecutePromptWithOverrides<LLMEntityGroupResponse>(
|
|
221
229
|
prompt,
|
|
222
230
|
schemaData,
|
|
223
231
|
contextUser,
|
|
@@ -329,7 +337,7 @@ export class EntityGrouper {
|
|
|
329
337
|
}
|
|
330
338
|
} catch (error: unknown) {
|
|
331
339
|
if (this.config.verbose) {
|
|
332
|
-
LogStatus(` ✗ Group validation error: ${
|
|
340
|
+
LogStatus(` ✗ Group validation error: ${ExtractErrorMessage(error, 'Group Validation')}`);
|
|
333
341
|
}
|
|
334
342
|
}
|
|
335
343
|
}
|
|
@@ -29,7 +29,7 @@ export class MetadataExporter {
|
|
|
29
29
|
* @param config - QueryGen configuration
|
|
30
30
|
* @returns Export result with file path and query count
|
|
31
31
|
*/
|
|
32
|
-
async
|
|
32
|
+
async ExportQueries(
|
|
33
33
|
validatedQueries: ValidatedQuery[],
|
|
34
34
|
uniqueCategories: QueryCategoryInfo[],
|
|
35
35
|
config: QueryGenConfig
|
|
@@ -87,6 +87,15 @@ export class MetadataExporter {
|
|
|
87
87
|
};
|
|
88
88
|
}
|
|
89
89
|
|
|
90
|
+
/** @deprecated Use {@link ExportQueries}. */
|
|
91
|
+
async exportQueries(
|
|
92
|
+
validatedQueries: ValidatedQuery[],
|
|
93
|
+
uniqueCategories: QueryCategoryInfo[],
|
|
94
|
+
config: QueryGenConfig
|
|
95
|
+
): Promise<ExportResult> {
|
|
96
|
+
return this.ExportQueries(validatedQueries, uniqueCategories, config);
|
|
97
|
+
}
|
|
98
|
+
|
|
90
99
|
/**
|
|
91
100
|
* Transform a validated query into MJ metadata format
|
|
92
101
|
*
|
|
@@ -13,7 +13,7 @@ import {
|
|
|
13
13
|
QueryEngine
|
|
14
14
|
} from '@memberjunction/core-entities';
|
|
15
15
|
import { ValidatedQuery, WriteResult } from '../data/schema';
|
|
16
|
-
import {
|
|
16
|
+
import { ExtractErrorMessage } from '../utils/error-handlers';
|
|
17
17
|
|
|
18
18
|
/**
|
|
19
19
|
* QueryDatabaseWriter class
|
|
@@ -40,7 +40,7 @@ export class QueryDatabaseWriter {
|
|
|
40
40
|
* @param contextUser - User context for entity operations
|
|
41
41
|
* @returns Write result with success status and per-query results
|
|
42
42
|
*/
|
|
43
|
-
async
|
|
43
|
+
async WriteQueriesToDatabase(
|
|
44
44
|
validatedQueries: ValidatedQuery[],
|
|
45
45
|
contextUser: UserInfo
|
|
46
46
|
): Promise<WriteResult> {
|
|
@@ -79,7 +79,7 @@ export class QueryDatabaseWriter {
|
|
|
79
79
|
return { success: true, results };
|
|
80
80
|
} catch (error: unknown) {
|
|
81
81
|
await provider.RollbackTransaction();
|
|
82
|
-
const message =
|
|
82
|
+
const message = ExtractErrorMessage(error, 'Database Write');
|
|
83
83
|
return {
|
|
84
84
|
success: false,
|
|
85
85
|
results: [`✗ Batch rolled back: ${message}`, ...results.map(r => r.replace('✓', '~'))]
|
|
@@ -87,6 +87,14 @@ export class QueryDatabaseWriter {
|
|
|
87
87
|
}
|
|
88
88
|
}
|
|
89
89
|
|
|
90
|
+
/** @deprecated Use {@link WriteQueriesToDatabase}. */
|
|
91
|
+
async writeQueriesToDatabase(
|
|
92
|
+
validatedQueries: ValidatedQuery[],
|
|
93
|
+
contextUser: UserInfo
|
|
94
|
+
): Promise<WriteResult> {
|
|
95
|
+
return this.WriteQueriesToDatabase(validatedQueries, contextUser);
|
|
96
|
+
}
|
|
97
|
+
|
|
90
98
|
/**
|
|
91
99
|
* Get or create category ID from QueryCategoryInfo
|
|
92
100
|
* Uses caching to avoid repeated lookups/creations
|
package/src/core/QueryFixer.ts
CHANGED
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
import { AIEngine } from '@memberjunction/aiengine';
|
|
9
9
|
import { MJAIPromptEntityExtended } from '@memberjunction/ai-core-plus';
|
|
10
10
|
import { UserInfo, LogStatus } from '@memberjunction/core';
|
|
11
|
-
import {
|
|
11
|
+
import { ExtractErrorMessage } from '../utils/error-handlers';
|
|
12
12
|
import {
|
|
13
13
|
GeneratedQuery,
|
|
14
14
|
EntityMetadataForPrompt,
|
|
@@ -16,7 +16,7 @@ import {
|
|
|
16
16
|
} from '../data/schema';
|
|
17
17
|
import { PROMPT_SQL_QUERY_FIXER } from '../prompts/PromptNames';
|
|
18
18
|
import { QueryGenConfig } from '../cli/config';
|
|
19
|
-
import {
|
|
19
|
+
import { ExecutePromptWithOverrides } from '../utils/prompt-helpers';
|
|
20
20
|
|
|
21
21
|
/**
|
|
22
22
|
* QueryFixer class
|
|
@@ -38,7 +38,7 @@ export class QueryFixer {
|
|
|
38
38
|
* @param businessQuestion - Original business question for context
|
|
39
39
|
* @returns Corrected SQL query with updated metadata
|
|
40
40
|
*/
|
|
41
|
-
async
|
|
41
|
+
async FixQuery(
|
|
42
42
|
query: GeneratedQuery,
|
|
43
43
|
errorMessage: string,
|
|
44
44
|
entityMetadata: EntityMetadataForPrompt[],
|
|
@@ -71,10 +71,20 @@ export class QueryFixer {
|
|
|
71
71
|
|
|
72
72
|
return fixedQuery;
|
|
73
73
|
} catch (error: unknown) {
|
|
74
|
-
throw new Error(
|
|
74
|
+
throw new Error(ExtractErrorMessage(error, 'QueryFixer.fixQuery'));
|
|
75
75
|
}
|
|
76
76
|
}
|
|
77
77
|
|
|
78
|
+
/** @deprecated Use {@link FixQuery}. */
|
|
79
|
+
async fixQuery(
|
|
80
|
+
query: GeneratedQuery,
|
|
81
|
+
errorMessage: string,
|
|
82
|
+
entityMetadata: EntityMetadataForPrompt[],
|
|
83
|
+
businessQuestion: BusinessQuestion
|
|
84
|
+
): Promise<GeneratedQuery> {
|
|
85
|
+
return this.FixQuery(query, errorMessage, entityMetadata, businessQuestion);
|
|
86
|
+
}
|
|
87
|
+
|
|
78
88
|
/**
|
|
79
89
|
* Find prompt by name in AIEngine cache
|
|
80
90
|
* Throws if prompt not found
|
|
@@ -107,7 +117,7 @@ export class QueryFixer {
|
|
|
107
117
|
}
|
|
108
118
|
): Promise<GeneratedQuery> {
|
|
109
119
|
// The SQL Query Fixer template returns { newSQL, reasoning }
|
|
110
|
-
const result = await
|
|
120
|
+
const result = await ExecutePromptWithOverrides<{
|
|
111
121
|
newSQL: string;
|
|
112
122
|
reasoning: string;
|
|
113
123
|
}>(prompt, promptData, this.contextUser, this.config);
|
package/src/core/QueryRefiner.ts
CHANGED
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
import { AIEngine } from '@memberjunction/aiengine';
|
|
9
9
|
import { MJAIPromptEntityExtended } from '@memberjunction/ai-core-plus';
|
|
10
10
|
import { UserInfo, LogStatus } from '@memberjunction/core';
|
|
11
|
-
import {
|
|
11
|
+
import { ExtractErrorMessage } from '../utils/error-handlers';
|
|
12
12
|
import {
|
|
13
13
|
GeneratedQuery,
|
|
14
14
|
BusinessQuestion,
|
|
@@ -20,7 +20,7 @@ import {
|
|
|
20
20
|
import { QueryTester } from './QueryTester';
|
|
21
21
|
import { PROMPT_QUERY_EVALUATOR, PROMPT_QUERY_REFINER } from '../prompts/PromptNames';
|
|
22
22
|
import { QueryGenConfig } from '../cli/config';
|
|
23
|
-
import {
|
|
23
|
+
import { ExecutePromptWithOverrides } from '../utils/prompt-helpers';
|
|
24
24
|
|
|
25
25
|
/**
|
|
26
26
|
* QueryRefiner class
|
|
@@ -47,7 +47,7 @@ export class QueryRefiner {
|
|
|
47
47
|
* @param maxRefinements - Maximum refinement iterations (default: 3)
|
|
48
48
|
* @returns Refined query with test results and evaluation
|
|
49
49
|
*/
|
|
50
|
-
async
|
|
50
|
+
async RefineQuery(
|
|
51
51
|
query: GeneratedQuery,
|
|
52
52
|
businessQuestion: BusinessQuestion,
|
|
53
53
|
entityMetadata: EntityMetadataForPrompt[],
|
|
@@ -78,7 +78,7 @@ export class QueryRefiner {
|
|
|
78
78
|
} catch (error: unknown) {
|
|
79
79
|
// Query broke during refinement - revert to last working version
|
|
80
80
|
if (this.config.verbose) {
|
|
81
|
-
LogStatus(`Refinement produced broken query: ${
|
|
81
|
+
LogStatus(`Refinement produced broken query: ${ExtractErrorMessage(error, 'Refinement Test')}. Reverting to last working version.`);
|
|
82
82
|
}
|
|
83
83
|
|
|
84
84
|
// If we have a previous working version, use that
|
|
@@ -147,6 +147,16 @@ export class QueryRefiner {
|
|
|
147
147
|
);
|
|
148
148
|
}
|
|
149
149
|
|
|
150
|
+
/** @deprecated Use {@link RefineQuery}. */
|
|
151
|
+
async refineQuery(
|
|
152
|
+
query: GeneratedQuery,
|
|
153
|
+
businessQuestion: BusinessQuestion,
|
|
154
|
+
entityMetadata: EntityMetadataForPrompt[],
|
|
155
|
+
maxRefinements: number = 3
|
|
156
|
+
): Promise<RefinedQuery> {
|
|
157
|
+
return this.RefineQuery(query, businessQuestion, entityMetadata, maxRefinements);
|
|
158
|
+
}
|
|
159
|
+
|
|
150
160
|
/**
|
|
151
161
|
* Configure AIEngine for prompt execution
|
|
152
162
|
* Ensures engine is ready before running prompts
|
|
@@ -156,7 +166,7 @@ export class QueryRefiner {
|
|
|
156
166
|
const aiEngine = AIEngine.Instance;
|
|
157
167
|
await aiEngine.Config(false, this.contextUser);
|
|
158
168
|
} catch (error: unknown) {
|
|
159
|
-
throw new Error(
|
|
169
|
+
throw new Error(ExtractErrorMessage(error, 'AIEngine Configuration'));
|
|
160
170
|
}
|
|
161
171
|
}
|
|
162
172
|
|
|
@@ -265,7 +275,7 @@ export class QueryRefiner {
|
|
|
265
275
|
this.logEvaluation(evaluation);
|
|
266
276
|
return evaluation;
|
|
267
277
|
} catch (error: unknown) {
|
|
268
|
-
throw new Error(
|
|
278
|
+
throw new Error(ExtractErrorMessage(error, 'QueryRefiner.evaluateQuery'));
|
|
269
279
|
}
|
|
270
280
|
}
|
|
271
281
|
|
|
@@ -312,7 +322,7 @@ export class QueryRefiner {
|
|
|
312
322
|
};
|
|
313
323
|
} catch (error: unknown) {
|
|
314
324
|
throw new Error(
|
|
315
|
-
|
|
325
|
+
ExtractErrorMessage(error, 'QueryRefiner.performRefinement')
|
|
316
326
|
);
|
|
317
327
|
}
|
|
318
328
|
}
|
|
@@ -340,7 +350,7 @@ export class QueryRefiner {
|
|
|
340
350
|
prompt: MJAIPromptEntityExtended,
|
|
341
351
|
promptData: Record<string, unknown>
|
|
342
352
|
): Promise<T> {
|
|
343
|
-
const result = await
|
|
353
|
+
const result = await ExecutePromptWithOverrides<T>(
|
|
344
354
|
prompt,
|
|
345
355
|
promptData,
|
|
346
356
|
this.contextUser,
|
package/src/core/QueryTester.ts
CHANGED
|
@@ -12,7 +12,7 @@ import {
|
|
|
12
12
|
UserInfo,
|
|
13
13
|
LogError,
|
|
14
14
|
} from '@memberjunction/core';
|
|
15
|
-
import {
|
|
15
|
+
import { ExtractErrorMessage } from '../utils/error-handlers';
|
|
16
16
|
import {
|
|
17
17
|
GeneratedQuery,
|
|
18
18
|
QueryTestResult,
|
|
@@ -63,7 +63,7 @@ export class QueryTester {
|
|
|
63
63
|
* @param maxAttempts - Maximum number of retry attempts (default: 5)
|
|
64
64
|
* @returns Test result with success status, SQL, and sample data
|
|
65
65
|
*/
|
|
66
|
-
async
|
|
66
|
+
async TestQuery(
|
|
67
67
|
query: GeneratedQuery,
|
|
68
68
|
maxAttempts: number = 5
|
|
69
69
|
): Promise<QueryTestResult> {
|
|
@@ -94,7 +94,7 @@ export class QueryTester {
|
|
|
94
94
|
attempts: attempt,
|
|
95
95
|
};
|
|
96
96
|
} catch (error: unknown) {
|
|
97
|
-
lastError =
|
|
97
|
+
lastError = ExtractErrorMessage(error, 'Query Testing');
|
|
98
98
|
if (this.config.verbose) {
|
|
99
99
|
LogError(`Attempt ${attempt}/${maxAttempts} failed: ${lastError}`);
|
|
100
100
|
}
|
|
@@ -114,6 +114,14 @@ export class QueryTester {
|
|
|
114
114
|
};
|
|
115
115
|
}
|
|
116
116
|
|
|
117
|
+
/** @deprecated Use {@link TestQuery}. */
|
|
118
|
+
async testQuery(
|
|
119
|
+
query: GeneratedQuery,
|
|
120
|
+
maxAttempts: number = 5
|
|
121
|
+
): Promise<QueryTestResult> {
|
|
122
|
+
return this.TestQuery(query, maxAttempts);
|
|
123
|
+
}
|
|
124
|
+
|
|
117
125
|
/**
|
|
118
126
|
* Render query template with sample parameter values
|
|
119
127
|
* Uses QueryParameterProcessor for proper type handling
|
|
@@ -138,7 +146,7 @@ export class QueryTester {
|
|
|
138
146
|
return renderedSQL;
|
|
139
147
|
} catch (error: unknown) {
|
|
140
148
|
throw new Error(
|
|
141
|
-
`Template rendering failed: ${
|
|
149
|
+
`Template rendering failed: ${ExtractErrorMessage(error, 'Nunjucks')}`
|
|
142
150
|
);
|
|
143
151
|
}
|
|
144
152
|
}
|
|
@@ -236,7 +244,7 @@ export class QueryTester {
|
|
|
236
244
|
return result;
|
|
237
245
|
} catch (error: unknown) {
|
|
238
246
|
throw new Error(
|
|
239
|
-
`SQL execution failed: ${
|
|
247
|
+
`SQL execution failed: ${ExtractErrorMessage(error, 'Database')}`
|
|
240
248
|
);
|
|
241
249
|
}
|
|
242
250
|
}
|
package/src/core/QueryWriter.ts
CHANGED
|
@@ -9,8 +9,8 @@ import { AIEngine } from '@memberjunction/aiengine';
|
|
|
9
9
|
import { MJAIPromptEntityExtended } from '@memberjunction/ai-core-plus';
|
|
10
10
|
import { UserInfo, LogStatus } from '@memberjunction/core';
|
|
11
11
|
import { QueryGenConfig } from '../cli/config';
|
|
12
|
-
import {
|
|
13
|
-
import {
|
|
12
|
+
import { ExtractErrorMessage } from '../utils/error-handlers';
|
|
13
|
+
import { ExecutePromptWithOverrides } from '../utils/prompt-helpers';
|
|
14
14
|
import { BusinessQuestion, GeneratedQuery, EntityMetadataForPrompt, GoldenQuery } from '../data/schema';
|
|
15
15
|
import { PROMPT_SQL_QUERY_WRITER } from '../prompts/PromptNames';
|
|
16
16
|
|
|
@@ -33,7 +33,7 @@ export class QueryWriter {
|
|
|
33
33
|
* @param fewShotExamples - Similar golden queries for few-shot learning
|
|
34
34
|
* @returns Generated SQL query with parameters and output schema
|
|
35
35
|
*/
|
|
36
|
-
async
|
|
36
|
+
async GenerateQuery(
|
|
37
37
|
businessQuestion: BusinessQuestion,
|
|
38
38
|
entityMetadata: EntityMetadataForPrompt[],
|
|
39
39
|
fewShotExamples: GoldenQuery[]
|
|
@@ -64,11 +64,20 @@ export class QueryWriter {
|
|
|
64
64
|
return generatedQuery;
|
|
65
65
|
} catch (error: unknown) {
|
|
66
66
|
throw new Error(
|
|
67
|
-
|
|
67
|
+
ExtractErrorMessage(error, 'QueryWriter.generateQuery')
|
|
68
68
|
);
|
|
69
69
|
}
|
|
70
70
|
}
|
|
71
71
|
|
|
72
|
+
/** @deprecated Use {@link GenerateQuery}. */
|
|
73
|
+
async generateQuery(
|
|
74
|
+
businessQuestion: BusinessQuestion,
|
|
75
|
+
entityMetadata: EntityMetadataForPrompt[],
|
|
76
|
+
fewShotExamples: GoldenQuery[]
|
|
77
|
+
): Promise<GeneratedQuery> {
|
|
78
|
+
return this.GenerateQuery(businessQuestion, entityMetadata, fewShotExamples);
|
|
79
|
+
}
|
|
80
|
+
|
|
72
81
|
/**
|
|
73
82
|
* Find prompt by name in AIEngine cache
|
|
74
83
|
* Throws if prompt not found
|
|
@@ -105,7 +114,7 @@ export class QueryWriter {
|
|
|
105
114
|
for (let attempt = 0; attempt <= maxRetries; attempt++) {
|
|
106
115
|
try {
|
|
107
116
|
// Execute AI prompt
|
|
108
|
-
const result = await
|
|
117
|
+
const result = await ExecutePromptWithOverrides<GeneratedQuery>(
|
|
109
118
|
prompt,
|
|
110
119
|
promptData,
|
|
111
120
|
this.contextUser,
|