spomory 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 (156) hide show
  1. spomory-0.1.0/.claude/scheduled_tasks.lock +1 -0
  2. spomory-0.1.0/.github/workflows/ci.yml +27 -0
  3. spomory-0.1.0/.gitignore +37 -0
  4. spomory-0.1.0/LICENSE +201 -0
  5. spomory-0.1.0/PKG-INFO +334 -0
  6. spomory-0.1.0/README.md +300 -0
  7. spomory-0.1.0/README.zh-CN.md +261 -0
  8. spomory-0.1.0/benchmarks/__init__.py +0 -0
  9. spomory-0.1.0/benchmarks/baseline.py +71 -0
  10. spomory-0.1.0/benchmarks/data/images/picsum_1015.jpg +0 -0
  11. spomory-0.1.0/benchmarks/data/images/picsum_1025.jpg +0 -0
  12. spomory-0.1.0/benchmarks/data/images/picsum_1035.jpg +0 -0
  13. spomory-0.1.0/benchmarks/data/images/picsum_1040.jpg +0 -0
  14. spomory-0.1.0/benchmarks/data/images/picsum_1050.jpg +0 -0
  15. spomory-0.1.0/benchmarks/data/images/picsum_1069.jpg +0 -0
  16. spomory-0.1.0/benchmarks/data/images/picsum_1074.jpg +0 -0
  17. spomory-0.1.0/benchmarks/data/images/picsum_1080.jpg +0 -0
  18. spomory-0.1.0/benchmarks/data/images/picsum_1084.jpg +0 -0
  19. spomory-0.1.0/benchmarks/data/images/picsum_237.jpg +0 -0
  20. spomory-0.1.0/benchmarks/data/multimodal_ground_truth.json +72 -0
  21. spomory-0.1.0/benchmarks/download_data.py +35 -0
  22. spomory-0.1.0/benchmarks/harness.py +146 -0
  23. spomory-0.1.0/benchmarks/loaders.py +131 -0
  24. spomory-0.1.0/benchmarks/multimodal_eval.py +113 -0
  25. spomory-0.1.0/benchmarks/results/.gitkeep +0 -0
  26. spomory-0.1.0/benchmarks/results/locomo_full_run.json +769 -0
  27. spomory-0.1.0/benchmarks/results/locomo_full_run_after_date_fix.json +797 -0
  28. spomory-0.1.0/benchmarks/results/locomo_subset_baseline.json +54 -0
  29. spomory-0.1.0/benchmarks/results/locomo_subset_smoke.json +53 -0
  30. spomory-0.1.0/benchmarks/results/multimodal_eval.json +278 -0
  31. spomory-0.1.0/benchmarks/results/multimodal_real_extraction.json +272 -0
  32. spomory-0.1.0/benchmarks/run_locomo_conv26_subset.py +116 -0
  33. spomory-0.1.0/benchmarks/run_longmemeval_subset.py +131 -0
  34. spomory-0.1.0/dist_pypi/.gitignore +1 -0
  35. spomory-0.1.0/docs/benchmark_smoke_test.en.md +246 -0
  36. spomory-0.1.0/docs/benchmark_smoke_test.md +191 -0
  37. spomory-0.1.0/docs/dataset_format.en.md +81 -0
  38. spomory-0.1.0/docs/dataset_format.md +70 -0
  39. spomory-0.1.0/docs/eng_note_cjk_rendering_bug.en.md +125 -0
  40. spomory-0.1.0/docs/eng_note_cjk_rendering_bug.md +105 -0
  41. spomory-0.1.0/docs/examples/memory_passport_sample.json +61 -0
  42. spomory-0.1.0/docs/export_format.en.md +84 -0
  43. spomory-0.1.0/docs/export_format.md +66 -0
  44. spomory-0.1.0/docs/gpu_training_runbook.en.md +84 -0
  45. spomory-0.1.0/docs/gpu_training_runbook.md +62 -0
  46. spomory-0.1.0/docs/graph_store_interface.en.md +84 -0
  47. spomory-0.1.0/docs/graph_store_interface.md +66 -0
  48. spomory-0.1.0/docs/leaderboard_submission.en.md +77 -0
  49. spomory-0.1.0/docs/leaderboard_submission.md +56 -0
  50. spomory-0.1.0/docs/mcp_quickstart.en.md +684 -0
  51. spomory-0.1.0/docs/mcp_quickstart.md +580 -0
  52. spomory-0.1.0/docs/memory_manager_eval.en.md +134 -0
  53. spomory-0.1.0/docs/memory_manager_eval.md +95 -0
  54. spomory-0.1.0/docs/methodology.en.md +103 -0
  55. spomory-0.1.0/docs/methodology.md +77 -0
  56. spomory-0.1.0/docs/multimodal_verification.en.md +107 -0
  57. spomory-0.1.0/docs/multimodal_verification.md +79 -0
  58. spomory-0.1.0/docs/mvp_scope.en.md +132 -0
  59. spomory-0.1.0/docs/mvp_scope.md +96 -0
  60. spomory-0.1.0/docs/postgres_setup.en.md +56 -0
  61. spomory-0.1.0/docs/postgres_setup.md +45 -0
  62. spomory-0.1.0/docs/privacy_policy_draft.en.md +172 -0
  63. spomory-0.1.0/docs/privacy_policy_draft.md +125 -0
  64. spomory-0.1.0/docs/product_copy_memory_passport.en.md +72 -0
  65. spomory-0.1.0/docs/product_copy_memory_passport.md +53 -0
  66. spomory-0.1.0/modelscope_listing.en.md +19 -0
  67. spomory-0.1.0/modelscope_listing.md +19 -0
  68. spomory-0.1.0/pyproject.toml +63 -0
  69. spomory-0.1.0/server.json +23 -0
  70. spomory-0.1.0/src/cloud_api/__init__.py +0 -0
  71. spomory-0.1.0/src/cloud_api/app.py +439 -0
  72. spomory-0.1.0/src/cloud_api/auth.py +246 -0
  73. spomory-0.1.0/src/cloud_api/billing.py +94 -0
  74. spomory-0.1.0/src/cloud_api/demo.py +78 -0
  75. spomory-0.1.0/src/cloud_api/email.py +45 -0
  76. spomory-0.1.0/src/cloud_api/oauth_store.py +413 -0
  77. spomory-0.1.0/src/cloud_api/remote_main.py +160 -0
  78. spomory-0.1.0/src/memory_core/__init__.py +0 -0
  79. spomory-0.1.0/src/memory_core/audit.py +69 -0
  80. spomory-0.1.0/src/memory_core/export/__init__.py +0 -0
  81. spomory-0.1.0/src/memory_core/export/exporter.py +69 -0
  82. spomory-0.1.0/src/memory_core/export/schema.py +90 -0
  83. spomory-0.1.0/src/memory_core/graph/__init__.py +0 -0
  84. spomory-0.1.0/src/memory_core/graph/extract.py +16 -0
  85. spomory-0.1.0/src/memory_core/graph/incremental.py +174 -0
  86. spomory-0.1.0/src/memory_core/graph/local_store.py +287 -0
  87. spomory-0.1.0/src/memory_core/graph/models.py +98 -0
  88. spomory-0.1.0/src/memory_core/graph/postgres_store.py +202 -0
  89. spomory-0.1.0/src/memory_core/graph/store.py +104 -0
  90. spomory-0.1.0/src/memory_core/llm/__init__.py +0 -0
  91. spomory-0.1.0/src/memory_core/llm/base.py +35 -0
  92. spomory-0.1.0/src/memory_core/llm/embedding_base.py +16 -0
  93. spomory-0.1.0/src/memory_core/llm/local_sentence_transformer.py +26 -0
  94. spomory-0.1.0/src/memory_core/llm/openai_compatible.py +72 -0
  95. spomory-0.1.0/src/memory_core/llm/redact.py +44 -0
  96. spomory-0.1.0/src/memory_core/mcp_server/__init__.py +0 -0
  97. spomory-0.1.0/src/memory_core/mcp_server/__main__.py +13 -0
  98. spomory-0.1.0/src/memory_core/mcp_server/remote.py +235 -0
  99. spomory-0.1.0/src/memory_core/mcp_server/server.py +311 -0
  100. spomory-0.1.0/src/memory_core/memory_manager/__init__.py +0 -0
  101. spomory-0.1.0/src/memory_core/memory_manager/actions.py +95 -0
  102. spomory-0.1.0/src/memory_core/memory_manager/policy.py +120 -0
  103. spomory-0.1.0/src/memory_core/memory_manager/reward.py +28 -0
  104. spomory-0.1.0/src/memory_core/memory_manager/train_grpo.py +142 -0
  105. spomory-0.1.0/src/memory_core/multimodal/__init__.py +0 -0
  106. spomory-0.1.0/src/memory_core/multimodal/clip_verification.py +47 -0
  107. spomory-0.1.0/src/memory_core/multimodal/image_captioning.py +82 -0
  108. spomory-0.1.0/src/memory_core/onboarding.py +57 -0
  109. spomory-0.1.0/src/memory_core/retrieval/__init__.py +0 -0
  110. spomory-0.1.0/src/memory_core/retrieval/ppr.py +38 -0
  111. spomory-0.1.0/src/memory_core/retrieval/query_match.py +81 -0
  112. spomory-0.1.0/src/memory_core/retrieval/ranker.py +152 -0
  113. spomory-0.1.0/src/memory_core/usage.py +57 -0
  114. spomory-0.1.0/tests/__init__.py +0 -0
  115. spomory-0.1.0/tests/graph_store_contract.py +179 -0
  116. spomory-0.1.0/tests/test_audit.py +40 -0
  117. spomory-0.1.0/tests/test_backend_selection.py +108 -0
  118. spomory-0.1.0/tests/test_benchmarks_baseline.py +33 -0
  119. spomory-0.1.0/tests/test_benchmarks_harness.py +59 -0
  120. spomory-0.1.0/tests/test_benchmarks_loaders.py +22 -0
  121. spomory-0.1.0/tests/test_billing.py +81 -0
  122. spomory-0.1.0/tests/test_clip_verification.py +41 -0
  123. spomory-0.1.0/tests/test_cloud_api.py +370 -0
  124. spomory-0.1.0/tests/test_e2e_pipeline.py +110 -0
  125. spomory-0.1.0/tests/test_e2e_real_llm.py +87 -0
  126. spomory-0.1.0/tests/test_embedding.py +34 -0
  127. spomory-0.1.0/tests/test_encryption.py +111 -0
  128. spomory-0.1.0/tests/test_entity_disambiguation.py +59 -0
  129. spomory-0.1.0/tests/test_export.py +51 -0
  130. spomory-0.1.0/tests/test_graph_models.py +34 -0
  131. spomory-0.1.0/tests/test_image_captioning.py +27 -0
  132. spomory-0.1.0/tests/test_incremental.py +120 -0
  133. spomory-0.1.0/tests/test_incremental_with_policy.py +54 -0
  134. spomory-0.1.0/tests/test_llm_base.py +29 -0
  135. spomory-0.1.0/tests/test_local_graph_store.py +76 -0
  136. spomory-0.1.0/tests/test_local_graph_store_contract.py +11 -0
  137. spomory-0.1.0/tests/test_longmemeval_loader.py +24 -0
  138. spomory-0.1.0/tests/test_mcp_server.py +157 -0
  139. spomory-0.1.0/tests/test_memory_actions.py +136 -0
  140. spomory-0.1.0/tests/test_multimodal_eval.py +46 -0
  141. spomory-0.1.0/tests/test_oauth_login_flow.py +149 -0
  142. spomory-0.1.0/tests/test_oauth_mount_routing.py +246 -0
  143. spomory-0.1.0/tests/test_oauth_store.py +220 -0
  144. spomory-0.1.0/tests/test_onboarding.py +36 -0
  145. spomory-0.1.0/tests/test_policy.py +82 -0
  146. spomory-0.1.0/tests/test_postgres_mcp_parity.py +42 -0
  147. spomory-0.1.0/tests/test_postgres_store.py +65 -0
  148. spomory-0.1.0/tests/test_ppr.py +48 -0
  149. spomory-0.1.0/tests/test_query_match.py +60 -0
  150. spomory-0.1.0/tests/test_ranker.py +167 -0
  151. spomory-0.1.0/tests/test_redact.py +64 -0
  152. spomory-0.1.0/tests/test_remote_mcp_server.py +223 -0
  153. spomory-0.1.0/tests/test_remote_oauth_context.py +40 -0
  154. spomory-0.1.0/tests/test_reward.py +11 -0
  155. spomory-0.1.0/tests/test_train_grpo.py +67 -0
  156. spomory-0.1.0/tests/test_usage.py +27 -0
