Skip to content

Commit 26ce317

Browse files
authored
πŸ› fix: fix multi tasks no summary issue (#11685)
fix task issue
1 parent 3110e2c commit 26ce317

File tree

5 files changed

+296
-0
lines changed

5 files changed

+296
-0
lines changed
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
import type { Message } from '../../../../types';
2+
import multiTasksWithSummary from './multi-tasks-with-summary.json';
23
import simple from './simple.json';
34
import withSummary from './with-summary.json';
45

56
export const tasks = {
7+
multiTasksWithSummary: multiTasksWithSummary as Message[],
68
simple: simple as Message[],
79
withSummary: withSummary as Message[],
810
};
Lines changed: 234 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,234 @@
1+
[
2+
{
3+
"id": "msg-user-1",
4+
"role": "user",
5+
"content": "Process these files in 10 parallel tasks and give me a summary.",
6+
"parentId": null,
7+
"createdAt": 1735526559382,
8+
"updatedAt": 1735526559382
9+
},
10+
{
11+
"id": "msg-assistant-1",
12+
"role": "assistant",
13+
"content": "I'll process these files in 10 parallel tasks.",
14+
"parentId": "msg-user-1",
15+
"createdAt": 1735526560163,
16+
"updatedAt": 1735526585550,
17+
"model": "gpt-4",
18+
"provider": "openai",
19+
"tools": [
20+
{
21+
"id": "call_exec_tasks_1",
22+
"type": "builtin",
23+
"apiName": "execTasks",
24+
"arguments": "{\"tasks\": [{\"description\": \"Task 1\"}, {\"description\": \"Task 2\"}, {\"description\": \"Task 3\"}, {\"description\": \"Task 4\"}, {\"description\": \"Task 5\"}, {\"description\": \"Task 6\"}, {\"description\": \"Task 7\"}, {\"description\": \"Task 8\"}, {\"description\": \"Task 9\"}, {\"description\": \"Task 10\"}]}",
25+
"identifier": "lobe-gtd"
26+
}
27+
]
28+
},
29+
{
30+
"id": "msg-tool-1",
31+
"role": "tool",
32+
"content": "Triggered 10 async tasks",
33+
"parentId": "msg-assistant-1",
34+
"tool_call_id": "call_exec_tasks_1",
35+
"createdAt": 1735526588116,
36+
"updatedAt": 1735526591337,
37+
"pluginState": {
38+
"type": "execTasks",
39+
"tasks": [
40+
{ "description": "Task 1" },
41+
{ "description": "Task 2" },
42+
{ "description": "Task 3" },
43+
{ "description": "Task 4" },
44+
{ "description": "Task 5" },
45+
{ "description": "Task 6" },
46+
{ "description": "Task 7" },
47+
{ "description": "Task 8" },
48+
{ "description": "Task 9" },
49+
{ "description": "Task 10" }
50+
],
51+
"parentMessageId": "msg-tool-1"
52+
}
53+
},
54+
{
55+
"id": "msg-task-1",
56+
"role": "task",
57+
"content": "Task 1 completed with results...",
58+
"parentId": "msg-tool-1",
59+
"createdAt": 1735526594643,
60+
"updatedAt": 1735526756262,
61+
"taskDetail": {
62+
"duration": 120000,
63+
"status": "completed",
64+
"threadId": "thd_task_1",
65+
"title": "Task 1",
66+
"totalCost": 0.015,
67+
"totalMessages": 15,
68+
"totalTokens": 100000
69+
}
70+
},
71+
{
72+
"id": "msg-task-2",
73+
"role": "task",
74+
"content": "Task 2 completed with results...",
75+
"parentId": "msg-tool-1",
76+
"createdAt": 1735526595000,
77+
"updatedAt": 1735526757000,
78+
"taskDetail": {
79+
"duration": 121000,
80+
"status": "completed",
81+
"threadId": "thd_task_2",
82+
"title": "Task 2",
83+
"totalCost": 0.016,
84+
"totalMessages": 16,
85+
"totalTokens": 101000
86+
}
87+
},
88+
{
89+
"id": "msg-task-3",
90+
"role": "task",
91+
"content": "Task 3 completed with results...",
92+
"parentId": "msg-tool-1",
93+
"createdAt": 1735526596000,
94+
"updatedAt": 1735526758000,
95+
"taskDetail": {
96+
"duration": 122000,
97+
"status": "completed",
98+
"threadId": "thd_task_3",
99+
"title": "Task 3",
100+
"totalCost": 0.017,
101+
"totalMessages": 17,
102+
"totalTokens": 102000
103+
}
104+
},
105+
{
106+
"id": "msg-task-4",
107+
"role": "task",
108+
"content": "Task 4 completed with results...",
109+
"parentId": "msg-tool-1",
110+
"createdAt": 1735526597000,
111+
"updatedAt": 1735526759000,
112+
"taskDetail": {
113+
"duration": 123000,
114+
"status": "completed",
115+
"threadId": "thd_task_4",
116+
"title": "Task 4",
117+
"totalCost": 0.018,
118+
"totalMessages": 18,
119+
"totalTokens": 103000
120+
}
121+
},
122+
{
123+
"id": "msg-task-5",
124+
"role": "task",
125+
"content": "Task 5 completed with results...",
126+
"parentId": "msg-tool-1",
127+
"createdAt": 1735526598000,
128+
"updatedAt": 1735526760000,
129+
"taskDetail": {
130+
"duration": 124000,
131+
"status": "completed",
132+
"threadId": "thd_task_5",
133+
"title": "Task 5",
134+
"totalCost": 0.019,
135+
"totalMessages": 19,
136+
"totalTokens": 104000
137+
}
138+
},
139+
{
140+
"id": "msg-task-6",
141+
"role": "task",
142+
"content": "Task 6 completed with results...",
143+
"parentId": "msg-tool-1",
144+
"createdAt": 1735526599000,
145+
"updatedAt": 1735526761000,
146+
"taskDetail": {
147+
"duration": 125000,
148+
"status": "completed",
149+
"threadId": "thd_task_6",
150+
"title": "Task 6",
151+
"totalCost": 0.02,
152+
"totalMessages": 20,
153+
"totalTokens": 105000
154+
}
155+
},
156+
{
157+
"id": "msg-task-7",
158+
"role": "task",
159+
"content": "Task 7 completed with results...",
160+
"parentId": "msg-tool-1",
161+
"createdAt": 1735526600000,
162+
"updatedAt": 1735526762000,
163+
"taskDetail": {
164+
"duration": 126000,
165+
"status": "completed",
166+
"threadId": "thd_task_7",
167+
"title": "Task 7",
168+
"totalCost": 0.021,
169+
"totalMessages": 21,
170+
"totalTokens": 106000
171+
}
172+
},
173+
{
174+
"id": "msg-task-8",
175+
"role": "task",
176+
"content": "Task 8 completed with results...",
177+
"parentId": "msg-tool-1",
178+
"createdAt": 1735526601000,
179+
"updatedAt": 1735526763000,
180+
"taskDetail": {
181+
"duration": 127000,
182+
"status": "completed",
183+
"threadId": "thd_task_8",
184+
"title": "Task 8",
185+
"totalCost": 0.022,
186+
"totalMessages": 22,
187+
"totalTokens": 107000
188+
}
189+
},
190+
{
191+
"id": "msg-task-9",
192+
"role": "task",
193+
"content": "Task 9 completed with results...",
194+
"parentId": "msg-tool-1",
195+
"createdAt": 1735526602000,
196+
"updatedAt": 1735526764000,
197+
"taskDetail": {
198+
"duration": 128000,
199+
"status": "completed",
200+
"threadId": "thd_task_9",
201+
"title": "Task 9",
202+
"totalCost": 0.023,
203+
"totalMessages": 23,
204+
"totalTokens": 108000
205+
}
206+
},
207+
{
208+
"id": "msg-task-10",
209+
"role": "task",
210+
"content": "Task 10 completed with results...",
211+
"parentId": "msg-tool-1",
212+
"createdAt": 1735526603000,
213+
"updatedAt": 1735526765000,
214+
"taskDetail": {
215+
"duration": 129000,
216+
"status": "completed",
217+
"threadId": "thd_task_10",
218+
"title": "Task 10",
219+
"totalCost": 0.024,
220+
"totalMessages": 24,
221+
"totalTokens": 109000
222+
}
223+
},
224+
{
225+
"id": "msg-assistant-summary",
226+
"role": "assistant",
227+
"content": "All 10 tasks completed successfully! Here's the comprehensive summary...",
228+
"parentId": "msg-task-10",
229+
"createdAt": 1735526810000,
230+
"updatedAt": 1735526820000,
231+
"model": "gpt-4",
232+
"provider": "openai"
233+
}
234+
]

β€Žpackages/conversation-flow/src/__tests__/parse.test.tsβ€Ž

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -194,6 +194,31 @@ describe('parse', () => {
194194

195195
expect(serializeParseResult(result)).toEqual(outputs.tasks.withSummary);
196196
});
197+
198+
it('should handle 10 parallel tasks with summary as task child', () => {
199+
const result = parse(inputs.tasks.multiTasksWithSummary);
200+
201+
// The critical assertions:
202+
// 1. flatList should have 4 items: user, assistantGroup(+tool), tasks(10 tasks), assistant-summary
203+
expect(result.flatList).toHaveLength(4);
204+
expect(result.flatList[0].role).toBe('user');
205+
expect(result.flatList[1].role).toBe('assistantGroup');
206+
expect(result.flatList[2].role).toBe('tasks');
207+
expect(result.flatList[3].role).toBe('assistant');
208+
209+
// 2. tasks virtual message should have 10 task messages
210+
expect((result.flatList[2] as any).tasks).toHaveLength(10);
211+
212+
// 3. Verify all tasks are completed
213+
const tasks = (result.flatList[2] as any).tasks;
214+
for (const task of tasks) {
215+
expect(task.taskDetail.status).toBe('completed');
216+
}
217+
218+
// 4. The summary message should be present and accessible
219+
expect(result.flatList[3].id).toBe('msg-assistant-summary');
220+
expect(result.flatList[3].content).toContain('All 10 tasks completed');
221+
});
197222
});
198223

