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:
@@ -21,6 +21,8 @@ import type { OpenClawAgentInfo } from './core/openclaw-agents.js';
|
||||
import { registerGatewayStartHook } from './hooks/gateway-start.js';
|
||||
import { registerGatewayStopHook } from './hooks/gateway-stop.js';
|
||||
import { Block as KBBlock } from './tools/kbblock.js';
|
||||
import { defaultFadeParams } from './tools/fade.js';
|
||||
import { bumpTurnForSession, currentTurnForSession } from './tools/turn-tracker.js';
|
||||
import { KBClient } from './tools/kbclient.js';
|
||||
import {
|
||||
type KBDeps,
|
||||
@@ -978,7 +980,7 @@ function register(api: PluginAPI): void {
|
||||
}
|
||||
},
|
||||
makeClient: (token: string) => new KBClient(kbBackendUrl, token),
|
||||
turnFor: () => 0,
|
||||
turnFor: (sessionId: string) => currentTurnForSession(sessionId),
|
||||
};
|
||||
|
||||
// Wrap each KB tool factory: pass ctx into execute so cache/evict can
|
||||
@@ -1003,7 +1005,12 @@ function register(api: PluginAPI): void {
|
||||
// <kb-block> subblock injection via before_prompt_build hook
|
||||
// (DESIGN-DYNAMIC-BLOCK.md §2 + §7: openclaw side uses
|
||||
// appendSystemContext since the hook can't replace baked-in
|
||||
// <available_skills> precisely). Empty block → no append.
|
||||
// <available_skills> precisely).
|
||||
//
|
||||
// Per-turn fade: bump the session turn counter, then tick
|
||||
// (dropping entries past the m% threshold) + renderFaded so the
|
||||
// rendered text shows accumulated underscore masking. The Plexum
|
||||
// mirror runs the same algorithm inside RenderDynamicSubblock.
|
||||
const apiOn = (api as any).on;
|
||||
if (typeof apiOn === 'function') {
|
||||
apiOn.call(
|
||||
@@ -1016,7 +1023,16 @@ function register(api: PluginAPI): void {
|
||||
let body = '';
|
||||
try {
|
||||
const block = KBBlock.open(agentId, sessionId);
|
||||
body = block.render();
|
||||
const turn = bumpTurnForSession(sessionId, block);
|
||||
const fadeParams = defaultFadeParams();
|
||||
const dropped = block.tick(turn, fadeParams);
|
||||
if (dropped.length > 0) {
|
||||
logger.info(
|
||||
`kb-block fade tick agent=${agentId} session=${sessionId} dropped=[${dropped.join(',')}]`,
|
||||
);
|
||||
block.save();
|
||||
}
|
||||
body = block.renderFaded(turn, fadeParams);
|
||||
} catch (err) {
|
||||
logger.warn(`kb-block render failed: ${err}`);
|
||||
return undefined;
|
||||
|
||||
Reference in New Issue
Block a user