Compare commits
1
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
409ab9a9b4 |
No files matched your search
@@ -340,13 +340,7 @@ def sdk_migrate(options: Sequence[str], stream: TextIO) -> int:
|
||||
_write_restore(stream, as_json, document, "预览通过;加 --yes 后执行迁移。")
|
||||
return 4
|
||||
|
||||
from one_memory.hy_runtime_config import (
|
||||
HY_MEMORY_NAMESPACE,
|
||||
HY_MEMORY_VERSION,
|
||||
configure_hy_runtime_environment,
|
||||
)
|
||||
|
||||
configure_hy_runtime_environment(settings.data_dir)
|
||||
from one_memory.hy_runtime_config import HY_MEMORY_NAMESPACE, HY_MEMORY_VERSION
|
||||
from one_memory.sdk_migration_runner import run_startup_migration
|
||||
|
||||
step_names = {
|
||||
@@ -656,7 +650,6 @@ def serve(*, maintenance: bool = False) -> None:
|
||||
from one_memory.diagnostic_log import configure_diagnostics, diagnostic_event
|
||||
from one_memory.hy_runtime_config import (
|
||||
apply_diagnostic_log_level,
|
||||
configure_hy_runtime_environment,
|
||||
diagnostic_log_level,
|
||||
)
|
||||
from one_memory.log_file import start_logging_to_file
|
||||
@@ -664,15 +657,10 @@ def serve(*, maintenance: bool = False) -> None:
|
||||
from one_memory.runtime import CoreRuntime, parent_pid
|
||||
|
||||
settings = load_settings()
|
||||
if not maintenance:
|
||||
_refuse_unmigrated_home(settings.data_dir)
|
||||
# HY resolves some trace paths at import time and its pipeline path when
|
||||
# SharedRuntime starts. Bind both to the MemHub root before importing the
|
||||
# application graph; otherwise HY falls back to ~/.hy_memory while the
|
||||
# desktop Debug panel watches the managed data directory.
|
||||
configure_hy_runtime_environment(settings.data_dir)
|
||||
from one_memory.api import create_app
|
||||
|
||||
if not maintenance:
|
||||
_refuse_unmigrated_home(settings.data_dir)
|
||||
start_logging_to_file(settings.data_dir)
|
||||
apply_diagnostic_log_level(diagnostic_log_level(settings.data_dir))
|
||||
configure_diagnostics(
|
||||
|
||||
@@ -110,24 +110,11 @@ def test_log_level_document_migrates_the_old_boolean_shape(tmp_path: Path) -> No
|
||||
assert json.loads(target.read_text()) == {"schema_version": 2, "level": "error"}
|
||||
|
||||
|
||||
def test_configure_environment_passes_debug_content_settings_to_sdk(
|
||||
tmp_path: Path, monkeypatch
|
||||
) -> None:
|
||||
for name in (
|
||||
"MEMORY_DATA_DIR",
|
||||
"MEMORY_LOG_DIR",
|
||||
"MEMORY_LOG_LEVEL",
|
||||
"MEMORY_PIPELINE_TRACE_ENABLED",
|
||||
"MEMORY_LOG_LLM_CONTENT",
|
||||
):
|
||||
monkeypatch.delenv(name, raising=False)
|
||||
def test_configure_environment_passes_debug_content_settings_to_sdk(tmp_path: Path) -> None:
|
||||
set_diagnostic_log_level(tmp_path, "debug")
|
||||
configure_hy_runtime_environment(tmp_path)
|
||||
|
||||
environment = __import__("os").environ
|
||||
memory_root = tmp_path / "hy-memory" / "governed-v2"
|
||||
assert environment["MEMORY_DATA_DIR"] == str(memory_root)
|
||||
assert environment["MEMORY_LOG_DIR"] == str(memory_root / "logs")
|
||||
assert environment["MEMORY_LOG_LEVEL"] == "DEBUG"
|
||||
assert environment["MEMORY_PIPELINE_TRACE_ENABLED"] == "true"
|
||||
assert environment["MEMORY_LOG_LLM_CONTENT"] == "true"
|
||||
@@ -1,24 +1,18 @@
|
||||
import inspect
|
||||
from types import SimpleNamespace
|
||||
|
||||
from one_memory import api, cli, hy_runtime_config, log_file, runtime
|
||||
from one_memory import api, cli, log_file, runtime
|
||||
|
||||
|
||||
def test_production_serve_passes_only_supported_app_options(monkeypatch, tmp_path):
|
||||
import uvicorn
|
||||
|
||||
serve_source = inspect.getsource(cli.serve)
|
||||
assert serve_source.index("configure_hy_runtime_environment(settings.data_dir)") < (
|
||||
serve_source.index("from one_memory.api import create_app")
|
||||
)
|
||||
settings = SimpleNamespace(data_dir=tmp_path, host="127.0.0.1", port=12345)
|
||||
captured = {}
|
||||
startup_order = []
|
||||
marker = object()
|
||||
create_app_signature = inspect.signature(api.create_app)
|
||||
|
||||
def factory(*args, **kwargs):
|
||||
startup_order.append("create_app")
|
||||
create_app_signature.bind(*args, **kwargs)
|
||||
captured.update(kwargs)
|
||||
return marker
|
||||
@@ -33,18 +27,12 @@ def test_production_serve_passes_only_supported_app_options(monkeypatch, tmp_pat
|
||||
}
|
||||
|
||||
monkeypatch.setattr(cli, "load_settings", lambda: settings)
|
||||
monkeypatch.setattr(
|
||||
hy_runtime_config,
|
||||
"configure_hy_runtime_environment",
|
||||
lambda data_dir: startup_order.append(f"configure_hy:{data_dir}"),
|
||||
)
|
||||
monkeypatch.setattr(log_file, "start_logging_to_file", lambda _: None)
|
||||
monkeypatch.setattr(runtime, "parent_pid", lambda: None)
|
||||
monkeypatch.setattr(api, "create_app", factory)
|
||||
monkeypatch.setattr(uvicorn, "run", run)
|
||||
cli.serve()
|
||||
assert captured == {"manage_runtime": True}
|
||||
assert startup_order == [f"configure_hy:{tmp_path}", "create_app"]
|
||||
|
||||
|
||||
def test_maintenance_serve_does_not_own_the_runtime(monkeypatch, tmp_path):
|
||||
@@ -71,11 +59,6 @@ def test_maintenance_serve_does_not_own_the_runtime(monkeypatch, tmp_path):
|
||||
}
|
||||
|
||||
monkeypatch.setattr(cli, "load_settings", lambda: settings)
|
||||
monkeypatch.setattr(
|
||||
hy_runtime_config,
|
||||
"configure_hy_runtime_environment",
|
||||
lambda _data_dir: None,
|
||||
)
|
||||
monkeypatch.setattr(log_file, "start_logging_to_file", lambda _: None)
|
||||
monkeypatch.setattr(runtime, "parent_pid", lambda: None)
|
||||
monkeypatch.setattr(api, "create_app", factory)
|
||||
|
||||
@@ -143,24 +143,14 @@ def test_a_finished_migration_records_the_result(home, monkeypatch):
|
||||
legacy_home(home)
|
||||
from one_memory.sdk_migration_runner import StartupMigrationResult
|
||||
|
||||
startup_order = []
|
||||
|
||||
def run_startup_migration(**options):
|
||||
startup_order.append("run_migration")
|
||||
options["progress"]("cutover")
|
||||
return StartupMigrationResult(state="cutover", migration_id="sdk-authority-v2-abc")
|
||||
|
||||
import one_memory.hy_runtime_config as hy_runtime_config
|
||||
import one_memory.sdk_migration_runner as runner
|
||||
|
||||
monkeypatch.setattr(
|
||||
hy_runtime_config,
|
||||
"configure_hy_runtime_environment",
|
||||
lambda data_dir: startup_order.append(f"configure_hy:{data_dir}"),
|
||||
)
|
||||
monkeypatch.setattr(runner, "run_startup_migration", run_startup_migration)
|
||||
assert cli.run(MIGRATE, output=StringIO()) == 0
|
||||
assert startup_order == [f"configure_hy:{home}", "run_migration"]
|
||||
finished = lines(home)[-1]
|
||||
assert finished["event"] == "migrate.finished"
|
||||
assert finished["migration_id"] == "sdk-authority-v2-abc"
|
||||
|
||||
@@ -246,23 +246,21 @@ it("shows HY pipeline metrics without exposing model content", async () => {
|
||||
const target = path.join(pipelineDir, "2026-10-14.log");
|
||||
await writeFile(target, "");
|
||||
const cursor = await captureDebugLogCursor(dataDir);
|
||||
const pipelineEntry = {
|
||||
request_id: "request-safe-1",
|
||||
user_id: "private-user",
|
||||
agent_id: "private-agent",
|
||||
session_id: "private-session",
|
||||
step: "EXTRACT",
|
||||
prompt: "private prompt",
|
||||
content: "private response",
|
||||
parsed: "private parsed output",
|
||||
tokens: 42,
|
||||
elapsed_ms: 123.5,
|
||||
timestamp: "2026-10-14T10:01:00.000",
|
||||
};
|
||||
await appendFile(target, `${JSON.stringify(pipelineEntry)}\n`);
|
||||
await writeFile(
|
||||
path.join(dataDir, "hy-memory", "governed-v2", "logs", "hy_memory.log"),
|
||||
`${JSON.stringify({ ...pipelineEntry, request_id: "must-not-appear" })}\n`,
|
||||
await appendFile(
|
||||
target,
|
||||
`${JSON.stringify({
|
||||
request_id: "request-safe-1",
|
||||
user_id: "private-user",
|
||||
agent_id: "private-agent",
|
||||
session_id: "private-session",
|
||||
step: "EXTRACT",
|
||||
prompt: "private prompt",
|
||||
content: "private response",
|
||||
parsed: "private parsed output",
|
||||
tokens: 42,
|
||||
elapsed_ms: 123.5,
|
||||
timestamp: "2026-10-14T10:01:00.000",
|
||||
})}\n`,
|
||||
);
|
||||
|
||||
const snapshot = await readDebugLogSnapshot(
|
||||
|
||||
@@ -18,7 +18,6 @@ const UI_TRACE = "one-memory:log-ui-trace";
|
||||
const DEBUG_LOGS = "one-memory:get-debug-logs";
|
||||
const DEBUG_LOG_NAME =
|
||||
/^diagnostic-(runtime|core|host-bridge|desktop|cli)\.jsonl(?:\.\d+)?$/;
|
||||
const PIPELINE_LOG_NAME = /^\d{4}-\d{2}-\d{2}\.log$/;
|
||||
const SERVICE_LOG_NAMES = [
|
||||
"service.log",
|
||||
"service-error.log",
|
||||
@@ -555,11 +554,7 @@ async function pipelineLogFiles(root: string): Promise<PipelineLogCursor[]> {
|
||||
await visit(target);
|
||||
continue;
|
||||
}
|
||||
// The same root also contains HY's human-readable hy_memory.log.
|
||||
// Pipeline files are date-named JSONL; accepting every .log file makes
|
||||
// the Debug poller repeatedly parse unrelated text and still display no
|
||||
// HY entries.
|
||||
if (!entry.isFile() || !PIPELINE_LOG_NAME.test(entry.name)) continue;
|
||||
if (!entry.isFile() || !entry.name.endsWith(".log")) continue;
|
||||
const info = await safeRegularFile(target);
|
||||
if (!info) continue;
|
||||
files.push({
|
||||
|
||||
@@ -223,6 +223,35 @@ it("searches only when 搜索 is pressed, not on every keystroke", async () => {
|
||||
expect(resetPage).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("clearing a submitted keyword immediately shows every memory from the selected source", async () => {
|
||||
const onQuery = vi.fn();
|
||||
const onSource = vi.fn();
|
||||
const resetPage = vi.fn();
|
||||
render(
|
||||
<Host
|
||||
simplified
|
||||
libraryView={{
|
||||
...pagedView({ items: [], total: 0, offset: 0, limit: 100 }),
|
||||
query: "github",
|
||||
source: "workbuddy",
|
||||
onQuery,
|
||||
onSource,
|
||||
resetPage,
|
||||
}}
|
||||
/>,
|
||||
);
|
||||
|
||||
const input = screen.getByRole<HTMLInputElement>("textbox", {
|
||||
name: "筛选地图记忆",
|
||||
});
|
||||
expect(input.value).toBe("github");
|
||||
await userEvent.clear(input);
|
||||
|
||||
expect(onQuery).toHaveBeenCalledExactlyOnceWith("");
|
||||
expect(resetPage).toHaveBeenCalledOnce();
|
||||
expect(onSource).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("OBS-15: switching memory shows a read in progress instead of the previous memory", async () => {
|
||||
const user = userEvent.setup();
|
||||
// The read is deliberately never answered: what matters is what is on
|
||||
|
||||
@@ -679,7 +679,18 @@ export function MemoryMap(props: Props) {
|
||||
}}
|
||||
onChange={(e) => {
|
||||
if (library) {
|
||||
setSearchDraft(e.target.value);
|
||||
const next = e.target.value;
|
||||
setSearchDraft(next);
|
||||
// An empty search box means "no keyword filter". Keeping the
|
||||
// last submitted query active after the reader removed its
|
||||
// text made the source picker look empty even when that app
|
||||
// had memories.
|
||||
if (!next && library.query.trim()) {
|
||||
setFilterNotice("");
|
||||
clear();
|
||||
library.onQuery("");
|
||||
library.resetPage();
|
||||
}
|
||||
return;
|
||||
}
|
||||
setFilterNotice("");
|
||||
|
||||
Reference in new issue
Block a user