stageflow 0.40.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.
Files changed (519) hide show
  1. package/README.md +15 -4
  2. package/dist/agent/activity.d.ts +18 -0
  3. package/dist/agent/claudeAdapter.js +7 -0
  4. package/dist/agent/claudeTools.d.ts +27 -18
  5. package/dist/agent/claudeTools.js +54 -15
  6. package/dist/agent/compactionEvents.d.ts +34 -0
  7. package/dist/agent/compactionEvents.js +37 -0
  8. package/dist/agent/openRouterRouting.d.ts +7 -0
  9. package/dist/agent/openRouterRouting.js +23 -0
  10. package/dist/agent/piAdapter.d.ts +6 -0
  11. package/dist/agent/piAdapter.js +128 -27
  12. package/dist/agent/piSettings.d.ts +7 -0
  13. package/dist/agent/piSettings.js +9 -0
  14. package/dist/agent/sandboxPiTools.d.ts +3 -1
  15. package/dist/agent/sandboxPiTools.js +8 -2
  16. package/dist/agent/stageTurnDriver.d.ts +11 -2
  17. package/dist/agent/stageTurnDriver.js +45 -4
  18. package/dist/agent/toolOutputBudget.d.ts +15 -1
  19. package/dist/agent/toolOutputBudget.js +18 -0
  20. package/dist/agent/toolOutputBudgetExtension.d.ts +2 -0
  21. package/dist/agent/toolOutputBudgetExtension.js +40 -3
  22. package/dist/agents/authorChat.d.ts +5 -0
  23. package/dist/agents/authorChat.js +120 -12
  24. package/dist/agents/authorSessionStore.d.ts +38 -0
  25. package/dist/agents/authorSessionStore.js +167 -0
  26. package/dist/agents/chatTurn.d.ts +2 -0
  27. package/dist/agents/chatTurn.js +17 -1
  28. package/dist/agents/errors.d.ts +1 -1
  29. package/dist/agents/errors.js +1 -0
  30. package/dist/agents/evalGate.d.ts +61 -0
  31. package/dist/agents/evalGate.js +103 -0
  32. package/dist/agents/evalSession.d.ts +26 -0
  33. package/dist/agents/evalSession.js +29 -0
  34. package/dist/agents/hostContext.d.ts +4 -1
  35. package/dist/agents/hostContext.js +4 -1
  36. package/dist/agents/runtime/piRuntime.d.ts +6 -2
  37. package/dist/agents/runtime/piRuntime.js +50 -16
  38. package/dist/agents/runtime/types.d.ts +3 -1
  39. package/dist/agents/service.d.ts +27 -2
  40. package/dist/agents/service.js +91 -15
  41. package/dist/agents/sessions.d.ts +8 -0
  42. package/dist/agents/sessions.js +53 -11
  43. package/dist/agents/store.d.ts +14 -3
  44. package/dist/agents/store.js +45 -7
  45. package/dist/agents/toolRisk.d.ts +21 -0
  46. package/dist/agents/toolRisk.js +50 -0
  47. package/dist/cli/doctorCommand.js +26 -0
  48. package/dist/cli/evalCommand.d.ts +20 -0
  49. package/dist/cli/evalCommand.js +720 -0
  50. package/dist/cli/exportAllCommand.js +1 -1
  51. package/dist/cli/hostClient.d.ts +60 -0
  52. package/dist/cli/hostClient.js +71 -0
  53. package/dist/cli/validateOutput.d.ts +2 -2
  54. package/dist/cli/validateOutput.js +2 -2
  55. package/dist/cli.js +10 -0
  56. package/dist/compaction/directives.d.ts +18 -0
  57. package/dist/compaction/directives.js +119 -0
  58. package/dist/compaction/extension.d.ts +20 -0
  59. package/dist/compaction/extension.js +78 -0
  60. package/dist/compaction/mask.d.ts +18 -0
  61. package/dist/compaction/mask.js +155 -0
  62. package/dist/compaction/pin.d.ts +21 -0
  63. package/dist/compaction/pin.js +270 -0
  64. package/dist/compaction/scrub.d.ts +7 -0
  65. package/dist/compaction/scrub.js +26 -0
  66. package/dist/compaction/sessionWiring.d.ts +22 -0
  67. package/dist/compaction/sessionWiring.js +26 -0
  68. package/dist/compaction/summarize.d.ts +79 -0
  69. package/dist/compaction/summarize.js +171 -0
  70. package/dist/compaction/toolPolicy.d.ts +3 -0
  71. package/dist/compaction/toolPolicy.js +33 -0
  72. package/dist/compaction/types.d.ts +45 -0
  73. package/dist/compaction/types.js +7 -0
  74. package/dist/compaction/workingState.d.ts +56 -0
  75. package/dist/compaction/workingState.js +198 -0
  76. package/dist/config/atomicWrite.d.ts +15 -0
  77. package/dist/config/atomicWrite.js +43 -0
  78. package/dist/config/browseCatalog.d.ts +2 -0
  79. package/dist/config/browseCatalog.js +4 -2
  80. package/dist/config/createPipeline.js +2 -0
  81. package/dist/config/createTrigger.js +7 -1
  82. package/dist/config/csv.d.ts +9 -0
  83. package/dist/config/csv.js +81 -0
  84. package/dist/config/datasetAgentCheck.d.ts +18 -0
  85. package/dist/config/datasetAgentCheck.js +109 -0
  86. package/dist/config/datasetCandidates.d.ts +22 -0
  87. package/dist/config/datasetCandidates.js +86 -0
  88. package/dist/config/datasetFromSessions.d.ts +34 -0
  89. package/dist/config/datasetFromSessions.js +105 -0
  90. package/dist/config/datasetHash.d.ts +1 -0
  91. package/dist/config/datasetHash.js +4 -0
  92. package/dist/config/datasetImport.d.ts +21 -0
  93. package/dist/config/datasetImport.js +120 -0
  94. package/dist/config/datasetStageCheck.d.ts +9 -0
  95. package/dist/config/datasetStageCheck.js +17 -0
  96. package/dist/config/datasetTypes.d.ts +27 -0
  97. package/dist/config/datasetTypes.js +1 -0
  98. package/dist/config/ensureCatalogScanRoot.d.ts +4 -1
  99. package/dist/config/ensureCatalogScanRoot.js +8 -6
  100. package/dist/config/evalCatalog.d.ts +22 -0
  101. package/dist/config/evalCatalog.js +95 -0
  102. package/dist/config/evalWriteRoots.d.ts +17 -0
  103. package/dist/config/evalWriteRoots.js +109 -0
  104. package/dist/config/githubTriggerAction.d.ts +8 -0
  105. package/dist/config/githubTriggerAction.js +29 -0
  106. package/dist/config/hostConfig.js +3 -0
  107. package/dist/config/installEvalSample.d.ts +34 -0
  108. package/dist/config/installEvalSample.js +182 -0
  109. package/dist/config/loadDataset.d.ts +16 -0
  110. package/dist/config/loadDataset.js +318 -0
  111. package/dist/config/loadEval.d.ts +32 -0
  112. package/dist/config/loadEval.js +1103 -0
  113. package/dist/config/loadOutcome.d.ts +5 -0
  114. package/dist/config/loadStageflowManifest.js +64 -0
  115. package/dist/config/pipelineNeeds.d.ts +2 -0
  116. package/dist/config/pipelineNeeds.js +16 -3
  117. package/dist/config/pipelineRoute.js +5 -4
  118. package/dist/config/resolveAgentTarget.d.ts +32 -0
  119. package/dist/config/resolveAgentTarget.js +118 -0
  120. package/dist/config/resolveEvalTarget.d.ts +21 -0
  121. package/dist/config/resolveEvalTarget.js +89 -0
  122. package/dist/config/scanCatalogPaths.d.ts +1 -1
  123. package/dist/config/scanCatalogPaths.js +17 -5
  124. package/dist/config/validateCatalog.d.ts +2 -2
  125. package/dist/config/validateCatalog.js +21 -1
  126. package/dist/config/validateEval.d.ts +36 -0
  127. package/dist/config/validateEval.js +446 -0
  128. package/dist/config/writeDataset.d.ts +54 -0
  129. package/dist/config/writeDataset.js +186 -0
  130. package/dist/config/writeEval.d.ts +25 -0
  131. package/dist/config/writeEval.js +398 -0
  132. package/dist/diagnostics/checks.js +1 -1
  133. package/dist/envelope/assertEmittedArtifacts.d.ts +12 -0
  134. package/dist/envelope/assertEmittedArtifacts.js +43 -0
  135. package/dist/envelope/preEmitChecks.d.ts +3 -0
  136. package/dist/evals/agentDiff.d.ts +13 -0
  137. package/dist/evals/agentDiff.js +11 -0
  138. package/dist/evals/canonical.d.ts +3 -0
  139. package/dist/evals/canonical.js +24 -0
  140. package/dist/evals/caseTask.d.ts +3 -0
  141. package/dist/evals/caseTask.js +9 -0
  142. package/dist/evals/compare.d.ts +94 -0
  143. package/dist/evals/compare.js +201 -0
  144. package/dist/evals/constants.d.ts +62 -0
  145. package/dist/evals/constants.js +97 -0
  146. package/dist/evals/engine/FakeEngine.d.ts +33 -0
  147. package/dist/evals/engine/FakeEngine.js +177 -0
  148. package/dist/evals/engine/index.d.ts +9 -0
  149. package/dist/evals/engine/index.js +19 -0
  150. package/dist/evals/engine/promptfoo/PromptfooEngine.d.ts +52 -0
  151. package/dist/evals/engine/promptfoo/PromptfooEngine.js +312 -0
  152. package/dist/evals/engine/promptfoo/errors.d.ts +5 -0
  153. package/dist/evals/engine/promptfoo/errors.js +8 -0
  154. package/dist/evals/engine/promptfoo/generate.d.ts +30 -0
  155. package/dist/evals/engine/promptfoo/generate.js +345 -0
  156. package/dist/evals/engine/promptfoo/guard.d.ts +10 -0
  157. package/dist/evals/engine/promptfoo/guard.js +116 -0
  158. package/dist/evals/engine/promptfoo/install.d.ts +17 -0
  159. package/dist/evals/engine/promptfoo/install.js +73 -0
  160. package/dist/evals/engine/promptfoo/judgeProviders.d.ts +2 -0
  161. package/dist/evals/engine/promptfoo/judgeProviders.js +9 -0
  162. package/dist/evals/engine/promptfoo/judgeServices.d.ts +6 -0
  163. package/dist/evals/engine/promptfoo/judgeServices.js +41 -0
  164. package/dist/evals/engine/promptfoo/locate.d.ts +21 -0
  165. package/dist/evals/engine/promptfoo/locate.js +68 -0
  166. package/dist/evals/engine/promptfoo/nodeVersion.d.ts +7 -0
  167. package/dist/evals/engine/promptfoo/nodeVersion.js +14 -0
  168. package/dist/evals/engine/promptfoo/normalize.d.ts +66 -0
  169. package/dist/evals/engine/promptfoo/normalize.js +261 -0
  170. package/dist/evals/engine/promptfoo/pinned.d.ts +5 -0
  171. package/dist/evals/engine/promptfoo/pinned.js +5 -0
  172. package/dist/evals/engine/promptfoo/rubricPrompt.d.ts +14 -0
  173. package/dist/evals/engine/promptfoo/rubricPrompt.js +105 -0
  174. package/dist/evals/engine/promptfoo/runTokens.d.ts +18 -0
  175. package/dist/evals/engine/promptfoo/runTokens.js +31 -0
  176. package/dist/evals/engine/promptfoo/status.d.ts +13 -0
  177. package/dist/evals/engine/promptfoo/status.js +16 -0
  178. package/dist/evals/estimate.d.ts +56 -0
  179. package/dist/evals/estimate.js +66 -0
  180. package/dist/evals/graders/codeGrader.d.ts +6 -0
  181. package/dist/evals/graders/codeGrader.js +85 -0
  182. package/dist/evals/graders/conversationCheckGrader.d.ts +6 -0
  183. package/dist/evals/graders/conversationCheckGrader.js +62 -0
  184. package/dist/evals/graders/fieldGrader.d.ts +11 -0
  185. package/dist/evals/graders/fieldGrader.js +117 -0
  186. package/dist/evals/graders/goal.d.ts +3 -0
  187. package/dist/evals/graders/goal.js +14 -0
  188. package/dist/evals/graders/index.d.ts +18 -0
  189. package/dist/evals/graders/index.js +34 -0
  190. package/dist/evals/graders/notApplicable.d.ts +5 -0
  191. package/dist/evals/graders/notApplicable.js +9 -0
  192. package/dist/evals/graders/path.d.ts +26 -0
  193. package/dist/evals/graders/path.js +75 -0
  194. package/dist/evals/graders/referenceGrader.d.ts +5 -0
  195. package/dist/evals/graders/referenceGrader.js +59 -0
  196. package/dist/evals/graders/schemaGrader.d.ts +5 -0
  197. package/dist/evals/graders/schemaGrader.js +29 -0
  198. package/dist/evals/graders/subject.d.ts +6 -0
  199. package/dist/evals/graders/subject.js +33 -0
  200. package/dist/evals/graders/toolCallsGrader.d.ts +6 -0
  201. package/dist/evals/graders/toolCallsGrader.js +100 -0
  202. package/dist/evals/graders/transcript.d.ts +12 -0
  203. package/dist/evals/graders/transcript.js +57 -0
  204. package/dist/evals/graders/types.d.ts +20 -0
  205. package/dist/evals/graders/types.js +1 -0
  206. package/dist/evals/judgeProviders.d.ts +16 -0
  207. package/dist/evals/judgeProviders.js +27 -0
  208. package/dist/evals/lineDiff.d.ts +5 -0
  209. package/dist/evals/lineDiff.js +34 -0
  210. package/dist/evals/listStatus.d.ts +31 -0
  211. package/dist/evals/listStatus.js +48 -0
  212. package/dist/evals/manager.d.ts +187 -0
  213. package/dist/evals/manager.js +795 -0
  214. package/dist/evals/plan.d.ts +65 -0
  215. package/dist/evals/plan.js +621 -0
  216. package/dist/evals/planInternalAgent.d.ts +19 -0
  217. package/dist/evals/planInternalAgent.js +205 -0
  218. package/dist/evals/providerKeys.d.ts +1 -0
  219. package/dist/evals/providerKeys.js +21 -0
  220. package/dist/evals/read/agentTargets.d.ts +37 -0
  221. package/dist/evals/read/agentTargets.js +101 -0
  222. package/dist/evals/read/api.d.ts +208 -0
  223. package/dist/evals/read/api.js +363 -0
  224. package/dist/evals/read/compare.d.ts +4 -0
  225. package/dist/evals/read/compare.js +39 -0
  226. package/dist/evals/read/datasets.d.ts +105 -0
  227. package/dist/evals/read/datasets.js +318 -0
  228. package/dist/evals/read/list.d.ts +66 -0
  229. package/dist/evals/read/list.js +182 -0
  230. package/dist/evals/read/results.d.ts +46 -0
  231. package/dist/evals/read/results.js +107 -0
  232. package/dist/evals/read/runs.d.ts +154 -0
  233. package/dist/evals/read/runs.js +295 -0
  234. package/dist/evals/read/suggestions.d.ts +43 -0
  235. package/dist/evals/read/suggestions.js +73 -0
  236. package/dist/evals/runner/FakeAgentBackend.d.ts +40 -0
  237. package/dist/evals/runner/FakeAgentBackend.js +82 -0
  238. package/dist/evals/runner/agentCaseRunner.d.ts +24 -0
  239. package/dist/evals/runner/agentCaseRunner.js +388 -0
  240. package/dist/evals/runner/caseRunner.d.ts +8 -0
  241. package/dist/evals/runner/caseRunner.js +28 -0
  242. package/dist/evals/runner/conversationSubject.d.ts +18 -0
  243. package/dist/evals/runner/conversationSubject.js +123 -0
  244. package/dist/evals/runner/internalAgentCaseRunner.d.ts +6 -0
  245. package/dist/evals/runner/internalAgentCaseRunner.js +250 -0
  246. package/dist/evals/runner/simulatorModel.d.ts +51 -0
  247. package/dist/evals/runner/simulatorModel.js +58 -0
  248. package/dist/evals/runner/simulatorPrompt.d.ts +29 -0
  249. package/dist/evals/runner/simulatorPrompt.js +59 -0
  250. package/dist/evals/runner/stageCaseRunner.d.ts +30 -0
  251. package/dist/evals/runner/stageCaseRunner.js +279 -0
  252. package/dist/evals/runner/userDriver.d.ts +71 -0
  253. package/dist/evals/runner/userDriver.js +104 -0
  254. package/dist/evals/scoring.d.ts +34 -0
  255. package/dist/evals/scoring.js +67 -0
  256. package/dist/evals/snapshot.d.ts +191 -0
  257. package/dist/evals/snapshot.js +70 -0
  258. package/dist/evals/stageDiff.d.ts +8 -0
  259. package/dist/evals/stageDiff.js +48 -0
  260. package/dist/evals/stats.d.ts +95 -0
  261. package/dist/evals/stats.js +220 -0
  262. package/dist/evals/statsAdapter.d.ts +4 -0
  263. package/dist/evals/statsAdapter.js +30 -0
  264. package/dist/evals/statsTypes.d.ts +51 -0
  265. package/dist/evals/statsTypes.js +18 -0
  266. package/dist/evals/storeError.d.ts +5 -0
  267. package/dist/evals/storeError.js +8 -0
  268. package/dist/evals/storeTypes.d.ts +207 -0
  269. package/dist/evals/storeTypes.js +1 -0
  270. package/dist/evals/tTable.d.ts +3 -0
  271. package/dist/evals/tTable.js +15 -0
  272. package/dist/evals/triage/constants.d.ts +26 -0
  273. package/dist/evals/triage/constants.js +33 -0
  274. package/dist/evals/triage/credentials.d.ts +13 -0
  275. package/dist/evals/triage/credentials.js +20 -0
  276. package/dist/evals/triage/jevClassifier.d.ts +14 -0
  277. package/dist/evals/triage/jevClassifier.js +124 -0
  278. package/dist/evals/triage/judgeClassifier.d.ts +10 -0
  279. package/dist/evals/triage/judgeClassifier.js +76 -0
  280. package/dist/evals/triage/prompts.d.ts +16 -0
  281. package/dist/evals/triage/prompts.js +64 -0
  282. package/dist/evals/triage/service.d.ts +79 -0
  283. package/dist/evals/triage/service.js +217 -0
  284. package/dist/evals/triage/stateBuilder.d.ts +19 -0
  285. package/dist/evals/triage/stateBuilder.js +125 -0
  286. package/dist/evals/triage/types.d.ts +60 -0
  287. package/dist/evals/triage/types.js +8 -0
  288. package/dist/evals/types.d.ts +357 -0
  289. package/dist/evals/types.js +4 -0
  290. package/dist/guide/cardContract.d.ts +133 -0
  291. package/dist/guide/cardContract.js +156 -0
  292. package/dist/guide/chat.d.ts +45 -0
  293. package/dist/guide/chat.js +378 -0
  294. package/dist/guide/knowledge/index.d.ts +14 -0
  295. package/dist/guide/knowledge/index.js +109 -0
  296. package/dist/guide/knowledge/topics/agents.d.ts +2 -0
  297. package/dist/guide/knowledge/topics/agents.js +58 -0
  298. package/dist/guide/knowledge/topics/bestPractices.d.ts +2 -0
  299. package/dist/guide/knowledge/topics/bestPractices.js +67 -0
  300. package/dist/guide/knowledge/topics/connections.d.ts +2 -0
  301. package/dist/guide/knowledge/topics/connections.js +66 -0
  302. package/dist/guide/knowledge/topics/consoleMap.d.ts +2 -0
  303. package/dist/guide/knowledge/topics/consoleMap.js +55 -0
  304. package/dist/guide/knowledge/topics/evals.d.ts +2 -0
  305. package/dist/guide/knowledge/topics/evals.js +72 -0
  306. package/dist/guide/knowledge/topics/limitations.d.ts +2 -0
  307. package/dist/guide/knowledge/topics/limitations.js +84 -0
  308. package/dist/guide/knowledge/topics/mcpSkillsBrowser.d.ts +2 -0
  309. package/dist/guide/knowledge/topics/mcpSkillsBrowser.js +57 -0
  310. package/dist/guide/knowledge/topics/memories.d.ts +2 -0
  311. package/dist/guide/knowledge/topics/memories.js +63 -0
  312. package/dist/guide/knowledge/topics/modelsAndProviders.d.ts +2 -0
  313. package/dist/guide/knowledge/topics/modelsAndProviders.js +56 -0
  314. package/dist/guide/knowledge/topics/overview.d.ts +2 -0
  315. package/dist/guide/knowledge/topics/overview.js +56 -0
  316. package/dist/guide/knowledge/topics/pipelines.d.ts +2 -0
  317. package/dist/guide/knowledge/topics/pipelines.js +93 -0
  318. package/dist/guide/knowledge/topics/stages.d.ts +2 -0
  319. package/dist/guide/knowledge/topics/stages.js +54 -0
  320. package/dist/guide/knowledge/topics/tasks.d.ts +2 -0
  321. package/dist/guide/knowledge/topics/tasks.js +52 -0
  322. package/dist/guide/knowledge/topics/triggers.d.ts +2 -0
  323. package/dist/guide/knowledge/topics/triggers.js +68 -0
  324. package/dist/guide/knowledge/topics/troubleshooting.d.ts +2 -0
  325. package/dist/guide/knowledge/topics/troubleshooting.js +85 -0
  326. package/dist/guide/knowledgeTools.d.ts +2 -0
  327. package/dist/guide/knowledgeTools.js +56 -0
  328. package/dist/guide/showUi.d.ts +6 -0
  329. package/dist/guide/showUi.js +546 -0
  330. package/dist/guide/threadStore.d.ts +48 -0
  331. package/dist/guide/threadStore.js +189 -0
  332. package/dist/guide/writeRoot.d.ts +11 -0
  333. package/dist/guide/writeRoot.js +70 -0
  334. package/dist/hosted/translate.js +2 -0
  335. package/dist/mcp/agentTools.js +12 -0
  336. package/dist/mcp/catalogTools.js +18 -20
  337. package/dist/mcp/catalogWriteTools.d.ts +8 -0
  338. package/dist/mcp/catalogWriteTools.js +225 -0
  339. package/dist/mcp/connectionTools.d.ts +3 -0
  340. package/dist/mcp/connectionTools.js +85 -0
  341. package/dist/mcp/controlTools.js +34 -1
  342. package/dist/mcp/deps.d.ts +16 -0
  343. package/dist/mcp/evalTools.d.ts +3 -0
  344. package/dist/mcp/evalTools.js +943 -0
  345. package/dist/mcp/memoryHostTools.d.ts +3 -0
  346. package/dist/mcp/memoryHostTools.js +72 -0
  347. package/dist/mcp/pipelineAuthorTools.js +14 -1
  348. package/dist/mcp/server.js +6 -0
  349. package/dist/mcp/tools.js +8 -0
  350. package/dist/mcp/triggerTools.js +77 -31
  351. package/dist/models/response.d.ts +7 -2
  352. package/dist/models/response.js +6 -1
  353. package/dist/operatorAgent/agentAuthorContext.d.ts +1 -1
  354. package/dist/operatorAgent/agentAuthorContext.js +1 -1
  355. package/dist/operatorAgent/evalGate.d.ts +22 -0
  356. package/dist/operatorAgent/evalGate.js +77 -0
  357. package/dist/operatorAgent/fakeHost.js +10 -2
  358. package/dist/operatorAgent/host.js +18 -2
  359. package/dist/operatorAgent/index.d.ts +1 -0
  360. package/dist/operatorAgent/index.js +1 -0
  361. package/dist/operatorAgent/internalAgents.d.ts +11 -0
  362. package/dist/operatorAgent/internalAgents.js +13 -0
  363. package/dist/operatorAgent/piModel.d.ts +5 -1
  364. package/dist/operatorAgent/piModel.js +32 -14
  365. package/dist/operatorAgent/profiles/agentAuthor.d.ts +3 -1
  366. package/dist/operatorAgent/profiles/agentAuthor.js +201 -32
  367. package/dist/operatorAgent/profiles/agentAuthorPlaybook.d.ts +1 -1
  368. package/dist/operatorAgent/profiles/agentAuthorPlaybook.js +48 -15
  369. package/dist/operatorAgent/profiles/authorReadable.d.ts +2 -0
  370. package/dist/operatorAgent/profiles/authorReadable.js +26 -0
  371. package/dist/operatorAgent/profiles/guideConfirm.d.ts +21 -0
  372. package/dist/operatorAgent/profiles/guideConfirm.js +100 -0
  373. package/dist/operatorAgent/profiles/guideTools.d.ts +7 -0
  374. package/dist/operatorAgent/profiles/guideTools.js +123 -0
  375. package/dist/operatorAgent/profiles/stageflowGuide.d.ts +7 -0
  376. package/dist/operatorAgent/profiles/stageflowGuide.js +132 -0
  377. package/dist/operatorAgent/profiles/workshopAuthor.js +23 -0
  378. package/dist/operatorAgent/profiles/workshopAuthorPlaybook.d.ts +1 -1
  379. package/dist/operatorAgent/profiles/workshopAuthorPlaybook.js +9 -1
  380. package/dist/operatorAgent/profiles/workshopAuthorTools.d.ts +2 -0
  381. package/dist/operatorAgent/profiles/workshopAuthorTools.js +197 -9
  382. package/dist/operatorAgent/types.d.ts +23 -0
  383. package/dist/package-meta.d.ts +1 -1
  384. package/dist/package-meta.js +1 -1
  385. package/dist/runstore/port.d.ts +43 -0
  386. package/dist/runstore/retention.d.ts +2 -1
  387. package/dist/runstore/retention.js +3 -7
  388. package/dist/runstore/runStatusClock.d.ts +17 -0
  389. package/dist/runstore/runStatusClock.js +19 -0
  390. package/dist/runstore/sqlite/SqliteRunStore.d.ts +29 -0
  391. package/dist/runstore/sqlite/SqliteRunStore.js +144 -50
  392. package/dist/runstore/sqlite/evalStore.d.ts +20 -0
  393. package/dist/runstore/sqlite/evalStore.js +541 -0
  394. package/dist/runstore/sqlite/migrations/015-evals.d.ts +12 -0
  395. package/dist/runstore/sqlite/migrations/015-evals.js +157 -0
  396. package/dist/runstore/sqlite/migrations/016-eval-subject-ref.d.ts +12 -0
  397. package/dist/runstore/sqlite/migrations/016-eval-subject-ref.js +20 -0
  398. package/dist/runstore/sqlite/migrations/017-eval-result-suggestions.d.ts +11 -0
  399. package/dist/runstore/sqlite/migrations/017-eval-result-suggestions.js +36 -0
  400. package/dist/runstore/sqlite/migrations/index.js +6 -0
  401. package/dist/runstore/sqlite/suggestionStore.d.ts +14 -0
  402. package/dist/runstore/sqlite/suggestionStore.js +132 -0
  403. package/dist/runstore/workspaceLayout.js +6 -1
  404. package/dist/runtime/artifactDiskInspect.d.ts +14 -0
  405. package/dist/runtime/artifactDiskInspect.js +52 -0
  406. package/dist/runtime/artifactPath.d.ts +24 -0
  407. package/dist/runtime/artifactPath.js +84 -0
  408. package/dist/runtime/completionCheckRunner.js +15 -43
  409. package/dist/runtime/githubPollSource.d.ts +22 -4
  410. package/dist/runtime/githubPollSource.js +93 -8
  411. package/dist/runtime/pipelineRunner.d.ts +2 -1
  412. package/dist/runtime/pipelineRunner.js +2 -0
  413. package/dist/runtime/priorArtifactGrants.d.ts +8 -0
  414. package/dist/runtime/priorArtifactGrants.js +105 -0
  415. package/dist/runtime/runActionEligibility.d.ts +46 -0
  416. package/dist/runtime/runActionEligibility.js +123 -0
  417. package/dist/runtime/runManager.d.ts +6 -2
  418. package/dist/runtime/runManager.js +60 -16
  419. package/dist/runtime/runRetentionSweep.js +2 -2
  420. package/dist/runtime/runRetryCoordinator.d.ts +2 -14
  421. package/dist/runtime/runRetryCoordinator.js +3 -67
  422. package/dist/runtime/sandboxContainer.d.ts +7 -0
  423. package/dist/runtime/sandboxContainer.js +48 -6
  424. package/dist/runtime/sandboxDesk.d.ts +2 -1
  425. package/dist/runtime/sandboxDesk.js +11 -12
  426. package/dist/runtime/stageEnvironment.js +1 -0
  427. package/dist/runtime/stageRoots.d.ts +12 -0
  428. package/dist/runtime/stageSandbox.d.ts +2 -1
  429. package/dist/runtime/stageSandbox.js +18 -2
  430. package/dist/runtime/stageWorker.js +20 -0
  431. package/dist/server/agentAuthorRoutes.js +59 -1
  432. package/dist/server/bootstrap.d.ts +13 -0
  433. package/dist/server/bootstrap.js +69 -0
  434. package/dist/server/controlToken.js +3 -0
  435. package/dist/server/evalInternalRoutes.d.ts +14 -0
  436. package/dist/server/evalInternalRoutes.js +87 -0
  437. package/dist/server/evalRouteContext.d.ts +46 -0
  438. package/dist/server/evalRouteContext.js +43 -0
  439. package/dist/server/evalRoutes.d.ts +5 -0
  440. package/dist/server/evalRoutes.js +1456 -0
  441. package/dist/server/evalTriageRoutes.d.ts +2 -0
  442. package/dist/server/evalTriageRoutes.js +95 -0
  443. package/dist/server/guideRoutes.d.ts +5 -0
  444. package/dist/server/guideRoutes.js +166 -0
  445. package/dist/server/http.d.ts +15 -0
  446. package/dist/server/http.js +67 -3
  447. package/dist/server/internalAgentRoutes.d.ts +6 -0
  448. package/dist/server/internalAgentRoutes.js +12 -0
  449. package/dist/server/mcpHost.js +5 -0
  450. package/dist/toolkit/meta.d.ts +1 -1
  451. package/dist/toolkit/meta.js +53 -0
  452. package/dist/toolkit/profiles.d.ts +5 -0
  453. package/dist/toolkit/profiles.js +13 -1
  454. package/dist/tools/askOperator.js +2 -1
  455. package/dist/tools/emitStageEnvelope.d.ts +17 -16
  456. package/dist/tools/emitStageEnvelope.js +46 -32
  457. package/dist/tools/stageToolNames.d.ts +4 -0
  458. package/dist/tools/stageToolNames.js +4 -0
  459. package/dist/tools/workingState.d.ts +40 -0
  460. package/dist/tools/workingState.js +108 -0
  461. package/dist/tools/writeStageArtifact.d.ts +0 -9
  462. package/dist/tools/writeStageArtifact.js +2 -1
  463. package/dist/types/stageflowManifest.d.ts +6 -0
  464. package/dist/ui/assets/{MarkdownText-D7tYaIFO.js → MarkdownText-S5C_vemc.js} +2 -2
  465. package/dist/ui/assets/adapters-C0l4ruiR.js +17 -0
  466. package/dist/ui/assets/chat-CjnsmvqR.js +2 -0
  467. package/dist/ui/assets/chat-DFDd4UjS.css +2 -0
  468. package/dist/ui/assets/{main-BFo79krC.css → main-Del1GeLf.css} +1 -1
  469. package/dist/ui/assets/main-_yXVqcW9.js +277 -0
  470. package/dist/ui/chat.html +3 -4
  471. package/dist/ui/index.html +3 -4
  472. package/dist/workshop/chatTurn.js +1 -1
  473. package/dist/workshop/workshopPin.d.ts +3 -3
  474. package/dist/workshop/workshopPin.js +16 -15
  475. package/examples/README.md +2 -0
  476. package/examples/compaction-stress/README.md +30 -0
  477. package/examples/compaction-stress/check-run.mjs +53 -0
  478. package/examples/compaction-stress/collect-evidence.yaml +60 -0
  479. package/examples/compaction-stress/compaction-stress.pipeline.yaml +141 -0
  480. package/examples/compaction-stress/compaction-stress.task.yaml +15 -0
  481. package/examples/compaction-stress/generate-evidence.mjs +110 -0
  482. package/examples/compaction-stress/root-cause.yaml +26 -0
  483. package/examples/compaction-stress/stageflow.yaml +9 -0
  484. package/examples/compaction-stress/write-postmortem.yaml +40 -0
  485. package/examples/document-policy-review/README.md +35 -0
  486. package/examples/document-policy-review/agents/compliance.agent.yaml +42 -0
  487. package/examples/document-policy-review/documents/acme-vendor-sow.md +15 -0
  488. package/examples/document-policy-review/documents/support-runbook.md +13 -0
  489. package/examples/document-policy-review/policies/acceptable-use.md +13 -0
  490. package/examples/document-policy-review/policies/data-handling.md +17 -0
  491. package/examples/document-policy-review/policies/vendor-security.md +17 -0
  492. package/examples/evals/README.md +141 -0
  493. package/examples/evals/critique-sample.dataset.jsonl +8 -0
  494. package/examples/evals/critique-sample.eval.yaml +34 -0
  495. package/examples/evals/critique-sample.task.yaml +4 -0
  496. package/examples/evals/eval-sample.pipeline.yaml +35 -0
  497. package/examples/evals/guide-behavior.dataset.jsonl +15 -0
  498. package/examples/evals/guide-behavior.eval.yaml +35 -0
  499. package/examples/evals/guide-depth.dataset.jsonl +35 -0
  500. package/examples/evals/guide-depth.eval.yaml +169 -0
  501. package/examples/evals/support-sample.agent.yaml +20 -0
  502. package/examples/evals/support-sample.dataset.jsonl +6 -0
  503. package/examples/evals/support-sample.eval.yaml +38 -0
  504. package/examples/memory/evals/guide-behavior.dataset.jsonl +15 -0
  505. package/examples/memory/evals/guide-behavior.eval.yaml +35 -0
  506. package/examples/memory/evals/guide-depth.dataset.jsonl +35 -0
  507. package/examples/memory/evals/guide-depth.eval.yaml +169 -0
  508. package/examples/stageflow.yaml +6 -0
  509. package/package.json +1 -1
  510. package/skills/stageflow/SKILL.md +5 -2
  511. package/skills/stageflow/references/control-surface.md +4 -2
  512. package/skills/stageflow/references/evals.md +68 -0
  513. package/skills/stageflow-author/SKILL.md +4 -0
  514. package/skills/stageflow-run/SKILL.md +4 -0
  515. package/dist/ui/assets/AssistantRuntimeProvider-CsiPFhCT.js +0 -9
  516. package/dist/ui/assets/ReadonlyStore-BfXqHykm.js +0 -6
  517. package/dist/ui/assets/chat-BbLukq9W.js +0 -5
  518. package/dist/ui/assets/chat-zIZU_bP1.css +0 -2
  519. package/dist/ui/assets/main-CijYMeM0.js +0 -259
