orma-ai 0.1.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 (69) hide show
  1. orma_ai-0.1.0/.gitignore +51 -0
  2. orma_ai-0.1.0/HANDOVER.md +115 -0
  3. orma_ai-0.1.0/LICENSE +176 -0
  4. orma_ai-0.1.0/PKG-INFO +234 -0
  5. orma_ai-0.1.0/README.md +213 -0
  6. orma_ai-0.1.0/docs/ARCHITECTURE.md +103 -0
  7. orma_ai-0.1.0/docs/CLIENTS.md +83 -0
  8. orma_ai-0.1.0/docs/SETUP_GUIDE.md +44 -0
  9. orma_ai-0.1.0/docs/superpowers/plans/2026-10-12-memory-core.md +2949 -0
  10. orma_ai-0.1.0/docs/superpowers/plans/2026-10-13-proxy-cli.md +978 -0
  11. orma_ai-0.1.0/docs/superpowers/specs/2026-10-12-local-neurosymbolic-memory-design.md +152 -0
  12. orma_ai-0.1.0/eval/__init__.py +1 -0
  13. orma_ai-0.1.0/eval/cases.json +143 -0
  14. orma_ai-0.1.0/eval/run.py +207 -0
  15. orma_ai-0.1.0/eval/score.py +98 -0
  16. orma_ai-0.1.0/eval/test_cases.json +151 -0
  17. orma_ai-0.1.0/implementation.md +49 -0
  18. orma_ai-0.1.0/orma/__init__.py +7 -0
  19. orma_ai-0.1.0/orma/__main__.py +5 -0
  20. orma_ai-0.1.0/orma/cli.py +192 -0
  21. orma_ai-0.1.0/orma/clock.py +110 -0
  22. orma_ai-0.1.0/orma/config.py +89 -0
  23. orma_ai-0.1.0/orma/embed.py +53 -0
  24. orma_ai-0.1.0/orma/encode.py +52 -0
  25. orma_ai-0.1.0/orma/llm.py +91 -0
  26. orma_ai-0.1.0/orma/memory.py +148 -0
  27. orma_ai-0.1.0/orma/messages.py +12 -0
  28. orma_ai-0.1.0/orma/recall/__init__.py +148 -0
  29. orma_ai-0.1.0/orma/recall/pack.py +87 -0
  30. orma_ai-0.1.0/orma/recall/rank.py +46 -0
  31. orma_ai-0.1.0/orma/serve/__init__.py +1 -0
  32. orma_ai-0.1.0/orma/serve/capture.py +97 -0
  33. orma_ai-0.1.0/orma/serve/proxy.py +174 -0
  34. orma_ai-0.1.0/orma/serve/scheduler.py +57 -0
  35. orma_ai-0.1.0/orma/sleep/__init__.py +126 -0
  36. orma_ai-0.1.0/orma/sleep/consolidate.py +240 -0
  37. orma_ai-0.1.0/orma/sleep/extract.py +169 -0
  38. orma_ai-0.1.0/orma/store/__init__.py +6 -0
  39. orma_ai-0.1.0/orma/store/db.py +160 -0
  40. orma_ai-0.1.0/orma/store/index.py +103 -0
  41. orma_ai-0.1.0/orma/store/records.py +122 -0
  42. orma_ai-0.1.0/orma/store/store.py +452 -0
  43. orma_ai-0.1.0/orma/text.py +86 -0
  44. orma_ai-0.1.0/pyproject.toml +39 -0
  45. orma_ai-0.1.0/scripts/demo_ollama.py +93 -0
  46. orma_ai-0.1.0/scripts/latency_smoke.py +48 -0
  47. orma_ai-0.1.0/tasks.md +27 -0
  48. orma_ai-0.1.0/tests/conftest.py +103 -0
  49. orma_ai-0.1.0/tests/test_capture.py +66 -0
  50. orma_ai-0.1.0/tests/test_cli.py +73 -0
  51. orma_ai-0.1.0/tests/test_clock.py +65 -0
  52. orma_ai-0.1.0/tests/test_config.py +23 -0
  53. orma_ai-0.1.0/tests/test_consolidate.py +221 -0
  54. orma_ai-0.1.0/tests/test_embed.py +32 -0
  55. orma_ai-0.1.0/tests/test_encode.py +56 -0
  56. orma_ai-0.1.0/tests/test_eval.py +94 -0
  57. orma_ai-0.1.0/tests/test_extract.py +81 -0
  58. orma_ai-0.1.0/tests/test_llm.py +114 -0
  59. orma_ai-0.1.0/tests/test_memory.py +113 -0
  60. orma_ai-0.1.0/tests/test_proxy.py +284 -0
  61. orma_ai-0.1.0/tests/test_rank_pack.py +104 -0
  62. orma_ai-0.1.0/tests/test_recall.py +106 -0
  63. orma_ai-0.1.0/tests/test_scheduler.py +74 -0
  64. orma_ai-0.1.0/tests/test_sleep.py +102 -0
  65. orma_ai-0.1.0/tests/test_stats.py +22 -0
  66. orma_ai-0.1.0/tests/test_store_db.py +123 -0
  67. orma_ai-0.1.0/tests/test_store_episodes.py +38 -0
  68. orma_ai-0.1.0/tests/test_store_events.py +22 -0
  69. orma_ai-0.1.0/tests/test_text.py +33 -0
