Skip to content

Commit b44b289

Browse files
committed
feat: implement task extraction from assistant messages and clear processed message IDs on session switch
1 parent f48c199 commit b44b289

1 file changed

Lines changed: 66 additions & 37 deletions

File tree

src/client/components/chat-panel.tsx

Lines changed: 66 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -280,6 +280,8 @@ export function ChatPanel({
280280
setVisibleMessages([]);
281281
return;
282282
}
283+
// Clear processed message IDs when switching sessions
284+
processedMessageIdsRef.current.clear();
283285
// Load history if not yet loaded
284286
fetchSessionHistory(activeSessionId);
285287
setVisibleMessages(messagesBySession[activeSessionId] ?? []);
@@ -641,9 +643,70 @@ export function ChatPanel({
641643
if (Object.keys(modeUpdates).length > 0) {
642644
setSessionModeById((prev) => ({ ...prev, ...modeUpdates }));
643645
}
644-
// eslint-disable-next-line react-hooks/exhaustive-deps
645646
}, [updates]);
646647

648+
// ── Extract tasks from messages after SSE updates ────────────────────
649+
// Track which messages have been checked for tasks to avoid re-processing
650+
const processedMessageIdsRef = useRef<Set<string>>(new Set());
651+
652+
useEffect(() => {
653+
if (!onTasksDetected || !activeSessionId) return;
654+
655+
const messages = messagesBySession[activeSessionId];
656+
if (!messages || messages.length === 0) return;
657+
658+
// Check if any NEW assistant message contains task blocks
659+
let detectedTasks: ParsedTask[] = [];
660+
let hasNewTasksToExtract = false;
661+
662+
for (const msg of messages) {
663+
if (msg.role === "assistant" &&
664+
!processedMessageIdsRef.current.has(msg.id) &&
665+
hasTaskBlocks(msg.content)) {
666+
hasNewTasksToExtract = true;
667+
break;
668+
}
669+
}
670+
671+
if (!hasNewTasksToExtract) return;
672+
673+
// Extract tasks and clean message content
674+
setMessagesBySession((prev) => {
675+
const msgs = prev[activeSessionId];
676+
if (!msgs) return prev;
677+
678+
const arr = [...msgs];
679+
let tasksFound = false;
680+
681+
for (let i = 0; i < arr.length; i++) {
682+
const msg = arr[i];
683+
if (msg.role === "assistant" &&
684+
!processedMessageIdsRef.current.has(msg.id) &&
685+
hasTaskBlocks(msg.content)) {
686+
const { tasks, cleanedContent } = extractTaskBlocks(msg.content);
687+
if (tasks.length > 0) {
688+
// Replace the message content with cleaned version (tasks removed)
689+
arr[i] = { ...msg, content: cleanedContent };
690+
detectedTasks = tasks;
691+
tasksFound = true;
692+
// Mark this message as processed
693+
processedMessageIdsRef.current.add(msg.id);
694+
}
695+
}
696+
}
697+
698+
if (tasksFound) {
699+
return { ...prev, [activeSessionId]: arr };
700+
}
701+
return prev;
702+
});
703+
704+
// Notify parent about detected tasks
705+
if (detectedTasks.length > 0) {
706+
onTasksDetected(detectedTasks);
707+
}
708+
}, [messagesBySession, activeSessionId, onTasksDetected]);
709+
647710
// ── Actions ──────────────────────────────────────────────────────────
648711

649712
const handleRepoChange = onRepoChange;
@@ -711,42 +774,8 @@ export function ChatPanel({
711774
streamingMsgIdRef.current[sid] = null;
712775
streamingThoughtIdRef.current[sid] = null;
713776

714-
// After prompt completes, check assistant messages for @@@task blocks
715-
if (onTasksDetected) {
716-
let detectedTasks: ParsedTask[] = [];
717-
718-
setMessagesBySession((prev) => {
719-
const msgs = prev[sid];
720-
if (!msgs) return prev;
721-
722-
const arr = [...msgs];
723-
let tasksFound = false;
724-
725-
for (let i = 0; i < arr.length; i++) {
726-
const msg = arr[i];
727-
if (msg.role === "assistant" && hasTaskBlocks(msg.content)) {
728-
const { tasks, cleanedContent } = extractTaskBlocks(msg.content);
729-
if (tasks.length > 0) {
730-
// Replace the message content with cleaned version (tasks removed)
731-
arr[i] = { ...msg, content: cleanedContent };
732-
detectedTasks = tasks;
733-
tasksFound = true;
734-
}
735-
}
736-
}
737-
738-
if (tasksFound) {
739-
return { ...prev, [sid]: arr };
740-
}
741-
return prev;
742-
});
743-
744-
// Call onTasksDetected outside the state updater to avoid setState-during-render
745-
if (detectedTasks.length > 0) {
746-
onTasksDetected(detectedTasks);
747-
}
748-
}
749-
}, [activeSessionId, onEnsureSession, onSelectSession, prompt, repoSelection, onLoadSkill, acp, onTasksDetected]);
777+
// Task extraction is now handled by the useEffect that watches messagesBySession
778+
}, [activeSessionId, onEnsureSession, onSelectSession, prompt, repoSelection, onLoadSkill, acp]);
750779

751780
// ── Render ───────────────────────────────────────────────────────────
752781

0 commit comments

Comments
 (0)