build(memhub): pin hy-memory 2.0.11 and set the SDK language directly
Core pins and locks the published hy-memory 2.0.11 from PyPI, which adds MemoryConfig.language and the prompt registry. apply_sdk_language now sets the language directly; the guard that skipped it on an SDK without the field (and its debug log) is gone, and the tests use the real field. The version constant, README, architecture notes, SBOM, notices and their tests follow. CHANGELOG records 2.0.11 as published. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
1 parent
35128f2c84
commit
7a2ff2f4c4
16 files changed
+35
-88
No files matched your search
@@ -6,6 +6,8 @@ Hy Memory and MemHub are versioned and released independently.
|
||||
|
||||
## Hy Memory 2.0.11 — 2026-11-01
|
||||
|
||||
- Published
|
||||
[`hy-memory==2.0.11`](https://pypi.org/project/hy-memory/2.0.11/).
|
||||
- LLM prompts now ship in 11 languages: `en`, `zh-Hans`,
|
||||
`zh-Hant`, `ja`, `es`, `de`, `pt`, `fr`, `ko`, `ru` and `id`. They live in
|
||||
one registry, `hy_memory/prompts/`, with one module per language. Call
|
||||
|
||||
+2
-2
@@ -18,7 +18,7 @@ If you run into a problem, please open an Issue with the version, platform,repro
|
||||
|
||||
## 发行与平台合同
|
||||
|
||||
源码当前固定使用公开 PyPI 正式版 `hy-memory==2.0.10`。MemHub 源码版本为 `1.0.5`
|
||||
源码当前固定使用公开 PyPI 正式版 `hy-memory==2.0.11`。MemHub 源码版本为 `1.0.5`
|
||||
(build 36),GitHub 仓库为
|
||||
[`Tencent-Hunyuan/Hy-Memory`](https://github.com/Tencent-Hunyuan/Hy-Memory),npm 包名为
|
||||
`memhub-cli`。当前代码架构见
|
||||
@@ -118,7 +118,7 @@ MemHub 的 SQLite 数据默认位于 `~/.one-memory`,不在 npm 包或 Runtime
|
||||
|
||||
## Hy Memory
|
||||
|
||||
SDK 依赖固定为公开 PyPI 正式版 `hy-memory==2.0.10`。SDK 配置、权限边界及 search
|
||||
SDK 依赖固定为公开 PyPI 正式版 `hy-memory==2.0.11`。SDK 配置、权限边界及 search
|
||||
返回格式见 [`MEMORY.md`](MEMORY.md)。HY search 返回的 `content` 已包含 SDK 统一生成的
|
||||
逻辑时间和演化上下文;调用方不应再次转换时间戳或重复拼接 `When`。
|
||||
|
||||
|
||||
@@ -2352,7 +2352,7 @@
|
||||
{
|
||||
"SPDXID": "SPDXRef-Package-hy-memory",
|
||||
"name": "hy-memory",
|
||||
"versionInfo": "2.0.10",
|
||||
"versionInfo": "2.0.11",
|
||||
"downloadLocation": "NOASSERTION",
|
||||
"filesAnalyzed": false,
|
||||
"licenseConcluded": "Apache-2.0",
|
||||
|
||||
@@ -9,7 +9,7 @@ Per-package license texts are not reproduced here yet; the license
|
||||
column is filled in as part of release review, and the SBOM records
|
||||
`NOASSERTION` until then rather than guessing.
|
||||
|
||||
## hy-memory 2.0.10
|
||||
## hy-memory 2.0.11
|
||||
|
||||
License: Apache-2.0
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@ dependencies = [
|
||||
"fastapi>=0.141.1",
|
||||
"filelock>=3.32.4",
|
||||
# Public SDK version validated against MemHub's permission and recall contracts.
|
||||
"hy-memory==2.0.10",
|
||||
"hy-memory==2.0.11",
|
||||
# chromadb arrives through the HY SDK; locked here so an unrelated upgrade
|
||||
# cannot move the SDK's store. Built-in embedding consumes numpy directly.
|
||||
"chromadb==1.5.9",
|
||||
|
||||
@@ -14,7 +14,7 @@ from pathlib import Path
|
||||
from typing import Literal, cast
|
||||
|
||||
HY_MEMORY_DISTRIBUTION = "hy-memory"
|
||||
HY_MEMORY_VERSION = "2.0.10"
|
||||
HY_MEMORY_VERSION = "2.0.11"
|
||||
HY_MEMORY_NAMESPACE = "governed-v2"
|
||||
DiagnosticLogLevel = Literal["error", "warning", "info", "debug"]
|
||||
|
||||
|
||||
@@ -503,7 +503,7 @@ def _ensure_coding_schema(path: Path) -> None:
|
||||
CodingMemoryStore,
|
||||
)
|
||||
|
||||
# Relies on the pinned SDK's internals (hy-memory==2.0.10 is pinned exactly).
|
||||
# Relies on the pinned SDK's internals (hy-memory==2.0.11 is pinned exactly).
|
||||
store = CodingMemoryStore.__new__(CodingMemoryStore)
|
||||
store._db_path = str(path)
|
||||
store._conn = None
|
||||
|
||||
@@ -9,7 +9,6 @@ from __future__ import annotations
|
||||
|
||||
import asyncio
|
||||
import hashlib
|
||||
import logging
|
||||
import os
|
||||
import threading
|
||||
from collections.abc import Callable, Coroutine, Iterable, Iterator, Mapping
|
||||
@@ -58,8 +57,6 @@ from one_memory.model_profiles import (
|
||||
disable_thinking_params,
|
||||
)
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
_RUNTIME_LOCK = threading.RLock()
|
||||
BUILTIN_RETRIEVAL_PROFILE_ID = "builtin-retrieval"
|
||||
_LOCAL_ONNX_PLACEHOLDER_URL = "http://127.0.0.1/local-onnx"
|
||||
@@ -354,9 +351,6 @@ def apply_sdk_features(
|
||||
return config
|
||||
|
||||
|
||||
_LANGUAGE_UNSUPPORTED_LOGGED = False
|
||||
|
||||
|
||||
class LanguageKwargs(TypedDict, total=False):
|
||||
language: str
|
||||
|
||||
@@ -371,22 +365,14 @@ def language_kwargs(language: str | None) -> LanguageKwargs:
|
||||
|
||||
|
||||
def apply_sdk_language(config: MemoryConfig, language: str | None) -> MemoryConfig:
|
||||
"""Set the SDK prompt language, when there is one and the SDK has the field.
|
||||
"""Set the SDK prompt language (`MemoryConfig.language`), when there is one.
|
||||
|
||||
None (zh-Hans, or no choice) sets nothing: the SDK detects zh/en as it
|
||||
always did. An SDK without `MemoryConfig.language` keeps working without
|
||||
it; that is logged once at debug level. Like a feature, the language never
|
||||
touches `vector_store`, so the collection identity never depends on it.
|
||||
always did. Like a feature, the language never touches `vector_store`, so
|
||||
the collection identity never depends on it.
|
||||
"""
|
||||
global _LANGUAGE_UNSUPPORTED_LOGGED
|
||||
if language is None:
|
||||
return config
|
||||
if not hasattr(config, "language"):
|
||||
if not _LANGUAGE_UNSUPPORTED_LOGGED:
|
||||
_LANGUAGE_UNSUPPORTED_LOGGED = True
|
||||
logger.debug("hy_sdk_language_unsupported language=%s", language)
|
||||
return config
|
||||
config.language = language
|
||||
if language is not None:
|
||||
config.language = language
|
||||
return config
|
||||
|
||||
|
||||
|
||||
@@ -91,7 +91,7 @@ def test_bundle_contains_management_sdk_config_and_verified_manifest(tmp_path):
|
||||
assert manifest["bundle_id"] == "migration-1"
|
||||
assert manifest["sdk_namespace"] == "governed-v2"
|
||||
assert manifest["runtime_build"] == "build-13"
|
||||
assert manifest["snapshot_sdk_version"] == "2.0.10"
|
||||
assert manifest["snapshot_sdk_version"] == "2.0.11"
|
||||
paths = {item["path"]: item for item in manifest["files"]}
|
||||
assert {
|
||||
"management/one-memory.sqlite3",
|
||||
|
||||
@@ -2,8 +2,7 @@
|
||||
|
||||
The owner's rule: zh-Hans, or no explicit choice, passes no language, so the
|
||||
SDK keeps detecting zh/en exactly as before; every other code (en included)
|
||||
is passed as `MemoryConfig.language`. The pinned SDK may not have that field
|
||||
yet: then nothing is passed and that is logged once. A change rebuilds the
|
||||
is passed as `MemoryConfig.language` (hy-memory 2.0.11). A change rebuilds the
|
||||
handles the way a mode or feature change does, and the language never touches
|
||||
the vector collection identity.
|
||||
"""
|
||||
@@ -13,7 +12,6 @@ from __future__ import annotations
|
||||
import asyncio
|
||||
import dataclasses
|
||||
import json
|
||||
import logging
|
||||
from contextlib import asynccontextmanager
|
||||
from pathlib import Path
|
||||
from types import SimpleNamespace
|
||||
@@ -34,31 +32,10 @@ TOKEN = "ui-language-test"
|
||||
PASSED = ("en", "zh-Hant", "ja", "es", "de", "pt", "fr", "ko", "ru", "id")
|
||||
|
||||
|
||||
@dataclasses.dataclass
|
||||
class _MemoryConfigWithLanguage(hy_sdk_runtime.MemoryConfig):
|
||||
"""The released SDK's `MemoryConfig`, which adds `language`."""
|
||||
|
||||
language: str | None = None
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def sdk_with_language(monkeypatch):
|
||||
monkeypatch.setattr(hy_sdk_runtime, "MemoryConfig", _MemoryConfigWithLanguage)
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def sdk_without_language(monkeypatch):
|
||||
"""The pinned SDK, whose `MemoryConfig` has no `language` yet."""
|
||||
monkeypatch.setattr(hy_sdk_runtime, "_LANGUAGE_UNSUPPORTED_LOGGED", False)
|
||||
|
||||
@dataclasses.dataclass
|
||||
class Pinned(hy_sdk_runtime.MemoryConfig):
|
||||
def __getattribute__(self, name):
|
||||
if name == "language":
|
||||
raise AttributeError(name)
|
||||
return super().__getattribute__(name)
|
||||
|
||||
monkeypatch.setattr(hy_sdk_runtime, "MemoryConfig", Pinned)
|
||||
@pytest.fixture(autouse=True)
|
||||
def _clean_sdk_env(monkeypatch):
|
||||
"""The SDK's own `MEMORY_LANGUAGE` feeds its default; tests start without it."""
|
||||
monkeypatch.delenv("MEMORY_LANGUAGE", raising=False)
|
||||
|
||||
|
||||
def _config(tmp_path: Path, language: str | None):
|
||||
@@ -92,19 +69,19 @@ def test_only_zh_hans_and_no_choice_leave_the_sdk_to_detect() -> None:
|
||||
assert sdk_language(code) == code
|
||||
|
||||
|
||||
def test_zh_hans_and_no_choice_build_the_config_of_before(tmp_path, sdk_with_language) -> None:
|
||||
def test_zh_hans_and_no_choice_build_the_config_of_before(tmp_path) -> None:
|
||||
before = repr(dataclasses.asdict(_config(tmp_path, None)))
|
||||
assert _config(tmp_path, None).language is None
|
||||
assert repr(dataclasses.asdict(_config(tmp_path, sdk_language("zh-Hans")))) == before
|
||||
|
||||
|
||||
@pytest.mark.parametrize("code", ("en", "ja"))
|
||||
def test_a_passed_code_reaches_the_memory_config(tmp_path, sdk_with_language, code) -> None:
|
||||
@pytest.mark.parametrize("code", PASSED)
|
||||
def test_a_passed_code_reaches_the_memory_config(tmp_path, code) -> None:
|
||||
config = _config(tmp_path, sdk_language(code))
|
||||
assert config.language == code
|
||||
|
||||
|
||||
def test_the_language_never_changes_the_collection_identity(tmp_path, sdk_with_language) -> None:
|
||||
def test_the_language_never_changes_the_collection_identity(tmp_path) -> None:
|
||||
def identity(config):
|
||||
return (
|
||||
dataclasses.asdict(config.vector_store),
|
||||
@@ -119,24 +96,6 @@ def test_the_language_never_changes_the_collection_identity(tmp_path, sdk_with_l
|
||||
assert identity(_config(tmp_path, code)) == baseline
|
||||
|
||||
|
||||
def test_an_sdk_without_the_field_is_left_alone_and_logged_once(
|
||||
tmp_path, sdk_without_language, caplog
|
||||
) -> None:
|
||||
caplog.set_level(logging.DEBUG, logger=hy_sdk_runtime.__name__)
|
||||
before = repr(dataclasses.asdict(_config(tmp_path, None)))
|
||||
assert repr(dataclasses.asdict(_config(tmp_path, "ja"))) == before
|
||||
assert repr(dataclasses.asdict(_config(tmp_path, "fr"))) == before
|
||||
logged = [r for r in caplog.records if "hy_sdk_language_unsupported" in r.getMessage()]
|
||||
assert len(logged) == 1 and logged[0].levelno == logging.DEBUG
|
||||
|
||||
|
||||
def test_the_pinned_sdk_builds_with_a_language(tmp_path) -> None:
|
||||
"""Whatever the pinned SDK is, a language never breaks building a config."""
|
||||
config = _config(tmp_path, "ja")
|
||||
if hasattr(config, "language"):
|
||||
assert config.language == "ja"
|
||||
|
||||
|
||||
def test_acquire_client_passes_the_language_only_when_there_is_one(tmp_path, monkeypatch) -> None:
|
||||
calls: list[dict] = []
|
||||
monkeypatch.setattr(
|
||||
|
||||
Generated
+4
-4
@@ -991,7 +991,7 @@ wheels = [
|
||||
|
||||
[[package]]
|
||||
name = "hy-memory"
|
||||
version = "2.0.10"
|
||||
version = "2.0.11"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "chromadb" },
|
||||
@@ -1008,9 +1008,9 @@ dependencies = [
|
||||
{ name = "scikit-learn" },
|
||||
{ name = "tiktoken" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/86/ed/1e1264d5b8741237c34fdaf17ae68bf5d16d403ca73c054997a502cd06a3/hy_memory-2.0.10.tar.gz", hash = "sha256:0841a441862e2427f75898bb8c958ed22fa083d2c0326298687ee129bcb729a8", size = 881659, upload-time = "2026-11-01T11:33:33.742Z" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/01/93/aec7d243259f6a315f38e8ebc21a9eea153a48fc13648fda149be7672788/hy_memory-2.0.11.tar.gz", hash = "sha256:96d6bd606d61052f127cd274aa6f8de8e7151d6250f1e89e4ef5b90e18ec7cb0", size = 1245738, upload-time = "2026-11-01T14:15:02.474Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/9f/d6/c07a9d2d3af14da5a90c2bc466a46fc77068c24570fafe8f5729e46e2cae/hy_memory-2.0.10-py3-none-any.whl", hash = "sha256:54528d61a1730c7ea0f464f15144de3d1952f5d9aab1875bc841c97a193914b1", size = 947165, upload-time = "2026-11-01T11:33:31.66Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/1a/85/1f5e6a13507a0cfcdce26f67c590df00d327a0f7d5c5b5483c3bd0fa2f85/hy_memory-2.0.11-py3-none-any.whl", hash = "sha256:c0173444a83c1197a49acaccb123f8286cea205b4838c1e83d106974f5bad259", size = 1315871, upload-time = "2026-11-01T14:14:58.764Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1837,7 +1837,7 @@ requires-dist = [
|
||||
{ name = "fastapi", specifier = ">=0.141.1" },
|
||||
{ name = "filelock", specifier = ">=3.32.4" },
|
||||
{ name = "httpx", specifier = ">=0.28.1" },
|
||||
{ name = "hy-memory", specifier = "==2.0.10" },
|
||||
{ name = "hy-memory", specifier = "==2.0.11" },
|
||||
{ name = "keyring", specifier = ">=25.7.0" },
|
||||
{ name = "numpy", specifier = "==2.5.2" },
|
||||
{ name = "onnxruntime", specifier = "==1.23.2" },
|
||||
|
||||
@@ -282,7 +282,7 @@ Support is declared per immutable GitHub Release manifest:
|
||||
- Linux x64/arm64 Runtime on native GHA runners.
|
||||
- macOS arm64/x64 App/Runtime: Developer ID, notarization, native acceptance.
|
||||
- Windows is not supported.
|
||||
- `hy-memory==2.0.10` is the current stable SDK dependency; the release
|
||||
- `hy-memory==2.0.11` is the current stable SDK dependency; the release
|
||||
lock and [`../MEMORY.md`](../MEMORY.md) are authoritative when the pin changes.
|
||||
|
||||
See [`INSTALLATION.md`](INSTALLATION.md).
|
||||
|
||||
@@ -195,7 +195,7 @@ node apps/cli/dist/one-memory.cjs settings language system # 跟随系统(
|
||||
- 可选 11 种:`en`、`zh-Hans`、`zh-Hant`、`ja`、`es`、`de`、`pt`、`fr`、`ko`、`ru`、`id`,以及 `system`;旧代码 `zh-CN` 按 `zh-Hans` 处理。
|
||||
- App 切换语言时会自动设置(Desktop 启动时也会同步一次已保存的选择)。全局设置,存于 `config.json` 的 `ui_language`;从未选择时不写入。
|
||||
- `zh-Hans` 和 `system` 不向 SDK 传语言,SDK 照旧自动识别中文或英文;其余语言(包括 `en`)作为 `MemoryConfig.language` 传给 SDK,提取等提示使用该语言。
|
||||
- 修改会像功能开关一样重建 SDK 客户端;不迁移数据,不改集合名。当前固定的 SDK 版本还没有 `language` 字段时只在 debug 日志记一次,不影响运行。
|
||||
- 修改会像功能开关一样重建 SDK 客户端;不迁移数据,不改集合名(需要 hy-memory 2.0.11 的 `MemoryConfig.language`)。
|
||||
- `status --json` 的 `pipeline.ui_language` / `pipeline.sdk_language`(`auto` 或语言代码)。API:`GET`/`PUT /api/v1/settings/ui-language`。
|
||||
|
||||
## 8. 召回(recall)
|
||||
|
||||
@@ -36,7 +36,7 @@ MEMMY_LICENSE = (
|
||||
MEMMY_PROVENANCE = MEMMY_LICENSE.with_name("PROVENANCE.md")
|
||||
MEMMY_PIN = "25acd5f29fc7df73b943713abe61f1b2f9839887"
|
||||
HY_MEMORY_NAME = "hy-memory"
|
||||
HY_MEMORY_VERSION = "2.0.10"
|
||||
HY_MEMORY_VERSION = "2.0.11"
|
||||
|
||||
|
||||
class SbomError(RuntimeError):
|
||||
|
||||
@@ -12,7 +12,7 @@ test("installation docs disclose publication and lifecycle boundaries", async ()
|
||||
"utf8",
|
||||
);
|
||||
|
||||
assert.match(readme, /`hy-memory==2\.0\.10`/);
|
||||
assert.match(readme, /`hy-memory==2\.0\.11`/);
|
||||
assert.match(readme, /`v1\.0\.5` 的发行目标是 Linux x64\/arm64 Runtime/);
|
||||
assert.match(readme, /Linux 制品由 GitHub Actions/);
|
||||
assert.match(readme, /macOS.*Developer ID 签名、公证/s);
|
||||
|
||||
@@ -13,7 +13,7 @@ spec.loader.exec_module(module)
|
||||
|
||||
|
||||
def test_hy_memory_notice_comes_from_the_installed_dist_info(tmp_path: Path) -> None:
|
||||
dist_info = tmp_path / "hy_memory-2.0.10.dist-info"
|
||||
dist_info = tmp_path / "hy_memory-2.0.11.dist-info"
|
||||
licenses = dist_info / "licenses"
|
||||
licenses.mkdir(parents=True)
|
||||
(dist_info / "METADATA").write_text(
|
||||
@@ -21,7 +21,7 @@ def test_hy_memory_notice_comes_from_the_installed_dist_info(tmp_path: Path) ->
|
||||
(
|
||||
"Metadata-Version: 2.4",
|
||||
"Name: hy-memory",
|
||||
"Version: 2.0.10",
|
||||
"Version: 2.0.11",
|
||||
"License-Expression: Apache-2.0",
|
||||
"",
|
||||
)
|
||||
@@ -38,7 +38,7 @@ def test_hy_memory_notice_comes_from_the_installed_dist_info(tmp_path: Path) ->
|
||||
notice = module.hy_memory_notice(dist_info)
|
||||
|
||||
assert notice["name"] == "hy-memory"
|
||||
assert notice["version"] == "2.0.10"
|
||||
assert notice["version"] == "2.0.11"
|
||||
assert notice["license"] == "Apache-2.0"
|
||||
assert notice["copyright"] == "Copyright (C) 2026 Tencent. All rights reserved."
|
||||
assert "Licensed under the Apache License" in notice["text"]
|
||||
|
||||
Reference in new issue
Block a user