Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 24 additions & 3 deletions dist/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,16 @@ import { spawn } from "node:child_process";
// lifecycle logs are noisy in CLI context (printed to stderr before command output),
// so we downgrade them to debug level when running in CLI mode.
const isCliMode = () => process.env.OPENCLAW_CLI === "1";
// The host registers plugins in "cli-metadata" mode to collect the CLI command
// tree before any runtime exists; nothing registered there ever executes.
export function isCliMetadataRegistration(api) {
return api.registrationMode === "cli-metadata";
}
export const MEMORY_PRO_CLI_DESCRIPTOR = {
name: "memory-pro",
description: "Enhanced memory management commands (LanceDB Pro)",
hasSubcommands: true,
};
// register() can run several times per gateway boot (one per registration
// context) and once per CLI command; the dual-memory hint only needs to be
// taught once per process.
Expand Down Expand Up @@ -784,7 +794,14 @@ function asNonEmptyString(value) {
* expose it yet, so callers can fall back to the direct/oauth transport.
*/
export function resolveRuntimeLlmComplete(api) {
const runtimeLlm = api.runtime?.llm;
let runtimeLlm;
try {
runtimeLlm = api.runtime?.llm;
}
catch {
// Metadata-only registrations hand out a runtime that throws on access.
return undefined;
}
return typeof runtimeLlm?.complete === "function"
? runtimeLlm.complete.bind(runtimeLlm)
: undefined;
Expand Down Expand Up @@ -1991,7 +2008,11 @@ function _initPluginState(api) {
let smartExtractor = null;
let admissionController = null;
let admissionControllerReflectionLane = null;
if (config.smartExtraction !== false || config.admissionControl?.enabled === true) {
const cliMetadataRegistration = isCliMetadataRegistration(api);
if (cliMetadataRegistration) {
api.logger.debug("memory-lancedb-pro: cli-metadata registration; LLM client, smart extraction and admission wiring wait for the runtime registration");
}
if (!cliMetadataRegistration && (config.smartExtraction !== false || config.admissionControl?.enabled === true)) {
try {
const { llmClient, llmModel, llmModelExplicit, llmTimeoutMs, makeClientForModel } = buildMemoryLlmClient();
// Model resolution for admission calls: explicit admissionControl.model
Expand Down Expand Up @@ -2702,7 +2723,7 @@ const memoryLanceDBProPlugin = {
return undefined;
}
})() : undefined,
}), { commands: ["memory-pro"] });
}), { commands: [MEMORY_PRO_CLI_DESCRIPTOR.name], descriptors: [MEMORY_PRO_CLI_DESCRIPTOR] });
// ========================================================================
// Lifecycle Hooks
// ========================================================================
Expand Down
30 changes: 27 additions & 3 deletions index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,18 @@ import { spawn } from "node:child_process";
// so we downgrade them to debug level when running in CLI mode.
const isCliMode = () => process.env.OPENCLAW_CLI === "1";

// The host registers plugins in "cli-metadata" mode to collect the CLI command
// tree before any runtime exists; nothing registered there ever executes.
export function isCliMetadataRegistration(api: OpenClawPluginApi): boolean {
return (api as unknown as { registrationMode?: unknown }).registrationMode === "cli-metadata";
}

export const MEMORY_PRO_CLI_DESCRIPTOR = {
name: "memory-pro",
description: "Enhanced memory management commands (LanceDB Pro)",
hasSubcommands: true,
} as const;

