gobby 0.2.5__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.
Files changed (383) hide show
  1. gobby/__init__.py +3 -0
  2. gobby/adapters/__init__.py +30 -0
  3. gobby/adapters/base.py +93 -0
  4. gobby/adapters/claude_code.py +276 -0
  5. gobby/adapters/codex.py +1292 -0
  6. gobby/adapters/gemini.py +343 -0
  7. gobby/agents/__init__.py +37 -0
  8. gobby/agents/codex_session.py +120 -0
  9. gobby/agents/constants.py +112 -0
  10. gobby/agents/context.py +362 -0
  11. gobby/agents/definitions.py +133 -0
  12. gobby/agents/gemini_session.py +111 -0
  13. gobby/agents/registry.py +618 -0
  14. gobby/agents/runner.py +968 -0
  15. gobby/agents/session.py +259 -0
  16. gobby/agents/spawn.py +916 -0
  17. gobby/agents/spawners/__init__.py +77 -0
  18. gobby/agents/spawners/base.py +142 -0
  19. gobby/agents/spawners/cross_platform.py +266 -0
  20. gobby/agents/spawners/embedded.py +225 -0
  21. gobby/agents/spawners/headless.py +226 -0
  22. gobby/agents/spawners/linux.py +125 -0
  23. gobby/agents/spawners/macos.py +277 -0
  24. gobby/agents/spawners/windows.py +308 -0
  25. gobby/agents/tty_config.py +319 -0
  26. gobby/autonomous/__init__.py +32 -0
  27. gobby/autonomous/progress_tracker.py +447 -0
  28. gobby/autonomous/stop_registry.py +269 -0
  29. gobby/autonomous/stuck_detector.py +383 -0
  30. gobby/cli/__init__.py +67 -0
  31. gobby/cli/__main__.py +8 -0
  32. gobby/cli/agents.py +529 -0
  33. gobby/cli/artifacts.py +266 -0
  34. gobby/cli/daemon.py +329 -0
  35. gobby/cli/extensions.py +526 -0
  36. gobby/cli/github.py +263 -0
  37. gobby/cli/init.py +53 -0
  38. gobby/cli/install.py +614 -0
  39. gobby/cli/installers/__init__.py +37 -0
  40. gobby/cli/installers/antigravity.py +65 -0
  41. gobby/cli/installers/claude.py +363 -0
  42. gobby/cli/installers/codex.py +192 -0
  43. gobby/cli/installers/gemini.py +294 -0
  44. gobby/cli/installers/git_hooks.py +377 -0
  45. gobby/cli/installers/shared.py +737 -0
  46. gobby/cli/linear.py +250 -0
  47. gobby/cli/mcp.py +30 -0
  48. gobby/cli/mcp_proxy.py +698 -0
  49. gobby/cli/memory.py +304 -0
  50. gobby/cli/merge.py +384 -0
  51. gobby/cli/projects.py +79 -0
  52. gobby/cli/sessions.py +622 -0
  53. gobby/cli/tasks/__init__.py +30 -0
  54. gobby/cli/tasks/_utils.py +658 -0
  55. gobby/cli/tasks/ai.py +1025 -0
  56. gobby/cli/tasks/commits.py +169 -0
  57. gobby/cli/tasks/crud.py +685 -0
  58. gobby/cli/tasks/deps.py +135 -0
  59. gobby/cli/tasks/labels.py +63 -0
  60. gobby/cli/tasks/main.py +273 -0
  61. gobby/cli/tasks/search.py +178 -0
  62. gobby/cli/tui.py +34 -0
  63. gobby/cli/utils.py +513 -0
  64. gobby/cli/workflows.py +927 -0
  65. gobby/cli/worktrees.py +481 -0
  66. gobby/config/__init__.py +129 -0
  67. gobby/config/app.py +551 -0
  68. gobby/config/extensions.py +167 -0
  69. gobby/config/features.py +472 -0
  70. gobby/config/llm_providers.py +98 -0
  71. gobby/config/logging.py +66 -0
  72. gobby/config/mcp.py +346 -0
  73. gobby/config/persistence.py +247 -0
  74. gobby/config/servers.py +141 -0
  75. gobby/config/sessions.py +250 -0
  76. gobby/config/tasks.py +784 -0
  77. gobby/hooks/__init__.py +104 -0
  78. gobby/hooks/artifact_capture.py +213 -0
  79. gobby/hooks/broadcaster.py +243 -0
  80. gobby/hooks/event_handlers.py +723 -0
  81. gobby/hooks/events.py +218 -0
  82. gobby/hooks/git.py +169 -0
  83. gobby/hooks/health_monitor.py +171 -0
  84. gobby/hooks/hook_manager.py +856 -0
  85. gobby/hooks/hook_types.py +575 -0
  86. gobby/hooks/plugins.py +813 -0
  87. gobby/hooks/session_coordinator.py +396 -0
  88. gobby/hooks/verification_runner.py +268 -0
  89. gobby/hooks/webhooks.py +339 -0
  90. gobby/install/claude/commands/gobby/bug.md +51 -0
  91. gobby/install/claude/commands/gobby/chore.md +51 -0
  92. gobby/install/claude/commands/gobby/epic.md +52 -0
  93. gobby/install/claude/commands/gobby/eval.md +235 -0
  94. gobby/install/claude/commands/gobby/feat.md +49 -0
  95. gobby/install/claude/commands/gobby/nit.md +52 -0
  96. gobby/install/claude/commands/gobby/ref.md +52 -0
  97. gobby/install/claude/hooks/HOOK_SCHEMAS.md +632 -0
  98. gobby/install/claude/hooks/hook_dispatcher.py +364 -0
  99. gobby/install/claude/hooks/validate_settings.py +102 -0
  100. gobby/install/claude/hooks-template.json +118 -0
  101. gobby/install/codex/hooks/hook_dispatcher.py +153 -0
  102. gobby/install/codex/prompts/forget.md +7 -0
  103. gobby/install/codex/prompts/memories.md +7 -0
  104. gobby/install/codex/prompts/recall.md +7 -0
  105. gobby/install/codex/prompts/remember.md +13 -0
  106. gobby/install/gemini/hooks/hook_dispatcher.py +268 -0
  107. gobby/install/gemini/hooks-template.json +138 -0
  108. gobby/install/shared/plugins/code_guardian.py +456 -0
  109. gobby/install/shared/plugins/example_notify.py +331 -0
  110. gobby/integrations/__init__.py +10 -0
  111. gobby/integrations/github.py +145 -0
  112. gobby/integrations/linear.py +145 -0
  113. gobby/llm/__init__.py +40 -0
  114. gobby/llm/base.py +120 -0
  115. gobby/llm/claude.py +578 -0
  116. gobby/llm/claude_executor.py +503 -0
  117. gobby/llm/codex.py +322 -0
  118. gobby/llm/codex_executor.py +513 -0
  119. gobby/llm/executor.py +316 -0
  120. gobby/llm/factory.py +34 -0
  121. gobby/llm/gemini.py +258 -0
  122. gobby/llm/gemini_executor.py +339 -0
  123. gobby/llm/litellm.py +287 -0
  124. gobby/llm/litellm_executor.py +303 -0
  125. gobby/llm/resolver.py +499 -0
  126. gobby/llm/service.py +236 -0
  127. gobby/mcp_proxy/__init__.py +29 -0
  128. gobby/mcp_proxy/actions.py +175 -0
  129. gobby/mcp_proxy/daemon_control.py +198 -0
  130. gobby/mcp_proxy/importer.py +436 -0
  131. gobby/mcp_proxy/lazy.py +325 -0
  132. gobby/mcp_proxy/manager.py +798 -0
  133. gobby/mcp_proxy/metrics.py +609 -0
  134. gobby/mcp_proxy/models.py +139 -0
  135. gobby/mcp_proxy/registries.py +215 -0
  136. gobby/mcp_proxy/schema_hash.py +381 -0
  137. gobby/mcp_proxy/semantic_search.py +706 -0
  138. gobby/mcp_proxy/server.py +549 -0
  139. gobby/mcp_proxy/services/__init__.py +0 -0
  140. gobby/mcp_proxy/services/fallback.py +306 -0
  141. gobby/mcp_proxy/services/recommendation.py +224 -0
  142. gobby/mcp_proxy/services/server_mgmt.py +214 -0
  143. gobby/mcp_proxy/services/system.py +72 -0
  144. gobby/mcp_proxy/services/tool_filter.py +231 -0
  145. gobby/mcp_proxy/services/tool_proxy.py +309 -0
  146. gobby/mcp_proxy/stdio.py +565 -0
  147. gobby/mcp_proxy/tools/__init__.py +27 -0
  148. gobby/mcp_proxy/tools/agents.py +1103 -0
  149. gobby/mcp_proxy/tools/artifacts.py +207 -0
  150. gobby/mcp_proxy/tools/hub.py +335 -0
  151. gobby/mcp_proxy/tools/internal.py +337 -0
  152. gobby/mcp_proxy/tools/memory.py +543 -0
  153. gobby/mcp_proxy/tools/merge.py +422 -0
  154. gobby/mcp_proxy/tools/metrics.py +283 -0
  155. gobby/mcp_proxy/tools/orchestration/__init__.py +23 -0
  156. gobby/mcp_proxy/tools/orchestration/cleanup.py +619 -0
  157. gobby/mcp_proxy/tools/orchestration/monitor.py +380 -0
  158. gobby/mcp_proxy/tools/orchestration/orchestrate.py +746 -0
  159. gobby/mcp_proxy/tools/orchestration/review.py +736 -0
  160. gobby/mcp_proxy/tools/orchestration/utils.py +16 -0
  161. gobby/mcp_proxy/tools/session_messages.py +1056 -0
  162. gobby/mcp_proxy/tools/task_dependencies.py +219 -0
  163. gobby/mcp_proxy/tools/task_expansion.py +591 -0
  164. gobby/mcp_proxy/tools/task_github.py +393 -0
  165. gobby/mcp_proxy/tools/task_linear.py +379 -0
  166. gobby/mcp_proxy/tools/task_orchestration.py +77 -0
  167. gobby/mcp_proxy/tools/task_readiness.py +522 -0
  168. gobby/mcp_proxy/tools/task_sync.py +351 -0
  169. gobby/mcp_proxy/tools/task_validation.py +843 -0
  170. gobby/mcp_proxy/tools/tasks/__init__.py +25 -0
  171. gobby/mcp_proxy/tools/tasks/_context.py +112 -0
  172. gobby/mcp_proxy/tools/tasks/_crud.py +516 -0
  173. gobby/mcp_proxy/tools/tasks/_factory.py +176 -0
  174. gobby/mcp_proxy/tools/tasks/_helpers.py +129 -0
  175. gobby/mcp_proxy/tools/tasks/_lifecycle.py +517 -0
  176. gobby/mcp_proxy/tools/tasks/_lifecycle_validation.py +301 -0
  177. gobby/mcp_proxy/tools/tasks/_resolution.py +55 -0
  178. gobby/mcp_proxy/tools/tasks/_search.py +215 -0
  179. gobby/mcp_proxy/tools/tasks/_session.py +125 -0
  180. gobby/mcp_proxy/tools/workflows.py +973 -0
  181. gobby/mcp_proxy/tools/worktrees.py +1264 -0
  182. gobby/mcp_proxy/transports/__init__.py +0 -0
  183. gobby/mcp_proxy/transports/base.py +95 -0
  184. gobby/mcp_proxy/transports/factory.py +44 -0
  185. gobby/mcp_proxy/transports/http.py +139 -0
  186. gobby/mcp_proxy/transports/stdio.py +213 -0
  187. gobby/mcp_proxy/transports/websocket.py +136 -0
  188. gobby/memory/backends/__init__.py +116 -0
  189. gobby/memory/backends/mem0.py +408 -0
  190. gobby/memory/backends/memu.py +485 -0
  191. gobby/memory/backends/null.py +111 -0
  192. gobby/memory/backends/openmemory.py +537 -0
  193. gobby/memory/backends/sqlite.py +304 -0
  194. gobby/memory/context.py +87 -0
  195. gobby/memory/manager.py +1001 -0
  196. gobby/memory/protocol.py +451 -0
  197. gobby/memory/search/__init__.py +66 -0
  198. gobby/memory/search/text.py +127 -0
  199. gobby/memory/viz.py +258 -0
  200. gobby/prompts/__init__.py +13 -0
  201. gobby/prompts/defaults/expansion/system.md +119 -0
  202. gobby/prompts/defaults/expansion/user.md +48 -0
  203. gobby/prompts/defaults/external_validation/agent.md +72 -0
  204. gobby/prompts/defaults/external_validation/external.md +63 -0
  205. gobby/prompts/defaults/external_validation/spawn.md +83 -0
  206. gobby/prompts/defaults/external_validation/system.md +6 -0
  207. gobby/prompts/defaults/features/import_mcp.md +22 -0
  208. gobby/prompts/defaults/features/import_mcp_github.md +17 -0
  209. gobby/prompts/defaults/features/import_mcp_search.md +16 -0
  210. gobby/prompts/defaults/features/recommend_tools.md +32 -0
  211. gobby/prompts/defaults/features/recommend_tools_hybrid.md +35 -0
  212. gobby/prompts/defaults/features/recommend_tools_llm.md +30 -0
  213. gobby/prompts/defaults/features/server_description.md +20 -0
  214. gobby/prompts/defaults/features/server_description_system.md +6 -0
  215. gobby/prompts/defaults/features/task_description.md +31 -0
  216. gobby/prompts/defaults/features/task_description_system.md +6 -0
  217. gobby/prompts/defaults/features/tool_summary.md +17 -0
  218. gobby/prompts/defaults/features/tool_summary_system.md +6 -0
  219. gobby/prompts/defaults/research/step.md +58 -0
  220. gobby/prompts/defaults/validation/criteria.md +47 -0
  221. gobby/prompts/defaults/validation/validate.md +38 -0
  222. gobby/prompts/loader.py +346 -0
  223. gobby/prompts/models.py +113 -0
  224. gobby/py.typed +0 -0
  225. gobby/runner.py +488 -0
  226. gobby/search/__init__.py +23 -0
  227. gobby/search/protocol.py +104 -0
  228. gobby/search/tfidf.py +232 -0
  229. gobby/servers/__init__.py +7 -0
  230. gobby/servers/http.py +636 -0
  231. gobby/servers/models.py +31 -0
  232. gobby/servers/routes/__init__.py +23 -0
  233. gobby/servers/routes/admin.py +416 -0
  234. gobby/servers/routes/dependencies.py +118 -0
  235. gobby/servers/routes/mcp/__init__.py +24 -0
  236. gobby/servers/routes/mcp/hooks.py +135 -0
  237. gobby/servers/routes/mcp/plugins.py +121 -0
  238. gobby/servers/routes/mcp/tools.py +1337 -0
  239. gobby/servers/routes/mcp/webhooks.py +159 -0
  240. gobby/servers/routes/sessions.py +582 -0
  241. gobby/servers/websocket.py +766 -0
  242. gobby/sessions/__init__.py +13 -0
  243. gobby/sessions/analyzer.py +322 -0
  244. gobby/sessions/lifecycle.py +240 -0
  245. gobby/sessions/manager.py +563 -0
  246. gobby/sessions/processor.py +225 -0
  247. gobby/sessions/summary.py +532 -0
  248. gobby/sessions/transcripts/__init__.py +41 -0
  249. gobby/sessions/transcripts/base.py +125 -0
  250. gobby/sessions/transcripts/claude.py +386 -0
  251. gobby/sessions/transcripts/codex.py +143 -0
  252. gobby/sessions/transcripts/gemini.py +195 -0
  253. gobby/storage/__init__.py +21 -0
  254. gobby/storage/agents.py +409 -0
  255. gobby/storage/artifact_classifier.py +341 -0
  256. gobby/storage/artifacts.py +285 -0
  257. gobby/storage/compaction.py +67 -0
  258. gobby/storage/database.py +357 -0
  259. gobby/storage/inter_session_messages.py +194 -0
  260. gobby/storage/mcp.py +680 -0
  261. gobby/storage/memories.py +562 -0
  262. gobby/storage/merge_resolutions.py +550 -0
  263. gobby/storage/migrations.py +860 -0
  264. gobby/storage/migrations_legacy.py +1359 -0
  265. gobby/storage/projects.py +166 -0
  266. gobby/storage/session_messages.py +251 -0
  267. gobby/storage/session_tasks.py +97 -0
  268. gobby/storage/sessions.py +817 -0
  269. gobby/storage/task_dependencies.py +223 -0
  270. gobby/storage/tasks/__init__.py +42 -0
  271. gobby/storage/tasks/_aggregates.py +180 -0
  272. gobby/storage/tasks/_crud.py +449 -0
  273. gobby/storage/tasks/_id.py +104 -0
  274. gobby/storage/tasks/_lifecycle.py +311 -0
  275. gobby/storage/tasks/_manager.py +889 -0
  276. gobby/storage/tasks/_models.py +300 -0
  277. gobby/storage/tasks/_ordering.py +119 -0
  278. gobby/storage/tasks/_path_cache.py +110 -0
  279. gobby/storage/tasks/_queries.py +343 -0
  280. gobby/storage/tasks/_search.py +143 -0
  281. gobby/storage/workflow_audit.py +393 -0
  282. gobby/storage/worktrees.py +547 -0
  283. gobby/sync/__init__.py +29 -0
  284. gobby/sync/github.py +333 -0
  285. gobby/sync/linear.py +304 -0
  286. gobby/sync/memories.py +284 -0
  287. gobby/sync/tasks.py +641 -0
  288. gobby/tasks/__init__.py +8 -0
  289. gobby/tasks/build_verification.py +193 -0
  290. gobby/tasks/commits.py +633 -0
  291. gobby/tasks/context.py +747 -0
  292. gobby/tasks/criteria.py +342 -0
  293. gobby/tasks/enhanced_validator.py +226 -0
  294. gobby/tasks/escalation.py +263 -0
  295. gobby/tasks/expansion.py +626 -0
  296. gobby/tasks/external_validator.py +764 -0
  297. gobby/tasks/issue_extraction.py +171 -0
  298. gobby/tasks/prompts/expand.py +327 -0
  299. gobby/tasks/research.py +421 -0
  300. gobby/tasks/tdd.py +352 -0
  301. gobby/tasks/tree_builder.py +263 -0
  302. gobby/tasks/validation.py +712 -0
  303. gobby/tasks/validation_history.py +357 -0
  304. gobby/tasks/validation_models.py +89 -0
  305. gobby/tools/__init__.py +0 -0
  306. gobby/tools/summarizer.py +170 -0
  307. gobby/tui/__init__.py +5 -0
  308. gobby/tui/api_client.py +281 -0
  309. gobby/tui/app.py +327 -0
  310. gobby/tui/screens/__init__.py +25 -0
  311. gobby/tui/screens/agents.py +333 -0
  312. gobby/tui/screens/chat.py +450 -0
  313. gobby/tui/screens/dashboard.py +377 -0
  314. gobby/tui/screens/memory.py +305 -0
  315. gobby/tui/screens/metrics.py +231 -0
  316. gobby/tui/screens/orchestrator.py +904 -0
  317. gobby/tui/screens/sessions.py +412 -0
  318. gobby/tui/screens/tasks.py +442 -0
  319. gobby/tui/screens/workflows.py +289 -0
  320. gobby/tui/screens/worktrees.py +174 -0
  321. gobby/tui/widgets/__init__.py +21 -0
  322. gobby/tui/widgets/chat.py +210 -0
  323. gobby/tui/widgets/conductor.py +104 -0
  324. gobby/tui/widgets/menu.py +132 -0
  325. gobby/tui/widgets/message_panel.py +160 -0
  326. gobby/tui/widgets/review_gate.py +224 -0
  327. gobby/tui/widgets/task_tree.py +99 -0
  328. gobby/tui/widgets/token_budget.py +166 -0
  329. gobby/tui/ws_client.py +258 -0
  330. gobby/utils/__init__.py +3 -0
  331. gobby/utils/daemon_client.py +235 -0
  332. gobby/utils/git.py +222 -0
  333. gobby/utils/id.py +38 -0
  334. gobby/utils/json_helpers.py +161 -0
  335. gobby/utils/logging.py +376 -0
  336. gobby/utils/machine_id.py +135 -0
  337. gobby/utils/metrics.py +589 -0
  338. gobby/utils/project_context.py +182 -0
  339. gobby/utils/project_init.py +263 -0
  340. gobby/utils/status.py +256 -0
  341. gobby/utils/validation.py +80 -0
  342. gobby/utils/version.py +23 -0
  343. gobby/workflows/__init__.py +4 -0
  344. gobby/workflows/actions.py +1310 -0
  345. gobby/workflows/approval_flow.py +138 -0
  346. gobby/workflows/artifact_actions.py +103 -0
  347. gobby/workflows/audit_helpers.py +110 -0
  348. gobby/workflows/autonomous_actions.py +286 -0
  349. gobby/workflows/context_actions.py +394 -0
  350. gobby/workflows/definitions.py +130 -0
  351. gobby/workflows/detection_helpers.py +208 -0
  352. gobby/workflows/engine.py +485 -0
  353. gobby/workflows/evaluator.py +669 -0
  354. gobby/workflows/git_utils.py +96 -0
  355. gobby/workflows/hooks.py +169 -0
  356. gobby/workflows/lifecycle_evaluator.py +613 -0
  357. gobby/workflows/llm_actions.py +70 -0
  358. gobby/workflows/loader.py +333 -0
  359. gobby/workflows/mcp_actions.py +60 -0
  360. gobby/workflows/memory_actions.py +272 -0
  361. gobby/workflows/premature_stop.py +164 -0
  362. gobby/workflows/session_actions.py +139 -0
  363. gobby/workflows/state_actions.py +123 -0
  364. gobby/workflows/state_manager.py +104 -0
  365. gobby/workflows/stop_signal_actions.py +163 -0
  366. gobby/workflows/summary_actions.py +344 -0
  367. gobby/workflows/task_actions.py +249 -0
  368. gobby/workflows/task_enforcement_actions.py +901 -0
  369. gobby/workflows/templates.py +52 -0
  370. gobby/workflows/todo_actions.py +84 -0
  371. gobby/workflows/webhook.py +223 -0
  372. gobby/workflows/webhook_executor.py +399 -0
  373. gobby/worktrees/__init__.py +5 -0
  374. gobby/worktrees/git.py +690 -0
  375. gobby/worktrees/merge/__init__.py +20 -0
  376. gobby/worktrees/merge/conflict_parser.py +177 -0
  377. gobby/worktrees/merge/resolver.py +485 -0
  378. gobby-0.2.5.dist-info/METADATA +351 -0
  379. gobby-0.2.5.dist-info/RECORD +383 -0
  380. gobby-0.2.5.dist-info/WHEEL +5 -0
  381. gobby-0.2.5.dist-info/entry_points.txt +2 -0
  382. gobby-0.2.5.dist-info/licenses/LICENSE.md +193 -0
  383. gobby-0.2.5.dist-info/top_level.txt +1 -0