199224
describe('Performance', () => {

β€Žpackages/conversation-flow/src/transformation/ContextTreeBuilder.tsβ€Ž

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,21 @@ export class ContextTreeBuilder {
125125
for (const nonTaskChild of nonTaskChildren) {
126126
this.transformToLinear(nonTaskChild, contextTree);
127127
}
128+
129+
// Also check for children of task messages (e.g., summary as child of last task)
130+
const taskChildren = idNode.children.filter((child) => {
131+
const childMsg = this.messageMap.get(child.id);
132+
return childMsg?.role === 'task';
133+
});
134+
135+
for (const taskChild of taskChildren) {
136+
for (const taskGrandchild of taskChild.children) {
137+
const taskGrandchildMsg = this.messageMap.get(taskGrandchild.id);
138+
if (taskGrandchildMsg && taskGrandchildMsg.role !== 'task') {
139+
this.transformToLinear(taskGrandchild, contextTree);
140+
}
141+
}
142+
}
128143
return;
129144
}
130145

β€Žpackages/conversation-flow/src/transformation/FlatListBuilder.tsβ€Ž

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,26 @@ export class FlatListBuilder {
113113
}
114114
}
115115
}
116+
117+
// Also check for children of task messages (e.g., summary as child of last task)
118+
for (const taskChildId of taskChildren) {
119+
const taskChildrenIds = this.childrenMap.get(taskChildId) ?? [];
120+
for (const taskGrandchildId of taskChildrenIds) {
121+
if (!processedIds.has(taskGrandchildId)) {
122+
const taskGrandchild = this.messageMap.get(taskGrandchildId);
123+
if (taskGrandchild && taskGrandchild.role !== 'task') {
124+
flatList.push(taskGrandchild);
125+
processedIds.add(taskGrandchildId);
126+
this.buildFlatListRecursive(
127+
taskGrandchildId,
128+
flatList,
129+
processedIds,
130+
allMessages,
131+
);
132+
}
133+
}
134+
}
135+
}
116136
return;
117137
}
118138
}

0 commit comments

Comments
Β (0)