@@ -26,6 +26,7 @@ import { snapshotService } from '@/lib/logs/execution/snapshot/service'
2626import type {
2727 BlockOutputData ,
2828 ExecutionEnvironment ,
29+ ExecutionFinalizationPath ,
2930 ExecutionTrigger ,
3031 ExecutionLoggerService as IExecutionLoggerService ,
3132 TraceSpan ,
@@ -48,7 +49,70 @@ export interface ToolCall {
4849
4950const logger = createLogger ( 'ExecutionLogger' )
5051
52+ function countTraceSpans ( traceSpans ?: TraceSpan [ ] ) : number {
53+ if ( ! Array . isArray ( traceSpans ) || traceSpans . length === 0 ) {
54+ return 0
55+ }
56+
57+ return traceSpans . reduce ( ( count , span ) => count + 1 + countTraceSpans ( span . children ) , 0 )
58+ }
59+
5160export class ExecutionLogger implements IExecutionLoggerService {
61+ private buildCompletedExecutionData ( params : {
62+ existingExecutionData ?: WorkflowExecutionLog [ 'executionData' ]
63+ traceSpans ?: TraceSpan [ ]
64+ finalOutput : BlockOutputData
65+ finalizationPath ?: ExecutionFinalizationPath
66+ completionFailure ?: string
67+ executionCost : {
68+ tokens : {
69+ input : number
70+ output : number
71+ total : number
72+ }
73+ models : NonNullable < WorkflowExecutionLog [ 'executionData' ] [ 'models' ] >
74+ }
75+ executionState ?: SerializableExecutionState
76+ } ) : WorkflowExecutionLog [ 'executionData' ] {
77+ const {
78+ existingExecutionData,
79+ traceSpans,
80+ finalOutput,
81+ finalizationPath,
82+ completionFailure,
83+ executionCost,
84+ executionState,
85+ } = params
86+ const traceSpanCount = countTraceSpans ( traceSpans )
87+
88+ return {
89+ ...( existingExecutionData ?. environment
90+ ? { environment : existingExecutionData . environment }
91+ : { } ) ,
92+ ...( existingExecutionData ?. trigger ? { trigger : existingExecutionData . trigger } : { } ) ,
93+ ...( existingExecutionData ?. error ? { error : existingExecutionData . error } : { } ) ,
94+ ...( existingExecutionData ?. lastStartedBlock
95+ ? { lastStartedBlock : existingExecutionData . lastStartedBlock }
96+ : { } ) ,
97+ ...( existingExecutionData ?. lastCompletedBlock
98+ ? { lastCompletedBlock : existingExecutionData . lastCompletedBlock }
99+ : { } ) ,
100+ ...( completionFailure ? { completionFailure } : { } ) ,
101+ ...( finalizationPath ? { finalizationPath } : { } ) ,
102+ hasTraceSpans : traceSpanCount > 0 ,
103+ traceSpanCount,
104+ traceSpans,
105+ finalOutput,
106+ tokens : {
107+ input : executionCost . tokens . input ,
108+ output : executionCost . tokens . output ,
109+ total : executionCost . tokens . total ,
110+ } ,
111+ models : executionCost . models ,
112+ ...( executionState ? { executionState } : { } ) ,
113+ }
114+ }
115+
52116 async startWorkflowExecution ( params : {
53117 workflowId : string
54118 workspaceId : string
@@ -131,6 +195,8 @@ export class ExecutionLogger implements IExecutionLoggerService {
131195 executionData : {
132196 environment,
133197 trigger,
198+ hasTraceSpans : false ,
199+ traceSpanCount : 0 ,
134200 } ,
135201 cost : {
136202 total : BASE_EXECUTION_CHARGE ,
@@ -189,6 +255,8 @@ export class ExecutionLogger implements IExecutionLoggerService {
189255 traceSpans ?: TraceSpan [ ]
190256 workflowInput ?: any
191257 executionState ?: SerializableExecutionState
258+ finalizationPath ?: ExecutionFinalizationPath
259+ completionFailure ?: string
192260 isResume ?: boolean
193261 level ?: 'info' | 'error'
194262 status ?: 'completed' | 'failed' | 'cancelled' | 'pending'
@@ -202,6 +270,8 @@ export class ExecutionLogger implements IExecutionLoggerService {
202270 traceSpans,
203271 workflowInput,
204272 executionState,
273+ finalizationPath,
274+ completionFailure,
205275 isResume,
206276 level : levelOverride ,
207277 status : statusOverride ,
@@ -216,7 +286,7 @@ export class ExecutionLogger implements IExecutionLoggerService {
216286 . limit ( 1 )
217287 const billingUserId = this . extractBillingUserId ( existingLog ?. executionData )
218288 const existingExecutionData = existingLog ?. executionData as
219- | { traceSpans ?: TraceSpan [ ] }
289+ | WorkflowExecutionLog [ 'executionData' ]
220290 | undefined
221291
222292 // Determine if workflow failed by checking trace spans for unhandled errors
@@ -272,6 +342,16 @@ export class ExecutionLogger implements IExecutionLoggerService {
272342 ? Math . max ( 0 , Math . round ( rawDurationMs ) )
273343 : 0
274344
345+ const completedExecutionData = this . buildCompletedExecutionData ( {
346+ existingExecutionData,
347+ traceSpans : redactedTraceSpans ,
348+ finalOutput : redactedFinalOutput ,
349+ finalizationPath,
350+ completionFailure,
351+ executionCost,
352+ executionState,
353+ } )
354+
275355 const [ updatedLog ] = await db
276356 . update ( workflowExecutionLogs )
277357 . set ( {
@@ -280,17 +360,7 @@ export class ExecutionLogger implements IExecutionLoggerService {
280360 endedAt : new Date ( endedAt ) ,
281361 totalDurationMs : totalDuration ,
282362 files : executionFiles . length > 0 ? executionFiles : null ,
283- executionData : {
284- traceSpans : redactedTraceSpans ,
285- finalOutput : redactedFinalOutput ,
286- tokens : {
287- input : executionCost . tokens . input ,
288- output : executionCost . tokens . output ,
289- total : executionCost . tokens . total ,
290- } ,
291- models : executionCost . models ,
292- ...( executionState ? { executionState } : { } ) ,
293- } ,
363+ executionData : completedExecutionData ,
294364 cost : executionCost ,
295365 } )
296366 . where ( eq ( workflowExecutionLogs . executionId , executionId ) )
0 commit comments