aboutsummaryrefslogtreecommitdiff
path: root/modules/core/module-aiassist.js
diff options
context:
space:
mode:
Diffstat (limited to 'modules/core/module-aiassist.js')
-rw-r--r--modules/core/module-aiassist.js47
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;