Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
7593c1a
refactor: add persistent SSE event buffer for background task replay
amir-ghasemi Feb 7, 2026
a1e898e
fix: minor fixes
amir-ghasemi Feb 7, 2026
f783548
feat: unified event buffer architecture - FE always saves chat_tasks …
amir-ghasemi Feb 7, 2026
41fe370
fix: Implicit buffer cleanup, remove chat_tasks persistence from Task…
amir-ghasemi Feb 7, 2026
1ea591a
fix: auto title generation from chat_tasks with new endpoint
amir-ghasemi Feb 7, 2026
934a5d6
fix: repeated background task status calls
amir-ghasemi Feb 7, 2026
a836440
fix: replay fixes
amir-ghasemi Feb 7, 2026
736fa8d
fix: remove timeout
amir-ghasemi Feb 7, 2026
d3811c8
feat: add hybrid RAM+DB buffer with task-close flush fix
amir-ghasemi Feb 8, 2026
1f947a4
fix: add hybrid buffer config flag
amir-ghasemi Feb 8, 2026
0ccf4e1
fix: unit tests, optimize task query
amir-ghasemi Feb 8, 2026
0d869b4
Merge branch 'main' of github.com:SolaceLabs/solace-agent-mesh into a…
amir-ghasemi Feb 8, 2026
21288a7
fix: Sequence number race condition
amir-ghasemi Feb 8, 2026
7d84878
fix: stale buffer size in debug log
amir-ghasemi Feb 8, 2026
20cb10d
fix: rename _is_background_task to reflect new unified architecture
amir-ghasemi Feb 8, 2026
d2fed1f
fix: confirmation dialog when navigating away from running tak with b…
amir-ghasemi Feb 8, 2026
12b2961
`fix: Start new transaction after rollback in task_logger_service to …
amir-ghasemi Feb 8, 2026
3523db8
fix: Add auth protection to /tasks/{task_id}/title-data endpoint with…
amir-ghasemi Feb 8, 2026
a691876
fix: add auth unit tests
amir-ghasemi Feb 9, 2026
46ffcc4
chore: more tests
amir-ghasemi Feb 9, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 6 additions & 3 deletions client/webui/frontend/src/lib/components/chat/SessionList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -37,10 +37,13 @@ const SessionName: React.FC<SessionNameProps> = ({ session, respondingSessionId
return false; // No pulse when auto title generation is disabled
}
const isNewChat = !session.name || session.name === "New Chat";
// Only pulse if this session is the one that started the response
// Pulse if this session is the one that started the response
const isThisSessionResponding = respondingSessionId === session.id;
return isThisSessionResponding && isNewChat;
}, [session.name, session.id, respondingSessionId, isGenerating, autoTitleGenerationEnabled]);
// Also pulse if this session has a running background task and no title yet
// This handles the case where user switched away while task is running
const hasBackgroundTaskWithNewTitle = session.hasRunningBackgroundTask && isNewChat;
return (isThisSessionResponding && isNewChat) || hasBackgroundTaskWithNewTitle;
}, [session.name, session.id, respondingSessionId, isGenerating, autoTitleGenerationEnabled, session.hasRunningBackgroundTask]);

// Show slow pulse while waiting for title, faster pulse during transition animation
const animationClass = useMemo(() => {
Expand Down
14 changes: 13 additions & 1 deletion client/webui/frontend/src/lib/hooks/useBackgroundTaskMonitor.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
/**
* Hook for monitoring and reconnecting to background tasks.
* Stores active background tasks in localStorage and automatically reconnects on session load.
*/

import { useState, useEffect, useCallback, useRef } from "react";
import { api } from "@/lib/api";
import type { BackgroundTaskState, BackgroundTaskStatusResponse, ActiveBackgroundTasksResponse, BackgroundTaskNotification } from "@/lib/types/background-tasks";
Expand All @@ -17,8 +22,8 @@ interface UseBackgroundTaskMonitorProps {
*/
export function useBackgroundTaskMonitor({ userId, onTaskCompleted, onTaskFailed }: UseBackgroundTaskMonitorProps) {
const [backgroundTasks, setBackgroundTasks] = useState<BackgroundTaskState[]>([]);
const backgroundTasksRef = useRef<BackgroundTaskState[]>(backgroundTasks);
const [notifications, setNotifications] = useState<BackgroundTaskNotification[]>([]);
const backgroundTasksRef = useRef<BackgroundTaskState[]>([]);

// Load background tasks from localStorage on mount
useEffect(() => {
Expand All @@ -34,6 +39,11 @@ export function useBackgroundTaskMonitor({ userId, onTaskCompleted, onTaskFailed
}
}, []);

// Keep the ref in sync with state
useEffect(() => {
backgroundTasksRef.current = backgroundTasks;
}, [backgroundTasks]);

// Save background tasks to localStorage whenever they change
useEffect(() => {
if (backgroundTasks.length > 0) {
Expand Down Expand Up @@ -101,6 +111,7 @@ export function useBackgroundTaskMonitor({ userId, onTaskCompleted, onTaskFailed
);

// Check all background tasks and update their status
// Uses backgroundTasksRef to read current tasks, making this callback stable
const checkAllBackgroundTasks = useCallback(async () => {
const tasks = backgroundTasksRef.current;
if (tasks.length === 0) {
Expand Down Expand Up @@ -202,6 +213,7 @@ export function useBackgroundTaskMonitor({ userId, onTaskCompleted, onTaskFailed
// Periodic checking to detect background task completion when not connected to SSE
// This handles the case where a task completes while the user is on a different session
const hasBackgroundTasks = backgroundTasks.length > 0;

useEffect(() => {
if (!hasBackgroundTasks) {
return;
Expand Down
16 changes: 13 additions & 3 deletions client/webui/frontend/src/lib/hooks/useBeforeUnload.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,25 @@ import { useChatContext } from "./useChatContext";
import { useConfigContext } from "./useConfigContext";

export function useBeforeUnload() {
const { messages } = useChatContext();
const { messages, isResponding } = useChatContext();
const config = useConfigContext();

/**
* Cross-browser beforeunload event handler
* Only warns when persistence is disabled and messages exist
* Warns when:
* 1. Persistence is disabled and messages exist (chat history would be lost)
* 2. A task is running and background tasks are disabled (task results would be lost)
*/
const handleBeforeUnload = useCallback(
(event: BeforeUnloadEvent): string | void => {
// Case 1: Task is running and background tasks are disabled
// In this case, navigating away may cause the user to lose the task results
if (isResponding && config?.backgroundTasksEnabled === false) {
event.preventDefault();
return "A task is currently running. If you leave now, you may lose the response. Are you sure you want to leave?";
}

// Case 2: Persistence disabled and messages exist (original behavior)
if (config?.persistenceEnabled !== false) {
return;
}
Expand All @@ -24,7 +34,7 @@ export function useBeforeUnload() {

return "Are you sure you want to leave? Your chat history will be lost.";
},
[messages.length, config?.persistenceEnabled]
[messages.length, config?.persistenceEnabled, config?.backgroundTasksEnabled, isResponding]
);

/**
Expand Down
4 changes: 2 additions & 2 deletions client/webui/frontend/src/lib/hooks/useTitleGeneration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ export const useTitleGeneration = () => {
}
}

console.log(`[useTitleGeneration] Initial title: "${initialTitle}"`);
console.debug(`[useTitleGeneration] Initial title: "${initialTitle}"`);

// Dispatch event to indicate title generation is starting
if (typeof window !== "undefined") {
Expand Down Expand Up @@ -66,7 +66,7 @@ export const useTitleGeneration = () => {
return;
}

console.log("[useTitleGeneration] Title generation triggered, polling for update...");
console.debug("[useTitleGeneration] Title generation triggered, polling for update...");

// Poll for title update with exponential backoff
const pollForTitle = async () => {
Expand Down
Loading
Loading