From dc62cd0e32e12523ef3df72c262cb1685d399751 Mon Sep 17 00:00:00 2001 From: centdix Date: Thu, 16 Apr 2026 17:48:16 +0200 Subject: [PATCH] fix: roll back failed inline script seeding --- .../copilot/chat/flow/helperUtils.test.ts | 36 +++++++++ .../copilot/chat/flow/helperUtils.ts | 79 +++++++++++-------- 2 files changed, 84 insertions(+), 31 deletions(-) diff --git a/frontend/src/lib/components/copilot/chat/flow/helperUtils.test.ts b/frontend/src/lib/components/copilot/chat/flow/helperUtils.test.ts index 3d69821edf..b7e7307ff7 100644 --- a/frontend/src/lib/components/copilot/chat/flow/helperUtils.test.ts +++ b/frontend/src/lib/components/copilot/chat/flow/helperUtils.test.ts @@ -65,6 +65,42 @@ describe('applyFlowJsonUpdate', () => { applyFlowJsonUpdate(flow as any, inlineScriptSession, { modules: [makeRawScriptModule('validate_data', 'inline_script.other_module')] }) + ).toThrow('Unresolved inline script references: other_module') + }) + + it('rolls back seeded inline scripts after a failed update so retries still warn', () => { + const flow = { + value: { + modules: [makeRawScriptModule('process_data', 'existing code')] + } + } + const inlineScriptSession = createInlineScriptSession() + inlineScriptSession.set('process_data', 'existing code') + + expect(() => + applyFlowJsonUpdate(flow as any, inlineScriptSession, { + modules: [ + makeRawScriptModule('validate_data', 'inline_script.validate_data'), + makeRawScriptModule('save_results', 'inline_script.other_module') + ] + }) ).toThrow('Unresolved inline script references: other_module') + + expect(inlineScriptSession.getAll()).toEqual({ + process_data: 'existing code' + }) + expect((flow.value.modules as Array)[0]?.value.content).toBe( + 'existing code' + ) + + const result = applyFlowJsonUpdate(flow as any, inlineScriptSession, { + modules: [ + makeRawScriptModule('process_data', 'inline_script.process_data'), + makeRawScriptModule('validate_data', 'inline_script.validate_data') + ] + }) + + expect(result.emptyInlineScriptModuleIds).toEqual(['validate_data']) + expect(inlineScriptSession.get('validate_data')).toBe('') }) }) diff --git a/frontend/src/lib/components/copilot/chat/flow/helperUtils.ts b/frontend/src/lib/components/copilot/chat/flow/helperUtils.ts index 1c3b272130..5ab269abee 100644 --- a/frontend/src/lib/components/copilot/chat/flow/helperUtils.ts +++ b/frontend/src/lib/components/copilot/chat/flow/helperUtils.ts @@ -65,43 +65,60 @@ export function applyFlowJsonUpdate( inlineScriptSession: InlineScriptSession, { modules, schema, preprocessorModule, failureModule }: FlowJsonUpdate ): FlowJsonUpdateResult { + const previousModules = flow.value.modules + const previousSchema = flow.schema + const previousPreprocessorModule = flow.value.preprocessor_module + const previousFailureModule = flow.value.failure_module + const previousInlineScripts = inlineScriptSession.getAll() const emptyInlineScriptModuleIds = new Set() - if (modules !== undefined) { - seedMissingInlineScripts(modules, inlineScriptSession).forEach((id) => - emptyInlineScriptModuleIds.add(id) - ) - flow.value.modules = restoreFlowModules(modules, inlineScriptSession) - } + try { + if (modules !== undefined) { + seedMissingInlineScripts(modules, inlineScriptSession).forEach((id) => + emptyInlineScriptModuleIds.add(id) + ) + flow.value.modules = restoreFlowModules(modules, inlineScriptSession) + } - if (schema !== undefined) { - flow.schema = schema ?? undefined - } + if (schema !== undefined) { + flow.schema = schema ?? undefined + } - if (preprocessorModule !== undefined) { - flow.value.preprocessor_module = - preprocessorModule === null - ? undefined - : restoreFlowModuleWithSeededInlineScripts( - preprocessorModule, - inlineScriptSession, - emptyInlineScriptModuleIds - ) - } + if (preprocessorModule !== undefined) { + flow.value.preprocessor_module = + preprocessorModule === null + ? undefined + : restoreFlowModuleWithSeededInlineScripts( + preprocessorModule, + inlineScriptSession, + emptyInlineScriptModuleIds + ) + } - if (failureModule !== undefined) { - flow.value.failure_module = - failureModule === null - ? undefined - : restoreFlowModuleWithSeededInlineScripts( - failureModule, - inlineScriptSession, - emptyInlineScriptModuleIds - ) - } + if (failureModule !== undefined) { + flow.value.failure_module = + failureModule === null + ? undefined + : restoreFlowModuleWithSeededInlineScripts( + failureModule, + inlineScriptSession, + emptyInlineScriptModuleIds + ) + } - return { - emptyInlineScriptModuleIds: Array.from(emptyInlineScriptModuleIds) + return { + emptyInlineScriptModuleIds: Array.from(emptyInlineScriptModuleIds) + } + } catch (error) { + flow.value.modules = previousModules + flow.schema = previousSchema + flow.value.preprocessor_module = previousPreprocessorModule + flow.value.failure_module = previousFailureModule + inlineScriptSession.clear() + for (const [moduleId, content] of Object.entries(previousInlineScripts)) { + inlineScriptSession.set(moduleId, content) + } + throw error } }