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,380 @@
|
|
|
1
|
+
"""Task orchestration tools: monitor (poll_agent_status, get_orchestration_status)."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import logging
|
|
6
|
+
from typing import TYPE_CHECKING, Any
|
|
7
|
+
|
|
8
|
+
from gobby.mcp_proxy.tools.internal import InternalToolRegistry
|
|
9
|
+
from gobby.storage.tasks import TaskNotFoundError
|
|
10
|
+
|
|
11
|
+
from .utils import get_current_project_id
|
|
12
|
+
|
|
13
|
+
if TYPE_CHECKING:
|
|
14
|
+
from gobby.agents.runner import AgentRunner
|
|
15
|
+
from gobby.storage.tasks import LocalTaskManager
|
|
16
|
+
from gobby.storage.worktrees import LocalWorktreeManager
|
|
17
|
+
|
|
18
|
+
logger = logging.getLogger(__name__)
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def register_monitor(
|
|
22
|
+
registry: InternalToolRegistry,
|
|
23
|
+
task_manager: LocalTaskManager,
|
|
24
|
+
worktree_storage: LocalWorktreeManager,
|
|
25
|
+
agent_runner: AgentRunner | None = None,
|
|
26
|
+
default_project_id: str | None = None,
|
|
27
|
+
) -> None:
|
|
28
|
+
"""Register monitor tools."""
|
|
29
|
+
from gobby.mcp_proxy.tools.tasks import resolve_task_id_for_mcp
|
|
30
|
+
|
|
31
|
+
async def get_orchestration_status(
|
|
32
|
+
parent_task_id: str,
|
|
33
|
+
project_path: str | None = None,
|
|
34
|
+
) -> dict[str, Any]:
|
|
35
|
+
"""
|
|
36
|
+
Get the current orchestration status for a parent task.
|
|
37
|
+
|
|
38
|
+
Returns information about spawned agents, their status, and worktree state.
|
|
39
|
+
|
|
40
|
+
Args:
|
|
41
|
+
parent_task_id: Task reference: #N, N (seq_num), path (1.2.3), or UUID
|
|
42
|
+
project_path: Path to project directory
|
|
43
|
+
|
|
44
|
+
Returns:
|
|
45
|
+
Dict with orchestration status
|
|
46
|
+
"""
|
|
47
|
+
# Resolve parent_task_id reference
|
|
48
|
+
try:
|
|
49
|
+
resolved_parent_task_id = resolve_task_id_for_mcp(task_manager, parent_task_id)
|
|
50
|
+
except (TaskNotFoundError, ValueError) as e:
|
|
51
|
+
return {
|
|
52
|
+
"success": False,
|
|
53
|
+
"error": f"Invalid parent_task_id: {e}",
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
# Resolve project ID
|
|
57
|
+
resolved_project_id = default_project_id
|
|
58
|
+
if project_path:
|
|
59
|
+
from pathlib import Path
|
|
60
|
+
|
|
61
|
+
from gobby.utils.project_context import get_project_context
|
|
62
|
+
|
|
63
|
+
ctx = get_project_context(Path(project_path))
|
|
64
|
+
if ctx:
|
|
65
|
+
resolved_project_id = ctx.get("id")
|
|
66
|
+
|
|
67
|
+
if not resolved_project_id:
|
|
68
|
+
resolved_project_id = get_current_project_id()
|
|
69
|
+
|
|
70
|
+
if not resolved_project_id:
|
|
71
|
+
return {
|
|
72
|
+
"success": False,
|
|
73
|
+
"error": "Could not resolve project ID",
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
# Get subtasks
|
|
77
|
+
subtasks = task_manager.list_tasks(parent_task_id=resolved_parent_task_id, limit=100)
|
|
78
|
+
|
|
79
|
+
# Categorize by status
|
|
80
|
+
open_tasks = []
|
|
81
|
+
in_progress_tasks = []
|
|
82
|
+
review_tasks: list[dict[str, Any]] = []
|
|
83
|
+
closed_tasks = []
|
|
84
|
+
|
|
85
|
+
for task in subtasks:
|
|
86
|
+
task_info: dict[str, Any] = {
|
|
87
|
+
"id": task.id,
|
|
88
|
+
"title": task.title,
|
|
89
|
+
"status": task.status,
|
|
90
|
+
"validation_status": task.validation_status,
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
# Check for linked worktree
|
|
94
|
+
worktree = worktree_storage.get_by_task(task.id)
|
|
95
|
+
if worktree:
|
|
96
|
+
task_info["worktree_id"] = worktree.id
|
|
97
|
+
task_info["worktree_status"] = worktree.status
|
|
98
|
+
task_info["has_active_agent"] = worktree.agent_session_id is not None
|
|
99
|
+
|
|
100
|
+
if task.status == "closed":
|
|
101
|
+
closed_tasks.append(task_info)
|
|
102
|
+
elif task.status == "in_progress":
|
|
103
|
+
in_progress_tasks.append(task_info)
|
|
104
|
+
elif task.status == "review":
|
|
105
|
+
review_tasks.append(task_info)
|
|
106
|
+
else:
|
|
107
|
+
open_tasks.append(task_info)
|
|
108
|
+
|
|
109
|
+
# Check if parent task is complete
|
|
110
|
+
parent_task = task_manager.get_task(resolved_parent_task_id)
|
|
111
|
+
is_complete = parent_task and parent_task.status == "closed"
|
|
112
|
+
|
|
113
|
+
return {
|
|
114
|
+
"success": True,
|
|
115
|
+
"parent_task_id": resolved_parent_task_id,
|
|
116
|
+
"is_complete": is_complete,
|
|
117
|
+
"summary": {
|
|
118
|
+
"open": len(open_tasks),
|
|
119
|
+
"in_progress": len(in_progress_tasks),
|
|
120
|
+
"review": len(review_tasks),
|
|
121
|
+
"closed": len(closed_tasks),
|
|
122
|
+
"total": len(subtasks),
|
|
123
|
+
},
|
|
124
|
+
"open_tasks": open_tasks,
|
|
125
|
+
"in_progress_tasks": in_progress_tasks,
|
|
126
|
+
"review_tasks": review_tasks,
|
|
127
|
+
"closed_tasks": closed_tasks,
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
registry.register(
|
|
131
|
+
name="get_orchestration_status",
|
|
132
|
+
description="Get current orchestration status for a parent task",
|
|
133
|
+
input_schema={
|
|
134
|
+
"type": "object",
|
|
135
|
+
"properties": {
|
|
136
|
+
"parent_task_id": {
|
|
137
|
+
"type": "string",
|
|
138
|
+
"description": "Task reference: #N, N (seq_num), path (1.2.3), or UUID",
|
|
139
|
+
},
|
|
140
|
+
"project_path": {
|
|
141
|
+
"type": "string",
|
|
142
|
+
"description": "Path to project directory",
|
|
143
|
+
},
|
|
144
|
+
},
|
|
145
|
+
"required": ["parent_task_id"],
|
|
146
|
+
},
|
|
147
|
+
func=get_orchestration_status,
|
|
148
|
+
)
|
|
149
|
+
|
|
150
|
+
async def poll_agent_status(
|
|
151
|
+
parent_session_id: str,
|
|
152
|
+
) -> dict[str, Any]:
|
|
153
|
+
"""
|
|
154
|
+
Poll running agents and update tracking lists in workflow state.
|
|
155
|
+
|
|
156
|
+
Checks all spawned agents for completion/failure and moves them to
|
|
157
|
+
appropriate lists (completed_agents, failed_agents). Used by the
|
|
158
|
+
auto-orchestrator workflow's monitor step.
|
|
159
|
+
|
|
160
|
+
Args:
|
|
161
|
+
parent_session_id: Parent session ID (orchestrator session)
|
|
162
|
+
|
|
163
|
+
Returns:
|
|
164
|
+
Dict with:
|
|
165
|
+
- still_running: List of agents still in progress
|
|
166
|
+
- newly_completed: List of agents that completed since last poll
|
|
167
|
+
- newly_failed: List of agents that failed since last poll
|
|
168
|
+
- summary: Counts of running/completed/failed
|
|
169
|
+
"""
|
|
170
|
+
if agent_runner is None:
|
|
171
|
+
return {
|
|
172
|
+
"success": False,
|
|
173
|
+
"error": "Agent runner not configured",
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
# Get workflow state
|
|
177
|
+
from gobby.workflows.state_manager import WorkflowStateManager
|
|
178
|
+
|
|
179
|
+
state_manager = WorkflowStateManager(task_manager.db)
|
|
180
|
+
state = state_manager.get_state(parent_session_id)
|
|
181
|
+
if not state:
|
|
182
|
+
return {
|
|
183
|
+
"success": True,
|
|
184
|
+
"still_running": [],
|
|
185
|
+
"newly_completed": [],
|
|
186
|
+
"newly_failed": [],
|
|
187
|
+
"summary": {"running": 0, "completed": 0, "failed": 0},
|
|
188
|
+
"message": "No workflow state found",
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
workflow_vars = state.variables
|
|
192
|
+
spawned_agents = workflow_vars.get("spawned_agents", [])
|
|
193
|
+
completed_agents = workflow_vars.get("completed_agents", [])
|
|
194
|
+
failed_agents = workflow_vars.get("failed_agents", [])
|
|
195
|
+
|
|
196
|
+
if not spawned_agents:
|
|
197
|
+
return {
|
|
198
|
+
"success": True,
|
|
199
|
+
"still_running": [],
|
|
200
|
+
"newly_completed": completed_agents,
|
|
201
|
+
"newly_failed": failed_agents,
|
|
202
|
+
"summary": {
|
|
203
|
+
"running": 0,
|
|
204
|
+
"completed": len(completed_agents),
|
|
205
|
+
"failed": len(failed_agents),
|
|
206
|
+
},
|
|
207
|
+
"message": "No spawned agents to poll",
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
# Check status of each spawned agent
|
|
211
|
+
still_running: list[dict[str, Any]] = []
|
|
212
|
+
newly_completed: list[dict[str, Any]] = []
|
|
213
|
+
newly_failed: list[dict[str, Any]] = []
|
|
214
|
+
|
|
215
|
+
for agent_info in spawned_agents:
|
|
216
|
+
session_id = agent_info.get("session_id")
|
|
217
|
+
task_id = agent_info.get("task_id")
|
|
218
|
+
|
|
219
|
+
if not session_id:
|
|
220
|
+
# Invalid agent info, mark as failed
|
|
221
|
+
newly_failed.append(
|
|
222
|
+
{
|
|
223
|
+
**agent_info,
|
|
224
|
+
"failure_reason": "Missing session_id in agent info",
|
|
225
|
+
}
|
|
226
|
+
)
|
|
227
|
+
continue
|
|
228
|
+
|
|
229
|
+
# Check if the task is closed (agent completed successfully)
|
|
230
|
+
if task_id:
|
|
231
|
+
try:
|
|
232
|
+
task = task_manager.get_task(task_id)
|
|
233
|
+
except Exception as e:
|
|
234
|
+
logger.warning(f"Failed to get task {task_id}: {e}")
|
|
235
|
+
task = None
|
|
236
|
+
|
|
237
|
+
if task is not None and task.status == "closed":
|
|
238
|
+
newly_completed.append(
|
|
239
|
+
{
|
|
240
|
+
**agent_info,
|
|
241
|
+
"completed_at": task.closed_at,
|
|
242
|
+
"closed_reason": task.closed_reason,
|
|
243
|
+
"commit_sha": task.closed_commit_sha,
|
|
244
|
+
}
|
|
245
|
+
)
|
|
246
|
+
continue
|
|
247
|
+
|
|
248
|
+
# Check worktree status (if agent released worktree, it's done)
|
|
249
|
+
worktree_id = agent_info.get("worktree_id")
|
|
250
|
+
if worktree_id:
|
|
251
|
+
worktree = worktree_storage.get(worktree_id)
|
|
252
|
+
if worktree and not worktree.agent_session_id:
|
|
253
|
+
# Worktree released but task not closed - check if failed
|
|
254
|
+
if task_id:
|
|
255
|
+
task = task_manager.get_task(task_id)
|
|
256
|
+
if task and task.status != "closed":
|
|
257
|
+
# Agent released worktree without closing task
|
|
258
|
+
newly_failed.append(
|
|
259
|
+
{
|
|
260
|
+
**agent_info,
|
|
261
|
+
"failure_reason": "Agent released worktree without closing task",
|
|
262
|
+
}
|
|
263
|
+
)
|
|
264
|
+
continue
|
|
265
|
+
|
|
266
|
+
# Check if agent is still running via in-memory registry
|
|
267
|
+
running_agent = agent_runner.get_running_agent(session_id)
|
|
268
|
+
if running_agent:
|
|
269
|
+
# Still running
|
|
270
|
+
still_running.append(
|
|
271
|
+
{
|
|
272
|
+
**agent_info,
|
|
273
|
+
"running_since": running_agent.started_at.isoformat()
|
|
274
|
+
if running_agent.started_at
|
|
275
|
+
else None,
|
|
276
|
+
}
|
|
277
|
+
)
|
|
278
|
+
else:
|
|
279
|
+
# Agent not in running registry and task not closed
|
|
280
|
+
# Could be completed or failed - check task status
|
|
281
|
+
if task_id:
|
|
282
|
+
task = task_manager.get_task(task_id)
|
|
283
|
+
if task and task.status == "closed":
|
|
284
|
+
newly_completed.append(
|
|
285
|
+
{
|
|
286
|
+
**agent_info,
|
|
287
|
+
"completed_at": task.closed_at,
|
|
288
|
+
}
|
|
289
|
+
)
|
|
290
|
+
elif task and task.status == "in_progress":
|
|
291
|
+
# Still in progress but agent not running - likely crashed
|
|
292
|
+
newly_failed.append(
|
|
293
|
+
{
|
|
294
|
+
**agent_info,
|
|
295
|
+
"failure_reason": "Agent exited without completing task",
|
|
296
|
+
}
|
|
297
|
+
)
|
|
298
|
+
else:
|
|
299
|
+
# Task open, agent not running - was never started properly
|
|
300
|
+
newly_failed.append(
|
|
301
|
+
{
|
|
302
|
+
**agent_info,
|
|
303
|
+
"failure_reason": "Agent not running and task not started",
|
|
304
|
+
}
|
|
305
|
+
)
|
|
306
|
+
else:
|
|
307
|
+
# No task ID, can't determine status
|
|
308
|
+
newly_failed.append(
|
|
309
|
+
{
|
|
310
|
+
**agent_info,
|
|
311
|
+
"failure_reason": "Unknown status - no task_id",
|
|
312
|
+
}
|
|
313
|
+
)
|
|
314
|
+
|
|
315
|
+
# Update workflow state
|
|
316
|
+
# Compare by session IDs to detect real changes in agent membership
|
|
317
|
+
# (dict comparison would fail due to added fields like running_since)
|
|
318
|
+
still_running_ids = {a.get("session_id") for a in still_running}
|
|
319
|
+
spawned_ids = {a.get("session_id") for a in spawned_agents}
|
|
320
|
+
agents_changed = still_running_ids != spawned_ids
|
|
321
|
+
|
|
322
|
+
if newly_completed or newly_failed or agents_changed:
|
|
323
|
+
try:
|
|
324
|
+
# Re-fetch state to ensure we have the latest
|
|
325
|
+
state = state_manager.get_state(parent_session_id)
|
|
326
|
+
if state:
|
|
327
|
+
# Update completed_agents list
|
|
328
|
+
if newly_completed:
|
|
329
|
+
existing_completed = state.variables.get("completed_agents", [])
|
|
330
|
+
existing_completed.extend(newly_completed)
|
|
331
|
+
state.variables["completed_agents"] = existing_completed
|
|
332
|
+
completed_agents = existing_completed
|
|
333
|
+
|
|
334
|
+
# Update failed_agents list
|
|
335
|
+
if newly_failed:
|
|
336
|
+
existing_failed = state.variables.get("failed_agents", [])
|
|
337
|
+
existing_failed.extend(newly_failed)
|
|
338
|
+
state.variables["failed_agents"] = existing_failed
|
|
339
|
+
failed_agents = existing_failed
|
|
340
|
+
|
|
341
|
+
# Update spawned_agents to only include still running
|
|
342
|
+
state.variables["spawned_agents"] = still_running
|
|
343
|
+
|
|
344
|
+
state_manager.save_state(state)
|
|
345
|
+
|
|
346
|
+
except Exception as e:
|
|
347
|
+
logger.warning(f"Failed to update workflow state during poll: {e}")
|
|
348
|
+
|
|
349
|
+
return {
|
|
350
|
+
"success": True,
|
|
351
|
+
"still_running": still_running,
|
|
352
|
+
"newly_completed": newly_completed,
|
|
353
|
+
"newly_failed": newly_failed,
|
|
354
|
+
"summary": {
|
|
355
|
+
"running": len(still_running),
|
|
356
|
+
"completed": len(completed_agents),
|
|
357
|
+
"failed": len(failed_agents),
|
|
358
|
+
},
|
|
359
|
+
"all_done": len(still_running) == 0,
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
registry.register(
|
|
363
|
+
name="poll_agent_status",
|
|
364
|
+
description=(
|
|
365
|
+
"Poll running agents and update tracking lists. "
|
|
366
|
+
"Checks spawned_agents, moves completed to completed_agents and failed to failed_agents. "
|
|
367
|
+
"Used by auto-orchestrator monitor step."
|
|
368
|
+
),
|
|
369
|
+
input_schema={
|
|
370
|
+
"type": "object",
|
|
371
|
+
"properties": {
|
|
372
|
+
"parent_session_id": {
|
|
373
|
+
"type": "string",
|
|
374
|
+
"description": "Parent session ID (orchestrator session)",
|
|
375
|
+
},
|
|
376
|
+
},
|
|
377
|
+
"required": ["parent_session_id"],
|
|
378
|
+
},
|
|
379
|
+
func=poll_agent_status,
|
|
380
|
+
)
|