refactor: anonymous/free chat experience

- Enhanced lambda function formatting in `_after_commit` for better clarity.
- Simplified generator expression in `_match_condition` for improved readability.
- Streamlined function signature in `_eligible` for consistency.
- Updated imports and refactored anonymous chat routes to use a new agent creation method.
- Added a new function `_load_anon_document` to handle document loading from Redis.
- Improved UI components by replacing legacy structures with modern alternatives, including alerts and separators.
- Refactored quota-related components to utilize new alert structures for better user feedback.
- Cleaned up unused variables and optimized component states for performance.
This commit is contained in:
DESKTOP-RTLN3BA\$punk 2026-05-31 15:58:21 -07:00
parent 0cce9b7e64
commit 0f2e3c7655
17 changed files with 493 additions and 278 deletions

View file

@ -15,6 +15,7 @@ import {
type TokenUsageData,
TokenUsageProvider,
} from "@/components/assistant-ui/token-usage-context";
import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert";
import { useAnonymousMode } from "@/contexts/anonymous-mode";
import { TimelineDataUI } from "@/features/chat-messages/timeline";
import {
@ -101,11 +102,16 @@ export function FreeChatPage() {
const anonMode = useAnonymousMode();
const modelSlug = anonMode.isAnonymous ? anonMode.modelSlug : "";
const resetKey = anonMode.isAnonymous ? anonMode.resetKey : 0;
const webSearchEnabled = anonMode.isAnonymous ? anonMode.webSearchEnabled : true;
const [messages, setMessages] = useState<ThreadMessageLike[]>([]);
const [isRunning, setIsRunning] = useState(false);
const [tokenUsageStore] = useState(() => createTokenUsageStore());
const abortControllerRef = useRef<AbortController | null>(null);
// Mirror the latest messages into a ref so onNew stays a stable callback
// (it reads history on demand instead of depending on the array).
const messagesRef = useRef<ThreadMessageLike[]>([]);
messagesRef.current = messages;
// Turnstile CAPTCHA state
const [captchaRequired, setCaptchaRequired] = useState(false);
@ -152,6 +158,7 @@ export function FreeChatPage() {
model_slug: modelSlug,
messages: messageHistory,
};
if (!webSearchEnabled) reqBody.disabled_tools = ["web_search"];
if (turnstileToken) reqBody.turnstile_token = turnstileToken;
const response = await fetch(`${BACKEND_URL}/api/v1/public/anon-chat/stream`, {
@ -301,7 +308,7 @@ export function FreeChatPage() {
throw err;
}
},
[modelSlug, tokenUsageStore]
[modelSlug, tokenUsageStore, webSearchEnabled]
);
const onNew = useCallback(
@ -345,7 +352,7 @@ export function FreeChatPage() {
},
]);
const messageHistory = messages
const messageHistory = messagesRef.current
.filter((m) => m.role === "user" || m.role === "assistant")
.map((m) => {
let text = "";
@ -395,7 +402,7 @@ export function FreeChatPage() {
abortControllerRef.current = null;
}
},
[messages, doStream]
[modelSlug, anonMode, doStream]
);
/** Called when Turnstile resolves successfully. Stores the token and auto-retries. */
@ -481,19 +488,21 @@ export function FreeChatPage() {
</div>
{captchaRequired && TURNSTILE_SITE_KEY && (
<div className="flex flex-col items-center gap-3 border-b border-border/40 bg-muted/30 py-4">
<div className="flex items-center gap-2 text-sm text-muted-foreground">
<ShieldCheck className="h-4 w-4" />
<span>Quick verification to continue chatting</span>
</div>
<Turnstile
ref={turnstileRef}
siteKey={TURNSTILE_SITE_KEY}
onSuccess={handleTurnstileSuccess}
onError={() => turnstileRef.current?.reset()}
onExpire={() => turnstileRef.current?.reset()}
options={{ theme: "auto", size: "normal" }}
/>
<div className="flex justify-center border-b bg-muted/30 px-4 py-4">
<Alert className="w-auto max-w-md">
<ShieldCheck />
<AlertTitle>Quick verification to continue chatting</AlertTitle>
<AlertDescription>
<Turnstile
ref={turnstileRef}
siteKey={TURNSTILE_SITE_KEY}
onSuccess={handleTurnstileSuccess}
onError={() => turnstileRef.current?.reset()}
onExpire={() => turnstileRef.current?.reset()}
options={{ theme: "auto", size: "normal" }}
/>
</AlertDescription>
</Alert>
</div>
)}