memu-cli 0.3.0__tar.gz → 0.4.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 (216) hide show
  1. {memu_cli-0.3.0 → memu_cli-0.4.0}/CHANGELOG.md +100 -0
  2. memu_cli-0.4.0/INSTALL-LATEST.md +134 -0
  3. {memu_cli-0.3.0 → memu_cli-0.4.0}/PKG-INFO +9 -4
  4. {memu_cli-0.3.0 → memu_cli-0.4.0}/README.md +8 -3
  5. {memu_cli-0.3.0 → memu_cli-0.4.0}/SKILL.md +20 -1
  6. {memu_cli-0.3.0 → memu_cli-0.4.0}/pyproject.toml +2 -1
  7. {memu_cli-0.3.0 → memu_cli-0.4.0}/src/memu/app/agentic.py +17 -4
  8. {memu_cli-0.3.0 → memu_cli-0.4.0}/src/memu/cli.py +8 -0
  9. {memu_cli-0.3.0 → memu_cli-0.4.0}/src/memu/embedding/http_client.py +60 -5
  10. {memu_cli-0.3.0 → memu_cli-0.4.0}/src/memu/embedding/openai_sdk.py +21 -2
  11. {memu_cli-0.3.0 → memu_cli-0.4.0}/src/memu/env.py +20 -1
  12. {memu_cli-0.3.0 → memu_cli-0.4.0}/src/memu/hosts/bridging/layout.py +15 -2
  13. {memu_cli-0.3.0 → memu_cli-0.4.0}/src/memu/hosts/bridging/manifest.py +8 -4
  14. {memu_cli-0.3.0 → memu_cli-0.4.0}/src/memu/hosts/bridging/pipeline.py +24 -4
  15. {memu_cli-0.3.0 → memu_cli-0.4.0}/src/memu/hosts/bridging/transcripts.py +14 -7
  16. {memu_cli-0.3.0 → memu_cli-0.4.0}/src/memu/hosts/claude_code/BRIDGING_TASK.md +39 -6
  17. memu_cli-0.4.0/src/memu/hosts/claude_code/INSTALL.md +197 -0
  18. memu_cli-0.4.0/src/memu/hosts/claude_code/UNINSTALL.md +108 -0
  19. {memu_cli-0.3.0 → memu_cli-0.4.0}/src/memu/hosts/claude_code/cli.py +6 -0
  20. {memu_cli-0.3.0 → memu_cli-0.4.0}/src/memu/hosts/claude_code/sessions.py +11 -9
  21. {memu_cli-0.3.0 → memu_cli-0.4.0}/src/memu/hosts/codex/BRIDGING_TASK.md +21 -10
  22. {memu_cli-0.3.0 → memu_cli-0.4.0}/src/memu/hosts/codex/INSTALL.md +68 -19
  23. memu_cli-0.4.0/src/memu/hosts/codex/UNINSTALL.md +101 -0
  24. {memu_cli-0.3.0 → memu_cli-0.4.0}/src/memu/hosts/codex/cli.py +6 -0
  25. memu_cli-0.4.0/src/memu/hosts/codex/sessions.py +80 -0
  26. {memu_cli-0.3.0 → memu_cli-0.4.0}/src/memu/hosts/cursor/BRIDGING_TASK.md +37 -5
  27. {memu_cli-0.3.0 → memu_cli-0.4.0}/src/memu/hosts/cursor/INSTALL.md +34 -1
  28. memu_cli-0.4.0/src/memu/hosts/cursor/UNINSTALL.md +105 -0
  29. {memu_cli-0.3.0 → memu_cli-0.4.0}/src/memu/hosts/cursor/cli.py +1 -0
  30. {memu_cli-0.3.0 → memu_cli-0.4.0}/src/memu/hosts/generic/BRIDGING_TASK.md +47 -10
  31. {memu_cli-0.3.0 → memu_cli-0.4.0}/src/memu/hosts/generic/INSTALL.md +34 -1
  32. memu_cli-0.4.0/src/memu/hosts/generic/UNINSTALL.md +108 -0
  33. {memu_cli-0.3.0 → memu_cli-0.4.0}/src/memu/hosts/generic/cli.py +1 -0
  34. {memu_cli-0.3.0 → memu_cli-0.4.0}/src/memu/hosts/hermes/BRIDGING_TASK.md +35 -3
  35. {memu_cli-0.3.0 → memu_cli-0.4.0}/src/memu/hosts/hermes/INSTALL.md +57 -11
  36. memu_cli-0.4.0/src/memu/hosts/hermes/UNINSTALL.md +114 -0
  37. {memu_cli-0.3.0 → memu_cli-0.4.0}/src/memu/hosts/hermes/cli.py +8 -1
  38. {memu_cli-0.3.0 → memu_cli-0.4.0}/src/memu/hosts/hermes/sessions.py +4 -1
  39. {memu_cli-0.3.0 → memu_cli-0.4.0}/src/memu/hosts/host_cli.py +101 -5
  40. memu_cli-0.4.0/src/memu/hosts/instruction.py +320 -0
  41. {memu_cli-0.3.0 → memu_cli-0.4.0}/src/memu/hosts/openclaw/BRIDGING_TASK.md +40 -9
  42. memu_cli-0.4.0/src/memu/hosts/openclaw/INSTALL.md +179 -0
  43. memu_cli-0.4.0/src/memu/hosts/openclaw/UNINSTALL.md +112 -0
  44. {memu_cli-0.3.0 → memu_cli-0.4.0}/src/memu/hosts/openclaw/cli.py +8 -1
  45. {memu_cli-0.3.0 → memu_cli-0.4.0}/src/memu/hosts/openclaw/sessions.py +17 -1
  46. memu_cli-0.4.0/src/memu/hosts/workbuddy/BRIDGING_TASK.md +115 -0
  47. {memu_cli-0.3.0/src/memu/hosts/claude_code → memu_cli-0.4.0/src/memu/hosts/workbuddy}/INSTALL.md +46 -37
  48. memu_cli-0.4.0/src/memu/hosts/workbuddy/UNINSTALL.md +96 -0
  49. memu_cli-0.4.0/src/memu/hosts/workbuddy/__init__.py +11 -0
  50. memu_cli-0.4.0/src/memu/hosts/workbuddy/cli.py +48 -0
  51. memu_cli-0.4.0/src/memu/hosts/workbuddy/sessions.py +86 -0
  52. {memu_cli-0.3.0 → memu_cli-0.4.0}/tests/test_agentic.py +8 -3
  53. memu_cli-0.4.0/tests/test_bridging_promotion.py +125 -0
  54. memu_cli-0.4.0/tests/test_cli_stdio.py +47 -0
  55. memu_cli-0.4.0/tests/test_doctor_proxy_hint.py +169 -0
  56. memu_cli-0.4.0/tests/test_embedding_proxy.py +200 -0
  57. memu_cli-0.4.0/tests/test_env_passthrough.py +72 -0
  58. {memu_cli-0.3.0 → memu_cli-0.4.0}/tests/test_host_generic.py +7 -6
  59. memu_cli-0.4.0/tests/test_host_instruction.py +294 -0
  60. {memu_cli-0.3.0 → memu_cli-0.4.0}/tests/test_host_sessions.py +199 -2
  61. memu_cli-0.3.0/src/memu/hosts/codex/sessions.py +0 -52
  62. memu_cli-0.3.0/src/memu/hosts/instruction.py +0 -167
  63. memu_cli-0.3.0/src/memu/hosts/openclaw/INSTALL.md +0 -129
  64. memu_cli-0.3.0/tests/test_host_instruction.py +0 -107
  65. {memu_cli-0.3.0 → memu_cli-0.4.0}/.github/ISSUE_TEMPLATE/bug_report.yml +0 -0
  66. {memu_cli-0.3.0 → memu_cli-0.4.0}/.github/ISSUE_TEMPLATE/config.yml +0 -0
  67. {memu_cli-0.3.0 → memu_cli-0.4.0}/.github/ISSUE_TEMPLATE/feature_request.yml +0 -0
  68. {memu_cli-0.3.0 → memu_cli-0.4.0}/.github/ISSUE_TEMPLATE/hackathon_task.yml +0 -0
  69. {memu_cli-0.3.0 → memu_cli-0.4.0}/.github/ISSUE_TEMPLATE/improvement_suggestion.yml +0 -0
  70. {memu_cli-0.3.0 → memu_cli-0.4.0}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
  71. {memu_cli-0.3.0 → memu_cli-0.4.0}/.github/workflows/build.yml +0 -0
  72. {memu_cli-0.3.0 → memu_cli-0.4.0}/.github/workflows/pr-title.yml +0 -0
  73. {memu_cli-0.3.0 → memu_cli-0.4.0}/.github/workflows/publish-memu-cli.yml +0 -0
  74. {memu_cli-0.3.0 → memu_cli-0.4.0}/.github/workflows/release-please.yml +0 -0
  75. {memu_cli-0.3.0 → memu_cli-0.4.0}/.gitignore +0 -0
  76. {memu_cli-0.3.0 → memu_cli-0.4.0}/.pre-commit-config.yaml +0 -0
  77. {memu_cli-0.3.0 → memu_cli-0.4.0}/.python-version +0 -0
  78. {memu_cli-0.3.0 → memu_cli-0.4.0}/AGENTS.md +0 -0
  79. {memu_cli-0.3.0 → memu_cli-0.4.0}/CONTRIBUTING.md +0 -0
  80. {memu_cli-0.3.0 → memu_cli-0.4.0}/Cargo.lock +0 -0
  81. {memu_cli-0.3.0 → memu_cli-0.4.0}/Cargo.toml +0 -0
  82. {memu_cli-0.3.0 → memu_cli-0.4.0}/LICENSE.txt +0 -0
  83. {memu_cli-0.3.0 → memu_cli-0.4.0}/MANIFEST.in +0 -0
  84. {memu_cli-0.3.0 → memu_cli-0.4.0}/Makefile +0 -0
  85. {memu_cli-0.3.0 → memu_cli-0.4.0}/assets/banner.png +0 -0
  86. {memu_cli-0.3.0 → memu_cli-0.4.0}/assets/benchmark.png +0 -0
  87. {memu_cli-0.3.0 → memu_cli-0.4.0}/assets/memUbot.png +0 -0
  88. {memu_cli-0.3.0 → memu_cli-0.4.0}/assets/memorize.png +0 -0
  89. {memu_cli-0.3.0 → memu_cli-0.4.0}/assets/partners/Clawdchat.png +0 -0
  90. {memu_cli-0.3.0 → memu_cli-0.4.0}/assets/partners/LazyLLM.png +0 -0
  91. {memu_cli-0.3.0 → memu_cli-0.4.0}/assets/partners/buddie.png +0 -0
  92. {memu_cli-0.3.0 → memu_cli-0.4.0}/assets/partners/bytebase.png +0 -0
  93. {memu_cli-0.3.0 → memu_cli-0.4.0}/assets/partners/jazz.png +0 -0
  94. {memu_cli-0.3.0 → memu_cli-0.4.0}/assets/partners/openagents.png +0 -0
  95. {memu_cli-0.3.0 → memu_cli-0.4.0}/assets/partners/xroute.png +0 -0
  96. {memu_cli-0.3.0 → memu_cli-0.4.0}/assets/qrcode.png +0 -0
  97. {memu_cli-0.3.0 → memu_cli-0.4.0}/assets/retrieve.png +0 -0
  98. {memu_cli-0.3.0 → memu_cli-0.4.0}/assets/star.gif +0 -0
  99. {memu_cli-0.3.0 → memu_cli-0.4.0}/assets/structure-v2.png +0 -0
  100. {memu_cli-0.3.0 → memu_cli-0.4.0}/assets/structure.png +0 -0
  101. {memu_cli-0.3.0 → memu_cli-0.4.0}/assets/usecase/ai_companion-0000.jpg +0 -0
  102. {memu_cli-0.3.0 → memu_cli-0.4.0}/assets/usecase/ai_creation-0000.jpg +0 -0
  103. {memu_cli-0.3.0 → memu_cli-0.4.0}/assets/usecase/ai_edu-0000.jpg +0 -0
  104. {memu_cli-0.3.0 → memu_cli-0.4.0}/assets/usecase/ai_ip-0000.png +0 -0
  105. {memu_cli-0.3.0 → memu_cli-0.4.0}/assets/usecase/ai_robot-0000.jpg +0 -0
  106. {memu_cli-0.3.0 → memu_cli-0.4.0}/assets/usecase/ai_role_play-0000.jpg +0 -0
  107. {memu_cli-0.3.0 → memu_cli-0.4.0}/assets/usecase/ai_therapy-0000.jpg +0 -0
  108. {memu_cli-0.3.0 → memu_cli-0.4.0}/docs/adr/0001-workflow-pipeline-architecture.md +0 -0
  109. {memu_cli-0.3.0 → memu_cli-0.4.0}/docs/adr/0002-pluggable-storage-and-vector-strategy.md +0 -0
  110. {memu_cli-0.3.0 → memu_cli-0.4.0}/docs/adr/0003-user-scope-in-data-model.md +0 -0
  111. {memu_cli-0.3.0 → memu_cli-0.4.0}/docs/adr/0004-workspace-memorize-and-memory-file-system.md +0 -0
  112. {memu_cli-0.3.0 → memu_cli-0.4.0}/docs/adr/0005-dedicated-embedding-package.md +0 -0
  113. {memu_cli-0.3.0 → memu_cli-0.4.0}/docs/adr/0006-from-memory-item-category-to-tracked-workspace-memorization.md +0 -0
  114. {memu_cli-0.3.0 → memu_cli-0.4.0}/docs/adr/0007-three-independent-memory-lines-wiki-graph.md +0 -0
  115. {memu_cli-0.3.0 → memu_cli-0.4.0}/docs/adr/0008-two-integration-surfaces-hooks-and-api.md +0 -0
  116. {memu_cli-0.3.0 → memu_cli-0.4.0}/docs/adr/0009-codex-packaging-cli-and-config.md +0 -0
  117. {memu_cli-0.3.0 → memu_cli-0.4.0}/docs/adr/0010-multi-host-adapters.md +0 -0
  118. {memu_cli-0.3.0 → memu_cli-0.4.0}/docs/adr/0011-generic-host-adapter.md +0 -0
  119. {memu_cli-0.3.0 → memu_cli-0.4.0}/docs/adr/README.md +0 -0
  120. {memu_cli-0.3.0 → memu_cli-0.4.0}/docs/sqlite.md +0 -0
  121. {memu_cli-0.3.0 → memu_cli-0.4.0}/npm/README.md +0 -0
  122. {memu_cli-0.3.0 → memu_cli-0.4.0}/npm/bin/memu.js +0 -0
  123. {memu_cli-0.3.0 → memu_cli-0.4.0}/npm/package.json +0 -0
  124. {memu_cli-0.3.0 → memu_cli-0.4.0}/scripts/db.py +0 -0
  125. {memu_cli-0.3.0 → memu_cli-0.4.0}/setup.cfg +0 -0
  126. {memu_cli-0.3.0 → memu_cli-0.4.0}/src/lib.rs +0 -0
  127. {memu_cli-0.3.0 → memu_cli-0.4.0}/src/memu/__init__.py +0 -0
  128. {memu_cli-0.3.0 → memu_cli-0.4.0}/src/memu/__main__.py +0 -0
  129. {memu_cli-0.3.0 → memu_cli-0.4.0}/src/memu/_core.pyi +0 -0
  130. {memu_cli-0.3.0 → memu_cli-0.4.0}/src/memu/app/__init__.py +0 -0
  131. {memu_cli-0.3.0 → memu_cli-0.4.0}/src/memu/app/client_pool.py +0 -0
  132. {memu_cli-0.3.0 → memu_cli-0.4.0}/src/memu/app/service.py +0 -0
  133. {memu_cli-0.3.0 → memu_cli-0.4.0}/src/memu/app/settings.py +0 -0
  134. {memu_cli-0.3.0 → memu_cli-0.4.0}/src/memu/database/__init__.py +0 -0
  135. {memu_cli-0.3.0 → memu_cli-0.4.0}/src/memu/database/factory.py +0 -0
  136. {memu_cli-0.3.0 → memu_cli-0.4.0}/src/memu/database/inmemory/__init__.py +0 -0
  137. {memu_cli-0.3.0 → memu_cli-0.4.0}/src/memu/database/inmemory/models.py +0 -0
  138. {memu_cli-0.3.0 → memu_cli-0.4.0}/src/memu/database/inmemory/repo.py +0 -0
  139. {memu_cli-0.3.0 → memu_cli-0.4.0}/src/memu/database/inmemory/repositories/__init__.py +0 -0
  140. {memu_cli-0.3.0 → memu_cli-0.4.0}/src/memu/database/inmemory/repositories/filter.py +0 -0
  141. {memu_cli-0.3.0 → memu_cli-0.4.0}/src/memu/database/inmemory/repositories/recall_file_repo.py +0 -0
  142. {memu_cli-0.3.0 → memu_cli-0.4.0}/src/memu/database/inmemory/repositories/recall_file_resource_repo.py +0 -0
  143. {memu_cli-0.3.0 → memu_cli-0.4.0}/src/memu/database/inmemory/repositories/recall_file_segment_repo.py +0 -0
  144. {memu_cli-0.3.0 → memu_cli-0.4.0}/src/memu/database/inmemory/repositories/resource_repo.py +0 -0
  145. {memu_cli-0.3.0 → memu_cli-0.4.0}/src/memu/database/inmemory/state.py +0 -0
  146. {memu_cli-0.3.0 → memu_cli-0.4.0}/src/memu/database/inmemory/vector.py +0 -0
  147. {memu_cli-0.3.0 → memu_cli-0.4.0}/src/memu/database/interfaces.py +0 -0
  148. {memu_cli-0.3.0 → memu_cli-0.4.0}/src/memu/database/models.py +0 -0
  149. {memu_cli-0.3.0 → memu_cli-0.4.0}/src/memu/database/postgres/__init__.py +0 -0
  150. {memu_cli-0.3.0 → memu_cli-0.4.0}/src/memu/database/postgres/migration.py +0 -0
  151. {memu_cli-0.3.0 → memu_cli-0.4.0}/src/memu/database/postgres/migrations/__init__.py +0 -0
  152. {memu_cli-0.3.0 → memu_cli-0.4.0}/src/memu/database/postgres/migrations/env.py +0 -0
  153. {memu_cli-0.3.0 → memu_cli-0.4.0}/src/memu/database/postgres/migrations/script.py.mako +0 -0
  154. {memu_cli-0.3.0 → memu_cli-0.4.0}/src/memu/database/postgres/migrations/versions/20260703_0001_initial_schema.py +0 -0
  155. {memu_cli-0.3.0 → memu_cli-0.4.0}/src/memu/database/postgres/models.py +0 -0
  156. {memu_cli-0.3.0 → memu_cli-0.4.0}/src/memu/database/postgres/postgres.py +0 -0
  157. {memu_cli-0.3.0 → memu_cli-0.4.0}/src/memu/database/postgres/repositories/__init__.py +0 -0
  158. {memu_cli-0.3.0 → memu_cli-0.4.0}/src/memu/database/postgres/repositories/base.py +0 -0
  159. {memu_cli-0.3.0 → memu_cli-0.4.0}/src/memu/database/postgres/repositories/recall_file_repo.py +0 -0
  160. {memu_cli-0.3.0 → memu_cli-0.4.0}/src/memu/database/postgres/repositories/recall_file_resource_repo.py +0 -0
  161. {memu_cli-0.3.0 → memu_cli-0.4.0}/src/memu/database/postgres/repositories/recall_file_segment_repo.py +0 -0
  162. {memu_cli-0.3.0 → memu_cli-0.4.0}/src/memu/database/postgres/repositories/resource_repo.py +0 -0
  163. {memu_cli-0.3.0 → memu_cli-0.4.0}/src/memu/database/postgres/schema.py +0 -0
  164. {memu_cli-0.3.0 → memu_cli-0.4.0}/src/memu/database/postgres/session.py +0 -0
  165. {memu_cli-0.3.0 → memu_cli-0.4.0}/src/memu/database/repositories/__init__.py +0 -0
  166. {memu_cli-0.3.0 → memu_cli-0.4.0}/src/memu/database/repositories/recall_file.py +0 -0
  167. {memu_cli-0.3.0 → memu_cli-0.4.0}/src/memu/database/repositories/recall_file_resource.py +0 -0
  168. {memu_cli-0.3.0 → memu_cli-0.4.0}/src/memu/database/repositories/recall_file_segment.py +0 -0
  169. {memu_cli-0.3.0 → memu_cli-0.4.0}/src/memu/database/repositories/resource.py +0 -0
  170. {memu_cli-0.3.0 → memu_cli-0.4.0}/src/memu/database/sqlite/__init__.py +0 -0
  171. {memu_cli-0.3.0 → memu_cli-0.4.0}/src/memu/database/sqlite/models.py +0 -0
  172. {memu_cli-0.3.0 → memu_cli-0.4.0}/src/memu/database/sqlite/repositories/__init__.py +0 -0
  173. {memu_cli-0.3.0 → memu_cli-0.4.0}/src/memu/database/sqlite/repositories/base.py +0 -0
  174. {memu_cli-0.3.0 → memu_cli-0.4.0}/src/memu/database/sqlite/repositories/recall_file_repo.py +0 -0
  175. {memu_cli-0.3.0 → memu_cli-0.4.0}/src/memu/database/sqlite/repositories/recall_file_resource_repo.py +0 -0
  176. {memu_cli-0.3.0 → memu_cli-0.4.0}/src/memu/database/sqlite/repositories/recall_file_segment_repo.py +0 -0
  177. {memu_cli-0.3.0 → memu_cli-0.4.0}/src/memu/database/sqlite/repositories/resource_repo.py +0 -0
  178. {memu_cli-0.3.0 → memu_cli-0.4.0}/src/memu/database/sqlite/schema.py +0 -0
  179. {memu_cli-0.3.0 → memu_cli-0.4.0}/src/memu/database/sqlite/session.py +0 -0
  180. {memu_cli-0.3.0 → memu_cli-0.4.0}/src/memu/database/sqlite/sqlite.py +0 -0
  181. {memu_cli-0.3.0 → memu_cli-0.4.0}/src/memu/database/state.py +0 -0
  182. {memu_cli-0.3.0 → memu_cli-0.4.0}/src/memu/embedding/__init__.py +0 -0
  183. {memu_cli-0.3.0 → memu_cli-0.4.0}/src/memu/embedding/backends/__init__.py +0 -0
  184. {memu_cli-0.3.0 → memu_cli-0.4.0}/src/memu/embedding/backends/base.py +0 -0
  185. {memu_cli-0.3.0 → memu_cli-0.4.0}/src/memu/embedding/backends/doubao.py +0 -0
  186. {memu_cli-0.3.0 → memu_cli-0.4.0}/src/memu/embedding/backends/jina.py +0 -0
  187. {memu_cli-0.3.0 → memu_cli-0.4.0}/src/memu/embedding/backends/openai.py +0 -0
  188. {memu_cli-0.3.0 → memu_cli-0.4.0}/src/memu/embedding/backends/openrouter.py +0 -0
  189. {memu_cli-0.3.0 → memu_cli-0.4.0}/src/memu/embedding/backends/voyage.py +0 -0
  190. {memu_cli-0.3.0 → memu_cli-0.4.0}/src/memu/embedding/base.py +0 -0
  191. {memu_cli-0.3.0 → memu_cli-0.4.0}/src/memu/embedding/defaults.py +0 -0
  192. {memu_cli-0.3.0 → memu_cli-0.4.0}/src/memu/embedding/gateway.py +0 -0
  193. {memu_cli-0.3.0 → memu_cli-0.4.0}/src/memu/hosts/__init__.py +0 -0
  194. {memu_cli-0.3.0 → memu_cli-0.4.0}/src/memu/hosts/base.py +0 -0
  195. {memu_cli-0.3.0 → memu_cli-0.4.0}/src/memu/hosts/bridging/__init__.py +0 -0
  196. {memu_cli-0.3.0 → memu_cli-0.4.0}/src/memu/hosts/bridging/instructions.py +0 -0
  197. {memu_cli-0.3.0 → memu_cli-0.4.0}/src/memu/hosts/bridging/recall_files.py +0 -0
  198. {memu_cli-0.3.0 → memu_cli-0.4.0}/src/memu/hosts/bridging/resources.py +0 -0
  199. {memu_cli-0.3.0 → memu_cli-0.4.0}/src/memu/hosts/claude_code/__init__.py +0 -0
  200. {memu_cli-0.3.0 → memu_cli-0.4.0}/src/memu/hosts/codex/__init__.py +0 -0
  201. {memu_cli-0.3.0 → memu_cli-0.4.0}/src/memu/hosts/cursor/__init__.py +0 -0
  202. {memu_cli-0.3.0 → memu_cli-0.4.0}/src/memu/hosts/cursor/sessions.py +0 -0
  203. {memu_cli-0.3.0 → memu_cli-0.4.0}/src/memu/hosts/generic/__init__.py +0 -0
  204. {memu_cli-0.3.0 → memu_cli-0.4.0}/src/memu/hosts/generic/detect.py +0 -0
  205. {memu_cli-0.3.0 → memu_cli-0.4.0}/src/memu/hosts/generic/sessions.py +0 -0
  206. {memu_cli-0.3.0 → memu_cli-0.4.0}/src/memu/hosts/hermes/__init__.py +0 -0
  207. {memu_cli-0.3.0 → memu_cli-0.4.0}/src/memu/hosts/openclaw/__init__.py +0 -0
  208. {memu_cli-0.3.0 → memu_cli-0.4.0}/src/memu/hosts/retrieval.py +0 -0
  209. {memu_cli-0.3.0 → memu_cli-0.4.0}/src/memu/vector.py +0 -0
  210. {memu_cli-0.3.0 → memu_cli-0.4.0}/tests/__init__.py +0 -0
  211. {memu_cli-0.3.0 → memu_cli-0.4.0}/tests/rust_entry_test.py +0 -0
  212. {memu_cli-0.3.0 → memu_cli-0.4.0}/tests/test_cli.py +0 -0
  213. {memu_cli-0.3.0 → memu_cli-0.4.0}/tests/test_embedding.py +0 -0
  214. {memu_cli-0.3.0 → memu_cli-0.4.0}/tests/test_postgres_migration_config.py +0 -0
  215. {memu_cli-0.3.0 → memu_cli-0.4.0}/tests/test_vector.py +0 -0
  216. {memu_cli-0.3.0 → memu_cli-0.4.0}/uv.lock +0 -0
