summaryrefslogtreecommitdiffhomepage
path: root/packages/transport-http/src/app.ts
diff options
context:
space:
mode:
authorAdam Malczewski <[email protected]>2026-06-06 19:53:51 +0900
committerAdam Malczewski <[email protected]>2026-06-06 19:53:51 +0900
commit61b6e24c7abb4eebf94da0a0498a68a1bb8ba92e (patch)
tree47f8a60a0c4c51c1fa8beee2cb90fd54abf91c68 /packages/transport-http/src/app.ts
parent44e27177892a48a51c440676ff3f6613deef5164 (diff)
downloaddispatch-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.ts27
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();