fix(webui): clarify new chat command text

This commit is contained in:
chengyongru 2026-07-07 14:34:18 +08:00 committed by Xubin Ren
parent 7e135b45f3
commit a7b8a9ed46
12 changed files with 50 additions and 17 deletions

View File

@ -58,7 +58,7 @@ BUILTIN_COMMAND_SPECS: tuple[BuiltinCommandSpec, ...] = (
BuiltinCommandSpec( BuiltinCommandSpec(
"/new", "/new",
"New chat", "New chat",
"Stop the current task and start a fresh conversation.", "Reset this chat and start a fresh conversation.",
"square-pen", "square-pen",
lifecycle="finalize_active_turn", lifecycle="finalize_active_turn",
), ),

View File

@ -975,12 +975,13 @@ export function ThreadComposer({
}, [cursorPosition, disabled, slashMenuDismissed, value]); }, [cursorPosition, disabled, slashMenuDismissed, value]);
const visibleSlashCommands = useMemo(() => { const visibleSlashCommands = useMemo(() => {
const baseCommands = slashCommands.filter( if (!(isStreaming && onStop)) return slashCommands;
(command) => command.command !== "/stop" && command.command !== "/restart",
);
if (!(isStreaming && onStop)) return baseCommands;
const stopCommand = slashCommands.find((command) => command.command === "/stop"); const stopCommand = slashCommands.find((command) => command.command === "/stop");
return stopCommand ? [stopCommand, ...baseCommands] : baseCommands; if (!stopCommand) return slashCommands;
return [
stopCommand,
...slashCommands.filter((command) => command.command !== "/stop"),
];
}, [isStreaming, onStop, slashCommands]); }, [isStreaming, onStop, slashCommands]);
const filteredSlashCommands = useMemo<SlashPaletteCommand[]>(() => { const filteredSlashCommands = useMemo<SlashPaletteCommand[]>(() => {
@ -1012,6 +1013,15 @@ export function ThreadComposer({
if (slashQuery === null) return []; if (slashQuery === null) return [];
const withDetails = visibleSlashCommands const withDetails = visibleSlashCommands
.filter((command) => { .filter((command) => {
if (
slashQuery === ""
&& (
command.command === "/restart"
|| (command.command === "/stop" && !(isStreaming && onStop))
)
) {
return false;
}
const commandKey = slashCommandI18nKey(command.command); const commandKey = slashCommandI18nKey(command.command);
const title = t(`thread.composer.slash.commands.${commandKey}.title`, { const title = t(`thread.composer.slash.commands.${commandKey}.title`, {
defaultValue: command.title, defaultValue: command.title,

View File

@ -905,7 +905,7 @@
"commands": { "commands": {
"new": { "new": {
"title": "New chat", "title": "New chat",
"description": "Stop the current task and start a fresh conversation." "description": "Reset this chat and start a fresh conversation."
}, },
"stop": { "stop": {
"title": "Stop current task", "title": "Stop current task",

View File

@ -895,7 +895,7 @@
"commands": { "commands": {
"new": { "new": {
"title": "Nuevo chat", "title": "Nuevo chat",
"description": "Detiene la tarea actual e inicia una conversación nueva." "description": "Restablece este chat e inicia una conversación nueva."
}, },
"stop": { "stop": {
"title": "Detener tarea actual", "title": "Detener tarea actual",

View File

@ -895,7 +895,7 @@
"commands": { "commands": {
"new": { "new": {
"title": "Nouvelle discussion", "title": "Nouvelle discussion",
"description": "Arrêter la tâche en cours et démarrer une nouvelle conversation." "description": "Réinitialiser cette discussion et démarrer une nouvelle conversation."
}, },
"stop": { "stop": {
"title": "Arrêter la tâche en cours", "title": "Arrêter la tâche en cours",

View File

@ -895,7 +895,7 @@
"commands": { "commands": {
"new": { "new": {
"title": "Obrolan baru", "title": "Obrolan baru",
"description": "Hentikan tugas saat ini dan mulai percakapan baru." "description": "Reset chat ini dan mulai percakapan baru."
}, },
"stop": { "stop": {
"title": "Hentikan tugas saat ini", "title": "Hentikan tugas saat ini",

View File

@ -895,7 +895,7 @@
"commands": { "commands": {
"new": { "new": {
"title": "新しいチャット", "title": "新しいチャット",
"description": "現在のタスクを停止して、新しい会話を開始します。" "description": "このチャットをリセットして、新しい会話を開始します。"
}, },
"stop": { "stop": {
"title": "現在のタスクを停止", "title": "現在のタスクを停止",

View File

@ -895,7 +895,7 @@
"commands": { "commands": {
"new": { "new": {
"title": "새 채팅", "title": "새 채팅",
"description": "현재 작업을 중지하고 새 대화를 시작합니다." "description": "이 채팅을 초기화하고 새 대화를 시작합니다."
}, },
"stop": { "stop": {
"title": "현재 작업 중지", "title": "현재 작업 중지",

View File

@ -895,7 +895,7 @@
"commands": { "commands": {
"new": { "new": {
"title": "Cuộc trò chuyện mới", "title": "Cuộc trò chuyện mới",
"description": "Dừng tác vụ hiện tại và bắt đầu một cuộc trò chuyện mới." "description": "Đặt lại cuộc trò chuyện này và bắt đầu một cuộc trò chuyện mới."
}, },
"stop": { "stop": {
"title": "Dừng tác vụ hiện tại", "title": "Dừng tác vụ hiện tại",

View File

@ -904,7 +904,7 @@
"commands": { "commands": {
"new": { "new": {
"title": "新建对话", "title": "新建对话",
"description": "停止当前任务,并开始一个新的对话。" "description": "重置当前对话,并开始一个新的对话。"
}, },
"stop": { "stop": {
"title": "停止当前任务", "title": "停止当前任务",

View File

@ -895,7 +895,7 @@
"commands": { "commands": {
"new": { "new": {
"title": "新增對話", "title": "新增對話",
"description": "停止目前任務,並開始新的對話。" "description": "重置目前對話,並開始新的對話。"
}, },
"stop": { "stop": {
"title": "停止目前任務", "title": "停止目前任務",

View File

@ -854,6 +854,29 @@ describe("ThreadComposer", () => {
expect(screen.queryByRole("listbox", { name: "Slash commands" })).not.toBeInTheDocument(); expect(screen.queryByRole("listbox", { name: "Slash commands" })).not.toBeInTheDocument();
}); });
it("offers stop autocomplete once the user starts typing it", () => {
const onSend = vi.fn();
render(
<ThreadComposer
onSend={onSend}
placeholder="Type your message..."
slashCommands={COMMANDS}
/>,
);
const input = screen.getByLabelText("Message input");
fireEvent.change(input, { target: { value: "/sto" } });
expect(screen.getByRole("option", { name: /\/stop/i })).toHaveAttribute(
"aria-selected",
"true",
);
fireEvent.keyDown(input, { key: "Enter" });
expect(input).toHaveValue("/stop");
expect(onSend).not.toHaveBeenCalled();
});
it("renders slash commands as direct actions with current status", () => { it("renders slash commands as direct actions with current status", () => {
render( render(
<ThreadComposer <ThreadComposer
@ -1363,7 +1386,7 @@ describe("ThreadComposer", () => {
{ {
command: "/new", command: "/new",
title: "New chat", title: "New chat",
description: "Stop the current task and start a fresh conversation.", description: "Reset this chat and start a fresh conversation.",
icon: "square-pen", icon: "square-pen",
lifecycle: "finalize_active_turn", lifecycle: "finalize_active_turn",
acceptsArgs: false, acceptsArgs: false,
@ -1393,7 +1416,7 @@ describe("ThreadComposer", () => {
{ {
command: "/new", command: "/new",
title: "New chat", title: "New chat",
description: "Stop the current task and start a fresh conversation.", description: "Reset this chat and start a fresh conversation.",
icon: "square-pen", icon: "square-pen",
lifecycle: "finalize_active_turn", lifecycle: "finalize_active_turn",
acceptsArgs: false, acceptsArgs: false,