feat(FN-3062): add /clear command to Chat and Quick Chat, fix session banne

The merge adds a `/clear` command to both the Chat view and Quick Chat that clears transient chat state on session resets, with tests for all new hooks and components. It also persists session banner dismissals via a new `useSessionBannerPref` hook, adds a hide-banner setting, and preserves planning

Fusion-Task-Id: FN-3062
This commit is contained in:
Fusion
2026-05-01 13:17:09 -07:00
committed by gsxdsm
parent 0e0754f790
commit c729527fcc
9 changed files with 294 additions and 31 deletions

View File

@@ -979,18 +979,13 @@ export function ChatView({ projectId, addToast }: ChatViewProps) {
[createSession, addToast, isMobile],
);
// Handle send message including pending attachment uploads.
const handleSend = useCallback(() => {
const trimmed = messageInput.trim();
const files = pendingAttachments.map((attachment) => attachment.file);
if ((!trimmed && files.length === 0) || !activeSession) return;
const clearComposerState = useCallback(() => {
setMessageInput("");
setShowSkillMenu(false);
setSkillFilter("");
setMentionPopupVisible(false);
setMentionFilter("");
setMentionStartPos(-1);
sendMessage(trimmed, files);
setPendingAttachments((prev) => {
for (const attachment of prev) {
if (attachment.previewUrl) {
@@ -999,7 +994,41 @@ export function ChatView({ projectId, addToast }: ChatViewProps) {
}
return [];
});
}, [messageInput, pendingAttachments, activeSession, sendMessage]);
}, []);
// Handle send message including pending attachment uploads.
const handleSend = useCallback(() => {
const trimmed = messageInput.trim();
const files = pendingAttachments.map((attachment) => attachment.file);
if ((!trimmed && files.length === 0) || !activeSession) return;
if (trimmed === "/clear") {
clearComposerState();
stopStreaming();
clearPendingMessage();
void createSession({
agentId: activeSession.agentId,
modelProvider: activeSession.modelProvider ?? undefined,
modelId: activeSession.modelId ?? undefined,
}).catch(() => {
addToast("Failed to clear conversation", "error");
});
return;
}
clearComposerState();
sendMessage(trimmed, files);
}, [
messageInput,
pendingAttachments,
activeSession,
clearComposerState,
stopStreaming,
clearPendingMessage,
createSession,
addToast,
sendMessage,
]);
const focusComposerInput = useCallback(() => {
if (typeof window === "undefined") return;