diff options
| author | Agando <roduccomm@gmail.com> | 2026-10-18 16:30:46 +0200 |
|---|---|---|
| committer | Agando <roduccomm@gmail.com> | 2026-10-18 16:30:46 +0200 |
| commit | 4de231bc9a869ef5049224ad43e2200a882b424c (patch) | |
| tree | f0fe4789dce59bac6e3f24f643fc69b163ca27f4 /modules/core | |
| parent | c2863016f1708e4638640aac38d4cbadd495dbde (diff) | |
newOS4 v4.6.30: per-agent session isolation (D1)
Diffstat (limited to 'modules/core')
| -rw-r--r-- | modules/core/core-bundle.js | 24 | ||||
| -rw-r--r-- | modules/core/module-aiassist.js | 20 | ||||
| -rw-r--r-- | modules/core/module-loader.js | 2 | ||||
| -rw-r--r-- | modules/core/module-orchestrator.js | 4 |
4 files changed, 37 insertions, 13 deletions
diff --git a/modules/core/core-bundle.js b/modules/core/core-bundle.js index ddfad31..6022a37 100644 --- a/modules/core/core-bundle.js +++ b/modules/core/core-bundle.js @@ -8029,6 +8029,7 @@ class ServerMonitorModule { }; this.terminal = null; this.systemPrompt = this.buildSystemPrompt(); this.context = []; this.maxContext = 10; + this._sessions = new Map(); // agentTag -> {context, profile}; 'main' aliases this.context this.maxContextTokens = 2000; this.MAX_TOOL_TURNS = 8; this._pendingConfirmation = null; @@ -8782,6 +8783,13 @@ buildSystemPrompt() { this.commands['vaultmind-query'] = (args) => this._vaultmindQueryCmd(args); this.commands['wallet-lookup'] = (args) => this._walletLookupCmd(args); } + _sessionCtx(tag) { + const k = tag || 'main'; + // main is always the live this.context (commands like `ai-clear`/`load` reassign it) + if (k === 'main') return { context: this.context, profile: null }; + if (!this._sessions.has(k)) this._sessions.set(k, { context: [], profile: null }); + return this._sessions.get(k); + } async chat(args, opts = {}) { const userMessage = args.join(' '); if (!userMessage) { @@ -8816,12 +8824,14 @@ buildSystemPrompt() { this._loadContext(); // Compress context if it exceeds the token threshold this._compressContext(); + // Per-agent session: 'main' aliases this.context, agents get their own history. + const sess = this._sessionCtx(opts.agentTag); let loopResult; try { const messages = [ { role: 'system', content: this.systemPrompt } ]; - this.context.slice().forEach(msg => messages.push(msg)); + sess.context.slice().forEach(msg => messages.push(msg)); messages.push({ role: 'user', content: userMessage }); this.terminal.print('🤖 WebX11AI thinking...', 'info'); // Auto-load skills relevant to the user's query (awaited, not fire-and-forget) @@ -8884,12 +8894,12 @@ buildSystemPrompt() { } catch (e) { /* world model not available */ } loopResult = await this.agenticLoop(messages, opts); - this.context.push({ role: 'user', content: userMessage }); + sess.context.push({ role: 'user', content: userMessage }); if (loopResult.finalAnswer) { - this.context.push({ role: 'assistant', content: loopResult.finalAnswer }); + sess.context.push({ role: 'assistant', content: loopResult.finalAnswer }); } - if (this.context.length > this.maxContext * 2) { - this.context = this.context.slice(-this.maxContext * 2); + if (sess.context.length > this.maxContext * 2) { + sess.context.splice(0, sess.context.length - this.maxContext * 2); } // Reflection: after complex tasks, run health scan and auto-skill creation if (loopResult.toolTurns >= 2 && !this._cancelled) { @@ -15962,7 +15972,9 @@ class OrchestratorModule { try { const aiModule = this.terminal.moduleManager.modules['WebX11AIAssistantModule']; if (aiModule && typeof aiModule.chat === 'function') { - const result = await aiModule.chat([`[DELEGATED] ${task}`], { agentTag: agent.id + '/' + (agent.role || 'worker') }); + const _agentTag = agent.id + '/' + (agent.role || 'worker'); + const result = await aiModule.chat([`[DELEGATED] ${task}`], { agentTag: _agentTag }); + try { aiModule._sessions.delete(_agentTag); } catch (_e) {} agent.status = 'completed'; // Write result to outbox diff --git a/modules/core/module-aiassist.js b/modules/core/module-aiassist.js index 96f822d..74a071b 100644 --- a/modules/core/module-aiassist.js +++ b/modules/core/module-aiassist.js @@ -6,6 +6,7 @@ }; this.terminal = null; this.systemPrompt = this.buildSystemPrompt(); this.context = []; this.maxContext = 10; + this._sessions = new Map(); // agentTag -> {context, profile}; 'main' aliases this.context this.maxContextTokens = 2000; this.MAX_TOOL_TURNS = 8; this._pendingConfirmation = null; @@ -759,6 +760,13 @@ buildSystemPrompt() { this.commands['vaultmind-query'] = (args) => this._vaultmindQueryCmd(args); this.commands['wallet-lookup'] = (args) => this._walletLookupCmd(args); } + _sessionCtx(tag) { + const k = tag || 'main'; + // main is always the live this.context (commands like `ai-clear`/`load` reassign it) + if (k === 'main') return { context: this.context, profile: null }; + if (!this._sessions.has(k)) this._sessions.set(k, { context: [], profile: null }); + return this._sessions.get(k); + } async chat(args, opts = {}) { const userMessage = args.join(' '); if (!userMessage) { @@ -793,12 +801,14 @@ buildSystemPrompt() { this._loadContext(); // Compress context if it exceeds the token threshold this._compressContext(); + // Per-agent session: 'main' aliases this.context, agents get their own history. + const sess = this._sessionCtx(opts.agentTag); let loopResult; try { const messages = [ { role: 'system', content: this.systemPrompt } ]; - this.context.slice().forEach(msg => messages.push(msg)); + sess.context.slice().forEach(msg => messages.push(msg)); messages.push({ role: 'user', content: userMessage }); this.terminal.print('🤖 WebX11AI thinking...', 'info'); // Auto-load skills relevant to the user's query (awaited, not fire-and-forget) @@ -861,12 +871,12 @@ buildSystemPrompt() { } catch (e) { /* world model not available */ } loopResult = await this.agenticLoop(messages, opts); - this.context.push({ role: 'user', content: userMessage }); + sess.context.push({ role: 'user', content: userMessage }); if (loopResult.finalAnswer) { - this.context.push({ role: 'assistant', content: loopResult.finalAnswer }); + sess.context.push({ role: 'assistant', content: loopResult.finalAnswer }); } - if (this.context.length > this.maxContext * 2) { - this.context = this.context.slice(-this.maxContext * 2); + if (sess.context.length > this.maxContext * 2) { + sess.context.splice(0, sess.context.length - this.maxContext * 2); } // Reflection: after complex tasks, run health scan and auto-skill creation if (loopResult.toolTurns >= 2 && !this._cancelled) { diff --git a/modules/core/module-loader.js b/modules/core/module-loader.js index 8a2df64..0674d07 100644 --- a/modules/core/module-loader.js +++ b/modules/core/module-loader.js @@ -4,7 +4,7 @@ // Core module bundle loaded synchronously in main.html. // This loader only handles version cache-busting, splash, terminal init, and optional ext modules. - const LATEST_VER = 'v4.6.29'; + const LATEST_VER = 'v4.6.30'; const CACHE = '?v=' + LATEST_VER; const stored = localStorage.getItem('webx11_cache_ver'); if (stored !== LATEST_VER) { diff --git a/modules/core/module-orchestrator.js b/modules/core/module-orchestrator.js index b695974..5cff89e 100644 --- a/modules/core/module-orchestrator.js +++ b/modules/core/module-orchestrator.js @@ -1150,7 +1150,9 @@ class OrchestratorModule { try { const aiModule = this.terminal.moduleManager.modules['WebX11AIAssistantModule']; if (aiModule && typeof aiModule.chat === 'function') { - const result = await aiModule.chat([`[DELEGATED] ${task}`], { agentTag: agent.id + '/' + (agent.role || 'worker') }); + const _agentTag = agent.id + '/' + (agent.role || 'worker'); + const result = await aiModule.chat([`[DELEGATED] ${task}`], { agentTag: _agentTag }); + try { aiModule._sessions.delete(_agentTag); } catch (_e) {} agent.status = 'completed'; // Write result to outbox |