From baedca20a4c50845525a7490cd8bf513c6785d69 Mon Sep 17 00:00:00 2001 From: Agando Date: Tue, 29 Sep 2026 19:03:27 +0200 Subject: fix: sequential safe-tool execution — parallel fan-out corrupted print-capture attribution + shadow diff pairing MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- modules/core/core-bundle.js | 11 +++++++---- modules/core/module-aiassist.js | 11 +++++++---- 2 files changed, 14 insertions(+), 8 deletions(-) diff --git a/modules/core/core-bundle.js b/modules/core/core-bundle.js index 6127f36..dd86773 100644 --- a/modules/core/core-bundle.js +++ b/modules/core/core-bundle.js @@ -9432,8 +9432,11 @@ buildSystemPrompt() { let pendingText = res.message?.content || null; const destructiveTools = res.tool_calls.filter(tc => this.isDestructive(tc.function.name, tc.function.arguments)); const safeTools = res.tool_calls.filter(tc => !this.isDestructive(tc.function.name, tc.function.arguments)); - // Execute non-destructive tools in parallel (independent read-only operations) - const safeResults = await Promise.all(safeTools.map(async (tc) => { + // Execute non-destructive tools SEQUENTIALLY — parallel fan-out corrupts + // print-capture attribution, shadow-VFS snapshot/diff pairing, and telemetry + // under interleaved awaits. Inference latency dominates anyway. + const safeResults = []; + for (const tc of safeTools) { const fn = tc.function; const t0 = Date.now(); const toolResult = await this.runTool(fn.name, fn.arguments); @@ -9454,8 +9457,8 @@ buildSystemPrompt() { const sm = this.terminal.moduleManager.modules['ServerMonitorModule']; if (sm && sm.logToolCall) sm.logToolCall(fn.name, (t1 * 1000) || 1, this._isToolError(toolResult)); if (this._debugPanelEnabled) this._updateDebugPanel(); - return { fn, toolResult, t1 }; - })); + safeResults.push({ fn, toolResult, t1 }); + } for (const { fn, toolResult, t1 } of safeResults) { this.terminal.print(`🔧 Tool: ${fn.name}(${typeof fn.arguments === 'string' ? fn.arguments : JSON.stringify(fn.arguments)})`, 'info'); // Memory graph: record tool call + file access diff --git a/modules/core/module-aiassist.js b/modules/core/module-aiassist.js index 9c090ce..193c58d 100644 --- a/modules/core/module-aiassist.js +++ b/modules/core/module-aiassist.js @@ -1417,8 +1417,11 @@ buildSystemPrompt() { let pendingText = res.message?.content || null; const destructiveTools = res.tool_calls.filter(tc => this.isDestructive(tc.function.name, tc.function.arguments)); const safeTools = res.tool_calls.filter(tc => !this.isDestructive(tc.function.name, tc.function.arguments)); - // Execute non-destructive tools in parallel (independent read-only operations) - const safeResults = await Promise.all(safeTools.map(async (tc) => { + // Execute non-destructive tools SEQUENTIALLY — parallel fan-out corrupts + // print-capture attribution, shadow-VFS snapshot/diff pairing, and telemetry + // under interleaved awaits. Inference latency dominates anyway. + const safeResults = []; + for (const tc of safeTools) { const fn = tc.function; const t0 = Date.now(); const toolResult = await this.runTool(fn.name, fn.arguments); @@ -1439,8 +1442,8 @@ buildSystemPrompt() { const sm = this.terminal.moduleManager.modules['ServerMonitorModule']; if (sm && sm.logToolCall) sm.logToolCall(fn.name, (t1 * 1000) || 1, this._isToolError(toolResult)); if (this._debugPanelEnabled) this._updateDebugPanel(); - return { fn, toolResult, t1 }; - })); + safeResults.push({ fn, toolResult, t1 }); + } for (const { fn, toolResult, t1 } of safeResults) { this.terminal.print(`🔧 Tool: ${fn.name}(${typeof fn.arguments === 'string' ? fn.arguments : JSON.stringify(fn.arguments)})`, 'info'); // Memory graph: record tool call + file access -- cgit v1.2.3