summaryrefslogtreecommitdiffhomepage
path: root/packages/transport-http/src/extension.ts
diff options
context:
space:
mode:
Diffstat (limited to 'packages/transport-http/src/extension.ts')
-rw-r--r--packages/transport-http/src/extension.ts277
1 files changed, 154 insertions, 123 deletions
diff --git a/packages/transport-http/src/extension.ts b/packages/transport-http/src/extension.ts
index 4ab43ce..effbadd 100644
--- a/packages/transport-http/src/extension.ts
+++ b/packages/transport-http/src/extension.ts
@@ -1,140 +1,171 @@
import type { Extension, HostAPI, Manifest } from "@dispatch/kernel";
import { createApp } from "./app.js";
import {
- type ComputerService,
- cacheWarmHandle,
- compactionHandle,
- computerServiceHandle,
- conversationStoreHandle,
- credentialStoreHandle,
- lspServiceHandle,
- mcpServiceHandle,
- sessionOrchestratorHandle,
- systemPromptHandle,
- throughputStoreHandle,
+ type ComputerService,
+ type ConcurrencyService,
+ cacheWarmHandle,
+ compactionHandle,
+ computerServiceHandle,
+ concurrencyServiceHandle,
+ conversationStoreHandle,
+ credentialStoreHandle,
+ heartbeatServiceHandle,
+ type LspService,
+ lspServiceHandle,
+ mcpServiceHandle,
+ sessionOrchestratorHandle,
+ systemPromptHandle,
+ throughputStoreHandle,
} from "./seam.js";
export const manifest: Manifest = {
- id: "transport-http",
- name: "Transport HTTP",
- version: "0.0.0",
- apiVersion: "^0.1.0",
- trust: "bundled",
- dependsOn: [
- "conversation-store",
- "credential-store",
- "lsp",
- "mcp",
- "session-orchestrator",
- "throughput-store",
- ],
- capabilities: { network: true },
- contributes: {
- routes: [
- "/chat",
- "/chat/warm",
- "/computers",
- "/computers/:alias",
- "/computers/:alias/status",
- "/computers/:alias/test",
- "/conversations",
- "/conversations/:id",
- "/conversations/:id/close",
- "/conversations/:id/compact",
- "/conversations/:id/compact-percent",
- "/conversations/:id/computer",
- "/conversations/:id/cwd",
- "/conversations/:id/last",
- "/conversations/:id/lsp",
- "/conversations/:id/mcp",
- "/conversations/:id/open",
- "/conversations/:id/queue",
- "/conversations/:id/reasoning-effort",
- "/conversations/:id/status",
- "/conversations/:id/stop",
- "/conversations/:id/title",
- "/health",
- "/models",
- "/metrics/throughput",
- "/system-prompt",
- "/system-prompt/variables",
- "/workspaces",
- "/workspaces/:id",
- "/workspaces/:id/title",
- "/workspaces/:id/default-cwd",
- "/workspaces/:id/default-computer",
- ],
- },
- activation: "eager",
+ id: "transport-http",
+ name: "Transport HTTP",
+ version: "0.0.0",
+ apiVersion: "^0.1.0",
+ trust: "bundled",
+ dependsOn: [
+ "conversation-store",
+ "credential-store",
+ "heartbeat",
+ "mcp",
+ "session-orchestrator",
+ "throughput-store",
+ ],
+ capabilities: { network: true },
+ contributes: {
+ routes: [
+ "/chat",
+ "/chat/warm",
+ "/computers",
+ "/computers/:alias",
+ "/computers/:alias/status",
+ "/computers/:alias/test",
+ "/concurrency/limits",
+ "/concurrency/limits/:providerId",
+ "/concurrency/status",
+ "/conversations",
+ "/conversations/:id",
+ "/conversations/:id/close",
+ "/conversations/:id/compact",
+ "/conversations/:id/compact-percent",
+ "/conversations/:id/computer",
+ "/conversations/:id/cwd",
+ "/conversations/:id/last",
+ "/conversations/:id/lsp",
+ "/conversations/:id/mcp",
+ "/conversations/:id/open",
+ "/conversations/:id/queue",
+ "/conversations/:id/queue/:messageId",
+ "/conversations/:id/reasoning-effort",
+ "/conversations/:id/status",
+ "/conversations/:id/stop",
+ "/conversations/:id/title",
+ "/health",
+ "/models",
+ "/metrics/throughput",
+ "/system-prompt",
+ "/system-prompt/variables",
+ "/workspaces",
+ "/workspaces/:id",
+ "/workspaces/:id/default-cwd",
+ "/workspaces/:id/default-computer",
+ "/workspaces/:id/heartbeat",
+ "/workspaces/:id/heartbeat/runs",
+ "/workspaces/:id/heartbeat/runs/:runId/stop",
+ "/workspaces/:id/star",
+ "/workspaces/:id/title",
+ ],
+ },
+ activation: "eager",
};
export function createTransportHttpExtension(): Extension & {
- readonly _testServer: ReturnType<typeof Bun.serve> | undefined;
+ readonly _testServer: ReturnType<typeof Bun.serve> | undefined;
} {
- let server: ReturnType<typeof Bun.serve> | undefined;
+ let server: ReturnType<typeof Bun.serve> | undefined;
- return {
- get _testServer() {
- return server;
- },
- manifest,
- async activate(host: HostAPI) {
- const conversationStore = host.getService(conversationStoreHandle);
- const orchestrator = host.getService(sessionOrchestratorHandle);
- const credentialStore = host.getService(credentialStoreHandle);
- const throughputStore = host.getService(throughputStoreHandle);
- const warmService = host.getService(cacheWarmHandle);
- const compactionService = host.getService(compactionHandle);
- const lspService = host.getService(lspServiceHandle);
- const mcpService = host.getService(mcpServiceHandle);
- const systemPromptService = host.getService(systemPromptHandle);
- // Optional: the `ssh` extension provides ComputerService. It is NOT in
- // dependsOn (ssh may be absent), so resolve defensively — when no
- // provider registered the handle, the computer routes degrade to
- // empty/disconnected (see app.ts). Wrapped because getService throws
- // for an unregistered handle.
- let computerService: ComputerService | undefined;
- try {
- computerService = host.getService(computerServiceHandle);
- } catch {
- computerService = undefined;
- }
- const logger = host.logger;
+ return {
+ get _testServer() {
+ return server;
+ },
+ manifest,
+ async activate(host: HostAPI) {
+ const conversationStore = host.getService(conversationStoreHandle);
+ const orchestrator = host.getService(sessionOrchestratorHandle);
+ const credentialStore = host.getService(credentialStoreHandle);
+ const throughputStore = host.getService(throughputStoreHandle);
+ const warmService = host.getService(cacheWarmHandle);
+ const compactionService = host.getService(compactionHandle);
+ // Optional: the `lsp` extension may be disabled (hot-fix). Wrapped because
+ // getService throws for an unregistered handle — degrades to no diagnostics.
+ let lspService: LspService | undefined;
+ try {
+ lspService = host.getService(lspServiceHandle);
+ } catch {
+ lspService = undefined;
+ }
+ const mcpService = host.getService(mcpServiceHandle);
+ const systemPromptService = host.getService(systemPromptHandle);
+ const heartbeatService = host.getService(heartbeatServiceHandle);
+ // Optional: the `ssh` extension provides ComputerService. It is NOT in
+ // dependsOn (ssh may be absent), so resolve defensively — when no
+ // provider registered the handle, the computer routes degrade to
+ // empty/disconnected (see app.ts). Wrapped because getService throws
+ // for an unregistered handle.
+ let computerService: ComputerService | undefined;
+ try {
+ computerService = host.getService(computerServiceHandle);
+ } catch {
+ computerService = undefined;
+ }
+ // Optional: the `provider-concurrency` extension provides the
+ // concurrency limiter service. NOT in dependsOn (may be absent), so
+ // resolve defensively — when absent the /concurrency/* routes degrade.
+ let concurrencyService: ConcurrencyService | undefined;
+ try {
+ concurrencyService = host.getService(concurrencyServiceHandle);
+ } catch {
+ concurrencyService = undefined;
+ }
+ const logger = host.logger;
- const app = createApp({
- conversationStore,
- orchestrator,
- credentialStore,
- throughputStore,
- warmService,
- compactionService,
- lspService,
- mcpService,
- systemPromptService,
- ...(computerService !== undefined ? { computerService } : {}),
- logger,
- emit: host.emit.bind(host),
- ...(process.env.DISPATCH_WEB_DIR !== undefined
- ? { webDir: process.env.DISPATCH_WEB_DIR }
- : {}),
- });
+ const app = createApp({
+ conversationStore,
+ orchestrator,
+ credentialStore,
+ throughputStore,
+ warmService,
+ compactionService,
+ ...(lspService !== undefined ? { lspService } : {}),
+ mcpService,
+ systemPromptService,
+ heartbeatService,
+ ...(computerService !== undefined ? { computerService } : {}),
+ ...(concurrencyService !== undefined ? { concurrencyService } : {}),
+ logger,
+ emit: host.emit.bind(host),
+ ...(process.env.DISPATCH_WEB_DIR !== undefined
+ ? { webDir: process.env.DISPATCH_WEB_DIR }
+ : {}),
+ });
- const port = host.config.get<number>("httpPort") ?? 24203;
+ const port = host.config.get<number>("httpPort") ?? 24203;
- server = Bun.serve({
- port,
- fetch: app.fetch,
- idleTimeout: 0,
- });
+ server = Bun.serve({
+ port,
+ fetch: app.fetch,
+ idleTimeout: 0,
+ });
- logger.info("transport-http: listening", { port });
- },
+ logger.info("transport-http: listening", { port });
+ },
- deactivate() {
- if (server) {
- server.stop();
- server = undefined;
- }
- },
- };
+ deactivate() {
+ if (server) {
+ server.stop();
+ server = undefined;
+ }
+ },
+ };
}