@dailephd/my-dev-kit-lab 0.6.3 → 0.7.1
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/CHANGELOG.md +17 -0
- package/README.md +7 -4
- package/benchmarks/contracts/context-window-scaling-cases.json +220 -0
- package/benchmarks/projects/README.md +3 -1
- package/benchmarks/projects/context-window-scaling-fixed-ts/README.md +14 -0
- package/benchmarks/projects/context-window-scaling-fixed-ts/src/filler/tier-1/carrier-depot-catalog-01.ts +302 -0
- package/benchmarks/projects/context-window-scaling-fixed-ts/src/filler/tier-1/course-module-catalog-06.ts +302 -0
- package/benchmarks/projects/context-window-scaling-fixed-ts/src/filler/tier-1/library-shelf-catalog-07.ts +302 -0
- package/benchmarks/projects/context-window-scaling-fixed-ts/src/filler/tier-1/sensor-station-catalog-05.ts +302 -0
- package/benchmarks/projects/context-window-scaling-fixed-ts/src/filler/tier-1/staff-rota-catalog-03.ts +302 -0
- package/benchmarks/projects/context-window-scaling-fixed-ts/src/filler/tier-1/supplier-contract-catalog-02.ts +302 -0
- package/benchmarks/projects/context-window-scaling-fixed-ts/src/filler/tier-1/vehicle-route-catalog-04.ts +302 -0
- package/benchmarks/projects/context-window-scaling-fixed-ts/src/filler/tier-2/archive-box-catalog-12.ts +302 -0
- package/benchmarks/projects/context-window-scaling-fixed-ts/src/filler/tier-2/clinic-ward-catalog-08.ts +302 -0
- package/benchmarks/projects/context-window-scaling-fixed-ts/src/filler/tier-2/greenhouse-bay-catalog-13.ts +302 -0
- package/benchmarks/projects/context-window-scaling-fixed-ts/src/filler/tier-2/harbor-berth-catalog-10.ts +302 -0
- package/benchmarks/projects/context-window-scaling-fixed-ts/src/filler/tier-2/kitchen-section-catalog-15.ts +302 -0
- package/benchmarks/projects/context-window-scaling-fixed-ts/src/filler/tier-2/market-stall-catalog-09.ts +302 -0
- package/benchmarks/projects/context-window-scaling-fixed-ts/src/filler/tier-2/station-platform-catalog-14.ts +302 -0
- package/benchmarks/projects/context-window-scaling-fixed-ts/src/filler/tier-2/workshop-bench-catalog-11.ts +302 -0
- package/benchmarks/projects/context-window-scaling-fixed-ts/src/filler/tier-3/archive-box-catalog-28.ts +302 -0
- package/benchmarks/projects/context-window-scaling-fixed-ts/src/filler/tier-3/carrier-depot-catalog-17.ts +302 -0
- package/benchmarks/projects/context-window-scaling-fixed-ts/src/filler/tier-3/clinic-ward-catalog-24.ts +302 -0
- package/benchmarks/projects/context-window-scaling-fixed-ts/src/filler/tier-3/course-module-catalog-22.ts +302 -0
- package/benchmarks/projects/context-window-scaling-fixed-ts/src/filler/tier-3/greenhouse-bay-catalog-29.ts +302 -0
- package/benchmarks/projects/context-window-scaling-fixed-ts/src/filler/tier-3/harbor-berth-catalog-26.ts +302 -0
- package/benchmarks/projects/context-window-scaling-fixed-ts/src/filler/tier-3/kitchen-section-catalog-31.ts +302 -0
- package/benchmarks/projects/context-window-scaling-fixed-ts/src/filler/tier-3/library-shelf-catalog-23.ts +302 -0
- package/benchmarks/projects/context-window-scaling-fixed-ts/src/filler/tier-3/market-stall-catalog-25.ts +302 -0
- package/benchmarks/projects/context-window-scaling-fixed-ts/src/filler/tier-3/sensor-station-catalog-21.ts +302 -0
- package/benchmarks/projects/context-window-scaling-fixed-ts/src/filler/tier-3/staff-rota-catalog-19.ts +302 -0
- package/benchmarks/projects/context-window-scaling-fixed-ts/src/filler/tier-3/station-platform-catalog-30.ts +302 -0
- package/benchmarks/projects/context-window-scaling-fixed-ts/src/filler/tier-3/supplier-contract-catalog-18.ts +302 -0
- package/benchmarks/projects/context-window-scaling-fixed-ts/src/filler/tier-3/vehicle-route-catalog-20.ts +302 -0
- package/benchmarks/projects/context-window-scaling-fixed-ts/src/filler/tier-3/warehouse-zone-catalog-16.ts +302 -0
- package/benchmarks/projects/context-window-scaling-fixed-ts/src/filler/tier-3/workshop-bench-catalog-27.ts +302 -0
- package/benchmarks/projects/context-window-scaling-fixed-ts/src/filler/tier-4/archive-box-catalog-44.ts +302 -0
- package/benchmarks/projects/context-window-scaling-fixed-ts/src/filler/tier-4/carrier-depot-catalog-33.ts +302 -0
- package/benchmarks/projects/context-window-scaling-fixed-ts/src/filler/tier-4/carrier-depot-catalog-49.ts +302 -0
- package/benchmarks/projects/context-window-scaling-fixed-ts/src/filler/tier-4/clinic-ward-catalog-40.ts +302 -0
- package/benchmarks/projects/context-window-scaling-fixed-ts/src/filler/tier-4/clinic-ward-catalog-56.ts +302 -0
- package/benchmarks/projects/context-window-scaling-fixed-ts/src/filler/tier-4/course-module-catalog-38.ts +302 -0
- package/benchmarks/projects/context-window-scaling-fixed-ts/src/filler/tier-4/course-module-catalog-54.ts +302 -0
- package/benchmarks/projects/context-window-scaling-fixed-ts/src/filler/tier-4/greenhouse-bay-catalog-45.ts +302 -0
- package/benchmarks/projects/context-window-scaling-fixed-ts/src/filler/tier-4/harbor-berth-catalog-42.ts +302 -0
- package/benchmarks/projects/context-window-scaling-fixed-ts/src/filler/tier-4/harbor-berth-catalog-58.ts +302 -0
- package/benchmarks/projects/context-window-scaling-fixed-ts/src/filler/tier-4/kitchen-section-catalog-47.ts +302 -0
- package/benchmarks/projects/context-window-scaling-fixed-ts/src/filler/tier-4/library-shelf-catalog-39.ts +302 -0
- package/benchmarks/projects/context-window-scaling-fixed-ts/src/filler/tier-4/library-shelf-catalog-55.ts +302 -0
- package/benchmarks/projects/context-window-scaling-fixed-ts/src/filler/tier-4/market-stall-catalog-41.ts +302 -0
- package/benchmarks/projects/context-window-scaling-fixed-ts/src/filler/tier-4/market-stall-catalog-57.ts +302 -0
- package/benchmarks/projects/context-window-scaling-fixed-ts/src/filler/tier-4/sensor-station-catalog-37.ts +302 -0
- package/benchmarks/projects/context-window-scaling-fixed-ts/src/filler/tier-4/sensor-station-catalog-53.ts +302 -0
- package/benchmarks/projects/context-window-scaling-fixed-ts/src/filler/tier-4/staff-rota-catalog-35.ts +302 -0
- package/benchmarks/projects/context-window-scaling-fixed-ts/src/filler/tier-4/staff-rota-catalog-51.ts +302 -0
- package/benchmarks/projects/context-window-scaling-fixed-ts/src/filler/tier-4/station-platform-catalog-46.ts +302 -0
- package/benchmarks/projects/context-window-scaling-fixed-ts/src/filler/tier-4/supplier-contract-catalog-34.ts +302 -0
- package/benchmarks/projects/context-window-scaling-fixed-ts/src/filler/tier-4/supplier-contract-catalog-50.ts +302 -0
- package/benchmarks/projects/context-window-scaling-fixed-ts/src/filler/tier-4/vehicle-route-catalog-36.ts +302 -0
- package/benchmarks/projects/context-window-scaling-fixed-ts/src/filler/tier-4/vehicle-route-catalog-52.ts +302 -0
- package/benchmarks/projects/context-window-scaling-fixed-ts/src/filler/tier-4/warehouse-zone-catalog-32.ts +302 -0
- package/benchmarks/projects/context-window-scaling-fixed-ts/src/filler/tier-4/warehouse-zone-catalog-48.ts +302 -0
- package/benchmarks/projects/context-window-scaling-fixed-ts/src/filler/tier-4/workshop-bench-catalog-43.ts +302 -0
- package/benchmarks/projects/context-window-scaling-fixed-ts/src/tasks/auditRedaction.ts +25 -0
- package/benchmarks/projects/context-window-scaling-fixed-ts/src/tasks/inventoryReservation.ts +26 -0
- package/benchmarks/projects/context-window-scaling-fixed-ts/src/tasks/invoiceTotals.ts +25 -0
- package/benchmarks/projects/context-window-scaling-fixed-ts/src/tasks/shippingQuote.ts +32 -0
- package/benchmarks/projects/context-window-scaling-fixed-ts/tests/tasks/auditRedaction.test.ts +17 -0
- package/benchmarks/projects/context-window-scaling-fixed-ts/tests/tasks/inventoryReservation.test.ts +19 -0
- package/benchmarks/projects/context-window-scaling-fixed-ts/tests/tasks/invoiceTotals.test.ts +14 -0
- package/benchmarks/projects/context-window-scaling-fixed-ts/tests/tasks/shippingQuote.test.ts +19 -0
- package/dist/src/cli/help.js +19 -3
- package/dist/src/commands/runExperimentDescribeCommand.js +6 -0
- package/dist/src/commands/runExperimentRunCommand.js +118 -7
- package/dist/src/evaluation/syntheticRepository/config.js +304 -0
- package/dist/src/evaluation/syntheticRepository/evaluationCase.js +43 -0
- package/dist/src/evaluation/syntheticRepository/identity.js +41 -0
- package/dist/src/evaluation/syntheticRepository/index.js +16 -0
- package/dist/src/evaluation/syntheticRepository/inspection.js +92 -0
- package/dist/src/evaluation/syntheticRepository/layout.js +50 -0
- package/dist/src/evaluation/syntheticRepository/manifest.js +281 -0
- package/dist/src/evaluation/syntheticRepository/manifestVerification.js +112 -0
- package/dist/src/evaluation/syntheticRepository/materialize.js +170 -0
- package/dist/src/evaluation/syntheticRepository/planning.js +479 -0
- package/dist/src/evaluation/syntheticRepository/prng.js +47 -0
- package/dist/src/evaluation/syntheticRepository/renderPython.js +68 -0
- package/dist/src/evaluation/syntheticRepository/renderRepository.js +39 -0
- package/dist/src/evaluation/syntheticRepository/renderShared.js +93 -0
- package/dist/src/evaluation/syntheticRepository/renderTypeScript.js +82 -0
- package/dist/src/evaluation/syntheticRepository/topology.js +96 -0
- package/dist/src/evaluation/syntheticRepository/types.js +26 -0
- package/dist/src/experiments/defaultRegistry.js +2 -0
- package/dist/src/experiments/plugins/contextWindowScaling/cliBudgets.js +31 -0
- package/dist/src/experiments/plugins/contextWindowScaling/config.js +84 -0
- package/dist/src/experiments/plugins/contextWindowScaling/contextBudget.js +43 -0
- package/dist/src/experiments/plugins/contextWindowScaling/evaluation.js +36 -0
- package/dist/src/experiments/plugins/contextWindowScaling/execution.js +187 -0
- package/dist/src/experiments/plugins/contextWindowScaling/executionArtifact.js +15 -0
- package/dist/src/experiments/plugins/contextWindowScaling/executionArtifactReader.js +186 -0
- package/dist/src/experiments/plugins/contextWindowScaling/index.js +15 -0
- package/dist/src/experiments/plugins/contextWindowScaling/metadata.js +12 -0
- package/dist/src/experiments/plugins/contextWindowScaling/metrics.js +149 -0
- package/dist/src/experiments/plugins/contextWindowScaling/plugin.js +185 -0
- package/dist/src/experiments/plugins/contextWindowScaling/projectProfile.js +51 -0
- package/dist/src/experiments/plugins/contextWindowScaling/relevantFiles.js +76 -0
- package/dist/src/experiments/plugins/contextWindowScaling/successEvidence.js +60 -0
- package/dist/src/experiments/plugins/contextWindowScaling/syntheticInputs.js +56 -0
- package/dist/src/experiments/plugins/contextWindowScaling/types.js +1 -0
- package/dist/src/experiments/plugins/index.js +1 -0
- package/dist/src/experiments/plugins/warmIndexReuse/agentEvaluation.js +1 -1
- package/dist/src/plots/buildContextWindowScalingPlotData.js +96 -0
- package/dist/src/plots/index.js +1 -0
- package/dist/src/plots/writePlotArtifacts.js +12 -3
- package/dist/src/report/experiments/buildContextWindowScalingReport.js +84 -0
- package/dist/src/report/experiments/buildPluginExperimentReport.js +22 -2
- package/dist/src/report/experiments/contextWindowScalingReportModel.js +3 -0
- package/dist/src/report/experiments/index.js +4 -0
- package/dist/src/report/experiments/renderContextWindowScalingHtml.js +99 -0
- package/dist/src/report/experiments/renderContextWindowScalingText.js +108 -0
- package/dist/src/report/experiments/renderPluginExperimentReportHtml.js +3 -0
- package/dist/src/report/experiments/renderPluginExperimentReportText.js +8 -0
- package/docs/METRICS.md +29 -1
- package/package.json +1 -1
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import path from "node:path";
|
|
2
|
+
import { resolveWithinRoot } from "../../../core/pathSafety.js";
|
|
3
|
+
import { evaluateFakeSide } from "../warmIndexReuse/agentEvaluation.js";
|
|
4
|
+
import { taskOutputSegment } from "../warmIndexReuse/selection.js";
|
|
5
|
+
import { toCorrectnessEvidence } from "./successEvidence.js";
|
|
6
|
+
/**
|
|
7
|
+
* Reuses the single existing fake-agent pipeline (prompt owner, fake agent, parseAgentAnswer,
|
|
8
|
+
* classifyAgentRunOutcome, scoreCorrectness) owned by warm-index agent evaluation. The pipeline
|
|
9
|
+
* derives its prompt from the case and never receives a budget, so the result is identical for
|
|
10
|
+
* every budget the treatment context fits.
|
|
11
|
+
*/
|
|
12
|
+
export const evaluateTreatmentWithFakeAgent = async (args) => {
|
|
13
|
+
const side = await evaluateFakeSide({
|
|
14
|
+
evaluationCase: args.evaluationCase,
|
|
15
|
+
caseId: args.evaluationCase.id,
|
|
16
|
+
// The shared pipeline's side ids map to prompt strategies; the guided treatment uses the
|
|
17
|
+
// my-dev-kit-guided strategy. The side id is internal and is not persisted as a variant.
|
|
18
|
+
variantId: args.treatment === "raw-full-file" ? "raw-full-file" : "warm-index-reuse",
|
|
19
|
+
projectProfiles: args.projectProfiles,
|
|
20
|
+
outDir: resolveWithinRoot(args.outputRoot, path.join("agents", taskOutputSegment(args.evaluationCase.id), args.treatment)),
|
|
21
|
+
cwd: args.cwd,
|
|
22
|
+
env: args.env,
|
|
23
|
+
});
|
|
24
|
+
return {
|
|
25
|
+
agentId: "fake-agent",
|
|
26
|
+
agentStatus: side.status,
|
|
27
|
+
correctness: toCorrectnessEvidence({
|
|
28
|
+
available: side.correctness.available,
|
|
29
|
+
score: side.correctness.score,
|
|
30
|
+
passed: side.correctness.passed,
|
|
31
|
+
}),
|
|
32
|
+
failureReasons: [...side.correctness.failureReasons],
|
|
33
|
+
warnings: [...side.warnings],
|
|
34
|
+
errors: [...side.errors],
|
|
35
|
+
};
|
|
36
|
+
};
|
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
import path from "node:path";
|
|
2
|
+
import { tokenCountMethod } from "../../../core/countTokens.js";
|
|
3
|
+
import { runMyDevKitRetrieval } from "../../../evaluation/runMyDevKitRetrieval.js";
|
|
4
|
+
import { runRawFullFileBaseline } from "../../../evaluation/runRawFullFileBaseline.js";
|
|
5
|
+
import { taskOutputSegment } from "../warmIndexReuse/selection.js";
|
|
6
|
+
import { evaluateTreatmentWithFakeAgent } from "./evaluation.js";
|
|
7
|
+
import { CONTEXT_WINDOW_SCALING_TREATMENT_IDS } from "./metadata.js";
|
|
8
|
+
import { computeRelevantFileEvidence } from "./relevantFiles.js";
|
|
9
|
+
import { buildBudgetCell, UNAVAILABLE_CORRECTNESS } from "./successEvidence.js";
|
|
10
|
+
export const defaultContextWindowScalingDependencies = {
|
|
11
|
+
constructRawContext: (evaluationCase) => runRawFullFileBaseline(evaluationCase),
|
|
12
|
+
constructGuidedContext: ({ evaluationCase, kitCommand, outputDir }) => runMyDevKitRetrieval({ evaluationCase, kitCommand, outputDir, requireKit: false }),
|
|
13
|
+
evaluateTreatment: evaluateTreatmentWithFakeAgent,
|
|
14
|
+
};
|
|
15
|
+
/**
|
|
16
|
+
* Per case: construct each treatment context once, then evaluate that one context against every
|
|
17
|
+
* budget. A deterministic evaluation runs at most once per treatment and is shared by the budgets
|
|
18
|
+
* the context fits. Nothing is truncated, retried, or rebuilt per budget.
|
|
19
|
+
*/
|
|
20
|
+
export async function executeContextWindowScalingCases(args) {
|
|
21
|
+
const deps = { ...defaultContextWindowScalingDependencies, ...args.dependencies };
|
|
22
|
+
const results = [];
|
|
23
|
+
for (const evaluationCase of args.cases) {
|
|
24
|
+
const treatments = [];
|
|
25
|
+
for (const variantId of CONTEXT_WINDOW_SCALING_TREATMENT_IDS) {
|
|
26
|
+
treatments.push(await executeTreatment({ ...args, evaluationCase, variantId, deps }));
|
|
27
|
+
}
|
|
28
|
+
results.push({
|
|
29
|
+
caseId: evaluationCase.id,
|
|
30
|
+
caseName: evaluationCase.title,
|
|
31
|
+
benchmarkProject: evaluationCase.benchmarkProject,
|
|
32
|
+
targetRoot: evaluationCase.targetRoot,
|
|
33
|
+
taskLocality: evaluationCase.taskLocality ?? null,
|
|
34
|
+
treatments,
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
return results;
|
|
38
|
+
}
|
|
39
|
+
async function executeTreatment(args) {
|
|
40
|
+
const { evaluationCase, variantId, deps } = args;
|
|
41
|
+
const constructed = await constructContext(args);
|
|
42
|
+
const tokens = constructed.context.estimatedTokens;
|
|
43
|
+
const expectedFiles = evaluationCase.answerKey?.expectedFiles ?? evaluationCase.expectedFiles;
|
|
44
|
+
const relevantFileEvidence = computeRelevantFileEvidence({
|
|
45
|
+
expectedFiles,
|
|
46
|
+
observedFiles: constructed.context.observedFiles,
|
|
47
|
+
});
|
|
48
|
+
let evaluation;
|
|
49
|
+
const anyFits = tokens !== null && args.contextBudgets.some((budget) => tokens <= budget);
|
|
50
|
+
if (tokens === null) {
|
|
51
|
+
evaluation = emptyEvaluation("unavailable", "Treatment context is unavailable.");
|
|
52
|
+
}
|
|
53
|
+
else if (!anyFits) {
|
|
54
|
+
evaluation = emptyEvaluation("not-evaluated-no-fitting-budget", "The context is too large for every selected budget.");
|
|
55
|
+
}
|
|
56
|
+
else {
|
|
57
|
+
evaluation = await evaluateOnce(args, deps);
|
|
58
|
+
}
|
|
59
|
+
const budgetCells = args.contextBudgets.map((contextBudgetTokens) => buildBudgetCell({
|
|
60
|
+
contextBudgetTokens,
|
|
61
|
+
contextEstimatedTokens: tokens,
|
|
62
|
+
shared: evaluation.status === "evaluated" || evaluation.status === "unavailable" ? evaluation.correctness : null,
|
|
63
|
+
}));
|
|
64
|
+
return {
|
|
65
|
+
variantId,
|
|
66
|
+
status: treatmentStatus(constructed, budgetCells.map((cell) => cell.contextFitStatus === "fits" && cell.evaluationStatus === "unavailable")),
|
|
67
|
+
context: constructed.context,
|
|
68
|
+
evaluation,
|
|
69
|
+
relevantFileEvidence,
|
|
70
|
+
budgetCells,
|
|
71
|
+
errors: constructed.error ? [constructed.error] : [],
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
async function evaluateOnce(args, deps) {
|
|
75
|
+
try {
|
|
76
|
+
const result = await deps.evaluateTreatment({
|
|
77
|
+
evaluationCase: args.evaluationCase,
|
|
78
|
+
treatment: args.variantId,
|
|
79
|
+
projectProfiles: args.projectProfiles,
|
|
80
|
+
outputRoot: args.outputRoot,
|
|
81
|
+
cwd: args.cwd,
|
|
82
|
+
env: args.env,
|
|
83
|
+
});
|
|
84
|
+
const available = result.correctness.availability === "available";
|
|
85
|
+
return {
|
|
86
|
+
status: available ? "evaluated" : "unavailable",
|
|
87
|
+
agentId: result.agentId,
|
|
88
|
+
agentStatus: result.agentStatus,
|
|
89
|
+
evaluationCount: 1,
|
|
90
|
+
correctness: result.correctness,
|
|
91
|
+
failureReasons: result.failureReasons,
|
|
92
|
+
warnings: [...result.warnings, ...result.errors],
|
|
93
|
+
reason: available ? null : `Deterministic evaluation was not scoreable (agent status ${result.agentStatus}).`,
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
catch (error) {
|
|
97
|
+
return {
|
|
98
|
+
...emptyEvaluation("unavailable", error instanceof Error ? error.message : String(error)),
|
|
99
|
+
evaluationCount: 1,
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
function emptyEvaluation(status, reason) {
|
|
104
|
+
return {
|
|
105
|
+
status,
|
|
106
|
+
agentId: null,
|
|
107
|
+
agentStatus: null,
|
|
108
|
+
evaluationCount: 0,
|
|
109
|
+
correctness: { ...UNAVAILABLE_CORRECTNESS },
|
|
110
|
+
failureReasons: [],
|
|
111
|
+
warnings: [],
|
|
112
|
+
reason,
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
function treatmentStatus(constructed, fittingCellUnavailable) {
|
|
116
|
+
if (constructed.error)
|
|
117
|
+
return "failed";
|
|
118
|
+
if (constructed.skipped)
|
|
119
|
+
return "skipped";
|
|
120
|
+
return fittingCellUnavailable.some(Boolean) ? "partial" : "completed";
|
|
121
|
+
}
|
|
122
|
+
async function constructContext(args) {
|
|
123
|
+
const { evaluationCase, variantId, deps } = args;
|
|
124
|
+
try {
|
|
125
|
+
if (variantId === "raw-full-file") {
|
|
126
|
+
const raw = await deps.constructRawContext(evaluationCase);
|
|
127
|
+
return {
|
|
128
|
+
skipped: false,
|
|
129
|
+
error: null,
|
|
130
|
+
context: {
|
|
131
|
+
status: "available",
|
|
132
|
+
characterCount: raw.totalChars,
|
|
133
|
+
estimatedTokens: raw.totalEstimatedTokens,
|
|
134
|
+
tokenCountMethod: raw.tokenCountMethod,
|
|
135
|
+
observedFiles: [...raw.filesIncluded],
|
|
136
|
+
warnings: [],
|
|
137
|
+
reason: null,
|
|
138
|
+
},
|
|
139
|
+
};
|
|
140
|
+
}
|
|
141
|
+
const guided = await deps.constructGuidedContext({
|
|
142
|
+
evaluationCase,
|
|
143
|
+
kitCommand: args.kitCommand,
|
|
144
|
+
outputDir: path.join(args.outputRoot, "guided", taskOutputSegment(evaluationCase.id)),
|
|
145
|
+
});
|
|
146
|
+
if (guided.skipped) {
|
|
147
|
+
return {
|
|
148
|
+
skipped: true,
|
|
149
|
+
error: null,
|
|
150
|
+
context: unavailableContext(guided.warnings, "my-dev-kit-guided retrieval was skipped and produced no context."),
|
|
151
|
+
};
|
|
152
|
+
}
|
|
153
|
+
return {
|
|
154
|
+
skipped: false,
|
|
155
|
+
error: null,
|
|
156
|
+
context: {
|
|
157
|
+
status: "available",
|
|
158
|
+
characterCount: guided.totalChars,
|
|
159
|
+
estimatedTokens: guided.totalEstimatedTokens,
|
|
160
|
+
tokenCountMethod: guided.tokenCountMethod,
|
|
161
|
+
observedFiles: [...guided.filesRead],
|
|
162
|
+
warnings: [...guided.warnings],
|
|
163
|
+
reason: null,
|
|
164
|
+
},
|
|
165
|
+
};
|
|
166
|
+
}
|
|
167
|
+
catch (error) {
|
|
168
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
169
|
+
return {
|
|
170
|
+
skipped: false,
|
|
171
|
+
error: { code: "context-construction-failed", message },
|
|
172
|
+
context: unavailableContext([], message),
|
|
173
|
+
};
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
function unavailableContext(warnings, reason) {
|
|
177
|
+
return {
|
|
178
|
+
status: "unavailable",
|
|
179
|
+
characterCount: null,
|
|
180
|
+
estimatedTokens: null,
|
|
181
|
+
tokenCountMethod: null,
|
|
182
|
+
observedFiles: null,
|
|
183
|
+
warnings: [...warnings],
|
|
184
|
+
reason,
|
|
185
|
+
};
|
|
186
|
+
}
|
|
187
|
+
export { tokenCountMethod as CONTEXT_WINDOW_SCALING_TOKEN_COUNT_METHOD };
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export const CONTEXT_WINDOW_SCALING_EXECUTION_ARTIFACT_FILE = "context-window-scaling-execution.json";
|
|
2
|
+
export const CONTEXT_WINDOW_SCALING_EXECUTION_SCHEMA_VERSION = "my-dev-kit-lab-context-window-scaling-execution-v1";
|
|
3
|
+
export function buildContextWindowScalingExecutionArtifact(args) {
|
|
4
|
+
return {
|
|
5
|
+
schemaVersion: CONTEXT_WINDOW_SCALING_EXECUTION_SCHEMA_VERSION,
|
|
6
|
+
runId: args.runId,
|
|
7
|
+
pluginId: args.pluginId,
|
|
8
|
+
pluginSchemaVersion: args.pluginSchemaVersion,
|
|
9
|
+
startedAt: args.startedAt,
|
|
10
|
+
completedAt: args.completedAt,
|
|
11
|
+
estimator: { tokenCountMethod: args.tokenCountMethod },
|
|
12
|
+
contextBudgets: [...args.contextBudgets],
|
|
13
|
+
cases: structuredClone([...args.cases]),
|
|
14
|
+
};
|
|
15
|
+
}
|
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
import { validateContextBudgets } from "./config.js";
|
|
2
|
+
import { CONTEXT_WINDOW_SCALING_EXECUTION_SCHEMA_VERSION, } from "./executionArtifact.js";
|
|
3
|
+
import { CONTEXT_WINDOW_SCALING_PLUGIN_ID, CONTEXT_WINDOW_SCALING_TREATMENT_IDS } from "./metadata.js";
|
|
4
|
+
const MAX_REPORTED_PROBLEMS = 8;
|
|
5
|
+
const RUN_STATUSES = ["completed", "partial", "failed", "skipped"];
|
|
6
|
+
const AVAILABILITY = ["available", "unavailable"];
|
|
7
|
+
const EVALUATION_STATUSES = ["evaluated", "not-evaluated-no-fitting-budget", "unavailable"];
|
|
8
|
+
const RELEVANT_STATUSES = ["available", "unavailable", "not-applicable"];
|
|
9
|
+
const FIT_STATUSES = ["fits", "context-too-large", "unavailable"];
|
|
10
|
+
const CELL_EVALUATION_STATUSES = ["evaluated", "not-evaluated-context-too-large", "unavailable"];
|
|
11
|
+
const SUCCESS_REASONS = ["correctness-pass", "correctness-fail", "context-too-large", "evaluation-unavailable", "context-unavailable"];
|
|
12
|
+
const isObj = (v) => typeof v === "object" && v !== null && !Array.isArray(v);
|
|
13
|
+
const isStr = (v) => typeof v === "string";
|
|
14
|
+
const isStrOrNull = (v) => v === null || typeof v === "string";
|
|
15
|
+
const isCount = (v) => typeof v === "number" && Number.isSafeInteger(v) && v >= 0;
|
|
16
|
+
const isCountOrNull = (v) => v === null || isCount(v);
|
|
17
|
+
const isNumOrNull = (v) => v === null || (typeof v === "number" && Number.isFinite(v));
|
|
18
|
+
const isStrArray = (v) => Array.isArray(v) && v.every((item) => typeof item === "string");
|
|
19
|
+
const isOneOf = (v, allowed) => typeof v === "string" && allowed.includes(v);
|
|
20
|
+
/**
|
|
21
|
+
* Structural validator for the persisted V1 execution artifact. It checks only what aggregation and
|
|
22
|
+
* plotting need (closed enums, types, budget/cell agreement); it never repairs or coerces values.
|
|
23
|
+
* Throws one Error listing bounded problems; returns the input, typed, when valid.
|
|
24
|
+
*/
|
|
25
|
+
export function parseContextWindowScalingExecutionArtifact(value) {
|
|
26
|
+
if (!isObj(value)) {
|
|
27
|
+
throw new Error("Invalid context-window-scaling execution artifact: expected a JSON object.");
|
|
28
|
+
}
|
|
29
|
+
if (value.schemaVersion !== CONTEXT_WINDOW_SCALING_EXECUTION_SCHEMA_VERSION) {
|
|
30
|
+
throw new Error(`Invalid context-window-scaling execution artifact: unsupported schemaVersion ${JSON.stringify(value.schemaVersion)}; expected ${CONTEXT_WINDOW_SCALING_EXECUTION_SCHEMA_VERSION}.`);
|
|
31
|
+
}
|
|
32
|
+
const problems = [];
|
|
33
|
+
const fail = (message) => {
|
|
34
|
+
problems.push(message);
|
|
35
|
+
};
|
|
36
|
+
const checkCorrectness = (correctness, at) => {
|
|
37
|
+
if (!isObj(correctness) ||
|
|
38
|
+
!isOneOf(correctness.availability, AVAILABILITY) ||
|
|
39
|
+
!isNumOrNull(correctness.score) ||
|
|
40
|
+
!(correctness.pass === null || typeof correctness.pass === "boolean")) {
|
|
41
|
+
fail(`${at} is malformed.`);
|
|
42
|
+
}
|
|
43
|
+
};
|
|
44
|
+
for (const field of ["runId", "pluginSchemaVersion", "startedAt", "completedAt"]) {
|
|
45
|
+
if (!isStr(value[field]))
|
|
46
|
+
fail(`${field} must be a string.`);
|
|
47
|
+
}
|
|
48
|
+
if (value.pluginId !== CONTEXT_WINDOW_SCALING_PLUGIN_ID)
|
|
49
|
+
fail(`pluginId must be ${CONTEXT_WINDOW_SCALING_PLUGIN_ID}.`);
|
|
50
|
+
if (!isObj(value.estimator) || !isStr(value.estimator.tokenCountMethod))
|
|
51
|
+
fail("estimator.tokenCountMethod must be a string.");
|
|
52
|
+
let budgets = [];
|
|
53
|
+
const budgetCheck = validateContextBudgets(value.contextBudgets);
|
|
54
|
+
if (budgetCheck.errors.length > 0) {
|
|
55
|
+
fail(`contextBudgets: ${budgetCheck.errors.join(" ")}`);
|
|
56
|
+
}
|
|
57
|
+
else if (budgetCheck.budgets.some((budget, index) => budget !== value.contextBudgets[index])) {
|
|
58
|
+
fail("contextBudgets must be in ascending order.");
|
|
59
|
+
}
|
|
60
|
+
else {
|
|
61
|
+
budgets = budgetCheck.budgets;
|
|
62
|
+
}
|
|
63
|
+
const cases = value.cases;
|
|
64
|
+
if (!Array.isArray(cases) || cases.length === 0) {
|
|
65
|
+
fail("cases must be a non-empty array.");
|
|
66
|
+
}
|
|
67
|
+
else {
|
|
68
|
+
cases.forEach((caseEvidence, caseIndex) => {
|
|
69
|
+
const at = `cases[${caseIndex}]`;
|
|
70
|
+
if (!isObj(caseEvidence))
|
|
71
|
+
return fail(`${at} must be an object.`);
|
|
72
|
+
for (const field of ["caseId", "caseName", "benchmarkProject", "targetRoot"]) {
|
|
73
|
+
if (!isStr(caseEvidence[field]))
|
|
74
|
+
fail(`${at}.${field} must be a string.`);
|
|
75
|
+
}
|
|
76
|
+
if (!isStrOrNull(caseEvidence.taskLocality))
|
|
77
|
+
fail(`${at}.taskLocality must be a string or null.`);
|
|
78
|
+
const treatments = caseEvidence.treatments;
|
|
79
|
+
if (!Array.isArray(treatments))
|
|
80
|
+
return fail(`${at}.treatments must be an array.`);
|
|
81
|
+
const ids = treatments.map((t) => (isObj(t) ? t.variantId : undefined));
|
|
82
|
+
if (ids.length !== CONTEXT_WINDOW_SCALING_TREATMENT_IDS.length ||
|
|
83
|
+
CONTEXT_WINDOW_SCALING_TREATMENT_IDS.some((id) => ids.filter((x) => x === id).length !== 1)) {
|
|
84
|
+
fail(`${at}.treatments must contain exactly ${CONTEXT_WINDOW_SCALING_TREATMENT_IDS.join(" and ")}.`);
|
|
85
|
+
}
|
|
86
|
+
treatments.forEach((treatment, treatmentIndex) => {
|
|
87
|
+
const tat = `${at}.treatments[${treatmentIndex}]`;
|
|
88
|
+
if (!isObj(treatment))
|
|
89
|
+
return fail(`${tat} must be an object.`);
|
|
90
|
+
if (!isOneOf(treatment.status, RUN_STATUSES))
|
|
91
|
+
fail(`${tat}.status is not a known status.`);
|
|
92
|
+
const context = treatment.context;
|
|
93
|
+
if (!isObj(context)) {
|
|
94
|
+
fail(`${tat}.context must be an object.`);
|
|
95
|
+
}
|
|
96
|
+
else {
|
|
97
|
+
if (!isOneOf(context.status, AVAILABILITY))
|
|
98
|
+
fail(`${tat}.context.status is not a known status.`);
|
|
99
|
+
if (!isCountOrNull(context.characterCount) || !isCountOrNull(context.estimatedTokens)) {
|
|
100
|
+
fail(`${tat}.context counts must be nonnegative integers or null.`);
|
|
101
|
+
}
|
|
102
|
+
if (!isStrOrNull(context.tokenCountMethod) || !isStrOrNull(context.reason))
|
|
103
|
+
fail(`${tat}.context strings must be strings or null.`);
|
|
104
|
+
if (!(context.observedFiles === null || isStrArray(context.observedFiles)) || !isStrArray(context.warnings)) {
|
|
105
|
+
fail(`${tat}.context file/warning lists are malformed.`);
|
|
106
|
+
}
|
|
107
|
+
if (context.status === "available" && context.estimatedTokens === null)
|
|
108
|
+
fail(`${tat}.context is available without estimatedTokens.`);
|
|
109
|
+
}
|
|
110
|
+
const evaluation = treatment.evaluation;
|
|
111
|
+
if (!isObj(evaluation)) {
|
|
112
|
+
fail(`${tat}.evaluation must be an object.`);
|
|
113
|
+
}
|
|
114
|
+
else {
|
|
115
|
+
if (!isOneOf(evaluation.status, EVALUATION_STATUSES))
|
|
116
|
+
fail(`${tat}.evaluation.status is not a known status.`);
|
|
117
|
+
if (!(evaluation.agentId === null || evaluation.agentId === "fake-agent"))
|
|
118
|
+
fail(`${tat}.evaluation.agentId must be fake-agent or null.`);
|
|
119
|
+
if (!isStrOrNull(evaluation.agentStatus) || !isStrOrNull(evaluation.reason))
|
|
120
|
+
fail(`${tat}.evaluation strings must be strings or null.`);
|
|
121
|
+
if (!isCount(evaluation.evaluationCount))
|
|
122
|
+
fail(`${tat}.evaluation.evaluationCount must be a nonnegative integer.`);
|
|
123
|
+
if (!isStrArray(evaluation.failureReasons) || !isStrArray(evaluation.warnings))
|
|
124
|
+
fail(`${tat}.evaluation lists must be string arrays.`);
|
|
125
|
+
checkCorrectness(evaluation.correctness, `${tat}.evaluation.correctness`);
|
|
126
|
+
}
|
|
127
|
+
const relevant = treatment.relevantFileEvidence;
|
|
128
|
+
if (!isObj(relevant)) {
|
|
129
|
+
fail(`${tat}.relevantFileEvidence must be an object.`);
|
|
130
|
+
}
|
|
131
|
+
else {
|
|
132
|
+
if (!isOneOf(relevant.status, RELEVANT_STATUSES))
|
|
133
|
+
fail(`${tat}.relevantFileEvidence.status is not a known status.`);
|
|
134
|
+
if (!isStrArray(relevant.expectedRelevantFiles) || !isStrArray(relevant.omittedRelevantFiles)) {
|
|
135
|
+
fail(`${tat}.relevantFileEvidence file lists must be string arrays.`);
|
|
136
|
+
}
|
|
137
|
+
if (!isCount(relevant.expectedRelevantFileCount))
|
|
138
|
+
fail(`${tat}.relevantFileEvidence.expectedRelevantFileCount must be a nonnegative integer.`);
|
|
139
|
+
if (!isCountOrNull(relevant.observedExpectedFileCount) || !isCountOrNull(relevant.omittedRelevantFileCount)) {
|
|
140
|
+
fail(`${tat}.relevantFileEvidence counts must be nonnegative integers or null.`);
|
|
141
|
+
}
|
|
142
|
+
if (!isStrOrNull(relevant.reason))
|
|
143
|
+
fail(`${tat}.relevantFileEvidence.reason must be a string or null.`);
|
|
144
|
+
}
|
|
145
|
+
const cells = treatment.budgetCells;
|
|
146
|
+
if (!Array.isArray(cells)) {
|
|
147
|
+
fail(`${tat}.budgetCells must be an array.`);
|
|
148
|
+
}
|
|
149
|
+
else {
|
|
150
|
+
const cellBudgets = cells.map((cell) => (isObj(cell) ? cell.contextBudgetTokens : undefined));
|
|
151
|
+
if (budgets.length > 0 && (cells.length !== budgets.length || budgets.some((b) => cellBudgets.filter((x) => x === b).length !== 1))) {
|
|
152
|
+
fail(`${tat}.budgetCells do not match contextBudgets.`);
|
|
153
|
+
}
|
|
154
|
+
cells.forEach((cell, cellIndex) => {
|
|
155
|
+
const cat = `${tat}.budgetCells[${cellIndex}]`;
|
|
156
|
+
if (!isObj(cell))
|
|
157
|
+
return fail(`${cat} must be an object.`);
|
|
158
|
+
if (!isOneOf(cell.contextFitStatus, FIT_STATUSES))
|
|
159
|
+
fail(`${cat}.contextFitStatus is not a known status.`);
|
|
160
|
+
if (!isNumOrNull(cell.contextBudgetUtilizationPercent))
|
|
161
|
+
fail(`${cat}.contextBudgetUtilizationPercent must be a number or null.`);
|
|
162
|
+
if (!isOneOf(cell.evaluationStatus, CELL_EVALUATION_STATUSES))
|
|
163
|
+
fail(`${cat}.evaluationStatus is not a known status.`);
|
|
164
|
+
checkCorrectness(cell.correctness, `${cat}.correctness`);
|
|
165
|
+
const success = cell.successEvidence;
|
|
166
|
+
if (!isObj(success) ||
|
|
167
|
+
!isOneOf(success.status, AVAILABILITY) ||
|
|
168
|
+
!(success.success === null || typeof success.success === "boolean") ||
|
|
169
|
+
!isOneOf(success.reason, SUCCESS_REASONS)) {
|
|
170
|
+
fail(`${cat}.successEvidence is malformed.`);
|
|
171
|
+
}
|
|
172
|
+
});
|
|
173
|
+
}
|
|
174
|
+
if (!Array.isArray(treatment.errors) || !treatment.errors.every((e) => isObj(e) && isStr(e.code) && isStr(e.message))) {
|
|
175
|
+
fail(`${tat}.errors must be an array of { code, message }.`);
|
|
176
|
+
}
|
|
177
|
+
});
|
|
178
|
+
});
|
|
179
|
+
}
|
|
180
|
+
if (problems.length > 0) {
|
|
181
|
+
const shown = problems.slice(0, MAX_REPORTED_PROBLEMS);
|
|
182
|
+
const extra = problems.length - shown.length;
|
|
183
|
+
throw new Error(`Invalid context-window-scaling execution artifact: ${shown.join(" ")}${extra > 0 ? ` (${extra} more problem(s) omitted.)` : ""}`);
|
|
184
|
+
}
|
|
185
|
+
return value;
|
|
186
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export * from "./config.js";
|
|
2
|
+
export * from "./cliBudgets.js";
|
|
3
|
+
export * from "./contextBudget.js";
|
|
4
|
+
export * from "./evaluation.js";
|
|
5
|
+
export * from "./execution.js";
|
|
6
|
+
export * from "./executionArtifact.js";
|
|
7
|
+
export * from "./executionArtifactReader.js";
|
|
8
|
+
export * from "./metadata.js";
|
|
9
|
+
export * from "./metrics.js";
|
|
10
|
+
export * from "./plugin.js";
|
|
11
|
+
export * from "./projectProfile.js";
|
|
12
|
+
export * from "./relevantFiles.js";
|
|
13
|
+
export * from "./successEvidence.js";
|
|
14
|
+
export * from "./types.js";
|
|
15
|
+
export * from "./syntheticInputs.js";
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export const CONTEXT_WINDOW_SCALING_PLUGIN_ID = "context-window-scaling";
|
|
2
|
+
/** Stable strategy IDs shared with existing plugins; budget is never part of variant identity. */
|
|
3
|
+
export const CONTEXT_WINDOW_SCALING_TREATMENT_IDS = ["raw-full-file", "my-dev-kit-guided"];
|
|
4
|
+
export const contextWindowScalingMetadata = {
|
|
5
|
+
id: CONTEXT_WINDOW_SCALING_PLUGIN_ID,
|
|
6
|
+
name: "Context Window Scaling",
|
|
7
|
+
description: "Measure raw-full-file and my-dev-kit-guided strategies under increasing deterministic estimated-context-token budgets, over the bundled fixed scaling corpus or caller-supplied deterministic synthetic repositories (--synthetic-config).",
|
|
8
|
+
schemaVersion: "1.0.0",
|
|
9
|
+
status: "experimental",
|
|
10
|
+
supportedTargets: ["self"],
|
|
11
|
+
supportedOutputs: ["json", "text", "html", "plot"],
|
|
12
|
+
};
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
import { CONTEXT_WINDOW_SCALING_TREATMENT_IDS } from "./metadata.js";
|
|
2
|
+
export function aggregateContextWindowScaling(args) {
|
|
3
|
+
const budgets = [...args.contextBudgets].sort((a, b) => a - b);
|
|
4
|
+
const treatments = [...CONTEXT_WINDOW_SCALING_TREATMENT_IDS];
|
|
5
|
+
const treatmentsOf = (variantId) => args.cases.map((caseEvidence) => ({ caseEvidence, treatment: requireTreatment(caseEvidence, variantId, budgets) }));
|
|
6
|
+
const budgetTreatmentSummaries = [];
|
|
7
|
+
for (const contextBudgetTokens of budgets) {
|
|
8
|
+
for (const variantId of treatments) {
|
|
9
|
+
const cells = treatmentsOf(variantId).map(({ treatment }) => cellFor(treatment, contextBudgetTokens));
|
|
10
|
+
budgetTreatmentSummaries.push(summarizeCells(contextBudgetTokens, variantId, cells));
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
const caseTreatmentContextSummaries = args.cases.flatMap((caseEvidence) => treatments.map((variantId) => {
|
|
14
|
+
const treatment = requireTreatment(caseEvidence, variantId, budgets);
|
|
15
|
+
return {
|
|
16
|
+
caseId: caseEvidence.caseId,
|
|
17
|
+
caseName: caseEvidence.caseName,
|
|
18
|
+
variantId,
|
|
19
|
+
contextStatus: treatment.context.status,
|
|
20
|
+
characterCount: treatment.context.characterCount,
|
|
21
|
+
estimatedTokens: treatment.context.estimatedTokens,
|
|
22
|
+
tokenCountMethod: treatment.context.tokenCountMethod,
|
|
23
|
+
observedFileCount: treatment.context.observedFiles === null ? null : treatment.context.observedFiles.length,
|
|
24
|
+
relevantFileEvidence: structuredClone(treatment.relevantFileEvidence),
|
|
25
|
+
};
|
|
26
|
+
}));
|
|
27
|
+
const allCells = budgetTreatmentSummaries;
|
|
28
|
+
const relevant = caseTreatmentContextSummaries.map((summary) => summary.relevantFileEvidence);
|
|
29
|
+
const relevantCount = (status) => relevant.filter((evidence) => evidence.status === status).length;
|
|
30
|
+
const relevantFileSummary = {
|
|
31
|
+
relevantFileEvidenceAvailableCount: relevantCount("available"),
|
|
32
|
+
relevantFileEvidenceUnavailableCount: relevantCount("unavailable"),
|
|
33
|
+
relevantFileEvidenceNotApplicableCount: relevantCount("not-applicable"),
|
|
34
|
+
totalOmittedRelevantFileCount: relevant.reduce((sum, evidence) => sum + (evidence.omittedRelevantFileCount ?? 0), 0),
|
|
35
|
+
};
|
|
36
|
+
const sumOf = (pick) => allCells.reduce((sum, summary) => sum + pick(summary), 0);
|
|
37
|
+
const evaluatedBudgetCellCount = args.cases
|
|
38
|
+
.flatMap((caseEvidence) => caseEvidence.treatments)
|
|
39
|
+
.flatMap((treatment) => treatment.budgetCells)
|
|
40
|
+
.filter((cell) => cell.evaluationStatus === "evaluated").length;
|
|
41
|
+
return {
|
|
42
|
+
budgets,
|
|
43
|
+
treatments,
|
|
44
|
+
runSummary: {
|
|
45
|
+
caseCount: args.cases.length,
|
|
46
|
+
treatmentCount: treatments.length,
|
|
47
|
+
budgetCount: budgets.length,
|
|
48
|
+
totalBudgetCellCount: sumOf((s) => s.totalCellCount),
|
|
49
|
+
evaluatedBudgetCellCount,
|
|
50
|
+
contextTooLargeCellCount: sumOf((s) => s.contextTooLargeCount),
|
|
51
|
+
contextUnavailableCellCount: sumOf((s) => s.contextUnavailableCount),
|
|
52
|
+
correctnessAvailableCellCount: sumOf((s) => s.correctnessAvailableCount),
|
|
53
|
+
correctnessUnavailableCellCount: sumOf((s) => s.correctnessUnavailableCount),
|
|
54
|
+
successEvidenceAvailableCellCount: sumOf((s) => s.successEvidenceAvailableCount),
|
|
55
|
+
successEvidenceUnavailableCellCount: sumOf((s) => s.successEvidenceUnavailableCount),
|
|
56
|
+
relevantFileEvidenceAvailableTreatmentCount: relevantFileSummary.relevantFileEvidenceAvailableCount,
|
|
57
|
+
relevantFileEvidenceUnavailableTreatmentCount: relevantFileSummary.relevantFileEvidenceUnavailableCount,
|
|
58
|
+
relevantFileEvidenceNotApplicableTreatmentCount: relevantFileSummary.relevantFileEvidenceNotApplicableCount,
|
|
59
|
+
},
|
|
60
|
+
budgetTreatmentSummaries,
|
|
61
|
+
caseTreatmentContextSummaries,
|
|
62
|
+
relevantFileSummary,
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
function requireTreatment(caseEvidence, variantId, budgets) {
|
|
66
|
+
const matches = caseEvidence.treatments.filter((treatment) => treatment.variantId === variantId);
|
|
67
|
+
const treatment = matches[0];
|
|
68
|
+
if (matches.length !== 1 || !treatment) {
|
|
69
|
+
throw new Error(`Invalid context-window-scaling evidence: case ${caseEvidence.caseId} must have exactly one ${variantId} treatment.`);
|
|
70
|
+
}
|
|
71
|
+
const cellBudgets = treatment.budgetCells.map((cell) => cell.contextBudgetTokens);
|
|
72
|
+
if (cellBudgets.length !== budgets.length || budgets.some((budget) => cellBudgets.filter((value) => value === budget).length !== 1)) {
|
|
73
|
+
throw new Error(`Invalid context-window-scaling evidence: case ${caseEvidence.caseId} ${variantId} cells do not match the selected budgets.`);
|
|
74
|
+
}
|
|
75
|
+
return treatment;
|
|
76
|
+
}
|
|
77
|
+
function cellFor(treatment, budget) {
|
|
78
|
+
return treatment.budgetCells.find((cell) => cell.contextBudgetTokens === budget);
|
|
79
|
+
}
|
|
80
|
+
function isFiniteNumber(value) {
|
|
81
|
+
return typeof value === "number" && Number.isFinite(value);
|
|
82
|
+
}
|
|
83
|
+
function summarizeCells(contextBudgetTokens, variantId, cells) {
|
|
84
|
+
const fitCount = cells.filter((cell) => cell.contextFitStatus === "fits").length;
|
|
85
|
+
const contextTooLargeCount = cells.filter((cell) => cell.contextFitStatus === "context-too-large").length;
|
|
86
|
+
const contextUnavailableCount = cells.filter((cell) => cell.contextFitStatus === "unavailable").length;
|
|
87
|
+
const successAvailable = cells.filter((cell) => cell.successEvidence.status === "available");
|
|
88
|
+
const successfulCellCount = successAvailable.filter((cell) => cell.successEvidence.success === true).length;
|
|
89
|
+
const scores = cells
|
|
90
|
+
.filter((cell) => cell.correctness.availability === "available")
|
|
91
|
+
.map((cell) => cell.correctness.score)
|
|
92
|
+
.filter(isFiniteNumber);
|
|
93
|
+
const utilizations = cells.map((cell) => cell.contextBudgetUtilizationPercent).filter(isFiniteNumber);
|
|
94
|
+
const mean = (values) => (values.length === 0 ? null : values.reduce((sum, value) => sum + value, 0) / values.length);
|
|
95
|
+
return {
|
|
96
|
+
contextBudgetTokens,
|
|
97
|
+
variantId,
|
|
98
|
+
totalCellCount: cells.length,
|
|
99
|
+
contextMeasuredCount: fitCount + contextTooLargeCount,
|
|
100
|
+
fitCount,
|
|
101
|
+
contextTooLargeCount,
|
|
102
|
+
contextUnavailableCount,
|
|
103
|
+
successfulCellCount,
|
|
104
|
+
notSuccessfulCellCount: successAvailable.length - successfulCellCount,
|
|
105
|
+
successEvidenceAvailableCount: successAvailable.length,
|
|
106
|
+
successEvidenceUnavailableCount: cells.length - successAvailable.length,
|
|
107
|
+
successRatePercent: successAvailable.length === 0 ? null : (successfulCellCount / successAvailable.length) * 100,
|
|
108
|
+
correctnessAvailableCount: scores.length,
|
|
109
|
+
correctnessUnavailableCount: cells.length - scores.length,
|
|
110
|
+
meanCorrectnessScore: mean(scores),
|
|
111
|
+
utilizationAvailableCount: utilizations.length,
|
|
112
|
+
utilizationUnavailableCount: cells.length - utilizations.length,
|
|
113
|
+
meanContextBudgetUtilizationPercent: mean(utilizations),
|
|
114
|
+
minContextBudgetUtilizationPercent: utilizations.length === 0 ? null : Math.min(...utilizations),
|
|
115
|
+
maxContextBudgetUtilizationPercent: utilizations.length === 0 ? null : Math.max(...utilizations),
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
/** Run-level scalar metrics: one set per budget x treatment, scoped by variantId and budget-bearing ids. */
|
|
119
|
+
export function toAggregateExperimentMetrics(aggregate) {
|
|
120
|
+
const metrics = [
|
|
121
|
+
{ id: "context-window-scaling-case-count", name: "Context-window-scaling case count", value: aggregate.runSummary.caseCount, unit: "count" },
|
|
122
|
+
{ id: "context-window-scaling-budget-count", name: "Context budget count", value: aggregate.runSummary.budgetCount, unit: "count" },
|
|
123
|
+
];
|
|
124
|
+
for (const summary of aggregate.budgetTreatmentSummaries) {
|
|
125
|
+
const prefix = `context-budget-${summary.contextBudgetTokens}`;
|
|
126
|
+
const scoped = (suffix, name, value, unit, description) => ({
|
|
127
|
+
id: `${prefix}-${suffix}`,
|
|
128
|
+
name: `${name} (${summary.contextBudgetTokens} token budget)`,
|
|
129
|
+
value,
|
|
130
|
+
unit,
|
|
131
|
+
...(description ? { description } : {}),
|
|
132
|
+
variantId: summary.variantId,
|
|
133
|
+
});
|
|
134
|
+
metrics.push(scoped("fit-count", "Cases whose context fits", summary.fitCount, "count"), scoped("context-too-large-count", "Cases whose context is too large", summary.contextTooLargeCount, "count"), scoped("successful-cell-count", "Successful cells", summary.successfulCellCount, "count"), scoped("success-rate-percent", "Success rate", summary.successRatePercent, "percent", "Successful cells over success-evidence-available cells; null when none are available."), scoped("mean-correctness-score", "Mean correctness score", summary.meanCorrectnessScore, "score", "Mean of available existing correctness scores; unavailable correctness is excluded, not zero."), scoped("mean-context-budget-utilization-percent", "Mean context budget utilization", summary.meanContextBudgetUtilizationPercent, "percent", "Uncapped; may exceed 100."));
|
|
135
|
+
}
|
|
136
|
+
return metrics;
|
|
137
|
+
}
|
|
138
|
+
/** Per-outcome scalar metrics for one treatment, one set per budget cell. */
|
|
139
|
+
export function toOutcomeBudgetMetrics(treatment, caseId) {
|
|
140
|
+
return treatment.budgetCells.flatMap((cell) => {
|
|
141
|
+
const base = { variantId: treatment.variantId, caseId };
|
|
142
|
+
const prefix = `budget-${cell.contextBudgetTokens}`;
|
|
143
|
+
return [
|
|
144
|
+
{ id: `${prefix}-context-budget-utilization-percent`, name: `Context budget utilization (${cell.contextBudgetTokens})`, value: cell.contextBudgetUtilizationPercent, unit: "percent", ...base },
|
|
145
|
+
{ id: `${prefix}-correctness-score`, name: `Correctness score (${cell.contextBudgetTokens})`, value: cell.correctness.score, unit: "score", ...base },
|
|
146
|
+
{ id: `${prefix}-success`, name: `Success (${cell.contextBudgetTokens})`, value: cell.successEvidence.success, ...base },
|
|
147
|
+
];
|
|
148
|
+
});
|
|
149
|
+
}
|