File size: 2,936 Bytes
fc93158 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 | import type { OpenClawConfig } from "../config/config.js";
import { defaultSlotIdForKey } from "../plugins/slots.js";
import type { ContextEngine } from "./types.js";
/**
* A factory that creates a ContextEngine instance.
* Supports async creation for engines that need DB connections etc.
*/
export type ContextEngineFactory = () => ContextEngine | Promise<ContextEngine>;
// ---------------------------------------------------------------------------
// Registry (module-level singleton)
// ---------------------------------------------------------------------------
const CONTEXT_ENGINE_REGISTRY_STATE = Symbol.for("openclaw.contextEngineRegistryState");
type ContextEngineRegistryState = {
engines: Map<string, ContextEngineFactory>;
};
// Keep context-engine registrations process-global so duplicated dist chunks
// still share one registry map at runtime.
function getContextEngineRegistryState(): ContextEngineRegistryState {
const globalState = globalThis as typeof globalThis & {
[CONTEXT_ENGINE_REGISTRY_STATE]?: ContextEngineRegistryState;
};
if (!globalState[CONTEXT_ENGINE_REGISTRY_STATE]) {
globalState[CONTEXT_ENGINE_REGISTRY_STATE] = {
engines: new Map<string, ContextEngineFactory>(),
};
}
return globalState[CONTEXT_ENGINE_REGISTRY_STATE];
}
/**
* Register a context engine implementation under the given id.
*/
export function registerContextEngine(id: string, factory: ContextEngineFactory): void {
getContextEngineRegistryState().engines.set(id, factory);
}
/**
* Return the factory for a registered engine, or undefined.
*/
export function getContextEngineFactory(id: string): ContextEngineFactory | undefined {
return getContextEngineRegistryState().engines.get(id);
}
/**
* List all registered engine ids.
*/
export function listContextEngineIds(): string[] {
return [...getContextEngineRegistryState().engines.keys()];
}
// ---------------------------------------------------------------------------
// Resolution
// ---------------------------------------------------------------------------
/**
* Resolve which ContextEngine to use based on plugin slot configuration.
*
* Resolution order:
* 1. `config.plugins.slots.contextEngine` (explicit slot override)
* 2. Default slot value ("legacy")
*
* Throws if the resolved engine id has no registered factory.
*/
export async function resolveContextEngine(config?: OpenClawConfig): Promise<ContextEngine> {
const slotValue = config?.plugins?.slots?.contextEngine;
const engineId =
typeof slotValue === "string" && slotValue.trim()
? slotValue.trim()
: defaultSlotIdForKey("contextEngine");
const factory = getContextEngineRegistryState().engines.get(engineId);
if (!factory) {
throw new Error(
`Context engine "${engineId}" is not registered. ` +
`Available engines: ${listContextEngineIds().join(", ") || "(none)"}`,
);
}
return factory();
}
|