stageflow 0.35.0 → 0.39.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 +18 -8
- package/dist/agent/claudeAdapter.js +12 -0
- package/dist/agent/piAdapter.d.ts +9 -1
- package/dist/agent/piAdapter.js +30 -2
- 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 +7 -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/config.d.ts +11 -0
- package/dist/channels/config.js +95 -0
- package/dist/channels/configWriter.d.ts +40 -0
- package/dist/channels/configWriter.js +148 -0
- package/dist/channels/connectionEdits.d.ts +34 -0
- package/dist/channels/connectionEdits.js +53 -0
- package/dist/channels/errorInfo.d.ts +18 -0
- package/dist/channels/errorInfo.js +71 -0
- package/dist/channels/errors.d.ts +12 -0
- package/dist/channels/errors.js +13 -0
- package/dist/channels/health.d.ts +41 -0
- package/dist/channels/health.js +99 -0
- package/dist/channels/host.d.ts +55 -0
- package/dist/channels/host.js +185 -0
- package/dist/channels/http.d.ts +31 -0
- package/dist/channels/http.js +79 -0
- package/dist/channels/index.d.ts +10 -0
- package/dist/channels/index.js +9 -0
- package/dist/channels/ledger.d.ts +37 -0
- package/dist/channels/ledger.js +95 -0
- package/dist/channels/providers/agentmail.d.ts +26 -0
- package/dist/channels/providers/agentmail.js +94 -0
- package/dist/channels/providers/kit.d.ts +40 -0
- package/dist/channels/providers/kit.js +78 -0
- package/dist/channels/providers/photonImessage.d.ts +45 -0
- package/dist/channels/providers/photonImessage.js +188 -0
- package/dist/channels/providers/photonWhatsapp.d.ts +49 -0
- package/dist/channels/providers/photonWhatsapp.js +146 -0
- package/dist/channels/providers/slack.d.ts +25 -0
- package/dist/channels/providers/slack.js +102 -0
- package/dist/channels/providers/telegram.d.ts +21 -0
- package/dist/channels/providers/telegram.js +101 -0
- package/dist/channels/providers.d.ts +5 -0
- package/dist/channels/providers.js +22 -0
- package/dist/channels/registry.d.ts +54 -0
- package/dist/channels/registry.js +186 -0
- package/dist/channels/secretStore.d.ts +21 -0
- package/dist/channels/secretStore.js +75 -0
- package/dist/channels/secrets.d.ts +15 -0
- package/dist/channels/secrets.js +50 -0
- package/dist/channels/service.d.ts +54 -0
- package/dist/channels/service.js +307 -0
- package/dist/channels/stageChannels.d.ts +45 -0
- package/dist/channels/stageChannels.js +110 -0
- package/dist/channels/types.d.ts +169 -0
- package/dist/channels/types.js +1 -0
- package/dist/cli/agentsCommand.d.ts +14 -0
- package/dist/cli/agentsCommand.js +291 -0
- package/dist/cli/doctorCommand.js +3 -1
- package/dist/cli.js +9 -0
- package/dist/config/browseCatalog.js +4 -11
- package/dist/config/draftPackage.d.ts +2 -0
- package/dist/config/draftPackage.js +8 -0
- package/dist/config/hostConfig.js +8 -0
- package/dist/config/loadAgent.d.ts +266 -0
- package/dist/config/loadAgent.js +374 -0
- package/dist/config/loadPipeline.js +31 -4
- package/dist/config/loadStage.js +15 -0
- 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 +5 -0
- package/dist/config/mergePipelineIncludes.js +52 -0
- package/dist/config/pipelineStageKeys.js +1 -0
- package/dist/config/resolveStageMcpServers.d.ts +35 -3
- package/dist/config/resolveStageMcpServers.js +124 -9
- package/dist/config/validateCatalog.d.ts +4 -1
- package/dist/config/validateCatalog.js +45 -1
- package/dist/errors/codes.d.ts +1 -1
- package/dist/errors/codes.js +1 -0
- package/dist/mcp/agentTools.d.ts +8 -0
- package/dist/mcp/agentTools.js +132 -0
- package/dist/mcp/catalogTools.js +7 -9
- 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/channelChecks.d.ts +17 -0
- package/dist/preflight/channelChecks.js +106 -0
- package/dist/preflight/pipelinePreflight.d.ts +9 -2
- package/dist/preflight/pipelinePreflight.js +10 -1
- 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/pipelineRunner.js +3 -1
- package/dist/runtime/repositoryMaterialize.d.ts +1 -1
- package/dist/runtime/runManager.js +4 -1
- package/dist/runtime/stageAttemptBootstrap.js +31 -1
- package/dist/runtime/stageEnvironment.d.ts +2 -0
- package/dist/runtime/stageEnvironment.js +6 -1
- package/dist/runtime/stageProcessLauncher.js +54 -1
- package/dist/runtime/stageSecrets.d.ts +6 -1
- package/dist/runtime/stageSecrets.js +34 -1
- 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 +11 -0
- package/dist/server/bootstrap.js +40 -10
- package/dist/server/channelRoutes.d.ts +9 -0
- package/dist/server/channelRoutes.js +88 -0
- package/dist/server/controlToken.js +8 -0
- package/dist/server/http.d.ts +8 -1
- package/dist/server/http.js +183 -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/tools/sendMessage.d.ts +21 -0
- package/dist/tools/sendMessage.js +25 -0
- package/dist/types/pipeline.d.ts +7 -1
- package/dist/types/stage.d.ts +15 -0
- 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-CIPbbBUi.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 +23 -0
- package/examples/channels-smoke/channels-smoke.pipeline.yaml +11 -0
- package/examples/channels-smoke/channels-smoke.task.yaml +3 -0
- package/examples/channels-smoke/send-email.yaml +32 -0
- package/examples/channels-smoke/send-text.yaml +31 -0
- package/examples/github-release/README.md +1 -1
- package/examples/memory/README.md +99 -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/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/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/stage-mcp/README.md +1 -1
- package/package.json +9 -3
- package/dist/ui/assets/index-BoFPkKFg.js +0 -256
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";
|
|
@@ -20,6 +20,8 @@ import { GithubPollSource, githubPollIntervalMsFromEnv, } from "../runtime/githu
|
|
|
20
20
|
import { EmailSource } from "../runtime/emailSource.js";
|
|
21
21
|
import { emailHostFor, releaseEmailHost } from "../email/host.js";
|
|
22
22
|
import { EmailTriggers } from "../email/triggers.js";
|
|
23
|
+
import { startChannelService } from "../channels/service.js";
|
|
24
|
+
import { memoryHostFor } from "../memory/host.js";
|
|
23
25
|
import { fireTrigger } from "../runtime/triggerRunner.js";
|
|
24
26
|
import { createRunChangeBus, getRunChangeBusFromWrappedStore, isRunStoreWrapped, wrapRunStoreWithChangeBus, } from "../runtime/runChangeBus.js";
|
|
25
27
|
import { createMcpHttpHandler, resolveMcpStateless, } from "../mcp/server.js";
|
|
@@ -29,16 +31,9 @@ import { readCursorApiKey } from "../agent/cursorProvider.js";
|
|
|
29
31
|
import { applyPendingRestoreAtBoot, } from "../runstore/restore.js";
|
|
30
32
|
import { assertTmpdirUsable } from "../runstore/assertTmpdir.js";
|
|
31
33
|
import { logger as rootLogger } from "../logging/logger.js";
|
|
34
|
+
import { getModelCatalog } from "../models/catalog.js";
|
|
35
|
+
import { createAgentHostContext } from "../agents/hostContext.js";
|
|
32
36
|
export const DEFAULT_GC_INTERVAL_MS = 60 * 60 * 1000;
|
|
33
|
-
function sqliteConnectionFromStore(store) {
|
|
34
|
-
const connection = store.connection;
|
|
35
|
-
if (connection !== undefined &&
|
|
36
|
-
connection !== null &&
|
|
37
|
-
typeof connection.prepare === "function") {
|
|
38
|
-
return connection;
|
|
39
|
-
}
|
|
40
|
-
return undefined;
|
|
41
|
-
}
|
|
42
37
|
/** Parse `STAGEFLOW_GC_INTERVAL_MS`; default 1h; `0` disables. */
|
|
43
38
|
export function gcIntervalMsFromEnv(env = process.env) {
|
|
44
39
|
const raw = env.STAGEFLOW_GC_INTERVAL_MS;
|
|
@@ -331,10 +326,35 @@ export async function bootstrapStageflowHost(options) {
|
|
|
331
326
|
await Promise.all([stopAccountEmail(), emailSource.stop(), scheduleSource.stop(), githubPollSource.stop()]);
|
|
332
327
|
throw error;
|
|
333
328
|
}
|
|
329
|
+
const channels = startChannelService(cwd);
|
|
334
330
|
const stopEmailSource = () => {
|
|
331
|
+
void agentHost?.stop();
|
|
335
332
|
void emailSource.stop();
|
|
336
333
|
void stopAccountEmail();
|
|
334
|
+
void channels.stop();
|
|
337
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;
|
|
338
358
|
const mcpStateless = resolveMcpStateless({
|
|
339
359
|
mcpStateless: options.mcpStateless,
|
|
340
360
|
});
|
|
@@ -346,6 +366,13 @@ export async function bootstrapStageflowHost(options) {
|
|
|
346
366
|
runChangeBus,
|
|
347
367
|
providerAuthContext: options.providerAuthContext,
|
|
348
368
|
projectRoot: rootDir,
|
|
369
|
+
...(agentHost
|
|
370
|
+
? {
|
|
371
|
+
agentService: agentHost.service,
|
|
372
|
+
agentChat: agentHost.chat,
|
|
373
|
+
agentConversationBackend: agentHost.backend,
|
|
374
|
+
}
|
|
375
|
+
: {}),
|
|
349
376
|
...(providerBoot !== undefined ? { providerBoot } : {}),
|
|
350
377
|
}, { mcpStateless });
|
|
351
378
|
return {
|
|
@@ -374,7 +401,10 @@ export async function bootstrapStageflowHost(options) {
|
|
|
374
401
|
stopGithubPollSource,
|
|
375
402
|
stopEmailSource,
|
|
376
403
|
email: { ...emailHost, triggers: emailTriggers, stop: stopAccountEmail },
|
|
404
|
+
channels,
|
|
405
|
+
memories: memoryHostFor(),
|
|
377
406
|
storeFilesystem,
|
|
378
407
|
workspaceCatalog,
|
|
408
|
+
...(agentHost ? { agentHost } : {}),
|
|
379
409
|
};
|
|
380
410
|
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { IncomingMessage, ServerResponse } from "node:http";
|
|
2
|
+
import type { ChannelService } from "../channels/service.js";
|
|
3
|
+
type Json = (res: ServerResponse, status: number, body: unknown) => void;
|
|
4
|
+
/**
|
|
5
|
+
* Listing, live checks and edits. Request bodies carry secret values on the way in only; nothing
|
|
6
|
+
* the API returns contains one, and failures answer with a code, never the request or its values.
|
|
7
|
+
*/
|
|
8
|
+
export declare function handleChannelRoutes(req: IncomingMessage, method: string, pathname: string, service: ChannelService, res: ServerResponse, json: Json): Promise<boolean>;
|
|
9
|
+
export {};
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import { ChannelError } from "../channels/errors.js";
|
|
2
|
+
import { channelErrorStatus } from "../channels/errorInfo.js";
|
|
3
|
+
const MAX_BODY_BYTES = 65536;
|
|
4
|
+
async function readBody(req) {
|
|
5
|
+
const chunks = [];
|
|
6
|
+
let size = 0;
|
|
7
|
+
for await (const chunk of req) {
|
|
8
|
+
const buffer = typeof chunk === "string" ? Buffer.from(chunk) : chunk;
|
|
9
|
+
size += buffer.length;
|
|
10
|
+
if (size > MAX_BODY_BYTES)
|
|
11
|
+
throw new ChannelError("CHANNEL_RESOURCE_LIMIT");
|
|
12
|
+
chunks.push(buffer);
|
|
13
|
+
}
|
|
14
|
+
if (chunks.length === 0)
|
|
15
|
+
return {};
|
|
16
|
+
try {
|
|
17
|
+
return JSON.parse(Buffer.concat(chunks).toString("utf8"));
|
|
18
|
+
}
|
|
19
|
+
catch {
|
|
20
|
+
throw new ChannelError("CHANNEL_INVALID_INPUT");
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Listing, live checks and edits. Request bodies carry secret values on the way in only; nothing
|
|
25
|
+
* the API returns contains one, and failures answer with a code, never the request or its values.
|
|
26
|
+
*/
|
|
27
|
+
export async function handleChannelRoutes(req, method, pathname, service, res, json) {
|
|
28
|
+
const idMatch = pathname.match(/^\/api\/connections\/([^/]+)(?:\/(check|validate-target))?$/);
|
|
29
|
+
const isCollection = pathname === "/api/connections";
|
|
30
|
+
const isTest = pathname === "/api/connections/test";
|
|
31
|
+
const isMeta = pathname === "/api/connections/meta";
|
|
32
|
+
if (!isCollection && !isTest && !isMeta && !idMatch)
|
|
33
|
+
return false;
|
|
34
|
+
try {
|
|
35
|
+
if (isMeta && method === "GET") {
|
|
36
|
+
json(res, 200, service.meta());
|
|
37
|
+
return true;
|
|
38
|
+
}
|
|
39
|
+
if (isCollection && method === "GET") {
|
|
40
|
+
json(res, 200, service.list());
|
|
41
|
+
return true;
|
|
42
|
+
}
|
|
43
|
+
if (isCollection && method === "POST") {
|
|
44
|
+
json(res, 201, await service.create(await readBody(req)));
|
|
45
|
+
return true;
|
|
46
|
+
}
|
|
47
|
+
if (isTest && method === "POST") {
|
|
48
|
+
json(res, 200, await service.test(await readBody(req)));
|
|
49
|
+
return true;
|
|
50
|
+
}
|
|
51
|
+
if (idMatch) {
|
|
52
|
+
let id;
|
|
53
|
+
try {
|
|
54
|
+
id = decodeURIComponent(idMatch[1]);
|
|
55
|
+
}
|
|
56
|
+
catch {
|
|
57
|
+
throw new ChannelError("CHANNEL_INVALID_INPUT");
|
|
58
|
+
}
|
|
59
|
+
if (idMatch[2] === "check" && method === "POST") {
|
|
60
|
+
const health = await service.checkNow(id);
|
|
61
|
+
if (health)
|
|
62
|
+
json(res, 200, health);
|
|
63
|
+
else
|
|
64
|
+
json(res, 404, { code: "CHANNEL_NOT_FOUND" });
|
|
65
|
+
return true;
|
|
66
|
+
}
|
|
67
|
+
if (idMatch[2] === "validate-target" && method === "POST") {
|
|
68
|
+
json(res, 200, service.validateTarget(id, await readBody(req)));
|
|
69
|
+
return true;
|
|
70
|
+
}
|
|
71
|
+
if (!idMatch[2] && method === "PATCH") {
|
|
72
|
+
json(res, 200, await service.update(id, await readBody(req)));
|
|
73
|
+
return true;
|
|
74
|
+
}
|
|
75
|
+
if (!idMatch[2] && method === "DELETE") {
|
|
76
|
+
await service.remove(id);
|
|
77
|
+
json(res, 200, { removed: true });
|
|
78
|
+
return true;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
catch (error) {
|
|
83
|
+
const code = error instanceof ChannelError ? error.code : "CHANNEL_STORAGE_FAILED";
|
|
84
|
+
json(res, channelErrorStatus(code), { code });
|
|
85
|
+
return true;
|
|
86
|
+
}
|
|
87
|
+
return false;
|
|
88
|
+
}
|
|
@@ -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,
|
package/dist/server/http.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { OVERVIEW_RANGES, buildOverview, isOverviewRange, overviewWindowMs, } from "../runstore/overviewSummary.js";
|
|
1
2
|
import { readFile, access } from "node:fs/promises";
|
|
2
3
|
import { createReadStream, statSync } from "node:fs";
|
|
3
4
|
import path from "node:path";
|
|
@@ -25,7 +26,7 @@ import { createWorkshopBuild, focusUnboundWorkshopBuild, getWorkshopBuild, listW
|
|
|
25
26
|
import { resolveAgentPort } from "../operatorAgent/index.js";
|
|
26
27
|
import { listPipelinesForContext } from "../config/browseCatalog.js";
|
|
27
28
|
import { catalogContextFromStageflow } from "../config/resolveCatalogContext.js";
|
|
28
|
-
import {
|
|
29
|
+
import { listPipelinesMultiProject, listTasksMultiProject, } from "../config/multiProjectCatalog.js";
|
|
29
30
|
import { catalogPathErrorBody, CatalogPathError, resolveCatalogRelativePath, resolveCatalogStartInput, resolveDefaultWriteRoot, resolveWritableCatalogRoot, } from "../config/catalogRelativePath.js";
|
|
30
31
|
import { listExtensions } from "../config/listExtensions.js";
|
|
31
32
|
import { listSkills } from "../config/listSkills.js";
|
|
@@ -36,6 +37,7 @@ import { validateCatalog } from "../config/validateCatalog.js";
|
|
|
36
37
|
import { artifactMediaType, classifyArtifactContent, readRunArtifact, readRunArtifactBytes, } from "../mcp/readArtifact.js";
|
|
37
38
|
import { getRunDiff, listCheckoutChanges, readCheckoutFileBytes, } from "../mcp/checkoutTools.js";
|
|
38
39
|
import { readStageVerificationHistory } from "../runstore/verificationHistory.js";
|
|
40
|
+
import { sqliteConnectionFromStore } from "../runstore/createStore.js";
|
|
39
41
|
import { BackupError, createBackup, resolveBackupDownloadPath, } from "../runstore/backup.js";
|
|
40
42
|
import { RestoreError, resolveBackupNameForRestore, stageRestoreForBoot, } from "../runstore/restore.js";
|
|
41
43
|
import { iterateExportNdjson } from "../cli/exportAllCommand.js";
|
|
@@ -51,6 +53,15 @@ import { isTaskFile } from "../runtime/taskInput.js";
|
|
|
51
53
|
import { findTokenShapedField, tokenRejectedPayload, } from "../runtime/startPayload.js";
|
|
52
54
|
import { parseAskOperatorAnswer } from "../tools/askOperator.js";
|
|
53
55
|
import { handleEmailRoutes } from "./emailRoutes.js";
|
|
56
|
+
import { defaultAgentProjectRoot } from "../agents/projectRoot.js";
|
|
57
|
+
import { PublicWebChat } from "../agents/webChat/publicChat.js";
|
|
58
|
+
import { buildModelsResponse } from "../models/response.js";
|
|
59
|
+
import { createAgentHostContext } from "../agents/hostContext.js";
|
|
60
|
+
import { AgentScheduleSource, agentScheduleTickIntervalMsFromEnv, } from "../agents/scheduleSource.js";
|
|
61
|
+
import { handleAgentAuthorRoutes } from "./agentAuthorRoutes.js";
|
|
62
|
+
import { handleAgentRoutes } from "./agentRoutes.js";
|
|
63
|
+
import { handleChannelRoutes } from "./channelRoutes.js";
|
|
64
|
+
import { handleMemoryRoutes } from "./memoryRoutes.js";
|
|
54
65
|
import { bootstrapStageflowHost, } from "./bootstrap.js";
|
|
55
66
|
import { assertAllowedHttpAccess, isTrustedLocalHttpRequest, resolveAllowedHosts, } from "./allowedHosts.js";
|
|
56
67
|
import { enforceBearerAuth, loadControlTokens, requiredScopeFor, } from "./controlToken.js";
|
|
@@ -172,13 +183,38 @@ export function defaultUiDistDir() {
|
|
|
172
183
|
return path.resolve(here, "../ui");
|
|
173
184
|
}
|
|
174
185
|
export function createOperatorRoutes(deps) {
|
|
175
|
-
const { manager, store, cwd, agentDir, rootDir, providerAuthContext, uiDistDir, workshopOperatorHost, } = deps;
|
|
176
|
-
const
|
|
177
|
-
|
|
178
|
-
|
|
186
|
+
const { manager, store, cwd, agentDir, rootDir, providerAuthContext, uiDistDir, workshopOperatorHost, agentConversationBackend, agentHost: injectedHost, } = deps;
|
|
187
|
+
const agentConnection = injectedHost ? undefined : sqliteConnectionFromStore(store);
|
|
188
|
+
const agentHost = injectedHost ??
|
|
189
|
+
(agentConnection
|
|
190
|
+
? createAgentHostContext({
|
|
179
191
|
cwd,
|
|
180
|
-
|
|
181
|
-
|
|
192
|
+
agentDir,
|
|
193
|
+
connection: agentConnection,
|
|
194
|
+
...(agentConversationBackend ? { backend: agentConversationBackend } : {}),
|
|
195
|
+
})
|
|
196
|
+
: undefined);
|
|
197
|
+
const agentScheduleSource = agentHost
|
|
198
|
+
? new AgentScheduleSource({
|
|
199
|
+
service: agentHost.service,
|
|
200
|
+
projectRoot: defaultAgentProjectRoot(cwd),
|
|
201
|
+
intervalMs: agentScheduleTickIntervalMsFromEnv(),
|
|
202
|
+
})
|
|
203
|
+
: undefined;
|
|
204
|
+
void agentScheduleSource?.start(async (event) => {
|
|
205
|
+
await agentHost.chat.send({
|
|
206
|
+
projectRoot: defaultAgentProjectRoot(cwd),
|
|
207
|
+
agentId: event.agentId,
|
|
208
|
+
text: event.message,
|
|
209
|
+
source: "schedule",
|
|
210
|
+
});
|
|
211
|
+
});
|
|
212
|
+
const operatorHost = workshopOperatorHost ??
|
|
213
|
+
resolveAgentPort({
|
|
214
|
+
cwd,
|
|
215
|
+
projectRoot: cwd,
|
|
216
|
+
});
|
|
217
|
+
const workshopChatRegistry = deps.workshopChatRegistry ?? new WorkshopChatSessionRegistry(operatorHost);
|
|
182
218
|
const workshopSessionStoreRoot = () => resolveWorkshopSessionStoreRoot();
|
|
183
219
|
const workshopBuildStoreRoot = () => resolveWorkshopBuildStoreRoot();
|
|
184
220
|
const allowedHosts = deps.allowedHosts ?? resolveAllowedHosts();
|
|
@@ -214,6 +250,108 @@ export function createOperatorRoutes(deps) {
|
|
|
214
250
|
try {
|
|
215
251
|
if (await liveView.handle(req, res))
|
|
216
252
|
return true;
|
|
253
|
+
if (pathname === "/api/agent-author/chat" || pathname === "/api/agent-author/undo") {
|
|
254
|
+
if (await handleAgentAuthorRoutes(req, method, pathname, cwd, operatorHost, res, json))
|
|
255
|
+
return true;
|
|
256
|
+
}
|
|
257
|
+
if (PublicWebChat.owns(pathname)) {
|
|
258
|
+
if (!agentHost) {
|
|
259
|
+
json(res, 503, { code: "web_chat.unavailable" });
|
|
260
|
+
return true;
|
|
261
|
+
}
|
|
262
|
+
return await agentHost.publicChat.handle(req, res, method, pathname);
|
|
263
|
+
}
|
|
264
|
+
if (method === "GET" && uiDistDir !== undefined && /^\/chat\/[^/]+$/.test(pathname)) {
|
|
265
|
+
const page = path.join(uiDistDir, "chat.html");
|
|
266
|
+
try {
|
|
267
|
+
const html = await readFile(page);
|
|
268
|
+
res.writeHead(200, { "Content-Type": "text/html; charset=utf-8", "Cache-Control": "no-store", "Referrer-Policy": "no-referrer", "X-Robots-Tag": "noindex" });
|
|
269
|
+
res.end(html);
|
|
270
|
+
return true;
|
|
271
|
+
}
|
|
272
|
+
catch {
|
|
273
|
+
json(res, 404, { error: "Chat page not built. Run npm run ui:build." });
|
|
274
|
+
return true;
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
const agentInbound = method === "POST" ? pathname.match(/^\/api\/agent-inbound\/([^/]+)$/) : null;
|
|
278
|
+
if (agentInbound) {
|
|
279
|
+
if (!agentHost) {
|
|
280
|
+
json(res, 503, { code: "agent.store_unavailable" });
|
|
281
|
+
return true;
|
|
282
|
+
}
|
|
283
|
+
const declared = Number(req.headers["content-length"] ?? 0);
|
|
284
|
+
if (declared > 1024 * 1024) {
|
|
285
|
+
json(res, 413, {});
|
|
286
|
+
return true;
|
|
287
|
+
}
|
|
288
|
+
const chunks = [];
|
|
289
|
+
let received = 0;
|
|
290
|
+
for await (const chunk of req) {
|
|
291
|
+
const buffer = typeof chunk === "string" ? Buffer.from(chunk) : chunk;
|
|
292
|
+
received += buffer.length;
|
|
293
|
+
if (received > 1024 * 1024) {
|
|
294
|
+
json(res, 413, {});
|
|
295
|
+
req.destroy();
|
|
296
|
+
return true;
|
|
297
|
+
}
|
|
298
|
+
chunks.push(buffer);
|
|
299
|
+
}
|
|
300
|
+
const raw = Buffer.concat(chunks);
|
|
301
|
+
const headers = {};
|
|
302
|
+
for (const [name, value] of Object.entries(req.headers))
|
|
303
|
+
headers[name] = Array.isArray(value) ? value[0] : value;
|
|
304
|
+
const outcome = await agentHost.inbound.handle(decodeURIComponent(agentInbound[1]), headers, raw.toString("utf8"));
|
|
305
|
+
json(res, outcome.status, outcome.body ?? {});
|
|
306
|
+
return true;
|
|
307
|
+
}
|
|
308
|
+
if (pathname === "/api/agents" || pathname.startsWith("/api/agents/")) {
|
|
309
|
+
if (!agentHost) {
|
|
310
|
+
json(res, 503, { code: "agent.store_unavailable" });
|
|
311
|
+
return true;
|
|
312
|
+
}
|
|
313
|
+
// Default: the Host's own project. An explicit project_root must be a known catalog root
|
|
314
|
+
// (writable for writes); its filesystem path, not its wire id, is where agents/ lives.
|
|
315
|
+
let agentProjectRoot = defaultAgentProjectRoot(cwd);
|
|
316
|
+
const requestedRoot = url.searchParams.get("project_root");
|
|
317
|
+
if (requestedRoot !== null && path.resolve(requestedRoot) !== path.resolve(agentProjectRoot)) {
|
|
318
|
+
try {
|
|
319
|
+
const resolved = method === "GET"
|
|
320
|
+
? await resolveCatalogStartInput({ store, bootCwd: cwd }, requestedRoot)
|
|
321
|
+
: await resolveWritableCatalogRoot({ store, bootCwd: cwd }, requestedRoot);
|
|
322
|
+
agentProjectRoot = resolved.wireRoot.path;
|
|
323
|
+
}
|
|
324
|
+
catch (err) {
|
|
325
|
+
if (err instanceof CatalogPathError) {
|
|
326
|
+
json(res, 400, catalogPathErrorBody(err));
|
|
327
|
+
return true;
|
|
328
|
+
}
|
|
329
|
+
throw err;
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
if (await handleAgentRoutes(req, method, pathname, agentHost, agentProjectRoot, res, json))
|
|
333
|
+
return true;
|
|
334
|
+
}
|
|
335
|
+
if (pathname === "/api/memories" || pathname.startsWith("/api/memories/")) {
|
|
336
|
+
if (!assertAllowedHttpAccess({ entries: [] }, req, res, { requireOrigin: method !== "GET" }))
|
|
337
|
+
return true;
|
|
338
|
+
if (!boot.memories) {
|
|
339
|
+
json(res, 503, { code: "memory.unavailable" });
|
|
340
|
+
return true;
|
|
341
|
+
}
|
|
342
|
+
if (await handleMemoryRoutes(req, method, pathname, boot.memories, res, json))
|
|
343
|
+
return true;
|
|
344
|
+
}
|
|
345
|
+
if (pathname === "/api/connections" || pathname.startsWith("/api/connections/")) {
|
|
346
|
+
if (!assertAllowedHttpAccess({ entries: [] }, req, res, { requireOrigin: method !== "GET" }))
|
|
347
|
+
return true;
|
|
348
|
+
if (!boot.channels) {
|
|
349
|
+
json(res, 503, { code: "CHANNEL_CONNECTION_FAILED" });
|
|
350
|
+
return true;
|
|
351
|
+
}
|
|
352
|
+
if (await handleChannelRoutes(req, method, pathname, boot.channels, res, json))
|
|
353
|
+
return true;
|
|
354
|
+
}
|
|
217
355
|
if (pathname.startsWith("/api/email/")) {
|
|
218
356
|
if (!assertAllowedHttpAccess({ entries: [] }, req, res, { requireOrigin: ["POST", "PATCH", "DELETE"].includes(method) }))
|
|
219
357
|
return true;
|
|
@@ -2719,27 +2857,26 @@ export function createOperatorRoutes(deps) {
|
|
|
2719
2857
|
});
|
|
2720
2858
|
return true;
|
|
2721
2859
|
}
|
|
2722
|
-
if (method === "GET" && pathname === "/api/models") {
|
|
2860
|
+
if ((method === "GET" && pathname === "/api/models") || (method === "POST" && pathname === "/api/models/refresh")) {
|
|
2861
|
+
if (method === "POST" && !assertAllowedHttpAccess({ entries: [] }, req, res, { requireOrigin: true }))
|
|
2862
|
+
return true;
|
|
2723
2863
|
const filter = url.searchParams.get("project_root") ?? undefined;
|
|
2724
|
-
const
|
|
2864
|
+
const { response, used } = await buildModelsResponse({
|
|
2725
2865
|
store,
|
|
2726
|
-
|
|
2866
|
+
cwd,
|
|
2727
2867
|
projectRootFilter: filter,
|
|
2868
|
+
refresh: method === "POST",
|
|
2728
2869
|
});
|
|
2729
|
-
if (
|
|
2730
|
-
|
|
2870
|
+
if (used.root_errors.some((e) => e.code === "unknown_project_root") &&
|
|
2871
|
+
used.items.length === 0) {
|
|
2731
2872
|
json(res, 400, {
|
|
2732
|
-
error:
|
|
2873
|
+
error: used.root_errors[0].message,
|
|
2733
2874
|
code: "unknown_project_root",
|
|
2734
|
-
root_errors:
|
|
2875
|
+
root_errors: used.root_errors,
|
|
2735
2876
|
});
|
|
2736
2877
|
return true;
|
|
2737
2878
|
}
|
|
2738
|
-
json(res, 200,
|
|
2739
|
-
models: result.models,
|
|
2740
|
-
entries: result.items,
|
|
2741
|
-
root_errors: result.root_errors,
|
|
2742
|
-
});
|
|
2879
|
+
json(res, 200, response);
|
|
2743
2880
|
return true;
|
|
2744
2881
|
}
|
|
2745
2882
|
if (await handleProviderRoutes(req, res, {
|
|
@@ -2752,6 +2889,7 @@ export function createOperatorRoutes(deps) {
|
|
|
2752
2889
|
}
|
|
2753
2890
|
if (await handleProjectMcpRoutes(req, res, {
|
|
2754
2891
|
projectRoot: rootDir,
|
|
2892
|
+
readJsonBody,
|
|
2755
2893
|
json,
|
|
2756
2894
|
})) {
|
|
2757
2895
|
return true;
|
|
@@ -2865,6 +3003,20 @@ export function createOperatorRoutes(deps) {
|
|
|
2865
3003
|
await handleApiHealth(req, res, boot);
|
|
2866
3004
|
return true;
|
|
2867
3005
|
}
|
|
3006
|
+
if (method === "GET" && pathname === "/api/overview") {
|
|
3007
|
+
const rangeParam = url.searchParams.get("range") ?? "7d";
|
|
3008
|
+
if (!isOverviewRange(rangeParam)) {
|
|
3009
|
+
json(res, 400, {
|
|
3010
|
+
error: `range must be one of ${OVERVIEW_RANGES.join(", ")}`,
|
|
3011
|
+
code: "invalid_range",
|
|
3012
|
+
});
|
|
3013
|
+
return true;
|
|
3014
|
+
}
|
|
3015
|
+
const now = new Date();
|
|
3016
|
+
const since = new Date(now.getTime() - 2 * overviewWindowMs(rangeParam)).toISOString();
|
|
3017
|
+
json(res, 200, buildOverview(await store.listRunOverviewRows(since), rangeParam, now));
|
|
3018
|
+
return true;
|
|
3019
|
+
}
|
|
2868
3020
|
if (method === "GET" && pathname === "/api/settings") {
|
|
2869
3021
|
const health = manager.getHealth();
|
|
2870
3022
|
const credential = getCredentialSourceSettings(cwd);
|
|
@@ -2961,7 +3113,14 @@ export function createOperatorRoutes(deps) {
|
|
|
2961
3113
|
}
|
|
2962
3114
|
}
|
|
2963
3115
|
};
|
|
2964
|
-
return Object.assign(handler, {
|
|
3116
|
+
return Object.assign(handler, {
|
|
3117
|
+
dispose: async () => {
|
|
3118
|
+
await agentScheduleSource?.stop();
|
|
3119
|
+
if (!injectedHost)
|
|
3120
|
+
await agentHost?.stop();
|
|
3121
|
+
await liveView.dispose();
|
|
3122
|
+
},
|
|
3123
|
+
});
|
|
2965
3124
|
}
|
|
2966
3125
|
export async function startUiServer(options) {
|
|
2967
3126
|
const host = options.host ?? "127.0.0.1";
|
|
@@ -2991,6 +3150,10 @@ export async function startUiServer(options) {
|
|
|
2991
3150
|
...(options.workshopOperatorHost
|
|
2992
3151
|
? { workshopOperatorHost: options.workshopOperatorHost }
|
|
2993
3152
|
: {}),
|
|
3153
|
+
...(boot.agentHost ? { agentHost: boot.agentHost } : {}),
|
|
3154
|
+
...(options.agentConversationBackend
|
|
3155
|
+
? { agentConversationBackend: options.agentConversationBackend }
|
|
3156
|
+
: {}),
|
|
2994
3157
|
});
|
|
2995
3158
|
const envelope = await createHttpHost({
|
|
2996
3159
|
boot,
|
package/dist/server/mcpHost.js
CHANGED
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { IncomingMessage, ServerResponse } from "node:http";
|
|
2
|
+
import { type MemoryHost } from "../memory/host.js";
|
|
3
|
+
type Json = (res: ServerResponse, status: number, body: unknown) => void;
|
|
4
|
+
export declare function handleMemoryRoutes(req: IncomingMessage, method: string, pathname: string, host: MemoryHost, res: ServerResponse, json: Json): Promise<boolean>;
|
|
5
|
+
export {};
|