aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAgando <roduccomm@gmail.com>2026-10-18 16:30:46 +0200
committerAgando <roduccomm@gmail.com>2026-10-18 16:30:46 +0200
commitc011c40a42a1ef913ccd6bfd131864be11f9b669 (patch)
tree24a030e7400c3136a6ab2f6443193b658fa2a4db
parenteb888c1d4f13ce059694dc8a1b840429491fcb26 (diff)
newOS4 v4.6.30: per-agent session isolation (D1)
-rw-r--r--main.html6
-rw-r--r--modules/core/core-bundle.js24
-rw-r--r--modules/core/module-aiassist.js20
-rw-r--r--modules/core/module-loader.js2
-rw-r--r--modules/core/module-orchestrator.js4
5 files changed, 40 insertions, 16 deletions
diff --git a/main.html b/main.html
index fd0ba8c..b75ebf2 100644
--- a/main.html
+++ b/main.html
@@ -1349,13 +1349,13 @@
</script>
<!-- v4.5.63: A2A scratchpad fixes + agent-register arg fix -->
-<script src="modules/core/core-bundle.js?v=v4.6.29"></script>
+<script src="modules/core/core-bundle.js?v=v4.6.30"></script>
<!-- Async dependency-ordered module loader now only initializes terminal and loads optional ext modules -->
-<script src="modules/core/module-loader.js?v=v4.6.29"></script>
+<script src="modules/core/module-loader.js?v=v4.6.30"></script>
<!-- Critical ext bundle loads AFTER webx11 exists so registerModule calls work -->
-<script src="modules/ext/critical-ext-bundle.js?v=v4.6.29"></script>
+<script src="modules/ext/critical-ext-bundle.js?v=v4.6.30"></script>
<script>
// ═══ ONE TRUE VERSION SOURCE ═══
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