-
-
Notifications
You must be signed in to change notification settings - Fork 6
Fix Chat Crash and Build Error #343
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
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -69,42 +69,45 @@ export const ChatPanel = forwardRef<ChatPanelRef, ChatPanelProps>(({ messages, i | |
| } | ||
| } | ||
|
|
||
| const handleSubmit = async (e: React.FormEvent<HTMLFormElement>) => { | ||
| e.preventDefault() | ||
| if (!input && !selectedFile) { | ||
| return | ||
| const handleSubmit = (e: React.FormEvent<HTMLFormElement>) => { | ||
| e.preventDefault(); | ||
| if (!input.trim() && !selectedFile) { | ||
| return; | ||
| } | ||
|
|
||
| const content: ({ type: 'text'; text: string } | { type: 'image'; image: string })[] = [] | ||
| // Create the user message content first, while we still have the input and file | ||
| const content: ({ type: 'text'; text: string } | { type: 'image'; image: File })[] = []; | ||
| if (input) { | ||
| content.push({ type: 'text', text: input }) | ||
| content.push({ type: 'text', text: input }); | ||
| } | ||
| if (selectedFile && selectedFile.type.startsWith('image/')) { | ||
| content.push({ | ||
| type: 'image', | ||
| image: URL.createObjectURL(selectedFile) | ||
| }) | ||
| content.push({ type: 'image', image: selectedFile }); | ||
| } | ||
|
|
||
| setMessages(currentMessages => [ | ||
| ...currentMessages, | ||
| { | ||
| id: nanoid(), | ||
| component: <UserMessage content={content} /> | ||
| } | ||
| ]) | ||
|
|
||
| const formData = new FormData(e.currentTarget) | ||
| // Prepare the form data for the server action | ||
| const formData = new FormData(e.currentTarget); | ||
| if (selectedFile) { | ||
| formData.append('file', selectedFile) | ||
| formData.append('file', selectedFile); | ||
| } | ||
|
|
||
| setInput('') | ||
| clearAttachment() | ||
| // Clear the input fields for the user | ||
| setInput(''); | ||
| clearAttachment(); | ||
|
|
||
| const responseMessage = await submit(formData) | ||
| setMessages(currentMessages => [...currentMessages, responseMessage as any]) | ||
| } | ||
| // Call the server action. It will immediately return a streamable UI component. | ||
| const responseMessage = submit(formData); | ||
|
|
||
| // Update the UI state with both the user's message and the initial assistant response | ||
| // in a single operation. This ensures the component tree structure is consistent. | ||
| setMessages(currentMessages => [ | ||
| ...currentMessages, | ||
| { | ||
| id: nanoid(), | ||
| component: <UserMessage content={content} />, | ||
| }, | ||
| responseMessage as any, | ||
|
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. Relying on SuggestionDefine a concrete message type and type the server action accordingly, then remove the // Example
type ChatMessage = { id: string; component: React.ReactNode };
// In the server action typing
async function submit(formData: FormData): Promise<ChatMessage> { /* ... */ }
// When replacing the placeholder in the previous suggestion
.then((resolved: ChatMessage) => {
setMessages((curr) => curr.map((m) => (m.id === pendingId ? resolved : m)));
})Reply with "@CharlieHelps yes please" if you'd like me to add a commit with this suggestion. |
||
| ]); | ||
|
Comment on lines
+98
to
+109
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. This assumes SuggestionConsider adding a placeholder assistant message atomically, then replacing it when the server action resolves. For example: // Call the server action and immediately stage a placeholder assistant message
const pendingId = nanoid();
const userMsg = {
id: nanoid(),
component: <UserMessage content={content} />,
};
setMessages((curr) => [
...curr,
userMsg,
{ id: pendingId, component: <span aria-busy="true">Thinking…</span> },
]);
submit(formData)
.then((resolved) => {
setMessages((curr) =>
curr.map((m) => (m.id === pendingId ? (resolved as any) : m))
);
})
.catch((err) => {
// Optional: surface an error state in place of the placeholder
setMessages((curr) =>
curr.map((m) =>
m.id === pendingId
? { id: pendingId, component: <span role="alert">Something went wrong</span> }
: m
)
);
console.error('submit(formData) failed', err);
});Reply with "@CharlieHelps yes please" if you'd like me to add a commit with this suggestion. |
||
| }; | ||
|
|
||
| const handleClear = async () => { | ||
| setMessages([]) | ||
|
|
||
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.
🧩 Analysis chain
Trimmed validation vs send-button disabled state are inconsistent.
You guard on input.trim() here, but the submit button uses input.length (Line 254). Users can click “Send” with only spaces, then nothing happens. Align the disabled condition to trimmed length.
If you agree, update the button to: disabled={input.trim().length === 0 && !selectedFile}.
I'll verify the review comment by examining the actual code in the chat-panel.tsx file.
🏁 Script executed:
Length of output: 25
🏁 Script executed:
Length of output: 776
🏁 Script executed:
Length of output: 232
🏁 Script executed:
Length of output: 409
Fix button disabled state to prevent clicking with only whitespace input.
Line 254's disabled condition uses
input.length === 0, but handleSubmit (line 74) validates!input.trim(). This allows users to click "Send" with only spaces, where nothing happens. Also, line 228 validatesinput.trim().length === 0, indicating consistent intent across handlers.Update line 254 to:
disabled={input.trim().length === 0 && !selectedFile}🤖 Prompt for AI Agents