diff options
Diffstat (limited to 'modules/core/module-aiassist.js')
| -rw-r--r-- | modules/core/module-aiassist.js | 47 |
1 files changed, 37 insertions, 10 deletions
diff --git a/modules/core/module-aiassist.js b/modules/core/module-aiassist.js index f6fadb5..8f8a60c 100644 --- a/modules/core/module-aiassist.js +++ b/modules/core/module-aiassist.js @@ -415,7 +415,15 @@ RULES: } this._cancelled = false; this.terminal.setAiBusy(true); - while (this._chatLock) await new Promise(r => setTimeout(r, 50)); + const lockStart = Date.now(); + while (this._chatLock) { + if (Date.now() - lockStart > 10000) { + this._chatLock = false; + this.terminal.print('⚠️ Chat lock timed out — force released', 'warning'); + break; + } + await new Promise(r => setTimeout(r, 50)); + } this._chatLock = true; this.terminal.markDirty(); // Re-read context from localStorage (auto-restore may have written it after init) @@ -545,18 +553,35 @@ RULES: } _trackToolFailure(toolName, error) { try { + if (!this._toolFailuresBuffer) this._toolFailuresBuffer = {}; + if (!this._toolFailuresBuffer[toolName]) this._toolFailuresBuffer[toolName] = { count: 0, last: '', errors: [] }; + const entry = this._toolFailuresBuffer[toolName]; + entry.count++; + entry.last = new Date().toISOString(); + entry.errors.push(error); + if (entry.errors.length > 5) entry.errors.shift(); + if (entry.count >= 3) { + this.terminal.print(`⚠️ Tool '${toolName}' has failed ${entry.count} times. Consider creating a workaround skill.`, 'warning'); + } + if (this._toolFailureFlushTimer) clearTimeout(this._toolFailureFlushTimer); + this._toolFailureFlushTimer = setTimeout(() => this._flushToolFailures(), 2000); + } catch (e) { /* ignore */ } + } + _flushToolFailures() { + try { + if (!this._toolFailuresBuffer || Object.keys(this._toolFailuresBuffer).length === 0) return; const key = 'webx11_tool_failures'; const raw = localStorage.getItem(key) || '{}'; const map = JSON.parse(raw); - if (!map[toolName]) map[toolName] = { count: 0, last: '', errors: [] }; - map[toolName].count++; - map[toolName].last = new Date().toISOString(); - map[toolName].errors.push(error); - if (map[toolName].errors.length > 5) map[toolName].errors.shift(); - localStorage.setItem(key, JSON.stringify(map)); - if (map[toolName].count >= 3) { - this.terminal.print(`⚠️ Tool '${toolName}' has failed ${map[toolName].count} times. Consider creating a workaround skill.`, 'warning'); + for (const [toolName, entry] of Object.entries(this._toolFailuresBuffer)) { + if (!map[toolName]) map[toolName] = { count: 0, last: '', errors: [] }; + map[toolName].count += entry.count; + map[toolName].last = entry.last; + map[toolName].errors.push(...entry.errors); + if (map[toolName].errors.length > 10) map[toolName].errors = map[toolName].errors.slice(-10); } + localStorage.setItem(key, JSON.stringify(map)); + this._toolFailuresBuffer = {}; } catch (e) { /* ignore */ } } async agenticLoop(messages) { @@ -781,7 +806,7 @@ RULES: } }, 500); this._confirmTimerInterval = timerInterval; - setTimeout(() => { + this._confirmTimeout = setTimeout(() => { clearInterval(timerInterval); if (this._confirmResolve) { this._confirmResolve(false); @@ -804,6 +829,8 @@ RULES: } _cleanupConfirmBar() { clearInterval(this._confirmTimerInterval); + clearTimeout(this._confirmTimeout); + this._confirmTimeout = null; this._confirmTimerInterval = null; this._confirmResolve = null; this._pendingConfirmation = null; |