Polish chat UI and wire flue agent env

- Add chat components (header, composer, conversation, message, thinking response, identity)
- Add chat hooks (use-chat-agent, use-chat-composer)
- Add chat lib (constants, transforms, types)
- Wire agent model config through env (provider, name, api, base url, key, context window, max tokens)
- Refresh web styling and routes
This commit is contained in:
-Puter
2026-07-19 19:33:41 +05:30
parent 8cd479f20c
commit 5347db578d
24 changed files with 1336 additions and 93 deletions
+16
View File
@@ -0,0 +1,16 @@
import { useFlueAgent } from "@flue/react";
import { CHAT_AGENT } from "@/lib/chat/constants";
import type { ChatAgentState } from "@/lib/chat/types";
export const useChatAgent = (): ChatAgentState => {
const agent = useFlueAgent(CHAT_AGENT);
return {
error: agent.error,
historyReady: agent.historyReady,
messages: agent.messages,
sendMessage: agent.sendMessage,
status: agent.status,
};
};
@@ -0,0 +1,58 @@
import type { ChangeEvent, FormEvent, KeyboardEvent } from "react";
import { useRef, useState } from "react";
interface UseChatComposerOptions {
busy: boolean;
onSend: (message: string) => Promise<void>;
}
export const useChatComposer = ({ busy, onSend }: UseChatComposerOptions) => {
const [draft, setDraft] = useState("");
const [isFocused, setIsFocused] = useState(false);
const textareaRef = useRef<HTMLTextAreaElement>(null);
const canSend = draft.trim().length > 0 && !busy;
const handleSubmit = async (event?: FormEvent) => {
event?.preventDefault();
const message = draft.trim();
if (!message || busy) {
return;
}
setDraft("");
try {
await onSend(message);
} finally {
textareaRef.current?.focus();
}
};
const handleKeyDown = (event: KeyboardEvent<HTMLTextAreaElement>) => {
if (
event.key === "Enter" &&
!event.shiftKey &&
!event.nativeEvent.isComposing
) {
event.preventDefault();
void handleSubmit();
}
};
const inputProps = {
onBlur: () => setIsFocused(false),
onChange: (event: ChangeEvent<HTMLTextAreaElement>) =>
setDraft(event.target.value),
onFocus: () => setIsFocused(true),
onKeyDown: handleKeyDown,
ref: textareaRef,
value: draft,
};
return {
canSend,
draft,
handleSubmit,
inputProps,
isFocused,
};
};