-
-
Notifications
You must be signed in to change notification settings - Fork 6
Add counter-clockwise spinning plant icon during token generation #357
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
base: main
Are you sure you want to change the base?
Changes from all commits
f3fd726
5ab27d7
d33cd2f
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 | ||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -7,9 +7,16 @@ import remarkGfm from 'remark-gfm' | |||||||||||||||||
| import remarkMath from 'remark-math' | ||||||||||||||||||
| import rehypeKatex from 'rehype-katex' | ||||||||||||||||||
| import 'katex/dist/katex.min.css' | ||||||||||||||||||
| import { useStreaming } from './streaming-context' | ||||||||||||||||||
| import { useEffect } from 'react' | ||||||||||||||||||
|
|
||||||||||||||||||
| export function BotMessage({ content }: { content: StreamableValue<string> }) { | ||||||||||||||||||
| const [data, error, pending] = useStreamableValue(content) | ||||||||||||||||||
| const { setIsStreaming } = useStreaming() | ||||||||||||||||||
|
|
||||||||||||||||||
| useEffect(() => { | ||||||||||||||||||
| setIsStreaming(pending) | ||||||||||||||||||
| }, [pending, setIsStreaming]) | ||||||||||||||||||
|
Comment on lines
+15
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. Using a single boolean SuggestionRefactor the streaming context to track a reference count and expose
export interface StreamingContextType {
isStreaming: boolean
start: () => void
stop: () => void
}
export const StreamingProvider = ({ children }: { children: React.ReactNode }) => {
const [count, setCount] = useState(0)
const start = () => setCount(c => c + 1)
const stop = () => setCount(c => Math.max(0, c - 1))
return (
<StreamingContext.Provider value={{ isStreaming: count > 0, start, stop }}>
{children}
</StreamingContext.Provider>
)
}
const { start, stop } = useStreaming()
useEffect(() => {
if (pending) start()
else stop()
return () => { if (pending) stop() }
}, [pending, start, stop])Reply with "@CharlieHelps yes please" if you'd like me to add a commit implementing this safer ref-count approach.
Comment on lines
+17
to
+19
Contributor
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. 🧹 Nitpick | 🔵 Trivial Approve with suggestion: Add explanatory comment. The implementation correctly tracks streaming state by relying on stable Consider adding a comment explaining the behavior: + // Update global streaming state when this message's streaming status changes.
+ // Only the newest message will have pending=true, older messages remain pending=false.
useEffect(() => {
setIsStreaming(pending)
}, [pending, setIsStreaming])📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||
|
|
||||||||||||||||||
| // Currently, sometimes error occurs after finishing the stream. | ||||||||||||||||||
| if (error) return <div>Error</div> | ||||||||||||||||||
|
|
||||||||||||||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,29 @@ | ||
| 'use client' | ||
|
|
||
| import { createContext, useContext, useState, ReactNode } from 'react' | ||
|
|
||
| interface StreamingContextType { | ||
| isStreaming: boolean | ||
| setIsStreaming: (streaming: boolean) => void | ||
| } | ||
|
|
||
| const StreamingContext = createContext<StreamingContextType | undefined>(undefined) | ||
|
|
||
| export const useStreaming = () => { | ||
| const context = useContext(StreamingContext) | ||
| if (!context) { | ||
| // Return default values if used outside provider (e.g., during SSR) | ||
| return { isStreaming: false, setIsStreaming: () => {} } | ||
| } | ||
| return context | ||
| } | ||
|
|
||
| export const StreamingProvider = ({ children }: { children: ReactNode }) => { | ||
| const [isStreaming, setIsStreaming] = useState(false) | ||
|
|
||
| return ( | ||
| <StreamingContext.Provider value={{ isStreaming, setIsStreaming }}> | ||
| {children} | ||
| </StreamingContext.Provider> | ||
| ) | ||
| } | ||
|
Comment on lines
+21
to
+29
Contributor
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. 🧹 Nitpick | 🔵 Trivial Memoize the context value to prevent unnecessary re-renders. The context value object is recreated on every render, causing all consumers (Header, BotMessage) to re-render even when Apply this diff to memoize the value: -import { createContext, useContext, useState, ReactNode } from 'react'
+import { createContext, useContext, useState, ReactNode, useMemo } from 'react'
export const StreamingProvider = ({ children }: { children: ReactNode }) => {
const [isStreaming, setIsStreaming] = useState(false)
+ const value = useMemo(
+ () => ({ isStreaming, setIsStreaming }),
+ [isStreaming]
+ )
+
return (
- <StreamingContext.Provider value={{ isStreaming, setIsStreaming }}>
+ <StreamingContext.Provider value={value}>
{children}
</StreamingContext.Provider>
)
}🤖 Prompt for AI Agents |
||
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.
useStreaming()throws if used outside ofStreamingProvider, butStreamingProvideris only mounted underChat. IfHeaderis rendered at a higher level (e.g., inapp/layout.tsx), this will crash at runtime. The provider must wrapHeader(or the whole app tree), not just theChatsubtree.Suggestion
Move
StreamingProviderto a top-level provider that wrapsHeaderand page content (e.g., via anapp/providers.tsxclient component used inapp/layout.tsx), and remove the per-Chatwrappers to avoid duplication. For example:Then delete the
StreamingProviderwrappers added incomponents/chat.tsx.Reply with "@CharlieHelps yes please" if you'd like me to add a commit with this refactor.