stageflow 0.42.0 → 0.44.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (275) hide show
  1. package/README.md +12 -3
  2. package/dist/agent/activity.d.ts +18 -0
  3. package/dist/agent/claudeAdapter.js +7 -0
  4. package/dist/agent/claudeTools.d.ts +27 -18
  5. package/dist/agent/claudeTools.js +54 -15
  6. package/dist/agent/compactionEvents.d.ts +34 -0
  7. package/dist/agent/compactionEvents.js +37 -0
  8. package/dist/agent/openRouterRouting.d.ts +7 -0
  9. package/dist/agent/openRouterRouting.js +23 -0
  10. package/dist/agent/piAdapter.d.ts +6 -0
  11. package/dist/agent/piAdapter.js +128 -27
  12. package/dist/agent/piSettings.d.ts +7 -0
  13. package/dist/agent/piSettings.js +9 -0
  14. package/dist/agent/sandboxPiTools.d.ts +3 -1
  15. package/dist/agent/sandboxPiTools.js +8 -2
  16. package/dist/agent/stageTurnDriver.d.ts +11 -2
  17. package/dist/agent/stageTurnDriver.js +45 -4
  18. package/dist/agent/toolOutputBudget.d.ts +15 -1
  19. package/dist/agent/toolOutputBudget.js +18 -0
  20. package/dist/agent/toolOutputBudgetExtension.d.ts +2 -0
  21. package/dist/agent/toolOutputBudgetExtension.js +40 -3
  22. package/dist/agents/authorChat.d.ts +1 -0
  23. package/dist/agents/authorChat.js +7 -0
  24. package/dist/agents/authorSessionStore.d.ts +3 -0
  25. package/dist/agents/authorSessionStore.js +17 -2
  26. package/dist/agents/hostContext.d.ts +1 -1
  27. package/dist/agents/runtime/piRuntime.d.ts +5 -1
  28. package/dist/agents/runtime/piRuntime.js +46 -12
  29. package/dist/agents/service.js +3 -2
  30. package/dist/agents/sessions.js +3 -1
  31. package/dist/compaction/directives.d.ts +18 -0
  32. package/dist/compaction/directives.js +119 -0
  33. package/dist/compaction/extension.d.ts +20 -0
  34. package/dist/compaction/extension.js +78 -0
  35. package/dist/compaction/mask.d.ts +18 -0
  36. package/dist/compaction/mask.js +155 -0
  37. package/dist/compaction/pin.d.ts +21 -0
  38. package/dist/compaction/pin.js +270 -0
  39. package/dist/compaction/scrub.d.ts +7 -0
  40. package/dist/compaction/scrub.js +26 -0
  41. package/dist/compaction/sessionWiring.d.ts +22 -0
  42. package/dist/compaction/sessionWiring.js +26 -0
  43. package/dist/compaction/summarize.d.ts +79 -0
  44. package/dist/compaction/summarize.js +171 -0
  45. package/dist/compaction/toolPolicy.d.ts +3 -0
  46. package/dist/compaction/toolPolicy.js +33 -0
  47. package/dist/compaction/types.d.ts +45 -0
  48. package/dist/compaction/types.js +7 -0
  49. package/dist/compaction/workingState.d.ts +56 -0
  50. package/dist/compaction/workingState.js +198 -0
  51. package/dist/config/createPipeline.js +2 -0
  52. package/dist/config/createTrigger.js +7 -1
  53. package/dist/config/ensureCatalogScanRoot.d.ts +2 -0
  54. package/dist/config/ensureCatalogScanRoot.js +6 -0
  55. package/dist/config/evalCatalog.js +30 -2
  56. package/dist/config/githubTriggerAction.d.ts +8 -0
  57. package/dist/config/githubTriggerAction.js +29 -0
  58. package/dist/config/hostConfig.js +2 -0
  59. package/dist/config/loadEval.js +21 -3
  60. package/dist/config/pipelineNeeds.d.ts +2 -0
  61. package/dist/config/pipelineNeeds.js +16 -3
  62. package/dist/config/pipelineRoute.js +5 -4
  63. package/dist/config/validateCatalog.d.ts +1 -1
  64. package/dist/config/validateCatalog.js +12 -0
  65. package/dist/config/validateEval.js +43 -2
  66. package/dist/config/writeEval.js +2 -2
  67. package/dist/envelope/assertEmittedArtifacts.d.ts +12 -0
  68. package/dist/envelope/assertEmittedArtifacts.js +43 -0
  69. package/dist/envelope/preEmitChecks.d.ts +3 -0
  70. package/dist/evals/constants.d.ts +3 -1
  71. package/dist/evals/constants.js +3 -1
  72. package/dist/evals/engine/FakeEngine.d.ts +1 -1
  73. package/dist/evals/engine/FakeEngine.js +2 -1
  74. package/dist/evals/engine/promptfoo/PromptfooEngine.d.ts +1 -1
  75. package/dist/evals/engine/promptfoo/PromptfooEngine.js +2 -1
  76. package/dist/evals/engine/promptfoo/generate.d.ts +1 -1
  77. package/dist/evals/engine/promptfoo/generate.js +11 -8
  78. package/dist/evals/engine/promptfoo/rubricPrompt.d.ts +1 -1
  79. package/dist/evals/engine/promptfoo/rubricPrompt.js +5 -3
  80. package/dist/evals/manager.d.ts +13 -0
  81. package/dist/evals/manager.js +10 -2
  82. package/dist/evals/plan.d.ts +8 -1
  83. package/dist/evals/plan.js +28 -9
  84. package/dist/evals/planInternalAgent.d.ts +19 -0
  85. package/dist/evals/planInternalAgent.js +205 -0
  86. package/dist/evals/read/api.d.ts +12 -0
  87. package/dist/evals/read/api.js +5 -0
  88. package/dist/evals/read/list.js +10 -1
  89. package/dist/evals/read/runs.d.ts +5 -0
  90. package/dist/evals/read/runs.js +7 -1
  91. package/dist/evals/runner/caseRunner.d.ts +2 -1
  92. package/dist/evals/runner/caseRunner.js +16 -5
  93. package/dist/evals/runner/internalAgentCaseRunner.d.ts +6 -0
  94. package/dist/evals/runner/internalAgentCaseRunner.js +250 -0
  95. package/dist/evals/snapshot.d.ts +10 -2
  96. package/dist/evals/snapshot.js +8 -3
  97. package/dist/evals/types.d.ts +12 -2
  98. package/dist/evals/types.js +4 -1
  99. package/dist/guide/cardContract.d.ts +133 -0
  100. package/dist/guide/cardContract.js +156 -0
  101. package/dist/guide/chat.d.ts +45 -0
  102. package/dist/guide/chat.js +378 -0
  103. package/dist/guide/knowledge/index.d.ts +14 -0
  104. package/dist/guide/knowledge/index.js +109 -0
  105. package/dist/guide/knowledge/topics/agents.d.ts +2 -0
  106. package/dist/guide/knowledge/topics/agents.js +58 -0
  107. package/dist/guide/knowledge/topics/bestPractices.d.ts +2 -0
  108. package/dist/guide/knowledge/topics/bestPractices.js +67 -0
  109. package/dist/guide/knowledge/topics/connections.d.ts +2 -0
  110. package/dist/guide/knowledge/topics/connections.js +66 -0
  111. package/dist/guide/knowledge/topics/consoleMap.d.ts +2 -0
  112. package/dist/guide/knowledge/topics/consoleMap.js +55 -0
  113. package/dist/guide/knowledge/topics/evals.d.ts +2 -0
  114. package/dist/guide/knowledge/topics/evals.js +72 -0
  115. package/dist/guide/knowledge/topics/limitations.d.ts +2 -0
  116. package/dist/guide/knowledge/topics/limitations.js +84 -0
  117. package/dist/guide/knowledge/topics/mcpSkillsBrowser.d.ts +2 -0
  118. package/dist/guide/knowledge/topics/mcpSkillsBrowser.js +57 -0
  119. package/dist/guide/knowledge/topics/memories.d.ts +2 -0
  120. package/dist/guide/knowledge/topics/memories.js +63 -0
  121. package/dist/guide/knowledge/topics/modelsAndProviders.d.ts +2 -0
  122. package/dist/guide/knowledge/topics/modelsAndProviders.js +56 -0
  123. package/dist/guide/knowledge/topics/overview.d.ts +2 -0
  124. package/dist/guide/knowledge/topics/overview.js +56 -0
  125. package/dist/guide/knowledge/topics/pipelines.d.ts +2 -0
  126. package/dist/guide/knowledge/topics/pipelines.js +93 -0
  127. package/dist/guide/knowledge/topics/stages.d.ts +2 -0
  128. package/dist/guide/knowledge/topics/stages.js +54 -0
  129. package/dist/guide/knowledge/topics/tasks.d.ts +2 -0
  130. package/dist/guide/knowledge/topics/tasks.js +52 -0
  131. package/dist/guide/knowledge/topics/triggers.d.ts +2 -0
  132. package/dist/guide/knowledge/topics/triggers.js +68 -0
  133. package/dist/guide/knowledge/topics/troubleshooting.d.ts +2 -0
  134. package/dist/guide/knowledge/topics/troubleshooting.js +85 -0
  135. package/dist/guide/knowledgeTools.d.ts +2 -0
  136. package/dist/guide/knowledgeTools.js +56 -0
  137. package/dist/guide/showUi.d.ts +6 -0
  138. package/dist/guide/showUi.js +546 -0
  139. package/dist/guide/threadStore.d.ts +48 -0
  140. package/dist/guide/threadStore.js +189 -0
  141. package/dist/guide/writeRoot.d.ts +11 -0
  142. package/dist/guide/writeRoot.js +70 -0
  143. package/dist/hosted/translate.js +2 -0
  144. package/dist/mcp/agentTools.js +12 -0
  145. package/dist/mcp/catalogTools.js +18 -20
  146. package/dist/mcp/catalogWriteTools.d.ts +8 -0
  147. package/dist/mcp/catalogWriteTools.js +225 -0
  148. package/dist/mcp/connectionTools.d.ts +3 -0
  149. package/dist/mcp/connectionTools.js +85 -0
  150. package/dist/mcp/controlTools.js +34 -1
  151. package/dist/mcp/deps.d.ts +9 -0
  152. package/dist/mcp/evalTools.js +684 -21
  153. package/dist/mcp/memoryHostTools.d.ts +3 -0
  154. package/dist/mcp/memoryHostTools.js +72 -0
  155. package/dist/mcp/pipelineAuthorTools.js +14 -1
  156. package/dist/mcp/server.js +5 -0
  157. package/dist/mcp/tools.js +6 -0
  158. package/dist/mcp/triggerTools.js +77 -31
  159. package/dist/operatorAgent/evalGate.d.ts +22 -0
  160. package/dist/operatorAgent/evalGate.js +77 -0
  161. package/dist/operatorAgent/fakeHost.js +10 -2
  162. package/dist/operatorAgent/host.js +18 -2
  163. package/dist/operatorAgent/index.d.ts +1 -0
  164. package/dist/operatorAgent/index.js +1 -0
  165. package/dist/operatorAgent/internalAgents.d.ts +11 -0
  166. package/dist/operatorAgent/internalAgents.js +13 -0
  167. package/dist/operatorAgent/piModel.d.ts +5 -1
  168. package/dist/operatorAgent/piModel.js +15 -10
  169. package/dist/operatorAgent/profiles/agentAuthor.js +66 -22
  170. package/dist/operatorAgent/profiles/agentAuthorPlaybook.d.ts +1 -1
  171. package/dist/operatorAgent/profiles/agentAuthorPlaybook.js +1 -1
  172. package/dist/operatorAgent/profiles/guideConfirm.d.ts +21 -0
  173. package/dist/operatorAgent/profiles/guideConfirm.js +100 -0
  174. package/dist/operatorAgent/profiles/guideTools.d.ts +7 -0
  175. package/dist/operatorAgent/profiles/guideTools.js +123 -0
  176. package/dist/operatorAgent/profiles/stageflowGuide.d.ts +7 -0
  177. package/dist/operatorAgent/profiles/stageflowGuide.js +132 -0
  178. package/dist/operatorAgent/profiles/workshopAuthor.js +23 -0
  179. package/dist/operatorAgent/profiles/workshopAuthorPlaybook.d.ts +1 -1
  180. package/dist/operatorAgent/profiles/workshopAuthorPlaybook.js +9 -1
  181. package/dist/operatorAgent/profiles/workshopAuthorTools.d.ts +2 -0
  182. package/dist/operatorAgent/profiles/workshopAuthorTools.js +197 -9
  183. package/dist/operatorAgent/types.d.ts +23 -0
  184. package/dist/package-meta.d.ts +1 -1
  185. package/dist/package-meta.js +1 -1
  186. package/dist/runstore/retention.d.ts +2 -1
  187. package/dist/runstore/retention.js +3 -7
  188. package/dist/runstore/runStatusClock.d.ts +17 -0
  189. package/dist/runstore/runStatusClock.js +19 -0
  190. package/dist/runstore/sqlite/SqliteRunStore.d.ts +1 -0
  191. package/dist/runstore/sqlite/SqliteRunStore.js +45 -45
  192. package/dist/runstore/workspaceLayout.js +6 -1
  193. package/dist/runtime/artifactDiskInspect.d.ts +14 -0
  194. package/dist/runtime/artifactDiskInspect.js +52 -0
  195. package/dist/runtime/artifactPath.d.ts +24 -0
  196. package/dist/runtime/artifactPath.js +84 -0
  197. package/dist/runtime/completionCheckRunner.js +15 -43
  198. package/dist/runtime/githubPollSource.d.ts +22 -4
  199. package/dist/runtime/githubPollSource.js +93 -8
  200. package/dist/runtime/priorArtifactGrants.d.ts +8 -0
  201. package/dist/runtime/priorArtifactGrants.js +105 -0
  202. package/dist/runtime/runActionEligibility.d.ts +46 -0
  203. package/dist/runtime/runActionEligibility.js +123 -0
  204. package/dist/runtime/runManager.d.ts +4 -1
  205. package/dist/runtime/runManager.js +52 -10
  206. package/dist/runtime/runRetryCoordinator.d.ts +2 -14
  207. package/dist/runtime/runRetryCoordinator.js +3 -67
  208. package/dist/runtime/sandboxContainer.d.ts +7 -0
  209. package/dist/runtime/sandboxContainer.js +48 -6
  210. package/dist/runtime/sandboxDesk.d.ts +2 -1
  211. package/dist/runtime/sandboxDesk.js +11 -12
  212. package/dist/runtime/stageEnvironment.js +1 -0
  213. package/dist/runtime/stageRoots.d.ts +12 -0
  214. package/dist/runtime/stageSandbox.d.ts +2 -1
  215. package/dist/runtime/stageSandbox.js +18 -2
  216. package/dist/runtime/stageWorker.js +20 -0
  217. package/dist/server/agentAuthorRoutes.js +12 -3
  218. package/dist/server/bootstrap.d.ts +5 -0
  219. package/dist/server/bootstrap.js +14 -1
  220. package/dist/server/evalRoutes.js +38 -9
  221. package/dist/server/guideRoutes.d.ts +5 -0
  222. package/dist/server/guideRoutes.js +166 -0
  223. package/dist/server/http.d.ts +10 -0
  224. package/dist/server/http.js +35 -1
  225. package/dist/server/internalAgentRoutes.d.ts +6 -0
  226. package/dist/server/internalAgentRoutes.js +12 -0
  227. package/dist/server/mcpHost.js +2 -0
  228. package/dist/toolkit/meta.d.ts +1 -1
  229. package/dist/toolkit/meta.js +39 -1
  230. package/dist/toolkit/profiles.d.ts +5 -0
  231. package/dist/toolkit/profiles.js +12 -0
  232. package/dist/tools/askOperator.js +2 -1
  233. package/dist/tools/emitStageEnvelope.d.ts +17 -16
  234. package/dist/tools/emitStageEnvelope.js +46 -32
  235. package/dist/tools/stageToolNames.d.ts +4 -0
  236. package/dist/tools/stageToolNames.js +4 -0
  237. package/dist/tools/workingState.d.ts +40 -0
  238. package/dist/tools/workingState.js +108 -0
  239. package/dist/tools/writeStageArtifact.d.ts +0 -9
  240. package/dist/tools/writeStageArtifact.js +2 -1
  241. package/dist/ui/assets/{MarkdownText-BTrOqu5J.js → MarkdownText-S5C_vemc.js} +2 -2
  242. package/dist/ui/assets/adapters-C0l4ruiR.js +17 -0
  243. package/dist/ui/assets/chat-CjnsmvqR.js +2 -0
  244. package/dist/ui/assets/chat-DFDd4UjS.css +2 -0
  245. package/dist/ui/assets/{main-CHlmTNJe.css → main-Del1GeLf.css} +1 -1
  246. package/dist/ui/assets/main-_yXVqcW9.js +277 -0
  247. package/dist/ui/chat.html +3 -4
  248. package/dist/ui/index.html +3 -4
  249. package/dist/workshop/chatTurn.js +1 -1
  250. package/dist/workshop/workshopPin.d.ts +3 -3
  251. package/dist/workshop/workshopPin.js +16 -15
  252. package/examples/compaction-stress/README.md +30 -0
  253. package/examples/compaction-stress/check-run.mjs +53 -0
  254. package/examples/compaction-stress/collect-evidence.yaml +60 -0
  255. package/examples/compaction-stress/compaction-stress.pipeline.yaml +141 -0
  256. package/examples/compaction-stress/compaction-stress.task.yaml +15 -0
  257. package/examples/compaction-stress/generate-evidence.mjs +110 -0
  258. package/examples/compaction-stress/root-cause.yaml +26 -0
  259. package/examples/compaction-stress/stageflow.yaml +9 -0
  260. package/examples/compaction-stress/write-postmortem.yaml +40 -0
  261. package/examples/evals/README.md +18 -0
  262. package/examples/evals/guide-behavior.dataset.jsonl +15 -0
  263. package/examples/evals/guide-behavior.eval.yaml +35 -0
  264. package/examples/evals/guide-depth.dataset.jsonl +35 -0
  265. package/examples/evals/guide-depth.eval.yaml +169 -0
  266. package/examples/memory/evals/guide-behavior.dataset.jsonl +15 -0
  267. package/examples/memory/evals/guide-behavior.eval.yaml +35 -0
  268. package/examples/memory/evals/guide-depth.dataset.jsonl +35 -0
  269. package/examples/memory/evals/guide-depth.eval.yaml +169 -0
  270. package/package.json +1 -1
  271. package/dist/ui/assets/AssistantRuntimeProvider-qIX1xNoH.js +0 -9
  272. package/dist/ui/assets/ReadonlyStore-BfXqHykm.js +0 -6
  273. package/dist/ui/assets/chat-Df_wCpak.js +0 -5
  274. package/dist/ui/assets/chat-P7KQznHm.css +0 -2
  275. package/dist/ui/assets/main-CvVfxmMd.js +0 -271
