Revert "feat: add conversation schemas (#154)"

This reverts commit be8ad24d7d.
This commit is contained in:
2026-07-02 23:41:26 +01:00
committed by GitHub
parent be8ad24d7d
commit 7f066ab7f3
7 changed files with 54 additions and 354 deletions

View File

@@ -1,24 +1,14 @@
import {
AssistantMessagePayload,
AttachmentPayload,
ConversationEntryKind,
ConversationEntryVisibility,
ContextSummaryPayload,
GenericObjectPayload,
ToolCallPayload,
ToolResultPayload,
UserMessagePayload,
type Conversation,
type ConversationEntry,
} from "@freya/core"
import { type } from "arktype"
import type { Context, Hono } from "hono"
import { ConversationEntryVisibility } from "@freya/core"
import { type } from "arktype"
import { createMiddleware } from "hono/factory"
import type { AuthSessionMiddleware } from "../auth/session-middleware.ts"
import type { Database } from "../db/index.ts"
import type { ConversationRow } from "./storage.ts"
import { ConversationNotFoundError } from "./errors.ts"
import type { ConversationEntryRow, ConversationRow } from "./storage.ts"
import { conversations } from "./storage.ts"
/** Hono environment populated by the conversations route middleware. */
@@ -28,20 +18,19 @@ type Env = {
}
}
/** Serialized conversation summary returned by the list endpoint. */
interface ConversationSummaryResponse {
id: string
createdAt: string
updatedAt: string
}
/** Dependencies required to register conversation HTTP handlers. */
interface ConversationsHttpHandlersDeps {
db: Database
authSessionMiddleware: AuthSessionMiddleware
}
interface ListConversationsResponse {
conversations: Conversation[]
}
interface ListConversationEntriesResponse {
entries: ConversationEntry[]
}
const ConversationIdParam = type("string.uuid")
export function registerConversationsHttpHandlers(
@@ -60,13 +49,12 @@ export function registerConversationsHttpHandlers(
async function handleListConversations(c: Context<Env>) {
const user = c.get("user")!
const db = c.get("db")
const response: ListConversationsResponse = {
return c.json({
conversations: (await conversations(db, user.id).listConversations()).map(
serializeConversation,
),
}
return c.json(response)
})
}
async function handleListEntries(c: Context<Env>) {
@@ -85,11 +73,20 @@ async function handleListEntries(c: Context<Env>) {
const entries = await conversations(db, user.id).listEntries(parsedConversationId, {
visibility: ConversationEntryVisibility.UserVisible,
})
const response: ListConversationEntriesResponse = {
entries: entries.map(serializeConversationEntry),
}
return c.json(response)
return c.json({
entries: entries.map((row) => ({
id: row.id,
conversationId: row.conversationId,
sequence: row.sequence,
kind: row.kind,
visibility: row.visibility,
fileId: row.fileId,
payload: row.payload,
metadata: row.metadata,
createdAt: row.createdAt.toISOString(),
})),
})
} catch (err) {
if (err instanceof ConversationNotFoundError) {
return c.json({ error: "Conversation not found" }, 404)
@@ -98,89 +95,10 @@ async function handleListEntries(c: Context<Env>) {
}
}
function serializeConversation(row: ConversationRow): Conversation {
function serializeConversation(row: ConversationRow): ConversationSummaryResponse {
return {
id: row.id,
createdAt: row.createdAt.toISOString(),
updatedAt: row.updatedAt.toISOString(),
}
}
function serializeConversationEntry(row: ConversationEntryRow): ConversationEntry {
const base = {
id: row.id,
conversationId: row.conversationId,
sequence: row.sequence,
visibility: row.visibility,
metadata: row.metadata,
createdAt: row.createdAt.toISOString(),
}
switch (row.kind) {
case ConversationEntryKind.UserMessage:
return {
...base,
kind: row.kind,
fileId: nullFileId(row),
payload: UserMessagePayload.assert(row.payload),
}
case ConversationEntryKind.AssistantMessage:
return {
...base,
kind: row.kind,
fileId: nullFileId(row),
payload: AssistantMessagePayload.assert(row.payload),
}
case ConversationEntryKind.Attachment:
return {
...base,
kind: row.kind,
fileId: requireFileId(row),
payload: AttachmentPayload.assert(row.payload),
}
case ConversationEntryKind.ToolCall:
return {
...base,
kind: row.kind,
fileId: nullFileId(row),
payload: ToolCallPayload.assert(row.payload),
}
case ConversationEntryKind.ToolResult:
return {
...base,
kind: row.kind,
fileId: nullFileId(row),
payload: ToolResultPayload.assert(row.payload),
}
case ConversationEntryKind.ContextSummary:
return {
...base,
kind: row.kind,
fileId: nullFileId(row),
payload: ContextSummaryPayload.assert(row.payload),
}
case ConversationEntryKind.SystemNote:
return {
...base,
kind: row.kind,
fileId: nullFileId(row),
payload: GenericObjectPayload.assert(row.payload),
}
}
}
function requireFileId(row: ConversationEntryRow): string {
if (!row.fileId) {
throw new Error(`Conversation attachment entry "${row.id}" is missing a file id`)
}
return row.fileId
}
function nullFileId(row: ConversationEntryRow): null {
if (row.fileId !== null) {
throw new Error(`Conversation entry "${row.id}" unexpectedly references a file`)
}
return null
}

View File

@@ -1,4 +1,4 @@
import { AssistantMessagePayload, ConversationEntry, UserMessagePayload } from "@freya/core"
import { AssistantMessagePayload, UserMessagePayload } from "@freya/core"
import { FlashList } from "@shopify/flash-list"
import { useQuery } from "@tanstack/react-query"
import { View, ViewStyle } from "react-native"
@@ -6,6 +6,7 @@ import tw from "twrnc"
import { SansSerifText } from "@/components/ui/sans-serif-text"
import { ConversationEntry } from "./conversations"
import { useListConversationEntriesQuery, useDefaultConversationQuery } from "./queries"
type ConversationListProps = Omit<

View File

@@ -0,0 +1,21 @@
import {
ConversationEntryKind,
ConversationEntryPayload,
ConversationEntryVisibility,
} from "@freya/core"
import { type } from "arktype"
export const Conversation = type({
id: "string.uuid",
createdAt: "string.date.iso",
updatedAt: "string.date.iso",
})
export const ConversationEntry = type({
id: "string.uuid",
sequence: "number",
kind: type.enumerated(...Object.values(ConversationEntryKind)),
visibility: type.enumerated(...Object.values(ConversationEntryVisibility)),
fileId: "string | null",
payload: ConversationEntryPayload,
})

View File

@@ -1,16 +1,15 @@
import { Conversation, ConversationEntry } from "@freya/core"
import { queryOptions, skipToken } from "@tanstack/react-query"
import { type } from "arktype"
import { useApiClient } from "@/api/client"
import { Conversation, ConversationEntry } from "./conversations"
const ListConversationsResponse = type({
"+": "reject",
conversations: Conversation.array(),
})
const ConversationEntriesResponse = type({
"+": "reject",
entries: ConversationEntry.array(),
})