diff options
Diffstat (limited to 'packages/transport-http/src')
| -rw-r--r-- | packages/transport-http/src/app.test.ts | 25 | ||||
| -rw-r--r-- | packages/transport-http/src/app.ts | 78 | ||||
| -rw-r--r-- | packages/transport-http/src/extension.ts | 5 | ||||
| -rw-r--r-- | packages/transport-http/src/seam.ts | 7 | ||||
| -rw-r--r-- | packages/transport-http/src/server.bun.test.ts | 5 |
5 files changed, 119 insertions, 1 deletions
diff --git a/packages/transport-http/src/app.test.ts b/packages/transport-http/src/app.test.ts index 789efce..51f791f 100644 --- a/packages/transport-http/src/app.test.ts +++ b/packages/transport-http/src/app.test.ts @@ -138,6 +138,11 @@ function createFakeConversationStore( return null; }, async setConversationStatus() {}, + async replaceHistory() {}, + async getCompactThreshold() { + return null; + }, + async setCompactThreshold() {}, }; } @@ -859,6 +864,11 @@ describe("GET /conversations/:id", () => { return null; }, async setConversationStatus() {}, + async replaceHistory() {}, + async getCompactThreshold() { + return null; + }, + async setCompactThreshold() {}, }; const app = createApp({ conversationStore: store, @@ -927,6 +937,11 @@ describe("GET /conversations/:id", () => { return null; }, async setConversationStatus() {}, + async replaceHistory() {}, + async getCompactThreshold() { + return null; + }, + async setCompactThreshold() {}, }; const app = createApp({ conversationStore: store, @@ -1064,6 +1079,11 @@ describe("GET /conversations/:id/metrics", () => { return null; }, async setConversationStatus() {}, + async replaceHistory() {}, + async getCompactThreshold() { + return null; + }, + async setCompactThreshold() {}, }; const app = createApp({ conversationStore: brokenStore, @@ -2034,6 +2054,11 @@ describe("PUT /conversations/:id/reasoning-effort", () => { return null; }, async setConversationStatus() {}, + async replaceHistory() {}, + async getCompactThreshold() { + return null; + }, + async setCompactThreshold() {}, }; const app = createApp({ conversationStore: store, diff --git a/packages/transport-http/src/app.ts b/packages/transport-http/src/app.ts index e9f56c9..fd78f3e 100644 --- a/packages/transport-http/src/app.ts +++ b/packages/transport-http/src/app.ts @@ -1,6 +1,8 @@ import type { AgentEvent, HostAPI, Logger } from "@dispatch/kernel"; import type { CloseConversationResponse, + CompactResponse, + CompactThresholdResponse, ConversationHistoryResponse, ConversationListResponse, ConversationMetricsResponse, @@ -12,6 +14,7 @@ import type { OpenConversationResponse, QueueResponse, ReasoningEffortResponse, + SetCompactThresholdRequest, ThroughputResponse, TitleResponse, WarmResponse, @@ -36,6 +39,7 @@ import { serializeEventLine, } from "./logic.js"; import { + type CompactionService, type ConversationStore, type CredentialStore, conversationOpened, @@ -52,6 +56,7 @@ export interface CreateServerOptions { readonly orchestrator: SessionOrchestrator; readonly credentialStore: CredentialStore; readonly warmService?: WarmService; + readonly compactionService?: CompactionService; readonly lspService?: LspService; /** Optional — defaults to a no-op store (recording disabled, empty reports). */ readonly throughputStore?: ThroughputStore; @@ -683,6 +688,79 @@ export function createApp(opts: CreateServerOptions): Hono { } }); + // ─── Compaction ────────────────────────────────────────────────────────── + + app.post("/conversations/:id/compact", async (c) => { + if (opts.compactionService === undefined) { + return c.json({ error: "Compaction service not available" }, 503); + } + const conversationId = c.req.param("id"); + let body: unknown = {}; + try { + body = await c.req.json(); + } catch { + // No body is fine — use defaults. + } + const obj = body as Record<string, unknown>; + const keepLastN = + typeof obj.keepLastN === "number" && Number.isFinite(obj.keepLastN) && obj.keepLastN > 0 + ? Math.floor(obj.keepLastN) + : undefined; + const modelName = typeof obj.modelName === "string" ? obj.modelName : undefined; + + log.info("conversations: compact request", { conversationId }); + + const result = await opts.compactionService.compact(conversationId, { + ...(keepLastN !== undefined ? { keepLastN } : {}), + ...(modelName !== undefined ? { modelName } : {}), + }); + + if ("error" in result) { + log.warn("conversations: compact returned error", { + conversationId, + error: result.error, + }); + return c.json({ error: result.error }, 409); + } + + const response: CompactResponse = { + conversationId, + messagesSummarized: result.messagesSummarized, + messagesKept: result.messagesKept, + }; + return c.json(response, 200); + }); + + app.get("/conversations/:id/compact-threshold", async (c) => { + const conversationId = c.req.param("id"); + const threshold = (await opts.conversationStore.getCompactThreshold(conversationId)) ?? 0; + const response: CompactThresholdResponse = { conversationId, threshold }; + return c.json(response, 200); + }); + + app.put("/conversations/:id/compact-threshold", async (c) => { + const conversationId = c.req.param("id"); + let body: unknown; + try { + body = await c.req.json(); + } catch { + return c.json({ error: "Invalid JSON body" }, 400); + } + const parsed = body as SetCompactThresholdRequest; + if ( + typeof parsed.threshold !== "number" || + !Number.isFinite(parsed.threshold) || + parsed.threshold < 0 + ) { + return c.json({ error: "threshold must be a non-negative number" }, 400); + } + const threshold = Math.floor(parsed.threshold); + await opts.conversationStore.setCompactThreshold(conversationId, threshold); + log.info("conversations: compact-threshold set", { conversationId, threshold }); + const response: CompactThresholdResponse = { conversationId, threshold }; + return c.json(response, 200); + }); + // ─── Static frontend serving (catch-all, API routes take precedence) ────── if (opts.webDir !== undefined) { const webDir = opts.webDir; diff --git a/packages/transport-http/src/extension.ts b/packages/transport-http/src/extension.ts index 3555f8e..351dd4a 100644 --- a/packages/transport-http/src/extension.ts +++ b/packages/transport-http/src/extension.ts @@ -2,6 +2,7 @@ import type { Extension, HostAPI, Manifest } from "@dispatch/kernel"; import { createApp } from "./app.js"; import { cacheWarmHandle, + compactionHandle, conversationStoreHandle, credentialStoreHandle, lspServiceHandle, @@ -30,6 +31,8 @@ export const manifest: Manifest = { "/conversations", "/conversations/:id", "/conversations/:id/close", + "/conversations/:id/compact", + "/conversations/:id/compact-threshold", "/conversations/:id/cwd", "/conversations/:id/last", "/conversations/:id/lsp", @@ -61,6 +64,7 @@ export function createTransportHttpExtension(): Extension & { 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 logger = host.logger; @@ -70,6 +74,7 @@ export function createTransportHttpExtension(): Extension & { credentialStore, throughputStore, warmService, + compactionService, lspService, logger, emit: host.emit.bind(host), diff --git a/packages/transport-http/src/seam.ts b/packages/transport-http/src/seam.ts index 1c89a34..3c507dc 100644 --- a/packages/transport-http/src/seam.ts +++ b/packages/transport-http/src/seam.ts @@ -4,9 +4,14 @@ export type { CredentialStore } from "@dispatch/credential-store"; export { credentialStoreHandle } from "@dispatch/credential-store"; export type { LspServerStatus, LspService } from "@dispatch/lsp"; export { lspServiceHandle } from "@dispatch/lsp"; -export type { SessionOrchestrator, WarmService } from "@dispatch/session-orchestrator"; +export type { + CompactionService, + SessionOrchestrator, + WarmService, +} from "@dispatch/session-orchestrator"; export { cacheWarmHandle, + compactionHandle, conversationOpened, sessionOrchestratorHandle, } from "@dispatch/session-orchestrator"; diff --git a/packages/transport-http/src/server.bun.test.ts b/packages/transport-http/src/server.bun.test.ts index a15a2c7..e770867 100644 --- a/packages/transport-http/src/server.bun.test.ts +++ b/packages/transport-http/src/server.bun.test.ts @@ -65,6 +65,11 @@ function fakeConversationStore(): ConversationStore { return null; }, async setConversationStatus() {}, + async replaceHistory() {}, + async getCompactThreshold() { + return null; + }, + async setCompactThreshold() {}, }; } |
