aboutsummaryrefslogtreecommitdiff
path: root/modules/core/module-aiassist.js
diff options
context:
space:
mode:
authorAgando <roduccomm@gmail.com>2026-06-13 18:00:58 +0200
committerAgando <roduccomm@gmail.com>2026-06-13 18:00:58 +0200
commitde713efd619360e29b9bfc4b99d30d2a86b96caf (patch)
tree0cb94ba7cbeca0cd47cc77a9a31f744d28aa5e76 /modules/core/module-aiassist.js
parent764128fbf5c5516eb26700ca3cf2f1ad523c48bd (diff)
auto: 2026-06-13_18:00 changes
Diffstat (limited to 'modules/core/module-aiassist.js')
-rw-r--r--modules/core/module-aiassist.js124
1 files changed, 115 insertions, 9 deletions
diff --git a/modules/core/module-aiassist.js b/modules/core/module-aiassist.js
index 5273678..44a7574 100644
--- a/modules/core/module-aiassist.js
+++ b/modules/core/module-aiassist.js
@@ -67,7 +67,7 @@ buildSystemPrompt() {
} catch (e) {}
return 'Current date: ' + dateStr + nvfsNote + '\n'
+ 'VFS→Modules→AI. nvfs-index for commands. Tool→Observe→Answer. nvfs-resolve. Destructive cmds need confirm.\n'
- + 'FS: list/read/write/delete | NVFS: nvfs-resolve | Web: search/fetch [POST=method+body] | Mod: view/edit/test/reload | Config | Skills\n'
+ + 'FS: list/read/write/delete | NVFS: nvfs-resolve | Web: search/fetch [POST=method+body] | Mod: view/edit/test/reload | Config | Skills | VaultMind: vaultmind_query(ep,msg,agent) — Hyperliquid prices/portfolio/chat\n'
+ 'web_fetch tool: GET for normal pages (returns title+content+word_count), POST for JSON APIs like Hyperliquid /info (pass method="POST" and body as JSON string).\n'
+ 'Other: floating, webdav, cron, vault, sandbox, agents, wpm, mindmap, memgraph, guardrail, wget, tar, secret-* — discoverable via help';
}
@@ -423,6 +423,21 @@ buildSystemPrompt() {
required: ['topic']
}
}
+ }, {
+ type: 'function',
+ function: {
+ name: 'vaultmind_query',
+ description: "Query VaultMind AI for Hyperliquid market data (prices, portfolio, transactions, copy-trade) or ask an AI agent. Uses same-origin /vmai/ API.",
+ parameters: {
+ type: 'object',
+ properties: {
+ endpoint: { type: 'string', description: 'prices, portfolio, transactions, copy-trade, or chat' },
+ message: { type: 'string', description: 'Question for the AI agent (chat endpoint only)' },
+ agent: { type: 'string', enum: ['market', 'trading', 'transaction', 'copy'], description: 'Which AI agent to query (chat endpoint only)' }
+ },
+ required: ['endpoint']
+ }
+ }
}];
}
getHelpInfo() {
@@ -439,7 +454,7 @@ buildSystemPrompt() {
'ai-model': 'ai-model [model] — Show or set AI model',
'ai-config': 'ai-config [key] [value] — View or set AI loop config (max-turns, max-context, confirm-timeout(0=disabled))',
'mem-debug': 'mem-debug — Show memory breakdown by component',
- 'reset-mem': 'reset-mem — Reset AI memory (logs, patterns) without losing VFS or config'
+ 'reset-mem': 'reset-mem — Reset AI memory (logs, context, profile, guardrails) without losing VFS or config'
};
}
registerCommands() {
@@ -1859,6 +1874,30 @@ buildSystemPrompt() {
case 'list_modified_modules':
case 'get_module_status':
return await this.runModuleTool(name, argsStr);
+ case 'vaultmind_query': {
+ const ep = a.endpoint;
+ const validEps = ['prices', 'portfolio', 'transactions', 'copy-trade', 'chat'];
+ if (!validEps.includes(ep)) {
+ return JSON.stringify({ error: 'Invalid endpoint. Valid: ' + validEps.join(', ') });
+ }
+ try {
+ let url = '/vmai/' + ep;
+ let opts = { method: 'GET', headers: { 'Accept': 'application/json' } };
+ if (ep === 'chat') {
+ opts.method = 'POST';
+ opts.headers['Content-Type'] = 'application/json';
+ opts.body = JSON.stringify({
+ message: a.message || 'What is the current market status?',
+ agent: a.agent || 'market'
+ });
+ }
+ const resp = await fetch(url, opts);
+ const data = await resp.json();
+ return JSON.stringify({ success: true, data });
+ } catch (e) {
+ return JSON.stringify({ error: 'VaultMind API error: ' + e.message });
+ }
+ }
default:
return JSON.stringify({ error: `Unknown tool: ${name}` });
}
@@ -2087,31 +2126,80 @@ buildSystemPrompt() {
const errLogSize = this._errorLog.length;
const freqKeys = Object.keys(this._commandFreq).length;
const contextSize = this.context.length;
+ const factKeys = this._userProfile?.knownFacts ? Object.keys(this._userProfile.knownFacts).length : 0;
+ const shadowSize = this._shadowSnapshot ? JSON.stringify(this._shadowSnapshot).length : 0;
+ const guardrailSize = this._guardrailPolicy ? JSON.stringify(this._guardrailPolicy).length : 0;
const vfsSize = (localStorage.getItem('webx11_filesystem') || '').length +
(localStorage.getItem('webx11_filesystem_v2') || '').length;
const aiCtxSize = (localStorage.getItem('webx11_ai_context') || '').length;
+ const aiPatternSize = (localStorage.getItem('webx11_ai_patterns') || '').length;
+ const userProfileSize = (localStorage.getItem('webx11_user_profile') || '').length;
+ const systemPromptSize = (localStorage.getItem('webx11_ai_system_prompt') || '').length;
+ const guardrailPolicySize = (localStorage.getItem('webx11_guardrail_policy') || '').length;
this.terminal.print('=== Memory Debug ===', 'info');
this.terminal.print(` _toolCallLog: ${toolLogSize} entries (cap: 50)`, toolLogSize > 30 ? 'warning' : 'text-muted');
this.terminal.print(` _errorLog: ${errLogSize} entries (cap: 20)`, errLogSize > 10 ? 'warning' : 'text-muted');
- this.terminal.print(` _commandFreq: ${freqKeys} tracked patterns`, freqKeys > 15 ? 'warning' : 'text-muted');
+ this.terminal.print(` _commandFreq: ${freqKeys} tracked patterns (cap: 30)`, freqKeys > 20 ? 'warning' : 'text-muted');
this.terminal.print(` AI context: ${contextSize} messages (max: ${this.maxContext * 2})`, 'text-muted');
+ this.terminal.print(` User facts: ${factKeys} facts (cap: 50)`, 'text-muted');
this.terminal.print(` VFS localStorage: ${(vfsSize / 1024).toFixed(1)} KB`, 'text-muted');
this.terminal.print(` AI context localStorage: ${(aiCtxSize / 1024).toFixed(1)} KB`, 'text-muted');
+ this.terminal.print(` AI patterns localStorage: ${(aiPatternSize / 1024).toFixed(1)} KB`, 'text-muted');
+ this.terminal.print(` User profile localStorage: ${(userProfileSize / 1024).toFixed(1)} KB`, userProfileSize > 10240 ? 'warning' : 'text-muted');
+ this.terminal.print(` System prompt localStorage: ${(systemPromptSize / 1024).toFixed(1)} KB`, systemPromptSize > 10240 ? 'warning' : 'text-muted');
+ this.terminal.print(` Guardrail policy localStorage: ${(guardrailPolicySize / 1024).toFixed(1)} KB`, 'text-muted');
+ this.terminal.print(` Runtime shadow snapshot: ${(shadowSize / 1024).toFixed(1)} KB`, shadowSize > 10240 ? 'warning' : 'text-muted');
+ this.terminal.print(` Runtime guardrail policy: ${(guardrailSize / 1024).toFixed(1)} KB`, 'text-muted');
const heap = performance.memory ? performance.memory.usedJSHeapSize : null;
if (heap) {
this.terminal.print(` JS heap: ${(heap / 1048576).toFixed(1)} MB / ${(performance.memory.jsHeapSizeLimit / 1048576).toFixed(1)} MB`, 'text-muted');
}
- this.terminal.print('Use reset-mem to clear AI internal logs without touching VFS/config', 'info');
+ this.terminal.print('Use reset-mem to clear AI internal logs, context, profile, and guardrail policy', 'info');
}
resetMem() {
+ // Capture size before clearing for the success message
+ const aiCtxSize = (localStorage.getItem('webx11_ai_context') || '').length;
+ const userProfileSize = (localStorage.getItem('webx11_user_profile') || '').length;
+ const patternSize = (localStorage.getItem('webx11_ai_patterns') || '').length;
+ const guardrailSize = (localStorage.getItem('webx11_guardrail_policy') || '').length;
+
+ // Runtime in-memory resets
this._toolCallLog = [];
this._errorLog = [];
this._commandFreq = {};
this.context = [];
+ this._messageCount = 0;
+ this._userProfile = {};
+ this._guardrailViolations = {};
+ this._shadowSnapshot = null;
+ this._guardrailPolicy = null;
+ this._toolDefs = null; // will be rebuilt on next use
+
+ // Persisted localStorage resets
localStorage.removeItem('webx11_ai_context');
localStorage.removeItem('webx11_ai_patterns');
- this.terminal.print('AI memory reset: tool logs, error logs, command patterns, and context cleared', 'success');
- this.terminal.print('VFS, config, skills, system prompt, and floating elements preserved', 'text-muted');
+ localStorage.removeItem('webx11_user_profile');
+ localStorage.removeItem('webx11_guardrail_policy');
+ localStorage.removeItem('webx11_ai_system_prompt');
+
+ // VFS backups that _autoRestoreSession can resurrect
+ try {
+ const fs = this.terminal.fs;
+ if (fs) {
+ fs.deleteFile('_sessions/_auto-context.json');
+ fs.deleteFile('_sessions/_auto.json');
+ }
+ } catch (e) {}
+
+ // Mark reset timestamp so auto-restore skips stale backups
+ localStorage.setItem('webx11_last_reset', Date.now().toString());
+
+ const totalCleared = aiCtxSize + userProfileSize + patternSize + guardrailSize;
+ this.terminal.print(`✅ AI memory reset: ${(totalCleared / 1024).toFixed(1)} KB cleared`, 'success');
+ this.terminal.print(' • tool logs, error logs, command patterns, conversation context', 'text-muted');
+ this.terminal.print(' • user profile / known facts, guardrail policy, shadow snapshot', 'text-muted');
+ this.terminal.print(' • VFS session backups and cached system prompt', 'text-muted');
+ this.terminal.print('VFS files, terminal history, AI config, and module registry preserved', 'text-muted');
}
showModel(args) {
const om = this.terminal.ollamaManager;
@@ -2204,6 +2292,7 @@ buildSystemPrompt() {
this.terminal.print(`${icon} ${content}...`);
});
}
+ // Extract facts about user from conversation
_extractFacts(userMsg, aiResp) {
const patterns = [
{ re: /my name is (\w+)/i, key: 'name' },
@@ -2215,16 +2304,26 @@ buildSystemPrompt() {
{ re: /i (?:like|prefer|love) (.+)/i, key: 'preference' },
];
let changed = false;
+ if (!this._userProfile.knownFacts) this._userProfile.knownFacts = {};
for (const { re, key } of patterns) {
const m = (userMsg + ' ' + (aiResp || '')).match(re);
if (m && m[1]) {
- if (!this._userProfile.knownFacts) this._userProfile.knownFacts = {};
- if (this._userProfile.knownFacts[key] !== m[1].trim()) {
- this._userProfile.knownFacts[key] = m[1].trim();
+ const val = m[1].trim();
+ if (this._userProfile.knownFacts[key] !== val) {
+ this._userProfile.knownFacts[key] = val;
changed = true;
}
}
}
+ // v4.5.47: cap knownFacts so the profile doesn't bloat indefinitely
+ const MAX_FACTS = 50;
+ const factKeys = Object.keys(this._userProfile.knownFacts);
+ if (factKeys.length > MAX_FACTS) {
+ this._userProfile.knownFacts = Object.fromEntries(
+ factKeys.slice(-MAX_FACTS).map(k => [k, this._userProfile.knownFacts[k]])
+ );
+ changed = true;
+ }
if (changed) {
try { localStorage.setItem('webx11_user_profile', JSON.stringify(this._userProfile)); } catch (e) {}
}
@@ -2235,6 +2334,13 @@ buildSystemPrompt() {
for (const p of patterns) {
if (lower.includes(p)) this._commandFreq[p] = (this._commandFreq[p] || 0) + 1;
}
+ // v4.5.47: cap command frequency map to top 30 patterns to prevent unbounded growth
+ const MAX_PATTERNS = 30;
+ const keys = Object.keys(this._commandFreq);
+ if (keys.length > MAX_PATTERNS) {
+ const sorted = keys.sort((a, b) => this._commandFreq[b] - this._commandFreq[a]);
+ this._commandFreq = Object.fromEntries(sorted.slice(0, MAX_PATTERNS).map(k => [k, this._commandFreq[k]]));
+ }
try { localStorage.setItem('webx11_ai_patterns', JSON.stringify(this._commandFreq)); } catch (e) {}
}
async _autoCreateErrorSkill() {