stageflow 0.36.0 → 0.40.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 +61 -26
- package/dist/agent/claudeAdapter.js +21 -1
- package/dist/agent/claudeTools.d.ts +13 -0
- package/dist/agent/claudeTools.js +98 -0
- package/dist/agent/piAdapter.d.ts +9 -1
- package/dist/agent/piAdapter.js +59 -18
- package/dist/agent/piIsolatedMcp.js +14 -2
- package/dist/agent/piIsolatedMcpProbe.d.ts +5 -1
- package/dist/agent/piIsolatedMcpProbe.js +16 -30
- package/dist/agent/port.d.ts +5 -0
- package/dist/agent/sandboxPiTools.d.ts +99 -0
- package/dist/agent/sandboxPiTools.js +109 -0
- package/dist/agents/agentId.d.ts +8 -0
- package/dist/agents/agentId.js +27 -0
- package/dist/agents/approvalBroker.d.ts +16 -0
- package/dist/agents/approvalBroker.js +45 -0
- package/dist/agents/authorChat.d.ts +19 -0
- package/dist/agents/authorChat.js +63 -0
- package/dist/agents/chatTurn.d.ts +23 -0
- package/dist/agents/chatTurn.js +77 -0
- package/dist/agents/communications/agentmail.d.ts +19 -0
- package/dist/agents/communications/agentmail.js +46 -0
- package/dist/agents/communications/agentmailListener.d.ts +59 -0
- package/dist/agents/communications/agentmailListener.js +183 -0
- package/dist/agents/communications/allowlist.d.ts +10 -0
- package/dist/agents/communications/allowlist.js +36 -0
- package/dist/agents/communications/channelConnections.d.ts +3 -0
- package/dist/agents/communications/channelConnections.js +51 -0
- package/dist/agents/communications/delivery.d.ts +53 -0
- package/dist/agents/communications/delivery.js +142 -0
- package/dist/agents/communications/email.d.ts +26 -0
- package/dist/agents/communications/email.js +20 -0
- package/dist/agents/communications/identity.d.ts +13 -0
- package/dist/agents/communications/identity.js +18 -0
- package/dist/agents/communications/imessageListener.d.ts +41 -0
- package/dist/agents/communications/imessageListener.js +92 -0
- package/dist/agents/communications/inbound.d.ts +63 -0
- package/dist/agents/communications/inbound.js +143 -0
- package/dist/agents/communications/listener.d.ts +36 -0
- package/dist/agents/communications/listener.js +38 -0
- package/dist/agents/communications/photon.d.ts +19 -0
- package/dist/agents/communications/photon.js +38 -0
- package/dist/agents/communications/port.d.ts +27 -0
- package/dist/agents/communications/port.js +6 -0
- package/dist/agents/communications/slack.d.ts +28 -0
- package/dist/agents/communications/slack.js +65 -0
- package/dist/agents/communications/supervisor.d.ts +36 -0
- package/dist/agents/communications/supervisor.js +96 -0
- package/dist/agents/communications/telegram.d.ts +19 -0
- package/dist/agents/communications/telegram.js +52 -0
- package/dist/agents/definitionSummary.d.ts +13 -0
- package/dist/agents/definitionSummary.js +91 -0
- package/dist/agents/delegate.d.ts +3 -0
- package/dist/agents/delegate.js +8 -0
- package/dist/agents/errors.d.ts +10 -0
- package/dist/agents/errors.js +32 -0
- package/dist/agents/guardrails.d.ts +24 -0
- package/dist/agents/guardrails.js +39 -0
- package/dist/agents/historyFit.d.ts +10 -0
- package/dist/agents/historyFit.js +26 -0
- package/dist/agents/hostContext.d.ts +54 -0
- package/dist/agents/hostContext.js +156 -0
- package/dist/agents/ledgers.d.ts +29 -0
- package/dist/agents/ledgers.js +31 -0
- package/dist/agents/lineDiff.d.ts +12 -0
- package/dist/agents/lineDiff.js +46 -0
- package/dist/agents/ndjson.d.ts +9 -0
- package/dist/agents/ndjson.js +47 -0
- package/dist/agents/otlpExport.d.ts +9 -0
- package/dist/agents/otlpExport.js +58 -0
- package/dist/agents/otlpSink.d.ts +7 -0
- package/dist/agents/otlpSink.js +23 -0
- package/dist/agents/policy.d.ts +31 -0
- package/dist/agents/policy.js +84 -0
- package/dist/agents/projectRoot.d.ts +5 -0
- package/dist/agents/projectRoot.js +15 -0
- package/dist/agents/runtime/piRuntime.d.ts +52 -0
- package/dist/agents/runtime/piRuntime.js +474 -0
- package/dist/agents/runtime/types.d.ts +77 -0
- package/dist/agents/runtime/types.js +26 -0
- package/dist/agents/sandbox.d.ts +17 -0
- package/dist/agents/sandbox.js +10 -0
- package/dist/agents/scheduleSource.d.ts +32 -0
- package/dist/agents/scheduleSource.js +100 -0
- package/dist/agents/service.d.ts +298 -0
- package/dist/agents/service.js +1105 -0
- package/dist/agents/sessions.d.ts +38 -0
- package/dist/agents/sessions.js +321 -0
- package/dist/agents/store.d.ts +277 -0
- package/dist/agents/store.js +643 -0
- package/dist/agents/trace.d.ts +27 -0
- package/dist/agents/trace.js +29 -0
- package/dist/agents/turnLifecycle.d.ts +72 -0
- package/dist/agents/turnLifecycle.js +157 -0
- package/dist/agents/webChat/publicChat.d.ts +36 -0
- package/dist/agents/webChat/publicChat.js +290 -0
- package/dist/agents/webChat/rateLimit.d.ts +15 -0
- package/dist/agents/webChat/rateLimit.js +33 -0
- package/dist/agents/webChat/slug.d.ts +2 -0
- package/dist/agents/webChat/slug.js +9 -0
- package/dist/channels/providers/agentmail.js +14 -1
- package/dist/channels/providers/photonImessage.js +36 -0
- package/dist/channels/providers/slack.js +2 -1
- package/dist/channels/providers/telegram.js +2 -1
- package/dist/channels/types.d.ts +27 -0
- package/dist/cli/agentsCommand.d.ts +14 -0
- package/dist/cli/agentsCommand.js +291 -0
- package/dist/cli.js +9 -0
- package/dist/config/browseCatalog.js +4 -11
- package/dist/config/draftPackage.d.ts +1 -0
- package/dist/config/draftPackage.js +4 -0
- package/dist/config/hostConfig.js +9 -0
- package/dist/config/loadAgent.d.ts +266 -0
- package/dist/config/loadAgent.js +374 -0
- package/dist/config/loadPipeline.js +5 -2
- package/dist/config/loadTask.js +34 -1
- package/dist/config/mcpHostCatalog.d.ts +50 -0
- package/dist/config/mcpHostCatalog.js +405 -0
- package/dist/config/mcpOAuth.d.ts +37 -0
- package/dist/config/mcpOAuth.js +263 -0
- package/dist/config/mcpRedaction.d.ts +42 -0
- package/dist/config/mcpRedaction.js +314 -0
- package/dist/config/mcpToolCache.d.ts +20 -0
- package/dist/config/mcpToolCache.js +43 -0
- package/dist/config/mergePipelineIncludes.d.ts +2 -0
- package/dist/config/mergePipelineIncludes.js +25 -0
- package/dist/config/resolveStageMcpServers.d.ts +35 -3
- package/dist/config/resolveStageMcpServers.js +124 -9
- package/dist/config/validateCatalog.d.ts +1 -1
- package/dist/config/validateCatalog.js +22 -1
- package/dist/mcp/agentTools.d.ts +8 -0
- package/dist/mcp/agentTools.js +132 -0
- package/dist/mcp/catalogTools.js +17 -10
- package/dist/mcp/deps.d.ts +6 -0
- package/dist/mcp/pipelineAuthorSupport.d.ts +19 -0
- package/dist/mcp/pipelineAuthorSupport.js +10 -0
- package/dist/mcp/pipelineAuthorTools.d.ts +8 -0
- package/dist/mcp/pipelineAuthorTools.js +109 -0
- package/dist/mcp/server.js +5 -0
- package/dist/mcp/tools.js +4 -0
- package/dist/mcp/triggerTools.js +32 -0
- package/dist/memory/access.d.ts +36 -0
- package/dist/memory/access.js +116 -0
- package/dist/memory/agentIssues.d.ts +3 -0
- package/dist/memory/agentIssues.js +23 -0
- package/dist/memory/bashDeny.d.ts +6 -0
- package/dist/memory/bashDeny.js +35 -0
- package/dist/memory/host.d.ts +51 -0
- package/dist/memory/host.js +394 -0
- package/dist/memory/ids.d.ts +15 -0
- package/dist/memory/ids.js +31 -0
- package/dist/memory/worker.d.ts +1 -0
- package/dist/memory/worker.js +84 -0
- package/dist/models/catalog.d.ts +113 -0
- package/dist/models/catalog.js +238 -0
- package/dist/models/response.d.ts +29 -0
- package/dist/models/response.js +25 -0
- package/dist/operatorAgent/agentAuthorContext.d.ts +17 -0
- package/dist/operatorAgent/agentAuthorContext.js +32 -0
- package/dist/operatorAgent/fakeHost.js +2 -0
- package/dist/operatorAgent/host.js +6 -3
- package/dist/operatorAgent/index.d.ts +4 -0
- package/dist/operatorAgent/index.js +4 -0
- package/dist/operatorAgent/piModel.js +2 -0
- package/dist/operatorAgent/profiles/agentAuthor.d.ts +11 -0
- package/dist/operatorAgent/profiles/agentAuthor.js +192 -0
- package/dist/operatorAgent/profiles/agentAuthorPlaybook.d.ts +1 -0
- package/dist/operatorAgent/profiles/agentAuthorPlaybook.js +29 -0
- package/dist/operatorAgent/profiles/workshopAuthor.js +2 -2
- package/dist/operatorAgent/profiles/workshopAuthorTools.js +3 -3
- package/dist/operatorAgent/proposals.d.ts +1 -0
- package/dist/operatorAgent/proposals.js +23 -2
- package/dist/package-meta.d.ts +1 -1
- package/dist/package-meta.js +1 -1
- package/dist/preflight/pipelinePreflight.js +1 -0
- package/dist/runstore/createStore.d.ts +2 -0
- package/dist/runstore/createStore.js +8 -0
- package/dist/runstore/overviewSummary.d.ts +56 -0
- package/dist/runstore/overviewSummary.js +134 -0
- package/dist/runstore/port.d.ts +3 -0
- package/dist/runstore/sqlite/SqliteRunStore.d.ts +2 -0
- package/dist/runstore/sqlite/SqliteRunStore.js +18 -0
- package/dist/runstore/sqlite/migrations/013-agents.d.ts +12 -0
- package/dist/runstore/sqlite/migrations/013-agents.js +156 -0
- package/dist/runstore/sqlite/migrations/014-agent-deliveries.d.ts +11 -0
- package/dist/runstore/sqlite/migrations/014-agent-deliveries.js +32 -0
- package/dist/runstore/sqlite/migrations/index.js +4 -0
- package/dist/runtime/gitCheckoutCapability.d.ts +1 -0
- package/dist/runtime/gitCheckoutCapability.js +1 -1
- package/dist/runtime/gitWorktreeCheckout.d.ts +22 -0
- package/dist/runtime/gitWorktreeCheckout.js +120 -0
- package/dist/runtime/sandboxContainer.d.ts +62 -0
- package/dist/runtime/sandboxContainer.js +151 -0
- package/dist/runtime/sandboxDesk.d.ts +28 -0
- package/dist/runtime/sandboxDesk.js +242 -0
- package/dist/runtime/sandboxFiles.d.ts +20 -0
- package/dist/runtime/sandboxFiles.js +150 -0
- package/dist/runtime/stageAttemptBootstrap.js +15 -1
- package/dist/runtime/stageEnvironment.d.ts +2 -0
- package/dist/runtime/stageEnvironment.js +8 -1
- package/dist/runtime/stageProcessLauncher.js +23 -0
- package/dist/runtime/stageRoots.d.ts +9 -0
- package/dist/runtime/stageRoots.js +14 -0
- package/dist/runtime/stageRunner.d.ts +5 -0
- package/dist/runtime/stageRunner.js +38 -4
- package/dist/runtime/stageSandbox.d.ts +16 -0
- package/dist/runtime/stageSandbox.js +54 -0
- package/dist/runtime/stageSecrets.d.ts +6 -1
- package/dist/runtime/stageSecrets.js +34 -1
- package/dist/runtime/stageWorker.js +138 -105
- package/dist/runtime/workspaceBinding.d.ts +2 -1
- package/dist/runtime/workspaceBinding.js +20 -4
- package/dist/server/agentAuthorRoutes.d.ts +5 -0
- package/dist/server/agentAuthorRoutes.js +64 -0
- package/dist/server/agentRoutes.d.ts +5 -0
- package/dist/server/agentRoutes.js +323 -0
- package/dist/server/bootstrap.d.ts +8 -0
- package/dist/server/bootstrap.js +36 -10
- package/dist/server/controlToken.js +8 -0
- package/dist/server/http.d.ts +8 -1
- package/dist/server/http.js +172 -20
- package/dist/server/mcpHost.js +1 -0
- package/dist/server/memoryRoutes.d.ts +5 -0
- package/dist/server/memoryRoutes.js +146 -0
- package/dist/server/projectMcpRoutes.d.ts +1 -0
- package/dist/server/projectMcpRoutes.js +241 -3
- package/dist/toolkit/guard.d.ts +27 -0
- package/dist/toolkit/guard.js +98 -0
- package/dist/toolkit/index.d.ts +48 -0
- package/dist/toolkit/index.js +82 -0
- package/dist/toolkit/meta.d.ts +36 -0
- package/dist/toolkit/meta.js +117 -0
- package/dist/toolkit/profiles.d.ts +13 -0
- package/dist/toolkit/profiles.js +25 -0
- package/dist/toolkit/record.d.ts +15 -0
- package/dist/toolkit/record.js +17 -0
- package/dist/tools/memoryTools.d.ts +95 -0
- package/dist/tools/memoryTools.js +179 -0
- package/dist/types/pipeline.d.ts +3 -0
- package/dist/types/stage.d.ts +2 -0
- package/dist/types/task.d.ts +11 -1
- package/dist/ui/assets/AssistantRuntimeProvider-CsiPFhCT.js +9 -0
- package/dist/ui/assets/MarkdownText-D7tYaIFO.js +29 -0
- package/dist/ui/assets/ReadonlyStore-BfXqHykm.js +6 -0
- package/dist/ui/assets/Tooltip-DrpoRRNi.js +1 -0
- package/dist/ui/assets/chat-BbLukq9W.js +5 -0
- package/dist/ui/assets/chat-zIZU_bP1.css +2 -0
- package/dist/ui/assets/jsx-runtime-iVoFAvQ_.js +1 -0
- package/dist/ui/assets/{index-Clv4sJpU.css → main-BFo79krC.css} +1 -1
- package/dist/ui/assets/main-CijYMeM0.js +259 -0
- package/dist/ui/chat.html +25 -0
- package/dist/ui/index.html +6 -2
- package/dist/workshop/modelSettings.d.ts +2 -2
- package/dist/workshop/modelSettings.js +5 -11
- package/examples/README.md +1 -0
- package/examples/channels-smoke/README.md +12 -1
- package/examples/github-release/README.md +1 -1
- package/examples/memory/README.md +101 -0
- package/examples/memory/desk-outage.task.yaml +15 -0
- package/examples/memory/desk-refund.task.yaml +15 -0
- package/examples/memory/desk-revisit-outage.task.yaml +11 -0
- package/examples/memory/desk-revisit.pipeline.yaml +123 -0
- package/examples/memory/desk.pipeline.yaml +192 -0
- package/examples/memory/file-card.pipeline.yaml +39 -0
- package/examples/memory/file-ledger.task.yaml +22 -0
- package/examples/memory/file-release.task.yaml +24 -0
- package/examples/memory/file-rich.pipeline.yaml +40 -0
- package/examples/memory/file-ticket.task.yaml +7 -0
- package/examples/memory/file-timeline.task.yaml +28 -0
- package/examples/memory/find-card.pipeline.yaml +46 -0
- package/examples/memory/find-ticket.task.yaml +7 -0
- package/examples/memory/missing.pipeline.yaml +16 -0
- package/examples/memory/probe-bash.task.yaml +3 -0
- package/examples/memory/recall.pipeline.yaml +24 -0
- package/examples/memory/recall.task.yaml +5 -0
- package/examples/memory/remember-ada.task.yaml +6 -0
- package/examples/memory/remember-grace.task.yaml +6 -0
- package/examples/memory/remember.pipeline.yaml +58 -0
- package/examples/memory/sandbox-memory-bash.pipeline.yaml +28 -0
- package/examples/memory/stageflow.yaml +12 -0
- package/examples/memory/update-card.pipeline.yaml +43 -0
- package/examples/memory/update-ledger.task.yaml +23 -0
- package/examples/memory/update-rich.pipeline.yaml +44 -0
- package/examples/memory/update-ticket.task.yaml +7 -0
- package/examples/ship-feature/README.md +15 -0
- package/examples/stage-mcp/README.md +1 -1
- package/package.json +2 -1
- package/dist/ui/assets/index-BOhqnPNg.js +0 -260
|
@@ -0,0 +1,323 @@
|
|
|
1
|
+
import { AgentError, isAgentError } from "../agents/errors.js";
|
|
2
|
+
import { describeToolkit } from "../toolkit/index.js";
|
|
3
|
+
import { isSessionStatus } from "../agents/store.js";
|
|
4
|
+
import { BodyError, readJsonBody, writeFrame } from "../agents/ndjson.js";
|
|
5
|
+
const MAX_BODY_BYTES = 256 * 1024;
|
|
6
|
+
const CONSOLE_ACTOR = { source: "console" };
|
|
7
|
+
async function readBody(req) {
|
|
8
|
+
try {
|
|
9
|
+
return await readJsonBody(req, MAX_BODY_BYTES);
|
|
10
|
+
}
|
|
11
|
+
catch (error) {
|
|
12
|
+
if (!(error instanceof BodyError))
|
|
13
|
+
throw error;
|
|
14
|
+
throw new AgentError("agent.invalid", error.reason === "too_large" ? "Request body is too large" : error.reason === "not_json" ? "Request body is not JSON" : "Request body must be a JSON object");
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
function requireInt(value, name) {
|
|
18
|
+
if (typeof value !== "number" || !Number.isInteger(value) || value < 0) {
|
|
19
|
+
throw new AgentError("agent.invalid", `${name} must be a non-negative integer`);
|
|
20
|
+
}
|
|
21
|
+
return value;
|
|
22
|
+
}
|
|
23
|
+
function requireText(value, name) {
|
|
24
|
+
if (typeof value !== "string" || value.trim().length === 0)
|
|
25
|
+
throw new AgentError("agent.invalid", `${name} is required`);
|
|
26
|
+
return value.trim();
|
|
27
|
+
}
|
|
28
|
+
function optionalText(value) {
|
|
29
|
+
return typeof value === "string" && value.trim().length > 0 ? value.trim() : undefined;
|
|
30
|
+
}
|
|
31
|
+
function sessionQuery(url) {
|
|
32
|
+
const status = url.searchParams.get("status") ?? undefined;
|
|
33
|
+
if (status !== undefined && !isSessionStatus(status)) {
|
|
34
|
+
throw new AgentError("agent.invalid", "Unknown session status");
|
|
35
|
+
}
|
|
36
|
+
const limit = Number(url.searchParams.get("limit") ?? 25);
|
|
37
|
+
return {
|
|
38
|
+
limit: Number.isInteger(limit) && limit > 0 && limit <= 100 ? limit : 25,
|
|
39
|
+
...(status && isSessionStatus(status) ? { status } : {}),
|
|
40
|
+
...(url.searchParams.get("source") ? { source: url.searchParams.get("source") } : {}),
|
|
41
|
+
...(url.searchParams.get("q")?.trim() ? { search: url.searchParams.get("q").trim() } : {}),
|
|
42
|
+
...(url.searchParams.get("cursor") ? { cursor: url.searchParams.get("cursor") } : {}),
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
/** A session must belong to the agent named in the path, or the request is a 404. */
|
|
46
|
+
async function sessionFor(ctx, agentId, sessionId) {
|
|
47
|
+
const detail = await ctx.host.service.getSession(ctx.projectRoot, sessionId);
|
|
48
|
+
if (detail.session.agentId !== agentId)
|
|
49
|
+
throw new AgentError("agent.session_not_found");
|
|
50
|
+
return detail;
|
|
51
|
+
}
|
|
52
|
+
async function chat(ctx, agentId) {
|
|
53
|
+
const body = await readBody(ctx.req);
|
|
54
|
+
const message = requireText(body.message, "message");
|
|
55
|
+
const sessionId = optionalText(body.sessionId);
|
|
56
|
+
const wantsStream = body.stream === true || String(ctx.req.headers.accept ?? "").includes("application/x-ndjson");
|
|
57
|
+
const send = (onDelta, onSessionOpened) => ctx.host.chat.send({
|
|
58
|
+
projectRoot: ctx.projectRoot,
|
|
59
|
+
agentId,
|
|
60
|
+
text: message,
|
|
61
|
+
source: "console",
|
|
62
|
+
...(sessionId ? { sessionId } : {}),
|
|
63
|
+
...(onDelta ? { onDelta } : {}),
|
|
64
|
+
...(onSessionOpened ? { onSessionOpened } : {}),
|
|
65
|
+
});
|
|
66
|
+
if (!wantsStream) {
|
|
67
|
+
ctx.json(ctx.res, 200, await send());
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
ctx.res.writeHead(200, { "Content-Type": "application/x-ndjson; charset=utf-8", "Cache-Control": "no-store" });
|
|
71
|
+
let writes = Promise.resolve();
|
|
72
|
+
let finished = false;
|
|
73
|
+
let openedId = sessionId;
|
|
74
|
+
ctx.res.once("close", () => {
|
|
75
|
+
if (finished)
|
|
76
|
+
return;
|
|
77
|
+
if (openedId)
|
|
78
|
+
ctx.host.chat.stop(openedId);
|
|
79
|
+
else
|
|
80
|
+
ctx.host.chat.stopOpening(agentId);
|
|
81
|
+
});
|
|
82
|
+
try {
|
|
83
|
+
const detail = await send((text) => {
|
|
84
|
+
writes = writes.then(() => writeFrame(ctx.res, { type: "delta", text }));
|
|
85
|
+
}, (id) => {
|
|
86
|
+
openedId = id;
|
|
87
|
+
writes = writes.then(() => writeFrame(ctx.res, { type: "session", sessionId: id }));
|
|
88
|
+
});
|
|
89
|
+
finished = true;
|
|
90
|
+
await writes;
|
|
91
|
+
await writeFrame(ctx.res, { type: "done", session: detail });
|
|
92
|
+
}
|
|
93
|
+
catch (error) {
|
|
94
|
+
finished = true;
|
|
95
|
+
await writes.catch(() => undefined);
|
|
96
|
+
await writeFrame(ctx.res, {
|
|
97
|
+
type: "error",
|
|
98
|
+
code: isAgentError(error) ? error.code : "agent.internal",
|
|
99
|
+
...(isAgentError(error) && error.message !== error.code ? { message: error.message } : {}),
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
finally {
|
|
103
|
+
if (!ctx.res.writableEnded && !ctx.res.destroyed)
|
|
104
|
+
ctx.res.end();
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
const routes = [
|
|
108
|
+
{
|
|
109
|
+
method: "GET",
|
|
110
|
+
pattern: /^\/api\/agents$/,
|
|
111
|
+
handle: async (ctx) => ctx.json(ctx.res, 200, { agents: await ctx.host.service.list(ctx.projectRoot) }),
|
|
112
|
+
},
|
|
113
|
+
{
|
|
114
|
+
method: "POST",
|
|
115
|
+
pattern: /^\/api\/agents$/,
|
|
116
|
+
handle: async (ctx) => {
|
|
117
|
+
const body = await readBody(ctx.req);
|
|
118
|
+
ctx.json(ctx.res, 201, await ctx.host.service.create(ctx.projectRoot, body.definition, CONSOLE_ACTOR));
|
|
119
|
+
},
|
|
120
|
+
},
|
|
121
|
+
{
|
|
122
|
+
method: "POST",
|
|
123
|
+
pattern: /^\/api\/agents\/validate$/,
|
|
124
|
+
handle: async (ctx) => {
|
|
125
|
+
const body = await readBody(ctx.req);
|
|
126
|
+
ctx.json(ctx.res, 200, await ctx.host.service.validate(ctx.projectRoot, body.definition));
|
|
127
|
+
},
|
|
128
|
+
},
|
|
129
|
+
{
|
|
130
|
+
method: "GET",
|
|
131
|
+
pattern: /^\/api\/agents\/stageflow-tools$/,
|
|
132
|
+
handle: async ({ res, json }) => json(res, 200, describeToolkit()),
|
|
133
|
+
},
|
|
134
|
+
{
|
|
135
|
+
method: "GET",
|
|
136
|
+
pattern: /^\/api\/agents\/([^/]+)\/channel$/,
|
|
137
|
+
handle: async (ctx) => {
|
|
138
|
+
const detail = await ctx.host.service.get(ctx.projectRoot, ctx.params[0]);
|
|
139
|
+
const connectionId = detail.definition?.channel?.connection_id ?? null;
|
|
140
|
+
// `listener` is absent for webhook providers and for agents that are disabled.
|
|
141
|
+
const listener = connectionId ? ctx.host.channelListeners?.status(connectionId) : undefined;
|
|
142
|
+
const failed = ctx.host.service.latestUndelivered(ctx.projectRoot, ctx.params[0]);
|
|
143
|
+
ctx.json(ctx.res, 200, {
|
|
144
|
+
connectionId,
|
|
145
|
+
...(listener ? { listener } : {}),
|
|
146
|
+
...(failed ? { lastUndelivered: { turnId: failed.turnId, sessionId: failed.sessionId, state: failed.state, code: failed.errorCode, message: failed.errorMessage, at: failed.updatedAt } } : {}),
|
|
147
|
+
});
|
|
148
|
+
},
|
|
149
|
+
},
|
|
150
|
+
{
|
|
151
|
+
method: "POST",
|
|
152
|
+
pattern: /^\/api\/agents\/([^/]+)\/sessions\/([^/]+)\/turns\/([^/]+)\/delivery\/(resend|delivered)$/,
|
|
153
|
+
handle: async (ctx) => {
|
|
154
|
+
const [agentId, sessionId, turnId, action] = ctx.params;
|
|
155
|
+
const session = await ctx.host.service.getSession(ctx.projectRoot, sessionId);
|
|
156
|
+
if (session.session.agentId !== agentId || !session.turns.some((turn) => turn.id === turnId))
|
|
157
|
+
throw new AgentError("agent.session_not_found");
|
|
158
|
+
if (action === "resend")
|
|
159
|
+
await ctx.host.delivery.resend(turnId);
|
|
160
|
+
else
|
|
161
|
+
ctx.host.delivery.markDelivered(turnId);
|
|
162
|
+
ctx.json(ctx.res, 200, await ctx.host.service.getSession(ctx.projectRoot, sessionId));
|
|
163
|
+
},
|
|
164
|
+
},
|
|
165
|
+
{
|
|
166
|
+
method: "GET",
|
|
167
|
+
pattern: /^\/api\/agents\/([^/]+)\/channel\/contact$/,
|
|
168
|
+
handle: async (ctx) => {
|
|
169
|
+
const detail = await ctx.host.service.get(ctx.projectRoot, ctx.params[0]);
|
|
170
|
+
const connectionId = detail.definition?.channel?.connection_id;
|
|
171
|
+
const found = connectionId ? await ctx.host.channelContact(connectionId) : undefined;
|
|
172
|
+
ctx.json(ctx.res, 200, { connectionId: connectionId ?? null, ...(found ?? {}) });
|
|
173
|
+
},
|
|
174
|
+
},
|
|
175
|
+
{
|
|
176
|
+
method: "GET",
|
|
177
|
+
pattern: /^\/api\/agents\/sessions$/,
|
|
178
|
+
handle: async (ctx) => ctx.json(ctx.res, 200, await ctx.host.service.listAllSessions(ctx.projectRoot, sessionQuery(ctx.url), ctx.url.searchParams.get("agent") || undefined)),
|
|
179
|
+
},
|
|
180
|
+
{
|
|
181
|
+
method: "GET",
|
|
182
|
+
pattern: /^\/api\/agents\/approvals$/,
|
|
183
|
+
handle: async (ctx) => ctx.json(ctx.res, 200, { approvals: await ctx.host.service.pendingApprovals(ctx.projectRoot) }),
|
|
184
|
+
},
|
|
185
|
+
{
|
|
186
|
+
method: "GET",
|
|
187
|
+
pattern: /^\/api\/agents\/([^/]+)$/,
|
|
188
|
+
handle: async (ctx) => ctx.json(ctx.res, 200, await ctx.host.service.get(ctx.projectRoot, ctx.params[0])),
|
|
189
|
+
},
|
|
190
|
+
{
|
|
191
|
+
method: "POST",
|
|
192
|
+
pattern: /^\/api\/agents\/([^/]+)\/save$/,
|
|
193
|
+
handle: async (ctx) => {
|
|
194
|
+
const body = await readBody(ctx.req);
|
|
195
|
+
ctx.json(ctx.res, 200, await ctx.host.service.save(ctx.projectRoot, ctx.params[0], {
|
|
196
|
+
baseRevision: requireInt(body.baseRevision, "baseRevision"),
|
|
197
|
+
definition: body.definition,
|
|
198
|
+
summary: optionalText(body.summary) ?? null,
|
|
199
|
+
}, CONSOLE_ACTOR));
|
|
200
|
+
},
|
|
201
|
+
},
|
|
202
|
+
{
|
|
203
|
+
method: "POST",
|
|
204
|
+
pattern: /^\/api\/agents\/([^/]+)\/(enable|disable)$/,
|
|
205
|
+
handle: async (ctx) => ctx.json(ctx.res, 200, await ctx.host.service.setEnabled(ctx.projectRoot, ctx.params[0], ctx.params[1] === "enable", CONSOLE_ACTOR)),
|
|
206
|
+
},
|
|
207
|
+
{
|
|
208
|
+
method: "POST",
|
|
209
|
+
pattern: /^\/api\/agents\/([^/]+)\/archive$/,
|
|
210
|
+
handle: async (ctx) => {
|
|
211
|
+
await ctx.host.service.archive(ctx.projectRoot, ctx.params[0]);
|
|
212
|
+
ctx.json(ctx.res, 200, { archived: true });
|
|
213
|
+
},
|
|
214
|
+
},
|
|
215
|
+
{
|
|
216
|
+
method: "GET",
|
|
217
|
+
pattern: /^\/api\/agents\/([^/]+)\/revisions$/,
|
|
218
|
+
handle: async (ctx) => ctx.json(ctx.res, 200, { revisions: await ctx.host.service.listRevisions(ctx.projectRoot, ctx.params[0]) }),
|
|
219
|
+
},
|
|
220
|
+
{
|
|
221
|
+
method: "GET",
|
|
222
|
+
pattern: /^\/api\/agents\/([^/]+)\/revisions\/(\d+)$/,
|
|
223
|
+
handle: async (ctx) => ctx.json(ctx.res, 200, await ctx.host.service.getRevision(ctx.projectRoot, ctx.params[0], Number(ctx.params[1]))),
|
|
224
|
+
},
|
|
225
|
+
{
|
|
226
|
+
method: "GET",
|
|
227
|
+
pattern: /^\/api\/agents\/([^/]+)\/revisions\/(\d+)\/diff\/(\d+)$/,
|
|
228
|
+
handle: async (ctx) => ctx.json(ctx.res, 200, {
|
|
229
|
+
lines: await ctx.host.service.diffRevisions(ctx.projectRoot, ctx.params[0], Number(ctx.params[1]), Number(ctx.params[2])),
|
|
230
|
+
}),
|
|
231
|
+
},
|
|
232
|
+
{
|
|
233
|
+
method: "POST",
|
|
234
|
+
pattern: /^\/api\/agents\/([^/]+)\/revisions\/(\d+)\/restore$/,
|
|
235
|
+
handle: async (ctx) => {
|
|
236
|
+
const body = await readBody(ctx.req);
|
|
237
|
+
ctx.json(ctx.res, 200, await ctx.host.service.restore(ctx.projectRoot, ctx.params[0], { revision: Number(ctx.params[1]), baseRevision: requireInt(body.baseRevision, "baseRevision") }, CONSOLE_ACTOR));
|
|
238
|
+
},
|
|
239
|
+
},
|
|
240
|
+
{
|
|
241
|
+
method: "GET",
|
|
242
|
+
pattern: /^\/api\/agents\/([^/]+)\/sessions$/,
|
|
243
|
+
handle: async (ctx) => ctx.json(ctx.res, 200, await ctx.host.service.listSessions(ctx.projectRoot, ctx.params[0], sessionQuery(ctx.url))),
|
|
244
|
+
},
|
|
245
|
+
{
|
|
246
|
+
method: "GET",
|
|
247
|
+
pattern: /^\/api\/agents\/([^/]+)\/sessions\/([^/]+)$/,
|
|
248
|
+
handle: async (ctx) => ctx.json(ctx.res, 200, await sessionFor(ctx, ctx.params[0], ctx.params[1])),
|
|
249
|
+
},
|
|
250
|
+
{
|
|
251
|
+
method: "GET",
|
|
252
|
+
pattern: /^\/api\/agents\/([^/]+)\/sessions\/([^/]+)\/otlp$/,
|
|
253
|
+
handle: async (ctx) => {
|
|
254
|
+
await sessionFor(ctx, ctx.params[0], ctx.params[1]);
|
|
255
|
+
ctx.res.setHeader("Content-Disposition", `attachment; filename="${ctx.params[1]}.otlp.json"`);
|
|
256
|
+
ctx.json(ctx.res, 200, ctx.host.service.exportSessionOtlp(ctx.projectRoot, ctx.params[1]));
|
|
257
|
+
},
|
|
258
|
+
},
|
|
259
|
+
{
|
|
260
|
+
method: "POST",
|
|
261
|
+
pattern: /^\/api\/agents\/([^/]+)\/sessions\/([^/]+)\/approval\/(approve|deny)$/,
|
|
262
|
+
handle: async (ctx) => {
|
|
263
|
+
await sessionFor(ctx, ctx.params[0], ctx.params[1]);
|
|
264
|
+
const approval = await ctx.host.service.decideApproval(ctx.projectRoot, ctx.params[1], ctx.params[2] === "approve" ? "approve" : "deny", { kind: "operator" });
|
|
265
|
+
ctx.json(ctx.res, 200, { approval, session: await sessionFor(ctx, ctx.params[0], ctx.params[1]) });
|
|
266
|
+
},
|
|
267
|
+
},
|
|
268
|
+
{
|
|
269
|
+
method: "POST",
|
|
270
|
+
pattern: /^\/api\/agents\/([^/]+)\/chat$/,
|
|
271
|
+
handle: async (ctx) => chat(ctx, ctx.params[0]),
|
|
272
|
+
},
|
|
273
|
+
{
|
|
274
|
+
method: "POST",
|
|
275
|
+
pattern: /^\/api\/agents\/([^/]+)\/chat\/stop$/,
|
|
276
|
+
handle: async (ctx) => {
|
|
277
|
+
const body = await readBody(ctx.req);
|
|
278
|
+
const sessionId = requireText(body.sessionId, "sessionId");
|
|
279
|
+
await sessionFor(ctx, ctx.params[0], sessionId);
|
|
280
|
+
ctx.json(ctx.res, 200, { stopped: ctx.host.chat.stop(sessionId) });
|
|
281
|
+
},
|
|
282
|
+
},
|
|
283
|
+
];
|
|
284
|
+
export async function handleAgentRoutes(req, method, pathname, host, projectRoot, res, json) {
|
|
285
|
+
for (const route of routes) {
|
|
286
|
+
const match = route.pattern.exec(pathname);
|
|
287
|
+
if (!match)
|
|
288
|
+
continue;
|
|
289
|
+
if (route.method !== method)
|
|
290
|
+
continue;
|
|
291
|
+
try {
|
|
292
|
+
const params = match.slice(1).map((segment) => decodeURIComponent(segment));
|
|
293
|
+
await route.handle({ req, res, json, host, projectRoot, params, url: new URL(req.url ?? pathname, "http://agents") });
|
|
294
|
+
}
|
|
295
|
+
catch (error) {
|
|
296
|
+
if (res.headersSent) {
|
|
297
|
+
if (!res.writableEnded)
|
|
298
|
+
res.end();
|
|
299
|
+
return true;
|
|
300
|
+
}
|
|
301
|
+
if (error instanceof URIError) {
|
|
302
|
+
json(res, 400, { code: "agent.invalid", message: "Malformed path" });
|
|
303
|
+
}
|
|
304
|
+
else if (isAgentError(error)) {
|
|
305
|
+
json(res, error.httpStatus, {
|
|
306
|
+
code: error.code,
|
|
307
|
+
...(error.message !== error.code ? { message: error.message } : {}),
|
|
308
|
+
...(error.issues.length > 0 ? { issues: error.issues } : {}),
|
|
309
|
+
});
|
|
310
|
+
}
|
|
311
|
+
else {
|
|
312
|
+
throw error;
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
return true;
|
|
316
|
+
}
|
|
317
|
+
const known = routes.some((route) => route.pattern.test(pathname));
|
|
318
|
+
if (known) {
|
|
319
|
+
json(res, 405, { code: "agent.method_not_allowed" });
|
|
320
|
+
return true;
|
|
321
|
+
}
|
|
322
|
+
return false;
|
|
323
|
+
}
|
|
@@ -10,10 +10,13 @@ import { RunManager } from "../runtime/runManager.js";
|
|
|
10
10
|
import { emailHostFor } from "../email/host.js";
|
|
11
11
|
import { EmailTriggers } from "../email/triggers.js";
|
|
12
12
|
import { type ChannelService } from "../channels/service.js";
|
|
13
|
+
import { type MemoryHost } from "../memory/host.js";
|
|
13
14
|
import { type RunChangeBus } from "../runtime/runChangeBus.js";
|
|
14
15
|
import { type McpHttpHandler } from "../mcp/server.js";
|
|
15
16
|
import { type HostConfig } from "../config/hostConfig.js";
|
|
16
17
|
import { bootProviderConfig } from "../agent/bootProviderConfig.js";
|
|
18
|
+
import { type AgentHostContext } from "../agents/hostContext.js";
|
|
19
|
+
import type { ConversationBackend } from "../agents/sessions.js";
|
|
17
20
|
export declare const DEFAULT_GC_INTERVAL_MS: number;
|
|
18
21
|
export type StageflowHostOptions = {
|
|
19
22
|
agent: StagePort;
|
|
@@ -33,6 +36,7 @@ export type StageflowHostOptions = {
|
|
|
33
36
|
/** Browser support for the runs this Host executes; defaults to the local host with the live view relay. */
|
|
34
37
|
browser?: StageBrowserSupport;
|
|
35
38
|
emailTriggerQueue?: ConstructorParameters<typeof EmailTriggers>[0]["queue"];
|
|
39
|
+
agentConversationBackend?: ConversationBackend;
|
|
36
40
|
};
|
|
37
41
|
export type StageflowHostBootstrap = {
|
|
38
42
|
a2a?: A2aHost;
|
|
@@ -62,6 +66,10 @@ export type StageflowHostBootstrap = {
|
|
|
62
66
|
stopEmailSource: () => void;
|
|
63
67
|
/** Connections page read model and background health checks. */
|
|
64
68
|
channels?: ChannelService;
|
|
69
|
+
/** Named markdown pages under `$STAGEFLOW_HOME/memories`. */
|
|
70
|
+
memories?: MemoryHost;
|
|
71
|
+
/** Shared agent store, chat controller, and conversation backend for HTTP/MCP. */
|
|
72
|
+
agentHost?: AgentHostContext;
|
|
65
73
|
email?: ReturnType<typeof emailHostFor> & {
|
|
66
74
|
triggers: EmailTriggers;
|
|
67
75
|
stop: () => Promise<void>;
|
package/dist/server/bootstrap.js
CHANGED
|
@@ -2,7 +2,7 @@ import path from "node:path";
|
|
|
2
2
|
import { getAgentDir } from "@earendil-works/pi-coding-agent";
|
|
3
3
|
import { createA2aHost } from "../a2a/server.js";
|
|
4
4
|
import { A2aStore } from "../a2a/store.js";
|
|
5
|
-
import { createRunStoreWithConnection } from "../runstore/createStore.js";
|
|
5
|
+
import { createRunStoreWithConnection, sqliteConnectionFromStore } from "../runstore/createStore.js";
|
|
6
6
|
import { resolveA2aConfigPath } from "../a2a/configDiscovery.js";
|
|
7
7
|
import { ensureProjectRootsFromEnv } from "../project/ensureProjectRootsFromEnv.js";
|
|
8
8
|
import { ensureGlobalHome, globalStageflowHome } from "../project/globalHome.js";
|
|
@@ -21,6 +21,7 @@ import { EmailSource } from "../runtime/emailSource.js";
|
|
|
21
21
|
import { emailHostFor, releaseEmailHost } from "../email/host.js";
|
|
22
22
|
import { EmailTriggers } from "../email/triggers.js";
|
|
23
23
|
import { startChannelService } from "../channels/service.js";
|
|
24
|
+
import { memoryHostFor } from "../memory/host.js";
|
|
24
25
|
import { fireTrigger } from "../runtime/triggerRunner.js";
|
|
25
26
|
import { createRunChangeBus, getRunChangeBusFromWrappedStore, isRunStoreWrapped, wrapRunStoreWithChangeBus, } from "../runtime/runChangeBus.js";
|
|
26
27
|
import { createMcpHttpHandler, resolveMcpStateless, } from "../mcp/server.js";
|
|
@@ -30,16 +31,9 @@ import { readCursorApiKey } from "../agent/cursorProvider.js";
|
|
|
30
31
|
import { applyPendingRestoreAtBoot, } from "../runstore/restore.js";
|
|
31
32
|
import { assertTmpdirUsable } from "../runstore/assertTmpdir.js";
|
|
32
33
|
import { logger as rootLogger } from "../logging/logger.js";
|
|
34
|
+
import { getModelCatalog } from "../models/catalog.js";
|
|
35
|
+
import { createAgentHostContext } from "../agents/hostContext.js";
|
|
33
36
|
export const DEFAULT_GC_INTERVAL_MS = 60 * 60 * 1000;
|
|
34
|
-
function sqliteConnectionFromStore(store) {
|
|
35
|
-
const connection = store.connection;
|
|
36
|
-
if (connection !== undefined &&
|
|
37
|
-
connection !== null &&
|
|
38
|
-
typeof connection.prepare === "function") {
|
|
39
|
-
return connection;
|
|
40
|
-
}
|
|
41
|
-
return undefined;
|
|
42
|
-
}
|
|
43
37
|
/** Parse `STAGEFLOW_GC_INTERVAL_MS`; default 1h; `0` disables. */
|
|
44
38
|
export function gcIntervalMsFromEnv(env = process.env) {
|
|
45
39
|
const raw = env.STAGEFLOW_GC_INTERVAL_MS;
|
|
@@ -334,10 +328,33 @@ export async function bootstrapStageflowHost(options) {
|
|
|
334
328
|
}
|
|
335
329
|
const channels = startChannelService(cwd);
|
|
336
330
|
const stopEmailSource = () => {
|
|
331
|
+
void agentHost?.stop();
|
|
337
332
|
void emailSource.stop();
|
|
338
333
|
void stopAccountEmail();
|
|
339
334
|
void channels.stop();
|
|
340
335
|
};
|
|
336
|
+
// Resolve the connected-provider list and the default model once at boot so sync callers see the catalog's answer.
|
|
337
|
+
void getModelCatalog(cwd)
|
|
338
|
+
.defaultModel()
|
|
339
|
+
.catch((error) => bootLog.warn("models.catalog_warm_failed", String(error)));
|
|
340
|
+
const agentHost = sqliteConnection !== undefined
|
|
341
|
+
? createAgentHostContext({
|
|
342
|
+
cwd,
|
|
343
|
+
agentDir,
|
|
344
|
+
connection: sqliteConnection,
|
|
345
|
+
channels,
|
|
346
|
+
...(options.agentConversationBackend ? { backend: options.agentConversationBackend } : {}),
|
|
347
|
+
listenOnChannels: process.env.STAGEFLOW_AGENT_CHANNEL_LISTENERS !== "0",
|
|
348
|
+
toolkitDeps: {
|
|
349
|
+
manager,
|
|
350
|
+
store,
|
|
351
|
+
agentDir,
|
|
352
|
+
projectRoot: rootDir,
|
|
353
|
+
...(options.providerAuthContext ? { providerAuthContext: options.providerAuthContext } : {}),
|
|
354
|
+
...(providerBoot !== undefined ? { providerBoot } : {}),
|
|
355
|
+
},
|
|
356
|
+
})
|
|
357
|
+
: undefined;
|
|
341
358
|
const mcpStateless = resolveMcpStateless({
|
|
342
359
|
mcpStateless: options.mcpStateless,
|
|
343
360
|
});
|
|
@@ -349,6 +366,13 @@ export async function bootstrapStageflowHost(options) {
|
|
|
349
366
|
runChangeBus,
|
|
350
367
|
providerAuthContext: options.providerAuthContext,
|
|
351
368
|
projectRoot: rootDir,
|
|
369
|
+
...(agentHost
|
|
370
|
+
? {
|
|
371
|
+
agentService: agentHost.service,
|
|
372
|
+
agentChat: agentHost.chat,
|
|
373
|
+
agentConversationBackend: agentHost.backend,
|
|
374
|
+
}
|
|
375
|
+
: {}),
|
|
352
376
|
...(providerBoot !== undefined ? { providerBoot } : {}),
|
|
353
377
|
}, { mcpStateless });
|
|
354
378
|
return {
|
|
@@ -378,7 +402,9 @@ export async function bootstrapStageflowHost(options) {
|
|
|
378
402
|
stopEmailSource,
|
|
379
403
|
email: { ...emailHost, triggers: emailTriggers, stop: stopAccountEmail },
|
|
380
404
|
channels,
|
|
405
|
+
memories: memoryHostFor(),
|
|
381
406
|
storeFilesystem,
|
|
382
407
|
workspaceCatalog,
|
|
408
|
+
...(agentHost ? { agentHost } : {}),
|
|
383
409
|
};
|
|
384
410
|
}
|
|
@@ -175,6 +175,10 @@ export class BindRefusedError extends Error {
|
|
|
175
175
|
function isTriggerWebhookRoute(method, pathname) {
|
|
176
176
|
return method === "POST" && /^\/api\/triggers\/[^/]+\/webhook$/.test(pathname);
|
|
177
177
|
}
|
|
178
|
+
/** Agent webhooks authenticate by the provider's own signature against the connection's inbound secret. */
|
|
179
|
+
function isAgentInboundRoute(method, pathname) {
|
|
180
|
+
return method === "POST" && /^\/api\/agent-inbound\/[^/]+$/.test(pathname);
|
|
181
|
+
}
|
|
178
182
|
/**
|
|
179
183
|
* Live view routes authenticate themselves: the ticket route checks the bearer
|
|
180
184
|
* scope for the requested mode, and the browser's event stream and input posts
|
|
@@ -190,6 +194,10 @@ export function requiredScopeFor(method, pathname) {
|
|
|
190
194
|
return null;
|
|
191
195
|
if (isTriggerWebhookRoute(method, pathname))
|
|
192
196
|
return null;
|
|
197
|
+
if (isAgentInboundRoute(method, pathname))
|
|
198
|
+
return null;
|
|
199
|
+
if (pathname.startsWith("/api/public/chat/"))
|
|
200
|
+
return null;
|
|
193
201
|
if (isLiveViewRoute(pathname))
|
|
194
202
|
return null;
|
|
195
203
|
if (pathname === "/api/backup" || pathname.startsWith("/api/backup/")) {
|
package/dist/server/http.d.ts
CHANGED
|
@@ -3,11 +3,13 @@ import { type ProviderAuthContext } from "../agent/providerAuth.js";
|
|
|
3
3
|
import { type LiveViewRoutesOptions } from "./liveViewRoutes.js";
|
|
4
4
|
import { WorkshopChatSessionRegistry } from "../workshop/chatTurn.js";
|
|
5
5
|
import { type AgentPort } from "../operatorAgent/index.js";
|
|
6
|
-
import type
|
|
6
|
+
import { type RunStoreKind } from "../runstore/createStore.js";
|
|
7
7
|
import type { RunStore } from "../runstore/port.js";
|
|
8
8
|
import type { RunManager } from "../runtime/runManager.js";
|
|
9
9
|
import type { RunChangeBus } from "../runtime/runChangeBus.js";
|
|
10
10
|
import type { StageBrowserSupport } from "../browser/browserHost.js";
|
|
11
|
+
import { type AgentHostContext } from "../agents/hostContext.js";
|
|
12
|
+
import type { ConversationBackend } from "../agents/sessions.js";
|
|
11
13
|
import { EmailTriggers } from "../email/triggers.js";
|
|
12
14
|
import { type AllowedHosts } from "./allowedHosts.js";
|
|
13
15
|
import { type ControlTokens } from "./controlToken.js";
|
|
@@ -33,6 +35,7 @@ export type UiServerOptions = {
|
|
|
33
35
|
browser?: StageBrowserSupport;
|
|
34
36
|
/** Optional AgentPort. Workshop is the caller today; tests inject a fake. */
|
|
35
37
|
workshopOperatorHost?: AgentPort;
|
|
38
|
+
agentConversationBackend?: ConversationBackend;
|
|
36
39
|
};
|
|
37
40
|
export declare function defaultUiDistDir(): string;
|
|
38
41
|
export type OperatorRouteDeps = {
|
|
@@ -61,6 +64,10 @@ export type OperatorRouteDeps = {
|
|
|
61
64
|
* Defaults to a registry owned by this route surface.
|
|
62
65
|
*/
|
|
63
66
|
workshopChatRegistry?: WorkshopChatSessionRegistry;
|
|
67
|
+
/** Injectable agent chat backend (tests). Defaults to Pi conversation host. */
|
|
68
|
+
agentConversationBackend?: ConversationBackend;
|
|
69
|
+
/** Shared with MCP when set by bootstrap. */
|
|
70
|
+
agentHost?: AgentHostContext;
|
|
64
71
|
};
|
|
65
72
|
/**
|
|
66
73
|
* The full operator-console route surface: REST API (runs, stages,
|