chat-utils.ts 1.7 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556
  1. // Pure helper functions extracted from ChatBar for reuse in ChatPage and tests.
  2. interface ChatMessage {
  3. readonly role: "user" | "assistant";
  4. readonly content: string;
  5. readonly timestamp: number;
  6. }
  7. interface SharedSessionMeta {
  8. readonly activeBookId?: string;
  9. readonly automationMode?: string;
  10. readonly currentStage?: string;
  11. readonly pendingSummary?: string;
  12. readonly draftTitle?: string;
  13. }
  14. interface BookRef {
  15. readonly id: string;
  16. }
  17. export function coerceSharedSessionMessages(
  18. messages: ReadonlyArray<{ role: "user" | "assistant" | "system"; content: string; timestamp: number }>,
  19. ): ReadonlyArray<ChatMessage> {
  20. return messages
  21. .filter((message) => message.role === "user" || message.role === "assistant")
  22. .map((message) => ({
  23. role: message.role as "user" | "assistant",
  24. content: message.content,
  25. timestamp: message.timestamp,
  26. }));
  27. }
  28. export function resolveDirectWriteTarget(
  29. activeBookId: string | undefined,
  30. books: ReadonlyArray<BookRef>,
  31. ): { bookId: string | null; reason: "active" | "single" | "missing" | "ambiguous" } {
  32. if (activeBookId && books.some((book) => book.id === activeBookId)) {
  33. return { bookId: activeBookId, reason: "active" };
  34. }
  35. if (books.length === 1) {
  36. return { bookId: books[0]!.id, reason: "single" };
  37. }
  38. if (books.length === 0) {
  39. return { bookId: null, reason: "missing" };
  40. }
  41. return { bookId: null, reason: "ambiguous" };
  42. }
  43. export function formatSharedSessionContext(meta: SharedSessionMeta): string {
  44. return [
  45. meta.activeBookId ?? "no-book",
  46. meta.draftTitle ? `draft:${meta.draftTitle}` : undefined,
  47. meta.automationMode ?? "semi",
  48. meta.currentStage,
  49. ].filter(Boolean).join(" · ");
  50. }