@@ -215,6 +215,35 @@ const getActiveThread = (state: ChatState) => state.threads[state.activeThread]
215215
216216const getMessages = ( state : ChatState ) => getActiveThread ( state ) . messages
217217
218+ /**
219+ * Converts a Task to a ChatCompletionMessageToolCall for display purposes
220+ */
221+ const taskToToolCall = ( task : Task ) : ChatCompletionMessageToolCall => ( {
222+ id : `task_${ task . id } ` ,
223+ type : 'function' ,
224+ function : {
225+ name : task . agent ,
226+ arguments : JSON . stringify ( task . args )
227+ }
228+ } )
229+
230+ /**
231+ * Converts a Task result to ActionChatMessageContent
232+ * Assumes task.result is always a string
233+ */
234+ const taskResultToContent = ( task : Task ) : ActionChatMessageContent => {
235+ return {
236+ type : 'BLANK' ,
237+ content : task . result as string ,
238+ renderInfo : {
239+ text : '' ,
240+ code : undefined ,
241+ oldCode : undefined ,
242+ hidden : true
243+ }
244+ }
245+ }
246+
218247export const chatSlice = createSlice ( {
219248 name : 'chat' ,
220249 initialState,
@@ -260,12 +289,32 @@ export const chatSlice = createSlice({
260289 state ,
261290 action : PayloadAction < { llmResponse : LLMResponse , debug : any } >
262291 ) => {
263- // const actions: Array<OngoingAction> =
264292 const messages = getMessages ( state )
265293 const latestMessageIndex = messages . length
266294 const toolCalls = action . payload . llmResponse . tool_calls
267295 const messageContent = action . payload . llmResponse . content
268- const actionMessageIDs = [ ...Array ( toolCalls . length ) . keys ( ) ] . map ( ( value ) => value + 1 + latestMessageIndex )
296+ const newTasks = action . payload . llmResponse . tasks || [ ]
297+ const currentTasks = getActiveThread ( state ) . tasks || [ ]
298+
299+ // Defensive programming: ensure we have valid arrays and lengths
300+ const currentTasksLength = Array . isArray ( currentTasks ) ? currentTasks . length : 0
301+ const newTasksLength = Array . isArray ( newTasks ) ? newTasks . length : 0
302+
303+ // Find completed tasks from task diff (excluding first task which is main agent)
304+ // Only proceed if we have new tasks beyond the current ones
305+ const completedTasks = newTasksLength > currentTasksLength
306+ ? newTasks
307+ . slice ( Math . max ( currentTasksLength , 1 ) ) // Get only new tasks, skip main agent
308+ . filter ( task => task && task . result !== null && task . result !== undefined )
309+ : [ ]
310+
311+ // Convert completed tasks to tool calls for display
312+ const completedToolCalls = completedTasks . map ( taskToToolCall )
313+
314+ // Calculate total action message IDs for both completed and pending tool calls
315+ const totalToolCalls = completedToolCalls . length + toolCalls . length
316+ const actionMessageIDs = [ ...Array ( totalToolCalls ) . keys ( ) ] . map ( ( value ) => value + 1 + latestMessageIndex )
317+
269318 const timestamp = Date . now ( )
270319 const actionPlanMessage : ActionPlanChatMessage = {
271320 role : 'assistant' ,
@@ -276,18 +325,47 @@ export const chatSlice = createSlice({
276325 content : {
277326 type : 'ACTIONS' ,
278327 actionMessageIDs : actionMessageIDs ,
279- toolCalls,
328+ toolCalls : [ ... completedToolCalls , ... toolCalls ] , // Completed first, then pending
280329 messageContent,
281330 finishReason : action . payload . llmResponse . finish_reason ,
282- finished : false
331+ finished : completedTasks . length === totalToolCalls // Only finished if all are completed
283332 } ,
284333 createdAt : timestamp ,
285334 updatedAt : timestamp ,
286335 debug : action . payload . debug
287336 }
288337 messages . push ( actionPlanMessage )
289- toolCalls . forEach ( ( toolCall , index ) => {
290- const actionMessageID = index + 1 + latestMessageIndex
338+
339+ let messageIndex = 1
340+
341+ // Add completed tasks as SUCCESS messages first
342+ completedTasks . forEach ( ( task ) => {
343+ const actionMessageID = messageIndex + latestMessageIndex
344+ const timestamp = Date . now ( )
345+ const actionMessage : ActionChatMessage = {
346+ role : 'tool' ,
347+ action : {
348+ ...taskToToolCall ( task ) ,
349+ planID : latestMessageIndex ,
350+ status : 'SUCCESS' ,
351+ finished : true ,
352+ } ,
353+ feedback : {
354+ reaction : "unrated"
355+ } ,
356+ index : actionMessageID ,
357+ content : taskResultToContent ( task ) ,
358+ createdAt : timestamp ,
359+ updatedAt : timestamp ,
360+ debug : { }
361+ }
362+ messages . push ( actionMessage )
363+ messageIndex ++
364+ } )
365+
366+ // Add pending tool calls as TODO messages
367+ toolCalls . forEach ( ( toolCall ) => {
368+ const actionMessageID = messageIndex + latestMessageIndex
291369 const timestamp = Date . now ( )
292370 const actionMessage : ActionChatMessage = {
293371 role : 'tool' ,
@@ -304,20 +382,21 @@ export const chatSlice = createSlice({
304382 content : {
305383 type : 'BLANK' ,
306384 renderInfo : {
307- text : null ,
308- code : null ,
309- oldCode : null
385+ text : undefined ,
386+ code : undefined ,
387+ oldCode : undefined
310388 }
311389 } ,
312390 createdAt : timestamp ,
313391 updatedAt : timestamp ,
314392 debug : { }
315393 }
316394 messages . push ( actionMessage )
395+ messageIndex ++
317396 } )
318397
319- const tasks = action . payload . llmResponse . tasks || [ ]
320- getActiveThread ( state ) . tasks = tasks
398+ // Update tasks array with new tasks
399+ getActiveThread ( state ) . tasks = newTasks
321400
322401 } ,
323402 startAction : (
@@ -576,8 +655,8 @@ export const chatSlice = createSlice({
576655 const previousID = state . threads [ state . threads . length - 1 ] . id
577656 const newID = generateNextThreadID ( previousID )
578657
579- // Clone messages up to and including the assistant response after the tool call
580- const endIndex = Math . min ( upToMessageIndex + 1 , sourceThread . messages . length - 1 ) ;
658+ // Clone messages up to and including the specified index (threadHistory already calculated the correct endpoint)
659+ const endIndex = Math . min ( upToMessageIndex , sourceThread . messages . length - 1 ) ;
581660 const clonedMessages = sourceThread . messages
582661 . slice ( 0 , endIndex + 1 )
583662 . map ( ( message , index ) => ( {
0 commit comments