diff options
Diffstat (limited to 'modules/core/core-bundle.js')
| -rw-r--r-- | modules/core/core-bundle.js | 36 |
1 files changed, 35 insertions, 1 deletions
diff --git a/modules/core/core-bundle.js b/modules/core/core-bundle.js index 6022a37..5bbc840 100644 --- a/modules/core/core-bundle.js +++ b/modules/core/core-bundle.js @@ -8030,6 +8030,14 @@ class ServerMonitorModule { this.systemPrompt = this.buildSystemPrompt(); this.context = []; this.maxContext = 10; this._sessions = new Map(); // agentTag -> {context, profile}; 'main' aliases this.context + this._toolCache = new Map(); // D2: key -> {result, ts, epoch} + this._toolEpoch = 0; + this._mutatingTools = new Set(['write_file', 'edit_module', 'run_command', 'delete_file', + 'make_directory', 'commit_module', 'ship_module', 'patch_skill', 'delegate_task', + 'reload_module', 'create_skill']); + // Only deterministic reads are cached — never status/log/polling tools. + this._cacheableTools = new Set(['read_file', 'list_files', 'list_modules', 'view_module', + 'nvfs_resolve', 'get_help', 'list_skills', 'diff_module', 'get_module_status']); this.maxContextTokens = 2000; this.MAX_TOOL_TURNS = 8; this._pendingConfirmation = null; @@ -8783,6 +8791,23 @@ buildSystemPrompt() { this.commands['vaultmind-query'] = (args) => this._vaultmindQueryCmd(args); this.commands['wallet-lookup'] = (args) => this._walletLookupCmd(args); } + _cacheGet(name, args) { + const key = name + ':' + (typeof args === 'string' ? args : JSON.stringify(args || {})); + if (!this._cacheableTools.has(name)) return { hit: false, key: key }; + const e = this._toolCache.get(key); + if (e && e.epoch === this._toolEpoch && (Date.now() - e.ts) < 30000) { + return { hit: true, key: key, result: e.result }; + } + return { hit: false, key: key }; + } + _cacheSet(name, key, result) { + if (this._mutatingTools.has(name)) { this._toolEpoch++; return; } // invalidate all + if (!this._cacheableTools.has(name) || !key || typeof result !== 'string') return; + this._toolCache.set(key, { result: result, ts: Date.now(), epoch: this._toolEpoch }); + if (this._toolCache.size > 200) { + this._toolCache.delete(this._toolCache.keys().next().value); + } + } _sessionCtx(tag) { const k = tag || 'main'; // main is always the live this.context (commands like `ai-clear`/`load` reassign it) @@ -9500,7 +9525,15 @@ buildSystemPrompt() { for (const tc of safeTools) { const fn = tc.function; const t0 = Date.now(); - const toolResult = await this.runTool(fn.name, fn.arguments); + const _cg = this._cacheGet(fn.name, fn.arguments); + let toolResult; + if (_cg.hit) { + toolResult = _cg.result; + this.terminal.print(`♻️ ${fn.name} → cached (${toolResult.length}b, not re-run)`, 'info'); + } else { + toolResult = await this.runTool(fn.name, fn.arguments); + this._cacheSet(fn.name, _cg.key, toolResult); + } const t1 = Math.round((Date.now() - t0) / 1000); this._toolCallLog.push({ turn: toolTurns, @@ -9581,6 +9614,7 @@ buildSystemPrompt() { const t0 = Date.now(); this.terminal.print(`🔧 Tool: ${fn.name}(${typeof fn.arguments === 'string' ? fn.arguments : JSON.stringify(fn.arguments)})`, 'info'); const toolResult = await this.runTool(fn.name, fn.arguments); + this._toolEpoch++; // D2: mutating action invalidates every cached read const t1 = Math.round((Date.now() - t0) / 1000); this._toolCallLog.push({ turn: toolTurns, |