refactor(web): 前端单页收敛修正——导航式侧边栏 + 去输入模式 chip,mode 由后端自切

按设计/01 §3 + 主人要求:行为模式切换由后端/agent 自切(热切换),前端不再提供
手动切换的行为模式按钮列表。
- 侧边栏改为导航式(连接状态 / 设置 / 管理面板 / 主题),不再列行为模式按钮;
  App.tsx 还原 <Sidebar/> 布局。
- ChatInput 去掉行为模式 chip 切换条(模式不由用户手选)。
- useChat.send/chatStream 不再传 mode;消息 mode 由后端在回复时决定,
  MessageBubble 仍按 message.mode 渲染。
- ChatShell onVoice 为占位(语音处理在 agent)。
This commit is contained in:
Aska committed 2026-09-06 14:04:46 +08:00
1 parent 4aab0f501a
commit 77f75b0d99
6 files changed
+105 -129

No files matched your search

+2 -2
View File
@@ -155,10 +155,10 @@ export function chatSync(
}
/** POST /api/v1/chat with stream:true — triggers streaming over the WS channel. */
export function chatStream(sessionId: string, text: string, mode?: Mode): Promise<{ stream: true }> {
export function chatStream(sessionId: string, text: string): Promise<{ stream: true }> {
return request<{ stream: true }>("/chat", {
method: "POST",
body: JSON.stringify({ sessionId, text, stream: true, mode }),
body: JSON.stringify({ sessionId, text, stream: true }),
});
}
+8 -10
View File
@@ -2,19 +2,18 @@ import { useCallback, useState } from "react";
import { chatStream } from "./api";
import { connectWs, isWsOpen } from "./ws";
import { useAppStore } from "../store/useAppStore";
import { useModeStore } from "../store/useModeStore";
import { now } from "./util";
import type { Mode } from "./types";
/** 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.
*
* Each message carries the current input mode, so its bubble renders per that
* mode (design/07 §1: shared message stream, per-message mode rendering). */
* The behavior mode is NOT chosen by the user at send time — the agent / backend
* hot-switches it (design/01 §3), and each message carries its own mode, so the
* bubble renders per that message's mode. */
export function useSendChat(): {
send: (text: string, mode?: Mode) => Promise<void>;
send: (text: string) => Promise<void>;
sending: boolean;
} {
const [sending, setSending] = useState(false);
@@ -27,18 +26,17 @@ export function useSendChat(): {
const appendTaskLog = useAppStore((s) => s.appendTaskLog);
const send = useCallback(
async (text: string, mode?: Mode) => {
async (text: string) => {
const trimmed = text.trim();
if (!trimmed || sending) return;
setSending(true);
if (!isWsOpen()) connectWs();
const m = mode ?? "chat";
addUserMessage(trimmed, m);
beginAssistant(m);
addUserMessage(trimmed);
beginAssistant();
try {
await chatStream(sessionId, trimmed, m);
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.