Files
gbrain/src/openclaw-context-engine.ts
T
8f45624e55 v0.42.39.0 feat(context): Retrieval Reflex — teach the agent when/what to retrieve (#1981) (#2019)
* fix(integrations): parameterize resolver-row fence by recipe id

The install fence was hardcoded gbrain:agent-voice:resolver-rows, so any
second copy-into-host-repo recipe wrote a mislabeled block (and refresh/
uninstall keyed on recipe id would miss it). Derive it from manifest.recipe.

* feat(context): Retrieval Reflex — teach the agent when/what to retrieve (#1981)

Deterministic per-turn pointer layer in the context engine: a zero-LLM,
precision-biased scan resolves salient entities (names, @handles) to existing
brain pages and injects compact pointers (name → slug → safe synopsis). Detect
+ point, never auto-dump. Fail-open, capped, suppression on prior context only.

Engine-aware resolver ladder (no second DB connection): host ctx.brainQuery →
PGLite serve resolve IPC (unix socket) → Postgres cached direct → disabled.
Synopsis runs through get_page's privacy strip. Plus the retrieval-reflex recipe
+ policy skill, the retrieval_reflex_health doctor check, config gate, and the
init next-step hint.

* chore: bump version and changelog (v0.42.38.0)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* docs(architecture): KEY_FILES entries for Retrieval Reflex surface (#1981)

Document the new src/core/context/ modules, the context-engine resolver
ladder, the serve resolve IPC, the retrieval_reflex_health doctor check,
and the recipe-id-keyed install fence. Current-state only.

---------

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-10 21:12:33 -07:00

88 lines
3.2 KiB
TypeScript

/**
* OpenClaw plugin entry point for gbrain-context engine.
*
* Registers a deterministic context engine that injects live temporal/spatial
* context on every turn. Prevents the "time warp" bug class where compacted
* sessions lose track of the user's current time, location, and state.
*
* Enable in openclaw.json:
* plugins.slots.contextEngine: "gbrain-context"
*
* @module
*/
/**
* OpenClaw plugin entry — registers gbrain-context engine.
*
* This file is discovered via the `openclaw.extensions` field in package.json.
* It requires the OpenClaw plugin SDK at runtime (available when loaded by the
* gateway). The core engine logic in `./core/context-engine.ts` is SDK-free
* and independently testable.
*/
import { createGBrainContextEngine, ENGINE_ID } from './core/context-engine.ts';
import type { ResolveEntitiesFn } from './core/context/reflex.ts';
/**
* Plugin-entry shape consumed by the OpenClaw host. The host's plugin loader
* reads `id`, `name`, `description`, and `register` directly off the default
* export — pre-v0.32.5 we wrapped this in `definePluginEntry` from the
* OpenClaw plugin SDK, but that created an unnecessary build-time import of
* a runtime-only package. The wrapper was a type-tag (no behavior), so the
* bare object is equivalent at the host's consumption point. Codex outside-
* voice F1 flagged the SDK import as the gate keeping the e2e test brittle;
* removing it unblocks `mock.module()`-based plugin-shape testing AND removes
* a class of module-load failures in non-Node-resolving runtimes.
*/
interface PluginEntry {
id: string;
name: string;
description: string;
register(api: PluginApi): void;
}
interface PluginApi {
registerContextEngine(id: string, factory: (ctx: PluginCtx) => unknown): void;
}
interface PluginCtx {
workspaceDir: string;
/**
* Retrieval Reflex (#1981, D1=A): OPTIONAL host-provided resolve capability.
* When the OpenClaw host supplies it (backed by the gbrain connection the
* gateway already holds), the deterministic pointer layer resolves through it
* — works on every engine, including PGLite where a second connection is
* impossible. Narrow by contract: candidates in, a pointer block out (no raw
* SQL crosses the boundary). Absent → the engine falls to the serve-IPC /
* Postgres-direct ladder. Additive + guarded, so older hosts (which don't
* provide it) keep working unchanged — no pluginApi floor bump needed.
*/
resolveEntities?: ResolveEntitiesFn;
/** Back-compat alias some hosts may use for the same capability. */
brainQuery?: ResolveEntitiesFn;
[key: string]: unknown;
}
const entry: PluginEntry = {
id: 'gbrain-context-engine',
name: 'GBrain Context Engine',
description: 'Deterministic temporal/spatial context injection on every turn',
register(api: PluginApi) {
api.registerContextEngine(ENGINE_ID, (ctx: PluginCtx) => {
const hostResolver =
typeof ctx.resolveEntities === 'function'
? ctx.resolveEntities
: typeof ctx.brainQuery === 'function'
? ctx.brainQuery
: undefined;
return createGBrainContextEngine({
workspaceDir: ctx.workspaceDir,
resolveEntities: hostResolver,
});
});
},
};
export default entry;