diff options
| author | Adam Malczewski <[email protected]> | 2026-06-06 19:53:51 +0900 |
|---|---|---|
| committer | Adam Malczewski <[email protected]> | 2026-06-06 19:53:51 +0900 |
| commit | 61b6e24c7abb4eebf94da0a0498a68a1bb8ba92e (patch) | |
| tree | 47f8a60a0c4c51c1fa8beee2cb90fd54abf91c68 /packages/transport-http/src/app.ts | |
| parent | 44e27177892a48a51c440676ff3f6613deef5164 (diff) | |
| download | dispatch-61b6e24c7abb4eebf94da0a0498a68a1bb8ba92e.tar.gz dispatch-61b6e24c7abb4eebf94da0a0498a68a1bb8ba92e.zip | |
feat(transport-http): GET /conversations/:id?sinceSeq= read-side history endpoint
Incremental rehydration endpoint for long-lived clients. Returns
ConversationHistoryResponse { chunks: StoredChunk[], latestSeq } — the RAW,
append-order, seq-filtered slice from conversation-store.loadSince, NOT
reconciled (reconcile conflicts with the per-chunk seq cursor, so it stays on
the turn path; the read path is a pure sync primitive).
- transport-contract: add ConversationHistoryResponse + StoredChunk re-export.
- transport-http: GET /conversations/:id route reaching the log directly via
conversationStoreHandle (dependsOn conversation-store); pure parseSinceSeq
(absent->0, invalid->400).
- build wiring: conversation-store dep + project ref.
FE Slice 2 backend prereq (read-side). typecheck clean, 481 vitest, biome clean.
Diffstat (limited to 'packages/transport-http/src/app.ts')
| -rw-r--r-- | packages/transport-http/src/app.ts | 27 |
1 files changed, 24 insertions, 3 deletions
diff --git a/packages/transport-http/src/app.ts b/packages/transport-http/src/app.ts index d5492ce..5f63683 100644 --- a/packages/transport-http/src/app.ts +++ b/packages/transport-http/src/app.ts @@ -1,10 +1,17 @@ import type { AgentEvent } from "@dispatch/kernel"; -import type { ModelsResponse } from "@dispatch/transport-contract"; +import type { ConversationHistoryResponse, ModelsResponse } from "@dispatch/transport-contract"; import { Hono } from "hono"; -import { isParseError, parseChatBody, serializeEventLine } from "./logic.js"; -import type { CredentialStore, SessionOrchestrator } from "./seam.js"; +import { + isParseError, + isSinceSeqError, + parseChatBody, + parseSinceSeq, + serializeEventLine, +} from "./logic.js"; +import type { ConversationStore, CredentialStore, SessionOrchestrator } from "./seam.js"; export interface CreateServerOptions { + readonly conversationStore: ConversationStore; readonly orchestrator: SessionOrchestrator; readonly credentialStore: CredentialStore; readonly generateId?: () => string; @@ -16,6 +23,20 @@ export function createApp(opts: CreateServerOptions): Hono { app.get("/health", (c) => c.json({ ok: true })); + app.get("/conversations/:id", async (c) => { + const conversationId = c.req.param("id"); + const sinceSeqResult = parseSinceSeq(c.req.query("sinceSeq")); + if (isSinceSeqError(sinceSeqResult)) { + return c.json({ error: sinceSeqResult.error }, 400); + } + + const chunks = await opts.conversationStore.loadSince(conversationId, sinceSeqResult); + const latestSeq = + chunks.length > 0 ? (chunks[chunks.length - 1]?.seq ?? sinceSeqResult) : sinceSeqResult; + const body: ConversationHistoryResponse = { chunks, latestSeq }; + return c.json(body, 200); + }); + app.get("/models", async (c) => { try { const models = await opts.credentialStore.listCatalog(); |
