smolAmem 1.0.0__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.
Files changed (82) hide show
  1. smolamem-1.0.0/.env.example +44 -0
  2. smolamem-1.0.0/.github/workflows/docs.yml +71 -0
  3. smolamem-1.0.0/.github/workflows/release.yml +150 -0
  4. smolamem-1.0.0/.gitignore +82 -0
  5. smolamem-1.0.0/CHANGELOG.md +133 -0
  6. smolamem-1.0.0/LICENSE +21 -0
  7. smolamem-1.0.0/PKG-INFO +122 -0
  8. smolamem-1.0.0/README.md +78 -0
  9. smolamem-1.0.0/docker-compose.yml +47 -0
  10. smolamem-1.0.0/docs/adapters.md +149 -0
  11. smolamem-1.0.0/docs/api.md +81 -0
  12. smolamem-1.0.0/docs/backends.md +181 -0
  13. smolamem-1.0.0/docs/concepts.md +200 -0
  14. smolamem-1.0.0/docs/embedders.md +98 -0
  15. smolamem-1.0.0/docs/eval.md +213 -0
  16. smolamem-1.0.0/docs/index.md +115 -0
  17. smolamem-1.0.0/docs/quickstart.md +180 -0
  18. smolamem-1.0.0/evals/README.md +162 -0
  19. smolamem-1.0.0/evals/__init__.py +19 -0
  20. smolamem-1.0.0/evals/__main__.py +217 -0
  21. smolamem-1.0.0/evals/baselines/__init__.py +19 -0
  22. smolamem-1.0.0/evals/baselines/base.py +64 -0
  23. smolamem-1.0.0/evals/baselines/full_history.py +43 -0
  24. smolamem-1.0.0/evals/baselines/no_memory.py +31 -0
  25. smolamem-1.0.0/evals/baselines/summary_buffer.py +93 -0
  26. smolamem-1.0.0/evals/corpus/001_typescript_preference.json +28 -0
  27. smolamem-1.0.0/evals/corpus/002_react_to_vue_switch.json +28 -0
  28. smolamem-1.0.0/evals/corpus/003_project_facts.json +37 -0
  29. smolamem-1.0.0/evals/corpus/004_time_bounded_request.json +26 -0
  30. smolamem-1.0.0/evals/corpus/005_multi_fact_recall.json +26 -0
  31. smolamem-1.0.0/evals/corpus/README.md +80 -0
  32. smolamem-1.0.0/evals/metrics/__init__.py +11 -0
  33. smolamem-1.0.0/evals/metrics/recall.py +59 -0
  34. smolamem-1.0.0/evals/metrics/tokens.py +67 -0
  35. smolamem-1.0.0/evals/runners/__init__.py +11 -0
  36. smolamem-1.0.0/evals/runners/base.py +123 -0
  37. smolamem-1.0.0/evals/runners/mneme.py +137 -0
  38. smolamem-1.0.0/evals/schema.py +93 -0
  39. smolamem-1.0.0/mkdocs.yml +104 -0
  40. smolamem-1.0.0/pyproject.toml +175 -0
  41. smolamem-1.0.0/scripts/check.ps1 +46 -0
  42. smolamem-1.0.0/scripts/smoke.py +229 -0
  43. smolamem-1.0.0/src/mneme/__init__.py +57 -0
  44. smolamem-1.0.0/src/mneme/adapters/__init__.py +58 -0
  45. smolamem-1.0.0/src/mneme/adapters/langchain.py +143 -0
  46. smolamem-1.0.0/src/mneme/adapters/llamaindex.py +151 -0
  47. smolamem-1.0.0/src/mneme/adapters/openai_helper.py +192 -0
  48. smolamem-1.0.0/src/mneme/backends/__init__.py +33 -0
  49. smolamem-1.0.0/src/mneme/backends/base.py +176 -0
  50. smolamem-1.0.0/src/mneme/backends/memory.py +170 -0
  51. smolamem-1.0.0/src/mneme/backends/pgvector.py +400 -0
  52. smolamem-1.0.0/src/mneme/backends/qdrant.py +448 -0
  53. smolamem-1.0.0/src/mneme/backends/sqlite.py +493 -0
  54. smolamem-1.0.0/src/mneme/embeddings.py +212 -0
  55. smolamem-1.0.0/src/mneme/judge.py +209 -0
  56. smolamem-1.0.0/src/mneme/manager.py +750 -0
  57. smolamem-1.0.0/src/mneme/py.typed +0 -0
  58. smolamem-1.0.0/src/mneme/tiers/__init__.py +17 -0
  59. smolamem-1.0.0/src/mneme/tiers/episodic.py +108 -0
  60. smolamem-1.0.0/src/mneme/tiers/semantic.py +119 -0
  61. smolamem-1.0.0/src/mneme/tiers/working.py +78 -0
  62. smolamem-1.0.0/src/mneme/types.py +156 -0
  63. smolamem-1.0.0/tests/__init__.py +0 -0
  64. smolamem-1.0.0/tests/conftest.py +39 -0
  65. smolamem-1.0.0/tests/test_adapter_langchain.py +161 -0
  66. smolamem-1.0.0/tests/test_adapter_llamaindex.py +140 -0
  67. smolamem-1.0.0/tests/test_adapter_openai.py +180 -0
  68. smolamem-1.0.0/tests/test_backends.py +571 -0
  69. smolamem-1.0.0/tests/test_consolidate.py +389 -0
  70. smolamem-1.0.0/tests/test_embeddings.py +173 -0
  71. smolamem-1.0.0/tests/test_eval_harness.py +229 -0
  72. smolamem-1.0.0/tests/test_forget.py +330 -0
  73. smolamem-1.0.0/tests/test_judge.py +165 -0
  74. smolamem-1.0.0/tests/test_manager.py +133 -0
  75. smolamem-1.0.0/tests/test_retrieve.py +356 -0
  76. smolamem-1.0.0/tests/test_scheduler.py +183 -0
  77. smolamem-1.0.0/tests/test_smoke.py +17 -0
  78. smolamem-1.0.0/tests/test_tier_episodic.py +151 -0
  79. smolamem-1.0.0/tests/test_tier_semantic.py +127 -0
  80. smolamem-1.0.0/tests/test_tier_working.py +77 -0
  81. smolamem-1.0.0/tests/test_types.py +81 -0
  82. smolamem-1.0.0/uv.lock +3555 -0
