@bjoernrochel/sevro 0.1.0-rc.8 → 1.0.0
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 +22 -6
- package/README.md +5 -1
- package/docs/README.md +19 -15
- package/docs/architecture.md +138 -17
- package/docs/assets/README.md +5 -4
- package/docs/builtin-graders-v1.md +9 -2
- package/docs/codex-host.md +155 -57
- package/docs/contracts.md +2 -1
- package/docs/creating-cases.md +9 -2
- package/docs/development-cli.md +187 -19
- package/docs/documentation-quality.md +12 -2
- package/docs/evaluation-workflow.md +110 -0
- package/docs/extension-protocol-v1.md +26 -3
- package/docs/getting-started.md +23 -2
- package/docs/guide-evaluation.md +33 -1
- package/docs/identity-v1.md +25 -2
- package/docs/installing.md +11 -11
- package/docs/native-controls.md +76 -5
- package/docs/native-hosts.md +196 -7
- package/docs/reading-results.md +102 -0
- package/docs/recipes.md +489 -0
- package/docs/releases.md +31 -12
- package/docs/report-v1.md +29 -1
- package/docs/results-v1.md +122 -4
- package/docs/run-settings-v1.md +147 -0
- package/docs/runtime-v1.md +255 -22
- package/docs/troubleshooting.md +12 -12
- package/docs/typescript-quality.md +89 -26
- 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 +11 -5
- package/schemas/report-v1.schema.json +9 -0
- package/schemas/run-evidence-v1.schema.json +2 -1
- package/schemas/runtime-v1.schema.json +43 -7
- package/src/advisory.ts +2 -2
- package/src/candidate-artifacts.ts +42 -11
- package/src/candidate-codex-state.ts +185 -0
- package/src/case-validation.ts +73 -50
- package/src/cli/cancellation.ts +20 -0
- package/src/cli/command.ts +87 -0
- package/src/cli/completion.ts +15 -0
- package/src/cli/demo.ts +60 -0
- package/src/cli/evaluation.ts +55 -0
- package/src/cli/extension.ts +79 -0
- package/src/cli/help.ts +198 -0
- package/src/cli/hosts.ts +55 -0
- package/src/cli/init-settings.ts +30 -0
- package/src/cli/init.ts +111 -0
- package/src/{cli-invocation.ts → cli/invocation.ts} +214 -218
- package/src/cli/loading.ts +151 -0
- package/src/cli/preparation.ts +154 -0
- package/src/cli/presentation.ts +93 -0
- package/src/cli/progress.ts +6 -0
- package/src/cli/run-manifest.ts +128 -0
- package/src/cli/run-options.ts +403 -0
- package/src/cli/run-overrides.ts +69 -0
- package/src/cli/settings.ts +154 -0
- package/src/cli/summary.ts +43 -0
- package/src/cli.ts +13 -591
- package/src/contract-types.ts +94 -0
- package/src/engine.ts +9 -5
- package/src/evaluation/advisory.ts +150 -0
- package/src/{evaluation-check-plan.ts → evaluation/check-plan.ts} +103 -67
- package/src/evaluation/collection.ts +88 -0
- package/src/evaluation/context.ts +10 -0
- package/src/{evaluation-grading-host.ts → evaluation/grading-host.ts} +5 -5
- package/src/evaluation/grading.ts +235 -0
- package/src/{evaluation-invocation-plan.ts → evaluation/invocation-plan.ts} +147 -58
- package/src/{evaluation-plan.ts → evaluation/plan.ts} +208 -141
- package/src/evaluation/progress.ts +19 -0
- package/src/evaluation/resources.ts +241 -0
- package/src/evaluation/run.ts +206 -0
- package/src/{evaluation-semantic.ts → evaluation/semantic.ts} +77 -87
- package/src/evaluation/trial.ts +800 -0
- package/src/{evaluation-types.ts → evaluation/types.ts} +79 -29
- package/src/evidence/host-results.ts +85 -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 +34 -96
- package/src/extension-session.ts +24 -48
- package/src/{advisory-fixture.ts → fixtures/advisory.ts} +12 -72
- package/src/{fixture-bin.ts → fixtures/bin.ts} +1 -1
- package/src/{fixture-cleanup.ts → fixtures/cleanup.ts} +13 -7
- package/src/fixtures/create.ts +183 -0
- package/src/{generated-fixture.ts → fixtures/generated.ts} +10 -53
- package/src/{git-hooks.ts → fixtures/git-hooks.ts} +1 -1
- package/src/{preparation.ts → fixtures/preparation.ts} +6 -16
- package/src/{repository-fixture.ts → fixtures/repository.ts} +30 -64
- package/src/{fixture-setup.ts → fixtures/setup.ts} +33 -51
- package/src/{fixture-tools.ts → fixtures/tools.ts} +1 -1
- package/src/{workspace-state.ts → fixtures/workspace-state.ts} +5 -5
- package/src/generated/cli-result.d.cts +2 -1
- package/src/generated/extension.d.cts +2 -1
- package/src/generated/report.cjs +1 -1
- package/src/generated/report.d.cts +2 -1
- package/src/generated/run-evidence.cjs +1 -1
- package/src/generated/run-evidence.d.cts +2 -1
- package/src/generated/runtime.cjs +1 -1
- package/src/generated/runtime.d.cts +2 -1
- package/src/git.ts +93 -0
- package/src/graders/git-head.ts +29 -84
- package/src/graders/shell.ts +50 -68
- package/src/host-diagnostic-redaction.ts +52 -0
- package/src/host-diagnostics.ts +331 -0
- package/src/hosts/claude-continuation.ts +57 -40
- package/src/hosts/claude-credential.ts +160 -63
- package/src/hosts/claude-events.ts +34 -18
- package/src/hosts/claude-keychain.ts +78 -21
- package/src/hosts/claude-login-recovery.ts +85 -0
- package/src/hosts/claude-login-refresh.ts +178 -0
- package/src/hosts/claude-login-store.ts +162 -0
- package/src/hosts/claude-login.ts +107 -0
- package/src/hosts/claude-native-goal.ts +15 -12
- package/src/hosts/claude-process.ts +10 -50
- package/src/hosts/claude-refresh-lock.ts +81 -0
- package/src/hosts/claude-repository-invocation.ts +9 -34
- package/src/hosts/claude-settings.ts +46 -9
- package/src/hosts/claude-skill-activations.ts +169 -0
- package/src/hosts/claude-state.ts +28 -15
- package/src/hosts/claude-tool-calls.ts +13 -10
- package/src/hosts/claude.ts +121 -81
- package/src/hosts/codex-app-server.ts +78 -52
- package/src/hosts/codex-configuration.ts +5 -10
- package/src/hosts/codex-exec-controls.ts +516 -0
- package/src/hosts/codex-marketplace.ts +12 -10
- package/src/hosts/codex-native-calls.ts +15 -122
- package/src/hosts/codex-process.ts +10 -183
- package/src/hosts/codex-profile.ts +36 -21
- package/src/hosts/codex-session-files.ts +1 -9
- package/src/hosts/codex-state.ts +134 -18
- package/src/hosts/codex.ts +210 -183
- package/src/hosts/isolation-common.ts +8 -11
- package/src/hosts/isolation-roots.ts +2 -2
- package/src/hosts/linux-sandbox.ts +15 -2
- package/src/hosts/mac-sandbox.ts +87 -18
- package/src/hosts/native-controls.ts +72 -22
- package/src/hosts/native-request.ts +55 -0
- package/src/hosts/process-lifecycle.ts +216 -48
- package/src/hosts/protected-worktrees.ts +1 -1
- package/src/hosts/skill-hook-catalog.ts +131 -0
- package/src/hosts/skill-hook-handler.ts +374 -0
- package/src/hosts/skill-hooks.ts +577 -0
- package/src/instrumentation.ts +7 -8
- package/src/native-transcript-state.ts +22 -3
- package/src/native-transcript-view.ts +52 -13
- package/src/native-transcripts.ts +26 -11
- package/src/paths.ts +22 -0
- package/src/process-lifecycle.ts +150 -0
- package/src/provenance.ts +27 -7
- package/src/prune.ts +300 -0
- package/src/report.ts +63 -36
- package/src/resolved-case.ts +1 -1
- package/src/results-lock.ts +42 -0
- package/src/results.ts +14 -18
- package/src/{runtime-config.ts → runtime/config.ts} +160 -46
- package/src/{runtime-discovery-apple.ts → runtime/discovery-apple.ts} +3 -3
- package/src/{runtime-discovery-providers.ts → runtime/discovery-providers.ts} +3 -9
- package/src/{runtime-discovery.ts → runtime/discovery.ts} +4 -4
- package/src/{runtime-hook-processes.ts → runtime/hook-processes.ts} +1 -1
- package/src/{runtime-hooks.ts → runtime/hooks.ts} +32 -22
- package/src/{runtime-paths.ts → runtime/paths.ts} +5 -19
- package/src/{runtime-query.ts → runtime/query.ts} +5 -5
- package/src/{runtime-seeds.ts → runtime/seeds.ts} +3 -3
- package/src/runtime/shared-cache.ts +130 -0
- package/src/{runtime-state.ts → runtime/state.ts} +28 -11
- package/src/schema-types.ts +73 -161
- package/src/shell.ts +4 -0
- package/src/transcript-retention.ts +146 -0
- package/src/value-guards.ts +22 -0
- package/docs/assets/sevro-logo.png +0 -0
- package/docs/assets/sevro-symbol.svg +0 -1
- package/docs/assets/sevro-wordmark.svg +0 -1
- package/docs/cache-ownership-validation.md +0 -49
- package/docs/claude-continuation-validation.md +0 -47
- package/docs/concurrency-validation.md +0 -86
- package/docs/configuration-root-validation.md +0 -70
- package/docs/engine-slice.md +0 -114
- package/docs/evidence/runtime-startup-30/README.md +0 -185
- package/docs/evidence/runtime-startup-30/after.json +0 -319
- package/docs/evidence/runtime-startup-30/baseline-timeout.jsonl +0 -2
- package/docs/evidence/runtime-startup-30/before.json +0 -403
- package/docs/evidence/runtime-startup-30/consumer-smoke.json +0 -63
- package/docs/evidence/runtime-startup-30/full-policy-diagnostic.jsonl +0 -3
- package/docs/evidence/runtime-startup-30/minimal-policy-diagnostic.jsonl +0 -3
- package/docs/evidence/runtime-startup-30/plugin-template-assessment.json +0 -20
- package/docs/evidence/runtime-startup-30/seedless-timeout.jsonl +0 -2
- package/docs/evidence.md +0 -17
- package/docs/fixture-cleanup-validation.md +0 -73
- package/docs/guide-verification.json +0 -239
- package/src/evaluation-context.ts +0 -259
- package/src/evaluation-fixture.ts +0 -302
- package/src/evaluation-run.ts +0 -200
- package/src/evaluation-trial.ts +0 -1016
- package/src/hosts/claude-nested-skills.ts +0 -272
- package/src/hosts/codex-command-output.ts +0 -510
- package/src/hosts/codex-executor-command.ts +0 -291
- package/src/hosts/codex-skill-reads.ts +0 -783
- /package/src/{trial-scheduler.ts → evaluation/scheduler.ts} +0 -0
|
@@ -1,302 +0,0 @@
|
|
|
1
|
-
import { isRecord } from "./value-guards";
|
|
2
|
-
import { sha256 } from "./identity";
|
|
3
|
-
import { appendFile, mkdir, readFile, writeFile } from "node:fs/promises";
|
|
4
|
-
import { allocateWorkspace, removeWorkspace } from "./workspace-state";
|
|
5
|
-
import { dirname, join } from "node:path";
|
|
6
|
-
import { fileURLToPath } from "node:url";
|
|
7
|
-
import { canonicalJson } from "./identity";
|
|
8
|
-
import { fixtureBinDirectory, installFixtureBin } from "./fixture-bin";
|
|
9
|
-
import { installGitHooks } from "./git-hooks";
|
|
10
|
-
import {
|
|
11
|
-
materializeGeneratedFixture,
|
|
12
|
-
type GeneratedFixture,
|
|
13
|
-
} from "./generated-fixture";
|
|
14
|
-
import { runFixtureSetup, type FixtureSetup } from "./fixture-setup";
|
|
15
|
-
import {
|
|
16
|
-
fixtureParts,
|
|
17
|
-
safePreparationTarget,
|
|
18
|
-
type InlineArtifact,
|
|
19
|
-
type PreparationSources,
|
|
20
|
-
} from "./preparation";
|
|
21
|
-
import {
|
|
22
|
-
applyRepositoryOverlay,
|
|
23
|
-
cloneRepositorySource,
|
|
24
|
-
type RepositoryFixture,
|
|
25
|
-
type RepositorySource,
|
|
26
|
-
} from "./repository-fixture";
|
|
27
|
-
import {
|
|
28
|
-
EvaluationConfigurationError,
|
|
29
|
-
type HostResult,
|
|
30
|
-
type ResolvedCase,
|
|
31
|
-
} from "./evaluation-types";
|
|
32
|
-
|
|
33
|
-
export { sha256 } from "./identity";
|
|
34
|
-
|
|
35
|
-
export async function createFixture(
|
|
36
|
-
fixture: ResolvedCase["fixture"],
|
|
37
|
-
artifacts: InlineArtifact[],
|
|
38
|
-
sources: PreparationSources | undefined,
|
|
39
|
-
repository: RepositorySource | null,
|
|
40
|
-
repositoryFixture: RepositoryFixture | null,
|
|
41
|
-
generated: GeneratedFixture | null,
|
|
42
|
-
setup: FixtureSetup | null,
|
|
43
|
-
projectRoot: string,
|
|
44
|
-
signal?: AbortSignal,
|
|
45
|
-
reservedWorkspace?: string,
|
|
46
|
-
): Promise<string> {
|
|
47
|
-
const paths = inlineFixturePaths(fixture, generated, repository);
|
|
48
|
-
const workspace = reservedWorkspace ?? (await allocateWorkspace());
|
|
49
|
-
try {
|
|
50
|
-
await initializeFixtureHistory(
|
|
51
|
-
fixture,
|
|
52
|
-
sources,
|
|
53
|
-
repository,
|
|
54
|
-
repositoryFixture,
|
|
55
|
-
generated,
|
|
56
|
-
workspace,
|
|
57
|
-
);
|
|
58
|
-
await installDeclaredFixtureTools(
|
|
59
|
-
generated ?? repositoryFixture,
|
|
60
|
-
workspace,
|
|
61
|
-
);
|
|
62
|
-
await writeInlineFixtureFiles(paths, workspace);
|
|
63
|
-
await setupFixture(setup, workspace, projectRoot, signal);
|
|
64
|
-
await mountPreparationArtifacts(artifacts, workspace);
|
|
65
|
-
await excludePreparationArtifacts(artifacts, workspace);
|
|
66
|
-
await fixtureBinDirectory(workspace);
|
|
67
|
-
return workspace;
|
|
68
|
-
} catch (error) {
|
|
69
|
-
if (!reservedWorkspace) await removeWorkspace(workspace);
|
|
70
|
-
throw error;
|
|
71
|
-
}
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
function inlineFixturePaths(
|
|
75
|
-
fixture: ResolvedCase["fixture"],
|
|
76
|
-
generated: GeneratedFixture | null,
|
|
77
|
-
repository: RepositorySource | null,
|
|
78
|
-
) {
|
|
79
|
-
return Object.entries(
|
|
80
|
-
generated || repository ? {} : (fixture.files ?? {}),
|
|
81
|
-
).map(([path, content]) => ({ path, parts: fixtureParts(path), content }));
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
async function cloneFixtureRepository(
|
|
85
|
-
fixture: ResolvedCase["fixture"],
|
|
86
|
-
sources: PreparationSources | undefined,
|
|
87
|
-
repository: RepositorySource,
|
|
88
|
-
workspace: string,
|
|
89
|
-
): Promise<void> {
|
|
90
|
-
if (!fixture.sourceRef || !sources)
|
|
91
|
-
throw new EvaluationConfigurationError(
|
|
92
|
-
"repository source root is required and must be absolute",
|
|
93
|
-
);
|
|
94
|
-
await cloneRepositorySource(
|
|
95
|
-
fixture.sourceRef,
|
|
96
|
-
sources,
|
|
97
|
-
repository,
|
|
98
|
-
workspace,
|
|
99
|
-
);
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
async function initializeFixtureHistory(
|
|
103
|
-
fixture: ResolvedCase["fixture"],
|
|
104
|
-
sources: PreparationSources | undefined,
|
|
105
|
-
repository: RepositorySource | null,
|
|
106
|
-
repositoryFixture: RepositoryFixture | null,
|
|
107
|
-
generated: GeneratedFixture | null,
|
|
108
|
-
workspace: string,
|
|
109
|
-
): Promise<void> {
|
|
110
|
-
if (repository)
|
|
111
|
-
await cloneFixtureRepository(fixture, sources, repository, workspace);
|
|
112
|
-
if (generated) await materializeGeneratedFixture(generated, workspace);
|
|
113
|
-
if (repositoryFixture)
|
|
114
|
-
await applyRepositoryOverlay(repositoryFixture, workspace);
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
async function installDeclaredFixtureTools(
|
|
118
|
-
fixture: GeneratedFixture | RepositoryFixture | null,
|
|
119
|
-
workspace: string,
|
|
120
|
-
): Promise<void> {
|
|
121
|
-
await installFixtureBin(fixture?.bin, workspace);
|
|
122
|
-
await installGitHooks(fixture?.hooks, workspace);
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
async function writeInlineFixtureFiles(
|
|
126
|
-
files: ReturnType<typeof inlineFixturePaths>,
|
|
127
|
-
workspace: string,
|
|
128
|
-
): Promise<void> {
|
|
129
|
-
for (const file of files) {
|
|
130
|
-
const target = join(workspace, ...file.parts);
|
|
131
|
-
await mkdir(dirname(target), { recursive: true, mode: 0o700 });
|
|
132
|
-
await writeFile(target, file.content, { flag: "wx", mode: 0o600 });
|
|
133
|
-
}
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
async function setupFixture(
|
|
137
|
-
setup: FixtureSetup | null,
|
|
138
|
-
workspace: string,
|
|
139
|
-
projectRoot: string,
|
|
140
|
-
signal?: AbortSignal,
|
|
141
|
-
): Promise<void> {
|
|
142
|
-
if (!setup) return;
|
|
143
|
-
await runFixtureSetup(setup, {
|
|
144
|
-
workspace,
|
|
145
|
-
projectRoot,
|
|
146
|
-
fixtureBinDir: (await fixtureBinDirectory(workspace)) ?? undefined,
|
|
147
|
-
signal,
|
|
148
|
-
});
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
async function mountPreparationArtifacts(
|
|
152
|
-
artifacts: InlineArtifact[],
|
|
153
|
-
workspace: string,
|
|
154
|
-
): Promise<void> {
|
|
155
|
-
for (const artifact of artifacts) {
|
|
156
|
-
const target = await safePreparationTarget(
|
|
157
|
-
workspace,
|
|
158
|
-
artifact.relativePath,
|
|
159
|
-
);
|
|
160
|
-
await writeFile(target, artifact.bytes, {
|
|
161
|
-
flag: "wx",
|
|
162
|
-
mode: artifact.executable ? 0o700 : 0o600,
|
|
163
|
-
});
|
|
164
|
-
}
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
async function excludePreparationArtifacts(
|
|
168
|
-
artifacts: InlineArtifact[],
|
|
169
|
-
workspace: string,
|
|
170
|
-
): Promise<void> {
|
|
171
|
-
const gitExcluded = artifacts.filter((artifact) => artifact.gitExclude);
|
|
172
|
-
if (!gitExcluded.length) return;
|
|
173
|
-
const special = new Set(["\\", "*", "?", "[", "]", "#", "!", " "]);
|
|
174
|
-
const patterns = gitExcluded.map((artifact) =>
|
|
175
|
-
Array.from(artifact.relativePath)
|
|
176
|
-
.map((character) =>
|
|
177
|
-
special.has(character) ? `\\${character}` : character,
|
|
178
|
-
)
|
|
179
|
-
.join(""),
|
|
180
|
-
);
|
|
181
|
-
await appendFile(
|
|
182
|
-
join(workspace, ".git", "info", "exclude"),
|
|
183
|
-
`\n${patterns.map((path) => `/${path}`).join("\n")}\n`,
|
|
184
|
-
);
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
export function hostObservations(
|
|
188
|
-
result: HostResult,
|
|
189
|
-
hostId: string,
|
|
190
|
-
existingIds: Set<string>,
|
|
191
|
-
) {
|
|
192
|
-
const items = result.observations ?? [];
|
|
193
|
-
if (items.length > 128) throw new Error("too many host observations");
|
|
194
|
-
const ids = new Set([...existingIds, "sevro.observation.final-message"]);
|
|
195
|
-
let totalBytes = 0;
|
|
196
|
-
return items.map((value: unknown) => {
|
|
197
|
-
const item = validatedHostObservation(value, ids);
|
|
198
|
-
ids.add(item.id);
|
|
199
|
-
const data = canonicalJson(item.data);
|
|
200
|
-
totalBytes += Buffer.byteLength(data, "utf8");
|
|
201
|
-
if (totalBytes > 8 * 1024 * 1024)
|
|
202
|
-
throw new Error("host observations exceed 8 MiB");
|
|
203
|
-
return {
|
|
204
|
-
id: item.id,
|
|
205
|
-
source: hostId,
|
|
206
|
-
completeness: item.completeness,
|
|
207
|
-
data: JSON.parse(data) as Record<string, unknown>,
|
|
208
|
-
};
|
|
209
|
-
});
|
|
210
|
-
}
|
|
211
|
-
|
|
212
|
-
export function hostArtifacts(result: HostResult, existingIds: Set<string>) {
|
|
213
|
-
const items = result.artifacts ?? [];
|
|
214
|
-
if (!Array.isArray(items) || items.length > 32)
|
|
215
|
-
throw new Error("too many host artifacts");
|
|
216
|
-
const ids = new Set(existingIds);
|
|
217
|
-
let totalBytes = 0;
|
|
218
|
-
return items.map((value: unknown) => {
|
|
219
|
-
const item = validatedHostArtifact(value, ids);
|
|
220
|
-
ids.add(item.id);
|
|
221
|
-
totalBytes += item.bytes.byteLength;
|
|
222
|
-
if (
|
|
223
|
-
item.bytes.byteLength > 8 * 1024 * 1024 ||
|
|
224
|
-
totalBytes > 32 * 1024 * 1024
|
|
225
|
-
)
|
|
226
|
-
throw new Error("host artifacts exceed the size limit");
|
|
227
|
-
return { id: item.id, bytes: Buffer.from(item.bytes) };
|
|
228
|
-
});
|
|
229
|
-
}
|
|
230
|
-
|
|
231
|
-
function validEvidenceId(value: unknown): value is string {
|
|
232
|
-
return (
|
|
233
|
-
typeof value === "string" &&
|
|
234
|
-
/^[a-z][a-z0-9]*(?:[.-][a-z0-9]+)+$/.test(value)
|
|
235
|
-
);
|
|
236
|
-
}
|
|
237
|
-
|
|
238
|
-
function validObservationId(value: unknown, ids: Set<string>): value is string {
|
|
239
|
-
return (
|
|
240
|
-
validEvidenceId(value) &&
|
|
241
|
-
!value.startsWith("sevro.observation.") &&
|
|
242
|
-
!ids.has(value)
|
|
243
|
-
);
|
|
244
|
-
}
|
|
245
|
-
|
|
246
|
-
function validCompleteness(
|
|
247
|
-
value: unknown,
|
|
248
|
-
): value is "complete" | "partial" | "unavailable" {
|
|
249
|
-
return value === "complete" || value === "partial" || value === "unavailable";
|
|
250
|
-
}
|
|
251
|
-
|
|
252
|
-
function validatedHostObservation(value: unknown, ids: Set<string>) {
|
|
253
|
-
if (!isRecord(value)) throw new Error("invalid host observation");
|
|
254
|
-
if (
|
|
255
|
-
!validObservationId(value.id, ids) ||
|
|
256
|
-
!validCompleteness(value.completeness) ||
|
|
257
|
-
!isRecord(value.data)
|
|
258
|
-
)
|
|
259
|
-
throw new Error("invalid host observation");
|
|
260
|
-
return { id: value.id, completeness: value.completeness, data: value.data };
|
|
261
|
-
}
|
|
262
|
-
|
|
263
|
-
function validArtifactId(value: unknown, ids: Set<string>): value is string {
|
|
264
|
-
return validEvidenceId(value) && !ids.has(value);
|
|
265
|
-
}
|
|
266
|
-
|
|
267
|
-
function validatedHostArtifact(value: unknown, ids: Set<string>) {
|
|
268
|
-
if (!isRecord(value)) throw new Error("invalid host artifact");
|
|
269
|
-
if (!validArtifactId(value.id, ids) || !(value.bytes instanceof Uint8Array))
|
|
270
|
-
throw new Error("invalid host artifact");
|
|
271
|
-
return { id: value.id, bytes: value.bytes };
|
|
272
|
-
}
|
|
273
|
-
|
|
274
|
-
export async function verifyRetainedArtifacts(
|
|
275
|
-
artifacts: { path: string; sha256: string }[],
|
|
276
|
-
): Promise<void> {
|
|
277
|
-
for (const artifact of artifacts) {
|
|
278
|
-
let actual: string;
|
|
279
|
-
try {
|
|
280
|
-
actual = sha256(await readFile(fileURLToPath(artifact.path)));
|
|
281
|
-
} catch {
|
|
282
|
-
throw new Error("retained preparation artifact is unreadable");
|
|
283
|
-
}
|
|
284
|
-
if (actual !== artifact.sha256)
|
|
285
|
-
throw new Error("retained preparation artifact changed");
|
|
286
|
-
}
|
|
287
|
-
}
|
|
288
|
-
|
|
289
|
-
export function usage(result: HostResult | null) {
|
|
290
|
-
return result === null
|
|
291
|
-
? { inputTokens: null, outputTokens: null, costUsd: null, complete: false }
|
|
292
|
-
: availableUsage(result);
|
|
293
|
-
}
|
|
294
|
-
|
|
295
|
-
function availableUsage(result: HostResult) {
|
|
296
|
-
return {
|
|
297
|
-
inputTokens: result.inputTokens ?? null,
|
|
298
|
-
outputTokens: result.outputTokens ?? null,
|
|
299
|
-
costUsd: result.costUsd ?? null,
|
|
300
|
-
complete: result.usageComplete ?? false,
|
|
301
|
-
};
|
|
302
|
-
}
|
package/src/evaluation-run.ts
DELETED
|
@@ -1,200 +0,0 @@
|
|
|
1
|
-
import { prepareEvaluation } from "./evaluation-plan";
|
|
2
|
-
import {
|
|
3
|
-
type CaseSummary,
|
|
4
|
-
type CliResult,
|
|
5
|
-
type EvaluationOptions,
|
|
6
|
-
} from "./evaluation-types";
|
|
7
|
-
import { canonicalJson, hashJson } from "./identity";
|
|
8
|
-
import {
|
|
9
|
-
exitCodeFor,
|
|
10
|
-
summarizeAssessments,
|
|
11
|
-
summarizeCases,
|
|
12
|
-
type Assessment,
|
|
13
|
-
} from "./results";
|
|
14
|
-
import { runtimePolicySnapshot } from "./runtime-config";
|
|
15
|
-
import { cleanupExpiredWorkspaces } from "./workspace-state";
|
|
16
|
-
import { assertCliResult, assertRunEvidence } from "./schema";
|
|
17
|
-
import { atomicWriteJson } from "./storage";
|
|
18
|
-
import {
|
|
19
|
-
allocateEvaluationRun,
|
|
20
|
-
checkpointEvaluation,
|
|
21
|
-
cleanupEvaluationWorkspaces,
|
|
22
|
-
diagnoseEvaluationFailure,
|
|
23
|
-
reserveEvaluationWorkspaces,
|
|
24
|
-
retainPreparationArtifacts,
|
|
25
|
-
type EvaluationContext,
|
|
26
|
-
} from "./evaluation-context";
|
|
27
|
-
import { executeEvaluationTrials } from "./evaluation-trial";
|
|
28
|
-
|
|
29
|
-
function evaluationCaseSummary(
|
|
30
|
-
options: EvaluationOptions,
|
|
31
|
-
context: EvaluationContext,
|
|
32
|
-
): CaseSummary {
|
|
33
|
-
const assessment: Assessment =
|
|
34
|
-
!context.trialSummaries.length && options.signal?.aborted
|
|
35
|
-
? {
|
|
36
|
-
execution: { status: "cancelled" },
|
|
37
|
-
grading: { status: "not_requested" },
|
|
38
|
-
task: { verdict: "not_assessed" },
|
|
39
|
-
}
|
|
40
|
-
: summarizeAssessments(context.trialSummaries, options.passThreshold);
|
|
41
|
-
return {
|
|
42
|
-
caseId: options.case.id,
|
|
43
|
-
...assessment,
|
|
44
|
-
trials: context.trialSummaries,
|
|
45
|
-
};
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
function evaluationSignal(
|
|
49
|
-
options: EvaluationOptions,
|
|
50
|
-
): "SIGINT" | "SIGTERM" | undefined {
|
|
51
|
-
const reason: unknown = options.signal?.aborted
|
|
52
|
-
? options.signal.reason
|
|
53
|
-
: null;
|
|
54
|
-
return reason === "SIGINT" || reason === "SIGTERM" ? reason : undefined;
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
function finalCliResult(
|
|
58
|
-
options: EvaluationOptions,
|
|
59
|
-
context: EvaluationContext,
|
|
60
|
-
): CliResult {
|
|
61
|
-
const caseResult = evaluationCaseSummary(options, context);
|
|
62
|
-
const assessment = summarizeCases([caseResult]);
|
|
63
|
-
const diagnostic = context.diagnostics.sort(
|
|
64
|
-
(left, right) => left.trial - right.trial,
|
|
65
|
-
)[0]?.diagnostic;
|
|
66
|
-
return {
|
|
67
|
-
format: "sevro.cli-result.v1",
|
|
68
|
-
runId: context.runId,
|
|
69
|
-
...assessment,
|
|
70
|
-
exitCode: exitCodeFor(assessment, {
|
|
71
|
-
dryRun: options.dry,
|
|
72
|
-
signal: evaluationSignal(options),
|
|
73
|
-
}),
|
|
74
|
-
evidencePath: context.evidencePath,
|
|
75
|
-
cases: [caseResult],
|
|
76
|
-
...(diagnostic ? { diagnostic } : {}),
|
|
77
|
-
};
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
function finalConditionEvidence(
|
|
81
|
-
options: EvaluationOptions,
|
|
82
|
-
context: EvaluationContext,
|
|
83
|
-
) {
|
|
84
|
-
const actualConditions = [
|
|
85
|
-
...new Set(context.trialEvidence.map((entry) => entry.condition.actual)),
|
|
86
|
-
];
|
|
87
|
-
const commonAppliedInstrumentation =
|
|
88
|
-
context.trialEvidence.length === options.trialCount &&
|
|
89
|
-
context.trialEvidence.every(
|
|
90
|
-
(entry) =>
|
|
91
|
-
canonicalJson(entry.condition.appliedInstrumentation) ===
|
|
92
|
-
canonicalJson(context.requestedInstrumentation),
|
|
93
|
-
)
|
|
94
|
-
? context.requestedInstrumentation
|
|
95
|
-
: [];
|
|
96
|
-
return {
|
|
97
|
-
requested: options.condition,
|
|
98
|
-
actual: actualConditions.length === 1 ? actualConditions[0] : "unknown",
|
|
99
|
-
requestedInstrumentation: context.requestedInstrumentation,
|
|
100
|
-
appliedInstrumentation: commonAppliedInstrumentation,
|
|
101
|
-
};
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
function finalExtensionEvidence(
|
|
105
|
-
options: EvaluationOptions,
|
|
106
|
-
replacedBuiltinGraders: string[],
|
|
107
|
-
) {
|
|
108
|
-
const extension = options.extension;
|
|
109
|
-
if (!extension) return null;
|
|
110
|
-
const identity = extension.session.identity;
|
|
111
|
-
return {
|
|
112
|
-
id: identity.id,
|
|
113
|
-
version: identity.version,
|
|
114
|
-
sourceDigest: identity.sourceDigest,
|
|
115
|
-
configurationDigest: identity.configurationDigest,
|
|
116
|
-
protocol: identity.protocol,
|
|
117
|
-
capabilities: identity.capabilities,
|
|
118
|
-
replacements: {
|
|
119
|
-
graders: replacedBuiltinGraders,
|
|
120
|
-
taskVerdictPolicy: identity.selectedTaskVerdictPolicy,
|
|
121
|
-
},
|
|
122
|
-
};
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
function finalRunEvidence(
|
|
126
|
-
options: EvaluationOptions,
|
|
127
|
-
context: EvaluationContext,
|
|
128
|
-
result: CliResult,
|
|
129
|
-
diagnostic: { code: string; message: string } | undefined,
|
|
130
|
-
) {
|
|
131
|
-
const condition = finalConditionEvidence(options, context);
|
|
132
|
-
return {
|
|
133
|
-
format: "sevro.run-evidence.v1",
|
|
134
|
-
runId: context.runId,
|
|
135
|
-
evaluationIdentity: context.evaluationIdentity,
|
|
136
|
-
configuration: {
|
|
137
|
-
digest: hashJson(context.redactedConfig),
|
|
138
|
-
redacted: context.redactedConfig,
|
|
139
|
-
},
|
|
140
|
-
runner: context.runner,
|
|
141
|
-
project: context.project,
|
|
142
|
-
extension: finalExtensionEvidence(options, context.replacedBuiltinGraders),
|
|
143
|
-
condition,
|
|
144
|
-
graders: {
|
|
145
|
-
active: context.activeGraders,
|
|
146
|
-
replacedDefaults: context.replacedBuiltinGraders,
|
|
147
|
-
},
|
|
148
|
-
routes: context.routes,
|
|
149
|
-
result,
|
|
150
|
-
trials: context.trialEvidence,
|
|
151
|
-
...(diagnostic ? { diagnostic } : {}),
|
|
152
|
-
};
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
async function finishEvaluationRun(
|
|
156
|
-
options: EvaluationOptions,
|
|
157
|
-
context: EvaluationContext,
|
|
158
|
-
) {
|
|
159
|
-
const diagnostic = context.diagnostics.sort(
|
|
160
|
-
(left, right) => left.trial - right.trial,
|
|
161
|
-
)[0]?.diagnostic;
|
|
162
|
-
const result = finalCliResult(options, context);
|
|
163
|
-
const evidence = finalRunEvidence(options, context, result, diagnostic);
|
|
164
|
-
assertCliResult(result);
|
|
165
|
-
assertRunEvidence(evidence);
|
|
166
|
-
await atomicWriteJson(context.evidencePath, evidence);
|
|
167
|
-
checkpointEvaluation(
|
|
168
|
-
context,
|
|
169
|
-
options.signal?.aborted ? "interrupted" : "complete",
|
|
170
|
-
);
|
|
171
|
-
return { result };
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
/** Execute resolved evaluator data through an injected host and retain every trial. */
|
|
175
|
-
export async function runEvaluation(
|
|
176
|
-
options: EvaluationOptions,
|
|
177
|
-
): Promise<{ result: CliResult }> {
|
|
178
|
-
options = {
|
|
179
|
-
...options,
|
|
180
|
-
runtimePolicy: runtimePolicySnapshot(options.runtimePolicy),
|
|
181
|
-
};
|
|
182
|
-
await cleanupExpiredWorkspaces();
|
|
183
|
-
const plan = await prepareEvaluation(options);
|
|
184
|
-
const runtime = await allocateEvaluationRun(options, plan);
|
|
185
|
-
try {
|
|
186
|
-
const artifacts = await retainPreparationArtifacts({ ...plan, ...runtime });
|
|
187
|
-
const records = await reserveEvaluationWorkspaces(options, {
|
|
188
|
-
...plan,
|
|
189
|
-
...runtime,
|
|
190
|
-
});
|
|
191
|
-
const context = { ...plan, ...runtime, ...artifacts, ...records };
|
|
192
|
-
await executeEvaluationTrials(options, context);
|
|
193
|
-
return await finishEvaluationRun(options, context);
|
|
194
|
-
} catch (error) {
|
|
195
|
-
diagnoseEvaluationFailure(runtime);
|
|
196
|
-
throw error;
|
|
197
|
-
} finally {
|
|
198
|
-
await cleanupEvaluationWorkspaces(runtime);
|
|
199
|
-
}
|
|
200
|
-
}
|