@@ -0,0 +1 @@
1
+ {"sessionId":"3d509812-ea3e-4078-9b6d-fa66ce821bd8","pid":15034,"procStart":"Sat Sep 5 10:23:25 2026","acquiredAt":1788679152497}
@@ -0,0 +1,27 @@
1
+ name: CI
2
+
3
+ on:
4
+ pull_request:
5
+ push:
6
+ branches: [main]
7
+
8
+ jobs:
9
+ lint-and-test:
10
+ runs-on: ubuntu-latest
11
+ steps:
12
+ - uses: actions/checkout@v4
13
+
14
+ - name: Install uv
15
+ uses: astral-sh/setup-uv@v3
16
+
17
+ - name: Set up Python
18
+ run: uv python install 3.11
19
+
20
+ - name: Install dependencies
21
+ run: uv pip install -e ".[dev]" --python 3.11
22
+
23
+ - name: Lint (ruff)
24
+ run: uv run --python 3.11 ruff check .
25
+
26
+ - name: Test (pytest)
27
+ run: uv run --python 3.11 pytest
@@ -0,0 +1,37 @@
1
+ __pycache__/
2
+ *.py[cod]
3
+ *.egg-info/
4
+ .eggs/
5
+ build/
6
+ dist/
7
+ .venv/
8
+ venv/
9
+ .env
10
+ .pytest_cache/
11
+ .mypy_cache/
12
+ .ruff_cache/
13
+ *.db
14
+ *.sqlite3
15
+ .DS_Store
16
+ benchmarks/results/*.json
17
+ !benchmarks/results/.gitkeep
18
+ !benchmarks/results/locomo_subset_smoke.json
19
+ !benchmarks/results/locomo_subset_baseline.json
20
+ !benchmarks/results/locomo_full_run.json
21
+ !benchmarks/results/locomo_full_run_after_date_fix.json
22
+ !benchmarks/results/multimodal_eval.json
23
+ !benchmarks/results/multimodal_real_extraction.json
24
+ benchmarks/data/*
25
+ !benchmarks/data/images
26
+ !benchmarks/data/images/*.jpg
27
+ !benchmarks/data/multimodal_ground_truth.json
28
+
29
+ # internal working docs, not for the public repo
30
+ TASKS.md
31
+ AI个人记忆方案.docx
32
+ AI个人记忆方案-v2.docx
33
+ 运维.md
34
+ PH.md
35
+ GOAL.md
36
+ GOALs.md
37
+ VIDEO_SCRIPT.md
spomory-0.1.0/LICENSE ADDED
@@ -0,0 +1,201 @@
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
177
+
178
+ APPENDIX: How to apply the Apache License to your work.
179
+
180
+ To apply the Apache License to your work, attach the following
181
+ boilerplate notice, with the fields enclosed by brackets "[]"
182
+ replaced with your own identifying information. (Don't include
183
+ the brackets!) The text should be enclosed in the appropriate
184
+ comment syntax for the file format. We also recommend that a
185
+ file or class name and description of purpose be included on the
186
+ same "printed page" as the copyright notice for easier
187
+ identification within third-party archives.
188
+
189
+ Copyright [yyyy] [name of copyright owner]
190
+
191
+ Licensed under the Apache License, Version 2.0 (the "License");
192
+ you may not use this file except in compliance with the License.
193
+ You may obtain a copy of the License at
194
+
195
+ http://www.apache.org/licenses/LICENSE-2.0
196
+
197
+ Unless required by applicable law or agreed to in writing, software
198
+ distributed under the License is distributed on an "AS IS" BASIS,
199
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200
+ See the License for the specific language governing permissions and
201
+ limitations under the License.
spomory-0.1.0/PKG-INFO ADDED
@@ -0,0 +1,334 @@
1
+ Metadata-Version: 2.5
2
+ Name: spomory
3
+ Version: 0.1.0
4
+ Summary: Persistent memory for AI agents via MCP — entity/relation knowledge graph, HippoRAG-style retrieval, local-first
5
+ Project-URL: Homepage, https://spomory.yliuai.com
6
+ Project-URL: Repository, https://github.com/yliuai/spomory
7
+ Project-URL: Documentation, https://github.com/yliuai/spomory/blob/main/docs/mcp_quickstart.en.md
8
+ License-Expression: Apache-2.0
9
+ License-File: LICENSE
10
+ Requires-Python: >=3.11
11
+ Requires-Dist: networkx>=3.0
12
+ Requires-Dist: numpy>=1.26
13
+ Requires-Dist: pydantic>=2.0
14
+ Requires-Dist: scipy>=1.11
15
+ Provides-Extra: dev
16
+ Requires-Dist: mypy>=1.10; extra == 'dev'
17
+ Requires-Dist: pytest>=8.0; extra == 'dev'
18
+ Requires-Dist: ruff>=0.4; extra == 'dev'
19
+ Provides-Extra: embedding
20
+ Requires-Dist: sentence-transformers>=3.0; extra == 'embedding'
21
+ Provides-Extra: llm
22
+ Requires-Dist: openai>=1.0; extra == 'llm'
23
+ Provides-Extra: mcp
24
+ Requires-Dist: mcp>=2.0; extra == 'mcp'
25
+ Provides-Extra: multimodal
26
+ Requires-Dist: pillow>=10.0; extra == 'multimodal'
27
+ Requires-Dist: torch>=2.0; extra == 'multimodal'
28
+ Requires-Dist: transformers>=4.40; extra == 'multimodal'
29
+ Provides-Extra: rl
30
+ Requires-Dist: peft>=0.11; extra == 'rl'
31
+ Requires-Dist: transformers>=4.40; extra == 'rl'
32
+ Requires-Dist: trl>=0.9; extra == 'rl'
33
+ Description-Content-Type: text/markdown
34
+
35
+ # Spomory
36
+
37
+ **English | [中文](README.zh-CN.md)**
38
+
39
+ The core engine behind a personal AI memory product: HippoRAG-style
40
+ retrieval (query→triple matching + personalized PageRank diffusion) +
41
+ a LightRAG-style dual-layer incremental knowledge graph + a lightweight
42
+ GRPO-trained memory-management policy, exposed to Claude Desktop / Cursor
43
+ and other clients via an MCP server, with a path to a cloud deployment
44
+ (Postgres backend, FastAPI auth/billing skeleton) already scaffolded.
45
+
46
+ > Spomory is the product/client-facing display name. The Python package
47
+ > name, CLI command (`memory-core-mcp`), and module name (`memory_core`)
48
+ > are unchanged — see the "Quickstart: MCP Server" section below.
49
+
50
+ ## What's implemented
51
+
52
+ - **Pluggable LLM / embedding providers**: defaults to any OpenAI-compatible
53
+ API (including Chinese-market LLM providers) + local
54
+ `sentence-transformers` (default `bge-m3`, bilingual Chinese/English).
55
+ - **Dual-layer incremental knowledge graph**: entities and relations are
56
+ modeled as independent layers; new data is only extracted and merged in,
57
+ never a full rebuild. Exact-match filler input ("thanks", "好的", "ok", ...)
58
+ is skipped before it ever reaches the extraction LLM call, since it can't
59
+ contain an extractable fact — relevant cost protection on any
60
+ unauthenticated endpoint. Defaults to a local `LocalGraphStore`
61
+ (networkx + SQLite); a `PostgresGraphStore` cloud implementation also
62
+ exists, and both share the same behavioral contract test suite.
63
+ - **HippoRAG 2-style retrieval**: the query is matched directly against
64
+ triples rather than only against entity nodes; the matched seed nodes
65
+ are diffused via personalized PageRank for multi-hop association, then
66
+ assembled into a natural-language context (with source timestamps, so
67
+ "when did I mention X" is answerable). Ranking on top of that decays a
68
+ relation's relevance the longer it's gone without being retrieved, and
69
+ boosts it back up (log-dampened, so it can't dominate PPR rank) the more
70
+ times the same fact has been restated — a passive signal alongside the
71
+ active ADD/UPDATE/DELETE/NOOP decisions below.
72
+ - **Memory management**: an ADD/UPDATE/DELETE/NOOP action space, with a
73
+ rule-based default policy (`RuleBasedPolicy`) and a full GRPO training
74
+ pipeline (`memory_manager/train_grpo.py`, actually run and verified on
75
+ a real GPU).
76
+ - **MCP Server**: exposes six tools — `add_memory`, `search_memory`,
77
+ `get_graph`, `export_memory`, `forget_memory`, `forget_all_memory` —
78
+ verified end-to-end against a real Claude Desktop.
79
+ - **Memory passport export + true delete**: a JSON-LD style export format,
80
+ physical deletion, and an audit log.
81
+ - **Multimodal image verification**: image captioning → reuses the text
82
+ extraction pipeline → CLIP cross-checks candidate triples. Honestly
83
+ positioned as "verification," not "native cross-modal extraction."
84
+ - **Cloud skeleton**: FastAPI user auth/API keys/quotas, a Stripe webhook
85
+ billing scaffold (skeleton-level only, not production-deployed).
86
+
87
+ ## Project layout
88
+
89
+ ```
90
+ src/
91
+ ├── memory_core/
92
+ │ ├── graph/ # entity/relation models, storage adapters (local SQLite / cloud Postgres), incremental writes
93
+ │ ├── retrieval/ # query→triple matching, personalized PageRank, context assembly
94
+ │ ├── memory_manager/ # action space, reward functions, GRPO training script, policy inference
95
+ │ ├── multimodal/ # image captioning + CLIP verification
96
+ │ ├── mcp_server/ # MCP Server (the distribution entry point)
97
+ │ ├── export/ # memory passport export format + true delete
98
+ │ ├── llm/ # pluggable LLM/embedding providers
99
+ │ ├── audit.py # deletion audit log
100
+ │ └── usage.py # retention/usage tracking
101
+ └── cloud_api/ # FastAPI cloud service skeleton (auth, quotas, billing)
102
+ benchmarks/ # LoCoMo/LongMemEval evaluation harness + multimodal comparison experiments
103
+ tests/ # 94+ tests, from unit tests to real LLM/GPU/Postgres end-to-end verification
104
+ docs/ # per-epic design notes, verification reports, runbooks (see index below)
105
+ ```
106
+
107
+ ## Installation
108
+
109
+ Prerequisites: Python **3.11+**, [uv](https://docs.astral.sh/uv/getting-started/installation/)
110
+ (no uv? `python -m venv` + `pip install -e` works as a substitute for the
111
+ `uv` commands below).
112
+
113
+ ```bash
114
+ git clone <this repo's URL> memory-core && cd memory-core
115
+ uv venv --python 3.11 .venv
116
+ source .venv/bin/activate # Windows: .venv\Scripts\activate
117
+
118
+ # Pick dependency groups as needed — they can be combined, no need to install everything:
119
+ uv pip install -e ".[dev]" # required to run tests/lint
120
+ uv pip install -e ".[llm,embedding]" # required for the "minimal working memory system" (see the demo below)
121
+ uv pip install -e ".[mcp]" # extra: connecting to Claude Desktop/Cursor
122
+ uv pip install -e ".[rl]" # extra: GRPO training (requires a GPU + CUDA)
123
+ uv pip install -e ".[cloud]" # extra: cloud API / Postgres backend
124
+ uv pip install -e ".[multimodal]" # extra: image + CLIP verification
125
+ ```
126
+
127
+ The `embedding` group downloads the default model `BAAI/bge-m3` from
128
+ HuggingFace on first use (~2.2GB) — make sure huggingface.co is reachable
129
+ (if you're behind the Great Firewall, `export HF_ENDPOINT=https://hf-mirror.com`
130
+ routes through a mirror). You can also swap in a smaller model via
131
+ `export EMBEDDING_MODEL=<any sentence-transformers model name>`.
132
+
133
+ The `llm` group itself downloads nothing, but **`LLM_API_KEY` must be set
134
+ at runtime** (any OpenAI-compatible Chat Completions endpoint works — OpenAI,
135
+ DeepSeek, Qwen, etc.):
136
+
137
+ ```bash
138
+ export LLM_API_KEY=sk-...
139
+ export LLM_BASE_URL=https://api.deepseek.com # optional; defaults to OpenAI's endpoint
140
+ export LLM_MODEL=deepseek-chat # optional; defaults to gpt-4o-mini
141
+ ```
142
+
143
+ ### Run a minimal example (no MCP, plain Python calls)
144
+
145
+ With `dev` + `llm` + `embedding` installed and the three env vars above
146
+ set, this script exercises the full "write a memory → retrieve it"
147
+ pipeline directly (the same logic behind `mcp_server/server.py`'s
148
+ `add_memory`/`search_memory` tools, just calling the library directly
149
+ instead of going through the MCP protocol layer):
150
+
151
+ ```python
152
+ # demo.py
153
+ from memory_core.graph.local_store import LocalGraphStore
154
+ from memory_core.graph.incremental import IncrementalIngestor
155
+ from memory_core.llm.openai_compatible import OpenAICompatibleProvider
156
+ from memory_core.llm.local_sentence_transformer import SentenceTransformerProvider
157
+ from memory_core.memory_manager.policy import RuleBasedPolicy
158
+ from memory_core.retrieval.ppr import personalized_pagerank, rank_entities
159
+ from memory_core.retrieval.query_match import match_query_to_triples
160
+ from memory_core.retrieval.ranker import build_context
161
+
162
+ store = LocalGraphStore("demo.sqlite3") # a local file; delete it to reset
163
+ llm = OpenAICompatibleProvider() # reads LLM_API_KEY etc. from the environment
164
+ embedder = SentenceTransformerProvider() # downloads bge-m3 on first run
165
+
166
+ # 1. Write a memory: the LLM extracts triples, incrementally merged into the graph
167
+ ingestor = IncrementalIngestor(store, llm, policy=RuleBasedPolicy())
168
+ result = ingestor.ingest("I do AI research at CAS, mostly in Python.", source_id="demo")
169
+ print(f"added {result.new_entities} entities, {result.new_relations} relations")
170
+
171
+ # 2. Retrieve: match the query against triples -> PPR diffusion -> assemble a natural-language context
172
+ query = "Where do I work?"
173
+ entities, relations = store.all_entities(), store.all_relations()
174
+ entities_by_id = {e.id: e for e in entities}
175
+ matches = match_query_to_triples(query, relations, entities_by_id, embedder, top_k=10)
176
+ seed_ids = {r.relation.subject_id for r in matches} | {r.relation.object_id for r in matches}
177
+ scores = personalized_pagerank(entities, relations, seed_entity_ids=list(seed_ids))
178
+ ranked_ids = [eid for eid, _ in rank_entities(scores)]
179
+ print(build_context(relations, entities_by_id, ranked_ids, top_k=10))
180
+ ```
181
+
182
+ ```bash
183
+ python demo.py
184
+ ```
185
+
186
+ Here's real output from a live run against DeepSeek with the exact input
187
+ shown above (not fabricated, not cleaned up — this is what actually came
188
+ back):
189
+
190
+ ```
191
+ added 3 entities, 2 relations
192
+ I do AI research at CAS (recorded at 2026-09-05 10:40:00).I do AI research mostly in Python (recorded at 2026-09-05 10:40:00).
193
+ ```
194
+
195
+ Exact wording and entity/relation counts depend on the LLM's own
196
+ extraction and will vary between runs, but as long as the env vars are
197
+ set correctly, non-empty output means the pipeline works end to end.
198
+ `retrieval/ranker.py` detects whether a relation's text is CJK or not and
199
+ renders it accordingly (no spaces + a Chinese timestamp label for CJK,
200
+ spaced words + an English timestamp label otherwise), so English input no
201
+ longer comes out as one run-on word like earlier versions of this demo
202
+ did.
203
+
204
+ ## Quickstart: MCP Server (connecting to Claude Desktop / Cursor / Codex CLI)
205
+
206
+ This MCP server shows up in Claude Desktop / Cursor / Codex CLI as **Spomory** (set
207
+ by the `mcpServers` key in the client's config file — see the docs
208
+ below). The Python package name and CLI command are still
209
+ `memory-core` / `memory-core-mcp`; the two are independent of each other.
210
+
211
+ With the `mcp` dependency group installed and `LLM_API_KEY` etc. set:
212
+
213
+ ```bash
214
+ uv pip install -e ".[llm,embedding,mcp]"
215
+ memory-core-mcp # stays running as a stdio MCP server, waiting for a client to connect
216
+ ```
217
+
218
+ Data lives in `~/.memory-core/` by default (override with
219
+ `MEMORY_CORE_DATA_DIR`); setting `DATABASE_URL` switches to the Postgres
220
+ backend instead of local SQLite.
221
+
222
+ Connecting it to Claude Desktop / Cursor / Codex CLI requires registering
223
+ this command's **absolute path** in the client's config file (don't rely
224
+ on `PATH`). Full steps, a config file example, and a real gotcha we
225
+ actually hit (macOS's TCC privacy protection blocks a venv running under
226
+ `~/Documents`) are in
227
+ [`docs/mcp_quickstart.en.md`](docs/mcp_quickstart.en.md).
228
+
229
+ ## Measured results
230
+
231
+ Real runs against DeepSeek on 84 QA pairs from LoCoMo-10 (conv-26, first
232
+ 150 turns) — not cherry-picked, and not competitive with the bigger
233
+ players' published numbers yet:
234
+
235
+ | Metric | Value |
236
+ |---|---|
237
+ | Recall@10 (did the right evidence turn make it into context) | 52.4% |
238
+ | Accuracy — strict substring match | 19.0% |
239
+ | Accuracy — LLM-judged (looser, wording-tolerant) | 44.0% |
240
+
241
+ A prior run (before a fix that folds dates into extracted predicates so
242
+ "when" questions are answerable) scored lower on accuracy but higher on
243
+ recall (62.0%) — the fix traded some retrieval recall for a real
244
+ +14.3-point accuracy gain, and we went and found out exactly why instead
245
+ of just reporting the accuracy number: the date-folding instruction
246
+ sometimes misfires on content-free small talk ("Thanks!" → "thanked on
247
+ 2023-07-03"), and those extra low-value triples crowd out relevant ones
248
+ out of the fixed top-10 retrieval window. Full numbers, per-category
249
+ breakdown, and the side-by-side extraction comparison that found this are
250
+ in [`docs/benchmark_smoke_test.md`](docs/benchmark_smoke_test.md).
251
+
252
+ **LongMemEval** (`xiaowu0162/longmemeval-cleaned` oracle variant, first 10
253
+ of 500 questions):
254
+
255
+ | Metric | Value |
256
+ |---|---|
257
+ | Recall@10 | 100% (10/10) |
258
+ | Accuracy — strict substring match | 30% |
259
+ | Accuracy — LLM-judged | 80% |
260
+
261
+ The limitations here matter as much as the numbers:
262
+ 1. **Only 10 questions, not the full 500** — each question ingests ~27
263
+ turns on average (~27 real extraction calls plus one generation and one
264
+ judge call), and this environment's LLM API calls go through a proxy
265
+ with real latency; the full dataset would take tens of hours. This is a
266
+ real run, not a mock, but it's a small sample and shouldn't be read as
267
+ generalizing to the full dataset.
268
+ 2. **All 10 happen to be `temporal-reasoning` type** — the dataset also has
269
+ a `multi-session` type; `load_longmemeval(limit=10)` takes the first 10
270
+ entries in file order with no stratified sampling, so this sample isn't
271
+ representative of the dataset as a whole.
272
+ 3. **Recall@10 = 100% is largely an artifact of the oracle variant's
273
+ design, not a strong retrieval claim** — the oracle variant pre-filters
274
+ each question's haystack down to only the relevant sessions (no
275
+ distractor sessions), which is considerably easier than a real
276
+ deployment's memory store (hundreds/thousands of unrelated turns). This
277
+ isn't the same task as the full (non-oracle) LongMemEval benchmark and
278
+ shouldn't be compared directly against numbers other products report on
279
+ that harder variant.
280
+ 4. Strict-match accuracy (30%) is far below LLM-judged accuracy (80%),
281
+ consistent with the same pattern seen in the LoCoMo results — substring
282
+ matching systematically undercounts answers that are correct but worded
283
+ differently.
284
+
285
+ Raw data:
286
+ [`benchmarks/results/longmemeval_oracle_subset.json`](benchmarks/results/longmemeval_oracle_subset.json);
287
+ the run script is
288
+ [`benchmarks/run_longmemeval_subset.py`](benchmarks/run_longmemeval_subset.py).
289
+
290
+ ## Testing
291
+
292
+ ```bash
293
+ pytest # everything
294
+ pytest -m "not slow" # skip tests that download models / train — runs in seconds
295
+ ```
296
+
297
+ Most of the "slow" tests aren't mocked — they're real calls (real LLM API,
298
+ real local embedding model, real CLIP model) and need the corresponding
299
+ env vars (`LLM_API_KEY`, etc.) or an already-downloaded model cache.
300
+
301
+ ## Documentation index
302
+
303
+ | Doc | Content |
304
+ |---|---|
305
+ | [mcp_quickstart.en.md](docs/mcp_quickstart.en.md) ([中文](docs/mcp_quickstart.md)) | MCP Server install, configuration, connecting Claude Desktop/Cursor/Codex CLI, real-world gotchas |
306
+ | [graph_store_interface.en.md](docs/graph_store_interface.en.md) ([中文](docs/graph_store_interface.md)) | Storage adapter interface design |
307
+ | [export_format.en.md](docs/export_format.en.md) ([中文](docs/export_format.md)) | The "memory passport" export format |
308
+ | [dataset_format.en.md](docs/dataset_format.en.md) ([中文](docs/dataset_format.md)) | GRPO training data format and how the real dataset was generated |
309
+ | [methodology.en.md](docs/methodology.en.md) ([中文](docs/methodology.md)) | Technical methodology: what's actually verified vs. still open |
310
+ | [benchmark_smoke_test.en.md](docs/benchmark_smoke_test.en.md) ([中文](docs/benchmark_smoke_test.md)) | Real LoCoMo benchmark results and failure-case analysis |
311
+ | [memory_manager_eval.en.md](docs/memory_manager_eval.en.md) ([中文](docs/memory_manager_eval.md)) | Rule-based vs. GRPO-trained policy comparison, including the debugging process |
312
+ | [multimodal_verification.en.md](docs/multimodal_verification.en.md) ([中文](docs/multimodal_verification.md)) | Image + CLIP verification experiment results |
313
+ | [gpu_training_runbook.en.md](docs/gpu_training_runbook.en.md) ([中文](docs/gpu_training_runbook.md)) | GPU training environment setup log (including real gotchas hit) |
314
+ | [postgres_setup.en.md](docs/postgres_setup.en.md) ([中文](docs/postgres_setup.md)) | Cloud Postgres backend deployment log |
315
+ | [leaderboard_submission.en.md](docs/leaderboard_submission.en.md) ([中文](docs/leaderboard_submission.md)) | Third-party leaderboard research |
316
+ | [mvp_scope.en.md](docs/mvp_scope.en.md) ([中文](docs/mvp_scope.md)) | MVP scope definition |
317
+ | [privacy_policy_draft.en.md](docs/privacy_policy_draft.en.md) ([中文](docs/privacy_policy_draft.md)) / [product_copy_memory_passport.en.md](docs/product_copy_memory_passport.en.md) ([中文](docs/product_copy_memory_passport.md)) | Draft privacy policy / external-facing product copy |
318
+ | [eng_note_cjk_rendering_bug.en.md](docs/eng_note_cjk_rendering_bug.en.md) ([中文](docs/eng_note_cjk_rendering_bug.md)) | Engineering note: a real discover→fix→verify trace for a CJK rendering bug |
319
+
320
+ Every doc above now has both a Chinese and an English version.
321
+
322
+ ## Known limitations
323
+
324
+ - Multimodal verification for voice input (ASR + audio embedding) isn't
325
+ implemented yet.
326
+ - The GRPO training dataset (140 real samples) and the number of training
327
+ steps are still small; `memory_manager_eval.md` honestly documents how
328
+ that limits training effectiveness.
329
+ - The cloud API/billing is skeleton-level only and hasn't been connected
330
+ to a real production environment.
331
+
332
+ ## License
333
+
334
+ See [LICENSE](LICENSE).