feat(dynamic-tools-cache): 4 cache tools + global __padded API

Implements the openclaw side of Plexum decision #37: agent-driven
per-session whitelist of which tools the model sees. Cross-runtime
aligned with Plexum's host implementation (same tool names, same
input schemas, takes-effect-next-turn).

New surface:
  - tools/dynamic-tools-cache.ts:
      Catalog (in-memory map), Cache file (atomic tmp+rename at
      <openclaw>/agents/<id>/sessions/<sid>/dynamic-tools-cache.json),
      4 tool factories (list/search/cache/evict), allowTool gate,
      installGlobalApi for globalThis.__padded with buffer-drain
  - index.ts: install __padded early; register the 4 cache tools
    as factories wrapping ctx into execute
  - openclaw.plugin.json contracts.tools += 4 names

Other Hangman-Lab plugins (Fabric / HF / Dialectic) opt in to the
gate by wrapping their registerTool calls (separate commits in those
repos). Built-in openclaw tools and non-opt-in plugins remain
always-on.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
h z
2026-06-05 15:38:26 +01:00
parent a7ee414bca
commit a39fe5c2d0
3 changed files with 442 additions and 1 deletions

View File

@@ -12,6 +12,13 @@ import {
queueDynamicTrim,
drainTrimQueueForSession,
} from './tools/session-rewrite.js';
import {
installGlobalApi as installPaddedGlobalApi,
createListToolsTool,
createSearchToolsTool,
createCacheToolsTool,
createEvictToolsTool,
} from './tools/dynamic-tools-cache.js';
import {
safeRestart,
createSafeRestartTool,
@@ -51,6 +58,12 @@ function register(api: OpenClawPluginApi): void {
logger.info('PaddedCell plugin initializing...');
// Install globalThis.__padded EARLY so other plugins loaded after
// PaddedCell can register catalog entries / query allowTool. Plugins
// loaded BEFORE PaddedCell can pre-fill _pendingCatalog on a stub;
// installGlobalApi drains it.
installPaddedGlobalApi();
const pluginConfig = getPluginConfig(api);
const openclawPath = resolveOpenclawPath(pluginConfig as { openclawProfilePath?: string });
const proxyAllowlist = resolveProxyAllowlist(pluginConfig as { proxyAllowlist?: unknown; 'proxy-allowlist'?: unknown });
@@ -241,6 +254,27 @@ function register(api: OpenClawPluginApi): void {
} as any;
});
// dynamic-{list,search,cache,evict}-tools — per-session tools-cache
// family (cross-runtime alignment with Plexum decision #37). All four
// are essentials (always exposed). The cache they manage gates other
// opt-in plugins via globalThis.__padded.allowTool — see
// tools/dynamic-tools-cache.ts and plans/OPENCLAW_TOOLS_FILTER_HOOK.md.
const cacheToolFactories = [
createListToolsTool,
createSearchToolsTool,
createCacheToolsTool,
createEvictToolsTool,
];
for (const make of cacheToolFactories) {
api.registerTool((ctx) => {
const tool = make();
const inner = tool.execute;
tool.execute = async (callId: string, params: any) =>
inner(callId, params, { agentId: ctx.agentId, sessionId: ctx.sessionId });
return tool;
});
}
// Register /ego-mgr slash command if the host exposes the (non-standard) hook.
// This API is not part of the current OpenClawPluginApi surface; the guard
// makes the plugin a no-op for slash commands when the host doesn't support