Skip to content

Commit e2e86a7

Browse files
committed
fix(snapshot): consolidate to use hasWorkflowChanges check
1 parent 78410ee commit e2e86a7

File tree

5 files changed

+277
-317
lines changed

5 files changed

+277
-317
lines changed

apps/sim/lib/logs/execution/snapshot/service.test.ts

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,13 @@ describe('SnapshotService', () => {
8686
type: 'agent',
8787
position: { x: 100, y: 200 },
8888

89-
subBlocks: {},
89+
subBlocks: {
90+
prompt: {
91+
id: 'prompt',
92+
type: 'short-input',
93+
value: 'Hello world',
94+
},
95+
},
9096
outputs: {},
9197
enabled: true,
9298
horizontalHandles: true,
@@ -104,8 +110,14 @@ describe('SnapshotService', () => {
104110
blocks: {
105111
block1: {
106112
...baseState.blocks.block1,
107-
// Different block state - we can change outputs to make it different
108-
outputs: { response: { type: 'string', description: 'different result' } },
113+
// Different subBlock value - this is a meaningful change
114+
subBlocks: {
115+
prompt: {
116+
id: 'prompt',
117+
type: 'short-input',
118+
value: 'Different prompt',
119+
},
120+
},
109121
},
110122
},
111123
}

apps/sim/lib/logs/execution/snapshot/service.ts

Lines changed: 8 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,7 @@ import type {
1111
WorkflowExecutionSnapshotInsert,
1212
WorkflowState,
1313
} from '@/lib/logs/types'
14-
import {
15-
normalizedStringify,
16-
normalizeEdge,
17-
normalizeValue,
18-
sortEdges,
19-
} from '@/lib/workflows/comparison'
14+
import { normalizedStringify, normalizeWorkflowState } from '@/lib/workflows/comparison'
2015

2116
const logger = createLogger('SnapshotService')
2217

@@ -38,7 +33,9 @@ export class SnapshotService implements ISnapshotService {
3833

3934
const existingSnapshot = await this.getSnapshotByHash(workflowId, stateHash)
4035
if (existingSnapshot) {
41-
logger.debug(`Reusing existing snapshot for workflow ${workflowId} with hash ${stateHash}`)
36+
logger.info(
37+
`Reusing existing snapshot for workflow ${workflowId} (hash: ${stateHash.slice(0, 12)}...)`
38+
)
4239
return {
4340
snapshot: existingSnapshot,
4441
isNew: false,
@@ -59,8 +56,9 @@ export class SnapshotService implements ISnapshotService {
5956
.values(snapshotData)
6057
.returning()
6158

62-
logger.debug(`Created new snapshot for workflow ${workflowId} with hash ${stateHash}`)
63-
logger.debug(`Stored full state with ${Object.keys(state.blocks || {}).length} blocks`)
59+
logger.info(
60+
`Created new snapshot for workflow ${workflowId} (hash: ${stateHash.slice(0, 12)}..., blocks: ${Object.keys(state.blocks || {}).length})`
61+
)
6462
return {
6563
snapshot: {
6664
...newSnapshot,
@@ -112,7 +110,7 @@ export class SnapshotService implements ISnapshotService {
112110
}
113111

114112
computeStateHash(state: WorkflowState): string {
115-
const normalizedState = this.normalizeStateForHashing(state)
113+
const normalizedState = normalizeWorkflowState(state)
116114
const stateString = normalizedStringify(normalizedState)
117115
return createHash('sha256').update(stateString).digest('hex')
118116
}
@@ -130,69 +128,6 @@ export class SnapshotService implements ISnapshotService {
130128
logger.info(`Cleaned up ${deletedCount} orphaned snapshots older than ${olderThanDays} days`)
131129
return deletedCount
132130
}
133-
134-
private normalizeStateForHashing(state: WorkflowState): any {
135-
// 1. Normalize and sort edges
136-
const normalizedEdges = sortEdges((state.edges || []).map(normalizeEdge))
137-
138-
// 2. Normalize blocks
139-
const normalizedBlocks: Record<string, any> = {}
140-
141-
for (const [blockId, block] of Object.entries(state.blocks || {})) {
142-
const { position, layout, height, ...blockWithoutLayoutFields } = block
143-
144-
// Also exclude width/height from data object (container dimensions from autolayout)
145-
const {
146-
width: _dataWidth,
147-
height: _dataHeight,
148-
...dataRest
149-
} = blockWithoutLayoutFields.data || {}
150-
151-
// Normalize subBlocks
152-
const subBlocks = blockWithoutLayoutFields.subBlocks || {}
153-
const normalizedSubBlocks: Record<string, any> = {}
154-
155-
for (const [subBlockId, subBlock] of Object.entries(subBlocks)) {
156-
const value = subBlock.value ?? null
157-
158-
normalizedSubBlocks[subBlockId] = {
159-
type: subBlock.type,
160-
value: normalizeValue(value),
161-
...Object.fromEntries(
162-
Object.entries(subBlock).filter(([key]) => key !== 'value' && key !== 'type')
163-
),
164-
}
165-
}
166-
167-
normalizedBlocks[blockId] = {
168-
...blockWithoutLayoutFields,
169-
data: dataRest,
170-
subBlocks: normalizedSubBlocks,
171-
}
172-
}
173-
174-
// 3. Normalize loops and parallels
175-
const normalizedLoops: Record<string, any> = {}
176-
for (const [loopId, loop] of Object.entries(state.loops || {})) {
177-
normalizedLoops[loopId] = normalizeValue(loop)
178-
}
179-
180-
const normalizedParallels: Record<string, any> = {}
181-
for (const [parallelId, parallel] of Object.entries(state.parallels || {})) {
182-
normalizedParallels[parallelId] = normalizeValue(parallel)
183-
}
184-
185-
// 4. Normalize variables (if present)
186-
const normalizedVariables = state.variables ? normalizeValue(state.variables) : undefined
187-
188-
return {
189-
blocks: normalizedBlocks,
190-
edges: normalizedEdges,
191-
loops: normalizedLoops,
192-
parallels: normalizedParallels,
193-
...(normalizedVariables !== undefined && { variables: normalizedVariables }),
194-
}
195-
}
196131
}
197132

198133
export const snapshotService = new SnapshotService()

0 commit comments

Comments
 (0)