gobby 0.2.6__py3-none-any.whl → 0.2.7__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 +1 -1
- gobby/adapters/__init__.py +2 -1
- gobby/adapters/codex_impl/__init__.py +28 -0
- gobby/adapters/codex_impl/adapter.py +722 -0
- gobby/adapters/codex_impl/client.py +679 -0
- gobby/adapters/codex_impl/protocol.py +20 -0
- gobby/adapters/codex_impl/types.py +68 -0
- gobby/agents/definitions.py +11 -1
- gobby/agents/isolation.py +395 -0
- gobby/agents/sandbox.py +261 -0
- gobby/agents/spawn.py +42 -287
- gobby/agents/spawn_executor.py +385 -0
- gobby/agents/spawners/__init__.py +24 -0
- gobby/agents/spawners/command_builder.py +189 -0
- gobby/agents/spawners/embedded.py +21 -2
- gobby/agents/spawners/headless.py +21 -2
- gobby/agents/spawners/prompt_manager.py +125 -0
- gobby/cli/install.py +4 -4
- gobby/cli/installers/claude.py +6 -0
- gobby/cli/installers/gemini.py +6 -0
- gobby/cli/installers/shared.py +103 -4
- gobby/cli/sessions.py +1 -1
- gobby/cli/utils.py +9 -2
- gobby/config/__init__.py +12 -97
- gobby/config/app.py +10 -94
- gobby/config/extensions.py +2 -2
- gobby/config/features.py +7 -130
- gobby/config/tasks.py +4 -28
- gobby/hooks/__init__.py +0 -13
- gobby/hooks/event_handlers.py +45 -2
- gobby/hooks/hook_manager.py +2 -2
- gobby/hooks/plugins.py +1 -1
- gobby/hooks/webhooks.py +1 -1
- gobby/llm/resolver.py +3 -2
- gobby/mcp_proxy/importer.py +62 -4
- gobby/mcp_proxy/instructions.py +2 -0
- gobby/mcp_proxy/registries.py +1 -4
- gobby/mcp_proxy/services/recommendation.py +43 -11
- gobby/mcp_proxy/tools/agents.py +31 -731
- gobby/mcp_proxy/tools/clones.py +0 -385
- gobby/mcp_proxy/tools/memory.py +2 -2
- gobby/mcp_proxy/tools/sessions/__init__.py +14 -0
- gobby/mcp_proxy/tools/sessions/_commits.py +232 -0
- gobby/mcp_proxy/tools/sessions/_crud.py +253 -0
- gobby/mcp_proxy/tools/sessions/_factory.py +63 -0
- gobby/mcp_proxy/tools/sessions/_handoff.py +499 -0
- gobby/mcp_proxy/tools/sessions/_messages.py +138 -0
- gobby/mcp_proxy/tools/skills/__init__.py +14 -29
- gobby/mcp_proxy/tools/spawn_agent.py +417 -0
- gobby/mcp_proxy/tools/tasks/_lifecycle.py +52 -18
- gobby/mcp_proxy/tools/tasks/_lifecycle_validation.py +1 -1
- gobby/mcp_proxy/tools/worktrees.py +0 -343
- gobby/memory/ingestion/__init__.py +5 -0
- gobby/memory/ingestion/multimodal.py +221 -0
- gobby/memory/manager.py +62 -283
- gobby/memory/search/__init__.py +10 -0
- gobby/memory/search/coordinator.py +248 -0
- gobby/memory/services/__init__.py +5 -0
- gobby/memory/services/crossref.py +142 -0
- gobby/prompts/loader.py +5 -2
- gobby/servers/http.py +1 -4
- gobby/servers/routes/admin.py +14 -0
- gobby/servers/routes/mcp/endpoints/__init__.py +61 -0
- gobby/servers/routes/mcp/endpoints/discovery.py +405 -0
- gobby/servers/routes/mcp/endpoints/execution.py +568 -0
- gobby/servers/routes/mcp/endpoints/registry.py +378 -0
- gobby/servers/routes/mcp/endpoints/server.py +304 -0
- gobby/servers/routes/mcp/hooks.py +1 -1
- gobby/servers/routes/mcp/tools.py +48 -1506
- gobby/sessions/lifecycle.py +1 -1
- gobby/sessions/processor.py +10 -0
- gobby/sessions/transcripts/base.py +1 -0
- gobby/sessions/transcripts/claude.py +15 -5
- gobby/skills/parser.py +30 -2
- gobby/storage/migrations.py +159 -372
- gobby/storage/sessions.py +43 -7
- gobby/storage/skills.py +37 -4
- gobby/storage/tasks/_lifecycle.py +18 -3
- gobby/sync/memories.py +1 -1
- gobby/tasks/external_validator.py +1 -1
- gobby/tasks/validation.py +22 -20
- gobby/tools/summarizer.py +91 -10
- gobby/utils/project_context.py +2 -3
- gobby/utils/status.py +13 -0
- gobby/workflows/actions.py +221 -1217
- gobby/workflows/artifact_actions.py +31 -0
- gobby/workflows/autonomous_actions.py +11 -0
- gobby/workflows/context_actions.py +50 -1
- gobby/workflows/enforcement/__init__.py +47 -0
- gobby/workflows/enforcement/blocking.py +269 -0
- gobby/workflows/enforcement/commit_policy.py +283 -0
- gobby/workflows/enforcement/handlers.py +269 -0
- gobby/workflows/enforcement/task_policy.py +542 -0
- gobby/workflows/git_utils.py +106 -0
- gobby/workflows/llm_actions.py +30 -0
- gobby/workflows/mcp_actions.py +20 -1
- gobby/workflows/memory_actions.py +80 -0
- gobby/workflows/safe_evaluator.py +183 -0
- gobby/workflows/session_actions.py +44 -0
- gobby/workflows/state_actions.py +60 -1
- gobby/workflows/stop_signal_actions.py +55 -0
- gobby/workflows/summary_actions.py +94 -1
- gobby/workflows/task_sync_actions.py +347 -0
- gobby/workflows/todo_actions.py +34 -1
- gobby/workflows/webhook_actions.py +185 -0
- {gobby-0.2.6.dist-info → gobby-0.2.7.dist-info}/METADATA +6 -1
- {gobby-0.2.6.dist-info → gobby-0.2.7.dist-info}/RECORD +111 -111
- {gobby-0.2.6.dist-info → gobby-0.2.7.dist-info}/WHEEL +1 -1
- gobby/adapters/codex.py +0 -1332
- gobby/install/claude/commands/gobby/bug.md +0 -51
- gobby/install/claude/commands/gobby/chore.md +0 -51
- gobby/install/claude/commands/gobby/epic.md +0 -52
- gobby/install/claude/commands/gobby/eval.md +0 -235
- gobby/install/claude/commands/gobby/feat.md +0 -49
- gobby/install/claude/commands/gobby/nit.md +0 -52
- gobby/install/claude/commands/gobby/ref.md +0 -52
- gobby/mcp_proxy/tools/session_messages.py +0 -1055
- gobby/prompts/defaults/expansion/system.md +0 -119
- gobby/prompts/defaults/expansion/user.md +0 -48
- gobby/prompts/defaults/external_validation/agent.md +0 -72
- gobby/prompts/defaults/external_validation/external.md +0 -63
- gobby/prompts/defaults/external_validation/spawn.md +0 -83
- gobby/prompts/defaults/external_validation/system.md +0 -6
- gobby/prompts/defaults/features/import_mcp.md +0 -22
- gobby/prompts/defaults/features/import_mcp_github.md +0 -17
- gobby/prompts/defaults/features/import_mcp_search.md +0 -16
- gobby/prompts/defaults/features/recommend_tools.md +0 -32
- gobby/prompts/defaults/features/recommend_tools_hybrid.md +0 -35
- gobby/prompts/defaults/features/recommend_tools_llm.md +0 -30
- gobby/prompts/defaults/features/server_description.md +0 -20
- gobby/prompts/defaults/features/server_description_system.md +0 -6
- gobby/prompts/defaults/features/task_description.md +0 -31
- gobby/prompts/defaults/features/task_description_system.md +0 -6
- gobby/prompts/defaults/features/tool_summary.md +0 -17
- gobby/prompts/defaults/features/tool_summary_system.md +0 -6
- gobby/prompts/defaults/handoff/compact.md +0 -63
- gobby/prompts/defaults/handoff/session_end.md +0 -57
- gobby/prompts/defaults/memory/extract.md +0 -61
- gobby/prompts/defaults/research/step.md +0 -58
- gobby/prompts/defaults/validation/criteria.md +0 -47
- gobby/prompts/defaults/validation/validate.md +0 -38
- gobby/storage/migrations_legacy.py +0 -1359
- gobby/workflows/task_enforcement_actions.py +0 -1343
- {gobby-0.2.6.dist-info → gobby-0.2.7.dist-info}/entry_points.txt +0 -0
- {gobby-0.2.6.dist-info → gobby-0.2.7.dist-info}/licenses/LICENSE.md +0 -0
- {gobby-0.2.6.dist-info → gobby-0.2.7.dist-info}/top_level.txt +0 -0
gobby/mcp_proxy/importer.py
CHANGED
|
@@ -5,6 +5,8 @@ import re
|
|
|
5
5
|
from typing import TYPE_CHECKING, Any
|
|
6
6
|
|
|
7
7
|
from gobby.config.app import DaemonConfig
|
|
8
|
+
from gobby.config.features import DEFAULT_IMPORT_MCP_SERVER_PROMPT
|
|
9
|
+
from gobby.prompts import PromptLoader
|
|
8
10
|
from gobby.storage.database import DatabaseProtocol
|
|
9
11
|
from gobby.storage.mcp import LocalMCPManager
|
|
10
12
|
from gobby.storage.projects import LocalProjectManager
|
|
@@ -18,6 +20,21 @@ logger = logging.getLogger(__name__)
|
|
|
18
20
|
# Pattern to detect placeholder secrets like <YOUR_API_KEY>
|
|
19
21
|
SECRET_PLACEHOLDER_PATTERN = re.compile(r"<YOUR_[A-Z0-9_]+>")
|
|
20
22
|
|
|
23
|
+
DEFAULT_GITHUB_FETCH_PROMPT = """Fetch the README from this GitHub repository and extract MCP server configuration:
|
|
24
|
+
|
|
25
|
+
{github_url}
|
|
26
|
+
|
|
27
|
+
If the URL doesn't point directly to a README, try to find and fetch the README.md file.
|
|
28
|
+
|
|
29
|
+
After reading the documentation, extract the MCP server configuration as a JSON object."""
|
|
30
|
+
|
|
31
|
+
DEFAULT_SEARCH_FETCH_PROMPT = """Search for MCP server: {search_query}
|
|
32
|
+
|
|
33
|
+
Find the official documentation or GitHub repository for this MCP server.
|
|
34
|
+
Then fetch and read the README or installation docs.
|
|
35
|
+
|
|
36
|
+
After reading the documentation, extract the MCP server configuration as a JSON object."""
|
|
37
|
+
|
|
21
38
|
|
|
22
39
|
class MCPServerImporter:
|
|
23
40
|
"""Handles importing MCP servers from various sources."""
|
|
@@ -46,6 +63,21 @@ class MCPServerImporter:
|
|
|
46
63
|
self.mcp_client_manager = mcp_client_manager
|
|
47
64
|
self.import_config = config.get_import_mcp_server_config()
|
|
48
65
|
|
|
66
|
+
# Initialize prompt loader
|
|
67
|
+
project_path = None
|
|
68
|
+
if current_project_id:
|
|
69
|
+
if project := self.project_manager.get(current_project_id):
|
|
70
|
+
project_path = project.repo_path
|
|
71
|
+
|
|
72
|
+
from pathlib import Path
|
|
73
|
+
|
|
74
|
+
self._loader = PromptLoader(project_dir=Path(project_path) if project_path else None)
|
|
75
|
+
|
|
76
|
+
# Register fallbacks
|
|
77
|
+
self._loader.register_fallback("import/github_fetch", lambda: DEFAULT_GITHUB_FETCH_PROMPT)
|
|
78
|
+
self._loader.register_fallback("import/search_fetch", lambda: DEFAULT_SEARCH_FETCH_PROMPT)
|
|
79
|
+
self._loader.register_fallback("import/system", lambda: DEFAULT_IMPORT_MCP_SERVER_PROMPT)
|
|
80
|
+
|
|
49
81
|
async def import_from_project(
|
|
50
82
|
self,
|
|
51
83
|
source_project: str,
|
|
@@ -171,10 +203,23 @@ class MCPServerImporter:
|
|
|
171
203
|
from claude_agent_sdk import AssistantMessage, ClaudeAgentOptions, TextBlock, query
|
|
172
204
|
|
|
173
205
|
# Build prompt to fetch and extract config
|
|
174
|
-
|
|
206
|
+
prompt_path = self.import_config.github_fetch_prompt_path or "import/github_fetch"
|
|
207
|
+
try:
|
|
208
|
+
prompt = self._loader.render(prompt_path, {"github_url": github_url})
|
|
209
|
+
except Exception as e:
|
|
210
|
+
logger.warning(f"Failed to load Github fetch prompt: {e}")
|
|
211
|
+
prompt = DEFAULT_GITHUB_FETCH_PROMPT.format(github_url=github_url)
|
|
212
|
+
|
|
213
|
+
# Get system prompt
|
|
214
|
+
sys_prompt_path = self.import_config.prompt_path or "import/system"
|
|
215
|
+
try:
|
|
216
|
+
system_prompt = self._loader.render(sys_prompt_path, {})
|
|
217
|
+
except Exception as e:
|
|
218
|
+
logger.warning(f"Failed to load import system prompt: {e}")
|
|
219
|
+
system_prompt = DEFAULT_IMPORT_MCP_SERVER_PROMPT
|
|
175
220
|
|
|
176
221
|
options = ClaudeAgentOptions(
|
|
177
|
-
system_prompt=
|
|
222
|
+
system_prompt=system_prompt,
|
|
178
223
|
max_turns=3,
|
|
179
224
|
model=self.import_config.model,
|
|
180
225
|
allowed_tools=["WebFetch"],
|
|
@@ -222,10 +267,23 @@ class MCPServerImporter:
|
|
|
222
267
|
from claude_agent_sdk import AssistantMessage, ClaudeAgentOptions, TextBlock, query
|
|
223
268
|
|
|
224
269
|
# Build prompt to search and extract config
|
|
225
|
-
|
|
270
|
+
prompt_path = self.import_config.search_fetch_prompt_path or "import/search_fetch"
|
|
271
|
+
try:
|
|
272
|
+
prompt = self._loader.render(prompt_path, {"search_query": search_query})
|
|
273
|
+
except Exception as e:
|
|
274
|
+
logger.warning(f"Failed to load search fetch prompt: {e}")
|
|
275
|
+
prompt = DEFAULT_SEARCH_FETCH_PROMPT.format(search_query=search_query)
|
|
276
|
+
|
|
277
|
+
# Get system prompt
|
|
278
|
+
sys_prompt_path = self.import_config.prompt_path or "import/system"
|
|
279
|
+
try:
|
|
280
|
+
system_prompt = self._loader.render(sys_prompt_path, {})
|
|
281
|
+
except Exception as e:
|
|
282
|
+
logger.warning(f"Failed to load import system prompt: {e}")
|
|
283
|
+
system_prompt = DEFAULT_IMPORT_MCP_SERVER_PROMPT
|
|
226
284
|
|
|
227
285
|
options = ClaudeAgentOptions(
|
|
228
|
-
system_prompt=
|
|
286
|
+
system_prompt=system_prompt,
|
|
229
287
|
max_turns=5, # More turns for search + fetch
|
|
230
288
|
model=self.import_config.model,
|
|
231
289
|
allowed_tools=["WebSearch", "WebFetch"],
|
gobby/mcp_proxy/instructions.py
CHANGED
|
@@ -29,6 +29,8 @@ At the start of EVERY session:
|
|
|
29
29
|
3. Session ID: Look for `session_id: <uuid>` in your context.
|
|
30
30
|
If missing, call:
|
|
31
31
|
`call_tool("gobby-sessions", "get_current", {"external_id": "<your-session-id>", "source": "claude"})`
|
|
32
|
+
|
|
33
|
+
Session and task references use `#N` format (e.g., `#1`, `#42`) which is project-scoped.
|
|
32
34
|
</startup>
|
|
33
35
|
|
|
34
36
|
<tool_discovery>
|
gobby/mcp_proxy/registries.py
CHANGED
|
@@ -114,7 +114,7 @@ def setup_internal_registries(
|
|
|
114
114
|
# Initialize sessions registry (messages + session CRUD)
|
|
115
115
|
# Register if either message_manager or local_session_manager is available
|
|
116
116
|
if message_manager is not None or local_session_manager is not None:
|
|
117
|
-
from gobby.mcp_proxy.tools.
|
|
117
|
+
from gobby.mcp_proxy.tools.sessions import create_session_messages_registry
|
|
118
118
|
|
|
119
119
|
session_messages_registry = create_session_messages_registry(
|
|
120
120
|
message_manager=message_manager,
|
|
@@ -173,7 +173,6 @@ def setup_internal_registries(
|
|
|
173
173
|
|
|
174
174
|
agents_registry = create_agents_registry(
|
|
175
175
|
runner=agent_runner,
|
|
176
|
-
tool_proxy_getter=tool_proxy_getter,
|
|
177
176
|
)
|
|
178
177
|
|
|
179
178
|
# Add inter-agent messaging tools if message manager is available
|
|
@@ -198,7 +197,6 @@ def setup_internal_registries(
|
|
|
198
197
|
worktree_storage=worktree_storage,
|
|
199
198
|
git_manager=git_manager,
|
|
200
199
|
project_id=project_id,
|
|
201
|
-
agent_runner=agent_runner,
|
|
202
200
|
)
|
|
203
201
|
manager.add_registry(worktrees_registry)
|
|
204
202
|
logger.debug("Worktrees registry initialized")
|
|
@@ -222,7 +220,6 @@ def setup_internal_registries(
|
|
|
222
220
|
clone_storage=clone_storage,
|
|
223
221
|
git_manager=clone_git_manager,
|
|
224
222
|
project_id=project_id or "",
|
|
225
|
-
agent_runner=agent_runner,
|
|
226
223
|
)
|
|
227
224
|
manager.add_registry(clones_registry)
|
|
228
225
|
logger.debug("Clones registry initialized")
|
|
@@ -7,13 +7,30 @@ import logging
|
|
|
7
7
|
from typing import TYPE_CHECKING, Any, Literal
|
|
8
8
|
|
|
9
9
|
if TYPE_CHECKING:
|
|
10
|
-
from gobby.config.
|
|
10
|
+
from gobby.config.features import RecommendToolsConfig
|
|
11
|
+
from gobby.prompts import PromptLoader
|
|
11
12
|
|
|
12
13
|
logger = logging.getLogger("gobby.mcp.server")
|
|
13
14
|
|
|
14
15
|
# Search mode type
|
|
15
16
|
SearchMode = Literal["llm", "semantic", "hybrid"]
|
|
16
17
|
|
|
18
|
+
DEFAULT_HYBRID_RERANK_PROMPT = """Re-rank the following tools for the task: "{task_description}"
|
|
19
|
+
|
|
20
|
+
Candidates:
|
|
21
|
+
{candidate_list}
|
|
22
|
+
|
|
23
|
+
Select the best {top_k} tools. Return JSON:
|
|
24
|
+
{{"recommendations": [{{"server": "...", "tool": "...", "reason": "..."}}]}}"""
|
|
25
|
+
|
|
26
|
+
DEFAULT_LLM_PROMPT = """Recommend tools for the task: "{task_description}"
|
|
27
|
+
|
|
28
|
+
Available Servers:
|
|
29
|
+
{available_servers}
|
|
30
|
+
|
|
31
|
+
Return JSON:
|
|
32
|
+
{{"recommendations": [{{"server": "...", "tool": "...", "reason": "..."}}]}}"""
|
|
33
|
+
|
|
17
34
|
|
|
18
35
|
class RecommendationService:
|
|
19
36
|
"""Service for recommending tools."""
|
|
@@ -31,12 +48,17 @@ class RecommendationService:
|
|
|
31
48
|
self._semantic_search = semantic_search
|
|
32
49
|
self._project_id = project_id
|
|
33
50
|
self._config = config
|
|
51
|
+
self._loader = PromptLoader()
|
|
52
|
+
self._loader.register_fallback(
|
|
53
|
+
"features/recommend_hybrid", lambda: DEFAULT_HYBRID_RERANK_PROMPT
|
|
54
|
+
)
|
|
55
|
+
self._loader.register_fallback("features/recommend_llm", lambda: DEFAULT_LLM_PROMPT)
|
|
34
56
|
|
|
35
57
|
def _get_config(self) -> RecommendToolsConfig:
|
|
36
58
|
"""Get config with fallback to defaults."""
|
|
37
59
|
if self._config is not None:
|
|
38
60
|
return self._config
|
|
39
|
-
from gobby.config.
|
|
61
|
+
from gobby.config.features import RecommendToolsConfig
|
|
40
62
|
|
|
41
63
|
return RecommendToolsConfig()
|
|
42
64
|
|
|
@@ -153,11 +175,16 @@ class RecommendationService:
|
|
|
153
175
|
for c in candidates
|
|
154
176
|
)
|
|
155
177
|
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
178
|
+
prompt_path = config.hybrid_rerank_prompt_path or "features/recommend_hybrid"
|
|
179
|
+
context = {
|
|
180
|
+
"task_description": task_description,
|
|
181
|
+
"candidate_list": candidate_list,
|
|
182
|
+
"top_k": top_k,
|
|
183
|
+
}
|
|
184
|
+
try:
|
|
185
|
+
prompt = self._loader.render(prompt_path, context)
|
|
186
|
+
except Exception:
|
|
187
|
+
prompt = DEFAULT_HYBRID_RERANK_PROMPT.format(**context)
|
|
161
188
|
|
|
162
189
|
provider = self._llm_service.get_default_provider()
|
|
163
190
|
response = await provider.generate_text(prompt)
|
|
@@ -191,10 +218,15 @@ class RecommendationService:
|
|
|
191
218
|
config = self._get_config()
|
|
192
219
|
available_servers = self._mcp_manager.get_available_servers()
|
|
193
220
|
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
221
|
+
prompt_path = config.llm_prompt_path or "features/recommend_llm"
|
|
222
|
+
context = {
|
|
223
|
+
"task_description": task_description,
|
|
224
|
+
"available_servers": ", ".join(available_servers),
|
|
225
|
+
}
|
|
226
|
+
try:
|
|
227
|
+
prompt = self._loader.render(prompt_path, context)
|
|
228
|
+
except Exception:
|
|
229
|
+
prompt = DEFAULT_LLM_PROMPT.format(**context)
|
|
198
230
|
|
|
199
231
|
provider = self._llm_service.get_default_provider()
|
|
200
232
|
response = await provider.generate_text(prompt)
|