feat(FN-2306): add fresh quick-chat thread creation flow

- Add startFreshSession to useQuickChat so users can explicitly create a new persisted session for the current agent/model target
- Refactor session creation into a shared helper and track current session target to support fresh-thread creation without changing selection
- Add a New chat action to the QuickChatFAB header that starts a fresh thread while preserving active model/agent context
- Update quick chat hook/component tests to verify new-session behavior and message streaming targets
- Add header action styling for the new quick-chat controls
This commit is contained in:
Fusion
2026-04-23 10:24:19 -07:00
committed by gsxdsm
parent c7f7ac722a
commit 187e5fccf0
5 changed files with 203 additions and 21 deletions

View File

@@ -59,6 +59,7 @@ export interface UseQuickChatReturn {
clearPendingMessage: () => void;
switchSession: (agentId: string, modelProvider?: string, modelId?: string) => Promise<void>;
startModelChat: (modelProvider: string, modelId: string) => Promise<void>;
startFreshSession: () => Promise<void>;
loadMessages: () => Promise<void>;
reloadMessages: () => Promise<void>;
}
@@ -187,11 +188,29 @@ export function useQuickChat(
// Track the current selected chat target for session management
const currentSessionKeyRef = useRef<string>("");
const currentSessionTargetRef = useRef<SessionTarget | null>(null);
useEffect(() => {
pendingMessageRef.current = pendingMessage;
}, [pendingMessage]);
const createSessionForTarget = useCallback(
async (target: SessionTarget): Promise<ChatSession> => {
const newSessionInput: { agentId: string; modelProvider?: string; modelId?: string } = {
agentId: target.agentId,
};
if (target.modelProvider && target.modelId) {
newSessionInput.modelProvider = target.modelProvider;
newSessionInput.modelId = target.modelId;
}
const newSession = await createChatSession(newSessionInput, projectId);
return newSession.session;
},
[projectId],
);
// Fetch existing sessions and find/create one for the given target
const initializeSession = useCallback(
async (agentId: string, modelProvider?: string, modelId?: string) => {
@@ -209,17 +228,8 @@ export function useQuickChat(
setActiveSession(existingSession);
currentSessionKeyRef.current = sessionKey;
} else {
const newSessionInput: { agentId: string; modelProvider?: string; modelId?: string } = {
agentId: target.agentId,
};
if (target.modelProvider && target.modelId) {
newSessionInput.modelProvider = target.modelProvider;
newSessionInput.modelId = target.modelId;
}
const newSession = await createChatSession(newSessionInput, projectId);
setActiveSession(newSession.session);
const newSession = await createSessionForTarget(target);
setActiveSession(newSession);
currentSessionKeyRef.current = sessionKey;
}
} catch (err) {
@@ -229,7 +239,7 @@ export function useQuickChat(
setSessionsLoading(false);
}
},
[projectId, addToast],
[projectId, addToast, createSessionForTarget],
);
// Load messages for the active session
@@ -277,6 +287,7 @@ export function useQuickChat(
if (!target) return;
const targetSessionKey = buildSessionKey(target.agentId, target.modelProvider, target.modelId);
currentSessionTargetRef.current = target;
// Close any existing stream
if (streamRef.current) {
@@ -314,6 +325,38 @@ export function useQuickChat(
[switchSession],
);
const startFreshSession = useCallback(async () => {
const target = currentSessionTargetRef.current;
if (!target) return;
// Explicit "new chat" action: keep the same target key but create a new persisted session.
// This preserves normal switchSession resume behavior while allowing multiple threads per target.
const targetSessionKey = buildSessionKey(target.agentId, target.modelProvider, target.modelId);
if (streamRef.current) {
streamRef.current.close();
streamRef.current = null;
}
setStreamingText("");
setStreamingThinking("");
setStreamingToolCalls([]);
setIsStreaming(false);
setMessages([]);
setSessionsLoading(true);
try {
const newSession = await createSessionForTarget(target);
setActiveSession(newSession);
currentSessionKeyRef.current = targetSessionKey;
} catch (err) {
console.error("[useQuickChat] Failed to start a fresh session:", err);
addToast?.("Failed to start a new chat", "error");
} finally {
setSessionsLoading(false);
}
}, [addToast, createSessionForTarget]);
const stopStreaming = useCallback(() => {
if (!activeSession) return;
@@ -505,6 +548,7 @@ export function useQuickChat(
clearPendingMessage,
switchSession,
startModelChat,
startFreshSession,
loadMessages,
reloadMessages,
}), [
@@ -522,6 +566,7 @@ export function useQuickChat(
clearPendingMessage,
switchSession,
startModelChat,
startFreshSession,
loadMessages,
reloadMessages,
]);