Merge pull request #3719 from github/koesie10/remove-automodel

Remove automodel-related functionality
This commit is contained in:
Koen Vlaswinkel 2024-09-16 14:37:28 +02:00 коммит произвёл GitHub
Родитель 5f4522d7ca 2b4fa0d2a5
Коммит 7907d8de5d
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: B5690EEEBB952194
60 изменённых файлов: 136 добавлений и 2190 удалений

Просмотреть файл

@ -560,16 +560,6 @@ interface SetModifiedMethodsMessage {
methodSignatures: string[];
}
interface SetInProgressMethodsMessage {
t: "setInProgressMethods";
methods: string[];
}
interface SetProcessedByAutoModelMethodsMessage {
t: "setProcessedByAutoModelMethods";
methods: string[];
}
interface SwitchModeMessage {
t: "switchMode";
mode: Mode;
@ -601,17 +591,6 @@ interface GenerateMethodMessage {
t: "generateMethod";
}
interface GenerateMethodsFromLlmMessage {
t: "generateMethodsFromLlm";
packageName: string;
methodSignatures: string[];
}
interface StopGeneratingMethodsFromLlmMessage {
t: "stopGeneratingMethodsFromLlm";
packageName: string;
}
interface StartModelEvaluationMessage {
t: "startModelEvaluation";
}
@ -649,16 +628,6 @@ interface SetInModelingModeMessage {
inModelingMode: boolean;
}
interface SetInProgressMessage {
t: "setInProgress";
inProgress: boolean;
}
interface SetProcessedByAutoModelMessage {
t: "setProcessedByAutoModel";
processedByAutoModel: boolean;
}
interface RevealMethodMessage {
t: "revealMethod";
methodSignature: string;
@ -679,8 +648,6 @@ export type ToModelEditorMessage =
| SetMethodsMessage
| SetModeledAndModifiedMethodsMessage
| SetModifiedMethodsMessage
| SetInProgressMethodsMessage
| SetProcessedByAutoModelMethodsMessage
| RevealMethodMessage
| SetAccessPathSuggestionsMessage
| SetModelEvaluationRunMessage;
@ -694,8 +661,6 @@ export type FromModelEditorMessage =
| JumpToMethodMessage
| SaveModeledMethods
| GenerateMethodMessage
| GenerateMethodsFromLlmMessage
| StopGeneratingMethodsFromLlmMessage
| ModelDependencyMessage
| HideModeledMethodsMessage
| SetMultipleModeledMethodsMessage
@ -738,8 +703,6 @@ interface SetSelectedMethodMessage {
method: Method;
modeledMethods: ModeledMethod[];
isModified: boolean;
isInProgress: boolean;
processedByAutoModel: boolean;
}
export type ToMethodModelingMessage =
@ -748,9 +711,7 @@ export type ToMethodModelingMessage =
| SetMethodModifiedMessage
| SetNoMethodSelectedMessage
| SetSelectedMethodMessage
| SetInModelingModeMessage
| SetInProgressMessage
| SetProcessedByAutoModelMessage;
| SetInModelingModeMessage;
interface SetModelAlertsViewStateMessage {
t: "setModelAlertsViewState";

Просмотреть файл

@ -14,7 +14,6 @@ export enum RequestKind {
GetVariantAnalysisRepo = "getVariantAnalysisRepo",
GetVariantAnalysisRepoResult = "getVariantAnalysisRepoResult",
CodeSearch = "codeSearch",
AutoModel = "autoModel",
}
export interface BasicErrorResponse {
@ -92,31 +91,13 @@ interface CodeSearchRequest {
};
}
export interface AutoModelResponse {
models: string;
}
interface AutoModelRequest {
request: {
kind: RequestKind.AutoModel;
body?: {
candidates: string;
};
};
response: {
status: number;
body?: AutoModelResponse | BasicErrorResponse;
};
}
export type GitHubApiRequest =
| GetRepoRequest
| SubmitVariantAnalysisRequest
| GetVariantAnalysisRequest
| GetVariantAnalysisRepoRequest
| GetVariantAnalysisRepoResultRequest
| CodeSearchRequest
| AutoModelRequest;
| CodeSearchRequest;
export const isGetRepoRequest = (
request: GitHubApiRequest,
@ -146,8 +127,3 @@ export const isCodeSearchRequest = (
request: GitHubApiRequest,
): request is CodeSearchRequest =>
request.request.kind === RequestKind.CodeSearch;
export const isAutoModelRequest = (
request: GitHubApiRequest,
): request is AutoModelRequest =>
request.request.kind === RequestKind.AutoModel;

Просмотреть файл

@ -8,7 +8,6 @@ import { DisposableObject } from "../disposable-object";
import { gzipDecode } from "../zlib";
import type {
AutoModelResponse,
BasicErrorResponse,
CodeSearchResponse,
GetVariantAnalysisRepoResultRequest,
@ -265,23 +264,6 @@ async function createGitHubApiRequest(
};
}
const autoModelMatch = url.match(
/\/repos\/github\/codeql\/code-scanning\/codeql\/auto-model/,
);
if (autoModelMatch) {
return {
request: {
kind: RequestKind.AutoModel,
},
response: {
status,
body: await jsonResponseBody<
BasicErrorResponse | AutoModelResponse | undefined
>(response),
},
};
}
return undefined;
}

Просмотреть файл

@ -4,7 +4,6 @@ import type { RequestHandler } from "msw";
import { http } from "msw";
import type { GitHubApiRequest } from "./gh-api-request";
import {
isAutoModelRequest,
isCodeSearchRequest,
isGetRepoRequest,
isGetVariantAnalysisRepoRequest,
@ -41,7 +40,6 @@ export async function createRequestHandlers(
createGetVariantAnalysisRepoRequestHandler(requests),
createGetVariantAnalysisRepoResultRequestHandler(requests),
createCodeSearchRequestHandler(requests),
createAutoModelRequestHandler(requests),
];
return handlers;
@ -230,29 +228,3 @@ function createCodeSearchRequestHandler(
});
});
}
function createAutoModelRequestHandler(
requests: GitHubApiRequest[],
): RequestHandler {
const autoModelRequests = requests.filter(isAutoModelRequest);
let requestIndex = 0;
// During automodeling there can be multiple API requests for each batch
// of candidates we want to model. We need to return different responses for each request,
// so keep an index of the request and return the appropriate response.
return http.post(
`${baseUrl}/repos/github/codeql/code-scanning/codeql/auto-model`,
() => {
const request = autoModelRequests[requestIndex];
if (requestIndex < autoModelRequests.length - 1) {
// If there are more requests to come, increment the index.
requestIndex++;
}
return jsonResponse(request.response.body, {
status: request.response.status,
});
},
);
}

Просмотреть файл

@ -1,11 +0,0 @@
{
"request": {
"kind": "autoModel"
},
"response": {
"status": 200,
"body": {
"models": "extensions:\n- addsTo: {extensible: sinkModel, pack: codeql/java-all}\n data:\n - [javax.servlet.http, HttpServletResponse, true, sendRedirect, (String), '', 'Argument[this]',\n request-forgery, ai-generated]\n - [javax.servlet.http, HttpServletResponse, true, sendRedirect, (String), '', 'Argument[0]',\n request-forgery, ai-generated]\n"
}
}
}

Просмотреть файл

@ -1,11 +0,0 @@
{
"request": {
"kind": "autoModel"
},
"response": {
"status": 200,
"body": {
"models": "extensions:\n- addsTo: {extensible: sinkModel, pack: codeql/java-all}\n data:\n - [javax.servlet, MultipartConfigElement, true, MultipartConfigElement, (String),\n '', 'Argument[0]', request-forgery, ai-generated]\n"
}
}
}

Просмотреть файл

@ -1 +0,0 @@
This scenario is best when modeling the `javax.servlet-api` package.

Просмотреть файл

@ -1,10 +1,5 @@
import { promisify } from "util";
import { gzip, gunzip } from "zlib";
/**
* Promisified version of zlib.gzip
*/
export const gzipEncode = promisify(gzip);
import { gunzip } from "zlib";
/**
* Promisified version of zlib.gunzip

Просмотреть файл

@ -828,15 +828,6 @@ export async function setAutogenerateQlPacks(choice: AutogenerateQLPacks) {
const MODEL_SETTING = new Setting("model", ROOT_SETTING);
const FLOW_GENERATION = new Setting("flowGeneration", MODEL_SETTING);
const LLM_GENERATION = new Setting("llmGeneration", MODEL_SETTING);
const LLM_GENERATION_BATCH_SIZE = new Setting(
"llmGenerationBatchSize",
MODEL_SETTING,
);
const LLM_GENERATION_DEV_ENDPOINT = new Setting(
"llmGenerationDevEndpoint",
MODEL_SETTING,
);
const MODEL_EVALUATION = new Setting("evaluation", MODEL_SETTING);
const MODEL_PACK_LOCATION = new Setting("packLocation", MODEL_SETTING);
const MODEL_PACK_NAME = new Setting("packName", MODEL_SETTING);
@ -850,7 +841,6 @@ export type ModelConfigPackVariables = {
export interface ModelConfig {
flowGeneration: boolean;
llmGeneration: boolean;
getPackLocation(
languageId: string,
variables: ModelConfigPackVariables,
@ -870,26 +860,6 @@ export class ModelConfigListener extends ConfigListener implements ModelConfig {
return !!FLOW_GENERATION.getValue<boolean>();
}
public get llmGeneration(): boolean {
return !!LLM_GENERATION.getValue<boolean>() && !hasEnterpriseUri();
}
/**
* Limits the number of candidates we send to the model in each request to avoid long requests.
* Note that the model may return fewer than this number of candidates.
*/
public get llmGenerationBatchSize(): number {
return LLM_GENERATION_BATCH_SIZE.getValue<number | null>() || 5;
}
/**
* The URL of the endpoint to use for LLM generation. This should only be set
* if you want to test against a dev server.
*/
public get llmGenerationDevEndpoint(): string | undefined {
return LLM_GENERATION_DEV_ENDPOINT.getValue<string | undefined>();
}
public get modelEvaluation(): boolean {
return !!MODEL_EVALUATION.getValue<boolean>();
}

Просмотреть файл

@ -1,65 +0,0 @@
import type { Credentials } from "../common/authentication";
import type { OctokitResponse } from "@octokit/types";
import fetch from "node-fetch";
import type { ModelConfigListener } from "../config";
export enum AutomodelMode {
Unspecified = "AUTOMODEL_MODE_UNSPECIFIED",
Framework = "AUTOMODEL_MODE_FRAMEWORK",
Application = "AUTOMODEL_MODE_APPLICATION",
}
export interface ModelRequest {
mode: AutomodelMode;
// Base64-encoded GZIP-compressed SARIF log
candidates: string;
}
export interface ModelResponse {
models: string;
}
export async function autoModel(
credentials: Credentials,
request: ModelRequest,
modelingConfig: ModelConfigListener,
): Promise<ModelResponse> {
const devEndpoint = modelingConfig.llmGenerationDevEndpoint;
if (devEndpoint) {
return callAutoModelDevEndpoint(devEndpoint, request);
} else {
const octokit = await credentials.getOctokit();
const response: OctokitResponse<ModelResponse> = await octokit.request(
"POST /repos/github/codeql/code-scanning/codeql/auto-model",
{
data: request,
},
);
return response.data;
}
}
async function callAutoModelDevEndpoint(
endpoint: string,
request: ModelRequest,
): Promise<ModelResponse> {
const json = JSON.stringify(request);
const response = await fetch(endpoint, {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: json,
});
if (!response.ok) {
throw new Error(
`Error calling auto-model API: ${response.status} ${response.statusText}`,
);
}
const data = await response.json();
return data as ModelResponse;
}

Просмотреть файл

