diff options
| author | Agando <roduccomm@gmail.com> | 2026-06-01 18:00:38 +0200 |
|---|---|---|
| committer | Agando <roduccomm@gmail.com> | 2026-06-01 18:00:38 +0200 |
| commit | b839e58aa45da1945d0c46c8070b4e7016c59f94 (patch) | |
| tree | d394c7ee9c338e8f449f9f09e53e59f8d41ec5c1 /modules/core/module-aiassist.js | |
| parent | 6aed9c9e0252b0c8f681a358e5a8707271454137 (diff) | |
auto: 2026-06-01_18:00 changes
Diffstat (limited to 'modules/core/module-aiassist.js')
| -rw-r--r-- | modules/core/module-aiassist.js | 78 |
1 files changed, 77 insertions, 1 deletions
diff --git a/modules/core/module-aiassist.js b/modules/core/module-aiassist.js index f77ec61..f7be209 100644 --- a/modules/core/module-aiassist.js +++ b/modules/core/module-aiassist.js @@ -16,7 +16,10 @@ this._sessionSaved = false; this._thinkingTimer = null; this._thinkingStartTime = 0; + this._validatorSuppressed = false; this._toolDefs = null; + this._toolCallLog = []; + this._debugPanelEnabled = false; try { const s = localStorage.getItem('webx11_ai_patterns'); if (s) this._commandFreq = JSON.parse(s); } catch (e) {} try { const p = localStorage.getItem('webx11_user_profile'); if (p) this._userProfile = JSON.parse(p); } catch (e) {} // Restore AI conversation context from localStorage @@ -392,6 +395,7 @@ RULES: 'ai-context': 'ai-context — Show current conversation context', 'ai-allow': 'ai-allow — Confirm pending AI action', 'ai-deny': 'ai-deny — Deny pending AI action', + 'ai-ignore': 'ai-ignore — Suppress validator warnings for this session', 'ai-stop': 'ai-stop — Cancel current AI operation', 'ai-model': 'ai-model [model] — Show or set AI model' }; @@ -404,9 +408,11 @@ RULES: this.commands['ai-context'] = () => this.showContext(); this.commands['ai-allow'] = () => this.confirmPending(); this.commands['ai-deny'] = () => this.denyPending(); + this.commands['ai-ignore'] = () => this.ignoreValidator(); this.commands['ai-stop'] = () => this.cancelAi(); this.commands['ai-model'] = (args) => this.showModel(args); this.commands['ai-compress'] = () => this._manualCompress(); + this.commands['debug'] = () => this.toggleDebug(); } async chat(args) { const userMessage = args.join(' '); @@ -542,6 +548,28 @@ RULES: } return result.substring(0, maxLen) + '...(truncated from ' + result.length + ' chars)'; } + _escapeHtml(str) { + return String(str).replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>').replace(/"/g, '"'); + } + _updateDebugPanel() { + if (!this._debugPanelEnabled) return; + const panel = document.getElementById('debug-panel'); + if (!panel) return; + const recent = this._toolCallLog.slice(-20); + let html = ''; + for (const entry of recent) { + const statusClass = entry.error ? 'debug-entry-error' : 'debug-entry-ok'; + const argsStr = typeof entry.args === 'string' ? entry.args.substring(0, 60) : JSON.stringify(entry.args).substring(0, 60); + html += '<div class="debug-entry ' + statusClass + '">' + + '<span class="debug-turn">#' + entry.turn + '</span> ' + + '<span class="debug-name">' + this._escapeHtml(entry.name) + '</span> ' + + '<span class="debug-args">' + this._escapeHtml(argsStr) + '</span> ' + + '<span class="debug-time">' + entry.duration + 's</span>' + + (entry.error ? ' <span class="debug-err">⚠️</span>' : '') + + '</div>'; + } + panel.innerHTML = '<div class="debug-header">🔧 Tool Log <span class="debug-count">' + this._toolCallLog.length + ' calls</span></div>' + html; + } _isToolError(result) { if (!result || typeof result !== 'string') return null; const trimmed = result.trim(); @@ -618,6 +646,15 @@ RULES: const t0 = Date.now(); const toolResult = await this.runTool(fn.name, fn.arguments); const t1 = Math.round((Date.now() - t0) / 1000); + this._toolCallLog.push({ + turn: toolTurns, + name: fn.name, + args: fn.arguments, + result: toolResult, + duration: t1, + error: this._isToolError(toolResult) ? true : false + }); + if (this._debugPanelEnabled) this._updateDebugPanel(); return { fn, toolResult, t1 }; })); for (const { fn, toolResult, t1 } of safeResults) { @@ -628,6 +665,10 @@ RULES: this.terminal.log('WARN', 'AI', `Tool ${fn.name} failed: ${err} (${t1}s)`); this._trackToolFailure(fn.name, err); this.terminal.print(`📊 Result (${t1}s): ⚠️ Error: ${err}`, 'warning'); + } else if (toolResult && toolResult.length > 150) { + this.terminal.log('INFO', 'AI', `Tool ${fn.name} ok (${t1}s)`); + const safeId = 'toolresult-' + Date.now() + '-' + Math.random().toString(36).slice(2, 6); + this.terminal.printHTML(`📊 Result (${t1}s): <span id="${safeId}-short">${this._escapeHtml(obs)} <a href="#" onclick="var e=document.getElementById('${safeId}-full');var s=document.getElementById('${safeId}-short');if(e){e.style.display='inline';s.style.display='none'}return false" style="color:var(--info-color);cursor:pointer">[+] show full (${toolResult.length} chars)</a></span><span id="${safeId}-full" style="display:none">${this._escapeHtml(toolResult)} <a href="#" onclick="var e=document.getElementById('${safeId}-full');var s=document.getElementById('${safeId}-short');if(e&&s){e.style.display='none';s.style.display='inline'}return false" style="color:var(--warning-color);cursor:pointer">[-] collapse</a></span>`); } else { this.terminal.log('INFO', 'AI', `Tool ${fn.name} ok (${t1}s)`); this.terminal.print(`📊 Result (${t1}s): ${obs}`, 'info'); @@ -644,6 +685,15 @@ RULES: this.terminal.print(`🔧 Tool: ${fn.name}(${typeof fn.arguments === 'string' ? fn.arguments : JSON.stringify(fn.arguments)})`, 'info'); const toolResult = await this.runTool(fn.name, fn.arguments); const t1 = Math.round((Date.now() - t0) / 1000); + this._toolCallLog.push({ + turn: toolTurns, + name: fn.name, + args: fn.arguments, + result: toolResult, + duration: t1, + error: this._isToolError(toolResult) ? true : false + }); + if (this._debugPanelEnabled) this._updateDebugPanel(); const dObs = this._summarizeObservation(toolResult, 150); const dErr = this._isToolError(toolResult); if (dErr) { @@ -664,7 +714,7 @@ RULES: } } // Validator: check safe tool results for consistency - if (safeResults.length > 0 && pendingText) { + if (safeResults.length > 0 && pendingText && !this._validatorSuppressed) { const om = this.terminal.ollamaManager; if (om && om.validatorEnabled && om.validatorModel) { let invalidTools = []; @@ -856,6 +906,10 @@ RULES: denyPending() { this._resolveConfirm(false); } + ignoreValidator() { + this._validatorSuppressed = true; + this.terminal.print('🔍 Validator suppressed for this session', 'info'); + } cancelAi() { this._cancelled = true; this.terminal.print('⏹ Cancelling AI...', 'warning'); @@ -870,6 +924,28 @@ RULES: // Immediately reset UI so user knows it stopped this.terminal.setAiBusy(false); } + toggleDebug() { + this._debugPanelEnabled = !this._debugPanelEnabled; + let panel = document.getElementById('debug-panel'); + if (!panel) { + // Create the debug panel + panel = document.createElement('div'); + panel.id = 'debug-panel'; + panel.style.cssText = 'position:fixed;right:10px;bottom:50px;width:380px;max-height:400px;overflow-y:auto;background:#0a0a0a;border:1px solid #333;border-radius:6px;z-index:9999;font-family:monospace;font-size:0.78em;display:none;'; + document.body.appendChild(panel); + // Add close button handler + panel.addEventListener('click', function() { + // Toggle collapsed/expanded state + }); + } + panel.style.display = this._debugPanelEnabled ? 'block' : 'none'; + if (this._debugPanelEnabled) { + this._updateDebugPanel(); + this.terminal.print('🔧 Debug panel enabled — shows tool call log in bottom-right corner. Close with: debug', 'info'); + } else { + this.terminal.print('🔧 Debug panel disabled', 'info'); + } + } isDestructive(name) { return name === 'write_file' || name === 'delete_file' || name === 'run_command' || name === 'make_directory' || name === 'edit_module'; } |