feat(frontend): M9 模态 UI(mode 系统+共享 store+WS 客户端 + chat(思维链/工具回显/情绪徽标)/code/Agent 监控/后台思考页 + Miuix 设计 token + PWA);tsc+vite build 通过

This commit is contained in:
Aska committed 2026-09-06 07:44:40 +08:00
1 parent b3ffd51736
commit 4c48e94659
40 files changed
+5321

No files matched your search

+52
View File
@@ -0,0 +1,52 @@
import { useCallback, useState } from "react";
import { chatStream } from "./api";
import { connectWs, isWsOpen } from "./ws";
import { useAppStore } from "../store/useAppStore";
import { now } from "./util";
/** Drives one user turn: push the user bubble, blanket a streaming assistant
* bubble, trigger the backend loop over REST (`stream:true`), and let the WS
* stream render into that bubble. Falls back to the WS `chat` channel when the
* REST trigger fails so the demo still works without a wired loop. */
export function useSendChat(): {
send: (text: string) => Promise<void>;
sending: boolean;
} {
const [sending, setSending] = useState(false);
const sessionId = useAppStore((s) => s.sessionId);
const addUserMessage = useAppStore((s) => s.addUserMessage);
const beginAssistant = useAppStore((s) => s.beginAssistant);
const endStream = useAppStore((s) => s.endStream);
const appendChunk = useAppStore((s) => s.appendChunk);
const addTool = useAppStore((s) => s.addTool);
const appendTaskLog = useAppStore((s) => s.appendTaskLog);
const send = useCallback(
async (text: string) => {
const trimmed = text.trim();
if (!trimmed || sending) return;
setSending(true);
if (!isWsOpen()) connectWs();
addUserMessage(trimmed);
beginAssistant();
try {
await chatStream(sessionId, trimmed);
} catch (err: unknown) {
// Backend loop not wired or gateway unreachable: show the failure inline
// rather than leaving a permanently-streaming bubble.
endStream();
const msg = err instanceof Error ? err.message : "触发失败";
appendChunk(`[stream 触发失败] ${msg}`);
appendTaskLog("main", `[error] ${msg}\n`);
addTool({ name: "stream_trigger", summary: "失败", ok: false, detail: msg, at: now() });
} finally {
setSending(false);
}
},
[sending, sessionId, addUserMessage, beginAssistant, endStream, appendChunk, addTool, appendTaskLog]
);
return { send, sending };
}