aboutsummaryrefslogtreecommitdiff
path: root/modules/core/module-aiassist.js
diff options
context:
space:
mode:
authorAgando <roduccomm@gmail.com>2026-06-04 06:01:04 +0200
committerAgando <roduccomm@gmail.com>2026-06-04 06:01:04 +0200
commita5023e61be61f2f2287342039addab6bb28ad2fd (patch)
tree9b1b3c166869cd6fee91bffe1f4134513005b8b1 /modules/core/module-aiassist.js
parent301f75ab03302a05b3c35950a3b0ab49f9f69ed6 (diff)
auto: 2026-06-04_06:00 changes
Diffstat (limited to 'modules/core/module-aiassist.js')
-rw-r--r--modules/core/module-aiassist.js208
1 files changed, 195 insertions, 13 deletions
diff --git a/modules/core/module-aiassist.js b/modules/core/module-aiassist.js
index eb41af9..cb1482f 100644
--- a/modules/core/module-aiassist.js
+++ b/modules/core/module-aiassist.js
@@ -418,6 +418,56 @@ RULES:
required: ['role']
}
}
+ }, {
+ type: 'function',
+ function: {
+ name: 'nvfs_resolve',
+ description: 'Search VFS files by semantic concept using Neural VFS index. Call nvfs-index first to build the index.',
+ parameters: {
+ type: 'object',
+ properties: {
+ concept: { type: 'string', description: 'Concept to search (e.g. skill, memory, module, webdav, security)' }
+ },
+ required: ['concept']
+ }
+ }
+ }, {
+ type: 'function',
+ function: {
+ name: 'list_available_modules',
+ description: 'List all available modules with metadata (core/ext, commands, class name, layer). Filter by type with type=core or type=ext.',
+ parameters: {
+ type: 'object',
+ properties: {
+ type: { type: 'string', description: 'Optional: filter to "core" or "ext"' }
+ },
+ required: []
+ }
+ }
+ }, {
+ type: 'function',
+ function: {
+ name: 'smart_context_list',
+ description: 'List available AI context profiles (e.g. coding, debug, creative, technical). Returns profile names and system prompts.',
+ parameters: {
+ type: 'object',
+ properties: {},
+ required: []
+ }
+ }
+ }, {
+ type: 'function',
+ function: {
+ name: 'smart_context_set',
+ description: 'Set the active AI context profile. Changes the AI\'s behavior (temperature, style) for subsequent responses.',
+ parameters: {
+ type: 'object',
+ properties: {
+ name: { type: 'string', description: 'Profile name (e.g. "coding", "debug", "creative", "technical", "chat")' }
+ },
+ required: ['name']
+ }
+ }
}];
}
getHelpInfo() {
@@ -695,6 +745,9 @@ RULES:
duration: t1,
error: this._isToolError(toolResult) ? true : false
});
+ // Telemetry
+ 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 };
}));
@@ -734,6 +787,9 @@ RULES:
duration: t1,
error: this._isToolError(toolResult) ? true : false
});
+ // Telemetry
+ const sm2 = this.terminal.moduleManager.modules['ServerMonitorModule'];
+ if (sm2 && sm2.logToolCall) sm2.logToolCall(fn.name, (t1 * 1000) || 1, this._isToolError(toolResult));
if (this._debugPanelEnabled) this._updateDebugPanel();
const dObs = this._summarizeObservation(toolResult, 150);
const dErr = this._isToolError(toolResult);
@@ -1338,6 +1394,76 @@ RULES:
.filter(s => !filterCat || (s.category || '').toLowerCase() === filterCat);
return JSON.stringify({ skills: list, count: list.length });
}
+ case 'nvfs_resolve': {
+ const concept = (a.concept || '').toLowerCase();
+ if (!concept) return JSON.stringify({ error: 'Concept is required' });
+ const nvfs = this.terminal.moduleManager.modules['NeuralVFSModule'];
+ if (!nvfs) return JSON.stringify({ error: 'Neural VFS module not loaded — run nvfs-index first' });
+ // Build index if empty
+ if (Object.keys(nvfs.index).length === 0) {
+ const saved = this.terminal.fs.fsReadJSON('/.semantic_index/map.json');
+ if (saved) { nvfs.index = saved; }
+ else { return JSON.stringify({ error: 'No semantic index found — run nvfs-index first' }); }
+ }
+ const exact = nvfs.index[concept];
+ const fuzzy = Object.keys(nvfs.index).filter(k =>
+ k.includes(concept) || concept.includes(k)
+ ).filter(k => k !== concept);
+ const results = [];
+ if (exact) results.push(...exact.map(e => ({ concept, path: e.path, summary: e.summary })));
+ for (const f of fuzzy.slice(0, 5)) {
+ results.push(...nvfs.index[f].slice(0, 3).map(e => ({ concept: f, path: e.path, summary: e.summary })));
+ }
+ return JSON.stringify({ concept, exact: !!exact, count: results.length, results: results.slice(0, 20) });
+ }
+ case 'list_available_modules': {
+ try {
+ const resp = await fetch('/spaces/newos4/modules-index.json?v=' + (localStorage.getItem('webx11_cache_ver') || ''));
+ if (!resp.ok) return JSON.stringify({ error: 'Module index not available' });
+ const idx = await resp.json();
+ const filterType = (a.type || '').toLowerCase();
+ let mods = Object.values(idx.modules);
+ if (filterType) mods = mods.filter(m => m.type === filterType);
+ return JSON.stringify({
+ total: mods.length,
+ available: idx.total,
+ type: filterType || 'all',
+ modules: mods.map(m => ({
+ name: m.name,
+ type: m.type,
+ class: m.class,
+ commands: m.commands.slice(0, 8),
+ description: (m.description || '').substring(0, 80),
+ auto_load: m.auto_load
+ }))
+ });
+ } catch (e) { return JSON.stringify({ error: 'Failed to load module index: ' + e.message }); }
+ }
+ case 'smart_context_list': {
+ const scm = this.terminal.moduleManager.modules['SmartContextModule'];
+ if (!scm) return JSON.stringify({ error: 'SmartContextModule not loaded', profiles: [] });
+ const profiles = scm.contextProfiles || {};
+ return JSON.stringify({
+ profiles: Object.entries(profiles).map(([key, p]) => ({
+ name: key,
+ displayName: p.name || key,
+ systemPrompt: (p.systemPrompt || '').substring(0, 80),
+ temperature: p.temperature || 0.7,
+ active: scm.activeProfile === key
+ }))
+ });
+ }
+ case 'smart_context_set': {
+ const scm = this.terminal.moduleManager.modules['SmartContextModule'];
+ if (!scm) return JSON.stringify({ error: 'SmartContextModule not loaded' });
+ const name = (a.name || '').toLowerCase();
+ if (!scm.contextProfiles[name]) {
+ return JSON.stringify({ error: `Profile '${name}' not found`, available: Object.keys(scm.contextProfiles) });
+ }
+ scm.activeProfile = name;
+ const profile = scm.contextProfiles[name];
+ return JSON.stringify({ success: true, name, displayName: profile.name, systemPrompt: profile.systemPrompt, temperature: profile.temperature });
+ }
case 'view_module':
case 'edit_module':
case 'test_module':
@@ -1364,16 +1490,41 @@ RULES:
const code = this.terminal.fs.readFile(`_mods/${modName}.js`);
if (code) return code;
const url = entry ? entry.url : null;
- if (!url) return JSON.stringify({ error: `No source URL for ${modName}` });
+ // Try registry URL first
+ if (url) {
+ try {
+ const resp = await fetch(url);
+ if (resp.ok) {
+ const src = await resp.text();
+ this.terminal.fs.writeFile(`_mods/${modName}.orig.js`, src);
+ return src.substring(0, 8000);
+ }
+ } catch (e) { /* fall through */ }
+ }
+ // Fallback: use modules-index.json to map class name to filename
try {
- const resp = await fetch(url);
- if (resp.ok) {
- const src = await resp.text();
- this.terminal.fs.writeFile(`_mods/${modName}.orig.js`, src);
- return src.substring(0, 8000);
+ const idxResp = await fetch('/spaces/newos4/modules-index.json?v=' + (localStorage.getItem('webx11_cache_ver') || ''));
+ if (idxResp.ok) {
+ const idx = await idxResp.json();
+ // modName is the class name (e.g. "WebX11AIAssistantModule")
+ // or already a filename (e.g. "module-aiassist")
+ // Try matching by class name first
+ let match = Object.values(idx.modules).find(m => m.class === modName);
+ // Then by name
+ if (!match) match = idx.modules[modName];
+ if (match) {
+ const filePath = match.file; // e.g. "modules/core/module-aiassist.js"
+ const fetchUrl = `/spaces/newos4/${filePath}`;
+ const resp = await fetch(fetchUrl);
+ if (resp.ok) {
+ const src = await resp.text();
+ this.terminal.fs.writeFile(`_mods/${modName}.orig.js`, src);
+ return src.substring(0, 8000);
+ }
+ }
}
- return JSON.stringify({ error: `HTTP ${resp.status}` });
- } catch (e) { return JSON.stringify({ error: e.message }); }
+ } catch (e) { /* fall through */ }
+ return JSON.stringify({ error: `Cannot find source for ${modName} — not in registry, not in modules-index.json` });
}
case 'edit_module': {
const modName = a.name || '';
@@ -1425,11 +1576,42 @@ RULES:
const mm = this.terminal.moduleManager;
const modsDir = this.terminal.fs.getCurrentDir();
const hasMods = modsDir.content['_mods'] ? !!Object.keys(modsDir.content['_mods'].content).length : false;
- const modules = mm.moduleRegistry.map(m => ({
- name: m.name, url: m.url, enabled: m.enabled,
- loaded: !!mm.modules[m.name],
- modified: !!this.terminal.fs.readFile(`_mods/${m.name}.js`)
- }));
+ // Load module index for file path lookup
+ let idxMap = {};
+ try {
+ const resp = await fetch('/spaces/newos4/modules-index.json?v=' + (localStorage.getItem('webx11_cache_ver') || ''));
+ if (resp.ok) {
+ const idx = await resp.json();
+ for (const [name, meta] of Object.entries(idx.modules)) {
+ idxMap[meta.class] = '/spaces/newos4/' + meta.file;
+ }
+ }
+ } catch (e) {}
+ const modules = [];
+ const seen = new Set();
+ for (const [className, instance] of Object.entries(mm.modules)) {
+ const name = instance.constructor ? instance.constructor.name : className;
+ if (seen.has(name)) continue;
+ seen.add(name);
+ modules.push({
+ name: name,
+ url: idxMap[name] || null,
+ enabled: true,
+ loaded: true,
+ modified: !!this.terminal.fs.readFile(`_mods/${name}.js`),
+ source: 'loaded'
+ });
+ }
+ for (const m of mm.moduleRegistry) {
+ if (seen.has(m.name)) continue;
+ seen.add(m.name);
+ modules.push({
+ name: m.name, url: m.url || idxMap[m.name] || null, enabled: m.enabled,
+ loaded: !!mm.modules[m.name],
+ modified: !!this.terminal.fs.readFile(`_mods/${m.name}.js`),
+ source: m.url ? 'ext' : 'core'
+ });
+ }
return JSON.stringify({ modules, total: modules.length, hasLocalEdits: hasMods });
}
default: return JSON.stringify({ error: `Unknown module tool: ${name}` });