@@ -0,0 +1,44 @@
1
+ # Example .env file. Copy to `.env` (gitignored) and fill in real values.
2
+ #
3
+ # `tests/conftest.py` loads this on test startup so any test using
4
+ # OpenAIEmbeddings (or any other env-dependent code) just works locally.
5
+ # The library itself never auto-loads dotenv.
6
+ #
7
+ # IMPORTANT — Windows / PowerShell users:
8
+ # Do NOT create .env with `echo ... > .env`. PowerShell's `>` redirection
9
+ # writes UTF-16 LE with a BOM, and python-dotenv reads UTF-8. The test
10
+ # suite will warn and skip key-dependent tests instead of crashing, but
11
+ # your tests still won't see the key.
12
+ #
13
+ # Correct ways to create `.env` on Windows:
14
+ # * Open `.env.example` in VS Code / Notepad, "Save As" -> `.env` with
15
+ # UTF-8 encoding.
16
+ # * Or PowerShell with explicit encoding:
17
+ # Set-Content -Encoding utf8 -Path .env -Value 'OPENAI_API_KEY=sk-...'
18
+
19
+ # ---------------------------------------------------------------------------
20
+ # OpenAI (embeddings + LLM judge)
21
+ # ---------------------------------------------------------------------------
22
+
23
+ # Required for OpenAIEmbeddings + OpenAILLMJudge integration tests. Without
24
+ # it the OpenAI-specific tests skip cleanly.
25
+ # Get one at https://platform.openai.com/api-keys.
26
+ OPENAI_API_KEY=sk-...
27
+
28
+ # ---------------------------------------------------------------------------
29
+ # Backend integration tests (v0.4)
30
+ # ---------------------------------------------------------------------------
31
+ # Setting either of the next two env vars opts that backend into the
32
+ # conformance suite. With neither set, qdrant + pgvector tests skip and
33
+ # memory + sqlite still run normally.
34
+ #
35
+ # To spin both services up locally:
36
+ # docker compose up -d
37
+ #
38
+ # Then uncomment the lines below.
39
+
40
+ # Qdrant: default REST endpoint exposed by docker-compose.yml.
41
+ # MNEME_TEST_QDRANT_URL=http://localhost:6333
42
+
43
+ # pgvector: connection string matching docker-compose.yml's defaults.
44
+ # MNEME_TEST_PGVECTOR_DSN=postgresql://mneme:mneme@localhost:5433/mneme
@@ -0,0 +1,71 @@
1
+ # Build + deploy the mkdocs-material site to GitHub Pages.
2
+ #
3
+ # Runs on every push to main of the public mirror repo. The private dev repo
4
+ # uses the same workflow file (it's part of the published tree) but won't
5
+ # have Pages enabled, so the deploy step no-ops there if the GITHUB_PAGES
6
+ # environment isn't configured. To enable for a fresh fork:
7
+ #
8
+ # 1. Settings -> Pages -> Source: "GitHub Actions"
9
+ # 2. Push to main. The workflow takes over from there.
10
+ name: Build docs
11
+
12
+ on:
13
+ push:
14
+ branches: [main]
15
+ paths:
16
+ - "docs/**"
17
+ - "mkdocs.yml"
18
+ - "src/**"
19
+ - "pyproject.toml"
20
+ - ".github/workflows/docs.yml"
21
+ workflow_dispatch:
22
+
23
+ permissions:
24
+ contents: read
25
+ pages: write
26
+ id-token: write
27
+
28
+ # Only one in-flight docs build at a time; cancel any superseded run.
29
+ concurrency:
30
+ group: "pages"
31
+ cancel-in-progress: false
32
+
33
+ jobs:
34
+ build:
35
+ runs-on: ubuntu-latest
36
+ steps:
37
+ - uses: actions/checkout@v4
38
+
39
+ - name: Set up Python
40
+ uses: actions/setup-python@v5
41
+ with:
42
+ python-version: "3.12"
43
+
44
+ - name: Install uv
45
+ uses: astral-sh/setup-uv@v3
46
+ with:
47
+ enable-cache: true
48
+
49
+ # Install the project with the [docs] extra. mkdocstrings autogen needs
50
+ # the package importable, so we install + the extra in one shot.
51
+ - name: Install project + docs deps
52
+ run: uv sync --extra docs
53
+
54
+ - name: Build site
55
+ run: uv run mkdocs build --strict
56
+
57
+ - name: Upload artifact
58
+ uses: actions/upload-pages-artifact@v3
59
+ with:
60
+ path: site
61
+
62
+ deploy:
63
+ needs: build
64
+ runs-on: ubuntu-latest
65
+ environment:
66
+ name: github-pages
67
+ url: ${{ steps.deployment.outputs.page_url }}
68
+ steps:
69
+ - name: Deploy to GitHub Pages
70
+ id: deployment
71
+ uses: actions/deploy-pages@v4
@@ -0,0 +1,150 @@
1
+ # Build a wheel + sdist and publish to PyPI via trusted publishing (OIDC).
2
+ #
3
+ # Triggers on tags matching ``v*`` pushed to the repo. No long-lived API
4
+ # token is stored anywhere — PyPI verifies the OIDC token GitHub Actions
5
+ # issues and authorises the upload directly.
6
+ #
7
+ # One-time PyPI setup (done in the PyPI web UI, not here):
8
+ #
9
+ # 1. Create an account at https://pypi.org/account/register/ if you
10
+ # don't have one.
11
+ # 2. Go to https://pypi.org/manage/account/publishing/ and add a
12
+ # "pending publisher":
13
+ # - PyPI Project Name: smolAmem
14
+ # - Owner: AshwinUgale
15
+ # - Repository name: ashwinugale-mneme
16
+ # - Workflow name: release.yml
17
+ # - Environment name: pypi (must match the `environment:` below)
18
+ # 3. The first time this workflow runs successfully, PyPI creates the
19
+ # real project and removes the "pending" status. Subsequent releases
20
+ # use the same publisher config without any further setup.
21
+ #
22
+ # Cutting a release:
23
+ #
24
+ # git tag v1.0.0
25
+ # git push private --tags # (your private remote)
26
+ # ./.cowork/publish.sh "v1.0.0" # also push to the public mirror
27
+ # # then on the PUBLIC mirror repo, create a tag matching the version:
28
+ # # git tag v1.0.0
29
+ # # git push origin v1.0.0
30
+ # # That tag push fires this workflow.
31
+
32
+ name: Release
33
+
34
+ on:
35
+ push:
36
+ tags:
37
+ - "v*"
38
+ workflow_dispatch:
39
+
40
+ permissions:
41
+ contents: read
42
+
43
+ concurrency:
44
+ group: release-${{ github.ref }}
45
+ cancel-in-progress: false
46
+
47
+ jobs:
48
+ build:
49
+ runs-on: ubuntu-latest
50
+ steps:
51
+ - uses: actions/checkout@v4
52
+
53
+ - name: Set up Python
54
+ uses: actions/setup-python@v5
55
+ with:
56
+ python-version: "3.12"
57
+
58
+ - name: Install uv
59
+ uses: astral-sh/setup-uv@v3
60
+ with:
61
+ enable-cache: true
62
+
63
+ - name: Verify tag matches package version
64
+ run: |
65
+ set -e
66
+ TAG_VERSION="${GITHUB_REF_NAME#v}"
67
+ PKG_VERSION="$(uv run --no-project python -c '
68
+ import tomllib, pathlib
69
+ print(tomllib.loads(pathlib.Path("pyproject.toml").read_text())["project"]["version"])
70
+ ')"
71
+ if [ "$TAG_VERSION" != "$PKG_VERSION" ]; then
72
+ echo "::error::tag $TAG_VERSION does not match pyproject version $PKG_VERSION"
73
+ exit 1
74
+ fi
75
+ echo "tag and pyproject agree on version $PKG_VERSION"
76
+
77
+ - name: Build sdist + wheel
78
+ run: uv build
79
+
80
+ - name: List build artifacts
81
+ run: ls -la dist/
82
+
83
+ - name: Upload artifacts
84
+ uses: actions/upload-artifact@v4
85
+ with:
86
+ name: dist
87
+ path: dist/
88
+
89
+ publish-pypi:
90
+ needs: build
91
+ runs-on: ubuntu-latest
92
+ # The environment name MUST match what's registered as the
93
+ # trusted-publisher environment in PyPI's "pending publisher"
94
+ # config. PyPI will reject the upload otherwise.
95
+ environment:
96
+ name: pypi
97
+ url: https://pypi.org/p/smolAmem
98
+ permissions:
99
+ # id-token: write is what lets GitHub mint the OIDC token PyPI
100
+ # uses to authenticate. contents: read is the default.
101
+ id-token: write
102
+ contents: read
103
+ steps:
104
+ - name: Download build artifacts
105
+ uses: actions/download-artifact@v4
106
+ with:
107
+ name: dist
108
+ path: dist/
109
+
110
+ - name: Publish to PyPI
111
+ uses: pypa/gh-action-pypi-publish@release/v1
112
+ with:
113
+ # No `password:` / `user:` — trusted publishing handles auth.
114
+ # `verbose: true` makes the upload log show why if it fails.
115
+ verbose: true
116
+
117
+ github-release:
118
+ needs: publish-pypi
119
+ runs-on: ubuntu-latest
120
+ permissions:
121
+ contents: write
122
+ steps:
123
+ - uses: actions/checkout@v4
124
+ with:
125
+ fetch-depth: 0
126
+
127
+ - name: Download build artifacts
128
+ uses: actions/download-artifact@v4
129
+ with:
130
+ name: dist
131
+ path: dist/
132
+
133
+ - name: Create GitHub Release
134
+ uses: softprops/action-gh-release@v2
135
+ with:
136
+ tag_name: ${{ github.ref_name }}
137
+ name: ${{ github.ref_name }}
138
+ body: |
139
+ See [CHANGELOG.md](./CHANGELOG.md) for what's in this release.
140
+
141
+ Install:
142
+
143
+ pip install smolAmem==${{ github.ref_name }}
144
+
145
+ (the leading `v` is dropped from the version in `pip` install lines)
146
+ generate_release_notes: true
147
+ fail_on_unmatched_files: true
148
+ files: |
149
+ dist/*.whl
150
+ dist/*.tar.gz
@@ -0,0 +1,82 @@
1
+ # Python
2
+ __pycache__/
3
+ *.py[cod]
4
+ *$py.class
5
+ *.so
6
+ .Python
7
+ build/
8
+ develop-eggs/
9
+ dist/
10
+ downloads/
11
+ eggs/
12
+ .eggs/
13
+ lib/
14
+ lib64/
15
+ parts/
16
+ sdist/
17
+ var/
18
+ wheels/
19
+ *.egg-info/
20
+ *.egg
21
+ MANIFEST
22
+
23
+ # uv
24
+ .venv/
25
+ .uv-cache/
26
+
27
+ # Testing / coverage
28
+ .pytest_cache/
29
+ .coverage
30
+ .coverage.*
31
+ htmlcov/
32
+ .tox/
33
+ .nox/
34
+ coverage.xml
35
+ *.cover
36
+ .cache/
37
+
38
+ # Mypy / ruff
39
+ .mypy_cache/
40
+ .dmypy.json
41
+ dmypy.json
42
+ .ruff_cache/
43
+
44
+ # Type checker
45
+ .pyre/
46
+ .pytype/
47
+
48
+ # IDEs
49
+ .idea/
50
+ .vscode/
51
+ *.swp
52
+ *.swo
53
+ *~
54
+
55
+ # Claude Code local config / memory (machine-local, never commit)
56
+ .claude/
57
+
58
+ # OS
59
+ .DS_Store
60
+ Thumbs.db
61
+
62
+ # Secrets / local env
63
+ .env
64
+ .env.*
65
+ !.env.example
66
+ *.local
67
+
68
+ # SQLite databases created during dev/eval
69
+ *.sqlite
70
+ *.sqlite3
71
+ *.db
72
+
73
+ # Eval artifacts (results get checked in selectively, not blanket)
74
+ .eval-cache/
75
+ out/
76
+
77
+ # mkdocs build output
78
+ site/
79
+
80
+ # NOTE: .cowork/ is intentionally NOT gitignored.
81
+ # It contains private dev context that we want versioned in the PRIVATE repo.
82
+ # It is excluded from the PUBLIC repo via .cowork/publish.sh.
@@ -0,0 +1,133 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project are documented here. Format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/); this project follows [Semantic Versioning](https://semver.org/spec/v2.0.0.html) from `1.0.0` onward.
4
+
5
+ > **Naming note:** install with `pip install smolAmem`; import as `import mneme`. Two-name pattern (same as Pillow/PIL) because `mneme` was already taken on PyPI when this library was published.
6
+
7
+ ## [Unreleased]
8
+
9
+ (empty)
10
+
11
+ ## [1.0.0] — 2026-05-23
12
+
13
+ First stable release. Public APIs are now under semver; minor bumps add features without breaking, patch bumps fix bugs, major bumps will be rare and pre-announced.
14
+
15
+ ### Added
16
+ - PyPI release as `smolAmem`. Install with `pip install smolAmem`; import name stays `mneme`.
17
+ - `Development Status :: 5 - Production/Stable` classifier.
18
+ - `CHANGELOG.md` (this file).
19
+ - GitHub Actions release workflow that builds + publishes to PyPI via OIDC trusted publishing (no long-lived API token).
20
+
21
+ ### Changed
22
+ - Dropped pre-alpha warnings from README and docs landing page.
23
+
24
+ ## [0.8.0] — 2026-05-23
25
+
26
+ Integration validation. No new features — every previously env-skipped backend test is now actually executed against real Qdrant + pgvector containers, and an end-to-end smoke script proves the full lifecycle works with real OpenAI.
27
+
28
+ ### Added
29
+ - `scripts/smoke.py` — end-to-end smoke test that wires `MemoryManager` + real `OpenAIEmbeddings` + real `OpenAILLMJudge` against the chosen backend and walks through write → retrieve → consolidate → retrieve → forget. `--backend {sqlite,qdrant,pgvector}`.
30
+ - `scripts/check.ps1` — Windows-native full check pipeline wrapper (ruff + format + mypy + pytest + `mkdocs build --strict`).
31
+ - `.cowork/publish.ps1` — Windows-native equivalent of `publish.sh` using `robocopy` instead of `rsync`.
32
+ - Qdrant payload indexes on `created_at` (DATETIME, required by `order_by`), `agent_id` and `tier` (KEYWORD, performance) created during `_ensure_collection`.
33
+
34
+ ### Fixed
35
+ - `QdrantBackend.list_recent()` no longer crashes with `"No range index for order_by key: created_at"`. Caused by missing payload index; now created at construction time.
36
+ - `QdrantBackend.touch()` no longer crashes on IDs that aren't valid hex UUIDs. Now silently skips them, matching the existing `get()` / `delete()` "unknown id" contract.
37
+
38
+ ### Changed
39
+ - README + docs lead with the OpenAI-embedder benchmark (`recall@5 = 1.000` at 67.7 tokens/test point) and keep the HashEmbedder row as the no-API-key deterministic baseline.
40
+
41
+ ## [0.7.0] — 2026-05-22
42
+
43
+ Public documentation site.
44
+
45
+ ### Added
46
+ - `[docs]` extra: mkdocs, mkdocs-material, mkdocstrings[python], pymdown-extensions.
47
+ - `mkdocs.yml` at repo root (Material theme, indigo palette, full feature set).
48
+ - Eight hand-written documentation pages under `docs/`: index, quickstart, concepts, backends, embedders, adapters, eval, api.
49
+ - `docs/api.md` autogenerated from docstrings via mkdocstrings (Google docstring style, source-order members, filtered to public symbols).
50
+ - `.github/workflows/docs.yml` — build + deploy to GitHub Pages on push to main via `actions/upload-pages-artifact@v3` + `actions/deploy-pages@v4`. `mkdocs build --strict` so any warning fails the build.
51
+
52
+ ### Changed
53
+ - README rewritten with badges, concise pitch, install/quickstart snippet, and links to the live docs site.
54
+
55
+ ## [0.6.0] — 2026-05-22
56
+
57
+ Eval harness.
58
+
59
+ ### Added
60
+ - `evals/` sibling directory at repo root (not shipped in the wheel).
61
+ - `evals/schema.py` — Pydantic models for the corpus shape (`Conversation`, `Turn`, `TestPoint`).
62
+ - `evals/corpus/` with five labelled starter conversations covering long-range preference recall, contradiction handling (newer-wins), multi-fact retrieval, in-flight tasks, and multi-fact recall queries.
63
+ - `evals/baselines/` — `MemoryStrategy` Protocol plus three reference strategies: `NoMemoryStrategy` (floor), `SummaryBufferStrategy` (LangChain-style rolling summary), `FullHistoryStrategy` (oracle ceiling).
64
+ - `evals/runners/base.py::EvalRunner` orchestrator + `evals/runners/mneme.py` adapter.
65
+ - `evals/metrics/recall.py::recall_at_k` and `evals/metrics/tokens.py::token_cost_summary` — both pure functions over `RunResult`.
66
+ - `python -m evals` CLI with flags `--corpus`, `--runner`, `--backend`, `--embedder`, `--output`, `--seed`, `--k`. `--with-answers` / `--judge` reserved for future LLM-judged accuracy.
67
+ - `tests/test_eval_harness.py` end-to-end coverage of all four strategies plus the CLI.
68
+
69
+ ## [0.5.0] — 2026-05-21
70
+
71
+ Framework adapters.
72
+
73
+ ### Added
74
+ - `mneme.adapters.MnemeChatMessageHistory` — subclass of LangChain's `BaseChatMessageHistory`. Dual-writes to working + episodic by default; `also_persist_episodic=False` for ephemeral chat.
75
+ - `mneme.adapters.MnemeLlamaIndexMemory` — subclass of LlamaIndex's `BaseMemory`. Same dual-write semantics.
76
+ - `mneme.adapters.context_for()` — raw-OpenAI helper returning `messages=[...]` with retrieved memory as a `system` block (with `[FACT id=...]` / `[EPISODE id=...]` citation markers) plus working-memory turns. Optional `token_budget` packs to a tiktoken (`cl100k_base`) count.
77
+ - Three optional extras: `[langchain]`, `[llamaindex]`, `[tokens]`.
78
+ - PEP 562 lazy submodule loading in `mneme.adapters.__init__` so users only pay for the framework deps they actually use.
79
+
80
+ ## [0.4.0] — 2026-05-21
81
+
82
+ Production-grade backends.
83
+
84
+ ### Added
85
+ - `mneme.QdrantBackend` — one Qdrant collection per backend instance; multi-tenancy via `agent_id` payload filter; cosine distance; UUID round-trip at the boundary.
86
+ - `mneme.PgVectorBackend` — psycopg3 sync, pgvector extension, `<=>` cosine operator. Schema mirrors `SQLiteBackend`.
87
+ - Conformance suite (`tests/test_backends.py`) now parametrises over `["memory", "sqlite", "qdrant", "pgvector"]`. Env-gated via `MNEME_TEST_QDRANT_URL` / `MNEME_TEST_PGVECTOR_DSN`.
88
+ - `docker-compose.yml` at repo root for local Qdrant + pgvector services.
89
+ - Two new extras: `[qdrant]`, `[pgvector]`.
90
+
91
+ ## [0.3.0] — 2026-05-21
92
+
93
+ Forgetting + scheduled background work.
94
+
95
+ ### Added
96
+ - `MemoryRecord.expires_at` — UTC datetime, default `None`. Round-trips through every backend.
97
+ - `MnemeBackend.touch(record_ids, *, now)` — persists access count + last-accessed timestamp.
98
+ - `retrieve()` calls `backend.touch()` on the returned top-k and defensively filters records with `expires_at <= now`.
99
+ - `MemoryManager.forget(*, now, ttl_only, access_floor, cold_age_days, max_per_tier)` — two-phase: TTL eviction, then access-frequency decay. Walks `(EPISODIC, SEMANTIC)`; working memory untouched.
100
+ - `MemoryManager.start_scheduler()` / `stop_scheduler()` — APScheduler `BackgroundScheduler` integration. `max_instances=1, coalesce=True` on both jobs.
101
+ - New `[scheduler]` extra: `apscheduler>=3.10`.
102
+
103
+ ## [0.2.0] — 2026-05-21
104
+
105
+ Real consolidation. Episodic → semantic pipeline driven by an LLM judge.
106
+
107
+ ### Added
108
+ - `mneme.LLMJudge` Protocol + `OpenAILLMJudge` (uses `response_format={"type":"json_schema","strict":true}`) + `MockLLMJudge` (handler callable + call log for tests).
109
+ - `MemoryManager.consolidate(*, since, batch_size, dedup_threshold, max_episodes)` — reads recent episodes, batches them, asks the judge to extract durable facts, dedups against existing semantic facts via cosine similarity (newer-wins-with-provenance merge).
110
+ - `MnemeBackend.list_recent(*, agent_id, tier, since, limit)` added to the protocol.
111
+
112
+ ## [0.1.0] — 2026-05-21
113
+
114
+ Walking skeleton. The library does something end-to-end.
115
+
116
+ ### Added
117
+ - `mneme.MemoryTier` enum + `MemoryRecord` base + `WorkingMemory` / `EpisodicMemory` / `SemanticFact` subclasses.
118
+ - `mneme.MnemeBackend` Protocol + reference `InMemoryBackend`.
119
+ - `mneme.SQLiteBackend` using sqlite-vec via a `vec0` virtual table joined by rowid.
120
+ - `mneme.EmbeddingProvider` Protocol + `OpenAIEmbeddings` (defaults to `text-embedding-3-small`) + `HashEmbedder` (deterministic, no-key test double).
121
+ - Three tier classes (`WorkingMemoryTier`, `EpisodicMemoryTier`, `SemanticMemoryTier`).
122
+ - `MemoryManager` facade exposing `.working`, `.episodic`, `.semantic` as attributes and a single `retrieve(query, *, k, tiers, authority_weights, half_life_days, use_confidence, now)` with multiplicative score fusion (similarity × authority × recency × confidence).
123
+
124
+ [unreleased]: https://github.com/ashwinugale/ashwinugale-mneme/compare/v1.0.0...HEAD
125
+ [1.0.0]: https://github.com/ashwinugale/ashwinugale-mneme/releases/tag/v1.0.0
126
+ [0.8.0]: https://github.com/ashwinugale/ashwinugale-mneme/releases/tag/v0.8.0
127
+ [0.7.0]: https://github.com/ashwinugale/ashwinugale-mneme/releases/tag/v0.7.0
128
+ [0.6.0]: https://github.com/ashwinugale/ashwinugale-mneme/releases/tag/v0.6.0
129
+ [0.5.0]: https://github.com/ashwinugale/ashwinugale-mneme/releases/tag/v0.5.0
130
+ [0.4.0]: https://github.com/ashwinugale/ashwinugale-mneme/releases/tag/v0.4.0
131
+ [0.3.0]: https://github.com/ashwinugale/ashwinugale-mneme/releases/tag/v0.3.0
132
+ [0.2.0]: https://github.com/ashwinugale/ashwinugale-mneme/releases/tag/v0.2.0
133
+ [0.1.0]: https://github.com/ashwinugale/ashwinugale-mneme/releases/tag/v0.1.0
smolamem-1.0.0/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Ashwin Ugale
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,122 @@
1
+ Metadata-Version: 2.4
2
+ Name: smolAmem
3
+ Version: 1.0.0
4
+ Summary: Multi-tier long-term memory for LLM agents. Install: pip install smolAmem. Import: import mneme.
5
+ Project-URL: Homepage, https://ashwinugale.github.io/ashwinugale-mneme/
6
+ Project-URL: Documentation, https://ashwinugale.github.io/ashwinugale-mneme/
7
+ Project-URL: Repository, https://github.com/ashwinugale/ashwinugale-mneme
8
+ Project-URL: Issues, https://github.com/ashwinugale/ashwinugale-mneme/issues
9
+ Author-email: Ashwin Ugale <ugaleashwin@gmail.com>
10
+ License: MIT
11
+ License-File: LICENSE
12
+ Keywords: agents,llm,memory,rag,vector-search
13
+ Classifier: Development Status :: 5 - Production/Stable
14
+ Classifier: Intended Audience :: Developers
15
+ Classifier: License :: OSI Approved :: MIT License
16
+ Classifier: Programming Language :: Python :: 3
17
+ Classifier: Programming Language :: Python :: 3.11
18
+ Classifier: Programming Language :: Python :: 3.12
19
+ Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
20
+ Requires-Python: >=3.11
21
+ Provides-Extra: docs
22
+ Requires-Dist: mkdocs-material>=9.5; extra == 'docs'
23
+ Requires-Dist: mkdocs>=1.6; extra == 'docs'
24
+ Requires-Dist: mkdocstrings[python]>=0.26; extra == 'docs'
25
+ Requires-Dist: pymdown-extensions>=10.7; extra == 'docs'
26
+ Provides-Extra: langchain
27
+ Requires-Dist: langchain-core>=0.3; extra == 'langchain'
28
+ Provides-Extra: llamaindex
29
+ Requires-Dist: llama-index-core>=0.11; extra == 'llamaindex'
30
+ Provides-Extra: openai
31
+ Requires-Dist: openai>=1.40; extra == 'openai'
32
+ Provides-Extra: pgvector
33
+ Requires-Dist: pgvector>=0.3; extra == 'pgvector'
34
+ Requires-Dist: psycopg[binary]>=3.2; extra == 'pgvector'
35
+ Provides-Extra: qdrant
36
+ Requires-Dist: qdrant-client>=1.12; extra == 'qdrant'
37
+ Provides-Extra: scheduler
38
+ Requires-Dist: apscheduler>=3.10; extra == 'scheduler'
39
+ Provides-Extra: sqlite
40
+ Requires-Dist: sqlite-vec>=0.1.6; extra == 'sqlite'
41
+ Provides-Extra: tokens
42
+ Requires-Dist: tiktoken>=0.7; extra == 'tokens'
43
+ Description-Content-Type: text/markdown
44
+
45
+ # Mneme
46
+
47
+ > Multi-tier long-term memory for LLM agents. Working / episodic / semantic tiers, pluggable storage backends, framework-agnostic adapters, and explicit forgetting + consolidation.
48
+
49
+ [![docs](https://img.shields.io/badge/docs-ashwinugale.github.io%2Fashwinugale--mneme-blue)](https://ashwinugale.github.io/ashwinugale-mneme/)
50
+ [![python](https://img.shields.io/badge/python-3.11%2B-blue)](https://www.python.org/)
51
+ [![license](https://img.shields.io/badge/license-MIT-green)](./LICENSE)
52
+
53
+ **Status:** 1.0 released. APIs are stable; semver from here. Bug reports welcome.
54
+
55
+ ## Why
56
+
57
+ Every agent framework ships with toy memory: last-N messages, or an LLM-summarised buffer. Real agents need to remember user preferences across weeks, recall specific past interactions, and store semantic facts extracted from many interactions — and they need to forget things that stop being relevant.
58
+
59
+ Mneme is the library you wish existed.
60
+
61
+ ## Install
62
+
63
+ ```bash
64
+ pip install smolAmem # core only
65
+ pip install "smolAmem[sqlite,openai]" # SQLite + OpenAI embeddings
66
+ pip install "smolAmem[qdrant,openai]" # production vector backend
67
+ ```
68
+
69
+ > **Heads-up on naming:** PyPI install name is `smolAmem` (the `mneme` slot was already taken). Python import name stays `mneme` — same dual-name pattern as `Pillow` / `PIL` or `pyyaml` / `yaml`. So you `pip install smolAmem` but write `import mneme` everywhere in your code.
70
+
71
+ ## Quickstart
72
+
73
+ ```python
74
+ from mneme import MemoryManager, SQLiteBackend, OpenAIEmbeddings
75
+
76
+ m = MemoryManager(
77
+ agent_id="alice",
78
+ backend=SQLiteBackend(path="mneme.db", dimensions=1536),
79
+ embedder=OpenAIEmbeddings(),
80
+ )
81
+
82
+ m.episodic.add("user mostly works in TypeScript", metadata={"role": "user"})
83
+
84
+ for r in m.retrieve("what language does the user prefer?", k=3):
85
+ print(r.score, r.record.content)
86
+ ```
87
+
88
+ Full walkthrough: [docs/quickstart](https://ashwinugale.github.io/ashwinugale-mneme/quickstart/).
89
+
90
+ ## Documentation
91
+
92
+ The full site lives at **[ashwinugale.github.io/ashwinugale-mneme](https://ashwinugale.github.io/ashwinugale-mneme/)**.
93
+
94
+ - [Concepts](https://ashwinugale.github.io/ashwinugale-mneme/concepts/) — the three-tier model, retrieval, consolidation, forgetting.
95
+ - [Backends](https://ashwinugale.github.io/ashwinugale-mneme/backends/) — InMemory, SQLite, Qdrant, pgvector.
96
+ - [Adapters](https://ashwinugale.github.io/ashwinugale-mneme/adapters/) — LangChain, LlamaIndex, raw OpenAI.
97
+ - [Eval harness](https://ashwinugale.github.io/ashwinugale-mneme/eval/) — reproducible recall@k + token-cost benchmark.
98
+ - [API reference](https://ashwinugale.github.io/ashwinugale-mneme/api/) — autogen from docstrings.
99
+
100
+ ## Benchmark snapshot
101
+
102
+ From the v0.6 [eval harness](https://ashwinugale.github.io/ashwinugale-mneme/eval/) on the 5-conversation starter corpus, k=5:
103
+
104
+ | Strategy | recall@5 | tokens / test point |
105
+ |---|---|---|
106
+ | `no_memory` | 0.000 | 0.0 |
107
+ | `mneme` (hash, deterministic) | 0.833 | 68.0 |
108
+ | **`mneme` (OpenAI embeddings)** | **1.000** | **67.7** |
109
+ | `full_history` | 1.000 | 141.0 |
110
+ | `summary_buffer` | 1.000 | 165.3 |
111
+
112
+ Mneme matches the full-history oracle for accuracy at **less than half** the token cost. The HashEmbedder row is the cheap deterministic baseline that runs without an API key — useful in CI and for reviewers reproducing numbers.
113
+
114
+ Reproduce:
115
+
116
+ ```bash
117
+ uv run python -m evals --runner mneme --embedder openai --output out/mneme.json
118
+ ```
119
+
120
+ ## License
121
+
122
+ MIT. See [LICENSE](./LICENSE).