@@ -6,6 +6,7 @@ import { track } from "@renderer/lib/analytics";
66import type {
77 ClarifyingQuestion ,
88 ExecutionMode ,
9+ LogEntry ,
910 PlanModePhase ,
1011 QuestionAnswer ,
1112 Task ,
@@ -79,14 +80,10 @@ const toClarifyingQuestions = (
7980/**
8081 * Convert S3 LogEntry to AgentEvent
8182 */
82- function logEntryToAgentEvent (
83- entry : import ( "@shared/types" ) . LogEntry ,
84- ) : AgentEvent | null {
83+ function logEntryToAgentEvent ( entry : LogEntry ) : AgentEvent | null {
8584 try {
86- // Use a base timestamp - will be overridden by actual event timestamps if available
8785 const baseTs = Date . now ( ) ;
8886
89- // For token events (stored as plain text in message)
9087 if ( entry . type === "token" ) {
9188 return {
9289 type : "token" ,
@@ -95,7 +92,6 @@ function logEntryToAgentEvent(
9592 } as AgentEvent ;
9693 }
9794
98- // For legacy info entries
9995 if ( entry . type === "info" ) {
10096 return {
10197 type : "token" ,
@@ -104,18 +100,15 @@ function logEntryToAgentEvent(
104100 } as AgentEvent ;
105101 }
106102
107- // For all other events stored as JSON strings in the message field
108103 if ( entry . message ) {
109104 try {
110105 const parsed = JSON . parse ( entry . message ) ;
111- // Preserve the original structure from S3, just add the type
112106 return {
113107 ...parsed ,
114108 type : entry . type as any ,
115- ts : parsed . ts || baseTs , // Use parsed ts if available, otherwise base
109+ ts : parsed . ts || baseTs ,
116110 } as AgentEvent ;
117111 } catch {
118- // If parsing fails, treat as a simple message event
119112 return {
120113 type : entry . type as any ,
121114 ts : baseTs ,
@@ -137,7 +130,6 @@ function logEntryToAgentEvent(
137130 */
138131async function fetchLogsFromS3Url ( logUrl : string ) : Promise < AgentEvent [ ] > {
139132 try {
140- // Fetch through main process to avoid CORS
141133 const content = await window . electronAPI ?. fetchS3Logs ( logUrl ) ;
142134
143135 if ( ! content || ! content . trim ( ) ) {
@@ -147,15 +139,10 @@ async function fetchLogsFromS3Url(logUrl: string): Promise<AgentEvent[]> {
147139 const logEntries = content
148140 . trim ( )
149141 . split ( "\n" )
150- . map (
151- ( line : string ) => JSON . parse ( line ) as import ( "@shared/types" ) . LogEntry ,
152- ) ;
142+ . map ( ( line : string ) => JSON . parse ( line ) as LogEntry ) ;
153143
154- // Convert all log entries to AgentEvents
155144 const events = logEntries
156- . map ( ( entry : import ( "@shared/types" ) . LogEntry ) =>
157- logEntryToAgentEvent ( entry ) ,
158- )
145+ . map ( ( entry : LogEntry ) => logEntryToAgentEvent ( entry ) )
159146 . filter ( ( event ) : event is AgentEvent => event !== null ) ;
160147
161148 return events ;
@@ -362,7 +349,6 @@ export const useTaskExecutionStore = create<TaskExecutionStore>()(
362349 subscribeToAgentEvents : ( taskId : string , channel : string ) => {
363350 const store = get ( ) ;
364351
365- // Clean up existing subscription and poller if any
366352 const existingState = store . taskStates [ taskId ] ;
367353 if ( existingState ?. unsubscribe ) {
368354 existingState . unsubscribe ( ) ;
@@ -371,7 +357,6 @@ export const useTaskExecutionStore = create<TaskExecutionStore>()(
371357 clearInterval ( existingState . logPoller ) ;
372358 }
373359
374- // Reset polling state
375360 store . updateTaskState ( taskId , { logPoller : null } ) ;
376361
377362 // Create new subscription that listens only to progress events
@@ -380,7 +365,6 @@ export const useTaskExecutionStore = create<TaskExecutionStore>()(
380365 ( ev : AgentEvent | { type : "progress" ; progress : TaskRun } ) => {
381366 const currentStore = get ( ) ;
382367
383- // Handle custom progress events from Array backend
384368 if ( ev ?. type === "progress" && "progress" in ev ) {
385369 const newProgress = ev . progress ;
386370 const oldProgress = currentStore . getTaskState ( taskId ) . progress ;
@@ -389,10 +373,8 @@ export const useTaskExecutionStore = create<TaskExecutionStore>()(
389373 : null ;
390374 const newSig = createProgressSignature ( newProgress ) ;
391375
392- // Always update the stored progress state for UI (like TaskDetail)
393376 currentStore . setProgress ( taskId , newProgress ) ;
394377
395- // Only add to logs if signature changed (to avoid duplicate log entries)
396378 if ( oldSig !== newSig ) {
397379 currentStore . addLog ( taskId , {
398380 type : "progress" ,
@@ -401,7 +383,6 @@ export const useTaskExecutionStore = create<TaskExecutionStore>()(
401383 } as unknown as AgentEvent ) ;
402384 }
403385
404- // Start or continue log polling if we have a log_url
405386 if ( newProgress . log_url ) {
406387 const currentState = currentStore . getTaskState ( taskId ) ;
407388
@@ -422,15 +403,13 @@ export const useTaskExecutionStore = create<TaskExecutionStore>()(
422403 . then ( ( allEvents ) => {
423404 if ( allEvents . length > 0 ) {
424405 const store = get ( ) ;
425- // Check if there's a "done" event
426406 const hasDone = allEvents . some (
427407 ( event ) => event . type === "done" ,
428408 ) ;
429409 if ( hasDone ) {
430410 store . setRunning ( taskId , false ) ;
431411 store . checkPlanCompletion ( taskId ) ;
432412 }
433- // Replace all logs with the full S3 content
434413 store . setLogs ( taskId , allEvents ) ;
435414 }
436415 } )
@@ -441,13 +420,11 @@ export const useTaskExecutionStore = create<TaskExecutionStore>()(
441420 return ;
442421 }
443422
444- // Start polling if not already started
445423 if ( ! currentState . logPoller ) {
446424 const pollLogs = async ( ) => {
447425 const state = get ( ) . getTaskState ( taskId ) ;
448426 const progress = state . progress ;
449427
450- // Stop polling if task is now complete
451428 if (
452429 ! progress ?. log_url ||
453430 progress . status === "completed" ||
@@ -467,7 +444,6 @@ export const useTaskExecutionStore = create<TaskExecutionStore>()(
467444 if ( allEvents . length > 0 ) {
468445 const store = get ( ) ;
469446
470- // Check for special event types
471447 const hasError = allEvents . some (
472448 ( event ) => event . type === "error" ,
473449 ) ;
@@ -478,26 +454,21 @@ export const useTaskExecutionStore = create<TaskExecutionStore>()(
478454 if ( hasError || hasDone ) {
479455 store . setRunning ( taskId , false ) ;
480456 if ( hasDone ) {
481- // Stop polling when done event found
482457 const currentState = store . getTaskState ( taskId ) ;
483458 if ( currentState . logPoller ) {
484459 clearInterval ( currentState . logPoller ) ;
485460 store . updateTaskState ( taskId , { logPoller : null } ) ;
486461 }
487462 }
488- // Check if plan needs to be loaded after run completes
489463 store . checkPlanCompletion ( taskId ) ;
490464 }
491465
492- // Replace all logs with the full S3 content
493466 store . setLogs ( taskId , allEvents ) ;
494467 }
495468 } ;
496469
497- // Initial fetch
498470 void pollLogs ( ) ;
499471
500- // Start polling every 2 seconds
501472 const poller = setInterval ( ( ) => {
502473 void pollLogs ( ) ;
503474 } , 2000 ) ;
0 commit comments