// register() can run several times per gateway boot (one per registration
// context) and once per CLI command; the dual-memory hint only needs to be
// taught once per process.
Expand Down Expand Up @@ -1230,7 +1242,13 @@ function asNonEmptyString(value: unknown): string | undefined {
* expose it yet, so callers can fall back to the direct/oauth transport.
*/
export function resolveRuntimeLlmComplete(api: OpenClawPluginApi): RuntimeLlmCompleteFn | undefined {
const runtimeLlm = (api as unknown as { runtime?: { llm?: { complete?: unknown } } }).runtime?.llm;
let runtimeLlm: { complete?: unknown } | undefined;
try {
runtimeLlm = (api as unknown as { runtime?: { llm?: { complete?: unknown } } }).runtime?.llm;
} catch {
// Metadata-only registrations hand out a runtime that throws on access.
return undefined;
}
return typeof runtimeLlm?.complete === "function"
? (runtimeLlm.complete.bind(runtimeLlm) as RuntimeLlmCompleteFn)
: undefined;
Expand Down Expand Up @@ -2700,7 +2718,13 @@ function _initPluginState(api: OpenClawPluginApi): PluginSingletonState {
let smartExtractor: SmartExtractor | null = null;
let admissionController: AdmissionController | null = null;
let admissionControllerReflectionLane: AdmissionController | null = null;
if (config.smartExtraction !== false || config.admissionControl?.enabled === true) {
const cliMetadataRegistration = isCliMetadataRegistration(api);
if (cliMetadataRegistration) {
api.logger.debug(
"memory-lancedb-pro: cli-metadata registration; LLM client, smart extraction and admission wiring wait for the runtime registration",
);
}
if (!cliMetadataRegistration && (config.smartExtraction !== false || config.admissionControl?.enabled === true)) {
try {
const { llmClient, llmModel, llmModelExplicit, llmTimeoutMs, makeClientForModel } = buildMemoryLlmClient();

Expand Down Expand Up @@ -3590,7 +3614,7 @@ const memoryLanceDBProPlugin = {
} catch { return undefined; }
})() : undefined,
}),
{ commands: ["memory-pro"] },
{ commands: [MEMORY_PRO_CLI_DESCRIPTOR.name], descriptors: [MEMORY_PRO_CLI_DESCRIPTOR] },
);

// ========================================================================
Expand Down
7 changes: 7 additions & 0 deletions openclaw.plugin.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,13 @@
"cliCommand": "memory"
}
],
"cliCommands": [
{
"name": "memory-pro",
"description": "Enhanced memory management commands (LanceDB Pro)",
"hasSubcommands": true
}
],
"hooks": {
"allowConversationAccess": true
},
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@
"skills/**/*.md"
],
"scripts": {
"test": "node test/embedder-error-hints.test.mjs && node --test test/embedder-max-input-chars.test.mjs && node test/cjk-recursion-regression.test.mjs && node test/extraction-prompt-structural-noise.test.mjs && node test/i18n-memory-triggers.test.mjs && node test/migrate-legacy-schema.test.mjs && node --test test/config-session-strategy-migration.test.mjs && node --test test/scope-access-undefined.test.mjs && node --test test/reflection-bypass-hook.test.mjs && node --test test/reflection-unattributed-session-read.test.mjs && node --test test/smart-extractor-scope-filter.test.mjs && node --test test/store-empty-scope-filter.test.mjs && node --test test/recall-text-cleanup.test.mjs && node test/update-consistency-lancedb.test.mjs && node --test test/strip-envelope-metadata.test.mjs && node test/cli-smoke.mjs && node test/functional-e2e.mjs && node --test test/per-agent-auto-recall.test.mjs && node test/retriever-rerank-regression.mjs && node test/smart-memory-lifecycle.mjs && node test/smart-extractor-branches.mjs && node --test test/smart-extractor-noise-gating.test.mjs && node test/memory-capability-runtime.test.mjs && node --test test/startup-health-diagnostics.test.mjs && node test/corpus-indexer.test.mjs && node --test test/regex-fallback-bulk-store.test.mjs && node test/plugin-manifest-regression.mjs && node --test test/dreaming-engine.test.mjs && node --test test/session-summary-before-reset.test.mjs && node --test test/sync-plugin-version.test.mjs && node test/smart-metadata-v2.mjs && node test/vector-search-cosine.test.mjs && node test/context-support-e2e.mjs && node test/temporal-facts.test.mjs && node test/memory-update-supersede.test.mjs && node test/memory-update-metadata-refresh.test.mjs && node test/memory-upgrader-diagnostics.test.mjs && node --test test/llm-api-key-client.test.mjs && node --test test/llm-oauth-client.test.mjs && node --test test/cli-oauth-login.test.mjs && node --test test/workflow-fork-guards.test.mjs && node --test test/clawteam-scope.test.mjs && node --test test/cross-process-lock.test.mjs && node --test test/preference-slots.test.mjs && node test/is-latest-auto-supersede.test.mjs && node --test test/temporal-awareness.test.mjs && node --test test/command-reflection-guard.test.mjs && node --test test/tier1-counters.test.mjs && node --test test/startup-check-timeout.test.mjs && node --test test/memory-subsession-prompt-hooks.test.mjs && node --test test/read-consistency-interval.test.mjs && node --test test/reflection-distiller-hook-skip.test.mjs && node --test test/register-scope-dedup.test.mjs && node --test test/raw-run-distiller-hooks.test.mjs && node --test test/autocapture-watermark-reset.test.mjs && node --test test/autocapture-internal-session-guard.test.mjs && node --test test/memory-categories-storage-map.test.mjs && node --test test/delete-invalidate-reflection-caches.test.mjs && node --test test/reflection-mapped-rows-admission.test.mjs && node --test test/smart-metadata-source-classification.test.mjs && node --test test/reflection-embed-transient-retry.test.mjs && node --test test/scope-owner-leak-hardening.test.mjs && node --test test/isOwnedByAgent.test.mjs && node --test test/typed-array-vector-fetch.test.mjs && node --test test/extraction-grounding-register.test.mjs && node test/grounding-rejudge.test.mjs && node --test test/reverse-map-legacy-category.test.mjs && node --test test/reflection-mapped-category-stamping.test.mjs && node --test test/memory-upgrader-category-normalization.test.mjs && node --test test/autocapture-fallback-gating.test.mjs && node --test test/prompt-architecture.test.mjs && node test/extraction-category-rubric.test.mjs && node --test test/admission-control-batch-utility.test.mjs && node --test test/smart-extractor-batch-admission.test.mjs && node --test test/admission-control-prompt-shape.test.mjs && node --test test/smart-extractor-merge-accounting.test.mjs && node --test test/admission-utility-veto.test.mjs && node --test test/cli-subcommand-attachment.test.mjs && node --test test/admission-lane-model-affinity.test.mjs && node --test test/admission-model-resolution.test.mjs && node --test test/admission-controller-standalone.test.mjs && node --test test/smart-extractor-admission-controller-injection.test.mjs && node --test test/admission-without-smart-extraction.test.mjs && node --test test/llm-thinklevel.test.mjs && node --test test/memory-id-prefix-resolution.test.mjs && node --test test/manual-store-supersede.test.mjs && node --test test/extraction-transcript-speaker-tags.test.mjs && node --test test/session-compressor.test.mjs && node --test test/reflection-derived-cache-invalidation.test.mjs && node --test test/reflection-tagged-input.test.mjs && node --test test/reflection-mapped-uniform-pipeline.test.mjs && node --test test/llm-host-transport.test.mjs && node --test test/llm-host-transport-composition.test.mjs && node --test test/admission-control-host-transport.test.mjs && node --test test/llm-transport-credential-hygiene.test.mjs",
"test": "node test/embedder-error-hints.test.mjs && node --test test/embedder-max-input-chars.test.mjs && node test/cjk-recursion-regression.test.mjs && node test/extraction-prompt-structural-noise.test.mjs && node test/i18n-memory-triggers.test.mjs && node test/migrate-legacy-schema.test.mjs && node --test test/config-session-strategy-migration.test.mjs && node --test test/scope-access-undefined.test.mjs && node --test test/reflection-bypass-hook.test.mjs && node --test test/reflection-unattributed-session-read.test.mjs && node --test test/smart-extractor-scope-filter.test.mjs && node --test test/store-empty-scope-filter.test.mjs && node --test test/recall-text-cleanup.test.mjs && node test/update-consistency-lancedb.test.mjs && node --test test/strip-envelope-metadata.test.mjs && node test/cli-smoke.mjs && node test/functional-e2e.mjs && node --test test/per-agent-auto-recall.test.mjs && node test/retriever-rerank-regression.mjs && node test/smart-memory-lifecycle.mjs && node test/smart-extractor-branches.mjs && node --test test/smart-extractor-noise-gating.test.mjs && node test/memory-capability-runtime.test.mjs && node --test test/startup-health-diagnostics.test.mjs && node test/corpus-indexer.test.mjs && node --test test/regex-fallback-bulk-store.test.mjs && node test/plugin-manifest-regression.mjs && node --test test/dreaming-engine.test.mjs && node --test test/session-summary-before-reset.test.mjs && node --test test/sync-plugin-version.test.mjs && node test/smart-metadata-v2.mjs && node test/vector-search-cosine.test.mjs && node test/context-support-e2e.mjs && node test/temporal-facts.test.mjs && node test/memory-update-supersede.test.mjs && node test/memory-update-metadata-refresh.test.mjs && node test/memory-upgrader-diagnostics.test.mjs && node --test test/llm-api-key-client.test.mjs && node --test test/llm-oauth-client.test.mjs && node --test test/cli-oauth-login.test.mjs && node --test test/workflow-fork-guards.test.mjs && node --test test/clawteam-scope.test.mjs && node --test test/cross-process-lock.test.mjs && node --test test/preference-slots.test.mjs && node test/is-latest-auto-supersede.test.mjs && node --test test/temporal-awareness.test.mjs && node --test test/command-reflection-guard.test.mjs && node --test test/cli-metadata-registration.test.mjs && node --test test/tier1-counters.test.mjs && node --test test/startup-check-timeout.test.mjs && node --test test/memory-subsession-prompt-hooks.test.mjs && node --test test/read-consistency-interval.test.mjs && node --test test/reflection-distiller-hook-skip.test.mjs && node --test test/register-scope-dedup.test.mjs && node --test test/raw-run-distiller-hooks.test.mjs && node --test test/autocapture-watermark-reset.test.mjs && node --test test/autocapture-internal-session-guard.test.mjs && node --test test/memory-categories-storage-map.test.mjs && node --test test/delete-invalidate-reflection-caches.test.mjs && node --test test/reflection-mapped-rows-admission.test.mjs && node --test test/smart-metadata-source-classification.test.mjs && node --test test/reflection-embed-transient-retry.test.mjs && node --test test/scope-owner-leak-hardening.test.mjs && node --test test/isOwnedByAgent.test.mjs && node --test test/typed-array-vector-fetch.test.mjs && node --test test/extraction-grounding-register.test.mjs && node test/grounding-rejudge.test.mjs && node --test test/reverse-map-legacy-category.test.mjs && node --test test/reflection-mapped-category-stamping.test.mjs && node --test test/memory-upgrader-category-normalization.test.mjs && node --test test/autocapture-fallback-gating.test.mjs && node --test test/prompt-architecture.test.mjs && node test/extraction-category-rubric.test.mjs && node --test test/admission-control-batch-utility.test.mjs && node --test test/smart-extractor-batch-admission.test.mjs && node --test test/admission-control-prompt-shape.test.mjs && node --test test/smart-extractor-merge-accounting.test.mjs && node --test test/admission-utility-veto.test.mjs && node --test test/cli-subcommand-attachment.test.mjs && node --test test/admission-lane-model-affinity.test.mjs && node --test test/admission-model-resolution.test.mjs && node --test test/admission-controller-standalone.test.mjs && node --test test/smart-extractor-admission-controller-injection.test.mjs && node --test test/admission-without-smart-extraction.test.mjs && node --test test/llm-thinklevel.test.mjs && node --test test/memory-id-prefix-resolution.test.mjs && node --test test/manual-store-supersede.test.mjs && node --test test/extraction-transcript-speaker-tags.test.mjs && node --test test/session-compressor.test.mjs && node --test test/reflection-derived-cache-invalidation.test.mjs && node --test test/reflection-tagged-input.test.mjs && node --test test/reflection-mapped-uniform-pipeline.test.mjs && node --test test/llm-host-transport.test.mjs && node --test test/llm-host-transport-composition.test.mjs && node --test test/admission-control-host-transport.test.mjs && node --test test/llm-transport-credential-hygiene.test.mjs",
"test:cli-smoke": "node scripts/run-ci-tests.mjs --group cli-smoke",
"test:core-regression": "node scripts/run-ci-tests.mjs --group core-regression",
"test:storage-and-schema": "node scripts/run-ci-tests.mjs --group storage-and-schema",
Expand Down
1 change: 1 addition & 0 deletions scripts/ci-test-manifest.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,7 @@ export const CI_TEST_MANIFEST = [
// Issue #492 agentId validation tests
{ group: "core-regression", runner: "node", file: "test/agentid-validation.test.mjs", args: ["--test"] },
{ group: "core-regression", runner: "node", file: "test/command-reflection-guard.test.mjs", args: ["--test"] },
{ group: "core-regression", runner: "node", file: "test/cli-metadata-registration.test.mjs", args: ["--test"] },
// Tier 1 memory counter fix
{ group: "core-regression", runner: "node", file: "test/tier1-counters.test.mjs", args: ["--test"] },
{ group: "core-regression", runner: "node", file: "test/memory-subsession-prompt-hooks.test.mjs", args: ["--test"] },
Expand Down
Loading
Loading