@ -1,233 +0,0 @@
import type { CodeQLCliServer, SourceInfo } from "../codeql-cli/cli";
import type { CoreCompletedQuery, QueryRunner } from "../query-server";
import type { DatabaseItem } from "../databases/local-databases";
import type { ProgressCallback } from "../common/vscode/progress";
import type { Log } from "sarif";
import type { Mode } from "./shared/mode";
import { getOnDiskWorkspaceFolders } from "../common/vscode/workspace-folders";
import { interpretResultsSarif } from "../query-results";
import { join } from "path";
import { dir } from "tmp-promise";
import { writeFile, outputFile } from "fs-extra";
import { dump as dumpYaml } from "js-yaml";
import type { MethodSignature } from "./method";
import { runQuery } from "../local-queries/run-query";
import type { QueryMetadata } from "../common/interface-types";
import type { CancellationTokenSource } from "vscode";
import { resolveQueries } from "../local-queries";
import { modeTag } from "./mode-tag";
type AutoModelQueriesOptions = {
mode: Mode;
candidateMethods: MethodSignature[];
cliServer: CodeQLCliServer;
queryRunner: QueryRunner;
databaseItem: DatabaseItem;
queryStorageDir: string;
progress: ProgressCallback;
cancellationTokenSource: CancellationTokenSource;
};
export type AutoModelQueriesResult = {
candidates: Log;
};
export async function runAutoModelQueries({
mode,
candidateMethods,
cliServer,
queryRunner,
databaseItem,
queryStorageDir,
progress,
cancellationTokenSource,
}: AutoModelQueriesOptions): Promise<AutoModelQueriesResult | undefined> {
// First, resolve the query that we want to run.
const queryPath = await resolveAutomodelQuery(
cliServer,
databaseItem,
"candidates",
mode,
);
// Generate a pack containing the candidate filters
const { packDir: filterPackDir, cleanup: cleanupFilterPack } =
await generateCandidateFilterPack(databaseItem.language, candidateMethods);
const additionalPacks = [...getOnDiskWorkspaceFolders(), filterPackDir];
const extensionPacks = Object.keys(
await cliServer.resolveQlpacks(additionalPacks, true),
);
// Run the actual query
const completedQuery = await runQuery({
queryRunner,
databaseItem,
queryPath,
queryStorageDir,
additionalPacks,
extensionPacks,
progress,
token: cancellationTokenSource.token,
});
await cleanupFilterPack();
if (!completedQuery) {
return undefined;
}
// Get metadata for the query. This is required to interpret the results. We already know the kind is problem
// (because of the constraint in resolveQueries), so we don't need any more checks on the metadata.
const metadata = await cliServer.resolveMetadata(queryPath);
// CodeQL needs to have access to the database to be able to retrieve the
// snippets from it. The source location prefix is used to determine the
// base path of the database.
const sourceLocationPrefix =
await databaseItem.getSourceLocationPrefix(cliServer);
const sourceArchiveUri = databaseItem.sourceArchive;
const sourceInfo =
sourceArchiveUri === undefined
? undefined
: {
sourceArchive: sourceArchiveUri.fsPath,
sourceLocationPrefix,
};
const candidates = await interpretAutomodelResults(
cliServer,
completedQuery,
metadata,
sourceInfo,
);
return {
candidates,
};
}
async function resolveAutomodelQuery(
cliServer: CodeQLCliServer,
databaseItem: DatabaseItem,
queryTag: string,
mode: Mode,
): Promise<string> {
const packsToSearch = [`codeql/${databaseItem.language}-automodel-queries`];
// First, resolve the query that we want to run.
// All queries are tagged like this:
// internal extract automodel <mode> <queryTag>
// Example: internal extract automodel framework-mode candidates
const queries = await resolveQueries(
cliServer,
packsToSearch,
`Extract automodel ${queryTag}`,
{
kind: "problem",
"tags contain all": ["automodel", modeTag(mode), ...queryTag.split(" ")],
},
);
if (queries.length > 1) {
throw new Error(
`Found multiple auto model queries for ${mode} ${queryTag}. Can't continue`,
);
}
if (queries.length === 0) {
throw new Error(
`Did not found any auto model queries for ${mode} ${queryTag}. Can't continue`,
);
}
return queries[0];
}
type CandidateFilterPackResult = {
packDir: string;
cleanup: () => Promise<void>;
};
/**
* generateCandidateFilterPack will create a temporary extension pack.
* This pack will contain a filter that will restrict the automodel queries
* to the specified candidate methods only.
* This is done using the `extensible` predicate "automodelCandidateFilter".
* @param language
* @param candidateMethods
* @returns
*/
export async function generateCandidateFilterPack(
language: string,
candidateMethods: MethodSignature[],
): Promise<CandidateFilterPackResult> {
// Pack resides in a temporary directory, to not pollute the workspace.
const { path: packDir, cleanup } = await dir({ unsafeCleanup: true });
const syntheticConfigPack = {
name: "codeql/automodel-filter",
version: "0.0.0",
library: true,
extensionTargets: {
[`codeql/${language}-automodel-queries`]: "*",
},
dataExtensions: ["filter.yml"],
};
const qlpackFile = join(packDir, "codeql-pack.yml");
await outputFile(qlpackFile, dumpYaml(syntheticConfigPack), "utf8");
// The predicate has the following defintion:
// extensible predicate automodelCandidateFilter(string package, string type, string name, string signature)
const dataRows = candidateMethods.map((method) => [
method.packageName,
method.typeName,
method.methodName,
method.methodParameters,
]);
const filter = {
extensions: [
{
addsTo: {
pack: `codeql/${language}-automodel-queries`,
extensible: "automodelCandidateFilter",
},
data: dataRows,
},
],
};
const filterFile = join(packDir, "filter.yml");
await writeFile(filterFile, dumpYaml(filter), "utf8");
return {
packDir,
cleanup,
};
}
async function interpretAutomodelResults(
cliServer: CodeQLCliServer,
completedQuery: CoreCompletedQuery,
metadata: QueryMetadata,
sourceInfo: SourceInfo | undefined,
): Promise<Log> {
const interpretedResultsPath = join(
completedQuery.outputDir.querySaveDir,
"results.sarif",
);
const { ...sarif } = await interpretResultsSarif(
cliServer,
metadata,
{
resultsPath: completedQuery.outputDir.bqrsPath,
interpretedResultsPath,
},
sourceInfo,
["--sarif-add-snippets"],
);
return sarif;
}

Просмотреть файл

@ -1,41 +0,0 @@
import type { ModelRequest } from "./auto-model-api";
import { AutomodelMode } from "./auto-model-api";
import { Mode } from "./shared/mode";
import type { AutoModelQueriesResult } from "./auto-model-codeml-queries";
import { assertNever } from "../common/helpers-pure";
import type { Log } from "sarif";
import { gzipEncode } from "../common/zlib";
/**
* Encode a SARIF log to the format expected by the server: JSON, GZIP-compressed, base64-encoded
* @param log SARIF log to encode
* @returns base64-encoded GZIP-compressed SARIF log
*/
export async function encodeSarif(log: Log): Promise<string> {
const json = JSON.stringify(log);
const buffer = Buffer.from(json, "utf-8");
const compressed = await gzipEncode(buffer);
return compressed.toString("base64");
}
export async function createAutoModelRequest(
mode: Mode,
result: AutoModelQueriesResult,
): Promise<ModelRequest> {
let requestMode: AutomodelMode;
switch (mode) {
case Mode.Application:
requestMode = AutomodelMode.Application;
break;
case Mode.Framework:
requestMode = AutomodelMode.Framework;
break;
default:
assertNever(mode);
}
return {
mode: requestMode,
candidates: await encodeSarif(result.candidates),
};
}

Просмотреть файл

@ -1,249 +0,0 @@
import type { Method, MethodSignature } from "./method";
import type { ModeledMethod } from "./modeled-method";
import { load as loadYaml } from "js-yaml";
import type { ProgressCallback } from "../common/vscode/progress";
import { withProgress } from "../common/vscode/progress";
import { createAutoModelRequest } from "./auto-model";
import { getCandidates } from "./shared/auto-model-candidates";
import { runAutoModelQueries } from "./auto-model-codeml-queries";
import { loadDataExtensionYaml } from "./yaml";
import type { ModelRequest, ModelResponse } from "./auto-model-api";
import { autoModel } from "./auto-model-api";
import { RequestError } from "@octokit/request-error";
import { showAndLogExceptionWithTelemetry } from "../common/logging";
import { redactableError } from "../common/errors";
import type { App } from "../common/app";
import type { CodeQLCliServer } from "../codeql-cli/cli";
import type { QueryRunner } from "../query-server";
import type { DatabaseItem } from "../databases/local-databases";
import type { Mode } from "./shared/mode";
import { CancellationTokenSource } from "vscode";
import type { ModelingStore } from "./modeling-store";
import type { ModelConfigListener } from "../config";
import type { QueryLanguage } from "../common/query-language";
/**
* The auto-modeler holds state around auto-modeling jobs and allows
* starting and stopping them.
*/
export class AutoModeler {
// Keep track of auto-modeling jobs that are in progress
// so that we can stop them.
private readonly jobs: Map<string, CancellationTokenSource>;
constructor(
private readonly app: App,
private readonly cliServer: CodeQLCliServer,
private readonly queryRunner: QueryRunner,
private readonly modelConfig: ModelConfigListener,
private readonly modelingStore: ModelingStore,
private readonly queryStorageDir: string,
private readonly databaseItem: DatabaseItem,
private readonly language: QueryLanguage,
private readonly addModeledMethods: (
modeledMethods: Record<string, ModeledMethod[]>,
) => Promise<void>,
) {
this.jobs = new Map<string, CancellationTokenSource>();
}
/**
* Models the given package's external API usages, except
* the ones that are already modeled.
* @param packageName The name of the package to model.
* @param methods The methods.
* @param modeledMethods The currently modeled methods.
* @param mode The mode we are modeling in.
*/
public async startModeling(
packageName: string,
methods: readonly Method[],
modeledMethods: Record<string, readonly ModeledMethod[]>,
processedByAutoModelMethods: Set<string>,
mode: Mode,
): Promise<void> {
if (this.jobs.has(packageName)) {
return;
}
const cancellationTokenSource = new CancellationTokenSource();
this.jobs.set(packageName, cancellationTokenSource);
try {
await this.modelPackage(
packageName,
methods,
modeledMethods,
processedByAutoModelMethods,
mode,
cancellationTokenSource,
);
} finally {
this.jobs.delete(packageName);
}
}
/**
* Stops modeling the given package.
* @param packageName The name of the package to stop modeling.
*/
public async stopModeling(packageName: string): Promise<void> {
void this.app.logger.log(`Stopping modeling for package ${packageName}`);
const cancellationTokenSource = this.jobs.get(packageName);
if (cancellationTokenSource) {
cancellationTokenSource.cancel();
}
}
/**
* Stops all in-progress modeling jobs.
*/
public async stopAllModeling(): Promise<void> {
for (const cancellationTokenSource of this.jobs.values()) {
cancellationTokenSource.cancel();
}
}
private async modelPackage(
packageName: string,
methods: readonly Method[],
modeledMethods: Record<string, readonly ModeledMethod[]>,
processedByAutoModelMethods: Set<string>,
mode: Mode,
cancellationTokenSource: CancellationTokenSource,
): Promise<void> {
void this.app.logger.log(`Modeling package ${packageName}`);
const candidateBatchSize = this.modelConfig.llmGenerationBatchSize;
await withProgress(async (progress) => {
// Fetch the candidates to send to the model
const allCandidateMethods = getCandidates(
mode,
methods,
modeledMethods,
processedByAutoModelMethods,
);
// If there are no candidates, there is nothing to model and we just return
if (allCandidateMethods.length === 0) {
void this.app.logger.log("No candidates to model. Stopping.");
return;
}
// Find number of slices to make
const batchNumber = Math.ceil(
allCandidateMethods.length / candidateBatchSize,
);
try {
for (let i = 0; i < batchNumber; i++) {
// Check if we should stop
if (cancellationTokenSource.token.isCancellationRequested) {
break;
}
const start = i * candidateBatchSize;
const end = start + candidateBatchSize;
const candidatesToProcess = allCandidateMethods.slice(start, end);
const candidateSignatures = candidatesToProcess.map(
(c) => c.signature,
);
// Let the UI know which candidates we are modeling
this.modelingStore.addInProgressMethods(
this.databaseItem,
candidateSignatures,
);
// Kick off the process to model the slice of candidates
await this.modelCandidates(
candidatesToProcess,
mode,
progress,
cancellationTokenSource,
);
// Let the UI know which candidates we are done modeling
this.modelingStore.removeInProgressMethods(
this.databaseItem,
candidateSignatures,
);
// Let the UI know which methods have been sent to the LLM
this.modelingStore.addProcessedByAutoModelMethods(
this.databaseItem,
candidateSignatures,
);
}
} finally {
// Clear out in progress methods in case anything went wrong
this.modelingStore.removeInProgressMethods(
this.databaseItem,
allCandidateMethods.map((c) => c.signature),
);
}
});
}
private async modelCandidates(
candidateMethods: MethodSignature[],
mode: Mode,
progress: ProgressCallback,
cancellationTokenSource: CancellationTokenSource,
): Promise<void> {
void this.app.logger.log("Executing auto-model queries");
const usages = await runAutoModelQueries({
mode,
candidateMethods,
cliServer: this.cliServer,
queryRunner: this.queryRunner,
queryStorageDir: this.queryStorageDir,
databaseItem: this.databaseItem,
progress: (update) => progress({ ...update }),
cancellationTokenSource,
});
if (!usages) {
return;
}
const request = await createAutoModelRequest(mode, usages);
void this.app.logger.log("Calling auto-model API");
const response = await this.callAutoModelApi(request);
if (!response) {
return;
}
const models = loadYaml(response.models, {
filename: "auto-model.yml",
});
const loadedMethods = loadDataExtensionYaml(models, this.language);
if (!loadedMethods) {
return;
}
await this.addModeledMethods(loadedMethods);
}
private async callAutoModelApi(
request: ModelRequest,
): Promise<ModelResponse | null> {
try {
return await autoModel(this.app.credentials, request, this.modelConfig);
} catch (e) {
if (e instanceof RequestError && e.status === 429) {
void showAndLogExceptionWithTelemetry(
this.app.logger,
this.app.telemetry,
redactableError`Rate limit hit, please try again soon.`,
);
return null;
} else {
throw e;
}
}
}
}

Просмотреть файл

