From a09a5478cfe4f0c9a4e29b6f0a99e4f1eb2f386b Mon Sep 17 00:00:00 2001 From: Mohammad Kermani Date: Fri, 14 Mar 2025 11:15:28 +0000 Subject: [PATCH 1/2] chore: improve imports --- app/(chat)/adapter.ts | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/app/(chat)/adapter.ts b/app/(chat)/adapter.ts index 06fe0df..0818252 100644 --- a/app/(chat)/adapter.ts +++ b/app/(chat)/adapter.ts @@ -1,14 +1,13 @@ import { Ok, Err, type Result } from 'ts-results-es'; -import type { ApiGetConversationMessagesResponse } from '@/app/(chat)/types'; -import { extractErrorMessageOrDefault } from '@/lib/utils'; - import type { + ApiGetConversationMessagesResponse, ApiCreateConversationResponse, ApiGetConversationResponse, ApiSendMessageResponse, ApiSendMessageStreamedResponse, -} from './types'; +} from '@/app/(chat)/types'; +import { extractErrorMessageOrDefault } from '@/lib/utils'; const patternCoreEndpoint = process.env.PATTERN_CORE_ENDPOINT; if (!patternCoreEndpoint) { From 61dbb0b2e8997b44d734a3b6a0c053ef91e9d7e9 Mon Sep 17 00:00:00 2001 From: Mohammad Kermani Date: Sat, 15 Mar 2025 11:17:25 +0000 Subject: [PATCH 2/2] feat: enable conversations history --- app/(chat)/adapter.ts | 35 ++++++++++++++++++++++++++++ app/(chat)/api/history/route.ts | 22 ++++++++++++++---- app/(chat)/service.ts | 41 ++++++++++++++++++++++++++++++++- app/(chat)/types.ts | 3 +++ 4 files changed, 95 insertions(+), 6 deletions(-) diff --git a/app/(chat)/adapter.ts b/app/(chat)/adapter.ts index 0818252..43582cb 100644 --- a/app/(chat)/adapter.ts +++ b/app/(chat)/adapter.ts @@ -6,6 +6,7 @@ import type { ApiGetConversationResponse, ApiSendMessageResponse, ApiSendMessageStreamedResponse, + ApiGetAllConversationsResponse, } from '@/app/(chat)/types'; import { extractErrorMessageOrDefault } from '@/lib/utils'; @@ -231,3 +232,37 @@ export const sendMessageStreamed = async ( return Err(extractErrorMessageOrDefault(error)); } }; + +/** + * Get all conversations + * @param accessToken + * @returns result containing all conversations of current user + */ +export const getAllConversations = async ( + accessToken: string, + projectId: string, +): Promise> => { + try { + const allConversationsResponse = await fetch( + `${patternCoreEndpoint}/playground/conversation/${projectId}`, + { + headers: { + Authorization: `Bearer ${accessToken}`, + 'Content-Type': 'application/json', + }, + }, + ); + if (allConversationsResponse.ok) { + const allConversations: ApiGetAllConversationsResponse = ( + await allConversationsResponse.json() + ).data; + + return Ok(allConversations); + } + return Err( + `Fetching projects failed with error code ${allConversationsResponse.status}`, + ); + } catch (error) { + return Err(extractErrorMessageOrDefault(error)); + } +}; diff --git a/app/(chat)/api/history/route.ts b/app/(chat)/api/history/route.ts index 5b796ac..56ae00b 100644 --- a/app/(chat)/api/history/route.ts +++ b/app/(chat)/api/history/route.ts @@ -1,14 +1,26 @@ import { auth } from '@/app/(auth)/auth'; -import { getChatsByUserId } from '@/lib/db/queries'; + +import { getAllChats } from '../../service'; export async function GET() { const session = await auth(); - if (!session || !session.user) { + if ( + !session || + !session.chainId || + !session.address || + !session.accessToken + ) { return Response.json('Unauthorized!', { status: 401 }); } - // biome-ignore lint: Forbidden non-null assertion. - const chats = await getChatsByUserId({ id: session.user.id! }); - return Response.json(chats); + const chatsResult = await getAllChats(session.accessToken, session.projectId); + + if (chatsResult.isErr()) { + return new Response(chatsResult.error, { status: 400 }); + } + + const allChats = chatsResult.value; + + return Response.json(allChats); } diff --git a/app/(chat)/service.ts b/app/(chat)/service.ts index a2af95b..e8757e5 100644 --- a/app/(chat)/service.ts +++ b/app/(chat)/service.ts @@ -1,6 +1,12 @@ import { type Result, Err, Ok } from 'ts-results-es'; -import { createConversation, getConversation } from './adapter'; +import type { Chat } from '@/lib/db/schema'; + +import { + createConversation, + getAllConversations, + getConversation, +} from './adapter'; import type { Conversation } from './types'; /** @@ -41,6 +47,39 @@ export const getOrCreateConversation = async ( return Ok(conversation); }; +/** + * fetches all of current user's conversations and transforms it into + * ui-friendly chats + * @param accessToken + * @param projectId + * @returns result containing ui-friendly chats list + */ +export const getAllChats = async ( + accessToken: string, + projectId: string, +): Promise> => { + const allConversationsResult = await getAllConversations( + accessToken, + projectId, + ); + + if (allConversationsResult.isErr()) { + return Err(allConversationsResult.error); + } + + const allConversations = allConversationsResult.value; + + const history: Chat[] = allConversations.map((conversation) => ({ + createdAt: new Date(conversation.updated_at), + id: conversation.id, + title: conversation.name, + userId: conversation.user_id, + visibility: 'private', + })); + + return Ok(history); +}; + export { sendMessage, sendMessageStreamed, diff --git a/app/(chat)/types.ts b/app/(chat)/types.ts index c48a13f..e6b93a1 100644 --- a/app/(chat)/types.ts +++ b/app/(chat)/types.ts @@ -2,6 +2,8 @@ export interface Conversation { id: string; name: string; project_id: string; + user_id: string; + updated_at: string; } export interface Message { @@ -14,3 +16,4 @@ export type ApiGetConversationMessagesResponse = Message[]; export type ApiCreateConversationResponse = Conversation; export type ApiSendMessageResponse = string; export type ApiSendMessageStreamedResponse = ReadableStream; +export type ApiGetAllConversationsResponse = Conversation[];