Skip to content

Commit 84ecbfc

Browse files
committed
Resolve ML models and pass them to the queryserver
1 parent e13349c commit 84ecbfc

3 files changed

Lines changed: 54 additions & 4 deletions

File tree

extensions/ql-vscode/src/cli.ts

Lines changed: 27 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,15 @@ export type QlpacksInfo = { [name: string]: string[] };
8787
*/
8888
export type LanguagesInfo = { [name: string]: string[] };
8989

90+
/** Information about an ML model, as resolved by `codeql resolve ml-models`. */
91+
export type MlModelInfo = {
92+
checksum: string;
93+
path: string;
94+
};
95+
96+
/** The expected output of `codeql resolve ml-models`. */
97+
export type MlModelsInfo = { models: MlModelInfo[] };
98+
9099
/**
91100
* The expected output of `codeql resolve qlref`.
92101
*/
@@ -584,6 +593,12 @@ export class CodeQLCliServer implements Disposable {
584593
return await this.runJsonCodeQlCliCommand<QueryMetadata>(['resolve', 'metadata'], [queryPath], 'Resolving query metadata');
585594
}
586595

596+
/** Resolves the ML models that should be available when evaluating a query. */
597+
async resolveMlModels(additionalPacks: string[]): Promise<MlModelsInfo> {
598+
return await this.runJsonCodeQlCliCommand<MlModelsInfo>(['resolve', 'ml-models'], ['--additional-packs',
599+
additionalPacks.join(path.delimiter)], 'Resolving ML models', false);
600+
}
601+
587602
/**
588603
* Gets the RAM setting for the query server.
589604
* @param queryMemoryMb The maximum amount of RAM to use, in MB.
@@ -621,16 +636,16 @@ export class CodeQLCliServer implements Disposable {
621636

622637
return await this.runCodeQlCliCommand(['database', 'unbundle'], subcommandArgs, `Extracting ${archivePath} to directory ${target}`);
623638
}
624-
639+
625640
/**
626641
* Uses a .qhelp file to generate Query Help documentation in a specified format.
627642
* @param pathToQhelp The path to the .qhelp file
628643
* @param format The format in which the query help should be generated {@link https://codeql.github.com/docs/codeql-cli/manual/generate-query-help/#cmdoption-codeql-generate-query-help-format}
629644
* @param outputDirectory The output directory for the generated file
630645
*/
631-
async generateQueryHelp(pathToQhelp:string, outputDirectory?: string): Promise<string> {
646+
async generateQueryHelp(pathToQhelp: string, outputDirectory?: string): Promise<string> {
632647
const subcommandArgs = ['--format=markdown'];
633-
if(outputDirectory) subcommandArgs.push('--output', outputDirectory);
648+
if (outputDirectory) subcommandArgs.push('--output', outputDirectory);
634649
subcommandArgs.push(pathToQhelp);
635650

636651
return await this.runCodeQlCliCommand(['generate', 'query-help'], subcommandArgs, `Generating qhelp in markdown format at ${outputDirectory}`);
@@ -1166,6 +1181,11 @@ export class CliVersionConstraint {
11661181
*/
11671182
public static CLI_VERSION_REMOTE_QUERIES = new SemVer('2.6.3');
11681183

1184+
/**
1185+
* CLI version where the `resolve ml-models` subcommand was introduced.
1186+
*/
1187+
public static CLI_VERSION_WITH_RESOLVE_ML_MODELS = new SemVer('2.7.3');
1188+
11691189
constructor(private readonly cli: CodeQLCliServer) {
11701190
/**/
11711191
}
@@ -1210,4 +1230,8 @@ export class CliVersionConstraint {
12101230
return this.isVersionAtLeast(CliVersionConstraint.CLI_VERSION_REMOTE_QUERIES);
12111231
}
12121232

1233+
async supportsResolveMlModels() {
1234+
return this.isVersionAtLeast(CliVersionConstraint.CLI_VERSION_WITH_RESOLVE_ML_MODELS);
1235+
}
1236+
12131237
}

extensions/ql-vscode/src/pure/messages.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -711,6 +711,11 @@ export interface EvaluateQueriesParams {
711711

712712
export type TemplateDefinitions = { [key: string]: TemplateSource }
713713

714+
export interface MlModel {
715+
/** A URI pointing to the root directory of the model. */
716+
uri: string;
717+
}
718+
714719
/**
715720
* A single query that should be run
716721
*/
@@ -744,6 +749,11 @@ export interface QueryToRun {
744749
* map should be set to the empty set or give an error.
745750
*/
746751
allowUnknownTemplates: boolean;
752+
/**
753+
* The list of ML models that should be made available
754+
* when evaluating the query.
755+
*/
756+
availableMlModels?: MlModel[];
747757
}
748758

749759
/**

extensions/ql-vscode/src/run-queries.ts

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,19 +86,23 @@ export class QueryInfo {
8686
async run(
8787
qs: qsClient.QueryServerClient,
8888
upgradeQlo: string | undefined,
89+
availableMlModels: cli.MlModelInfo[],
8990
progress: ProgressCallback,
9091
token: CancellationToken,
9192
): Promise<messages.EvaluationResult> {
9293
let result: messages.EvaluationResult | null = null;
9394

9495
const callbackId = qs.registerCallback(res => { result = res; });
9596

97+
const availableMlModelUris: messages.MlModel[] = availableMlModels.map(model => ({ uri: Uri.file(model.path).toString() }));
98+
9699
const queryToRun: messages.QueryToRun = {
97100
resultsPath: this.resultsPaths.resultsPath,
98101
qlo: Uri.file(this.compiledQueryPath).toString(),
99102
compiledUpgrade: upgradeQlo && Uri.file(upgradeQlo).toString(),
100103
allowUnknownTemplates: true,
101104
templateValues: this.templates,
105+
availableMlModels: availableMlModelUris,
102106
id: callbackId,
103107
timeoutSecs: qs.config.timeoutSecs,
104108
};
@@ -612,6 +616,18 @@ export async function compileAndRunQueryAgainstDatabase(
612616
void logger.log(`Couldn't resolve metadata for ${qlProgram.queryPath}: ${e}`);
613617
}
614618

619+
let availableMlModels: cli.MlModelInfo[] = [];
620+
if (await cliServer.cliConstraints.supportsResolveMlModels()) {
621+
try {
622+
availableMlModels = (await cliServer.resolveMlModels(diskWorkspaceFolders)).models;
623+
void logger.log(`Found available ML models at the following paths: ${availableMlModels.map(x => `'${x.path}'`).join(', ')}.`);
624+
} catch (e) {
625+
const message = `Couldn't resolve available ML models for ${qlProgram.queryPath}: ${e}`;
626+
void logger.log(message);
627+
void showAndLogErrorMessage(message);
628+
}
629+
}
630+
615631
const query = new QueryInfo(qlProgram, db, packConfig.dbscheme, quickEvalPosition, metadata, templates);
616632

617633
const upgradeDir = await tmp.dir({ dir: upgradesTmpDir.name, unsafeCleanup: true });
@@ -634,7 +650,7 @@ export async function compileAndRunQueryAgainstDatabase(
634650
}
635651

636652
if (errors.length === 0) {
637-
const result = await query.run(qs, upgradeQlo, progress, token);
653+
const result = await query.run(qs, upgradeQlo, availableMlModels, progress, token);
638654
if (result.resultType !== messages.QueryResultType.SUCCESS) {
639655
const message = result.message || 'Failed to run query';
640656
void logger.log(message);

0 commit comments

Comments
 (0)