@ -70,8 +70,6 @@ export class MethodModelingViewProvider extends AbstractWebviewViewProvider<
method: Method,
modeledMethods: readonly ModeledMethod[],
isModified: boolean,
isInProgress: boolean,
processedByAutoModel: boolean,
): Promise<void> {
this.method = method;
this.databaseItem = databaseItem;
@ -82,8 +80,6 @@ export class MethodModelingViewProvider extends AbstractWebviewViewProvider<
method,
modeledMethods,
isModified,
isInProgress,
processedByAutoModel,
});
}
@ -104,8 +100,6 @@ export class MethodModelingViewProvider extends AbstractWebviewViewProvider<
selectedMethod.method,
selectedMethod.modeledMethods,
selectedMethod.isModified,
selectedMethod.isInProgress,
selectedMethod.processedByAutoModel,
);
}
}
@ -203,8 +197,6 @@ export class MethodModelingViewProvider extends AbstractWebviewViewProvider<
e.method,
e.modeledMethods,
e.isModified,
e.isInProgress,
e.processedByAutoModel,
);
}
}),
@ -232,36 +224,6 @@ export class MethodModelingViewProvider extends AbstractWebviewViewProvider<
}
}),
);
this.push(
this.modelingEvents.onInProgressMethodsChanged(async (e) => {
if (this.method && this.databaseItem) {
const dbUri = this.databaseItem.databaseUri.toString();
if (e.dbUri === dbUri) {
const inProgress = e.methods.has(this.method.signature);
await this.postMessage({
t: "setInProgress",
inProgress,
});
}
}
}),
);
this.push(
this.modelingEvents.onProcessedByAutoModelMethodsChanged(async (e) => {
if (this.method && this.databaseItem) {
const dbUri = this.databaseItem.databaseUri.toString();
if (e.dbUri === dbUri) {
const processedByAutoModel = e.methods.has(this.method.signature);
await this.postMessage({
t: "setProcessedByAutoModel",
processedByAutoModel,
});
}
}
}),
);
}
private registerToModelConfigEvents(): void {

Просмотреть файл

@ -204,7 +204,6 @@ export class ModelEditorModule extends DisposableObject {
this.app.logger,
queryDir,
language,
this.modelConfig,
initialMode,
);
if (!success) {

Просмотреть файл

@ -8,7 +8,6 @@ import {
syntheticQueryPackName,
} from "./model-editor-queries";
import type { CodeQLCliServer } from "../codeql-cli/cli";
import type { ModelConfig } from "../config";
import type { Mode } from "./shared/mode";
import type { NotificationLogger } from "../common/logging";
@ -30,7 +29,6 @@ import type { NotificationLogger } from "../common/logging";
* @param logger The logger to use.
* @param queryDir The directory to set up.
* @param language The language to use for the queries.
* @param modelConfig The model config to use.
* @param initialMode The initial mode to use to check the existence of the queries.
* @returns true if the setup was successful, false otherwise.
*/
@ -39,7 +37,6 @@ export async function setUpPack(
logger: NotificationLogger,
queryDir: string,
language: QueryLanguage,
modelConfig: ModelConfig,
initialMode: Mode,
): Promise<boolean> {
// Download the required query packs
@ -91,10 +88,5 @@ export async function setUpPack(
await cliServer.packInstall(queryDir);
}
// Download any other required packs
if (language === "java" && modelConfig.llmGeneration) {
await cliServer.packDownload([`codeql/${language}-automodel-queries`]);
}
return true;
}

Просмотреть файл

@ -49,7 +49,6 @@ import {
import { pickExtensionPack } from "./extension-pack-picker";
import type { QueryLanguage } from "../common/query-language";
import { getLanguageDisplayName } from "../common/query-language";
import { AutoModeler } from "./auto-modeler";
import { telemetryListener } from "../common/vscode/telemetry";
import type { ModelingStore } from "./modeling-store";
import type { ModelingEvents } from "./modeling-events";
@ -77,7 +76,6 @@ export class ModelEditorView extends AbstractWebview<
ToModelEditorMessage,
FromModelEditorMessage
> {
private readonly autoModeler: AutoModeler;
private readonly modelEvaluator: ModelEvaluator;
private readonly languageDefinition: ModelsAsDataLanguage;
// Cancellation token source that can be used for passing into long-running operations. Should only
@ -114,19 +112,6 @@ export class ModelEditorView extends AbstractWebview<
this.registerToModelingEvents();
this.registerToModelConfigEvents();
this.autoModeler = new AutoModeler(
app,
cliServer,
queryRunner,
this.modelConfig,
modelingStore,
queryStorageDir,
databaseItem,
language,
async (modeledMethods) => {
this.addModeledMethods(modeledMethods);
},
);
this.languageDefinition = getModelsAsDataLanguage(language);
this.modelEvaluator = new ModelEvaluator(
@ -317,21 +302,6 @@ export class ModelEditorView extends AbstractWebview<
"model-editor-generate-modeled-methods",
);
break;
case "generateMethodsFromLlm":
await this.generateModeledMethodsFromLlm(
msg.packageName,
msg.methodSignatures,
);
void telemetryListener?.sendUIInteraction(
"model-editor-generate-methods-from-llm",
);
break;
case "stopGeneratingMethodsFromLlm":
await this.autoModeler.stopModeling(msg.packageName);
void telemetryListener?.sendUIInteraction(
"model-editor-stop-generating-methods-from-llm",
);
break;
case "modelDependency":
await this.modelDependency();
@ -438,9 +408,6 @@ export class ModelEditorView extends AbstractWebview<
this.modelConfig.flowGeneration) &&
!!modelsAsDataLanguage.modelGeneration;
const showLlmButton =
this.databaseItem.language === "java" && this.modelConfig.llmGeneration;
const showEvaluationUi = this.modelConfig.modelEvaluation;
const sourceArchiveAvailable =
@ -456,7 +423,6 @@ export class ModelEditorView extends AbstractWebview<
extensionPack: this.extensionPack,
language: this.language,
showGenerateButton,
showLlmButton,
showEvaluationUi,
mode: this.modelingStore.getMode(this.databaseItem),
showModeSwitchButton,
@ -805,33 +771,6 @@ export class ModelEditorView extends AbstractWebview<
);
}
private async generateModeledMethodsFromLlm(
packageName: string,
methodSignatures: string[],
): Promise<void> {
const methods = this.modelingStore.getMethods(
this.databaseItem,
methodSignatures,
);
const modeledMethods = this.modelingStore.getModeledMethods(
this.databaseItem,
methodSignatures,
);
const processedByAutoModelMethods =
this.modelingStore.getProcessedByAutoModelMethods(
this.databaseItem,
methodSignatures,
);
const mode = this.modelingStore.getMode(this.databaseItem);
await this.autoModeler.startModeling(
packageName,
methods,
modeledMethods,
processedByAutoModelMethods,
mode,
);
}
private async modelDependency(): Promise<void> {
return withProgress(
async (progress, token) => {
@ -983,30 +922,6 @@ export class ModelEditorView extends AbstractWebview<
}),
);
this.push(
this.modelingEvents.onInProgressMethodsChanged(async (event) => {
if (event.dbUri === this.databaseItem.databaseUri.toString()) {
await this.postMessage({
t: "setInProgressMethods",
methods: Array.from(event.methods),
});
}
}),
);
this.push(
this.modelingEvents.onProcessedByAutoModelMethodsChanged(
async (event) => {
if (event.dbUri === this.databaseItem.databaseUri.toString()) {
await this.postMessage({
t: "setProcessedByAutoModelMethods",
methods: Array.from(event.methods),
});
}
},
),
);
this.push(
this.modelingEvents.onRevealInModelEditor(async (event) => {
if (event.dbUri === this.databaseItem.databaseUri.toString()) {

Просмотреть файл

@ -1,6 +1,5 @@
import { assertNever } from "../common/helpers-pure";
import type { MethodSignature } from "./method";
import type { ModelingStatus } from "./shared/modeling-status";
export type ModeledMethodType =
| "none"
@ -15,10 +14,6 @@ export type Provenance =
| "df-generated"
// Generated by the dataflow model and manually edited
| "df-manual"
// Generated by the auto-model
| "ai-generated"
// Generated by the auto-model and manually edited
| "ai-manual"
// Entered by the user in the editor manually
| "manual";
@ -112,30 +107,6 @@ export function modeledMethodSupportsProvenance(
);
}
export function isModelPending(
modeledMethod: ModeledMethod | undefined,
modelingStatus: ModelingStatus,
processedByAutoModel: boolean,
): boolean {
if (
(!modeledMethod || modeledMethod.type === "none") &&
processedByAutoModel
) {
return true;
}
if (!modeledMethod) {
return false;
}
return (
modelingStatus === "unsaved" &&
modeledMethod.type !== "none" &&
modeledMethodSupportsProvenance(modeledMethod) &&
modeledMethod.provenance === "ai-generated"
);
}
/**
* Calculates the new provenance for a modeled method based on the current provenance.
* @param modeledMethod The modeled method if there is one.
@ -158,13 +129,6 @@ export function calculateNewProvenance(
case "df-manual":
// If the method has had manual edits, we want the provenance to stay the same.
return "df-manual";
case "ai-generated":
// If the method has been generated and there has been a change, we assume
// that the user has manually edited it.
return "ai-manual";
case "ai-manual":
// If the method has had manual edits, we want the provenance to stay the same.
return "ai-manual";
default:
// The method has been modeled manually.
return "manual";

Просмотреть файл

@ -37,18 +37,6 @@ interface SelectedMethodChangedEvent {
readonly usage: Usage;
readonly modeledMethods: readonly ModeledMethod[];
readonly isModified: boolean;
readonly isInProgress: boolean;
readonly processedByAutoModel: boolean;
}
interface InProgressMethodsChangedEvent {
readonly dbUri: string;
readonly methods: ReadonlySet<string>;
}
interface ProcessedByAutoModelMethodsChangedEvent {
readonly dbUri: string;
readonly methods: ReadonlySet<string>;
}
interface ModelEvaluationRunChangedEvent {
@ -83,8 +71,6 @@ export class ModelingEvents extends DisposableObject {
public readonly onModeChanged: AppEvent<ModeChangedEvent>;
public readonly onModeledAndModifiedMethodsChanged: AppEvent<ModeledAndModifiedMethodsChangedEvent>;
public readonly onSelectedMethodChanged: AppEvent<SelectedMethodChangedEvent>;
public readonly onInProgressMethodsChanged: AppEvent<InProgressMethodsChangedEvent>;
public readonly onProcessedByAutoModelMethodsChanged: AppEvent<ProcessedByAutoModelMethodsChangedEvent>;
public readonly onModelEvaluationRunChanged: AppEvent<ModelEvaluationRunChangedEvent>;
public readonly onRevealInModelEditor: AppEvent<RevealInModelEditorEvent>;
public readonly onFocusModelEditor: AppEvent<FocusModelEditorEvent>;
@ -99,8 +85,6 @@ export class ModelingEvents extends DisposableObject {
private readonly onModeChangedEventEmitter: AppEventEmitter<ModeChangedEvent>;
private readonly onModeledAndModifiedMethodsChangedEventEmitter: AppEventEmitter<ModeledAndModifiedMethodsChangedEvent>;
private readonly onSelectedMethodChangedEventEmitter: AppEventEmitter<SelectedMethodChangedEvent>;
private readonly onInProgressMethodsChangedEventEmitter: AppEventEmitter<InProgressMethodsChangedEvent>;
private readonly onProcessedByAutoModelMethodsChangedEventEmitter: AppEventEmitter<ProcessedByAutoModelMethodsChangedEvent>;
private readonly onModelEvaluationRunChangedEventEmitter: AppEventEmitter<ModelEvaluationRunChangedEvent>;
private readonly onRevealInModelEditorEventEmitter: AppEventEmitter<RevealInModelEditorEvent>;
private readonly onFocusModelEditorEventEmitter: AppEventEmitter<FocusModelEditorEvent>;
@ -151,18 +135,6 @@ export class ModelingEvents extends DisposableObject {
this.onSelectedMethodChanged =
this.onSelectedMethodChangedEventEmitter.event;
this.onInProgressMethodsChangedEventEmitter = this.push(
app.createEventEmitter<InProgressMethodsChangedEvent>(),
);
this.onInProgressMethodsChanged =
this.onInProgressMethodsChangedEventEmitter.event;
this.onProcessedByAutoModelMethodsChangedEventEmitter = this.push(
app.createEventEmitter<ProcessedByAutoModelMethodsChangedEvent>(),
);
this.onProcessedByAutoModelMethodsChanged =
this.onProcessedByAutoModelMethodsChangedEventEmitter.event;
this.onModelEvaluationRunChangedEventEmitter = this.push(
app.createEventEmitter<ModelEvaluationRunChangedEvent>(),
);
@ -254,8 +226,6 @@ export class ModelingEvents extends DisposableObject {
usage: Usage,
modeledMethods: ModeledMethod[],
isModified: boolean,
isInProgress: boolean,
processedByAutoModel: boolean,
) {
this.onSelectedMethodChangedEventEmitter.fire({
databaseItem,
@ -263,28 +233,6 @@ export class ModelingEvents extends DisposableObject {
usage,
modeledMethods,
isModified,
isInProgress,
processedByAutoModel,
});
}
public fireInProgressMethodsChangedEvent(
dbUri: string,
methods: ReadonlySet<string>,
) {
this.onInProgressMethodsChangedEventEmitter.fire({
dbUri,
methods,
});
}
public fireProcessedByAutoModelMethodsChangedEvent(
dbUri: string,
methods: ReadonlySet<string>,
) {
this.onProcessedByAutoModelMethodsChangedEventEmitter.fire({
dbUri,
methods,
});
}

Просмотреть файл

@ -15,8 +15,6 @@ interface InternalDbModelingState {
mode: Mode;
modeledMethods: Record<string, ModeledMethod[]>;
modifiedMethodSignatures: Set<string>;
inProgressMethods: Set<string>;
processedByAutoModelMethods: Set<string>;
selectedMethod: Method | undefined;
selectedUsage: Usage | undefined;
modelEvaluationRun: ModelEvaluationRun | undefined;
@ -30,8 +28,6 @@ export interface DbModelingState {
readonly mode: Mode;
readonly modeledMethods: Readonly<Record<string, readonly ModeledMethod[]>>;
readonly modifiedMethodSignatures: ReadonlySet<string>;
readonly inProgressMethods: ReadonlySet<string>;
readonly processedByAutoModelMethods: ReadonlySet<string>;
readonly selectedMethod: Method | undefined;
readonly selectedUsage: Usage | undefined;
readonly modelEvaluationRun: ModelEvaluationRun | undefined;
@ -44,8 +40,6 @@ export interface SelectedMethodDetails {
readonly usage: Usage | undefined;
readonly modeledMethods: readonly ModeledMethod[];
readonly isModified: boolean;
readonly isInProgress: boolean;
readonly processedByAutoModel: boolean;
}
export class ModelingStore extends DisposableObject {
@ -68,10 +62,8 @@ export class ModelingStore extends DisposableObject {
mode,
modeledMethods: {},
modifiedMethodSignatures: new Set(),
processedByAutoModelMethods: new Set(),
selectedMethod: undefined,
selectedUsage: undefined,
inProgressMethods: new Set(),
modelEvaluationRun: undefined,
isModelAlertsViewOpen: false,
});
@ -160,7 +152,6 @@ export class ModelingStore extends DisposableObject {
methods,
state.modeledMethods,
state.modifiedMethodSignatures,
state.processedByAutoModelMethods,
);
});
}
@ -171,7 +162,6 @@ export class ModelingStore extends DisposableObject {
state.methods,
state.modeledMethods,
state.modifiedMethodSignatures,
state.processedByAutoModelMethods,
);
});
}
@ -308,75 +298,15 @@ export class ModelingStore extends DisposableObject {
const modeledMethods = dbState.modeledMethods[method.signature] ?? [];
const isModified = dbState.modifiedMethodSignatures.has(method.signature);
const isInProgress = dbState.inProgressMethods.has(method.signature);
const processedByAutoModel = dbState.processedByAutoModelMethods.has(
method.signature,
);
this.modelingEvents.fireSelectedMethodChangedEvent(
dbItem,
method,
usage,
modeledMethods,
isModified,
isInProgress,
processedByAutoModel,
);
}
public addInProgressMethods(
dbItem: DatabaseItem,
inProgressMethods: string[],
) {
this.changeInProgressMethods(dbItem, (state) => {
state.inProgressMethods = new Set([
...state.inProgressMethods,
...inProgressMethods,
]);
});
}
public removeInProgressMethods(
dbItem: DatabaseItem,
methodSignatures: string[],
) {
this.changeInProgressMethods(dbItem, (state) => {
state.inProgressMethods = new Set(
Array.from(state.inProgressMethods).filter(
(s) => !methodSignatures.includes(s),
),
);
});
}
public getProcessedByAutoModelMethods(
dbItem: DatabaseItem,
methodSignatures?: string[],
): Set<string> {
const processedByAutoModelMethods =
this.getState(dbItem).processedByAutoModelMethods;
if (!methodSignatures) {
return processedByAutoModelMethods;
}
return new Set(
Array.from(processedByAutoModelMethods).filter((x) =>
methodSignatures.includes(x),
),
);
}
public addProcessedByAutoModelMethods(
dbItem: DatabaseItem,
processedByAutoModelMethods: string[],
) {
this.changeProcessedByAutoModelMethods(dbItem, (state) => {
state.processedByAutoModelMethods = new Set([
...state.processedByAutoModelMethods,
...processedByAutoModelMethods,
]);
});
this.updateMethodSorting(dbItem);
}
public updateModelEvaluationRun(
dbItem: DatabaseItem,
evaluationRun: ModelEvaluationRun | undefined,
@ -405,10 +335,6 @@ export class ModelingStore extends DisposableObject {
isModified: dbState.modifiedMethodSignatures.has(
selectedMethod.signature,
),
isInProgress: dbState.inProgressMethods.has(selectedMethod.signature),
processedByAutoModel: dbState.processedByAutoModelMethods.has(
selectedMethod.signature,
),
};
}
@ -460,34 +386,6 @@ export class ModelingStore extends DisposableObject {
);
}
private changeInProgressMethods(
dbItem: DatabaseItem,
updateState: (state: InternalDbModelingState) => void,
) {
const state = this.getState(dbItem);
updateState(state);
this.modelingEvents.fireInProgressMethodsChangedEvent(
dbItem.databaseUri.toString(),
state.inProgressMethods,
);
}
private changeProcessedByAutoModelMethods(
dbItem: DatabaseItem,
updateState: (state: InternalDbModelingState) => void,
) {
const state = this.getState(dbItem);
updateState(state);
this.modelingEvents.fireProcessedByAutoModelMethodsChangedEvent(
dbItem.databaseUri.toString(),
state.processedByAutoModelMethods,
);
}
private changeModelEvaluationRun(
dbItem: DatabaseItem,
updateState: (state: InternalDbModelingState) => void,

Просмотреть файл

@ -1,48 +0,0 @@
import type { Method, MethodSignature } from "../method";
import type { ModeledMethod } from "../modeled-method";
import type { Mode } from "./mode";
import { groupMethods, sortGroupNames } from "./sorting";
/**
* Return the candidates that the model should be run on. This includes limiting the number of
* candidates to the candidate limit and filtering out anything that is already modeled and respecting
* the order in the UI.
* @param mode Whether it is application or framework mode.
* @param methods all methods.
* @param modeledMethodsBySignature the currently modeled methods.
* @returns list of modeled methods that are candidates for modeling.
*/
export function getCandidates(
mode: Mode,
methods: readonly Method[],
modeledMethodsBySignature: Record<string, readonly ModeledMethod[]>,
processedByAutoModelMethods: Set<string>,
): MethodSignature[] {
const candidateMethods = methods.filter((method) => {
// Filter out any methods already processed by auto-model
if (processedByAutoModelMethods.has(method.signature)) {
return false;
}
const modeledMethods: ModeledMethod[] = [
...(modeledMethodsBySignature[method.signature] ?? []),
];
// Anything that is modeled is not a candidate
if (modeledMethods.some((m) => m.type !== "none")) {
return false;
}
// A method that is supported is modeled outside of the model file, so it is not a candidate.
if (method.supported) {
return false;
}
return true;
});
// Sort the same way as the UI so we send the first ones listed in the UI first
const grouped = groupMethods(candidateMethods, mode);
return sortGroupNames(grouped).flatMap((name) => grouped[name]);
}

Просмотреть файл

@ -47,7 +47,6 @@ export function sortMethods(
methods: readonly Method[],
modeledMethodsMap: Record<string, readonly ModeledMethod[]>,
modifiedSignatures: ReadonlySet<string>,
processedByAutoModelMethods: ReadonlySet<string>,
): Method[] {
const sortedMethods = [...methods];
sortedMethods.sort((a, b) => {
@ -56,13 +55,11 @@ export function sortMethods(
a,
modeledMethodsMap[a.signature] ?? [],
modifiedSignatures.has(a.signature),
processedByAutoModelMethods.has(a.signature),
);
const methodBPrimarySortOrdinal = getMethodPrimarySortOrdinal(
b,
modeledMethodsMap[b.signature] ?? [],
modifiedSignatures.has(b.signature),
processedByAutoModelMethods.has(b.signature),
);
if (methodAPrimarySortOrdinal !== methodBPrimarySortOrdinal) {
return methodAPrimarySortOrdinal - methodBPrimarySortOrdinal;
@ -82,32 +79,25 @@ export function sortMethods(
/**
* Assigns numbers to the following classes of methods:
* - Unsaved positive AutoModel predictions => 0
* - Negative AutoModel predictions => 1
* - Unsaved manual models + unmodeled methods => 2
* - Saved models from this model pack (AutoModel and manual) => 3
* - Methods not modelable in this model pack => 4
* - Unsaved manual models + unmodeled methods => 0
* - Saved models from this model pack (AutoModel and manual) => 1
* - Methods not modelable in this model pack => 2
*/
function getMethodPrimarySortOrdinal(
method: Method,
modeledMethods: readonly ModeledMethod[],
isUnsaved: boolean,
isProcessedByAutoModel: boolean,
): number {
const canBeModeled = canMethodBeModeled(method, modeledMethods, isUnsaved);
const isModeled = modeledMethods.length > 0;
if (canBeModeled) {
if (isModeled && isUnsaved && isProcessedByAutoModel) {
if ((isModeled && isUnsaved) || !isModeled) {
return 0;
} else if (!isModeled && isProcessedByAutoModel) {
return 1;
} else if ((isModeled && isUnsaved) || !isModeled) {
return 2;
} else {
return 3;
return 1;
}
} else {
return 4;
return 2;
}
}

Просмотреть файл

@ -7,7 +7,6 @@ export interface ModelEditorViewState {
extensionPack: ExtensionPack;
language: QueryLanguage;
showGenerateButton: boolean;
showLlmButton: boolean;
showEvaluationUi: boolean;
mode: Mode;
showModeSwitchButton: boolean;

Просмотреть файл

@ -53,20 +53,3 @@ FullyModeledMethod.args = {
method,
modeledMethod,
};
export const ModelingInProgress = Template.bind({});
ModelingInProgress.args = {
method,
modeledMethod,
isModelingInProgress: true,
};
const generatedModeledMethod = createSinkModeledMethod({
provenance: "ai-generated",
});
export const ModelingNotAccepted = Template.bind({});
ModelingNotAccepted.args = {
method,
modeledMethod: generatedModeledMethod,
modelPending: true,
};

Просмотреть файл

@ -1,14 +0,0 @@
import type { Meta, StoryFn } from "@storybook/react";
import { InProgressDropdown as InProgressDropdownComponent } from "../../view/model-editor/InProgressDropdown";
export default {
title: "CodeQL Model Editor/In Progress Dropdown",
component: InProgressDropdownComponent,
} as Meta<typeof InProgressDropdownComponent>;
const Template: StoryFn<typeof InProgressDropdownComponent> = (args) => (
<InProgressDropdownComponent />
);
export const InProgressDropdown = Template.bind({});

Просмотреть файл

@ -220,10 +220,8 @@ LibraryRow.args = {
],
},
modifiedSignatures: new Set(["org.sql2o.Sql2o#Sql2o(String)"]),
inProgressMethods: new Set(),
viewState: createMockModelEditorViewState({
showGenerateButton: true,
showLlmButton: true,
}),
hideModeledMethods: false,
};

Просмотреть файл

@ -96,7 +96,6 @@ const modeledMethod: ModeledMethod = {
const viewState = createMockModelEditorViewState({
showGenerateButton: true,
showLlmButton: true,
});
export const Unmodeled = Template.bind({});
@ -146,15 +145,6 @@ AlreadyModeled.args = {
viewState,
};
export const ModelingInProgress = Template.bind({});
ModelingInProgress.args = {
method,
modeledMethods: [modeledMethod],
modelingInProgress: true,
methodCanBeModeled: true,
viewState,
};
export const MultipleModelings = Template.bind({});
MultipleModelings.args = {
method,

Просмотреть файл

@ -27,7 +27,6 @@ ModelEditor.args = {
dataExtensions: [],
},
showGenerateButton: true,
showLlmButton: true,
}),
initialMethods: [
{

Просмотреть файл

@ -55,8 +55,6 @@ export type MethodModelingProps = {
modelingStatus: ModelingStatus;
method: Method;
modeledMethods: ModeledMethod[];
isModelingInProgress: boolean;
isProcessedByAutoModel: boolean;
onChange: (methodSignature: string, modeledMethods: ModeledMethod[]) => void;
};
@ -66,8 +64,6 @@ export const MethodModeling = ({
modelingStatus,
modeledMethods,
method,
isModelingInProgress,
isProcessedByAutoModel,
onChange,
}: MethodModelingProps): React.JSX.Element => {
return (
@ -86,9 +82,6 @@ export const MethodModeling = ({
modelConfig={modelConfig}
method={method}
modeledMethods={modeledMethods}
isModelingInProgress={isModelingInProgress}
isProcessedByAutoModel={isProcessedByAutoModel}
modelingStatus={modelingStatus}
onChange={onChange}
/>
<ReviewInEditorButton method={method} />

Просмотреть файл

@ -5,7 +5,6 @@ import { ModelTypeDropdown } from "../model-editor/ModelTypeDropdown";
import { ModelInputDropdown } from "../model-editor/ModelInputDropdown";
import { ModelOutputDropdown } from "../model-editor/ModelOutputDropdown";
import { ModelKindDropdown } from "../model-editor/ModelKindDropdown";
import { InProgressDropdown } from "../model-editor/InProgressDropdown";
import type { QueryLanguage } from "../../common/query-language";
import type { ModelConfig } from "../../model-editor/languages";
@ -28,8 +27,6 @@ export type MethodModelingInputsProps = {
modelConfig: ModelConfig;
method: Method;
modeledMethod: ModeledMethod | undefined;
modelPending: boolean;
isModelingInProgress: boolean;
onChange: (modeledMethod: ModeledMethod) => void;
};
@ -38,15 +35,12 @@ export const MethodModelingInputs = ({
modelConfig,
method,
modeledMethod,
modelPending,
isModelingInProgress,
onChange,
}: MethodModelingInputsProps): React.JSX.Element => {
const inputProps = {
language,
method,
modeledMethod,
modelPending,
onChange,
};
@ -55,41 +49,25 @@ export const MethodModelingInputs = ({
<Container>
<Input>
<Name>Model Type</Name>
{isModelingInProgress ? (
<InProgressDropdown />
) : (
<ModelTypeDropdown modelConfig={modelConfig} {...inputProps} />
)}
<ModelTypeDropdown modelConfig={modelConfig} {...inputProps} />
</Input>
</Container>
<Container>
<Input>
<Name>Input</Name>
{isModelingInProgress ? (
<InProgressDropdown />
) : (
<ModelInputDropdown {...inputProps} />
)}
<ModelInputDropdown {...inputProps} />
</Input>
</Container>
<Container>
<Input>
<Name>Output</Name>
{isModelingInProgress ? (
<InProgressDropdown />
) : (
<ModelOutputDropdown {...inputProps} />
)}
<ModelOutputDropdown {...inputProps} />
</Input>
</Container>
<Container>
<Input>
<Name>Kind</Name>
{isModelingInProgress ? (
<InProgressDropdown />
) : (
<ModelKindDropdown {...inputProps} />
)}
<ModelKindDropdown {...inputProps} />
</Input>
</Container>
</>

Просмотреть файл

@ -31,12 +31,6 @@ export function MethodModelingView({
const [isMethodModified, setIsMethodModified] = useState<boolean>(false);
const [isModelingInProgress, setIsModelingInProgress] =
useState<boolean>(false);
const [isProcessedByAutoModel, setIsProcessedByAutoModel] =
useState<boolean>(false);
const modelingStatus = useMemo(
() => getModelingStatus(modeledMethods, isMethodModified),
[modeledMethods, isMethodModified],
@ -63,21 +57,11 @@ export function MethodModelingView({
setMethod(undefined);
setModeledMethods([]);
setIsMethodModified(false);
setIsModelingInProgress(false);
setIsProcessedByAutoModel(false);
break;
case "setSelectedMethod":
setMethod(msg.method);
setModeledMethods(msg.modeledMethods);
setIsMethodModified(msg.isModified);
setIsModelingInProgress(msg.isInProgress);
setIsProcessedByAutoModel(msg.processedByAutoModel);
break;
case "setInProgress":
setIsModelingInProgress(msg.inProgress);
break;
case "setProcessedByAutoModel":
setIsProcessedByAutoModel(msg.processedByAutoModel);
break;
default:
assertNever(msg);
@ -125,8 +109,6 @@ export function MethodModelingView({
modelingStatus={modelingStatus}
method={method}
modeledMethods={modeledMethods}
isModelingInProgress={isModelingInProgress}
isProcessedByAutoModel={isProcessedByAutoModel}
onChange={onChange}
/>
);

Просмотреть файл

@ -1,7 +1,6 @@
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
import type { Method } from "../../model-editor/method";
import type { ModeledMethod } from "../../model-editor/modeled-method";
import { isModelPending } from "../../model-editor/modeled-method";
import {
canAddNewModeledMethod,
canRemoveModeledMethod,
@ -15,7 +14,6 @@ import { ModeledMethodAlert } from "./ModeledMethodAlert";
import type { QueryLanguage } from "../../common/query-language";
import { createEmptyModeledMethod } from "../../model-editor/modeled-method-empty";
import { sendTelemetry } from "../common/telemetry";
import type { ModelingStatus } from "../../model-editor/shared/modeling-status";
import type { ModelConfig } from "../../model-editor/languages";
export type MultipleModeledMethodsPanelProps = {
@ -23,9 +21,6 @@ export type MultipleModeledMethodsPanelProps = {
modelConfig: ModelConfig;
method: Method;
modeledMethods: ModeledMethod[];
modelingStatus: ModelingStatus;
isModelingInProgress: boolean;
isProcessedByAutoModel: boolean;
onChange: (methodSignature: string, modeledMethods: ModeledMethod[]) => void;
};
@ -66,9 +61,6 @@ export const MultipleModeledMethodsPanel = ({
modelConfig,
method,
modeledMethods,
modelingStatus,
isModelingInProgress,
isProcessedByAutoModel,
onChange,
}: MultipleModeledMethodsPanelProps) => {
const [selectedIndex, setSelectedIndex] = useState<number>(0);
@ -163,12 +155,6 @@ export const MultipleModeledMethodsPanel = ({
modelConfig={modelConfig}
method={method}
modeledMethod={modeledMethods[selectedIndex]}
modelPending={isModelPending(
modeledMethods[selectedIndex],
modelingStatus,
isProcessedByAutoModel,
)}
isModelingInProgress={isModelingInProgress}
onChange={handleChange}
/>
) : (
@ -177,12 +163,6 @@ export const MultipleModeledMethodsPanel = ({
modelConfig={modelConfig}
method={method}
modeledMethod={undefined}
modelPending={isModelPending(
modeledMethods[selectedIndex],
modelingStatus,
isProcessedByAutoModel,
)}
isModelingInProgress={isModelingInProgress}
onChange={handleChange}
/>
)}

Просмотреть файл

@ -13,8 +13,6 @@ describe(MethodModeling.name, () => {
it("renders method modeling panel", () => {
const method = createMethod();
const modeledMethod = createSinkModeledMethod();
const isModelingInProgress = false;
const isProcessedByAutoModel = false;
const onChange = jest.fn();
render({
@ -23,8 +21,6 @@ describe(MethodModeling.name, () => {
modelingStatus: "saved",
method,
modeledMethods: [modeledMethod],
isModelingInProgress,
isProcessedByAutoModel,
onChange,
});

Просмотреть файл

@ -18,8 +18,6 @@ describe(MethodModelingInputs.name, () => {
const language = QueryLanguage.Java;
const method = createMethod();
const modeledMethod = createSinkModeledMethod();
const modelPending = false;
const isModelingInProgress = false;
const modelConfig = defaultModelConfig;
const onChange = jest.fn();
@ -28,8 +26,6 @@ describe(MethodModelingInputs.name, () => {
language,
method,
modeledMethod,
modelPending,
isModelingInProgress,
modelConfig,
onChange,
});
@ -56,8 +52,6 @@ describe(MethodModelingInputs.name, () => {
language,
method,
modeledMethod,
modelPending,
isModelingInProgress,
modelConfig,
onChange,
});
@ -80,8 +74,6 @@ describe(MethodModelingInputs.name, () => {
language,
method,
modeledMethod,
modelPending,
isModelingInProgress,
modelConfig,
onChange,
});
@ -96,8 +88,6 @@ describe(MethodModelingInputs.name, () => {
language={language}
method={method}
modeledMethod={updatedModeledMethod}
modelPending={modelPending}
isModelingInProgress={isModelingInProgress}
modelConfig={modelConfig}
onChange={onChange}
/>,
@ -121,32 +111,4 @@ describe(MethodModelingInputs.name, () => {
expect(modelOutputDropdown).toHaveValue("ReturnValue");
expect(modelKindDropdown).toHaveValue("local");
});
it("sets in progress dropdowns when modeling is in progress", () => {
render({
language,
method,
modeledMethod,
modelPending,
isModelingInProgress: true,
modelConfig,
onChange,
});
// Check that all the labels are rendered.
expect(screen.getByText("Model Type")).toBeInTheDocument();
expect(screen.getByText("Input")).toBeInTheDocument();
expect(screen.getByText("Output")).toBeInTheDocument();
expect(screen.getByText("Kind")).toBeInTheDocument();
// Check that all the dropdowns are rendered.
const dropdowns = screen.getAllByRole("combobox");
expect(dropdowns.length).toBe(4);
// Check that all the dropdowns are disabled and indicate have the value "Thinking...".
dropdowns.forEach((dropdown) => {
expect(dropdown).toBeDisabled();
expect(dropdown).toHaveValue("Thinking...");
});
});
});

Просмотреть файл

@ -10,25 +10,18 @@ import { MultipleModeledMethodsPanel } from "../MultipleModeledMethodsPanel";
import { userEvent } from "@testing-library/user-event";
import type { ModeledMethod } from "../../../model-editor/modeled-method";
import { QueryLanguage } from "../../../common/query-language";
import type { ModelingStatus } from "../../../model-editor/shared/modeling-status";
import { defaultModelConfig } from "../../../model-editor/languages";
describe(MultipleModeledMethodsPanel.name, () => {
const language = QueryLanguage.Java;
const method = createMethod();
const isModelingInProgress = false;
const isProcessedByAutoModel = false;
const modelingStatus: ModelingStatus = "unmodeled";
const onChange = jest.fn<void, [string, ModeledMethod[]]>();
const modelConfig = defaultModelConfig;
const baseProps = {
language,
method,
modelingStatus,
isModelingInProgress,
modelConfig,
isProcessedByAutoModel,
onChange,
};

Просмотреть файл

@ -1,17 +0,0 @@
import { styled } from "styled-components";
import { Dropdown } from "../common/Dropdown";
const StyledDropdown = styled(Dropdown)`
font-style: italic;
`;
export const InProgressDropdown = () => {
return (
<StyledDropdown
value="Thinking..."
options={[]}
disabled={true}
disabledPlaceholder="Thinking..."
/>
);
};

Просмотреть файл

@ -1,6 +1,4 @@
import { styled } from "styled-components";
import { Dropdown } from "../common/Dropdown";
export const InputDropdown = styled(Dropdown)<{ $pending: boolean }>`
font-style: ${(props) => (props.$pending ? "italic" : "normal")};
`;
export const InputDropdown = styled(Dropdown)``;

Просмотреть файл

@ -14,7 +14,6 @@ import {
} from "@vscode/webview-ui-toolkit/react";
import type { ModelEditorViewState } from "../../model-editor/shared/view-state";
import type { AccessPathSuggestionOptions } from "../../model-editor/suggestions";
import { getCandidates } from "../../model-editor/shared/auto-model-candidates";
import type { ModelEvaluationRunState } from "../../model-editor/shared/model-evaluation-run-state";
const LibraryContainer = styled.div`
@ -75,8 +74,6 @@ export type LibraryRowProps = {
modeledMethodsMap: Record<string, ModeledMethod[]>;
modifiedSignatures: Set<string>;
selectedSignatures: Set<string>;
inProgressMethods: Set<string>;
processedByAutoModelMethods: Set<string>;
viewState: ModelEditorViewState;
hideModeledMethods: boolean;
revealedMethodSignature: string | null;
@ -85,11 +82,6 @@ export type LibraryRowProps = {
onChange: (methodSignature: string, modeledMethods: ModeledMethod[]) => void;
onMethodClick: (methodSignature: string) => void;
onSaveModelClick: (methodSignatures: string[]) => void;
onGenerateFromLlmClick: (
dependencyName: string,
methodSignatures: string[],
) => void;
onStopGenerateFromLlmClick: (dependencyName: string) => void;
onGenerateFromSourceClick: () => void;
onModelDependencyClick: () => void;
};
@ -101,8 +93,6 @@ export const LibraryRow = ({
modeledMethodsMap,
modifiedSignatures,
selectedSignatures,
inProgressMethods,
processedByAutoModelMethods,
viewState,
hideModeledMethods,
revealedMethodSignature,
@ -111,8 +101,6 @@ export const LibraryRow = ({
onChange,
onMethodClick,
onSaveModelClick,
onGenerateFromLlmClick,
onStopGenerateFromLlmClick,
onGenerateFromSourceClick,
onModelDependencyClick,
}: LibraryRowProps) => {
@ -134,27 +122,6 @@ export const LibraryRow = ({
}
}, [methods, revealedMethodSignature]);
const handleModelWithAI = useCallback(
async (e: React.MouseEvent) => {
onGenerateFromLlmClick(
title,
methods.map((m) => m.signature),
);
e.stopPropagation();
e.preventDefault();
},
[title, methods, onGenerateFromLlmClick],
);
const handleStopModelWithAI = useCallback(
async (e: React.MouseEvent) => {
onStopGenerateFromLlmClick(title);
e.stopPropagation();
e.preventDefault();
},
[title, onStopGenerateFromLlmClick],
);
const handleModelFromSource = useCallback(
async (e: React.MouseEvent) => {
onGenerateFromSourceClick();
@ -186,21 +153,6 @@ export const LibraryRow = ({
return methods.some((method) => modifiedSignatures.has(method.signature));
}, [methods, modifiedSignatures]);
const canStopAutoModeling = useMemo(() => {
return methods.some((method) => inProgressMethods.has(method.signature));
}, [methods, inProgressMethods]);
const modelWithAIDisabled = useMemo(() => {
return (
getCandidates(
viewState.mode,
methods,
modeledMethodsMap,
processedByAutoModelMethods,
).length === 0
);
}, [methods, modeledMethodsMap, processedByAutoModelMethods, viewState.mode]);
return (
<LibraryContainer>
<TitleContainer onClick={toggleExpanded} aria-expanded={isExpanded}>
@ -219,22 +171,6 @@ export const LibraryRow = ({
</ModeledPercentage>
{hasUnsavedChanges ? <VSCodeTag>UNSAVED</VSCodeTag> : null}
</NameContainer>
{viewState.showLlmButton && !canStopAutoModeling && (
<VSCodeButton
appearance="icon"
disabled={modelWithAIDisabled}
onClick={handleModelWithAI}
>
<Codicon name="lightbulb-autofix" label="Model with AI" />
&nbsp;Model with AI
</VSCodeButton>
)}
{viewState.showLlmButton && canStopAutoModeling && (
<VSCodeButton appearance="icon" onClick={handleStopModelWithAI}>
<Codicon name="debug-stop" label="Stop model with AI" />
&nbsp;Stop
</VSCodeButton>
)}
{viewState.showGenerateButton &&
viewState.mode === Mode.Application && (
<VSCodeButton appearance="icon" onClick={handleModelFromSource}>
@ -257,8 +193,6 @@ export const LibraryRow = ({
modeledMethodsMap={modeledMethodsMap}
modifiedSignatures={modifiedSignatures}
selectedSignatures={selectedSignatures}
inProgressMethods={inProgressMethods}
processedByAutoModelMethods={processedByAutoModelMethods}
viewState={viewState}
hideModeledMethods={hideModeledMethods}
revealedMethodSignature={revealedMethodSignature}

Просмотреть файл

@ -2,7 +2,6 @@ import {
VSCodeBadge,
VSCodeButton,
VSCodeLink,
VSCodeProgressRing,
} from "@vscode/webview-ui-toolkit/react";
import {
forwardRef,
@ -17,13 +16,11 @@ import { vscode } from "../vscode-api";
import type { Method } from "../../model-editor/method";
import type { ModeledMethod } from "../../model-editor/modeled-method";
import { isModelPending } from "../../model-editor/modeled-method";
import { ModelKindDropdown } from "./ModelKindDropdown";
import { Mode } from "../../model-editor/shared/mode";
import { MethodClassifications } from "./MethodClassifications";
import { getModelingStatus } from "../../model-editor/shared/modeling-status";
import { ModelingStatusIndicator } from "./ModelingStatusIndicator";
import { InProgressDropdown } from "./InProgressDropdown";
import { MethodName } from "./MethodName";
import { ModelTypeDropdown } from "./ModelTypeDropdown";
import { ModelInputDropdown } from "./ModelInputDropdown";
@ -66,12 +63,6 @@ const ViewLink = styled(VSCodeLink)`
white-space: nowrap;
`;
const ProgressRing = styled(VSCodeProgressRing)`
width: 16px;
height: 16px;
margin-left: auto;
`;
const CodiconRow = styled(VSCodeButton)`
min-height: calc(var(--input-height) * 1px);
align-items: center;
@ -83,8 +74,6 @@ export type MethodRowProps = {
modeledMethods: ModeledMethod[];
methodIsUnsaved: boolean;
methodIsSelected: boolean;
modelingInProgress: boolean;
processedByAutoModel: boolean;
viewState: ModelEditorViewState;
revealedMethodSignature: string | null;
inputAccessPathSuggestions?: AccessPathOption[];
@ -122,7 +111,6 @@ const ModelableMethodRow = forwardRef<HTMLElement | undefined, MethodRowProps>(
modeledMethods: modeledMethodsProp,
methodIsUnsaved,
methodIsSelected,
processedByAutoModel,
viewState,
revealedMethodSignature,
inputAccessPathSuggestions,
@ -269,140 +257,105 @@ const ModelableMethodRow = forwardRef<HTMLElement | undefined, MethodRowProps>(
>
View
</ViewLink>
{props.modelingInProgress && <ProgressRing />}
</ApiOrMethodRow>
</DataGridCell>
{props.modelingInProgress && (
<>
<DataGridCell>
<InProgressDropdown />
</DataGridCell>
<DataGridCell>
<InProgressDropdown />
</DataGridCell>
<DataGridCell>
<InProgressDropdown />
</DataGridCell>
<DataGridCell>
<InProgressDropdown />
</DataGridCell>
<DataGridCell>
<CodiconRow appearance="icon" disabled={true}>
<Codicon name="add" label="Add new model" />
</CodiconRow>
</DataGridCell>
</>
)}
{!props.modelingInProgress && (
<>
{shownModeledMethods.map((modeledMethod, index) => {
const modelPending = isModelPending(
modeledMethod,
modelingStatus,
processedByAutoModel,
);
return (
<DataGridRow key={index} focused={focusedIndex === index}>
<DataGridCell>
<ModelTypeDropdown
language={viewState.language}
modelConfig={viewState.modelConfig}
method={method}
modeledMethod={modeledMethod}
modelPending={modelPending}
onChange={modeledMethodChangedHandlers[index]}
/>
</DataGridCell>
<DataGridCell>
{inputAccessPathSuggestions === undefined ? (
<ModelInputDropdown
language={viewState.language}
method={method}
modeledMethod={modeledMethod}
modelPending={modelPending}
onChange={modeledMethodChangedHandlers[index]}
/>
) : (
<ModelInputSuggestBox
modeledMethod={modeledMethod}
suggestions={inputAccessPathSuggestions}
typePathSuggestions={outputAccessPathSuggestions ?? []}
onChange={modeledMethodChangedHandlers[index]}
/>
)}
</DataGridCell>
<DataGridCell>
{outputAccessPathSuggestions === undefined ? (
<ModelOutputDropdown
language={viewState.language}
method={method}
modeledMethod={modeledMethod}
modelPending={modelPending}
onChange={modeledMethodChangedHandlers[index]}
/>
) : (
<ModelOutputSuggestBox
modeledMethod={modeledMethod}
suggestions={outputAccessPathSuggestions}
onChange={modeledMethodChangedHandlers[index]}
/>
)}
</DataGridCell>
<DataGridCell>
<ModelKindDropdown
language={viewState.language}
modeledMethod={modeledMethod}
modelPending={modelPending}
onChange={modeledMethodChangedHandlers[index]}
/>
</DataGridCell>
<DataGridCell>
<ModelButtonsContainer>
<ModelAlertsIndicator
viewState={viewState}
modeledMethod={modeledMethod}
evaluationRun={evaluationRun}
></ModelAlertsIndicator>
{index === 0 ? (
<CodiconRow
appearance="icon"
aria-label="Add new model"
onClick={(event: React.MouseEvent) => {
event.stopPropagation();
handleAddModelClick();
}}
disabled={addModelButtonDisabled}
>
<Codicon name="add" />
</CodiconRow>
) : (
<CodiconRow
appearance="icon"
aria-label="Remove model"
onClick={(event: React.MouseEvent) => {
event.stopPropagation();
removeModelClickedHandlers[index]();
}}
>
<Codicon name="trash" />
</CodiconRow>
)}
</ModelButtonsContainer>
</DataGridCell>
</DataGridRow>
);
})}
{validationErrors.map((error, index) => (
<DataGridCell gridColumn="span 5" key={index}>
<ModeledMethodAlert
error={error}
setSelectedIndex={setFocusedIndex}
{shownModeledMethods.map((modeledMethod, index) => {
return (
<DataGridRow key={index} focused={focusedIndex === index}>
<DataGridCell>
<ModelTypeDropdown
language={viewState.language}
modelConfig={viewState.modelConfig}
method={method}
modeledMethod={modeledMethod}
onChange={modeledMethodChangedHandlers[index]}
/>
</DataGridCell>
))}
</>
)}
<DataGridCell>
{inputAccessPathSuggestions === undefined ? (
<ModelInputDropdown
language={viewState.language}
method={method}
modeledMethod={modeledMethod}
onChange={modeledMethodChangedHandlers[index]}
/>
) : (
<ModelInputSuggestBox
modeledMethod={modeledMethod}
suggestions={inputAccessPathSuggestions}
typePathSuggestions={outputAccessPathSuggestions ?? []}
onChange={modeledMethodChangedHandlers[index]}
/>
)}
</DataGridCell>
<DataGridCell>
{outputAccessPathSuggestions === undefined ? (
<ModelOutputDropdown
language={viewState.language}
method={method}
modeledMethod={modeledMethod}
onChange={modeledMethodChangedHandlers[index]}
/>
) : (
<ModelOutputSuggestBox
modeledMethod={modeledMethod}
suggestions={outputAccessPathSuggestions}
onChange={modeledMethodChangedHandlers[index]}
/>
)}
</DataGridCell>
<DataGridCell>
<ModelKindDropdown
language={viewState.language}
modeledMethod={modeledMethod}
onChange={modeledMethodChangedHandlers[index]}
/>
</DataGridCell>
<DataGridCell>
<ModelButtonsContainer>
<ModelAlertsIndicator
viewState={viewState}
modeledMethod={modeledMethod}
evaluationRun={evaluationRun}
></ModelAlertsIndicator>
{index === 0 ? (
<CodiconRow
appearance="icon"
aria-label="Add new model"
onClick={(event: React.MouseEvent) => {
event.stopPropagation();
handleAddModelClick();
}}
disabled={addModelButtonDisabled}
>
<Codicon name="add" />
</CodiconRow>
) : (
<CodiconRow
appearance="icon"
aria-label="Remove model"
onClick={(event: React.MouseEvent) => {
event.stopPropagation();
removeModelClickedHandlers[index]();
}}
>
<Codicon name="trash" />
</CodiconRow>
)}
</ModelButtonsContainer>
</DataGridCell>
</DataGridRow>
);
})}
{validationErrors.map((error, index) => (
<DataGridCell gridColumn="span 5" key={index}>
<ModeledMethodAlert
error={error}
setSelectedIndex={setFocusedIndex}
/>
</DataGridCell>
))}
</DataGridRow>
);
},

Просмотреть файл

@ -102,12 +102,6 @@ export function ModelEditor({
new Set(),
);
const [inProgressMethods, setInProgressMethods] = useState<Set<string>>(
new Set(),
);
const [processedByAutoModelMethods, setProcessedByAutoModelMethods] =
useState<Set<string>>(new Set());
const [hideModeledMethods, setHideModeledMethods] = useState(
initialHideModeledMethods,
);
@ -153,14 +147,6 @@ export function ModelEditor({
case "setModifiedMethods":
setModifiedSignatures(new Set(msg.methodSignatures));
break;
case "setInProgressMethods": {
setInProgressMethods(new Set(msg.methods));
break;
}
case "setProcessedByAutoModelMethods": {
setProcessedByAutoModelMethods(new Set(msg.methods));
break;
}
case "revealMethod":
setRevealedMethodSignature(msg.methodSignature);
break;
@ -294,24 +280,6 @@ export function ModelEditor({
});
}, []);
const onGenerateFromLlmClick = useCallback(
(packageName: string, methodSignatures: string[]) => {
vscode.postMessage({
t: "generateMethodsFromLlm",
packageName,
methodSignatures,
});
},
[],
);
const onStopGenerateFromLlmClick = useCallback((packageName: string) => {
vscode.postMessage({
t: "stopGeneratingMethodsFromLlm",
packageName,
});
}, []);
const onOpenDatabaseClick = useCallback(() => {
vscode.postMessage({
t: "openDatabase",
@ -430,8 +398,6 @@ export function ModelEditor({
modeledMethodsMap={modeledMethods}
modifiedSignatures={modifiedSignatures}
selectedSignatures={selectedSignatures}
inProgressMethods={inProgressMethods}
processedByAutoModelMethods={processedByAutoModelMethods}
viewState={viewState}
hideModeledMethods={hideModeledMethods}
revealedMethodSignature={revealedMethodSignature}
@ -440,8 +406,6 @@ export function ModelEditor({
onChange={onChange}
onMethodClick={onMethodClick}
onSaveModelClick={onSaveModelClick}
onGenerateFromLlmClick={onGenerateFromLlmClick}
onStopGenerateFromLlmClick={onStopGenerateFromLlmClick}
onGenerateFromSourceClick={onGenerateFromSourceClick}
onModelDependencyClick={onModelDependencyClick}
/>

Просмотреть файл

@ -15,7 +15,6 @@ type Props = {
language: QueryLanguage;
method: Method;
modeledMethod: ModeledMethod | undefined;
modelPending: boolean;
onChange: (modeledMethod: ModeledMethod) => void;
};
@ -23,7 +22,6 @@ export const ModelInputDropdown = ({
language,
method,
modeledMethod,
modelPending,
onChange,
}: Props): React.JSX.Element => {
const options = useMemo(() => {
@ -80,7 +78,6 @@ export const ModelInputDropdown = ({
value={value}
options={options}
disabled={!enabled}
$pending={modelPending}
onChange={handleChange}
aria-label="Input"
/>

Просмотреть файл

@ -15,14 +15,12 @@ import { InputDropdown } from "./InputDropdown";
type Props = {
language: QueryLanguage;
modeledMethod: ModeledMethod | undefined;
modelPending: boolean;
onChange: (modeledMethod: ModeledMethod) => void;
};
export const ModelKindDropdown = ({
language,
modeledMethod,
modelPending,
onChange,
}: Props) => {
const predicate = useMemo(() => {
@ -92,7 +90,6 @@ export const ModelKindDropdown = ({
value={value}
options={options}
disabled={disabled}
$pending={modelPending}
onChange={handleChange}
aria-label="Kind"
/>

Просмотреть файл

@ -15,7 +15,6 @@ type Props = {
language: QueryLanguage;
method: Method;
modeledMethod: ModeledMethod | undefined;
modelPending: boolean;
onChange: (modeledMethod: ModeledMethod) => void;
};
@ -23,7 +22,6 @@ export const ModelOutputDropdown = ({
language,
method,
modeledMethod,
modelPending,
onChange,
}: Props): React.JSX.Element => {
const options = useMemo(() => {
@ -81,7 +79,6 @@ export const ModelOutputDropdown = ({
value={value}
options={options}
disabled={!enabled}
$pending={modelPending}
onChange={handleChange}
aria-label="Output"
/>

Просмотреть файл

@ -22,7 +22,6 @@ type Props = {
modelConfig: ModelConfig;
method: Method;
modeledMethod: ModeledMethod | undefined;
modelPending: boolean;
onChange: (modeledMethod: ModeledMethod) => void;
};
@ -41,7 +40,6 @@ export const ModelTypeDropdown = ({
modelConfig,
method,
modeledMethod,
modelPending,
onChange,
}: Props): React.JSX.Element => {
const options = useMemo(() => {
@ -126,7 +124,6 @@ export const ModelTypeDropdown = ({
<InputDropdown
value={modeledMethod?.type ?? "none"}
options={options}
$pending={modelPending}
onChange={handleChange}
aria-label="Model type"
/>

Просмотреть файл

@ -18,8 +18,6 @@ export type ModeledMethodDataGridProps = {
modeledMethodsMap: Record<string, ModeledMethod[]>;
modifiedSignatures: Set<string>;
selectedSignatures: Set<string>;
inProgressMethods: Set<string>;
processedByAutoModelMethods: Set<string>;
viewState: ModelEditorViewState;
hideModeledMethods: boolean;
revealedMethodSignature: string | null;
@ -34,8 +32,6 @@ export const ModeledMethodDataGrid = ({
modeledMethodsMap,
modifiedSignatures,
selectedSignatures,
inProgressMethods,
processedByAutoModelMethods,
viewState,
hideModeledMethods,
revealedMethodSignature,
@ -96,10 +92,6 @@ export const ModeledMethodDataGrid = ({
modeledMethods={modeledMethods}
methodIsUnsaved={modifiedSignatures.has(method.signature)}
methodIsSelected={selectedSignatures.has(method.signature)}
modelingInProgress={inProgressMethods.has(method.signature)}
processedByAutoModel={processedByAutoModelMethods.has(
method.signature,
)}
viewState={viewState}
revealedMethodSignature={revealedMethodSignature}
inputAccessPathSuggestions={inputAccessPathSuggestions}

Просмотреть файл

@ -16,8 +16,6 @@ export type ModeledMethodsListProps = {
modeledMethodsMap: Record<string, ModeledMethod[]>;
modifiedSignatures: Set<string>;
selectedSignatures: Set<string>;
inProgressMethods: Set<string>;
processedByAutoModelMethods: Set<string>;
revealedMethodSignature: string | null;
accessPathSuggestions?: AccessPathSuggestionOptions;
evaluationRun: ModelEvaluationRunState | undefined;
@ -26,11 +24,6 @@ export type ModeledMethodsListProps = {
onChange: (methodSignature: string, modeledMethods: ModeledMethod[]) => void;
onMethodClick: (methodSignature: string) => void;
onSaveModelClick: (methodSignatures: string[]) => void;
onGenerateFromLlmClick: (
packageName: string,
methodSignatures: string[],
) => void;
onStopGenerateFromLlmClick: (packageName: string) => void;
onGenerateFromSourceClick: () => void;
onModelDependencyClick: () => void;
};
@ -44,8 +37,6 @@ export const ModeledMethodsList = ({
modeledMethodsMap,
modifiedSignatures,
selectedSignatures,
inProgressMethods,
processedByAutoModelMethods,
viewState,
hideModeledMethods,
revealedMethodSignature,
@ -54,8 +45,6 @@ export const ModeledMethodsList = ({
onChange,
onMethodClick,
onSaveModelClick,
onGenerateFromLlmClick,
onStopGenerateFromLlmClick,
onGenerateFromSourceClick,
onModelDependencyClick,
}: ModeledMethodsListProps) => {
@ -95,8 +84,6 @@ export const ModeledMethodsList = ({
modeledMethodsMap={modeledMethodsMap}
modifiedSignatures={modifiedSignatures}
selectedSignatures={selectedSignatures}
inProgressMethods={inProgressMethods}
processedByAutoModelMethods={processedByAutoModelMethods}
viewState={viewState}
hideModeledMethods={hideModeledMethods}
revealedMethodSignature={revealedMethodSignature}
@ -105,8 +92,6 @@ export const ModeledMethodsList = ({
onChange={onChange}
onMethodClick={onMethodClick}
onSaveModelClick={onSaveModelClick}
onGenerateFromLlmClick={onGenerateFromLlmClick}
onStopGenerateFromLlmClick={onStopGenerateFromLlmClick}
onGenerateFromSourceClick={onGenerateFromSourceClick}
onModelDependencyClick={onModelDependencyClick}
/>

Просмотреть файл

@ -10,8 +10,6 @@ describe(LibraryRow.name, () => {
const onChange = jest.fn();
const onMethodClick = jest.fn();
const onSaveModelClick = jest.fn();
const onGenerateFromLlmClick = jest.fn();
const onStopGenerateFromLlmClick = jest.fn();
const onModelDependencyClick = jest.fn();
const viewState = createMockModelEditorViewState();
@ -35,8 +33,6 @@ describe(LibraryRow.name, () => {
}}
modifiedSignatures={new Set([method.signature])}
selectedSignatures={new Set()}
inProgressMethods={new Set()}
processedByAutoModelMethods={new Set()}
evaluationRun={undefined}
viewState={viewState}
hideModeledMethods={false}
@ -44,8 +40,6 @@ describe(LibraryRow.name, () => {
onChange={onChange}
onMethodClick={onMethodClick}
onSaveModelClick={onSaveModelClick}
onGenerateFromLlmClick={onGenerateFromLlmClick}
onStopGenerateFromLlmClick={onStopGenerateFromLlmClick}
onGenerateFromSourceClick={jest.fn()}
onModelDependencyClick={onModelDependencyClick}
{...props}
@ -74,33 +68,6 @@ describe(LibraryRow.name, () => {
expect(screen.queryByText("Model dependency")).toBeInTheDocument();
});
it("renders the row when LLM is enabled", () => {
render({
viewState: {
...viewState,
showLlmButton: true,
},
});
expect(screen.queryByText("Model from source")).not.toBeInTheDocument();
expect(screen.queryByText("Model with AI")).toBeInTheDocument();
expect(screen.queryByText("Model dependency")).toBeInTheDocument();
});
it("renders the row when generate button and LLM are enabled", () => {
render({
viewState: {
...viewState,
showGenerateButton: true,
showLlmButton: true,
},
});
expect(screen.queryByText("Model from source")).toBeInTheDocument();
expect(screen.queryByText("Model with AI")).toBeInTheDocument();
expect(screen.queryByText("Model dependency")).toBeInTheDocument();
});
it("can expand the row", async () => {
render();

Просмотреть файл

@ -42,8 +42,6 @@ describe(MethodRow.name, () => {
modeledMethods={[modeledMethod]}
methodIsUnsaved={false}
methodIsSelected={false}
modelingInProgress={false}
processedByAutoModel={false}
revealedMethodSignature={null}
evaluationRun={undefined}
viewState={viewState}
@ -186,14 +184,6 @@ describe(MethodRow.name, () => {
expect(screen.getByLabelText("Method not modeled")).toBeInTheDocument();
});
it("shows the in progress indicator when in progress", () => {
render({
modelingInProgress: true,
});
expect(screen.getByLabelText("Loading")).toBeInTheDocument();
});
it("can render multiple models", () => {
render({
modeledMethods: [

Просмотреть файл

@ -24,7 +24,6 @@ describe(ModelKindDropdown.name, () => {
<ModelKindDropdown
language={QueryLanguage.Java}
modeledMethod={modeledMethod}
modelPending={false}
onChange={onChange}
/>,
);
@ -47,7 +46,6 @@ describe(ModelKindDropdown.name, () => {
<ModelKindDropdown
language={QueryLanguage.Java}
modeledMethod={modeledMethod}
modelPending={false}
onChange={onChange}
/>,
);
@ -64,7 +62,6 @@ describe(ModelKindDropdown.name, () => {
<ModelKindDropdown
language={QueryLanguage.Java}
modeledMethod={updatedModeledMethod}
modelPending={false}
onChange={onChange}
/>,
);
@ -82,7 +79,6 @@ describe(ModelKindDropdown.name, () => {
<ModelKindDropdown
language={QueryLanguage.Java}
modeledMethod={modeledMethod}
modelPending={false}
onChange={onChange}
/>,
);
@ -102,7 +98,6 @@ describe(ModelKindDropdown.name, () => {
<ModelKindDropdown
language={QueryLanguage.Java}
modeledMethod={modeledMethod}
modelPending={false}
onChange={onChange}
/>,
);

Просмотреть файл

@ -21,7 +21,6 @@ describe(ModelTypeDropdown.name, () => {
<ModelTypeDropdown
language={QueryLanguage.Java}
modeledMethod={modeledMethod}
modelPending={false}
onChange={onChange}
method={method}
modelConfig={defaultModelConfig}
@ -44,7 +43,6 @@ describe(ModelTypeDropdown.name, () => {
<ModelTypeDropdown
language={QueryLanguage.Ruby}
modeledMethod={modeledMethod}
modelPending={false}
onChange={onChange}
method={method}
modelConfig={defaultModelConfig}
@ -67,7 +65,6 @@ describe(ModelTypeDropdown.name, () => {
<ModelTypeDropdown
language={QueryLanguage.Java}
modeledMethod={modeledMethod}
modelPending={false}
onChange={onChange}
method={method}
modelConfig={defaultModelConfig}

Просмотреть файл

@ -57,8 +57,6 @@ describe(ModeledMethodDataGrid.name, () => {
}}
modifiedSignatures={new Set([method1.signature])}
selectedSignatures={new Set()}
inProgressMethods={new Set()}
processedByAutoModelMethods={new Set()}
evaluationRun={undefined}
viewState={viewState}
hideModeledMethods={false}

Просмотреть файл

@ -35,8 +35,6 @@ describe(ModeledMethodsList.name, () => {
const onChange = jest.fn();
const onMethodClick = jest.fn();
const onSaveModelClick = jest.fn();
const onGenerateFromLlmClick = jest.fn();
const onStopGenerateFromLlmClick = jest.fn();
const onModelDependencyClick = jest.fn();
const viewState = createMockModelEditorViewState();
@ -58,8 +56,6 @@ describe(ModeledMethodsList.name, () => {
}}
modifiedSignatures={new Set([method1.signature])}
selectedSignatures={new Set()}
inProgressMethods={new Set()}
processedByAutoModelMethods={new Set()}
evaluationRun={undefined}
viewState={viewState}
hideModeledMethods={false}
@ -67,8 +63,6 @@ describe(ModeledMethodsList.name, () => {
onChange={onChange}
onMethodClick={onMethodClick}
onSaveModelClick={onSaveModelClick}
onGenerateFromLlmClick={onGenerateFromLlmClick}
onStopGenerateFromLlmClick={onStopGenerateFromLlmClick}
onGenerateFromSourceClick={jest.fn()}
onModelDependencyClick={onModelDependencyClick}
{...props}

Просмотреть файл

@ -11,7 +11,6 @@ export function createMockModelEditorViewState(
language: QueryLanguage.Java,
mode: Mode.Application,
showGenerateButton: false,
showLlmButton: false,
showEvaluationUi: false,
showModeSwitchButton: true,
extensionPack: createMockExtensionPack(),

Просмотреть файл

@ -1,82 +0,0 @@
import {
createAutoModelRequest,
encodeSarif,
} from "../../../src/model-editor/auto-model";
import { Mode } from "../../../src/model-editor/shared/mode";
import { AutomodelMode } from "../../../src/model-editor/auto-model-api";
import type { AutoModelQueriesResult } from "../../../src/model-editor/auto-model-codeml-queries";
import type { Log } from "sarif";
import { gzipDecode } from "../../../src/common/zlib";
describe("createAutoModelRequest", () => {
const createSarifLog = (queryId: string): Log => {
return {
version: "2.1.0",
$schema: "http://json.schemastore.org/sarif-2.1.0-rtm.4",
runs: [
{
tool: {
driver: {
name: "CodeQL",
rules: [
{
id: queryId,
},
],
},
},
results: [
{
message: {
text: "msg",
},
locations: [
{
physicalLocation: {
contextRegion: {
startLine: 10,
endLine: 12,
snippet: {
text: "Foo",
},
},
region: {
startLine: 10,
startColumn: 1,
endColumn: 3,
},
artifactLocation: {
uri: "foo.js",
},
},
},
],
},
],
},
],
};
};
const result: AutoModelQueriesResult = {
candidates: createSarifLog(
"java/ml/extract-automodel-application-candidates",
),
};
it("creates a matching request", async () => {
expect(await createAutoModelRequest(Mode.Application, result)).toEqual({
mode: AutomodelMode.Application,
candidates: await encodeSarif(result.candidates),
});
});
it("can decode the SARIF", async () => {
const request = await createAutoModelRequest(Mode.Application, result);
const decoded = Buffer.from(request.candidates, "base64");
const decompressed = await gzipDecode(decoded);
const json = decompressed.toString("utf-8");
const parsed = JSON.parse(json);
expect(parsed).toEqual(result.candidates);
});
});

Просмотреть файл

@ -1,120 +0,0 @@
import type { Method } from "../../../../src/model-editor/method";
import { EndpointType } from "../../../../src/model-editor/method";
import type { ModeledMethod } from "../../../../src/model-editor/modeled-method";
import { getCandidates } from "../../../../src/model-editor/shared/auto-model-candidates";
import { Mode } from "../../../../src/model-editor/shared/mode";
describe("getCandidates", () => {
it("doesn't return methods that are already modelled", () => {
const methods: Method[] = [
{
library: "my.jar",
signature: "org.my.A#x()",
endpointType: EndpointType.Method,
packageName: "org.my",
typeName: "A",
methodName: "x",
methodParameters: "()",
supported: false,
supportedType: "none",
usages: [],
},
];
const modeledMethods: Record<string, ModeledMethod[]> = {
"org.my.A#x()": [
{
type: "neutral",
kind: "sink",
provenance: "manual",
signature: "org.my.A#x()",
endpointType: EndpointType.Method,
packageName: "org.my",
typeName: "A",
methodName: "x",
methodParameters: "()",
},
],
};
const candidates = getCandidates(
Mode.Application,
methods,
modeledMethods,
new Set(),
);
expect(candidates.length).toEqual(0);
});
it("doesn't return methods that are supported from other sources", () => {
const methods: Method[] = [
{
library: "my.jar",
signature: "org.my.A#x()",
endpointType: EndpointType.Method,
packageName: "org.my",
typeName: "A",
methodName: "x",
methodParameters: "()",
supported: true,
supportedType: "none",
usages: [],
},
];
const modeledMethods = {};
const candidates = getCandidates(
Mode.Application,
methods,
modeledMethods,
new Set(),
);
expect(candidates.length).toEqual(0);
});
it("doesn't return methods that are already processed by auto model", () => {
const methods: Method[] = [
{
library: "my.jar",
signature: "org.my.A#x()",
endpointType: EndpointType.Method,
packageName: "org.my",
typeName: "A",
methodName: "x",
methodParameters: "()",
supported: false,
supportedType: "none",
usages: [],
},
];
const modeledMethods = {};
const candidates = getCandidates(
Mode.Application,
methods,
modeledMethods,
new Set(["org.my.A#x()"]),
);
expect(candidates.length).toEqual(0);
});
it("returns methods that are neither modeled nor supported from other sources", () => {
const methods: Method[] = [];
methods.push({
library: "my.jar",
signature: "org.my.A#x()",
endpointType: EndpointType.Method,
packageName: "org.my",
typeName: "A",
methodName: "x",
methodParameters: "()",
supported: false,
supportedType: "none",
usages: [],
});
const modeledMethods = {};
const candidates = getCandidates(
Mode.Application,
methods,
modeledMethods,
new Set(),
);
expect(candidates.length).toEqual(1);
});
});

Просмотреть файл

@ -10,16 +10,8 @@ import { shuffle } from "../../../vscode-tests/utils/list-helpers";
describe("sortMethods", () => {
it("uses primary sort order", () => {
const unsavedPositiveAutoModelPrediction = createMethod({
signature: "org.sql2o.Sql2o#unsavedPositiveAutoModelPrediction()",
supported: false,
});
const negativeAutoModelPrediction = createMethod({
signature: "org.sql2o.Sql2o#negativeAutoModelPrediction()",
supported: false,
});
const unsavedManualModel = createMethod({
signature: "org.sql2o.Sql2o#unsavedManualModel()",
const unsavedModel = createMethod({
signature: "org.sql2o.Sql2o#unsavedModel()",
supported: false,
});
const unmodeledMethodWithEarlierSignature = createMethod({
@ -30,12 +22,8 @@ describe("sortMethods", () => {
signature: "org.sql2o.Sql2o#zzz_unmodeledMethodWithLaterSignature()",
supported: false,
});
const savedAutoModelPrediction = createMethod({
signature: "org.sql2o.Sql2o#savedAutoModelPrediction()",
supported: false,
});
const savedManualModel = createMethod({
signature: "org.sql2o.Sql2o#savedManualModel()",
const savedModel = createMethod({
signature: "org.sql2o.Sql2o#savedModel()",
supported: false,
});
const supportedMethod = createMethod({
@ -44,65 +32,31 @@ describe("sortMethods", () => {
});
const methods: Method[] = shuffle([
unsavedPositiveAutoModelPrediction,
negativeAutoModelPrediction,
unsavedManualModel,
unsavedModel,
unmodeledMethodWithEarlierSignature,
unmodeledMethodWithLaterSignature,
savedAutoModelPrediction,
savedManualModel,
savedModel,
supportedMethod,
]);
const modeledMethodsMap: Record<string, readonly ModeledMethod[]> = {};
modeledMethodsMap[unsavedPositiveAutoModelPrediction.signature] = [
createSinkModeledMethod(),
];
modeledMethodsMap[unsavedManualModel.signature] = [
createSinkModeledMethod(),
];
modeledMethodsMap[savedAutoModelPrediction.signature] = [
createSinkModeledMethod(),
];
modeledMethodsMap[savedManualModel.signature] = [createSinkModeledMethod()];
modeledMethodsMap[unsavedModel.signature] = [createSinkModeledMethod()];
modeledMethodsMap[savedModel.signature] = [createSinkModeledMethod()];
const modifiedSignatures: Set<string> = new Set([
unsavedPositiveAutoModelPrediction.signature,
unsavedManualModel.signature,
]);
const modifiedSignatures: Set<string> = new Set([unsavedModel.signature]);
const processedByAutoModelMethods: Set<string> = new Set([
unsavedPositiveAutoModelPrediction.signature,
negativeAutoModelPrediction.signature,
savedAutoModelPrediction.signature,
]);
expect(
sortMethods(
methods,
modeledMethodsMap,
modifiedSignatures,
processedByAutoModelMethods,
),
).toEqual([
unsavedPositiveAutoModelPrediction,
negativeAutoModelPrediction,
unmodeledMethodWithEarlierSignature,
unsavedManualModel,
unmodeledMethodWithLaterSignature,
savedAutoModelPrediction,
savedManualModel,
supportedMethod,
]);
expect(sortMethods(methods, modeledMethodsMap, modifiedSignatures)).toEqual(
[
unmodeledMethodWithEarlierSignature,
unsavedModel,
unmodeledMethodWithLaterSignature,
savedModel,
supportedMethod,
],
);
});
it("uses secondary sort order based on usages and signature", () => {
const negativeAutoModelPrediction = createMethod({
signature: "org.sql2o.Sql2o#negativeAutoModelPrediction()",
supported: false,
usages: [],
});
const unmodeledMethodWithTwoUsages = createMethod({
signature: "org.sql2o.Sql2o#unmodeledMethodWithTwoUsages()",
supported: false,
@ -126,7 +80,6 @@ describe("sortMethods", () => {
});
const methods: Method[] = shuffle([
negativeAutoModelPrediction,
unmodeledMethodWithTwoUsages,
unmodeledMethodWithOneUsage,
unmodeledMethodWithEarlierSignature,
@ -137,23 +90,13 @@ describe("sortMethods", () => {
const modifiedSignatures: Set<string> = new Set([]);
const processedByAutoModelMethods: Set<string> = new Set([
negativeAutoModelPrediction.signature,
]);
expect(
sortMethods(
methods,
modeledMethodsMap,
modifiedSignatures,
processedByAutoModelMethods,
),
).toEqual([
negativeAutoModelPrediction,
unmodeledMethodWithTwoUsages,
unmodeledMethodWithOneUsage,
unmodeledMethodWithEarlierSignature,
unmodeledMethodWithLaterSignature,
]);
expect(sortMethods(methods, modeledMethodsMap, modifiedSignatures)).toEqual(
[
unmodeledMethodWithTwoUsages,
unmodeledMethodWithOneUsage,
unmodeledMethodWithEarlierSignature,
unmodeledMethodWithLaterSignature,
],
);
});
});

Просмотреть файл

@ -1,207 +0,0 @@
import { createMockLogger } from "../../../__mocks__/loggerMock";
import type { DatabaseItem } from "../../../../src/databases/local-databases";
import { DatabaseKind } from "../../../../src/databases/local-databases";
import { file } from "tmp-promise";
import { QueryResultType } from "../../../../src/query-server/messages";
import {
generateCandidateFilterPack,
runAutoModelQueries,
} from "../../../../src/model-editor/auto-model-codeml-queries";
import { Mode } from "../../../../src/model-editor/shared/mode";
import { mockedObject, mockedUri } from "../../utils/mocking.helpers";
import type { CodeQLCliServer } from "../../../../src/codeql-cli/cli";
import type { QueryRunner } from "../../../../src/query-server";
import * as queryResolver from "../../../../src/local-queries/query-resolver";
import type { MethodSignature } from "../../../../src/model-editor/method";
import { EndpointType } from "../../../../src/model-editor/method";
import { join } from "path";
import { pathExists, readFile } from "fs-extra";
import { load as loadYaml } from "js-yaml";
import { CancellationTokenSource } from "vscode-jsonrpc";
import { QueryOutputDir } from "../../../../src/local-queries/query-output-dir";
import type { ModelExtensionFile } from "../../../../src/model-editor/model-extension-file";
describe("runAutoModelQueries", () => {
let resolveQueriesSpy: jest.SpiedFunction<
typeof queryResolver.resolveQueries
>;
beforeEach(() => {
resolveQueriesSpy = jest
.spyOn(queryResolver, "resolveQueries")
.mockImplementation(
async (_cliServer, _packsToSearch, _name, constraints) => {
if (constraints["tags contain all"]?.includes("candidates")) {
return ["/a/b/c/ql/candidates.ql"];
}
if (constraints["tags contain all"]?.includes("positive")) {
return ["/a/b/c/ql/positive-examples.ql"];
}
if (constraints["tags contain all"]?.includes("negative")) {
return ["/a/b/c/ql/negative-examples.ql"];
}
return [];
},
);
});
it("should run the query and return the results", async () => {
const queryStorageDir = (await file()).path;
const outputDir = new QueryOutputDir(join(queryStorageDir, "1"));
const options = {
mode: Mode.Application,
candidateMethods: [],
cliServer: mockedObject<CodeQLCliServer>({
resolveQlpacks: jest.fn().mockResolvedValue({
"/a/b/c/my-extension-pack": {},
}),
resolveMetadata: jest.fn().mockResolvedValue({
kind: "problem",
}),
interpretBqrsSarif: jest.fn().mockResolvedValue({
version: "2.1.0",
$schema: "http://json.schemastore.org/sarif-2.1.0-rtm.4",
runs: [
{
tool: {
driver: {
name: "CodeQL",
},
},
results: [
{
message: {
text: "msg",
},
locations: [
{
physicalLocation: {
contextRegion: {
startLine: 10,
endLine: 12,
snippet: {
text: "Foo",
},
},
region: {
startLine: 10,
startColumn: 1,
endColumn: 3,
},
artifactLocation: {
uri: "foo.js",
},
},
},
],
},
],
},
],
}),
}),
queryRunner: mockedObject<QueryRunner>({
createQueryRun: jest.fn().mockReturnValue({
evaluate: jest.fn().mockResolvedValue({
resultType: QueryResultType.SUCCESS,
outputDir,
}),
outputDir,
}),
logger: createMockLogger(),
}),
databaseItem: mockedObject<DatabaseItem>({
databaseUri: mockedUri("/a/b/c/src.zip"),
contents: {
kind: DatabaseKind.Database,
name: "foo",
datasetUri: mockedUri(),
},
language: "java",
getSourceLocationPrefix: jest
.fn()
.mockResolvedValue("/home/runner/work/my-repo/my-repo"),
sourceArchive: mockedUri("/a/b/c/src.zip"),
}),
queryStorageDir: "/tmp/queries",
progress: jest.fn(),
cancellationTokenSource: new CancellationTokenSource(),
};
const result = await runAutoModelQueries(options);
expect(result).not.toBeUndefined();
expect(options.cliServer.resolveQlpacks).toHaveBeenCalledTimes(1);
expect(options.cliServer.resolveQlpacks).toHaveBeenCalledWith(
expect.arrayContaining([expect.stringContaining("tmp")]),
true,
);
expect(resolveQueriesSpy).toHaveBeenCalledTimes(1);
expect(resolveQueriesSpy).toHaveBeenCalledWith(
options.cliServer,
["codeql/java-automodel-queries"],
"Extract automodel candidates",
{
kind: "problem",
"tags contain all": ["automodel", "application-mode", "candidates"],
},
);
expect(options.queryRunner.createQueryRun).toHaveBeenCalledTimes(1);
expect(options.queryRunner.createQueryRun).toHaveBeenCalledWith(
"/a/b/c/src.zip",
{
queryPath: "/a/b/c/ql/candidates.ql",
quickEvalPosition: undefined,
quickEvalCountOnly: false,
},
false,
expect.arrayContaining([expect.stringContaining("tmp")]),
["/a/b/c/my-extension-pack"],
{},
"/tmp/queries",
undefined,
undefined,
);
});
});
describe("generateCandidateFilterPack", () => {
it("should create a temp pack containing the candidate filters", async () => {
const candidateMethods: MethodSignature[] = [
{
signature: "org.my.A#x()",
endpointType: EndpointType.Method,
packageName: "org.my",
typeName: "A",
methodName: "x",
methodParameters: "()",
},
];
const { packDir, cleanup } = await generateCandidateFilterPack(
"java",
candidateMethods,
);
expect(packDir).not.toBeUndefined();
const qlpackFile = join(packDir, "codeql-pack.yml");
expect(await pathExists(qlpackFile)).toBe(true);
const filterFile = join(packDir, "filter.yml");
expect(await pathExists(filterFile)).toBe(true);
// Read the contents of filterFile and parse as yaml
const yaml = (await loadYaml(
await readFile(filterFile, "utf8"),
)) as ModelExtensionFile;
const extensions = yaml.extensions;
expect(extensions).toBeInstanceOf(Array);
expect(extensions).toHaveLength(1);
const extension = extensions[0];
expect(extension.addsTo.pack).toEqual("codeql/java-automodel-queries");
expect(extension.addsTo.extensible).toEqual("automodelCandidateFilter");
expect(extension.data).toBeInstanceOf(Array);
expect(extension.data).toHaveLength(1);
expect(extension.data[0]).toEqual(["org.my", "A", "x", "()"]);
await cleanup();
expect(await pathExists(packDir)).toBe(false);
});
});

Просмотреть файл

@ -153,8 +153,6 @@ describe("method modeling view provider", () => {
usage: createUsage(),
modeledMethods: [],
isModified: false,
isInProgress: false,
processedByAutoModel: false,
};
getSelectedMethodDetails.mockReturnValue(selectedMethodDetails);
@ -191,8 +189,6 @@ describe("method modeling view provider", () => {
method: selectedMethodDetails.method,
modeledMethods: selectedMethodDetails.modeledMethods,
isModified: selectedMethodDetails.isModified,
isInProgress: selectedMethodDetails.isInProgress,
processedByAutoModel: selectedMethodDetails.processedByAutoModel,
});
});
});

Просмотреть файл

@ -104,8 +104,6 @@ describe("MethodsUsagePanel", () => {
usage,
modeledMethods[method.signature],
modifiedMethodSignatures.has(method.signature),
false,
false,
);
expect(mockTreeView.reveal).toHaveBeenCalledWith(
@ -139,8 +137,6 @@ describe("MethodsUsagePanel", () => {
usage,
modeledMethods[method.signature],
modifiedMethodSignatures.has(method.signature),
false,
false,
);
expect(mockTreeView.reveal).not.toHaveBeenCalled();

Просмотреть файл

@ -8,7 +8,6 @@ import type { QueryLanguage } from "../../../../src/common/query-language";
import { Mode } from "../../../../src/model-editor/shared/mode";
import { mockedObject } from "../../utils/mocking.helpers";
import type { CodeQLCliServer } from "../../../../src/codeql-cli/cli";
import type { ModelConfig } from "../../../../src/config";
import { createMockLogger } from "../../../__mocks__/loggerMock";
describe("setUpPack", () => {
@ -44,18 +43,8 @@ describe("setUpPack", () => {
resolveQueriesInSuite: jest.fn().mockResolvedValue([]),
});
const logger = createMockLogger();
const modelConfig = mockedObject<ModelConfig>({
llmGeneration: false,
});
await setUpPack(
cliServer,
logger,
queryDir,
language,
modelConfig,
Mode.Application,
);
await setUpPack(cliServer, logger, queryDir, language, Mode.Application);
const queryFiles = await readdir(queryDir);
expect(queryFiles).toEqual(
@ -109,18 +98,8 @@ describe("setUpPack", () => {
.mockResolvedValue(["/a/b/c/ApplicationModeEndpoints.ql"]),
});
const logger = createMockLogger();
const modelConfig = mockedObject<ModelConfig>({
llmGeneration: false,
});
await setUpPack(
cliServer,
logger,
queryDir,
language,
modelConfig,
Mode.Application,
);
await setUpPack(cliServer, logger, queryDir, language, Mode.Application);
const queryFiles = await readdir(queryDir);
expect(queryFiles.sort()).toEqual(["codeql-pack.yml"].sort());