(name, args)
| 413 | // Wrapped with dedup (Feature 6): identical pure-tool calls within the recent |
| 414 | // window are short-circuited with a cached result. Disable with SMALLCODE_DEDUP=false. |
| 415 | async function executeTool(name, args) { |
| 416 | let dedup = null; |
| 417 | try { |
| 418 | const { getDedup, ToolDedup } = require('../src/tools/dedup'); |
| 419 | dedup = getDedup(); |
| 420 | const cached = dedup.lookup(name, args); |
| 421 | if (cached) return ToolDedup.markCached(cached); |
| 422 | } catch {} |
| 423 | |
| 424 | // Per-turn idempotent-write dedup: stop spirals where the model calls |
| 425 | // memory_remember (or memory_forget) with the same args repeatedly within |
| 426 | // a single turn. PURE_TOOLS dedup doesn't cover these — they DO mutate state |
| 427 | // and can't be cached across turns — but inside a turn they're idempotent |
| 428 | // and re-calling is always wasted work. |
| 429 | let writeSet = null; |
| 430 | try { |
| 431 | const { getIdempotentWriteSet } = require('../src/tools/dedup'); |
| 432 | writeSet = getIdempotentWriteSet(); |
| 433 | if (writeSet.has(name, args)) { |
| 434 | return writeSet.shortCircuitResult(name); |
| 435 | } |
| 436 | } catch {} |
| 437 | |
| 438 | const result = await _executeToolModule(name, args, { |
| 439 | _fullscreenRef, |
| 440 | mcpCall, |
| 441 | memoryStore, |
| 442 | pluginLoader, |
| 443 | mcpClient: (typeof mcpClient !== 'undefined' ? mcpClient : null), |
| 444 | flags, |
| 445 | config, |
| 446 | tui, |
| 447 | }); |
| 448 | |
| 449 | try { if (dedup) dedup.record(name, args, result); } catch {} |
| 450 | try { if (writeSet) writeSet.record(name, args, result); } catch {} |
| 451 | return result; |
| 452 | } |
| 453 | |
| 454 | // ─── COMPOUND TOOLS ────────────────────────────────────────────────────────── |
| 455 | // Tool definitions + routing loaded from bin/tools.js |
no test coverage detected