stageflow 0.42.0 → 0.46.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/README.md +12 -3
- package/dist/agent/activity.d.ts +18 -0
- package/dist/agent/claudeAdapter.js +7 -0
- package/dist/agent/claudeTools.d.ts +27 -18
- package/dist/agent/claudeTools.js +54 -15
- package/dist/agent/compactionEvents.d.ts +34 -0
- package/dist/agent/compactionEvents.js +37 -0
- package/dist/agent/openRouterRouting.d.ts +7 -0
- package/dist/agent/openRouterRouting.js +23 -0
- package/dist/agent/piAdapter.d.ts +6 -0
- package/dist/agent/piAdapter.js +128 -27
- package/dist/agent/piSettings.d.ts +7 -0
- package/dist/agent/piSettings.js +9 -0
- package/dist/agent/sandboxPiTools.d.ts +3 -1
- package/dist/agent/sandboxPiTools.js +8 -2
- package/dist/agent/stageTurnDriver.d.ts +11 -2
- package/dist/agent/stageTurnDriver.js +45 -4
- package/dist/agent/toolOutputBudget.d.ts +15 -1
- package/dist/agent/toolOutputBudget.js +18 -0
- package/dist/agent/toolOutputBudgetExtension.d.ts +2 -0
- package/dist/agent/toolOutputBudgetExtension.js +40 -3
- package/dist/agents/authorChat.d.ts +1 -0
- package/dist/agents/authorChat.js +7 -0
- package/dist/agents/authorSessionStore.d.ts +3 -0
- package/dist/agents/authorSessionStore.js +17 -2
- package/dist/agents/evalGate.js +1 -0
- package/dist/agents/hostContext.d.ts +1 -1
- package/dist/agents/runtime/piRuntime.d.ts +5 -1
- package/dist/agents/runtime/piRuntime.js +46 -12
- package/dist/agents/service.js +3 -2
- package/dist/agents/sessions.js +3 -1
- package/dist/cli/evalCommand.d.ts +1 -1
- package/dist/cli/evalCommand.js +39 -2
- package/dist/cli/hostClient.d.ts +6 -0
- package/dist/cli/hostClient.js +4 -0
- package/dist/compaction/directives.d.ts +18 -0
- package/dist/compaction/directives.js +119 -0
- package/dist/compaction/extension.d.ts +20 -0
- package/dist/compaction/extension.js +78 -0
- package/dist/compaction/mask.d.ts +18 -0
- package/dist/compaction/mask.js +155 -0
- package/dist/compaction/pin.d.ts +21 -0
- package/dist/compaction/pin.js +270 -0
- package/dist/compaction/scrub.d.ts +7 -0
- package/dist/compaction/scrub.js +26 -0
- package/dist/compaction/sessionWiring.d.ts +22 -0
- package/dist/compaction/sessionWiring.js +26 -0
- package/dist/compaction/summarize.d.ts +79 -0
- package/dist/compaction/summarize.js +171 -0
- package/dist/compaction/toolPolicy.d.ts +3 -0
- package/dist/compaction/toolPolicy.js +33 -0
- package/dist/compaction/types.d.ts +45 -0
- package/dist/compaction/types.js +7 -0
- package/dist/compaction/workingState.d.ts +56 -0
- package/dist/compaction/workingState.js +198 -0
- package/dist/config/createPipeline.js +2 -0
- package/dist/config/createTrigger.js +7 -1
- package/dist/config/ensureCatalogScanRoot.d.ts +2 -0
- package/dist/config/ensureCatalogScanRoot.js +6 -0
- package/dist/config/evalCatalog.js +30 -2
- package/dist/config/githubTriggerAction.d.ts +8 -0
- package/dist/config/githubTriggerAction.js +29 -0
- package/dist/config/hostConfig.js +2 -0
- package/dist/config/loadEval.d.ts +3 -1
- package/dist/config/loadEval.js +96 -10
- package/dist/config/pipelineNeeds.d.ts +2 -0
- package/dist/config/pipelineNeeds.js +16 -3
- package/dist/config/pipelineRoute.js +5 -4
- package/dist/config/validateCatalog.d.ts +1 -1
- package/dist/config/validateCatalog.js +12 -0
- package/dist/config/validateEval.js +60 -3
- package/dist/config/writeEval.js +2 -2
- package/dist/envelope/assertEmittedArtifacts.d.ts +12 -0
- package/dist/envelope/assertEmittedArtifacts.js +43 -0
- package/dist/envelope/preEmitChecks.d.ts +3 -0
- package/dist/evals/calibration.d.ts +21 -0
- package/dist/evals/calibration.js +69 -0
- package/dist/evals/calibrationSuggest.d.ts +29 -0
- package/dist/evals/calibrationSuggest.js +72 -0
- package/dist/evals/calibrator.d.ts +46 -0
- package/dist/evals/calibrator.js +148 -0
- package/dist/evals/compare.d.ts +1 -1
- package/dist/evals/compare.js +3 -0
- package/dist/evals/constants.d.ts +7 -3
- package/dist/evals/constants.js +7 -1
- package/dist/evals/engine/FakeEngine.d.ts +2 -1
- package/dist/evals/engine/FakeEngine.js +9 -3
- package/dist/evals/engine/promptfoo/PromptfooEngine.d.ts +1 -1
- package/dist/evals/engine/promptfoo/PromptfooEngine.js +4 -2
- package/dist/evals/engine/promptfoo/generate.d.ts +3 -1
- package/dist/evals/engine/promptfoo/generate.js +43 -23
- package/dist/evals/engine/promptfoo/judgeProviders.js +2 -1
- package/dist/evals/engine/promptfoo/normalize.d.ts +4 -1
- package/dist/evals/engine/promptfoo/normalize.js +16 -3
- package/dist/evals/engine/promptfoo/rubricPrompt.d.ts +3 -1
- package/dist/evals/engine/promptfoo/rubricPrompt.js +15 -5
- package/dist/evals/errors.d.ts +7 -0
- package/dist/evals/errors.js +10 -0
- package/dist/evals/judgeProviders.d.ts +6 -0
- package/dist/evals/judgeProviders.js +14 -0
- package/dist/evals/judged.d.ts +7 -0
- package/dist/evals/judged.js +7 -0
- package/dist/evals/manager.d.ts +27 -8
- package/dist/evals/manager.js +73 -12
- package/dist/evals/plan.d.ts +10 -1
- package/dist/evals/plan.js +33 -13
- package/dist/evals/planInternalAgent.d.ts +19 -0
- package/dist/evals/planInternalAgent.js +201 -0
- package/dist/evals/read/api.d.ts +18 -0
- package/dist/evals/read/api.js +10 -1
- package/dist/evals/read/labelQueue.d.ts +45 -0
- package/dist/evals/read/labelQueue.js +83 -0
- package/dist/evals/read/list.js +10 -1
- package/dist/evals/read/runs.d.ts +5 -0
- package/dist/evals/read/runs.js +7 -1
- package/dist/evals/runner/caseRunner.d.ts +2 -1
- package/dist/evals/runner/caseRunner.js +16 -5
- package/dist/evals/runner/internalAgentCaseRunner.d.ts +6 -0
- package/dist/evals/runner/internalAgentCaseRunner.js +250 -0
- package/dist/evals/snapshot.d.ts +10 -2
- package/dist/evals/snapshot.js +8 -3
- package/dist/evals/stats.d.ts +40 -0
- package/dist/evals/stats.js +69 -0
- package/dist/evals/storeTypes.d.ts +42 -0
- package/dist/evals/types.d.ts +25 -2
- package/dist/evals/types.js +4 -1
- package/dist/evals/votes.d.ts +10 -0
- package/dist/evals/votes.js +60 -0
- package/dist/guide/cardContract.d.ts +133 -0
- package/dist/guide/cardContract.js +156 -0
- package/dist/guide/chat.d.ts +45 -0
- package/dist/guide/chat.js +378 -0
- package/dist/guide/knowledge/index.d.ts +14 -0
- package/dist/guide/knowledge/index.js +109 -0
- package/dist/guide/knowledge/topics/agents.d.ts +2 -0
- package/dist/guide/knowledge/topics/agents.js +58 -0
- package/dist/guide/knowledge/topics/bestPractices.d.ts +2 -0
- package/dist/guide/knowledge/topics/bestPractices.js +67 -0
- package/dist/guide/knowledge/topics/connections.d.ts +2 -0
- package/dist/guide/knowledge/topics/connections.js +66 -0
- package/dist/guide/knowledge/topics/consoleMap.d.ts +2 -0
- package/dist/guide/knowledge/topics/consoleMap.js +55 -0
- package/dist/guide/knowledge/topics/evals.d.ts +2 -0
- package/dist/guide/knowledge/topics/evals.js +72 -0
- package/dist/guide/knowledge/topics/limitations.d.ts +2 -0
- package/dist/guide/knowledge/topics/limitations.js +84 -0
- package/dist/guide/knowledge/topics/mcpSkillsBrowser.d.ts +2 -0
- package/dist/guide/knowledge/topics/mcpSkillsBrowser.js +57 -0
- package/dist/guide/knowledge/topics/memories.d.ts +2 -0
- package/dist/guide/knowledge/topics/memories.js +63 -0
- package/dist/guide/knowledge/topics/modelsAndProviders.d.ts +2 -0
- package/dist/guide/knowledge/topics/modelsAndProviders.js +56 -0
- package/dist/guide/knowledge/topics/overview.d.ts +2 -0
- package/dist/guide/knowledge/topics/overview.js +56 -0
- package/dist/guide/knowledge/topics/pipelines.d.ts +2 -0
- package/dist/guide/knowledge/topics/pipelines.js +93 -0
- package/dist/guide/knowledge/topics/stages.d.ts +2 -0
- package/dist/guide/knowledge/topics/stages.js +54 -0
- package/dist/guide/knowledge/topics/tasks.d.ts +2 -0
- package/dist/guide/knowledge/topics/tasks.js +52 -0
- package/dist/guide/knowledge/topics/triggers.d.ts +2 -0
- package/dist/guide/knowledge/topics/triggers.js +68 -0
- package/dist/guide/knowledge/topics/troubleshooting.d.ts +2 -0
- package/dist/guide/knowledge/topics/troubleshooting.js +85 -0
- package/dist/guide/knowledgeTools.d.ts +2 -0
- package/dist/guide/knowledgeTools.js +56 -0
- package/dist/guide/showUi.d.ts +6 -0
- package/dist/guide/showUi.js +546 -0
- package/dist/guide/threadStore.d.ts +48 -0
- package/dist/guide/threadStore.js +189 -0
- package/dist/guide/writeRoot.d.ts +11 -0
- package/dist/guide/writeRoot.js +70 -0
- package/dist/hosted/translate.js +2 -0
- package/dist/mcp/agentTools.js +12 -0
- package/dist/mcp/catalogTools.js +18 -20
- package/dist/mcp/catalogWriteTools.d.ts +8 -0
- package/dist/mcp/catalogWriteTools.js +225 -0
- package/dist/mcp/connectionTools.d.ts +3 -0
- package/dist/mcp/connectionTools.js +85 -0
- package/dist/mcp/controlTools.js +34 -1
- package/dist/mcp/deps.d.ts +9 -0
- package/dist/mcp/evalTools.js +723 -21
- package/dist/mcp/memoryHostTools.d.ts +3 -0
- package/dist/mcp/memoryHostTools.js +72 -0
- package/dist/mcp/pipelineAuthorTools.js +14 -1
- package/dist/mcp/server.js +5 -0
- package/dist/mcp/tools.js +6 -0
- package/dist/mcp/triggerTools.js +77 -31
- package/dist/operatorAgent/evalGate.d.ts +22 -0
- package/dist/operatorAgent/evalGate.js +77 -0
- package/dist/operatorAgent/fakeHost.js +10 -2
- package/dist/operatorAgent/host.js +18 -2
- package/dist/operatorAgent/index.d.ts +1 -0
- package/dist/operatorAgent/index.js +1 -0
- package/dist/operatorAgent/internalAgents.d.ts +11 -0
- package/dist/operatorAgent/internalAgents.js +13 -0
- package/dist/operatorAgent/piModel.d.ts +5 -1
- package/dist/operatorAgent/piModel.js +15 -10
- package/dist/operatorAgent/profiles/agentAuthor.js +66 -22
- package/dist/operatorAgent/profiles/agentAuthorPlaybook.d.ts +1 -1
- package/dist/operatorAgent/profiles/agentAuthorPlaybook.js +1 -1
- package/dist/operatorAgent/profiles/guideConfirm.d.ts +21 -0
- package/dist/operatorAgent/profiles/guideConfirm.js +100 -0
- package/dist/operatorAgent/profiles/guideTools.d.ts +7 -0
- package/dist/operatorAgent/profiles/guideTools.js +123 -0
- package/dist/operatorAgent/profiles/stageflowGuide.d.ts +7 -0
- package/dist/operatorAgent/profiles/stageflowGuide.js +133 -0
- package/dist/operatorAgent/profiles/workshopAuthor.js +23 -0
- package/dist/operatorAgent/profiles/workshopAuthorPlaybook.d.ts +1 -1
- package/dist/operatorAgent/profiles/workshopAuthorPlaybook.js +9 -1
- package/dist/operatorAgent/profiles/workshopAuthorTools.d.ts +2 -0
- package/dist/operatorAgent/profiles/workshopAuthorTools.js +197 -9
- package/dist/operatorAgent/types.d.ts +23 -0
- package/dist/package-meta.d.ts +1 -1
- package/dist/package-meta.js +1 -1
- package/dist/runstore/port.d.ts +13 -1
- package/dist/runstore/retention.d.ts +2 -1
- package/dist/runstore/retention.js +3 -7
- package/dist/runstore/runStatusClock.d.ts +17 -0
- package/dist/runstore/runStatusClock.js +19 -0
- package/dist/runstore/sqlite/SqliteRunStore.d.ts +11 -1
- package/dist/runstore/sqlite/SqliteRunStore.js +70 -45
- package/dist/runstore/sqlite/calibrationStore.d.ts +10 -0
- package/dist/runstore/sqlite/calibrationStore.js +106 -0
- package/dist/runstore/sqlite/evalStore.d.ts +5 -0
- package/dist/runstore/sqlite/evalStore.js +7 -0
- package/dist/runstore/sqlite/migrations/018-eval-grader-labels.d.ts +11 -0
- package/dist/runstore/sqlite/migrations/018-eval-grader-labels.js +43 -0
- package/dist/runstore/sqlite/migrations/index.js +2 -0
- package/dist/runstore/workspaceLayout.js +6 -1
- package/dist/runtime/artifactDiskInspect.d.ts +14 -0
- package/dist/runtime/artifactDiskInspect.js +52 -0
- package/dist/runtime/artifactPath.d.ts +24 -0
- package/dist/runtime/artifactPath.js +84 -0
- package/dist/runtime/completionCheckRunner.js +15 -43
- package/dist/runtime/githubPollSource.d.ts +22 -4
- package/dist/runtime/githubPollSource.js +93 -8
- package/dist/runtime/priorArtifactGrants.d.ts +8 -0
- package/dist/runtime/priorArtifactGrants.js +105 -0
- package/dist/runtime/runActionEligibility.d.ts +46 -0
- package/dist/runtime/runActionEligibility.js +123 -0
- package/dist/runtime/runManager.d.ts +4 -1
- package/dist/runtime/runManager.js +52 -10
- package/dist/runtime/runRetryCoordinator.d.ts +2 -14
- package/dist/runtime/runRetryCoordinator.js +3 -67
- package/dist/runtime/sandboxContainer.d.ts +7 -0
- package/dist/runtime/sandboxContainer.js +48 -6
- package/dist/runtime/sandboxDesk.d.ts +2 -1
- package/dist/runtime/sandboxDesk.js +11 -12
- package/dist/runtime/stageEnvironment.js +1 -0
- package/dist/runtime/stageRoots.d.ts +12 -0
- package/dist/runtime/stageSandbox.d.ts +2 -1
- package/dist/runtime/stageSandbox.js +18 -2
- package/dist/runtime/stageWorker.js +20 -0
- package/dist/server/agentAuthorRoutes.js +12 -3
- package/dist/server/bootstrap.d.ts +5 -0
- package/dist/server/bootstrap.js +14 -1
- package/dist/server/evalRoutes.js +251 -12
- package/dist/server/guideRoutes.d.ts +5 -0
- package/dist/server/guideRoutes.js +166 -0
- package/dist/server/http.d.ts +10 -0
- package/dist/server/http.js +35 -1
- package/dist/server/internalAgentRoutes.d.ts +6 -0
- package/dist/server/internalAgentRoutes.js +12 -0
- package/dist/server/mcpHost.js +2 -0
- package/dist/toolkit/meta.d.ts +1 -1
- package/dist/toolkit/meta.js +41 -1
- package/dist/toolkit/profiles.d.ts +5 -0
- package/dist/toolkit/profiles.js +12 -0
- package/dist/tools/askOperator.js +2 -1
- package/dist/tools/emitStageEnvelope.d.ts +17 -16
- package/dist/tools/emitStageEnvelope.js +46 -32
- package/dist/tools/stageToolNames.d.ts +4 -0
- package/dist/tools/stageToolNames.js +4 -0
- package/dist/tools/workingState.d.ts +40 -0
- package/dist/tools/workingState.js +108 -0
- package/dist/tools/writeStageArtifact.d.ts +0 -9
- package/dist/tools/writeStageArtifact.js +2 -1
- package/dist/ui/assets/{MarkdownText-BTrOqu5J.js → MarkdownText-BS2BBbCx.js} +2 -2
- package/dist/ui/assets/adapters-DPD-cAsy.js +17 -0
- package/dist/ui/assets/chat-BD1-VTT6.js +2 -0
- package/dist/ui/assets/chat-DXnQv9st.css +2 -0
- package/dist/ui/assets/main-AX5XNLtX.js +278 -0
- package/dist/ui/assets/{main-CHlmTNJe.css → main-CFX0_n8J.css} +1 -1
- package/dist/ui/chat.html +3 -4
- package/dist/ui/index.html +3 -4
- package/dist/workshop/chatTurn.js +1 -1
- package/dist/workshop/workshopPin.d.ts +3 -3
- package/dist/workshop/workshopPin.js +16 -15
- package/examples/compaction-stress/README.md +30 -0
- package/examples/compaction-stress/check-run.mjs +53 -0
- package/examples/compaction-stress/collect-evidence.yaml +60 -0
- package/examples/compaction-stress/compaction-stress.pipeline.yaml +141 -0
- package/examples/compaction-stress/compaction-stress.task.yaml +15 -0
- package/examples/compaction-stress/generate-evidence.mjs +110 -0
- package/examples/compaction-stress/root-cause.yaml +26 -0
- package/examples/compaction-stress/stageflow.yaml +9 -0
- package/examples/compaction-stress/write-postmortem.yaml +40 -0
- package/examples/evals/README.md +18 -0
- package/examples/evals/guide-behavior.dataset.jsonl +15 -0
- package/examples/evals/guide-behavior.eval.yaml +35 -0
- package/examples/evals/guide-depth.dataset.jsonl +35 -0
- package/examples/evals/guide-depth.eval.yaml +169 -0
- package/examples/memory/evals/guide-behavior.dataset.jsonl +15 -0
- package/examples/memory/evals/guide-behavior.eval.yaml +35 -0
- package/examples/memory/evals/guide-depth.dataset.jsonl +35 -0
- package/examples/memory/evals/guide-depth.eval.yaml +169 -0
- package/package.json +1 -1
- package/skills/stageflow/references/control-surface.md +1 -1
- package/skills/stageflow/references/evals.md +1 -0
- package/dist/ui/assets/AssistantRuntimeProvider-qIX1xNoH.js +0 -9
- package/dist/ui/assets/ReadonlyStore-BfXqHykm.js +0 -6
- package/dist/ui/assets/chat-Df_wCpak.js +0 -5
- package/dist/ui/assets/chat-P7KQznHm.css +0 -2
- package/dist/ui/assets/main-CvVfxmMd.js +0 -271
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { RunStore } from "../runstore/port.js";
|
|
2
|
+
import type { EvalCalibrationSplit, EvalGraderLabelRow } from "./storeTypes.js";
|
|
3
|
+
import type { CaseOutput } from "./types.js";
|
|
4
|
+
export type CalibrationSampleSource = {
|
|
5
|
+
caseId: string;
|
|
6
|
+
/** Position within the case's samples; the replay repeat index. */
|
|
7
|
+
repeatIndex: number;
|
|
8
|
+
label: "pass" | "fail";
|
|
9
|
+
output: CaseOutput;
|
|
10
|
+
originalRunId: string;
|
|
11
|
+
originalRepeatIndex: number;
|
|
12
|
+
};
|
|
13
|
+
export type CalibrationStore = Pick<RunStore, "listEvalGraderLabelsForEval" | "listEvalResults">;
|
|
14
|
+
/** Rebuilds the in-memory case output from the stored result JSON. */
|
|
15
|
+
export declare function replayOutput(stored: unknown): CaseOutput | null;
|
|
16
|
+
/**
|
|
17
|
+
* The labeled samples for one grader across every run of the eval: the newest label per identical
|
|
18
|
+
* (case, output), grouped per case with a fresh repeat index so the engine can replay them.
|
|
19
|
+
*/
|
|
20
|
+
export declare function collectCalibrationSamples(store: CalibrationStore, projectRoot: string, evalId: string, graderId: string, split: EvalCalibrationSplit): Promise<CalibrationSampleSource[]>;
|
|
21
|
+
export type { EvalGraderLabelRow };
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
2
|
+
import { calibrationSplitOf } from "./stats.js";
|
|
3
|
+
import { renderTranscript } from "./graders/transcript.js";
|
|
4
|
+
function outputKey(caseId, output) {
|
|
5
|
+
return createHash("sha256")
|
|
6
|
+
.update(caseId)
|
|
7
|
+
.update("\u0000")
|
|
8
|
+
.update(JSON.stringify(output ?? null))
|
|
9
|
+
.digest("hex");
|
|
10
|
+
}
|
|
11
|
+
/** Rebuilds the in-memory case output from the stored result JSON. */
|
|
12
|
+
export function replayOutput(stored) {
|
|
13
|
+
if (stored === null || typeof stored !== "object")
|
|
14
|
+
return null;
|
|
15
|
+
const o = stored;
|
|
16
|
+
if (o.kind === "conversation") {
|
|
17
|
+
const out = { ...o };
|
|
18
|
+
out.transcript = renderTranscript(out);
|
|
19
|
+
return out;
|
|
20
|
+
}
|
|
21
|
+
if (typeof o.status !== "string" || typeof o.summary !== "string")
|
|
22
|
+
return null;
|
|
23
|
+
return {
|
|
24
|
+
kind: "envelope",
|
|
25
|
+
status: o.status === "failure" ? "failure" : "success",
|
|
26
|
+
summary: o.summary,
|
|
27
|
+
...(o.payload !== undefined && typeof o.payload === "object" ? { payload: o.payload } : {}),
|
|
28
|
+
artifacts: Array.isArray(o.artifacts) ? o.artifacts : [],
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* The labeled samples for one grader across every run of the eval: the newest label per identical
|
|
33
|
+
* (case, output), grouped per case with a fresh repeat index so the engine can replay them.
|
|
34
|
+
*/
|
|
35
|
+
export async function collectCalibrationSamples(store, projectRoot, evalId, graderId, split) {
|
|
36
|
+
const labels = await store.listEvalGraderLabelsForEval(projectRoot, evalId, graderId);
|
|
37
|
+
const resultsByRun = new Map();
|
|
38
|
+
const seen = new Set();
|
|
39
|
+
const perCase = new Map();
|
|
40
|
+
const out = [];
|
|
41
|
+
for (const label of labels) {
|
|
42
|
+
if (split !== "all" && calibrationSplitOf(label.caseId) !== split)
|
|
43
|
+
continue;
|
|
44
|
+
let results = resultsByRun.get(label.evalRunId);
|
|
45
|
+
if (!results) {
|
|
46
|
+
results = new Map((await store.listEvalResults(label.evalRunId)).map((r) => [`${r.caseId}#${r.repeatIndex}`, r]));
|
|
47
|
+
resultsByRun.set(label.evalRunId, results);
|
|
48
|
+
}
|
|
49
|
+
const result = results.get(`${label.caseId}#${label.repeatIndex}`);
|
|
50
|
+
const output = result ? replayOutput(result.output) : null;
|
|
51
|
+
if (!output)
|
|
52
|
+
continue;
|
|
53
|
+
const key = outputKey(label.caseId, result?.output);
|
|
54
|
+
if (seen.has(key))
|
|
55
|
+
continue;
|
|
56
|
+
seen.add(key);
|
|
57
|
+
const repeatIndex = perCase.get(label.caseId) ?? 0;
|
|
58
|
+
perCase.set(label.caseId, repeatIndex + 1);
|
|
59
|
+
out.push({
|
|
60
|
+
caseId: label.caseId,
|
|
61
|
+
repeatIndex,
|
|
62
|
+
label: label.label,
|
|
63
|
+
output,
|
|
64
|
+
originalRunId: label.evalRunId,
|
|
65
|
+
originalRepeatIndex: label.repeatIndex,
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
return out;
|
|
69
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import type { RunStore } from "../runstore/port.js";
|
|
2
|
+
import type { EvalCalibrationRow } from "./storeTypes.js";
|
|
3
|
+
import type { CaseOutput, RubricExample } from "./types.js";
|
|
4
|
+
export declare const EXAMPLE_SUGGESTION_LIMIT = 3;
|
|
5
|
+
export type SuggestedExample = {
|
|
6
|
+
eval_run_id: string;
|
|
7
|
+
case_id: string;
|
|
8
|
+
repeat_index: number;
|
|
9
|
+
/** What the judge said, so the author can see why this example would help. */
|
|
10
|
+
judge: "pass" | "fail";
|
|
11
|
+
example: RubricExample;
|
|
12
|
+
};
|
|
13
|
+
export type SuggestStore = Pick<RunStore, "listEvalResults" | "listEvalGraderLabelsForEval">;
|
|
14
|
+
/** The text a judge example shows for one stored output. */
|
|
15
|
+
export declare function exampleOutputText(output: CaseOutput): string;
|
|
16
|
+
/**
|
|
17
|
+
* Up to three few-shot examples built from where the judge disagreed with the author on the dev split (a held-out row
|
|
18
|
+
* is never offered, so the held-out check stays a fair test): one of each kind of
|
|
19
|
+
* disagreement first (judge too lenient, judge too strict), distinct outputs only. The author's label note,
|
|
20
|
+
* when there is one, becomes the example's reason. Nothing is written.
|
|
21
|
+
*/
|
|
22
|
+
export declare function suggestExamples(store: SuggestStore, input: {
|
|
23
|
+
projectRoot: string;
|
|
24
|
+
evalId: string;
|
|
25
|
+
graderId: string;
|
|
26
|
+
scale: "pass_fail" | "1_to_5";
|
|
27
|
+
calibration: Pick<EvalCalibrationRow, "disagreements">;
|
|
28
|
+
limit?: number;
|
|
29
|
+
}): Promise<SuggestedExample[]>;
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { replayOutput } from "./calibration.js";
|
|
2
|
+
import { calibrationSplitOf } from "./stats.js";
|
|
3
|
+
export const EXAMPLE_SUGGESTION_LIMIT = 3;
|
|
4
|
+
const EXAMPLE_OUTPUT_MAX_CHARS = 1500;
|
|
5
|
+
function cut(text) {
|
|
6
|
+
return text.length <= EXAMPLE_OUTPUT_MAX_CHARS ? text : `${text.slice(0, EXAMPLE_OUTPUT_MAX_CHARS)}…`;
|
|
7
|
+
}
|
|
8
|
+
/** The text a judge example shows for one stored output. */
|
|
9
|
+
export function exampleOutputText(output) {
|
|
10
|
+
if (output.kind === "conversation")
|
|
11
|
+
return cut(output.transcript ?? output.final_reply);
|
|
12
|
+
const payload = output.payload === undefined ? "" : `\n${JSON.stringify(output.payload)}`;
|
|
13
|
+
return cut(`${output.summary}${payload}`);
|
|
14
|
+
}
|
|
15
|
+
function exampleFor(scale, label, output, reason) {
|
|
16
|
+
const base = { output, ...(reason !== undefined && reason !== "" ? { reason } : {}) };
|
|
17
|
+
if (scale === "pass_fail")
|
|
18
|
+
return { verdict: label, ...base };
|
|
19
|
+
return { score: label === "pass" ? 5 : 1, ...base };
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Up to three few-shot examples built from where the judge disagreed with the author on the dev split (a held-out row
|
|
23
|
+
* is never offered, so the held-out check stays a fair test): one of each kind of
|
|
24
|
+
* disagreement first (judge too lenient, judge too strict), distinct outputs only. The author's label note,
|
|
25
|
+
* when there is one, becomes the example's reason. Nothing is written.
|
|
26
|
+
*/
|
|
27
|
+
export async function suggestExamples(store, input) {
|
|
28
|
+
const limit = input.limit ?? EXAMPLE_SUGGESTION_LIMIT;
|
|
29
|
+
const labels = await store.listEvalGraderLabelsForEval(input.projectRoot, input.evalId, input.graderId);
|
|
30
|
+
const notes = new Map(labels.map((l) => [`${l.evalRunId}#${l.caseId}#${l.repeatIndex}`, l.note]));
|
|
31
|
+
const dev = input.calibration.disagreements.filter((d) => calibrationSplitOf(d.caseId) === "dev");
|
|
32
|
+
const lenient = dev.filter((d) => d.judge === "pass");
|
|
33
|
+
const strict = dev.filter((d) => d.judge === "fail");
|
|
34
|
+
const ordered = [];
|
|
35
|
+
for (let i = 0; ordered.length < lenient.length + strict.length; i++) {
|
|
36
|
+
if (lenient[i])
|
|
37
|
+
ordered.push(lenient[i]);
|
|
38
|
+
if (strict[i])
|
|
39
|
+
ordered.push(strict[i]);
|
|
40
|
+
}
|
|
41
|
+
const runs = new Map();
|
|
42
|
+
const seen = new Set();
|
|
43
|
+
const out = [];
|
|
44
|
+
for (const d of ordered) {
|
|
45
|
+
if (out.length >= limit)
|
|
46
|
+
break;
|
|
47
|
+
if (d.evalRunId === undefined)
|
|
48
|
+
continue;
|
|
49
|
+
let results = runs.get(d.evalRunId);
|
|
50
|
+
if (!results) {
|
|
51
|
+
results = await store.listEvalResults(d.evalRunId);
|
|
52
|
+
runs.set(d.evalRunId, results);
|
|
53
|
+
}
|
|
54
|
+
const result = results.find((r) => r.caseId === d.caseId && r.repeatIndex === d.repeatIndex);
|
|
55
|
+
const output = result ? replayOutput(result.output) : null;
|
|
56
|
+
if (!output)
|
|
57
|
+
continue;
|
|
58
|
+
const text = exampleOutputText(output);
|
|
59
|
+
if (seen.has(text))
|
|
60
|
+
continue;
|
|
61
|
+
seen.add(text);
|
|
62
|
+
const note = notes.get(`${d.evalRunId}#${d.caseId}#${d.repeatIndex}`) ?? undefined;
|
|
63
|
+
out.push({
|
|
64
|
+
eval_run_id: d.evalRunId,
|
|
65
|
+
case_id: d.caseId,
|
|
66
|
+
repeat_index: d.repeatIndex,
|
|
67
|
+
judge: d.judge,
|
|
68
|
+
example: exampleFor(input.scale, d.label, text, note),
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
return out;
|
|
72
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { type CalibrationStore } from "./calibration.js";
|
|
2
|
+
import type { JudgedGrader } from "./judged.js";
|
|
3
|
+
import { type CalibrationStats, type StabilityStats } from "./stats.js";
|
|
4
|
+
import type { EvalCalibrationDisagreement, EvalCalibrationRow, EvalCalibrationSplit } from "./storeTypes.js";
|
|
5
|
+
import type { EvalEngine, EvalPlan, JudgeSettings, RubricExample } from "./types.js";
|
|
6
|
+
import type { RunStore } from "../runstore/port.js";
|
|
7
|
+
export type CalibrateInput = {
|
|
8
|
+
projectRoot: string;
|
|
9
|
+
evalPath: string;
|
|
10
|
+
graderId: string;
|
|
11
|
+
split?: EvalCalibrationSplit;
|
|
12
|
+
/** A rubric to measure instead of the saved one; the result is stored as a candidate. */
|
|
13
|
+
candidate?: {
|
|
14
|
+
rubric?: string;
|
|
15
|
+
examples?: RubricExample[];
|
|
16
|
+
judge?: string;
|
|
17
|
+
judgeSettings?: JudgeSettings;
|
|
18
|
+
};
|
|
19
|
+
maxCostUsd?: number;
|
|
20
|
+
/** Judge each output 3 times (or the grader's own larger vote count) and report how often the verdict splits. */
|
|
21
|
+
stability?: boolean;
|
|
22
|
+
/** Cancels the check (for example when the request closes); nothing is stored when it fires. */
|
|
23
|
+
signal?: AbortSignal;
|
|
24
|
+
};
|
|
25
|
+
export type CalibrateResult = {
|
|
26
|
+
calibration: EvalCalibrationRow;
|
|
27
|
+
stats: CalibrationStats;
|
|
28
|
+
disagreements: EvalCalibrationDisagreement[];
|
|
29
|
+
errored: number;
|
|
30
|
+
stability?: StabilityStats;
|
|
31
|
+
costUsd: number;
|
|
32
|
+
};
|
|
33
|
+
export type CalibrationDeps = {
|
|
34
|
+
store: CalibrationStore & Pick<RunStore, "insertEvalCalibration">;
|
|
35
|
+
engine: EvalEngine;
|
|
36
|
+
log: (level: "info" | "warn" | "error", message: string) => void;
|
|
37
|
+
};
|
|
38
|
+
export declare const CALIBRATION_DEFAULT_MAX_COST_USD = 1;
|
|
39
|
+
/**
|
|
40
|
+
* Re-judges the stored outputs of results the author labeled for one judged grader and compares the verdicts to the
|
|
41
|
+
* labels. No stage or agent runs: the engine's case callback replays the stored output. `base` is the eval's built
|
|
42
|
+
* plan and `found` is the saved grader; the caller owns the one-at-a-time claim and the work directory.
|
|
43
|
+
*/
|
|
44
|
+
export declare function measureCalibration({ store, engine, log }: CalibrationDeps, input: CalibrateInput, base: EvalPlan, found: JudgedGrader, abort: AbortController,
|
|
45
|
+
/** Fires when the caller cancels; the budget limit uses `abort` instead and still stores the partial reading. */
|
|
46
|
+
cancel: AbortSignal): Promise<CalibrateResult>;
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
import { collectCalibrationSamples } from "./calibration.js";
|
|
2
|
+
import { CONVERSATION_RUBRIC_PROMPT_VERSION, RUBRIC_PROMPT_VERSION } from "./constants.js";
|
|
3
|
+
import { computeCalibration, computeStability } from "./stats.js";
|
|
4
|
+
import { EvalRunError } from "./errors.js";
|
|
5
|
+
export const CALIBRATION_DEFAULT_MAX_COST_USD = 1;
|
|
6
|
+
const key = (caseId, repeatIndex) => `${caseId}:${repeatIndex}`;
|
|
7
|
+
/**
|
|
8
|
+
* Re-judges the stored outputs of results the author labeled for one judged grader and compares the verdicts to the
|
|
9
|
+
* labels. No stage or agent runs: the engine's case callback replays the stored output. `base` is the eval's built
|
|
10
|
+
* plan and `found` is the saved grader; the caller owns the one-at-a-time claim and the work directory.
|
|
11
|
+
*/
|
|
12
|
+
export async function measureCalibration({ store, engine, log }, input, base, found, abort,
|
|
13
|
+
/** Fires when the caller cancels; the budget limit uses `abort` instead and still stores the partial reading. */
|
|
14
|
+
cancel) {
|
|
15
|
+
let grader = found;
|
|
16
|
+
if (input.candidate !== undefined) {
|
|
17
|
+
if (grader.type === "rubric") {
|
|
18
|
+
grader = {
|
|
19
|
+
...grader,
|
|
20
|
+
...(input.candidate.rubric !== undefined ? { rubric: input.candidate.rubric } : {}),
|
|
21
|
+
...(input.candidate.examples !== undefined ? { examples: input.candidate.examples } : {}),
|
|
22
|
+
...(input.candidate.judge !== undefined ? { judge: input.candidate.judge } : {}),
|
|
23
|
+
...(input.candidate.judgeSettings !== undefined
|
|
24
|
+
? { judgeSettings: { ...(grader.judgeSettings ?? {}), ...input.candidate.judgeSettings } }
|
|
25
|
+
: {}),
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
else {
|
|
29
|
+
grader = {
|
|
30
|
+
...grader,
|
|
31
|
+
...(input.candidate.judge !== undefined ? { judge: input.candidate.judge } : {}),
|
|
32
|
+
...(input.candidate.judgeSettings !== undefined
|
|
33
|
+
? { judgeSettings: { ...(grader.judgeSettings ?? {}), ...input.candidate.judgeSettings } }
|
|
34
|
+
: {}),
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
const stabilityVotes = input.stability === true ? Math.max(grader.judgeSettings?.votes ?? 1, 3) : undefined;
|
|
39
|
+
if (stabilityVotes !== undefined) {
|
|
40
|
+
grader = { ...grader, judgeSettings: { ...(grader.judgeSettings ?? {}), votes: stabilityVotes } };
|
|
41
|
+
}
|
|
42
|
+
const split = input.split ?? "all";
|
|
43
|
+
const samples = await collectCalibrationSamples(store, input.projectRoot, base.evalId, grader.id, split);
|
|
44
|
+
const casesById = new Map(base.cases.map((c) => [c.id, c]));
|
|
45
|
+
const usable = samples.filter((s) => casesById.has(s.caseId));
|
|
46
|
+
if (usable.length === 0) {
|
|
47
|
+
throw new EvalRunError("EVAL_CALIBRATION_NO_LABELS", `No labeled results for grader ${grader.id} can be re-judged; label results in a run first`);
|
|
48
|
+
}
|
|
49
|
+
const replay = new Map(usable.map((s) => [key(s.caseId, s.repeatIndex), s]));
|
|
50
|
+
const plan = {
|
|
51
|
+
...base,
|
|
52
|
+
cases: [...new Set(usable.map((s) => s.caseId))].map((id, position) => ({
|
|
53
|
+
...casesById.get(id),
|
|
54
|
+
position,
|
|
55
|
+
})),
|
|
56
|
+
graders: [{ ...grader, weight: 1, mustPass: false }],
|
|
57
|
+
repeats: Math.max(...usable.map((s) => s.repeatIndex)) + 1,
|
|
58
|
+
maxCostUsd: input.maxCostUsd ?? CALIBRATION_DEFAULT_MAX_COST_USD,
|
|
59
|
+
};
|
|
60
|
+
let spend = 0;
|
|
61
|
+
const verdicts = new Map();
|
|
62
|
+
const io = {
|
|
63
|
+
runCase: async (req) => {
|
|
64
|
+
const sample = replay.get(key(req.caseId, req.repeatIndex));
|
|
65
|
+
if (!sample) {
|
|
66
|
+
return { ok: false, code: "EVAL_ENGINE_ERROR", message: "not labeled for this grader" };
|
|
67
|
+
}
|
|
68
|
+
return { ok: true, output: sample.output, latencyMs: 0, costUsd: 0, tokensIn: 0, tokensOut: 0 };
|
|
69
|
+
},
|
|
70
|
+
onResult: (nr) => {
|
|
71
|
+
const grade = nr.grades.find((g) => g.graderId === grader.id);
|
|
72
|
+
if (grade)
|
|
73
|
+
verdicts.set(key(nr.caseId, nr.repeatIndex), grade);
|
|
74
|
+
if (grade?.judgeCostUsd !== undefined && Number.isFinite(grade.judgeCostUsd))
|
|
75
|
+
spend += grade.judgeCostUsd;
|
|
76
|
+
if (spend >= plan.maxCostUsd)
|
|
77
|
+
abort.abort();
|
|
78
|
+
},
|
|
79
|
+
reportJudgeCost: () => undefined,
|
|
80
|
+
onPhase: () => undefined,
|
|
81
|
+
log: (level, message) => {
|
|
82
|
+
if (level === "info")
|
|
83
|
+
log("info", message);
|
|
84
|
+
else
|
|
85
|
+
log(level, message);
|
|
86
|
+
},
|
|
87
|
+
};
|
|
88
|
+
const stop = () => abort.abort();
|
|
89
|
+
if (cancel.aborted)
|
|
90
|
+
stop();
|
|
91
|
+
cancel.addEventListener("abort", stop, { once: true });
|
|
92
|
+
try {
|
|
93
|
+
await engine.run(plan, io, abort.signal);
|
|
94
|
+
}
|
|
95
|
+
finally {
|
|
96
|
+
cancel.removeEventListener("abort", stop);
|
|
97
|
+
}
|
|
98
|
+
if (cancel.aborted)
|
|
99
|
+
throw new EvalRunError("EVAL_CALIBRATION_CANCELLED", "The check was cancelled");
|
|
100
|
+
const voteSets = [];
|
|
101
|
+
const measured = [];
|
|
102
|
+
const disagreements = [];
|
|
103
|
+
let errored = 0;
|
|
104
|
+
for (const s of usable) {
|
|
105
|
+
const grade = verdicts.get(key(s.caseId, s.repeatIndex));
|
|
106
|
+
if (!grade || grade.status !== "graded" || grade.passed === undefined) {
|
|
107
|
+
errored++;
|
|
108
|
+
continue;
|
|
109
|
+
}
|
|
110
|
+
const label = s.label === "pass";
|
|
111
|
+
const votes = grade.details?.votes;
|
|
112
|
+
if (Array.isArray(votes)) {
|
|
113
|
+
voteSets.push(votes.filter((v) => v.status === "graded" && typeof v.passed === "boolean").map((v) => v.passed));
|
|
114
|
+
}
|
|
115
|
+
measured.push({ caseId: s.caseId, repeatIndex: s.originalRepeatIndex, label, judge: grade.passed });
|
|
116
|
+
if (label !== grade.passed) {
|
|
117
|
+
disagreements.push({
|
|
118
|
+
evalRunId: s.originalRunId,
|
|
119
|
+
caseId: s.caseId,
|
|
120
|
+
repeatIndex: s.originalRepeatIndex,
|
|
121
|
+
label: s.label,
|
|
122
|
+
judge: grade.passed ? "pass" : "fail",
|
|
123
|
+
reason: grade.reason ?? null,
|
|
124
|
+
});
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
const stats = computeCalibration(measured);
|
|
128
|
+
const stability = stabilityVotes !== undefined ? computeStability(voteSets, stabilityVotes) : undefined;
|
|
129
|
+
const calibration = await store.insertEvalCalibration({
|
|
130
|
+
projectRoot: input.projectRoot,
|
|
131
|
+
evalId: base.evalId,
|
|
132
|
+
graderId: grader.id,
|
|
133
|
+
graderHash: found.hash,
|
|
134
|
+
judge: grader.judge,
|
|
135
|
+
promptVersion: base.target.kind === "agent" ? CONVERSATION_RUBRIC_PROMPT_VERSION : RUBRIC_PROMPT_VERSION,
|
|
136
|
+
split,
|
|
137
|
+
candidate: input.candidate !== undefined,
|
|
138
|
+
stats: {
|
|
139
|
+
...stats,
|
|
140
|
+
errored,
|
|
141
|
+
skipped_missing_case: samples.length - usable.length,
|
|
142
|
+
...(stability !== undefined ? { stability } : {}),
|
|
143
|
+
},
|
|
144
|
+
disagreements,
|
|
145
|
+
costUsd: spend,
|
|
146
|
+
});
|
|
147
|
+
return { calibration, stats, disagreements, errored, ...(stability !== undefined ? { stability } : {}), costUsd: spend };
|
|
148
|
+
}
|
package/dist/evals/compare.d.ts
CHANGED
|
@@ -46,7 +46,7 @@ export interface ComponentDiff {
|
|
|
46
46
|
a: unknown;
|
|
47
47
|
b: unknown;
|
|
48
48
|
}
|
|
49
|
-
export type CompareWarningCode = "dataset_differs" | "graders_differ" | "engine_differs" | "few_shared_cases";
|
|
49
|
+
export type CompareWarningCode = "dataset_differs" | "graders_differ" | "engine_differs" | "judge_differs" | "few_shared_cases";
|
|
50
50
|
export interface CompareWarning {
|
|
51
51
|
code: CompareWarningCode;
|
|
52
52
|
shared_cases?: number;
|
package/dist/evals/compare.js
CHANGED
|
@@ -151,6 +151,9 @@ export function compareRuns(a, b) {
|
|
|
151
151
|
if (components.find((c) => c.key === "engine")?.status === "changed") {
|
|
152
152
|
warnings.push({ code: "engine_differs" });
|
|
153
153
|
}
|
|
154
|
+
if (["judge", "rubric_prompt_version"].some((key) => components.find((c) => c.key === key)?.status === "changed")) {
|
|
155
|
+
warnings.push({ code: "judge_differs" });
|
|
156
|
+
}
|
|
154
157
|
if (m < 5)
|
|
155
158
|
warnings.push({ code: "few_shared_cases", shared_cases: m });
|
|
156
159
|
const stage = !isAgent &&
|
|
@@ -16,8 +16,8 @@ export type EvalReviewLabel = (typeof EVAL_REVIEW_LABELS)[number];
|
|
|
16
16
|
export declare const EVAL_BUDGET_WARNINGS: readonly ["latency", "cost"];
|
|
17
17
|
export type EvalBudgetWarning = (typeof EVAL_BUDGET_WARNINGS)[number];
|
|
18
18
|
export declare const EVAL_RESULT_ERROR_CODES: readonly ["EVAL_STAGE_FAILED", "EVAL_STAGE_NEEDS_INPUT", "EVAL_STAGE_TIMEOUT", "EVAL_ENGINE_ERROR", "EVAL_BUDGET_EXCEEDED", "EVAL_CANCELLED", "EVAL_JUDGE_ERROR", "EVAL_GRADER_CODE_ERROR", "EVAL_CASE_MISSING_EXPECTED", "EVAL_AGENT_FAILED", "EVAL_AGENT_EMPTY_REPLY", "EVAL_AGENT_TIMEOUT", "EVAL_SIMULATOR_ERROR", "EVAL_GRADER_NOT_APPLICABLE"];
|
|
19
|
-
export declare const EVAL_REQUEST_ERROR_CODES: readonly ["EVAL_INVALID", "EVAL_RUN_ACTIVE", "EVAL_ENGINE_UNAVAILABLE", "EVAL_NODE_TOO_OLD", "FILE_CHANGED", "EVAL_NOT_FOUND", "DATASET_NOT_FOUND", "EVAL_RUN_NOT_FOUND", "EVAL_TAGS_ON_PASSED_RESULT", "EVAL_REAL_TOOLS_NOT_CONFIRMED", "EVAL_CLASSIFIER_UNAVAILABLE"];
|
|
20
|
-
export declare const EVAL_ERROR_CODES: readonly ["EVAL_STAGE_FAILED", "EVAL_STAGE_NEEDS_INPUT", "EVAL_STAGE_TIMEOUT", "EVAL_ENGINE_ERROR", "EVAL_BUDGET_EXCEEDED", "EVAL_CANCELLED", "EVAL_JUDGE_ERROR", "EVAL_GRADER_CODE_ERROR", "EVAL_CASE_MISSING_EXPECTED", "EVAL_AGENT_FAILED", "EVAL_AGENT_EMPTY_REPLY", "EVAL_AGENT_TIMEOUT", "EVAL_SIMULATOR_ERROR", "EVAL_GRADER_NOT_APPLICABLE", "EVAL_INVALID", "EVAL_RUN_ACTIVE", "EVAL_ENGINE_UNAVAILABLE", "EVAL_NODE_TOO_OLD", "FILE_CHANGED", "EVAL_NOT_FOUND", "DATASET_NOT_FOUND", "EVAL_RUN_NOT_FOUND", "EVAL_TAGS_ON_PASSED_RESULT", "EVAL_REAL_TOOLS_NOT_CONFIRMED", "EVAL_CLASSIFIER_UNAVAILABLE"];
|
|
19
|
+
export declare const EVAL_REQUEST_ERROR_CODES: readonly ["EVAL_INVALID", "EVAL_RUN_ACTIVE", "EVAL_ENGINE_UNAVAILABLE", "EVAL_NODE_TOO_OLD", "FILE_CHANGED", "EVAL_NOT_FOUND", "DATASET_NOT_FOUND", "EVAL_RUN_NOT_FOUND", "EVAL_TAGS_ON_PASSED_RESULT", "EVAL_REAL_TOOLS_NOT_CONFIRMED", "EVAL_CLASSIFIER_UNAVAILABLE", "EVAL_CALIBRATION_NO_LABELS", "EVAL_CALIBRATION_CANCELLED"];
|
|
20
|
+
export declare const EVAL_ERROR_CODES: readonly ["EVAL_STAGE_FAILED", "EVAL_STAGE_NEEDS_INPUT", "EVAL_STAGE_TIMEOUT", "EVAL_ENGINE_ERROR", "EVAL_BUDGET_EXCEEDED", "EVAL_CANCELLED", "EVAL_JUDGE_ERROR", "EVAL_GRADER_CODE_ERROR", "EVAL_CASE_MISSING_EXPECTED", "EVAL_AGENT_FAILED", "EVAL_AGENT_EMPTY_REPLY", "EVAL_AGENT_TIMEOUT", "EVAL_SIMULATOR_ERROR", "EVAL_GRADER_NOT_APPLICABLE", "EVAL_INVALID", "EVAL_RUN_ACTIVE", "EVAL_ENGINE_UNAVAILABLE", "EVAL_NODE_TOO_OLD", "FILE_CHANGED", "EVAL_NOT_FOUND", "DATASET_NOT_FOUND", "EVAL_RUN_NOT_FOUND", "EVAL_TAGS_ON_PASSED_RESULT", "EVAL_REAL_TOOLS_NOT_CONFIRMED", "EVAL_CLASSIFIER_UNAVAILABLE", "EVAL_CALIBRATION_NO_LABELS", "EVAL_CALIBRATION_CANCELLED"];
|
|
21
21
|
export type EvalErrorCode = (typeof EVAL_ERROR_CODES)[number];
|
|
22
22
|
export declare const EVAL_LIMITS: {
|
|
23
23
|
readonly maxCasesPerDataset: 5000;
|
|
@@ -35,12 +35,16 @@ export declare const EVAL_LIMITS: {
|
|
|
35
35
|
readonly labelMaxChars: 80;
|
|
36
36
|
readonly failureTypeNameMaxChars: 60;
|
|
37
37
|
readonly reviewNoteMaxChars: 500;
|
|
38
|
+
/** Worked examples one rubric may hold. The console mirrors this in `tuningModel.ts`. */
|
|
39
|
+
readonly rubricExamplesMax: 6;
|
|
38
40
|
};
|
|
39
41
|
export declare const EVAL_RUN_ID_PREFIX = "er_";
|
|
40
42
|
export declare const RUBRIC_PROMPT_VERSION = 1;
|
|
41
43
|
export declare const CONFIG_SNAPSHOT_VERSION = 1;
|
|
42
44
|
export declare const SIMULATOR_PROMPT_VERSION = 1;
|
|
43
|
-
export declare const CONVERSATION_RUBRIC_PROMPT_VERSION =
|
|
45
|
+
export declare const CONVERSATION_RUBRIC_PROMPT_VERSION = 2;
|
|
46
|
+
/** Room for reasoning judges, whose hidden thinking counts against the output cap. */
|
|
47
|
+
export declare const JUDGE_MAX_OUTPUT_TOKENS = 8192;
|
|
44
48
|
/** Bump when the failure-sorting questions, bucket criteria or judge prompt text change. */
|
|
45
49
|
export declare const TRIAGE_PROMPT_VERSION = 1;
|
|
46
50
|
export declare const EVAL_CONVERSATION_LIMITS: {
|
package/dist/evals/constants.js
CHANGED
|
@@ -55,6 +55,8 @@ export const EVAL_REQUEST_ERROR_CODES = [
|
|
|
55
55
|
"EVAL_TAGS_ON_PASSED_RESULT",
|
|
56
56
|
"EVAL_REAL_TOOLS_NOT_CONFIRMED",
|
|
57
57
|
"EVAL_CLASSIFIER_UNAVAILABLE",
|
|
58
|
+
"EVAL_CALIBRATION_NO_LABELS",
|
|
59
|
+
"EVAL_CALIBRATION_CANCELLED",
|
|
58
60
|
];
|
|
59
61
|
export const EVAL_ERROR_CODES = [
|
|
60
62
|
...EVAL_RESULT_ERROR_CODES,
|
|
@@ -70,12 +72,16 @@ export const EVAL_LIMITS = {
|
|
|
70
72
|
labelMaxChars: 80,
|
|
71
73
|
failureTypeNameMaxChars: 60,
|
|
72
74
|
reviewNoteMaxChars: 500,
|
|
75
|
+
/** Worked examples one rubric may hold. The console mirrors this in `tuningModel.ts`. */
|
|
76
|
+
rubricExamplesMax: 6,
|
|
73
77
|
};
|
|
74
78
|
export const EVAL_RUN_ID_PREFIX = "er_";
|
|
75
79
|
export const RUBRIC_PROMPT_VERSION = 1;
|
|
76
80
|
export const CONFIG_SNAPSHOT_VERSION = 1;
|
|
77
81
|
export const SIMULATOR_PROMPT_VERSION = 1;
|
|
78
|
-
export const CONVERSATION_RUBRIC_PROMPT_VERSION =
|
|
82
|
+
export const CONVERSATION_RUBRIC_PROMPT_VERSION = 2;
|
|
83
|
+
/** Room for reasoning judges, whose hidden thinking counts against the output cap. */
|
|
84
|
+
export const JUDGE_MAX_OUTPUT_TOKENS = 8_192;
|
|
79
85
|
/** Bump when the failure-sorting questions, bucket criteria or judge prompt text change. */
|
|
80
86
|
export const TRIAGE_PROMPT_VERSION = 1;
|
|
81
87
|
export const EVAL_CONVERSATION_LIMITS = {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type
|
|
1
|
+
import { type CaseOutput, type EngineIo, type EvalEngine, type EvalPlan, type PlanCase, type ResolvedGrader } from "../types.js";
|
|
2
2
|
export type FakeJudgeReply = ({
|
|
3
3
|
verdict: "pass" | "fail";
|
|
4
4
|
} | {
|
|
@@ -29,5 +29,6 @@ export declare class FakeEngine implements EvalEngine {
|
|
|
29
29
|
constructor(options?: FakeEngineOptions);
|
|
30
30
|
version(): Promise<string>;
|
|
31
31
|
run(plan: EvalPlan, io: EngineIo, signal: AbortSignal): Promise<void>;
|
|
32
|
+
private gradeJudged;
|
|
32
33
|
private gradeRubric;
|
|
33
34
|
}
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import { caseGoal, goalRubricText, gradeDeterministic, isDeterministicGrader } from "../graders/index.js";
|
|
2
|
+
import { combineVotes } from "../votes.js";
|
|
3
|
+
import { isConversationTarget, } from "../types.js";
|
|
2
4
|
export class FakeEngineError extends Error {
|
|
3
5
|
code = "EVAL_ENGINE_ERROR";
|
|
4
6
|
constructor(message) {
|
|
@@ -71,7 +73,7 @@ export class FakeEngine {
|
|
|
71
73
|
throw new FakeEngineError(`fake engine failed after ${emitted} results`);
|
|
72
74
|
}
|
|
73
75
|
const { testCase, repeatIndex } = items[next++];
|
|
74
|
-
await phase(testCase, repeatIndex, plan.target.kind
|
|
76
|
+
await phase(testCase, repeatIndex, isConversationTarget(plan.target.kind) ? "agent_running" : "stage_running");
|
|
75
77
|
const run = await io.runCase({ evalRunId: plan.evalRunId, caseId: testCase.id, repeatIndex });
|
|
76
78
|
const grades = [];
|
|
77
79
|
if (run.ok) {
|
|
@@ -88,7 +90,7 @@ export class FakeEngine {
|
|
|
88
90
|
};
|
|
89
91
|
for (const grader of plan.graders) {
|
|
90
92
|
if (grader.type === "rubric") {
|
|
91
|
-
grades.push(this.
|
|
93
|
+
grades.push(this.gradeJudged(grader, testCase, run.output, io));
|
|
92
94
|
}
|
|
93
95
|
else if (grader.type === "goal_reached") {
|
|
94
96
|
const goal = caseGoal(testCase);
|
|
@@ -101,7 +103,7 @@ export class FakeEngine {
|
|
|
101
103
|
reason: "case has no input.goal or expected.outcome",
|
|
102
104
|
}
|
|
103
105
|
: {
|
|
104
|
-
...this.
|
|
106
|
+
...this.gradeJudged({
|
|
105
107
|
...grader,
|
|
106
108
|
type: "rubric",
|
|
107
109
|
rubric: goalRubricText(goal, grader.guidance),
|
|
@@ -134,6 +136,10 @@ export class FakeEngine {
|
|
|
134
136
|
if (failure !== undefined)
|
|
135
137
|
throw failure;
|
|
136
138
|
}
|
|
139
|
+
gradeJudged(grader, testCase, output, io) {
|
|
140
|
+
const votes = grader.judgeSettings?.votes ?? 1;
|
|
141
|
+
return combineVotes(grader, Array.from({ length: votes }, () => this.gradeRubric(grader, testCase, output, io)));
|
|
142
|
+
}
|
|
137
143
|
gradeRubric(grader, testCase, output, io) {
|
|
138
144
|
const base = { graderId: grader.id, graderType: "rubric", judgeModel: grader.judge };
|
|
139
145
|
const reply = this.options.judge?.(grader, testCase, output) ??
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { type ChildProcess, type SpawnOptions } from "node:child_process";
|
|
2
|
-
import type
|
|
2
|
+
import { type EngineIo, type EvalEngine, type EvalPlan } from "../../types.js";
|
|
3
3
|
import { type JudgeKeyResolver, type JudgePriceLoader } from "./judgeServices.js";
|
|
4
4
|
import type { RunTokenRegistry } from "./runTokens.js";
|
|
5
5
|
export declare const PROMPTFOO_KILL_GRACE_MS = 5000;
|
|
@@ -3,6 +3,7 @@ import { closeSync, existsSync, mkdirSync, openSync, readFileSync, readSync, rmS
|
|
|
3
3
|
import path from "node:path";
|
|
4
4
|
import { fileURLToPath, pathToFileURL } from "node:url";
|
|
5
5
|
import { globalStageflowHome } from "../../../project/globalHome.js";
|
|
6
|
+
import { isConversationTarget, } from "../../types.js";
|
|
6
7
|
import { EngineError } from "./errors.js";
|
|
7
8
|
import { CALLBACK_URL_ENV, CONFIG_FILE, RESULTS_FILE, RESULTS_STREAM_FILE, RUN_TOKEN_ENV, generateFiles, } from "./generate.js";
|
|
8
9
|
import { GUARD_FILENAME } from "./guard.js";
|
|
@@ -13,6 +14,7 @@ import { locatePromptfoo } from "./locate.js";
|
|
|
13
14
|
import { normalizeRecord, recordIdentity, recordsFromResultsFile } from "./normalize.js";
|
|
14
15
|
import { assertNode } from "./nodeVersion.js";
|
|
15
16
|
import { PINNED_PROMPTFOO_VERSION } from "./pinned.js";
|
|
17
|
+
import { isJudged } from "../../judged.js";
|
|
16
18
|
export const PROMPTFOO_KILL_GRACE_MS = 5_000;
|
|
17
19
|
export const PROMPTFOO_STREAM_POLL_MS = 100;
|
|
18
20
|
export const STDERR_TAIL_BYTES = 2048;
|
|
@@ -131,7 +133,7 @@ export class PromptfooEngine {
|
|
|
131
133
|
const judgeEnv = {};
|
|
132
134
|
const judgeModels = new Set();
|
|
133
135
|
for (const grader of plan.graders) {
|
|
134
|
-
if (grader
|
|
136
|
+
if (!isJudged(grader))
|
|
135
137
|
continue;
|
|
136
138
|
judgeModels.add(grader.judge);
|
|
137
139
|
const mapping = mapJudge(grader.judge);
|
|
@@ -160,7 +162,7 @@ export class PromptfooEngine {
|
|
|
160
162
|
const hostRuns = new Map();
|
|
161
163
|
const keyOf = (caseId, repeatIndex) => `${caseId}#${repeatIndex}`;
|
|
162
164
|
const runCase = async (req) => {
|
|
163
|
-
io.onPhase(req.caseId, req.repeatIndex, plan.target.kind
|
|
165
|
+
io.onPhase(req.caseId, req.repeatIndex, isConversationTarget(plan.target.kind) ? "agent_running" : "stage_running");
|
|
164
166
|
const result = await io.runCase(req);
|
|
165
167
|
hostRuns.set(keyOf(req.caseId, req.repeatIndex), result);
|
|
166
168
|
if (result.ok)
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { GUARD_FILENAME } from "./guard.js";
|
|
2
|
-
import type
|
|
2
|
+
import { type EvalPlan } from "../../types.js";
|
|
3
3
|
export declare const CALLBACK_URL_ENV = "STAGEFLOW_EVAL_CALLBACK_URL";
|
|
4
4
|
export declare const RUN_TOKEN_ENV = "STAGEFLOW_EVAL_TOKEN";
|
|
5
5
|
export declare const CONFIG_FILE = "promptfooconfig.json";
|
|
@@ -26,5 +26,7 @@ export declare function assertionFnName(index: number): string;
|
|
|
26
26
|
export declare function buildProviderSource(evalRunId: string, agent?: boolean): string;
|
|
27
27
|
export declare function buildHooksSource(agent?: boolean): string;
|
|
28
28
|
export declare function buildAssertionsSource(plan: EvalPlan, graderModuleUrl: string): string;
|
|
29
|
+
/** The metric of vote `n` (1-based) for a judged grader; vote 1 keeps the grader id. */
|
|
30
|
+
export declare function voteMetric(graderId: string, vote: number): string;
|
|
29
31
|
export declare function buildConfig(plan: EvalPlan, options: GenerateOptions): Record<string, unknown>;
|
|
30
32
|
export declare function generateFiles(plan: EvalPlan, options: GenerateOptions): GeneratedFiles;
|