mirror of
https://github.com/windmill-labs/windmill.git
synced 2026-08-20 00:02:19 +00:00
74a2329d2e
* test: add global-mode path-selection eval cases with seeded user Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * feat(copilot): guide global-mode path selection with injected folder list Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(copilot): tailor global-mode folder guidance for workspace admins Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(copilot): type folders_read; isolate global-eval user from store Addresses PR review: - Add folders_read to the User/whoami openapi schema and UserExt; the global prompt builder and eval harness now read it typed instead of via inline casts (regen the client to pick it up). - prepareGlobalSystemMessage takes an explicit user; the eval harness passes it rather than mutating the process-global userStore, removing the concurrency race (path cases no longer need --verbose). - Rewrite the path-selection case comment as a current invariant. - Add buildFolderGuidance unit tests in core.test.ts. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
117 lines
3.7 KiB
TypeScript
117 lines
3.7 KiB
TypeScript
import { readFile, stat } from "node:fs/promises";
|
|
import { basename } from "node:path";
|
|
import { loadAppFixtureForEval } from "../adapters/frontend/core/app/appFixtureLoader";
|
|
import {
|
|
runGlobalEval,
|
|
type GlobalLiveEditorDraftFixture,
|
|
type GlobalUserFixture,
|
|
} from "../adapters/frontend/core/global/globalEvalRunner";
|
|
import type { BenchmarkWorkspaceRunnables } from "../adapters/frontend/mockBackend";
|
|
import type { FrontendEvalModelConfig } from "../core/models";
|
|
import type { BenchmarkArtifactFile, GlobalValidationSpec, ModeRunner } from "../core/types";
|
|
import { validateGlobalState, type GlobalDraftState } from "../core/validators";
|
|
import type { WindmillBackendSettings } from "../core/windmillBackendSettings";
|
|
import { getFrontendApiKey } from "./frontendCommon";
|
|
|
|
export interface GlobalInitialFixture {
|
|
workspace?: BenchmarkWorkspaceRunnables;
|
|
liveEditorDrafts?: GlobalLiveEditorDraftFixture[];
|
|
user?: GlobalUserFixture;
|
|
}
|
|
|
|
export function createGlobalModeRunner(
|
|
modelConfig: FrontendEvalModelConfig,
|
|
backendSettings: WindmillBackendSettings,
|
|
): ModeRunner<GlobalInitialFixture, GlobalDraftState, GlobalDraftState> {
|
|
return {
|
|
mode: "global",
|
|
concurrency: 3,
|
|
judgeThreshold: 80,
|
|
async loadInitial(path) {
|
|
return path ? await loadGlobalInitialFixture(path) : undefined;
|
|
},
|
|
async loadExpected(path) {
|
|
return path ? await loadGlobalExpectedFixture(path) : undefined;
|
|
},
|
|
async run(prompt, initial, context) {
|
|
const result = await runGlobalEval(
|
|
prompt,
|
|
getFrontendApiKey(modelConfig.provider),
|
|
{
|
|
workspaceFixtures: initial?.workspace,
|
|
liveEditorDrafts: initial?.liveEditorDrafts,
|
|
user: initial?.user,
|
|
maxIterations: context.evalCase?.runtime?.maxTurns,
|
|
provider: modelConfig.provider,
|
|
model: modelConfig.model,
|
|
backend: backendSettings,
|
|
runContext: context,
|
|
},
|
|
);
|
|
|
|
return {
|
|
success: result.success,
|
|
actual: result.state,
|
|
error: result.error,
|
|
assistantMessageCount: result.assistantMessageCount,
|
|
toolCallCount: result.toolCallCount,
|
|
toolsUsed: result.toolsUsed,
|
|
toolCallDetails: result.toolCallDetails,
|
|
skillsInvoked: [],
|
|
tokenUsage: result.tokenUsage,
|
|
finalContextTokens: result.finalContextTokens,
|
|
};
|
|
},
|
|
validate({ evalCase, actual, expected }) {
|
|
return validateGlobalState({
|
|
actual,
|
|
expected,
|
|
validate: evalCase.validate as GlobalValidationSpec | undefined,
|
|
});
|
|
},
|
|
buildArtifacts(actual): BenchmarkArtifactFile[] {
|
|
return [
|
|
{
|
|
path: "global-drafts.json",
|
|
content: JSON.stringify(actual, null, 2) + "\n",
|
|
},
|
|
];
|
|
},
|
|
};
|
|
}
|
|
|
|
async function loadGlobalInitialFixture(path: string): Promise<GlobalInitialFixture> {
|
|
if ((await stat(path)).isDirectory()) {
|
|
const { initialFrontend, initialBackend, initialDatatables } =
|
|
await loadAppFixtureForEval(path);
|
|
const name = basename(path);
|
|
return {
|
|
workspace: {
|
|
apps: [
|
|
{
|
|
path: `f/evals/global/${name}`,
|
|
summary: name,
|
|
value: {
|
|
files: initialFrontend,
|
|
runnables: initialBackend,
|
|
data: initialDatatables,
|
|
},
|
|
},
|
|
],
|
|
},
|
|
liveEditorDrafts: [],
|
|
};
|
|
}
|
|
|
|
const parsed = JSON.parse(await readFile(path, "utf8")) as GlobalInitialFixture;
|
|
return {
|
|
workspace: parsed.workspace ?? {},
|
|
liveEditorDrafts: parsed.liveEditorDrafts ?? [],
|
|
user: parsed.user,
|
|
};
|
|
}
|
|
|
|
async function loadGlobalExpectedFixture(path: string): Promise<GlobalDraftState> {
|
|
return JSON.parse(await readFile(path, "utf8")) as GlobalDraftState;
|
|
}
|