@@ -1,5 +1,105 @@
1
1
  # Changelog
2
2
 
3
+ ## [2.0.0-beta.0](https://github.com/NevaMind-AI/memU/compare/v1.5.1...v2.0.0-beta.0) (2026-07-23)
4
+
5
+
6
+ ### Features
7
+
8
+ * **blob:** ingest rich documents (PDF/Office/HTML) via MarkItDown ([#447](https://github.com/NevaMind-AI/memU/issues/447)) ([1e16341](https://github.com/NevaMind-AI/memU/commit/1e1634131f84ceb023d03cd87bcf062317abd5ba))
9
+ * Codex session-bridging pipeline and scheduled-task skill ([#477](https://github.com/NevaMind-AI/memU/issues/477)) ([1a8edb5](https://github.com/NevaMind-AI/memU/commit/1a8edb57110ebfd208b2fe1f52e3998058fed408))
10
+ * **doctor:** diagnose proxy hijacking instead of printing a bare 502 ([7c41eec](https://github.com/NevaMind-AI/memU/commit/7c41eecd53e4c13b1a5c25b01b70f484147295fb))
11
+ * **env:** config.env carries NO_PROXY; MEMU_HTTP_PROXY works from the file ([5265945](https://github.com/NevaMind-AI/memU/commit/5265945e3063529819415194e79c46b7614d6081))
12
+ * from memory item/category to tracked entry/file for workspace memorization (ADR 0006) ([#456](https://github.com/NevaMind-AI/memU/issues/456)) ([68877da](https://github.com/NevaMind-AI/memU/commit/68877da10a1a18be5c708ec1ab7eb6c45b80ae50))
13
+ * **hermes:** install retrieval as a skill ([#536](https://github.com/NevaMind-AI/memU/issues/536)) ([8766d3d](https://github.com/NevaMind-AI/memU/commit/8766d3d3903383a3d4ff38d0f0d620cdf97418ec))
14
+ * **hosts:** add Claude Code, Cursor, OpenClaw, and Hermes host adapters ([#494](https://github.com/NevaMind-AI/memU/issues/494)) ([24d1b3b](https://github.com/NevaMind-AI/memU/commit/24d1b3b4f345106f07f1262dc2756b49fb7102cf))
15
+ * **hosts:** add memu-agent, a generic adapter for any other agent ([#496](https://github.com/NevaMind-AI/memU/issues/496)) ([e46a1f0](https://github.com/NevaMind-AI/memU/commit/e46a1f04a216a80b3a38064866420c79205fbe22))
16
+ * **hosts:** agent-driven uninstall — remove-instruction, docs uninstall, per-host guides ([#509](https://github.com/NevaMind-AI/memU/issues/509)) ([f51673e](https://github.com/NevaMind-AI/memU/commit/f51673e6e80b23c570a7364b415bf61481956971))
17
+ * **hosts:** install retrieval as a skill on Codex and Claude Code ([#535](https://github.com/NevaMind-AI/memU/issues/535)) ([2ed480e](https://github.com/NevaMind-AI/memU/commit/2ed480ebe462fe4008fdb4315cf5ab9e0316dba4))
18
+ * layered, track-aware workspace memorize & retrieve ([#466](https://github.com/NevaMind-AI/memU/issues/466)) ([094e22f](https://github.com/NevaMind-AI/memU/commit/094e22f0e10e7fe71c079608407b6a01b4d67e55))
19
+ * **llm,vlm:** multi-provider LLM gateway, modular preprocessing, and VLM package ([#442](https://github.com/NevaMind-AI/memU/issues/442)) ([6f1b0bc](https://github.com/NevaMind-AI/memU/commit/6f1b0bc19d600e77abe7d6ec82d4196d1efe1516))
20
+ * **memory_fs:** workspace memorize + markdown memory file system ([#439](https://github.com/NevaMind-AI/memU/issues/439)) ([1b1ad61](https://github.com/NevaMind-AI/memU/commit/1b1ad61bdb96030f00e169b14d7864c1f6adb931))
21
+ * memu CLI, npm launcher, and agent skills for the workspace pair ([#467](https://github.com/NevaMind-AI/memU/issues/467)) ([c861974](https://github.com/NevaMind-AI/memU/commit/c8619744b13c67f7efc3322c060e6090255a8522))
22
+ * **npm:** point the launcher at the memu-cli PyPI channel ([#483](https://github.com/NevaMind-AI/memU/issues/483)) ([5056389](https://github.com/NevaMind-AI/memU/commit/505638905f279e0b2fac61572ea551f819007aa1))
23
+ * **openclaw:** install retrieval as a skill ([#537](https://github.com/NevaMind-AI/memU/issues/537)) ([3cef5ae](https://github.com/NevaMind-AI/memU/commit/3cef5ae2610ce9227de6471a63cc139ff09cf63c))
24
+ * **preprocess:** classify audio type and add an overview on ingest ([#448](https://github.com/NevaMind-AI/memU/issues/448)) ([f7601da](https://github.com/NevaMind-AI/memU/commit/f7601daf4ed89815af5c1c1c9011db6af63c1fa5))
25
+ * **vlm,preprocess:** native whole-video understanding via OpenRouter ([#450](https://github.com/NevaMind-AI/memU/issues/450)) ([1de5784](https://github.com/NevaMind-AI/memU/commit/1de57847e0ffc430cbf5d6dc17183f33d08be8fe))
26
+
27
+
28
+ ### Bug Fixes
29
+
30
+ * **app:** unpack the (vectors, raw_response) tuple embed() returns ([#504](https://github.com/NevaMind-AI/memU/issues/504)) ([9b2a70c](https://github.com/NevaMind-AI/memU/commit/9b2a70ca214cd3a5b22e902cad0dc19ad07bfeb9))
31
+ * **bridging:** advance the cursor and snapshot at commit, not prepare ([#531](https://github.com/NevaMind-AI/memU/issues/531)) ([0ceaa19](https://github.com/NevaMind-AI/memU/commit/0ceaa190d92f8c7c6705db0dcfd6628581d10213))
32
+ * **ci:** sort workbuddy cli imports so make check passes ([#522](https://github.com/NevaMind-AI/memU/issues/522)) ([151298c](https://github.com/NevaMind-AI/memU/commit/151298c3c03a6b3cc9ef371d8211b469fffc2469))
33
+ * **cli:** force UTF-8 stdio so piped output survives non-UTF-8 Windows code pages ([#513](https://github.com/NevaMind-AI/memU/issues/513)) ([b521453](https://github.com/NevaMind-AI/memU/commit/b5214536c5fce628c174c9c074b9c1d0a53da2ca))
34
+ * **codex:** drop harness-injected user records from the conversation seam ([#511](https://github.com/NevaMind-AI/memU/issues/511)) ([c827157](https://github.com/NevaMind-AI/memU/commit/c827157ead066f0a859cb2f1e5deac62ffbe63a5))
35
+ * **embedding:** never route loopback embedding calls through a proxy ([#519](https://github.com/NevaMind-AI/memU/issues/519)) ([df6cfba](https://github.com/NevaMind-AI/memU/commit/df6cfba6b9741cc062b7d219af042ddddffcbb5c))
36
+ * handle multiple root-level XML elements from non-conformant LLMs ([#409](https://github.com/NevaMind-AI/memU/issues/409)) ([fed42b6](https://github.com/NevaMind-AI/memU/commit/fed42b6142ec1e9f9820e46d8899823d68de8276))
37
+ * **hermes:** escape the state.db path when building the SQLite URI ([#503](https://github.com/NevaMind-AI/memU/issues/503)) ([3135132](https://github.com/NevaMind-AI/memU/commit/313513204d87e7156d6a7d459df1bcac64469044))
38
+ * **llm/vlm:** correct OpenAI token-limit param and simplify conversation preprocess ([#449](https://github.com/NevaMind-AI/memU/issues/449)) ([ff3c2be](https://github.com/NevaMind-AI/memU/commit/ff3c2bee2ec96ebd303f3e22dae1977ff6388120))
39
+ * make lazyllm an optional dependency (fixes [#373](https://github.com/NevaMind-AI/memU/issues/373)) ([#402](https://github.com/NevaMind-AI/memU/issues/402)) ([7652982](https://github.com/NevaMind-AI/memU/commit/7652982a016b2a2426d20bc11c46491d909704d0))
40
+ * **memory_fs:** restore LLM-free skill bypass and unify synthesis paths ([#444](https://github.com/NevaMind-AI/memU/issues/444)) ([bc13bd4](https://github.com/NevaMind-AI/memU/commit/bc13bd43c6ed3d480b671736bab987434675c717))
41
+ * **openclaw:** scan only main session transcripts, not trajectory/checkpoint sidecars ([0245de9](https://github.com/NevaMind-AI/memU/commit/0245de9710f8f73a8b21361442ac3dfd6c7829c7))
42
+ * optimize category initialization to avoid unnecessary embedding ([#388](https://github.com/NevaMind-AI/memU/issues/388)) ([a92f266](https://github.com/NevaMind-AI/memU/commit/a92f2666bf94336f8c6bf950088249e611915e7d))
43
+ * remove broken memu-server entry point (fixes [#354](https://github.com/NevaMind-AI/memU/issues/354)) ([#398](https://github.com/NevaMind-AI/memU/issues/398)) ([0672b56](https://github.com/NevaMind-AI/memU/commit/0672b56725e12c35bd46061bb23ccd93690a5fbb))
44
+ * remove duplicate document text from preprocess prompt ([#420](https://github.com/NevaMind-AI/memU/issues/420)) ([44aa5ff](https://github.com/NevaMind-AI/memU/commit/44aa5ff0cbceae56ab283848e722a9d4bd8eddd0))
45
+ * remove stale memu-server script entry point (fixes [#393](https://github.com/NevaMind-AI/memU/issues/393)) ([#403](https://github.com/NevaMind-AI/memU/issues/403)) ([c5fe493](https://github.com/NevaMind-AI/memU/commit/c5fe493b0596d68479b0ce6c6d83e362ffb04e90))
46
+ * resolve SQLite embedding TypeError by using sa_column=False ([#401](https://github.com/NevaMind-AI/memU/issues/401)) ([7e198f3](https://github.com/NevaMind-AI/memU/commit/7e198f3718fa6028c809ba7d816a96541fe7e13f))
47
+ * return empty list for non-positive top_k in cosine_topk ([#423](https://github.com/NevaMind-AI/memU/issues/423)) ([39023a8](https://github.com/NevaMind-AI/memU/commit/39023a81d758eb4447ed7d88503b8d782aecaf73))
48
+ * **tests:** pin UTF-8 on test file I/O so the suite passes on non-UTF-8-locale Windows ([#501](https://github.com/NevaMind-AI/memU/issues/501)) ([dda515a](https://github.com/NevaMind-AI/memU/commit/dda515a4eb3117ff804cd7ce1ae66e03c23028b6))
49
+
50
+
51
+ ### Documentation
52
+
53
+ * add ADR 0008 — trajectory as the source, hooks over API ([#476](https://github.com/NevaMind-AI/memU/issues/476)) ([ff90dac](https://github.com/NevaMind-AI/memU/commit/ff90dac6976bc920667e03d295a75d5da8626f75))
54
+ * add INSTALL-LATEST.md and register the WorkBuddy adapter ([#527](https://github.com/NevaMind-AI/memU/issues/527)) ([4871c55](https://github.com/NevaMind-AI/memU/commit/4871c558d5b84c7649d822015dab617a095d678f))
55
+ * add SKILL.md, one routing entry point for agent-driven install ([#497](https://github.com/NevaMind-AI/memU/issues/497)) ([bf7aaf3](https://github.com/NevaMind-AI/memU/commit/bf7aaf3bf95cb37f723e7a81b6d5bcdaf35a0f2e))
56
+ * add the architecture image the README references ([#492](https://github.com/NevaMind-AI/memU/issues/492)) ([c07b905](https://github.com/NevaMind-AI/memU/commit/c07b9055dc245680c67df02199d4c95cd7a9a62f))
57
+ * add under-construction notice, stabilizing ~July 15 ([#472](https://github.com/NevaMind-AI/memU/issues/472)) ([6426ff0](https://github.com/NevaMind-AI/memU/commit/6426ff02aacca12e9d4efbcfc89f53eeed2ae55b))
58
+ * ADR 0007 — drop the graph, retrieval is hybrid (embedding + BM25) ([#464](https://github.com/NevaMind-AI/memU/issues/464)) ([3dd7d5c](https://github.com/NevaMind-AI/memU/commit/3dd7d5c055fc6a3244d4c2390f7b8e6bc4321857))
59
+ * ADR 0007 — invert L1/L2 (L1 = coarse doc, L2 = item slices) ([#465](https://github.com/NevaMind-AI/memU/issues/465)) ([0afbcc5](https://github.com/NevaMind-AI/memU/commit/0afbcc550ac5b816e5ae9ad309e62adbdf4b80b4))
60
+ * ADR 0007 — replace the explicit item graph with entity linking ([#463](https://github.com/NevaMind-AI/memU/issues/463)) ([0bd3c77](https://github.com/NevaMind-AI/memU/commit/0bd3c7765ac791020941de8791ba5b7c50ecc5e0))
61
+ * ADR 0007 — three independent memory lines on a layered wiki-graph kernel ([#461](https://github.com/NevaMind-AI/memU/issues/461)) ([a6cf62e](https://github.com/NevaMind-AI/memU/commit/a6cf62e069765b7b234597e537ec170d169d751c))
62
+ * align architecture.md and READMEs with ADR 0006 data model ([#460](https://github.com/NevaMind-AI/memU/issues/460)) ([8062b91](https://github.com/NevaMind-AI/memU/commit/8062b91776e69757fd467e79e56cd72eba62c72c))
63
+ * consolidate agent skills into one memu SKILL.md, link it atop README ([#469](https://github.com/NevaMind-AI/memU/issues/469)) ([6f0ae82](https://github.com/NevaMind-AI/memU/commit/6f0ae82aaf9d1193841b8e082a2f9fed8753ed70))
64
+ * drop the API and CLI reference sections from the README ([#489](https://github.com/NevaMind-AI/memU/issues/489)) ([94a1111](https://github.com/NevaMind-AI/memU/commit/94a11117cf5684888fb7858356c51203c903e9bb))
65
+ * expand the README; rename provider var to MEMU_EMBED_PROVIDER ([#486](https://github.com/NevaMind-AI/memU/issues/486)) ([96da89b](https://github.com/NevaMind-AI/memU/commit/96da89bfe048b86516faa4b86f69b508fb4c4c3c))
66
+ * focus readme on workspace APIs ([9241f31](https://github.com/NevaMind-AI/memU/commit/9241f3112e912bd47add2fabe6dc2611a4bdac8c))
67
+ * **grok:** fix MemoryService initialization example ([#405](https://github.com/NevaMind-AI/memU/issues/405)) ([96e693a](https://github.com/NevaMind-AI/memU/commit/96e693aa09add032f67b342e21b86fa96078611b))
68
+ * highlight self-evolving skills in README and description ([#452](https://github.com/NevaMind-AI/memU/issues/452)) ([fb68d22](https://github.com/NevaMind-AI/memU/commit/fb68d22c3caa4a9b6f5cb2a57d185bb9b5e22a5f))
69
+ * **hosts:** bind the session cursor's lifecycle to the store's ([75959a6](https://github.com/NevaMind-AI/memU/commit/75959a6e72727c35929f4296c087ed00c97971bf))
70
+ * **hosts:** correct the Claude Code multi-block claim and pin it with tests ([#502](https://github.com/NevaMind-AI/memU/issues/502)) ([5995e05](https://github.com/NevaMind-AI/memU/commit/5995e05f27c7d90231468bcb062713af30813b08))
71
+ * **hosts:** default bridging schedule to hourly ([#516](https://github.com/NevaMind-AI/memU/issues/516)) ([c1046bb](https://github.com/NevaMind-AI/memU/commit/c1046bb1954c3dd7b16ced769da030d8a02c8d32))
72
+ * **hosts:** name the OS system-wide proxy as a 502 source ([#523](https://github.com/NevaMind-AI/memU/issues/523)) ([2b79803](https://github.com/NevaMind-AI/memU/commit/2b79803612872e65201a40dde95ac00541f93fae))
73
+ * **hosts:** no-key local fallback hint; default bridging schedule to cron ([#508](https://github.com/NevaMind-AI/memU/issues/508)) ([d155c48](https://github.com/NevaMind-AI/memU/commit/d155c48ac6a35465ad47848927b271f34e2dc4d0))
74
+ * **hosts:** scheduled runs drain leftover jobs first; config repairs stay at the connection layer ([9195d14](https://github.com/NevaMind-AI/memU/commit/9195d14cef2d308cff3fcb853a6274e1f0db9d31))
75
+ * **hosts:** the scheduler's PATH is not your shell's — fix and honest verify for the bridging guides ([#530](https://github.com/NevaMind-AI/memU/issues/530)) ([19302d2](https://github.com/NevaMind-AI/memU/commit/19302d24260c7b941bdfee66bba8f16b6b47c8c2))
76
+ * lead the README with the one-message agent-driven install ([#498](https://github.com/NevaMind-AI/memU/issues/498)) ([aae3d44](https://github.com/NevaMind-AI/memU/commit/aae3d44b0a4332981c4459e7da9258298bcc0fb1))
77
+ * make the workspace pair primary, mark memorize/retrieve as legacy ([#470](https://github.com/NevaMind-AI/memU/issues/470)) ([6f3c1be](https://github.com/NevaMind-AI/memU/commit/6f3c1beb36bba21a7d640b0dbdead9361a90a811))
78
+ * never fall back to legacy memorize/retrieve ([#471](https://github.com/NevaMind-AI/memU/issues/471)) ([28ee09d](https://github.com/NevaMind-AI/memU/commit/28ee09de54de5bd74f4f6bb1e0185c854ecf1053))
79
+ * pitch memU as a 500-line memory system ([#488](https://github.com/NevaMind-AI/memU/issues/488)) ([2a8f8b3](https://github.com/NevaMind-AI/memU/commit/2a8f8b3403548a8d8917a19d5ac0015adf4eab17))
80
+ * point the README at the memu-cli package ([#491](https://github.com/NevaMind-AI/memU/issues/491)) ([9ceea5b](https://github.com/NevaMind-AI/memU/commit/9ceea5b32a2694cf4ab5e5f0069b029ac13800b3))
81
+ * **readme:** readme accuracy updates ([#430](https://github.com/NevaMind-AI/memU/issues/430)) ([5f17725](https://github.com/NevaMind-AI/memU/commit/5f1772579c8d0881ec1c9ab071404aea6b3bfadc))
82
+ * **readme:** reframe intro around MEMORY.md, SKILL.md, and INDEX.md ([#434](https://github.com/NevaMind-AI/memU/issues/434)) ([ca0c755](https://github.com/NevaMind-AI/memU/commit/ca0c755dcc06874c227df811d6b7a3ca972f6be2))
83
+ * **readme:** reframe README around file-system-as-memory narrative ([#432](https://github.com/NevaMind-AI/memU/issues/432)) ([cd8150a](https://github.com/NevaMind-AI/memU/commit/cd8150ac7d68f4972d9a9e8268e3169da9b4cfc3))
84
+ * **readme:** reframe README around workspace-runtime narrative ([#438](https://github.com/NevaMind-AI/memU/issues/438)) ([7c104b1](https://github.com/NevaMind-AI/memU/commit/7c104b1eb0883437d49bea0edae3a24eea12f275))
85
+ * **readme:** sync translated READMEs to file-system-as-memory narrative ([#433](https://github.com/NevaMind-AI/memU/issues/433)) ([f4e82ce](https://github.com/NevaMind-AI/memU/commit/f4e82cec1898e34f82612ec3628f8de1faedf701))
86
+ * refine ADR 0007 with the L0/L1/L2 layer model ([#462](https://github.com/NevaMind-AI/memU/issues/462)) ([6456c35](https://github.com/NevaMind-AI/memU/commit/6456c357b22039a3b12ba2f2bc0294a8693bceb5))
87
+ * Refine OpenClaw reference and feature descriptions ([#410](https://github.com/NevaMind-AI/memU/issues/410)) ([707b80e](https://github.com/NevaMind-AI/memU/commit/707b80e5f4394b8e4aafff1ef23fd331a8b557f8))
88
+ * refine README memory filesystem positioning ([#429](https://github.com/NevaMind-AI/memU/issues/429)) ([dda0374](https://github.com/NevaMind-AI/memU/commit/dda03743b007c0863c7fe7237592f7e4a0de32b6))
89
+ * refine README positioning around personal memory as files ([#455](https://github.com/NevaMind-AI/memU/issues/455)) ([88982d3](https://github.com/NevaMind-AI/memU/commit/88982d3d22640501be09ced1876520e95d956312))
90
+ * reframe README and description around personal-information memory ([#451](https://github.com/NevaMind-AI/memU/issues/451)) ([6b5b11c](https://github.com/NevaMind-AI/memU/commit/6b5b11c0787704c119b8d2e2d3c779bd56ee66fa))
91
+ * refresh memory diagrams ([#473](https://github.com/NevaMind-AI/memU/issues/473)) ([0d8770f](https://github.com/NevaMind-AI/memU/commit/0d8770f0c9d49f3a09e6ac33ca72b34c8128a855))
92
+ * retitle around file-based memory and trim README ([#453](https://github.com/NevaMind-AI/memU/issues/453)) ([2c1cc86](https://github.com/NevaMind-AI/memU/commit/2c1cc86ba66f31ffb7c6afcd0717f7e1880c0fd0))
93
+ * rewrite README — raw data → memory → agent ([#426](https://github.com/NevaMind-AI/memU/issues/426)) ([c2a2aac](https://github.com/NevaMind-AI/memU/commit/c2a2aac52b4424583955f85f5a35776e76beb68a))
94
+ * swap the tagline to lead with Across Agents ([#490](https://github.com/NevaMind-AI/memU/issues/490)) ([6e0fc06](https://github.com/NevaMind-AI/memU/commit/6e0fc068a1e3a2212dfea52f52438b438dae88f3))
95
+ * tagline across sessions/agents/devices, lowercase memU in banner alt ([#515](https://github.com/NevaMind-AI/memU/issues/515)) ([1f4f831](https://github.com/NevaMind-AI/memU/commit/1f4f8315bc0a68a6d2c2fa8018d64e7f22e5b164))
96
+ * tighten the README intro to two sentences ([#487](https://github.com/NevaMind-AI/memU/issues/487)) ([da160f2](https://github.com/NevaMind-AI/memU/commit/da160f2155439923bfe744ac770733c1c9824cd9))
97
+
98
+
99
+ ### Miscellaneous Chores
100
+
101
+ * release 2.0.0-beta.0 ([#541](https://github.com/NevaMind-AI/memU/issues/541)) ([3dc60ce](https://github.com/NevaMind-AI/memU/commit/3dc60cea094e29f86ead2fad148ea0fbeab198c3))
102
+
3
103
  ## [1.5.1](https://github.com/NevaMind-AI/memU/compare/v1.5.0...v1.5.1) (2026-03-23)
4
104
 
5
105
 
@@ -0,0 +1,134 @@
1
+ ---
2
+ name: install-memu-latest
3
+ description: Install the latest development build of memU-cli from git (main HEAD). Use when the user wants the newest unreleased code — clean any old install, install from git, verify, then set up.
4
+ ---
5
+
6
+ # Install the latest (development) memU
7
+
8
+ > **Audience: the agent.** A user pointed you here ("read this and install the
9
+ > latest memU"). Do the install yourself — the user should not run commands by
10
+ > hand. This installs memU-cli from **git `main`**, the latest source.
11
+
12
+ ## Step 1 — remove any existing memU install
13
+
14
+ An older memU already on the machine can stay on `PATH` and **shadow the one you
15
+ are about to install**, so the version that actually runs would not be the
16
+ latest. Remove it first — try each installer, ignore "not installed":
17
+
18
+ ```
19
+ uv tool uninstall memu-cli
20
+ pipx uninstall memu-cli
21
+ pip uninstall -y memu-cli
22
+ ```
23
+
24
+ **Tell the user what you removed** — the name and version, or "no previous
25
+ install found" — so they know their old version is gone before you continue.
26
+
27
+ This removes only the memU **package** (the binaries). The store and
28
+ `~/.memu/config.env` live under `~/.memu/` and are **not** touched, so the
29
+ user's memories and settings carry straight over — Step 4 reuses the existing
30
+ `config.env` instead of asking again. (If this newer build needs a config value
31
+ the old file lacks, Step 4's `doctor` gate names exactly what to add.)
32
+
33
+ ## Step 2 — install from git, persistently
34
+
35
+ The install **must persist on `PATH`**: the scheduled bridging task will call
36
+ these binaries later from a bare, non-interactive shell. So install as a durable
37
+ tool — **never** with an ephemeral runner (`uvx`, `npx`), which vanish after one
38
+ command and leave nothing for the task to find.
39
+
40
+ Requirement: `git` on `PATH`. Then take the first option that fits the machine:
41
+
42
+ - **uv (preferred — isolated, global, on `PATH`):**
43
+ ```
44
+ uv tool install "git+https://github.com/NevaMind-AI/memU"
45
+ ```
46
+ - **no uv, but you can install it:** install uv, then run the command above.
47
+ ```
48
+ curl -LsSf https://astral.sh/uv/install.sh | sh # macOS / Linux
49
+ powershell -c "irm https://astral.sh/uv/install.ps1 | iex" # Windows
50
+ ```
51
+ - **pip fallback (only into a stable, on-`PATH` environment):**
52
+ ```
53
+ pip install "git+https://github.com/NevaMind-AI/memU"
54
+ ```
55
+
56
+ To pin an exact commit instead of the moving `main`, append `@<sha>` to the URL.
57
+
58
+ The installer prints the exact commit it resolved — with uv, a line like
59
+ `Building memu-cli @ git+…@<sha>`. Note that SHA; you confirm it to the user in
60
+ Step 3, before the setup.
61
+
62
+ ## Step 3 — verify, then confirm the version with the user
63
+
64
+ From a **fresh** shell (not the one that ran the installer, whose `PATH` may be
65
+ stale):
66
+
67
+ ```
68
+ memu --help
69
+ memu-<your-host> --help # e.g. memu-claude-code, memu-codex
70
+ ```
71
+
72
+ Both must print usage. If they do not, the install's bin directory is not on
73
+ `PATH` (with uv it is `~/.local/bin`) — fix that before continuing, since the
74
+ scheduled task depends on the same resolution.
75
+
76
+ Then confirm the version with the user — **before the setup below**, since setup
77
+ is the long part and a wrong or stale build is painful to discover afterward. A
78
+ bare SHA is hard to judge, so report what the commit actually **is**:
79
+
80
+ - the SHA (from Step 2),
81
+ - its **subject line and date**, and
82
+ - the link to inspect it: `https://github.com/NevaMind-AI/memU/commit/<sha>`.
83
+
84
+ Fetch the subject and date from the GitHub API — no clone needed:
85
+
86
+ ```
87
+ curl -s https://api.github.com/repos/NevaMind-AI/memU/commits/<sha>
88
+ ```
89
+
90
+ read `.commit.message` (first line) and `.commit.author.date`. Then offer a
91
+ **one-tap choice** — not an open question the user has to answer in a sentence.
92
+ If your host can render selectable options, present exactly these two; otherwise
93
+ accept a plain "yes":
94
+
95
+ - **Use this version** → continue straight into Step 4 and run it to completion
96
+ **yourself**; do not make the user run `docs install` or any setup command.
97
+ Pause again only if you genuinely need them (e.g. an embedding API key).
98
+ - **Pick a different commit** → ask which, reinstall it (Step 2 with `@<sha>`),
99
+ then confirm again here.
100
+
101
+ A bare "yes" / "ok" means **Use this version** — default to proceeding.
102
+
103
+ ## Step 4 — set up memU
104
+
105
+ You now have the latest binaries. Identify **which agent you are** and use its
106
+ binary — memU has seven host adapters:
107
+
108
+ | You are | Your binary |
109
+ | --- | --- |
110
+ | Codex | `memu-codex` |
111
+ | Claude Code | `memu-claude-code` |
112
+ | Cursor | `memu-cursor` |
113
+ | OpenClaw | `memu-openclaw` |
114
+ | Hermes | `memu-hermes` |
115
+ | WorkBuddy | `memu-workbuddy` |
116
+ | anything else | `memu-agent` — run `memu-agent detect` if unsure |
117
+
118
+ Then print your host's packaged guide and follow it to the letter:
119
+
120
+ ```
121
+ memu-<your-host> docs install
122
+ ```
123
+
124
+ It walks you through configuring the store in `~/.memu/config.env`, registering
125
+ the scheduled bridging task, and patching your instruction file, each behind a
126
+ verify gate.
127
+
128
+ Because the existing `config.env` is reused, also **check it against the settings
129
+ this build documents** (the guide lists them): if this version recognizes any
130
+ `MEMU_*` option the user's file does not set, tell the user its name and what it
131
+ does — that is configuration this newer build introduces. Optional ones keep
132
+ working on their defaults; a required one is caught by the `doctor` gate.
133
+
134
+ When done, report which seams (memorization / retrieval) are now active.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: memu-cli
3
- Version: 0.3.0
3
+ Version: 0.4.0
4
4
  Classifier: Development Status :: 4 - Beta
5
5
  Classifier: Intended Audience :: Developers
6
6
  Classifier: Operating System :: OS Independent
@@ -26,7 +26,7 @@ Project-URL: Bug Tracker, https://github.com/NevaMind-AI/MemU/issues
26
26
  Project-URL: Documentation, https://github.com/NevaMind-AI/MemU#readme
27
27
  Project-URL: Homepage, https://github.com/NevaMind-AI/MemU
28
28
 
29
- ![MemU Banner](assets/banner.png)
29
+ ![memU Banner](assets/banner.png)
30
30
 
31
31
  <div align="center">
32
32
 
@@ -34,7 +34,7 @@ Project-URL: Homepage, https://github.com/NevaMind-AI/MemU
34
34
 
35
35
  ### Personal memory, stored as files
36
36
 
37
- **Across Agents. Fast retrieval. Lower cost.**
37
+ **Across Sessions. Across Agents. Across Devices.**
38
38
 
39
39
  [![PyPI version](https://badge.fury.io/py/memu-cli.svg)](https://badge.fury.io/py/memu-cli)
40
40
  [![License: Apache 2.0](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://opensource.org/licenses/Apache-2.0)
@@ -54,7 +54,11 @@ memU is a 500-line memory system for AI agents. Agents write what's worth keepin
54
54
 
55
55
  > Read https://raw.githubusercontent.com/NevaMind-AI/MemU/main/SKILL.md and follow it to install memU.
56
56
 
57
- It works for Codex, Claude Code, Cursor, OpenClaw, Hermes — and any other agent, via detection. Details in [Host adapters](#host-adapters-memory-for-desktop-coding-agents).
57
+ It works for Codex, Claude Code, Cursor, OpenClaw, Hermes, WorkBuddy — and any other agent, via detection. Details in [Host adapters](#host-adapters-memory-for-desktop-coding-agents).
58
+
59
+ Want to follow the latest development instead? Install from the newest source (git `main`) — tell your agent:
60
+
61
+ > Read https://raw.githubusercontent.com/NevaMind-AI/MemU/main/INSTALL-LATEST.md and follow it to install the latest memU.
58
62
 
59
63
  ## Quick start
60
64
 
@@ -143,6 +147,7 @@ memU runs as a sidecar to a desktop agent (ADR 0008/0009/0010), one binary per h
143
147
  | Cursor (Agent/CLI) | `memu-cursor` | `~/.cursor/projects/<project>/agent-transcripts/**.jsonl` | `./AGENTS.md` (per project) |
144
148
  | OpenClaw | `memu-openclaw` | `~/.openclaw/agents/<agentId>/sessions/*.jsonl` | `~/.openclaw/workspace/AGENTS.md` |
145
149
  | Hermes Agent | `memu-hermes` | `~/.hermes/state.db` (SQLite, read-only) | `~/.hermes/SOUL.md` |
150
+ | WorkBuddy | `memu-workbuddy` | `~/.workbuddy/projects/<project>/<session>.jsonl` | `~/.workbuddy/MEMORY.md` |
146
151
  | **any other agent** | `memu-agent` | found by `memu-agent detect` (JSONL dialect sniffed) | found by `detect` (AGENTS.md / CLAUDE.md / SOUL.md / …) |
147
152
 
148
153
  For agents without a dedicated binary, `memu-agent detect` probes the machine and reports per agent whether **memorization** works (a recognizable session log exists) and whether **retrieval** works (an instruction file exists to patch) — then the same verbs run against what it found.
@@ -1,4 +1,4 @@
1
- ![MemU Banner](assets/banner.png)
1
+ ![memU Banner](assets/banner.png)
2
2
 
3
3
  <div align="center">
4
4
 
@@ -6,7 +6,7 @@
6
6
 
7
7
  ### Personal memory, stored as files
8
8
 
9
- **Across Agents. Fast retrieval. Lower cost.**
9
+ **Across Sessions. Across Agents. Across Devices.**
10
10
 
11
11
  [![PyPI version](https://badge.fury.io/py/memu-cli.svg)](https://badge.fury.io/py/memu-cli)
12
12
  [![License: Apache 2.0](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://opensource.org/licenses/Apache-2.0)
@@ -26,7 +26,11 @@ memU is a 500-line memory system for AI agents. Agents write what's worth keepin
26
26
 
27
27
  > Read https://raw.githubusercontent.com/NevaMind-AI/MemU/main/SKILL.md and follow it to install memU.
28
28
 
29
- It works for Codex, Claude Code, Cursor, OpenClaw, Hermes — and any other agent, via detection. Details in [Host adapters](#host-adapters-memory-for-desktop-coding-agents).
29
+ It works for Codex, Claude Code, Cursor, OpenClaw, Hermes, WorkBuddy — and any other agent, via detection. Details in [Host adapters](#host-adapters-memory-for-desktop-coding-agents).
30
+
31
+ Want to follow the latest development instead? Install from the newest source (git `main`) — tell your agent:
32
+
33
+ > Read https://raw.githubusercontent.com/NevaMind-AI/MemU/main/INSTALL-LATEST.md and follow it to install the latest memU.
30
34
 
31
35
  ## Quick start
32
36
 
@@ -115,6 +119,7 @@ memU runs as a sidecar to a desktop agent (ADR 0008/0009/0010), one binary per h
115
119
  | Cursor (Agent/CLI) | `memu-cursor` | `~/.cursor/projects/<project>/agent-transcripts/**.jsonl` | `./AGENTS.md` (per project) |
116
120
  | OpenClaw | `memu-openclaw` | `~/.openclaw/agents/<agentId>/sessions/*.jsonl` | `~/.openclaw/workspace/AGENTS.md` |
117
121
  | Hermes Agent | `memu-hermes` | `~/.hermes/state.db` (SQLite, read-only) | `~/.hermes/SOUL.md` |
122
+ | WorkBuddy | `memu-workbuddy` | `~/.workbuddy/projects/<project>/<session>.jsonl` | `~/.workbuddy/MEMORY.md` |
118
123
  | **any other agent** | `memu-agent` | found by `memu-agent detect` (JSONL dialect sniffed) | found by `detect` (AGENTS.md / CLAUDE.md / SOUL.md / …) |
119
124
 
120
125
  For agents without a dedicated binary, `memu-agent detect` probes the machine and reports per agent whether **memorization** works (a recognizable session log exists) and whether **retrieval** works (an instruction file exists to patch) — then the same verbs run against what it found.
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: install-memu
3
- description: Install memU for whatever agent you are — identify your host, print its packaged install guide, and follow it to wire both seams (record and inject). Use when the user asks to install, set up, or integrate memU.
3
+ description: Install or uninstall memU for whatever agent you are — identify your host, print its packaged guide, and follow it to wire (or unwire) both seams (record and inject). Use when the user asks to install, set up, integrate, remove, or uninstall memU.
4
4
  ---
5
5
 
6
6
  # Install memU
@@ -41,6 +41,7 @@ executing this skill):
41
41
  | Cursor (Agent/CLI) | `memu-cursor` |
42
42
  | OpenClaw | `memu-openclaw` |
43
43
  | Hermes Agent | `memu-hermes` |
44
+ | WorkBuddy | `memu-workbuddy` |
44
45
  | anything else | `memu-agent` |
45
46
 
46
47
  Unsure, or not in the table? You are `memu-agent`. Run:
@@ -76,3 +77,21 @@ Two rules that hold for every host:
76
77
  the instruction file patched). For `memu-agent`, the detect report decides
77
78
  this; a retrieval-only integration is a valid outcome to report, not a
78
79
  failure to hide.
80
+
81
+ ## Uninstall
82
+
83
+ Same routing, in reverse. If the user asked to **uninstall** memU instead:
84
+ identify your binary exactly as in Step 2, then print and follow its removal
85
+ guide —
86
+
87
+ ```
88
+ <your-binary> docs uninstall
89
+ ```
90
+
91
+ It unregisters the bridging task, removes the instruction block
92
+ (`<your-binary> remove-instruction` — never hand-edit it out), then applies
93
+ the defaults: the user's memory — the shared store and `~/.memu/config.env` —
94
+ is **kept** (deleted only if they explicitly asked to erase it), while this
95
+ host's residue and, if no other host still uses it, the package are
96
+ **removed**. Close by reporting exactly those two things: what was kept, and
97
+ what was removed.
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "memu-cli"
3
- version = "0.3.0"
3
+ version = "0.4.0"
4
4
  authors = [
5
5
  {name = "MemU Team", email = "contact@nevamind.ai"},
6
6
  ]
@@ -66,6 +66,7 @@ memu-claude-code = "memu.hosts.claude_code.cli:main"
66
66
  memu-cursor = "memu.hosts.cursor.cli:main"
67
67
  memu-openclaw = "memu.hosts.openclaw.cli:main"
68
68
  memu-hermes = "memu.hosts.hermes.cli:main"
69
+ memu-workbuddy = "memu.hosts.workbuddy.cli:main"
69
70
  # The generic adapter: any agent without a dedicated binary. `memu-agent
70
71
  # detect` finds the session log and instruction file, then reports which of
71
72
  # the two seams (memorization / retrieval) work for that agent.
@@ -13,6 +13,19 @@ if TYPE_CHECKING:
13
13
  from memu.database.models import RecallFile, Resource
14
14
 
15
15
 
16
+ async def _embed_one(embed_client: Any, text: str) -> list[float]:
17
+ """One text in, one vector out.
18
+
19
+ ``embed`` returns ``(vectors, raw_response)`` — the raw response carries
20
+ provider usage metadata (see :class:`memu.embedding.base.EmbeddingClient`).
21
+ Every call site here wants just the vector; indexing the tuple with ``[0]``
22
+ would hand back the whole vectors list instead.
23
+ """
24
+ vectors: list[list[float]]
25
+ vectors, _ = await embed_client.embed([text])
26
+ return vectors[0]
27
+
28
+
16
29
  class AgenticMixin:
17
30
  if TYPE_CHECKING:
18
31
  _get_database: Callable[[], Database]
@@ -64,7 +77,7 @@ class AgenticMixin:
64
77
  where_filters = self._normalize_where(where)
65
78
  config = self.progressive_retrieve_config
66
79
  embed_client = self._get_embedding_client("embedding")
67
- query_vector = (await embed_client.embed([query]))[0]
80
+ query_vector = await _embed_one(embed_client, query)
68
81
 
69
82
  segment_hits, segment_pool = self._recall_segments(
70
83
  store=store, where_filters=where_filters, query_vector=query_vector, enabled=config.file.enabled
@@ -265,7 +278,7 @@ class AgenticMixin:
265
278
  store.recall_file_resource_repo.unlink_resource(res.id)
266
279
  store.resource_repo.delete_resource(res.id)
267
280
 
268
- caption_embedding = (await embed_client.embed([caption]))[0] if caption else None
281
+ caption_embedding = await _embed_one(embed_client, caption) if caption else None
269
282
  res = store.resource_repo.create_resource(
270
283
  url=url,
271
284
  local_path=url,
@@ -307,7 +320,7 @@ class AgenticMixin:
307
320
  file = {f.name: f for f in existing.values()}.get(name)
308
321
  if file is None:
309
322
  emb_text = f"{name}: {description}" if description else name
310
- embedding = (await embed_client.embed([emb_text]))[0]
323
+ embedding = await _embed_one(embed_client, emb_text)
311
324
  file = store.recall_file_repo.get_or_create_category(
312
325
  name=name,
313
326
  description=description,
@@ -372,7 +385,7 @@ class AgenticMixin:
372
385
  to_add = [text for text in new_texts if text not in existing_texts]
373
386
  if not to_add:
374
387
  return
375
- vecs = await embed_client.embed(to_add)
388
+ vecs, _ = await embed_client.embed(to_add)
376
389
  for text, vec in zip(to_add, vecs, strict=True):
377
390
  store.recall_file_segment_repo.create_segment(
378
391
  recall_file_id=file.id, track=file_track, text=text, embedding=vec, user_data=dict(user_scope)
@@ -167,6 +167,14 @@ def build_parser() -> argparse.ArgumentParser:
167
167
 
168
168
 
169
169
  def main(argv: list[str] | None = None) -> int:
170
+ # Piped stdio on Windows falls back to the ANSI code page (gbk, cp1252, …),
171
+ # which cannot encode retrieved memory content printed raw (ensure_ascii=False)
172
+ # — and agents read every command through a pipe. Force UTF-8; on UTF-8 stdio
173
+ # it's a no-op.
174
+ for stream in (sys.stdout, sys.stderr):
175
+ reconfigure = getattr(stream, "reconfigure", None)
176
+ if reconfigure is not None:
177
+ reconfigure(encoding="utf-8", errors="replace")
170
178
  args = build_parser().parse_args(argv)
171
179
  handler: Callable[[argparse.Namespace], Coroutine[Any, Any, int]] = args.handler
172
180
  try:
@@ -1,7 +1,9 @@
1
1
  from __future__ import annotations
2
2
 
3
+ import ipaddress
3
4
  import logging
4
5
  import os
6
+ import urllib.parse
5
7
  from collections.abc import Callable
6
8
  from typing import Any, Literal
7
9
 
@@ -15,8 +17,52 @@ from memu.embedding.backends.openrouter import OpenRouterEmbeddingBackend
15
17
  from memu.embedding.backends.voyage import VoyageEmbeddingBackend
16
18
 
17
19
 
18
- def _load_proxy() -> str | None:
19
- return os.getenv("MEMU_HTTP_PROXY") or os.getenv("HTTP_PROXY") or os.getenv("HTTPS_PROXY") or None
20
+ def is_loopback_url(url: str) -> bool:
21
+ """True when ``url`` targets the local machine (``localhost``, ``127.x``, ``::1``).
22
+
23
+ A request to the machine itself must never be routed through a proxy: the
24
+ proxy sits on another host, where "localhost" means the proxy, not the
25
+ caller. Sandboxed hosts that force all traffic through a proxy (Codex's
26
+ sandbox, corporate CI) would otherwise turn every local-embedding-server
27
+ call into a 502 unless the user hand-writes a ``NO_PROXY`` exemption.
28
+ """
29
+ host = urllib.parse.urlsplit(url).hostname or ""
30
+ if host == "localhost" or host.endswith(".localhost"):
31
+ return True
32
+ try:
33
+ return ipaddress.ip_address(host).is_loopback
34
+ except ValueError:
35
+ return False
36
+
37
+
38
+ def proxy_bypass_mounts(url: str) -> dict[str, httpx.AsyncBaseTransport | None] | None:
39
+ """httpx ``mounts`` that exempt a loopback target from env proxies, else ``None``.
40
+
41
+ httpx gives scheme-specific env-proxy mounts (``HTTP_PROXY`` mounts on
42
+ ``http://``) priority over a generic ``all://`` unmount, so the bypass must
43
+ be *host*-specific — more specific than any env mount. Unmounting (rather
44
+ than ``trust_env=False``) keeps the rest of the environment —
45
+ ``SSL_CERT_FILE``, ``.netrc``, the user's own ``NO_PROXY`` — working.
46
+ """
47
+ if not is_loopback_url(url):
48
+ return None
49
+ host = urllib.parse.urlsplit(url).hostname or ""
50
+ if ":" in host: # IPv6 literal needs its brackets back
51
+ host = f"[{host}]"
52
+ return {f"all://{host}": None}
53
+
54
+
55
+ def _load_proxy(base_url: str) -> str | None:
56
+ from memu.env import env as memu_env
57
+
58
+ explicit = memu_env("MEMU_HTTP_PROXY") or None
59
+ if is_loopback_url(base_url):
60
+ # Ambient proxies (HTTP_PROXY, HTTPS_PROXY) are aimed at the network at
61
+ # large, never at the machine itself. An explicit MEMU_HTTP_PROXY is
62
+ # different — it states intent about memU's own traffic (e.g. capturing
63
+ # it with a local debugging proxy) — so it still wins.
64
+ return explicit
65
+ return explicit or os.getenv("HTTP_PROXY") or os.getenv("HTTPS_PROXY") or None
20
66
 
21
67
 
22
68
  logger = logging.getLogger(__name__)
@@ -63,7 +109,12 @@ class HTTPEmbeddingClient:
63
109
  # Strip leading "/" so httpx resolves relative to base_url
64
110
  self.embedding_endpoint = raw_embedding_ep.lstrip("/")
65
111
  self.timeout = timeout
66
- self.proxy = _load_proxy()
112
+ self.proxy = _load_proxy(self.base_url)
113
+ # httpx falls back to env proxies even when proxy=None, so a loopback
114
+ # target explicitly unmounts them (host-specifically — see
115
+ # proxy_bypass_mounts). An explicit MEMU_HTTP_PROXY means self.proxy is
116
+ # set and no bypass applies.
117
+ self.mounts = proxy_bypass_mounts(self.base_url) if self.proxy is None else None
67
118
 
68
119
  async def embed(self, inputs: list[str]) -> tuple[list[list[float]], dict[str, Any]]:
69
120
  """
@@ -78,7 +129,9 @@ class HTTPEmbeddingClient:
78
129
  track token consumption.
79
130
  """
80
131
  payload = self.backend.build_embedding_payload(inputs=inputs, embed_model=self.embed_model)
81
- async with httpx.AsyncClient(base_url=self.base_url, timeout=self.timeout, proxy=self.proxy) as client:
132
+ async with httpx.AsyncClient(
133
+ base_url=self.base_url, timeout=self.timeout, proxy=self.proxy, mounts=self.mounts
134
+ ) as client:
82
135
  resp = await client.post(self.embedding_endpoint, json=payload, headers=self._headers())
83
136
  resp.raise_for_status()
84
137
  data = resp.json()
@@ -140,7 +193,9 @@ class HTTPEmbeddingClient:
140
193
  )
141
194
 
142
195
  endpoint = self.backend.multimodal_embedding_endpoint.lstrip("/")
143
- async with httpx.AsyncClient(base_url=self.base_url, timeout=self.timeout, proxy=self.proxy) as client:
196
+ async with httpx.AsyncClient(
197
+ base_url=self.base_url, timeout=self.timeout, proxy=self.proxy, mounts=self.mounts
198
+ ) as client:
144
199
  resp = await client.post(endpoint, json=payload, headers=self._headers())
145
200
  resp.raise_for_status()
146
201
  data = resp.json()
@@ -1,9 +1,12 @@
1
1
  import logging
2
2
  from typing import cast
3
3
 
4
- from openai import AsyncOpenAI
4
+ from openai import AsyncOpenAI, DefaultAsyncHttpxClient
5
5
  from openai.types import CreateEmbeddingResponse
6
6
 
7
+ from memu.embedding.http_client import proxy_bypass_mounts
8
+ from memu.env import env as memu_env
9
+
7
10
  logger = logging.getLogger(__name__)
8
11
 
9
12
 
@@ -15,7 +18,23 @@ class OpenAIEmbeddingSDKClient:
15
18
  self.api_key = api_key or ""
16
19
  self.embed_model = embed_model
17
20
  self.batch_size = batch_size
18
- self.client = AsyncOpenAI(api_key=self.api_key, base_url=self.base_url)
21
+ # The SDK's default transport trusts env proxies; a loopback target
22
+ # (local Ollama & co.) must bypass them — the proxy is on another host,
23
+ # where "localhost" no longer means the caller. Unmounting the target
24
+ # host (rather than trust_env=False) keeps SSL_CERT_FILE/.netrc
25
+ # working, and DefaultAsyncHttpxClient (rather than a bare httpx
26
+ # client) keeps the SDK's own timeouts, limits, and lifecycle. An
27
+ # explicit MEMU_HTTP_PROXY states intent about memU's own traffic, so
28
+ # it is wired into the transport for real — the same semantics as
29
+ # HTTPEmbeddingClient — and beats both the bypass and ambient proxies.
30
+ explicit_proxy = memu_env("MEMU_HTTP_PROXY") or None
31
+ http_client: DefaultAsyncHttpxClient | None
32
+ if explicit_proxy:
33
+ http_client = DefaultAsyncHttpxClient(proxy=explicit_proxy)
34
+ else:
35
+ mounts = proxy_bypass_mounts(self.base_url)
36
+ http_client = DefaultAsyncHttpxClient(mounts=mounts) if mounts else None
37
+ self.client = AsyncOpenAI(api_key=self.api_key, base_url=self.base_url, http_client=http_client)
19
38
 
20
39
  async def embed(self, inputs: list[str]) -> tuple[list[list[float]], CreateEmbeddingResponse | None]:
21
40
  """