feat(web-console): unify spatial UI and chat reset

This commit is contained in:
Miayui
2026-09-14 18:48:11 +08:00
parent 58f1a2da42
commit 84a3cd73bb
16 changed files with 333 additions and 86 deletions
+65 -18
View File
@@ -72,7 +72,14 @@
trigger.setAttribute("aria-label", "展开AI助手");
trigger.title = "展开AI助手";
trigger.innerHTML = '<i data-lucide="bot-message-square"></i><span class="visually-hidden">AI助手</span><b aria-hidden="true"></b>';
($("#v2PanelControlDock") || document.body).append(trigger);
const panelDock = $("#v2PanelControlDock");
if (panelDock) {
const firstRightPanelToggle = $("[data-panel-toggle]", panelDock);
if (firstRightPanelToggle) panelDock.insertBefore(trigger, firstRightPanelToggle);
else panelDock.append(trigger);
} else {
document.body.append(trigger);
}
trigger.addEventListener("click", () => {
setDrawerOpen(!document.body.classList.contains("assistant-drawer-open"));
@@ -1405,17 +1412,22 @@
const assistantMessage = createMessage("assistant", "", { pending: true });
pendingMessage = assistantMessage;
latestControlResult = null;
pendingController = new AbortController();
const requestController = new AbortController();
pendingController = requestController;
setComposerPending(true);
let completedError = null;
let resetForNewConversation = false;
try {
await streamAssistant(messageText, assistantMessage, pendingController.signal);
await streamAssistant(messageText, assistantMessage, requestController.signal);
setMessageContent(assistantMessage, assistantMessage.content, { final: true });
persistMessages();
} catch (error) {
completedError = error;
if (pendingController.signal.aborted) {
resetForNewConversation = requestController.signal.aborted
&& requestController.signal.reason === "new_conversation";
if (resetForNewConversation) return;
if (requestController.signal.aborted) {
const stopped = assistantMessage.content
? `${assistantMessage.content}\n\n已停止继续生成。已下发的车辆操作仍会由安全执行链路完成。`
: "已停止生成。已下发的车辆操作仍会由安全执行链路完成。";
@@ -1429,17 +1441,21 @@
}
persistMessages();
} finally {
pendingController = null;
pendingMessage = null;
setComposerPending(false);
input.focus({ preventScroll: true });
window.dispatchEvent(new CustomEvent("cognitive-agent:request-complete", {
detail: {
utterance: messageText,
result: latestControlResult,
error: completedError,
},
}));
if (pendingController === requestController) {
pendingController = null;
pendingMessage = null;
setComposerPending(false);
}
if (!resetForNewConversation) {
input.focus({ preventScroll: true });
window.dispatchEvent(new CustomEvent("cognitive-agent:request-complete", {
detail: {
utterance: messageText,
result: latestControlResult,
error: completedError,
},
}));
}
}
}
@@ -1490,6 +1506,37 @@
stored.forEach((message) => createMessage(message.role, String(message.content || "")));
}
function resetConversation() {
const activeController = pendingController;
pendingController = null;
pendingMessage = null;
latestControlResult = null;
if (activeController) activeController.abort("new_conversation");
sessionStorage.removeItem(STORAGE_KEY);
clearActiveModeDraftContext();
const nextConversationId = createConversationId();
sessionStorage.setItem(CONVERSATION_STORAGE_KEY, nextConversationId);
const input = $("#utterance");
if (input) {
input.value = "";
delete input.dataset.speechStage;
delete input.dataset.speechUtteranceId;
delete input.dataset.speechValue;
input.dispatchEvent(new Event("input", { bubbles: true }));
resizeComposerInput(input);
}
renderInitialMessages();
setComposerPending(false);
setDrawerOpen(true);
requestAnimationFrame(() => input?.focus({ preventScroll: true }));
window.dispatchEvent(new CustomEvent("cognitive-agent:new-conversation", {
detail: { conversationId: nextConversationId },
}));
return nextConversationId;
}
function initialize() {
if (initialized || !$("#requestForm") || !$("#assistantMessages")) return;
initialized = true;
@@ -1526,9 +1573,8 @@
document.addEventListener("click", (event) => {
const target = event.target instanceof Element ? event.target : null;
if (!target?.closest("#newConversation")) return;
sessionStorage.removeItem(STORAGE_KEY);
clearActiveModeDraftContext();
sessionStorage.setItem(CONVERSATION_STORAGE_KEY, createConversationId());
event.preventDefault?.();
resetConversation();
}, true);
document.addEventListener("DOMContentLoaded", initialize);
@@ -1536,6 +1582,7 @@
submit: submitAssistant,
open: () => setDrawerOpen(true),
close: () => setDrawerOpen(false),
resetConversation,
startModeCreation,
announceModeExecution,
announceModeCreated(profile) {