Merge pull request #3719 from github/koesie10/remove-automodel
Remove automodel-related functionality
This commit is contained in:
Коммит
7907d8de5d
|
@ -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} />
|
||||
)}
|
||||
</Input>
|
||||
</Container>
|
||||
<Container>
|
||||
<Input>
|
||||
<Name>Input</Name>
|
||||
{isModelingInProgress ? (
|
||||
<InProgressDropdown />
|
||||
) : (
|
||||
<ModelInputDropdown {...inputProps} />
|
||||
)}
|
||||
</Input>
|
||||
</Container>
|
||||
<Container>
|
||||
<Input>
|
||||
<Name>Output</Name>
|
||||
{isModelingInProgress ? (
|
||||
<InProgressDropdown />
|
||||
) : (
|
||||
<ModelOutputDropdown {...inputProps} />
|
||||
)}
|
||||
</Input>
|
||||
</Container>
|
||||
<Container>
|
||||
<Input>
|
||||
<Name>Kind</Name>
|
||||
{isModelingInProgress ? (
|
||||
<InProgressDropdown />
|
||||
) : (
|
||||
<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" />
|
||||
Model with AI
|
||||
</VSCodeButton>
|
||||
)}
|
||||
{viewState.showLlmButton && canStopAutoModeling && (
|
||||
<VSCodeButton appearance="icon" onClick={handleStopModelWithAI}>
|
||||
<Codicon name="debug-stop" label="Stop model with AI" />
|
||||
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,39 +257,10 @@ 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,
|
||||
);
|
||||
|
||||
{shownModeledMethods.map((modeledMethod, index) => {
|
||||
return (
|
||||
<DataGridRow key={index} focused={focusedIndex === index}>
|
||||
<DataGridCell>
|
||||
|
@ -310,7 +269,6 @@ const ModelableMethodRow = forwardRef<HTMLElement | undefined, MethodRowProps>(
|
|||
modelConfig={viewState.modelConfig}
|
||||
method={method}
|
||||
modeledMethod={modeledMethod}
|
||||
modelPending={modelPending}
|
||||
onChange={modeledMethodChangedHandlers[index]}
|
||||
/>
|
||||
</DataGridCell>
|
||||
|
@ -320,7 +278,6 @@ const ModelableMethodRow = forwardRef<HTMLElement | undefined, MethodRowProps>(
|
|||
language={viewState.language}
|
||||
method={method}
|
||||
modeledMethod={modeledMethod}
|
||||
modelPending={modelPending}
|
||||
onChange={modeledMethodChangedHandlers[index]}
|
||||
/>
|
||||
) : (
|
||||
|
@ -338,7 +295,6 @@ const ModelableMethodRow = forwardRef<HTMLElement | undefined, MethodRowProps>(
|
|||
language={viewState.language}
|
||||
method={method}
|
||||
modeledMethod={modeledMethod}
|
||||
modelPending={modelPending}
|
||||
onChange={modeledMethodChangedHandlers[index]}
|
||||
/>
|
||||
) : (
|
||||
|
@ -353,7 +309,6 @@ const ModelableMethodRow = forwardRef<HTMLElement | undefined, MethodRowProps>(
|
|||
<ModelKindDropdown
|
||||
language={viewState.language}
|
||||
modeledMethod={modeledMethod}
|
||||
modelPending={modelPending}
|
||||
onChange={modeledMethodChangedHandlers[index]}
|
||||
/>
|
||||
</DataGridCell>
|
||||
|
@ -401,8 +356,6 @@ const ModelableMethodRow = forwardRef<HTMLElement | undefined, MethodRowProps>(
|
|||
/>
|
||||
</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,
|
||||
expect(sortMethods(methods, modeledMethodsMap, modifiedSignatures)).toEqual(
|
||||
[
|
||||
unmodeledMethodWithEarlierSignature,
|
||||
unsavedManualModel,
|
||||
unsavedModel,
|
||||
unmodeledMethodWithLaterSignature,
|
||||
savedAutoModelPrediction,
|
||||
savedManualModel,
|
||||
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,
|
||||
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());
|
||||
|
|
Загрузка…
Ссылка в новой задаче