@@ -0,0 +1,446 @@
1
+ import { internalAgentsVisible } from "../operatorAgent/internalAgents.js";
2
+ import { PROFILE_GRANTS } from "../toolkit/profiles.js";
3
+ import { realpath, stat } from "node:fs/promises";
4
+ import path from "node:path";
5
+ import { mapJudge } from "../evals/judgeProviders.js";
6
+ import { classifyTool } from "../agents/toolRisk.js";
7
+ import { checkDatasetAgainstAgent } from "./datasetAgentCheck.js";
8
+ import { checkDatasetAgainstStage } from "./datasetStageCheck.js";
9
+ import { EVAL_DEFAULT_REPEATS, resolveConversation, resolveEvalPaths, } from "./loadEval.js";
10
+ import { resolveAgentTarget, resolveAgentTargetFromFile, } from "./resolveAgentTarget.js";
11
+ import { resolveEvalTarget } from "./resolveEvalTarget.js";
12
+ export const EVAL_LARGE_RUN = 500;
13
+ export const EVAL_TOO_LARGE_RUN = 5000;
14
+ const CONVERSATION_GRADER_TYPES = ["tool_calls", "conversation_check", "goal_reached"];
15
+ export function evalFinding(relPath, severity, code, message, location = {}) {
16
+ return {
17
+ severity,
18
+ code,
19
+ path: relPath,
20
+ message,
21
+ category: "eval",
22
+ ...(location.line !== undefined ? { line: location.line } : {}),
23
+ ...(location.column !== undefined ? { column: location.column } : {}),
24
+ };
25
+ }
26
+ export function evalFindingsFromIssues(relPath, issues) {
27
+ return issues.flatMap((issue) => issue.category === "eval"
28
+ ? [evalFinding(relPath, issue.severity ?? "error", issue.code, issue.message, issue)]
29
+ : []);
30
+ }
31
+ function valueAtPath(root, dotted) {
32
+ let current = root;
33
+ for (const segment of dotted.split(".")) {
34
+ if (typeof current !== "object" || current === null)
35
+ return undefined;
36
+ current = current[segment];
37
+ }
38
+ return current;
39
+ }
40
+ async function datasetFileFinding(loaded, datasetPath, projectRoot) {
41
+ const missing = (reason) => evalFinding(loaded.relPath, "error", "eval.dataset_unresolved", `Dataset "${loaded.file.dataset}" ${reason}`);
42
+ try {
43
+ const info = await stat(datasetPath);
44
+ if (!info.isFile())
45
+ return missing("is not a file");
46
+ const [realFile, realRoot] = await Promise.all([realpath(datasetPath), realpath(projectRoot)]);
47
+ const rel = path.relative(realRoot, realFile);
48
+ if (rel.startsWith("..") || path.isAbsolute(rel))
49
+ return missing("resolves outside the project root");
50
+ }
51
+ catch {
52
+ return missing("was not found");
53
+ }
54
+ return undefined;
55
+ }
56
+ function stageNeedsCheckout(target) {
57
+ return target.completion?.checks.some((check) => check.type === "checkout_changes") === true;
58
+ }
59
+ export async function validateEval(loaded, ctx) {
60
+ const findings = [];
61
+ const add = (severity, code, message) => {
62
+ findings.push(evalFinding(loaded.relPath, severity, code, message));
63
+ };
64
+ const { file } = loaded;
65
+ const sameId = (ctx.evals ?? []).filter((other) => other.id === loaded.id && path.resolve(other.absPath) !== path.resolve(loaded.path));
66
+ if (sameId.length > 0) {
67
+ const others = sameId
68
+ .map((other) => path.relative(ctx.projectRoot, other.absPath).split(path.sep).join("/"))
69
+ .join(", ");
70
+ add("error", "eval.duplicate_id", `Duplicate eval id "${loaded.id}" also declared in: ${others}`);
71
+ }
72
+ const targetKind = file.target.kind;
73
+ for (const grader of loaded.graders) {
74
+ const conversationTarget = targetKind === "agent" || targetKind === "internal_agent";
75
+ const wrongKind = conversationTarget
76
+ ? grader.type === "schema"
77
+ : CONVERSATION_GRADER_TYPES.includes(grader.type);
78
+ if (wrongKind) {
79
+ add("error", "eval.grader_not_applicable", `Grader "${grader.id}" (${grader.type}) cannot grade ${conversationTarget ? "an agent" : "a stage"} target`);
80
+ }
81
+ }
82
+ if (file.target.kind === "agent") {
83
+ return validateAgentEval(loaded, ctx, findings);
84
+ }
85
+ if (file.target.kind === "internal_agent") {
86
+ return validateInternalAgentEval(loaded, findings);
87
+ }
88
+ const target = await resolveEvalTarget(file, loaded.path, ctx.projectRoot);
89
+ let resolved;
90
+ if (!target.ok) {
91
+ findings.push(...evalFindingsFromIssues(loaded.relPath, target.issues));
92
+ }
93
+ else {
94
+ resolved = target.value;
95
+ }
96
+ if (resolved) {
97
+ if (loaded.graders.some((g) => g.type === "schema") && resolved.outputSchema === undefined) {
98
+ add("error", "eval.schema_grader_without_output_schema", `A schema grader needs the target stage to declare io.output.schema`);
99
+ }
100
+ if ((resolved.stageConfig.gate_kinds?.length ?? 0) > 0) {
101
+ add("warning", "eval.stage_has_gates", `Target stage declares gate_kinds (${resolved.stageConfig.gate_kinds?.join(", ")}); a case that stops to ask the operator is recorded as an error`);
102
+ }
103
+ if (stageNeedsCheckout(resolved)) {
104
+ add("warning", "eval.stage_needs_checkout", "Target stage needs a repository checkout, which eval runs do not provide in release 1");
105
+ }
106
+ }
107
+ const stageModel = file.defaults?.model ?? resolved?.modelResolved;
108
+ const unknownChecked = new Set();
109
+ for (const grader of loaded.graders) {
110
+ if (grader.type !== "rubric")
111
+ continue;
112
+ if (grader.judge === "") {
113
+ add("error", "eval.judge_missing", `Rubric grader "${grader.id}" has no judge: set defaults.judge or the grader's judge`);
114
+ continue;
115
+ }
116
+ if (ctx.isKnownModel && !unknownChecked.has(grader.judge)) {
117
+ unknownChecked.add(grader.judge);
118
+ if (!(await ctx.isKnownModel(grader.judge))) {
119
+ add("warning", "eval.judge_unknown_model", `Judge model "${grader.judge}" is not in the model catalog`);
120
+ }
121
+ }
122
+ if (stageModel !== undefined && grader.judge === stageModel) {
123
+ add("warning", "eval.judge_same_as_stage", `Rubric grader "${grader.id}" uses judge "${grader.judge}", the same model as the stage (self-preference bias)`);
124
+ }
125
+ }
126
+ const paths = resolveEvalPaths(file, loaded.path);
127
+ const datasetProblem = ctx.datasetInline
128
+ ? undefined
129
+ : await datasetFileFinding(loaded, paths.datasetPath, ctx.projectRoot);
130
+ if (datasetProblem) {
131
+ findings.push(datasetProblem);
132
+ return findings;
133
+ }
134
+ const report = ctx.datasetReport;
135
+ if (!report)
136
+ return findings;
137
+ const datasetErrors = report.findings.filter((f) => f.severity === "error");
138
+ if (datasetErrors.length > 0) {
139
+ add("error", "eval.dataset_invalid", `Dataset ${report.relPath} has ${datasetErrors.length} error(s); first: ${datasetErrors[0]?.message}`);
140
+ }
141
+ const mismatches = resolved
142
+ ? checkDatasetAgainstStage(report.cases, resolved.inputSchema).filter((r) => !r.valid)
143
+ : [];
144
+ const skipped = new Set(mismatches.map((m) => m.caseId));
145
+ for (const mismatch of mismatches) {
146
+ findings.push({
147
+ severity: "warning",
148
+ code: "dataset.input_mismatch",
149
+ path: report.relPath,
150
+ message: `case ${mismatch.caseId}: input does not match the stage's io.input.schema: ${mismatch.message}`,
151
+ category: "dataset",
152
+ });
153
+ }
154
+ if (mismatches.length > 0) {
155
+ add("warning", "eval.cases_skipped", `${mismatches.length} case(s) fail the stage's io.input.schema and will be skipped when a run starts; first: ${mismatches[0]?.caseId}`);
156
+ }
157
+ const runnable = report.cases.filter((c) => !skipped.has(c.id));
158
+ if (datasetErrors.length === 0 && runnable.length === 0) {
159
+ add("error", "eval.no_valid_cases", `Dataset ${report.relPath} has no valid cases to run`);
160
+ }
161
+ for (const grader of loaded.graders) {
162
+ if (grader.type !== "reference")
163
+ continue;
164
+ const missingIds = runnable
165
+ .filter((c) => {
166
+ const value = valueAtPath(c, grader.expected);
167
+ return value === undefined || value === null;
168
+ })
169
+ .map((c) => c.id);
170
+ if (missingIds.length > 0) {
171
+ add("warning", "eval.cases_missing_expected", `Reference grader "${grader.id}": ${missingIds.length} of ${runnable.length} case(s) have no value at "${grader.expected}"; first: ${missingIds[0]}`);
172
+ }
173
+ }
174
+ const repeats = file.defaults?.repeats ?? EVAL_DEFAULT_REPEATS;
175
+ const results = runnable.length * repeats;
176
+ if (results > EVAL_TOO_LARGE_RUN) {
177
+ add("error", "eval.too_large_run", `${runnable.length} case(s) x ${repeats} repeat(s) = ${results} results, over the ${EVAL_TOO_LARGE_RUN} limit`);
178
+ }
179
+ else if (results > EVAL_LARGE_RUN) {
180
+ add("warning", "eval.large_run", `${runnable.length} case(s) x ${repeats} repeat(s) = ${results} results, over ${EVAL_LARGE_RUN}`);
181
+ }
182
+ return findings;
183
+ }
184
+ function toolGranted(target, name) {
185
+ const ids = target.tools.map((tool) => tool.id);
186
+ if (ids.includes(name))
187
+ return true;
188
+ if (name.endsWith(".*")) {
189
+ const prefix = name.slice(0, -1);
190
+ return ids.some((id) => id.startsWith(prefix));
191
+ }
192
+ const dot = name.indexOf(".");
193
+ return dot > 0 && ids.includes(`${name.slice(0, dot)}.*`);
194
+ }
195
+ function isReadClass(tool, listed) {
196
+ return tool.risk === "read" || classifyTool(undefined, tool.id, listed).readOnly;
197
+ }
198
+ function nameList(names) {
199
+ return names.slice(0, 5).join(", ") + (names.length > 5 ? ", ..." : "");
200
+ }
201
+ function hasExpectedTools(c) {
202
+ const expected = c.expected;
203
+ if (typeof expected !== "object" || expected === null)
204
+ return false;
205
+ const record = expected;
206
+ return record.tools !== undefined || record.forbidden_tools !== undefined;
207
+ }
208
+ function validateInternalAgentEval(loaded, findings) {
209
+ const add = (severity, code, message) => {
210
+ findings.push(evalFinding(loaded.relPath, severity, code, message));
211
+ };
212
+ const profile = loaded.file.target.kind === "internal_agent" ? loaded.file.target.profile : "";
213
+ if (!internalAgentsVisible()) {
214
+ add("error", "eval.internal_agent_hidden", "Internal agents are hidden. Set STAGEFLOW_SHOW_INTERNAL_AGENTS=1 on the Host to eval one.");
215
+ }
216
+ const grant = PROFILE_GRANTS[profile];
217
+ if (!grant) {
218
+ add("error", "eval.internal_agent_unknown", `No internal agent has id "${profile}"`);
219
+ }
220
+ const conversation = resolveConversation(loaded.file.conversation);
221
+ if (conversation.tools === "real") {
222
+ add("error", "eval.internal_agent_real_tools", "An internal agent eval cannot use real tools. They write the operator's project and do not pass the project-agent tool gate. Use read_only or mocked.");
223
+ }
224
+ if (grant) {
225
+ const names = new Set(grant.tools);
226
+ for (const grader of loaded.graders) {
227
+ if (grader.type !== "tool_calls")
228
+ continue;
229
+ const mentioned = [
230
+ ...(grader.mustCall ?? []),
231
+ ...(grader.mustNotCall ?? []),
232
+ ...(grader.mustAskFirst ?? []),
233
+ ...grader.args.map((arg) => arg.tool),
234
+ ];
235
+ const missing = [...new Set(mentioned)].filter((name) => !names.has(name));
236
+ if (missing.length > 0) {
237
+ add("warning", "eval.tool_not_granted", `Grader "${grader.id}" names tool(s) ${profile} does not have: ${missing.join(", ")}`);
238
+ }
239
+ }
240
+ }
241
+ return findings;
242
+ }
243
+ async function validateAgentEval(loaded, ctx, findings) {
244
+ const add = (severity, code, message) => {
245
+ findings.push(evalFinding(loaded.relPath, severity, code, message));
246
+ };
247
+ const { file } = loaded;
248
+ const conversation = resolveConversation(file.conversation);
249
+ const outcome = ctx.agents
250
+ ? await resolveAgentTarget(file, ctx.projectRoot, ctx.agents)
251
+ : await resolveAgentTargetFromFile(file, ctx.projectRoot);
252
+ let resolved;
253
+ if (outcome.ok) {
254
+ resolved = outcome.value;
255
+ findings.push(...evalFindingsFromIssues(loaded.relPath, outcome.issues ?? []));
256
+ }
257
+ else {
258
+ findings.push(...evalFindingsFromIssues(loaded.relPath, outcome.issues));
259
+ }
260
+ if (conversation.tools === "real") {
261
+ if (!conversation.allowRealTools) {
262
+ add("error", "eval.real_tools_not_allowed", "conversation.tools is real: set allow_real_tools: true to consent to real tools");
263
+ }
264
+ else {
265
+ add("warning", "eval.tools_real", "Real tools can change files and call services from this machine.");
266
+ }
267
+ }
268
+ const agentModel = file.defaults?.model ?? resolved?.modelResolved;
269
+ const unknownChecked = new Set();
270
+ for (const grader of loaded.graders) {
271
+ if (grader.type !== "rubric" && grader.type !== "goal_reached")
272
+ continue;
273
+ if (grader.judge === "") {
274
+ add("error", "eval.judge_missing", `${grader.type === "rubric" ? "Rubric" : "Goal"} grader "${grader.id}" has no judge: set defaults.judge or the grader's judge`);
275
+ continue;
276
+ }
277
+ if (ctx.isKnownModel && !unknownChecked.has(grader.judge)) {
278
+ unknownChecked.add(grader.judge);
279
+ if (!(await ctx.isKnownModel(grader.judge))) {
280
+ add("warning", "eval.judge_unknown_model", `Judge model "${grader.judge}" is not in the model catalog`);
281
+ }
282
+ }
283
+ if (agentModel !== undefined && grader.judge === agentModel) {
284
+ add("warning", "eval.judge_same_as_stage", `Grader "${grader.id}" uses judge "${grader.judge}", the same model as the agent (self-preference bias)`);
285
+ }
286
+ }
287
+ if (resolved) {
288
+ const grantWarn = (names, where) => {
289
+ const missing = [...new Set(names)].filter((name) => !toolGranted(resolved, name));
290
+ if (missing.length > 0) {
291
+ add("warning", "eval.tool_not_granted", `${where} names tool(s) the agent is not granted: ${nameList(missing)}`);
292
+ }
293
+ };
294
+ for (const grader of loaded.graders) {
295
+ if (grader.type !== "tool_calls")
296
+ continue;
297
+ grantWarn([
298
+ ...(grader.mustCall ?? []),
299
+ ...(grader.mustNotCall ?? []),
300
+ ...(grader.mustAskFirst ?? []),
301
+ ...grader.args.map((arg) => arg.tool),
302
+ ], `Grader "${grader.id}"`);
303
+ }
304
+ grantWarn(conversation.readOnlyTools, "conversation.read_only_tools");
305
+ const ineffective = [...new Set(conversation.readOnlyTools)].filter((name) => {
306
+ const cls = classifyTool(undefined, name).class;
307
+ return cls !== "mcp_unknown" && cls !== "read";
308
+ });
309
+ if (ineffective.length > 0) {
310
+ add("error", "eval.read_only_tools_not_mcp", `conversation.read_only_tools can only declare MCP tools read-only; these built-in or Stageflow tools stay stubbed: ${nameList(ineffective)}`);
311
+ }
312
+ if (conversation.tools === "read_only") {
313
+ const stubbed = resolved.tools
314
+ .filter((tool) => !isReadClass(tool, conversation.readOnlyTools))
315
+ .map((tool) => tool.id);
316
+ if (stubbed.length > 0) {
317
+ add("warning", "eval.tools_unstubbed_list", `Tools that are not read-only: ${nameList(stubbed)}. These are stubbed and recorded, not executed`);
318
+ }
319
+ }
320
+ }
321
+ const paths = resolveEvalPaths(file, loaded.path);
322
+ const datasetProblem = ctx.datasetInline
323
+ ? undefined
324
+ : await datasetFileFinding(loaded, paths.datasetPath, ctx.projectRoot);
325
+ const simulatedAnywhere = (inputs) => inputs === undefined
326
+ ? conversation.mode === "simulated"
327
+ : inputs.some((input) => (input.mode ?? conversation.mode) === "simulated");
328
+ const checkSimulator = async (usesSimulator) => {
329
+ if (!usesSimulator)
330
+ return;
331
+ const userModel = file.defaults?.user_model ?? file.defaults?.judge;
332
+ if (userModel === undefined) {
333
+ add("error", "eval.user_model_missing", "Simulated conversations need a user model: set defaults.user_model or defaults.judge");
334
+ return;
335
+ }
336
+ if (mapJudge(userModel) === null) {
337
+ add("error", "eval.simulator_unsupported", `User model "${userModel}" cannot be used: supported providers are anthropic, openai, openrouter`);
338
+ return;
339
+ }
340
+ if (ctx.isKnownModel && !(await ctx.isKnownModel(userModel))) {
341
+ add("warning", "eval.simulator_unknown_model", `User model "${userModel}" is not in the model catalog`);
342
+ }
343
+ if (agentModel !== undefined && userModel === agentModel) {
344
+ add("warning", "eval.simulator_same_as_agent", `User model "${userModel}" is the same model as the agent`);
345
+ }
346
+ };
347
+ if (datasetProblem) {
348
+ findings.push(datasetProblem);
349
+ await checkSimulator(simulatedAnywhere(undefined));
350
+ return findings;
351
+ }
352
+ const report = ctx.datasetReport;
353
+ if (!report) {
354
+ await checkSimulator(simulatedAnywhere(undefined));
355
+ return findings;
356
+ }
357
+ const datasetErrors = report.findings.filter((f) => f.severity === "error");
358
+ if (datasetErrors.length > 0) {
359
+ add("error", "eval.dataset_invalid", `Dataset ${report.relPath} has ${datasetErrors.length} error(s); first: ${datasetErrors[0]?.message}`);
360
+ }
361
+ const checks = checkDatasetAgainstAgent(report.cases, { mode: conversation.mode });
362
+ const mismatches = checks.filter((r) => !r.valid);
363
+ const skipped = new Set(mismatches.map((m) => m.caseId));
364
+ for (const mismatch of mismatches) {
365
+ findings.push({
366
+ severity: "warning",
367
+ code: "dataset.input_mismatch",
368
+ path: report.relPath,
369
+ message: `case ${mismatch.caseId}: ${mismatch.message}`,
370
+ category: "dataset",
371
+ });
372
+ }
373
+ for (const note of checks.flatMap((r) => r.notes)) {
374
+ findings.push({
375
+ severity: "warning",
376
+ code: note.code,
377
+ path: report.relPath,
378
+ message: note.message,
379
+ category: "dataset",
380
+ });
381
+ }
382
+ if (mismatches.length > 0) {
383
+ add("warning", "eval.cases_skipped", `${mismatches.length} case(s) have an invalid scenario and will be skipped when a run starts; first: ${mismatches[0]?.caseId}`);
384
+ }
385
+ const runnable = report.cases.filter((c) => !skipped.has(c.id));
386
+ if (datasetErrors.length === 0 && runnable.length === 0) {
387
+ add("error", "eval.no_valid_cases", `Dataset ${report.relPath} has no valid cases to run`);
388
+ }
389
+ await checkSimulator(simulatedAnywhere(runnable.map((c) => c.input)));
390
+ if (conversation.tools === "mocked" && !runnable.some((c) => c.input.tool_mocks !== undefined)) {
391
+ add("warning", "eval.tools_mocked_no_mocks", "conversation.tools is mocked but no case has tool_mocks");
392
+ }
393
+ if (resolved) {
394
+ const mockNames = runnable.flatMap((c) => typeof c.input.tool_mocks === "object" && c.input.tool_mocks !== null
395
+ ? Object.keys(c.input.tool_mocks)
396
+ : []);
397
+ const missing = [...new Set(mockNames)].filter((name) => !toolGranted(resolved, name));
398
+ if (missing.length > 0) {
399
+ add("warning", "eval.tool_not_granted", `Case tool_mocks name tool(s) the agent is not granted: ${nameList(missing)}`);
400
+ }
401
+ }
402
+ for (const grader of loaded.graders) {
403
+ if (grader.type === "goal_reached") {
404
+ const missingGoal = runnable.filter((c) => {
405
+ const expected = c.expected;
406
+ const hasGoal = typeof c.input.goal === "string" && c.input.goal !== "";
407
+ const hasOutcome = typeof expected?.outcome === "string" && expected.outcome !== "";
408
+ return !hasGoal && !hasOutcome;
409
+ });
410
+ if (missingGoal.length > 0) {
411
+ add("warning", "eval.cases_missing_goal", `Grader "${grader.id}": ${missingGoal.length} of ${runnable.length} case(s) have no input.goal or expected.outcome; first: ${missingGoal[0]?.id}`);
412
+ }
413
+ }
414
+ if (grader.type === "tool_calls" &&
415
+ grader.mustCall === undefined &&
416
+ grader.mustNotCall === undefined &&
417
+ grader.mustAskFirst === undefined &&
418
+ grader.maxCalls === undefined &&
419
+ grader.args.length === 0) {
420
+ const missingIds = runnable.filter((c) => !hasExpectedTools(c)).map((c) => c.id);
421
+ if (missingIds.length > 0) {
422
+ add("warning", "eval.cases_missing_expected", `Grader "${grader.id}": ${missingIds.length} of ${runnable.length} case(s) have no expected.tools or expected.forbidden_tools; first: ${missingIds[0]}`);
423
+ }
424
+ }
425
+ if (grader.type === "reference") {
426
+ const missingIds = runnable
427
+ .filter((c) => {
428
+ const value = valueAtPath(c, grader.expected);
429
+ return value === undefined || value === null;
430
+ })
431
+ .map((c) => c.id);
432
+ if (missingIds.length > 0) {
433
+ add("warning", "eval.cases_missing_expected", `Reference grader "${grader.id}": ${missingIds.length} of ${runnable.length} case(s) have no value at "${grader.expected}"; first: ${missingIds[0]}`);
434
+ }
435
+ }
436
+ }
437
+ const repeats = file.defaults?.repeats ?? EVAL_DEFAULT_REPEATS;
438
+ const results = runnable.length * repeats;
439
+ if (results > EVAL_TOO_LARGE_RUN) {
440
+ add("error", "eval.too_large_run", `${runnable.length} case(s) x ${repeats} repeat(s) = ${results} results, over the ${EVAL_TOO_LARGE_RUN} limit`);
441
+ }
442
+ else if (results > EVAL_LARGE_RUN) {
443
+ add("warning", "eval.large_run", `${runnable.length} case(s) x ${repeats} repeat(s) = ${results} results, over ${EVAL_LARGE_RUN}`);
444
+ }
445
+ return findings;
446
+ }
@@ -0,0 +1,54 @@
1
+ import type { DatasetCase } from "./datasetTypes.js";
2
+ import type { ValidationFinding } from "./validateCatalog.js";
3
+ export type NewDatasetCase = Omit<DatasetCase, "id"> & {
4
+ id?: string;
5
+ };
6
+ export type CaseOp = {
7
+ op: "add";
8
+ case: NewDatasetCase;
9
+ } | {
10
+ op: "update";
11
+ id: string;
12
+ case: NewDatasetCase;
13
+ } | {
14
+ op: "delete";
15
+ id: string;
16
+ } | {
17
+ op: "set_tags";
18
+ id: string;
19
+ tags: string[];
20
+ };
21
+ export type DatasetWriteResult = {
22
+ id: string;
23
+ path: string;
24
+ relPath: string;
25
+ text: string;
26
+ hash: string;
27
+ cases: DatasetCase[];
28
+ findings: ValidationFinding[];
29
+ };
30
+ export declare function renderDatasetJsonl(cases: readonly NewDatasetCase[]): string;
31
+ export declare function createDatasetFile(input: {
32
+ projectRoot: string;
33
+ name: string;
34
+ cases: readonly NewDatasetCase[];
35
+ directory?: string;
36
+ }): Promise<DatasetWriteResult>;
37
+ export declare function applyCaseOps(input: {
38
+ projectRoot: string;
39
+ id: string;
40
+ baseHash: string;
41
+ ops: readonly CaseOp[];
42
+ }): Promise<DatasetWriteResult>;
43
+ export declare function appendOrReplaceCases(input: {
44
+ projectRoot: string;
45
+ id: string;
46
+ baseHash: string;
47
+ mode: "append" | "replace";
48
+ cases: readonly NewDatasetCase[];
49
+ }): Promise<DatasetWriteResult>;
50
+ export declare function convertDatasetToJsonl(input: {
51
+ projectRoot: string;
52
+ id: string;
53
+ baseHash: string;
54
+ }): Promise<DatasetWriteResult>;
@@ -0,0 +1,186 @@
1
+ import { access } from "node:fs/promises";
2
+ import path from "node:path";
3
+ import { EvalsWriteError, FileChangedError, writeFileAtomic } from "./atomicWrite.js";
4
+ import { ensureCatalogScanRoot } from "./ensureCatalogScanRoot.js";
5
+ import { formatId, nextIdNumber } from "./datasetImport.js";
6
+ import { assertInsideProject, datasetStem, explicitRoots, findDatasetFile, manifestForWrite, resolveWriteDir, } from "./evalWriteRoots.js";
7
+ import { datasetFormatFromPath, loadDatasetFile, parseDatasetText } from "./loadDataset.js";
8
+ const NAME_PATTERN = /^[a-z0-9][a-z0-9-]{0,62}$/;
9
+ const CASE_KEY_ORDER = ["id", "title", "input", "expected", "tags", "goal", "metadata"];
10
+ function orderedCase(c) {
11
+ const source = c;
12
+ const out = {};
13
+ for (const key of CASE_KEY_ORDER) {
14
+ if (source[key] !== undefined)
15
+ out[key] = source[key];
16
+ }
17
+ for (const key of Object.keys(source)) {
18
+ if (!(key in out) && source[key] !== undefined)
19
+ out[key] = source[key];
20
+ }
21
+ return out;
22
+ }
23
+ export function renderDatasetJsonl(cases) {
24
+ return cases.map((c) => `${JSON.stringify(orderedCase(c))}\n`).join("");
25
+ }
26
+ function assignIds(cases, existingIds) {
27
+ const taken = [...existingIds, ...cases.flatMap((c) => (c.id !== undefined ? [c.id] : []))];
28
+ let next = nextIdNumber(taken);
29
+ return cases.map((c) => {
30
+ if (c.id !== undefined)
31
+ return c;
32
+ const id = formatId(next);
33
+ next += 1;
34
+ return { ...c, id };
35
+ });
36
+ }
37
+ function assertUniqueIds(cases) {
38
+ const seen = new Set();
39
+ for (const c of cases) {
40
+ if (seen.has(c.id)) {
41
+ throw new EvalsWriteError("DATASET_CASE_OP_INVALID", `duplicate case id "${c.id}"`);
42
+ }
43
+ seen.add(c.id);
44
+ }
45
+ }
46
+ function checkedCases(text, relPath) {
47
+ const parsed = parseDatasetText(text, "jsonl", { path: relPath });
48
+ const errors = parsed.findings.filter((f) => f.severity === "error");
49
+ if (errors.length > 0) {
50
+ throw new EvalsWriteError("DATASET_INVALID", errors[0].message, parsed.findings);
51
+ }
52
+ return { cases: parsed.cases, hash: parsed.contentHash, findings: parsed.findings };
53
+ }
54
+ function relOf(projectRoot, abs) {
55
+ return path.relative(projectRoot, abs).split(path.sep).join("/");
56
+ }
57
+ async function exists(abs) {
58
+ try {
59
+ await access(abs);
60
+ return true;
61
+ }
62
+ catch {
63
+ return false;
64
+ }
65
+ }
66
+ export async function createDatasetFile(input) {
67
+ const { projectRoot, name } = input;
68
+ const manifest = await manifestForWrite(projectRoot);
69
+ const dir = await resolveWriteDir(projectRoot, manifest, "datasets", input.directory);
70
+ const absPath = path.join(dir.absDir, `${name}.dataset.jsonl`);
71
+ assertInsideProject(projectRoot, absPath, "dataset path");
72
+ if (!NAME_PATTERN.test(name)) {
73
+ throw new EvalsWriteError("DATASET_NAME_INVALID", `Dataset name must match ${NAME_PATTERN.source}`);
74
+ }
75
+ if ((await findDatasetFile(projectRoot, name, manifest)) !== undefined || (await exists(absPath))) {
76
+ throw new EvalsWriteError("DATASET_EXISTS", `Dataset "${name}" already exists`);
77
+ }
78
+ const cases = assignIds(input.cases, []);
79
+ assertUniqueIds(cases);
80
+ const text = renderDatasetJsonl(cases);
81
+ const relPath = relOf(projectRoot, absPath);
82
+ const checked = checkedCases(text, relPath);
83
+ await writeFileAtomic(absPath, text);
84
+ if (explicitRoots(manifest, "datasets") !== undefined) {
85
+ await ensureCatalogScanRoot(projectRoot, dir.relDir, ["datasets"]);
86
+ }
87
+ return { id: name, path: absPath, relPath, text, ...checked };
88
+ }
89
+ async function loadEditable(projectRoot, id, baseHash, requireJsonl) {
90
+ const ref = await findDatasetFile(projectRoot, id);
91
+ if (ref === undefined)
92
+ throw new EvalsWriteError("DATASET_NOT_FOUND", `Dataset "${id}" not found`);
93
+ const format = datasetFormatFromPath(ref.absPath);
94
+ if (format === undefined)
95
+ throw new EvalsWriteError("DATASET_INVALID", "Unknown dataset format");
96
+ if (requireJsonl && format !== "jsonl") {
97
+ throw new EvalsWriteError("DATASET_READ_ONLY", `Dataset "${id}" is .${format}; only .dataset.jsonl is editable. Convert it to JSONL first`);
98
+ }
99
+ const loaded = await loadDatasetFile(ref.absPath, { root: projectRoot });
100
+ if (loaded.contentHash !== baseHash)
101
+ throw new FileChangedError(loaded.contentHash);
102
+ const errors = loaded.findings.filter((f) => f.severity === "error");
103
+ if (errors.length > 0) {
104
+ throw new EvalsWriteError("DATASET_INVALID", errors[0].message, loaded.findings);
105
+ }
106
+ return { absPath: ref.absPath, relPath: ref.relPath, cases: loaded.cases, format };
107
+ }
108
+ async function commit(projectRoot, target, cases, baseHash) {
109
+ assertUniqueIds(cases);
110
+ const text = renderDatasetJsonl(cases);
111
+ const checked = checkedCases(text, target.relPath);
112
+ const recheck = await loadDatasetFile(target.absPath, { root: projectRoot });
113
+ if (recheck.contentHash !== baseHash)
114
+ throw new FileChangedError(recheck.contentHash);
115
+ await writeFileAtomic(target.absPath, text);
116
+ return { id: target.id, path: target.absPath, relPath: target.relPath, text, ...checked };
117
+ }
118
+ function opError(index, op, message) {
119
+ return new EvalsWriteError("DATASET_CASE_OP_INVALID", `op ${index} (${op.op}): ${message}`);
120
+ }
121
+ function applyOps(cases, ops) {
122
+ let working = [...cases];
123
+ ops.forEach((op, index) => {
124
+ if (op.op === "add") {
125
+ if (op.case.id !== undefined && working.some((c) => c.id === op.case.id)) {
126
+ throw opError(index, op, `case "${op.case.id}" already exists`);
127
+ }
128
+ const [added] = assignIds([op.case], working.map((c) => c.id));
129
+ working = [...working, added];
130
+ return;
131
+ }
132
+ const at = working.findIndex((c) => c.id === op.id);
133
+ if (at === -1)
134
+ throw opError(index, op, `case "${op.id}" not found`);
135
+ if (op.op === "delete") {
136
+ working = working.filter((_, i) => i !== at);
137
+ }
138
+ else if (op.op === "update") {
139
+ if (op.case.id !== undefined && op.case.id !== op.id) {
140
+ throw opError(index, op, `case id cannot change from "${op.id}" to "${op.case.id}"`);
141
+ }
142
+ working = working.map((c, i) => (i === at ? { ...op.case, id: op.id } : c));
143
+ }
144
+ else if (op.op === "set_tags") {
145
+ working = working.map((c, i) => {
146
+ if (i !== at)
147
+ return c;
148
+ const { tags: _drop, ...rest } = c;
149
+ return op.tags.length > 0 ? { ...rest, tags: op.tags } : rest;
150
+ });
151
+ }
152
+ else {
153
+ throw opError(index, op, "unknown op");
154
+ }
155
+ });
156
+ return working;
157
+ }
158
+ export async function applyCaseOps(input) {
159
+ const { projectRoot, id, baseHash } = input;
160
+ const current = await loadEditable(projectRoot, id, baseHash, true);
161
+ const next = applyOps(current.cases, input.ops);
162
+ return commit(projectRoot, { ...current, id }, next, baseHash);
163
+ }
164
+ export async function appendOrReplaceCases(input) {
165
+ const { projectRoot, id, baseHash, mode } = input;
166
+ const current = await loadEditable(projectRoot, id, baseHash, true);
167
+ const kept = mode === "append" ? current.cases : [];
168
+ const added = assignIds(input.cases, kept.map((c) => c.id));
169
+ return commit(projectRoot, { ...current, id }, [...kept, ...added], baseHash);
170
+ }
171
+ export async function convertDatasetToJsonl(input) {
172
+ const { projectRoot, id, baseHash } = input;
173
+ const current = await loadEditable(projectRoot, id, baseHash, false);
174
+ if (current.format === "jsonl") {
175
+ throw new EvalsWriteError("DATASET_INVALID", `Dataset "${id}" is already .dataset.jsonl`);
176
+ }
177
+ const absPath = path.join(path.dirname(current.absPath), `${datasetStem(path.basename(current.absPath))}.dataset.jsonl`);
178
+ if (await exists(absPath)) {
179
+ throw new EvalsWriteError("DATASET_EXISTS", `${path.basename(absPath)} already exists`);
180
+ }
181
+ const relPath = relOf(projectRoot, absPath);
182
+ const text = renderDatasetJsonl(current.cases);
183
+ const checked = checkedCases(text, relPath);
184
+ await writeFileAtomic(absPath, text);
185
+ return { id: datasetStem(path.basename(absPath)), path: absPath, relPath, text, ...checked };
186
+ }