-
-
Notifications
You must be signed in to change notification settings - Fork 32
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
add onboarding ai agent #86
Changes from 1 commit
cd0fb69
0605d57
c97629d
ebfa716
bd8733e
c717def
fdd89ba
b9a3836
57fcecd
80e5fb0
a699836
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
"use server"; | ||
import { ReactNode } from "react"; | ||
import { getMutableAIState, streamUI } from "ai/rsc"; | ||
import { togetherai } from "@ai-sdk/togetherai"; | ||
import { AI } from "@/lib/ai"; | ||
import { BotMessage } from "@/components/custom/onboarding/message"; | ||
|
||
export type ServerMessage = { | ||
role: "user" | "assistant"; | ||
content: string; | ||
}; | ||
|
||
export type ClientMessage = { | ||
id: number; | ||
role: "user" | "assistant"; | ||
display: ReactNode; | ||
}; | ||
|
||
export const sendMessage = async ( | ||
message: string | ||
): Promise<{ | ||
id: number; | ||
role: "user" | "assistant"; | ||
display: ReactNode; | ||
}> => { | ||
const history = getMutableAIState<typeof AI>(); | ||
history.update([...history.get(), { role: "user", content: message }]); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Implement proper state management for message history The current implementation might lead to memory issues as the history grows indefinitely. Consider:
+ const MAX_HISTORY_SIZE = 50;
const history = getMutableAIState<typeof AI>();
- history.update([...history.get(), { role: "user", content: message }]);
+ const currentHistory = history.get();
+ const newHistory = [...currentHistory.slice(-MAX_HISTORY_SIZE), { role: "user", content: message }];
+ history.update(newHistory); Also applies to: 34-39 |
||
const response = await streamUI({ | ||
model: togetherai("deepseek-ai/deepseek-llm-67b-chat"), | ||
system: "You are a helpful assistant. give answer in only 10 words", | ||
messages: [{ role: "user", content: message }, ...history.get()], | ||
text: ({ content, done }) => { | ||
if (done) { | ||
history.update([ | ||
...history.get(), | ||
{ role: "assistant", content: content }, | ||
]); | ||
console.log("done", ...history.get()); | ||
} | ||
return <BotMessage>{content}</BotMessage>; | ||
}, | ||
}); | ||
|
||
|
||
return { | ||
id: Date.now(), | ||
role: "assistant" as const, | ||
display: response.value, | ||
}; | ||
}; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Add error handling and input validation The function lacks error handling for API failures and input validation. Consider implementing:
export const sendMessage = async (
message: string
): Promise<ClientMessage> => {
+ if (!message?.trim()) {
+ throw new Error('Message cannot be empty');
+ }
+
const history = getMutableAIState<typeof AI>();
try {
// ... existing code ...
+ } catch (error) {
+ console.error('Error in AI response:', error);
+ throw new Error('Failed to get AI response');
+ }
};
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
import { AI } from "@/lib/ai"; | ||
|
||
export default function OnboardingLayout({children}: {children: React.ReactNode}) { | ||
return <AI>{children}</AI>; | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
import Chatbox from "@/components/custom/onboarding/chatbox"; | ||
|
||
export default function Onboarding() { | ||
|
||
return <Chatbox /> | ||
} |
Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
@@ -0,0 +1,20 @@ | ||||||||||||||||||||||||
import Infobar from "@/components/custom/infobar/infobar"; | ||||||||||||||||||||||||
import ProgressBar from "@/components/custom/progress.bar"; | ||||||||||||||||||||||||
import { AppSidebar } from "@/components/custom/sidebar/sidebar"; | ||||||||||||||||||||||||
import { SidebarProvider } from "@/components/ui/sidebar"; | ||||||||||||||||||||||||
import { cookies } from "next/headers"; | ||||||||||||||||||||||||
async function RouteLayout({children}: {children: React.ReactNode}) { | ||||||||||||||||||||||||
const cookieStore = await cookies(); | ||||||||||||||||||||||||
const defaultOpen = cookieStore.get("plura-sidebar:state")?.value === "true"; | ||||||||||||||||||||||||
Comment on lines
+7
to
+8
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion Add error handling for cookie access The cookie access should handle potential errors and provide fallback behavior. - const cookieStore = await cookies();
- const defaultOpen = cookieStore.get("plura-sidebar:state")?.value === "true";
+ const defaultOpen = await (async () => {
+ try {
+ const cookieStore = await cookies();
+ return cookieStore.get("plura-sidebar:state")?.value === "true";
+ } catch (error) {
+ console.error('Failed to access cookies:', error);
+ return false;
+ }
+ })(); 📝 Committable suggestion
Suggested change
|
||||||||||||||||||||||||
return ( | ||||||||||||||||||||||||
<SidebarProvider defaultOpen={defaultOpen}> | ||||||||||||||||||||||||
<AppSidebar /> | ||||||||||||||||||||||||
<div className="p-2"> | ||||||||||||||||||||||||
<ProgressBar /> | ||||||||||||||||||||||||
<Infobar /> | ||||||||||||||||||||||||
{children} | ||||||||||||||||||||||||
</div> | ||||||||||||||||||||||||
</SidebarProvider> | ||||||||||||||||||||||||
); | ||||||||||||||||||||||||
} | ||||||||||||||||||||||||
export default RouteLayout; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
import type { UIState } from "@/lib/ai"; | ||
|
||
export function ChatList({ messages }: { messages: UIState[number][] }) { | ||
if (!messages.length) return null; | ||
|
||
return ( | ||
<div className="relative mx-auto max-w-2xl px-4"> | ||
{messages.map((message, index) => ( | ||
<div key={index} className="pb-4"> | ||
{message.display} | ||
</div> | ||
))} | ||
Comment on lines
+9
to
+13
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Avoid using array indices as React keys Using array indices as keys can lead to rendering issues when messages are reordered, deleted, or inserted. Consider using unique message IDs instead. - {messages.map((message, index) => (
- <div key={index} className="pb-4">
+ {messages.map((message) => (
+ <div key={message.id} className="pb-4">
|
||
</div> | ||
); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion Enhance accessibility and message differentiation The chat messages lack semantic structure and visual differentiation between user and AI messages. return (
- <div className="relative mx-auto max-w-2xl px-4">
+ <div
+ className="relative mx-auto max-w-2xl px-4"
+ role="log"
+ aria-label="Chat messages"
+ >
{messages.map((message) => (
- <div key={index} className="pb-4">
+ <article
+ key={message.id}
+ className={`pb-4 ${
+ message.role === 'assistant'
+ ? 'bg-muted/50 p-4 rounded-lg'
+ : ''
+ }`}
+ >
{message.display}
- </div>
+ </article>
))}
</div>
);
|
||
} |
Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
@@ -0,0 +1,34 @@ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
"use client" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
import { Input } from "@/components/ui/input"; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
import { AI } from "@/lib/ai"; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
import { useActions, useUIState } from "ai/rsc"; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
import { useState } from "react"; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
import { ChatList } from "./chatList"; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
import { UserMessage } from "./message"; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
export default function Chatbox() { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
const [messages, setMessages] = useUIState<typeof AI>(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
const [value, setValue] = useState(""); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
const { sendMessage } = useActions<typeof AI>(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
const handleSubmit = async() => { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
setMessages((currentMessages) => [ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
...currentMessages, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
{ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
id: Date.now(), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
role: "user", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
display: <UserMessage>{value}</UserMessage>, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
}, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
]); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
const response = await sendMessage(value); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
setMessages((currentMessages) => [...currentMessages, response]); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Add loading state and error handling The message submission lacks loading indicators and error handling, which could lead to poor user experience. Consider implementing: export default function Chatbox() {
const [messages, setMessages] = useUIState<typeof AI>();
const [value, setValue] = useState("");
+ const [isLoading, setIsLoading] = useState(false);
+ const [error, setError] = useState<string | null>(null);
const { sendMessage } = useActions<typeof AI>();
const handleSubmit = async() => {
+ if (!value.trim()) return;
+ setError(null);
+ setIsLoading(true);
try {
setMessages((currentMessages) => [
...currentMessages,
{
id: Date.now(),
role: "user",
display: <UserMessage>{value}</UserMessage>,
},
]);
const response = await sendMessage(value);
setMessages((currentMessages) => [...currentMessages, response]);
+ setValue('');
+ } catch (err) {
+ setError('Failed to send message. Please try again.');
+ } finally {
+ setIsLoading(false);
+ }
} 📝 Committable suggestion
Suggested change
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
return ( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
<div> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
<ChatList messages={messages} /> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
<Input value={value} onChange={(e) => setValue(e.target.value)} /> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
<button onClick={handleSubmit}>submit</button> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
</div> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion Improve accessibility and user experience The current implementation lacks proper accessibility features and UX enhancements. Consider these improvements: return (
- <div>
+ <div role="region" aria-label="Chat interface">
<ChatList messages={messages} />
- <Input value={value} onChange={(e) => setValue(e.target.value)} />
- <button onClick={handleSubmit}>submit</button>
+ <form onSubmit={(e) => { e.preventDefault(); handleSubmit(); }}>
+ <Input
+ value={value}
+ onChange={(e) => setValue(e.target.value)}
+ placeholder="Type your message..."
+ aria-label="Chat message"
+ disabled={isLoading}
+ onKeyPress={(e) => e.key === 'Enter' && handleSubmit()}
+ />
+ <button
+ type="submit"
+ disabled={isLoading || !value.trim()}
+ aria-busy={isLoading}
+ >
+ {isLoading ? 'Sending...' : 'Send'}
+ </button>
+ </form>
+ {error && <p role="alert" className="text-red-500">{error}</p>}
</div>
);
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} |
Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
@@ -0,0 +1,57 @@ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
import { cn } from "@/lib/utils"; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
import { Sparkle, UserIcon } from "lucide-react"; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// Different types of message bubbles. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
export function UserMessage({ children }: { children: React.ReactNode }) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
return ( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
<div className="group relative flex items-start md:-ml-12"> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
<div className="flex h-8 w-8 shrink-0 select-none items-center justify-center rounded-md border shadow-sm bg-background"> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
<UserIcon /> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
</div> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
<div className="ml-4 flex-1 space-y-2 overflow-hidden px-1"> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
{children} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
</div> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
</div> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
export function BotMessage({ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
children, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
className, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
}: { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
children: React.ReactNode; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
className?: string; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
}) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
return ( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
<div className={cn("group relative flex items-start md:-ml-12", className)}> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
<div className="flex h-8 w-8 shrink-0 select-none items-center justify-center rounded-md border shadow-sm bg-primary text-primary-foreground"> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
<Sparkle /> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
</div> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
<div className="ml-4 flex-1 space-y-2 overflow-hidden px-1"> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
{children} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
</div> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
</div> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
export function BotCard({ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
children, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
showAvatar = true, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
}: { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
children: React.ReactNode; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
showAvatar?: boolean; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
}) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
return ( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
<div className="group relative flex items-start md:-ml-12"> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
<div | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
className={cn( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
"flex h-8 w-8 shrink-0 select-none items-center justify-center rounded-md border shadow-sm bg-primary text-primary-foreground", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
!showAvatar && "invisible" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
)} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
<Sparkle /> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
</div> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
<div className="ml-4 flex-1 px-1">{children}</div> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
</div> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion Add accessibility attributes to message components. Enhance accessibility by adding appropriate ARIA roles and labels. export function UserMessage({ children }: { children: React.ReactNode }) {
return (
- <div className="group relative flex items-start md:-ml-12">
+ <div
+ role="log"
+ aria-label="User message"
+ className="group relative flex items-start md:-ml-12">
{/* ... */}
</div>
);
}
export function BotMessage({
children,
className,
}: {
children: React.ReactNode;
className?: string;
}) {
return (
- <div className={cn("group relative flex items-start md:-ml-12", className)}>
+ <div
+ role="log"
+ aria-label="Assistant message"
+ className={cn("group relative flex items-start md:-ml-12", className)}>
{/* ... */}
</div>
);
}
export function BotCard({
children,
showAvatar = true,
}: {
children: React.ReactNode;
showAvatar?: boolean;
}) {
return (
- <div className="group relative flex items-start md:-ml-12">
+ <div
+ role="log"
+ aria-label="Assistant card"
+ className="group relative flex items-start md:-ml-12">
{/* ... */}
</div>
);
} 📝 Committable suggestion
Suggested change
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
import { createAI } from "ai/rsc"; | ||
import { ClientMessage, ServerMessage, sendMessage } from "@/actions/action"; | ||
|
||
export type AIState = ServerMessage[]; | ||
export type UIState = ClientMessage[]; | ||
|
||
export const AI = createAI< | ||
AIState, | ||
UIState, | ||
{ | ||
sendMessage: (message: string) => Promise<ClientMessage>; | ||
} | ||
>({ | ||
initialAIState: [], | ||
initialUIState: [], | ||
actions: { | ||
sendMessage, | ||
}, | ||
}); |
Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
@@ -9,6 +9,8 @@ const redirectUrl = | |||||||||||||||||||||||||||||||||||||||||||||||
process.env.NODE_ENV === "production" | ||||||||||||||||||||||||||||||||||||||||||||||||
? "https://www.plura.pro/auth" | ||||||||||||||||||||||||||||||||||||||||||||||||
: "http://localhost:3003/auth"; | ||||||||||||||||||||||||||||||||||||||||||||||||
const appDomain = process.env.NODE_ENV === "production" ? "https://app.plura.pro" : "http://localhost:3002"; | ||||||||||||||||||||||||||||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion Use environment variables for domain configuration Hardcoding domains in the code makes it less maintainable and harder to configure. -const appDomain = process.env.NODE_ENV === "production" ? "https://app.plura.pro" : "http://localhost:3002";
+const appDomain = process.env.NEXT_PUBLIC_APP_DOMAIN || (
+ process.env.NODE_ENV === "production" ? "https://app.plura.pro" : "http://localhost:3002"
+); 📝 Committable suggestion
Suggested change
|
||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||
export default async function authMiddleware(request: NextRequest) { | ||||||||||||||||||||||||||||||||||||||||||||||||
const { data: session } = await betterFetch<Session>( | ||||||||||||||||||||||||||||||||||||||||||||||||
`${baseDomain}/api/auth/get-session`, | ||||||||||||||||||||||||||||||||||||||||||||||||
|
@@ -24,9 +26,19 @@ export default async function authMiddleware(request: NextRequest) { | |||||||||||||||||||||||||||||||||||||||||||||||
console.log("redirecting to sign in"); | ||||||||||||||||||||||||||||||||||||||||||||||||
return NextResponse.redirect(redirectUrl); | ||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||
const currentPath = request.nextUrl.pathname; | ||||||||||||||||||||||||||||||||||||||||||||||||
Comment on lines
27
to
+30
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion Add error handling for session fetch failures The current implementation doesn't handle potential errors from the session fetch. Consider adding try-catch block to handle network failures or invalid responses gracefully. - if (!session) {
- console.log("redirecting to sign in");
- return NextResponse.redirect(redirectUrl);
- }
+ try {
+ if (!session) {
+ return NextResponse.redirect(redirectUrl);
+ }
+ } catch (error) {
+ console.error('Session verification failed:', error);
+ return NextResponse.redirect(redirectUrl);
+ }
|
||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||
if (!currentPath.startsWith("/onboarding") && !session.user.isOnboarding) { | ||||||||||||||||||||||||||||||||||||||||||||||||
return NextResponse.redirect(`${appDomain}/onboarding`); | ||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||
if (currentPath.startsWith("/onboarding") && session.user.isOnboarding) { | ||||||||||||||||||||||||||||||||||||||||||||||||
return NextResponse.redirect(`${appDomain}/home`); | ||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||
Comment on lines
+33
to
+38
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Prevent potential redirect loops The current implementation might cause redirect loops if the session state is inconsistent. Add additional checks: + const MAX_REDIRECTS = 3;
+ const redirectCount = parseInt(request.headers.get('x-redirect-count') || '0');
+
+ if (redirectCount >= MAX_REDIRECTS) {
+ return new NextResponse('Too many redirects', { status: 500 });
+ }
+
if (!currentPath.startsWith("/onboarding") && !session.user.isOnboarding) {
- return NextResponse.redirect(`${appDomain}/onboarding`);
+ const response = NextResponse.redirect(`${appDomain}/onboarding`);
+ response.headers.set('x-redirect-count', (redirectCount + 1).toString());
+ return response;
}
if (currentPath.startsWith("/onboarding") && session.user.isOnboarding) {
- return NextResponse.redirect(`${appDomain}/home`);
+ const response = NextResponse.redirect(`${appDomain}/home`);
+ response.headers.set('x-redirect-count', (redirectCount + 1).toString());
+ return response;
} 📝 Committable suggestion
Suggested change
|
||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||
return NextResponse.next(); | ||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||
export const config = { | ||||||||||||||||||||||||||||||||||||||||||||||||
matcher: "/:path*", | ||||||||||||||||||||||||||||||||||||||||||||||||
matcher: ['/((?!api|_next/static|_next/image|favicon.ico|sitemap.xml|robots.txt).*)'] | ||||||||||||||||||||||||||||||||||||||||||||||||
}; |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -14,6 +14,8 @@ | |
"format:check": "prettier --check \"**/*.{ts,tsx,mdx}\" --cache" | ||
}, | ||
"dependencies": { | ||
"@ai-sdk/google": "^1.0.4", | ||
"@ai-sdk/togetherai": "^0.0.3", | ||
Comment on lines
+18
to
+19
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 💡 Codebase verification Add error handling for AI SDK integration The implementation in
🔗 Analysis chainVerify stability of AI SDK dependencies The
🏁 Scripts executedThe following scripts were executed for the analysis: Script: #!/bin/bash
# Check latest versions and weekly downloads for stability assessment
echo "Checking @ai-sdk/google package:"
curl -s https://registry.npmjs.org/@ai-sdk/google | jq '.["dist-tags"].latest, .versions[.["dist-tags"].latest].time'
echo -e "\nChecking @ai-sdk/togetherai package:"
curl -s https://registry.npmjs.org/@ai-sdk/togetherai | jq '.["dist-tags"].latest, .versions[.["dist-tags"].latest].time'
# Check for recent GitHub issues
gh api graphql -f query='
{
repository(owner: "togetherai", name: "sdk") {
issues(last: 5, states: OPEN) {
nodes {
title
createdAt
labels(first: 5) {
nodes {
name
}
}
}
}
}
}'
Length of output: 965 Script: #!/bin/bash
# Let's check if these AI SDK packages are being used in the codebase
# and how they are implemented to assess the risk
# Search for imports/usage of @ai-sdk/togetherai
echo "Usage of @ai-sdk/togetherai:"
rg "@ai-sdk/togetherai" -A 3
# Search for imports/usage of @ai-sdk/google
echo -e "\nUsage of @ai-sdk/google:"
rg "@ai-sdk/google" -A 3
# Check if there are any error handling or try-catch blocks around these SDKs
echo -e "\nError handling around AI SDKs:"
ast-grep --pattern 'try {
$$$
@ai-sdk
$$$
} catch'
Length of output: 2360 Script: #!/bin/bash
# Let's check the implementation in action.tsx to see how these SDKs are used
# and if there's proper error handling
echo "Checking AI SDK implementation in action.tsx:"
cat apps/app/actions/action.tsx
# Let's also check if there are any try-catch blocks in this file
# using a more general pattern
echo -e "\nChecking error handling in action.tsx:"
ast-grep --pattern 'try {
$$$
} catch' apps/app/actions/action.tsx
Length of output: 1625 |
||
"@better-fetch/fetch": "^1.1.12", | ||
"@hookform/resolvers": "^3.9.1", | ||
"@radix-ui/react-alert-dialog": "^1.1.2", | ||
|
@@ -35,6 +37,7 @@ | |
"@repo/db": "workspace:*", | ||
"@repo/types": "workspace:*", | ||
"@tabler/icons-react": "^3.21.0", | ||
"ai": "^4.0.8", | ||
"class-variance-authority": "^0.7.0", | ||
"clsx": "^2.1.1", | ||
"cmdk": "1.0.0", | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
-- AlterTable | ||
ALTER TABLE "user" ADD COLUMN "isOnboarding" BOOLEAN NOT NULL DEFAULT false; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
💡 Codebase verification
Documentation update needed for port 3001
The port change to 3001 in the API service requires documentation updates. Our verification found that:
Please update the following:
apps/api/README.md
.env.example
file in the API service directoryREADME.md
with the development ports for all services🔗 Analysis chain
Documentation update needed for port change.
Since this is a significant infrastructure change that affects local development and deployment, documentation should be updated to reflect the new port.
Please ensure the following are updated:
Let's check for documentation files that might need updating:
🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
Length of output: 294
Script:
Length of output: 7840
Script:
Length of output: 1115