From 71a4e685200267d7cc95df3a539aed94142b5c37 Mon Sep 17 00:00:00 2001 From: Oliver Bryan Date: Sat, 31 Jan 2026 14:16:54 +0000 Subject: [PATCH] model selection and highlighting logic --- packages/frontend/src/components/chat.tsx | 105 ++++++++++++++++++---- 1 file changed, 89 insertions(+), 16 deletions(-) diff --git a/packages/frontend/src/components/chat.tsx b/packages/frontend/src/components/chat.tsx index 0d2d2c3..9221e7b 100644 --- a/packages/frontend/src/components/chat.tsx +++ b/packages/frontend/src/components/chat.tsx @@ -1,22 +1,41 @@ -import { useState } from "react"; +import { Fragment, type SubmitEvent, useEffect, useState } from "react"; import { Button } from "@/components/ui/button"; import Icon from "@/components/ui/icon"; -import { useChatMutation, useSelectedOrganisation, useSelectedProject } from "@/lib/query/hooks"; +import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select"; +import { useChat, useModels, useSelectedOrganisation, useSelectedProject } from "@/lib/query/hooks"; import { parseError } from "@/lib/server"; +import Avatar from "./avatar"; +import { useAuthenticatedSession } from "./session-provider"; import { IconButton } from "./ui/icon-button"; import { Input } from "./ui/input"; -export function Chat() { +export function Chat({ setHighlighted }: { setHighlighted: (ids: number[]) => void }) { + const { user } = useAuthenticatedSession(); const selectedOrganisation = useSelectedOrganisation(); const selectedProject = useSelectedProject(); - const chatMutation = useChatMutation(); + const chat = useChat(); + const models = useModels(); const [isOpen, setIsOpen] = useState(false); const [message, setMessage] = useState(""); const [response, setResponse] = useState(""); + const [lastUserMessage, setLastUserMessage] = useState(""); const [error, setError] = useState(null); + const [selectedModel, setSelectedModel] = useState(""); - const handleSubmit = async (e: React.FormEvent) => { + useEffect(() => { + if (isOpen && !models.data) { + models.mutate(); + } + }, [isOpen, models]); + + useEffect(() => { + if (models.data && models.data.length > 0 && !selectedModel) { + setSelectedModel(models.data[0].id); + } + }, [models.data, selectedModel]); + + const handleSubmit = async (e: SubmitEvent) => { e.preventDefault(); if (!message.trim()) return; @@ -27,14 +46,18 @@ export function Chat() { setError(null); setResponse(""); + setHighlighted([]); + setLastUserMessage(message.trim()); try { - const data = await chatMutation.mutateAsync({ + const data = await chat.mutateAsync({ orgId: selectedOrganisation.Organisation.id, projectId: selectedProject.Project.id, message: message.trim(), + model: selectedModel || "trinity-large-preview-free", }); setResponse(data.text); + setHighlighted(data.highlighted_issues); setMessage(""); } catch (err) { const errorMessage = parseError(err as Error); @@ -54,43 +77,93 @@ export function Chat() { {isOpen && ( -
-
+
+
+ {lastUserMessage && ( +
+ +

{lastUserMessage}

+
+ )} {response && ( -
-

{response}

+
+

+ {response.split("\n").map((line, index) => ( + // biome-ignore lint/suspicious/noArrayIndexKey: <> + + {line} +
+
+ ))} +

)} - {chatMutation.isPending && ( + {chat.isPending && (
- +
)}
+ {models.data && models.data.length > 0 && ( + + )} ) => setMessage(e.target.value)} placeholder={`Ask me anything about the ${selectedProject?.Project.name || "..."} project...`} - disabled={chatMutation.isPending} + disabled={chat.isPending} showCounter={false} />
+ {} {error && ( -
+

{error}

)}