stageflow 0.40.0 → 0.42.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.
Files changed (326) hide show
  1. package/README.md +3 -1
  2. package/dist/agents/authorChat.d.ts +4 -0
  3. package/dist/agents/authorChat.js +113 -12
  4. package/dist/agents/authorSessionStore.d.ts +35 -0
  5. package/dist/agents/authorSessionStore.js +152 -0
  6. package/dist/agents/chatTurn.d.ts +2 -0
  7. package/dist/agents/chatTurn.js +17 -1
  8. package/dist/agents/errors.d.ts +1 -1
  9. package/dist/agents/errors.js +1 -0
  10. package/dist/agents/evalGate.d.ts +61 -0
  11. package/dist/agents/evalGate.js +103 -0
  12. package/dist/agents/evalSession.d.ts +26 -0
  13. package/dist/agents/evalSession.js +29 -0
  14. package/dist/agents/hostContext.d.ts +3 -0
  15. package/dist/agents/hostContext.js +4 -1
  16. package/dist/agents/runtime/piRuntime.d.ts +1 -1
  17. package/dist/agents/runtime/piRuntime.js +4 -4
  18. package/dist/agents/runtime/types.d.ts +3 -1
  19. package/dist/agents/service.d.ts +27 -2
  20. package/dist/agents/service.js +88 -13
  21. package/dist/agents/sessions.d.ts +8 -0
  22. package/dist/agents/sessions.js +50 -10
  23. package/dist/agents/store.d.ts +14 -3
  24. package/dist/agents/store.js +45 -7
  25. package/dist/agents/toolRisk.d.ts +21 -0
  26. package/dist/agents/toolRisk.js +50 -0
  27. package/dist/cli/doctorCommand.js +26 -0
  28. package/dist/cli/evalCommand.d.ts +20 -0
  29. package/dist/cli/evalCommand.js +720 -0
  30. package/dist/cli/exportAllCommand.js +1 -1
  31. package/dist/cli/hostClient.d.ts +60 -0
  32. package/dist/cli/hostClient.js +71 -0
  33. package/dist/cli/validateOutput.d.ts +2 -2
  34. package/dist/cli/validateOutput.js +2 -2
  35. package/dist/cli.js +10 -0
  36. package/dist/config/atomicWrite.d.ts +15 -0
  37. package/dist/config/atomicWrite.js +43 -0
  38. package/dist/config/browseCatalog.d.ts +2 -0
  39. package/dist/config/browseCatalog.js +4 -2
  40. package/dist/config/csv.d.ts +9 -0
  41. package/dist/config/csv.js +81 -0
  42. package/dist/config/datasetAgentCheck.d.ts +18 -0
  43. package/dist/config/datasetAgentCheck.js +109 -0
  44. package/dist/config/datasetCandidates.d.ts +22 -0
  45. package/dist/config/datasetCandidates.js +86 -0
  46. package/dist/config/datasetFromSessions.d.ts +34 -0
  47. package/dist/config/datasetFromSessions.js +105 -0
  48. package/dist/config/datasetHash.d.ts +1 -0
  49. package/dist/config/datasetHash.js +4 -0
  50. package/dist/config/datasetImport.d.ts +21 -0
  51. package/dist/config/datasetImport.js +120 -0
  52. package/dist/config/datasetStageCheck.d.ts +9 -0
  53. package/dist/config/datasetStageCheck.js +17 -0
  54. package/dist/config/datasetTypes.d.ts +27 -0
  55. package/dist/config/datasetTypes.js +1 -0
  56. package/dist/config/ensureCatalogScanRoot.d.ts +2 -1
  57. package/dist/config/ensureCatalogScanRoot.js +2 -6
  58. package/dist/config/evalCatalog.d.ts +22 -0
  59. package/dist/config/evalCatalog.js +67 -0
  60. package/dist/config/evalWriteRoots.d.ts +17 -0
  61. package/dist/config/evalWriteRoots.js +109 -0
  62. package/dist/config/hostConfig.js +1 -0
  63. package/dist/config/installEvalSample.d.ts +34 -0
  64. package/dist/config/installEvalSample.js +182 -0
  65. package/dist/config/loadDataset.d.ts +16 -0
  66. package/dist/config/loadDataset.js +318 -0
  67. package/dist/config/loadEval.d.ts +32 -0
  68. package/dist/config/loadEval.js +1085 -0
  69. package/dist/config/loadOutcome.d.ts +5 -0
  70. package/dist/config/loadStageflowManifest.js +64 -0
  71. package/dist/config/resolveAgentTarget.d.ts +32 -0
  72. package/dist/config/resolveAgentTarget.js +118 -0
  73. package/dist/config/resolveEvalTarget.d.ts +21 -0
  74. package/dist/config/resolveEvalTarget.js +89 -0
  75. package/dist/config/scanCatalogPaths.d.ts +1 -1
  76. package/dist/config/scanCatalogPaths.js +17 -5
  77. package/dist/config/validateCatalog.d.ts +1 -1
  78. package/dist/config/validateCatalog.js +9 -1
  79. package/dist/config/validateEval.d.ts +36 -0
  80. package/dist/config/validateEval.js +405 -0
  81. package/dist/config/writeDataset.d.ts +54 -0
  82. package/dist/config/writeDataset.js +186 -0
  83. package/dist/config/writeEval.d.ts +25 -0
  84. package/dist/config/writeEval.js +398 -0
  85. package/dist/diagnostics/checks.js +1 -1
  86. package/dist/evals/agentDiff.d.ts +13 -0
  87. package/dist/evals/agentDiff.js +11 -0
  88. package/dist/evals/canonical.d.ts +3 -0
  89. package/dist/evals/canonical.js +24 -0
  90. package/dist/evals/caseTask.d.ts +3 -0
  91. package/dist/evals/caseTask.js +9 -0
  92. package/dist/evals/compare.d.ts +94 -0
  93. package/dist/evals/compare.js +201 -0
  94. package/dist/evals/constants.d.ts +60 -0
  95. package/dist/evals/constants.js +95 -0
  96. package/dist/evals/engine/FakeEngine.d.ts +33 -0
  97. package/dist/evals/engine/FakeEngine.js +176 -0
  98. package/dist/evals/engine/index.d.ts +9 -0
  99. package/dist/evals/engine/index.js +19 -0
  100. package/dist/evals/engine/promptfoo/PromptfooEngine.d.ts +52 -0
  101. package/dist/evals/engine/promptfoo/PromptfooEngine.js +311 -0
  102. package/dist/evals/engine/promptfoo/errors.d.ts +5 -0
  103. package/dist/evals/engine/promptfoo/errors.js +8 -0
  104. package/dist/evals/engine/promptfoo/generate.d.ts +30 -0
  105. package/dist/evals/engine/promptfoo/generate.js +342 -0
  106. package/dist/evals/engine/promptfoo/guard.d.ts +10 -0
  107. package/dist/evals/engine/promptfoo/guard.js +116 -0
  108. package/dist/evals/engine/promptfoo/install.d.ts +17 -0
  109. package/dist/evals/engine/promptfoo/install.js +73 -0
  110. package/dist/evals/engine/promptfoo/judgeProviders.d.ts +2 -0
  111. package/dist/evals/engine/promptfoo/judgeProviders.js +9 -0
  112. package/dist/evals/engine/promptfoo/judgeServices.d.ts +6 -0
  113. package/dist/evals/engine/promptfoo/judgeServices.js +41 -0
  114. package/dist/evals/engine/promptfoo/locate.d.ts +21 -0
  115. package/dist/evals/engine/promptfoo/locate.js +68 -0
  116. package/dist/evals/engine/promptfoo/nodeVersion.d.ts +7 -0
  117. package/dist/evals/engine/promptfoo/nodeVersion.js +14 -0
  118. package/dist/evals/engine/promptfoo/normalize.d.ts +66 -0
  119. package/dist/evals/engine/promptfoo/normalize.js +261 -0
  120. package/dist/evals/engine/promptfoo/pinned.d.ts +5 -0
  121. package/dist/evals/engine/promptfoo/pinned.js +5 -0
  122. package/dist/evals/engine/promptfoo/rubricPrompt.d.ts +14 -0
  123. package/dist/evals/engine/promptfoo/rubricPrompt.js +103 -0
  124. package/dist/evals/engine/promptfoo/runTokens.d.ts +18 -0
  125. package/dist/evals/engine/promptfoo/runTokens.js +31 -0
  126. package/dist/evals/engine/promptfoo/status.d.ts +13 -0
  127. package/dist/evals/engine/promptfoo/status.js +16 -0
  128. package/dist/evals/estimate.d.ts +56 -0
  129. package/dist/evals/estimate.js +66 -0
  130. package/dist/evals/graders/codeGrader.d.ts +6 -0
  131. package/dist/evals/graders/codeGrader.js +85 -0
  132. package/dist/evals/graders/conversationCheckGrader.d.ts +6 -0
  133. package/dist/evals/graders/conversationCheckGrader.js +62 -0
  134. package/dist/evals/graders/fieldGrader.d.ts +11 -0
  135. package/dist/evals/graders/fieldGrader.js +117 -0
  136. package/dist/evals/graders/goal.d.ts +3 -0
  137. package/dist/evals/graders/goal.js +14 -0
  138. package/dist/evals/graders/index.d.ts +18 -0
  139. package/dist/evals/graders/index.js +34 -0
  140. package/dist/evals/graders/notApplicable.d.ts +5 -0
  141. package/dist/evals/graders/notApplicable.js +9 -0
  142. package/dist/evals/graders/path.d.ts +26 -0
  143. package/dist/evals/graders/path.js +75 -0
  144. package/dist/evals/graders/referenceGrader.d.ts +5 -0
  145. package/dist/evals/graders/referenceGrader.js +59 -0
  146. package/dist/evals/graders/schemaGrader.d.ts +5 -0
  147. package/dist/evals/graders/schemaGrader.js +29 -0
  148. package/dist/evals/graders/subject.d.ts +6 -0
  149. package/dist/evals/graders/subject.js +33 -0
  150. package/dist/evals/graders/toolCallsGrader.d.ts +6 -0
  151. package/dist/evals/graders/toolCallsGrader.js +100 -0
  152. package/dist/evals/graders/transcript.d.ts +12 -0
  153. package/dist/evals/graders/transcript.js +57 -0
  154. package/dist/evals/graders/types.d.ts +20 -0
  155. package/dist/evals/graders/types.js +1 -0
  156. package/dist/evals/judgeProviders.d.ts +16 -0
  157. package/dist/evals/judgeProviders.js +27 -0
  158. package/dist/evals/lineDiff.d.ts +5 -0
  159. package/dist/evals/lineDiff.js +34 -0
  160. package/dist/evals/listStatus.d.ts +31 -0
  161. package/dist/evals/listStatus.js +48 -0
  162. package/dist/evals/manager.d.ts +174 -0
  163. package/dist/evals/manager.js +787 -0
  164. package/dist/evals/plan.d.ts +58 -0
  165. package/dist/evals/plan.js +602 -0
  166. package/dist/evals/providerKeys.d.ts +1 -0
  167. package/dist/evals/providerKeys.js +21 -0
  168. package/dist/evals/read/agentTargets.d.ts +37 -0
  169. package/dist/evals/read/agentTargets.js +101 -0
  170. package/dist/evals/read/api.d.ts +196 -0
  171. package/dist/evals/read/api.js +358 -0
  172. package/dist/evals/read/compare.d.ts +4 -0
  173. package/dist/evals/read/compare.js +39 -0
  174. package/dist/evals/read/datasets.d.ts +105 -0
  175. package/dist/evals/read/datasets.js +318 -0
  176. package/dist/evals/read/list.d.ts +66 -0
  177. package/dist/evals/read/list.js +173 -0
  178. package/dist/evals/read/results.d.ts +46 -0
  179. package/dist/evals/read/results.js +107 -0
  180. package/dist/evals/read/runs.d.ts +149 -0
  181. package/dist/evals/read/runs.js +289 -0
  182. package/dist/evals/read/suggestions.d.ts +43 -0
  183. package/dist/evals/read/suggestions.js +73 -0
  184. package/dist/evals/runner/FakeAgentBackend.d.ts +40 -0
  185. package/dist/evals/runner/FakeAgentBackend.js +82 -0
  186. package/dist/evals/runner/agentCaseRunner.d.ts +24 -0
  187. package/dist/evals/runner/agentCaseRunner.js +388 -0
  188. package/dist/evals/runner/caseRunner.d.ts +7 -0
  189. package/dist/evals/runner/caseRunner.js +17 -0
  190. package/dist/evals/runner/conversationSubject.d.ts +18 -0
  191. package/dist/evals/runner/conversationSubject.js +123 -0
  192. package/dist/evals/runner/simulatorModel.d.ts +51 -0
  193. package/dist/evals/runner/simulatorModel.js +58 -0
  194. package/dist/evals/runner/simulatorPrompt.d.ts +29 -0
  195. package/dist/evals/runner/simulatorPrompt.js +59 -0
  196. package/dist/evals/runner/stageCaseRunner.d.ts +30 -0
  197. package/dist/evals/runner/stageCaseRunner.js +279 -0
  198. package/dist/evals/runner/userDriver.d.ts +71 -0
  199. package/dist/evals/runner/userDriver.js +104 -0
  200. package/dist/evals/scoring.d.ts +34 -0
  201. package/dist/evals/scoring.js +67 -0
  202. package/dist/evals/snapshot.d.ts +183 -0
  203. package/dist/evals/snapshot.js +65 -0
  204. package/dist/evals/stageDiff.d.ts +8 -0
  205. package/dist/evals/stageDiff.js +48 -0
  206. package/dist/evals/stats.d.ts +95 -0
  207. package/dist/evals/stats.js +220 -0
  208. package/dist/evals/statsAdapter.d.ts +4 -0
  209. package/dist/evals/statsAdapter.js +30 -0
  210. package/dist/evals/statsTypes.d.ts +51 -0
  211. package/dist/evals/statsTypes.js +18 -0
  212. package/dist/evals/storeError.d.ts +5 -0
  213. package/dist/evals/storeError.js +8 -0
  214. package/dist/evals/storeTypes.d.ts +207 -0
  215. package/dist/evals/storeTypes.js +1 -0
  216. package/dist/evals/tTable.d.ts +3 -0
  217. package/dist/evals/tTable.js +15 -0
  218. package/dist/evals/triage/constants.d.ts +26 -0
  219. package/dist/evals/triage/constants.js +33 -0
  220. package/dist/evals/triage/credentials.d.ts +13 -0
  221. package/dist/evals/triage/credentials.js +20 -0
  222. package/dist/evals/triage/jevClassifier.d.ts +14 -0
  223. package/dist/evals/triage/jevClassifier.js +124 -0
  224. package/dist/evals/triage/judgeClassifier.d.ts +10 -0
  225. package/dist/evals/triage/judgeClassifier.js +76 -0
  226. package/dist/evals/triage/prompts.d.ts +16 -0
  227. package/dist/evals/triage/prompts.js +64 -0
  228. package/dist/evals/triage/service.d.ts +79 -0
  229. package/dist/evals/triage/service.js +217 -0
  230. package/dist/evals/triage/stateBuilder.d.ts +19 -0
  231. package/dist/evals/triage/stateBuilder.js +125 -0
  232. package/dist/evals/triage/types.d.ts +60 -0
  233. package/dist/evals/triage/types.js +8 -0
  234. package/dist/evals/types.d.ts +347 -0
  235. package/dist/evals/types.js +1 -0
  236. package/dist/mcp/deps.d.ts +7 -0
  237. package/dist/mcp/evalTools.d.ts +3 -0
  238. package/dist/mcp/evalTools.js +280 -0
  239. package/dist/mcp/server.js +1 -0
  240. package/dist/mcp/tools.js +2 -0
  241. package/dist/models/response.d.ts +7 -2
  242. package/dist/models/response.js +6 -1
  243. package/dist/operatorAgent/agentAuthorContext.d.ts +1 -1
  244. package/dist/operatorAgent/agentAuthorContext.js +1 -1
  245. package/dist/operatorAgent/piModel.js +17 -4
  246. package/dist/operatorAgent/profiles/agentAuthor.d.ts +3 -1
  247. package/dist/operatorAgent/profiles/agentAuthor.js +145 -20
  248. package/dist/operatorAgent/profiles/agentAuthorPlaybook.d.ts +1 -1
  249. package/dist/operatorAgent/profiles/agentAuthorPlaybook.js +48 -15
  250. package/dist/operatorAgent/profiles/authorReadable.d.ts +2 -0
  251. package/dist/operatorAgent/profiles/authorReadable.js +26 -0
  252. package/dist/package-meta.d.ts +1 -1
  253. package/dist/package-meta.js +1 -1
  254. package/dist/runstore/port.d.ts +43 -0
  255. package/dist/runstore/sqlite/SqliteRunStore.d.ts +28 -0
  256. package/dist/runstore/sqlite/SqliteRunStore.js +99 -5
  257. package/dist/runstore/sqlite/evalStore.d.ts +20 -0
  258. package/dist/runstore/sqlite/evalStore.js +541 -0
  259. package/dist/runstore/sqlite/migrations/015-evals.d.ts +12 -0
  260. package/dist/runstore/sqlite/migrations/015-evals.js +157 -0
  261. package/dist/runstore/sqlite/migrations/016-eval-subject-ref.d.ts +12 -0
  262. package/dist/runstore/sqlite/migrations/016-eval-subject-ref.js +20 -0
  263. package/dist/runstore/sqlite/migrations/017-eval-result-suggestions.d.ts +11 -0
  264. package/dist/runstore/sqlite/migrations/017-eval-result-suggestions.js +36 -0
  265. package/dist/runstore/sqlite/migrations/index.js +6 -0
  266. package/dist/runstore/sqlite/suggestionStore.d.ts +14 -0
  267. package/dist/runstore/sqlite/suggestionStore.js +132 -0
  268. package/dist/runtime/pipelineRunner.d.ts +2 -1
  269. package/dist/runtime/pipelineRunner.js +2 -0
  270. package/dist/runtime/runManager.d.ts +2 -1
  271. package/dist/runtime/runManager.js +8 -6
  272. package/dist/runtime/runRetentionSweep.js +2 -2
  273. package/dist/server/agentAuthorRoutes.js +50 -1
  274. package/dist/server/bootstrap.d.ts +8 -0
  275. package/dist/server/bootstrap.js +56 -0
  276. package/dist/server/controlToken.js +3 -0
  277. package/dist/server/evalInternalRoutes.d.ts +14 -0
  278. package/dist/server/evalInternalRoutes.js +87 -0
  279. package/dist/server/evalRouteContext.d.ts +46 -0
  280. package/dist/server/evalRouteContext.js +43 -0
  281. package/dist/server/evalRoutes.d.ts +5 -0
  282. package/dist/server/evalRoutes.js +1427 -0
  283. package/dist/server/evalTriageRoutes.d.ts +2 -0
  284. package/dist/server/evalTriageRoutes.js +95 -0
  285. package/dist/server/http.d.ts +5 -0
  286. package/dist/server/http.js +32 -2
  287. package/dist/server/mcpHost.js +3 -0
  288. package/dist/toolkit/meta.d.ts +1 -1
  289. package/dist/toolkit/meta.js +15 -0
  290. package/dist/toolkit/profiles.js +1 -1
  291. package/dist/types/stageflowManifest.d.ts +6 -0
  292. package/dist/ui/assets/AssistantRuntimeProvider-qIX1xNoH.js +9 -0
  293. package/dist/ui/assets/{MarkdownText-D7tYaIFO.js → MarkdownText-BTrOqu5J.js} +1 -1
  294. package/dist/ui/assets/chat-Df_wCpak.js +5 -0
  295. package/dist/ui/assets/chat-P7KQznHm.css +2 -0
  296. package/dist/ui/assets/{main-BFo79krC.css → main-CHlmTNJe.css} +1 -1
  297. package/dist/ui/assets/main-CvVfxmMd.js +271 -0
  298. package/dist/ui/chat.html +3 -3
  299. package/dist/ui/index.html +3 -3
  300. package/examples/README.md +2 -0
  301. package/examples/document-policy-review/README.md +35 -0
  302. package/examples/document-policy-review/agents/compliance.agent.yaml +42 -0
  303. package/examples/document-policy-review/documents/acme-vendor-sow.md +15 -0
  304. package/examples/document-policy-review/documents/support-runbook.md +13 -0
  305. package/examples/document-policy-review/policies/acceptable-use.md +13 -0
  306. package/examples/document-policy-review/policies/data-handling.md +17 -0
  307. package/examples/document-policy-review/policies/vendor-security.md +17 -0
  308. package/examples/evals/README.md +123 -0
  309. package/examples/evals/critique-sample.dataset.jsonl +8 -0
  310. package/examples/evals/critique-sample.eval.yaml +34 -0
  311. package/examples/evals/critique-sample.task.yaml +4 -0
  312. package/examples/evals/eval-sample.pipeline.yaml +35 -0
  313. package/examples/evals/support-sample.agent.yaml +20 -0
  314. package/examples/evals/support-sample.dataset.jsonl +6 -0
  315. package/examples/evals/support-sample.eval.yaml +38 -0
  316. package/examples/stageflow.yaml +6 -0
  317. package/package.json +1 -1
  318. package/skills/stageflow/SKILL.md +5 -2
  319. package/skills/stageflow/references/control-surface.md +4 -2
  320. package/skills/stageflow/references/evals.md +68 -0
  321. package/skills/stageflow-author/SKILL.md +4 -0
  322. package/skills/stageflow-run/SKILL.md +4 -0
  323. package/dist/ui/assets/AssistantRuntimeProvider-CsiPFhCT.js +0 -9
  324. package/dist/ui/assets/chat-BbLukq9W.js +0 -5
  325. package/dist/ui/assets/chat-zIZU_bP1.css +0 -2
  326. package/dist/ui/assets/main-CijYMeM0.js +0 -259