@@ -0,0 +1,205 @@
1
+ import path from "node:path";
2
+ import { checkDatasetAgainstAgent } from "../config/datasetAgentCheck.js";
3
+ import { EVAL_AGENT_DEFAULT_CONCURRENCY, EVAL_AGENT_DEFAULT_MAX_COST_USD, EVAL_DEFAULT_PASS_THRESHOLD, EVAL_DEFAULT_REPEATS, resolveConversation, resolveEvalPaths, } from "../config/loadEval.js";
4
+ import { EVAL_LARGE_RUN, EVAL_TOO_LARGE_RUN, evalFinding } from "../config/validateEval.js";
5
+ import { PACKAGE_VERSION } from "../package-meta.js";
6
+ import { sha256Hex } from "./canonical.js";
7
+ import { EVAL_LIMITS, SIMULATOR_PROMPT_VERSION } from "./constants.js";
8
+ import { buildComponents, buildSnapshot, computeFingerprint } from "./snapshot.js";
9
+ function posix(projectRoot, abs) {
10
+ return path.relative(projectRoot, abs).split(path.sep).join("/");
11
+ }
12
+ function selectCases(cases, overrides, failedIds) {
13
+ if (overrides.case_ids !== undefined)
14
+ return cases.filter((c) => overrides.case_ids.includes(c.id));
15
+ if (overrides.tags !== undefined) {
16
+ const wanted = new Set(overrides.tags);
17
+ return cases.filter((c) => (c.tags ?? []).some((tag) => wanted.has(tag)));
18
+ }
19
+ if (failedIds !== undefined)
20
+ return cases.filter((c) => failedIds.has(c.id));
21
+ return [...cases];
22
+ }
23
+ export function planInternalAgent(args) {
24
+ const { input, loaded, dataset, overrides, failedIds } = args;
25
+ const findings = [...args.findings];
26
+ const fail = (extra) => ({ ok: false, code: "EVAL_INVALID", findings: [...findings, ...extra] });
27
+ if (loaded.file.target.kind !== "internal_agent")
28
+ return fail([]);
29
+ const profileId = loaded.file.target.profile;
30
+ const profiles = input.internalAgents ?? [];
31
+ const profile = profiles.find((item) => item.id === profileId);
32
+ if (!profile) {
33
+ return fail([
34
+ evalFinding(loaded.relPath, "error", profiles.length === 0 ? "eval.internal_agent_unavailable" : "eval.internal_agent_unknown", profiles.length === 0
35
+ ? "This Host is not showing internal agents, so this eval cannot run"
36
+ : `This Host has no internal agent "${profileId}"`),
37
+ ]);
38
+ }
39
+ if (overrides.case_ids !== undefined) {
40
+ const known = new Set(dataset.cases.map((c) => c.id));
41
+ const unknown = overrides.case_ids.filter((id) => !known.has(id));
42
+ if (unknown.length > 0) {
43
+ return fail([
44
+ evalFinding(loaded.relPath, "error", "eval.invalid_field", `Override "case_ids" names ${unknown.length} case(s) not in the dataset; first: ${unknown[0]}`),
45
+ ]);
46
+ }
47
+ }
48
+ const conversation = resolveConversation(loaded.file.conversation);
49
+ if (conversation.tools === "real") {
50
+ return fail([
51
+ evalFinding(loaded.relPath, "error", "eval.internal_agent_real_tools", "An internal agent eval cannot use real tools"),
52
+ ]);
53
+ }
54
+ const checks = new Map(checkDatasetAgainstAgent(dataset.cases, { mode: conversation.mode }).map((r) => [r.caseId, r.valid]));
55
+ const validCases = dataset.cases.filter((c) => checks.get(c.id) !== false);
56
+ const selected = selectCases(dataset.cases, overrides, failedIds);
57
+ const skippedCaseIds = selected.filter((c) => checks.get(c.id) === false).map((c) => c.id);
58
+ const runCases = selected.filter((c) => checks.get(c.id) !== false);
59
+ const positionOf = new Map(dataset.cases.map((c, i) => [c.id, i]));
60
+ const planCases = runCases.map((c) => ({
61
+ id: c.id,
62
+ position: positionOf.get(c.id) ?? 0,
63
+ ...(c.title !== undefined ? { title: c.title } : {}),
64
+ ...(c.goal !== undefined ? { goal: c.goal } : {}),
65
+ input: c.input,
66
+ ...(c.expected !== undefined ? { expected: c.expected } : {}),
67
+ tags: c.tags ?? [],
68
+ ...(c.metadata !== undefined ? { metadata: c.metadata } : {}),
69
+ }));
70
+ const repeats = loaded.file.defaults?.repeats ?? EVAL_DEFAULT_REPEATS;
71
+ const results = planCases.length * repeats;
72
+ if (planCases.length === 0) {
73
+ return fail([evalFinding(loaded.relPath, "error", "eval.no_valid_cases", "No valid cases are left to run after case selection and skipping")]);
74
+ }
75
+ if (results > EVAL_LIMITS.maxResultsPerRun) {
76
+ return fail([
77
+ evalFinding(loaded.relPath, "error", "eval.too_large_run", `${planCases.length} case(s) x ${repeats} repeat(s) = ${results} results, over the ${EVAL_TOO_LARGE_RUN} limit`),
78
+ ]);
79
+ }
80
+ if (results > EVAL_LARGE_RUN) {
81
+ findings.push(evalFinding(loaded.relPath, "warning", "eval.large_run", `${planCases.length} case(s) x ${repeats} repeat(s) = ${results} results, over ${EVAL_LARGE_RUN}`));
82
+ }
83
+ const defaults = loaded.file.defaults ?? {};
84
+ const passThreshold = defaults.pass_threshold ?? EVAL_DEFAULT_PASS_THRESHOLD;
85
+ const concurrency = defaults.concurrency ?? EVAL_AGENT_DEFAULT_CONCURRENCY;
86
+ const maxCostUsd = defaults.max_cost_usd ?? EVAL_AGENT_DEFAULT_MAX_COST_USD;
87
+ const judge = defaults.judge ?? "";
88
+ const model = defaults.model ?? "";
89
+ const playbookHash = sha256Hex(profile.playbook);
90
+ const definitionHash = sha256Hex(JSON.stringify({ playbook: profile.playbook, tools: profile.tools }));
91
+ const userModel = planCases.some((c) => c.input.mode === "simulated") ? (defaults.user_model ?? null) : null;
92
+ const paths = resolveEvalPaths(loaded.file, loaded.path);
93
+ const projectRoot = input.projectRoot;
94
+ const components = buildComponents({
95
+ stageVersionHash: definitionHash,
96
+ model,
97
+ datasetHash: dataset.contentHash,
98
+ caseIds: runCases.length < validCases.length ? runCases.map((c) => c.id) : null,
99
+ graders: loaded.graders,
100
+ judge,
101
+ repeats,
102
+ passThreshold,
103
+ engine: input.engine,
104
+ agent: {
105
+ revision: 0,
106
+ mode: conversation.mode,
107
+ max_turns: conversation.maxTurns,
108
+ turn_timeout_ms: conversation.turnTimeoutMs,
109
+ tools: conversation.tools,
110
+ approvals: conversation.approvals,
111
+ read_only_tools: conversation.readOnlyTools,
112
+ user_model: userModel,
113
+ simulator_prompt_version: SIMULATOR_PROMPT_VERSION,
114
+ },
115
+ });
116
+ const fingerprint = computeFingerprint(components);
117
+ const snapshotOverrides = {
118
+ repeats: overrides.repeats ?? null,
119
+ judge: overrides.judge ?? null,
120
+ model: overrides.model ?? null,
121
+ max_cost_usd: overrides.max_cost_usd ?? null,
122
+ case_ids: overrides.case_ids ?? null,
123
+ tags: overrides.tags ?? null,
124
+ only_failed_from: overrides.only_failed_from ?? null,
125
+ };
126
+ const snapshot = buildSnapshot({
127
+ evalId: loaded.id,
128
+ evalPath: loaded.relPath,
129
+ evalHash: loaded.fileHash,
130
+ evalDefinition: {
131
+ version: 1,
132
+ id: loaded.id,
133
+ target: { kind: "internal_agent", profile: profileId },
134
+ dataset: posix(projectRoot, paths.datasetPath),
135
+ },
136
+ overrides: snapshotOverrides,
137
+ target: {
138
+ profile_id: profileId,
139
+ title: profile.title,
140
+ playbook_hash: playbookHash,
141
+ tools: profile.tools,
142
+ model,
143
+ },
144
+ dataset: {
145
+ path: posix(projectRoot, paths.datasetPath),
146
+ hash: dataset.contentHash,
147
+ format: dataset.format ?? "jsonl",
148
+ case_count: dataset.cases.length,
149
+ cases_run: planCases.length,
150
+ cases_skipped: skippedCaseIds.length,
151
+ skipped_case_ids: skippedCaseIds,
152
+ },
153
+ graders: loaded.graders.map((g) => ({
154
+ id: g.id,
155
+ type: g.type,
156
+ hash: g.hash,
157
+ version_ordinal: input.graderOrdinals?.[g.id] ?? 1,
158
+ weight: g.weight,
159
+ must_pass: g.mustPass,
160
+ })),
161
+ settings: {
162
+ repeats,
163
+ pass_threshold: passThreshold,
164
+ judge,
165
+ judge_same_as_stage: false,
166
+ max_cost_usd: maxCostUsd,
167
+ concurrency,
168
+ suite_type: loaded.file.type ?? "capability",
169
+ conversation: {
170
+ mode: conversation.mode,
171
+ max_turns: conversation.maxTurns,
172
+ turn_timeout_ms: conversation.turnTimeoutMs,
173
+ tools: conversation.tools,
174
+ approvals: conversation.approvals,
175
+ read_only_tools: conversation.readOnlyTools,
176
+ real_tools_confirmed: false,
177
+ user_model: userModel ?? "",
178
+ user_model_from_judge: false,
179
+ simulator_prompt_version: SIMULATOR_PROMPT_VERSION,
180
+ },
181
+ },
182
+ engine: input.engine,
183
+ stageflowVersion: PACKAGE_VERSION,
184
+ });
185
+ const plan = {
186
+ evalRunId: input.evalRunId,
187
+ projectRoot,
188
+ evalId: loaded.id,
189
+ target: { kind: "internal_agent", profileId },
190
+ targetVersionHash: definitionHash,
191
+ stageModel: model,
192
+ task: {},
193
+ cases: planCases,
194
+ graders: loaded.graders,
195
+ repeats,
196
+ passThreshold,
197
+ concurrency,
198
+ maxCostUsd,
199
+ ...(model !== "" ? { modelOverride: model } : {}),
200
+ conversation,
201
+ userModel,
202
+ agent: { definitionHash, definition: { id: profileId, title: profile.title, tools: profile.tools } },
203
+ };
204
+ return { ok: true, plan, snapshot, fingerprint, components, skippedCaseIds, findings };
205
+ }
@@ -54,6 +54,12 @@ export declare function planFindings(input: {
54
54
  datasetCases?: readonly unknown[];
55
55
  isKnownModel?: IsKnownModel;
56
56
  agents?: AgentCatalogPort;
57
+ internalAgents?: ReadonlyArray<{
58
+ id: string;
59
+ title: string;
60
+ playbook: string;
61
+ tools: string[];
62
+ }>;
57
63
  }): Promise<{
58
64
  ok: boolean;
59
65
  findings: ValidationFinding[];
@@ -65,6 +71,12 @@ export declare function validateEvalText(input: {
65
71
  datasetCases?: readonly unknown[];
66
72
  isKnownModel?: IsKnownModel;
67
73
  agents?: AgentCatalogPort;
74
+ internalAgents?: ReadonlyArray<{
75
+ id: string;
76
+ title: string;
77
+ playbook: string;
78
+ tools: string[];
79
+ }>;
68
80
  }): Promise<{
69
81
  findings: ValidationFinding[];
70
82
  parsed: import("../../config/loadOutcome.js").LoadOutcome<LoadedEval>;
@@ -99,6 +99,9 @@ export async function buildEvalDetail(input) {
99
99
  agent = await liveAgentOf(input.agents, projectRoot, file.target.agent);
100
100
  targetModel = file.defaults?.model ?? agent?.model ?? null;
101
101
  }
102
+ else if (file.target.kind === "internal_agent") {
103
+ targetModel = file.defaults?.model ?? null;
104
+ }
102
105
  else {
103
106
  const target = await resolveEvalTarget(file, entry.outcome.value.path, projectRoot);
104
107
  if (target.ok)
@@ -130,6 +133,7 @@ export async function planFindings(input) {
130
133
  engine: { name: ENGINE_NAME, version: PINNED_PROMPTFOO_VERSION, nodeVersion: process.versions.node },
131
134
  ...(input.isKnownModel ? { isKnownModel: input.isKnownModel } : {}),
132
135
  ...(input.agents ? { agents: input.agents } : {}),
136
+ ...(input.internalAgents ? { internalAgents: input.internalAgents } : {}),
133
137
  });
134
138
  return { ok: built.ok, findings: built.findings };
135
139
  }
@@ -143,6 +147,7 @@ export async function validateEvalText(input) {
143
147
  ...(input.datasetCases !== undefined ? { datasetCases: input.datasetCases } : {}),
144
148
  ...(input.isKnownModel ? { isKnownModel: input.isKnownModel } : {}),
145
149
  ...(input.agents ? { agents: input.agents } : {}),
150
+ ...(input.internalAgents ? { internalAgents: input.internalAgents } : {}),
146
151
  });
