Align the openclaw side of the dynamic-* tool family with the new
Plexum design (decision #31, 2026-06-04 revision):
- trim-tool-result → dynamic-trim (same on-wire schema; same semantics)
- Drop list-tool-results entirely. Agents find the opaque tool_call_id
by reading their own prior assistant message's toolCall block id
instead of querying a separate "directory" tool. This removes a
workflow-step prerequisite and matches how Anthropic-shaped APIs
surface tool_use ids to the model anyway.
- On agent_end drain, ALSO self-compact the dynamic-trim's own
tool_use.input: rewrite to {tool_call_id, _self_compacted: true}.
Without this the bulky `replacement` text sits duplicated — once in
the rewritten target tool_result, once in dynamic-trim's call input.
Picks up the selfCallId from openclaw's execute(toolCallId, ...) first
arg (was previously discarded as _id).
Cross-runtime contract: tool name, input schema, return shape, and
sentinel prefix ("[trimmed by self] ") match Plexum's dynamic-trim
in internal/dynmem/trim.go + internal/persistence/trim.go.
Sim e2e tested: dynamic-trim queues, agent_end drain rewrites both
the target tool_result content AND the trim call's tool_use input.
No takeover errors. trimmed_bytes positive on real workloads.
Two new openclaw tools that let an agent reclaim ctx tokens consumed by
past tool results once it has extracted what it needs:
list-tool-results — enumerates past toolResults in the agent's own
session jsonl (size, tool name, turns-ago, args summary, already-
trimmed flag); does NOT return content body
trim-tool-result — replaces a past toolResult's content[].text with a
short sentinel-tagged replacement, identified by tool_call_id
The actual file rewrite is deferred to the `agent_end` hook (drained
from an in-memory queue) because writing during tool execute() trips
openclaw's session-file fence (EmbeddedAttemptSessionTakeoverError) —
the fingerprint check around releaseForPrompt rejects third-party
writes. By agent_end the lock window is closed and the next turn's
fence baseline picks up our mutation cleanly.
Queue-time validation rejects bad tool_call_ids up-front so weak
models that confuse opaque call_function_*_N ids with topic/fact
numeric ids get a clear error instead of a silent skip at drain time.
install.mjs now auto-sets plugins.entries.padded-cell.hooks.
allowConversationAccess=true (required for the agent_end hook on
non-bundled plugins; without it the drain never fires and queued
trims rot in memory).
Sim-verified end-to-end: model dispatches trim, drain fires on
agent_end, next turn's list shows already_trimmed=true.