@@ -0,0 +1,543 @@
1
+ """
2
+ Internal MCP tools for Gobby Memory System.
3
+
4
+ Exposes functionality for:
5
+ - Creating memories (create_memory)
6
+ - Searching memories (search_memories, formerly recall_memory)
7
+ - Deleting memories (delete_memory)
8
+ - Listing memories (list_memories)
9
+ - Getting memory details (get_memory)
10
+ - Updating memories (update_memory)
11
+ - Memory statistics (memory_stats)
12
+
13
+ These tools are registered with the InternalToolRegistry and accessed
14
+ via the downstream proxy pattern (call_tool).
15
+ """
16
+
17
+ from __future__ import annotations
18
+
19
+ from typing import TYPE_CHECKING, Any
20
+
21
+ from gobby.mcp_proxy.tools.internal import InternalToolRegistry
22
+ from gobby.memory.manager import MemoryManager
23
+
24
+ if TYPE_CHECKING:
25
+ from gobby.llm.service import LLMService
26
+ from gobby.llm.service import LLMService
27
+
28
+
29
+ # Helper to get current project context
30
+ def get_current_project_id() -> str | None:
31
+ """Get the current project ID from context, or None if not in a project."""
32
+ from gobby.utils.project_context import get_project_context
33
+
34
+ ctx = get_project_context()
35
+ if ctx and ctx.get("id"):
36
+ return str(ctx["id"])
37
+ return None
38
+
39
+
40
+ def create_memory_registry(
41
+ memory_manager: MemoryManager,
42
+ llm_service: LLMService | None = None,
43
+ ) -> InternalToolRegistry:
44
+ """
45
+ Create a memory tool registry with all memory-related tools.
46
+
47
+ Args:
48
+ memory_manager: MemoryManager instance
49
+ llm_service: LLM service for AI-powered extraction (optional)
50
+
51
+ Returns:
52
+ InternalToolRegistry with memory tools registered
53
+ """
54
+ registry = InternalToolRegistry(
55
+ name="gobby-memory",
56
+ description="Memory management - create_memory, search_memories, delete_memory, get_related_memories",
57
+ )
58
+
59
+ @registry.tool(
60
+ name="create_memory",
61
+ description="Create a new memory.",
62
+ )
63
+ async def create_memory(
64
+ content: str,
65
+ memory_type: str = "fact",
66
+ importance: float = 0.5,
67
+ tags: list[str] | None = None,
68
+ ) -> dict[str, Any]:
69
+ """
70
+ Create a new memory.
71
+
72
+ Args:
73
+ content: The memory content to store
74
+ memory_type: Type of memory (fact, preference, etc)
75
+ importance: Importance score (0.0-1.0)
76
+ tags: Optional list of tags
77
+ """
78
+ try:
79
+ memory = await memory_manager.remember(
80
+ content=content,
81
+ memory_type=memory_type,
82
+ importance=importance,
83
+ project_id=get_current_project_id(),
84
+ tags=tags,
85
+ source_type="mcp_tool",
86
+ )
87
+ return {
88
+ "success": True,
89
+ "memory": {
90
+ "id": memory.id,
91
+ },
92
+ }
93
+ except Exception as e:
94
+ return {"success": False, "error": str(e)}
95
+
96
+ @registry.tool(
97
+ name="search_memories",
98
+ description="Search memories based on query and filters. Supports tag-based filtering.",
99
+ )
100
+ def search_memories(
101
+ query: str | None = None,
102
+ limit: int = 10,
103
+ min_importance: float | None = None,
104
+ tags_all: list[str] | None = None,
105
+ tags_any: list[str] | None = None,
106
+ tags_none: list[str] | None = None,
107
+ ) -> dict[str, Any]:
108
+ """
109
+ Search memories based on query and filters.
110
+
111
+ Args:
112
+ query: Search query string
113
+ limit: Maximum number of memories to return
114
+ min_importance: Minimum importance threshold
115
+ tags_all: Memory must have ALL of these tags
116
+ tags_any: Memory must have at least ONE of these tags
117
+ tags_none: Memory must have NONE of these tags
118
+ """
119
+ try:
120
+ memories = memory_manager.recall(
121
+ query=query,
122
+ project_id=get_current_project_id(),
123
+ limit=limit,
124
+ min_importance=min_importance,
125
+ tags_all=tags_all,
126
+ tags_any=tags_any,
127
+ tags_none=tags_none,
128
+ )
129
+ return {
130
+ "success": True,
131
+ "memories": [
132
+ {
133
+ "id": m.id,
134
+ "content": m.content,
135
+ "type": m.memory_type,
136
+ "importance": m.importance,
137
+ "created_at": m.created_at,
138
+ "tags": m.tags,
139
+ "similarity": getattr(m, "similarity", None), # Might be added by search
140
+ }
141
+ for m in memories
142
+ ],
143
+ }
144
+ except Exception as e:
145
+ return {"success": False, "error": str(e)}
146
+
147
+ # Backward compatibility alias for recall_memory -> search_memories
148
+ @registry.tool(
149
+ name="recall_memory",
150
+ description="[DEPRECATED: Use search_memories] Search memories based on query.",
151
+ )
152
+ def recall_memory(
153
+ query: str | None = None,
154
+ limit: int = 10,
155
+ min_importance: float | None = None,
156
+ tags_all: list[str] | None = None,
157
+ tags_any: list[str] | None = None,
158
+ tags_none: list[str] | None = None,
159
+ ) -> dict[str, Any]:
160
+ """Deprecated alias for search_memories. Use search_memories instead."""
161
+ return search_memories( # type: ignore[no-any-return]
162
+ query=query,
163
+ limit=limit,
164
+ min_importance=min_importance,
165
+ tags_all=tags_all,
166
+ tags_any=tags_any,
167
+ tags_none=tags_none,
168
+ )
169
+
170
+ @registry.tool(
171
+ name="delete_memory",
172
+ description="Delete a memory by ID.",
173
+ )
174
+ def delete_memory(memory_id: str) -> dict[str, Any]:
175
+ """
176
+ Delete a memory by ID.
177
+
178
+ Args:
179
+ memory_id: The ID of the memory to delete
180
+ """
181
+ try:
182
+ success = memory_manager.forget(memory_id)
183
+ if success:
184
+ return {}
185
+ else:
186
+ return {"error": f"Memory {memory_id} not found"}
187
+ except Exception as e:
188
+ return {"error": str(e)}
189
+
190
+ @registry.tool(
191
+ name="list_memories",
192
+ description="List all memories with optional filtering. Supports tag-based filtering.",
193
+ )
194
+ def list_memories(
195
+ memory_type: str | None = None,
196
+ min_importance: float | None = None,
197
+ limit: int = 50,
198
+ tags_all: list[str] | None = None,
199
+ tags_any: list[str] | None = None,
200
+ tags_none: list[str] | None = None,
201
+ ) -> dict[str, Any]:
202
+ """
203
+ List all memories with optional filtering.
204
+
205
+ Args:
206
+ memory_type: Filter by memory type (fact, preference, pattern, context)
207
+ min_importance: Minimum importance threshold (0.0-1.0)
208
+ limit: Maximum number of memories to return
209
+ tags_all: Memory must have ALL of these tags
210
+ tags_any: Memory must have at least ONE of these tags
211
+ tags_none: Memory must have NONE of these tags
212
+ """
213
+ try:
214
+ memories = memory_manager.list_memories(
215
+ project_id=get_current_project_id(),
216
+ memory_type=memory_type,
217
+ min_importance=min_importance,
218
+ limit=limit,
219
+ tags_all=tags_all,
220
+ tags_any=tags_any,
221
+ tags_none=tags_none,
222
+ )
223
+ return {
224
+ "success": True,
225
+ "memories": [
226
+ {
227
+ "id": m.id,
228
+ "content": m.content,
229
+ "type": m.memory_type,
230
+ "importance": m.importance,
231
+ "created_at": m.created_at,
232
+ "tags": m.tags,
233
+ }
234
+ for m in memories
235
+ ],
236
+ "count": len(memories),
237
+ }
238
+ except Exception as e:
239
+ return {"success": False, "error": str(e)}
240
+
241
+ @registry.tool(
242
+ name="get_memory",
243
+ description="Get details of a specific memory by ID.",
244
+ )
245
+ def get_memory(memory_id: str) -> dict[str, Any]:
246
+ """
247
+ Get details of a specific memory.
248
+
249
+ Args:
250
+ memory_id: The ID of the memory to retrieve
251
+ """
252
+ try:
253
+ memory = memory_manager.get_memory(memory_id)
254
+ if memory:
255
+ return {
256
+ "success": True,
257
+ "memory": {
258
+ "id": memory.id,
259
+ "content": memory.content,
260
+ "type": memory.memory_type,
261
+ "importance": memory.importance,
262
+ "created_at": memory.created_at,
263
+ "updated_at": memory.updated_at,
264
+ "project_id": memory.project_id,
265
+ "source_type": memory.source_type,
266
+ "access_count": memory.access_count,
267
+ "tags": memory.tags,
268
+ },
269
+ }
270
+ else:
271
+ return {"success": False, "error": f"Memory {memory_id} not found"}
272
+ except ValueError as e:
273
+ return {"success": False, "error": str(e)}
274
+ except Exception as e:
275
+ return {"success": False, "error": str(e)}
276
+
277
+ @registry.tool(
278
+ name="get_related_memories",
279
+ description="Get memories related to a specific memory via cross-references.",
280
+ )
281
+ def get_related_memories(
282
+ memory_id: str,
283
+ limit: int = 5,
284
+ min_similarity: float = 0.0,
285
+ ) -> dict[str, Any]:
286
+ """
287
+ Get memories linked to a specific memory via cross-references.
288
+
289
+ Cross-references are automatically created based on semantic similarity
290
+ when memories are stored (if auto_crossref is enabled in config).
291
+
292
+ Args:
293
+ memory_id: The ID of the memory to find related memories for
294
+ limit: Maximum number of related memories to return
295
+ min_similarity: Minimum similarity threshold (0.0-1.0)
296
+ """
297
+ try:
298
+ memories = memory_manager.get_related(
299
+ memory_id=memory_id,
300
+ limit=limit,
301
+ min_similarity=min_similarity,
302
+ )
303
+ return {
304
+ "success": True,
305
+ "memory_id": memory_id,
306
+ "related": [
307
+ {
308
+ "id": m.id,
309
+ "content": m.content,
310
+ "type": m.memory_type,
311
+ "importance": m.importance,
312
+ "created_at": m.created_at,
313
+ "tags": m.tags,
314
+ }
315
+ for m in memories
316
+ ],
317
+ "count": len(memories),
318
+ }
319
+ except ValueError as e:
320
+ return {"success": False, "error": str(e)}
321
+ except Exception as e:
322
+ return {"success": False, "error": str(e)}
323
+
324
+ @registry.tool(
325
+ name="update_memory",
326
+ description="Update an existing memory's content, importance, or tags.",
327
+ )
328
+ def update_memory(
329
+ memory_id: str,
330
+ content: str | None = None,
331
+ importance: float | None = None,
332
+ tags: list[str] | None = None,
333
+ ) -> dict[str, Any]:
334
+ """
335
+ Update an existing memory.
336
+
337
+ Args:
338
+ memory_id: The ID of the memory to update
339
+ content: New content (optional)
340
+ importance: New importance score 0.0-1.0 (optional)
341
+ tags: New list of tags (optional)
342
+ """
343
+ try:
344
+ memory = memory_manager.update_memory(
345
+ memory_id=memory_id,
346
+ content=content,
347
+ importance=importance,
348
+ tags=tags,
349
+ )
350
+ return {
351
+ "success": True,
352
+ "memory": {
353
+ "id": memory.id,
354
+ "updated_at": memory.updated_at,
355
+ },
356
+ }
357
+ except ValueError as e:
358
+ return {"success": False, "error": str(e)}
359
+ except Exception as e:
360
+ return {"success": False, "error": str(e)}
361
+
362
+ @registry.tool(
363
+ name="remember_with_image",
364
+ description="Create a memory from an image. Uses LLM to describe the image and stores it with the description.",
365
+ )
366
+ async def remember_with_image(
367
+ image_path: str,
368
+ context: str | None = None,
369
+ memory_type: str = "fact",
370
+ importance: float = 0.5,
371
+ tags: list[str] | None = None,
372
+ ) -> dict[str, Any]:
373
+ """
374
+ Create a memory from an image file.
375
+
376
+ Uses the configured LLM provider to generate a description of the image,
377
+ then stores the memory with the description as content and the image
378
+ as a media attachment.
379
+
380
+ Args:
381
+ image_path: Path to the image file
382
+ context: Optional context to guide the image description (e.g., "This is a screenshot of an error")
383
+ memory_type: Type of memory (fact, preference, etc)
384
+ importance: Importance score (0.0-1.0)
385
+ tags: Optional list of tags
386
+ """
387
+ if not llm_service:
388
+ return {
389
+ "success": False,
390
+ "error": "LLM service not configured. Image memories require an LLM provider.",
391
+ }
392
+
393
+ try:
394
+ memory = await memory_manager.remember_with_image(
395
+ image_path=image_path,
396
+ context=context,
397
+ memory_type=memory_type,
398
+ importance=importance,
399
+ project_id=get_current_project_id(),
400
+ tags=tags,
401
+ source_type="mcp_tool",
402
+ )
403
+ return {
404
+ "success": True,
405
+ "memory": {
406
+ "id": memory.id,
407
+ "content": memory.content,
408
+ "media_path": image_path,
409
+ },
410
+ }
411
+ except ValueError as e:
412
+ return {"success": False, "error": str(e)}
413
+ except Exception as e:
414
+ return {"success": False, "error": str(e)}
415
+
416
+ @registry.tool(
417
+ name="remember_screenshot",
418
+ description="Create a memory from raw screenshot bytes (base64 encoded). Saves to .gobby/resources/ and describes with LLM.",
419
+ )
420
+ async def remember_screenshot(
421
+ screenshot_base64: str,
422
+ context: str | None = None,
423
+ memory_type: str = "observation",
424
+ importance: float = 0.5,
425
+ tags: list[str] | None = None,
426
+ ) -> dict[str, Any]:
427
+ """
428
+ Create a memory from raw screenshot bytes.
429
+
430
+ Saves the screenshot to .gobby/resources/ with a timestamp-based filename,
431
+ uses LLM to describe it, and stores the memory with the description.
432
+
433
+ Args:
434
+ screenshot_base64: Base64-encoded PNG screenshot bytes
435
+ context: Optional context to guide the image description
436
+ memory_type: Type of memory (default: "observation")
437
+ importance: Importance score (0.0-1.0)
438
+ tags: Optional list of tags
439
+ """
440
+ import base64
441
+
442
+ if not llm_service:
443
+ return {
444
+ "success": False,
445
+ "error": "LLM service not configured. Screenshot memories require an LLM provider.",
446
+ }
447
+
448
+ try:
449
+ # Decode base64 to bytes
450
+ screenshot_bytes = base64.b64decode(screenshot_base64)
451
+
452
+ memory = await memory_manager.remember_screenshot(
453
+ screenshot_bytes=screenshot_bytes,
454
+ context=context,
455
+ memory_type=memory_type,
456
+ importance=importance,
457
+ project_id=get_current_project_id(),
458
+ tags=tags,
459
+ source_type="mcp_tool",
460
+ )
461
+ return {
462
+ "success": True,
463
+ "memory": {
464
+ "id": memory.id,
465
+ "content": memory.content,
466
+ },
467
+ }
468
+ except ValueError as e:
469
+ return {"success": False, "error": str(e)}
470
+ except Exception as e:
471
+ return {"success": False, "error": str(e)}
472
+
473
+ @registry.tool(
474
+ name="memory_stats",
475
+ description="Get statistics about the memory system.",
476
+ )
477
+ def memory_stats() -> dict[str, Any]:
478
+ """
479
+ Get statistics about stored memories.
480
+ """
481
+ try:
482
+ stats = memory_manager.get_stats(project_id=get_current_project_id())
483
+ return {"stats": stats}
484
+ except Exception as e:
485
+ return {"error": str(e)}
486
+
487
+ @registry.tool(
488
+ name="export_memory_graph",
489
+ description="Export memories as an interactive HTML knowledge graph.",
490
+ )
491
+ def export_memory_graph_tool(
492
+ title: str = "Memory Knowledge Graph",
493
+ output_path: str | None = None,
494
+ ) -> dict[str, Any]:
495
+ """
496
+ Export memories as an interactive knowledge graph using vis.js.
497
+
498
+ Creates a standalone HTML file with visualization showing
499
+ memories as nodes (colored by type, sized by importance)
500
+ and cross-references as edges.
501
+
502
+ Args:
503
+ title: Title for the graph visualization
504
+ output_path: Optional file path to write the HTML (default: memory_graph.html)
505
+
506
+ Returns:
507
+ Success status and path where graph was written
508
+ """
509
+ from pathlib import Path
510
+
511
+ from gobby.memory.viz import export_memory_graph
512
+ from gobby.storage.memories import LocalMemoryManager
513
+
514
+ try:
515
+ # Get all memories
516
+ project_id = get_current_project_id()
517
+ memories = memory_manager.list_memories(project_id=project_id, limit=1000)
518
+ if not memories:
519
+ return {"success": False, "error": "No memories found"}
520
+
521
+ # Get cross-references
522
+ storage = LocalMemoryManager(memory_manager.db)
523
+ crossrefs = storage.get_all_crossrefs(project_id=project_id, limit=5000)
524
+
525
+ # Generate HTML
526
+ html_content = export_memory_graph(memories, crossrefs, title=title)
527
+
528
+ # Write to file
529
+ if output_path is None:
530
+ output_path = "memory_graph.html"
531
+ output_file = Path(output_path)
532
+ output_file.write_text(html_content)
533
+
534
+ return {
535
+ "success": True,
536
+ "path": str(output_file.absolute()),
537
+ "memory_count": len(memories),
538
+ "crossref_count": len(crossrefs),
539
+ }
540
+ except Exception as e:
541
+ return {"success": False, "error": str(e)}
542
+
543
+ return registry