loop-memory 0.4.10__tar.gz → 0.4.12__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {loop_memory-0.4.10 → loop_memory-0.4.12}/PKG-INFO +16 -1
- {loop_memory-0.4.10 → loop_memory-0.4.12}/README.md +15 -0
- {loop_memory-0.4.10 → loop_memory-0.4.12}/loop_memory/cli/commands/cognitive.py +46 -0
- {loop_memory-0.4.10 → loop_memory-0.4.12}/loop_memory/cli/main.py +4 -0
- {loop_memory-0.4.10 → loop_memory-0.4.12}/loop_memory/serve/app.py +6 -0
- {loop_memory-0.4.10 → loop_memory-0.4.12}/loop_memory/serve/routes/system.py +78 -0
- {loop_memory-0.4.10 → loop_memory-0.4.12}/loop_memory/storage/sqlite_store.py +582 -2
- {loop_memory-0.4.10 → loop_memory-0.4.12}/loop_memory.egg-info/PKG-INFO +16 -1
- {loop_memory-0.4.10 → loop_memory-0.4.12}/loop_memory.egg-info/SOURCES.txt +4 -0
- {loop_memory-0.4.10 → loop_memory-0.4.12}/pyproject.toml +1 -1
- {loop_memory-0.4.10 → loop_memory-0.4.12}/tests/test_agents_init.py +3 -3
- loop_memory-0.4.12/tests/test_audit_triggers_2026_09_27.py +188 -0
- loop_memory-0.4.12/tests/test_busy_timeout_2026_09_24.py +110 -0
- loop_memory-0.4.12/tests/test_healthz_readyz_2026_09_24.py +80 -0
- loop_memory-0.4.12/tests/test_import_okf_2026_09_27.py +425 -0
- {loop_memory-0.4.10 → loop_memory-0.4.12}/tests/test_supersession_chain.py +1 -1
- {loop_memory-0.4.10 → loop_memory-0.4.12}/LICENSE +0 -0
- {loop_memory-0.4.10 → loop_memory-0.4.12}/loop_memory/__init__.py +0 -0
- {loop_memory-0.4.10 → loop_memory-0.4.12}/loop_memory/backends/__init__.py +0 -0
- {loop_memory-0.4.10 → loop_memory-0.4.12}/loop_memory/backends/embedding.py +0 -0
- {loop_memory-0.4.10 → loop_memory-0.4.12}/loop_memory/backends/sentence_embedder.py +0 -0
- {loop_memory-0.4.10 → loop_memory-0.4.12}/loop_memory/backends/vector_store.py +0 -0
- {loop_memory-0.4.10 → loop_memory-0.4.12}/loop_memory/cli/__init__.py +0 -0
- {loop_memory-0.4.10 → loop_memory-0.4.12}/loop_memory/cli/_common.py +0 -0
- {loop_memory-0.4.10 → loop_memory-0.4.12}/loop_memory/cli/commands/__init__.py +0 -0
- {loop_memory-0.4.10 → loop_memory-0.4.12}/loop_memory/cli/commands/diag.py +0 -0
- {loop_memory-0.4.10 → loop_memory-0.4.12}/loop_memory/cli/commands/graph.py +0 -0
- {loop_memory-0.4.10 → loop_memory-0.4.12}/loop_memory/cli/commands/hooks.py +0 -0
- {loop_memory-0.4.10 → loop_memory-0.4.12}/loop_memory/cli/commands/read.py +0 -0
- {loop_memory-0.4.10 → loop_memory-0.4.12}/loop_memory/cli/commands/rules.py +0 -0
- {loop_memory-0.4.10 → loop_memory-0.4.12}/loop_memory/cli/commands/serve.py +0 -0
- {loop_memory-0.4.10 → loop_memory-0.4.12}/loop_memory/cli/commands/write.py +0 -0
- {loop_memory-0.4.10 → loop_memory-0.4.12}/loop_memory/engine/__init__.py +0 -0
- {loop_memory-0.4.10 → loop_memory-0.4.12}/loop_memory/engine/loop.py +0 -0
- {loop_memory-0.4.10 → loop_memory-0.4.12}/loop_memory/engine/reflect.py +0 -0
- {loop_memory-0.4.10 → loop_memory-0.4.12}/loop_memory/examples/__init__.py +0 -0
- {loop_memory-0.4.10 → loop_memory-0.4.12}/loop_memory/examples/demo.py +0 -0
- {loop_memory-0.4.10 → loop_memory-0.4.12}/loop_memory/export/__init__.py +0 -0
- {loop_memory-0.4.10 → loop_memory-0.4.12}/loop_memory/export/memory_md.py +0 -0
- {loop_memory-0.4.10 → loop_memory-0.4.12}/loop_memory/graph/__init__.py +0 -0
- {loop_memory-0.4.10 → loop_memory-0.4.12}/loop_memory/graph/build.py +0 -0
- {loop_memory-0.4.10 → loop_memory-0.4.12}/loop_memory/graph/extract.py +0 -0
- {loop_memory-0.4.10 → loop_memory-0.4.12}/loop_memory/ingest/__init__.py +0 -0
- {loop_memory-0.4.10 → loop_memory-0.4.12}/loop_memory/ingest/loader.py +0 -0
- {loop_memory-0.4.10 → loop_memory-0.4.12}/loop_memory/ingest/pipeline.py +0 -0
- {loop_memory-0.4.10 → loop_memory-0.4.12}/loop_memory/jobs/__init__.py +0 -0
- {loop_memory-0.4.10 → loop_memory-0.4.12}/loop_memory/jobs/cognitive.py +0 -0
- {loop_memory-0.4.10 → loop_memory-0.4.12}/loop_memory/jobs/compact.py +0 -0
- {loop_memory-0.4.10 → loop_memory-0.4.12}/loop_memory/jobs/consolidate.py +0 -0
- {loop_memory-0.4.10 → loop_memory-0.4.12}/loop_memory/jobs/contradiction.py +0 -0
- {loop_memory-0.4.10 → loop_memory-0.4.12}/loop_memory/jobs/evolution.py +0 -0
- {loop_memory-0.4.10 → loop_memory-0.4.12}/loop_memory/jobs/graph.py +0 -0
- {loop_memory-0.4.10 → loop_memory-0.4.12}/loop_memory/jobs/llm_compact_pass.py +0 -0
- {loop_memory-0.4.10 → loop_memory-0.4.12}/loop_memory/jobs/llm_consolidate.py +0 -0
- {loop_memory-0.4.10 → loop_memory-0.4.12}/loop_memory/jobs/scheduler.py +0 -0
- {loop_memory-0.4.10 → loop_memory-0.4.12}/loop_memory/llm/__init__.py +0 -0
- {loop_memory-0.4.10 → loop_memory-0.4.12}/loop_memory/llm/base.py +0 -0
- {loop_memory-0.4.10 → loop_memory-0.4.12}/loop_memory/llm/openai_adapter.py +0 -0
- {loop_memory-0.4.10 → loop_memory-0.4.12}/loop_memory/llm/providers.py +0 -0
- {loop_memory-0.4.10 → loop_memory-0.4.12}/loop_memory/mcp/__init__.py +0 -0
- {loop_memory-0.4.10 → loop_memory-0.4.12}/loop_memory/memory/__init__.py +0 -0
- {loop_memory-0.4.10 → loop_memory-0.4.12}/loop_memory/memory/types.py +0 -0
- {loop_memory-0.4.10 → loop_memory-0.4.12}/loop_memory/privacy/__init__.py +0 -0
- {loop_memory-0.4.10 → loop_memory-0.4.12}/loop_memory/privacy/private.py +0 -0
- {loop_memory-0.4.10 → loop_memory-0.4.12}/loop_memory/privacy/redact.py +0 -0
- {loop_memory-0.4.10 → loop_memory-0.4.12}/loop_memory/py.typed +0 -0
- {loop_memory-0.4.10 → loop_memory-0.4.12}/loop_memory/sdk.py +0 -0
- {loop_memory-0.4.10 → loop_memory-0.4.12}/loop_memory/sdk_extensions.py +0 -0
- {loop_memory-0.4.10 → loop_memory-0.4.12}/loop_memory/security/__init__.py +0 -0
- {loop_memory-0.4.10 → loop_memory-0.4.12}/loop_memory/security/secrets.py +0 -0
- {loop_memory-0.4.10 → loop_memory-0.4.12}/loop_memory/serve/__init__.py +0 -0
- {loop_memory-0.4.10 → loop_memory-0.4.12}/loop_memory/serve/handlers.py +0 -0
- {loop_memory-0.4.10 → loop_memory-0.4.12}/loop_memory/serve/routes/_shared.py +0 -0
- {loop_memory-0.4.10 → loop_memory-0.4.12}/loop_memory/serve/routes/admin.py +0 -0
- {loop_memory-0.4.10 → loop_memory-0.4.12}/loop_memory/serve/routes/cognitive.py +0 -0
- {loop_memory-0.4.10 → loop_memory-0.4.12}/loop_memory/serve/routes/export.py +0 -0
- {loop_memory-0.4.10 → loop_memory-0.4.12}/loop_memory/serve/routes/graph.py +0 -0
- {loop_memory-0.4.10 → loop_memory-0.4.12}/loop_memory/serve/routes/insights.py +0 -0
- {loop_memory-0.4.10 → loop_memory-0.4.12}/loop_memory/serve/routes/memories.py +0 -0
- {loop_memory-0.4.10 → loop_memory-0.4.12}/loop_memory/serve/routes/sessions.py +0 -0
- {loop_memory-0.4.10 → loop_memory-0.4.12}/loop_memory/serve/routes/wiki.py +0 -0
- {loop_memory-0.4.10 → loop_memory-0.4.12}/loop_memory/serve/static/__init__.py +0 -0
- {loop_memory-0.4.10 → loop_memory-0.4.12}/loop_memory/serve/static/index.html +0 -0
- {loop_memory-0.4.10 → loop_memory-0.4.12}/loop_memory/serve/watcher.py +0 -0
- {loop_memory-0.4.10 → loop_memory-0.4.12}/loop_memory/storage/__init__.py +0 -0
- {loop_memory-0.4.10 → loop_memory-0.4.12}/loop_memory/storage/retrieval.py +0 -0
- {loop_memory-0.4.10 → loop_memory-0.4.12}/loop_memory/storage/snapshot.py +0 -0
- {loop_memory-0.4.10 → loop_memory-0.4.12}/loop_memory/wiki/__init__.py +0 -0
- {loop_memory-0.4.10 → loop_memory-0.4.12}/loop_memory/wiki/backfill.py +0 -0
- {loop_memory-0.4.10 → loop_memory-0.4.12}/loop_memory/wiki/classifier.py +0 -0
- {loop_memory-0.4.10 → loop_memory-0.4.12}/loop_memory/wiki/prompts.py +0 -0
- {loop_memory-0.4.10 → loop_memory-0.4.12}/loop_memory/wiki/scope.py +0 -0
- {loop_memory-0.4.10 → loop_memory-0.4.12}/loop_memory.egg-info/dependency_links.txt +0 -0
- {loop_memory-0.4.10 → loop_memory-0.4.12}/loop_memory.egg-info/entry_points.txt +0 -0
- {loop_memory-0.4.10 → loop_memory-0.4.12}/loop_memory.egg-info/requires.txt +0 -0
- {loop_memory-0.4.10 → loop_memory-0.4.12}/loop_memory.egg-info/top_level.txt +0 -0
- {loop_memory-0.4.10 → loop_memory-0.4.12}/setup.cfg +0 -0
- {loop_memory-0.4.10 → loop_memory-0.4.12}/tests/test_admin_ingest_route.py +0 -0
- {loop_memory-0.4.10 → loop_memory-0.4.12}/tests/test_agent_memory_api.py +0 -0
- {loop_memory-0.4.10 → loop_memory-0.4.12}/tests/test_agent_memory_sdk.py +0 -0
- {loop_memory-0.4.10 → loop_memory-0.4.12}/tests/test_auth_token_rotate.py +0 -0
- {loop_memory-0.4.10 → loop_memory-0.4.12}/tests/test_cache_cap_2026_09_23.py +0 -0
- {loop_memory-0.4.10 → loop_memory-0.4.12}/tests/test_cli_audit_supersede.py +0 -0
- {loop_memory-0.4.10 → loop_memory-0.4.12}/tests/test_cli_export_okf.py +0 -0
- {loop_memory-0.4.10 → loop_memory-0.4.12}/tests/test_cli_init.py +0 -0
- {loop_memory-0.4.10 → loop_memory-0.4.12}/tests/test_cli_memory_stats.py +0 -0
- {loop_memory-0.4.10 → loop_memory-0.4.12}/tests/test_cli_recall_as_of.py +0 -0
- {loop_memory-0.4.10 → loop_memory-0.4.12}/tests/test_cli_recall_paths.py +0 -0
- {loop_memory-0.4.10 → loop_memory-0.4.12}/tests/test_cli_recall_verbose.py +0 -0
- {loop_memory-0.4.10 → loop_memory-0.4.12}/tests/test_cli_rules.py +0 -0
- {loop_memory-0.4.10 → loop_memory-0.4.12}/tests/test_cli_snapshot.py +0 -0
- {loop_memory-0.4.10 → loop_memory-0.4.12}/tests/test_cli_v7.py +0 -0
- {loop_memory-0.4.10 → loop_memory-0.4.12}/tests/test_cli_version.py +0 -0
- {loop_memory-0.4.10 → loop_memory-0.4.12}/tests/test_contradictions.py +0 -0
- {loop_memory-0.4.10 → loop_memory-0.4.12}/tests/test_evolution.py +0 -0
- {loop_memory-0.4.10 → loop_memory-0.4.12}/tests/test_evolution_quality.py +0 -0
- {loop_memory-0.4.10 → loop_memory-0.4.12}/tests/test_expanduser.py +0 -0
- {loop_memory-0.4.10 → loop_memory-0.4.12}/tests/test_export_ask.py +0 -0
- {loop_memory-0.4.10 → loop_memory-0.4.12}/tests/test_export_okf.py +0 -0
- {loop_memory-0.4.10 → loop_memory-0.4.12}/tests/test_graph.py +0 -0
- {loop_memory-0.4.10 → loop_memory-0.4.12}/tests/test_ingest.py +0 -0
- {loop_memory-0.4.10 → loop_memory-0.4.12}/tests/test_llm_consolidator.py +0 -0
- {loop_memory-0.4.10 → loop_memory-0.4.12}/tests/test_llm_fingerprint_not_persisted.py +0 -0
- {loop_memory-0.4.10 → loop_memory-0.4.12}/tests/test_llm_providers.py +0 -0
- {loop_memory-0.4.10 → loop_memory-0.4.12}/tests/test_llm_test_endpoint.py +0 -0
- {loop_memory-0.4.10 → loop_memory-0.4.12}/tests/test_loop.py +0 -0
- {loop_memory-0.4.10 → loop_memory-0.4.12}/tests/test_mcp.py +0 -0
- {loop_memory-0.4.10 → loop_memory-0.4.12}/tests/test_memories_pagination.py +0 -0
- {loop_memory-0.4.10 → loop_memory-0.4.12}/tests/test_memory_stats.py +0 -0
- {loop_memory-0.4.10 → loop_memory-0.4.12}/tests/test_openclaw_loader.py +0 -0
- {loop_memory-0.4.10 → loop_memory-0.4.12}/tests/test_package_version.py +0 -0
- {loop_memory-0.4.10 → loop_memory-0.4.12}/tests/test_path_safety_2026_09_23.py +0 -0
- {loop_memory-0.4.10 → loop_memory-0.4.12}/tests/test_recall_as_of.py +0 -0
- {loop_memory-0.4.10 → loop_memory-0.4.12}/tests/test_recall_paths.py +0 -0
- {loop_memory-0.4.10 → loop_memory-0.4.12}/tests/test_recall_provenance.py +0 -0
- {loop_memory-0.4.10 → loop_memory-0.4.12}/tests/test_reflection.py +0 -0
- {loop_memory-0.4.10 → loop_memory-0.4.12}/tests/test_repo_framing.py +0 -0
- {loop_memory-0.4.10 → loop_memory-0.4.12}/tests/test_routes_audit_2026_09_13.py +0 -0
- {loop_memory-0.4.10 → loop_memory-0.4.12}/tests/test_routes_audit_2026_09_20.py +0 -0
- {loop_memory-0.4.10 → loop_memory-0.4.12}/tests/test_score_api.py +0 -0
- {loop_memory-0.4.10 → loop_memory-0.4.12}/tests/test_scoring_v2.py +0 -0
- {loop_memory-0.4.10 → loop_memory-0.4.12}/tests/test_secrets.py +0 -0
- {loop_memory-0.4.10 → loop_memory-0.4.12}/tests/test_serve_app.py +0 -0
- {loop_memory-0.4.10 → loop_memory-0.4.12}/tests/test_serve_handlers.py +0 -0
- {loop_memory-0.4.10 → loop_memory-0.4.12}/tests/test_session_order.py +0 -0
- {loop_memory-0.4.10 → loop_memory-0.4.12}/tests/test_short_query.py +0 -0
- {loop_memory-0.4.10 → loop_memory-0.4.12}/tests/test_snapshot.py +0 -0
- {loop_memory-0.4.10 → loop_memory-0.4.12}/tests/test_store.py +0 -0
- {loop_memory-0.4.10 → loop_memory-0.4.12}/tests/test_subgraph_hops_2026_09_23.py +0 -0
- {loop_memory-0.4.10 → loop_memory-0.4.12}/tests/test_summarization.py +0 -0
- {loop_memory-0.4.10 → loop_memory-0.4.12}/tests/test_universal_memory.py +0 -0
- {loop_memory-0.4.10 → loop_memory-0.4.12}/tests/test_vector_store.py +0 -0
- {loop_memory-0.4.10 → loop_memory-0.4.12}/tests/test_watcher.py +0 -0
- {loop_memory-0.4.10 → loop_memory-0.4.12}/tests/test_wiki_classifier.py +0 -0
- {loop_memory-0.4.10 → loop_memory-0.4.12}/tests/test_wiki_export_escape.py +0 -0
- {loop_memory-0.4.10 → loop_memory-0.4.12}/tests/test_wiki_prompts.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: loop-memory
|
|
3
|
-
Version: 0.4.
|
|
3
|
+
Version: 0.4.12
|
|
4
4
|
Summary: A general-purpose, local memory system for every AI agent you run. Loop Memory auto-captures conversations from Codex / Claude / Hermes / OpenClaw, scores them by importance × recency × usage × feedback, distils them into a curated wiki, and serves everything from a single web UI.
|
|
5
5
|
Author: Loop Memory contributors <loop-memory@users.noreply.github.com>
|
|
6
6
|
License-Expression: MIT
|
|
@@ -66,6 +66,21 @@ Dynamic: license-file
|
|
|
66
66
|
|
|
67
67
|
---
|
|
68
68
|
|
|
69
|
+
> **What's new in 0.4.12** — **OKF bundle import** + **DB-level audit enforcement** (audit 2026-09-27). The new `loop-memory import-okf <in_dir>` (and `POST /api/import/okf`) is the symmetric counterpart to `export-okf` (0.4.9) — bring an OKF v0.2 bundle back into Loop Memory as wiki pages, with idempotent upsert on `(scope, slug)`, optional `--dry-run` and `--skip-conflicts`. Source: `thecolourfoundation/rune` HN launch (MIT, 2026-09-25) + `okf-memory/okf-agent-memory` Issues #12-#15 + `Deja-Vu` (MIT, 2026-09-24) + Google OKF v0.2 spec (Apache-2.0, 2026-09-01). The new `MemoryStore._install_audit_triggers()` installs 12 SQLite triggers on `memories` / `wiki_pages` / `relations` / `consolidation_runs` so the `audit_log` table cannot be skipped — even a raw `sqlite3` writer that bypasses the Python wrapper still appends an audit row with `actor='db_trigger'`. New `MemoryStore.list_audit_log()` reads the log; `GET /api/stats` reports `audit_log` + `audit_triggers` counts. Source: `cogstate-eng/memory-eternal v0.4.3` `enforceAudit()` pattern (MIT, 2026-09-23). 31 new regression cases. [Full CHANGELOG →](./CHANGELOG.md#0412---2026-09-27)
|
|
70
|
+
|
|
71
|
+
> **What's new in 0.4.11** — **operational probes** +
|
|
72
|
+
**SQLite write-contention fix** (audit 2026-09-24). New
|
|
73
|
+
``GET /api/healthz`` (liveness) + ``GET /api/readyz``
|
|
74
|
+
(readiness) endpoints let Kubernetes / launchd keepalive
|
|
75
|
+
polls probe the serve without provisioning a Bearer token;
|
|
76
|
+
``/api/readyz`` returns 503 when the SQLite store is
|
|
77
|
+
unreachable. Also fixed a real concurrency bug: every
|
|
78
|
+
store connection now sets ``PRAGMA busy_timeout=5000``
|
|
79
|
+
(was 0 ms) so the watcher + serve + scheduler threads no
|
|
80
|
+
longer fail with ``database is locked`` when the
|
|
81
|
+
consolidator writes concurrently. 7 new regression cases.
|
|
82
|
+
[Full CHANGELOG →](./CHANGELOG.md#0411---2026-09-24)
|
|
83
|
+
|
|
69
84
|
> **What's new in 0.4.10** — **path-safety guard** for the
|
|
70
85
|
five export / snapshot endpoints. ``MemoryStore`` already
|
|
71
86
|
validated query / wiki content; the new
|
|
@@ -22,6 +22,21 @@
|
|
|
22
22
|
|
|
23
23
|
---
|
|
24
24
|
|
|
25
|
+
> **What's new in 0.4.12** — **OKF bundle import** + **DB-level audit enforcement** (audit 2026-09-27). The new `loop-memory import-okf <in_dir>` (and `POST /api/import/okf`) is the symmetric counterpart to `export-okf` (0.4.9) — bring an OKF v0.2 bundle back into Loop Memory as wiki pages, with idempotent upsert on `(scope, slug)`, optional `--dry-run` and `--skip-conflicts`. Source: `thecolourfoundation/rune` HN launch (MIT, 2026-09-25) + `okf-memory/okf-agent-memory` Issues #12-#15 + `Deja-Vu` (MIT, 2026-09-24) + Google OKF v0.2 spec (Apache-2.0, 2026-09-01). The new `MemoryStore._install_audit_triggers()` installs 12 SQLite triggers on `memories` / `wiki_pages` / `relations` / `consolidation_runs` so the `audit_log` table cannot be skipped — even a raw `sqlite3` writer that bypasses the Python wrapper still appends an audit row with `actor='db_trigger'`. New `MemoryStore.list_audit_log()` reads the log; `GET /api/stats` reports `audit_log` + `audit_triggers` counts. Source: `cogstate-eng/memory-eternal v0.4.3` `enforceAudit()` pattern (MIT, 2026-09-23). 31 new regression cases. [Full CHANGELOG →](./CHANGELOG.md#0412---2026-09-27)
|
|
26
|
+
|
|
27
|
+
> **What's new in 0.4.11** — **operational probes** +
|
|
28
|
+
**SQLite write-contention fix** (audit 2026-09-24). New
|
|
29
|
+
``GET /api/healthz`` (liveness) + ``GET /api/readyz``
|
|
30
|
+
(readiness) endpoints let Kubernetes / launchd keepalive
|
|
31
|
+
polls probe the serve without provisioning a Bearer token;
|
|
32
|
+
``/api/readyz`` returns 503 when the SQLite store is
|
|
33
|
+
unreachable. Also fixed a real concurrency bug: every
|
|
34
|
+
store connection now sets ``PRAGMA busy_timeout=5000``
|
|
35
|
+
(was 0 ms) so the watcher + serve + scheduler threads no
|
|
36
|
+
longer fail with ``database is locked`` when the
|
|
37
|
+
consolidator writes concurrently. 7 new regression cases.
|
|
38
|
+
[Full CHANGELOG →](./CHANGELOG.md#0411---2026-09-24)
|
|
39
|
+
|
|
25
40
|
> **What's new in 0.4.10** — **path-safety guard** for the
|
|
26
41
|
five export / snapshot endpoints. ``MemoryStore`` already
|
|
27
42
|
validated query / wiki content; the new
|
|
@@ -119,6 +119,23 @@ def _build_parser() -> argparse.ArgumentParser:
|
|
|
119
119
|
eo.add_argument("--scope", default=None,
|
|
120
120
|
help="Filter: 'global' or a single source token (e.g. codex)")
|
|
121
121
|
|
|
122
|
+
# Audit 2026-09-27: OKF v0.2 bundle import
|
|
123
|
+
# (thecolourfoundation/rune + okf-memory/okf-agent-memory Issues
|
|
124
|
+
# #12-#15 + Deja-Vu HN front-page). Symmetric counterpart to
|
|
125
|
+
# ``export-okf`` (0.4.9): bring an OKF bundle back into Loop
|
|
126
|
+
# Memory as wiki pages. Idempotent upsert on (scope, slug).
|
|
127
|
+
io = sub.add_parser(
|
|
128
|
+
"import-okf",
|
|
129
|
+
help="Import an OKF v0.2 bundle directory as wiki pages")
|
|
130
|
+
io.add_argument("in_dir",
|
|
131
|
+
help="Bundle directory containing index.md and pages/")
|
|
132
|
+
io.add_argument("--scope", default=None,
|
|
133
|
+
help="Scope tag for imported pages (default: bundle's index.md, then 'global')")
|
|
134
|
+
io.add_argument("--dry-run", action="store_true",
|
|
135
|
+
help="Parse every file but do not write")
|
|
136
|
+
io.add_argument("--skip-conflicts", action="store_true",
|
|
137
|
+
help="Don't overwrite an existing (scope, slug) row")
|
|
138
|
+
|
|
122
139
|
return p
|
|
123
140
|
|
|
124
141
|
|
|
@@ -375,3 +392,32 @@ def run_export_okf(args) -> int:
|
|
|
375
392
|
s = MemoryStore(ns.db)
|
|
376
393
|
r = s.export_okf(ns.out_dir, scope_filter=ns.scope)
|
|
377
394
|
return _emit(r)
|
|
395
|
+
|
|
396
|
+
|
|
397
|
+
def run_import_okf(args) -> int:
|
|
398
|
+
"""``loop-memory import-okf <in_dir> [--scope S] [--dry-run] [--skip-conflicts]``
|
|
399
|
+
|
|
400
|
+
Audit 2026-09-27: OKF v0.2 bundle import
|
|
401
|
+
(thecolourfoundation/rune + okf-memory/okf-agent-memory Issues
|
|
402
|
+
#12-#15 + Deja-Vu HN front-page). Returns the summary dict
|
|
403
|
+
from ``MemoryStore.import_okf`` so the caller can confirm what
|
|
404
|
+
landed where. ``--dry-run`` parses every file but writes nothing;
|
|
405
|
+
``--skip-conflicts`` turns INSERT-vs-existing conflicts into
|
|
406
|
+
a ``skipped`` counter rather than an UPDATE.
|
|
407
|
+
"""
|
|
408
|
+
import argparse as _ap
|
|
409
|
+
p = _ap.ArgumentParser(prog="loop-memory import-okf")
|
|
410
|
+
p.add_argument("in_dir")
|
|
411
|
+
p.add_argument("--scope", default=None)
|
|
412
|
+
p.add_argument("--dry-run", action="store_true")
|
|
413
|
+
p.add_argument("--skip-conflicts", action="store_true")
|
|
414
|
+
p.add_argument("--db", default=os.environ.get("LOOP_MEMORY_DB", DEFAULT_DB))
|
|
415
|
+
ns = p.parse_args(args)
|
|
416
|
+
s = MemoryStore(ns.db)
|
|
417
|
+
r = s.import_okf(
|
|
418
|
+
ns.in_dir,
|
|
419
|
+
scope=ns.scope,
|
|
420
|
+
dry_run=ns.dry_run,
|
|
421
|
+
skip_conflicts=ns.skip_conflicts,
|
|
422
|
+
)
|
|
423
|
+
return _emit(r)
|
|
@@ -26,6 +26,7 @@ Usage:
|
|
|
26
26
|
loop-memory export <out_dir> # write a MEMORY.md bundle (v7)
|
|
27
27
|
loop-memory export-bundle <out_dir> # explicit v7 bundle alias
|
|
28
28
|
loop-memory import <in_dir> # re-hydrate a bundle
|
|
29
|
+
loop-memory import-okf <in_dir> [--scope S] [--dry-run] [--skip-conflicts] # ingest an OKF v0.2 bundle as wiki pages (audit 2026-09-27)
|
|
29
30
|
loop-memory fork [--branch-tag T] # snapshot every wiki page
|
|
30
31
|
loop-memory graph-edge <src> <dst> [--kind K] [--weight W] # push a relation
|
|
31
32
|
loop-memory subgraph <query> # print a small subgraph
|
|
@@ -128,6 +129,8 @@ COMMANDS = {
|
|
|
128
129
|
# Audit 2026-09-20 — OKF v0.2 export (akitaonrails/ai-memory 2.0
|
|
129
130
|
# + okf-agent-memory + Google OKF spec).
|
|
130
131
|
"export-okf": cognitive_cmd.run_export_okf,
|
|
132
|
+
# Audit 2026-09-27: OKF v0.2 bundle import (rune + okf-agent-memory #12-#15 + Deja-Vu).
|
|
133
|
+
"import-okf": cognitive_cmd.run_import_okf,
|
|
131
134
|
"rules": rules_cmd.run_rules,
|
|
132
135
|
"version": _run_version,
|
|
133
136
|
}
|
|
@@ -172,6 +175,7 @@ COMMAND_HELP: dict[str, str] = {
|
|
|
172
175
|
"memory-stats": "loop-memory memory-stats <id> [--prefix] # per-memory lifetime stats (audit 2026-09-06, agentmemory v1.3.0).",
|
|
173
176
|
"snapshot": "loop-memory snapshot <out.memory.sqlite> # write a portable SQLite snapshot (audit 2026-09-06, codexa-memory v0.2.0).",
|
|
174
177
|
"export-okf": "loop-memory export-okf <out_dir> [--scope S] # write an OKF v0.2 bundle (audit 2026-09-20).",
|
|
178
|
+
"import-okf": "loop-memory import-okf <in_dir> [--scope S] [--dry-run] [--skip-conflicts] # ingest an OKF v0.2 bundle as wiki pages (audit 2026-09-27).",
|
|
175
179
|
"restore": "loop-memory restore <in.memory.sqlite> # re-hydrate a portable SQLite snapshot.",
|
|
176
180
|
# Audit 2026-09-13 — L0 outline recall (tigerless-labs/agent-memory v0.3.0).
|
|
177
181
|
"recall-paths": "loop-memory recall-paths <query> [--limit N] # cheap L0 outline (id+abstract+score) instead of full text (audit 2026-09-13).",
|
|
@@ -176,6 +176,12 @@ def create_app(store: MemoryStore, static_dir: Path | None = None, scheduler=Non
|
|
|
176
176
|
'/api/pipeline', '/api/weekly-report', '/api/llm-audit',
|
|
177
177
|
'/api/source-health', '/api/write-guard', '/api/diag',
|
|
178
178
|
'/api/install-hooks', '/api/insights',
|
|
179
|
+
# Audit 2026-09-24: probes are intentionally public so a
|
|
180
|
+
# load balancer / keepalive script doesn't need a Bearer
|
|
181
|
+
# token to ask "is the process up?". The DB-touching
|
|
182
|
+
# ``/api/readyz`` only exposes a coarse health signal
|
|
183
|
+
# (UP / DOWN), no data.
|
|
184
|
+
'/api/healthz', '/api/readyz',
|
|
179
185
|
))
|
|
180
186
|
|
|
181
187
|
def _is_public_path(path: str) -> bool:
|
|
@@ -36,6 +36,41 @@ def register(app: FastAPI, store: MemoryStore, scheduler: Optional[Any] = None,
|
|
|
36
36
|
"""
|
|
37
37
|
if static_dir is None:
|
|
38
38
|
static_dir = Path(__file__).parent.parent / "static"
|
|
39
|
+
@app.get("/api/healthz")
|
|
40
|
+
def healthz():
|
|
41
|
+
"""Liveness probe.
|
|
42
|
+
|
|
43
|
+
Audit 2026-09-24. Returns 200 as long as the process is
|
|
44
|
+
responsive. **Does not** touch the SQLite store — so the
|
|
45
|
+
probe cannot deadlock behind a slow writer and cannot give
|
|
46
|
+
a false negative when the DB is briefly busy. Use this for
|
|
47
|
+
``livenessProbe`` in Kubernetes / launchd keepalive scripts.
|
|
48
|
+
"""
|
|
49
|
+
return {"status": "ok", "ts": time.time()}
|
|
50
|
+
|
|
51
|
+
@app.get("/api/readyz")
|
|
52
|
+
def readyz():
|
|
53
|
+
"""Readiness probe.
|
|
54
|
+
|
|
55
|
+
Audit 2026-09-24. Verifies the SQLite store is reachable AND
|
|
56
|
+
responsive (one trivial ``PRAGMA quick_check`` round-trip
|
|
57
|
+
inside a 1-second budget). Returns ``{"status": "ok"}`` on
|
|
58
|
+
success, or ``{"status": "degraded", "error": "..."}`` with
|
|
59
|
+
HTTP 503 when the DB is unhealthy. Use this for
|
|
60
|
+
``readinessProbe`` so a degraded loop-memory is taken out of
|
|
61
|
+
a load-balancer rotation until it recovers.
|
|
62
|
+
"""
|
|
63
|
+
import sqlite3 as _sq3
|
|
64
|
+
try:
|
|
65
|
+
with _sq3.connect(str(store.path), timeout=1.0) as c:
|
|
66
|
+
c.execute("PRAGMA quick_check").fetchone()
|
|
67
|
+
return {"status": "ok", "ts": time.time()}
|
|
68
|
+
except Exception as e:
|
|
69
|
+
return JSONResponse(
|
|
70
|
+
{"status": "degraded", "error": str(e)},
|
|
71
|
+
status_code=503,
|
|
72
|
+
)
|
|
73
|
+
|
|
39
74
|
@app.get("/")
|
|
40
75
|
def index():
|
|
41
76
|
"""Serve the dashboard HTML with the i18n JSONs inlined.
|
|
@@ -450,6 +485,49 @@ def register(app: FastAPI, store: MemoryStore, scheduler: Optional[Any] = None,
|
|
|
450
485
|
raise HTTPException(500, f"export-okf failed: {e}")
|
|
451
486
|
return r
|
|
452
487
|
|
|
488
|
+
@app.post("/api/import/okf")
|
|
489
|
+
def import_okf(body: dict):
|
|
490
|
+
"""Audit 2026-09-27: OKF v0.2 bundle import.
|
|
491
|
+
|
|
492
|
+
Body shape::
|
|
493
|
+
|
|
494
|
+
{
|
|
495
|
+
"in_dir": "/abs/path/to/bundle",
|
|
496
|
+
"scope": "global", # optional
|
|
497
|
+
"dry_run": false, # optional
|
|
498
|
+
"skip_conflicts": false # optional
|
|
499
|
+
}
|
|
500
|
+
|
|
501
|
+
Walks ``<in_dir>/index.md`` + ``<in_dir>/pages/*.md`` and
|
|
502
|
+
upserts each page as a wiki row keyed on ``(scope, slug)``.
|
|
503
|
+
``in_dir`` is validated by ``_safe_resolve_path`` (live DB
|
|
504
|
+
+ system dirs are still refused; per-user temp is OK).
|
|
505
|
+
Returns the same summary dict as the CLI handler.
|
|
506
|
+
"""
|
|
507
|
+
from ._shared import _safe_resolve_path as _safe_path
|
|
508
|
+
in_dir = (body.get("in_dir") or "").strip()
|
|
509
|
+
if not in_dir:
|
|
510
|
+
raise HTTPException(400, "in_dir is required")
|
|
511
|
+
scope = body.get("scope")
|
|
512
|
+
if scope is not None:
|
|
513
|
+
scope = str(scope).strip() or None
|
|
514
|
+
dry_run = bool(body.get("dry_run", False))
|
|
515
|
+
skip_conflicts = bool(body.get("skip_conflicts", False))
|
|
516
|
+
try:
|
|
517
|
+
safe_dir = _safe_path(in_dir, kind="read", live_db_path=str(store.path))
|
|
518
|
+
except ValueError as e:
|
|
519
|
+
raise HTTPException(400, str(e))
|
|
520
|
+
try:
|
|
521
|
+
r = store.import_okf(
|
|
522
|
+
safe_dir,
|
|
523
|
+
scope=scope,
|
|
524
|
+
dry_run=dry_run,
|
|
525
|
+
skip_conflicts=skip_conflicts,
|
|
526
|
+
)
|
|
527
|
+
except Exception as e:
|
|
528
|
+
raise HTTPException(500, f"import-okf failed: {e}")
|
|
529
|
+
return r
|
|
530
|
+
|
|
453
531
|
@app.get("/api/recall/outline")
|
|
454
532
|
def recall_outline(query: str = "", limit: int = 12,
|
|
455
533
|
include: str = "memories,wiki,entities",
|