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,337 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Internal tool registry for Gobby built-in tools.
|
|
3
|
+
|
|
4
|
+
Provides a registry system for internal tools that can be accessed via the
|
|
5
|
+
downstream proxy pattern (call_tool, list_tools, get_tool_schema) without
|
|
6
|
+
being registered directly on the FastMCP server.
|
|
7
|
+
|
|
8
|
+
This enables progressive disclosure for internal tools and reduces the
|
|
9
|
+
number of tools exposed on the main MCP server.
|
|
10
|
+
"""
|
|
11
|
+
|
|
12
|
+
import inspect
|
|
13
|
+
import logging
|
|
14
|
+
import types
|
|
15
|
+
from collections.abc import Callable
|
|
16
|
+
from dataclasses import dataclass
|
|
17
|
+
from typing import Any, Union, get_args, get_origin
|
|
18
|
+
|
|
19
|
+
logger = logging.getLogger(__name__)
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def _get_json_schema_type(annotation: Any) -> str:
|
|
23
|
+
"""
|
|
24
|
+
Convert a Python type annotation to a JSON schema type string.
|
|
25
|
+
|
|
26
|
+
Handles:
|
|
27
|
+
- Basic types: int, bool, str, dict, list
|
|
28
|
+
- Generic types: dict[str, Any], list[str], etc.
|
|
29
|
+
- Union types: str | None, dict[str, Any] | None, etc.
|
|
30
|
+
- typing.Union: Union[str, None], etc.
|
|
31
|
+
|
|
32
|
+
Args:
|
|
33
|
+
annotation: Python type annotation
|
|
34
|
+
|
|
35
|
+
Returns:
|
|
36
|
+
JSON schema type string ("string", "integer", "boolean", "object", "array")
|
|
37
|
+
"""
|
|
38
|
+
if annotation is inspect.Parameter.empty:
|
|
39
|
+
return "string"
|
|
40
|
+
|
|
41
|
+
# Handle Union types (X | Y or Union[X, Y])
|
|
42
|
+
origin = get_origin(annotation)
|
|
43
|
+
if origin is Union or origin is types.UnionType:
|
|
44
|
+
# Get non-None types from the union
|
|
45
|
+
args = [arg for arg in get_args(annotation) if arg is not type(None)]
|
|
46
|
+
if args:
|
|
47
|
+
# Use the first non-None type
|
|
48
|
+
return _get_json_schema_type(args[0])
|
|
49
|
+
return "string"
|
|
50
|
+
|
|
51
|
+
# Handle generic types like dict[str, Any], list[str]
|
|
52
|
+
if origin is dict:
|
|
53
|
+
return "object"
|
|
54
|
+
if origin is list:
|
|
55
|
+
return "array"
|
|
56
|
+
|
|
57
|
+
# Handle basic types
|
|
58
|
+
if annotation is int:
|
|
59
|
+
return "integer"
|
|
60
|
+
if annotation is bool:
|
|
61
|
+
return "boolean"
|
|
62
|
+
if annotation is dict:
|
|
63
|
+
return "object"
|
|
64
|
+
if annotation is list:
|
|
65
|
+
return "array"
|
|
66
|
+
if annotation is str:
|
|
67
|
+
return "string"
|
|
68
|
+
|
|
69
|
+
# Default to string for unknown types
|
|
70
|
+
return "string"
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
@dataclass
|
|
74
|
+
class InternalTool:
|
|
75
|
+
"""Represents an internal tool with its metadata and implementation."""
|
|
76
|
+
|
|
77
|
+
name: str
|
|
78
|
+
description: str
|
|
79
|
+
input_schema: dict[str, Any]
|
|
80
|
+
func: Callable[..., Any]
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
class InternalToolRegistry:
|
|
84
|
+
"""
|
|
85
|
+
Registry for a domain of internal tools (e.g., gobby-tasks).
|
|
86
|
+
|
|
87
|
+
Each registry represents a logical grouping of tools that can be
|
|
88
|
+
discovered and called via the proxy pattern.
|
|
89
|
+
"""
|
|
90
|
+
|
|
91
|
+
def __init__(self, name: str, description: str = ""):
|
|
92
|
+
"""
|
|
93
|
+
Initialize a tool registry.
|
|
94
|
+
|
|
95
|
+
Args:
|
|
96
|
+
name: Server name (e.g., "gobby-tasks")
|
|
97
|
+
description: Human-readable description of this tool domain
|
|
98
|
+
"""
|
|
99
|
+
self.name = name
|
|
100
|
+
self.description = description
|
|
101
|
+
self._tools: dict[str, InternalTool] = {}
|
|
102
|
+
|
|
103
|
+
def register(
|
|
104
|
+
self,
|
|
105
|
+
name: str,
|
|
106
|
+
description: str,
|
|
107
|
+
input_schema: dict[str, Any],
|
|
108
|
+
func: Callable[..., Any],
|
|
109
|
+
) -> None:
|
|
110
|
+
"""
|
|
111
|
+
Register a tool with the registry.
|
|
112
|
+
|
|
113
|
+
Args:
|
|
114
|
+
name: Tool name
|
|
115
|
+
description: Tool description (for progressive disclosure)
|
|
116
|
+
input_schema: JSON Schema for the tool's input parameters
|
|
117
|
+
func: The callable that implements the tool (sync or async)
|
|
118
|
+
"""
|
|
119
|
+
self._tools[name] = InternalTool(
|
|
120
|
+
name=name,
|
|
121
|
+
description=description,
|
|
122
|
+
input_schema=input_schema,
|
|
123
|
+
func=func,
|
|
124
|
+
)
|
|
125
|
+
logger.debug(f"Registered internal tool '{name}' on '{self.name}'")
|
|
126
|
+
|
|
127
|
+
def tool(
|
|
128
|
+
self,
|
|
129
|
+
name: str | None = None,
|
|
130
|
+
description: str | None = None,
|
|
131
|
+
) -> Callable[[Callable[..., Any]], Callable[..., Any]]:
|
|
132
|
+
"""
|
|
133
|
+
Decorator to register a function as a tool.
|
|
134
|
+
|
|
135
|
+
Args:
|
|
136
|
+
name: Optional tool name (defaults to function name)
|
|
137
|
+
description: Optional description (defaults to docstring)
|
|
138
|
+
|
|
139
|
+
Returns:
|
|
140
|
+
Decorator function
|
|
141
|
+
"""
|
|
142
|
+
|
|
143
|
+
def decorator(func: Callable[..., Any]) -> Callable[..., Any]:
|
|
144
|
+
tool_name = name or func.__name__
|
|
145
|
+
tool_desc = description or func.__doc__ or ""
|
|
146
|
+
|
|
147
|
+
# Simple schema generation (placeholder for fuller introspection)
|
|
148
|
+
# In a real system, we'd inspect signature to build JSON schema
|
|
149
|
+
# For now, we'll assume the decorated function is well-behaved
|
|
150
|
+
# or rely on manual registration if complex schema needed.
|
|
151
|
+
# But wait, tasks.py usage implies we need schema extraction.
|
|
152
|
+
# Extract schema from function signature using type annotations
|
|
153
|
+
sig = inspect.signature(func)
|
|
154
|
+
properties = {}
|
|
155
|
+
required = []
|
|
156
|
+
|
|
157
|
+
for param_name, param in sig.parameters.items():
|
|
158
|
+
if param_name == "self":
|
|
159
|
+
continue
|
|
160
|
+
|
|
161
|
+
param_type = _get_json_schema_type(param.annotation)
|
|
162
|
+
properties[param_name] = {"type": param_type}
|
|
163
|
+
|
|
164
|
+
if param.default == inspect.Parameter.empty:
|
|
165
|
+
required.append(param_name)
|
|
166
|
+
|
|
167
|
+
input_schema = {"type": "object", "properties": properties, "required": required}
|
|
168
|
+
|
|
169
|
+
self.register(
|
|
170
|
+
name=tool_name,
|
|
171
|
+
description=tool_desc.strip(),
|
|
172
|
+
input_schema=input_schema,
|
|
173
|
+
func=func,
|
|
174
|
+
)
|
|
175
|
+
return func
|
|
176
|
+
|
|
177
|
+
return decorator
|
|
178
|
+
|
|
179
|
+
async def call(self, name: str, args: dict[str, Any]) -> Any:
|
|
180
|
+
"""
|
|
181
|
+
Call a tool by name with the given arguments.
|
|
182
|
+
|
|
183
|
+
Args:
|
|
184
|
+
name: Tool name
|
|
185
|
+
args: Tool arguments
|
|
186
|
+
|
|
187
|
+
Returns:
|
|
188
|
+
Tool execution result
|
|
189
|
+
|
|
190
|
+
Raises:
|
|
191
|
+
ValueError: If tool not found
|
|
192
|
+
Exception: If tool execution fails
|
|
193
|
+
"""
|
|
194
|
+
tool = self._tools.get(name)
|
|
195
|
+
if not tool:
|
|
196
|
+
available = ", ".join(self._tools.keys())
|
|
197
|
+
raise ValueError(f"Tool '{name}' not found on '{self.name}'. Available: {available}")
|
|
198
|
+
|
|
199
|
+
# Call the function (handle both sync and async)
|
|
200
|
+
if inspect.iscoroutinefunction(tool.func):
|
|
201
|
+
return await tool.func(**args)
|
|
202
|
+
return tool.func(**args)
|
|
203
|
+
|
|
204
|
+
def list_tools(self) -> list[dict[str, str]]:
|
|
205
|
+
"""
|
|
206
|
+
List all tools with lightweight metadata.
|
|
207
|
+
|
|
208
|
+
Returns:
|
|
209
|
+
List of {name, brief} dicts for progressive disclosure
|
|
210
|
+
"""
|
|
211
|
+
return [
|
|
212
|
+
{
|
|
213
|
+
"name": tool.name,
|
|
214
|
+
"brief": tool.description[:100] if tool.description else "No description",
|
|
215
|
+
}
|
|
216
|
+
for tool in self._tools.values()
|
|
217
|
+
]
|
|
218
|
+
|
|
219
|
+
def get_schema(self, name: str) -> dict[str, Any] | None:
|
|
220
|
+
"""
|
|
221
|
+
Get full schema for a specific tool.
|
|
222
|
+
|
|
223
|
+
Args:
|
|
224
|
+
name: Tool name
|
|
225
|
+
|
|
226
|
+
Returns:
|
|
227
|
+
Dict with name, description, and inputSchema, or None if not found
|
|
228
|
+
"""
|
|
229
|
+
tool = self._tools.get(name)
|
|
230
|
+
if not tool:
|
|
231
|
+
return None
|
|
232
|
+
|
|
233
|
+
return {
|
|
234
|
+
"name": tool.name,
|
|
235
|
+
"description": tool.description,
|
|
236
|
+
"inputSchema": tool.input_schema,
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
def __len__(self) -> int:
|
|
240
|
+
"""Return number of registered tools."""
|
|
241
|
+
return len(self._tools)
|
|
242
|
+
|
|
243
|
+
|
|
244
|
+
class InternalRegistryManager:
|
|
245
|
+
"""
|
|
246
|
+
Manages multiple internal registries (gobby-tasks, gobby-hooks, etc.).
|
|
247
|
+
|
|
248
|
+
Provides routing logic to dispatch calls to the appropriate registry
|
|
249
|
+
based on server name prefix.
|
|
250
|
+
"""
|
|
251
|
+
|
|
252
|
+
INTERNAL_PREFIX = "gobby-"
|
|
253
|
+
|
|
254
|
+
def __init__(self) -> None:
|
|
255
|
+
self._registries: dict[str, InternalToolRegistry] = {}
|
|
256
|
+
|
|
257
|
+
def add_registry(self, registry: InternalToolRegistry) -> None:
|
|
258
|
+
"""
|
|
259
|
+
Add a registry to the manager.
|
|
260
|
+
|
|
261
|
+
Args:
|
|
262
|
+
registry: The registry to add
|
|
263
|
+
"""
|
|
264
|
+
self._registries[registry.name] = registry
|
|
265
|
+
logger.info(f"Added internal registry '{registry.name}' with {len(registry)} tools")
|
|
266
|
+
|
|
267
|
+
def is_internal(self, server_name: str | None) -> bool:
|
|
268
|
+
"""
|
|
269
|
+
Check if a server name refers to an internal registry.
|
|
270
|
+
|
|
271
|
+
Args:
|
|
272
|
+
server_name: Server name to check
|
|
273
|
+
|
|
274
|
+
Returns:
|
|
275
|
+
True if server_name starts with 'gobby-'
|
|
276
|
+
"""
|
|
277
|
+
if server_name is None:
|
|
278
|
+
return False
|
|
279
|
+
return server_name.startswith(self.INTERNAL_PREFIX)
|
|
280
|
+
|
|
281
|
+
def get_registry(self, server_name: str) -> InternalToolRegistry | None:
|
|
282
|
+
"""
|
|
283
|
+
Get a registry by name.
|
|
284
|
+
|
|
285
|
+
Args:
|
|
286
|
+
server_name: Registry name (e.g., "gobby-tasks")
|
|
287
|
+
|
|
288
|
+
Returns:
|
|
289
|
+
The registry if found, None otherwise
|
|
290
|
+
"""
|
|
291
|
+
return self._registries.get(server_name)
|
|
292
|
+
|
|
293
|
+
def list_servers(self) -> list[dict[str, Any]]:
|
|
294
|
+
"""
|
|
295
|
+
List all internal servers with metadata.
|
|
296
|
+
|
|
297
|
+
Returns:
|
|
298
|
+
List of server info dicts
|
|
299
|
+
"""
|
|
300
|
+
return [
|
|
301
|
+
{
|
|
302
|
+
"name": registry.name,
|
|
303
|
+
"description": registry.description,
|
|
304
|
+
"tool_count": len(registry),
|
|
305
|
+
}
|
|
306
|
+
for registry in self._registries.values()
|
|
307
|
+
]
|
|
308
|
+
|
|
309
|
+
def get_all_registries(self) -> list[InternalToolRegistry]:
|
|
310
|
+
"""
|
|
311
|
+
Get all registered registries.
|
|
312
|
+
|
|
313
|
+
Returns:
|
|
314
|
+
List of all registries
|
|
315
|
+
"""
|
|
316
|
+
return list(self._registries.values())
|
|
317
|
+
|
|
318
|
+
def find_tool_server(self, tool_name: str) -> str | None:
|
|
319
|
+
"""
|
|
320
|
+
Find which internal server owns a tool.
|
|
321
|
+
|
|
322
|
+
Searches all internal registries to find a tool by name.
|
|
323
|
+
|
|
324
|
+
Args:
|
|
325
|
+
tool_name: Name of the tool to find
|
|
326
|
+
|
|
327
|
+
Returns:
|
|
328
|
+
Server name if found, None otherwise
|
|
329
|
+
"""
|
|
330
|
+
for registry in self._registries.values():
|
|
331
|
+
if tool_name in registry._tools:
|
|
332
|
+
return registry.name
|
|
333
|
+
return None
|
|
334
|
+
|
|
335
|
+
def __len__(self) -> int:
|
|
336
|
+
"""Return number of registries."""
|
|
337
|
+
return len(self._registries)
|