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.
- package/README.md +12 -3
- package/dist/agent/activity.d.ts +18 -0
- package/dist/agent/claudeAdapter.js +7 -0
- package/dist/agent/claudeTools.d.ts +27 -18
- package/dist/agent/claudeTools.js +54 -15
- package/dist/agent/compactionEvents.d.ts +34 -0
- package/dist/agent/compactionEvents.js +37 -0
- package/dist/agent/openRouterRouting.d.ts +7 -0
- package/dist/agent/openRouterRouting.js +23 -0
- package/dist/agent/piAdapter.d.ts +6 -0
- package/dist/agent/piAdapter.js +128 -27
- package/dist/agent/piSettings.d.ts +7 -0
- package/dist/agent/piSettings.js +9 -0
- package/dist/agent/sandboxPiTools.d.ts +3 -1
- package/dist/agent/sandboxPiTools.js +8 -2
- package/dist/agent/stageTurnDriver.d.ts +11 -2
- package/dist/agent/stageTurnDriver.js +45 -4
- package/dist/agent/toolOutputBudget.d.ts +15 -1
- package/dist/agent/toolOutputBudget.js +18 -0
- package/dist/agent/toolOutputBudgetExtension.d.ts +2 -0
- package/dist/agent/toolOutputBudgetExtension.js +40 -3
- package/dist/agents/authorChat.d.ts +1 -0
- package/dist/agents/authorChat.js +7 -0
- package/dist/agents/authorSessionStore.d.ts +3 -0
- package/dist/agents/authorSessionStore.js +17 -2
- package/dist/agents/hostContext.d.ts +1 -1
- package/dist/agents/runtime/piRuntime.d.ts +5 -1
- package/dist/agents/runtime/piRuntime.js +46 -12
- package/dist/agents/service.js +3 -2
- package/dist/agents/sessions.js +3 -1
- package/dist/compaction/directives.d.ts +18 -0
- package/dist/compaction/directives.js +119 -0
- package/dist/compaction/extension.d.ts +20 -0
- package/dist/compaction/extension.js +78 -0
- package/dist/compaction/mask.d.ts +18 -0
- package/dist/compaction/mask.js +155 -0
- package/dist/compaction/pin.d.ts +21 -0
- package/dist/compaction/pin.js +270 -0
- package/dist/compaction/scrub.d.ts +7 -0
- package/dist/compaction/scrub.js +26 -0
- package/dist/compaction/sessionWiring.d.ts +22 -0
- package/dist/compaction/sessionWiring.js +26 -0
- package/dist/compaction/summarize.d.ts +79 -0
- package/dist/compaction/summarize.js +171 -0
- package/dist/compaction/toolPolicy.d.ts +3 -0
- package/dist/compaction/toolPolicy.js +33 -0
- package/dist/compaction/types.d.ts +45 -0
- package/dist/compaction/types.js +7 -0
- package/dist/compaction/workingState.d.ts +56 -0
- package/dist/compaction/workingState.js +198 -0
- package/dist/config/createPipeline.js +2 -0
- package/dist/config/createTrigger.js +7 -1
- package/dist/config/ensureCatalogScanRoot.d.ts +2 -0
- package/dist/config/ensureCatalogScanRoot.js +6 -0
- package/dist/config/evalCatalog.js +30 -2
- package/dist/config/githubTriggerAction.d.ts +8 -0
- package/dist/config/githubTriggerAction.js +29 -0
- package/dist/config/hostConfig.js +2 -0
- package/dist/config/loadEval.js +21 -3
- package/dist/config/pipelineNeeds.d.ts +2 -0
- package/dist/config/pipelineNeeds.js +16 -3
- package/dist/config/pipelineRoute.js +5 -4
- package/dist/config/validateCatalog.d.ts +1 -1
- package/dist/config/validateCatalog.js +12 -0
- package/dist/config/validateEval.js +43 -2
- package/dist/config/writeEval.js +2 -2
- package/dist/envelope/assertEmittedArtifacts.d.ts +12 -0
- package/dist/envelope/assertEmittedArtifacts.js +43 -0
- package/dist/envelope/preEmitChecks.d.ts +3 -0
- package/dist/evals/constants.d.ts +3 -1
- package/dist/evals/constants.js +3 -1
- package/dist/evals/engine/FakeEngine.d.ts +1 -1
- package/dist/evals/engine/FakeEngine.js +2 -1
- package/dist/evals/engine/promptfoo/PromptfooEngine.d.ts +1 -1
- package/dist/evals/engine/promptfoo/PromptfooEngine.js +2 -1
- package/dist/evals/engine/promptfoo/generate.d.ts +1 -1
- package/dist/evals/engine/promptfoo/generate.js +11 -8
- package/dist/evals/engine/promptfoo/rubricPrompt.d.ts +1 -1
- package/dist/evals/engine/promptfoo/rubricPrompt.js +5 -3
- package/dist/evals/manager.d.ts +13 -0
- package/dist/evals/manager.js +10 -2
- package/dist/evals/plan.d.ts +8 -1
- package/dist/evals/plan.js +28 -9
- package/dist/evals/planInternalAgent.d.ts +19 -0
- package/dist/evals/planInternalAgent.js +205 -0
- package/dist/evals/read/api.d.ts +12 -0
- package/dist/evals/read/api.js +5 -0
- package/dist/evals/read/list.js +10 -1
- package/dist/evals/read/runs.d.ts +5 -0
- package/dist/evals/read/runs.js +7 -1
- package/dist/evals/runner/caseRunner.d.ts +2 -1
- package/dist/evals/runner/caseRunner.js +16 -5
- package/dist/evals/runner/internalAgentCaseRunner.d.ts +6 -0
- package/dist/evals/runner/internalAgentCaseRunner.js +250 -0
- package/dist/evals/snapshot.d.ts +10 -2
- package/dist/evals/snapshot.js +8 -3
- package/dist/evals/types.d.ts +12 -2
- package/dist/evals/types.js +4 -1
- package/dist/guide/cardContract.d.ts +133 -0
- package/dist/guide/cardContract.js +156 -0
- package/dist/guide/chat.d.ts +45 -0
- package/dist/guide/chat.js +378 -0
- package/dist/guide/knowledge/index.d.ts +14 -0
- package/dist/guide/knowledge/index.js +109 -0
- package/dist/guide/knowledge/topics/agents.d.ts +2 -0
- package/dist/guide/knowledge/topics/agents.js +58 -0
- package/dist/guide/knowledge/topics/bestPractices.d.ts +2 -0
- package/dist/guide/knowledge/topics/bestPractices.js +67 -0
- package/dist/guide/knowledge/topics/connections.d.ts +2 -0
- package/dist/guide/knowledge/topics/connections.js +66 -0
- package/dist/guide/knowledge/topics/consoleMap.d.ts +2 -0
- package/dist/guide/knowledge/topics/consoleMap.js +55 -0
- package/dist/guide/knowledge/topics/evals.d.ts +2 -0
- package/dist/guide/knowledge/topics/evals.js +72 -0
- package/dist/guide/knowledge/topics/limitations.d.ts +2 -0
- package/dist/guide/knowledge/topics/limitations.js +84 -0
- package/dist/guide/knowledge/topics/mcpSkillsBrowser.d.ts +2 -0
- package/dist/guide/knowledge/topics/mcpSkillsBrowser.js +57 -0
- package/dist/guide/knowledge/topics/memories.d.ts +2 -0
- package/dist/guide/knowledge/topics/memories.js +63 -0
- package/dist/guide/knowledge/topics/modelsAndProviders.d.ts +2 -0
- package/dist/guide/knowledge/topics/modelsAndProviders.js +56 -0
- package/dist/guide/knowledge/topics/overview.d.ts +2 -0
- package/dist/guide/knowledge/topics/overview.js +56 -0
- package/dist/guide/knowledge/topics/pipelines.d.ts +2 -0
- package/dist/guide/knowledge/topics/pipelines.js +93 -0
- package/dist/guide/knowledge/topics/stages.d.ts +2 -0
- package/dist/guide/knowledge/topics/stages.js +54 -0
- package/dist/guide/knowledge/topics/tasks.d.ts +2 -0
- package/dist/guide/knowledge/topics/tasks.js +52 -0
- package/dist/guide/knowledge/topics/triggers.d.ts +2 -0
- package/dist/guide/knowledge/topics/triggers.js +68 -0
- package/dist/guide/knowledge/topics/troubleshooting.d.ts +2 -0
- package/dist/guide/knowledge/topics/troubleshooting.js +85 -0
- package/dist/guide/knowledgeTools.d.ts +2 -0
- package/dist/guide/knowledgeTools.js +56 -0
- package/dist/guide/showUi.d.ts +6 -0
- package/dist/guide/showUi.js +546 -0
- package/dist/guide/threadStore.d.ts +48 -0
- package/dist/guide/threadStore.js +189 -0
- package/dist/guide/writeRoot.d.ts +11 -0
- package/dist/guide/writeRoot.js +70 -0
- package/dist/hosted/translate.js +2 -0
- package/dist/mcp/agentTools.js +12 -0
- package/dist/mcp/catalogTools.js +18 -20
- package/dist/mcp/catalogWriteTools.d.ts +8 -0
- package/dist/mcp/catalogWriteTools.js +225 -0
- package/dist/mcp/connectionTools.d.ts +3 -0
- package/dist/mcp/connectionTools.js +85 -0
- package/dist/mcp/controlTools.js +34 -1
- package/dist/mcp/deps.d.ts +9 -0
- package/dist/mcp/evalTools.js +684 -21
- package/dist/mcp/memoryHostTools.d.ts +3 -0
- package/dist/mcp/memoryHostTools.js +72 -0
- package/dist/mcp/pipelineAuthorTools.js +14 -1
- package/dist/mcp/server.js +5 -0
- package/dist/mcp/tools.js +6 -0
- package/dist/mcp/triggerTools.js +77 -31
- package/dist/operatorAgent/evalGate.d.ts +22 -0
- package/dist/operatorAgent/evalGate.js +77 -0
- package/dist/operatorAgent/fakeHost.js +10 -2
- package/dist/operatorAgent/host.js +18 -2
- package/dist/operatorAgent/index.d.ts +1 -0
- package/dist/operatorAgent/index.js +1 -0
- package/dist/operatorAgent/internalAgents.d.ts +11 -0
- package/dist/operatorAgent/internalAgents.js +13 -0
- package/dist/operatorAgent/piModel.d.ts +5 -1
- package/dist/operatorAgent/piModel.js +15 -10
- package/dist/operatorAgent/profiles/agentAuthor.js +66 -22
- package/dist/operatorAgent/profiles/agentAuthorPlaybook.d.ts +1 -1
- package/dist/operatorAgent/profiles/agentAuthorPlaybook.js +1 -1
- package/dist/operatorAgent/profiles/guideConfirm.d.ts +21 -0
- package/dist/operatorAgent/profiles/guideConfirm.js +100 -0
- package/dist/operatorAgent/profiles/guideTools.d.ts +7 -0
- package/dist/operatorAgent/profiles/guideTools.js +123 -0
- package/dist/operatorAgent/profiles/stageflowGuide.d.ts +7 -0
- package/dist/operatorAgent/profiles/stageflowGuide.js +132 -0
- package/dist/operatorAgent/profiles/workshopAuthor.js +23 -0
- package/dist/operatorAgent/profiles/workshopAuthorPlaybook.d.ts +1 -1
- package/dist/operatorAgent/profiles/workshopAuthorPlaybook.js +9 -1
- package/dist/operatorAgent/profiles/workshopAuthorTools.d.ts +2 -0
- package/dist/operatorAgent/profiles/workshopAuthorTools.js +197 -9
- package/dist/operatorAgent/types.d.ts +23 -0
- package/dist/package-meta.d.ts +1 -1
- package/dist/package-meta.js +1 -1
- package/dist/runstore/retention.d.ts +2 -1
- package/dist/runstore/retention.js +3 -7
- package/dist/runstore/runStatusClock.d.ts +17 -0
- package/dist/runstore/runStatusClock.js +19 -0
- package/dist/runstore/sqlite/SqliteRunStore.d.ts +1 -0
- package/dist/runstore/sqlite/SqliteRunStore.js +45 -45
- package/dist/runstore/workspaceLayout.js +6 -1
- package/dist/runtime/artifactDiskInspect.d.ts +14 -0
- package/dist/runtime/artifactDiskInspect.js +52 -0
- package/dist/runtime/artifactPath.d.ts +24 -0
- package/dist/runtime/artifactPath.js +84 -0
- package/dist/runtime/completionCheckRunner.js +15 -43
- package/dist/runtime/githubPollSource.d.ts +22 -4
- package/dist/runtime/githubPollSource.js +93 -8
- package/dist/runtime/priorArtifactGrants.d.ts +8 -0
- package/dist/runtime/priorArtifactGrants.js +105 -0
- package/dist/runtime/runActionEligibility.d.ts +46 -0
- package/dist/runtime/runActionEligibility.js +123 -0
- package/dist/runtime/runManager.d.ts +4 -1
- package/dist/runtime/runManager.js +52 -10
- package/dist/runtime/runRetryCoordinator.d.ts +2 -14
- package/dist/runtime/runRetryCoordinator.js +3 -67
- package/dist/runtime/sandboxContainer.d.ts +7 -0
- package/dist/runtime/sandboxContainer.js +48 -6
- package/dist/runtime/sandboxDesk.d.ts +2 -1
- package/dist/runtime/sandboxDesk.js +11 -12
- package/dist/runtime/stageEnvironment.js +1 -0
- package/dist/runtime/stageRoots.d.ts +12 -0
- package/dist/runtime/stageSandbox.d.ts +2 -1
- package/dist/runtime/stageSandbox.js +18 -2
- package/dist/runtime/stageWorker.js +20 -0
- package/dist/server/agentAuthorRoutes.js +12 -3
- package/dist/server/bootstrap.d.ts +5 -0
- package/dist/server/bootstrap.js +14 -1
- package/dist/server/evalRoutes.js +38 -9
- package/dist/server/guideRoutes.d.ts +5 -0
- package/dist/server/guideRoutes.js +166 -0
- package/dist/server/http.d.ts +10 -0
- package/dist/server/http.js +35 -1
- package/dist/server/internalAgentRoutes.d.ts +6 -0
- package/dist/server/internalAgentRoutes.js +12 -0
- package/dist/server/mcpHost.js +2 -0
- package/dist/toolkit/meta.d.ts +1 -1
- package/dist/toolkit/meta.js +39 -1
- package/dist/toolkit/profiles.d.ts +5 -0
- package/dist/toolkit/profiles.js +12 -0
- package/dist/tools/askOperator.js +2 -1
- package/dist/tools/emitStageEnvelope.d.ts +17 -16
- package/dist/tools/emitStageEnvelope.js +46 -32
- package/dist/tools/stageToolNames.d.ts +4 -0
- package/dist/tools/stageToolNames.js +4 -0
- package/dist/tools/workingState.d.ts +40 -0
- package/dist/tools/workingState.js +108 -0
- package/dist/tools/writeStageArtifact.d.ts +0 -9
- package/dist/tools/writeStageArtifact.js +2 -1
- package/dist/ui/assets/{MarkdownText-BTrOqu5J.js → MarkdownText-S5C_vemc.js} +2 -2
- package/dist/ui/assets/adapters-C0l4ruiR.js +17 -0
- package/dist/ui/assets/chat-CjnsmvqR.js +2 -0
- package/dist/ui/assets/chat-DFDd4UjS.css +2 -0
- package/dist/ui/assets/{main-CHlmTNJe.css → main-Del1GeLf.css} +1 -1
- package/dist/ui/assets/main-_yXVqcW9.js +277 -0
- package/dist/ui/chat.html +3 -4
- package/dist/ui/index.html +3 -4
- package/dist/workshop/chatTurn.js +1 -1
- package/dist/workshop/workshopPin.d.ts +3 -3
- package/dist/workshop/workshopPin.js +16 -15
- package/examples/compaction-stress/README.md +30 -0
- package/examples/compaction-stress/check-run.mjs +53 -0
- package/examples/compaction-stress/collect-evidence.yaml +60 -0
- package/examples/compaction-stress/compaction-stress.pipeline.yaml +141 -0
- package/examples/compaction-stress/compaction-stress.task.yaml +15 -0
- package/examples/compaction-stress/generate-evidence.mjs +110 -0
- package/examples/compaction-stress/root-cause.yaml +26 -0
- package/examples/compaction-stress/stageflow.yaml +9 -0
- package/examples/compaction-stress/write-postmortem.yaml +40 -0
- package/examples/evals/README.md +18 -0
- package/examples/evals/guide-behavior.dataset.jsonl +15 -0
- package/examples/evals/guide-behavior.eval.yaml +35 -0
- package/examples/evals/guide-depth.dataset.jsonl +35 -0
- package/examples/evals/guide-depth.eval.yaml +169 -0
- package/examples/memory/evals/guide-behavior.dataset.jsonl +15 -0
- package/examples/memory/evals/guide-behavior.eval.yaml +35 -0
- package/examples/memory/evals/guide-depth.dataset.jsonl +35 -0
- package/examples/memory/evals/guide-depth.eval.yaml +169 -0
- package/package.json +1 -1
- package/dist/ui/assets/AssistantRuntimeProvider-qIX1xNoH.js +0 -9
- package/dist/ui/assets/ReadonlyStore-BfXqHykm.js +0 -6
- package/dist/ui/assets/chat-Df_wCpak.js +0 -5
- package/dist/ui/assets/chat-P7KQznHm.css +0 -2
- 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
|
|
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:
|
|
47
|
-
shape: "
|
|
43
|
+
hostPath: grant.hostPath,
|
|
44
|
+
containerPath: grant.containerPath,
|
|
45
|
+
shape: grant.kind === "directory" ? "directory" : "file",
|
|
48
46
|
copyIn: true,
|
|
49
|
-
copyOut:
|
|
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,
|
|
@@ -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>;
|
package/dist/server/bootstrap.js
CHANGED
|
@@ -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
|
|
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
|
-
|
|
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
|
|
261
|
-
|
|
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 =
|
|
271
|
-
const
|
|
272
|
-
|
|
273
|
-
|
|
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
|
-
|
|
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
|
+
}
|
package/dist/server/http.d.ts
CHANGED
|
@@ -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,
|
package/dist/server/http.js
CHANGED
|
@@ -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 {};
|