diff --git a/README.md b/README.md index d8a1ec9..0d5bd4e 100644 --- a/README.md +++ b/README.md @@ -334,6 +334,37 @@ Debugging no longer means probing an opaque database — it becomes a determinis | Hybrid retrieval | BM25 + vector + RRF — supports both keyword and semantic recall | | Agent tools | `tdai_memory_search` / `tdai_conversation_search` | +### Library Mode for Non-OpenClaw Hosts + +OpenClaw remains the default plugin entry point, but host-neutral embedders can +use the same core without depending on OpenClaw runtime APIs: + +```ts +import { TdaiCore, parseConfig } from "@tencentdb-agent-memory/memory-tencentdb/core" +import type { + CompletedTurn, + HostAdapter, +} from "@tencentdb-agent-memory/memory-tencentdb/core" + +const config = parseConfig({ + capture: { enabled: true }, + extraction: { enabled: false }, +}) + +const core = new TdaiCore({ + hostAdapter, + config, +}) +await core.initialize() +``` + +`TdaiCore` obtains model execution through +`HostAdapter.getLLMRunnerFactory()`, so the constructor only needs the adapter +and parsed config. + +For configuration-only integrations, import the parser from +`@tencentdb-agent-memory/memory-tencentdb/config`. + --- ## Documentation diff --git a/README_CN.md b/README_CN.md index 8698126..fd153ac 100644 --- a/README_CN.md +++ b/README_CN.md @@ -340,6 +340,36 @@ docker exec -it hermes-memory hermes | 混合检索 | BM25 + 向量 + RRF,兼顾关键词和语义召回 | | Agent 工具 | `tdai_memory_search` / `tdai_conversation_search` | +### 非 OpenClaw 宿主的 Library Mode + +OpenClaw 仍然是默认插件入口,但其他宿主可以复用同一套 +host-neutral core,而不需要依赖 OpenClaw runtime API: + +```ts +import { TdaiCore, parseConfig } from "@tencentdb-agent-memory/memory-tencentdb/core" +import type { + CompletedTurn, + HostAdapter, +} from "@tencentdb-agent-memory/memory-tencentdb/core" + +const config = parseConfig({ + capture: { enabled: true }, + extraction: { enabled: false }, +}) + +const core = new TdaiCore({ + hostAdapter, + config, +}) +await core.initialize() +``` + +`TdaiCore` 通过 `HostAdapter.getLLMRunnerFactory()` 获取模型执行器, +所以构造函数只需要 adapter 和解析后的 config。 + +如果只需要配置解析,可以从 +`@tencentdb-agent-memory/memory-tencentdb/config` 导入 `parseConfig`。 + --- ## 文档 diff --git a/package.json b/package.json index 2d74158..eaffc47 100644 --- a/package.json +++ b/package.json @@ -4,28 +4,28 @@ "description": "Four-layer local memory system plugin for OpenClaw — auto-captures, structures, and profiles conversational knowledge using local LLM + SQLite vector search (L0→L1→L2→L3 pipeline)", "type": "module", "main": "./dist/index.mjs", - "bin": { - "migrate-sqlite-to-tcvdb": "./bin/migrate-sqlite-to-tcvdb.mjs", - "export-tencent-vdb": "./bin/export-tencent-vdb.mjs", - "read-local-memory": "./bin/read-local-memory.mjs" - }, + "types": "./dist/index.d.mts", "exports": { ".": { + "types": "./dist/index.d.mts", "import": "./dist/index.mjs", "default": "./dist/index.mjs" + }, + "./core": { + "types": "./dist/core/index.d.mts", + "import": "./dist/core/index.mjs", + "default": "./dist/core/index.mjs" + }, + "./config": { + "types": "./dist/config.d.mts", + "import": "./dist/config.mjs", + "default": "./dist/config.mjs" } }, "scripts": { - "build": "npm run build:plugin && npm run build:scripts", + "build": "npm run build:plugin", "build:plugin": "tsdown", - "build:scripts": "npm run build:migrate-sqlite-to-vdb && npm run build:export-tencent-vdb && npm run build:read-local-memory", "prepack": "npm run build", - "build:migrate-sqlite-to-vdb": "tsc -p scripts/migrate-sqlite-to-tcvdb/tsconfig.json --noEmitOnError false", - "migrate-sqlite-to-tcvdb": "node ./bin/migrate-sqlite-to-tcvdb.mjs", - "build:export-tencent-vdb": "tsc --project scripts/export-tencent-vdb/tsconfig.json", - "export-tencent-vdb": "node ./bin/export-tencent-vdb.mjs", - "build:read-local-memory": "tsc --project scripts/read-local-memory/tsconfig.json", - "read-local-memory": "node ./bin/read-local-memory.mjs", "test": "vitest run", "test:watch": "vitest", "test:coverage": "vitest run --coverage", @@ -33,18 +33,14 @@ }, "files": [ "dist/", - "bin/", "index.ts", - "scripts/migrate-sqlite-to-tcvdb/dist/", - "scripts/export-tencent-vdb/dist/", - "scripts/read-local-memory/dist/", "scripts/memory-tencentdb-ctl.sh", "scripts/install_hermes_memory_tencentdb.sh", "scripts/README.memory-tencentdb-ctl.md", - "src/", "scripts/openclaw-after-tool-call-messages.patch.sh", "scripts/setup-offload.sh", "hermes-plugin/", + "!hermes-plugin/**/tests/", "openclaw.plugin.json", "README.md", "CHANGELOG.md", @@ -101,7 +97,7 @@ }, "openclaw": { "extensions": [ - "./index.ts" + "./dist/index.mjs" ], "compat": { "pluginApi": ">=2026.3.13", diff --git a/src/core/index.ts b/src/core/index.ts index a58b25a..8753f29 100644 --- a/src/core/index.ts +++ b/src/core/index.ts @@ -24,3 +24,21 @@ export type { // TdaiCore service facade export { TdaiCore } from "./tdai-core.js"; export type { TdaiCoreOptions } from "./tdai-core.js"; + +// Configuration parser used by host-neutral embedders. +export { parseConfig } from "../config.js"; +export type { + CaptureConfig, + EmbeddingConfig, + ExtractionConfig, + MemoryTdaiConfig, + BM25Config, + MemoryCleanupConfig, + OffloadConfig, + PersonaConfig, + PipelineTriggerConfig, + RecallConfig, + ReportConfig, + StandaloneLLMOverrideConfig, + TcvdbConfig, +} from "../config.js"; diff --git a/src/core/package-metadata.test.ts b/src/core/package-metadata.test.ts new file mode 100644 index 0000000..aad597a --- /dev/null +++ b/src/core/package-metadata.test.ts @@ -0,0 +1,25 @@ +import { existsSync } from "node:fs"; +import { resolve } from "node:path"; +import { describe, expect, it } from "vitest"; +import packageJson from "../../package.json" with { type: "json" }; + +const repoRoot = resolve(import.meta.dirname, "../.."); + +describe("npm package metadata", () => { + it("does not reference missing command-line binaries", () => { + for (const target of Object.values(packageJson.bin ?? {})) { + expect(existsSync(resolve(repoRoot, target))).toBe(true); + } + }); + + it("builds the publishable runtime without missing script tsconfigs", () => { + expect(packageJson.scripts.build).toBe("npm run build:plugin"); + expect(packageJson.scripts["build:scripts"]).toBeUndefined(); + }); + + it("publishes compiled runtime artifacts instead of duplicating source", () => { + expect(packageJson.files).toContain("dist/"); + expect(packageJson.files).not.toContain("src/"); + expect(packageJson.openclaw.extensions).toEqual(["./dist/index.mjs"]); + }); +}); diff --git a/src/core/public-exports.test.ts b/src/core/public-exports.test.ts new file mode 100644 index 0000000..91d5ac1 --- /dev/null +++ b/src/core/public-exports.test.ts @@ -0,0 +1,38 @@ +import { readFileSync } from "node:fs"; +import { resolve } from "node:path"; +import { describe, expect, it } from "vitest"; +import packageJson from "../../package.json" with { type: "json" }; +import { parseConfig, TdaiCore } from "./index.js"; + +const repoRoot = resolve(import.meta.dirname, "../.."); + +describe("library mode public exports", () => { + it("exposes host-neutral core and config subpaths", () => { + expect(packageJson.exports).toMatchObject({ + "./core": { + import: "./dist/core/index.mjs", + types: "./dist/core/index.d.mts", + }, + "./config": { + import: "./dist/config.mjs", + types: "./dist/config.d.mts", + }, + }); + }); + + it("keeps TdaiCore and parseConfig available from the core barrel", () => { + expect(typeof TdaiCore).toBe("function"); + expect(typeof parseConfig).toBe("function"); + expect(parseConfig({ extraction: { enabled: false } }).extraction.enabled).toBe(false); + }); + + it("documents TdaiCore construction through the HostAdapter contract", () => { + const readme = readFileSync(resolve(repoRoot, "README.md"), "utf8"); + const readmeCn = readFileSync(resolve(repoRoot, "README_CN.md"), "utf8"); + + expect(readme).not.toContain("llmRunnerFactory,"); + expect(readmeCn).not.toContain("llmRunnerFactory,"); + expect(readme).toContain("HostAdapter.getLLMRunnerFactory()"); + expect(readmeCn).toContain("HostAdapter.getLLMRunnerFactory()"); + }); +}); diff --git a/tsdown.config.ts b/tsdown.config.ts index 16b0073..eabbeeb 100644 --- a/tsdown.config.ts +++ b/tsdown.config.ts @@ -11,13 +11,17 @@ function collectExternalDependencies(): string[] { } export default defineConfig({ - entry: ["./index.ts"], + entry: { + index: "./index.ts", + "core/index": "./src/core/index.ts", + config: "./src/config.ts", + }, outDir: "./dist", format: "esm", platform: "node", clean: true, fixedExtension: true, - dts: false, + dts: true, sourcemap: false, deps: { neverBundle: (id) => {