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,157 @@
1
+ import { PACKAGE_VERSION } from "../../../package-meta.js";
2
+ /**
3
+ * Eval runs, their cases, results, grades and the author's reviews, plus `runs.origin` so stage runs
4
+ * started by an eval can be hidden from normal run views. `eval_run_counters` keeps `run_number`
5
+ * from being reused after an eval run is deleted.
6
+ */
7
+ export const MIGRATION_015 = {
8
+ version: 15,
9
+ name: "015_evals",
10
+ minStageflowVersion: PACKAGE_VERSION,
11
+ up(db) {
12
+ db.exec(`
13
+ ALTER TABLE runs ADD COLUMN origin TEXT;
14
+ CREATE INDEX runs_origin ON runs (origin);
15
+
16
+ CREATE TABLE eval_runs (
17
+ eval_run_id TEXT PRIMARY KEY,
18
+ project_root TEXT NOT NULL,
19
+ eval_id TEXT NOT NULL,
20
+ run_number INTEGER NOT NULL,
21
+ eval_path TEXT NOT NULL,
22
+ eval_hash TEXT NOT NULL,
23
+ target_kind TEXT NOT NULL CHECK (target_kind IN ('stage','agent')),
24
+ target_ref_json TEXT NOT NULL,
25
+ target_version_hash TEXT NOT NULL,
26
+ dataset_path TEXT NOT NULL,
27
+ dataset_hash TEXT NOT NULL,
28
+ config_json TEXT NOT NULL,
29
+ config_fingerprint TEXT NOT NULL,
30
+ config_components_json TEXT NOT NULL,
31
+ status TEXT NOT NULL CHECK (status IN ('queued','running','completed','failed','cancelled','budget_stopped')),
32
+ status_reason TEXT,
33
+ passed INTEGER,
34
+ repeats INTEGER NOT NULL,
35
+ pass_threshold REAL NOT NULL,
36
+ max_cost_usd REAL NOT NULL,
37
+ cases_total INTEGER NOT NULL,
38
+ results_total INTEGER NOT NULL,
39
+ results_done INTEGER NOT NULL DEFAULT 0,
40
+ cost_usd REAL NOT NULL DEFAULT 0,
41
+ engine_name TEXT NOT NULL,
42
+ engine_version TEXT NOT NULL,
43
+ stageflow_version TEXT NOT NULL,
44
+ label TEXT,
45
+ started_via TEXT NOT NULL CHECK (started_via IN ('console','cli','mcp')),
46
+ caller_id TEXT,
47
+ summary_json TEXT,
48
+ created_at TEXT NOT NULL,
49
+ started_at TEXT,
50
+ finished_at TEXT
51
+ );
52
+ CREATE UNIQUE INDEX eval_runs_number ON eval_runs (project_root, eval_id, run_number);
53
+ CREATE INDEX eval_runs_eval ON eval_runs (project_root, eval_id, created_at DESC);
54
+ CREATE INDEX eval_runs_status ON eval_runs (status);
55
+
56
+ CREATE TABLE eval_run_counters (
57
+ project_root TEXT NOT NULL,
58
+ eval_id TEXT NOT NULL,
59
+ last_number INTEGER NOT NULL,
60
+ PRIMARY KEY (project_root, eval_id)
61
+ );
62
+
63
+ CREATE TABLE eval_cases (
64
+ eval_run_id TEXT NOT NULL REFERENCES eval_runs (eval_run_id) ON DELETE CASCADE,
65
+ case_id TEXT NOT NULL,
66
+ position INTEGER NOT NULL,
67
+ case_json TEXT NOT NULL,
68
+ PRIMARY KEY (eval_run_id, case_id)
69
+ );
70
+
71
+ CREATE TABLE eval_results (
72
+ eval_run_id TEXT NOT NULL REFERENCES eval_runs (eval_run_id) ON DELETE CASCADE,
73
+ case_id TEXT NOT NULL,
74
+ repeat_index INTEGER NOT NULL,
75
+ status TEXT NOT NULL CHECK (status IN ('completed','stage_failed','needs_input','error','skipped_budget','cancelled')),
76
+ error_code TEXT,
77
+ error_message TEXT,
78
+ stage_run_id TEXT,
79
+ output_json TEXT,
80
+ latency_ms INTEGER,
81
+ cost_usd REAL,
82
+ tokens_in INTEGER,
83
+ tokens_out INTEGER,
84
+ score REAL,
85
+ passed INTEGER NOT NULL DEFAULT 0,
86
+ has_grader_errors INTEGER NOT NULL DEFAULT 0,
87
+ budget_warnings_json TEXT,
88
+ started_at TEXT,
89
+ finished_at TEXT,
90
+ PRIMARY KEY (eval_run_id, case_id, repeat_index),
91
+ FOREIGN KEY (eval_run_id, case_id) REFERENCES eval_cases (eval_run_id, case_id) ON DELETE CASCADE
92
+ );
93
+ CREATE INDEX eval_results_stage_run ON eval_results (stage_run_id);
94
+
95
+ CREATE TABLE eval_grades (
96
+ eval_run_id TEXT NOT NULL,
97
+ case_id TEXT NOT NULL,
98
+ repeat_index INTEGER NOT NULL,
99
+ grader_id TEXT NOT NULL,
100
+ grader_type TEXT NOT NULL,
101
+ status TEXT NOT NULL CHECK (status IN ('graded','error')),
102
+ passed INTEGER,
103
+ score REAL,
104
+ raw_value REAL,
105
+ reason TEXT,
106
+ details_json TEXT,
107
+ error_code TEXT,
108
+ judge_model TEXT,
109
+ judge_cost_usd REAL,
110
+ judge_tokens_in INTEGER,
111
+ judge_tokens_out INTEGER,
112
+ PRIMARY KEY (eval_run_id, case_id, repeat_index, grader_id),
113
+ FOREIGN KEY (eval_run_id, case_id, repeat_index) REFERENCES eval_results (eval_run_id, case_id, repeat_index) ON DELETE CASCADE
114
+ );
115
+
116
+ CREATE TABLE eval_grader_versions (
117
+ project_root TEXT NOT NULL,
118
+ eval_id TEXT NOT NULL,
119
+ grader_id TEXT NOT NULL,
120
+ grader_hash TEXT NOT NULL,
121
+ ordinal INTEGER NOT NULL,
122
+ first_seen_at TEXT NOT NULL,
123
+ PRIMARY KEY (project_root, eval_id, grader_id, grader_hash)
124
+ );
125
+
126
+ CREATE TABLE eval_failure_types (
127
+ project_root TEXT NOT NULL,
128
+ eval_id TEXT NOT NULL,
129
+ name TEXT NOT NULL,
130
+ created_at TEXT NOT NULL,
131
+ PRIMARY KEY (project_root, eval_id, name COLLATE NOCASE)
132
+ );
133
+
134
+ CREATE TABLE eval_result_reviews (
135
+ eval_run_id TEXT NOT NULL,
136
+ case_id TEXT NOT NULL,
137
+ repeat_index INTEGER NOT NULL,
138
+ label TEXT NOT NULL CHECK (label IN ('pass','fail')),
139
+ note TEXT,
140
+ created_at TEXT NOT NULL,
141
+ updated_at TEXT NOT NULL,
142
+ PRIMARY KEY (eval_run_id, case_id, repeat_index),
143
+ FOREIGN KEY (eval_run_id, case_id, repeat_index) REFERENCES eval_results (eval_run_id, case_id, repeat_index) ON DELETE CASCADE
144
+ );
145
+
146
+ CREATE TABLE eval_result_tags (
147
+ eval_run_id TEXT NOT NULL,
148
+ case_id TEXT NOT NULL,
149
+ repeat_index INTEGER NOT NULL,
150
+ tag TEXT NOT NULL,
151
+ created_at TEXT NOT NULL,
152
+ PRIMARY KEY (eval_run_id, case_id, repeat_index, tag COLLATE NOCASE),
153
+ FOREIGN KEY (eval_run_id, case_id, repeat_index) REFERENCES eval_results (eval_run_id, case_id, repeat_index) ON DELETE CASCADE
154
+ );
155
+ `);
156
+ },
157
+ };
@@ -0,0 +1,12 @@
1
+ import type Database from "better-sqlite3";
2
+ /**
3
+ * Agent eval results point at an agent session, not a stage run: `subject_ref` is the root subject id
4
+ * (stage run id for stage results, agent session id for agent results). `turns` and `tool_call_count`
5
+ * are agent summaries. Additive; stage rows keep `stage_run_id` and are backfilled.
6
+ */
7
+ export declare const MIGRATION_016: {
8
+ version: number;
9
+ name: string;
10
+ minStageflowVersion: string;
11
+ up(db: Database.Database): void;
12
+ };
@@ -0,0 +1,20 @@
1
+ import { PACKAGE_VERSION } from "../../../package-meta.js";
2
+ /**
3
+ * Agent eval results point at an agent session, not a stage run: `subject_ref` is the root subject id
4
+ * (stage run id for stage results, agent session id for agent results). `turns` and `tool_call_count`
5
+ * are agent summaries. Additive; stage rows keep `stage_run_id` and are backfilled.
6
+ */
7
+ export const MIGRATION_016 = {
8
+ version: 16,
9
+ name: "016_eval_subject_ref",
10
+ minStageflowVersion: PACKAGE_VERSION,
11
+ up(db) {
12
+ db.exec(`
13
+ ALTER TABLE eval_results ADD COLUMN subject_ref TEXT;
14
+ ALTER TABLE eval_results ADD COLUMN turns INTEGER;
15
+ ALTER TABLE eval_results ADD COLUMN tool_call_count INTEGER;
16
+ UPDATE eval_results SET subject_ref = stage_run_id WHERE stage_run_id IS NOT NULL;
17
+ CREATE INDEX eval_results_subject_ref ON eval_results (subject_ref);
18
+ `);
19
+ },
20
+ };
@@ -0,0 +1,11 @@
1
+ import type Database from "better-sqlite3";
2
+ /**
3
+ * Suggested bucket and failure type per failed eval result, produced on request by a classifier
4
+ * (`jev` or `judge`). A suggestion becomes a tag only when the author accepts it. Additive.
5
+ */
6
+ export declare const MIGRATION_017: {
7
+ version: number;
8
+ name: string;
9
+ minStageflowVersion: string;
10
+ up(db: Database.Database): void;
11
+ };
@@ -0,0 +1,36 @@
1
+ import { PACKAGE_VERSION } from "../../../package-meta.js";
2
+ /**
3
+ * Suggested bucket and failure type per failed eval result, produced on request by a classifier
4
+ * (`jev` or `judge`). A suggestion becomes a tag only when the author accepts it. Additive.
5
+ */
6
+ export const MIGRATION_017 = {
7
+ version: 17,
8
+ name: "017_eval_result_suggestions",
9
+ minStageflowVersion: PACKAGE_VERSION,
10
+ up(db) {
11
+ db.exec(`
12
+ CREATE TABLE eval_result_suggestions (
13
+ id TEXT PRIMARY KEY,
14
+ eval_run_id TEXT NOT NULL,
15
+ case_id TEXT NOT NULL,
16
+ repeat_index INTEGER NOT NULL,
17
+ source TEXT NOT NULL CHECK (source IN ('jev','judge')),
18
+ bucket TEXT NOT NULL CHECK (bucket IN ('agent_wrong','grader_wrong','case_wrong','unclear')),
19
+ failure_type TEXT,
20
+ confidence REAL NOT NULL,
21
+ probabilities_json TEXT NOT NULL,
22
+ grader_false_alarms_json TEXT NOT NULL,
23
+ model TEXT NOT NULL,
24
+ prompt_version INTEGER NOT NULL,
25
+ status TEXT NOT NULL DEFAULT 'pending' CHECK (status IN ('pending','accepted','dismissed')),
26
+ batch_id TEXT NOT NULL,
27
+ cost_usd REAL NOT NULL DEFAULT 0,
28
+ state_truncated INTEGER NOT NULL DEFAULT 0,
29
+ created_at TEXT NOT NULL,
30
+ UNIQUE (eval_run_id, case_id, repeat_index, source),
31
+ FOREIGN KEY (eval_run_id, case_id, repeat_index) REFERENCES eval_results (eval_run_id, case_id, repeat_index) ON DELETE CASCADE
32
+ );
33
+ CREATE INDEX eval_result_suggestions_run ON eval_result_suggestions (eval_run_id, status);
34
+ `);
35
+ },
36
+ };
@@ -13,6 +13,9 @@ import { MIGRATION_011 } from "./011-email-dispatch-key.js";
13
13
  import { MIGRATION_012 } from "./012-trigger-fires.js";
14
14
  import { MIGRATION_013 } from "./013-agents.js";
15
15
  import { MIGRATION_014 } from "./014-agent-deliveries.js";
16
+ import { MIGRATION_015 } from "./015-evals.js";
17
+ import { MIGRATION_016 } from "./016-eval-subject-ref.js";
18
+ import { MIGRATION_017 } from "./017-eval-result-suggestions.js";
16
19
  const DEFAULT_MIGRATIONS = [
17
20
  MIGRATION_001,
18
21
  MIGRATION_002,
@@ -28,6 +31,9 @@ const DEFAULT_MIGRATIONS = [
28
31
  MIGRATION_012,
29
32
  MIGRATION_013,
30
33
  MIGRATION_014,
34
+ MIGRATION_015,
35
+ MIGRATION_016,
36
+ MIGRATION_017,
31
37
  ];
32
38
  export const CURRENT_SCHEMA_VERSION = DEFAULT_MIGRATIONS[DEFAULT_MIGRATIONS.length - 1].version;
33
39
  function throwStoreSchemaTooNew(db, version, maxKnown) {
@@ -0,0 +1,14 @@
1
+ import type Database from "better-sqlite3";
2
+ import type { SuggestionInput, SuggestionRow } from "../../evals/triage/types.js";
3
+ /** Inserts or replaces pending suggestions; accepted and dismissed ones are kept. Returns the rows this call wrote. */
4
+ export declare function upsertEvalSuggestions(db: Database.Database, evalRunId: string, inputs: SuggestionInput[]): SuggestionRow[];
5
+ export declare function listEvalSuggestions(db: Database.Database, evalRunId: string, status?: SuggestionRow["status"]): SuggestionRow[];
6
+ export declare function dismissEvalSuggestions(db: Database.Database, evalRunId: string, ids: string[]): number;
7
+ /**
8
+ * Marks pending suggestions accepted and adds their failure type and `bucket:<bucket>` tags to the result
9
+ * through `putEvalReview`, keeping tags already there. Returns how many were accepted and how many results gained a tag.
10
+ */
11
+ export declare function acceptEvalSuggestions(db: Database.Database, evalRunId: string, ids: string[]): {
12
+ accepted: number;
13
+ tagged: number;
14
+ };
@@ -0,0 +1,132 @@
1
+ import { randomBytes } from "node:crypto";
2
+ import { EvalStoreError } from "../../evals/storeError.js";
3
+ import { BUCKET_TAG_PREFIX } from "../../evals/triage/constants.js";
4
+ import { getEvalReviews, putEvalReview } from "./evalStore.js";
5
+ const now = () => new Date().toISOString();
6
+ function suggestionFromDb(row) {
7
+ return {
8
+ id: row.id,
9
+ evalRunId: row.eval_run_id,
10
+ caseId: row.case_id,
11
+ repeatIndex: row.repeat_index,
12
+ source: row.source,
13
+ bucket: row.bucket,
14
+ failureType: row.failure_type,
15
+ confidence: row.confidence,
16
+ bucketProbabilities: JSON.parse(row.probabilities_json),
17
+ graderFalseAlarms: JSON.parse(row.grader_false_alarms_json),
18
+ model: row.model,
19
+ promptVersion: row.prompt_version,
20
+ status: row.status,
21
+ batchId: row.batch_id,
22
+ costUsd: row.cost_usd,
23
+ stateTruncated: row.state_truncated === 1,
24
+ createdAt: row.created_at,
25
+ };
26
+ }
27
+ /** Inserts or replaces pending suggestions; accepted and dismissed ones are kept. Returns the rows this call wrote. */
28
+ export function upsertEvalSuggestions(db, evalRunId, inputs) {
29
+ const written = [];
30
+ const at = now();
31
+ db.transaction(() => {
32
+ for (const input of inputs) {
33
+ const info = db
34
+ .prepare(`INSERT INTO eval_result_suggestions
35
+ (id, eval_run_id, case_id, repeat_index, source, bucket, failure_type, confidence, probabilities_json,
36
+ grader_false_alarms_json, model, prompt_version, status, batch_id, cost_usd, state_truncated, created_at)
37
+ VALUES (@id, @eval_run_id, @case_id, @repeat_index, @source, @bucket, @failure_type, @confidence, @probabilities_json,
38
+ @grader_false_alarms_json, @model, @prompt_version, 'pending', @batch_id, @cost_usd, @state_truncated, @at)
39
+ ON CONFLICT (eval_run_id, case_id, repeat_index, source) DO UPDATE SET
40
+ bucket = excluded.bucket, failure_type = excluded.failure_type, confidence = excluded.confidence,
41
+ probabilities_json = excluded.probabilities_json, grader_false_alarms_json = excluded.grader_false_alarms_json,
42
+ model = excluded.model, prompt_version = excluded.prompt_version, batch_id = excluded.batch_id,
43
+ cost_usd = excluded.cost_usd, state_truncated = excluded.state_truncated, created_at = excluded.created_at
44
+ WHERE eval_result_suggestions.status = 'pending'`)
45
+ .run({
46
+ id: `sg_${randomBytes(8).toString("hex")}`,
47
+ eval_run_id: evalRunId,
48
+ case_id: input.caseId,
49
+ repeat_index: input.repeatIndex,
50
+ source: input.source,
51
+ bucket: input.bucket,
52
+ failure_type: input.failureType,
53
+ confidence: input.confidence,
54
+ probabilities_json: JSON.stringify(input.bucketProbabilities),
55
+ grader_false_alarms_json: JSON.stringify(input.graderFalseAlarms),
56
+ model: input.model,
57
+ prompt_version: input.promptVersion,
58
+ batch_id: input.batchId,
59
+ cost_usd: input.costUsd,
60
+ state_truncated: input.stateTruncated ? 1 : 0,
61
+ at,
62
+ });
63
+ if (info.changes === 0)
64
+ continue;
65
+ const row = db
66
+ .prepare(`SELECT * FROM eval_result_suggestions WHERE eval_run_id = ? AND case_id = ? AND repeat_index = ? AND source = ?`)
67
+ .get(evalRunId, input.caseId, input.repeatIndex, input.source);
68
+ written.push(suggestionFromDb(row));
69
+ }
70
+ })();
71
+ return written;
72
+ }
73
+ export function listEvalSuggestions(db, evalRunId, status) {
74
+ const rows = (status !== undefined
75
+ ? db
76
+ .prepare(`SELECT * FROM eval_result_suggestions WHERE eval_run_id = ? AND status = ? ORDER BY case_id, repeat_index, source`)
77
+ .all(evalRunId, status)
78
+ : db
79
+ .prepare(`SELECT * FROM eval_result_suggestions WHERE eval_run_id = ? ORDER BY case_id, repeat_index, source`)
80
+ .all(evalRunId));
81
+ return rows.map(suggestionFromDb);
82
+ }
83
+ export function dismissEvalSuggestions(db, evalRunId, ids) {
84
+ let changed = 0;
85
+ db.transaction(() => {
86
+ for (const id of ids) {
87
+ changed += db
88
+ .prepare(`UPDATE eval_result_suggestions SET status = 'dismissed' WHERE eval_run_id = ? AND id = ? AND status = 'pending'`)
89
+ .run(evalRunId, id).changes;
90
+ }
91
+ })();
92
+ return changed;
93
+ }
94
+ /**
95
+ * Marks pending suggestions accepted and adds their failure type and `bucket:<bucket>` tags to the result
96
+ * through `putEvalReview`, keeping tags already there. Returns how many were accepted and how many results gained a tag.
97
+ */
98
+ export function acceptEvalSuggestions(db, evalRunId, ids) {
99
+ let accepted = 0;
100
+ let tagged = 0;
101
+ db.transaction(() => {
102
+ for (const id of ids) {
103
+ const found = db
104
+ .prepare(`SELECT * FROM eval_result_suggestions WHERE eval_run_id = ? AND id = ? AND status = 'pending'`)
105
+ .get(evalRunId, id);
106
+ if (found === undefined)
107
+ continue;
108
+ const suggestion = suggestionFromDb(found);
109
+ const add = [
110
+ ...(suggestion.failureType !== null ? [suggestion.failureType] : []),
111
+ `${BUCKET_TAG_PREFIX}${suggestion.bucket}`,
112
+ ];
113
+ const have = getEvalReviews(db, evalRunId).find((r) => r.caseId === suggestion.caseId && r.repeatIndex === suggestion.repeatIndex)?.tags ?? [];
114
+ const haveKeys = new Set(have.map((t) => t.toLowerCase()));
115
+ const fresh = add.filter((t) => !haveKeys.has(t.toLowerCase()));
116
+ if (fresh.length > 0) {
117
+ try {
118
+ putEvalReview(db, evalRunId, suggestion.caseId, suggestion.repeatIndex, { tags: [...have, ...fresh] });
119
+ tagged += 1;
120
+ }
121
+ catch (err) {
122
+ if (err instanceof EvalStoreError && err.code === "EVAL_TAGS_ON_PASSED_RESULT")
123
+ continue;
124
+ throw err;
125
+ }
126
+ }
127
+ db.prepare(`UPDATE eval_result_suggestions SET status = 'accepted' WHERE id = ?`).run(id);
128
+ accepted += 1;
129
+ }
130
+ })();
131
+ return { accepted, tagged };
132
+ }
@@ -1,7 +1,7 @@
1
1
  import type { RunSubmission } from "../runstore/submission.js";
2
2
  import type { StagePort } from "../agent/port.js";
3
3
  import { type ValidationFinding } from "../config/validateCatalog.js";
4
- import type { RunStore } from "../runstore/port.js";
4
+ import type { RunOrigin, RunStore } from "../runstore/port.js";
5
5
  import type { StageEnvelope } from "../types/envelope.js";
6
6
  import type { StageHitlController } from "./stageHitl.js";
7
7
  import type { InlinePipelineDefinition, LoadedPipeline } from "../types/pipeline.js";
@@ -130,6 +130,7 @@ export declare function startPipeline(options: {
130
130
  halted: boolean;
131
131
  };
132
132
  callerId?: string | null;
133
+ origin?: RunOrigin;
133
134
  skills?: SkillsPayload;
134
135
  }): Promise<StartedPipeline>;
135
136
  export declare function resolveTaskPath(taskArg: string, cwd?: string): string;
@@ -224,6 +224,7 @@ async function preparePipeline(options) {
224
224
  ? { pipelineBody: persistence.fields.pipelineBody }
225
225
  : {}),
226
226
  ...(callerId !== null ? { callerId } : {}),
227
+ ...(options.origin !== undefined ? { origin: options.origin } : {}),
227
228
  runManifest,
228
229
  skipGates: options.skipGates,
229
230
  });
