feat: support resuming ongoing streams (#974)
This commit is contained in:
parent
45978c27a2
commit
a3221fbcdc
13 changed files with 1005 additions and 47 deletions
1
.github/workflows/playwright.yml
vendored
1
.github/workflows/playwright.yml
vendored
|
|
@ -13,6 +13,7 @@ jobs:
|
||||||
AUTH_SECRET: ${{ secrets.AUTH_SECRET }}
|
AUTH_SECRET: ${{ secrets.AUTH_SECRET }}
|
||||||
POSTGRES_URL: ${{ secrets.POSTGRES_URL }}
|
POSTGRES_URL: ${{ secrets.POSTGRES_URL }}
|
||||||
BLOB_READ_WRITE_TOKEN: ${{ secrets.BLOB_READ_WRITE_TOKEN }}
|
BLOB_READ_WRITE_TOKEN: ${{ secrets.BLOB_READ_WRITE_TOKEN }}
|
||||||
|
REDIS_URL: ${{ secrets.REDIS_URL }}
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
|
|
|
||||||
|
|
@ -1,17 +1,19 @@
|
||||||
import {
|
import {
|
||||||
appendClientMessage,
|
appendClientMessage,
|
||||||
appendResponseMessages,
|
appendResponseMessages,
|
||||||
createDataStreamResponse,
|
createDataStream,
|
||||||
smoothStream,
|
smoothStream,
|
||||||
streamText,
|
streamText,
|
||||||
} from 'ai';
|
} from 'ai';
|
||||||
import { auth, type UserType } from '@/app/(auth)/auth';
|
import { auth, type UserType } from '@/app/(auth)/auth';
|
||||||
import { type RequestHints, systemPrompt } from '@/lib/ai/prompts';
|
import { type RequestHints, systemPrompt } from '@/lib/ai/prompts';
|
||||||
import {
|
import {
|
||||||
|
createStreamId,
|
||||||
deleteChatById,
|
deleteChatById,
|
||||||
getChatById,
|
getChatById,
|
||||||
getMessageCountByUserId,
|
getMessageCountByUserId,
|
||||||
getMessagesByChatId,
|
getMessagesByChatId,
|
||||||
|
getStreamIdsByChatId,
|
||||||
saveChat,
|
saveChat,
|
||||||
saveMessages,
|
saveMessages,
|
||||||
} from '@/lib/db/queries';
|
} from '@/lib/db/queries';
|
||||||
|
|
@ -26,9 +28,16 @@ import { myProvider } from '@/lib/ai/providers';
|
||||||
import { entitlementsByUserType } from '@/lib/ai/entitlements';
|
import { entitlementsByUserType } from '@/lib/ai/entitlements';
|
||||||
import { postRequestBodySchema, type PostRequestBody } from './schema';
|
import { postRequestBodySchema, type PostRequestBody } from './schema';
|
||||||
import { geolocation } from '@vercel/functions';
|
import { geolocation } from '@vercel/functions';
|
||||||
|
import { createResumableStreamContext } from 'resumable-stream';
|
||||||
|
import { after } from 'next/server';
|
||||||
|
import type { Chat } from '@/lib/db/schema';
|
||||||
|
|
||||||
export const maxDuration = 60;
|
export const maxDuration = 60;
|
||||||
|
|
||||||
|
const streamContext = createResumableStreamContext({
|
||||||
|
waitUntil: after,
|
||||||
|
});
|
||||||
|
|
||||||
export async function POST(request: Request) {
|
export async function POST(request: Request) {
|
||||||
let requestBody: PostRequestBody;
|
let requestBody: PostRequestBody;
|
||||||
|
|
||||||
|
|
@ -108,7 +117,10 @@ export async function POST(request: Request) {
|
||||||
],
|
],
|
||||||
});
|
});
|
||||||
|
|
||||||
return createDataStreamResponse({
|
const streamId = generateUUID();
|
||||||
|
await createStreamId({ streamId, chatId: id });
|
||||||
|
|
||||||
|
const stream = createDataStream({
|
||||||
execute: (dataStream) => {
|
execute: (dataStream) => {
|
||||||
const result = streamText({
|
const result = streamText({
|
||||||
model: myProvider.languageModel(selectedChatModel),
|
model: myProvider.languageModel(selectedChatModel),
|
||||||
|
|
@ -187,6 +199,10 @@ export async function POST(request: Request) {
|
||||||
return 'Oops, an error occurred!';
|
return 'Oops, an error occurred!';
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
return new Response(
|
||||||
|
await streamContext.resumableStream(streamId, () => stream),
|
||||||
|
);
|
||||||
} catch (_) {
|
} catch (_) {
|
||||||
return new Response('An error occurred while processing your request!', {
|
return new Response('An error occurred while processing your request!', {
|
||||||
status: 500,
|
status: 500,
|
||||||
|
|
@ -194,6 +210,60 @@ export async function POST(request: Request) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function GET(request: Request) {
|
||||||
|
const { searchParams } = new URL(request.url);
|
||||||
|
const chatId = searchParams.get('chatId');
|
||||||
|
|
||||||
|
if (!chatId) {
|
||||||
|
return new Response('id is required', { status: 400 });
|
||||||
|
}
|
||||||
|
|
||||||
|
const session = await auth();
|
||||||
|
|
||||||
|
if (!session?.user) {
|
||||||
|
return new Response('Unauthorized', { status: 401 });
|
||||||
|
}
|
||||||
|
|
||||||
|
let chat: Chat;
|
||||||
|
|
||||||
|
try {
|
||||||
|
chat = await getChatById({ id: chatId });
|
||||||
|
} catch {
|
||||||
|
return new Response('Not found', { status: 404 });
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!chat) {
|
||||||
|
return new Response('Not found', { status: 404 });
|
||||||
|
}
|
||||||
|
|
||||||
|
if (chat.userId !== session.user.id) {
|
||||||
|
return new Response('Forbidden', { status: 403 });
|
||||||
|
}
|
||||||
|
|
||||||
|
const streamIds = await getStreamIdsByChatId({ chatId });
|
||||||
|
|
||||||
|
if (!streamIds.length) {
|
||||||
|
return new Response('No streams found', { status: 404 });
|
||||||
|
}
|
||||||
|
|
||||||
|
const recentStreamId = streamIds.at(-1);
|
||||||
|
|
||||||
|
if (!recentStreamId) {
|
||||||
|
return new Response('No recent stream found', { status: 404 });
|
||||||
|
}
|
||||||
|
|
||||||
|
const emptyDataStream = createDataStream({
|
||||||
|
execute: () => {},
|
||||||
|
});
|
||||||
|
|
||||||
|
return new Response(
|
||||||
|
await streamContext.resumableStream(recentStreamId, () => emptyDataStream),
|
||||||
|
{
|
||||||
|
status: 200,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
export async function DELETE(request: Request) {
|
export async function DELETE(request: Request) {
|
||||||
const { searchParams } = new URL(request.url);
|
const { searchParams } = new URL(request.url);
|
||||||
const id = searchParams.get('id');
|
const id = searchParams.get('id');
|
||||||
|
|
@ -219,6 +289,7 @@ export async function DELETE(request: Request) {
|
||||||
|
|
||||||
return Response.json(deletedChat, { status: 200 });
|
return Response.json(deletedChat, { status: 200 });
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
console.error(error);
|
||||||
return new Response('An error occurred while processing your request!', {
|
return new Response('An error occurred while processing your request!', {
|
||||||
status: 500,
|
status: 500,
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -64,6 +64,7 @@ export default async function Page(props: { params: Promise<{ id: string }> }) {
|
||||||
selectedVisibilityType={chat.visibility}
|
selectedVisibilityType={chat.visibility}
|
||||||
isReadonly={session?.user?.id !== chat.userId}
|
isReadonly={session?.user?.id !== chat.userId}
|
||||||
session={session}
|
session={session}
|
||||||
|
autoResume={true}
|
||||||
/>
|
/>
|
||||||
<DataStreamHandler id={id} />
|
<DataStreamHandler id={id} />
|
||||||
</>
|
</>
|
||||||
|
|
@ -79,6 +80,7 @@ export default async function Page(props: { params: Promise<{ id: string }> }) {
|
||||||
selectedVisibilityType={chat.visibility}
|
selectedVisibilityType={chat.visibility}
|
||||||
isReadonly={session?.user?.id !== chat.userId}
|
isReadonly={session?.user?.id !== chat.userId}
|
||||||
session={session}
|
session={session}
|
||||||
|
autoResume={true}
|
||||||
/>
|
/>
|
||||||
<DataStreamHandler id={id} />
|
<DataStreamHandler id={id} />
|
||||||
</>
|
</>
|
||||||
|
|
|
||||||
|
|
@ -30,6 +30,7 @@ export default async function Page() {
|
||||||
selectedVisibilityType="private"
|
selectedVisibilityType="private"
|
||||||
isReadonly={false}
|
isReadonly={false}
|
||||||
session={session}
|
session={session}
|
||||||
|
autoResume={false}
|
||||||
/>
|
/>
|
||||||
<DataStreamHandler id={id} />
|
<DataStreamHandler id={id} />
|
||||||
</>
|
</>
|
||||||
|
|
@ -46,6 +47,7 @@ export default async function Page() {
|
||||||
selectedVisibilityType="private"
|
selectedVisibilityType="private"
|
||||||
isReadonly={false}
|
isReadonly={false}
|
||||||
session={session}
|
session={session}
|
||||||
|
autoResume={false}
|
||||||
/>
|
/>
|
||||||
<DataStreamHandler id={id} />
|
<DataStreamHandler id={id} />
|
||||||
</>
|
</>
|
||||||
|
|
|
||||||
|
|
@ -25,6 +25,7 @@ export function Chat({
|
||||||
selectedVisibilityType,
|
selectedVisibilityType,
|
||||||
isReadonly,
|
isReadonly,
|
||||||
session,
|
session,
|
||||||
|
autoResume,
|
||||||
}: {
|
}: {
|
||||||
id: string;
|
id: string;
|
||||||
initialMessages: Array<UIMessage>;
|
initialMessages: Array<UIMessage>;
|
||||||
|
|
@ -32,6 +33,7 @@ export function Chat({
|
||||||
selectedVisibilityType: VisibilityType;
|
selectedVisibilityType: VisibilityType;
|
||||||
isReadonly: boolean;
|
isReadonly: boolean;
|
||||||
session: Session;
|
session: Session;
|
||||||
|
autoResume: boolean;
|
||||||
}) {
|
}) {
|
||||||
const { mutate } = useSWRConfig();
|
const { mutate } = useSWRConfig();
|
||||||
|
|
||||||
|
|
@ -45,6 +47,7 @@ export function Chat({
|
||||||
status,
|
status,
|
||||||
stop,
|
stop,
|
||||||
reload,
|
reload,
|
||||||
|
experimental_resume,
|
||||||
} = useChat({
|
} = useChat({
|
||||||
id,
|
id,
|
||||||
initialMessages,
|
initialMessages,
|
||||||
|
|
@ -67,6 +70,15 @@ export function Chat({
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (autoResume) {
|
||||||
|
experimental_resume();
|
||||||
|
}
|
||||||
|
|
||||||
|
// note: this hook has no dependencies since it only needs to run once
|
||||||
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
|
}, []);
|
||||||
|
|
||||||
const searchParams = useSearchParams();
|
const searchParams = useSearchParams();
|
||||||
const query = searchParams.get('query');
|
const query = searchParams.get('query');
|
||||||
|
|
||||||
|
|
|
||||||
12
lib/db/migrations/0006_marvelous_frog_thor.sql
Normal file
12
lib/db/migrations/0006_marvelous_frog_thor.sql
Normal file
|
|
@ -0,0 +1,12 @@
|
||||||
|
CREATE TABLE IF NOT EXISTS "Stream" (
|
||||||
|
"id" uuid DEFAULT gen_random_uuid() NOT NULL,
|
||||||
|
"chatId" uuid NOT NULL,
|
||||||
|
"createdAt" timestamp NOT NULL,
|
||||||
|
CONSTRAINT "Stream_id_pk" PRIMARY KEY("id")
|
||||||
|
);
|
||||||
|
--> statement-breakpoint
|
||||||
|
DO $$ BEGIN
|
||||||
|
ALTER TABLE "Stream" ADD CONSTRAINT "Stream_chatId_Chat_id_fk" FOREIGN KEY ("chatId") REFERENCES "public"."Chat"("id") ON DELETE no action ON UPDATE no action;
|
||||||
|
EXCEPTION
|
||||||
|
WHEN duplicate_object THEN null;
|
||||||
|
END $$;
|
||||||
565
lib/db/migrations/meta/0006_snapshot.json
Normal file
565
lib/db/migrations/meta/0006_snapshot.json
Normal file
|
|
@ -0,0 +1,565 @@
|
||||||
|
{
|
||||||
|
"id": "443de550-b7e8-4bfb-b229-c12dc6c132f0",
|
||||||
|
"prevId": "c6c102e6-b64e-4f0c-a7a6-32df758de437",
|
||||||
|
"version": "7",
|
||||||
|
"dialect": "postgresql",
|
||||||
|
"tables": {
|
||||||
|
"public.Chat": {
|
||||||
|
"name": "Chat",
|
||||||
|
"schema": "",
|
||||||
|
"columns": {
|
||||||
|
"id": {
|
||||||
|
"name": "id",
|
||||||
|
"type": "uuid",
|
||||||
|
"primaryKey": true,
|
||||||
|
"notNull": true,
|
||||||
|
"default": "gen_random_uuid()"
|
||||||
|
},
|
||||||
|
"createdAt": {
|
||||||
|
"name": "createdAt",
|
||||||
|
"type": "timestamp",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"title": {
|
||||||
|
"name": "title",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"userId": {
|
||||||
|
"name": "userId",
|
||||||
|
"type": "uuid",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"visibility": {
|
||||||
|
"name": "visibility",
|
||||||
|
"type": "varchar",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"default": "'private'"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"indexes": {},
|
||||||
|
"foreignKeys": {
|
||||||
|
"Chat_userId_User_id_fk": {
|
||||||
|
"name": "Chat_userId_User_id_fk",
|
||||||
|
"tableFrom": "Chat",
|
||||||
|
"tableTo": "User",
|
||||||
|
"columnsFrom": [
|
||||||
|
"userId"
|
||||||
|
],
|
||||||
|
"columnsTo": [
|
||||||
|
"id"
|
||||||
|
],
|
||||||
|
"onDelete": "no action",
|
||||||
|
"onUpdate": "no action"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"compositePrimaryKeys": {},
|
||||||
|
"uniqueConstraints": {}
|
||||||
|
},
|
||||||
|
"public.Document": {
|
||||||
|
"name": "Document",
|
||||||
|
"schema": "",
|
||||||
|
"columns": {
|
||||||
|
"id": {
|
||||||
|
"name": "id",
|
||||||
|
"type": "uuid",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"default": "gen_random_uuid()"
|
||||||
|
},
|
||||||
|
"createdAt": {
|
||||||
|
"name": "createdAt",
|
||||||
|
"type": "timestamp",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"title": {
|
||||||
|
"name": "title",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"content": {
|
||||||
|
"name": "content",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
"text": {
|
||||||
|
"name": "text",
|
||||||
|
"type": "varchar",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"default": "'text'"
|
||||||
|
},
|
||||||
|
"userId": {
|
||||||
|
"name": "userId",
|
||||||
|
"type": "uuid",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"indexes": {},
|
||||||
|
"foreignKeys": {
|
||||||
|
"Document_userId_User_id_fk": {
|
||||||
|
"name": "Document_userId_User_id_fk",
|
||||||
|
"tableFrom": "Document",
|
||||||
|
"tableTo": "User",
|
||||||
|
"columnsFrom": [
|
||||||
|
"userId"
|
||||||
|
],
|
||||||
|
"columnsTo": [
|
||||||
|
"id"
|
||||||
|
],
|
||||||
|
"onDelete": "no action",
|
||||||
|
"onUpdate": "no action"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"compositePrimaryKeys": {
|
||||||
|
"Document_id_createdAt_pk": {
|
||||||
|
"name": "Document_id_createdAt_pk",
|
||||||
|
"columns": [
|
||||||
|
"id",
|
||||||
|
"createdAt"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"uniqueConstraints": {}
|
||||||
|
},
|
||||||
|
"public.Message_v2": {
|
||||||
|
"name": "Message_v2",
|
||||||
|
"schema": "",
|
||||||
|
"columns": {
|
||||||
|
"id": {
|
||||||
|
"name": "id",
|
||||||
|
"type": "uuid",
|
||||||
|
"primaryKey": true,
|
||||||
|
"notNull": true,
|
||||||
|
"default": "gen_random_uuid()"
|
||||||
|
},
|
||||||
|
"chatId": {
|
||||||
|
"name": "chatId",
|
||||||
|
"type": "uuid",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"role": {
|
||||||
|
"name": "role",
|
||||||
|
"type": "varchar",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"parts": {
|
||||||
|
"name": "parts",
|
||||||
|
"type": "json",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"attachments": {
|
||||||
|
"name": "attachments",
|
||||||
|
"type": "json",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"createdAt": {
|
||||||
|
"name": "createdAt",
|
||||||
|
"type": "timestamp",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"indexes": {},
|
||||||
|
"foreignKeys": {
|
||||||
|
"Message_v2_chatId_Chat_id_fk": {
|
||||||
|
"name": "Message_v2_chatId_Chat_id_fk",
|
||||||
|
"tableFrom": "Message_v2",
|
||||||
|
"tableTo": "Chat",
|
||||||
|
"columnsFrom": [
|
||||||
|
"chatId"
|
||||||
|
],
|
||||||
|
"columnsTo": [
|
||||||
|
"id"
|
||||||
|
],
|
||||||
|
"onDelete": "no action",
|
||||||
|
"onUpdate": "no action"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"compositePrimaryKeys": {},
|
||||||
|
"uniqueConstraints": {}
|
||||||
|
},
|
||||||
|
"public.Message": {
|
||||||
|
"name": "Message",
|
||||||
|
"schema": "",
|
||||||
|
"columns": {
|
||||||
|
"id": {
|
||||||
|
"name": "id",
|
||||||
|
"type": "uuid",
|
||||||
|
"primaryKey": true,
|
||||||
|
"notNull": true,
|
||||||
|
"default": "gen_random_uuid()"
|
||||||
|
},
|
||||||
|
"chatId": {
|
||||||
|
"name": "chatId",
|
||||||
|
"type": "uuid",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"role": {
|
||||||
|
"name": "role",
|
||||||
|
"type": "varchar",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"content": {
|
||||||
|
"name": "content",
|
||||||
|
"type": "json",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"createdAt": {
|
||||||
|
"name": "createdAt",
|
||||||
|
"type": "timestamp",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"indexes": {},
|
||||||
|
"foreignKeys": {
|
||||||
|
"Message_chatId_Chat_id_fk": {
|
||||||
|
"name": "Message_chatId_Chat_id_fk",
|
||||||
|
"tableFrom": "Message",
|
||||||
|
"tableTo": "Chat",
|
||||||
|
"columnsFrom": [
|
||||||
|
"chatId"
|
||||||
|
],
|
||||||
|
"columnsTo": [
|
||||||
|
"id"
|
||||||
|
],
|
||||||
|
"onDelete": "no action",
|
||||||
|
"onUpdate": "no action"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"compositePrimaryKeys": {},
|
||||||
|
"uniqueConstraints": {}
|
||||||
|
},
|
||||||
|
"public.Stream": {
|
||||||
|
"name": "Stream",
|
||||||
|
"schema": "",
|
||||||
|
"columns": {
|
||||||
|
"id": {
|
||||||
|
"name": "id",
|
||||||
|
"type": "uuid",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"default": "gen_random_uuid()"
|
||||||
|
},
|
||||||
|
"chatId": {
|
||||||
|
"name": "chatId",
|
||||||
|
"type": "uuid",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"createdAt": {
|
||||||
|
"name": "createdAt",
|
||||||
|
"type": "timestamp",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"indexes": {},
|
||||||
|
"foreignKeys": {
|
||||||
|
"Stream_chatId_Chat_id_fk": {
|
||||||
|
"name": "Stream_chatId_Chat_id_fk",
|
||||||
|
"tableFrom": "Stream",
|
||||||
|
"tableTo": "Chat",
|
||||||
|
"columnsFrom": [
|
||||||
|
"chatId"
|
||||||
|
],
|
||||||
|
"columnsTo": [
|
||||||
|
"id"
|
||||||
|
],
|
||||||
|
"onDelete": "no action",
|
||||||
|
"onUpdate": "no action"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"compositePrimaryKeys": {
|
||||||
|
"Stream_id_pk": {
|
||||||
|
"name": "Stream_id_pk",
|
||||||
|
"columns": [
|
||||||
|
"id"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"uniqueConstraints": {}
|
||||||
|
},
|
||||||
|
"public.Suggestion": {
|
||||||
|
"name": "Suggestion",
|
||||||
|
"schema": "",
|
||||||
|
"columns": {
|
||||||
|
"id": {
|
||||||
|
"name": "id",
|
||||||
|
"type": "uuid",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"default": "gen_random_uuid()"
|
||||||
|
},
|
||||||
|
"documentId": {
|
||||||
|
"name": "documentId",
|
||||||
|
"type": "uuid",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"documentCreatedAt": {
|
||||||
|
"name": "documentCreatedAt",
|
||||||
|
"type": "timestamp",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"originalText": {
|
||||||
|
"name": "originalText",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"suggestedText": {
|
||||||
|
"name": "suggestedText",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"description": {
|
||||||
|
"name": "description",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
"isResolved": {
|
||||||
|
"name": "isResolved",
|
||||||
|
"type": "boolean",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"default": false
|
||||||
|
},
|
||||||
|
"userId": {
|
||||||
|
"name": "userId",
|
||||||
|
"type": "uuid",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"createdAt": {
|
||||||
|
"name": "createdAt",
|
||||||
|
"type": "timestamp",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"indexes": {},
|
||||||
|
"foreignKeys": {
|
||||||
|
"Suggestion_userId_User_id_fk": {
|
||||||
|
"name": "Suggestion_userId_User_id_fk",
|
||||||
|
"tableFrom": "Suggestion",
|
||||||
|
"tableTo": "User",
|
||||||
|
"columnsFrom": [
|
||||||
|
"userId"
|
||||||
|
],
|
||||||
|
"columnsTo": [
|
||||||
|
"id"
|
||||||
|
],
|
||||||
|
"onDelete": "no action",
|
||||||
|
"onUpdate": "no action"
|
||||||
|
},
|
||||||
|
"Suggestion_documentId_documentCreatedAt_Document_id_createdAt_fk": {
|
||||||
|
"name": "Suggestion_documentId_documentCreatedAt_Document_id_createdAt_fk",
|
||||||
|
"tableFrom": "Suggestion",
|
||||||
|
"tableTo": "Document",
|
||||||
|
"columnsFrom": [
|
||||||
|
"documentId",
|
||||||
|
"documentCreatedAt"
|
||||||
|
],
|
||||||
|
"columnsTo": [
|
||||||
|
"id",
|
||||||
|
"createdAt"
|
||||||
|
],
|
||||||
|
"onDelete": "no action",
|
||||||
|
"onUpdate": "no action"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"compositePrimaryKeys": {
|
||||||
|
"Suggestion_id_pk": {
|
||||||
|
"name": "Suggestion_id_pk",
|
||||||
|
"columns": [
|
||||||
|
"id"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"uniqueConstraints": {}
|
||||||
|
},
|
||||||
|
"public.User": {
|
||||||
|
"name": "User",
|
||||||
|
"schema": "",
|
||||||
|
"columns": {
|
||||||
|
"id": {
|
||||||
|
"name": "id",
|
||||||
|
"type": "uuid",
|
||||||
|
"primaryKey": true,
|
||||||
|
"notNull": true,
|
||||||
|
"default": "gen_random_uuid()"
|
||||||
|
},
|
||||||
|
"email": {
|
||||||
|
"name": "email",
|
||||||
|
"type": "varchar(64)",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"password": {
|
||||||
|
"name": "password",
|
||||||
|
"type": "varchar(64)",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"indexes": {},
|
||||||
|
"foreignKeys": {},
|
||||||
|
"compositePrimaryKeys": {},
|
||||||
|
"uniqueConstraints": {}
|
||||||
|
},
|
||||||
|
"public.Vote_v2": {
|
||||||
|
"name": "Vote_v2",
|
||||||
|
"schema": "",
|
||||||
|
"columns": {
|
||||||
|
"chatId": {
|
||||||
|
"name": "chatId",
|
||||||
|
"type": "uuid",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"messageId": {
|
||||||
|
"name": "messageId",
|
||||||
|
"type": "uuid",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"isUpvoted": {
|
||||||
|
"name": "isUpvoted",
|
||||||
|
"type": "boolean",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"indexes": {},
|
||||||
|
"foreignKeys": {
|
||||||
|
"Vote_v2_chatId_Chat_id_fk": {
|
||||||
|
"name": "Vote_v2_chatId_Chat_id_fk",
|
||||||
|
"tableFrom": "Vote_v2",
|
||||||
|
"tableTo": "Chat",
|
||||||
|
"columnsFrom": [
|
||||||
|
"chatId"
|
||||||
|
],
|
||||||
|
"columnsTo": [
|
||||||
|
"id"
|
||||||
|
],
|
||||||
|
"onDelete": "no action",
|
||||||
|
"onUpdate": "no action"
|
||||||
|
},
|
||||||
|
"Vote_v2_messageId_Message_v2_id_fk": {
|
||||||
|
"name": "Vote_v2_messageId_Message_v2_id_fk",
|
||||||
|
"tableFrom": "Vote_v2",
|
||||||
|
"tableTo": "Message_v2",
|
||||||
|
"columnsFrom": [
|
||||||
|
"messageId"
|
||||||
|
],
|
||||||
|
"columnsTo": [
|
||||||
|
"id"
|
||||||
|
],
|
||||||
|
"onDelete": "no action",
|
||||||
|
"onUpdate": "no action"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"compositePrimaryKeys": {
|
||||||
|
"Vote_v2_chatId_messageId_pk": {
|
||||||
|
"name": "Vote_v2_chatId_messageId_pk",
|
||||||
|
"columns": [
|
||||||
|
"chatId",
|
||||||
|
"messageId"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"uniqueConstraints": {}
|
||||||
|
},
|
||||||
|
"public.Vote": {
|
||||||
|
"name": "Vote",
|
||||||
|
"schema": "",
|
||||||
|
"columns": {
|
||||||
|
"chatId": {
|
||||||
|
"name": "chatId",
|
||||||
|
"type": "uuid",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"messageId": {
|
||||||
|
"name": "messageId",
|
||||||
|
"type": "uuid",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"isUpvoted": {
|
||||||
|
"name": "isUpvoted",
|
||||||
|
"type": "boolean",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"indexes": {},
|
||||||
|
"foreignKeys": {
|
||||||
|
"Vote_chatId_Chat_id_fk": {
|
||||||
|
"name": "Vote_chatId_Chat_id_fk",
|
||||||
|
"tableFrom": "Vote",
|
||||||
|
"tableTo": "Chat",
|
||||||
|
"columnsFrom": [
|
||||||
|
"chatId"
|
||||||
|
],
|
||||||
|
"columnsTo": [
|
||||||
|
"id"
|
||||||
|
],
|
||||||
|
"onDelete": "no action",
|
||||||
|
"onUpdate": "no action"
|
||||||
|
},
|
||||||
|
"Vote_messageId_Message_id_fk": {
|
||||||
|
"name": "Vote_messageId_Message_id_fk",
|
||||||
|
"tableFrom": "Vote",
|
||||||
|
"tableTo": "Message",
|
||||||
|
"columnsFrom": [
|
||||||
|
"messageId"
|
||||||
|
],
|
||||||
|
"columnsTo": [
|
||||||
|
"id"
|
||||||
|
],
|
||||||
|
"onDelete": "no action",
|
||||||
|
"onUpdate": "no action"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"compositePrimaryKeys": {
|
||||||
|
"Vote_chatId_messageId_pk": {
|
||||||
|
"name": "Vote_chatId_messageId_pk",
|
||||||
|
"columns": [
|
||||||
|
"chatId",
|
||||||
|
"messageId"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"uniqueConstraints": {}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"enums": {},
|
||||||
|
"schemas": {},
|
||||||
|
"sequences": {},
|
||||||
|
"_meta": {
|
||||||
|
"columns": {},
|
||||||
|
"schemas": {},
|
||||||
|
"tables": {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -43,6 +43,13 @@
|
||||||
"when": 1741934630596,
|
"when": 1741934630596,
|
||||||
"tag": "0005_wooden_whistler",
|
"tag": "0005_wooden_whistler",
|
||||||
"breakpoints": true
|
"breakpoints": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idx": 6,
|
||||||
|
"version": "7",
|
||||||
|
"when": 1746118166211,
|
||||||
|
"tag": "0006_marvelous_frog_thor",
|
||||||
|
"breakpoints": true
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
@ -26,6 +26,7 @@ import {
|
||||||
vote,
|
vote,
|
||||||
type DBMessage,
|
type DBMessage,
|
||||||
type Chat,
|
type Chat,
|
||||||
|
stream,
|
||||||
} from './schema';
|
} from './schema';
|
||||||
import type { ArtifactKind } from '@/components/artifact';
|
import type { ArtifactKind } from '@/components/artifact';
|
||||||
import { generateUUID } from '../utils';
|
import { generateUUID } from '../utils';
|
||||||
|
|
@ -100,6 +101,7 @@ export async function deleteChatById({ id }: { id: string }) {
|
||||||
try {
|
try {
|
||||||
await db.delete(vote).where(eq(vote.chatId, id));
|
await db.delete(vote).where(eq(vote.chatId, id));
|
||||||
await db.delete(message).where(eq(message.chatId, id));
|
await db.delete(message).where(eq(message.chatId, id));
|
||||||
|
await db.delete(stream).where(eq(stream.chatId, id));
|
||||||
|
|
||||||
const [chatsDeleted] = await db
|
const [chatsDeleted] = await db
|
||||||
.delete(chat)
|
.delete(chat)
|
||||||
|
|
@ -470,3 +472,36 @@ export async function getMessageCountByUserId({
|
||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function createStreamId({
|
||||||
|
streamId,
|
||||||
|
chatId,
|
||||||
|
}: {
|
||||||
|
streamId: string;
|
||||||
|
chatId: string;
|
||||||
|
}) {
|
||||||
|
try {
|
||||||
|
await db
|
||||||
|
.insert(stream)
|
||||||
|
.values({ id: streamId, chatId, createdAt: new Date() });
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Failed to create stream id in database');
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function getStreamIdsByChatId({ chatId }: { chatId: string }) {
|
||||||
|
try {
|
||||||
|
const streamIds = await db
|
||||||
|
.select({ id: stream.id })
|
||||||
|
.from(stream)
|
||||||
|
.where(eq(stream.chatId, chatId))
|
||||||
|
.orderBy(desc(stream.createdAt))
|
||||||
|
.execute();
|
||||||
|
|
||||||
|
return streamIds.map(({ id }) => id);
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Failed to get stream ids by chat id from database');
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -150,3 +150,21 @@ export const suggestion = pgTable(
|
||||||
);
|
);
|
||||||
|
|
||||||
export type Suggestion = InferSelectModel<typeof suggestion>;
|
export type Suggestion = InferSelectModel<typeof suggestion>;
|
||||||
|
|
||||||
|
export const stream = pgTable(
|
||||||
|
'Stream',
|
||||||
|
{
|
||||||
|
id: uuid('id').notNull().defaultRandom(),
|
||||||
|
chatId: uuid('chatId').notNull(),
|
||||||
|
createdAt: timestamp('createdAt').notNull(),
|
||||||
|
},
|
||||||
|
(table) => ({
|
||||||
|
pk: primaryKey({ columns: [table.id] }),
|
||||||
|
chatRef: foreignKey({
|
||||||
|
columns: [table.chatId],
|
||||||
|
foreignColumns: [chat.id],
|
||||||
|
}),
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
|
export type Stream = InferSelectModel<typeof stream>;
|
||||||
|
|
|
||||||
10
package.json
10
package.json
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "ai-chatbot",
|
"name": "ai-chatbot",
|
||||||
"version": "3.0.15",
|
"version": "3.0.16",
|
||||||
"private": true,
|
"private": true,
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "next dev --turbo",
|
"dev": "next dev --turbo",
|
||||||
|
|
@ -19,8 +19,8 @@
|
||||||
"test": "export PLAYWRIGHT=True && pnpm exec playwright test"
|
"test": "export PLAYWRIGHT=True && pnpm exec playwright test"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@ai-sdk/react": "^1.2.8",
|
"@ai-sdk/react": "^1.2.11",
|
||||||
"@ai-sdk/xai": "^1.2.10",
|
"@ai-sdk/xai": "^1.2.15",
|
||||||
"@codemirror/lang-javascript": "^6.2.2",
|
"@codemirror/lang-javascript": "^6.2.2",
|
||||||
"@codemirror/lang-python": "^6.1.6",
|
"@codemirror/lang-python": "^6.1.6",
|
||||||
"@codemirror/state": "^6.5.0",
|
"@codemirror/state": "^6.5.0",
|
||||||
|
|
@ -40,7 +40,7 @@
|
||||||
"@vercel/blob": "^0.24.1",
|
"@vercel/blob": "^0.24.1",
|
||||||
"@vercel/functions": "^2.0.0",
|
"@vercel/functions": "^2.0.0",
|
||||||
"@vercel/postgres": "^0.10.0",
|
"@vercel/postgres": "^0.10.0",
|
||||||
"ai": "4.3.4",
|
"ai": "4.3.13",
|
||||||
"bcrypt-ts": "^5.0.2",
|
"bcrypt-ts": "^5.0.2",
|
||||||
"class-variance-authority": "^0.7.0",
|
"class-variance-authority": "^0.7.0",
|
||||||
"classnames": "^2.5.1",
|
"classnames": "^2.5.1",
|
||||||
|
|
@ -74,7 +74,9 @@
|
||||||
"react-dom": "19.0.0-rc-45804af1-20241021",
|
"react-dom": "19.0.0-rc-45804af1-20241021",
|
||||||
"react-markdown": "^9.0.1",
|
"react-markdown": "^9.0.1",
|
||||||
"react-resizable-panels": "^2.1.7",
|
"react-resizable-panels": "^2.1.7",
|
||||||
|
"redis": "^5.0.0",
|
||||||
"remark-gfm": "^4.0.0",
|
"remark-gfm": "^4.0.0",
|
||||||
|
"resumable-stream": "^2.0.0",
|
||||||
"server-only": "^0.0.1",
|
"server-only": "^0.0.1",
|
||||||
"sonner": "^1.5.0",
|
"sonner": "^1.5.0",
|
||||||
"swr": "^2.2.5",
|
"swr": "^2.2.5",
|
||||||
|
|
|
||||||
159
pnpm-lock.yaml
generated
159
pnpm-lock.yaml
generated
|
|
@ -9,11 +9,11 @@ importers:
|
||||||
.:
|
.:
|
||||||
dependencies:
|
dependencies:
|
||||||
'@ai-sdk/react':
|
'@ai-sdk/react':
|
||||||
specifier: ^1.2.8
|
specifier: ^1.2.11
|
||||||
version: 1.2.8(react@19.0.0-rc-45804af1-20241021)(zod@3.24.2)
|
version: 1.2.11(react@19.0.0-rc-45804af1-20241021)(zod@3.24.2)
|
||||||
'@ai-sdk/xai':
|
'@ai-sdk/xai':
|
||||||
specifier: ^1.2.10
|
specifier: ^1.2.15
|
||||||
version: 1.2.10(zod@3.24.2)
|
version: 1.2.15(zod@3.24.2)
|
||||||
'@codemirror/lang-javascript':
|
'@codemirror/lang-javascript':
|
||||||
specifier: ^6.2.2
|
specifier: ^6.2.2
|
||||||
version: 6.2.3
|
version: 6.2.3
|
||||||
|
|
@ -72,8 +72,8 @@ importers:
|
||||||
specifier: ^0.10.0
|
specifier: ^0.10.0
|
||||||
version: 0.10.0
|
version: 0.10.0
|
||||||
ai:
|
ai:
|
||||||
specifier: 4.3.4
|
specifier: 4.3.13
|
||||||
version: 4.3.4(react@19.0.0-rc-45804af1-20241021)(zod@3.24.2)
|
version: 4.3.13(react@19.0.0-rc-45804af1-20241021)(zod@3.24.2)
|
||||||
bcrypt-ts:
|
bcrypt-ts:
|
||||||
specifier: ^5.0.2
|
specifier: ^5.0.2
|
||||||
version: 5.0.3
|
version: 5.0.3
|
||||||
|
|
@ -173,9 +173,15 @@ importers:
|
||||||
react-resizable-panels:
|
react-resizable-panels:
|
||||||
specifier: ^2.1.7
|
specifier: ^2.1.7
|
||||||
version: 2.1.7(react-dom@19.0.0-rc-45804af1-20241021(react@19.0.0-rc-45804af1-20241021))(react@19.0.0-rc-45804af1-20241021)
|
version: 2.1.7(react-dom@19.0.0-rc-45804af1-20241021(react@19.0.0-rc-45804af1-20241021))(react@19.0.0-rc-45804af1-20241021)
|
||||||
|
redis:
|
||||||
|
specifier: ^5.0.0
|
||||||
|
version: 5.0.0
|
||||||
remark-gfm:
|
remark-gfm:
|
||||||
specifier: ^4.0.0
|
specifier: ^4.0.0
|
||||||
version: 4.0.1
|
version: 4.0.1
|
||||||
|
resumable-stream:
|
||||||
|
specifier: ^2.0.0
|
||||||
|
version: 2.0.0
|
||||||
server-only:
|
server-only:
|
||||||
specifier: ^0.0.1
|
specifier: ^0.0.1
|
||||||
version: 0.0.1
|
version: 0.0.1
|
||||||
|
|
@ -258,24 +264,24 @@ importers:
|
||||||
|
|
||||||
packages:
|
packages:
|
||||||
|
|
||||||
'@ai-sdk/openai-compatible@0.2.8':
|
'@ai-sdk/openai-compatible@0.2.13':
|
||||||
resolution: {integrity: sha512-o1CrhTrXnMj72G44oBqlDDBtunw6iwONysXj7EYN/Fx27rhP7YTcWwVeKs5gMx/u/8TIho9iZ9rkqXXc2xg8Bg==}
|
resolution: {integrity: sha512-tB+lL8Z3j0qDod/mvxwjrPhbLUHp/aQW+NvMoJaqeTtP+Vmv5qR800pncGczxn5WN0pllQm+7aIRDnm69XeSbg==}
|
||||||
engines: {node: '>=18'}
|
engines: {node: '>=18'}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
zod: ^3.0.0
|
zod: ^3.0.0
|
||||||
|
|
||||||
'@ai-sdk/provider-utils@2.2.6':
|
'@ai-sdk/provider-utils@2.2.7':
|
||||||
resolution: {integrity: sha512-sUlZ7Gnq84DCGWMQRIK8XVbkzIBnvPR1diV4v6JwPgpn5armnLI/j+rqn62MpLrU5ZCQZlDKl/Lw6ed3ulYqaA==}
|
resolution: {integrity: sha512-kM0xS3GWg3aMChh9zfeM+80vEZfXzR3JEUBdycZLtbRZ2TRT8xOj3WodGHPb06sUK5yD7pAXC/P7ctsi2fvUGQ==}
|
||||||
engines: {node: '>=18'}
|
engines: {node: '>=18'}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
zod: ^3.23.8
|
zod: ^3.23.8
|
||||||
|
|
||||||
'@ai-sdk/provider@1.1.2':
|
'@ai-sdk/provider@1.1.3':
|
||||||
resolution: {integrity: sha512-ITdgNilJZwLKR7X5TnUr1BsQW6UTX5yFp0h66Nfx8XjBYkWD9W3yugr50GOz3CnE9m/U/Cd5OyEbTMI0rgi6ZQ==}
|
resolution: {integrity: sha512-qZMxYJ0qqX/RfnuIaab+zp8UAeJn/ygXXAffR5I4N0n1IrvA6qBsjc8hXLmBiMV2zoXlifkacF7sEFnYnjBcqg==}
|
||||||
engines: {node: '>=18'}
|
engines: {node: '>=18'}
|
||||||
|
|
||||||
'@ai-sdk/react@1.2.8':
|
'@ai-sdk/react@1.2.11':
|
||||||
resolution: {integrity: sha512-S2FzCSi4uTF0JuSN6zYMXyiAWVAzi/Hho8ISYgHpGZiICYLNCP2si4DuXQOsnWef3IXzQPLVoE11C63lILZIkw==}
|
resolution: {integrity: sha512-+kPqLkJ3TWP6czaJPV+vzAKSUcKQ1598BUrcLHt56sH99+LhmIIW3ylZp0OfC3O6TR3eO1Lt0Yzw4R0mK6g9Gw==}
|
||||||
engines: {node: '>=18'}
|
engines: {node: '>=18'}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
react: ^18 || ^19 || ^19.0.0-rc
|
react: ^18 || ^19 || ^19.0.0-rc
|
||||||
|
|
@ -284,14 +290,14 @@ packages:
|
||||||
zod:
|
zod:
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
'@ai-sdk/ui-utils@1.2.7':
|
'@ai-sdk/ui-utils@1.2.10':
|
||||||
resolution: {integrity: sha512-OVRxa4SDj0wVsMZ8tGr/whT89oqNtNoXBKmqWC2BRv5ZG6azL2LYZ5ZK35u3lb4l1IE7cWGsLlmq0py0ttsL7A==}
|
resolution: {integrity: sha512-GUj+LBoAlRQF1dL/M49jtufGqtLOMApxTpCmVjoRpIPt/dFALVL9RfqfvxwztyIwbK+IxGzcYjSGRsrWrj+86g==}
|
||||||
engines: {node: '>=18'}
|
engines: {node: '>=18'}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
zod: ^3.23.8
|
zod: ^3.23.8
|
||||||
|
|
||||||
'@ai-sdk/xai@1.2.10':
|
'@ai-sdk/xai@1.2.15':
|
||||||
resolution: {integrity: sha512-jPaOq7HHJ9A7FF3i/zngcUd6jczFMJF1x9Ayle4IxCZ2gIhtLgv0hiUb1X95keh/gCHjtelBQdzLFNNuiPBadQ==}
|
resolution: {integrity: sha512-18qEYyVHIqTiOMePE00bfx4kJrTHM4dV3D3Rpe+eBISlY80X1FnzZRnRTJo3Q6MOSmW5+ZKVaX9jtryhoFpn0A==}
|
||||||
engines: {node: '>=18'}
|
engines: {node: '>=18'}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
zod: ^3.0.0
|
zod: ^3.0.0
|
||||||
|
|
@ -1480,6 +1486,34 @@ packages:
|
||||||
'@radix-ui/rect@1.1.0':
|
'@radix-ui/rect@1.1.0':
|
||||||
resolution: {integrity: sha512-A9+lCBZoaMJlVKcRBz2YByCG+Cp2t6nAnMnNba+XiWxnj6r4JUFqfsgwocMBZU9LPtdxC6wB56ySYpc7LQIoJg==}
|
resolution: {integrity: sha512-A9+lCBZoaMJlVKcRBz2YByCG+Cp2t6nAnMnNba+XiWxnj6r4JUFqfsgwocMBZU9LPtdxC6wB56ySYpc7LQIoJg==}
|
||||||
|
|
||||||
|
'@redis/bloom@5.0.0':
|
||||||
|
resolution: {integrity: sha512-YHlra6a7+brJ3Ustqa+jC68Pdnw2/wbnVLeULN0llP3gHpKxOSmiDyLwuHq5t/jFi6QUgjSprUQi2a8CieKFIA==}
|
||||||
|
engines: {node: '>= 18'}
|
||||||
|
peerDependencies:
|
||||||
|
'@redis/client': ^5.0.0
|
||||||
|
|
||||||
|
'@redis/client@5.0.0':
|
||||||
|
resolution: {integrity: sha512-1MqfzOOoFBwWprigJ3S5hM+LuzaWwxyyx+74NDzCpmjKWyjjC07xkWsd5E9fr+61NUDtvUivRiyAxGiRIwJCaQ==}
|
||||||
|
engines: {node: '>= 18'}
|
||||||
|
|
||||||
|
'@redis/json@5.0.0':
|
||||||
|
resolution: {integrity: sha512-8YFjshsvWR9dWjOiQ50TfBxfl+z1mjCae8jDnfOYN1aCvUZWJXqM1OpL56v6mWRyXwZ5C9qJJKDGmHTr4PVskQ==}
|
||||||
|
engines: {node: '>= 18'}
|
||||||
|
peerDependencies:
|
||||||
|
'@redis/client': ^5.0.0
|
||||||
|
|
||||||
|
'@redis/search@5.0.0':
|
||||||
|
resolution: {integrity: sha512-oEop/S/0NB5p7vpTTlp5X5LQO4oTomJnFEOaKhQ5xZWROLXTgEVvPSfXVNBbtr9maU2+OupxXQR63HW3MGeTUg==}
|
||||||
|
engines: {node: '>= 18'}
|
||||||
|
peerDependencies:
|
||||||
|
'@redis/client': ^5.0.0
|
||||||
|
|
||||||
|
'@redis/time-series@5.0.0':
|
||||||
|
resolution: {integrity: sha512-DNsP4DH5CRfXlQDyvLJm2DltZm3kjpVKZsNTI3SPdbRxhc9i2c0NehUbM/gDECnEfG+jkNN/LUv6Em4LaLwPBQ==}
|
||||||
|
engines: {node: '>= 18'}
|
||||||
|
peerDependencies:
|
||||||
|
'@redis/client': ^5.0.0
|
||||||
|
|
||||||
'@rtsao/scc@1.1.0':
|
'@rtsao/scc@1.1.0':
|
||||||
resolution: {integrity: sha512-zt6OdqaDoOnJ1ZYsCYGt9YmWzDXl4vQdKTyJev62gFhRGKdx7mcT54V9KIjg+d2wi9EXsPvAPKe7i7WjfVWB8g==}
|
resolution: {integrity: sha512-zt6OdqaDoOnJ1ZYsCYGt9YmWzDXl4vQdKTyJev62gFhRGKdx7mcT54V9KIjg+d2wi9EXsPvAPKe7i7WjfVWB8g==}
|
||||||
|
|
||||||
|
|
@ -1655,8 +1689,8 @@ packages:
|
||||||
engines: {node: '>=0.4.0'}
|
engines: {node: '>=0.4.0'}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
|
|
||||||
ai@4.3.4:
|
ai@4.3.13:
|
||||||
resolution: {integrity: sha512-uMjzrowIqfU8CCCxhx8QGl7ETydHBROeNL0VoEwetkmDCY6Q8ZTacj6jNNqGJOiCk595aUrGR9VHPY9Ylvy1fg==}
|
resolution: {integrity: sha512-cC5HXItuOwGykSMacCPzNp6+NMTxeuTjOenztVgSJhdC9Z4OrzBxwkyeDAf4h1QP938ZFi7IBdq3u4lxVoVmvw==}
|
||||||
engines: {node: '>=18'}
|
engines: {node: '>=18'}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
react: ^18 || ^19 || ^19.0.0-rc
|
react: ^18 || ^19 || ^19.0.0-rc
|
||||||
|
|
@ -1865,6 +1899,10 @@ packages:
|
||||||
resolution: {integrity: sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==}
|
resolution: {integrity: sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==}
|
||||||
engines: {node: '>=6'}
|
engines: {node: '>=6'}
|
||||||
|
|
||||||
|
cluster-key-slot@1.1.2:
|
||||||
|
resolution: {integrity: sha512-RMr0FhtfXemyinomL4hrWcYJxmX6deFdCxpJzhDttxgO1+bcCnkk+9drydLVDmAMG7NE6aN/fl4F7ucU/90gAA==}
|
||||||
|
engines: {node: '>=0.10.0'}
|
||||||
|
|
||||||
codemirror@6.0.1:
|
codemirror@6.0.1:
|
||||||
resolution: {integrity: sha512-J8j+nZ+CdWmIeFIGXEFbFPtpiYacFMDR8GlHK3IyHQJMCaVRfGx9NT+Hxivv1ckLWPvNdZqndbr/7lVhrf/Svg==}
|
resolution: {integrity: sha512-J8j+nZ+CdWmIeFIGXEFbFPtpiYacFMDR8GlHK3IyHQJMCaVRfGx9NT+Hxivv1ckLWPvNdZqndbr/7lVhrf/Svg==}
|
||||||
|
|
||||||
|
|
@ -3375,6 +3413,10 @@ packages:
|
||||||
resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==}
|
resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==}
|
||||||
engines: {node: '>=8.10.0'}
|
engines: {node: '>=8.10.0'}
|
||||||
|
|
||||||
|
redis@5.0.0:
|
||||||
|
resolution: {integrity: sha512-J/fzf0cYeFw5NP4aYIvv9owYOcNUsaDqF4qmwbSuaV4yKBLaIHJQIFbAKLgjn99GDXdJBbfqCRXE7+BIlkpATA==}
|
||||||
|
engines: {node: '>= 18'}
|
||||||
|
|
||||||
reflect.getprototypeof@1.0.10:
|
reflect.getprototypeof@1.0.10:
|
||||||
resolution: {integrity: sha512-00o4I+DVrefhv+nX0ulyi3biSHCPDe+yLv5o/p6d/UVlirijB8E16FtfwSAi4g3tcqrQ4lRAqQSoFEZJehYEcw==}
|
resolution: {integrity: sha512-00o4I+DVrefhv+nX0ulyi3biSHCPDe+yLv5o/p6d/UVlirijB8E16FtfwSAi4g3tcqrQ4lRAqQSoFEZJehYEcw==}
|
||||||
engines: {node: '>= 0.4'}
|
engines: {node: '>= 0.4'}
|
||||||
|
|
@ -3411,6 +3453,9 @@ packages:
|
||||||
resolution: {integrity: sha512-U7WjGVG9sH8tvjW5SmGbQuui75FiyjAX72HX15DwBBwF9dNiQZRQAg9nnPhYy+TUnE0+VcrttuvNI8oSxZcocA==}
|
resolution: {integrity: sha512-U7WjGVG9sH8tvjW5SmGbQuui75FiyjAX72HX15DwBBwF9dNiQZRQAg9nnPhYy+TUnE0+VcrttuvNI8oSxZcocA==}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
|
|
||||||
|
resumable-stream@2.0.0:
|
||||||
|
resolution: {integrity: sha512-D7E0wDUnfoy+Lerba/gyuD44OG3G0APqDcQ9soMSerujaVujPLWc5sSCLXf/ZFQPreLb3MKDjSm3TOPXpNtpZw==}
|
||||||
|
|
||||||
retry@0.13.1:
|
retry@0.13.1:
|
||||||
resolution: {integrity: sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg==}
|
resolution: {integrity: sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg==}
|
||||||
engines: {node: '>= 4'}
|
engines: {node: '>= 4'}
|
||||||
|
|
@ -3870,45 +3915,45 @@ packages:
|
||||||
|
|
||||||
snapshots:
|
snapshots:
|
||||||
|
|
||||||
'@ai-sdk/openai-compatible@0.2.8(zod@3.24.2)':
|
'@ai-sdk/openai-compatible@0.2.13(zod@3.24.2)':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@ai-sdk/provider': 1.1.2
|
'@ai-sdk/provider': 1.1.3
|
||||||
'@ai-sdk/provider-utils': 2.2.6(zod@3.24.2)
|
'@ai-sdk/provider-utils': 2.2.7(zod@3.24.2)
|
||||||
zod: 3.24.2
|
zod: 3.24.2
|
||||||
|
|
||||||
'@ai-sdk/provider-utils@2.2.6(zod@3.24.2)':
|
'@ai-sdk/provider-utils@2.2.7(zod@3.24.2)':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@ai-sdk/provider': 1.1.2
|
'@ai-sdk/provider': 1.1.3
|
||||||
nanoid: 3.3.11
|
nanoid: 3.3.11
|
||||||
secure-json-parse: 2.7.0
|
secure-json-parse: 2.7.0
|
||||||
zod: 3.24.2
|
zod: 3.24.2
|
||||||
|
|
||||||
'@ai-sdk/provider@1.1.2':
|
'@ai-sdk/provider@1.1.3':
|
||||||
dependencies:
|
dependencies:
|
||||||
json-schema: 0.4.0
|
json-schema: 0.4.0
|
||||||
|
|
||||||
'@ai-sdk/react@1.2.8(react@19.0.0-rc-45804af1-20241021)(zod@3.24.2)':
|
'@ai-sdk/react@1.2.11(react@19.0.0-rc-45804af1-20241021)(zod@3.24.2)':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@ai-sdk/provider-utils': 2.2.6(zod@3.24.2)
|
'@ai-sdk/provider-utils': 2.2.7(zod@3.24.2)
|
||||||
'@ai-sdk/ui-utils': 1.2.7(zod@3.24.2)
|
'@ai-sdk/ui-utils': 1.2.10(zod@3.24.2)
|
||||||
react: 19.0.0-rc-45804af1-20241021
|
react: 19.0.0-rc-45804af1-20241021
|
||||||
swr: 2.3.3(react@19.0.0-rc-45804af1-20241021)
|
swr: 2.3.3(react@19.0.0-rc-45804af1-20241021)
|
||||||
throttleit: 2.1.0
|
throttleit: 2.1.0
|
||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
zod: 3.24.2
|
zod: 3.24.2
|
||||||
|
|
||||||
'@ai-sdk/ui-utils@1.2.7(zod@3.24.2)':
|
'@ai-sdk/ui-utils@1.2.10(zod@3.24.2)':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@ai-sdk/provider': 1.1.2
|
'@ai-sdk/provider': 1.1.3
|
||||||
'@ai-sdk/provider-utils': 2.2.6(zod@3.24.2)
|
'@ai-sdk/provider-utils': 2.2.7(zod@3.24.2)
|
||||||
zod: 3.24.2
|
zod: 3.24.2
|
||||||
zod-to-json-schema: 3.24.5(zod@3.24.2)
|
zod-to-json-schema: 3.24.5(zod@3.24.2)
|
||||||
|
|
||||||
'@ai-sdk/xai@1.2.10(zod@3.24.2)':
|
'@ai-sdk/xai@1.2.15(zod@3.24.2)':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@ai-sdk/openai-compatible': 0.2.8(zod@3.24.2)
|
'@ai-sdk/openai-compatible': 0.2.13(zod@3.24.2)
|
||||||
'@ai-sdk/provider': 1.1.2
|
'@ai-sdk/provider': 1.1.3
|
||||||
'@ai-sdk/provider-utils': 2.2.6(zod@3.24.2)
|
'@ai-sdk/provider-utils': 2.2.7(zod@3.24.2)
|
||||||
zod: 3.24.2
|
zod: 3.24.2
|
||||||
|
|
||||||
'@alloc/quick-lru@5.2.0': {}
|
'@alloc/quick-lru@5.2.0': {}
|
||||||
|
|
@ -4849,6 +4894,26 @@ snapshots:
|
||||||
|
|
||||||
'@radix-ui/rect@1.1.0': {}
|
'@radix-ui/rect@1.1.0': {}
|
||||||
|
|
||||||
|
'@redis/bloom@5.0.0(@redis/client@5.0.0)':
|
||||||
|
dependencies:
|
||||||
|
'@redis/client': 5.0.0
|
||||||
|
|
||||||
|
'@redis/client@5.0.0':
|
||||||
|
dependencies:
|
||||||
|
cluster-key-slot: 1.1.2
|
||||||
|
|
||||||
|
'@redis/json@5.0.0(@redis/client@5.0.0)':
|
||||||
|
dependencies:
|
||||||
|
'@redis/client': 5.0.0
|
||||||
|
|
||||||
|
'@redis/search@5.0.0(@redis/client@5.0.0)':
|
||||||
|
dependencies:
|
||||||
|
'@redis/client': 5.0.0
|
||||||
|
|
||||||
|
'@redis/time-series@5.0.0(@redis/client@5.0.0)':
|
||||||
|
dependencies:
|
||||||
|
'@redis/client': 5.0.0
|
||||||
|
|
||||||
'@rtsao/scc@1.1.0': {}
|
'@rtsao/scc@1.1.0': {}
|
||||||
|
|
||||||
'@rushstack/eslint-patch@1.11.0': {}
|
'@rushstack/eslint-patch@1.11.0': {}
|
||||||
|
|
@ -5009,12 +5074,12 @@ snapshots:
|
||||||
|
|
||||||
acorn@8.14.1: {}
|
acorn@8.14.1: {}
|
||||||
|
|
||||||
ai@4.3.4(react@19.0.0-rc-45804af1-20241021)(zod@3.24.2):
|
ai@4.3.13(react@19.0.0-rc-45804af1-20241021)(zod@3.24.2):
|
||||||
dependencies:
|
dependencies:
|
||||||
'@ai-sdk/provider': 1.1.2
|
'@ai-sdk/provider': 1.1.3
|
||||||
'@ai-sdk/provider-utils': 2.2.6(zod@3.24.2)
|
'@ai-sdk/provider-utils': 2.2.7(zod@3.24.2)
|
||||||
'@ai-sdk/react': 1.2.8(react@19.0.0-rc-45804af1-20241021)(zod@3.24.2)
|
'@ai-sdk/react': 1.2.11(react@19.0.0-rc-45804af1-20241021)(zod@3.24.2)
|
||||||
'@ai-sdk/ui-utils': 1.2.7(zod@3.24.2)
|
'@ai-sdk/ui-utils': 1.2.10(zod@3.24.2)
|
||||||
'@opentelemetry/api': 1.9.0
|
'@opentelemetry/api': 1.9.0
|
||||||
jsondiffpatch: 0.6.0
|
jsondiffpatch: 0.6.0
|
||||||
zod: 3.24.2
|
zod: 3.24.2
|
||||||
|
|
@ -5233,6 +5298,8 @@ snapshots:
|
||||||
|
|
||||||
clsx@2.1.1: {}
|
clsx@2.1.1: {}
|
||||||
|
|
||||||
|
cluster-key-slot@1.1.2: {}
|
||||||
|
|
||||||
codemirror@6.0.1:
|
codemirror@6.0.1:
|
||||||
dependencies:
|
dependencies:
|
||||||
'@codemirror/autocomplete': 6.18.6
|
'@codemirror/autocomplete': 6.18.6
|
||||||
|
|
@ -7125,6 +7192,14 @@ snapshots:
|
||||||
dependencies:
|
dependencies:
|
||||||
picomatch: 2.3.1
|
picomatch: 2.3.1
|
||||||
|
|
||||||
|
redis@5.0.0:
|
||||||
|
dependencies:
|
||||||
|
'@redis/bloom': 5.0.0(@redis/client@5.0.0)
|
||||||
|
'@redis/client': 5.0.0
|
||||||
|
'@redis/json': 5.0.0(@redis/client@5.0.0)
|
||||||
|
'@redis/search': 5.0.0(@redis/client@5.0.0)
|
||||||
|
'@redis/time-series': 5.0.0(@redis/client@5.0.0)
|
||||||
|
|
||||||
reflect.getprototypeof@1.0.10:
|
reflect.getprototypeof@1.0.10:
|
||||||
dependencies:
|
dependencies:
|
||||||
call-bind: 1.0.8
|
call-bind: 1.0.8
|
||||||
|
|
@ -7195,6 +7270,8 @@ snapshots:
|
||||||
path-parse: 1.0.7
|
path-parse: 1.0.7
|
||||||
supports-preserve-symlinks-flag: 1.0.0
|
supports-preserve-symlinks-flag: 1.0.0
|
||||||
|
|
||||||
|
resumable-stream@2.0.0: {}
|
||||||
|
|
||||||
retry@0.13.1: {}
|
retry@0.13.1: {}
|
||||||
|
|
||||||
reusify@1.1.0: {}
|
reusify@1.1.0: {}
|
||||||
|
|
|
||||||
|
|
@ -80,4 +80,158 @@ test.describe
|
||||||
const deletedChat = await response.json();
|
const deletedChat = await response.json();
|
||||||
expect(deletedChat).toMatchObject({ id: chatId });
|
expect(deletedChat).toMatchObject({ id: chatId });
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('Ada cannot resume stream of chat that does not exist', async ({
|
||||||
|
adaContext,
|
||||||
|
}) => {
|
||||||
|
const response = await adaContext.request.get(
|
||||||
|
`/api/chat?chatId=${generateUUID()}`,
|
||||||
|
);
|
||||||
|
expect(response.status()).toBe(404);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('Ada can resume chat generation', async ({ adaContext }) => {
|
||||||
|
const chatId = generateUUID();
|
||||||
|
|
||||||
|
const firstRequest = adaContext.request.post('/api/chat', {
|
||||||
|
data: {
|
||||||
|
id: chatId,
|
||||||
|
message: {
|
||||||
|
id: generateUUID(),
|
||||||
|
role: 'user',
|
||||||
|
content: 'Help me write an essay about Silcon Valley',
|
||||||
|
parts: [
|
||||||
|
{
|
||||||
|
type: 'text',
|
||||||
|
text: 'Help me write an essay about Silicon Valley',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
createdAt: new Date().toISOString(),
|
||||||
|
},
|
||||||
|
selectedChatModel: 'chat-model',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
await new Promise((resolve) => setTimeout(resolve, 1000));
|
||||||
|
|
||||||
|
const secondRequest = adaContext.request.get(
|
||||||
|
`/api/chat?chatId=${chatId}`,
|
||||||
|
);
|
||||||
|
|
||||||
|
const [firstResponse, secondResponse] = await Promise.all([
|
||||||
|
firstRequest,
|
||||||
|
secondRequest,
|
||||||
|
]);
|
||||||
|
|
||||||
|
const [firstStatusCode, secondStatusCode] = await Promise.all([
|
||||||
|
firstResponse.status(),
|
||||||
|
secondResponse.status(),
|
||||||
|
]);
|
||||||
|
|
||||||
|
expect(firstStatusCode).toBe(200);
|
||||||
|
expect(secondStatusCode).toBe(200);
|
||||||
|
|
||||||
|
const [firstResponseBody, secondResponseBody] = await Promise.all([
|
||||||
|
await firstResponse.body(),
|
||||||
|
await secondResponse.body(),
|
||||||
|
]);
|
||||||
|
|
||||||
|
expect(firstResponseBody.toString()).toEqual(
|
||||||
|
secondResponseBody.toString(),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('Ada cannot resume chat generation that has ended', async ({
|
||||||
|
adaContext,
|
||||||
|
}) => {
|
||||||
|
const chatId = generateUUID();
|
||||||
|
|
||||||
|
const firstRequest = await adaContext.request.post('/api/chat', {
|
||||||
|
data: {
|
||||||
|
id: chatId,
|
||||||
|
message: {
|
||||||
|
id: generateUUID(),
|
||||||
|
role: 'user',
|
||||||
|
content: 'Help me write an essay about Silcon Valley',
|
||||||
|
parts: [
|
||||||
|
{
|
||||||
|
type: 'text',
|
||||||
|
text: 'Help me write an essay about Silicon Valley',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
createdAt: new Date().toISOString(),
|
||||||
|
},
|
||||||
|
selectedChatModel: 'chat-model',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const secondRequest = adaContext.request.get(
|
||||||
|
`/api/chat?chatId=${chatId}`,
|
||||||
|
);
|
||||||
|
|
||||||
|
const [firstResponse, secondResponse] = await Promise.all([
|
||||||
|
firstRequest,
|
||||||
|
secondRequest,
|
||||||
|
]);
|
||||||
|
|
||||||
|
const [firstStatusCode, secondStatusCode] = await Promise.all([
|
||||||
|
firstResponse.status(),
|
||||||
|
secondResponse.status(),
|
||||||
|
]);
|
||||||
|
|
||||||
|
expect(firstStatusCode).toBe(200);
|
||||||
|
expect(secondStatusCode).toBe(200);
|
||||||
|
|
||||||
|
const [, secondResponseContent] = await Promise.all([
|
||||||
|
firstResponse.text(),
|
||||||
|
secondResponse.text(),
|
||||||
|
]);
|
||||||
|
|
||||||
|
expect(secondResponseContent).toEqual('');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('Babbage cannot resume chat generation that belongs to Ada', async ({
|
||||||
|
adaContext,
|
||||||
|
babbageContext,
|
||||||
|
}) => {
|
||||||
|
const chatId = generateUUID();
|
||||||
|
|
||||||
|
const firstRequest = adaContext.request.post('/api/chat', {
|
||||||
|
data: {
|
||||||
|
id: chatId,
|
||||||
|
message: {
|
||||||
|
id: generateUUID(),
|
||||||
|
role: 'user',
|
||||||
|
content: 'Help me write an essay about Silcon Valley',
|
||||||
|
parts: [
|
||||||
|
{
|
||||||
|
type: 'text',
|
||||||
|
text: 'Help me write an essay about Silicon Valley',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
createdAt: new Date().toISOString(),
|
||||||
|
},
|
||||||
|
selectedChatModel: 'chat-model',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
await new Promise((resolve) => setTimeout(resolve, 1000));
|
||||||
|
|
||||||
|
const secondRequest = babbageContext.request.get(
|
||||||
|
`/api/chat?chatId=${chatId}`,
|
||||||
|
);
|
||||||
|
|
||||||
|
const [firstResponse, secondResponse] = await Promise.all([
|
||||||
|
firstRequest,
|
||||||
|
secondRequest,
|
||||||
|
]);
|
||||||
|
|
||||||
|
const [firstStatusCode, secondStatusCode] = await Promise.all([
|
||||||
|
firstResponse.status(),
|
||||||
|
secondResponse.status(),
|
||||||
|
]);
|
||||||
|
|
||||||
|
expect(firstStatusCode).toBe(200);
|
||||||
|
expect(secondStatusCode).toBe(403);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue