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,4 @@
1
+ import { type CompareResult } from "../compare.js";
2
+ import type { EvalRunRow } from "../storeTypes.js";
3
+ import { type ReadStore } from "./runs.js";
4
+ export declare function buildCompare(store: ReadStore, a: EvalRunRow, b: EvalRunRow): Promise<CompareResult>;
@@ -0,0 +1,39 @@
1
+ import { compareRuns } from "../compare.js";
2
+ import { toGradeRecords, toResultRecord } from "../statsAdapter.js";
3
+ import { graderRefsOf } from "./runs.js";
4
+ async function compareInput(store, row) {
5
+ const results = await store.listEvalResults(row.evalRunId);
6
+ const target = row.config
7
+ .target;
8
+ const isAgent = row.targetKind === "agent";
9
+ const definition = isAgent ? undefined : target?.stage_definition;
10
+ const agentDefinition = isAgent ? target?.definition : undefined;
11
+ const plain = (v) => (typeof v === "object" && v !== null && !Array.isArray(v) ? v : null);
12
+ return {
13
+ targetKind: row.targetKind === "agent" ? "agent" : "stage",
14
+ ...(isAgent
15
+ ? {
16
+ agentId: row.targetRef.agent_id ?? null,
17
+ agentRevision: typeof target?.revision === "number" ? target.revision : null,
18
+ agentDefinition: plain(agentDefinition),
19
+ }
20
+ : {}),
21
+ evalId: row.evalId,
22
+ runNumber: row.runNumber,
23
+ datasetHash: row.datasetHash,
24
+ stageVersionHash: row.targetVersionHash,
25
+ stageDefinition: typeof definition === "object" && definition !== null && !Array.isArray(definition)
26
+ ? definition
27
+ : null,
28
+ configComponents: row.configComponents,
29
+ results: results.map(toResultRecord),
30
+ grades: results.flatMap(toGradeRecords),
31
+ graders: graderRefsOf(row),
32
+ repeats: row.repeats,
33
+ passThreshold: row.passThreshold,
34
+ };
35
+ }
36
+ export async function buildCompare(store, a, b) {
37
+ const [left, right] = await Promise.all([compareInput(store, a), compareInput(store, b)]);
38
+ return compareRuns(left, right);
39
+ }
@@ -0,0 +1,105 @@
1
+ import { type UploadMapping, type UploadPreviewRow } from "../../config/datasetImport.js";
2
+ import type { DatasetCase, DatasetFormat, DatasetLoadResult } from "../../config/datasetTypes.js";
3
+ import type { ValidationFinding } from "../../config/validateCatalog.js";
4
+ import type { AgentCatalogPort } from "../../config/resolveAgentTarget.js";
5
+ import type { ConversationMode } from "../types.js";
6
+ export type InputField = {
7
+ name: string;
8
+ required: boolean;
9
+ type?: string;
10
+ };
11
+ export type DatasetTarget = {
12
+ pipeline_path?: string;
13
+ stage_id?: string;
14
+ file?: string;
15
+ agent_id?: string;
16
+ };
17
+ /** What an agent eval reads from a dataset: the effective conversation mode decides which scenario keys are required. */
18
+ export type AgentDatasetUse = {
19
+ mode: ConversationMode;
20
+ };
21
+ export declare function agentInputFields(mode: ConversationMode): InputField[];
22
+ /** The upload mapping targets an agent dataset cannot take from a column: scripts and tool mocks are JSON or JSONL only. */
23
+ export declare const AGENT_UNSUPPORTED_MAPPING_TARGETS: readonly ["input.script", "input.tool_mocks"];
24
+ export type DatasetListItem = {
25
+ project_root: string;
26
+ id: string;
27
+ path: string;
28
+ format: DatasetFormat | null;
29
+ cases: number;
30
+ hash: string;
31
+ editable: boolean;
32
+ used_by: string[];
33
+ findings_count: number;
34
+ };
35
+ export type DatasetQuery = {
36
+ offset: number;
37
+ limit: number;
38
+ tag?: string;
39
+ q?: string;
40
+ filter: "all" | "invalid" | "tagged";
41
+ };
42
+ export type DatasetDetail = {
43
+ id: string;
44
+ path: string;
45
+ format: DatasetFormat | null;
46
+ hash: string;
47
+ editable: boolean;
48
+ cases_total: number;
49
+ invalid_total: number;
50
+ tagged_total: number;
51
+ matched_total: number;
52
+ tags: Record<string, number>;
53
+ input_fields: InputField[];
54
+ cases: Array<DatasetCase & {
55
+ input_check: {
56
+ valid: boolean;
57
+ message?: string;
58
+ } | null;
59
+ }>;
60
+ findings: ValidationFinding[];
61
+ used_by: string[];
62
+ };
63
+ export declare function inputFieldsOf(schema: unknown): InputField[];
64
+ export type ResolvedDatasetTarget = {
65
+ inputSchema: unknown;
66
+ stageId: string | undefined;
67
+ pipelineAbsPath: string | undefined;
68
+ agentId?: string;
69
+ };
70
+ export declare function resolveDatasetTarget(projectRoot: string, target: DatasetTarget, agents?: AgentCatalogPort): Promise<{
71
+ ok: true;
72
+ value: ResolvedDatasetTarget;
73
+ } | {
74
+ ok: false;
75
+ message: string;
76
+ }>;
77
+ export declare function buildDatasetDetail(input: {
78
+ id: string;
79
+ loaded: DatasetLoadResult;
80
+ inputSchema: unknown;
81
+ hasEval: boolean;
82
+ usedBy: string[];
83
+ query: DatasetQuery;
84
+ agent?: AgentDatasetUse;
85
+ }): DatasetDetail;
86
+ export type PreviewInput = {
87
+ format: DatasetFormat;
88
+ content: string;
89
+ delimiter?: string;
90
+ mapping?: UploadMapping;
91
+ inputSchema?: unknown;
92
+ existingIds?: readonly string[];
93
+ /** Agent dataset: rows are checked as scenarios, in this mode unless the row maps `input.mode`. */
94
+ agent?: AgentDatasetUse;
95
+ };
96
+ export type PreviewResult = {
97
+ columns?: string[];
98
+ rows: UploadPreviewRow[];
99
+ findings: ValidationFinding[];
100
+ counts: {
101
+ ready: number;
102
+ skipped: number;
103
+ };
104
+ };
105
+ export declare function previewUpload(input: PreviewInput): PreviewResult;
@@ -0,0 +1,318 @@
1
+ import path from "node:path";
2
+ import { isInsideProjectRoot } from "../../config/catalogRelativePath.js";
3
+ import { parseCsv, CsvParseError } from "../../config/csv.js";
4
+ import { checkDatasetAgainstAgent } from "../../config/datasetAgentCheck.js";
5
+ import { checkDatasetAgainstStage } from "../../config/datasetStageCheck.js";
6
+ import { applyUploadMapping, formatId, nextIdNumber, } from "../../config/datasetImport.js";
7
+ import { DATASET_LIMITS } from "../../config/loadDataset.js";
8
+ import { resolveEvalTarget } from "../../config/resolveEvalTarget.js";
9
+ import { AGENT_ID_PATTERN, isReservedAgentId } from "../../agents/agentId.js";
10
+ import { isAgentError } from "../../agents/errors.js";
11
+ export function agentInputFields(mode) {
12
+ const simulated = mode === "simulated";
13
+ return [
14
+ { name: "mode", required: false },
15
+ { name: "opening", required: simulated },
16
+ { name: "persona", required: simulated },
17
+ { name: "goal", required: simulated },
18
+ { name: "facts", required: false },
19
+ { name: "script", required: !simulated },
20
+ { name: "tool_mocks", required: false },
21
+ ];
22
+ }
23
+ /** The upload mapping targets an agent dataset cannot take from a column: scripts and tool mocks are JSON or JSONL only. */
24
+ export const AGENT_UNSUPPORTED_MAPPING_TARGETS = ["input.script", "input.tool_mocks"];
25
+ export function inputFieldsOf(schema) {
26
+ if (typeof schema !== "object" || schema === null)
27
+ return [];
28
+ const { properties, required } = schema;
29
+ if (typeof properties !== "object" || properties === null)
30
+ return [];
31
+ const requiredSet = new Set(Array.isArray(required) ? required.filter((r) => typeof r === "string") : []);
32
+ return Object.entries(properties).map(([name, prop]) => {
33
+ const type = typeof prop === "object" && prop !== null ? prop.type : undefined;
34
+ return { name, required: requiredSet.has(name), ...(typeof type === "string" ? { type } : {}) };
35
+ });
36
+ }
37
+ export async function resolveDatasetTarget(projectRoot, target, agents) {
38
+ if (target.agent_id !== undefined) {
39
+ if (target.file !== undefined || target.pipeline_path !== undefined || target.stage_id !== undefined) {
40
+ return { ok: false, message: "target needs either agent_id, file, or pipeline_path with stage_id" };
41
+ }
42
+ const agentId = target.agent_id;
43
+ if (!AGENT_ID_PATTERN.test(agentId) || isReservedAgentId(agentId)) {
44
+ return { ok: false, message: `"${agentId}" is not a valid agent id` };
45
+ }
46
+ if (agents) {
47
+ try {
48
+ await agents.get(projectRoot, agentId);
49
+ }
50
+ catch (err) {
51
+ if (isAgentError(err))
52
+ return { ok: false, message: `Agent "${agentId}" was not found` };
53
+ throw err;
54
+ }
55
+ }
56
+ return { ok: true, value: { inputSchema: undefined, stageId: undefined, pipelineAbsPath: undefined, agentId } };
57
+ }
58
+ const kindFile = target.file !== undefined;
59
+ const kindPipeline = target.pipeline_path !== undefined && target.stage_id !== undefined;
60
+ if (kindFile === kindPipeline) {
61
+ return { ok: false, message: "target needs either file or pipeline_path with stage_id" };
62
+ }
63
+ const given = (kindFile ? target.file : target.pipeline_path);
64
+ if (path.isAbsolute(given) || !isInsideProjectRoot(projectRoot, path.resolve(projectRoot, given))) {
65
+ return { ok: false, message: "target path must be relative and inside the project" };
66
+ }
67
+ const evalAbs = path.join(projectRoot, "target-lookup.eval.yaml");
68
+ const file = {
69
+ version: 1,
70
+ id: "target-lookup",
71
+ target: kindFile
72
+ ? { kind: "stage", file: target.file }
73
+ : { kind: "stage", pipeline: target.pipeline_path, stage: target.stage_id },
74
+ dataset: "target-lookup.dataset.jsonl",
75
+ graders: [],
76
+ };
77
+ const outcome = await resolveEvalTarget(file, evalAbs, projectRoot);
78
+ if (!outcome.ok)
79
+ return { ok: false, message: outcome.issues[0]?.message ?? "target does not resolve" };
80
+ const { inputSchema, stageId, pipelinePath } = outcome.value;
81
+ return { ok: true, value: { inputSchema, stageId, pipelineAbsPath: pipelinePath } };
82
+ }
83
+ export function buildDatasetDetail(input) {
84
+ const { loaded, query } = input;
85
+ const checks = input.hasEval
86
+ ? new Map((input.agent
87
+ ? checkDatasetAgainstAgent(loaded.cases, { mode: input.agent.mode })
88
+ : checkDatasetAgainstStage(loaded.cases, input.inputSchema)).map((c) => [c.caseId, c]))
89
+ : undefined;
90
+ const tags = {};
91
+ let tagged = 0;
92
+ let invalid = 0;
93
+ for (const c of loaded.cases) {
94
+ if ((c.tags ?? []).length > 0)
95
+ tagged += 1;
96
+ for (const tag of c.tags ?? [])
97
+ tags[tag] = (tags[tag] ?? 0) + 1;
98
+ if (checks?.get(c.id)?.valid === false)
99
+ invalid += 1;
100
+ }
101
+ const q = query.q?.trim().toLowerCase();
102
+ const matched = loaded.cases.filter((c) => {
103
+ const check = checks?.get(c.id);
104
+ if (query.filter === "invalid" && check?.valid !== false)
105
+ return false;
106
+ if (query.filter === "tagged" && (c.tags ?? []).length === 0)
107
+ return false;
108
+ if (query.tag !== undefined && !(c.tags ?? []).includes(query.tag))
109
+ return false;
110
+ if (q === undefined || q === "")
111
+ return true;
112
+ return `${c.id}\n${c.title ?? ""}\n${JSON.stringify(c.input)}`.toLowerCase().includes(q);
113
+ });
114
+ const page = matched.slice(query.offset, query.offset + query.limit);
115
+ return {
116
+ id: input.id,
117
+ path: loaded.relPath,
118
+ format: loaded.format ?? null,
119
+ hash: loaded.contentHash,
120
+ editable: loaded.format === "jsonl",
121
+ cases_total: loaded.cases.length,
122
+ invalid_total: invalid,
123
+ tagged_total: tagged,
124
+ matched_total: matched.length,
125
+ tags,
126
+ input_fields: input.agent ? agentInputFields(input.agent.mode) : inputFieldsOf(input.inputSchema),
127
+ cases: page.map((c) => {
128
+ const check = checks?.get(c.id);
129
+ return {
130
+ ...c,
131
+ input_check: check === undefined ? null : { valid: check.valid, ...(check.message !== undefined ? { message: check.message } : {}) },
132
+ };
133
+ }),
134
+ findings: input.agent && input.hasEval ? [...loaded.findings, ...scenarioNotes(loaded.relPath, checks)] : loaded.findings,
135
+ used_by: input.usedBy,
136
+ };
137
+ }
138
+ function scenarioNotes(relPath, checks) {
139
+ const out = [];
140
+ for (const check of checks?.values() ?? []) {
141
+ for (const note of check.notes ?? []) {
142
+ out.push({ severity: "warning", code: note.code, path: relPath, message: note.message, category: "dataset" });
143
+ }
144
+ }
145
+ return out;
146
+ }
147
+ const CASE_KEYS = new Set(["id", "input", "title", "expected", "tags", "goal", "metadata"]);
148
+ const ID_RE = /^[A-Za-z0-9][A-Za-z0-9._-]{0,63}$/;
149
+ function uploadFinding(code, message, line) {
150
+ return {
151
+ severity: "error",
152
+ code,
153
+ path: "",
154
+ message,
155
+ category: "dataset",
156
+ ...(line !== undefined ? { line } : {}),
157
+ };
158
+ }
159
+ function isPlain(value) {
160
+ return typeof value === "object" && value !== null && !Array.isArray(value);
161
+ }
162
+ function parseObjectRows(format, content, findings) {
163
+ if (format === "jsonl") {
164
+ const rows = [];
165
+ content.split(/\r?\n/).forEach((line, idx) => {
166
+ if (line.trim() === "")
167
+ return;
168
+ try {
169
+ const value = JSON.parse(line);
170
+ if (isPlain(value))
171
+ rows.push(value);
172
+ else
173
+ findings.push(uploadFinding("dataset.not_object", `line ${idx + 1}: not a JSON object`, idx + 1));
174
+ }
175
+ catch {
176
+ findings.push(uploadFinding("dataset.load_error", `line ${idx + 1}: invalid JSON`, idx + 1));
177
+ }
178
+ });
179
+ return rows;
180
+ }
181
+ try {
182
+ const parsed = JSON.parse(content);
183
+ const list = Array.isArray(parsed) ? parsed : isPlain(parsed) && Array.isArray(parsed.cases) ? parsed.cases : undefined;
184
+ if (list === undefined) {
185
+ findings.push(uploadFinding("dataset.invalid_shape", "JSON must be an array of cases or { cases: [...] }"));
186
+ return [];
187
+ }
188
+ return list.filter(isPlain);
189
+ }
190
+ catch {
191
+ findings.push(uploadFinding("dataset.load_error", "content is not valid JSON"));
192
+ return [];
193
+ }
194
+ }
195
+ function stringCell(value) {
196
+ return typeof value === "string" ? value : JSON.stringify(value);
197
+ }
198
+ function defaultMapping(columns, inputSchema, agent) {
199
+ const mapping = {};
200
+ if (agent) {
201
+ for (const field of agentInputFields(agent.mode)) {
202
+ if (field.name === "script" || field.name === "tool_mocks")
203
+ continue;
204
+ const column = columns.find((c) => c === field.name || c === `input.${field.name}`);
205
+ mapping[`input.${field.name}`] =
206
+ column === undefined ? null : field.name === "facts" ? { column, split: "|" } : { column };
207
+ }
208
+ return mapping;
209
+ }
210
+ const fields = inputFieldsOf(inputSchema);
211
+ if (fields.length === 0) {
212
+ for (const column of columns)
213
+ mapping[`input.${column}`] = { column };
214
+ return mapping;
215
+ }
216
+ for (const field of fields) {
217
+ const column = columns.find((c) => c === field.name || c === `input.${field.name}`);
218
+ mapping[`input.${field.name}`] = column === undefined ? null : { column };
219
+ }
220
+ return mapping;
221
+ }
222
+ function scenarioReason(draft, mode) {
223
+ const [result] = checkDatasetAgainstAgent([draft], { mode });
224
+ return result !== undefined && !result.valid ? result.message : undefined;
225
+ }
226
+ function directRows(objects, inputSchema, existingIds, agent) {
227
+ const shaped = objects.map((raw) => (isPlain(raw.input) ? raw : { input: raw }));
228
+ let next = nextIdNumber([...existingIds, ...shaped.flatMap((o) => (typeof o.id === "string" ? [o.id] : []))]);
229
+ const cases = shaped.map((o, i) => ({ id: String(i), input: o.input }));
230
+ const checks = agent
231
+ ? checkDatasetAgainstAgent(cases, { mode: agent.mode })
232
+ : checkDatasetAgainstStage(cases, inputSchema);
233
+ return shaped.map((row, index) => {
234
+ const draft = { ...row, id: typeof row.id === "string" ? row.id : "" };
235
+ const unknownKey = Object.keys(row).find((k) => !CASE_KEYS.has(k));
236
+ let reason;
237
+ if (unknownKey !== undefined)
238
+ reason = `unknown key "${unknownKey}"`;
239
+ else if (draft.id !== "" && !ID_RE.test(draft.id))
240
+ reason = `id "${draft.id}" is not valid`;
241
+ else if (!checks[index]?.valid)
242
+ reason = checks[index]?.message?.replace(/\s+/g, " ").slice(0, 160);
243
+ if (reason !== undefined)
244
+ return { index, case: draft, status: "skipped", reason };
245
+ if (draft.id === "") {
246
+ draft.id = formatId(next);
247
+ next += 1;
248
+ }
249
+ return { index, case: draft, status: "ready" };
250
+ });
251
+ }
252
+ export function previewUpload(input) {
253
+ const findings = [];
254
+ const existingIds = input.existingIds ?? [];
255
+ const { agent } = input;
256
+ const mapOptions = agent
257
+ ? { caseMeta: true, check: (draft) => scenarioReason(draft, agent.mode) }
258
+ : {};
259
+ if (agent && input.mapping !== undefined) {
260
+ for (const target of AGENT_UNSUPPORTED_MAPPING_TARGETS) {
261
+ if (input.mapping[target] != null) {
262
+ findings.push(uploadFinding("dataset.mapping_unsupported_field", `${target} cannot be mapped from a file column; scripts and tool mocks need a JSON or JSONL file`));
263
+ }
264
+ }
265
+ if (findings.length > 0)
266
+ return { rows: [], findings, counts: { ready: 0, skipped: 0 } };
267
+ }
268
+ if (Buffer.byteLength(input.content, "utf8") > DATASET_LIMITS.maxFileBytes) {
269
+ findings.push(uploadFinding("dataset.file_too_large", `file is larger than ${DATASET_LIMITS.maxFileBytes} bytes`));
270
+ return { rows: [], findings, counts: { ready: 0, skipped: 0 } };
271
+ }
272
+ let columns;
273
+ let rows = [];
274
+ if (input.format === "csv") {
275
+ let records = [];
276
+ try {
277
+ records = parseCsv(input.content, input.delimiter !== undefined ? { delimiter: input.delimiter } : {});
278
+ }
279
+ catch (err) {
280
+ findings.push(uploadFinding("dataset.load_error", err instanceof CsvParseError ? err.message : "invalid CSV", err instanceof CsvParseError ? err.record : undefined));
281
+ }
282
+ const headerIdx = records.findIndex((r) => !(r.length === 1 && r[0] === ""));
283
+ if (headerIdx !== -1) {
284
+ const headers = records[headerIdx].map((h) => h.trim());
285
+ columns = headers;
286
+ const body = records
287
+ .slice(headerIdx + 1)
288
+ .filter((r) => !(r.length === 1 && r[0] === ""))
289
+ .map((cells) => Object.fromEntries(headers.map((h, i) => [h, cells[i] ?? ""])));
290
+ rows = applyUploadMapping(body, input.mapping ?? defaultMapping(headers, input.inputSchema, agent), input.inputSchema, existingIds, mapOptions);
291
+ }
292
+ }
293
+ else {
294
+ const objects = parseObjectRows(input.format, input.content, findings);
295
+ if (input.mapping !== undefined) {
296
+ const keys = [...new Set(objects.flatMap((o) => Object.keys(o)))];
297
+ columns = keys;
298
+ const flat = objects.map((o) => Object.fromEntries(keys.filter((k) => k in o).map((k) => [k, stringCell(o[k])])));
299
+ rows = applyUploadMapping(flat, input.mapping, input.inputSchema, existingIds, mapOptions);
300
+ }
301
+ else {
302
+ rows = directRows(objects, input.inputSchema, existingIds, agent);
303
+ }
304
+ }
305
+ if (rows.length === 0 && !findings.some((f) => f.severity === "error")) {
306
+ findings.push(uploadFinding("dataset.empty", "no rows found"));
307
+ }
308
+ if (rows.length > DATASET_LIMITS.maxCases) {
309
+ findings.push(uploadFinding("dataset.too_many_cases", `more than ${DATASET_LIMITS.maxCases} rows`));
310
+ }
311
+ const ready = rows.filter((r) => r.status === "ready").length;
312
+ return {
313
+ ...(columns !== undefined ? { columns } : {}),
314
+ rows,
315
+ findings,
316
+ counts: { ready, skipped: rows.length - ready },
317
+ };
318
+ }
@@ -0,0 +1,66 @@
1
+ import type { EvalCatalogEntry } from "../../config/evalCatalog.js";
2
+ import type { AgentCatalogPort } from "../../config/resolveAgentTarget.js";
3
+ import { type BannerEvalInput, type ListStatus, type RegressionBanner } from "../listStatus.js";
4
+ import { type ActiveRun, type ReadStore, type RunHeadline } from "./runs.js";
5
+ export type EvalListTarget = {
6
+ kind: "stage";
7
+ pipeline_path?: string;
8
+ stage_id?: string;
9
+ file?: string;
10
+ label: string;
11
+ } | {
12
+ kind: "agent";
13
+ agent_id: string;
14
+ agent_name: string;
15
+ model: string | null;
16
+ revision: number | null;
17
+ label: string;
18
+ };
19
+ export type EvalListItem = {
20
+ project_root?: string;
21
+ id: string;
22
+ name: string;
23
+ description: string | null;
24
+ type: string;
25
+ path: string;
26
+ target: EvalListTarget;
27
+ conversation?: {
28
+ mode: string;
29
+ max_turns: number;
30
+ tools: string;
31
+ approvals: string;
32
+ };
33
+ dataset_path: string;
34
+ dataset_cases: number;
35
+ repeats: number;
36
+ grader_count: number;
37
+ rubric_count: number;
38
+ valid: boolean;
39
+ finding_count: number;
40
+ status: ListStatus | "running";
41
+ active_run: ActiveRun | null;
42
+ last_run: RunHeadline | null;
43
+ last_run_delta_pts: number | null;
44
+ trend: Array<{
45
+ run_number: number;
46
+ passed: boolean;
47
+ pass_rate: number | null;
48
+ pass_threshold: number;
49
+ }>;
50
+ };
51
+ export declare function filterEvalListItems(items: readonly EvalListItem[], filter: {
52
+ target_kind?: string | null;
53
+ agent?: string | null;
54
+ }): EvalListItem[];
55
+ export declare function buildEvalListItems(input: {
56
+ store: ReadStore;
57
+ projectRoot: string;
58
+ entries: readonly EvalCatalogEntry[];
59
+ datasetCases: (absPath: string) => number;
60
+ agents?: AgentCatalogPort;
61
+ }): Promise<{
62
+ items: EvalListItem[];
63
+ banner: RegressionBanner | null;
64
+ bannerInputs: BannerEvalInput[];
65
+ }>;
66
+ export declare function costLastSevenDays(store: Pick<ReadStore, "listEvalRuns">, projectRoot: string, now: Date): Promise<number>;