Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
## vNEXT (not yet published)

### `@liveblocks/react-ui`

- Knowledge passed as a prop to `AiChat` no longer leaks that knowledge to other
instances of `AiChat` that are currently mounted on screen.

## v3.2.1

### `@liveblocks/react-ui`
Expand Down
111 changes: 111 additions & 0 deletions e2e/next-ai-kitchen-sink/app/dual-chat/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
"use client";

import { LiveblocksProvider, RegisterAiKnowledge } from "@liveblocks/react";
import { AiChat } from "@liveblocks/react-ui";
import { useState } from "react";

function ChatWithLocalKnowledge() {
const [localKnowledge, setLocalKnowledge] = useState("Spaghetti Carbonara");

return (
<div className="w-1/2 h-full border-r border-gray-300 p-4">
<div className="bg-blue-50 border border-blue-200 p-4 rounded-lg mb-4">
<label className="block text-sm font-medium mb-2 text-blue-700">
My favorite pasta dish:
</label>
<input
type="text"
value={localKnowledge}
onChange={(e) => setLocalKnowledge(e.target.value)}
className="w-full p-2 border border-blue-300 rounded bg-blue-50"
data-testid="chat-a-knowledge-input"
/>
<p className="text-xs text-blue-600 mt-3">
This knowledge is passed via the <code>knowledge</code> prop to chat A
only.
</p>
</div>

<h2 className="text-xl font-bold mb-4">Chat A</h2>
<div className="h-80" data-testid="chat-a">
<AiChat
chatId="chat-a"
className="h-full border border-gray-200 rounded"
knowledge={[
{ description: "My favorite pasta dish", value: localKnowledge },
]}
/>
</div>
</div>
);
}

function ChatWithoutLocalKnowledge() {
return (
<div className="w-1/2 h-full p-4">
<div className="bg-gray-50 border border-gray-200 p-4 rounded-lg mb-4">
<h3 className="text-sm font-semibold mb-2 text-gray-800 h-12">
No local knowledge
</h3>
<p className="text-sm text-gray-600">
This chat has no additional local knowledge passed via props. It can
only access the global knowledge.
</p>
</div>

<h2 className="text-xl font-bold mb-4">Chat B</h2>
<div className="h-80" data-testid="chat-b">
<AiChat
chatId="chat-b"
className="h-full border border-gray-200 rounded"
/>
</div>
</div>
);
}

export default function DualChatPage() {
const [globalKnowledge, setGlobalKnowledge] = useState("Tiramisu");

return (
<LiveblocksProvider
authEndpoint="/api/auth/liveblocks"
// @ts-expect-error
baseUrl={process.env.NEXT_PUBLIC_LIVEBLOCKS_BASE_URL}
>
{/* Global knowledge that should be accessible to ALL chat instances */}
<RegisterAiKnowledge
description="My favorite dessert"
value={globalKnowledge}
/>

<main className="h-screen w-full flex flex-col">
<div className="bg-yellow-50 border-b border-yellow-200 p-4">
<h1 className="text-2xl font-bold mb-2">Knowledge Isolation Test</h1>
<div className="mb-4">
<label className="block text-sm font-medium mb-2 text-yellow-800">
My favorite dessert:
</label>
<input
type="text"
value={globalKnowledge}
onChange={(e) => setGlobalKnowledge(e.target.value)}
className="w-full p-2 border border-yellow-300 rounded bg-yellow-50"
data-testid="global-knowledge-input"
/>
<p className="text-sm text-yellow-700 mt-1">
This knowledge is registered via{" "}
<code>&lt;RegisterAiKnowledge /&gt;</code> and should be
accessible to both chat A and B.
</p>
</div>
</div>

<div className="flex-1 flex">
<ChatWithLocalKnowledge />
<ChatWithoutLocalKnowledge />
</div>
</main>
</LiveblocksProvider>
);
}
17 changes: 15 additions & 2 deletions e2e/next-ai-kitchen-sink/app/knowledge/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ function DarkModeToggle() {
<div className="flex flex-col mx-auto px-4 max-w-4xl py-8 border-b-1">
<label>
<input
data-testid="expose-dark-mode-checkbox"
type="checkbox"
checked={exposed}
onChange={() => toggleExposeTool()}
Expand Down Expand Up @@ -71,6 +72,7 @@ function DarkModeToggle() {

<label>
<input
data-testid="dark-mode-toggle"
type="checkbox"
checked={mode === "dark"}
onChange={() => toggleDarkMode()}
Expand All @@ -94,7 +96,12 @@ function MyNickName() {
) : null}
<div className="flex flex-col mx-auto px-4 max-w-4xl py-8 border-b-1">
<label>
<input type="checkbox" checked={enabled} onChange={() => toggle()} />
<input
data-testid="share-nickname-checkbox"
type="checkbox"
checked={enabled}
onChange={() => toggle()}
/>
<span className="ml-2">Share my nickname</span>
</label>
</div>
Expand Down Expand Up @@ -230,6 +237,7 @@ export default function Page() {
<div className="flex flex-col px-4 max-w-4xl py-8 border-b-1">
<div className="flex gap-4 mx-auto">
<button
data-testid="tab-todo-app"
className={
selectedTab === 1
? "cursor-pointer font-bold"
Expand All @@ -240,6 +248,7 @@ export default function Page() {
Todo app
</button>
<button
data-testid="tab-another-app"
className={
selectedTab === 2
? "cursor-pointer font-bold"
Expand All @@ -250,6 +259,7 @@ export default function Page() {
Another app
</button>
<button
data-testid="tab-both"
className={
selectedTab === 3
? "cursor-pointer font-bold"
Expand All @@ -272,7 +282,10 @@ export default function Page() {

<div className="fixed bottom-8 right-8">
<Popover.Root>
<Popover.Trigger className="inline-flex items-center justify-center rounded-full p-4 shadow-[0_0_0_1px_#0000000a,0_2px_6px_#0000000f,0_8px_26px_#00000014] hover:shadow-[0_0_0_1px_#00000014,0_2px_6px_#00000014,0_8px_26px_#00000014] dark:shadow-[0_0_0_1px_#ffffff0f] dark:hover:shadow-[0_0_0_1px_#ffffff14,0_2px_6px_#ffffff14,0_8px_26px_#ffffff14]">
<Popover.Trigger
data-testid="ai-chat-trigger"
className="inline-flex items-center justify-center rounded-full p-4 shadow-[0_0_0_1px_#0000000a,0_2px_6px_#0000000f,0_8px_26px_#00000014] hover:shadow-[0_0_0_1px_#00000014,0_2px_6px_#00000014,0_8px_26px_#00000014] dark:shadow-[0_0_0_1px_#ffffff0f] dark:hover:shadow-[0_0_0_1px_#ffffff14,0_2px_6px_#ffffff14,0_8px_26px_#ffffff14]"
>
<svg
xmlns="http://www.w3.org/2000/svg"
width={32}
Expand Down
3 changes: 3 additions & 0 deletions e2e/next-ai-kitchen-sink/app/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@ export default function Home() {
<Link href="/knowledge" className="underline">
Registering client-side knowledge
</Link>
<Link href="/dual-chat" className="underline">
Dual chat - Knowledge isolation & sharing
</Link>
<Link href="/styles" className="underline">
Default styles playground
</Link>
Expand Down
Loading
Loading