@@ -329,6 +330,7 @@ export async function startPipeline(options) {
329
330
  operatorCatalog: options.operatorCatalog,
330
331
  skipGates: options.skipGates,
331
332
  callerId: options.callerId,
333
+ ...(options.origin !== undefined ? { origin: options.origin } : {}),
332
334
  ...(options.skills !== undefined ? { skills: options.skills } : {}),
333
335
  });
334
336
  if (prepared.run.created === false) {
@@ -2,7 +2,7 @@ import { type RunSubmission } from "../runstore/submission.js";
2
2
  import type { StagePort, OpaqueAnswer } from "../agent/port.js";
3
3
  import type { InlinePipelineDefinition } from "../types/pipeline.js";
4
4
  import { type DiskBreakdown, type FreeSpaceReader } from "../runstore/diskUsage.js";
5
- import { type RunStore } from "../runstore/port.js";
5
+ import { type RunOrigin, type RunStore } from "../runstore/port.js";
6
6
  import type { TaskFile } from "../types/task.js";
7
7
  import { type PipelineRunResult } from "./pipelineRunner.js";
8
8
  import { type SkillsPayload } from "./runSkills.js";
@@ -314,6 +314,7 @@ export declare class RunManager {
314
314
  projectRoot?: string;
315
315
  /** Attribution from auth only — never from request body/query. */
316
316
  callerId?: string | null;
317
+ origin?: RunOrigin;
317
318
  skills?: SkillsPayload;
318
319
  }, submission?: RunSubmission): Promise<StartRunResult>;
