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.
- gobby/__init__.py +3 -0
- gobby/adapters/__init__.py +30 -0
- gobby/adapters/base.py +93 -0
- gobby/adapters/claude_code.py +276 -0
- gobby/adapters/codex.py +1292 -0
- gobby/adapters/gemini.py +343 -0
- gobby/agents/__init__.py +37 -0
- gobby/agents/codex_session.py +120 -0
- gobby/agents/constants.py +112 -0
- gobby/agents/context.py +362 -0
- gobby/agents/definitions.py +133 -0
- gobby/agents/gemini_session.py +111 -0
- gobby/agents/registry.py +618 -0
- gobby/agents/runner.py +968 -0
- gobby/agents/session.py +259 -0
- gobby/agents/spawn.py +916 -0
- gobby/agents/spawners/__init__.py +77 -0
- gobby/agents/spawners/base.py +142 -0
- gobby/agents/spawners/cross_platform.py +266 -0
- gobby/agents/spawners/embedded.py +225 -0
- gobby/agents/spawners/headless.py +226 -0
- gobby/agents/spawners/linux.py +125 -0
- gobby/agents/spawners/macos.py +277 -0
- gobby/agents/spawners/windows.py +308 -0
- gobby/agents/tty_config.py +319 -0
- gobby/autonomous/__init__.py +32 -0
- gobby/autonomous/progress_tracker.py +447 -0
- gobby/autonomous/stop_registry.py +269 -0
- gobby/autonomous/stuck_detector.py +383 -0
- gobby/cli/__init__.py +67 -0
- gobby/cli/__main__.py +8 -0
- gobby/cli/agents.py +529 -0
- gobby/cli/artifacts.py +266 -0
- gobby/cli/daemon.py +329 -0
- gobby/cli/extensions.py +526 -0
- gobby/cli/github.py +263 -0
- gobby/cli/init.py +53 -0
- gobby/cli/install.py +614 -0
- gobby/cli/installers/__init__.py +37 -0
- gobby/cli/installers/antigravity.py +65 -0
- gobby/cli/installers/claude.py +363 -0
- gobby/cli/installers/codex.py +192 -0
- gobby/cli/installers/gemini.py +294 -0
- gobby/cli/installers/git_hooks.py +377 -0
- gobby/cli/installers/shared.py +737 -0
- gobby/cli/linear.py +250 -0
- gobby/cli/mcp.py +30 -0
- gobby/cli/mcp_proxy.py +698 -0
- gobby/cli/memory.py +304 -0
- gobby/cli/merge.py +384 -0
- gobby/cli/projects.py +79 -0
- gobby/cli/sessions.py +622 -0
- gobby/cli/tasks/__init__.py +30 -0
- gobby/cli/tasks/_utils.py +658 -0
- gobby/cli/tasks/ai.py +1025 -0
- gobby/cli/tasks/commits.py +169 -0
- gobby/cli/tasks/crud.py +685 -0
- gobby/cli/tasks/deps.py +135 -0
- gobby/cli/tasks/labels.py +63 -0
- gobby/cli/tasks/main.py +273 -0
- gobby/cli/tasks/search.py +178 -0
- gobby/cli/tui.py +34 -0
- gobby/cli/utils.py +513 -0
- gobby/cli/workflows.py +927 -0
- gobby/cli/worktrees.py +481 -0
- gobby/config/__init__.py +129 -0
- gobby/config/app.py +551 -0
- gobby/config/extensions.py +167 -0
- gobby/config/features.py +472 -0
- gobby/config/llm_providers.py +98 -0
- gobby/config/logging.py +66 -0
- gobby/config/mcp.py +346 -0
- gobby/config/persistence.py +247 -0
- gobby/config/servers.py +141 -0
- gobby/config/sessions.py +250 -0
- gobby/config/tasks.py +784 -0
- gobby/hooks/__init__.py +104 -0
- gobby/hooks/artifact_capture.py +213 -0
- gobby/hooks/broadcaster.py +243 -0
- gobby/hooks/event_handlers.py +723 -0
- gobby/hooks/events.py +218 -0
- gobby/hooks/git.py +169 -0
- gobby/hooks/health_monitor.py +171 -0
- gobby/hooks/hook_manager.py +856 -0
- gobby/hooks/hook_types.py +575 -0
- gobby/hooks/plugins.py +813 -0
- gobby/hooks/session_coordinator.py +396 -0
- gobby/hooks/verification_runner.py +268 -0
- gobby/hooks/webhooks.py +339 -0
- gobby/install/claude/commands/gobby/bug.md +51 -0
- gobby/install/claude/commands/gobby/chore.md +51 -0
- gobby/install/claude/commands/gobby/epic.md +52 -0
- gobby/install/claude/commands/gobby/eval.md +235 -0
- gobby/install/claude/commands/gobby/feat.md +49 -0
- gobby/install/claude/commands/gobby/nit.md +52 -0
- gobby/install/claude/commands/gobby/ref.md +52 -0
- gobby/install/claude/hooks/HOOK_SCHEMAS.md +632 -0
- gobby/install/claude/hooks/hook_dispatcher.py +364 -0
- gobby/install/claude/hooks/validate_settings.py +102 -0
- gobby/install/claude/hooks-template.json +118 -0
- gobby/install/codex/hooks/hook_dispatcher.py +153 -0
- gobby/install/codex/prompts/forget.md +7 -0
- gobby/install/codex/prompts/memories.md +7 -0
- gobby/install/codex/prompts/recall.md +7 -0
- gobby/install/codex/prompts/remember.md +13 -0
- gobby/install/gemini/hooks/hook_dispatcher.py +268 -0
- gobby/install/gemini/hooks-template.json +138 -0
- gobby/install/shared/plugins/code_guardian.py +456 -0
- gobby/install/shared/plugins/example_notify.py +331 -0
- gobby/integrations/__init__.py +10 -0
- gobby/integrations/github.py +145 -0
- gobby/integrations/linear.py +145 -0
- gobby/llm/__init__.py +40 -0
- gobby/llm/base.py +120 -0
- gobby/llm/claude.py +578 -0
- gobby/llm/claude_executor.py +503 -0
- gobby/llm/codex.py +322 -0
- gobby/llm/codex_executor.py +513 -0
- gobby/llm/executor.py +316 -0
- gobby/llm/factory.py +34 -0
- gobby/llm/gemini.py +258 -0
- gobby/llm/gemini_executor.py +339 -0
- gobby/llm/litellm.py +287 -0
- gobby/llm/litellm_executor.py +303 -0
- gobby/llm/resolver.py +499 -0
- gobby/llm/service.py +236 -0
- gobby/mcp_proxy/__init__.py +29 -0
- gobby/mcp_proxy/actions.py +175 -0
- gobby/mcp_proxy/daemon_control.py +198 -0
- gobby/mcp_proxy/importer.py +436 -0
- gobby/mcp_proxy/lazy.py +325 -0
- gobby/mcp_proxy/manager.py +798 -0
- gobby/mcp_proxy/metrics.py +609 -0
- gobby/mcp_proxy/models.py +139 -0
- gobby/mcp_proxy/registries.py +215 -0
- gobby/mcp_proxy/schema_hash.py +381 -0
- gobby/mcp_proxy/semantic_search.py +706 -0
- gobby/mcp_proxy/server.py +549 -0
- gobby/mcp_proxy/services/__init__.py +0 -0
- gobby/mcp_proxy/services/fallback.py +306 -0
- gobby/mcp_proxy/services/recommendation.py +224 -0
- gobby/mcp_proxy/services/server_mgmt.py +214 -0
- gobby/mcp_proxy/services/system.py +72 -0
- gobby/mcp_proxy/services/tool_filter.py +231 -0
- gobby/mcp_proxy/services/tool_proxy.py +309 -0
- gobby/mcp_proxy/stdio.py +565 -0
- gobby/mcp_proxy/tools/__init__.py +27 -0
- gobby/mcp_proxy/tools/agents.py +1103 -0
- gobby/mcp_proxy/tools/artifacts.py +207 -0
- gobby/mcp_proxy/tools/hub.py +335 -0
- gobby/mcp_proxy/tools/internal.py +337 -0
- gobby/mcp_proxy/tools/memory.py +543 -0
- gobby/mcp_proxy/tools/merge.py +422 -0
- gobby/mcp_proxy/tools/metrics.py +283 -0
- gobby/mcp_proxy/tools/orchestration/__init__.py +23 -0
- gobby/mcp_proxy/tools/orchestration/cleanup.py +619 -0
- gobby/mcp_proxy/tools/orchestration/monitor.py +380 -0
- gobby/mcp_proxy/tools/orchestration/orchestrate.py +746 -0
- gobby/mcp_proxy/tools/orchestration/review.py +736 -0
- gobby/mcp_proxy/tools/orchestration/utils.py +16 -0
- gobby/mcp_proxy/tools/session_messages.py +1056 -0
- gobby/mcp_proxy/tools/task_dependencies.py +219 -0
- gobby/mcp_proxy/tools/task_expansion.py +591 -0
- gobby/mcp_proxy/tools/task_github.py +393 -0
- gobby/mcp_proxy/tools/task_linear.py +379 -0
- gobby/mcp_proxy/tools/task_orchestration.py +77 -0
- gobby/mcp_proxy/tools/task_readiness.py +522 -0
- gobby/mcp_proxy/tools/task_sync.py +351 -0
- gobby/mcp_proxy/tools/task_validation.py +843 -0
- gobby/mcp_proxy/tools/tasks/__init__.py +25 -0
- gobby/mcp_proxy/tools/tasks/_context.py +112 -0
- gobby/mcp_proxy/tools/tasks/_crud.py +516 -0
- gobby/mcp_proxy/tools/tasks/_factory.py +176 -0
- gobby/mcp_proxy/tools/tasks/_helpers.py +129 -0
- gobby/mcp_proxy/tools/tasks/_lifecycle.py +517 -0
- gobby/mcp_proxy/tools/tasks/_lifecycle_validation.py +301 -0
- gobby/mcp_proxy/tools/tasks/_resolution.py +55 -0
- gobby/mcp_proxy/tools/tasks/_search.py +215 -0
- gobby/mcp_proxy/tools/tasks/_session.py +125 -0
- gobby/mcp_proxy/tools/workflows.py +973 -0
- gobby/mcp_proxy/tools/worktrees.py +1264 -0
- gobby/mcp_proxy/transports/__init__.py +0 -0
- gobby/mcp_proxy/transports/base.py +95 -0
- gobby/mcp_proxy/transports/factory.py +44 -0
- gobby/mcp_proxy/transports/http.py +139 -0
- gobby/mcp_proxy/transports/stdio.py +213 -0
- gobby/mcp_proxy/transports/websocket.py +136 -0
- gobby/memory/backends/__init__.py +116 -0
- gobby/memory/backends/mem0.py +408 -0
- gobby/memory/backends/memu.py +485 -0
- gobby/memory/backends/null.py +111 -0
- gobby/memory/backends/openmemory.py +537 -0
- gobby/memory/backends/sqlite.py +304 -0
- gobby/memory/context.py +87 -0
- gobby/memory/manager.py +1001 -0
- gobby/memory/protocol.py +451 -0
- gobby/memory/search/__init__.py +66 -0
- gobby/memory/search/text.py +127 -0
- gobby/memory/viz.py +258 -0
- gobby/prompts/__init__.py +13 -0
- gobby/prompts/defaults/expansion/system.md +119 -0
- gobby/prompts/defaults/expansion/user.md +48 -0
- gobby/prompts/defaults/external_validation/agent.md +72 -0
- gobby/prompts/defaults/external_validation/external.md +63 -0
- gobby/prompts/defaults/external_validation/spawn.md +83 -0
- gobby/prompts/defaults/external_validation/system.md +6 -0
- gobby/prompts/defaults/features/import_mcp.md +22 -0
- gobby/prompts/defaults/features/import_mcp_github.md +17 -0
- gobby/prompts/defaults/features/import_mcp_search.md +16 -0
- gobby/prompts/defaults/features/recommend_tools.md +32 -0
- gobby/prompts/defaults/features/recommend_tools_hybrid.md +35 -0
- gobby/prompts/defaults/features/recommend_tools_llm.md +30 -0
- gobby/prompts/defaults/features/server_description.md +20 -0
- gobby/prompts/defaults/features/server_description_system.md +6 -0
- gobby/prompts/defaults/features/task_description.md +31 -0
- gobby/prompts/defaults/features/task_description_system.md +6 -0
- gobby/prompts/defaults/features/tool_summary.md +17 -0
- gobby/prompts/defaults/features/tool_summary_system.md +6 -0
- gobby/prompts/defaults/research/step.md +58 -0
- gobby/prompts/defaults/validation/criteria.md +47 -0
- gobby/prompts/defaults/validation/validate.md +38 -0
- gobby/prompts/loader.py +346 -0
- gobby/prompts/models.py +113 -0
- gobby/py.typed +0 -0
- gobby/runner.py +488 -0
- gobby/search/__init__.py +23 -0
- gobby/search/protocol.py +104 -0
- gobby/search/tfidf.py +232 -0
- gobby/servers/__init__.py +7 -0
- gobby/servers/http.py +636 -0
- gobby/servers/models.py +31 -0
- gobby/servers/routes/__init__.py +23 -0
- gobby/servers/routes/admin.py +416 -0
- gobby/servers/routes/dependencies.py +118 -0
- gobby/servers/routes/mcp/__init__.py +24 -0
- gobby/servers/routes/mcp/hooks.py +135 -0
- gobby/servers/routes/mcp/plugins.py +121 -0
- gobby/servers/routes/mcp/tools.py +1337 -0
- gobby/servers/routes/mcp/webhooks.py +159 -0
- gobby/servers/routes/sessions.py +582 -0
- gobby/servers/websocket.py +766 -0
- gobby/sessions/__init__.py +13 -0
- gobby/sessions/analyzer.py +322 -0
- gobby/sessions/lifecycle.py +240 -0
- gobby/sessions/manager.py +563 -0
- gobby/sessions/processor.py +225 -0
- gobby/sessions/summary.py +532 -0
- gobby/sessions/transcripts/__init__.py +41 -0
- gobby/sessions/transcripts/base.py +125 -0
- gobby/sessions/transcripts/claude.py +386 -0
- gobby/sessions/transcripts/codex.py +143 -0
- gobby/sessions/transcripts/gemini.py +195 -0
- gobby/storage/__init__.py +21 -0
- gobby/storage/agents.py +409 -0
- gobby/storage/artifact_classifier.py +341 -0
- gobby/storage/artifacts.py +285 -0
- gobby/storage/compaction.py +67 -0
- gobby/storage/database.py +357 -0
- gobby/storage/inter_session_messages.py +194 -0
- gobby/storage/mcp.py +680 -0
- gobby/storage/memories.py +562 -0
- gobby/storage/merge_resolutions.py +550 -0
- gobby/storage/migrations.py +860 -0
- gobby/storage/migrations_legacy.py +1359 -0
- gobby/storage/projects.py +166 -0
- gobby/storage/session_messages.py +251 -0
- gobby/storage/session_tasks.py +97 -0
- gobby/storage/sessions.py +817 -0
- gobby/storage/task_dependencies.py +223 -0
- gobby/storage/tasks/__init__.py +42 -0
- gobby/storage/tasks/_aggregates.py +180 -0
- gobby/storage/tasks/_crud.py +449 -0
- gobby/storage/tasks/_id.py +104 -0
- gobby/storage/tasks/_lifecycle.py +311 -0
- gobby/storage/tasks/_manager.py +889 -0
- gobby/storage/tasks/_models.py +300 -0
- gobby/storage/tasks/_ordering.py +119 -0
- gobby/storage/tasks/_path_cache.py +110 -0
- gobby/storage/tasks/_queries.py +343 -0
- gobby/storage/tasks/_search.py +143 -0
- gobby/storage/workflow_audit.py +393 -0
- gobby/storage/worktrees.py +547 -0
- gobby/sync/__init__.py +29 -0
- gobby/sync/github.py +333 -0
- gobby/sync/linear.py +304 -0
- gobby/sync/memories.py +284 -0
- gobby/sync/tasks.py +641 -0
- gobby/tasks/__init__.py +8 -0
- gobby/tasks/build_verification.py +193 -0
- gobby/tasks/commits.py +633 -0
- gobby/tasks/context.py +747 -0
- gobby/tasks/criteria.py +342 -0
- gobby/tasks/enhanced_validator.py +226 -0
- gobby/tasks/escalation.py +263 -0
- gobby/tasks/expansion.py +626 -0
- gobby/tasks/external_validator.py +764 -0
- gobby/tasks/issue_extraction.py +171 -0
- gobby/tasks/prompts/expand.py +327 -0
- gobby/tasks/research.py +421 -0
- gobby/tasks/tdd.py +352 -0
- gobby/tasks/tree_builder.py +263 -0
- gobby/tasks/validation.py +712 -0
- gobby/tasks/validation_history.py +357 -0
- gobby/tasks/validation_models.py +89 -0
- gobby/tools/__init__.py +0 -0
- gobby/tools/summarizer.py +170 -0
- gobby/tui/__init__.py +5 -0
- gobby/tui/api_client.py +281 -0
- gobby/tui/app.py +327 -0
- gobby/tui/screens/__init__.py +25 -0
- gobby/tui/screens/agents.py +333 -0
- gobby/tui/screens/chat.py +450 -0
- gobby/tui/screens/dashboard.py +377 -0
- gobby/tui/screens/memory.py +305 -0
- gobby/tui/screens/metrics.py +231 -0
- gobby/tui/screens/orchestrator.py +904 -0
- gobby/tui/screens/sessions.py +412 -0
- gobby/tui/screens/tasks.py +442 -0
- gobby/tui/screens/workflows.py +289 -0
- gobby/tui/screens/worktrees.py +174 -0
- gobby/tui/widgets/__init__.py +21 -0
- gobby/tui/widgets/chat.py +210 -0
- gobby/tui/widgets/conductor.py +104 -0
- gobby/tui/widgets/menu.py +132 -0
- gobby/tui/widgets/message_panel.py +160 -0
- gobby/tui/widgets/review_gate.py +224 -0
- gobby/tui/widgets/task_tree.py +99 -0
- gobby/tui/widgets/token_budget.py +166 -0
- gobby/tui/ws_client.py +258 -0
- gobby/utils/__init__.py +3 -0
- gobby/utils/daemon_client.py +235 -0
- gobby/utils/git.py +222 -0
- gobby/utils/id.py +38 -0
- gobby/utils/json_helpers.py +161 -0
- gobby/utils/logging.py +376 -0
- gobby/utils/machine_id.py +135 -0
- gobby/utils/metrics.py +589 -0
- gobby/utils/project_context.py +182 -0
- gobby/utils/project_init.py +263 -0
- gobby/utils/status.py +256 -0
- gobby/utils/validation.py +80 -0
- gobby/utils/version.py +23 -0
- gobby/workflows/__init__.py +4 -0
- gobby/workflows/actions.py +1310 -0
- gobby/workflows/approval_flow.py +138 -0
- gobby/workflows/artifact_actions.py +103 -0
- gobby/workflows/audit_helpers.py +110 -0
- gobby/workflows/autonomous_actions.py +286 -0
- gobby/workflows/context_actions.py +394 -0
- gobby/workflows/definitions.py +130 -0
- gobby/workflows/detection_helpers.py +208 -0
- gobby/workflows/engine.py +485 -0
- gobby/workflows/evaluator.py +669 -0
- gobby/workflows/git_utils.py +96 -0
- gobby/workflows/hooks.py +169 -0
- gobby/workflows/lifecycle_evaluator.py +613 -0
- gobby/workflows/llm_actions.py +70 -0
- gobby/workflows/loader.py +333 -0
- gobby/workflows/mcp_actions.py +60 -0
- gobby/workflows/memory_actions.py +272 -0
- gobby/workflows/premature_stop.py +164 -0
- gobby/workflows/session_actions.py +139 -0
- gobby/workflows/state_actions.py +123 -0
- gobby/workflows/state_manager.py +104 -0
- gobby/workflows/stop_signal_actions.py +163 -0
- gobby/workflows/summary_actions.py +344 -0
- gobby/workflows/task_actions.py +249 -0
- gobby/workflows/task_enforcement_actions.py +901 -0
- gobby/workflows/templates.py +52 -0
- gobby/workflows/todo_actions.py +84 -0
- gobby/workflows/webhook.py +223 -0
- gobby/workflows/webhook_executor.py +399 -0
- gobby/worktrees/__init__.py +5 -0
- gobby/worktrees/git.py +690 -0
- gobby/worktrees/merge/__init__.py +20 -0
- gobby/worktrees/merge/conflict_parser.py +177 -0
- gobby/worktrees/merge/resolver.py +485 -0
- gobby-0.2.5.dist-info/METADATA +351 -0
- gobby-0.2.5.dist-info/RECORD +383 -0
- gobby-0.2.5.dist-info/WHEEL +5 -0
- gobby-0.2.5.dist-info/entry_points.txt +2 -0
- gobby-0.2.5.dist-info/licenses/LICENSE.md +193 -0
- 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
|