@bjoernrochel/sevro 0.1.0-rc.2 → 0.1.0-rc.21
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CONTRIBUTING.md +170 -0
- package/LICENSE +63 -136
- package/README.md +83 -66
- package/docs/README.md +44 -0
- package/docs/acknowledgements.md +14 -0
- package/docs/architecture.md +146 -0
- package/docs/assets/README.md +27 -0
- package/docs/assets/sevro-logo.png +0 -0
- package/docs/assets/sevro-symbol.svg +1 -0
- package/docs/assets/sevro-wordmark.svg +1 -0
- package/docs/builtin-graders-v1.md +41 -13
- package/docs/codex-host.md +184 -52
- package/docs/contracts.md +19 -0
- package/docs/creating-cases.md +139 -0
- package/docs/development-cli.md +190 -30
- package/docs/documentation-quality.md +61 -0
- package/docs/evaluation-workflow.md +110 -0
- package/docs/evidence/code-mode-controls-71.md +64 -0
- package/docs/evidence/code-mode-programs-85.md +64 -0
- package/docs/evidence/codex-state-73/README.md +204 -0
- package/docs/evidence/codex-state-73/darrow-migration.patch +182 -0
- package/docs/evidence/codex-state-73/results.json +661 -0
- package/docs/evidence/local-http-74.md +104 -0
- package/docs/evidence/runtime-startup-30/README.md +185 -0
- package/docs/evidence/runtime-startup-30/after.json +319 -0
- package/docs/evidence/runtime-startup-30/baseline-timeout.jsonl +2 -0
- package/docs/evidence/runtime-startup-30/before.json +403 -0
- package/docs/evidence/runtime-startup-30/consumer-smoke.json +63 -0
- package/docs/evidence/runtime-startup-30/full-policy-diagnostic.jsonl +3 -0
- package/docs/evidence/runtime-startup-30/minimal-policy-diagnostic.jsonl +3 -0
- package/docs/evidence/runtime-startup-30/plugin-template-assessment.json +20 -0
- package/docs/evidence/runtime-startup-30/seedless-timeout.jsonl +2 -0
- package/docs/evidence/skill-reads-70/results.json +823 -0
- package/docs/evidence.md +21 -0
- package/docs/extension-protocol-v1.md +50 -16
- package/docs/fixture-cleanup-validation.md +3 -0
- package/docs/getting-started.md +102 -0
- package/docs/guide-evaluation.md +89 -0
- package/docs/guide-verification.json +239 -0
- package/docs/identity-v1.md +35 -1
- package/docs/installing.md +88 -0
- package/docs/licenses/BUSL-1.1-0.1.0-rc.2.txt +159 -0
- package/docs/licensing.md +42 -0
- package/docs/native-controls.md +76 -5
- package/docs/native-hosts.md +228 -0
- package/docs/reading-results.md +141 -0
- package/docs/recipes.md +489 -0
- package/docs/releases.md +81 -40
- package/docs/report-v1.md +29 -1
- package/docs/results-v1.md +180 -0
- package/docs/run-settings-v1.md +147 -0
- package/docs/running-evaluations.md +31 -0
- package/docs/runtime-v1.md +614 -0
- package/docs/specs/repository-guide.md +58 -0
- package/docs/troubleshooting.md +30 -0
- package/docs/typescript-quality.md +234 -0
- package/docs/usability-study.md +114 -0
- package/examples/basic/host.ts +2 -2
- package/examples/recipes/candidate.ts +26 -0
- package/examples/recipes/cases/coding-change.json +21 -0
- package/examples/recipes/cases/host-tools.json +21 -0
- package/examples/recipes/cases/mise.json +21 -0
- package/examples/recipes/cases/node.json +21 -0
- package/examples/recipes/cases/python-uv.json +21 -0
- package/examples/recipes/cases/semantic.json +17 -0
- package/examples/recipes/coding-change/check.ts +23 -0
- package/examples/recipes/extension-artifacts.ts +65 -0
- package/examples/recipes/extension-methods.ts +174 -0
- package/examples/recipes/extension.ts +37 -0
- package/examples/recipes/repository-skill/.agents/skills/startup-guide/SKILL.md +7 -0
- package/examples/recipes/repository-skill/.claude/skills/startup-guide/SKILL.md +7 -0
- package/examples/recipes/repository-skill/README.md +3 -0
- package/examples/recipes/run-inputs.ts +188 -0
- package/examples/recipes/run-options.ts +131 -0
- package/examples/recipes/run.ts +63 -0
- package/examples/recipes/runtime/empty.json +1 -0
- package/examples/recipes/runtime/goals.json +1 -0
- package/examples/recipes/runtime/mise.json +6 -0
- package/examples/recipes/runtime/path.json +1 -0
- package/examples/recipes/runtime/plugins.json +4 -0
- package/examples/recipes/runtime/python-uv.json +10 -0
- package/examples/recipes/semantic-judge.ts +29 -0
- package/examples/templates/coding/adapter.ts +17 -0
- package/examples/templates/coding/case.json +15 -0
- package/examples/templates/repository-skill/.agents/skills/startup-guide/SKILL.md +6 -0
- package/examples/templates/repository-skill/extension-data.ts +64 -0
- package/examples/templates/repository-skill/extension.ts +31 -0
- package/examples/templates/response/adapter.ts +12 -0
- package/examples/templates/response/case.json +13 -0
- package/package.json +39 -6
- package/schemas/report-v1.schema.json +9 -0
- package/schemas/run-evidence-v1.schema.json +2 -1
- package/schemas/runtime-v1.schema.json +193 -0
- package/src/advisory.ts +10 -5
- package/src/candidate-artifacts.ts +208 -0
- package/src/candidate-codex-state.ts +185 -0
- package/src/case-validation.ts +105 -0
- package/src/cli/cancellation.ts +20 -0
- package/src/cli/command.ts +81 -0
- package/src/cli/completion.ts +15 -0
- package/src/cli/demo.ts +59 -0
- package/src/cli/evaluation.ts +55 -0
- package/src/cli/extension.ts +79 -0
- package/src/cli/help.ts +222 -0
- package/src/cli/hosts.ts +59 -0
- package/src/cli/init-settings.ts +30 -0
- package/src/cli/init.ts +111 -0
- package/src/cli/invocation.ts +627 -0
- package/src/cli/loading.ts +151 -0
- package/src/cli/preparation.ts +163 -0
- package/src/cli/presentation.ts +91 -0
- package/src/cli/progress.ts +6 -0
- package/src/cli/run-manifest.ts +133 -0
- package/src/cli/run-options.ts +101 -0
- package/src/cli/run-overrides.ts +83 -0
- package/src/cli/settings.ts +160 -0
- package/src/cli/summary.ts +43 -0
- package/src/cli.ts +13 -843
- package/src/contract-types.ts +94 -0
- package/src/engine.ts +19 -2373
- package/src/evaluation/advisory.ts +150 -0
- package/src/evaluation/check-plan.ts +510 -0
- package/src/evaluation/collection.ts +88 -0
- package/src/evaluation/context.ts +10 -0
- package/src/evaluation/grading-host.ts +39 -0
- package/src/evaluation/grading.ts +258 -0
- package/src/evaluation/invocation-plan.ts +548 -0
- package/src/evaluation/plan.ts +736 -0
- package/src/evaluation/progress.ts +19 -0
- package/src/evaluation/resources.ts +241 -0
- package/src/evaluation/run.ts +206 -0
- package/src/{trial-scheduler.ts → evaluation/scheduler.ts} +3 -1
- package/src/evaluation/semantic.ts +312 -0
- package/src/evaluation/trial.ts +866 -0
- package/src/evaluation/types.ts +207 -0
- package/src/evidence/host-results.ts +92 -0
- package/src/evidence/retained-artifacts.ts +18 -0
- package/src/evidence/trial-writer.ts +203 -0
- package/src/evidence/usage.ts +17 -0
- package/src/extension-client.ts +228 -148
- package/src/extension-session.ts +326 -195
- package/src/fixtures/advisory.ts +338 -0
- package/src/fixtures/bin.ts +57 -0
- package/src/{fixture-cleanup.ts → fixtures/cleanup.ts} +13 -7
- package/src/fixtures/create.ts +187 -0
- package/src/fixtures/generated.ts +300 -0
- package/src/fixtures/git-hooks.ts +24 -0
- package/src/fixtures/preparation.ts +270 -0
- package/src/{repository-fixture.ts → fixtures/repository.ts} +207 -85
- package/src/fixtures/setup.ts +224 -0
- package/src/fixtures/tools.ts +88 -0
- package/src/fixtures/workspace-state.ts +212 -0
- package/src/generated/cli-result.cjs +2 -0
- package/src/generated/cli-result.d.cts +3 -0
- package/src/generated/extension.cjs +2 -0
- package/src/generated/extension.d.cts +3 -0
- package/src/generated/report.cjs +2 -0
- package/src/generated/report.d.cts +3 -0
- package/src/generated/run-evidence.cjs +2 -0
- package/src/generated/run-evidence.d.cts +3 -0
- package/src/generated/runtime.cjs +2 -0
- package/src/generated/runtime.d.cts +3 -0
- package/src/graders/artifact.ts +56 -23
- package/src/graders/git-head.ts +79 -75
- package/src/graders/output.ts +222 -140
- package/src/graders/semantic.ts +102 -43
- package/src/graders/shell.ts +379 -207
- package/src/host-diagnostic-redaction.ts +52 -0
- package/src/host-diagnostics.ts +319 -0
- package/src/hosts/claude-continuation.ts +63 -18
- package/src/hosts/claude-credential.ts +43 -62
- package/src/hosts/claude-events.ts +86 -51
- package/src/hosts/claude-keychain.ts +59 -0
- package/src/hosts/claude-native-goal.ts +57 -33
- package/src/hosts/claude-process.ts +111 -0
- package/src/hosts/claude-repository-invocation.ts +208 -117
- package/src/hosts/claude-settings.ts +240 -21
- package/src/hosts/claude-skill-activations.ts +166 -0
- package/src/hosts/claude-state.ts +403 -0
- package/src/hosts/claude-tool-calls.ts +171 -106
- package/src/hosts/claude.ts +561 -451
- package/src/hosts/codex-app-server.ts +326 -178
- package/src/hosts/codex-configuration.ts +44 -18
- package/src/hosts/codex-events.ts +97 -60
- package/src/hosts/codex-exec-controls.ts +516 -0
- package/src/hosts/codex-invocation.ts +70 -0
- package/src/hosts/codex-marketplace.ts +283 -0
- package/src/hosts/codex-native-calls.ts +546 -500
- package/src/hosts/codex-process.ts +202 -0
- package/src/hosts/codex-profile.ts +257 -28
- package/src/hosts/codex-session-files.ts +106 -0
- package/src/hosts/codex-state.ts +492 -0
- package/src/hosts/codex.ts +783 -832
- package/src/hosts/isolation-common.ts +94 -0
- package/src/hosts/isolation-roots.ts +54 -27
- package/src/hosts/isolation.ts +10 -0
- package/src/hosts/linux-sandbox.ts +159 -0
- package/src/hosts/mac-sandbox.ts +187 -61
- package/src/hosts/native-controls.ts +152 -62
- package/src/hosts/process-lifecycle.ts +37 -0
- package/src/hosts/protected-worktrees.ts +51 -19
- package/src/hosts/skill-hook-catalog.ts +131 -0
- package/src/hosts/skill-hook-handler.ts +374 -0
- package/src/hosts/skill-hooks.ts +580 -0
- package/src/hosts/workspace-fingerprint.ts +55 -35
- package/src/identity.ts +102 -48
- package/src/instrumentation.ts +109 -48
- package/src/native-transcript-state.ts +131 -0
- package/src/native-transcript-view.ts +90 -0
- package/src/native-transcripts.ts +286 -0
- package/src/process-lifecycle.ts +150 -0
- package/src/provenance.ts +161 -81
- package/src/prune.ts +215 -0
- package/src/report.ts +172 -140
- package/src/resolved-case.ts +33 -0
- package/src/results-lock.ts +29 -0
- package/src/results.ts +133 -86
- package/src/run-owner.ts +154 -63
- package/src/runtime/config.ts +456 -0
- package/src/runtime/discovery-apple.ts +90 -0
- package/src/runtime/discovery-providers.ts +63 -0
- package/src/runtime/discovery.ts +70 -0
- package/src/runtime/hook-processes.ts +97 -0
- package/src/runtime/hooks.ts +476 -0
- package/src/runtime/paths.ts +313 -0
- package/src/runtime/query.ts +85 -0
- package/src/runtime/seeds.ts +134 -0
- package/src/runtime/shared-cache.ts +143 -0
- package/src/runtime/state.ts +143 -0
- package/src/schema-types.ts +198 -0
- package/src/schema.ts +15 -19
- package/src/transcript-retention.ts +146 -0
- package/src/value-guards.ts +20 -0
- package/src/advisory-fixture.ts +0 -282
- package/src/fixture-bin.ts +0 -87
- package/src/fixture-setup.ts +0 -163
- package/src/generated-fixture.ts +0 -220
- package/src/git-hooks.ts +0 -63
- package/src/hosts/claude-nested-skills.ts +0 -218
- package/src/hosts/codex-command-output.ts +0 -399
- package/src/hosts/codex-executor-command.ts +0 -195
- package/src/hosts/codex-skill-reads.ts +0 -391
- package/src/preparation.ts +0 -211
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { EvaluationOptions, EvaluationProgress } from "./types";
|
|
2
|
+
|
|
3
|
+
/** Observation is best-effort and cannot change assessment or persistence. */
|
|
4
|
+
export function evaluationProgress(
|
|
5
|
+
options: EvaluationOptions,
|
|
6
|
+
stage: EvaluationProgress["stage"],
|
|
7
|
+
status: EvaluationProgress["status"],
|
|
8
|
+
trial?: number,
|
|
9
|
+
): void {
|
|
10
|
+
try {
|
|
11
|
+
options.onProgress?.({
|
|
12
|
+
stage,
|
|
13
|
+
status,
|
|
14
|
+
...(trial === undefined ? {} : { trial }),
|
|
15
|
+
});
|
|
16
|
+
} catch {
|
|
17
|
+
// An observer has no authority over the evaluation lifecycle.
|
|
18
|
+
}
|
|
19
|
+
}
|
|
@@ -0,0 +1,241 @@
|
|
|
1
|
+
import { randomUUID } from "node:crypto";
|
|
2
|
+
import { mkdir, realpath, rm, writeFile } from "node:fs/promises";
|
|
3
|
+
import { dirname, join, resolve } from "node:path";
|
|
4
|
+
import { pathToFileURL } from "node:url";
|
|
5
|
+
import {
|
|
6
|
+
allocateWorkspace,
|
|
7
|
+
retainWorkspace,
|
|
8
|
+
removeWorkspace,
|
|
9
|
+
} from "../fixtures/workspace-state";
|
|
10
|
+
import { createFixture } from "../fixtures/create";
|
|
11
|
+
import { fixtureBinDirectory } from "../fixtures/bin";
|
|
12
|
+
import { fixtureParts } from "../fixtures/preparation";
|
|
13
|
+
import { startRunOwner, type RunOwner } from "../run-owner";
|
|
14
|
+
import { EvaluationConfigurationError, type EvaluationOptions } from "./types";
|
|
15
|
+
import type { PreparedFixture, PreparedInvocation } from "./plan";
|
|
16
|
+
import type { ArtifactReference as PreparationArtifactReference } from "../contract-types";
|
|
17
|
+
export type { ArtifactReference as PreparationArtifactReference } from "../contract-types";
|
|
18
|
+
|
|
19
|
+
/** Reservations outlive completed contents until all admitted trials drain. */
|
|
20
|
+
export class RunWorkspaceReservations {
|
|
21
|
+
private readonly candidates: string[] = [];
|
|
22
|
+
private readonly semantics: string[] = [];
|
|
23
|
+
private readonly retained = new Set<string>();
|
|
24
|
+
|
|
25
|
+
async reserve(input: {
|
|
26
|
+
count: number;
|
|
27
|
+
semantic: boolean;
|
|
28
|
+
signal?: AbortSignal;
|
|
29
|
+
}): Promise<void> {
|
|
30
|
+
for (
|
|
31
|
+
let trial = 1;
|
|
32
|
+
trial <= input.count && !input.signal?.aborted;
|
|
33
|
+
trial++
|
|
34
|
+
) {
|
|
35
|
+
this.candidates.push(await allocateWorkspace());
|
|
36
|
+
if (input.semantic) this.semantics.push(await allocateWorkspace());
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
candidate(trial: number): string {
|
|
41
|
+
const reservation = this.candidates[trial - 1];
|
|
42
|
+
if (reservation === undefined)
|
|
43
|
+
throw new Error(`trial ${trial} workspace was not reserved`);
|
|
44
|
+
return reservation;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
semantic(trial: number): string | undefined {
|
|
48
|
+
return this.semantics[trial - 1];
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
retain(workspace: string): void {
|
|
52
|
+
this.retained.add(workspace);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
completed(reservation: string): void {
|
|
56
|
+
this.retained.delete(reservation);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
async cleanup(): Promise<void> {
|
|
60
|
+
for (const workspace of this.retained) await retainWorkspace(workspace);
|
|
61
|
+
await Promise.all(
|
|
62
|
+
[...this.candidates, ...this.semantics]
|
|
63
|
+
.filter((workspace) => !this.retained.has(workspace))
|
|
64
|
+
.map(async (workspace) => {
|
|
65
|
+
try {
|
|
66
|
+
await removeWorkspace(workspace);
|
|
67
|
+
} catch {
|
|
68
|
+
console.warn(`fixture cleanup failed; retained at ${workspace}`);
|
|
69
|
+
}
|
|
70
|
+
}),
|
|
71
|
+
);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
export interface RunResources {
|
|
76
|
+
readonly runId: string;
|
|
77
|
+
readonly runDir: string;
|
|
78
|
+
readonly runStateRoot: string;
|
|
79
|
+
readonly stateDir: string;
|
|
80
|
+
readonly evidencePath: string;
|
|
81
|
+
readonly owner: RunOwner;
|
|
82
|
+
readonly workspaces: RunWorkspaceReservations;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
export async function allocateRunResources(
|
|
86
|
+
options: Pick<EvaluationOptions, "resultsRoot" | "runStateRoot">,
|
|
87
|
+
evaluationDigest: string,
|
|
88
|
+
): Promise<RunResources> {
|
|
89
|
+
const runId = randomUUID();
|
|
90
|
+
await mkdir(options.resultsRoot, { recursive: true, mode: 0o700 });
|
|
91
|
+
const runDir = resolve(await realpath(options.resultsRoot), runId);
|
|
92
|
+
await mkdir(runDir, { mode: 0o700 });
|
|
93
|
+
const runStateRoot = options.runStateRoot ?? options.resultsRoot;
|
|
94
|
+
await mkdir(runStateRoot, { recursive: true, mode: 0o700 });
|
|
95
|
+
const stateRoot = await realpath(runStateRoot);
|
|
96
|
+
const stateDir = join(stateRoot, runId);
|
|
97
|
+
if (stateDir !== runDir) await mkdir(stateDir, { mode: 0o700 });
|
|
98
|
+
const activePath = join(stateRoot, "active", `${runId}.json`);
|
|
99
|
+
const checkpointPath = join(stateDir, "checkpoint.json");
|
|
100
|
+
const evidencePath = join(runDir, "run.json");
|
|
101
|
+
let owner: RunOwner;
|
|
102
|
+
try {
|
|
103
|
+
owner = startRunOwner({
|
|
104
|
+
stateRoot,
|
|
105
|
+
evaluationDigest,
|
|
106
|
+
attemptId: runId,
|
|
107
|
+
activeRunPath: activePath,
|
|
108
|
+
checkpointPath,
|
|
109
|
+
evidenceDirectory: stateDir,
|
|
110
|
+
artifactPath: evidencePath,
|
|
111
|
+
});
|
|
112
|
+
} catch (error) {
|
|
113
|
+
await rm(runDir, { recursive: true, force: true });
|
|
114
|
+
if (stateDir !== runDir)
|
|
115
|
+
await rm(stateDir, { recursive: true, force: true });
|
|
116
|
+
throw error;
|
|
117
|
+
}
|
|
118
|
+
return {
|
|
119
|
+
runId,
|
|
120
|
+
runDir,
|
|
121
|
+
runStateRoot,
|
|
122
|
+
stateDir,
|
|
123
|
+
evidencePath,
|
|
124
|
+
owner,
|
|
125
|
+
workspaces: new RunWorkspaceReservations(),
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
export async function retainPreparationArtifacts(
|
|
130
|
+
artifacts: PreparedFixture["inlineArtifacts"],
|
|
131
|
+
runDir: string,
|
|
132
|
+
): Promise<PreparationArtifactReference[]> {
|
|
133
|
+
const artifactRefs: PreparationArtifactReference[] = [];
|
|
134
|
+
for (const artifact of artifacts) {
|
|
135
|
+
const retainedPath = join(
|
|
136
|
+
runDir,
|
|
137
|
+
"prepared",
|
|
138
|
+
...fixtureParts(artifact.relativePath),
|
|
139
|
+
);
|
|
140
|
+
await mkdir(dirname(retainedPath), { recursive: true, mode: 0o700 });
|
|
141
|
+
await writeFile(retainedPath, artifact.bytes, {
|
|
142
|
+
flag: "wx",
|
|
143
|
+
mode: artifact.executable ? 0o700 : 0o600,
|
|
144
|
+
});
|
|
145
|
+
artifactRefs.push({
|
|
146
|
+
id: artifact.id,
|
|
147
|
+
path: pathToFileURL(retainedPath).href,
|
|
148
|
+
sha256: artifact.sha256,
|
|
149
|
+
...(artifact.gitExclude ? { gitExclude: true } : {}),
|
|
150
|
+
...(artifact.executable ? { executable: true } : {}),
|
|
151
|
+
});
|
|
152
|
+
}
|
|
153
|
+
return artifactRefs;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
function renderTrialPrompt(
|
|
157
|
+
prompt: string,
|
|
158
|
+
workspace: string,
|
|
159
|
+
invocation: PreparedInvocation,
|
|
160
|
+
): string {
|
|
161
|
+
return prompt
|
|
162
|
+
.replaceAll("{{sevro.workspace}}", workspace)
|
|
163
|
+
.replaceAll(
|
|
164
|
+
invocation.invocationPlaceholder,
|
|
165
|
+
invocation.invocationToken ?? invocation.invocationPlaceholder,
|
|
166
|
+
)
|
|
167
|
+
.replaceAll(
|
|
168
|
+
invocation.legacyCodexPlaceholder,
|
|
169
|
+
invocation.invocationToken ?? invocation.legacyCodexPlaceholder,
|
|
170
|
+
);
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
type TrialPreparationOptions = Pick<
|
|
174
|
+
EvaluationOptions,
|
|
175
|
+
"case" | "preparationSources" | "signal"
|
|
176
|
+
>;
|
|
177
|
+
|
|
178
|
+
export async function prepareTrialWorkspace(
|
|
179
|
+
options: TrialPreparationOptions,
|
|
180
|
+
fixture: PreparedFixture,
|
|
181
|
+
invocation: PreparedInvocation,
|
|
182
|
+
workspaces: RunWorkspaceReservations,
|
|
183
|
+
trial: number,
|
|
184
|
+
candidateRuntimeRoot?: string,
|
|
185
|
+
) {
|
|
186
|
+
const reservation = workspaces.candidate(trial);
|
|
187
|
+
workspaces.retain(reservation);
|
|
188
|
+
const workspace = await createFixture(
|
|
189
|
+
options.case.fixture,
|
|
190
|
+
fixture.inlineArtifacts,
|
|
191
|
+
options.preparationSources,
|
|
192
|
+
fixture.repository,
|
|
193
|
+
fixture.repositoryFixture,
|
|
194
|
+
fixture.generated,
|
|
195
|
+
fixture.fixtureSetup,
|
|
196
|
+
fixture.projectRoot,
|
|
197
|
+
options.signal,
|
|
198
|
+
reservation,
|
|
199
|
+
candidateRuntimeRoot,
|
|
200
|
+
).catch((error: unknown) => {
|
|
201
|
+
if (
|
|
202
|
+
!options.signal?.aborted ||
|
|
203
|
+
error instanceof EvaluationConfigurationError
|
|
204
|
+
)
|
|
205
|
+
throw error;
|
|
206
|
+
return null;
|
|
207
|
+
});
|
|
208
|
+
const details = await trialWorkspaceDetails(
|
|
209
|
+
options.case,
|
|
210
|
+
invocation,
|
|
211
|
+
reservation,
|
|
212
|
+
workspace,
|
|
213
|
+
);
|
|
214
|
+
return { ...details, candidateRuntimeRoot };
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
async function trialWorkspaceDetails(
|
|
218
|
+
caseData: EvaluationOptions["case"],
|
|
219
|
+
invocation: PreparedInvocation,
|
|
220
|
+
reservation: string,
|
|
221
|
+
preparedWorkspace: string | null,
|
|
222
|
+
) {
|
|
223
|
+
const workspace = preparedWorkspace ?? reservation;
|
|
224
|
+
const fixtureBinDir =
|
|
225
|
+
preparedWorkspace === null
|
|
226
|
+
? undefined
|
|
227
|
+
: ((await fixtureBinDirectory(workspace)) ?? undefined);
|
|
228
|
+
const trialPrompt = renderTrialPrompt(caseData.prompt, workspace, invocation);
|
|
229
|
+
const trialFollowUpPrompt =
|
|
230
|
+
caseData.followUpPrompt === undefined
|
|
231
|
+
? undefined
|
|
232
|
+
: renderTrialPrompt(caseData.followUpPrompt, workspace, invocation);
|
|
233
|
+
return {
|
|
234
|
+
reservation,
|
|
235
|
+
workspace,
|
|
236
|
+
preparationCancelled: preparedWorkspace === null,
|
|
237
|
+
fixtureBinDir,
|
|
238
|
+
trialPrompt,
|
|
239
|
+
trialFollowUpPrompt,
|
|
240
|
+
};
|
|
241
|
+
}
|
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
import { prepareEvaluation, type PreparedEvaluation } from "./plan";
|
|
2
|
+
import { type CliResult, type EvaluationOptions } from "./types";
|
|
3
|
+
import { canonicalJson, hashJson } from "../identity";
|
|
4
|
+
import { exitCodeFor, summarizeCases } from "../results";
|
|
5
|
+
import { runtimePolicySnapshot } from "../runtime/config";
|
|
6
|
+
import { cleanupExpiredWorkspaces } from "../fixtures/workspace-state";
|
|
7
|
+
import { assertCliResult, assertRunEvidence } from "../schema";
|
|
8
|
+
import { atomicWriteJson } from "../storage";
|
|
9
|
+
import {
|
|
10
|
+
allocateRunResources,
|
|
11
|
+
retainPreparationArtifacts,
|
|
12
|
+
type RunResources,
|
|
13
|
+
} from "./resources";
|
|
14
|
+
import type { EvaluationContext } from "./context";
|
|
15
|
+
import { ResultCollector, type CollectedResults } from "./collection";
|
|
16
|
+
import { executeEvaluationTrials } from "./trial";
|
|
17
|
+
import { evaluationProgress } from "./progress";
|
|
18
|
+
|
|
19
|
+
function evaluationSignal(
|
|
20
|
+
options: EvaluationOptions,
|
|
21
|
+
): "SIGINT" | "SIGTERM" | undefined {
|
|
22
|
+
const reason: unknown = options.signal?.aborted
|
|
23
|
+
? options.signal.reason
|
|
24
|
+
: null;
|
|
25
|
+
return reason === "SIGINT" || reason === "SIGTERM" ? reason : undefined;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
function finalCliResult(
|
|
29
|
+
options: EvaluationOptions,
|
|
30
|
+
resources: RunResources,
|
|
31
|
+
collected: CollectedResults,
|
|
32
|
+
): CliResult {
|
|
33
|
+
const caseResult = collected.caseSummary;
|
|
34
|
+
const assessment = summarizeCases([caseResult]);
|
|
35
|
+
const diagnostic = collected.diagnostic;
|
|
36
|
+
return {
|
|
37
|
+
format: "sevro.cli-result.v1",
|
|
38
|
+
runId: resources.runId,
|
|
39
|
+
...assessment,
|
|
40
|
+
exitCode: exitCodeFor(assessment, {
|
|
41
|
+
dryRun: options.dry,
|
|
42
|
+
signal: evaluationSignal(options),
|
|
43
|
+
}),
|
|
44
|
+
evidencePath: resources.evidencePath,
|
|
45
|
+
cases: [caseResult],
|
|
46
|
+
...(diagnostic ? { diagnostic } : {}),
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
function finalConditionEvidence(
|
|
51
|
+
options: Pick<EvaluationOptions, "condition" | "trialCount">,
|
|
52
|
+
requestedInstrumentation: PreparedEvaluation["requestedInstrumentation"],
|
|
53
|
+
trials: CollectedResults["trials"],
|
|
54
|
+
) {
|
|
55
|
+
const actualConditions = [
|
|
56
|
+
...new Set(trials.map((entry) => entry.condition.actual)),
|
|
57
|
+
];
|
|
58
|
+
const commonAppliedInstrumentation =
|
|
59
|
+
trials.length === options.trialCount &&
|
|
60
|
+
trials.every(
|
|
61
|
+
(entry) =>
|
|
62
|
+
canonicalJson(entry.condition.appliedInstrumentation) ===
|
|
63
|
+
canonicalJson(requestedInstrumentation),
|
|
64
|
+
)
|
|
65
|
+
? requestedInstrumentation
|
|
66
|
+
: [];
|
|
67
|
+
return {
|
|
68
|
+
requested: options.condition,
|
|
69
|
+
actual: actualConditions.length === 1 ? actualConditions[0] : "unknown",
|
|
70
|
+
requestedInstrumentation,
|
|
71
|
+
appliedInstrumentation: commonAppliedInstrumentation,
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
function finalExtensionEvidence(
|
|
76
|
+
options: EvaluationOptions,
|
|
77
|
+
replacedBuiltinGraders: string[],
|
|
78
|
+
) {
|
|
79
|
+
const extension = options.extension;
|
|
80
|
+
if (!extension) return null;
|
|
81
|
+
const identity = extension.session.identity;
|
|
82
|
+
return {
|
|
83
|
+
id: identity.id,
|
|
84
|
+
version: identity.version,
|
|
85
|
+
sourceDigest: identity.sourceDigest,
|
|
86
|
+
configurationDigest: identity.configurationDigest,
|
|
87
|
+
protocol: identity.protocol,
|
|
88
|
+
capabilities: identity.capabilities,
|
|
89
|
+
replacements: {
|
|
90
|
+
graders: replacedBuiltinGraders,
|
|
91
|
+
taskVerdictPolicy: identity.selectedTaskVerdictPolicy,
|
|
92
|
+
},
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
function finalRunEvidence(
|
|
97
|
+
options: EvaluationOptions,
|
|
98
|
+
prepared: PreparedEvaluation,
|
|
99
|
+
resources: RunResources,
|
|
100
|
+
collected: CollectedResults,
|
|
101
|
+
result: CliResult,
|
|
102
|
+
) {
|
|
103
|
+
const condition = finalConditionEvidence(
|
|
104
|
+
options,
|
|
105
|
+
prepared.requestedInstrumentation,
|
|
106
|
+
collected.trials,
|
|
107
|
+
);
|
|
108
|
+
const diagnostic = collected.diagnostic;
|
|
109
|
+
return {
|
|
110
|
+
format: "sevro.run-evidence.v1",
|
|
111
|
+
runId: resources.runId,
|
|
112
|
+
evaluationIdentity: prepared.evaluationIdentity,
|
|
113
|
+
configuration: {
|
|
114
|
+
digest: hashJson(prepared.redactedConfig),
|
|
115
|
+
redacted: prepared.redactedConfig,
|
|
116
|
+
...(options.resolvedRunSettings
|
|
117
|
+
? { resolved: options.resolvedRunSettings }
|
|
118
|
+
: {}),
|
|
119
|
+
},
|
|
120
|
+
runner: prepared.runner,
|
|
121
|
+
project: prepared.project,
|
|
122
|
+
extension: finalExtensionEvidence(
|
|
123
|
+
options,
|
|
124
|
+
prepared.checks.replacedBuiltinGraders,
|
|
125
|
+
),
|
|
126
|
+
condition,
|
|
127
|
+
graders: {
|
|
128
|
+
active: prepared.activeGraders,
|
|
129
|
+
replacedDefaults: prepared.checks.replacedBuiltinGraders,
|
|
130
|
+
},
|
|
131
|
+
routes: prepared.routes,
|
|
132
|
+
result,
|
|
133
|
+
trials: collected.trials,
|
|
134
|
+
...(diagnostic ? { diagnostic } : {}),
|
|
135
|
+
};
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
async function finishEvaluationRun(
|
|
139
|
+
options: EvaluationOptions,
|
|
140
|
+
context: EvaluationContext,
|
|
141
|
+
) {
|
|
142
|
+
const collected = context.results.snapshot({
|
|
143
|
+
caseId: options.case.id,
|
|
144
|
+
passThreshold: options.passThreshold,
|
|
145
|
+
cancelled: Boolean(options.signal?.aborted),
|
|
146
|
+
});
|
|
147
|
+
const result = finalCliResult(options, context.resources, collected);
|
|
148
|
+
const evidence = finalRunEvidence(
|
|
149
|
+
options,
|
|
150
|
+
context.prepared,
|
|
151
|
+
context.resources,
|
|
152
|
+
collected,
|
|
153
|
+
result,
|
|
154
|
+
);
|
|
155
|
+
assertCliResult(result);
|
|
156
|
+
assertRunEvidence(evidence);
|
|
157
|
+
evaluationProgress(options, "evidence", "started");
|
|
158
|
+
await atomicWriteJson(context.resources.evidencePath, evidence);
|
|
159
|
+
context.results.checkpoint(
|
|
160
|
+
options.signal?.aborted ? "interrupted" : "complete",
|
|
161
|
+
);
|
|
162
|
+
evaluationProgress(options, "evidence", "completed");
|
|
163
|
+
return { result };
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
/** Execute resolved evaluator data through an injected host and retain every trial. */
|
|
167
|
+
export async function runEvaluation(
|
|
168
|
+
options: EvaluationOptions,
|
|
169
|
+
): Promise<{ result: CliResult }> {
|
|
170
|
+
options = {
|
|
171
|
+
...options,
|
|
172
|
+
runtimePolicy: runtimePolicySnapshot(options.runtimePolicy),
|
|
173
|
+
};
|
|
174
|
+
evaluationProgress(options, "preparation", "started");
|
|
175
|
+
await cleanupExpiredWorkspaces();
|
|
176
|
+
const prepared = await prepareEvaluation(options);
|
|
177
|
+
const resources = await allocateRunResources(
|
|
178
|
+
options,
|
|
179
|
+
prepared.evaluationIdentity.digest,
|
|
180
|
+
);
|
|
181
|
+
const results = new ResultCollector(resources.owner);
|
|
182
|
+
try {
|
|
183
|
+
const preparationArtifacts = await retainPreparationArtifacts(
|
|
184
|
+
prepared.fixture.inlineArtifacts,
|
|
185
|
+
resources.runDir,
|
|
186
|
+
);
|
|
187
|
+
await resources.workspaces.reserve({
|
|
188
|
+
count: options.trialCount,
|
|
189
|
+
semantic: prepared.checks.preparedSemantic.length > 0,
|
|
190
|
+
signal: options.signal,
|
|
191
|
+
});
|
|
192
|
+
const context: EvaluationContext = {
|
|
193
|
+
prepared,
|
|
194
|
+
resources,
|
|
195
|
+
results,
|
|
196
|
+
preparationArtifacts,
|
|
197
|
+
};
|
|
198
|
+
await executeEvaluationTrials(options, context);
|
|
199
|
+
return await finishEvaluationRun(options, context);
|
|
200
|
+
} catch (error) {
|
|
201
|
+
results.diagnoseFailure();
|
|
202
|
+
throw error;
|
|
203
|
+
} finally {
|
|
204
|
+
await resources.workspaces.cleanup();
|
|
205
|
+
}
|
|
206
|
+
}
|
|
@@ -9,8 +9,10 @@ export async function scheduleTrials(
|
|
|
9
9
|
stopped = true;
|
|
10
10
|
};
|
|
11
11
|
let failure: { error: unknown } | undefined;
|
|
12
|
+
const admitting = () =>
|
|
13
|
+
!stopped && !options.signal?.aborted && nextTrial <= options.count;
|
|
12
14
|
const worker = async () => {
|
|
13
|
-
while (
|
|
15
|
+
while (admitting()) {
|
|
14
16
|
const trial = nextTrial++;
|
|
15
17
|
try {
|
|
16
18
|
if (!(await run(trial, stopAdmission))) stopAdmission();
|