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,59 @@
1
+ import { isDeepStrictEqual } from "node:util";
2
+ import { resolveValue } from "./path.js";
3
+ import { show, subjectRoot, truncate } from "./subject.js";
4
+ const norm = (s) => s.replace(/\s+/g, " ").trim().toLowerCase();
5
+ function toText(value) {
6
+ if (typeof value === "string")
7
+ return value;
8
+ return JSON.stringify(value) ?? "";
9
+ }
10
+ export function gradeReference(grader, subject, testCase, _context) {
11
+ const base = { graderId: grader.id, graderType: "reference" };
12
+ const missing = (reason) => ({
13
+ ...base,
14
+ status: "error",
15
+ errorCode: "EVAL_CASE_MISSING_EXPECTED",
16
+ reason,
17
+ });
18
+ const expectedRef = resolveValue(testCase, grader.expected);
19
+ if (!expectedRef.found || expectedRef.value === undefined || expectedRef.value === null) {
20
+ return missing(`case has no value at ${grader.expected}`);
21
+ }
22
+ const actual = resolveValue(subjectRoot(subject), grader.path);
23
+ if (grader.mode === "equals") {
24
+ const passed = actual.found && isDeepStrictEqual(actual.value, expectedRef.value);
25
+ return {
26
+ ...base,
27
+ status: "graded",
28
+ passed,
29
+ score: passed ? 1 : 0,
30
+ rawValue: passed ? 1 : 0,
31
+ ...(passed
32
+ ? {}
33
+ : {
34
+ reason: truncate(`${grader.path} is ${actual.found ? show(actual.value) : "missing"}, expected ${show(expectedRef.value)}`),
35
+ }),
36
+ };
37
+ }
38
+ const expected = expectedRef.value;
39
+ if (!Array.isArray(expected) || !expected.every((e) => typeof e === "string")) {
40
+ return missing(`${grader.expected} must be an array of strings`);
41
+ }
42
+ const text = actual.found ? norm(toText(actual.value)) : "";
43
+ const items = expected.map((t) => ({ text: t, found: text.includes(norm(t)) }));
44
+ const foundCount = items.filter((i) => i.found).length;
45
+ const score = items.length === 0 ? 1 : foundCount / items.length;
46
+ const passed = score + 1e-9 >= grader.passAt;
47
+ const firstMissing = items.find((i) => !i.found);
48
+ return {
49
+ ...base,
50
+ status: "graded",
51
+ passed,
52
+ score,
53
+ rawValue: score,
54
+ ...(firstMissing
55
+ ? { reason: truncate(`found ${foundCount} of ${items.length}; missing ${show(firstMissing.text)}`) }
56
+ : {}),
57
+ details: { items },
58
+ };
59
+ }
@@ -0,0 +1,5 @@
1
+ import type { ResolvedGrader } from "../types.js";
2
+ import type { GradeData, GraderContext, Subject } from "./types.js";
3
+ export declare function gradeSchema(grader: Extract<ResolvedGrader, {
4
+ type: "schema";
5
+ }>, subject: Subject, _testCase: unknown, context: GraderContext): GradeData;
@@ -0,0 +1,29 @@
1
+ import { payloadInstanceMismatch } from "../../envelope/payloadSchema.js";
2
+ import { notApplicable } from "./notApplicable.js";
3
+ import { isConversation, truncate } from "./subject.js";
4
+ export function gradeSchema(grader, subject, _testCase, context) {
5
+ if (isConversation(subject))
6
+ return notApplicable(grader, "conversation");
7
+ const base = { graderId: grader.id, graderType: "schema" };
8
+ const fail = (reason) => ({
9
+ ...base,
10
+ status: "graded",
11
+ passed: false,
12
+ score: 0,
13
+ rawValue: 0,
14
+ reason: truncate(reason, 500),
15
+ });
16
+ if (subject.status !== "success") {
17
+ return fail(`envelope status is ${subject.status}, expected success`);
18
+ }
19
+ let mismatch;
20
+ try {
21
+ mismatch = payloadInstanceMismatch(subject.payload ?? {}, context.outputSchema);
22
+ }
23
+ catch (error) {
24
+ return fail(error instanceof Error ? error.message : String(error));
25
+ }
26
+ if (mismatch !== undefined)
27
+ return fail(mismatch);
28
+ return { ...base, status: "graded", passed: true, score: 1, rawValue: 1 };
29
+ }
@@ -0,0 +1,6 @@
1
+ import type { ConversationSubject, EnvelopeSubject, Subject } from "./types.js";
2
+ export declare function isConversation(subject: Subject): subject is ConversationSubject;
3
+ export declare function subjectEnvelope(subject: EnvelopeSubject): Record<string, unknown>;
4
+ export declare function subjectRoot(subject: Subject): Record<string, unknown>;
5
+ export declare function truncate(text: string, max?: number): string;
6
+ export declare function show(value: unknown): string;
@@ -0,0 +1,33 @@
1
+ export function isConversation(subject) {
2
+ return subject.kind === "conversation";
3
+ }
4
+ export function subjectEnvelope(subject) {
5
+ const env = {
6
+ status: subject.status,
7
+ summary: subject.summary,
8
+ artifacts: subject.artifacts,
9
+ };
10
+ if (subject.payload !== undefined)
11
+ env.payload = subject.payload;
12
+ return env;
13
+ }
14
+ export function subjectRoot(subject) {
15
+ if (isConversation(subject)) {
16
+ const { transcript: _transport, ...root } = subject;
17
+ return root;
18
+ }
19
+ return subjectEnvelope(subject);
20
+ }
21
+ export function truncate(text, max = 200) {
22
+ return text.length > max ? `${text.slice(0, max - 1)}…` : text;
23
+ }
24
+ export function show(value) {
25
+ if (value === undefined)
26
+ return "undefined";
27
+ try {
28
+ return JSON.stringify(value) ?? String(value);
29
+ }
30
+ catch {
31
+ return String(value);
32
+ }
33
+ }
@@ -0,0 +1,6 @@
1
+ import type { ResolvedGrader } from "../types.js";
2
+ import type { GradeCase, GradeData, GraderContext, Subject } from "./types.js";
3
+ export declare function toolNameMatches(pattern: string, name: string): boolean;
4
+ export declare function gradeToolCalls(grader: Extract<ResolvedGrader, {
5
+ type: "tool_calls";
6
+ }>, subject: Subject, testCase: GradeCase, _context?: GraderContext): GradeData;
@@ -0,0 +1,100 @@
1
+ import { describeCheck, runCheck } from "./fieldGrader.js";
2
+ import { notApplicable } from "./notApplicable.js";
3
+ import { isConversation, truncate } from "./subject.js";
4
+ function isRecord(v) {
5
+ return typeof v === "object" && v !== null && !Array.isArray(v);
6
+ }
7
+ function expectedList(testCase, key) {
8
+ const expected = testCase.expected;
9
+ if (!isRecord(expected))
10
+ return undefined;
11
+ const list = expected[key];
12
+ return Array.isArray(list) && list.every((x) => typeof x === "string") ? list : undefined;
13
+ }
14
+ export function toolNameMatches(pattern, name) {
15
+ if (pattern.endsWith(".*")) {
16
+ const prefix = pattern.slice(0, -2);
17
+ return name === prefix || name.startsWith(`${prefix}.`);
18
+ }
19
+ return name === pattern;
20
+ }
21
+ function plural(n, word) {
22
+ return `${n} ${word}${n === 1 ? "" : "s"}`;
23
+ }
24
+ export function gradeToolCalls(grader, subject, testCase, _context) {
25
+ if (!isConversation(subject))
26
+ return notApplicable(grader, "envelope");
27
+ const mustCall = grader.mustCall ?? expectedList(testCase, "tools");
28
+ const mustNotCall = grader.mustNotCall ?? expectedList(testCase, "forbidden_tools");
29
+ const { mustAskFirst, maxCalls } = grader;
30
+ if (mustCall === undefined &&
31
+ mustNotCall === undefined &&
32
+ mustAskFirst === undefined &&
33
+ maxCalls === undefined &&
34
+ grader.args.length === 0) {
35
+ return {
36
+ graderId: grader.id,
37
+ graderType: "tool_calls",
38
+ status: "error",
39
+ errorCode: "EVAL_CASE_MISSING_EXPECTED",
40
+ reason: "no tool rule: set a rule on the grader or expected.tools / expected.forbidden_tools on the case",
41
+ };
42
+ }
43
+ const calls = subject.tool_calls;
44
+ const named = (pattern) => calls.filter((c) => toolNameMatches(pattern, c.name));
45
+ const checks = [];
46
+ for (const name of mustCall ?? []) {
47
+ const n = named(name).length;
48
+ checks.push({ rule: `must_call ${name}`, passed: n > 0, found: n > 0 ? plural(n, "call") : "not called" });
49
+ }
50
+ for (const name of mustNotCall ?? []) {
51
+ const n = named(name).length;
52
+ checks.push({ rule: `must_not_call ${name}`, passed: n === 0, found: n === 0 ? "not called" : plural(n, "call") });
53
+ }
54
+ for (const name of mustAskFirst ?? []) {
55
+ const matching = named(name);
56
+ const asked = matching.filter((c) => c.policy_outcome === "would_ask_first").length;
57
+ checks.push({
58
+ rule: `must_ask_first ${name}`,
59
+ passed: asked > 0,
60
+ found: asked > 0 ? plural(asked, "approval request") : matching.length > 0 ? "called without asking" : "not called",
61
+ });
62
+ }
63
+ if (maxCalls !== undefined) {
64
+ checks.push({
65
+ rule: `max_calls ${maxCalls}`,
66
+ passed: calls.length <= maxCalls,
67
+ found: plural(calls.length, "call"),
68
+ });
69
+ }
70
+ for (const arg of grader.args) {
71
+ const check = { path: arg.path, op: arg.op, ...(arg.value !== undefined ? { value: arg.value } : {}) };
72
+ const matching = named(arg.tool);
73
+ const rule = `args ${arg.tool} ${describeCheck(check)}`;
74
+ let failure;
75
+ for (const call of matching) {
76
+ const outcome = runCheck(check, call.args);
77
+ if (!outcome.passed) {
78
+ failure = `call ${call.id}: ${outcome.found}`;
79
+ break;
80
+ }
81
+ }
82
+ checks.push({
83
+ rule,
84
+ passed: failure === undefined,
85
+ found: failure ?? (matching.length === 0 ? "no call to check" : plural(matching.length, "call")),
86
+ });
87
+ }
88
+ const first = checks.find((c) => !c.passed);
89
+ const passed = first === undefined;
90
+ return {
91
+ graderId: grader.id,
92
+ graderType: "tool_calls",
93
+ status: "graded",
94
+ passed,
95
+ score: passed ? 1 : 0,
96
+ rawValue: passed ? 1 : 0,
97
+ ...(first ? { reason: truncate(`${first.rule}: ${first.found}`) } : {}),
98
+ details: { checks: checks.map((c) => ({ ...c, found: truncate(c.found) })) },
99
+ };
100
+ }
@@ -0,0 +1,12 @@
1
+ import type { ConversationOutput } from "../types.js";
2
+ export type TranscriptLimits = {
3
+ turns: number;
4
+ messageChars: number;
5
+ toolArgsChars: number;
6
+ toolResultChars: number;
7
+ };
8
+ /**
9
+ * The bounded transcript the judge reads: one line block per message or tool call, tool arguments and results
10
+ * capped, and only the first and last turns kept past the turn limit.
11
+ */
12
+ export declare function renderTranscript(subject: Pick<ConversationOutput, "messages" | "tool_calls">, limits?: TranscriptLimits): string;
@@ -0,0 +1,57 @@
1
+ import { JUDGE_TRANSCRIPT_LIMITS } from "../constants.js";
2
+ const KEEP_FIRST_TURNS = 3;
3
+ function cut(text, max) {
4
+ if (text.length <= max)
5
+ return text;
6
+ return `${text.slice(0, max)}…[truncated ${text.length - max} chars]`;
7
+ }
8
+ function neutralize(text) {
9
+ return text.replace(/<(\/?)(transcript|rubric|examples|case_input|case_expected)\b/gi, "<\\$1$2");
10
+ }
11
+ function json(value) {
12
+ try {
13
+ return JSON.stringify(value ?? {}) ?? "{}";
14
+ }
15
+ catch {
16
+ return "{}";
17
+ }
18
+ }
19
+ /**
20
+ * The bounded transcript the judge reads: one line block per message or tool call, tool arguments and results
21
+ * capped, and only the first and last turns kept past the turn limit.
22
+ */
23
+ export function renderTranscript(subject, limits = JUDGE_TRANSCRIPT_LIMITS) {
24
+ const turns = [
25
+ ...new Set([...subject.messages.map((m) => m.turn), ...subject.tool_calls.map((c) => c.turn)]),
26
+ ].sort((a, b) => a - b);
27
+ let kept = turns;
28
+ let omitted = 0;
29
+ if (turns.length > limits.turns) {
30
+ const tail = Math.max(0, limits.turns - KEEP_FIRST_TURNS);
31
+ omitted = turns.length - limits.turns;
32
+ kept = [...turns.slice(0, KEEP_FIRST_TURNS), ...turns.slice(turns.length - tail)];
33
+ }
34
+ const lines = [];
35
+ kept.forEach((turn, index) => {
36
+ if (omitted > 0 && index === KEEP_FIRST_TURNS)
37
+ lines.push(`[${omitted} turns omitted]`);
38
+ const say = (role) => {
39
+ for (const m of subject.messages) {
40
+ if (m.turn === turn && m.role === role) {
41
+ lines.push(`[turn ${turn}] ${role === "user" ? "USER" : "AGENT"}: ${neutralize(cut(m.text, limits.messageChars))}`);
42
+ }
43
+ }
44
+ };
45
+ say("user");
46
+ for (const call of subject.tool_calls) {
47
+ if (call.turn !== turn)
48
+ continue;
49
+ const outcome = call.status === "error" ? `${call.policy_outcome}, error` : call.policy_outcome;
50
+ const args = neutralize(cut(json(call.args), limits.toolArgsChars));
51
+ const result = neutralize(cut(call.result_summary, limits.toolResultChars));
52
+ lines.push(`[turn ${turn}] TOOL ${call.name} (${outcome}) args=${args} -> ${result}`);
53
+ }
54
+ say("assistant");
55
+ });
56
+ return lines.join("\n");
57
+ }
@@ -0,0 +1,20 @@
1
+ import type { ConversationOutput, NormalizedGrade, PlanCase } from "../types.js";
2
+ export type EnvelopeSubject = {
3
+ kind?: "envelope";
4
+ status: "success" | "failure";
5
+ summary: string;
6
+ payload?: Record<string, unknown>;
7
+ artifacts: string[];
8
+ };
9
+ export type ConversationSubject = ConversationOutput;
10
+ export type Subject = EnvelopeSubject | ConversationSubject;
11
+ export type GraderContext = {
12
+ evalId: string;
13
+ runId: string;
14
+ repeat: number;
15
+ passThreshold: number;
16
+ outputSchema?: unknown;
17
+ codeTimeoutMs?: number;
18
+ };
19
+ export type GradeData = NormalizedGrade;
20
+ export type GradeCase = PlanCase;
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,16 @@
1
+ export type JudgeMapping = {
2
+ providerSpec: string;
3
+ envVar: string;
4
+ stageflowProvider: string;
5
+ };
6
+ type JudgeProviderRow = {
7
+ stageflowProvider: string;
8
+ envVar: string;
9
+ spec: (model: string) => string;
10
+ };
11
+ export declare const JUDGE_PROVIDERS: readonly JudgeProviderRow[];
12
+ export declare function supportedJudgeProviders(): string[];
13
+ export declare function mapJudge(modelId: string): JudgeMapping | null;
14
+ export declare function judgeCapableModels(modelIds: readonly string[]): string[];
15
+ export declare function unsupportedJudgeMessage(modelId: string): string;
16
+ export {};
@@ -0,0 +1,27 @@
1
+ export const JUDGE_PROVIDERS = [
2
+ { stageflowProvider: "anthropic", envVar: "ANTHROPIC_API_KEY", spec: (m) => `anthropic:messages:${m}` },
3
+ { stageflowProvider: "openai", envVar: "OPENAI_API_KEY", spec: (m) => `openai:chat:${m}` },
4
+ { stageflowProvider: "openrouter", envVar: "OPENROUTER_API_KEY", spec: (m) => `openrouter:${m}` },
5
+ ];
6
+ export function supportedJudgeProviders() {
7
+ return JUDGE_PROVIDERS.map((row) => row.stageflowProvider);
8
+ }
9
+ export function mapJudge(modelId) {
10
+ const slash = modelId.indexOf("/");
11
+ if (slash <= 0)
12
+ return null;
13
+ const provider = modelId.slice(0, slash);
14
+ const model = modelId.slice(slash + 1);
15
+ if (model.length === 0)
16
+ return null;
17
+ const row = JUDGE_PROVIDERS.find((entry) => entry.stageflowProvider === provider);
18
+ if (row === undefined)
19
+ return null;
20
+ return { providerSpec: row.spec(model), envVar: row.envVar, stageflowProvider: provider };
21
+ }
22
+ export function judgeCapableModels(modelIds) {
23
+ return modelIds.filter((id) => mapJudge(id) !== null);
24
+ }
25
+ export function unsupportedJudgeMessage(modelId) {
26
+ return `Judge model "${modelId}" cannot be used: supported judge providers are ${supportedJudgeProviders().join(", ")}.`;
27
+ }
@@ -0,0 +1,5 @@
1
+ export interface DiffLine {
2
+ op: "same" | "add" | "remove";
3
+ text: string;
4
+ }
5
+ export declare function lineDiff(a: string, b: string): DiffLine[];
@@ -0,0 +1,34 @@
1
+ function toLines(text) {
2
+ return text === "" ? [] : text.split("\n");
3
+ }
4
+ export function lineDiff(a, b) {
5
+ const x = toLines(a);
6
+ const y = toLines(b);
7
+ const lcs = Array.from({ length: x.length + 1 }, () => new Array(y.length + 1).fill(0));
8
+ for (let i = x.length - 1; i >= 0; i--) {
9
+ for (let j = y.length - 1; j >= 0; j--) {
10
+ lcs[i][j] = x[i] === y[j] ? lcs[i + 1][j + 1] + 1 : Math.max(lcs[i + 1][j], lcs[i][j + 1]);
11
+ }
12
+ }
13
+ const out = [];
14
+ let i = 0;
15
+ let j = 0;
16
+ while (i < x.length && j < y.length) {
17
+ if (x[i] === y[j]) {
18
+ out.push({ op: "same", text: x[i] });
19
+ i++;
20
+ j++;
21
+ }
22
+ else if (lcs[i + 1][j] >= lcs[i][j + 1]) {
23
+ out.push({ op: "remove", text: x[i++] });
24
+ }
25
+ else {
26
+ out.push({ op: "add", text: y[j++] });
27
+ }
28
+ }
29
+ while (i < x.length)
30
+ out.push({ op: "remove", text: x[i++] });
31
+ while (j < y.length)
32
+ out.push({ op: "add", text: y[j++] });
33
+ return out;
34
+ }
@@ -0,0 +1,31 @@
1
+ import type { EvalType } from "./statsTypes.js";
2
+ export type ListStatus = "never_run" | "saturated" | "passing" | "regressed" | "failing";
3
+ export interface ListRunGrader {
4
+ graderId: string;
5
+ hash: string;
6
+ passRate: number | null;
7
+ }
8
+ export interface ListRunSummary {
9
+ runNumber: number;
10
+ passed: boolean;
11
+ passRate: number | null;
12
+ finishedAt: string | null;
13
+ graders: ListRunGrader[];
14
+ }
15
+ export declare function listStatus(completedRunsNewestFirst: ListRunSummary[], type: EvalType): ListStatus;
16
+ export interface BannerEvalInput {
17
+ evalId: string;
18
+ status: ListStatus;
19
+ last: ListRunSummary | null;
20
+ previous: ListRunSummary | null;
21
+ }
22
+ export interface RegressionBanner {
23
+ eval_id: string;
24
+ previous_pass_rate: number | null;
25
+ last_pass_rate: number | null;
26
+ criteria_dropped: number;
27
+ last_run_number: number;
28
+ previous_run_number: number;
29
+ }
30
+ export declare function criteriaDropped(last: ListRunSummary, previous: ListRunSummary): number;
31
+ export declare function regressionBanner(evals: BannerEvalInput[]): RegressionBanner | null;
@@ -0,0 +1,48 @@
1
+ const EPS = 1e-9;
2
+ const SATURATED_PASS_RATE = 0.98;
3
+ const CRITERIA_DROP_POINTS = -5;
4
+ export function listStatus(completedRunsNewestFirst, type) {
5
+ const last = completedRunsNewestFirst[0];
6
+ if (!last)
7
+ return "never_run";
8
+ const previous = completedRunsNewestFirst[1];
9
+ if (last.passed) {
10
+ if (type === "capability" && (last.passRate ?? 0) + EPS >= SATURATED_PASS_RATE) {
11
+ return "saturated";
12
+ }
13
+ return "passing";
14
+ }
15
+ return previous?.passed ? "regressed" : "failing";
16
+ }
17
+ export function criteriaDropped(last, previous) {
18
+ let dropped = 0;
19
+ for (const g of last.graders) {
20
+ const prev = previous.graders.find((p) => p.graderId === g.graderId);
21
+ if (!prev || prev.hash !== g.hash)
22
+ continue;
23
+ if (g.passRate === null || prev.passRate === null)
24
+ continue;
25
+ if ((g.passRate - prev.passRate) * 100 <= CRITERIA_DROP_POINTS + EPS)
26
+ dropped += 1;
27
+ }
28
+ return dropped;
29
+ }
30
+ export function regressionBanner(evals) {
31
+ let best = null;
32
+ for (const e of evals) {
33
+ if (e.status !== "regressed" || !e.last || !e.previous)
34
+ continue;
35
+ if (!best || (e.last.finishedAt ?? "") > (best.last?.finishedAt ?? ""))
36
+ best = e;
37
+ }
38
+ if (!best?.last || !best.previous)
39
+ return null;
40
+ return {
41
+ eval_id: best.evalId,
42
+ previous_pass_rate: best.previous.passRate,
43
+ last_pass_rate: best.last.passRate,
44
+ criteria_dropped: criteriaDropped(best.last, best.previous),
45
+ last_run_number: best.last.runNumber,
46
+ previous_run_number: best.previous.runNumber,
47
+ };
48
+ }