@@ -0,0 +1,51 @@
1
+ # Python bytecode & cache
2
+ __pycache__/
3
+ *.py[cod]
4
+ *$py.class
5
+ *.so
6
+ .pytest_cache/
7
+ .ruff_cache/
8
+ .mypy_cache/
9
+
10
+ # Virtual Environment
11
+ .venv/
12
+ venv/
13
+ env/
14
+ ENV/
15
+
16
+ # Local databases & storage
17
+ .smruti/
18
+ .smriti/
19
+ .orma/
20
+ *.db
21
+ *.db-wal
22
+ *.db-shm
23
+ *.sqlite
24
+ *.sqlite3
25
+
26
+ # Build & packaging artifacts
27
+ build/
28
+ dist/
29
+ *.egg-info/
30
+ *.whl
31
+
32
+ # Test & coverage
33
+ .coverage
34
+ htmlcov/
35
+
36
+ # Environment & secrets
37
+ .env
38
+ .env.*
39
+ !.env.example
40
+
41
+ # IDE & OS
42
+ .vscode/
43
+ .idea/
44
+ .DS_Store
45
+ Thumbs.db
46
+ *.swp
47
+ *~
48
+
49
+ # Benchmark & eval run logs
50
+ eval/runs/
51
+ scratch/
@@ -0,0 +1,115 @@
1
+ # Smruti handover
2
+
3
+ Everything you need to take over Smruti: what it is, how to run it, how it is built and why, what has been verified, what is broken, and what to do next.
4
+
5
+ ## 1. What it is, in one paragraph
6
+
7
+ Smruti is a general long-term memory layer for small local LLMs (reference: Qwen2.5-3B on llama.cpp or `llama3.2:3b` on Ollama, 4k-token budget, an 8 GB laptop). Anything can be added: chat turns, notes, documents, tool output. Every record is kept in full and is searchable at once. In the background, while the machine is idle, the same local model reads new records and builds two kinds of structure that plain search cannot give: **states** (what is true now, one value at a time, superseded when it changes, with history) and **dated events**. Recall needs no LLM: hybrid search over the kept sentences plus the current states, rendered into the prompt with outdated lines marked. It ships as an SDK (`Memory.add / search / sleep / build_context`), a CLI, and an OpenAI-compatible proxy that adds memory to any chat client.
8
+
9
+ ## 2. Run it (about 5 minutes)
10
+
11
+ Python 3.10 or newer.
12
+
13
+ ```bash
14
+ git clone https://github.com/wizardwithcodehazard/smruti.git && cd smruti
15
+ python -m venv .venv && source .venv/bin/activate # Windows: .venv\Scripts\activate
16
+ pip install -e ".[dev]"
17
+ python -m pytest -q # no downloads needed
18
+ ```
19
+
20
+ ```bash
21
+ python -m smruti add "My dentist is Dr. Rao in Kothrud." # a note
22
+ python -m smruti add notes/handbook.md # a document
23
+ python -m smruti search "who is my dentist?"
24
+ python -m smruti sleep --model MODEL --upstream http://127.0.0.1:PORT/v1
25
+ python -m smruti facts --history
26
+
27
+ # the chat proxy (Ollama default; llama.cpp: --upstream http://127.0.0.1:PORT/v1)
28
+ python -m smruti proxy --model llama3.2:3b
29
+ ```
30
+
31
+ `python -m smruti` always runs this checkout, even if another `smruti` command is first on PATH. The first run downloads the bge-small embedding model (about 130 MB). Memory lives in `~/.smruti/memory.db` unless `SMRUTI_DIR` is set. A database from version 1 keeps its records; run `smruti rebuild` once.
32
+
33
+ ## 3. Repo map
34
+
35
+ | Path | What it is |
36
+ |---|---|
37
+ | `smruti/config.py` | `SmrutiConfig`: every tunable and every ablation switch (`enable_*`) |
38
+ | `smruti/text.py` | Sentence splitting, code-block markers, whole-word matching |
39
+ | `smruti/clock.py` | Timezone-aware days; date words resolved against when they were said |
40
+ | `smruti/store/` | SQLite schema (`db.py`), vector and FTS5 helpers (`index.py`), records, `Store` |
41
+ | `smruti/encode.py` | Adding a record: near-copy gate, sentences, indexing |
42
+ | `smruti/sleep/` | Batching and the lease (`__init__.py`), the two-list extraction (`extract.py`), checks and time maintenance (`consolidate.py`) |
43
+ | `smruti/recall/` | Hybrid search, ranking (`rank.py`), budgeted packing (`pack.py`) |
44
+ | `smruti/serve/` | The proxy, turn capture, the background sleep scheduler |
45
+ | `smruti/memory.py`, `smruti/cli.py` | The SDK and the `smruti` command |
46
+ | `eval/` | Dev cases (`cases.json`), held-out test cases (`test_cases.json`), the harness (`run.py`, `score.py`) |
47
+ | `tests/` | Unit and integration tests with `FakeEmbedder`, `NoisyEmbedder`, `FakeLLM` and `seed_state` |
48
+ | `scripts/` | Real-model chat demo, latency and needle-in-a-haystack smoke test |
49
+ | `docs/ARCHITECTURE.md` | Engineering overview of v2 (current) |
50
+ | `docs/superpowers/` | The v1 design spec and plans (historical) |
51
+
52
+ ## 4. How it works
53
+
54
+ Read `docs/ARCHITECTURE.md`. In short:
55
+
56
+ - **add** (no LLM): keep the record, split into sentences, embed and index them. A near-copy (≥ 0.97) is counted, not stored.
57
+ - **sleep** (one LLM call per batch): numbered lines in, `{user_name, states, events}` out, each citing a line number. Code checks the citation, who it is about (pronouns carry over from the last name before them), that the value is in the line, and maintains one value per entity and attribute over time.
58
+ - **recall** (no LLM, no writes): hybrid search with a bounded recency boost; the user's current states always shown; superseded sentences marked `[outdated]`.
59
+
60
+ ## 5. Key decisions and the history behind them (read before changing things)
61
+
62
+ | Decision | Why (what went wrong otherwise) |
63
+ |---|---|
64
+ | **v2: episodes are the memory; only states and events are structured** | v1 extracted a general triple graph. On Qwen2.5-3B the triples were often wrong (`user allergic_to Asha`), yet answers were right because the source sentence came along. Every repair (quotes, holder labels, learned cardinality, role aliases) added fields for a 3B model to get wrong and doubled sleep time (~40 s to ~110 s for 3 turns). Facts found swung 6/12 → 0/12 → 5/12 between patches. |
65
+ | Records are never deleted | v1 pruned raw turns after 7 days and kept the lossy extraction forever, so a bad extraction was permanent. Now `rebuild` can re-read everything with a better model. |
66
+ | The model cites line numbers, not quotes | Copying quotes made the answer long (the slow part) and needed fuzzy matching. A line number is a few tokens and exact. |
67
+ | Only one-valued states are structured | One-valued state is what plain search cannot do (what is true *now*). Many-valued facts (likes, allergies, hobbies) are found as sentences; no cardinality guessing is needed. |
68
+ | Who a memory is about is resolved in code; the model's label is not trusted | Qwen2.5-3B labelled "I live in Pune" as about someone else. First-person words in the user's own lines mean the user; "she" carries over the last name before it (Panini's anuvrtti). The two pronoun lists are config, replaceable per language. |
69
+ | No hand-written meaning heuristics | The pre-v1 engine was full of them and broke on ordinary input. Structural rules (sentence ends, code fences, dates, closed pronoun classes) are fine. |
70
+ | Recall never writes and never calls an LLM | Speed, and "retrieval is not evidence": a memory must not get stronger because it was retrieved. |
71
+ | Similarity weighted against a data-adaptive floor | bge-small gives unrelated short texts about 0.4–0.6 cosine, so plain rank fusion pulled in junk. |
72
+ | Others' states need lexical evidence to be shown | In a fresh space (before the floor warms up) vector-only matches put unrelated people's states into "Now true". |
73
+ | Recency is a bounded boost (`use_weight`) | With ACT-R decay 0.5 alone, a 90-day-old memory scores about 0.1 of a fresh one, so fresh trivia would outrank an old relevant fact. The boost moves rank by at most 30%. |
74
+ | Dates: the model copies date words, code resolves them in the user's timezone | Small models get date arithmetic wrong; UTC log dates put "yesterday" on the wrong day between 00:00 and 05:30 IST. |
75
+ | The novelty gate drops only near-copies (0.97) | Embeddings barely see negation: "is allergic to" vs "is not allergic to" is 0.883, so a looser gate dropped corrections. |
76
+ | Today's date in the memory block | Otherwise the model said "a few months ago" for an event four days earlier. |
77
+ | No eval names in the extraction prompt | v1 put "my sister Asha" in the prompt while the eval tested that exact sentence. |
78
+
79
+ ## 6. What has been verified
80
+
81
+ - **Tests:** `python -m pytest -q`, all passing, including the proxy against a fake upstream (streaming, disconnects, malformed bodies, CSRF guard, secret masking).
82
+ - **Real model:** Qwen2.5-3B-Instruct Q4_K_M on llama.cpp, eval dev split; see §9 for how to run it. Results of the latest run are in `tasks.md`.
83
+ - **Not verified:** any public benchmark (LongMemEval); the held-out test split beyond a single run; client configs in `docs/CLIENTS.md`; runtimes other than Ollama and llama.cpp.
84
+
85
+ ## 7. Known issues and limitations (most important first)
86
+
87
+ 1. **Extraction coverage is bounded by the sleep model.** A 3B model misses states. Sentences are still found by search, but "Now true" and `[outdated]` depend on sleep. `rebuild` with a 7B model is the cheapest improvement.
88
+ 2. **The eval is small** (8 dev cases, 10 test cases, keyword-scored answers). Treat differences of one or two cases as noise.
89
+ 3. **English-centred perception.** The prompt, date parser, FTS stemmer and pronoun lists are English; Hinglish works only as far as the model and embedder manage.
90
+ 4. **"user" filed for someone else's state is not caught** when the line has first-person words ("my sister Asha lives in Delhi" filed as the user's). The sentence shown with it lets the chat model correct it.
91
+ 5. **Fresh spaces are noisier** until `novelty_warmup` records exist.
92
+ 6. **Token counts are an estimate** (`chars_per_token` = 3.5).
93
+ 7. **Sleep competes with chat** for the GPU on small machines; `--sleep-upstream` can point sleep at another server.
94
+ 8. **No `LICENSE` file yet,** although `pyproject.toml` says Apache-2.0.
95
+
96
+ ## 8. What to do next
97
+
98
+ 1. Run the held-out test split once and report it next to dev, with the episodic-only baseline (`--set enable_semantic=false`).
99
+ 2. LongMemEval (oracle split) with last-k, full-context and plain-RAG baselines.
100
+ 3. A stronger sleep model through `rebuild` (7B on a second server) and measure the gain.
101
+ 4. Grow the eval to 30–50 cases, judged by a larger model instead of keywords.
102
+ 5. Coding sessions: tool-output memory (what was tried, what worked), now as a separate, tested module.
103
+
104
+ ## 9. Working on the code
105
+
106
+ - **Tests first.** The fakes make tests deterministic and fast. `seed_state` creates a state backed by a real sentence.
107
+ - **Every mechanism gets an `enable_*` switch** and stays only if turning it off hurts the eval.
108
+ - **Run the eval after every change to sleep or recall:** `python -m eval.run --upstream URL --model MODEL --label NAME` (dev). Ablate with `--set enable_x=false`. Compare with `--compare eval/runs/a.json eval/runs/b.json`. Run `--split test` only to report, never to tune.
109
+ - **Debug extraction by replaying:** `smruti.sleep.extract.build_messages(lines, context)` with `LLMClient.chat_json(..., schema=JSON_SCHEMA)`. Import the module with `importlib.import_module("smruti.sleep.extract")`, because `smruti.sleep` re-exports a function named `extract`.
110
+
111
+ ## 10. History
112
+
113
+ - Pre-v1: a coding-agent memory with anti-memories, MCP tools and hooks; replaced.
114
+ - v1 (Plans 1–2, Batches A and C): proxy, triple graph with spreading activation, priming, summaries, procedures, quotes, kartā labels, learned cardinality. Superseded by v2 for the reasons in §5; it is in git history.
115
+ - v2: the general, episode-first layer described here.
orma_ai-0.1.0/LICENSE ADDED
@@ -0,0 +1,176 @@
1
+ Apache License
2
+ Version 2.0, January 2004
3
+ http://www.apache.org/licenses/
4
+
5
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6
+
7
+ 1. Definitions.
8
+
9
+ "License" shall mean the terms and conditions for use, reproduction,
10
+ and distribution as defined by Sections 1 through 9 of this document.
11
+
12
+ "Licensor" shall mean the copyright owner or entity authorized by
13
+ the copyright owner that is granting the License.
14
+
15
+ "Legal Entity" shall mean the union of the acting entity and all
16
+ other entities that control, are controlled by, or are under common
17
+ control with that entity. For the purposes of this definition,
18
+ "control" means (i) the power, direct or indirect, to cause the
19
+ direction or management of such entity, whether by contract or
20
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
21
+ outstanding shares, or (iii) beneficial ownership of such entity.
22
+
23
+ "You" (or "Your") shall mean an individual or Legal Entity
24
+ exercising permissions granted by this License.
25
+
26
+ "Source" form shall mean the preferred form for making modifications,
27
+ including but not limited to software source code, documentation
28
+ source, and configuration files.
29
+
30
+ "Object" form shall mean any form resulting from mechanical
31
+ transformation or translation of a Source form, including but
32
+ not limited to compiled object code, generated documentation,
33
+ and conversions to other media types.
34
+
35
+ "Work" shall mean the work of authorship, whether in Source or
36
+ Object form, made available under the License, as indicated by a
37
+ copyright notice that is included in or attached to the work
38
+ (an example is provided in the Appendix below).
39
+
40
+ "Derivative Works" shall mean any work, whether in Source or Object
41
+ form, that is based on (or derived from) the Work and for which the
42
+ editorial revisions, annotations, elaborations, or other modifications
43
+ represent, as a whole, an original work of authorship. For the purposes
44
+ of this License, Derivative Works shall not include works that remain
45
+ separable from, or merely link (or bind by name) to the interfaces of,
46
+ the Work and Derivative Works thereof.
47
+
48
+ "Contribution" shall mean any work of authorship, including
49
+ the original version of the Work and any modifications or additions
50
+ to that Work or Derivative Works thereof, that is intentionally
51
+ submitted to Licensor for inclusion in the Work by the copyright owner
52
+ or by an individual or Legal Entity authorized to submit on behalf of
53
+ the copyright owner. For the purposes of this definition, "submitted"
54
+ means any form of electronic, verbal, or written communication sent
55
+ to the Licensor or its representatives, including but not limited to
56
+ communication on electronic mailing lists, source code control systems,
57
+ and issue tracking systems that are managed by, or on behalf of, the
58
+ Licensor for the purpose of discussing and improving the Work, but
59
+ excluding communication that is conspicuously marked or otherwise
60
+ designated in writing by the copyright owner as "Not a Contribution."
61
+
62
+ "Contributor" shall mean Licensor and any individual or Legal Entity
63
+ on behalf of whom a Contribution has been received by Licensor and
64
+ subsequently incorporated within the Work.
65
+
66
+ 2. Grant of Copyright License. Subject to the terms and conditions of
67
+ this License, each Contributor hereby grants to You a perpetual,
68
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69
+ copyright license to reproduce, prepare Derivative Works of,
70
+ publicly display, publicly perform, sublicense, and distribute the
71
+ Work and such Derivative Works in Source or Object form.
72
+
73
+ 3. Grant of Patent License. Subject to the terms and conditions of
74
+ this License, each Contributor hereby grants to You a perpetual,
75
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76
+ (except as stated in this section) patent license to make, have made,
77
+ use, offer to sell, sell, import, and otherwise transfer the Work,
78
+ where such license applies only to those patent claims licensable
79
+ by such Contributor that are necessarily infringed by their
80
+ Contribution(s) alone or by combination of their Contribution(s)
81
+ with the Work to which such Contribution(s) was submitted. If You
82
+ institute patent litigation against any entity (including a
83
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
84
+ or a Contribution incorporated within the Work constitutes direct
85
+ or contributory patent infringement, then any patent licenses
86
+ granted to You under this License for that Work shall terminate
87
+ as of the date such litigation is filed.
88
+
89
+ 4. Redistribution. You may reproduce and distribute copies of the
90
+ Work or Derivative Works thereof in any medium, with or without
91
+ modifications, and in Source or Object form, provided that You
92
+ meet the following conditions:
93
+
94
+ (a) You must give any other recipients of the Work or
95
+ Derivative Works a copy of this License; and
96
+
97
+ (b) You must cause any modified files to carry prominent notices
98
+ stating that You changed the files; and
99
+
100
+ (c) You must retain, in the Source form of any Derivative Works
101
+ that You distribute, all copyright, patent, trademark, and
102
+ attribution notices from the Source form of the Work,
103
+ excluding those notices that do not pertain to any part of
104
+ the Derivative Works; and
105
+
106
+ (d) If the Work includes a "NOTICE" text file as part of its
107
+ distribution, then any Derivative Works that You distribute must
108
+ include a readable copy of the attribution notices contained
109
+ within such NOTICE file, excluding those notices that do not
110
+ pertain to any part of the Derivative Works, in at least one
111
+ of the following places: within a NOTICE text file distributed
112
+ as part of the Derivative Works; within the Source form or
113
+ documentation, if provided along with the Derivative Works; or,
114
+ within a display generated by the Derivative Works, if and
115
+ wherever such third-party notices normally appear. The contents
116
+ of the NOTICE file are for informational purposes only and
117
+ do not modify the License. You may add Your own attribution
118
+ notices within Derivative Works that You distribute, alongside
119
+ or as an addendum to the NOTICE text from the Work, provided
120
+ that such additional attribution notices cannot be construed
121
+ as modifying the License.
122
+
123
+ You may add Your own copyright statement to Your modifications and
124
+ may provide additional or different license terms and conditions
125
+ for use, reproduction, or distribution of Your modifications, or
126
+ for any such Derivative Works as a whole, provided Your use,
127
+ reproduction, and distribution of the Work otherwise complies with
128
+ the conditions stated in this License.
129
+
130
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
131
+ any Contribution intentionally submitted for inclusion in the Work
132
+ by You to the Licensor shall be under the terms and conditions of
133
+ this License, without any additional terms or conditions.
134
+ Notwithstanding the above, nothing herein shall supersede or modify
135
+ the terms of any separate license agreement you may have executed
136
+ with Licensor regarding such Contributions.
137
+
138
+ 6. Trademarks. This License does not grant permission to use the trade
139
+ names, trademarks, service marks, or product names of the Licensor,
140
+ except as required for reasonable and customary use in describing the
141
+ origin of the Work and reproducing the content of the NOTICE file.
142
+
143
+ 7. Disclaimer of Warranty. Unless required by applicable law or
144
+ agreed to in writing, Licensor provides the Work (and each
145
+ Contributor provides its Contributions) on an "AS IS" BASIS,
146
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147
+ implied, including, without limitation, any warranties or conditions
148
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149
+ PARTICULAR PURPOSE. You are solely responsible for determining the
150
+ appropriateness of using or redistributing the Work and assume any
151
+ risks associated with Your exercise of permissions under this License.
152
+
153
+ 8. Limitation of Liability. In no event and under no legal theory,
154
+ whether in tort (including negligence), contract, or otherwise,
155
+ unless required by applicable law (such as deliberate and grossly
156
+ negligent acts) or agreed to in writing, shall any Contributor be
157
+ liable to You for damages, including any direct, indirect, special,
158
+ incidental, or consequential damages of any character arising as a
159
+ result of this License or out of the use or inability to use the
160
+ Work (including but not limited to damages for loss of goodwill,
161
+ work stoppage, computer failure or malfunction, or any and all
162
+ other commercial damages or losses), even if such Contributor
163
+ has been advised of the possibility of such damages.
164
+
165
+ 9. Accepting Warranty or Additional Liability. While redistributing
166
+ the Work or Derivative Works thereof, You may choose to offer,
167
+ and charge a fee for, acceptance of support, warranty, indemnity,
168
+ or other liability obligations and/or rights consistent with this
169
+ License. However, in accepting such obligations, You may act only
170
+ on Your own behalf and on Your sole responsibility, not on behalf
171
+ of any other Contributor, and only if You agree to indemnify,
172
+ defend, and hold each Contributor harmless for any liability
173
+ incurred by, or claims asserted against, such Contributor by reason
174
+ of your accepting any such warranty or additional liability.
175
+
176
+ END OF TERMS AND CONDITIONS
orma_ai-0.1.0/PKG-INFO ADDED
@@ -0,0 +1,234 @@
1
+ Metadata-Version: 2.5
2
+ Name: orma-ai
3
+ Version: 0.1.0
4
+ Summary: Local episode-first long-term memory for small LLMs
5
+ License-Expression: Apache-2.0
6
+ License-File: LICENSE
7
+ Requires-Python: >=3.10
8
+ Requires-Dist: dateparser>=1.2.0
9
+ Requires-Dist: fastembed>=0.2.0
10
+ Requires-Dist: httpx>=0.27.0
11
+ Requires-Dist: numpy>=1.20.0
12
+ Requires-Dist: sqlite-vec>=0.1.6
13
+ Requires-Dist: starlette>=0.37.0
14
+ Requires-Dist: typer>=0.9.0
15
+ Requires-Dist: tzdata; platform_system == 'Windows'
16
+ Requires-Dist: uvicorn>=0.29.0
17
+ Provides-Extra: dev
18
+ Requires-Dist: pytest>=7.0.0; extra == 'dev'
19
+ Requires-Dist: ruff>=0.1.0; extra == 'dev'
20
+ Description-Content-Type: text/markdown
21
+
22
+ # Orma (ഓർമ്മ)
23
+
24
+ > **Orma** *(Dravidian / Malayalam for "memory" or "recollection")* is an episode-first, zero-latency long-term memory layer built specifically for local, open-weight LLMs (3B–8B models on consumer 8–16 GB laptops).
25
+
26
+ [![License](https://img.shields.io/badge/License-Apache_2.0-blue.svg)](LICENSE)
27
+ [![Python 3.10+](https://img.shields.io/badge/python-3.10+-blue.svg)](https://www.python.org/downloads/)
28
+ [![Tests](https://img.shields.io/badge/tests-182%20passed-brightgreen.svg)](tests/)
29
+
30
+ Orma runs as an **OpenAI-compatible proxy** in front of Ollama, llama.cpp, LM Studio, or vLLM. It also ships a fast CLI and an embedded Python SDK. Everything runs locally inside SQLite with `sqlite-vec` and fast local embeddings—**no external servers, no cloud API keys, and zero data loss.**
31
+
32
+ ---
33
+
34
+ ## Why Orma?
35
+
36
+ Most agent memory frameworks (like Mem0 or Cognee) were designed for massive cloud models (GPT-4o, Claude 3.5 Sonnet) and enterprise graph databases:
37
+ 1. **They freeze chat turns:** Calling an LLM synchronously on every `add()` causes 5–15 second freezes on local laptops.
38
+ 2. **They hallucinate graphs:** 3B models struggle with complex entity-relation extraction and invert relationships or emit malformed JSON.
39
+ 3. **They permanently corrupt facts:** Prompting a 3B model with `DELETE / UPDATE` leads to destructive, irreversible overwrites.
40
+
41
+ ### The Orma Approach
42
+ * **Episodes are the memory:** Every conversation turn, document, or tool log is kept in full in an append-only log and indexed into sentences immediately.
43
+ * **Zero LLM calls on recall:** Recall runs in `< 25ms` using hybrid vector search (sqlite-vec) + BM25 full-text search (FTS5) with bounded recency boosting (ACT-R).
44
+ * **Sleep consolidates state asynchronously:** While the machine is idle, a background worker uses the local model to extract single-valued current states (`now true`) and dated events citing exact line numbers.
45
+ * **Deterministic code guards:** Time resolution, pronoun carry-over (*anuvṛtti*), and contradiction resolution are handled in verified Python code, not by trusting small model arithmetic.
46
+
47
+ ---
48
+
49
+ ## Architecture & Data Flow
50
+
51
+ ### 1. The Fast Request & Recall Path (Zero LLM Calls)
52
+
53
+ ```mermaid
54
+ flowchart LR
55
+ User["User / Chat Client"] -->|"1. Chat Request"| Proxy["Orma Proxy (Port 8080)"]
56
+ Proxy -->|"2. Hybrid Query"| Store[("SQLite + sqlite-vec + FTS5")]
57
+ Store -->|"3. Match Sentences & Current States"| Ranker["Ranker & Budget Packer"]
58
+ Ranker -->|"4. Injects Memory Block"| Upstream["Local LLM (Ollama / llama.cpp)"]
59
+ Upstream -->|"5. Stream Response"| Proxy
60
+ Proxy -->|"6. Return to User"| User
61
+ Proxy -.->|"7. Async Append Episode"| Store
62
+ ```
63
+
64
+ ### 2. The Background Sleep Path (Idempotent Consolidation)
65
+
66
+ ```mermaid
67
+ flowchart TD
68
+ Pending["Pending Episodes in SQLite"] --> Batcher["Batcher (Lines [s1, s2, ...])"]
69
+ Batcher --> LocalLLM["Local Sleep Model (Qwen2.5-3B / Llama-3.2-3B)"]
70
+ LocalLLM -->|"Schema Output: States & Events citing Line #"| Validator["Deterministic Grounding Engine"]
71
+
72
+ subgraph Verification ["Deterministic Python Code"]
73
+ Validator --> V1["Verify Line Citations Exist"]
74
+ Validator --> V2["Pronoun & Anuvrtti Resolution"]
75
+ Validator --> V3["Timezone Date Parsing (clock.py)"]
76
+ Validator --> V4["Grounding Check (No Hallucinations)"]
77
+ end
78
+
79
+ Verification --> Integrator["State Store"]
80
+ Integrator -->|"Closes Contradicted Old States"| ActiveStates[("Current States & History")]
81
+ ```
82
+
83
+ ---
84
+
85
+ ## Quickstart
86
+
87
+ ### Prerequisites
88
+ * Python 3.10+
89
+ * [Ollama](https://ollama.ai) or [llama.cpp](https://github.com/ggerganov/llama.cpp)
90
+
91
+ ### 1. Installation
92
+
93
+ ```bash
94
+ git clone https://github.com/wizardwithcodehazard/orma.git
95
+ cd orma
96
+ python -m venv .venv
97
+
98
+ # On Linux/macOS:
99
+ source .venv/bin/activate
100
+ # On Windows PowerShell:
101
+ # .venv\Scripts\Activate.ps1
102
+
103
+ pip install -e ".[dev]"
104
+ ```
105
+
106
+ Run tests to verify the setup (182 tests run deterministically with zero downloads in ~17s):
107
+ ```bash
108
+ python -m pytest -q
109
+ ```
110
+
111
+ ### 2. Run the Proxy
112
+
113
+ Pull a lightweight model in Ollama:
114
+ ```bash
115
+ ollama pull llama3.2:3b
116
+ ```
117
+
118
+ Start the Orma proxy:
119
+ ```bash
120
+ python -m smruti proxy --model llama3.2:3b
121
+ # Listening on http://127.0.0.1:8080 (forwarding upstream to http://localhost:11434/v1)
122
+ ```
123
+
124
+ Point any OpenAI-compatible client (Open WebUI, Continue.dev, Cursor, or Curl) to `http://localhost:8080/v1`:
125
+
126
+ ```bash
127
+ curl http://localhost:8080/v1/chat/completions \
128
+ -H "Content-Type: application/json" \
129
+ -d '{
130
+ "model": "llama3.2:3b",
131
+ "messages": [
132
+ {"role": "user", "content": "I live in Pune and work on compilers."}
133
+ ]
134
+ }'
135
+ ```
136
+
137
+ ### 3. Inspect Memory
138
+
139
+ ```bash
140
+ # Add a quick note or document
141
+ python -m smruti add "My dentist is Dr. Rao in Kothrud."
142
+ python -m smruti add docs/notes.md
143
+
144
+ # Search memory
145
+ python -m smruti search "Where is my dentist?"
146
+
147
+ # View active facts & history
148
+ python -m smruti facts --history
149
+
150
+ # Trigger background sleep manually
151
+ python -m smruti sleep --model llama3.2:3b
152
+ ```
153
+
154
+ ---
155
+
156
+ ## Python SDK
157
+
158
+ ```python
159
+ from smruti import Memory
160
+
161
+ # Initialize memory (default SQLite db: ~/.smruti/memory.db or SMRUTI_DIR)
162
+ mem = Memory(upstream="http://localhost:11434/v1", model="llama3.2:3b")
163
+
164
+ # Add memories directly
165
+ mem.add("I moved from Pune to Bangalore last week.", role="user")
166
+ mem.add_file("project_notes.txt")
167
+
168
+ # Build context for an outgoing prompt (hybrid search + current states)
169
+ messages = mem.build_context([
170
+ {"role": "user", "content": "Where do I currently live?"}
171
+ ])
172
+
173
+ # Stream or call your model
174
+ reply = mem.chat([{"role": "user", "content": "Where do I live?"}])
175
+ print(reply)
176
+
177
+ # Background consolidation
178
+ mem.sleep()
179
+
180
+ # Rebuild all memory from scratch using a stronger model if needed
181
+ # mem.rebuild()
182
+
183
+ mem.close()
184
+ ```
185
+
186
+ ---
187
+
188
+ ## Memory Prompt Output Format
189
+
190
+ When Orma recalls memories, it packs them into a tight token budget injected into the system prompt:
191
+
192
+ ```markdown
193
+ ## Memory
194
+ What you remember about the person you are talking to. Today is 2026-10-24.
195
+
196
+ Now true:
197
+ - user · home city: Bangalore (since 2026-10-17)
198
+
199
+ Things said before:
200
+ - 2026-10-10 user: I'm Sahil and I live in Pune. [outdated: now user · home city: Bangalore]
201
+ - 2026-10-18 user: Last Saturday I went trekking to Sinhagad with my sister Asha.
202
+
203
+ Events:
204
+ - 2026-10-12: user went trekking at Sinhagad with Asha
205
+ ```
206
+
207
+ ---
208
+
209
+ ## Comparison: Orma vs. Mem0 & Cognee
210
+
211
+ | Feature | Mem0 | Cognee | **Orma** |
212
+ | :--- | :--- | :--- | :--- |
213
+ | **Target LLMs** | Cloud (GPT-4o) | Cloud (GPT-4o) | **Local 3B–8B (Ollama / llama.cpp)** |
214
+ | **Write Overhead** | Synchronous LLM calls (5–15s delay) | Multi-stage graph pipelines | **Instant (< 5ms SQLite append)** |
215
+ | **Recall Overhead** | Vector + LLM synthesis | Graph traversal + LLM | **Instant (< 25ms hybrid search, 0 LLM calls)** |
216
+ | **Data Safety** | Destructive `DELETE / UPDATE` | Lossy graph extraction | **Lossless append-only logs (`rebuild` anytime)** |
217
+ | **Hallucination Protection** | Relies on LLM accuracy | Relies on Pydantic output | **Line citations + deterministic Python guards** |
218
+
219
+ ---
220
+
221
+ ## Configuration & Ablation Switches
222
+
223
+ Orma comes with built-in ablation switches in `smruti/config.py` to evaluate every mechanism against raw episodic baselines:
224
+
225
+ * `enable_semantic`: Toggle state and event extraction (off = pure episodic sentence search baseline).
226
+ * `enable_novelty_gate`: Drops near-duplicate records ($\ge 0.97$ cosine similarity).
227
+ * `enable_similarity_weighting`: Calibrates vector similarity against adaptive space noise floor.
228
+ * `enable_base_level`: Enables ACT-R recency and repetition boost.
229
+
230
+ ---
231
+
232
+ ## License
233
+
234
+ Distributed under the **Apache-2.0 License**. See [LICENSE](LICENSE) for more information.