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,250 @@
|
|
|
1
|
+
import { randomUUID } from "node:crypto";
|
|
2
|
+
import { createOperatorEvalGate } from "../../operatorAgent/evalGate.js";
|
|
3
|
+
import { buildConversationSubject } from "./conversationSubject.js";
|
|
4
|
+
import { createDriver, DriverScenarioError } from "./userDriver.js";
|
|
5
|
+
const ZERO_USAGE = {
|
|
6
|
+
cost_usd: 0,
|
|
7
|
+
agent_cost_usd: 0,
|
|
8
|
+
simulator_cost_usd: 0,
|
|
9
|
+
tokens_in: 0,
|
|
10
|
+
tokens_out: 0,
|
|
11
|
+
simulator_tokens_in: 0,
|
|
12
|
+
simulator_tokens_out: 0,
|
|
13
|
+
simulator_estimated: false,
|
|
14
|
+
agent_calls: 0,
|
|
15
|
+
simulator_calls: 0,
|
|
16
|
+
};
|
|
17
|
+
function failure(code, message, extra = {}) {
|
|
18
|
+
return { ok: false, code, message, ...extra };
|
|
19
|
+
}
|
|
20
|
+
function parseMocks(value) {
|
|
21
|
+
const out = {};
|
|
22
|
+
if (typeof value !== "object" || value === null || Array.isArray(value))
|
|
23
|
+
return out;
|
|
24
|
+
for (const [tool, mock] of Object.entries(value)) {
|
|
25
|
+
if (typeof mock !== "object" || mock === null)
|
|
26
|
+
continue;
|
|
27
|
+
const { result, error } = mock;
|
|
28
|
+
if (typeof error === "string")
|
|
29
|
+
out[tool] = { error };
|
|
30
|
+
else if ("result" in mock)
|
|
31
|
+
out[tool] = { result };
|
|
32
|
+
}
|
|
33
|
+
return out;
|
|
34
|
+
}
|
|
35
|
+
function detailFrom(sessionId, profileId, messages) {
|
|
36
|
+
const now = new Date().toISOString();
|
|
37
|
+
return {
|
|
38
|
+
session: {
|
|
39
|
+
id: sessionId,
|
|
40
|
+
agentId: profileId,
|
|
41
|
+
revision: 0,
|
|
42
|
+
backend: "pi",
|
|
43
|
+
status: "closed",
|
|
44
|
+
source: "eval",
|
|
45
|
+
sourceRef: null,
|
|
46
|
+
threadKey: null,
|
|
47
|
+
title: null,
|
|
48
|
+
createdAt: now,
|
|
49
|
+
updatedAt: now,
|
|
50
|
+
},
|
|
51
|
+
messages,
|
|
52
|
+
turns: [],
|
|
53
|
+
spans: [],
|
|
54
|
+
approvals: [],
|
|
55
|
+
pendingApproval: null,
|
|
56
|
+
evalScores: [],
|
|
57
|
+
deliveries: [],
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
export function createInternalAgentCaseRunner(deps) {
|
|
61
|
+
const clock = deps.now ?? Date.now;
|
|
62
|
+
const states = new Map();
|
|
63
|
+
const stateFor = (id) => {
|
|
64
|
+
let state = states.get(id);
|
|
65
|
+
if (!state) {
|
|
66
|
+
state = { cancelled: false, abort: new AbortController() };
|
|
67
|
+
states.set(id, state);
|
|
68
|
+
}
|
|
69
|
+
return state;
|
|
70
|
+
};
|
|
71
|
+
async function runCase(plan, req) {
|
|
72
|
+
const state = stateFor(req.evalRunId);
|
|
73
|
+
if (state.cancelled)
|
|
74
|
+
return failure("EVAL_CANCELLED", "Eval run was cancelled");
|
|
75
|
+
if (plan.target.kind !== "internal_agent" || !plan.conversation) {
|
|
76
|
+
return failure("EVAL_ENGINE_ERROR", "Not an internal-agent plan");
|
|
77
|
+
}
|
|
78
|
+
if (plan.conversation.tools === "real") {
|
|
79
|
+
return failure("EVAL_ENGINE_ERROR", "Internal agents cannot run an eval with real tools");
|
|
80
|
+
}
|
|
81
|
+
const host = deps.host();
|
|
82
|
+
if (!host)
|
|
83
|
+
return failure("EVAL_ENGINE_ERROR", "Internal agents are unavailable on this host");
|
|
84
|
+
const planCase = plan.cases.find((c) => c.id === req.caseId);
|
|
85
|
+
if (!planCase)
|
|
86
|
+
return failure("EVAL_ENGINE_ERROR", `Case "${req.caseId}" is not in the plan`);
|
|
87
|
+
const scenario = planCase.input;
|
|
88
|
+
const mode = scenario.mode === "script" || scenario.mode === "simulated" ? scenario.mode : plan.conversation.mode;
|
|
89
|
+
let driver;
|
|
90
|
+
try {
|
|
91
|
+
driver = createDriver(mode, scenario, {});
|
|
92
|
+
}
|
|
93
|
+
catch (err) {
|
|
94
|
+
return failure("EVAL_ENGINE_ERROR", err instanceof DriverScenarioError ? err.message : "Scenario could not be prepared");
|
|
95
|
+
}
|
|
96
|
+
if (mode === "simulated") {
|
|
97
|
+
return failure("EVAL_ENGINE_ERROR", "A simulated internal-agent case needs a user model, which this runner does not call");
|
|
98
|
+
}
|
|
99
|
+
const conversation = plan.conversation;
|
|
100
|
+
const sessionId = `op_eval_${randomUUID()}`;
|
|
101
|
+
let turn = 0;
|
|
102
|
+
const gate = createOperatorEvalGate({
|
|
103
|
+
policy: { tools: conversation.tools, mocks: parseMocks(scenario.tool_mocks) },
|
|
104
|
+
turn: () => turn,
|
|
105
|
+
});
|
|
106
|
+
let session;
|
|
107
|
+
try {
|
|
108
|
+
session = host.openEvalSession({
|
|
109
|
+
profileId: plan.target.profileId,
|
|
110
|
+
context: { kind: "stageflow_guide" },
|
|
111
|
+
gate,
|
|
112
|
+
});
|
|
113
|
+
}
|
|
114
|
+
catch (err) {
|
|
115
|
+
return failure("EVAL_ENGINE_ERROR", err instanceof Error ? err.message : "The eval session could not be opened");
|
|
116
|
+
}
|
|
117
|
+
const startedAt = clock();
|
|
118
|
+
const messages = [];
|
|
119
|
+
const transcript = [];
|
|
120
|
+
let end = {
|
|
121
|
+
kind: "done",
|
|
122
|
+
stopReason: "max_turns",
|
|
123
|
+
};
|
|
124
|
+
const caseCtl = new AbortController();
|
|
125
|
+
let wallExpired = false;
|
|
126
|
+
let turnTimedOut = false;
|
|
127
|
+
const stopCase = () => {
|
|
128
|
+
caseCtl.abort();
|
|
129
|
+
void session.abort().catch(() => undefined);
|
|
130
|
+
};
|
|
131
|
+
const onRunAbort = () => stopCase();
|
|
132
|
+
state.abort.signal.addEventListener("abort", onRunAbort, { once: true });
|
|
133
|
+
const wallMs = conversation.maxTurns * conversation.turnTimeoutMs + 60_000;
|
|
134
|
+
const wall = setTimeout(() => {
|
|
135
|
+
wallExpired = true;
|
|
136
|
+
stopCase();
|
|
137
|
+
}, wallMs);
|
|
138
|
+
const stopped = new Promise((resolve) => {
|
|
139
|
+
if (caseCtl.signal.aborted)
|
|
140
|
+
resolve("stopped");
|
|
141
|
+
else
|
|
142
|
+
caseCtl.signal.addEventListener("abort", () => resolve("stopped"), { once: true });
|
|
143
|
+
});
|
|
144
|
+
try {
|
|
145
|
+
for (turn = 1; turn <= conversation.maxTurns; turn += 1) {
|
|
146
|
+
if (state.cancelled) {
|
|
147
|
+
end = { kind: "cancelled" };
|
|
148
|
+
break;
|
|
149
|
+
}
|
|
150
|
+
if (wallExpired || turnTimedOut || caseCtl.signal.aborted) {
|
|
151
|
+
end = {
|
|
152
|
+
kind: "failed",
|
|
153
|
+
code: "EVAL_AGENT_TIMEOUT",
|
|
154
|
+
message: turnTimedOut ? `Turn ${turn} exceeded ${conversation.turnTimeoutMs} ms` : "Conversation exceeded its time limit",
|
|
155
|
+
stopReason: "timeout",
|
|
156
|
+
};
|
|
157
|
+
break;
|
|
158
|
+
}
|
|
159
|
+
const step = await driver.next({ turn, transcript, signal: caseCtl.signal });
|
|
160
|
+
if (step.kind === "end") {
|
|
161
|
+
end = { kind: "done", stopReason: step.reason };
|
|
162
|
+
break;
|
|
163
|
+
}
|
|
164
|
+
const now = new Date().toISOString();
|
|
165
|
+
messages.push({ id: randomUUID(), sessionId, seq: messages.length, turnId: String(turn), role: "user", author: null, text: step.text, createdAt: now });
|
|
166
|
+
const turnTimer = setTimeout(() => {
|
|
167
|
+
turnTimedOut = true;
|
|
168
|
+
stopCase();
|
|
169
|
+
}, conversation.turnTimeoutMs);
|
|
170
|
+
const sent = session.send(step.text, plan.modelOverride ? { modelId: plan.modelOverride } : {}).then((events) => ({ ok: true, events }), (err) => ({ ok: false, err }));
|
|
171
|
+
const outcome = await Promise.race([sent, stopped]);
|
|
172
|
+
clearTimeout(turnTimer);
|
|
173
|
+
if (state.cancelled) {
|
|
174
|
+
end = { kind: "cancelled" };
|
|
175
|
+
break;
|
|
176
|
+
}
|
|
177
|
+
if (outcome === "stopped" || wallExpired || turnTimedOut) {
|
|
178
|
+
end = {
|
|
179
|
+
kind: "failed",
|
|
180
|
+
code: "EVAL_AGENT_TIMEOUT",
|
|
181
|
+
message: turnTimedOut ? `Turn ${turn} exceeded ${conversation.turnTimeoutMs} ms` : "Conversation exceeded its time limit",
|
|
182
|
+
stopReason: "timeout",
|
|
183
|
+
};
|
|
184
|
+
break;
|
|
185
|
+
}
|
|
186
|
+
if (!outcome.ok) {
|
|
187
|
+
end = { kind: "failed", code: "EVAL_ENGINE_ERROR", message: outcome.err instanceof Error ? outcome.err.message : "Conversation failed", stopReason: "error" };
|
|
188
|
+
break;
|
|
189
|
+
}
|
|
190
|
+
const text = outcome.events
|
|
191
|
+
.filter((event) => event.type === "message" && event.role === "assistant")
|
|
192
|
+
.map((event) => (event.type === "message" ? event.text : ""))
|
|
193
|
+
.filter(Boolean)
|
|
194
|
+
.join("\n\n");
|
|
195
|
+
if (!text && gate.records().every((call) => call.turn !== turn)) {
|
|
196
|
+
end = { kind: "failed", code: "EVAL_AGENT_EMPTY_REPLY", message: "The agent returned an empty reply", stopReason: "error" };
|
|
197
|
+
break;
|
|
198
|
+
}
|
|
199
|
+
messages.push({ id: randomUUID(), sessionId, seq: messages.length, turnId: String(turn), role: "assistant", author: null, text, createdAt: now });
|
|
200
|
+
transcript.push({ role: "user", text: step.text }, { role: "assistant", text });
|
|
201
|
+
if (step.endAfter !== undefined) {
|
|
202
|
+
end = { kind: "done", stopReason: step.endAfter };
|
|
203
|
+
break;
|
|
204
|
+
}
|
|
205
|
+
if (turn === conversation.maxTurns)
|
|
206
|
+
end = { kind: "done", stopReason: "max_turns" };
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
catch (err) {
|
|
210
|
+
end = state.cancelled
|
|
211
|
+
? { kind: "cancelled" }
|
|
212
|
+
: wallExpired || turnTimedOut
|
|
213
|
+
? { kind: "failed", code: "EVAL_AGENT_TIMEOUT", message: turnTimedOut ? `Turn ${turn} exceeded ${conversation.turnTimeoutMs} ms` : "Conversation exceeded its time limit", stopReason: "timeout" }
|
|
214
|
+
: { kind: "failed", code: "EVAL_ENGINE_ERROR", message: err instanceof Error ? err.message : "Conversation failed", stopReason: "error" };
|
|
215
|
+
}
|
|
216
|
+
finally {
|
|
217
|
+
clearTimeout(wall);
|
|
218
|
+
state.abort.signal.removeEventListener("abort", onRunAbort);
|
|
219
|
+
session.close();
|
|
220
|
+
}
|
|
221
|
+
const usage = { ...ZERO_USAGE, agent_calls: messages.filter((m) => m.role === "assistant").length };
|
|
222
|
+
const subject = (stopReason, failed) => buildConversationSubject({
|
|
223
|
+
detail: detailFrom(sessionId, plan.target.kind === "internal_agent" ? plan.target.profileId : "", messages),
|
|
224
|
+
calls: gate.records(),
|
|
225
|
+
stopReason,
|
|
226
|
+
usage,
|
|
227
|
+
turns: messages.filter((m) => m.role === "user").length,
|
|
228
|
+
...(failed !== undefined ? { failure: failed } : {}),
|
|
229
|
+
});
|
|
230
|
+
const latencyMs = Math.max(0, clock() - startedAt);
|
|
231
|
+
if (end.kind === "done") {
|
|
232
|
+
return { ok: true, subjectRef: sessionId, output: subject(end.stopReason), latencyMs, costUsd: 0, tokensIn: 0, tokensOut: 0 };
|
|
233
|
+
}
|
|
234
|
+
if (end.kind === "cancelled")
|
|
235
|
+
return failure("EVAL_CANCELLED", "Eval run was cancelled", { subjectRef: sessionId, latencyMs, costUsd: 0 });
|
|
236
|
+
return failure(end.code, end.message, { subjectRef: sessionId, output: subject(end.stopReason, end.message), latencyMs, costUsd: 0 });
|
|
237
|
+
}
|
|
238
|
+
return {
|
|
239
|
+
runCase,
|
|
240
|
+
async cancelAll(evalRunId) {
|
|
241
|
+
const state = states.get(evalRunId);
|
|
242
|
+
if (!state)
|
|
243
|
+
return;
|
|
244
|
+
state.cancelled = true;
|
|
245
|
+
state.abort.abort();
|
|
246
|
+
},
|
|
247
|
+
spend: () => 0,
|
|
248
|
+
addSpend: () => undefined,
|
|
249
|
+
};
|
|
250
|
+
}
|
package/dist/evals/snapshot.d.ts
CHANGED
|
@@ -74,6 +74,14 @@ export type ConversationSettings = {
|
|
|
74
74
|
user_model_from_judge: boolean;
|
|
75
75
|
simulator_prompt_version: number;
|
|
76
76
|
};
|
|
77
|
+
export type InternalAgentSnapshotTarget = {
|
|
78
|
+
kind: "internal_agent";
|
|
79
|
+
profile_id: string;
|
|
80
|
+
title: string;
|
|
81
|
+
playbook_hash: string;
|
|
82
|
+
tools: string[];
|
|
83
|
+
model: string;
|
|
84
|
+
};
|
|
77
85
|
export type ConfigSnapshot = {
|
|
78
86
|
snapshot_version: number;
|
|
79
87
|
eval: {
|
|
@@ -83,7 +91,7 @@ export type ConfigSnapshot = {
|
|
|
83
91
|
definition: Record<string, unknown>;
|
|
84
92
|
};
|
|
85
93
|
overrides: SnapshotOverrides;
|
|
86
|
-
target: StageSnapshotTarget | AgentSnapshotTarget;
|
|
94
|
+
target: StageSnapshotTarget | AgentSnapshotTarget | InternalAgentSnapshotTarget;
|
|
87
95
|
dataset: {
|
|
88
96
|
path: string;
|
|
89
97
|
hash: string;
|
|
@@ -169,7 +177,7 @@ export type SnapshotInput = {
|
|
|
169
177
|
evalHash: string;
|
|
170
178
|
evalDefinition: Record<string, unknown>;
|
|
171
179
|
overrides: SnapshotOverrides;
|
|
172
|
-
target: Omit<StageSnapshotTarget, "kind"> | Omit<AgentSnapshotTarget, "kind">;
|
|
180
|
+
target: Omit<StageSnapshotTarget, "kind"> | Omit<AgentSnapshotTarget, "kind"> | Omit<InternalAgentSnapshotTarget, "kind">;
|
|
173
181
|
dataset: ConfigSnapshot["dataset"];
|
|
174
182
|
graders: SnapshotGrader[];
|
|
175
183
|
settings: ConfigSnapshot["settings"];
|
package/dist/evals/snapshot.js
CHANGED
|
@@ -40,7 +40,8 @@ export function computeFingerprint(components) {
|
|
|
40
40
|
return sha256Hex(canonicalJson(payload)).slice(0, 8);
|
|
41
41
|
}
|
|
42
42
|
export function buildSnapshot(input) {
|
|
43
|
-
const
|
|
43
|
+
const internalTarget = "profile_id" in input.target ? input.target : null;
|
|
44
|
+
const agentTarget = !internalTarget && "agent_id" in input.target ? input.target : null;
|
|
44
45
|
return {
|
|
45
46
|
snapshot_version: CONFIG_SNAPSHOT_VERSION,
|
|
46
47
|
eval: {
|
|
@@ -50,14 +51,18 @@ export function buildSnapshot(input) {
|
|
|
50
51
|
definition: input.evalDefinition,
|
|
51
52
|
},
|
|
52
53
|
overrides: input.overrides,
|
|
53
|
-
target:
|
|
54
|
+
target: internalTarget
|
|
55
|
+
? { kind: "internal_agent", ...internalTarget }
|
|
56
|
+
: agentTarget
|
|
57
|
+
? { kind: "agent", ...agentTarget }
|
|
58
|
+
: { kind: "stage", ...input.target },
|
|
54
59
|
dataset: input.dataset,
|
|
55
60
|
graders: input.graders,
|
|
56
61
|
settings: input.settings,
|
|
57
62
|
engine: {
|
|
58
63
|
name: input.engine.name,
|
|
59
64
|
version: input.engine.version,
|
|
60
|
-
rubric_prompt_version: agentTarget ? CONVERSATION_RUBRIC_PROMPT_VERSION : RUBRIC_PROMPT_VERSION,
|
|
65
|
+
rubric_prompt_version: agentTarget || internalTarget ? CONVERSATION_RUBRIC_PROMPT_VERSION : RUBRIC_PROMPT_VERSION,
|
|
61
66
|
node_version: input.engine.nodeVersion,
|
|
62
67
|
},
|
|
63
68
|
stageflow_version: input.stageflowVersion,
|
package/dist/evals/stats.d.ts
CHANGED
|
@@ -93,3 +93,43 @@ export declare function clusteredCi(center: number, perCase: number[], lo: numbe
|
|
|
93
93
|
export declare function buildCaseStats(results: ResultRecord[]): CaseStat[];
|
|
94
94
|
export declare function computeByGrader(graders: GraderRef[], grades: GradeRecord[], previousRun: PreviousRunLite | null | undefined): GraderStat[];
|
|
95
95
|
export declare function computeStats(input: ComputeStatsInput): Stats;
|
|
96
|
+
export declare const CALIBRATION_MIN_LABELS = 20;
|
|
97
|
+
export declare const CALIBRATION_MINORITY_SHARE = 0.2;
|
|
98
|
+
export interface CalibrationSample {
|
|
99
|
+
caseId: string;
|
|
100
|
+
repeatIndex: number;
|
|
101
|
+
label: boolean;
|
|
102
|
+
judge: boolean;
|
|
103
|
+
}
|
|
104
|
+
export interface CalibrationStats {
|
|
105
|
+
n: number;
|
|
106
|
+
agreement: number | null;
|
|
107
|
+
cohen_kappa: number | null;
|
|
108
|
+
tpr: number | null;
|
|
109
|
+
tnr: number | null;
|
|
110
|
+
confusion: {
|
|
111
|
+
tp: number;
|
|
112
|
+
fp: number;
|
|
113
|
+
tn: number;
|
|
114
|
+
fn: number;
|
|
115
|
+
};
|
|
116
|
+
warnings: Array<"low_n" | "imbalanced" | "no_variance">;
|
|
117
|
+
}
|
|
118
|
+
/** Judge pass is the positive class; the human label is the truth. */
|
|
119
|
+
export declare function computeCalibration(samples: CalibrationSample[]): CalibrationStats;
|
|
120
|
+
/** A strict majority of valid votes passes; a tie fails. */
|
|
121
|
+
export declare function majorityPasses(passes: number, valid: number): boolean;
|
|
122
|
+
export declare function meanOf(values: readonly number[]): number;
|
|
123
|
+
/** Deterministic 70/30 split by a stable hash of the case id, so every repeat of a case lands on the same side. */
|
|
124
|
+
export declare function calibrationSplitOf(caseId: string): "dev" | "held_out";
|
|
125
|
+
export interface StabilityStats {
|
|
126
|
+
/** Judge calls per output. */
|
|
127
|
+
k: number;
|
|
128
|
+
/** Outputs with at least two valid votes. */
|
|
129
|
+
n: number;
|
|
130
|
+
/** Outputs whose valid votes were not all the same verdict. */
|
|
131
|
+
unstable: number;
|
|
132
|
+
flip_rate: number | null;
|
|
133
|
+
}
|
|
134
|
+
/** How often the judge changes its mind on the same output: the share of outputs with a split vote. */
|
|
135
|
+
export declare function computeStability(voteSets: boolean[][], k: number): StabilityStats;
|
package/dist/evals/stats.js
CHANGED
|
@@ -218,3 +218,72 @@ export function computeStats(input) {
|
|
|
218
218
|
...(hasAgentData ? { mean_turns: mean(turnValues), mean_tool_calls: mean(toolCallValues) } : {}),
|
|
219
219
|
};
|
|
220
220
|
}
|
|
221
|
+
export const CALIBRATION_MIN_LABELS = 20;
|
|
222
|
+
export const CALIBRATION_MINORITY_SHARE = 0.2;
|
|
223
|
+
/** Judge pass is the positive class; the human label is the truth. */
|
|
224
|
+
export function computeCalibration(samples) {
|
|
225
|
+
let tp = 0;
|
|
226
|
+
let fp = 0;
|
|
227
|
+
let tn = 0;
|
|
228
|
+
let fn = 0;
|
|
229
|
+
for (const s of samples) {
|
|
230
|
+
if (s.judge && s.label)
|
|
231
|
+
tp++;
|
|
232
|
+
else if (s.judge && !s.label)
|
|
233
|
+
fp++;
|
|
234
|
+
else if (!s.judge && !s.label)
|
|
235
|
+
tn++;
|
|
236
|
+
else
|
|
237
|
+
fn++;
|
|
238
|
+
}
|
|
239
|
+
const n = tp + fp + tn + fn;
|
|
240
|
+
const warnings = [];
|
|
241
|
+
if (n < CALIBRATION_MIN_LABELS)
|
|
242
|
+
warnings.push("low_n");
|
|
243
|
+
const labelPass = tp + fn;
|
|
244
|
+
const labelFail = fp + tn;
|
|
245
|
+
if (n > 0 && Math.min(labelPass, labelFail) / n < CALIBRATION_MINORITY_SHARE)
|
|
246
|
+
warnings.push("imbalanced");
|
|
247
|
+
const agreement = n > 0 ? (tp + tn) / n : null;
|
|
248
|
+
const judgePass = tp + fp;
|
|
249
|
+
const judgeFail = fn + tn;
|
|
250
|
+
const expected = n > 0 ? (judgePass * labelPass + judgeFail * labelFail) / (n * n) : 0;
|
|
251
|
+
let kappa = null;
|
|
252
|
+
if (n > 0 && agreement !== null) {
|
|
253
|
+
if (expected >= 1)
|
|
254
|
+
warnings.push("no_variance");
|
|
255
|
+
else
|
|
256
|
+
kappa = (agreement - expected) / (1 - expected);
|
|
257
|
+
}
|
|
258
|
+
return {
|
|
259
|
+
n,
|
|
260
|
+
agreement,
|
|
261
|
+
cohen_kappa: kappa,
|
|
262
|
+
tpr: labelPass > 0 ? tp / labelPass : null,
|
|
263
|
+
tnr: labelFail > 0 ? tn / labelFail : null,
|
|
264
|
+
confusion: { tp, fp, tn, fn },
|
|
265
|
+
warnings,
|
|
266
|
+
};
|
|
267
|
+
}
|
|
268
|
+
/** A strict majority of valid votes passes; a tie fails. */
|
|
269
|
+
export function majorityPasses(passes, valid) {
|
|
270
|
+
return passes * 2 > valid;
|
|
271
|
+
}
|
|
272
|
+
export function meanOf(values) {
|
|
273
|
+
return values.reduce((total, v) => total + v, 0) / values.length;
|
|
274
|
+
}
|
|
275
|
+
/** Deterministic 70/30 split by a stable hash of the case id, so every repeat of a case lands on the same side. */
|
|
276
|
+
export function calibrationSplitOf(caseId) {
|
|
277
|
+
let h = 2166136261;
|
|
278
|
+
for (let i = 0; i < caseId.length; i++) {
|
|
279
|
+
h ^= caseId.charCodeAt(i);
|
|
280
|
+
h = Math.imul(h, 16777619) >>> 0;
|
|
281
|
+
}
|
|
282
|
+
return h % 10 < 7 ? "dev" : "held_out";
|
|
283
|
+
}
|
|
284
|
+
/** How often the judge changes its mind on the same output: the share of outputs with a split vote. */
|
|
285
|
+
export function computeStability(voteSets, k) {
|
|
286
|
+
const counted = voteSets.filter((votes) => votes.length >= 2);
|
|
287
|
+
const unstable = counted.filter((votes) => votes.some((v) => v !== votes[0])).length;
|
|
288
|
+
return { k, n: counted.length, unstable, flip_rate: counted.length > 0 ? unstable / counted.length : null };
|
|
289
|
+
}
|
|
@@ -205,3 +205,45 @@ export type EvalGraderVersionInput = {
|
|
|
205
205
|
graderId: string;
|
|
206
206
|
graderHash: string;
|
|
207
207
|
};
|
|
208
|
+
export type EvalGraderLabelRow = {
|
|
209
|
+
evalRunId: string;
|
|
210
|
+
caseId: string;
|
|
211
|
+
repeatIndex: number;
|
|
212
|
+
graderId: string;
|
|
213
|
+
label: EvalReviewLabel;
|
|
214
|
+
note: string | null;
|
|
215
|
+
createdAt: string;
|
|
216
|
+
updatedAt: string;
|
|
217
|
+
};
|
|
218
|
+
export type EvalGraderLabelPatch = {
|
|
219
|
+
label: EvalReviewLabel | null;
|
|
220
|
+
note?: string | null;
|
|
221
|
+
};
|
|
222
|
+
export type EvalCalibrationSplit = "all" | "dev" | "held_out";
|
|
223
|
+
export type EvalCalibrationDisagreement = {
|
|
224
|
+
/** The run the labeled result came from; absent on calibrations stored before this field existed. */
|
|
225
|
+
evalRunId?: string;
|
|
226
|
+
caseId: string;
|
|
227
|
+
repeatIndex: number;
|
|
228
|
+
label: EvalReviewLabel;
|
|
229
|
+
judge: EvalReviewLabel;
|
|
230
|
+
reason: string | null;
|
|
231
|
+
};
|
|
232
|
+
export type EvalCalibrationInput = {
|
|
233
|
+
projectRoot: string;
|
|
234
|
+
evalId: string;
|
|
235
|
+
graderId: string;
|
|
236
|
+
graderHash: string;
|
|
237
|
+
judge: string;
|
|
238
|
+
promptVersion: number;
|
|
239
|
+
split: EvalCalibrationSplit;
|
|
240
|
+
candidate: boolean;
|
|
241
|
+
stats: EvalJson;
|
|
242
|
+
disagreements: EvalCalibrationDisagreement[];
|
|
243
|
+
costUsd: number;
|
|
244
|
+
};
|
|
245
|
+
export type EvalCalibrationRow = Omit<EvalCalibrationInput, "stats"> & {
|
|
246
|
+
id: string;
|
|
247
|
+
stats: EvalJson;
|
|
248
|
+
createdAt: string;
|
|
249
|
+
};
|
package/dist/evals/types.d.ts
CHANGED
|
@@ -24,7 +24,13 @@ export type AgentEvalTarget = {
|
|
|
24
24
|
kind: "agent";
|
|
25
25
|
agent: string;
|
|
26
26
|
};
|
|
27
|
-
export type
|
|
27
|
+
export type InternalAgentEvalTarget = {
|
|
28
|
+
kind: "internal_agent";
|
|
29
|
+
profile: string;
|
|
30
|
+
};
|
|
31
|
+
export type EvalTarget = StageEvalTarget | AgentEvalTarget | InternalAgentEvalTarget;
|
|
32
|
+
/** A conversation eval: a project agent or a built-in operator agent. */
|
|
33
|
+
export declare function isConversationTarget(kind: string): boolean;
|
|
28
34
|
export type ConversationMode = "script" | "simulated";
|
|
29
35
|
export type ConversationTools = "real" | "read_only" | "mocked";
|
|
30
36
|
export type ConversationApprovals = "deny" | "auto_approve_read" | "record_only";
|
|
@@ -51,9 +57,18 @@ export type EvalTask = {
|
|
|
51
57
|
context?: string;
|
|
52
58
|
constraints?: string;
|
|
53
59
|
};
|
|
60
|
+
export type JudgeSettings = {
|
|
61
|
+
/** Sampling temperature for the judge call; unset leaves the provider default. */
|
|
62
|
+
temperature?: number;
|
|
63
|
+
/** The judge writes its reason before the verdict. */
|
|
64
|
+
reasoning?: boolean;
|
|
65
|
+
/** Judge calls per grade (odd, 1 to 5); the majority verdict wins. */
|
|
66
|
+
votes?: number;
|
|
67
|
+
};
|
|
54
68
|
export type EvalDefaults = {
|
|
55
69
|
repeats?: number;
|
|
56
70
|
judge?: string;
|
|
71
|
+
judge_settings?: JudgeSettings;
|
|
57
72
|
pass_threshold?: number;
|
|
58
73
|
max_cost_usd?: number;
|
|
59
74
|
concurrency?: number;
|
|
@@ -97,6 +112,7 @@ export type GraderConfig = (GraderCommon & {
|
|
|
97
112
|
scale?: "pass_fail" | "1_to_5";
|
|
98
113
|
pass_at?: number;
|
|
99
114
|
judge?: string;
|
|
115
|
+
judge_settings?: JudgeSettings;
|
|
100
116
|
examples?: RubricExample[];
|
|
101
117
|
}) | (GraderCommon & {
|
|
102
118
|
type: "code";
|
|
@@ -116,6 +132,7 @@ export type GraderConfig = (GraderCommon & {
|
|
|
116
132
|
}) | (GraderCommon & {
|
|
117
133
|
type: "goal_reached";
|
|
118
134
|
judge?: string;
|
|
135
|
+
judge_settings?: JudgeSettings;
|
|
119
136
|
guidance?: string;
|
|
120
137
|
});
|
|
121
138
|
export type EvalFile = {
|
|
@@ -143,7 +160,11 @@ export type AgentTargetRef = {
|
|
|
143
160
|
agentId: string;
|
|
144
161
|
revision?: number;
|
|
145
162
|
};
|
|
146
|
-
export type
|
|
163
|
+
export type InternalAgentTargetRef = {
|
|
164
|
+
kind: "internal_agent";
|
|
165
|
+
profileId: string;
|
|
166
|
+
};
|
|
167
|
+
export type TargetRef = StageTargetRef | AgentTargetRef | InternalAgentTargetRef;
|
|
147
168
|
type ResolvedGraderCommon = {
|
|
148
169
|
id: string;
|
|
149
170
|
weight: number;
|
|
@@ -168,6 +189,7 @@ export type ResolvedGrader = (ResolvedGraderCommon & {
|
|
|
168
189
|
scale: "pass_fail" | "1_to_5";
|
|
169
190
|
passAt: number;
|
|
170
191
|
judge: string;
|
|
192
|
+
judgeSettings?: JudgeSettings;
|
|
171
193
|
examples: RubricExample[];
|
|
172
194
|
}) | (ResolvedGraderCommon & {
|
|
173
195
|
type: "code";
|
|
@@ -187,6 +209,7 @@ export type ResolvedGrader = (ResolvedGraderCommon & {
|
|
|
187
209
|
}) | (ResolvedGraderCommon & {
|
|
188
210
|
type: "goal_reached";
|
|
189
211
|
judge: string;
|
|
212
|
+
judgeSettings?: JudgeSettings;
|
|
190
213
|
guidance?: string;
|
|
191
214
|
});
|
|
192
215
|
export type PlanCase = {
|
package/dist/evals/types.js
CHANGED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { NormalizedGrade } from "./types.js";
|
|
2
|
+
export declare const JUDGE_ERROR_CODE = "EVAL_JUDGE_ERROR";
|
|
3
|
+
/**
|
|
4
|
+
* One grade from several votes: the majority verdict for pass/fail (a tie fails), the mean raw score for 1 to 5.
|
|
5
|
+
* Errored votes are left out; if every vote errored the grade is an error. Tokens and cost add up over all votes.
|
|
6
|
+
*/
|
|
7
|
+
export declare function combineVotes(grader: {
|
|
8
|
+
scale: "pass_fail" | "1_to_5";
|
|
9
|
+
passAt: number;
|
|
10
|
+
}, votes: readonly NormalizedGrade[]): NormalizedGrade;
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { normalizeOneToFive } from "./scoring.js";
|
|
2
|
+
import { majorityPasses, meanOf } from "./stats.js";
|
|
3
|
+
export const JUDGE_ERROR_CODE = "EVAL_JUDGE_ERROR";
|
|
4
|
+
/**
|
|
5
|
+
* One grade from several votes: the majority verdict for pass/fail (a tie fails), the mean raw score for 1 to 5.
|
|
6
|
+
* Errored votes are left out; if every vote errored the grade is an error. Tokens and cost add up over all votes.
|
|
7
|
+
*/
|
|
8
|
+
export function combineVotes(grader, votes) {
|
|
9
|
+
const first = votes[0];
|
|
10
|
+
if (votes.length === 1)
|
|
11
|
+
return first;
|
|
12
|
+
const valid = votes.filter((g) => g.status === "graded" && g.passed !== undefined);
|
|
13
|
+
const sum = (pick) => votes.reduce((total, g) => total + (pick(g) ?? 0), 0);
|
|
14
|
+
const totals = {
|
|
15
|
+
judgeTokensIn: sum((g) => g.judgeTokensIn),
|
|
16
|
+
judgeTokensOut: sum((g) => g.judgeTokensOut),
|
|
17
|
+
judgeCostUsd: sum((g) => g.judgeCostUsd),
|
|
18
|
+
};
|
|
19
|
+
const priceUnknown = votes.some((g) => g.details?.judgeCostUnknown);
|
|
20
|
+
const record = votes.map((g) => ({
|
|
21
|
+
status: g.status,
|
|
22
|
+
...(g.passed !== undefined ? { passed: g.passed } : {}),
|
|
23
|
+
...(g.rawValue !== undefined ? { raw_value: g.rawValue } : {}),
|
|
24
|
+
...(g.reason !== undefined ? { reason: g.reason } : {}),
|
|
25
|
+
}));
|
|
26
|
+
const baseDetails = {
|
|
27
|
+
...(first.details ?? {}),
|
|
28
|
+
...(priceUnknown ? { judgeCostUnknown: true } : {}),
|
|
29
|
+
votes: record,
|
|
30
|
+
};
|
|
31
|
+
if (valid.length === 0) {
|
|
32
|
+
return { ...first, ...totals, status: "error", errorCode: first.errorCode ?? JUDGE_ERROR_CODE, details: baseDetails };
|
|
33
|
+
}
|
|
34
|
+
let passed;
|
|
35
|
+
let rawValue;
|
|
36
|
+
let score;
|
|
37
|
+
if (grader.scale === "1_to_5") {
|
|
38
|
+
rawValue = meanOf(valid.map((g) => g.rawValue ?? 0));
|
|
39
|
+
score = normalizeOneToFive(rawValue);
|
|
40
|
+
passed = rawValue >= grader.passAt;
|
|
41
|
+
}
|
|
42
|
+
else {
|
|
43
|
+
passed = majorityPasses(valid.filter((g) => g.passed === true).length, valid.length);
|
|
44
|
+
rawValue = passed ? 1 : 0;
|
|
45
|
+
score = rawValue;
|
|
46
|
+
}
|
|
47
|
+
const lead = valid.find((g) => g.passed === passed) ?? valid[0];
|
|
48
|
+
return {
|
|
49
|
+
graderId: first.graderId,
|
|
50
|
+
graderType: first.graderType,
|
|
51
|
+
status: "graded",
|
|
52
|
+
passed,
|
|
53
|
+
score,
|
|
54
|
+
rawValue,
|
|
55
|
+
...(lead.reason !== undefined ? { reason: lead.reason } : {}),
|
|
56
|
+
...(first.judgeModel !== undefined ? { judgeModel: first.judgeModel } : {}),
|
|
57
|
+
...totals,
|
|
58
|
+
details: baseDetails,
|
|
59
|
+
};
|
|
60
|
+
}
|