Path: blob/main/extensions/copilot/test/simulation/workbench/stores/amlSimulations.ts
13399 views
/*---------------------------------------------------------------------------------------------1* Copyright (c) Microsoft Corporation. All rights reserved.2* Licensed under the MIT License. See License.txt in the project root for license information.3*--------------------------------------------------------------------------------------------*/45import * as fs from 'fs';6import * as mobx from 'mobx';7import * as path from 'path';8import { RunOnceScheduler } from '../../../../src/util/vs/base/common/async';9import { Disposable, toDisposable } from '../../../../src/util/vs/base/common/lifecycle';10import { AML_OUTPUT_PATH, STDOUT_FILENAME } from '../../shared/sharedTypes';11import { REPO_ROOT } from '../utils/utils';12import { SimulationStorage, SimulationStorageValue } from './simulationStorage';1314const AML_OUTPUT_FOLDER_PATH = path.join(REPO_ROOT, AML_OUTPUT_PATH);1516export enum AMLRunKind {17Fix = 'fix',18Doc = 'doc',19WorkspaceE2E = 'workspace-e2e',20TestGen = 'test_gen',21MethodGen = 'method_gen',22EditFix = 'edit_fix',23Unknown = 'unknown',24Swebench = 'swebench',25FixTestFailure = 'fix_test_failure',26HumanEval = 'human_eval',27SafetyPrompt = 'safety_prompt',28}2930function pathIfExists(filePath: string): string | undefined {31return fs.existsSync(filePath) ? filePath : undefined;32}3334export class AMLRun {3536public readonly scoreCardCsvPath: string | undefined;37public readonly scoreCardByLanguageJsonPath: string | undefined;38public readonly scoredPredictionsJSONL: string | undefined;39public readonly simulationInputPath: string;4041constructor(42public readonly kind: AMLRunKind,43public readonly name: string,44public readonly runPath: string,45public readonly stat: fs.Stats,46public readonly stdoutPath: string,47) {48this.scoreCardCsvPath = kind !== 'unknown' ? pathIfExists(path.join(runPath, `eval/${kind}_scorecard.csv`)) : undefined;49this.scoreCardByLanguageJsonPath = pathIfExists(path.join(runPath, `eval/metric_scorecard_by_language.json`));5051this.scoredPredictionsJSONL = kind !== 'unknown' ? pathIfExists(path.join(runPath, `eval/${kind}_scored_predictions.jsonl`)) : undefined;52this.simulationInputPath = path.join(runPath, 'simulate', 'simulator_input');53}54}5556/**57* Detects possible AML runs58*/59export class AMLProvider extends Disposable {6061private readonly _updateSoon = this._register(new RunOnceScheduler(() => this._update(), 50));6263@mobx.observable64public runs: AMLRun[] = [];6566@mobx.observable67public selectedName: SimulationStorageValue<string>;6869@mobx.observable70public compareAgainstRunName: SimulationStorageValue<string>;7172@mobx.computed73public get selected(): AMLRun | undefined {74return this.runs.find(r => r.name === this.selectedName.value);75}7677@mobx.computed78public get compareAgainstRun(): AMLRun | undefined {79return this.runs.find(r => r.name === this.compareAgainstRunName.value);80}8182constructor(storage: SimulationStorage) {83super();8485this.selectedName = new SimulationStorageValue(storage, 'selectedAML', '');86this.compareAgainstRunName = new SimulationStorageValue(storage, 'compareAgainstAML', '');8788mobx.makeObservable(this);8990const listener = () => {91if (!this._updateSoon.isScheduled()) {92this._updateSoon.schedule();93}94};9596fs.promises.mkdir(AML_OUTPUT_FOLDER_PATH, { recursive: true }).then(() => {97fs.watch(AML_OUTPUT_FOLDER_PATH, { recursive: false }, listener);98this._register(toDisposable(() => fs.unwatchFile(AML_OUTPUT_FOLDER_PATH, listener)));99this._update();100});101}102103private async _update(): Promise<void> {104const amlOutputFolders = await fs.promises.readdir(AML_OUTPUT_FOLDER_PATH);105const rawEntries = await Promise.all(106amlOutputFolders.map(async (entry) => {107const entryPath = path.join(AML_OUTPUT_FOLDER_PATH, entry);108const stat = await fs.promises.stat(entryPath);109const stdoutPath = path.join(entryPath, 'simulate', 'simulator_output_dir', 'simulator_output', STDOUT_FILENAME);110try {111const stdoutStat = await fs.promises.stat(stdoutPath);112if (!stdoutStat.isFile()) {113return undefined;114}115} catch (err) {116// stdout does not exist117return undefined;118}119const kind = await AMLProvider.determineKind(entryPath);120return new AMLRun(kind, entry, entryPath, stat, stdoutPath);121})122);123124let entries = rawEntries.filter((entry): entry is AMLRun => !!entry);125entries = entries.filter(({ stat }) => stat.isDirectory());126entries.sort((a, b) => b.stat.ctimeMs - a.stat.ctimeMs);127128mobx.runInAction(() => {129this.runs = entries;130131// if no run is selected, pre-select first output folder132if (this.runs.length > 0 && !this.selected) {133this.selectedName.value = this.runs[0].name;134}135});136}137138/**139* Determines the kind (fix/doc/workspace-e2e/etc) of an AML run based on job_parameters.json.140* @param amlRunPath - The path to the AML run directory.141* @returns The kind of AML run.142*/143private static async determineKind(amlRunPath: string): Promise<AMLRunKind> {144145const defaultKind = AMLRunKind.Unknown;146const jobParametersPath = path.join(amlRunPath, 'simulate', 'simulator_output_dir', 'simulator_output', 'job_parameters.json');147try {148const file = await fs.promises.readFile(jobParametersPath);149const jobParameters = JSON.parse(file.toString());150if (Object.values(AMLRunKind).includes(jobParameters.dataset)) {151return jobParameters.dataset as AMLRunKind;152}153154console.error(`Unknown AML run kind: ${jobParameters.dataset}; considering it as 'unknown'`);155} catch (err) {156console.error(`Error determining AML run kind: Unable to read ${jobParametersPath}`);157}158return defaultKind;159}160}161162163