fixed chat

This commit is contained in:
2026-06-11 10:20:49 +03:00
parent 52ab7e1ac4
commit 363aca293a
2 changed files with 31 additions and 30 deletions
+2 -6
View File
@@ -243,9 +243,6 @@ class ChatService:
{"name": fn["name"], "result": json.loads(tool_result)} {"name": fn["name"], "result": json.loads(tool_result)}
) )
if notices:
return "\n\n".join(notices), notices, pomodoro_events
followup = await self.llm.complete( followup = await self.llm.complete(
messages, messages,
tools=None, tools=None,
@@ -384,6 +381,7 @@ class ChatService:
{"name": fn["name"], "result": json.loads(result)}, {"name": fn["name"], "result": json.loads(result)},
) )
yield self._sse("status", {"phase": "tools"})
for notice in round_notices: for notice in round_notices:
yield self._sse("notice", {"content": notice}) yield self._sse("notice", {"content": notice})
@@ -394,9 +392,6 @@ class ChatService:
final_content = "".join(streamed_reply_parts).strip() final_content = "".join(streamed_reply_parts).strip()
if not final_content and reasoning: if not final_content and reasoning:
final_content = reasoning.strip() final_content = reasoning.strip()
if not final_content and all_tool_notices:
final_content = "\n\n".join(all_tool_notices)
yield self._sse("token", {"content": final_content})
if not final_content and tools_executed: if not final_content and tools_executed:
retry = await self.llm.complete( retry = await self.llm.complete(
messages, messages,
@@ -407,6 +402,7 @@ class ChatService:
final_content = (retry.get("content") or "").strip() final_content = (retry.get("content") or "").strip()
if final_content: if final_content:
yield self._sse("token", {"content": final_content}) yield self._sse("token", {"content": final_content})
# Notices уже в чате как role=notice — не дублируем в assistant.
if not final_content: if not final_content:
final_content, fb_notices, fb_pomodoro = await self._fallback_complete( final_content, fb_notices, fb_pomodoro = await self._fallback_complete(
messages, session_id messages, session_id
+22 -17
View File
@@ -44,9 +44,9 @@ export default function Chat() {
const [input, setInput] = useState(""); const [input, setInput] = useState("");
const [loading, setLoading] = useState(false); const [loading, setLoading] = useState(false);
const [streaming, setStreaming] = useState(""); const [streaming, setStreaming] = useState("");
const [pendingPhase, setPendingPhase] = useState<"thinking" | "preparing" | "generating">( const [pendingPhase, setPendingPhase] = useState<
"thinking", "thinking" | "preparing" | "generating" | "tools"
); >("thinking");
const [liveNotices, setLiveNotices] = useState<string[]>([]); const [liveNotices, setLiveNotices] = useState<string[]>([]);
const [chatError, setChatError] = useState<string | null>(null); const [chatError, setChatError] = useState<string | null>(null);
const messagesRef = useRef<HTMLDivElement>(null); const messagesRef = useRef<HTMLDivElement>(null);
@@ -54,6 +54,7 @@ export default function Chat() {
const scrollRafRef = useRef<number | null>(null); const scrollRafRef = useRef<number | null>(null);
const { status: pomodoroStatus, refresh: refreshPomodoro } = usePomodoro(); const { status: pomodoroStatus, refresh: refreshPomodoro } = usePomodoro();
const [lastNotifySeq, setLastNotifySeq] = useState(0); const [lastNotifySeq, setLastNotifySeq] = useState(0);
const pendingHistoryReload = useRef(false);
const loadSessions = async () => { const loadSessions = async () => {
const data = await api.listSessions(); const data = await api.listSessions();
@@ -108,7 +109,9 @@ export default function Chat() {
const waitingForStream = loading && !streaming; const waitingForStream = loading && !streaming;
const pendingLabel = const pendingLabel =
liveNotices.length > 0 pendingPhase === "tools"
? "Выполняю команды…"
: liveNotices.length > 0
? "Обрабатываю…" ? "Обрабатываю…"
: pendingPhase === "preparing" : pendingPhase === "preparing"
? "Собираю контекст…" ? "Собираю контекст…"
@@ -121,11 +124,14 @@ export default function Chat() {
if (seq > lastNotifySeq) { if (seq > lastNotifySeq) {
setLastNotifySeq(seq); setLastNotifySeq(seq);
refreshPomodoro().catch(console.error); refreshPomodoro().catch(console.error);
// Не перезагружать историю во время стрима — ломает UI и сбивает ответ. if (activeId) {
if (activeId && !loading) { if (loading) {
pendingHistoryReload.current = true;
} else {
loadMessages(activeId).catch(console.error); loadMessages(activeId).catch(console.error);
} }
} }
}
}, [pomodoroStatus?.cycle?.chat_notify_seq, activeId, lastNotifySeq, refreshPomodoro, loading]); }, [pomodoroStatus?.cycle?.chat_notify_seq, activeId, lastNotifySeq, refreshPomodoro, loading]);
const handleNewChat = async () => { const handleNewChat = async () => {
@@ -178,9 +184,15 @@ export default function Chat() {
if (chunk.data.phase === "generating") { if (chunk.data.phase === "generating") {
setPendingPhase("generating"); setPendingPhase("generating");
} }
if (chunk.data.phase === "tools") {
setPendingPhase("tools");
assistantText = "";
setStreaming("");
}
} }
if (chunk.event === "token") { if (chunk.event === "token") {
assistantText += chunk.data.content; assistantText += chunk.data.content;
setPendingPhase("generating");
setStreaming(assistantText); setStreaming(assistantText);
} }
if (chunk.event === "notice") { if (chunk.event === "notice") {
@@ -196,17 +208,6 @@ export default function Chat() {
setStreaming(""); setStreaming("");
setLiveNotices([]); setLiveNotices([]);
setChatError(null); setChatError(null);
if (assistantText.trim()) {
setMessages((prev) => [
...prev,
{
id: Date.now(),
role: "assistant",
content: assistantText,
created_at: new Date().toISOString(),
},
]);
}
await loadMessages(activeId); await loadMessages(activeId);
await loadSessions(); await loadSessions();
} }
@@ -224,6 +225,10 @@ export default function Chat() {
} }
} finally { } finally {
setLoading(false); setLoading(false);
if (pendingHistoryReload.current && activeId) {
pendingHistoryReload.current = false;
loadMessages(activeId).catch(console.error);
}
} }
}; };