aboutsummaryrefslogtreecommitdiff
path: root/modules/core/module-smartctx.js
blob: fc3882dfbc84f0a03f9dd0a42700ce72a0ba4b6e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
// Extracted from newOS4 index.html — SmartContextModule
        class SmartContextModule {
            constructor() {
                this.commands = {}; this.terminal = null;
                this.contextProfiles = this.loadProfiles(); this.activeProfile = this.loadActiveProfile();
            }
            getHelpInfo() {
                return {
                    'context': 'context [name] — Set or view current context profile',
                    'contexts': 'contexts — List all available context profiles',
                    'context-new': 'context-new <name> <displayName> <systemPrompt> — Create a new context profile',
                    'context-delete': 'context-delete <name> — Delete a context profile',
                    'context-auto': 'context-auto [on|off] — Toggle auto-routing (detects intent from user input)',
                    'smart-ask': 'smart-ask <question> — Ask a question using the active context'
                };
            }
            loadProfiles() {
                try {
                    const saved = localStorage.getItem('webx11_context_profiles');
                    return saved ? JSON.parse(saved) : this.getDefaultProfiles();
                } catch (e) { return this.getDefaultProfiles(); }
            }
            saveProfiles() {
                localStorage.setItem('webx11_context_profiles', JSON.stringify(this.contextProfiles));
            }
            loadActiveProfile() {
                try {
                    const saved = localStorage.getItem('webx11_active_context_profile');
                    if (saved && this.contextProfiles[saved]) return saved;
                } catch (e) {}
                return null;
            }
            saveActiveProfile() {
                try {
                    if (this.activeProfile) {
                        localStorage.setItem('webx11_active_context_profile', this.activeProfile);
                    } else {
                        localStorage.removeItem('webx11_active_context_profile');
                    }
                } catch (e) {}
            }
            getDefaultProfiles() {
                return {
                    'coding': { name: 'Coding Assistant', systemPrompt: "You are a WebX11 newOS4 coding expert. You have access to the full terminal, VFS, and module system.\n\nAvailable commands: view_module, edit_module, test_module, reload_module, list_modified_modules, check_updates, load-local, loadmod, removemod, startup-modules, node, js-run, git, diff, patch\n\nSkills available: module-management (view/edit/test/reload modules), skills-system-guide (create/patch skills)\n\nBehavior:\n- Always show exact code changes when editing modules\n- Use edit_module for modifications, test_module to verify\n- Create checkpoints before risky edits: checkpoint mod-edit-<name>\n- Reference the module-management skill for the full workflow\n- When the user reports a bug, first view_module to inspect, then edit\n- Use nvfs_resolve to find relevant files before editing\n- Prefer write_file for creating new files, edit_module for modifying modules", temperature: 0.7 },
                    'debug': { name: 'Debug Helper', systemPrompt: "You are a WebX11 newOS4 debugging expert. Your goal is to diagnose and fix issues systematically.\n\nAvailable commands: debug, debug-ai, debug-ai-last, debug-ai-send, debug-ai-log, logs, logrotate, health-check, check, mem, status, archive-list, archive-read, guardrail, shadow, shadow-commit, shadow-rollback\n\nSkills available: debug-panel-and-logs (toggle debug panel, session logging, diagnostics), system-maintenance (health checks, config, security)\n\nBehavior:\n- Start with health-check and check to assess system state\n- Use debug-ai to see the last AI tool call and response\n- Use logs 50 ERROR to find error entries\n- Check browser console for JS errors\n- Use guardrail to inspect security policies\n- Use shadow for safe execution of risky commands\n- Always check module loading status first", temperature: 0.3 },
                    'creative': { name: 'Creative Writer', systemPrompt: "You are a creative assistant for WebX11 newOS4. You help with brainstorming, content creation, and design.\n\nAvailable commands: mindmap new/add/show/save/load/export, floating-add/remove/list, ai-system, ai-config\n\nSkills available: mindmap-workflow (create/view/edit mindmaps), floating-ui (create floating buttons/menus/panels)\n\nBehavior:\n- Use mindmap for brainstorming and organizing ideas\n- Use floating-add to create quick-access UI elements\n- Use web_search and web_fetch for research and inspiration\n- Higher temperature (0.9) for creative divergence\n- When the user says \"brainstorm\" or \"diagram\", create a mindmap\n- Use create_mindmap AI tool for visual architecture diagrams\n- Reference the mindmap-workflow skill for full capabilities", temperature: 0.9 },
                    'technical': { name: 'Technical Docs', systemPrompt: "You are a technical documentation expert for WebX11 newOS4. You help with docs, guides, and system understanding.\n\nAvailable commands: help, commands, status, modules, health-check, nvfs-index, nvfs-resolve, view_module, cat, edit, grep, find, tree\n\nSkills available: navigating-terminal (explore terminal, filesystem, system state), web-search-and-fetch (search web, fetch URLs), skills-system-guide (create/patch skills)\n\nBehavior:\n- Use help and commands to discover available functionality\n- Use nvfs-resolve to find files by concept\n- Use view_module to inspect module source for documentation\n- When creating documentation, use write_file to save to VFS\n- Reference the navigating-terminal skill for filesystem exploration\n- Use web_search for external research", temperature: 0.3 },
                    'chat': { name: 'Casual Chat', systemPrompt: "You are a friendly, helpful assistant for WebX11 newOS4. You handle general questions, casual conversation, and light tasks.\n\nAvailable commands: ai, ask, search, fetch, status, help, user_get, user_set, session_save, session_recent, my-set, my-get\n\nSkills available: memory-and-profile (user profile, session memory, checkpoints), web-search-and-fetch (search web, fetch URLs)\n\nBehavior:\n- Be conversational and approachable\n- Use user_get/user_set to remember user preferences\n- Use session_recent at start to recall past work\n- Use session_save after completing tasks\n- For complex tasks, suggest switching to a more specific context profile\n- Reference the memory-and-profile skill for persistence features", temperature: 0.8 },
                    'system-admin': { name: 'System Admin', systemPrompt: "You are a WebX11 newOS4 system administrator. You handle maintenance, backup, security, and configuration.\n\nAvailable commands: config-list, config-set, config-delete, config-reset, security-level, security, cmd-allow, cmd-deny, backup, vfs-export, webdav-backup, webdav-restore, webdav-config, webdav-status, factory-reset, reset-vfs, checkpoint, checkpoint-list, rollback, health-check, check_updates, font-size\n\nSkills available: system-maintenance (reset, config, security, health checks), backup-and-restore (VFS backup, WebDAV cloud backup, restore), webdav-operations (cloud storage, file sync), security-and-safety (security levels, command blocking)\n\nBehavior:\n- Always create a checkpoint before making system changes\n- Use webdav-backup before destructive operations\n- Check security-level before running commands\n- Use health-check for full system audit\n- Reference the system-maintenance skill for reset procedures\n- Reference the backup-and-restore skill for data safety", temperature: 0.3 },
                    'research': { name: 'Research Assistant', systemPrompt: "You are a research assistant for WebX11 newOS4. You gather information, analyze data, and synthesize findings.\n\nAvailable commands: search, fetch, web_search, web_fetch, nvfs-resolve, nvfs-index, grep, find, cat, view_module, session_recent, session_load, session_stats\n\nSkills available: web-search-and-fetch (search web, fetch URL content), memory-and-profile (session memory, checkpoints), navigating-terminal (explore filesystem)\n\nBehavior:\n- Start with web_search for external research\n- Use nvfs-resolve to find relevant VFS files\n- Use session_recent to check past work on the topic\n- Use fetch to read full articles from URLs\n- Synthesize findings before presenting\n- Reference the web-search-and-fetch skill for search flags", temperature: 0.5 },
                    'security': { name: 'Security Expert', systemPrompt: "You are a WebX11 newOS4 security expert. You handle threat assessment, command control, and safety.\n\nAvailable commands: security, security-level, cmd-allow, cmd-deny, guardrail, guardrail-add, guardrail-remove, shadow, shadow-commit, shadow-rollback, health-check, check, logs, debug\n\nSkills available: security-and-safety (security levels, command blocking, safety checklist), debug-panel-and-logs (diagnostics, logging), system-maintenance (config, health checks)\n\nBehavior:\n- Always check current security level first with security\n- Use guardrail to inspect and manage security policies\n- Use shadow for safe execution of suspicious commands\n- Never recommend factory-reset without backup first\n- Use cmd-deny to block dangerous commands\n- Reference the security-and-safety skill for level descriptions", temperature: 0.2 }
                };
            }
            registerCommands() {
                this.commands['context'] = (args) => this.setContext(args);
                this.commands['contexts'] = () => this.listContexts();
                this.commands['context-new'] = (args) => this.createContext(args);
                this.commands['context-delete'] = (args) => this.deleteContext(args);
                this.commands['context-auto'] = (args) => this.toggleAutoRouting(args);
                this.commands['smart-ask'] = (args) => this.smartAsk(args);
            }
            setContext(args) {
                if (!args[0]) {
                    this.terminal.print(`Current context: ${this.activeProfile || 'none'}`, "info"); return;
                }
                if (this.contextProfiles[args[0]]) {
                    this.activeProfile = args[0];
                    this.saveActiveProfile();
                    this.terminal.print(`Context set to: ${this.contextProfiles[args[0]].name}`, "success");
                    // Also switch agent loop profile to match
                    const PROFILE_MAP = {
                        'coding': 'coder',
                        'debug': 'minimal',
                        'creative': 'creative',
                        'technical': 'research',
                        'chat': 'default',
                        'system-admin': 'safe',
                        'research': 'research',
                        'security': 'safe'
                    };
                    const targetLoop = PROFILE_MAP[args[0]];
                    if (targetLoop) {
                        const aiMod = this.terminal?.moduleManager?.modules?.WebX11AIAssistantModule;
                        if (aiMod && aiMod._switchLoopProfile) {
                            aiMod._switchLoopProfile(targetLoop);
                            this.terminal.print(`  Agent loop switched to: ${targetLoop}`, "text-muted");
                        }
                    } else {
                        // Custom profile — rebuild system prompt without loop switch
                        const aiMod = this.terminal?.moduleManager?.modules?.WebX11AIAssistantModule;
                        if (aiMod && aiMod.buildSystemPrompt) {
                            aiMod.systemPrompt = aiMod.buildSystemPrompt();
                        }
                        this.terminal.print(`  No agent loop mapped for '${args[0]}'`, "text-muted");
                    }
                } else {
                    this.terminal.print(`Profile '${args[0]}' not found`, "error");
                }
            }
            listContexts() {
                this.terminal.print("=== Context Profiles ===", "info");
                Object.entries(this.contextProfiles).forEach(([key, profile]) => {
                    const active = key === this.activeProfile ? ' ✅' : '';
                    this.terminal.print(`${key}: ${profile.name}${active}`);
                });
            }
            createContext(args) {
                if (args.length < 3) {
                    this.terminal.print("Usage: context-new <name> <displayName> <systemPrompt>", "warning"); return;
                }
                const name = args[0], displayName = args[1], systemPrompt = args.slice(2).join(' ');
                this.contextProfiles[name] = { name: displayName, systemPrompt, temperature: 0.7 };
                this.saveProfiles();
                this.terminal.print(`Context profile '${name}' created`, "success");
            }
            deleteContext(args) {
                if (!args[0]) {
                    this.terminal.print("Usage: context-delete <name>", "warning"); return;
                }
                if (this.contextProfiles[args[0]]) {
                    delete this.contextProfiles[args[0]];
                    this.saveProfiles();
                    if (this.activeProfile === args[0]) { this.activeProfile = null; }
                    this.terminal.print(`Context profile '${args[0]}' deleted`, "success");
                } else {
                    this.terminal.print(`Profile '${args[0]}' not found`, "error");
                }
            }
            // ─── Intent Detection Engine ───
            _getIntentPatterns() {
                return {
                    'coding': [
                        /^code\b/i, /\b(edit|fix|write|create|implement|refactor|build)\s+(module|function|class|file|code|script)/i,
                        /\b(debug|bug|error|fix)\s+(code|module|function|script)/i, /\b(implement|write|create)\s+(a\s+)?(function|class|module|command)/i,
                        /\b(refactor|rewrite|optimize)\s+(code|module|function)/i, /\b(add\s+)(feature|command|functionality)/i
                    ],
                    'debug': [
                        /^debug\b/i, /\b(error|crash|bug|fail|traceback|exception|broken|not working)\b/i,
                        /\b(why|what happened|diagnose|investigate|find out why)\b/i, /\b(check|inspect|examine)\s+(log|error|issue|problem)/i
                    ],
                    'research': [
                        /^research\b/i, /\b(search|find|look up|research|investigate|analyze)\b/i,
                        /\b(what is|how does|tell me about|explain)\b.*\?$/i, /\b(find|search)\s+(for\s+)?(information|docs|documentation|article)/i
                    ],
                    'creative': [
                        /^brainstorm\b/i, /\b(create|design|imagine|generate|compose|draft)\s+(story|poem|art|design|idea|concept|mindmap)/i,
                        /\b(creative|inspire|innovative|novel)\b/i
                    ],
                    'system-admin': [
                        /^(config|setup|install|deploy|backup|restore|security|monitor|maintenance)\b/i,
                        /\b(configure|setup|install|deploy|backup|restore)\s+(system|server|module|service)/i,
                        /\b(security|permission|access|block|allow)\b/i
                    ],
                    'chat': [
                        /^(hi|hello|hey|how are you|what's up|good morning|good evening)\b/i,
                        /^.{0,30}\?$/  // short questions
                    ]
                };
            }
            autoDetectIntent(text) {
                if (!text || typeof text !== 'string') return { profile: null, confidence: 0 };
                const patterns = this._getIntentPatterns();
                const scores = {};
                const lower = text.toLowerCase();

                for (const [profile, regexes] of Object.entries(patterns)) {
                    let matches = 0;
                    for (const re of regexes) {
                        if (re.test(text) || re.test(lower)) matches++;
                    }
                    if (matches > 0) scores[profile] = matches;
                }

                // Code snippet detection (bias toward coding)
                if (/[{([\s]*['"`]/.test(text) || /\b(function|class|const|let|var|import|export|=>)\b/.test(text)) {
                    scores['coding'] = (scores['coding'] || 0) + 2;
                }

                // Very short text → chat
                if (text.length < 15 && !scores['coding'] && !scores['debug']) {
                    scores['chat'] = (scores['chat'] || 0) + 1;
                }

                // Find best match
                let bestProfile = null;
                let bestScore = 0;
                let totalScore = 0;
                for (const [profile, score] of Object.entries(scores)) {
                    totalScore += score;
                    if (score > bestScore) { bestScore = score; bestProfile = profile; }
                }

                // Calculate confidence (0-100)
                const confidence = totalScore > 0 ? Math.round((bestScore / totalScore) * 100) : 0;

                return { profile: bestProfile, confidence };
            }
            autoRouteContext(text) {
                if (!text) return { switched: false, from: this.activeProfile, to: this.activeProfile, confidence: 0, reason: 'no input' };

                // Check if auto-routing is enabled
                const enabled = localStorage.getItem('webx11_context_auto') !== 'off';
                if (!enabled) return { switched: false, from: this.activeProfile, to: this.activeProfile, confidence: 0, reason: 'auto-routing disabled' };

                const result = this.autoDetectIntent(text);
                if (!result.profile || result.confidence < 70) {
                    return { switched: false, from: this.activeProfile, to: this.activeProfile, confidence: result.confidence, reason: 'confidence too low (<70%)' };
                }

                // Don't switch if already on the best profile
                if (result.profile === this.activeProfile) {
                    return { switched: false, from: this.activeProfile, to: this.activeProfile, confidence: result.confidence, reason: 'already on best profile' };
                }

                // Check if the target profile exists
                if (!this.contextProfiles[result.profile]) {
                    return { switched: false, from: this.activeProfile, to: this.activeProfile, confidence: result.confidence, reason: 'profile "' + result.profile + '" not found' };
                }

                // Switch
                const from = this.activeProfile;
                this.setContext([result.profile]);
                return { switched: true, from: from, to: result.profile, confidence: result.confidence, reason: 'intent detected' };
            }
            toggleAutoRouting(args) {
                const val = args && args[0] ? args[0].toLowerCase() : null;
                if (val === 'on' || val === 'true' || val === '1') {
                    localStorage.setItem('webx11_context_auto', 'on');
                    this.terminal.print('✅ Auto-routing enabled — context will switch based on intent', 'success');
                } else if (val === 'off' || val === 'false' || val === '0') {
                    localStorage.setItem('webx11_context_auto', 'off');
                    this.terminal.print('⛔ Auto-routing disabled — use context <name> to switch manually', 'warning');
                } else {
                    const current = localStorage.getItem('webx11_context_auto') !== 'off';
                    this.terminal.print('Auto-routing: ' + (current ? 'ON' : 'OFF'), 'info');
                    this.terminal.print('Usage: context-auto on|off', 'info');
                }
            }
            async smartAsk(args) {
                if (!args[0]) {
                    this.terminal.print("Usage: smart-ask <your-question>", "warning"); return;
                }
                let systemPrompt = "You are a helpful assistant.";
                let temperature = 0.7;
                if (this.activeProfile && this.contextProfiles[this.activeProfile]) {
                    const profile = this.contextProfiles[this.activeProfile];
                    systemPrompt = profile.systemPrompt;
                    temperature = profile.temperature || 0.7;
                    this.terminal.print(`Using context: ${profile.name} (temp: ${temperature})`, "info");
                }
                // Use agentic loop via the AI assistant module for tool-enabled responses
                const aiModule = this.terminal?.moduleManager?.modules?.WebX11AIAssistantModule;
                if (aiModule) {
                    // Set temperature on ollamaManager modelParams temporarily
                    const om = this.terminal?.ollamaManager;
                    if (!om) { this.terminal?.print('⚠️ Ollama manager not available', 'error'); return; }
                    const savedTemp = om.modelParams ? om.modelParams.temperature : undefined;
                    if (om.modelParams) {
                        om.modelParams.temperature = temperature;
                    }
                    try {
                        const messages = [
                            { role: 'system', content: systemPrompt },
                            { role: 'user', content: args.join(' ') }
                        ];
                        const result = await om.chatWithTools(messages, aiModule.getToolDefinitions());
                        if (result && result.message) {
                            this.terminal.printAIResponse(result.message.content || '(no response)');
                        } else if (result && result.error) {
                            this.terminal.print(`⚠️ AI error: ${result.error}`, 'error');
                        }
                    } finally {
                        if (om.modelParams && savedTemp !== undefined) {
                            om.modelParams.temperature = savedTemp;
                        }
                    }
                } else {
                    // Fallback: simple chat with temperature
                    const om = this.terminal.ollamaManager;
                    const fullPrompt = `${systemPrompt}\n\nUser: ${args.join(' ')}`;
                    await om.chat(fullPrompt);
                }
            }
        }