feat(kb): wire kb-block fade into before_prompt_build

The previous commit shipped renderFaded + tick + seed on Block but
left them dead code because openclaw's `before_prompt_build` hook
ctx doesn't carry a currentTurn signal — the hook called plain
render() and turnFor() returned 0, so add() always stamped
last_refresh_at_turn=0 and fade distance never moved.

This adds a small per-session turn tracker (tools/turn-tracker.ts)
that the hook bumps each fire. On the first bump after plugin start
the counter is seeded from max(entry.last_refresh_at_turn) on the
loaded block, so a restart doesn't regress accumulated fade for
surviving entries. dynamic-kb-cache now reads currentTurnForSession
via the same counter so a fact cached on turn N reads back at d=0
on turn N+1.

The hook now: bumps turn, ticks (drop entries past the m% threshold,
log + save when anything drops), and renderFaded() into
appendSystemContext. Same algorithm as the Plexum-side
RenderDynamicSubblock path.

KBDeps.turnFor signature changed from (agentId) → (sessionId) since
turn is session-scoped — fixed the one cache-tool call site.

Verified end-to-end with a standalone smoke replaying the full
hook+tool flow against a temp profile: stale entry (d=201) drops on
turn 1, fresh entry (d=1) survives untouched, restart re-seeds the
counter from the surviving entry's last_refresh.
This commit is contained in:
h z
2026-06-06 01:06:30 +01:00
parent db323a2118
commit 70b0ccb7d2
4 changed files with 96 additions and 14 deletions

View File

@@ -9,11 +9,11 @@
// <OPENCLAW_PATH>/agents/<agentId>/sessions/<sessionId>/plugins/
// harbor-forge/kb-block.json
//
// Fade algorithm + types are implemented (see fade.ts + renderFaded /
// tick methods), but the openclaw `before_prompt_build` hook ctx
// doesn't currently expose currentTurn to plugins. Plain render() (no
// fade) is used in the hook for v1; renderFaded scaffolding stays for
// when turn signal lands. Plexum side fully wires fade per turn.
// Fade algorithm wired in v0.3 via turn-tracker.ts: the
// before_prompt_build hook bumps a per-session counter (seeded from
// max(entry.last_refresh_at_turn) on the first touch after plugin
// restart) and calls tick() + renderFaded() each turn. The Plexum
// mirror runs the same algorithm inside RenderDynamicSubblock.
import * as fs from 'node:fs';
import * as os from 'node:os';
@@ -149,9 +149,8 @@ export class Block {
/**
* RenderFaded mirrors render() but applies fade() per entry given
* currentTurn + params. Available for callers that have turn signal
* (Plexum side does; openclaw `before_prompt_build` hook doesn't
* currently — uses plain render()).
* currentTurn + params. Used by the before_prompt_build hook (turn
* source: tools/turn-tracker.ts).
*/
renderFaded(currentTurn: number, params: FadeParams): string {
return this.renderInner((e) => fade(e.content, e.seed, currentTurn - e.last_refresh_at_turn, params).rendered);