@@ -0,0 +1,311 @@
1
+ import { spawn as nodeSpawn } from "node:child_process";
2
+ import { closeSync, existsSync, mkdirSync, openSync, readFileSync, readSync, rmSync, statSync, writeFileSync } from "node:fs";
3
+ import path from "node:path";
4
+ import { fileURLToPath, pathToFileURL } from "node:url";
5
+ import { globalStageflowHome } from "../../../project/globalHome.js";
6
+ import { EngineError } from "./errors.js";
7
+ import { CALLBACK_URL_ENV, CONFIG_FILE, RESULTS_FILE, RESULTS_STREAM_FILE, RUN_TOKEN_ENV, generateFiles, } from "./generate.js";
8
+ import { GUARD_FILENAME } from "./guard.js";
9
+ import { mapJudge } from "../../judgeProviders.js";
10
+ import { assertJudgesSupported } from "./judgeProviders.js";
11
+ import { defaultLoadJudgePrices, defaultResolveJudgeKey, } from "./judgeServices.js";
12
+ import { locatePromptfoo } from "./locate.js";
13
+ import { normalizeRecord, recordIdentity, recordsFromResultsFile } from "./normalize.js";
14
+ import { assertNode } from "./nodeVersion.js";
15
+ import { PINNED_PROMPTFOO_VERSION } from "./pinned.js";
16
+ export const PROMPTFOO_KILL_GRACE_MS = 5_000;
17
+ export const PROMPTFOO_STREAM_POLL_MS = 100;
18
+ export const STDERR_TAIL_BYTES = 2048;
19
+ export const KEEP_WORKDIR_ENV = "STAGEFLOW_EVALS_KEEP_WORKDIR";
20
+ export const DISABLE_FLAGS = {
21
+ PROMPTFOO_DISABLE_TELEMETRY: "1",
22
+ PROMPTFOO_DISABLE_UPDATE: "1",
23
+ PROMPTFOO_DISABLE_SHARING: "1",
24
+ PROMPTFOO_DISABLE_REMOTE_GENERATION: "true",
25
+ };
26
+ export function quoteNodeOption(file) {
27
+ return `"${file.replace(/\\/g, "\\\\").replace(/"/g, '\\"')}"`;
28
+ }
29
+ export function buildChildEnv(input) {
30
+ return {
31
+ PATH: input.path ?? process.env.PATH ?? "",
32
+ HOME: input.workDir,
33
+ PROMPTFOO_CONFIG_DIR: path.join(input.workDir, "pf-home"),
34
+ NODE_OPTIONS: `--require ${quoteNodeOption(input.guardPath)}`,
35
+ ...DISABLE_FLAGS,
36
+ [CALLBACK_URL_ENV]: input.callbackUrl,
37
+ [RUN_TOKEN_ENV]: input.token,
38
+ ...input.judgeEnv,
39
+ ...input.extraEnv,
40
+ };
41
+ }
42
+ export function buildPromptfooArgs(binPath, plan) {
43
+ return [
44
+ binPath,
45
+ "eval",
46
+ "-c",
47
+ CONFIG_FILE,
48
+ "--output",
49
+ RESULTS_FILE,
50
+ "--no-cache",
51
+ "--no-progress-bar",
52
+ "--no-write",
53
+ "--repeat",
54
+ String(plan.repeats),
55
+ "-j",
56
+ String(Math.max(1, plan.concurrency)),
57
+ ];
58
+ }
59
+ export function resolveGraderModuleUrl() {
60
+ const here = path.dirname(fileURLToPath(import.meta.url));
61
+ const candidates = [
62
+ path.resolve(here, "../../graders/index.js"),
63
+ path.resolve(here, "../../../../dist/evals/graders/index.js"),
64
+ ];
65
+ const found = candidates.find((candidate) => existsSync(candidate));
66
+ if (found === undefined) {
67
+ throw new EngineError("EVAL_ENGINE_UNAVAILABLE", "Compiled graders were not found. Run `npm run build` before running evals from source.");
68
+ }
69
+ return pathToFileURL(found).href;
70
+ }
71
+ class StreamTail {
72
+ file;
73
+ offset = 0;
74
+ constructor(file) {
75
+ this.file = file;
76
+ }
77
+ lines() {
78
+ let size;
79
+ try {
80
+ size = statSync(this.file).size;
81
+ }
82
+ catch {
83
+ return [];
84
+ }
85
+ if (size <= this.offset)
86
+ return [];
87
+ const fd = openSync(this.file, "r");
88
+ let chunk;
89
+ try {
90
+ chunk = Buffer.alloc(size - this.offset);
91
+ readSync(fd, chunk, 0, chunk.length, this.offset);
92
+ }
93
+ finally {
94
+ closeSync(fd);
95
+ }
96
+ const lastNewline = chunk.lastIndexOf(0x0a);
97
+ if (lastNewline < 0)
98
+ return [];
99
+ this.offset += lastNewline + 1;
100
+ return chunk
101
+ .subarray(0, lastNewline)
102
+ .toString("utf8")
103
+ .split("\n")
104
+ .filter((line) => line.length > 0);
105
+ }
106
+ }
107
+ export class PromptfooEngine {
108
+ options;
109
+ name = "promptfoo";
110
+ constructor(options) {
111
+ this.options = options;
112
+ }
113
+ home() {
114
+ return this.options.home ?? globalStageflowHome();
115
+ }
116
+ async version() {
117
+ return PINNED_PROMPTFOO_VERSION;
118
+ }
119
+ validatePlan(plan) {
120
+ assertJudgesSupported(plan.graders);
121
+ }
122
+ async run(plan, io, signal) {
123
+ const opts = this.options;
124
+ assertNode(opts.nodeVersion);
125
+ assertJudgesSupported(plan.graders);
126
+ const located = locatePromptfoo({ home: this.home() });
127
+ if (!located.installed && opts.binPath === undefined) {
128
+ throw new EngineError("EVAL_ENGINE_UNAVAILABLE", located.reason);
129
+ }
130
+ const binPath = opts.binPath ?? (located.installed ? located.binPath : "");
131
+ const judgeEnv = {};
132
+ const judgeModels = new Set();
133
+ for (const grader of plan.graders) {
134
+ if (grader.type !== "rubric" && grader.type !== "goal_reached")
135
+ continue;
136
+ judgeModels.add(grader.judge);
137
+ const mapping = mapJudge(grader.judge);
138
+ if (judgeEnv[mapping.envVar] !== undefined)
139
+ continue;
140
+ const key = await (opts.resolveJudgeKey ?? defaultResolveJudgeKey)(mapping, plan.projectRoot);
141
+ if (key === undefined) {
142
+ throw new EngineError("EVAL_INVALID", `No API key is configured for judge provider "${mapping.stageflowProvider}" (model "${grader.judge}").`);
143
+ }
144
+ judgeEnv[mapping.envVar] = key;
145
+ }
146
+ const prices = await (opts.loadJudgePrices ?? defaultLoadJudgePrices)([...judgeModels], plan.projectRoot);
147
+ const judgePrice = (model) => prices.get(model);
148
+ const graderModuleUrl = opts.graderModuleUrl ?? resolveGraderModuleUrl();
149
+ const files = generateFiles(plan, {
150
+ graderModuleUrl,
151
+ ...(opts.judgeProviderConfig !== undefined ? { judgeProviderConfig: opts.judgeProviderConfig } : {}),
152
+ });
153
+ if (signal.aborted)
154
+ return;
155
+ const workDir = path.join(this.home(), "eval-runs", plan.evalRunId);
156
+ rmSync(workDir, { recursive: true, force: true });
157
+ mkdirSync(path.join(workDir, "pf-home"), { recursive: true, mode: 0o700 });
158
+ for (const [name, content] of Object.entries(files))
159
+ writeFileSync(path.join(workDir, name), content);
160
+ const hostRuns = new Map();
161
+ const keyOf = (caseId, repeatIndex) => `${caseId}#${repeatIndex}`;
162
+ const runCase = async (req) => {
163
+ io.onPhase(req.caseId, req.repeatIndex, plan.target.kind === "agent" ? "agent_running" : "stage_running");
164
+ const result = await io.runCase(req);
165
+ hostRuns.set(keyOf(req.caseId, req.repeatIndex), result);
166
+ if (result.ok)
167
+ io.onPhase(req.caseId, req.repeatIndex, "grading");
168
+ return result;
169
+ };
170
+ const token = opts.tokens.issue(plan.evalRunId, { plan, runCase });
171
+ const callbackUrl = typeof opts.callbackUrl === "function" ? opts.callbackUrl() : opts.callbackUrl;
172
+ const env = buildChildEnv({
173
+ workDir,
174
+ guardPath: path.join(workDir, GUARD_FILENAME),
175
+ callbackUrl,
176
+ token,
177
+ judgeEnv,
178
+ ...(opts.extraEnv !== undefined ? { extraEnv: opts.extraEnv } : {}),
179
+ });
180
+ const emitted = new Set();
181
+ const warnedPrice = new Set();
182
+ let stopping = false;
183
+ let killTimer;
184
+ let child;
185
+ let exited = false;
186
+ const terminate = () => {
187
+ if (child === undefined || exited || stopping)
188
+ return;
189
+ stopping = true;
190
+ child.kill("SIGTERM");
191
+ killTimer = setTimeout(() => {
192
+ if (!exited)
193
+ child?.kill("SIGKILL");
194
+ }, opts.killGraceMs ?? PROMPTFOO_KILL_GRACE_MS);
195
+ };
196
+ const handleRecord = (record) => {
197
+ const identity = recordIdentity(record, plan);
198
+ if (identity === undefined)
199
+ return;
200
+ const key = keyOf(identity.caseId, identity.repeatIndex);
201
+ if (emitted.has(key))
202
+ return;
203
+ emitted.add(key);
204
+ const outcome = normalizeRecord(record, identity, plan, {
205
+ hostRun: (caseId, repeatIndex) => hostRuns.get(keyOf(caseId, repeatIndex)),
206
+ judgePrice,
207
+ });
208
+ for (const model of outcome.priceUnknownModels) {
209
+ if (warnedPrice.has(model))
210
+ continue;
211
+ warnedPrice.add(model);
212
+ io.log("warn", `No catalog price for judge model ${model}; its cost is counted as $0.`);
213
+ }
214
+ io.onResult(outcome.result);
215
+ if (outcome.judgeCostUsd > 0)
216
+ io.reportJudgeCost(outcome.judgeCostUsd);
217
+ io.onPhase(identity.caseId, identity.repeatIndex, "done");
218
+ const run = outcome.result.run;
219
+ if (!run.ok && run.code === "EVAL_BUDGET_EXCEEDED")
220
+ terminate();
221
+ };
222
+ const tail = new StreamTail(path.join(workDir, RESULTS_STREAM_FILE));
223
+ const drain = () => {
224
+ for (const line of tail.lines()) {
225
+ try {
226
+ handleRecord(JSON.parse(line));
227
+ }
228
+ catch {
229
+ io.log("warn", "Skipped an unreadable progress line from the eval engine.");
230
+ }
231
+ }
232
+ };
233
+ const onAbort = () => terminate();
234
+ let poll;
235
+ let stderrTail = "";
236
+ try {
237
+ const exit = await new Promise((resolve) => {
238
+ try {
239
+ child = (opts.spawn ?? nodeSpawn)(process.execPath, buildPromptfooArgs(binPath, plan), {
240
+ cwd: workDir,
241
+ env,
242
+ stdio: ["ignore", "pipe", "pipe"],
243
+ });
244
+ }
245
+ catch (error) {
246
+ resolve({ code: null, signal: null, spawnError: error instanceof Error ? error : new Error(String(error)) });
247
+ return;
248
+ }
249
+ child.stdout?.on("data", () => undefined);
250
+ child.stderr?.on("data", (data) => {
251
+ stderrTail = (stderrTail + data.toString()).slice(-STDERR_TAIL_BYTES);
252
+ });
253
+ child.on("error", (error) => {
254
+ exited = true;
255
+ resolve({ code: null, signal: null, spawnError: error });
256
+ });
257
+ child.on("close", (code, sig) => {
258
+ exited = true;
259
+ resolve({ code, signal: sig });
260
+ });
261
+ poll = setInterval(drain, opts.streamPollMs ?? PROMPTFOO_STREAM_POLL_MS);
262
+ if (signal.aborted)
263
+ terminate();
264
+ else
265
+ signal.addEventListener("abort", onAbort, { once: true });
266
+ });
267
+ if (poll !== undefined)
268
+ clearInterval(poll);
269
+ if (killTimer !== undefined)
270
+ clearTimeout(killTimer);
271
+ signal.removeEventListener("abort", onAbort);
272
+ drain();
273
+ if (stopping || signal.aborted)
274
+ return;
275
+ const fail = (message) => {
276
+ if (stderrTail.length > 0)
277
+ io.log("error", `promptfoo stderr (last ${STDERR_TAIL_BYTES} bytes): ${stderrTail}`);
278
+ throw new EngineError("EVAL_ENGINE_ERROR", message);
279
+ };
280
+ if (exit.spawnError !== undefined)
281
+ fail("The eval engine could not be started");
282
+ if (exit.code !== 0 && exit.code !== 100)
283
+ fail(`The eval engine exited with code ${exit.code ?? exit.signal ?? "unknown"}`);
284
+ const resultsFile = path.join(workDir, RESULTS_FILE);
285
+ if (!existsSync(resultsFile))
286
+ fail("The eval engine wrote no results");
287
+ let records;
288
+ try {
289
+ records = recordsFromResultsFile(JSON.parse(readFileSync(resultsFile, "utf8")));
290
+ }
291
+ catch {
292
+ records = undefined;
293
+ }
294
+ if (records === undefined)
295
+ fail("The eval engine results could not be read");
296
+ for (const record of records ?? [])
297
+ handleRecord(record);
298
+ }
299
+ finally {
300
+ if (poll !== undefined)
301
+ clearInterval(poll);
302
+ if (killTimer !== undefined)
303
+ clearTimeout(killTimer);
304
+ signal.removeEventListener("abort", onAbort);
305
+ opts.tokens.revoke(plan.evalRunId);
306
+ if (!(opts.keepWorkDir ?? process.env[KEEP_WORKDIR_ENV] === "1")) {
307
+ rmSync(workDir, { recursive: true, force: true });
308
+ }
309
+ }
310
+ }
311
+ }
@@ -0,0 +1,5 @@
1
+ export type EngineErrorCode = "EVAL_NODE_TOO_OLD" | "EVAL_ENGINE_UNAVAILABLE" | "EVAL_ENGINE_ERROR" | "EVAL_INVALID";
2
+ export declare class EngineError extends Error {
3
+ readonly code: EngineErrorCode;
4
+ constructor(code: EngineErrorCode, message: string);
5
+ }
@@ -0,0 +1,8 @@
1
+ export class EngineError extends Error {
2
+ code;
3
+ constructor(code, message) {
4
+ super(message);
5
+ this.code = code;
6
+ this.name = "EngineError";
7
+ }
8
+ }
@@ -0,0 +1,30 @@
1
+ import { GUARD_FILENAME } from "./guard.js";
2
+ import type { EvalPlan } from "../../types.js";
3
+ export declare const CALLBACK_URL_ENV = "STAGEFLOW_EVAL_CALLBACK_URL";
4
+ export declare const RUN_TOKEN_ENV = "STAGEFLOW_EVAL_TOKEN";
5
+ export declare const CONFIG_FILE = "promptfooconfig.json";
6
+ export declare const PROVIDER_FILE = "provider.mjs";
7
+ export declare const ASSERTIONS_FILE = "assertions.mjs";
8
+ export declare const HOOKS_FILE = "hooks.mjs";
9
+ export declare const DATASET_FILE = "dataset.json";
10
+ export declare const RESULTS_STREAM_FILE = "results.ndjson";
11
+ export declare const RESULTS_FILE = "results.json";
12
+ export declare const EMPTY_EXPECTED = "(none)";
13
+ export type GenerateOptions = {
14
+ graderModuleUrl: string;
15
+ judgeProviderConfig?: Record<string, unknown>;
16
+ };
17
+ export type GeneratedFiles = {
18
+ [CONFIG_FILE]: string;
19
+ [PROVIDER_FILE]: string;
20
+ [ASSERTIONS_FILE]: string;
21
+ [HOOKS_FILE]: string;
22
+ [DATASET_FILE]: string;
23
+ [GUARD_FILENAME]: string;
24
+ };
25
+ export declare function assertionFnName(index: number): string;
26
+ export declare function buildProviderSource(evalRunId: string, agent?: boolean): string;
27
+ export declare function buildHooksSource(agent?: boolean): string;
28
+ export declare function buildAssertionsSource(plan: EvalPlan, graderModuleUrl: string): string;
29
+ export declare function buildConfig(plan: EvalPlan, options: GenerateOptions): Record<string, unknown>;
30
+ export declare function generateFiles(plan: EvalPlan, options: GenerateOptions): GeneratedFiles;