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
@@ -37,16 +37,14 @@ export function buildSandboxDesk(input) {
37
37
  optional: false,
38
38
  });
39
39
  }
40
- const grants = input.grantedPaths ?? [];
41
- for (let index = 0; index < grants.length; index += 1) {
42
- const hostPath = grants[index];
40
+ for (const grant of input.grants ?? []) {
43
41
  bindings.push({
44
42
  role: "grant",
45
- hostPath,
46
- containerPath: `${SANDBOX_MOUNT_PATH}/grants/${grantSegment(index, hostPath)}`,
47
- shape: "mirror",
43
+ hostPath: grant.hostPath,
44
+ containerPath: grant.containerPath,
45
+ shape: grant.kind === "directory" ? "directory" : "file",
48
46
  copyIn: true,
49
- copyOut: true,
47
+ copyOut: false,
50
48
  optional: false,
51
49
  });
52
50
  }
@@ -61,11 +59,6 @@ export function buildSandboxDesk(input) {
61
59
  });
62
60
  return { bindings };
63
61
  }
64
- function grantSegment(index, hostPath) {
65
- const base = path.basename(hostPath).replace(/[^A-Za-z0-9_.-]/g, "_");
66
- const safe = base.length > 0 && base !== "." && base !== ".." ? base : "path";
67
- return `${index}-${safe}`;
68
- }
69
62
  async function pathExists(target) {
70
63
  try {
71
64
  await access(target);
@@ -85,6 +78,12 @@ export async function populateSandboxDesk(params) {
85
78
  if (binding.role === "checkout" || binding.shape === "mirror") {
86
79
  dirs.add(binding.containerPath);
87
80
  }
81
+ if (binding.role === "grant" && binding.shape === "file") {
82
+ dirs.add(path.posix.dirname(binding.containerPath));
83
+ }
84
+ if (binding.role === "grant" && binding.shape === "directory") {
85
+ dirs.add(binding.containerPath);
86
+ }
88
87
  }
89
88
  const made = await execInSandboxContainer({
90
89
  containerName: params.containerName,
@@ -28,6 +28,7 @@ export const STAGE_ENV_ALLOWLIST = [
28
28
  "STAGEFLOW_CURSOR_EXTENSION",
29
29
  "STAGEFLOW_STAGE_CONTAINER_IMAGE",
30
30
  "STAGEFLOW_STAGE_CONTAINER_DOCKER_BIN",
31
+ "STAGEFLOW_STAGE_READONLY_DIR",
31
32
  ];
32
33
  export const PROVIDER_AND_CLOUD_NAMES = [
33
34
  "ANTHROPIC_API_KEY",
@@ -2,6 +2,14 @@ import type { RunMeta } from "../runstore/port.js";
2
2
  import type { StageAttemptContext } from "./stageAttemptContext.js";
3
3
  import type { TaskFile, TaskGitIdentity } from "../types/task.js";
4
4
  export type DerivedBindingKind = "repository" | "checkout" | "unbound";
5
+ export type StageArtifactGrant = {
6
+ /** Run-relative path from the prior envelope. */
7
+ listedPath: string;
8
+ hostPath: string;
9
+ /** File or directory inside the sandbox, under /workspace/grants. */
10
+ containerPath: string;
11
+ kind: "file" | "directory";
12
+ };
5
13
  export type StageRoots = {
6
14
  mode: "bound" | "unbound";
7
15
  cwd: string;
@@ -19,6 +27,10 @@ export type StageRoots = {
19
27
  containerName?: string;
20
28
  /** The docker binary the container above was started with (see STAGEFLOW_STAGE_CONTAINER_DOCKER_BIN). */
21
29
  containerDockerBin?: string;
30
+ /** Host folder bind-mounted read-only into the sandbox at this same path. */
31
+ readonlyDir?: string;
32
+ /** Prior artifacts mounted into the sandbox. Empty or omitted when none are granted. */
33
+ artifactGrants?: readonly StageArtifactGrant[];
22
34
  };
23
35
  export declare const STAGEFLOW_CHECKOUT = "STAGEFLOW_CHECKOUT";
24
36
  export declare const STAGEFLOW_RUN_WORKSPACE = "STAGEFLOW_RUN_WORKSPACE";
@@ -1,4 +1,4 @@
1
- import { type StageRoots } from "./stageRoots.js";
1
+ import { type StageArtifactGrant, type StageRoots } from "./stageRoots.js";
2
2
  export type StageSandbox = {
3
3
  roots: StageRoots;
4
4
  beforeVerify?: () => Promise<void>;
@@ -13,4 +13,5 @@ export declare function openStageSandbox(input: {
13
13
  attempt: number;
14
14
  attemptDir: string;
15
15
  checkoutRoot?: string;
16
+ grants?: readonly StageArtifactGrant[];
16
17
  }): Promise<StageSandbox>;
@@ -1,4 +1,4 @@
1
- import { resolveSandboxContainerOptions, startSandboxContainer, stopSandboxContainer, } from "./sandboxContainer.js";
1
+ import { assertStageReadOnlyDirExists, resolveSandboxContainerOptions, stageReadOnlyDir, startSandboxContainer, stopSandboxContainer, } from "./sandboxContainer.js";
2
2
  import { buildSandboxDesk, populateSandboxDesk, syncSandboxDesk, } from "./sandboxDesk.js";
3
3
  import { withContainerName } from "./stageRoots.js";
4
4
  export async function openStageSandbox(input) {
@@ -6,18 +6,34 @@ export async function openStageSandbox(input) {
6
6
  if (!options) {
7
7
  return { roots: input.roots, close: async () => { } };
8
8
  }
9
+ let readOnlyDir;
10
+ try {
11
+ readOnlyDir = stageReadOnlyDir(input.env);
12
+ if (readOnlyDir !== undefined)
13
+ await assertStageReadOnlyDirExists(readOnlyDir);
14
+ }
15
+ catch (err) {
16
+ return {
17
+ roots: input.roots,
18
+ close: async () => { },
19
+ failure: err instanceof Error ? err.message : String(err),
20
+ };
21
+ }
9
22
  const started = await startSandboxContainer({
10
23
  image: options.image,
11
24
  dockerBin: options.dockerBin,
12
25
  runId: input.runId,
13
26
  stageId: input.stageId,
14
27
  attempt: input.attempt,
28
+ ...(readOnlyDir !== undefined ? { readOnlyDir } : {}),
15
29
  });
16
- const roots = withContainerName(input.roots, started.containerName, options.dockerBin);
30
+ const roots = withContainerName(readOnlyDir !== undefined ? { ...input.roots, readonlyDir: readOnlyDir } : input.roots, started.containerName, options.dockerBin);
17
31
  const checkout = input.checkoutRoot?.trim();
32
+ const grants = input.grants ?? [];
18
33
  const desk = buildSandboxDesk({
19
34
  attemptDir: input.attemptDir,
20
35
  ...(checkout ? { checkoutRoot: checkout } : {}),
36
+ ...(grants.length > 0 ? { grants } : {}),
21
37
  });
22
38
  const session = {
23
39
  roots,
@@ -16,6 +16,9 @@ import { runStage, isRunStageWaiting, } from "./stageRunner.js";
16
16
  import { openStageAttempt } from "./stageAttemptBootstrap.js";
17
17
  import { attemptContext } from "./stageAttemptContext.js";
18
18
  import { loadActiveFeedbackLoopContext } from "./feedbackLoopCoordinator.js";
19
+ import { buildCompletedEnvelopesFromRun, resolvePriorEnvelope, } from "./envelopeRouting.js";
20
+ import { assignment } from "./cloneSchedule.js";
21
+ import { artifactGrantsFromPriors } from "./priorArtifactGrants.js";
19
22
  import { outcomeToWorkerResult, SF_STAGE_WORKER, STAGE_WORKER_EXIT, } from "./stageWorkerProtocol.js";
20
23
  export async function runStageWorker(input) {
21
24
  const store = createRunStore({ rootDir: globalStageflowHome() });
@@ -67,6 +70,19 @@ export async function runStageWorker(input) {
67
70
  const eventOptions = { attempt };
68
71
  let roots = withResolvedAuthPath(rootsForStageWorker(workspaceDir, input.stageId, stage.model, checkoutRoot, attemptCtx), input.rootDir);
69
72
  const unbindAgentDir = bindPiAgentDirEnv(roots.agentDir);
73
+ const completedEnvelopes = await buildCompletedEnvelopesFromRun(store, input.runId, undefined, dag);
74
+ const assigned = assignment(dag, input.stageId, definitionId, completedEnvelopes);
75
+ const priorResult = assigned ??
76
+ (await resolvePriorEnvelope({
77
+ dag,
78
+ stageId: input.stageId,
79
+ completedEnvelopes,
80
+ store,
81
+ runId: input.runId,
82
+ }));
83
+ const artifactGrants = priorResult.ok
84
+ ? await artifactGrantsFromPriors(workspaceDir, priorResult)
85
+ : [];
70
86
  const sandbox = await openStageSandbox({
71
87
  env: process.env,
72
88
  roots,
@@ -75,8 +91,12 @@ export async function runStageWorker(input) {
75
91
  attempt,
76
92
  attemptDir,
77
93
  ...(checkoutRoot !== undefined ? { checkoutRoot } : {}),
94
+ ...(artifactGrants.length > 0 ? { grants: artifactGrants } : {}),
78
95
  });
79
96
  roots = sandbox.roots;
97
+ if (artifactGrants.length > 0) {
98
+ roots = { ...roots, artifactGrants };
99
+ }
80
100
  const beforeVerify = sandbox.beforeVerify;
81
101
  let outcome;
82
102
  let thrown;
@@ -1,5 +1,5 @@
1
- import { authorSessionForApi, parseAgentAuthorDraft, runAgentAuthorTurn, undoAgentAuthorTurn, } from "../agents/authorChat.js";
2
- import { createAuthorSession, listAuthorDrafts, readAuthorSession, saveAuthorSession } from "../agents/authorSessionStore.js";
1
+ import { authorSessionForApi, forgetAgentAuthorSession, parseAgentAuthorDraft, runAgentAuthorTurn, undoAgentAuthorTurn, } from "../agents/authorChat.js";
2
+ import { createAuthorSession, deleteAuthorSession, listAuthorDrafts, readAuthorSession, saveAuthorSession, } from "../agents/authorSessionStore.js";
3
3
  import { parseWorkshopModel } from "../workshop/modelSettings.js";
4
4
  async function readBody(req) {
5
5
  const chunks = [];
@@ -46,13 +46,22 @@ export async function handleAgentAuthorRoutes(req, method, pathname, projectRoot
46
46
  json(res, 200, { drafts: listAuthorDrafts() });
47
47
  return true;
48
48
  }
49
- if (sessionMatch && (method === "GET" || method === "PUT")) {
49
+ if (sessionMatch && (method === "GET" || method === "PUT" || method === "DELETE")) {
50
50
  const sessionId = decodeURIComponent(sessionMatch[1] ?? "");
51
51
  try {
52
52
  if (method === "GET") {
53
53
  json(res, 200, authorSessionForApi(sessionId));
54
54
  return true;
55
55
  }
56
+ if (method === "DELETE") {
57
+ forgetAgentAuthorSession(sessionId);
58
+ if (!deleteAuthorSession(sessionId)) {
59
+ json(res, 404, { code: "agent.session_not_found" });
60
+ return true;
61
+ }
62
+ json(res, 200, { removed: true });
63
+ return true;
64
+ }
56
65
  const body = await readBody(req);
57
66
  if (body.__tooLarge || body.__invalid) {
58
67
  json(res, 400, { code: "agent.invalid" });
@@ -17,6 +17,7 @@ import { type RunChangeBus } from "../runtime/runChangeBus.js";
17
17
  import { type McpHttpHandler } from "../mcp/server.js";
18
18
  import { type HostConfig } from "../config/hostConfig.js";
19
19
  import { bootProviderConfig } from "../agent/bootProviderConfig.js";
20
+ import type { OperatorAgentHost } from "../operatorAgent/types.js";
20
21
  import { type AgentHostContext } from "../agents/hostContext.js";
21
22
  import type { ConversationBackend } from "../agents/sessions.js";
22
23
  export declare const DEFAULT_GC_INTERVAL_MS: number;
@@ -78,6 +79,10 @@ export type StageflowHostBootstrap = {
78
79
  memories?: MemoryHost;
79
80
  /** Shared agent store, chat controller, and conversation backend for HTTP/MCP. */
80
81
  agentHost?: AgentHostContext;
82
+ /** Filled when the operator console host is created, so internal-agent evals can open a gated session. */
83
+ operatorHostSlot?: {
84
+ current?: OperatorAgentHost;
85
+ };
81
86
  email?: ReturnType<typeof emailHostFor> & {
82
87
  triggers: EmailTriggers;
83
88
  stop: () => Promise<void>;
@@ -40,6 +40,8 @@ import { logger as rootLogger } from "../logging/logger.js";
40
40
  import { getModelCatalog } from "../models/catalog.js";
41
41
  import { createAgentCaseRunner } from "../evals/runner/agentCaseRunner.js";
42
42
  import { createEvalCaseRunner } from "../evals/runner/caseRunner.js";
43
+ import { createInternalAgentCaseRunner } from "../evals/runner/internalAgentCaseRunner.js";
44
+ import { describeInternalAgents, internalAgentsVisible } from "../operatorAgent/internalAgents.js";
43
45
  import { defaultLoadJudgePrices } from "../evals/engine/promptfoo/judgeServices.js";
44
46
  import { createAgentHostContext } from "../agents/hostContext.js";
45
47
  export const DEFAULT_GC_INTERVAL_MS = 60 * 60 * 1000;
@@ -268,17 +270,22 @@ export async function bootstrapStageflowHost(options) {
268
270
  await manager.reenqueuePersistedQueuedRuns();
269
271
  const evalLog = rootLogger.child({ component: "evals" });
270
272
  const evalStageRunner = createStageCaseRunner({ manager, store });
273
+ const operatorHostSlot = {};
271
274
  const evalAgentRunner = createAgentCaseRunner({
272
275
  host: () => agentHost,
273
276
  loadPrices: defaultLoadJudgePrices,
274
277
  });
275
- const evalRunner = createEvalCaseRunner({ stage: evalStageRunner, agent: evalAgentRunner });
278
+ const evalInternalRunner = createInternalAgentCaseRunner({ host: () => operatorHostSlot.current });
279
+ const evalRunner = createEvalCaseRunner({ stage: evalStageRunner, agent: evalAgentRunner, internalAgent: evalInternalRunner });
276
280
  const evalTokens = new RunTokenRegistry();
277
281
  let evalCallbackBase = "";
278
282
  const evalRunManager = new EvalRunManager({
279
283
  store,
280
284
  stageRunner: evalRunner,
281
285
  agents: () => agentHost?.service,
286
+ internalAgents: () => operatorHostSlot.current && internalAgentsVisible()
287
+ ? describeInternalAgents(operatorHostSlot.current).map(({ id, title, playbook, tools }) => ({ id, title, playbook, tools }))
288
+ : [],
282
289
  engines: (name, engineOptions) => getEngine(name, name === EVAL_DEFAULT_ENGINE
283
290
  ? {
284
291
  tokens: evalTokens,
@@ -400,6 +407,9 @@ export async function bootstrapStageflowHost(options) {
400
407
  store,
401
408
  agentDir,
402
409
  projectRoot: rootDir,
410
+ channels,
411
+ memories: memoryHostFor(),
412
+ evalRunManager,
403
413
  ...(options.providerAuthContext ? { providerAuthContext: options.providerAuthContext } : {}),
404
414
  ...(providerBoot !== undefined ? { providerBoot } : {}),
405
415
  },
@@ -419,6 +429,8 @@ export async function bootstrapStageflowHost(options) {
419
429
  providerAuthContext: options.providerAuthContext,
420
430
  projectRoot: rootDir,
421
431
  evalRunManager,
432
+ channels,
433
+ memories: memoryHostFor(),
422
434
  ...(agentHost
423
435
  ? {
424
436
  agentService: agentHost.service,
@@ -462,5 +474,6 @@ export async function bootstrapStageflowHost(options) {
462
474
  storeFilesystem,
463
475
  workspaceCatalog,
464
476
  ...(agentHost ? { agentHost } : {}),
477
+ operatorHostSlot,
465
478
  };
466
479
  }
@@ -141,7 +141,8 @@ function agentsOf(c) {
141
141
  }
142
142
  function agentsInput(c) {
143
143
  const agents = agentsOf(c);
144
- return agents ? { agents } : {};
144
+ const internalAgents = c.evalRunManager.visibleInternalAgents();
145
+ return { ...(agents ? { agents } : {}), ...(internalAgents.length > 0 ? { internalAgents } : {}) };
145
146
  }
146
147
  function engineCheck(c) {
147
148
  engineCheckStatus(c.engineStatus());
@@ -254,11 +255,30 @@ function parseDefinitionOrYaml(body) {
254
255
  throw bad(`"definition" must be an object`);
255
256
  return { definition: body.definition };
256
257
  }
258
+ function validateEvalId(input) {
259
+ if (isRecord(input.definition) && typeof input.definition.id === "string")
260
+ return input.definition.id;
261
+ if (typeof input.yaml !== "string")
262
+ return undefined;
263
+ const match = /^id:\s*["']?([A-Za-z0-9][A-Za-z0-9._-]{0,63})["']?\s*$/m.exec(input.yaml);
264
+ return match?.[1];
265
+ }
266
+ async function existingEvalFile(c, wire, id) {
267
+ try {
268
+ const located = await evalRootFor(c, wire, id);
269
+ return { projectRoot: located.projectRoot, absPath: located.ref.absPath };
270
+ }
271
+ catch (err) {
272
+ if (err instanceof EvalApiError && err.status === 404)
273
+ return undefined;
274
+ throw err;
275
+ }
276
+ }
257
277
  async function handleEvalValidate(c) {
258
278
  const body = await readBody(c);
259
279
  const input = parseDefinitionOrYaml(body);
260
- const projectRoot = await projectRootFor(c, wireFromBody(body));
261
- const manifest = await manifestForWrite(projectRoot);
280
+ const wire = wireFromBody(body);
281
+ let projectRoot = await projectRootFor(c, wire);
262
282
  const suppliedPath = optString(body, "path");
263
283
  const datasetCases = optDatasetCases(body);
264
284
  let evalAbs;
@@ -267,10 +287,18 @@ async function handleEvalValidate(c) {
267
287
  assertInsideProject(projectRoot, evalAbs, "eval path");
268
288
  }
269
289
  else {
270
- const rawId = isRecord(input.definition) ? input.definition.id : undefined;
271
- const dir = await resolveWriteDir(projectRoot, manifest, "evals");
272
- const fileName = typeof rawId === "string" && ID_RE.test(rawId) ? `${rawId}.eval.yaml` : "new.eval.yaml";
273
- evalAbs = path.join(dir.absDir, fileName);
290
+ const rawId = validateEvalId(input);
291
+ const located = rawId !== undefined && ID_RE.test(rawId) ? await existingEvalFile(c, wire, rawId) : undefined;
292
+ if (located) {
293
+ projectRoot = located.projectRoot;
294
+ evalAbs = located.absPath;
295
+ }
296
+ else {
297
+ const manifest = await manifestForWrite(projectRoot);
298
+ const dir = await resolveWriteDir(projectRoot, manifest, "evals");
299
+ const fileName = rawId !== undefined && ID_RE.test(rawId) ? `${rawId}.eval.yaml` : "new.eval.yaml";
300
+ evalAbs = path.join(dir.absDir, fileName);
301
+ }
274
302
  }
275
303
  let derived;
276
304
  if (input.yaml !== undefined) {
@@ -955,7 +983,7 @@ async function datasetDetailFor(c, projectRoot, id, absPath, evalId, query) {
955
983
  let inputSchema;
956
984
  let agent;
957
985
  if (useEval !== undefined) {
958
- if (useEval.loaded.file.target.kind === "agent") {
986
+ if (useEval.loaded.file.target.kind === "agent" || useEval.loaded.file.target.kind === "internal_agent") {
959
987
  agent = { mode: resolveConversation(useEval.loaded.file.conversation).mode };
960
988
  }
961
989
  else {
@@ -1014,7 +1042,8 @@ async function conversationModeOf(c, body) {
1014
1042
  return undefined;
1015
1043
  const { projectRoot, ref } = await evalRootFor(c, wireFromBody(body), evalId);
1016
1044
  const outcome = await loadEvalOutcome(ref.absPath, projectRoot);
1017
- return outcome.ok && outcome.value.file.target.kind === "agent"
1045
+ const kind = outcome.ok ? outcome.value.file.target.kind : undefined;
1046
+ return outcome.ok && (kind === "agent" || kind === "internal_agent")
1018
1047
  ? resolveConversation(outcome.value.file.conversation).mode
1019
1048
  : undefined;
1020
1049
  }
@@ -0,0 +1,5 @@
1
+ import type { IncomingMessage, ServerResponse } from "node:http";
2
+ import type { OperatorAgentHost } from "../operatorAgent/index.js";
3
+ type Json = (res: ServerResponse, status: number, body: unknown) => void;
4
+ export declare function handleGuideRoutes(req: IncomingMessage, method: string, pathname: string, host: OperatorAgentHost, res: ServerResponse, json: Json): Promise<boolean>;
5
+ export {};
@@ -0,0 +1,166 @@
1
+ import { abortGuideTurn, GuideError, guideAgentInfo, isGuideThreadRunning, streamGuideTurn, } from "../guide/chat.js";
2
+ import { createGuideThread, listGuideThreads, readGuideThread, setGuideThreadModel, } from "../guide/threadStore.js";
3
+ async function readBody(req) {
4
+ const chunks = [];
5
+ let size = 0;
6
+ for await (const chunk of req) {
7
+ const buffer = typeof chunk === "string" ? Buffer.from(chunk) : chunk;
8
+ size += buffer.length;
9
+ if (size > 1_500_000)
10
+ return { __tooLarge: true };
11
+ chunks.push(buffer);
12
+ }
13
+ if (chunks.length === 0)
14
+ return {};
15
+ try {
16
+ const parsed = JSON.parse(Buffer.concat(chunks).toString("utf8"));
17
+ return typeof parsed === "object" && parsed !== null && !Array.isArray(parsed)
18
+ ? parsed
19
+ : { __invalid: true };
20
+ }
21
+ catch {
22
+ return { __invalid: true };
23
+ }
24
+ }
25
+ function threadSummary(record) {
26
+ return { id: record.id, title: record.title, updatedAt: record.updatedAt };
27
+ }
28
+ function canWrite(res) {
29
+ return !res.writableEnded && !res.destroyed;
30
+ }
31
+ export async function handleGuideRoutes(req, method, pathname, host, res, json) {
32
+ const root = pathname === "/api/guide";
33
+ const threads = pathname === "/api/guide/threads";
34
+ const threadMatch = /^\/api\/guide\/threads\/([^/]+)$/.exec(pathname);
35
+ const messageMatch = /^\/api\/guide\/threads\/([^/]+)\/messages$/.exec(pathname);
36
+ const stopMatch = /^\/api\/guide\/threads\/([^/]+)\/stop$/.exec(pathname);
37
+ if (!root && !threads && !threadMatch && !messageMatch && !stopMatch)
38
+ return false;
39
+ if (root && method === "GET") {
40
+ json(res, 200, { agent: guideAgentInfo(host) });
41
+ return true;
42
+ }
43
+ if (threads && method === "GET") {
44
+ json(res, 200, {
45
+ threads: listGuideThreads().map((thread) => ({
46
+ ...thread,
47
+ status: isGuideThreadRunning(thread.id) ? "running" : "open",
48
+ })),
49
+ });
50
+ return true;
51
+ }
52
+ if (threads && method === "POST") {
53
+ const record = createGuideThread();
54
+ json(res, 201, { thread: threadSummary(record) });
55
+ return true;
56
+ }
57
+ if (stopMatch && method === "POST") {
58
+ const threadId = decodeURIComponent(stopMatch[1] ?? "");
59
+ const record = readGuideThread(threadId);
60
+ if (!record) {
61
+ json(res, 404, { code: "guide.not_found", message: "" });
62
+ return true;
63
+ }
64
+ json(res, 200, { ok: true, stopped: abortGuideTurn(threadId) });
65
+ return true;
66
+ }
67
+ if (threadMatch && method === "GET") {
68
+ const threadId = decodeURIComponent(threadMatch[1] ?? "");
69
+ const record = readGuideThread(threadId);
70
+ if (!record) {
71
+ json(res, 404, { code: "guide.not_found", message: "" });
72
+ return true;
73
+ }
74
+ json(res, 200, {
75
+ thread: threadSummary(record),
76
+ status: isGuideThreadRunning(record.id) ? "running" : "open",
77
+ messages: record.messages,
78
+ model: record.model ?? null,
79
+ });
80
+ return true;
81
+ }
82
+ if (threadMatch && method === "PATCH") {
83
+ const threadId = decodeURIComponent(threadMatch[1] ?? "");
84
+ const body = await readBody(req);
85
+ if (body.__tooLarge || body.__invalid) {
86
+ json(res, 400, { code: "guide.invalid", message: "" });
87
+ return true;
88
+ }
89
+ let record = readGuideThread(threadId);
90
+ if (!record) {
91
+ json(res, 404, { code: "guide.not_found", message: "" });
92
+ return true;
93
+ }
94
+ if ("model" in body) {
95
+ if (typeof body.model === "string") {
96
+ const next = setGuideThreadModel(threadId, body.model.trim() || null);
97
+ if (!next) {
98
+ json(res, 404, { code: "guide.not_found", message: "" });
99
+ return true;
100
+ }
101
+ record = next;
102
+ }
103
+ else if (body.model === null) {
104
+ const next = setGuideThreadModel(threadId, null);
105
+ if (!next) {
106
+ json(res, 404, { code: "guide.not_found", message: "" });
107
+ return true;
108
+ }
109
+ record = next;
110
+ }
111
+ else {
112
+ json(res, 400, { code: "guide.invalid", message: "" });
113
+ return true;
114
+ }
115
+ }
116
+ json(res, 200, { thread: threadSummary(record), model: record.model ?? null });
117
+ return true;
118
+ }
119
+ if (messageMatch && method === "POST") {
120
+ const threadId = decodeURIComponent(messageMatch[1] ?? "");
121
+ const body = await readBody(req);
122
+ if (body.__tooLarge || body.__invalid) {
123
+ json(res, 400, { code: "guide.invalid", message: "" });
124
+ return true;
125
+ }
126
+ const text = typeof body.text === "string" ? body.text : "";
127
+ let started = false;
128
+ try {
129
+ for await (const frame of streamGuideTurn({
130
+ host,
131
+ threadId,
132
+ text,
133
+ attachments: body.attachments,
134
+ model: typeof body.model === "string" ? body.model : undefined,
135
+ })) {
136
+ if (!canWrite(res))
137
+ continue;
138
+ if (!started) {
139
+ started = true;
140
+ res.writeHead(200, {
141
+ "Content-Type": "application/x-ndjson; charset=utf-8",
142
+ "Cache-Control": "no-store",
143
+ });
144
+ }
145
+ res.write(`${JSON.stringify(frame)}\n`);
146
+ }
147
+ }
148
+ catch (err) {
149
+ const code = err instanceof GuideError ? err.code : "guide.failed";
150
+ const status = err instanceof GuideError ? err.status : 500;
151
+ if (!started && canWrite(res))
152
+ json(res, status, { code, message: "" });
153
+ else if (started && canWrite(res))
154
+ res.write(`${JSON.stringify({ type: "error", code, message: "" })}\n`);
155
+ }
156
+ finally {
157
+ if (!res.headersSent && canWrite(res))
158
+ json(res, 200, { code: "guide.failed", message: "" });
159
+ else if (canWrite(res))
160
+ res.end();
161
+ }
162
+ return true;
163
+ }
164
+ json(res, 405, { code: "guide.invalid", message: "" });
165
+ return true;
166
+ }
@@ -1,6 +1,8 @@
1
1
  import type { StagePort } from "../agent/port.js";
2
2
  import { type ProviderAuthContext } from "../agent/providerAuth.js";
3
+ import type { ChannelService } from "../channels/service.js";
3
4
  import type { EvalRunManager } from "../evals/manager.js";
5
+ import type { MemoryHost } from "../memory/host.js";
4
6
  import { type LiveViewRoutesOptions } from "./liveViewRoutes.js";
5
7
  import { WorkshopChatSessionRegistry } from "../workshop/chatTurn.js";
6
8
  import { type AgentPort } from "../operatorAgent/index.js";
@@ -70,9 +72,17 @@ export type OperatorRouteDeps = {
70
72
  agentConversationBackend?: ConversationBackend;
71
73
  /** Shared with MCP when set by bootstrap. */
72
74
  agentHost?: AgentHostContext;
75
+ /** Bootstrap fills this once the operator host exists, so evals can run against it. */
76
+ operatorHostSlot?: {
77
+ current?: import("../operatorAgent/types.js").OperatorAgentHost;
78
+ };
73
79
  evalRunManager?: EvalRunManager;
74
80
  /** Wired by the eval manager; until then the internal eval callback answers 404. */
75
81
  evalServices?: EvalServices;
82
+ /** Host connections. Guide and MCP use the same service the console does. */
83
+ channels?: ChannelService;
84
+ /** Host memories. Guide and MCP use the same host the console does. */
85
+ memories?: MemoryHost;
76
86
  };
77
87
  /**
78
88
  * The full operator-console route surface: REST API (runs, stages,
@@ -8,6 +8,7 @@ import { mapProviderAuthError } from "../agent/providerInspect.js";
8
8
  import { handleProviderRoutes } from "./providerRoutes.js";
9
9
  import { handleProjectMcpRoutes } from "./projectMcpRoutes.js";
10
10
  import { handleTriggerRoutes } from "./triggerRoutes.js";
11
+ import { guideWriteRoot } from "../guide/writeRoot.js";
11
12
  import { handleEvalRoutes } from "./evalRoutes.js";
12
13
  import { defaultLoadJudgePrices } from "../evals/engine/promptfoo/judgeServices.js";
13
14
  import { engineStatus as promptfooEngineStatus } from "../evals/engine/promptfoo/status.js";
@@ -62,6 +63,8 @@ import { buildModelsResponse } from "../models/response.js";
62
63
  import { createAgentHostContext } from "../agents/hostContext.js";
63
64
  import { AgentScheduleSource, agentScheduleTickIntervalMsFromEnv, } from "../agents/scheduleSource.js";
64
65
  import { handleAgentAuthorRoutes } from "./agentAuthorRoutes.js";
66
+ import { handleGuideRoutes } from "./guideRoutes.js";
67
+ import { handleInternalAgentRoutes } from "./internalAgentRoutes.js";
65
68
  import { handleAgentRoutes } from "./agentRoutes.js";
66
69
  import { handleChannelRoutes } from "./channelRoutes.js";
67
70
  import { handleEvalInternalRoutes, isEvalInternalPath } from "./evalInternalRoutes.js";
@@ -217,7 +220,27 @@ export function createOperatorRoutes(deps) {
217
220
  resolveAgentPort({
218
221
  cwd,
219
222
  projectRoot: cwd,
223
+ guideDeps: {
224
+ manager,
225
+ store,
226
+ cwd,
227
+ agentDir,
228
+ projectRoot: guideWriteRoot(rootDir),
229
+ ...(providerAuthContext ? { providerAuthContext } : {}),
230
+ ...(deps.evalRunManager ? { evalRunManager: deps.evalRunManager } : {}),
231
+ ...(deps.channels ? { channels: deps.channels } : {}),
232
+ ...(deps.memories ? { memories: deps.memories } : {}),
233
+ ...(agentHost
234
+ ? {
235
+ agentService: agentHost.service,
236
+ agentChat: agentHost.chat,
237
+ agentConversationBackend: agentHost.backend,
238
+ }
239
+ : {}),
240
+ },
220
241
  });
242
+ if (deps.operatorHostSlot)
243
+ deps.operatorHostSlot.current = operatorHost;
221
244
  const workshopChatRegistry = deps.workshopChatRegistry ?? new WorkshopChatSessionRegistry(operatorHost);
222
245
  const workshopSessionStoreRoot = () => resolveWorkshopSessionStoreRoot();
223
246
  const workshopBuildStoreRoot = () => resolveWorkshopBuildStoreRoot();
@@ -263,6 +286,12 @@ export function createOperatorRoutes(deps) {
263
286
  if (await handleAgentAuthorRoutes(req, method, pathname, cwd, operatorHost, res, json))
264
287
  return true;
265
288
  }
289
+ if (pathname === "/api/guide" || pathname.startsWith("/api/guide/")) {
290
+ if (await handleGuideRoutes(req, method, pathname, operatorHost, res, json))
291
+ return true;
292
+ }
293
+ if (handleInternalAgentRoutes(method, pathname, operatorHost, res, json))
294
+ return true;
266
295
  if (PublicWebChat.owns(pathname)) {
267
296
  if (!agentHost) {
268
297
  json(res, 503, { code: "web_chat.unavailable" });
@@ -1064,7 +1093,9 @@ export function createOperatorRoutes(deps) {
1064
1093
  await readJsonBody(req);
1065
1094
  const runId = decodeURIComponent(retryMatch[1] ?? "");
1066
1095
  const stageId = decodeURIComponent(retryMatch[2] ?? "");
1067
- const result = await manager.retryStage(runId, stageId);
1096
+ const result = await manager.retryStage(runId, stageId, {
1097
+ awaitRoot: false,
1098
+ });
1068
1099
  if (!result.ok) {
1069
1100
  json(res, result.status ?? 500, mapRetryStageFailure(result));
1070
1101
  return true;
@@ -3178,8 +3209,11 @@ export async function startUiServer(options) {
3178
3209
  ? { workshopOperatorHost: options.workshopOperatorHost }
3179
3210
  : {}),
3180
3211
  ...(boot.agentHost ? { agentHost: boot.agentHost } : {}),
3212
+ ...(boot.operatorHostSlot ? { operatorHostSlot: boot.operatorHostSlot } : {}),
3181
3213
  ...(boot.evalRunManager ? { evalRunManager: boot.evalRunManager } : {}),
3182
3214
  ...(boot.evalServices ? { evalServices: boot.evalServices } : {}),
3215
+ ...(boot.channels ? { channels: boot.channels } : {}),
3216
+ ...(boot.memories ? { memories: boot.memories } : {}),
3183
3217
  ...(options.agentConversationBackend
3184
3218
  ? { agentConversationBackend: options.agentConversationBackend }
3185
3219
  : {}),
@@ -0,0 +1,6 @@
1
+ import type { ServerResponse } from "node:http";
2
+ import type { OperatorAgentHost } from "../operatorAgent/index.js";
3
+ type Json = (res: ServerResponse, status: number, body: unknown) => void;
4
+ export declare const INTERNAL_AGENTS_PATH = "/api/internal-agents";
5
+ export declare function handleInternalAgentRoutes(method: string, pathname: string, host: OperatorAgentHost, res: ServerResponse, json: Json, env?: NodeJS.ProcessEnv): boolean;
6
+ export {};