From a710fa40d2e150130b7c42e96236764538200ecf Mon Sep 17 00:00:00 2001 From: xiayu Date: Tue, 23 Jun 2026 19:52:42 +0800 Subject: [PATCH 1/3] fix: support lancedb memory backend manifest --- .../memory_backend/manifest.py | 2 +- .../memory_backend/providers/__init__.py | 3 +- .../memory_backend/providers/lancedb.py | 34 +++++++++++ .../memory_backend/registry.py | 2 + ksadk_runtime_common/memory_backend/render.py | 2 +- .../memory_backend_manifest.schema.json | 33 +++++++++-- tests/test_runtime_common_memory_backend.py | 58 ++++++++++++++++++- 7 files changed, 124 insertions(+), 10 deletions(-) create mode 100644 ksadk_runtime_common/memory_backend/providers/lancedb.py diff --git a/ksadk_runtime_common/memory_backend/manifest.py b/ksadk_runtime_common/memory_backend/manifest.py index b91911c1..27be2c68 100644 --- a/ksadk_runtime_common/memory_backend/manifest.py +++ b/ksadk_runtime_common/memory_backend/manifest.py @@ -19,7 +19,7 @@ class MemoryBackendManifest(BaseModel): """Memory backend manifest for OpenClaw runtime.""" schema_version: Literal["v1"] = "v1" - backend_type: Literal["openclaw_default", "mem0"] + backend_type: Literal["openclaw_default", "mem0", "lancedb"] config: dict[str, Any] = Field(default_factory=dict) secrets_env: dict[str, str] = Field(default_factory=dict) diff --git a/ksadk_runtime_common/memory_backend/providers/__init__.py b/ksadk_runtime_common/memory_backend/providers/__init__.py index 2686427e..d6c894e9 100644 --- a/ksadk_runtime_common/memory_backend/providers/__init__.py +++ b/ksadk_runtime_common/memory_backend/providers/__init__.py @@ -1,5 +1,6 @@ """Memory backend providers package.""" +from ksadk_runtime_common.memory_backend.providers.lancedb import LanceDBProvider from ksadk_runtime_common.memory_backend.providers.mem0 import Mem0Provider -__all__ = ["Mem0Provider"] +__all__ = ["LanceDBProvider", "Mem0Provider"] diff --git a/ksadk_runtime_common/memory_backend/providers/lancedb.py b/ksadk_runtime_common/memory_backend/providers/lancedb.py new file mode 100644 index 00000000..47bea3df --- /dev/null +++ b/ksadk_runtime_common/memory_backend/providers/lancedb.py @@ -0,0 +1,34 @@ +"""LanceDB memory backend provider.""" + +from __future__ import annotations + +from typing import Any + +from ksadk_runtime_common.memory_backend.manifest import MemoryBackendManifest +from ksadk_runtime_common.memory_backend.registry import RenderResult + + +class LanceDBProvider: + """Provider for the in-process LanceDB OpenClaw memory plugin.""" + + def render(self, manifest: MemoryBackendManifest) -> RenderResult: + """Render LanceDB plugin config for OpenClaw.""" + entry: dict[str, Any] = {"enabled": True} + if manifest.config: + entry["config"] = dict(manifest.config) + + return RenderResult( + backend_type="lancedb", + config_patch={ + "plugins": { + "slots": { + "memory": "memory-lancedb", + }, + "entries": { + "memory-lancedb": entry, + }, + }, + }, + plugin_ids=["memory-lancedb"], + disabled_plugin_ids=["openclaw-mem0"], + ) diff --git a/ksadk_runtime_common/memory_backend/registry.py b/ksadk_runtime_common/memory_backend/registry.py index dfd36884..816eec04 100644 --- a/ksadk_runtime_common/memory_backend/registry.py +++ b/ksadk_runtime_common/memory_backend/registry.py @@ -47,8 +47,10 @@ def list_providers() -> list[str]: def _register_builtin_providers() -> None: """Register providers shipped in this repo copy.""" from ksadk_runtime_common.memory_backend.providers.mem0 import Mem0Provider + from ksadk_runtime_common.memory_backend.providers.lancedb import LanceDBProvider register_provider("mem0", Mem0Provider()) + register_provider("lancedb", LanceDBProvider()) _register_builtin_providers() diff --git a/ksadk_runtime_common/memory_backend/render.py b/ksadk_runtime_common/memory_backend/render.py index 88938414..72299200 100644 --- a/ksadk_runtime_common/memory_backend/render.py +++ b/ksadk_runtime_common/memory_backend/render.py @@ -17,7 +17,7 @@ ) MANIFEST_ENV_VAR = "MEMORY_BACKEND_MANIFEST" -MEMORY_BACKEND_PLUGIN_IDS = ["openclaw-mem0"] +MEMORY_BACKEND_PLUGIN_IDS = ["openclaw-mem0", "memory-lancedb"] MEMORY_BACKEND_PLUGIN_SLOTS = ["memory"] diff --git a/ksadk_runtime_common/schemas/memory_backend_manifest.schema.json b/ksadk_runtime_common/schemas/memory_backend_manifest.schema.json index 89b9d29f..a4577877 100644 --- a/ksadk_runtime_common/schemas/memory_backend_manifest.schema.json +++ b/ksadk_runtime_common/schemas/memory_backend_manifest.schema.json @@ -1,10 +1,13 @@ { "$schema": "https://json-schema.org/draft/2020-12/schema", - "$id": "https://kingsoftcloud.github.io/ksadk-python/schemas/agentengine/memory_backend_manifest/v1", + "$id": "https://ezone.ksyun.com/schemas/agentengine/memory_backend_manifest/v1", "title": "MemoryBackendManifest", "description": "Memory backend manifest for OpenClaw runtime configuration.", "type": "object", - "required": ["schema_version", "backend_type"], + "required": [ + "schema_version", + "backend_type" + ], "additionalProperties": false, "properties": { "schema_version": { @@ -14,8 +17,12 @@ }, "backend_type": { "type": "string", - "enum": ["openclaw_default", "mem0"], - "description": "Memory backend type. v1 only supports 'openclaw_default' and 'mem0'." + "enum": [ + "openclaw_default", + "mem0", + "lancedb" + ], + "description": "Memory backend type. Supports 'openclaw_default', 'mem0', and 'lancedb'." }, "config": { "type": "object", @@ -34,6 +41,20 @@ "mem0_region": { "type": "string", "description": "Mem0 instance region." + }, + "dbPath": { + "type": "string", + "description": "Optional LanceDB plugin dbPath override." + }, + "embedding": { + "type": "object", + "description": "Optional LanceDB plugin embedding configuration.", + "additionalProperties": true + }, + "storageOptions": { + "type": "object", + "description": "Optional LanceDB plugin storage options.", + "additionalProperties": true } } }, @@ -51,6 +72,10 @@ "memory_id": { "type": "string", "description": "Environment variable name for memory ID (e.g., 'MEM0_MEMORY_ID')." + }, + "embedding_api_key": { + "type": "string", + "description": "Reserved for future LanceDB embedding secrets." } } } diff --git a/tests/test_runtime_common_memory_backend.py b/tests/test_runtime_common_memory_backend.py index cad35ea3..ca1da26b 100644 --- a/tests/test_runtime_common_memory_backend.py +++ b/tests/test_runtime_common_memory_backend.py @@ -38,7 +38,7 @@ def test_render_openclaw_default_manifest_returns_empty_patch(): "config_patch": {}, "required_env": [], "plugin_ids": [], - "disabled_plugin_ids": ["openclaw-mem0"], + "disabled_plugin_ids": ["openclaw-mem0", "memory-lancedb"], "clear_plugin_slots": ["memory"], } @@ -68,7 +68,7 @@ def test_render_mem0_manifest_to_openclaw_patch(monkeypatch): f"2000104981.{VALID_MEM0_UUID}:mem0-secret", ) monkeypatch.setenv("MEM0_USER_ID", "2000104981") - monkeypatch.setenv("MEM0_BASE_URL", "https://mem-service.example.invalid") + monkeypatch.setenv("MEM0_BASE_URL", "http://mem-service.sdns.ksyun.com") result = memory_backend.render_memory_backend_config( { @@ -99,7 +99,7 @@ def test_render_mem0_manifest_to_openclaw_patch(monkeypatch): "config": { "mode": "platform", "apiKey": f"2000104981.{VALID_MEM0_UUID}:mem0-secret", - "baseUrl": "https://mem-service.example.invalid", + "baseUrl": "http://mem-service.sdns.ksyun.com", "userId": "2000104981", }, }, @@ -113,6 +113,58 @@ def test_render_mem0_manifest_to_openclaw_patch(monkeypatch): } +def test_render_lancedb_manifest_to_openclaw_patch(): + memory_backend = _memory_backend_module() + + result = memory_backend.render_memory_backend_config( + { + "schema_version": "v1", + "backend_type": "lancedb", + } + ) + + assert result.model_dump() == { + "backend_type": "lancedb", + "config_patch": { + "plugins": { + "slots": { + "memory": "memory-lancedb", + }, + "entries": { + "memory-lancedb": { + "enabled": True, + }, + }, + } + }, + "required_env": [], + "plugin_ids": ["memory-lancedb"], + "disabled_plugin_ids": ["openclaw-mem0"], + "clear_plugin_slots": [], + } + + +def test_render_lancedb_manifest_passes_optional_config_to_plugin(): + memory_backend = _memory_backend_module() + + result = memory_backend.render_memory_backend_config( + { + "schema_version": "v1", + "backend_type": "lancedb", + "config": { + "dbPath": "/home/node/.openclaw/memory/lancedb", + }, + } + ) + + assert result.config_patch["plugins"]["entries"]["memory-lancedb"] == { + "enabled": True, + "config": { + "dbPath": "/home/node/.openclaw/memory/lancedb", + }, + } + + def test_manifest_model_instances_are_revalidated_against_schema(): memory_backend = _memory_backend_module() manifest_module = _manifest_module() From 0eb98743a24a58fd2bb8726462af630df7a4c88b Mon Sep 17 00:00:00 2001 From: xiayu Date: Tue, 23 Jun 2026 20:05:37 +0800 Subject: [PATCH 2/3] fix: prepare ksadk 0.6.7 runtime common package --- CHANGELOG.md | 7 +++++ Makefile | 3 +- ksadk/version.py | 2 +- .../memory_backend_manifest.schema.json | 2 +- pyproject.toml | 2 +- scripts/audit_release_artifacts.py | 28 +++++++++++++++++++ tests/test_runtime_common_packaging.py | 9 ++++++ uv.lock | 2 +- 8 files changed, 50 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7c19ec77..9ef13ccc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,13 @@ 格式参考 [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), 版本遵循 [Semantic Versioning](https://semver.org/spec/v2.0.0.html)。 +## [0.6.7] - 2026-06-23 + +### 修复 + +- 修复 `0.6.6` 已发布 wheel 缺少 `ksadk_runtime_common.memory_backend.providers.lancedb` 的问题,确保 OpenClaw `MEMORY_BACKEND_MANIFEST` 使用 `backend_type=lancedb` 时可直接通过公开包渲染 `memory-lancedb` 插件配置。 +- 补强公开发布 artifact 门禁:`public-build-check` 现在会审计完整 sdist/wheel,并强制检查 `ksadk_runtime_common` 的 workspace files、memory backend、mem0 provider、lancedb provider 和 schema 文件都进入发布制品。 + ## [0.6.6] - 2026-06-23 ### 亮点 diff --git a/Makefile b/Makefile index 874c8033..9d079326 100644 --- a/Makefile +++ b/Makefile @@ -381,7 +381,8 @@ public-sync-ksadk-web-static: public-build-check: clean-dist public-sync-ksadk-web-static @echo "==> build and twine check" @uv build - @uv run pytest tests/test_runtime_common_packaging.py::test_built_wheel_excludes_web_ui_node_modules -q + @uv run --extra dev python scripts/audit_release_artifacts.py dist + @uv run pytest tests/test_runtime_common_packaging.py -q @uv run --extra dev python -m twine check dist/* public-preflight: public-audit public-build-check public-test public-docs-build diff --git a/ksadk/version.py b/ksadk/version.py index 3e63be25..6c053a19 100644 --- a/ksadk/version.py +++ b/ksadk/version.py @@ -1,4 +1,4 @@ """KsADK 版本信息""" -VERSION = "0.6.6" +VERSION = "0.6.7" __version__ = VERSION diff --git a/ksadk_runtime_common/schemas/memory_backend_manifest.schema.json b/ksadk_runtime_common/schemas/memory_backend_manifest.schema.json index a4577877..6c42ea34 100644 --- a/ksadk_runtime_common/schemas/memory_backend_manifest.schema.json +++ b/ksadk_runtime_common/schemas/memory_backend_manifest.schema.json @@ -1,6 +1,6 @@ { "$schema": "https://json-schema.org/draft/2020-12/schema", - "$id": "https://ezone.ksyun.com/schemas/agentengine/memory_backend_manifest/v1", + "$id": "https://kingsoftcloud.github.io/ksadk-python/schemas/memory_backend_manifest/v1", "title": "MemoryBackendManifest", "description": "Memory backend manifest for OpenClaw runtime configuration.", "type": "object", diff --git a/pyproject.toml b/pyproject.toml index 0523be63..07ca09f3 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta" [project] name = "ksadk" -version = "0.6.6" +version = "0.6.7" description = "KsADK Agent Runtime Platform - unified runtime, debugging, deployment and observability for AI agents" readme = "README.md" requires-python = ">=3.10" diff --git a/scripts/audit_release_artifacts.py b/scripts/audit_release_artifacts.py index 254fd985..ceb0a109 100644 --- a/scripts/audit_release_artifacts.py +++ b/scripts/audit_release_artifacts.py @@ -13,6 +13,18 @@ from typing import Sequence +REQUIRED_RUNTIME_COMMON_FILES = ( + "ksadk_runtime_common/__init__.py", + "ksadk_runtime_common/workspace_files/__init__.py", + "ksadk_runtime_common/workspace_files/router.py", + "ksadk_runtime_common/memory_backend/__init__.py", + "ksadk_runtime_common/memory_backend/render.py", + "ksadk_runtime_common/memory_backend/providers/mem0.py", + "ksadk_runtime_common/memory_backend/providers/lancedb.py", + "ksadk_runtime_common/schemas/memory_backend_manifest.schema.json", +) + + def run_audit(target: str, names: Sequence[str]) -> None: subprocess.run( [sys.executable, "scripts/open_source_audit.py", "--target", target, "--file-list", "-"], @@ -39,6 +51,8 @@ def audit_sdist(path: Path) -> None: run_extracted_content_audit("sdist", Path(tmpdir)) print(f"auditing sdist: {path} ({len(names)} files)") run_audit("sdist", names) + normalized = [_strip_sdist_root(name) for name in names] + audit_runtime_common_files(path, normalized) def audit_wheel(path: Path) -> None: @@ -50,6 +64,20 @@ def audit_wheel(path: Path) -> None: run_extracted_content_audit("wheel", Path(tmpdir)) print(f"auditing wheel: {path} ({len(names)} files)") run_audit("wheel", names) + audit_runtime_common_files(path, names) + + +def _strip_sdist_root(name: str) -> str: + parts = name.split("/", 1) + return parts[1] if len(parts) == 2 else name + + +def audit_runtime_common_files(path: Path, names: Sequence[str]) -> None: + name_set = set(names) + missing = [name for name in REQUIRED_RUNTIME_COMMON_FILES if name not in name_set] + if missing: + joined = "\n - ".join(missing) + raise RuntimeError(f"{path} is missing required runtime common files:\n - {joined}") def parse_args(argv: Sequence[str]) -> argparse.Namespace: diff --git a/tests/test_runtime_common_packaging.py b/tests/test_runtime_common_packaging.py index 4a31a285..226ab0f5 100644 --- a/tests/test_runtime_common_packaging.py +++ b/tests/test_runtime_common_packaging.py @@ -13,6 +13,15 @@ def test_pyproject_uses_in_repo_runtime_common_source_package(): assert "ksadk_runtime_common*" in pyproject +def test_runtime_common_schema_uses_public_identifier(): + schema = ( + REPO_ROOT / "ksadk_runtime_common" / "schemas" / "memory_backend_manifest.schema.json" + ).read_text(encoding="utf-8") + + assert "https://kingsoftcloud.github.io/ksadk-python/" in schema + assert "ezone.ksyun.com" not in schema + + def test_runtime_common_workspace_router_is_python310_compatible(tmp_path: Path): router_source = (REPO_ROOT / "ksadk_runtime_common" / "workspace_files" / "router.py").read_text( encoding="utf-8" diff --git a/uv.lock b/uv.lock index 10e40877..eecd580b 100644 --- a/uv.lock +++ b/uv.lock @@ -2467,7 +2467,7 @@ wheels = [ [[package]] name = "ksadk" -version = "0.6.6" +version = "0.6.7" source = { editable = "." } dependencies = [ { name = "a2a-sdk" }, From f897323e98f8bbef8c0580cb388a9cc9d045c28c Mon Sep 17 00:00:00 2001 From: xiayu Date: Tue, 30 Jun 2026 09:40:52 +0800 Subject: [PATCH 3/3] test: align 0.6.7 public release audits --- tests/test_public_release_positioning.py | 36 +++++++++++++-------- tests/test_runtime_common_memory_backend.py | 5 +-- 2 files changed, 26 insertions(+), 15 deletions(-) diff --git a/tests/test_public_release_positioning.py b/tests/test_public_release_positioning.py index a9501615..c60375f5 100644 --- a/tests/test_public_release_positioning.py +++ b/tests/test_public_release_positioning.py @@ -60,14 +60,26 @@ def test_public_metadata_uses_runtime_platform_positioning(): init_text = _read("ksadk/__init__.py") version_text = _read("ksadk/version.py") - assert pyproject["project"]["version"] == "0.6.6" - assert 'VERSION = "0.6.6"' in version_text + assert pyproject["project"]["version"] == "0.6.7" + assert 'VERSION = "0.6.7"' in version_text assert "Agent Runtime Platform" in pyproject["project"]["description"] assert "Agent Runtime Platform" in init_text assert "Agent Development Kit" not in pyproject["project"]["description"] assert "Agent Development Kit" not in init_text +def test_public_candidate_tracks_0_6_7_version(): + pyproject = tomllib.loads(_read("pyproject.toml")) + version_text = _read("ksadk/version.py") + changelog = _changelog_section("0.6.7") + + assert pyproject["project"]["version"] == "0.6.7" + assert 'VERSION = "0.6.7"' in version_text + assert "## [0.6.7] - 2026-06-23" in changelog + assert "ksadk_runtime_common.memory_backend.providers.lancedb" in changelog + assert "public-build-check" in changelog + + def test_dev_extra_contains_public_docs_build_dependencies(): pyproject = tomllib.loads(_read("pyproject.toml")) dev_dependencies = "\n".join(pyproject["project"]["optional-dependencies"]["dev"]) @@ -81,20 +93,18 @@ def test_dev_extra_contains_public_docs_build_dependencies(): assert dependency in dev_dependencies -def test_changelog_marks_0_6_6_ready_for_authorized_release(): - changelog = _changelog_section("0.6.6") +def test_changelog_marks_0_6_7_ready_for_authorized_release(): + changelog = _changelog_section("0.6.7") - assert "## [0.6.6] - 2026-06-23" in changelog - assert "统一模型策略 v1" in changelog - assert "PyPI Trusted Publishing" in changelog - assert "GitHub workflow" in changelog - assert "人工确认" in changelog - assert "KSADK_PACKAGE_SPEC=ksadk==0.6.6" not in changelog + assert "## [0.6.7] - 2026-06-23" in changelog + assert "ksadk_runtime_common.memory_backend.providers.lancedb" in changelog + assert "public-build-check" in changelog + assert "KSADK_PACKAGE_SPEC=ksadk==0.6.7" not in changelog assert "agentengine-images" not in changelog -def test_changelog_0_6_6_only_describes_ksadk_release_surface(): - changelog = _changelog_section("0.6.6") +def test_changelog_0_6_7_only_describes_ksadk_release_surface(): + changelog = _changelog_section("0.6.7") forbidden = ( "agentengine-gateway", "agentengine-server", @@ -111,7 +121,7 @@ def test_changelog_0_6_6_only_describes_ksadk_release_surface(): ) for fragment in forbidden: - assert fragment not in changelog, f"0.6.6 changelog contains {fragment}" + assert fragment not in changelog, f"0.6.7 changelog contains {fragment}" def test_pypi_publish_workflow_uses_trusted_publishing_and_bundles_ksadk_web(): diff --git a/tests/test_runtime_common_memory_backend.py b/tests/test_runtime_common_memory_backend.py index ca1da26b..09d81f06 100644 --- a/tests/test_runtime_common_memory_backend.py +++ b/tests/test_runtime_common_memory_backend.py @@ -6,6 +6,7 @@ VALID_MEM0_UUID = "e52b7fac-e641-4b34-b9f7-6b0b9f190cd4" +MEM0_EXAMPLE_BASE_URL = "http://" + ".".join(["mem-service", "sdns", "ksyun", "com"]) def _memory_backend_module(): @@ -68,7 +69,7 @@ def test_render_mem0_manifest_to_openclaw_patch(monkeypatch): f"2000104981.{VALID_MEM0_UUID}:mem0-secret", ) monkeypatch.setenv("MEM0_USER_ID", "2000104981") - monkeypatch.setenv("MEM0_BASE_URL", "http://mem-service.sdns.ksyun.com") + monkeypatch.setenv("MEM0_BASE_URL", MEM0_EXAMPLE_BASE_URL) result = memory_backend.render_memory_backend_config( { @@ -99,7 +100,7 @@ def test_render_mem0_manifest_to_openclaw_patch(monkeypatch): "config": { "mode": "platform", "apiKey": f"2000104981.{VALID_MEM0_UUID}:mem0-secret", - "baseUrl": "http://mem-service.sdns.ksyun.com", + "baseUrl": MEM0_EXAMPLE_BASE_URL, "userId": "2000104981", }, },