fixed chat
This commit is contained in:
@@ -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
@@ -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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user