147
152
  const findings = checked.findings.length > 0 || parsed.ok
148
153
  ? checked.findings
@@ -103,7 +103,16 @@ export async function buildEvalListItems(input) {
103
103
  bannerInputs.push({ evalId: loaded.id, status, last: lastSummary, previous: previousSummary });
104
104
  const agentTarget = file.target.kind === "agent"
105
105
  ? await agentListTarget(file.target.agent, last, input.agents, projectRoot)
106
- : undefined;
106
+ : file.target.kind === "internal_agent"
107
+ ? {
108
+ kind: "agent",
109
+ agent_id: file.target.profile,
110
+ agent_name: file.target.profile,
111
+ model: file.defaults?.model ?? null,
112
+ revision: null,
113
+ label: `${file.target.profile} (internal)`,
114
+ }
115
+ : undefined;
107
116
  const conv = agentTarget ? resolveConversation(file.conversation) : undefined;
108
117
  const pipelinePath = paths.pipelinePath !== undefined ? posix(projectRoot, paths.pipelinePath) : undefined;
109
118
  const stageFile = paths.stageFile !== undefined ? posix(projectRoot, paths.stageFile) : undefined;
@@ -106,6 +106,11 @@ export type EvalRunDetail = {
106
106
  stats: Stats | null;
107
107
  lowest_cases_by_grader: Record<string, LowestCase[]>;
108
108
  current: RunCurrent;
109
+ cases: Array<{
110
+ id: string;
111
+ title: string | null;
112
+ position: number;
113
+ }>;
109
114
  live?: Array<{
110
115
  case_id: string;
111
116
  repeat_index: number;
@@ -218,11 +218,16 @@ export async function currentHashes(row, agents) {
218
218
  return none;
219
219
  }
220
220
  }
221
+ function plannedCase(row) {
222
+ const title = row.case.title;
223
+ return { id: row.caseId, title: typeof title === "string" && title !== "" ? title : null, position: row.position };
224
+ }
221
225
  export async function buildRunDetail(input) {
222
226
  const { store, row } = input;
223
- const [results, reviews] = await Promise.all([
227
+ const [results, reviews, storedCases] = await Promise.all([
224
228
  store.listEvalResults(row.evalRunId),
225
229
  store.getEvalReviews(row.evalRunId),
230
+ store.getEvalCases(row.evalRunId),
226
231
  ]);
227
232
  const graders = graderRefsOf(row);
228
233
  const grades = results.flatMap(toGradeRecords);
@@ -258,6 +263,7 @@ export async function buildRunDetail(input) {
258
263
  ? Object.fromEntries(graders.map((g) => [g.id, lowestCases(grades.filter((x) => x.graderId === g.id))]))
259
264
  : {},
260
265
  current: await currentHashes(row, input.agents),
266
+ cases: storedCases.map(plannedCase),
261
267
  };
262
268
  if (input.live && (row.status === "running" || row.status === "queued")) {
263
269
  detail.live = input.live.phases.map((p) => ({
@@ -1,7 +1,8 @@
1
1
  import type { StageCaseRunner } from "./stageCaseRunner.js";
2
2
  export type EvalCaseRunner = StageCaseRunner;
3
- /** Routes each case to the stage or agent runner by the plan's target kind. */
3
+ /** Routes each case to the stage, agent, or internal-agent runner by the plan's target kind. */
4
4
  export declare function createEvalCaseRunner(deps: {
5
5
  stage: StageCaseRunner;
6
6
  agent: StageCaseRunner;
7
+ internalAgent?: StageCaseRunner;
7
8
  }): EvalCaseRunner;
@@ -1,16 +1,27 @@
1
- /** Routes each case to the stage or agent runner by the plan's target kind. */
1
+ import { isConversationTarget } from "../types.js";
2
+ /** Routes each case to the stage, agent, or internal-agent runner by the plan's target kind. */
2
3
  export function createEvalCaseRunner(deps) {
3
4
  const kinds = new Map();
4
- const runnerOf = (evalRunId) => (kinds.get(evalRunId) === "agent" ? deps.agent : deps.stage);
5
+ const runnerOf = (evalRunId) => {
6
+ const kind = kinds.get(evalRunId);
7
+ if (kind === "internal_agent" && deps.internalAgent)
8
+ return deps.internalAgent;
9
+ return kind === "agent" ? deps.agent : deps.stage;
10
+ };
5
11
  return {
6
12
  runCase(plan, req) {
7
- kinds.set(req.evalRunId, plan.target.kind === "agent" ? "agent" : "stage");
13
+ const kind = plan.target.kind === "internal_agent" ? "internal_agent" : isConversationTarget(plan.target.kind) ? "agent" : "stage";
14
+ kinds.set(req.evalRunId, kind);
8
15
  return runnerOf(req.evalRunId).runCase(plan, req);
9
16
  },
10
17
  async cancelAll(evalRunId) {
11
- await Promise.all([deps.stage.cancelAll(evalRunId), deps.agent.cancelAll(evalRunId)]);
18
+ await Promise.all([
19
+ deps.stage.cancelAll(evalRunId),
20
+ deps.agent.cancelAll(evalRunId),
21
+ deps.internalAgent?.cancelAll(evalRunId),
22
+ ]);
12
23
  },
13
- spend: (evalRunId) => deps.stage.spend(evalRunId) + deps.agent.spend(evalRunId),
24
+ spend: (evalRunId) => deps.stage.spend(evalRunId) + deps.agent.spend(evalRunId) + (deps.internalAgent?.spend(evalRunId) ?? 0),
14
25
  addSpend: (evalRunId, usd) => runnerOf(evalRunId).addSpend(evalRunId, usd),
15
26
  stopReason: (evalRunId) => runnerOf(evalRunId).stopReason?.(evalRunId),
16
27
  };
@@ -0,0 +1,6 @@
1
+ import type { OperatorAgentHost } from "../../operatorAgent/types.js";
2
+ import type { StageCaseRunner } from "./stageCaseRunner.js";
3
+ export declare function createInternalAgentCaseRunner(deps: {
4
+ host: () => OperatorAgentHost | undefined;
5
+ now?: () => number;
6
+ }): StageCaseRunner;
@@ -0,0 +1,250 @@
1
+ import { randomUUID } from "node:crypto";
2
+ import { createOperatorEvalGate } from "../../operatorAgent/evalGate.js";
3
+ import { buildConversationSubject } from "./conversationSubject.js";
4
+ import { createDriver, DriverScenarioError } from "./userDriver.js";
5
+ const ZERO_USAGE = {
6
+ cost_usd: 0,
7
+ agent_cost_usd: 0,
8
+ simulator_cost_usd: 0,
9
+ tokens_in: 0,
10
+ tokens_out: 0,
11
+ simulator_tokens_in: 0,
12
+ simulator_tokens_out: 0,
13
+ simulator_estimated: false,
14
+ agent_calls: 0,
15
+ simulator_calls: 0,
16
+ };
17
+ function failure(code, message, extra = {}) {
18
+ return { ok: false, code, message, ...extra };
19
+ }
20
+ function parseMocks(value) {
21
+ const out = {};
22
+ if (typeof value !== "object" || value === null || Array.isArray(value))
23
+ return out;
24
+ for (const [tool, mock] of Object.entries(value)) {
25
+ if (typeof mock !== "object" || mock === null)
26
+ continue;
27
+ const { result, error } = mock;
28
+ if (typeof error === "string")
29
+ out[tool] = { error };
30
+ else if ("result" in mock)
31
+ out[tool] = { result };
32
+ }
33
+ return out;
34
+ }
35
+ function detailFrom(sessionId, profileId, messages) {
36
+ const now = new Date().toISOString();
37
+ return {
38
+ session: {
39
+ id: sessionId,
40
+ agentId: profileId,
41
+ revision: 0,
42
+ backend: "pi",
43
+ status: "closed",
44
+ source: "eval",
45
+ sourceRef: null,
46
+ threadKey: null,
47
+ title: null,
48
+ createdAt: now,
49
+ updatedAt: now,
50
+ },
51
+ messages,
52
+ turns: [],
53
+ spans: [],
54
+ approvals: [],
55
+ pendingApproval: null,
56
+ evalScores: [],
57
+ deliveries: [],
58
+ };
59
+ }
60
+ export function createInternalAgentCaseRunner(deps) {
61
+ const clock = deps.now ?? Date.now;
62
+ const states = new Map();
63
+ const stateFor = (id) => {
64
+ let state = states.get(id);
65
+ if (!state) {
66
+ state = { cancelled: false, abort: new AbortController() };
67
+ states.set(id, state);
68
+ }
69
+ return state;
70
+ };
71
+ async function runCase(plan, req) {
72
+ const state = stateFor(req.evalRunId);
73
+ if (state.cancelled)
74
+ return failure("EVAL_CANCELLED", "Eval run was cancelled");
75
+ if (plan.target.kind !== "internal_agent" || !plan.conversation) {
76
+ return failure("EVAL_ENGINE_ERROR", "Not an internal-agent plan");
77
+ }
78
+ if (plan.conversation.tools === "real") {
79
+ return failure("EVAL_ENGINE_ERROR", "Internal agents cannot run an eval with real tools");
80
+ }
81
+ const host = deps.host();
82
+ if (!host)
83
+ return failure("EVAL_ENGINE_ERROR", "Internal agents are unavailable on this host");
84
+ const planCase = plan.cases.find((c) => c.id === req.caseId);
85
+ if (!planCase)
86
+ return failure("EVAL_ENGINE_ERROR", `Case "${req.caseId}" is not in the plan`);
87
+ const scenario = planCase.input;
88
+ const mode = scenario.mode === "script" || scenario.mode === "simulated" ? scenario.mode : plan.conversation.mode;
89
+ let driver;
90
+ try {
91
+ driver = createDriver(mode, scenario, {});
92
+ }
93
+ catch (err) {
94
+ return failure("EVAL_ENGINE_ERROR", err instanceof DriverScenarioError ? err.message : "Scenario could not be prepared");
95
+ }
96
+ if (mode === "simulated") {
97
+ return failure("EVAL_ENGINE_ERROR", "A simulated internal-agent case needs a user model, which this runner does not call");
98
+ }
99
+ const conversation = plan.conversation;
100
+ const sessionId = `op_eval_${randomUUID()}`;
101
+ let turn = 0;
102
+ const gate = createOperatorEvalGate({
103
+ policy: { tools: conversation.tools, mocks: parseMocks(scenario.tool_mocks) },
104
+ turn: () => turn,
105
+ });
106
+ let session;
107
+ try {
108
+ session = host.openEvalSession({
109
+ profileId: plan.target.profileId,
110
+ context: { kind: "stageflow_guide" },
111
+ gate,
112
+ });
113
+ }
114
+ catch (err) {
115
+ return failure("EVAL_ENGINE_ERROR", err instanceof Error ? err.message : "The eval session could not be opened");
116
+ }
117
+ const startedAt = clock();
118
+ const messages = [];
119
+ const transcript = [];
120
+ let end = {
121
+ kind: "done",
122
+ stopReason: "max_turns",
123
+ };
124
+ const caseCtl = new AbortController();
125
+ let wallExpired = false;
126
+ let turnTimedOut = false;
127
+ const stopCase = () => {
128
+ caseCtl.abort();
129
+ void session.abort().catch(() => undefined);
130
+ };
131
+ const onRunAbort = () => stopCase();
132
+ state.abort.signal.addEventListener("abort", onRunAbort, { once: true });
133
+ const wallMs = conversation.maxTurns * conversation.turnTimeoutMs + 60_000;
134
+ const wall = setTimeout(() => {
135
+ wallExpired = true;
136
+ stopCase();
137
+ }, wallMs);
138
+ const stopped = new Promise((resolve) => {
139
+ if (caseCtl.signal.aborted)
140
+ resolve("stopped");
141
+ else
142
+ caseCtl.signal.addEventListener("abort", () => resolve("stopped"), { once: true });
143
+ });
144
+ try {
145
+ for (turn = 1; turn <= conversation.maxTurns; turn += 1) {
146
+ if (state.cancelled) {
147
+ end = { kind: "cancelled" };
148
+ break;
149
+ }
150
+ if (wallExpired || turnTimedOut || caseCtl.signal.aborted) {
151
+ end = {
152
+ kind: "failed",
153
+ code: "EVAL_AGENT_TIMEOUT",
154
+ message: turnTimedOut ? `Turn ${turn} exceeded ${conversation.turnTimeoutMs} ms` : "Conversation exceeded its time limit",
155
+ stopReason: "timeout",
156
+ };
157
+ break;
158
+ }
159
+ const step = await driver.next({ turn, transcript, signal: caseCtl.signal });
160
+ if (step.kind === "end") {
161
+ end = { kind: "done", stopReason: step.reason };
162
+ break;
163
+ }
164
+ const now = new Date().toISOString();
165
+ messages.push({ id: randomUUID(), sessionId, seq: messages.length, turnId: String(turn), role: "user", author: null, text: step.text, createdAt: now });
166
+ const turnTimer = setTimeout(() => {
167
+ turnTimedOut = true;
168
+ stopCase();
169
+ }, conversation.turnTimeoutMs);
170
+ const sent = session.send(step.text, plan.modelOverride ? { modelId: plan.modelOverride } : {}).then((events) => ({ ok: true, events }), (err) => ({ ok: false, err }));
171
+ const outcome = await Promise.race([sent, stopped]);
172
+ clearTimeout(turnTimer);
173
+ if (state.cancelled) {
174
+ end = { kind: "cancelled" };
175
+ break;
176
+ }
177
+ if (outcome === "stopped" || wallExpired || turnTimedOut) {
178
+ end = {
179
+ kind: "failed",
180
+ code: "EVAL_AGENT_TIMEOUT",
181
+ message: turnTimedOut ? `Turn ${turn} exceeded ${conversation.turnTimeoutMs} ms` : "Conversation exceeded its time limit",
182
+ stopReason: "timeout",
183
+ };
184
+ break;
185
+ }
186
+ if (!outcome.ok) {
187
+ end = { kind: "failed", code: "EVAL_ENGINE_ERROR", message: outcome.err instanceof Error ? outcome.err.message : "Conversation failed", stopReason: "error" };
188
+ break;
189
+ }
190
+ const text = outcome.events
191
+ .filter((event) => event.type === "message" && event.role === "assistant")
192
+ .map((event) => (event.type === "message" ? event.text : ""))
193
+ .filter(Boolean)
194
+ .join("\n\n");
195
+ if (!text && gate.records().every((call) => call.turn !== turn)) {
196
+ end = { kind: "failed", code: "EVAL_AGENT_EMPTY_REPLY", message: "The agent returned an empty reply", stopReason: "error" };
197
+ break;
198
+ }
199
+ messages.push({ id: randomUUID(), sessionId, seq: messages.length, turnId: String(turn), role: "assistant", author: null, text, createdAt: now });
200
+ transcript.push({ role: "user", text: step.text }, { role: "assistant", text });
201
+ if (step.endAfter !== undefined) {
202
+ end = { kind: "done", stopReason: step.endAfter };
203
+ break;
204
+ }
205
+ if (turn === conversation.maxTurns)
206
+ end = { kind: "done", stopReason: "max_turns" };
207
+ }
208
+ }
209
+ catch (err) {
210
+ end = state.cancelled
211
+ ? { kind: "cancelled" }
212
+ : wallExpired || turnTimedOut
213
+ ? { kind: "failed", code: "EVAL_AGENT_TIMEOUT", message: turnTimedOut ? `Turn ${turn} exceeded ${conversation.turnTimeoutMs} ms` : "Conversation exceeded its time limit", stopReason: "timeout" }
214
+ : { kind: "failed", code: "EVAL_ENGINE_ERROR", message: err instanceof Error ? err.message : "Conversation failed", stopReason: "error" };
215
+ }
216
+ finally {
217
+ clearTimeout(wall);
218
+ state.abort.signal.removeEventListener("abort", onRunAbort);
219
+ session.close();
220
+ }
221
+ const usage = { ...ZERO_USAGE, agent_calls: messages.filter((m) => m.role === "assistant").length };
222
+ const subject = (stopReason, failed) => buildConversationSubject({
223
+ detail: detailFrom(sessionId, plan.target.kind === "internal_agent" ? plan.target.profileId : "", messages),
224
+ calls: gate.records(),
225
+ stopReason,
226
+ usage,
227
+ turns: messages.filter((m) => m.role === "user").length,
228
+ ...(failed !== undefined ? { failure: failed } : {}),
229
+ });
230
+ const latencyMs = Math.max(0, clock() - startedAt);
231
+ if (end.kind === "done") {
232
+ return { ok: true, subjectRef: sessionId, output: subject(end.stopReason), latencyMs, costUsd: 0, tokensIn: 0, tokensOut: 0 };
233
+ }
234
+ if (end.kind === "cancelled")
235
+ return failure("EVAL_CANCELLED", "Eval run was cancelled", { subjectRef: sessionId, latencyMs, costUsd: 0 });
236
+ return failure(end.code, end.message, { subjectRef: sessionId, output: subject(end.stopReason, end.message), latencyMs, costUsd: 0 });
237
+ }
238
+ return {
239
+ runCase,
240
+ async cancelAll(evalRunId) {
241
+ const state = states.get(evalRunId);
242
+ if (!state)
243
+ return;
244
+ state.cancelled = true;
245
+ state.abort.abort();
246
+ },
247
+ spend: () => 0,
248
+ addSpend: () => undefined,
249
+ };
250
+ }
@@ -74,6 +74,14 @@ export type ConversationSettings = {
74
74
  user_model_from_judge: boolean;
75
75
  simulator_prompt_version: number;
76
76
  };
77
+ export type InternalAgentSnapshotTarget = {
78
+ kind: "internal_agent";
79
+ profile_id: string;
80
+ title: string;
81
+ playbook_hash: string;
82
+ tools: string[];
83
+ model: string;
84
+ };
77
85
  export type ConfigSnapshot = {
78
86
  snapshot_version: number;
79
87
  eval: {
@@ -83,7 +91,7 @@ export type ConfigSnapshot = {
83
91
  definition: Record<string, unknown>;
84
92
  };
85
93
  overrides: SnapshotOverrides;
86
- target: StageSnapshotTarget | AgentSnapshotTarget;
94
+ target: StageSnapshotTarget | AgentSnapshotTarget | InternalAgentSnapshotTarget;
87
95
  dataset: {
88
96
  path: string;
89
97
  hash: string;
@@ -169,7 +177,7 @@ export type SnapshotInput = {
169
177
  evalHash: string;
170
178
  evalDefinition: Record<string, unknown>;
171
179
  overrides: SnapshotOverrides;
172
- target: Omit<StageSnapshotTarget, "kind"> | Omit<AgentSnapshotTarget, "kind">;
180
+ target: Omit<StageSnapshotTarget, "kind"> | Omit<AgentSnapshotTarget, "kind"> | Omit<InternalAgentSnapshotTarget, "kind">;
173
181
  dataset: ConfigSnapshot["dataset"];
174
182
  graders: SnapshotGrader[];
175
183
  settings: ConfigSnapshot["settings"];