journal/Journal.App/src/lib/backend/conversations.ts
Jacob Schmidt 2aa9850782 style: apply dotnet format across solution
Co-Authored-By: Oz <oz-agent@warp.dev>
2026-03-01 16:15:04 -06:00

196 lines
4.9 KiB
TypeScript

import { sendCommand } from "./client";
import { pickCase } from "./normalize";
// ── Public types ────────────────────────────────────────────────
export type ConversationDto = {
id: string;
title: string;
createdAt: string;
updatedAt: string;
};
export type ConversationMessageDto = {
id: string;
role: string;
text: string;
createdAt: string;
};
export type ConversationDetailDto = {
id: string;
title: string;
messages: ConversationMessageDto[];
createdAt: string;
updatedAt: string;
};
export type ConversationChatResult = {
userMessage: ConversationMessageDto;
assistantMessage: ConversationMessageDto;
};
// ── Raw (PascalCase) variants ───────────────────────────────────
type ConversationDtoRaw = {
id?: string;
title?: string;
createdAt?: string;
updatedAt?: string;
Id?: string;
Title?: string;
CreatedAt?: string;
UpdatedAt?: string;
};
type ConversationMessageDtoRaw = {
id?: string;
role?: string;
text?: string;
createdAt?: string;
Id?: string;
Role?: string;
Text?: string;
CreatedAt?: string;
};
type ConversationDetailDtoRaw = {
id?: string;
title?: string;
messages?: ConversationMessageDtoRaw[];
createdAt?: string;
updatedAt?: string;
Id?: string;
Title?: string;
Messages?: ConversationMessageDtoRaw[];
CreatedAt?: string;
UpdatedAt?: string;
};
type ConversationChatResultRaw = {
userMessage?: ConversationMessageDtoRaw;
assistantMessage?: ConversationMessageDtoRaw;
UserMessage?: ConversationMessageDtoRaw;
AssistantMessage?: ConversationMessageDtoRaw;
};
// ── Normalizers ─────────────────────────────────────────────────
function normalizeMessage(
raw: ConversationMessageDtoRaw,
): ConversationMessageDto {
return {
id: pickCase(raw, "id", "Id", ""),
role: pickCase(raw, "role", "Role", ""),
text: pickCase(raw, "text", "Text", ""),
createdAt: pickCase(raw, "createdAt", "CreatedAt", ""),
};
}
function normalizeConversation(raw: ConversationDtoRaw): ConversationDto {
return {
id: pickCase(raw, "id", "Id", ""),
title: pickCase(raw, "title", "Title", ""),
createdAt: pickCase(raw, "createdAt", "CreatedAt", ""),
updatedAt: pickCase(raw, "updatedAt", "UpdatedAt", ""),
};
}
function normalizeDetail(raw: ConversationDetailDtoRaw): ConversationDetailDto {
const msgs = pickCase(
raw,
"messages",
"Messages",
[] as ConversationMessageDtoRaw[],
);
return {
id: pickCase(raw, "id", "Id", ""),
title: pickCase(raw, "title", "Title", ""),
messages: msgs.map(normalizeMessage),
createdAt: pickCase(raw, "createdAt", "CreatedAt", ""),
updatedAt: pickCase(raw, "updatedAt", "UpdatedAt", ""),
};
}
function normalizeChatResult(
raw: ConversationChatResultRaw,
): ConversationChatResult {
const userRaw = pickCase(
raw,
"userMessage",
"UserMessage",
{} as ConversationMessageDtoRaw,
);
const assistantRaw = pickCase(
raw,
"assistantMessage",
"AssistantMessage",
{} as ConversationMessageDtoRaw,
);
return {
userMessage: normalizeMessage(userRaw),
assistantMessage: normalizeMessage(assistantRaw),
};
}
// ── API functions ───────────────────────────────────────────────
export async function listConversations(): Promise<ConversationDto[]> {
const data = await sendCommand<ConversationDtoRaw[]>({
action: "conversations.list",
payload: {},
});
return (data ?? []).map(normalizeConversation);
}
export async function getConversation(
id: string,
): Promise<ConversationDetailDto> {
const data = await sendCommand<ConversationDetailDtoRaw>({
action: "conversations.get",
id,
payload: {},
});
return normalizeDetail(data);
}
export async function createConversation(
title: string,
): Promise<ConversationDto> {
const data = await sendCommand<ConversationDtoRaw>({
action: "conversations.create",
payload: { title },
});
return normalizeConversation(data);
}
export async function updateConversation(
id: string,
title: string,
): Promise<boolean> {
return sendCommand<boolean>({
action: "conversations.update",
id,
payload: { title },
});
}
export async function deleteConversation(id: string): Promise<boolean> {
return sendCommand<boolean>({
action: "conversations.delete",
id,
payload: {},
});
}
export async function conversationChat(
conversationId: string,
prompt: string,
): Promise<ConversationChatResult> {
const data = await sendCommand<ConversationChatResultRaw>({
action: "conversations.chat",
payload: { conversationId, prompt },
});
return normalizeChatResult(data);
}