claude-mpm 5.4.22__py3-none-any.whl → 5.6.34__py3-none-any.whl

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.

Potentially problematic release.


This version of claude-mpm might be problematic. Click here for more details.

Files changed (487) hide show
  1. claude_mpm/VERSION +1 -1
  2. claude_mpm/agents/BASE_AGENT.md +164 -0
  3. claude_mpm/agents/BASE_ENGINEER.md +658 -0
  4. claude_mpm/agents/CLAUDE_MPM_OUTPUT_STYLE.md +66 -241
  5. claude_mpm/agents/CLAUDE_MPM_RESEARCH_OUTPUT_STYLE.md +413 -0
  6. claude_mpm/agents/CLAUDE_MPM_TEACHER_OUTPUT_STYLE.md +109 -1925
  7. claude_mpm/agents/MEMORY.md +1 -1
  8. claude_mpm/agents/PM_INSTRUCTIONS.md +374 -1257
  9. claude_mpm/agents/WORKFLOW.md +6 -253
  10. claude_mpm/agents/agent_loader.py +1 -1
  11. claude_mpm/agents/base_agent.json +31 -0
  12. claude_mpm/agents/frontmatter_validator.py +2 -2
  13. claude_mpm/agents/templates/circuit-breakers.md +26 -17
  14. claude_mpm/cli/__init__.py +5 -1
  15. claude_mpm/cli/commands/agent_state_manager.py +10 -10
  16. claude_mpm/cli/commands/agents.py +11 -13
  17. claude_mpm/cli/commands/agents_reconcile.py +197 -0
  18. claude_mpm/cli/commands/auto_configure.py +4 -4
  19. claude_mpm/cli/commands/autotodos.py +566 -0
  20. claude_mpm/cli/commands/commander.py +216 -0
  21. claude_mpm/cli/commands/configure.py +621 -22
  22. claude_mpm/cli/commands/configure_agent_display.py +12 -0
  23. claude_mpm/cli/commands/hook_errors.py +60 -60
  24. claude_mpm/cli/commands/monitor.py +2 -2
  25. claude_mpm/cli/commands/mpm_init/core.py +72 -0
  26. claude_mpm/cli/commands/postmortem.py +1 -1
  27. claude_mpm/cli/commands/profile.py +276 -0
  28. claude_mpm/cli/commands/run.py +35 -3
  29. claude_mpm/cli/commands/skill_source.py +51 -2
  30. claude_mpm/cli/commands/skills.py +182 -32
  31. claude_mpm/cli/executor.py +130 -16
  32. claude_mpm/cli/interactive/__init__.py +10 -0
  33. claude_mpm/cli/interactive/agent_wizard.py +32 -52
  34. claude_mpm/cli/interactive/questionary_styles.py +65 -0
  35. claude_mpm/cli/interactive/skill_selector.py +481 -0
  36. claude_mpm/cli/parsers/base_parser.py +83 -1
  37. claude_mpm/cli/parsers/commander_parser.py +116 -0
  38. claude_mpm/cli/parsers/profile_parser.py +147 -0
  39. claude_mpm/cli/parsers/run_parser.py +10 -0
  40. claude_mpm/cli/parsers/skill_source_parser.py +4 -0
  41. claude_mpm/cli/parsers/skills_parser.py +2 -3
  42. claude_mpm/cli/startup.py +690 -386
  43. claude_mpm/cli/startup_display.py +74 -6
  44. claude_mpm/cli/startup_logging.py +2 -2
  45. claude_mpm/cli/utils.py +7 -3
  46. claude_mpm/commander/__init__.py +78 -0
  47. claude_mpm/commander/adapters/__init__.py +60 -0
  48. claude_mpm/commander/adapters/auggie.py +260 -0
  49. claude_mpm/commander/adapters/base.py +288 -0
  50. claude_mpm/commander/adapters/claude_code.py +392 -0
  51. claude_mpm/commander/adapters/codex.py +237 -0
  52. claude_mpm/commander/adapters/communication.py +366 -0
  53. claude_mpm/commander/adapters/example_usage.py +310 -0
  54. claude_mpm/commander/adapters/mpm.py +389 -0
  55. claude_mpm/commander/adapters/registry.py +204 -0
  56. claude_mpm/commander/api/__init__.py +16 -0
  57. claude_mpm/commander/api/app.py +121 -0
  58. claude_mpm/commander/api/errors.py +133 -0
  59. claude_mpm/commander/api/routes/__init__.py +8 -0
  60. claude_mpm/commander/api/routes/events.py +184 -0
  61. claude_mpm/commander/api/routes/inbox.py +171 -0
  62. claude_mpm/commander/api/routes/messages.py +148 -0
  63. claude_mpm/commander/api/routes/projects.py +271 -0
  64. claude_mpm/commander/api/routes/sessions.py +226 -0
  65. claude_mpm/commander/api/routes/work.py +296 -0
  66. claude_mpm/commander/api/schemas.py +186 -0
  67. claude_mpm/commander/chat/__init__.py +7 -0
  68. claude_mpm/commander/chat/cli.py +146 -0
  69. claude_mpm/commander/chat/commands.py +96 -0
  70. claude_mpm/commander/chat/repl.py +310 -0
  71. claude_mpm/commander/config.py +51 -0
  72. claude_mpm/commander/config_loader.py +115 -0
  73. claude_mpm/commander/core/__init__.py +10 -0
  74. claude_mpm/commander/core/block_manager.py +325 -0
  75. claude_mpm/commander/core/response_manager.py +323 -0
  76. claude_mpm/commander/daemon.py +603 -0
  77. claude_mpm/commander/env_loader.py +59 -0
  78. claude_mpm/commander/events/__init__.py +26 -0
  79. claude_mpm/commander/events/manager.py +332 -0
  80. claude_mpm/commander/frameworks/__init__.py +12 -0
  81. claude_mpm/commander/frameworks/base.py +146 -0
  82. claude_mpm/commander/frameworks/claude_code.py +58 -0
  83. claude_mpm/commander/frameworks/mpm.py +62 -0
  84. claude_mpm/commander/inbox/__init__.py +16 -0
  85. claude_mpm/commander/inbox/dedup.py +128 -0
  86. claude_mpm/commander/inbox/inbox.py +224 -0
  87. claude_mpm/commander/inbox/models.py +70 -0
  88. claude_mpm/commander/instance_manager.py +450 -0
  89. claude_mpm/commander/llm/__init__.py +6 -0
  90. claude_mpm/commander/llm/openrouter_client.py +167 -0
  91. claude_mpm/commander/llm/summarizer.py +70 -0
  92. claude_mpm/commander/memory/__init__.py +45 -0
  93. claude_mpm/commander/memory/compression.py +347 -0
  94. claude_mpm/commander/memory/embeddings.py +230 -0
  95. claude_mpm/commander/memory/entities.py +310 -0
  96. claude_mpm/commander/memory/example_usage.py +290 -0
  97. claude_mpm/commander/memory/integration.py +325 -0
  98. claude_mpm/commander/memory/search.py +381 -0
  99. claude_mpm/commander/memory/store.py +657 -0
  100. claude_mpm/commander/models/__init__.py +18 -0
  101. claude_mpm/commander/models/events.py +121 -0
  102. claude_mpm/commander/models/project.py +162 -0
  103. claude_mpm/commander/models/work.py +214 -0
  104. claude_mpm/commander/parsing/__init__.py +20 -0
  105. claude_mpm/commander/parsing/extractor.py +132 -0
  106. claude_mpm/commander/parsing/output_parser.py +270 -0
  107. claude_mpm/commander/parsing/patterns.py +100 -0
  108. claude_mpm/commander/persistence/__init__.py +11 -0
  109. claude_mpm/commander/persistence/event_store.py +274 -0
  110. claude_mpm/commander/persistence/state_store.py +309 -0
  111. claude_mpm/commander/persistence/work_store.py +164 -0
  112. claude_mpm/commander/polling/__init__.py +13 -0
  113. claude_mpm/commander/polling/event_detector.py +104 -0
  114. claude_mpm/commander/polling/output_buffer.py +49 -0
  115. claude_mpm/commander/polling/output_poller.py +153 -0
  116. claude_mpm/commander/project_session.py +268 -0
  117. claude_mpm/commander/proxy/__init__.py +12 -0
  118. claude_mpm/commander/proxy/formatter.py +89 -0
  119. claude_mpm/commander/proxy/output_handler.py +191 -0
  120. claude_mpm/commander/proxy/relay.py +155 -0
  121. claude_mpm/commander/registry.py +410 -0
  122. claude_mpm/commander/runtime/__init__.py +10 -0
  123. claude_mpm/commander/runtime/executor.py +191 -0
  124. claude_mpm/commander/runtime/monitor.py +346 -0
  125. claude_mpm/commander/session/__init__.py +6 -0
  126. claude_mpm/commander/session/context.py +81 -0
  127. claude_mpm/commander/session/manager.py +59 -0
  128. claude_mpm/commander/tmux_orchestrator.py +361 -0
  129. claude_mpm/commander/web/__init__.py +1 -0
  130. claude_mpm/commander/work/__init__.py +30 -0
  131. claude_mpm/commander/work/executor.py +207 -0
  132. claude_mpm/commander/work/queue.py +405 -0
  133. claude_mpm/commander/workflow/__init__.py +27 -0
  134. claude_mpm/commander/workflow/event_handler.py +241 -0
  135. claude_mpm/commander/workflow/notifier.py +146 -0
  136. claude_mpm/commands/mpm-config.md +20 -249
  137. claude_mpm/commands/mpm-doctor.md +16 -21
  138. claude_mpm/commands/mpm-help.md +12 -205
  139. claude_mpm/commands/mpm-init.md +88 -506
  140. claude_mpm/commands/mpm-monitor.md +22 -401
  141. claude_mpm/commands/mpm-organize.md +70 -442
  142. claude_mpm/commands/mpm-postmortem.md +13 -107
  143. claude_mpm/commands/mpm-session-resume.md +20 -363
  144. claude_mpm/commands/mpm-status.md +13 -69
  145. claude_mpm/commands/mpm-ticket-view.md +60 -495
  146. claude_mpm/commands/mpm-version.md +13 -107
  147. claude_mpm/commands/mpm.md +8 -0
  148. claude_mpm/config/agent_presets.py +8 -7
  149. claude_mpm/config/skill_sources.py +16 -0
  150. claude_mpm/constants.py +1 -0
  151. claude_mpm/core/claude_runner.py +154 -2
  152. claude_mpm/core/config.py +37 -26
  153. claude_mpm/core/config_constants.py +74 -9
  154. claude_mpm/core/constants.py +56 -12
  155. claude_mpm/core/framework/loaders/agent_loader.py +1 -1
  156. claude_mpm/core/framework/loaders/instruction_loader.py +52 -11
  157. claude_mpm/core/hook_manager.py +51 -3
  158. claude_mpm/core/interactive_session.py +12 -11
  159. claude_mpm/core/logger.py +26 -9
  160. claude_mpm/core/logging_utils.py +39 -13
  161. claude_mpm/core/network_config.py +148 -0
  162. claude_mpm/core/oneshot_session.py +7 -6
  163. claude_mpm/core/optimized_startup.py +61 -0
  164. claude_mpm/core/output_style_manager.py +66 -18
  165. claude_mpm/core/shared/config_loader.py +3 -1
  166. claude_mpm/core/socketio_pool.py +47 -15
  167. claude_mpm/core/unified_agent_registry.py +1 -1
  168. claude_mpm/core/unified_config.py +54 -8
  169. claude_mpm/core/unified_paths.py +95 -90
  170. claude_mpm/dashboard/static/svelte-build/_app/env.js +1 -0
  171. claude_mpm/dashboard/static/svelte-build/_app/immutable/assets/0.C33zOoyM.css +1 -0
  172. claude_mpm/dashboard/static/svelte-build/_app/immutable/assets/2.CW1J-YuA.css +1 -0
  173. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/1WZnGYqX.js +24 -0
  174. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/67pF3qNn.js +1 -0
  175. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/6RxdMKe4.js +1 -0
  176. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/8cZrfX0h.js +60 -0
  177. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/9a6T2nm-.js +7 -0
  178. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/B443AUzu.js +1 -0
  179. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/B8AwtY2H.js +1 -0
  180. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/BF15LAsF.js +1 -0
  181. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/BQaXIfA_.js +331 -0
  182. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/BRcwIQNr.js +4 -0
  183. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/BSNlmTZj.js +1 -0
  184. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/BV6nKitt.js +43 -0
  185. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/BViJ8lZt.js +128 -0
  186. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/BcQ-Q0FE.js +1 -0
  187. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/Bpyvgze_.js +30 -0
  188. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/BzTRqg-z.js +1 -0
  189. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/C0Fr8dve.js +1 -0
  190. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/C3rbW_a-.js +1 -0
  191. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/C8WYN38h.js +1 -0
  192. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/C9I8FlXH.js +61 -0
  193. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CIQcWgO2.js +36 -0
  194. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CIctN7YN.js +7 -0
  195. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CKrS_JZW.js +145 -0
  196. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CR6P9C4A.js +89 -0
  197. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CRRR9MD_.js +2 -0
  198. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CRcR2DqT.js +334 -0
  199. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CSXtMOf0.js +1 -0
  200. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CT-sbxSk.js +1 -0
  201. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CWm6DJsp.js +1 -0
  202. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CmKTTxBW.js +1 -0
  203. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CpqQ1Kzn.js +1 -0
  204. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/Cu_Erd72.js +261 -0
  205. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/D2nGpDRe.js +1 -0
  206. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/D9iCMida.js +267 -0
  207. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/D9ykgMoY.js +10 -0
  208. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/DL2Ldur1.js +1 -0
  209. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/DPfltzjH.js +165 -0
  210. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/DR8nis88.js +2 -0
  211. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/DUliQN2b.js +1 -0
  212. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/DVp1hx9R.js +1 -0
  213. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/DXlhR01x.js +122 -0
  214. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/D_lyTybS.js +1 -0
  215. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/DngoTTgh.js +1 -0
  216. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/DqkmHtDC.js +220 -0
  217. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/DsDh8EYs.js +1 -0
  218. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/DypDmXgd.js +139 -0
  219. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/Gi6I4Gst.js +1 -0
  220. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/IPYC-LnN.js +162 -0
  221. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/JTLiF7dt.js +24 -0
  222. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/JpevfAFt.js +68 -0
  223. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/NqQ1dWOy.js +1 -0
  224. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/R8CEIRAd.js +2 -0
  225. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/Zxy7qc-l.js +64 -0
  226. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/q9Hm6zAU.js +1 -0
  227. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/qtd3IeO4.js +15 -0
  228. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/ulBFON_C.js +65 -0
  229. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/wQVh1CoA.js +10 -0
  230. claude_mpm/dashboard/static/svelte-build/_app/immutable/entry/app.Dr7t0z2J.js +2 -0
  231. claude_mpm/dashboard/static/svelte-build/_app/immutable/entry/start.BGhZHUS3.js +1 -0
  232. claude_mpm/dashboard/static/svelte-build/_app/immutable/nodes/0.RgBboRvH.js +1 -0
  233. claude_mpm/dashboard/static/svelte-build/_app/immutable/nodes/1.DG-KkbDf.js +1 -0
  234. claude_mpm/dashboard/static/svelte-build/_app/immutable/nodes/2.D_jnf-x6.js +1 -0
  235. claude_mpm/dashboard/static/svelte-build/_app/version.json +1 -0
  236. claude_mpm/dashboard/static/svelte-build/favicon.svg +7 -0
  237. claude_mpm/dashboard/static/svelte-build/index.html +36 -0
  238. claude_mpm/dashboard-svelte/node_modules/katex/src/fonts/generate_fonts.py +58 -0
  239. claude_mpm/dashboard-svelte/node_modules/katex/src/metrics/extract_tfms.py +114 -0
  240. claude_mpm/dashboard-svelte/node_modules/katex/src/metrics/extract_ttfs.py +122 -0
  241. claude_mpm/dashboard-svelte/node_modules/katex/src/metrics/format_json.py +28 -0
  242. claude_mpm/dashboard-svelte/node_modules/katex/src/metrics/parse_tfm.py +211 -0
  243. claude_mpm/experimental/cli_enhancements.py +2 -1
  244. claude_mpm/hooks/claude_hooks/INTEGRATION_EXAMPLE.md +243 -0
  245. claude_mpm/hooks/claude_hooks/README_AUTO_PAUSE.md +403 -0
  246. claude_mpm/hooks/claude_hooks/__pycache__/__init__.cpython-311.pyc +0 -0
  247. claude_mpm/hooks/claude_hooks/__pycache__/auto_pause_handler.cpython-311.pyc +0 -0
  248. claude_mpm/hooks/claude_hooks/__pycache__/correlation_manager.cpython-311.pyc +0 -0
  249. claude_mpm/hooks/claude_hooks/__pycache__/event_handlers.cpython-311.pyc +0 -0
  250. claude_mpm/hooks/claude_hooks/__pycache__/hook_handler.cpython-311.pyc +0 -0
  251. claude_mpm/hooks/claude_hooks/__pycache__/memory_integration.cpython-311.pyc +0 -0
  252. claude_mpm/hooks/claude_hooks/__pycache__/response_tracking.cpython-311.pyc +0 -0
  253. claude_mpm/hooks/claude_hooks/__pycache__/tool_analysis.cpython-311.pyc +0 -0
  254. claude_mpm/hooks/claude_hooks/auto_pause_handler.py +485 -0
  255. claude_mpm/hooks/claude_hooks/event_handlers.py +527 -136
  256. claude_mpm/hooks/claude_hooks/hook_handler.py +313 -99
  257. claude_mpm/hooks/claude_hooks/hook_wrapper.sh +6 -11
  258. claude_mpm/hooks/claude_hooks/installer.py +206 -36
  259. claude_mpm/hooks/claude_hooks/memory_integration.py +52 -32
  260. claude_mpm/hooks/claude_hooks/response_tracking.py +43 -60
  261. claude_mpm/hooks/claude_hooks/services/__init__.py +21 -0
  262. claude_mpm/hooks/claude_hooks/services/__pycache__/__init__.cpython-311.pyc +0 -0
  263. claude_mpm/hooks/claude_hooks/services/__pycache__/connection_manager_http.cpython-311.pyc +0 -0
  264. claude_mpm/hooks/claude_hooks/services/__pycache__/container.cpython-311.pyc +0 -0
  265. claude_mpm/hooks/claude_hooks/services/__pycache__/duplicate_detector.cpython-311.pyc +0 -0
  266. claude_mpm/hooks/claude_hooks/services/__pycache__/protocols.cpython-311.pyc +0 -0
  267. claude_mpm/hooks/claude_hooks/services/__pycache__/state_manager.cpython-311.pyc +0 -0
  268. claude_mpm/hooks/claude_hooks/services/__pycache__/subagent_processor.cpython-311.pyc +0 -0
  269. claude_mpm/hooks/claude_hooks/services/connection_manager.py +67 -32
  270. claude_mpm/hooks/claude_hooks/services/connection_manager_http.py +38 -105
  271. claude_mpm/hooks/claude_hooks/services/container.py +310 -0
  272. claude_mpm/hooks/claude_hooks/services/protocols.py +328 -0
  273. claude_mpm/hooks/claude_hooks/services/state_manager.py +25 -38
  274. claude_mpm/hooks/claude_hooks/services/subagent_processor.py +75 -77
  275. claude_mpm/hooks/kuzu_memory_hook.py +5 -5
  276. claude_mpm/hooks/session_resume_hook.py +89 -1
  277. claude_mpm/hooks/templates/pre_tool_use_simple.py +6 -6
  278. claude_mpm/hooks/templates/pre_tool_use_template.py +16 -8
  279. claude_mpm/init.py +276 -0
  280. claude_mpm/models/git_repository.py +3 -3
  281. claude_mpm/scripts/claude-hook-handler.sh +46 -19
  282. claude_mpm/services/agents/agent_builder.py +3 -3
  283. claude_mpm/services/agents/agent_recommendation_service.py +8 -8
  284. claude_mpm/services/agents/agent_selection_service.py +2 -2
  285. claude_mpm/services/agents/cache_git_manager.py +7 -7
  286. claude_mpm/services/agents/deployment/agent_deployment.py +29 -7
  287. claude_mpm/services/agents/deployment/agent_discovery_service.py +4 -2
  288. claude_mpm/services/agents/deployment/agent_format_converter.py +25 -13
  289. claude_mpm/services/agents/deployment/agent_template_builder.py +39 -19
  290. claude_mpm/services/agents/deployment/agents_directory_resolver.py +2 -2
  291. claude_mpm/services/agents/deployment/async_agent_deployment.py +31 -27
  292. claude_mpm/services/agents/deployment/deployment_reconciler.py +577 -0
  293. claude_mpm/services/agents/deployment/local_template_deployment.py +3 -1
  294. claude_mpm/services/agents/deployment/multi_source_deployment_service.py +169 -26
  295. claude_mpm/services/agents/deployment/remote_agent_discovery_service.py +101 -75
  296. claude_mpm/services/agents/deployment/startup_reconciliation.py +138 -0
  297. claude_mpm/services/agents/git_source_manager.py +23 -4
  298. claude_mpm/services/agents/loading/framework_agent_loader.py +75 -2
  299. claude_mpm/services/agents/recommender.py +5 -3
  300. claude_mpm/services/agents/single_tier_deployment_service.py +6 -6
  301. claude_mpm/services/agents/sources/git_source_sync_service.py +121 -10
  302. claude_mpm/services/agents/startup_sync.py +27 -4
  303. claude_mpm/services/cli/__init__.py +3 -0
  304. claude_mpm/services/cli/incremental_pause_manager.py +561 -0
  305. claude_mpm/services/cli/session_resume_helper.py +10 -2
  306. claude_mpm/services/command_deployment_service.py +44 -26
  307. claude_mpm/services/delegation_detector.py +175 -0
  308. claude_mpm/services/diagnostics/checks/agent_check.py +2 -2
  309. claude_mpm/services/diagnostics/checks/agent_sources_check.py +31 -1
  310. claude_mpm/services/diagnostics/checks/configuration_check.py +24 -0
  311. claude_mpm/services/diagnostics/checks/installation_check.py +22 -0
  312. claude_mpm/services/diagnostics/checks/mcp_services_check.py +23 -0
  313. claude_mpm/services/diagnostics/doctor_reporter.py +31 -1
  314. claude_mpm/services/diagnostics/models.py +14 -1
  315. claude_mpm/services/event_log.py +325 -0
  316. claude_mpm/services/git/git_operations_service.py +8 -8
  317. claude_mpm/services/hook_installer_service.py +77 -8
  318. claude_mpm/services/infrastructure/__init__.py +4 -0
  319. claude_mpm/services/infrastructure/context_usage_tracker.py +291 -0
  320. claude_mpm/services/infrastructure/resume_log_generator.py +24 -5
  321. claude_mpm/services/monitor/daemon_manager.py +15 -4
  322. claude_mpm/services/monitor/management/lifecycle.py +15 -3
  323. claude_mpm/services/monitor/server.py +571 -11
  324. claude_mpm/services/pm_skills_deployer.py +884 -0
  325. claude_mpm/services/profile_manager.py +337 -0
  326. claude_mpm/services/skills/git_skill_source_manager.py +281 -20
  327. claude_mpm/services/skills/selective_skill_deployer.py +211 -46
  328. claude_mpm/services/skills/skill_discovery_service.py +74 -4
  329. claude_mpm/services/skills_deployer.py +192 -70
  330. claude_mpm/services/socketio/dashboard_server.py +1 -0
  331. claude_mpm/services/socketio/event_normalizer.py +37 -6
  332. claude_mpm/services/socketio/handlers/hook.py +14 -7
  333. claude_mpm/services/socketio/server/core.py +262 -123
  334. claude_mpm/services/socketio/server/main.py +12 -4
  335. claude_mpm/skills/__init__.py +2 -1
  336. claude_mpm/skills/bundled/collaboration/brainstorming/SKILL.md +79 -0
  337. claude_mpm/skills/bundled/collaboration/dispatching-parallel-agents/SKILL.md +178 -0
  338. claude_mpm/skills/bundled/collaboration/dispatching-parallel-agents/references/agent-prompts.md +577 -0
  339. claude_mpm/skills/bundled/collaboration/dispatching-parallel-agents/references/coordination-patterns.md +467 -0
  340. claude_mpm/skills/bundled/collaboration/dispatching-parallel-agents/references/examples.md +537 -0
  341. claude_mpm/skills/bundled/collaboration/dispatching-parallel-agents/references/troubleshooting.md +730 -0
  342. claude_mpm/skills/bundled/collaboration/git-worktrees.md +317 -0
  343. claude_mpm/skills/bundled/collaboration/requesting-code-review/SKILL.md +112 -0
  344. claude_mpm/skills/bundled/collaboration/requesting-code-review/references/code-reviewer-template.md +146 -0
  345. claude_mpm/skills/bundled/collaboration/requesting-code-review/references/review-examples.md +412 -0
  346. claude_mpm/skills/bundled/collaboration/stacked-prs.md +251 -0
  347. claude_mpm/skills/bundled/collaboration/writing-plans/SKILL.md +81 -0
  348. claude_mpm/skills/bundled/collaboration/writing-plans/references/best-practices.md +362 -0
  349. claude_mpm/skills/bundled/collaboration/writing-plans/references/plan-structure-templates.md +312 -0
  350. claude_mpm/skills/bundled/debugging/root-cause-tracing/SKILL.md +152 -0
  351. claude_mpm/skills/bundled/debugging/root-cause-tracing/references/advanced-techniques.md +668 -0
  352. claude_mpm/skills/bundled/debugging/root-cause-tracing/references/examples.md +587 -0
  353. claude_mpm/skills/bundled/debugging/root-cause-tracing/references/integration.md +438 -0
  354. claude_mpm/skills/bundled/debugging/root-cause-tracing/references/tracing-techniques.md +391 -0
  355. claude_mpm/skills/bundled/debugging/systematic-debugging/CREATION-LOG.md +119 -0
  356. claude_mpm/skills/bundled/debugging/systematic-debugging/SKILL.md +148 -0
  357. claude_mpm/skills/bundled/debugging/systematic-debugging/references/anti-patterns.md +483 -0
  358. claude_mpm/skills/bundled/debugging/systematic-debugging/references/examples.md +452 -0
  359. claude_mpm/skills/bundled/debugging/systematic-debugging/references/troubleshooting.md +449 -0
  360. claude_mpm/skills/bundled/debugging/systematic-debugging/references/workflow.md +411 -0
  361. claude_mpm/skills/bundled/debugging/systematic-debugging/test-academic.md +14 -0
  362. claude_mpm/skills/bundled/debugging/systematic-debugging/test-pressure-1.md +58 -0
  363. claude_mpm/skills/bundled/debugging/systematic-debugging/test-pressure-2.md +68 -0
  364. claude_mpm/skills/bundled/debugging/systematic-debugging/test-pressure-3.md +69 -0
  365. claude_mpm/skills/bundled/debugging/verification-before-completion/SKILL.md +131 -0
  366. claude_mpm/skills/bundled/debugging/verification-before-completion/references/gate-function.md +325 -0
  367. claude_mpm/skills/bundled/debugging/verification-before-completion/references/integration-and-workflows.md +490 -0
  368. claude_mpm/skills/bundled/debugging/verification-before-completion/references/red-flags-and-failures.md +425 -0
  369. claude_mpm/skills/bundled/debugging/verification-before-completion/references/verification-patterns.md +499 -0
  370. claude_mpm/skills/bundled/infrastructure/env-manager/INTEGRATION.md +611 -0
  371. claude_mpm/skills/bundled/infrastructure/env-manager/README.md +596 -0
  372. claude_mpm/skills/bundled/infrastructure/env-manager/SKILL.md +260 -0
  373. claude_mpm/skills/bundled/infrastructure/env-manager/examples/nextjs-env-structure.md +315 -0
  374. claude_mpm/skills/bundled/infrastructure/env-manager/references/frameworks.md +436 -0
  375. claude_mpm/skills/bundled/infrastructure/env-manager/references/security.md +433 -0
  376. claude_mpm/skills/bundled/infrastructure/env-manager/references/synchronization.md +452 -0
  377. claude_mpm/skills/bundled/infrastructure/env-manager/references/troubleshooting.md +404 -0
  378. claude_mpm/skills/bundled/infrastructure/env-manager/references/validation.md +420 -0
  379. claude_mpm/skills/bundled/main/artifacts-builder/SKILL.md +86 -0
  380. claude_mpm/skills/bundled/main/internal-comms/SKILL.md +43 -0
  381. claude_mpm/skills/bundled/main/internal-comms/examples/3p-updates.md +47 -0
  382. claude_mpm/skills/bundled/main/internal-comms/examples/company-newsletter.md +65 -0
  383. claude_mpm/skills/bundled/main/internal-comms/examples/faq-answers.md +30 -0
  384. claude_mpm/skills/bundled/main/internal-comms/examples/general-comms.md +16 -0
  385. claude_mpm/skills/bundled/main/mcp-builder/SKILL.md +160 -0
  386. claude_mpm/skills/bundled/main/mcp-builder/reference/design_principles.md +412 -0
  387. claude_mpm/skills/bundled/main/mcp-builder/reference/evaluation.md +602 -0
  388. claude_mpm/skills/bundled/main/mcp-builder/reference/mcp_best_practices.md +915 -0
  389. claude_mpm/skills/bundled/main/mcp-builder/reference/node_mcp_server.md +916 -0
  390. claude_mpm/skills/bundled/main/mcp-builder/reference/python_mcp_server.md +752 -0
  391. claude_mpm/skills/bundled/main/mcp-builder/reference/workflow.md +1237 -0
  392. claude_mpm/skills/bundled/main/skill-creator/SKILL.md +189 -0
  393. claude_mpm/skills/bundled/main/skill-creator/references/best-practices.md +500 -0
  394. claude_mpm/skills/bundled/main/skill-creator/references/creation-workflow.md +464 -0
  395. claude_mpm/skills/bundled/main/skill-creator/references/examples.md +619 -0
  396. claude_mpm/skills/bundled/main/skill-creator/references/progressive-disclosure.md +437 -0
  397. claude_mpm/skills/bundled/main/skill-creator/references/skill-structure.md +231 -0
  398. claude_mpm/skills/bundled/php/espocrm-development/SKILL.md +170 -0
  399. claude_mpm/skills/bundled/php/espocrm-development/references/architecture.md +602 -0
  400. claude_mpm/skills/bundled/php/espocrm-development/references/common-tasks.md +821 -0
  401. claude_mpm/skills/bundled/php/espocrm-development/references/development-workflow.md +742 -0
  402. claude_mpm/skills/bundled/php/espocrm-development/references/frontend-customization.md +726 -0
  403. claude_mpm/skills/bundled/php/espocrm-development/references/hooks-and-services.md +764 -0
  404. claude_mpm/skills/bundled/php/espocrm-development/references/testing-debugging.md +831 -0
  405. claude_mpm/skills/bundled/pm/mpm/SKILL.md +38 -0
  406. claude_mpm/skills/bundled/pm/mpm-agent-update-workflow/SKILL.md +75 -0
  407. claude_mpm/skills/bundled/pm/mpm-bug-reporting/SKILL.md +248 -0
  408. claude_mpm/skills/bundled/pm/mpm-circuit-breaker-enforcement/SKILL.md +476 -0
  409. claude_mpm/skills/bundled/pm/mpm-config/SKILL.md +29 -0
  410. claude_mpm/skills/bundled/pm/mpm-delegation-patterns/SKILL.md +167 -0
  411. claude_mpm/skills/bundled/pm/mpm-doctor/SKILL.md +53 -0
  412. claude_mpm/skills/bundled/pm/mpm-git-file-tracking/SKILL.md +113 -0
  413. claude_mpm/skills/bundled/pm/mpm-help/SKILL.md +35 -0
  414. claude_mpm/skills/bundled/pm/mpm-init/SKILL.md +125 -0
  415. claude_mpm/skills/bundled/pm/mpm-monitor/SKILL.md +32 -0
  416. claude_mpm/skills/bundled/pm/mpm-organize/SKILL.md +121 -0
  417. claude_mpm/skills/bundled/pm/mpm-postmortem/SKILL.md +22 -0
  418. claude_mpm/skills/bundled/pm/mpm-pr-workflow/SKILL.md +124 -0
  419. claude_mpm/skills/bundled/pm/mpm-session-management/SKILL.md +312 -0
  420. claude_mpm/skills/bundled/pm/mpm-session-pause/SKILL.md +170 -0
  421. claude_mpm/skills/bundled/pm/mpm-session-resume/SKILL.md +31 -0
  422. claude_mpm/skills/bundled/pm/mpm-status/SKILL.md +37 -0
  423. claude_mpm/skills/bundled/pm/mpm-teaching-mode/SKILL.md +657 -0
  424. claude_mpm/skills/bundled/pm/mpm-ticket-view/SKILL.md +110 -0
  425. claude_mpm/skills/bundled/pm/mpm-ticketing-integration/SKILL.md +154 -0
  426. claude_mpm/skills/bundled/pm/mpm-tool-usage-guide/SKILL.md +386 -0
  427. claude_mpm/skills/bundled/pm/mpm-verification-protocols/SKILL.md +198 -0
  428. claude_mpm/skills/bundled/pm/mpm-version/SKILL.md +21 -0
  429. claude_mpm/skills/bundled/react/flexlayout-react.md +742 -0
  430. claude_mpm/skills/bundled/rust/desktop-applications/SKILL.md +226 -0
  431. claude_mpm/skills/bundled/rust/desktop-applications/references/architecture-patterns.md +901 -0
  432. claude_mpm/skills/bundled/rust/desktop-applications/references/native-gui-frameworks.md +901 -0
  433. claude_mpm/skills/bundled/rust/desktop-applications/references/platform-integration.md +775 -0
  434. claude_mpm/skills/bundled/rust/desktop-applications/references/state-management.md +937 -0
  435. claude_mpm/skills/bundled/rust/desktop-applications/references/tauri-framework.md +770 -0
  436. claude_mpm/skills/bundled/rust/desktop-applications/references/testing-deployment.md +961 -0
  437. claude_mpm/skills/bundled/security-scanning.md +112 -0
  438. claude_mpm/skills/bundled/tauri/tauri-async-patterns.md +495 -0
  439. claude_mpm/skills/bundled/tauri/tauri-build-deploy.md +599 -0
  440. claude_mpm/skills/bundled/tauri/tauri-command-patterns.md +535 -0
  441. claude_mpm/skills/bundled/tauri/tauri-error-handling.md +613 -0
  442. claude_mpm/skills/bundled/tauri/tauri-event-system.md +648 -0
  443. claude_mpm/skills/bundled/tauri/tauri-file-system.md +673 -0
  444. claude_mpm/skills/bundled/tauri/tauri-frontend-integration.md +767 -0
  445. claude_mpm/skills/bundled/tauri/tauri-performance.md +669 -0
  446. claude_mpm/skills/bundled/tauri/tauri-state-management.md +573 -0
  447. claude_mpm/skills/bundled/tauri/tauri-testing.md +384 -0
  448. claude_mpm/skills/bundled/tauri/tauri-window-management.md +628 -0
  449. claude_mpm/skills/bundled/testing/condition-based-waiting/SKILL.md +119 -0
  450. claude_mpm/skills/bundled/testing/condition-based-waiting/references/patterns-and-implementation.md +253 -0
  451. claude_mpm/skills/bundled/testing/test-driven-development/SKILL.md +145 -0
  452. claude_mpm/skills/bundled/testing/test-driven-development/references/anti-patterns.md +543 -0
  453. claude_mpm/skills/bundled/testing/test-driven-development/references/examples.md +741 -0
  454. claude_mpm/skills/bundled/testing/test-driven-development/references/integration.md +470 -0
  455. claude_mpm/skills/bundled/testing/test-driven-development/references/philosophy.md +458 -0
  456. claude_mpm/skills/bundled/testing/test-driven-development/references/workflow.md +639 -0
  457. claude_mpm/skills/bundled/testing/test-quality-inspector/SKILL.md +458 -0
  458. claude_mpm/skills/bundled/testing/test-quality-inspector/examples/example-inspection-report.md +411 -0
  459. claude_mpm/skills/bundled/testing/test-quality-inspector/references/assertion-quality.md +317 -0
  460. claude_mpm/skills/bundled/testing/test-quality-inspector/references/inspection-checklist.md +270 -0
  461. claude_mpm/skills/bundled/testing/test-quality-inspector/references/red-flags.md +436 -0
  462. claude_mpm/skills/bundled/testing/testing-anti-patterns/SKILL.md +140 -0
  463. claude_mpm/skills/bundled/testing/testing-anti-patterns/references/completeness-anti-patterns.md +572 -0
  464. claude_mpm/skills/bundled/testing/testing-anti-patterns/references/core-anti-patterns.md +411 -0
  465. claude_mpm/skills/bundled/testing/testing-anti-patterns/references/detection-guide.md +569 -0
  466. claude_mpm/skills/bundled/testing/testing-anti-patterns/references/tdd-connection.md +695 -0
  467. claude_mpm/skills/bundled/testing/webapp-testing/SKILL.md +184 -0
  468. claude_mpm/skills/bundled/testing/webapp-testing/decision-tree.md +459 -0
  469. claude_mpm/skills/bundled/testing/webapp-testing/playwright-patterns.md +479 -0
  470. claude_mpm/skills/bundled/testing/webapp-testing/reconnaissance-pattern.md +687 -0
  471. claude_mpm/skills/bundled/testing/webapp-testing/server-management.md +758 -0
  472. claude_mpm/skills/bundled/testing/webapp-testing/troubleshooting.md +868 -0
  473. claude_mpm/skills/registry.py +295 -90
  474. claude_mpm/skills/skill_manager.py +98 -3
  475. claude_mpm/templates/.pre-commit-config.yaml +112 -0
  476. claude_mpm/utils/agent_dependency_loader.py +115 -4
  477. claude_mpm/utils/agent_filters.py +1 -1
  478. claude_mpm/utils/migration.py +4 -4
  479. claude_mpm/utils/robust_installer.py +86 -21
  480. claude_mpm-5.6.34.dist-info/METADATA +393 -0
  481. {claude_mpm-5.4.22.dist-info → claude_mpm-5.6.34.dist-info}/RECORD +486 -145
  482. claude_mpm-5.4.22.dist-info/METADATA +0 -996
  483. {claude_mpm-5.4.22.dist-info → claude_mpm-5.6.34.dist-info}/WHEEL +0 -0
  484. {claude_mpm-5.4.22.dist-info → claude_mpm-5.6.34.dist-info}/entry_points.txt +0 -0
  485. {claude_mpm-5.4.22.dist-info → claude_mpm-5.6.34.dist-info}/licenses/LICENSE +0 -0
  486. {claude_mpm-5.4.22.dist-info → claude_mpm-5.6.34.dist-info}/licenses/LICENSE-FAQ.md +0 -0
  487. {claude_mpm-5.4.22.dist-info → claude_mpm-5.6.34.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,45 @@
1
+ """Conversation memory system for Commander.
2
+
3
+ This module provides semantic search, storage, and context compression
4
+ for all Claude Code instance conversations.
5
+
6
+ Key Components:
7
+ - ConversationStore: CRUD operations for conversations
8
+ - EmbeddingService: Generate vector embeddings
9
+ - SemanticSearch: Query conversations semantically
10
+ - ContextCompressor: Summarize conversations for context
11
+ - EntityExtractor: Extract files, functions, errors
12
+
13
+ Example:
14
+ >>> from claude_mpm.commander.memory import (
15
+ ... ConversationStore,
16
+ ... EmbeddingService,
17
+ ... SemanticSearch,
18
+ ... ContextCompressor,
19
+ ... )
20
+ >>> store = ConversationStore()
21
+ >>> embeddings = EmbeddingService()
22
+ >>> search = SemanticSearch(store, embeddings)
23
+ >>> results = await search.search("how did we fix the login bug?")
24
+ """
25
+
26
+ from .compression import ContextCompressor
27
+ from .embeddings import EmbeddingService
28
+ from .entities import Entity, EntityExtractor, EntityType
29
+ from .integration import MemoryIntegration
30
+ from .search import SearchResult, SemanticSearch
31
+ from .store import Conversation, ConversationMessage, ConversationStore
32
+
33
+ __all__ = [
34
+ "ContextCompressor",
35
+ "Conversation",
36
+ "ConversationMessage",
37
+ "ConversationStore",
38
+ "EmbeddingService",
39
+ "Entity",
40
+ "EntityExtractor",
41
+ "EntityType",
42
+ "MemoryIntegration",
43
+ "SearchResult",
44
+ "SemanticSearch",
45
+ ]
@@ -0,0 +1,347 @@
1
+ """Context compression and conversation summarization.
2
+
3
+ Compresses long conversations into concise summaries for efficient context
4
+ loading when resuming sessions or searching past work.
5
+ """
6
+
7
+ import logging
8
+ from typing import List, Optional
9
+
10
+ from ..llm.openrouter_client import OpenRouterClient
11
+ from .store import Conversation, ConversationMessage
12
+
13
+ logger = logging.getLogger(__name__)
14
+
15
+
16
+ class ContextCompressor:
17
+ """Compress conversations into summaries for context loading.
18
+
19
+ Uses cheap LLM (mistral-small) to generate summaries of conversations
20
+ and compress multiple conversations into context strings.
21
+
22
+ Attributes:
23
+ client: OpenRouterClient for LLM requests
24
+ summary_threshold: Minimum messages to trigger summarization
25
+ max_context_tokens: Maximum tokens for compressed context
26
+
27
+ Example:
28
+ >>> compressor = ContextCompressor(client)
29
+ >>> summary = await compressor.summarize(messages)
30
+ >>> context = await compressor.compress_for_context(
31
+ ... conversations,
32
+ ... max_tokens=4000
33
+ ... )
34
+ """
35
+
36
+ def __init__(
37
+ self,
38
+ client: OpenRouterClient,
39
+ summary_threshold: int = 10,
40
+ max_context_tokens: int = 4000,
41
+ ):
42
+ """Initialize context compressor.
43
+
44
+ Args:
45
+ client: OpenRouterClient for LLM requests
46
+ summary_threshold: Minimum messages to summarize
47
+ max_context_tokens: Maximum tokens for context string
48
+ """
49
+ self.client = client
50
+ self.summary_threshold = summary_threshold
51
+ self.max_context_tokens = max_context_tokens
52
+
53
+ logger.info(
54
+ "ContextCompressor initialized (threshold: %d msgs, max_tokens: %d)",
55
+ summary_threshold,
56
+ max_context_tokens,
57
+ )
58
+
59
+ async def summarize(
60
+ self,
61
+ messages: List[ConversationMessage],
62
+ focus: Optional[str] = None,
63
+ ) -> str:
64
+ """Generate summary of conversation messages.
65
+
66
+ Args:
67
+ messages: List of messages to summarize
68
+ focus: Optional focus area (e.g., "bug fixes", "API changes")
69
+
70
+ Returns:
71
+ Concise summary (2-4 sentences)
72
+
73
+ Example:
74
+ >>> summary = await compressor.summarize(messages)
75
+ >>> print(summary)
76
+ "Fixed login authentication bug in src/auth.py by updating token validation..."
77
+ """
78
+ if len(messages) < 2:
79
+ # Too short to summarize
80
+ return messages[0].content if messages else ""
81
+
82
+ # Build conversation text
83
+ conversation_text = self._format_messages(messages)
84
+
85
+ # Build summarization prompt
86
+ if focus:
87
+ prompt = f"""Summarize the following conversation, focusing on: {focus}
88
+
89
+ Conversation:
90
+ {conversation_text}
91
+
92
+ Provide a concise summary (2-4 sentences) that captures:
93
+ 1. What was the main task or problem
94
+ 2. What actions were taken
95
+ 3. What was the outcome or current status
96
+ 4. Any important files, functions, or errors mentioned
97
+
98
+ Summary:"""
99
+ else:
100
+ prompt = f"""Summarize the following conversation in 2-4 sentences.
101
+
102
+ Conversation:
103
+ {conversation_text}
104
+
105
+ Focus on:
106
+ 1. What was the main task or problem
107
+ 2. What actions were taken
108
+ 3. What was the outcome or current status
109
+
110
+ Summary:"""
111
+
112
+ messages_for_llm = [{"role": "user", "content": prompt}]
113
+
114
+ system = (
115
+ "You are a technical summarization assistant. "
116
+ "Provide clear, concise summaries of development conversations. "
117
+ "Focus on actionable information and key outcomes."
118
+ )
119
+
120
+ summary = await self.client.chat(messages_for_llm, system=system)
121
+ logger.debug(
122
+ "Generated summary (%d chars) from %d messages", len(summary), len(messages)
123
+ )
124
+
125
+ return summary.strip()
126
+
127
+ async def compress_for_context(
128
+ self,
129
+ conversations: List[Conversation],
130
+ max_tokens: Optional[int] = None,
131
+ prioritize_recent: bool = True,
132
+ ) -> str:
133
+ """Compress multiple conversations into context string.
134
+
135
+ Prioritizes recent conversations and uses summaries for older ones
136
+ to fit within token budget.
137
+
138
+ Args:
139
+ conversations: List of conversations to compress
140
+ max_tokens: Maximum tokens (default: self.max_context_tokens)
141
+ prioritize_recent: Whether to prioritize recent conversations
142
+
143
+ Returns:
144
+ Compressed context string ready for LLM input
145
+
146
+ Example:
147
+ >>> context = await compressor.compress_for_context(
148
+ ... conversations,
149
+ ... max_tokens=4000
150
+ ... )
151
+ >>> print(f"Context: {len(context)} chars")
152
+ """
153
+ if max_tokens is None:
154
+ max_tokens = self.max_context_tokens
155
+
156
+ # Sort by recency if prioritizing
157
+ if prioritize_recent:
158
+ conversations = sorted(
159
+ conversations, key=lambda c: c.updated_at, reverse=True
160
+ )
161
+
162
+ # Build context incrementally
163
+ context_parts = []
164
+ current_tokens = 0
165
+
166
+ for conv in conversations:
167
+ # Use summary if available, else generate one
168
+ if conv.summary:
169
+ summary_text = conv.summary
170
+ elif len(conv.messages) >= self.summary_threshold:
171
+ # Generate summary on-the-fly
172
+ summary_text = await self.summarize(conv.messages)
173
+ else:
174
+ # Use full conversation for short ones
175
+ summary_text = conv.get_full_text()
176
+
177
+ # Format conversation section
178
+ section = self._format_conversation_section(conv, summary_text)
179
+ section_tokens = len(section) // 4 # Rough approximation
180
+
181
+ # Check if adding this would exceed budget
182
+ if current_tokens + section_tokens > max_tokens:
183
+ # Try to fit summary only
184
+ short_summary = summary_text.split(". ")[0] + "."
185
+ short_section = self._format_conversation_section(conv, short_summary)
186
+ short_tokens = len(short_section) // 4
187
+
188
+ if current_tokens + short_tokens <= max_tokens:
189
+ context_parts.append(short_section)
190
+ current_tokens += short_tokens
191
+ else:
192
+ # Can't fit any more, stop
193
+ break
194
+ else:
195
+ context_parts.append(section)
196
+ current_tokens += section_tokens
197
+
198
+ context = "\n\n---\n\n".join(context_parts)
199
+
200
+ logger.info(
201
+ "Compressed %d conversations into context (%d chars, ~%d tokens)",
202
+ len(context_parts),
203
+ len(context),
204
+ current_tokens,
205
+ )
206
+
207
+ return context
208
+
209
+ def needs_summarization(self, messages: List[ConversationMessage]) -> bool:
210
+ """Check if conversation needs summarization.
211
+
212
+ Args:
213
+ messages: List of messages to check
214
+
215
+ Returns:
216
+ True if message count exceeds threshold
217
+
218
+ Example:
219
+ >>> if compressor.needs_summarization(messages):
220
+ ... summary = await compressor.summarize(messages)
221
+ """
222
+ return len(messages) >= self.summary_threshold
223
+
224
+ def _format_messages(
225
+ self,
226
+ messages: List[ConversationMessage],
227
+ max_messages: Optional[int] = None,
228
+ ) -> str:
229
+ """Format messages as text for summarization.
230
+
231
+ Args:
232
+ messages: Messages to format
233
+ max_messages: Maximum messages to include
234
+
235
+ Returns:
236
+ Formatted conversation text
237
+ """
238
+ if max_messages:
239
+ messages = messages[:max_messages]
240
+
241
+ lines = []
242
+ for msg in messages:
243
+ # Format: ROLE: content
244
+ lines.append(f"{msg.role.upper()}: {msg.content}")
245
+
246
+ return "\n\n".join(lines)
247
+
248
+ def _format_conversation_section(
249
+ self, conversation: Conversation, summary: str
250
+ ) -> str:
251
+ """Format conversation section for context string.
252
+
253
+ Args:
254
+ conversation: Conversation to format
255
+ summary: Summary or full text
256
+
257
+ Returns:
258
+ Formatted section with metadata
259
+ """
260
+ # Format timestamp
261
+ timestamp = conversation.updated_at.strftime("%Y-%m-%d %H:%M")
262
+
263
+ # Build section
264
+ return f"""## Conversation: {conversation.id}
265
+ **Project:** {conversation.project_id}
266
+ **Instance:** {conversation.instance_name}
267
+ **Updated:** {timestamp}
268
+ **Messages:** {conversation.message_count}
269
+
270
+ {summary}"""
271
+
272
+ async def auto_summarize_conversation(
273
+ self, conversation: Conversation
274
+ ) -> Optional[str]:
275
+ """Automatically summarize conversation if needed.
276
+
277
+ Checks if conversation needs summarization and generates one if so.
278
+ Updates the conversation's summary field but does NOT save to store.
279
+
280
+ Args:
281
+ conversation: Conversation to summarize
282
+
283
+ Returns:
284
+ Summary if generated, None if not needed
285
+
286
+ Example:
287
+ >>> summary = await compressor.auto_summarize_conversation(conv)
288
+ >>> if summary:
289
+ ... conv.summary = summary
290
+ ... await store.save(conv)
291
+ """
292
+ if not self.needs_summarization(conversation.messages):
293
+ logger.debug(
294
+ "Conversation %s too short to summarize (%d messages)",
295
+ conversation.id,
296
+ len(conversation.messages),
297
+ )
298
+ return None
299
+
300
+ if conversation.summary:
301
+ logger.debug("Conversation %s already has summary", conversation.id)
302
+ return conversation.summary
303
+
304
+ # Generate summary
305
+ summary = await self.summarize(conversation.messages)
306
+ logger.info("Auto-generated summary for conversation %s", conversation.id)
307
+
308
+ return summary
309
+
310
+ async def update_summary_if_stale(
311
+ self,
312
+ conversation: Conversation,
313
+ message_threshold: int = 5,
314
+ ) -> Optional[str]:
315
+ """Update summary if conversation has grown significantly.
316
+
317
+ Args:
318
+ conversation: Conversation to check
319
+ message_threshold: New messages required to trigger update
320
+
321
+ Returns:
322
+ Updated summary if regenerated, None otherwise
323
+
324
+ Example:
325
+ >>> updated = await compressor.update_summary_if_stale(conv)
326
+ >>> if updated:
327
+ ... conv.summary = updated
328
+ ... await store.save(conv)
329
+ """
330
+ if not conversation.summary:
331
+ # No existing summary, generate one
332
+ return await self.auto_summarize_conversation(conversation)
333
+
334
+ # Check if conversation has grown significantly
335
+ # (Simple heuristic: if more than threshold messages since last summarization)
336
+ # In practice, you'd track when summary was generated
337
+ if len(conversation.messages) < self.summary_threshold + message_threshold:
338
+ return None
339
+
340
+ # Regenerate summary
341
+ logger.info(
342
+ "Regenerating stale summary for conversation %s (%d messages)",
343
+ conversation.id,
344
+ len(conversation.messages),
345
+ )
346
+
347
+ return await self.summarize(conversation.messages)
@@ -0,0 +1,230 @@
1
+ """Embedding service for semantic search.
2
+
3
+ Generates vector embeddings using sentence-transformers (local) or
4
+ OpenAI API (cloud). Defaults to local model for zero-cost operation.
5
+ """
6
+
7
+ import asyncio
8
+ import logging
9
+ from typing import List, Literal, Optional
10
+
11
+ logger = logging.getLogger(__name__)
12
+
13
+ EmbeddingProvider = Literal["sentence-transformers", "openai"]
14
+
15
+
16
+ class EmbeddingService:
17
+ """Generate vector embeddings for semantic search.
18
+
19
+ Supports multiple providers:
20
+ - sentence-transformers: Local, free, good quality (default)
21
+ - openai: Cloud API, best quality, costs money
22
+
23
+ Attributes:
24
+ provider: Embedding provider to use
25
+ model: Model name for the provider
26
+ dimension: Embedding vector dimension
27
+
28
+ Example:
29
+ >>> embeddings = EmbeddingService(provider="sentence-transformers")
30
+ >>> vector = await embeddings.embed("Fix the login bug")
31
+ >>> len(vector)
32
+ 384
33
+ """
34
+
35
+ def __init__(
36
+ self,
37
+ provider: EmbeddingProvider = "sentence-transformers",
38
+ model: Optional[str] = None,
39
+ ):
40
+ """Initialize embedding service.
41
+
42
+ Args:
43
+ provider: Embedding provider ('sentence-transformers' or 'openai')
44
+ model: Model name (provider-specific default if None)
45
+ """
46
+ self.provider = provider
47
+ self._encoder = None
48
+ self._client = None
49
+
50
+ if provider == "sentence-transformers":
51
+ self.model = model or "all-MiniLM-L6-v2"
52
+ self.dimension = 384
53
+ self._init_sentence_transformers()
54
+ elif provider == "openai":
55
+ self.model = model or "text-embedding-3-small"
56
+ self.dimension = 1536
57
+ self._init_openai()
58
+ else:
59
+ raise ValueError(f"Unknown provider: {provider}")
60
+
61
+ logger.info(
62
+ "EmbeddingService initialized (provider: %s, model: %s, dim: %d)",
63
+ provider,
64
+ self.model,
65
+ self.dimension,
66
+ )
67
+
68
+ def _init_sentence_transformers(self) -> None:
69
+ """Initialize sentence-transformers encoder.
70
+
71
+ Lazy loads on first use to avoid startup delay.
72
+ """
73
+ # Lazy import to avoid dependency if not used
74
+ try:
75
+ from sentence_transformers import SentenceTransformer
76
+
77
+ self._encoder = SentenceTransformer(self.model)
78
+ logger.info("Loaded sentence-transformers model: %s", self.model)
79
+ except ImportError:
80
+ logger.error(
81
+ "sentence-transformers not installed. "
82
+ "Install with: pip install sentence-transformers"
83
+ )
84
+ raise
85
+
86
+ def _init_openai(self) -> None:
87
+ """Initialize OpenAI client.
88
+
89
+ Requires OPENAI_API_KEY environment variable.
90
+ """
91
+ try:
92
+ from openai import AsyncOpenAI
93
+
94
+ self._client = AsyncOpenAI()
95
+ logger.info("Initialized OpenAI client")
96
+ except ImportError:
97
+ logger.error("openai not installed. Install with: pip install openai")
98
+ raise
99
+
100
+ async def embed(self, text: str) -> List[float]:
101
+ """Generate embedding for text.
102
+
103
+ Args:
104
+ text: Text to embed
105
+
106
+ Returns:
107
+ Embedding vector as list of floats
108
+
109
+ Example:
110
+ >>> vector = await embeddings.embed("Fix the login bug")
111
+ >>> len(vector)
112
+ 384
113
+ """
114
+ if self.provider == "sentence-transformers":
115
+ return await self._embed_sentence_transformers(text)
116
+ if self.provider == "openai":
117
+ return await self._embed_openai(text)
118
+ raise ValueError(f"Unknown provider: {self.provider}")
119
+
120
+ async def embed_batch(self, texts: List[str]) -> List[List[float]]:
121
+ """Generate embeddings for multiple texts.
122
+
123
+ More efficient than calling embed() in a loop.
124
+
125
+ Args:
126
+ texts: List of texts to embed
127
+
128
+ Returns:
129
+ List of embedding vectors
130
+
131
+ Example:
132
+ >>> vectors = await embeddings.embed_batch([
133
+ ... "Fix the login bug",
134
+ ... "Update the README"
135
+ ... ])
136
+ >>> len(vectors)
137
+ 2
138
+ """
139
+ if self.provider == "sentence-transformers":
140
+ return await self._embed_batch_sentence_transformers(texts)
141
+ if self.provider == "openai":
142
+ return await self._embed_batch_openai(texts)
143
+ raise ValueError(f"Unknown provider: {self.provider}")
144
+
145
+ async def _embed_sentence_transformers(self, text: str) -> List[float]:
146
+ """Generate embedding using sentence-transformers.
147
+
148
+ Runs in executor to avoid blocking event loop.
149
+ """
150
+ if self._encoder is None:
151
+ raise RuntimeError("Encoder not initialized")
152
+
153
+ # Run encoding in executor (CPU-bound operation)
154
+ loop = asyncio.get_event_loop()
155
+ embedding = await loop.run_in_executor(
156
+ None, lambda: self._encoder.encode(text, convert_to_numpy=True)
157
+ )
158
+
159
+ return embedding.tolist()
160
+
161
+ async def _embed_batch_sentence_transformers(
162
+ self, texts: List[str]
163
+ ) -> List[List[float]]:
164
+ """Generate batch embeddings using sentence-transformers."""
165
+ if self._encoder is None:
166
+ raise RuntimeError("Encoder not initialized")
167
+
168
+ # Run batch encoding in executor
169
+ loop = asyncio.get_event_loop()
170
+ embeddings = await loop.run_in_executor(
171
+ None,
172
+ lambda: self._encoder.encode(
173
+ texts, convert_to_numpy=True, show_progress_bar=False
174
+ ),
175
+ )
176
+
177
+ return [emb.tolist() for emb in embeddings]
178
+
179
+ async def _embed_openai(self, text: str) -> List[float]:
180
+ """Generate embedding using OpenAI API."""
181
+ if self._client is None:
182
+ raise RuntimeError("OpenAI client not initialized")
183
+
184
+ response = await self._client.embeddings.create(
185
+ model=self.model,
186
+ input=text,
187
+ )
188
+
189
+ return response.data[0].embedding
190
+
191
+ async def _embed_batch_openai(self, texts: List[str]) -> List[List[float]]:
192
+ """Generate batch embeddings using OpenAI API."""
193
+ if self._client is None:
194
+ raise RuntimeError("OpenAI client not initialized")
195
+
196
+ response = await self._client.embeddings.create(
197
+ model=self.model,
198
+ input=texts,
199
+ )
200
+
201
+ return [item.embedding for item in response.data]
202
+
203
+ def cosine_similarity(self, vec1: List[float], vec2: List[float]) -> float:
204
+ """Calculate cosine similarity between two vectors.
205
+
206
+ Args:
207
+ vec1: First vector
208
+ vec2: Second vector
209
+
210
+ Returns:
211
+ Similarity score in range [-1, 1] (1 = identical, -1 = opposite)
212
+
213
+ Example:
214
+ >>> sim = embeddings.cosine_similarity(vec1, vec2)
215
+ >>> print(f"Similarity: {sim:.3f}")
216
+ """
217
+ import math
218
+
219
+ # Dot product
220
+ dot_product = sum(a * b for a, b in zip(vec1, vec2))
221
+
222
+ # Magnitudes
223
+ mag1 = math.sqrt(sum(a * a for a in vec1))
224
+ mag2 = math.sqrt(sum(b * b for b in vec2))
225
+
226
+ # Avoid division by zero
227
+ if mag1 == 0 or mag2 == 0:
228
+ return 0.0
229
+
230
+ return dot_product / (mag1 * mag2)