fix(frontend): avoid render-time subtask context mutation

This commit is contained in:
copilot-swe-agent[bot]
2026-06-07 13:35:28 +00:00
committed by GitHub
parent 9593214065
commit 150d03f2e7
5 changed files with 135 additions and 90 deletions
+24 -21
View File
@@ -1,23 +1,26 @@
import type { AIMessage } from "@langchain/langgraph-sdk";
import { createContext, useCallback, useContext, useState } from "react";
import type { Subtask } from "./types";
export interface SubtaskContextValue {
tasks: Record<string, Subtask>;
setTasks: (tasks: Record<string, Subtask>) => void;
latestMessages: Record<string, AIMessage>;
setLatestMessages: React.Dispatch<
React.SetStateAction<Record<string, AIMessage>>
>;
}
export const SubtaskContext = createContext<SubtaskContextValue>({
tasks: {},
setTasks: () => {
latestMessages: {},
setLatestMessages: () => {
/* noop */
},
});
export function SubtasksProvider({ children }: { children: React.ReactNode }) {
const [tasks, setTasks] = useState<Record<string, Subtask>>({});
const [latestMessages, setLatestMessages] = useState<Record<string, AIMessage>>(
{},
);
return (
<SubtaskContext.Provider value={{ tasks, setTasks }}>
<SubtaskContext.Provider value={{ latestMessages, setLatestMessages }}>
{children}
</SubtaskContext.Provider>
);
@@ -33,21 +36,21 @@ export function useSubtaskContext() {
return context;
}
export function useSubtask(id: string) {
const { tasks } = useSubtaskContext();
return tasks[id];
export function useLatestSubtaskMessage(id: string) {
const { latestMessages } = useSubtaskContext();
return latestMessages[id];
}
export function useUpdateSubtask() {
const { tasks, setTasks } = useSubtaskContext();
const updateSubtask = useCallback(
(task: Partial<Subtask> & { id: string }) => {
tasks[task.id] = { ...tasks[task.id], ...task } as Subtask;
if (task.latestMessage) {
setTasks({ ...tasks });
}
export function useUpdateLatestMessage() {
const { setLatestMessages } = useSubtaskContext();
const updateLatestMessage = useCallback(
(taskId: string, message: AIMessage) => {
setLatestMessages((current) => ({
...current,
[taskId]: message,
}));
},
[tasks, setTasks],
[setLatestMessages],
);
return updateSubtask;
return updateLatestMessage;
}
+47
View File
@@ -0,0 +1,47 @@
import type { Message } from "@langchain/langgraph-sdk";
import { extractTextFromMessage } from "@/core/messages/utils";
import { parseSubtaskResult } from "./subtask-result";
import type { Subtask } from "./types";
export function buildSubtaskMapFromMessages(
messages: Message[],
): Record<string, Subtask> {
const tasks: Record<string, Subtask> = {};
for (const message of messages) {
if (message.type === "ai") {
for (const toolCall of message.tool_calls ?? []) {
if (toolCall.name !== "task" || !toolCall.id) {
continue;
}
tasks[toolCall.id] = {
id: toolCall.id,
status: "in_progress",
subagent_type: String(toolCall.args?.subagent_type ?? ""),
description: String(toolCall.args?.description ?? ""),
prompt: String(toolCall.args?.prompt ?? ""),
};
}
continue;
}
if (message.type !== "tool" || !message.tool_call_id) {
continue;
}
const task = tasks[message.tool_call_id];
if (!task) {
continue;
}
tasks[message.tool_call_id] = {
...task,
...parseSubtaskResult(extractTextFromMessage(message)),
};
}
return tasks;
}