stageflow 0.42.0 → 0.44.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/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/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.js +21 -3
- 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 +43 -2
- 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/constants.d.ts +3 -1
- package/dist/evals/constants.js +3 -1
- package/dist/evals/engine/FakeEngine.d.ts +1 -1
- package/dist/evals/engine/FakeEngine.js +2 -1
- package/dist/evals/engine/promptfoo/PromptfooEngine.d.ts +1 -1
- package/dist/evals/engine/promptfoo/PromptfooEngine.js +2 -1
- package/dist/evals/engine/promptfoo/generate.d.ts +1 -1
- package/dist/evals/engine/promptfoo/generate.js +11 -8
- package/dist/evals/engine/promptfoo/rubricPrompt.d.ts +1 -1
- package/dist/evals/engine/promptfoo/rubricPrompt.js +5 -3
- package/dist/evals/manager.d.ts +13 -0
- package/dist/evals/manager.js +10 -2
- package/dist/evals/plan.d.ts +8 -1
- package/dist/evals/plan.js +28 -9
- package/dist/evals/planInternalAgent.d.ts +19 -0
- package/dist/evals/planInternalAgent.js +205 -0
- package/dist/evals/read/api.d.ts +12 -0
- package/dist/evals/read/api.js +5 -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/types.d.ts +12 -2
- package/dist/evals/types.js +4 -1
- 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 +684 -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 +132 -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/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 +1 -0
- package/dist/runstore/sqlite/SqliteRunStore.js +45 -45
- 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 +38 -9
- 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 +39 -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-S5C_vemc.js} +2 -2
- package/dist/ui/assets/adapters-C0l4ruiR.js +17 -0
- package/dist/ui/assets/chat-CjnsmvqR.js +2 -0
- package/dist/ui/assets/chat-DFDd4UjS.css +2 -0
- package/dist/ui/assets/{main-CHlmTNJe.css → main-Del1GeLf.css} +1 -1
- package/dist/ui/assets/main-_yXVqcW9.js +277 -0
- 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/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,205 @@
|
|
|
1
|
+
import path from "node:path";
|
|
2
|
+
import { checkDatasetAgainstAgent } from "../config/datasetAgentCheck.js";
|
|
3
|
+
import { EVAL_AGENT_DEFAULT_CONCURRENCY, EVAL_AGENT_DEFAULT_MAX_COST_USD, EVAL_DEFAULT_PASS_THRESHOLD, EVAL_DEFAULT_REPEATS, resolveConversation, resolveEvalPaths, } from "../config/loadEval.js";
|
|
4
|
+
import { EVAL_LARGE_RUN, EVAL_TOO_LARGE_RUN, evalFinding } from "../config/validateEval.js";
|
|
5
|
+
import { PACKAGE_VERSION } from "../package-meta.js";
|
|
6
|
+
import { sha256Hex } from "./canonical.js";
|
|
7
|
+
import { EVAL_LIMITS, SIMULATOR_PROMPT_VERSION } from "./constants.js";
|
|
8
|
+
import { buildComponents, buildSnapshot, computeFingerprint } from "./snapshot.js";
|
|
9
|
+
function posix(projectRoot, abs) {
|
|
10
|
+
return path.relative(projectRoot, abs).split(path.sep).join("/");
|
|
11
|
+
}
|
|
12
|
+
function selectCases(cases, overrides, failedIds) {
|
|
13
|
+
if (overrides.case_ids !== undefined)
|
|
14
|
+
return cases.filter((c) => overrides.case_ids.includes(c.id));
|
|
15
|
+
if (overrides.tags !== undefined) {
|
|
16
|
+
const wanted = new Set(overrides.tags);
|
|
17
|
+
return cases.filter((c) => (c.tags ?? []).some((tag) => wanted.has(tag)));
|
|
18
|
+
}
|
|
19
|
+
if (failedIds !== undefined)
|
|
20
|
+
return cases.filter((c) => failedIds.has(c.id));
|
|
21
|
+
return [...cases];
|
|
22
|
+
}
|
|
23
|
+
export function planInternalAgent(args) {
|
|
24
|
+
const { input, loaded, dataset, overrides, failedIds } = args;
|
|
25
|
+
const findings = [...args.findings];
|
|
26
|
+
const fail = (extra) => ({ ok: false, code: "EVAL_INVALID", findings: [...findings, ...extra] });
|
|
27
|
+
if (loaded.file.target.kind !== "internal_agent")
|
|
28
|
+
return fail([]);
|
|
29
|
+
const profileId = loaded.file.target.profile;
|
|
30
|
+
const profiles = input.internalAgents ?? [];
|
|
31
|
+
const profile = profiles.find((item) => item.id === profileId);
|
|
32
|
+
if (!profile) {
|
|
33
|
+
return fail([
|
|
34
|
+
evalFinding(loaded.relPath, "error", profiles.length === 0 ? "eval.internal_agent_unavailable" : "eval.internal_agent_unknown", profiles.length === 0
|
|
35
|
+
? "This Host is not showing internal agents, so this eval cannot run"
|
|
36
|
+
: `This Host has no internal agent "${profileId}"`),
|
|
37
|
+
]);
|
|
38
|
+
}
|
|
39
|
+
if (overrides.case_ids !== undefined) {
|
|
40
|
+
const known = new Set(dataset.cases.map((c) => c.id));
|
|
41
|
+
const unknown = overrides.case_ids.filter((id) => !known.has(id));
|
|
42
|
+
if (unknown.length > 0) {
|
|
43
|
+
return fail([
|
|
44
|
+
evalFinding(loaded.relPath, "error", "eval.invalid_field", `Override "case_ids" names ${unknown.length} case(s) not in the dataset; first: ${unknown[0]}`),
|
|
45
|
+
]);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
const conversation = resolveConversation(loaded.file.conversation);
|
|
49
|
+
if (conversation.tools === "real") {
|
|
50
|
+
return fail([
|
|
51
|
+
evalFinding(loaded.relPath, "error", "eval.internal_agent_real_tools", "An internal agent eval cannot use real tools"),
|
|
52
|
+
]);
|
|
53
|
+
}
|
|
54
|
+
const checks = new Map(checkDatasetAgainstAgent(dataset.cases, { mode: conversation.mode }).map((r) => [r.caseId, r.valid]));
|
|
55
|
+
const validCases = dataset.cases.filter((c) => checks.get(c.id) !== false);
|
|
56
|
+
const selected = selectCases(dataset.cases, overrides, failedIds);
|
|
57
|
+
const skippedCaseIds = selected.filter((c) => checks.get(c.id) === false).map((c) => c.id);
|
|
58
|
+
const runCases = selected.filter((c) => checks.get(c.id) !== false);
|
|
59
|
+
const positionOf = new Map(dataset.cases.map((c, i) => [c.id, i]));
|
|
60
|
+
const planCases = runCases.map((c) => ({
|
|
61
|
+
id: c.id,
|
|
62
|
+
position: positionOf.get(c.id) ?? 0,
|
|
63
|
+
...(c.title !== undefined ? { title: c.title } : {}),
|
|
64
|
+
...(c.goal !== undefined ? { goal: c.goal } : {}),
|
|
65
|
+
input: c.input,
|
|
66
|
+
...(c.expected !== undefined ? { expected: c.expected } : {}),
|
|
67
|
+
tags: c.tags ?? [],
|
|
68
|
+
...(c.metadata !== undefined ? { metadata: c.metadata } : {}),
|
|
69
|
+
}));
|
|
70
|
+
const repeats = loaded.file.defaults?.repeats ?? EVAL_DEFAULT_REPEATS;
|
|
71
|
+
const results = planCases.length * repeats;
|
|
72
|
+
if (planCases.length === 0) {
|
|
73
|
+
return fail([evalFinding(loaded.relPath, "error", "eval.no_valid_cases", "No valid cases are left to run after case selection and skipping")]);
|
|
74
|
+
}
|
|
75
|
+
if (results > EVAL_LIMITS.maxResultsPerRun) {
|
|
76
|
+
return fail([
|
|
77
|
+
evalFinding(loaded.relPath, "error", "eval.too_large_run", `${planCases.length} case(s) x ${repeats} repeat(s) = ${results} results, over the ${EVAL_TOO_LARGE_RUN} limit`),
|
|
78
|
+
]);
|
|
79
|
+
}
|
|
80
|
+
if (results > EVAL_LARGE_RUN) {
|
|
81
|
+
findings.push(evalFinding(loaded.relPath, "warning", "eval.large_run", `${planCases.length} case(s) x ${repeats} repeat(s) = ${results} results, over ${EVAL_LARGE_RUN}`));
|
|
82
|
+
}
|
|
83
|
+
const defaults = loaded.file.defaults ?? {};
|
|
84
|
+
const passThreshold = defaults.pass_threshold ?? EVAL_DEFAULT_PASS_THRESHOLD;
|
|
85
|
+
const concurrency = defaults.concurrency ?? EVAL_AGENT_DEFAULT_CONCURRENCY;
|
|
86
|
+
const maxCostUsd = defaults.max_cost_usd ?? EVAL_AGENT_DEFAULT_MAX_COST_USD;
|
|
87
|
+
const judge = defaults.judge ?? "";
|
|
88
|
+
const model = defaults.model ?? "";
|
|
89
|
+
const playbookHash = sha256Hex(profile.playbook);
|
|
90
|
+
const definitionHash = sha256Hex(JSON.stringify({ playbook: profile.playbook, tools: profile.tools }));
|
|
91
|
+
const userModel = planCases.some((c) => c.input.mode === "simulated") ? (defaults.user_model ?? null) : null;
|
|
92
|
+
const paths = resolveEvalPaths(loaded.file, loaded.path);
|
|
93
|
+
const projectRoot = input.projectRoot;
|
|
94
|
+
const components = buildComponents({
|
|
95
|
+
stageVersionHash: definitionHash,
|
|
96
|
+
model,
|
|
97
|
+
datasetHash: dataset.contentHash,
|
|
98
|
+
caseIds: runCases.length < validCases.length ? runCases.map((c) => c.id) : null,
|
|
99
|
+
graders: loaded.graders,
|
|
100
|
+
judge,
|
|
101
|
+
repeats,
|
|
102
|
+
passThreshold,
|
|
103
|
+
engine: input.engine,
|
|
104
|
+
agent: {
|
|
105
|
+
revision: 0,
|
|
106
|
+
mode: conversation.mode,
|
|
107
|
+
max_turns: conversation.maxTurns,
|
|
108
|
+
turn_timeout_ms: conversation.turnTimeoutMs,
|
|
109
|
+
tools: conversation.tools,
|
|
110
|
+
approvals: conversation.approvals,
|
|
111
|
+
read_only_tools: conversation.readOnlyTools,
|
|
112
|
+
user_model: userModel,
|
|
113
|
+
simulator_prompt_version: SIMULATOR_PROMPT_VERSION,
|
|
114
|
+
},
|
|
115
|
+
});
|
|
116
|
+
const fingerprint = computeFingerprint(components);
|
|
117
|
+
const snapshotOverrides = {
|
|
118
|
+
repeats: overrides.repeats ?? null,
|
|
119
|
+
judge: overrides.judge ?? null,
|
|
120
|
+
model: overrides.model ?? null,
|
|
121
|
+
max_cost_usd: overrides.max_cost_usd ?? null,
|
|
122
|
+
case_ids: overrides.case_ids ?? null,
|
|
123
|
+
tags: overrides.tags ?? null,
|
|
124
|
+
only_failed_from: overrides.only_failed_from ?? null,
|
|
125
|
+
};
|
|
126
|
+
const snapshot = buildSnapshot({
|
|
127
|
+
evalId: loaded.id,
|
|
128
|
+
evalPath: loaded.relPath,
|
|
129
|
+
evalHash: loaded.fileHash,
|
|
130
|
+
evalDefinition: {
|
|
131
|
+
version: 1,
|
|
132
|
+
id: loaded.id,
|
|
133
|
+
target: { kind: "internal_agent", profile: profileId },
|
|
134
|
+
dataset: posix(projectRoot, paths.datasetPath),
|
|
135
|
+
},
|
|
136
|
+
overrides: snapshotOverrides,
|
|
137
|
+
target: {
|
|
138
|
+
profile_id: profileId,
|
|
139
|
+
title: profile.title,
|
|
140
|
+
playbook_hash: playbookHash,
|
|
141
|
+
tools: profile.tools,
|
|
142
|
+
model,
|
|
143
|
+
},
|
|
144
|
+
dataset: {
|
|
145
|
+
path: posix(projectRoot, paths.datasetPath),
|
|
146
|
+
hash: dataset.contentHash,
|
|
147
|
+
format: dataset.format ?? "jsonl",
|
|
148
|
+
case_count: dataset.cases.length,
|
|
149
|
+
cases_run: planCases.length,
|
|
150
|
+
cases_skipped: skippedCaseIds.length,
|
|
151
|
+
skipped_case_ids: skippedCaseIds,
|
|
152
|
+
},
|
|
153
|
+
graders: loaded.graders.map((g) => ({
|
|
154
|
+
id: g.id,
|
|
155
|
+
type: g.type,
|
|
156
|
+
hash: g.hash,
|
|
157
|
+
version_ordinal: input.graderOrdinals?.[g.id] ?? 1,
|
|
158
|
+
weight: g.weight,
|
|
159
|
+
must_pass: g.mustPass,
|
|
160
|
+
})),
|
|
161
|
+
settings: {
|
|
162
|
+
repeats,
|
|
163
|
+
pass_threshold: passThreshold,
|
|
164
|
+
judge,
|
|
165
|
+
judge_same_as_stage: false,
|
|
166
|
+
max_cost_usd: maxCostUsd,
|
|
167
|
+
concurrency,
|
|
168
|
+
suite_type: loaded.file.type ?? "capability",
|
|
169
|
+
conversation: {
|
|
170
|
+
mode: conversation.mode,
|
|
171
|
+
max_turns: conversation.maxTurns,
|
|
172
|
+
turn_timeout_ms: conversation.turnTimeoutMs,
|
|
173
|
+
tools: conversation.tools,
|
|
174
|
+
approvals: conversation.approvals,
|
|
175
|
+
read_only_tools: conversation.readOnlyTools,
|
|
176
|
+
real_tools_confirmed: false,
|
|
177
|
+
user_model: userModel ?? "",
|
|
178
|
+
user_model_from_judge: false,
|
|
179
|
+
simulator_prompt_version: SIMULATOR_PROMPT_VERSION,
|
|
180
|
+
},
|
|
181
|
+
},
|
|
182
|
+
engine: input.engine,
|
|
183
|
+
stageflowVersion: PACKAGE_VERSION,
|
|
184
|
+
});
|
|
185
|
+
const plan = {
|
|
186
|
+
evalRunId: input.evalRunId,
|
|
187
|
+
projectRoot,
|
|
188
|
+
evalId: loaded.id,
|
|
189
|
+
target: { kind: "internal_agent", profileId },
|
|
190
|
+
targetVersionHash: definitionHash,
|
|
191
|
+
stageModel: model,
|
|
192
|
+
task: {},
|
|
193
|
+
cases: planCases,
|
|
194
|
+
graders: loaded.graders,
|
|
195
|
+
repeats,
|
|
196
|
+
passThreshold,
|
|
197
|
+
concurrency,
|
|
198
|
+
maxCostUsd,
|
|
199
|
+
...(model !== "" ? { modelOverride: model } : {}),
|
|
200
|
+
conversation,
|
|
201
|
+
userModel,
|
|
202
|
+
agent: { definitionHash, definition: { id: profileId, title: profile.title, tools: profile.tools } },
|
|
203
|
+
};
|
|
204
|
+
return { ok: true, plan, snapshot, fingerprint, components, skippedCaseIds, findings };
|
|
205
|
+
}
|
package/dist/evals/read/api.d.ts
CHANGED
|
@@ -54,6 +54,12 @@ export declare function planFindings(input: {
|
|
|
54
54
|
datasetCases?: readonly unknown[];
|
|
55
55
|
isKnownModel?: IsKnownModel;
|
|
56
56
|
agents?: AgentCatalogPort;
|
|
57
|
+
internalAgents?: ReadonlyArray<{
|
|
58
|
+
id: string;
|
|
59
|
+
title: string;
|
|
60
|
+
playbook: string;
|
|
61
|
+
tools: string[];
|
|
62
|
+
}>;
|
|
57
63
|
}): Promise<{
|
|
58
64
|
ok: boolean;
|
|
59
65
|
findings: ValidationFinding[];
|
|
@@ -65,6 +71,12 @@ export declare function validateEvalText(input: {
|
|
|
65
71
|
datasetCases?: readonly unknown[];
|
|
66
72
|
isKnownModel?: IsKnownModel;
|
|
67
73
|
agents?: AgentCatalogPort;
|
|
74
|
+
internalAgents?: ReadonlyArray<{
|
|
75
|
+
id: string;
|
|
76
|
+
title: string;
|
|
77
|
+
playbook: string;
|
|
78
|
+
tools: string[];
|
|
79
|
+
}>;
|
|
68
80
|
}): Promise<{
|
|
69
81
|
findings: ValidationFinding[];
|
|
70
82
|
parsed: import("../../config/loadOutcome.js").LoadOutcome<LoadedEval>;
|
package/dist/evals/read/api.js
CHANGED
|
@@ -99,6 +99,9 @@ export async function buildEvalDetail(input) {
|
|
|
99
99
|
agent = await liveAgentOf(input.agents, projectRoot, file.target.agent);
|
|
100
100
|
targetModel = file.defaults?.model ?? agent?.model ?? null;
|
|
101
101
|
}
|
|
102
|
+
else if (file.target.kind === "internal_agent") {
|
|
103
|
+
targetModel = file.defaults?.model ?? null;
|
|
104
|
+
}
|
|
102
105
|
else {
|
|
103
106
|
const target = await resolveEvalTarget(file, entry.outcome.value.path, projectRoot);
|
|
104
107
|
if (target.ok)
|
|
@@ -130,6 +133,7 @@ export async function planFindings(input) {
|
|
|
130
133
|
engine: { name: ENGINE_NAME, version: PINNED_PROMPTFOO_VERSION, nodeVersion: process.versions.node },
|
|
131
134
|
...(input.isKnownModel ? { isKnownModel: input.isKnownModel } : {}),
|
|
132
135
|
...(input.agents ? { agents: input.agents } : {}),
|
|
136
|
+
...(input.internalAgents ? { internalAgents: input.internalAgents } : {}),
|
|
133
137
|
});
|
|
134
138
|
return { ok: built.ok, findings: built.findings };
|
|
135
139
|
}
|
|
@@ -143,6 +147,7 @@ export async function validateEvalText(input) {
|
|
|
143
147
|
...(input.datasetCases !== undefined ? { datasetCases: input.datasetCases } : {}),
|
|
144
148
|
...(input.isKnownModel ? { isKnownModel: input.isKnownModel } : {}),
|
|
145
149
|
...(input.agents ? { agents: input.agents } : {}),
|
|
150
|
+
...(input.internalAgents ? { internalAgents: input.internalAgents } : {}),
|
|
146
151
|
});
|
|
147
152
|
const findings = checked.findings.length > 0 || parsed.ok
|
|
148
153
|
? checked.findings
|
package/dist/evals/read/list.js
CHANGED
|
@@ -103,7 +103,16 @@ export async function buildEvalListItems(input) {
|
|
|
103
103
|
bannerInputs.push({ evalId: loaded.id, status, last: lastSummary, previous: previousSummary });
|
|
104
104
|
const agentTarget = file.target.kind === "agent"
|
|
105
105
|
? await agentListTarget(file.target.agent, last, input.agents, projectRoot)
|
|
106
|
-
:
|
|
106
|
+
: file.target.kind === "internal_agent"
|
|
107
|
+
? {
|
|
108
|
+
kind: "agent",
|
|
109
|
+
agent_id: file.target.profile,
|
|
110
|
+
agent_name: file.target.profile,
|
|
111
|
+
model: file.defaults?.model ?? null,
|
|
112
|
+
revision: null,
|
|
113
|
+
label: `${file.target.profile} (internal)`,
|
|
114
|
+
}
|
|
115
|
+
: undefined;
|
|
107
116
|
const conv = agentTarget ? resolveConversation(file.conversation) : undefined;
|
|
108
117
|
const pipelinePath = paths.pipelinePath !== undefined ? posix(projectRoot, paths.pipelinePath) : undefined;
|
|
109
118
|
const stageFile = paths.stageFile !== undefined ? posix(projectRoot, paths.stageFile) : undefined;
|
|
@@ -106,6 +106,11 @@ export type EvalRunDetail = {
|
|
|
106
106
|
stats: Stats | null;
|
|
107
107
|
lowest_cases_by_grader: Record<string, LowestCase[]>;
|
|
108
108
|
current: RunCurrent;
|
|
109
|
+
cases: Array<{
|
|
110
|
+
id: string;
|
|
111
|
+
title: string | null;
|
|
112
|
+
position: number;
|
|
113
|
+
}>;
|
|
109
114
|
live?: Array<{
|
|
110
115
|
case_id: string;
|
|
111
116
|
repeat_index: number;
|
package/dist/evals/read/runs.js
CHANGED
|
@@ -218,11 +218,16 @@ export async function currentHashes(row, agents) {
|
|
|
218
218
|
return none;
|
|
219
219
|
}
|
|
220
220
|
}
|
|
221
|
+
function plannedCase(row) {
|
|
222
|
+
const title = row.case.title;
|
|
223
|
+
return { id: row.caseId, title: typeof title === "string" && title !== "" ? title : null, position: row.position };
|
|
224
|
+
}
|
|
221
225
|
export async function buildRunDetail(input) {
|
|
222
226
|
const { store, row } = input;
|
|
223
|
-
const [results, reviews] = await Promise.all([
|
|
227
|
+
const [results, reviews, storedCases] = await Promise.all([
|
|
224
228
|
store.listEvalResults(row.evalRunId),
|
|
225
229
|
store.getEvalReviews(row.evalRunId),
|
|
230
|
+
store.getEvalCases(row.evalRunId),
|
|
226
231
|
]);
|
|
227
232
|
const graders = graderRefsOf(row);
|
|
228
233
|
const grades = results.flatMap(toGradeRecords);
|
|
@@ -258,6 +263,7 @@ export async function buildRunDetail(input) {
|
|
|
258
263
|
? Object.fromEntries(graders.map((g) => [g.id, lowestCases(grades.filter((x) => x.graderId === g.id))]))
|
|
259
264
|
: {},
|
|
260
265
|
current: await currentHashes(row, input.agents),
|
|
266
|
+
cases: storedCases.map(plannedCase),
|
|
261
267
|
};
|
|
262
268
|
if (input.live && (row.status === "running" || row.status === "queued")) {
|
|
263
269
|
detail.live = input.live.phases.map((p) => ({
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import type { StageCaseRunner } from "./stageCaseRunner.js";
|
|
2
2
|
export type EvalCaseRunner = StageCaseRunner;
|
|
3
|
-
/** Routes each case to the stage or agent runner by the plan's target kind. */
|
|
3
|
+
/** Routes each case to the stage, agent, or internal-agent runner by the plan's target kind. */
|
|
4
4
|
export declare function createEvalCaseRunner(deps: {
|
|
5
5
|
stage: StageCaseRunner;
|
|
6
6
|
agent: StageCaseRunner;
|
|
7
|
+
internalAgent?: StageCaseRunner;
|
|
7
8
|
}): EvalCaseRunner;
|
|
@@ -1,16 +1,27 @@
|
|
|
1
|
-
|
|
1
|
+
import { isConversationTarget } from "../types.js";
|
|
2
|
+
/** Routes each case to the stage, agent, or internal-agent runner by the plan's target kind. */
|
|
2
3
|
export function createEvalCaseRunner(deps) {
|
|
3
4
|
const kinds = new Map();
|
|
4
|
-
const runnerOf = (evalRunId) =>
|
|
5
|
+
const runnerOf = (evalRunId) => {
|
|
6
|
+
const kind = kinds.get(evalRunId);
|
|
7
|
+
if (kind === "internal_agent" && deps.internalAgent)
|
|
8
|
+
return deps.internalAgent;
|
|
9
|
+
return kind === "agent" ? deps.agent : deps.stage;
|
|
10
|
+
};
|
|
5
11
|
return {
|
|
6
12
|
runCase(plan, req) {
|
|
7
|
-
|
|
13
|
+
const kind = plan.target.kind === "internal_agent" ? "internal_agent" : isConversationTarget(plan.target.kind) ? "agent" : "stage";
|
|
14
|
+
kinds.set(req.evalRunId, kind);
|
|
8
15
|
return runnerOf(req.evalRunId).runCase(plan, req);
|
|
9
16
|
},
|
|
10
17
|
async cancelAll(evalRunId) {
|
|
11
|
-
await Promise.all([
|
|
18
|
+
await Promise.all([
|
|
19
|
+
deps.stage.cancelAll(evalRunId),
|
|
20
|
+
deps.agent.cancelAll(evalRunId),
|
|
21
|
+
deps.internalAgent?.cancelAll(evalRunId),
|
|
22
|
+
]);
|
|
12
23
|
},
|
|
13
|
-
spend: (evalRunId) => deps.stage.spend(evalRunId) + deps.agent.spend(evalRunId),
|
|
24
|
+
spend: (evalRunId) => deps.stage.spend(evalRunId) + deps.agent.spend(evalRunId) + (deps.internalAgent?.spend(evalRunId) ?? 0),
|
|
14
25
|
addSpend: (evalRunId, usd) => runnerOf(evalRunId).addSpend(evalRunId, usd),
|
|
15
26
|
stopReason: (evalRunId) => runnerOf(evalRunId).stopReason?.(evalRunId),
|
|
16
27
|
};
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { OperatorAgentHost } from "../../operatorAgent/types.js";
|
|
2
|
+
import type { StageCaseRunner } from "./stageCaseRunner.js";
|
|
3
|
+
export declare function createInternalAgentCaseRunner(deps: {
|
|
4
|
+
host: () => OperatorAgentHost | undefined;
|
|
5
|
+
now?: () => number;
|
|
6
|
+
}): StageCaseRunner;
|
|
@@ -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"];
|