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:
@@ -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,
|
||||
};
|
||||
};
|
||||
Reference in New Issue
Block a user