319
320
  rerun(runId: string, options?: {
@@ -530,7 +530,7 @@ export class RunManager {
530
530
  */
531
531
  async attachWaitingStages() {
532
532
  const found = [];
533
- const runs = await this.options.store.listRuns();
533
+ const runs = await this.options.store.listRuns({ origin: "any" });
534
534
  for (const summary of runs) {
535
535
  if (summary.status !== "running")
536
536
  continue;
@@ -627,7 +627,7 @@ export class RunManager {
627
627
  }
628
628
  async reconcileOrphanedStages() {
629
629
  const reconciled = [];
630
- const runs = await this.options.store.listRuns();
630
+ const runs = await this.options.store.listRuns({ origin: "any" });
631
631
  for (const summary of runs) {
632
632
  let meta;
633
633
  try {
@@ -806,7 +806,7 @@ export class RunManager {
806
806
  }
807
807
  async resumeStalledSchedules() {
808
808
  const resumed = [];
809
- const runs = await this.options.store.listRuns();
809
+ const runs = await this.options.store.listRuns({ origin: "any" });
810
810
  for (const summary of runs) {
811
811
  if (summary.status !== "running")
812
812
  continue;
@@ -828,7 +828,7 @@ export class RunManager {
828
828
  }
829
829
  /** Rebuild in-memory admission queue from persisted `queued` rows (R27). */
830
830
  async reenqueuePersistedQueuedRuns() {
831
- const queued = await this.options.store.listRuns({ status: "queued" });
831
+ const queued = await this.options.store.listRuns({ status: "queued", origin: "any" });
832
832
  const ordered = [...queued].sort((a, b) => a.created_at.localeCompare(b.created_at));
833
833
  this.admissionQueue.clear();
834
834
  for (const row of ordered) {
@@ -1273,7 +1273,7 @@ export class RunManager {
1273
1273
  gitSha: input.gitSha,
1274
1274
  ciPrUrl: input.ciPrUrl,
1275
1275
  ciJobUrl: input.ciJobUrl,
1276
- }, derivedProjectRoot, resolved.kind === "path" ? resolved.taskPath : undefined, submission, undefined, input.callerId, input.skills, input.dispatchKey);
1276
+ }, derivedProjectRoot, resolved.kind === "path" ? resolved.taskPath : undefined, submission, undefined, input.callerId, input.skills, input.dispatchKey, input.origin);
1277
1277
  }
1278
1278
  async rerun(runId, options) {
1279
1279
  if (!this.acceptingWork) {
@@ -2219,7 +2219,7 @@ export class RunManager {
2219
2219
  this.attachedWaiting.delete(`${runId}\0${stageId}`);
2220
2220
  }
2221
2221
  }
2222
- async reserveAndStartPipeline(taskYaml, pipeline, taskLabel, cwd, checkoutOverride, skipGates, ciIdentity, projectRoot, taskPath, submission, pinned, callerId, skills, dispatchKey) {
2222
+ async reserveAndStartPipeline(taskYaml, pipeline, taskLabel, cwd, checkoutOverride, skipGates, ciIdentity, projectRoot, taskPath, submission, pinned, callerId, skills, dispatchKey, origin) {
2223
2223
  const persistence = pipelinePersistenceForStart(pipeline);
2224
2224
  if (!persistence.ok) {
2225
2225
  return {
@@ -2419,6 +2419,7 @@ export class RunManager {
2419
2419
  ...(callerId !== undefined && callerId !== null
2420
2420
  ? { callerId }
2421
2421
  : {}),
2422
+ ...(origin !== undefined ? { origin } : {}),
2422
2423
  runManifest,
2423
2424
  skipGates,
2424
2425
  });
@@ -2506,6 +2507,7 @@ export class RunManager {
2506
2507
  skipGates,
2507
2508
  schedulingHalt,
2508
2509
  callerId,
2510
+ ...(origin !== undefined ? { origin } : {}),
2509
2511
  ...(hasSkills ? { skills: validatedSkills } : {}),
2510
2512
  });
2511
2513
  if (started.created === false)
@@ -252,7 +252,7 @@ export async function runRetentionSweep(store, a2aStore, options = {}) {
252
252
  const windows = options.windows ?? retentionWindowsFromEnv(env);
253
253
  const artifactMaxBytes = options.artifactMaxBytes ?? slimArtifactMaxBytesFromEnv(env);
254
254
  const bareCacheTtlMs = options.bareCacheTtlMs ?? bareCacheTtlFromEnv(env);
255
- const runs = await store.listRuns();
255
+ const runs = await store.listRuns({ origin: "any" });
256
256
  const slimmed = [];
257
257
  const purged = [];
258
258
  const metas = new Map();
@@ -305,7 +305,7 @@ export async function runRetentionSweep(store, a2aStore, options = {}) {
305
305
  }
306
306
  }
307
307
  // Re-list for bare-cache decisions after PURGE removed rows when execute.
308
- const runsForBare = execute ? await store.listRuns() : runs;
308
+ const runsForBare = execute ? await store.listRuns({ origin: "any" }) : runs;
309
309
  const bareCachesEvicted = await evictBareCaches({
310
310
  runs: runsForBare,
311
311
  now,
@@ -1,4 +1,6 @@
1
- import { parseAgentAuthorDraft, runAgentAuthorTurn, undoAgentAuthorTurn } from "../agents/authorChat.js";
1
+ import { authorSessionForApi, parseAgentAuthorDraft, runAgentAuthorTurn, undoAgentAuthorTurn, } from "../agents/authorChat.js";
2
+ import { createAuthorSession, listAuthorDrafts, readAuthorSession, saveAuthorSession } from "../agents/authorSessionStore.js";
3
+ import { parseWorkshopModel } from "../workshop/modelSettings.js";
2
4
  async function readBody(req) {
3
5
  const chunks = [];
4
6
  let size = 0;
@@ -24,6 +26,51 @@ async function readBody(req) {
24
26
  export async function handleAgentAuthorRoutes(req, method, pathname, projectRoot, host, res, json) {
25
27
  const chat = pathname === "/api/agent-author/chat";
26
28
  const undo = pathname === "/api/agent-author/undo";
29
+ const sessions = pathname === "/api/agent-author/sessions";
30
+ const sessionMatch = /^\/api\/agent-author\/sessions\/([^/]+)$/.exec(pathname);
31
+ if (!chat && !undo && !sessions && !sessionMatch)
32
+ return false;
33
+ if (sessions && method === "POST") {
34
+ const body = await readBody(req);
35
+ if (body.__tooLarge || body.__invalid) {
36
+ json(res, 400, { code: "agent.invalid" });
37
+ return true;
38
+ }
39
+ json(res, 200, createAuthorSession({
40
+ draft: parseAgentAuthorDraft(body.draft),
41
+ ...(parseWorkshopModel(body.model) ? { model: parseWorkshopModel(body.model) } : {}),
42
+ }));
43
+ return true;
44
+ }
45
+ if (sessions && method === "GET") {
46
+ json(res, 200, { drafts: listAuthorDrafts() });
47
+ return true;
48
+ }
49
+ if (sessionMatch && (method === "GET" || method === "PUT")) {
50
+ const sessionId = decodeURIComponent(sessionMatch[1] ?? "");
51
+ try {
52
+ if (method === "GET") {
53
+ json(res, 200, authorSessionForApi(sessionId));
54
+ return true;
55
+ }
56
+ const body = await readBody(req);
57
+ if (body.__tooLarge || body.__invalid) {
58
+ json(res, 400, { code: "agent.invalid" });
59
+ return true;
60
+ }
61
+ const current = readAuthorSession(sessionId);
62
+ if (!current) {
63
+ json(res, 404, { code: "agent.session_not_found" });
64
+ return true;
65
+ }
66
+ json(res, 200, saveAuthorSession({ ...current, draft: parseAgentAuthorDraft(body.draft) }));
67
+ }
68
+ catch (err) {
69
+ const code = err instanceof Error ? err.message : "agent.internal";
70
+ json(res, code === "agent.session_not_found" ? 404 : 400, { code: code.startsWith("agent.") ? code : "agent.internal" });
71
+ }
72
+ return true;
73
+ }
27
74
  if (!chat && !undo)
28
75
  return false;
29
76
  if (method !== "POST") {
@@ -46,12 +93,14 @@ export async function handleAgentAuthorRoutes(req, method, pathname, projectRoot
46
93
  return true;
47
94
  }
48
95
  const message = typeof body.message === "string" ? body.message : "";
96
+ const model = parseWorkshopModel(body.model);
49
97
  const result = await runAgentAuthorTurn({
50
98
  host,
51
99
  projectRoot,
52
100
  message,
53
101
  ...(typeof body.sessionId === "string" ? { sessionId: body.sessionId } : {}),
54
102
  draft: parseAgentAuthorDraft(body.draft),
103
+ ...(model ? { model } : {}),
55
104
  });
56
105
  json(res, 200, result);
57
106
  }
@@ -7,6 +7,8 @@ import type { RunStore } from "../runstore/port.js";
7
7
  import type { StoreFilesystemClassification } from "../runstore/storeFilesystem.js";
8
8
  import type { StageBrowserSupport } from "../browser/browserHost.js";
9
9
  import { RunManager } from "../runtime/runManager.js";
10
+ import { EvalRunManager } from "../evals/manager.js";
11
+ import type { EvalInternalServices } from "./evalInternalRoutes.js";
10
12
  import { emailHostFor } from "../email/host.js";
11
13
  import { EmailTriggers } from "../email/triggers.js";
12
14
  import { type ChannelService } from "../channels/service.js";
@@ -48,6 +50,12 @@ export type StageflowHostBootstrap = {
48
50
  store?: RunStore;
49
51
  /** Absent when `serveBlocked` — no RunManager lifecycle/resume. */
50
52
  manager?: RunManager;
53
+ /** Eval runs: shared with HTTP routes and MCP. Absent when `manager` is. */
54
+ evalRunManager?: EvalRunManager;
55
+ /** Services for the internal eval callback route; absent when `evalRunManager` is. */
56
+ evalServices?: EvalInternalServices;
57
+ /** Set once the HTTP host is listening so the promptfoo provider knows where to call back. */
58
+ setEvalCallbackBase?: (baseUrl: string) => void;
51
59
  runChangeBus: RunChangeBus;
52
60
  mcpStateless: boolean;
53
61
  providerAuthContext: ProviderAuthContext | undefined;