11import { auth } from '@databuddy/auth' ;
22import { db , websites } from '@databuddy/db' ;
3+ import { cacheable } from '@databuddy/redis' ;
34import { eq } from 'drizzle-orm' ;
4- import { Elysia , t } from 'elysia' ;
5+ import { Elysia } from 'elysia' ;
6+ import type { StreamingUpdate } from '../agent' ;
57import {
68 type AssistantContext ,
79 type AssistantRequest ,
810 createStreamingResponse ,
911 processAssistantRequest ,
1012} from '../agent' ;
1113import { createRateLimitMiddleware } from '../middleware/rate-limit' ;
14+ import { AssistantRequestSchema } from '../schemas' ;
1215
13- // ============================================================================
14- // SCHEMAS
15- // ============================================================================
16+ // biome-ignore lint/suspicious/useAwait: async generator function doesn't need await
17+ async function * createErrorResponse (
18+ message : string
19+ ) : AsyncGenerator < StreamingUpdate > {
20+ yield { type : 'error' , content : message } ;
21+ }
1622
17- const AssistantRequestSchema = t . Object ( {
18- message : t . String ( ) ,
19- website_id : t . String ( ) ,
20- model : t . Optional (
21- t . Union ( [ t . Literal ( 'chat' ) , t . Literal ( 'agent' ) , t . Literal ( 'agent-max' ) ] )
22- ) ,
23- context : t . Optional (
24- t . Object ( {
25- previousMessages : t . Optional (
26- t . Array (
27- t . Object ( {
28- role : t . Optional ( t . String ( ) ) ,
29- content : t . String ( ) ,
30- } )
31- )
32- ) ,
33- } )
34- ) ,
35- } ) ;
23+ const getCachedWebsite = cacheable (
24+ async ( websiteId : string ) => {
25+ try {
26+ const website = await db . query . websites . findFirst ( {
27+ where : eq ( websites . id , websiteId ) ,
28+ } ) ;
29+ return website || null ;
30+ } catch {
31+ return null ;
32+ }
33+ } ,
34+ {
35+ expireInSec : 300 ,
36+ prefix : 'assistant-website' ,
37+ staleWhileRevalidate : true ,
38+ staleTime : 60 ,
39+ }
40+ ) ;
41+
42+ async function validateWebsite ( websiteId : string ) {
43+ const website = await getCachedWebsite ( websiteId ) ;
3644
37- // ============================================================================
38- // ROUTER SETUP
39- // ============================================================================
45+ if ( ! website ) {
46+ return { success : false , error : 'Website not found' } ;
47+ }
48+
49+ return { success : true , website } ;
50+ }
4051
4152export const assistant = new Elysia ( { prefix : '/v1/assistant' } )
4253 . use ( createRateLimitMiddleware ( { type : 'expensive' } ) )
@@ -56,39 +67,47 @@ export const assistant = new Elysia({ prefix: '/v1/assistant' })
5667 async ( { body, user } ) => {
5768 const { message, website_id, model, context } = body ;
5869
59- // Get website info from the website_id in the body
60- const website = await db . query . websites . findFirst ( {
61- where : eq ( websites . id , website_id ) ,
62- } ) ;
70+ try {
71+ const websiteValidation = await validateWebsite ( website_id ) ;
6372
64- if ( ! website ) {
65- return createStreamingResponse (
66- ( async function * ( ) {
67- yield { type : 'error' , content : 'Website not found' } ;
68- } ) ( )
69- ) ;
70- }
73+ if ( ! websiteValidation . success ) {
74+ return createStreamingResponse (
75+ createErrorResponse ( websiteValidation . error || 'Website not found' )
76+ ) ;
77+ }
78+
79+ const { website } = websiteValidation ;
7180
72- const assistantRequest : AssistantRequest = {
73- message,
74- website_id,
75- website_hostname : website . domain ,
76- model : model || 'chat' ,
77- context,
78- } ;
81+ if ( ! website ) {
82+ return createStreamingResponse (
83+ createErrorResponse ( 'Website not found' )
84+ ) ;
85+ }
7986
80- const assistantContext : AssistantContext = {
81- user,
82- website,
83- debugInfo : { } ,
84- } ;
87+ const assistantRequest : AssistantRequest = {
88+ message,
89+ website_id,
90+ website_hostname : website . domain ,
91+ model : model || 'chat' ,
92+ context,
93+ } ;
8594
86- // Process the assistant request and create streaming response
87- const updates = processAssistantRequest (
88- assistantRequest ,
89- assistantContext
90- ) ;
91- return createStreamingResponse ( updates ) ;
95+ const assistantContext : AssistantContext = {
96+ user,
97+ website,
98+ debugInfo : { } ,
99+ } ;
100+
101+ const updates = processAssistantRequest (
102+ assistantRequest ,
103+ assistantContext
104+ ) ;
105+ return createStreamingResponse ( updates ) ;
106+ } catch ( error ) {
107+ const errorMessage =
108+ error instanceof Error ? error . message : 'Unknown error occurred' ;
109+ return createStreamingResponse ( createErrorResponse ( errorMessage ) ) ;
110+ }
92111 } ,
93112 {
94113 body : AssistantRequestSchema ,
0 commit comments