htmlgraph 0.9.3__py3-none-any.whl → 0.27.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.
- htmlgraph/.htmlgraph/.session-warning-state.json +6 -0
- htmlgraph/.htmlgraph/agents.json +72 -0
- htmlgraph/.htmlgraph/htmlgraph.db +0 -0
- htmlgraph/__init__.py +173 -17
- htmlgraph/__init__.pyi +123 -0
- htmlgraph/agent_detection.py +127 -0
- htmlgraph/agent_registry.py +45 -30
- htmlgraph/agents.py +160 -107
- htmlgraph/analytics/__init__.py +9 -2
- htmlgraph/analytics/cli.py +190 -51
- htmlgraph/analytics/cost_analyzer.py +391 -0
- htmlgraph/analytics/cost_monitor.py +664 -0
- htmlgraph/analytics/cost_reporter.py +675 -0
- htmlgraph/analytics/cross_session.py +617 -0
- htmlgraph/analytics/dependency.py +192 -100
- htmlgraph/analytics/pattern_learning.py +771 -0
- htmlgraph/analytics/session_graph.py +707 -0
- htmlgraph/analytics/strategic/__init__.py +80 -0
- htmlgraph/analytics/strategic/cost_optimizer.py +611 -0
- htmlgraph/analytics/strategic/pattern_detector.py +876 -0
- htmlgraph/analytics/strategic/preference_manager.py +709 -0
- htmlgraph/analytics/strategic/suggestion_engine.py +747 -0
- htmlgraph/analytics/work_type.py +190 -14
- htmlgraph/analytics_index.py +135 -51
- htmlgraph/api/__init__.py +3 -0
- htmlgraph/api/cost_alerts_websocket.py +416 -0
- htmlgraph/api/main.py +2498 -0
- htmlgraph/api/static/htmx.min.js +1 -0
- htmlgraph/api/static/style-redesign.css +1344 -0
- htmlgraph/api/static/style.css +1079 -0
- htmlgraph/api/templates/dashboard-redesign.html +1366 -0
- htmlgraph/api/templates/dashboard.html +794 -0
- htmlgraph/api/templates/partials/activity-feed-hierarchical.html +326 -0
- htmlgraph/api/templates/partials/activity-feed.html +1100 -0
- htmlgraph/api/templates/partials/agents-redesign.html +317 -0
- htmlgraph/api/templates/partials/agents.html +317 -0
- htmlgraph/api/templates/partials/event-traces.html +373 -0
- htmlgraph/api/templates/partials/features-kanban-redesign.html +509 -0
- htmlgraph/api/templates/partials/features.html +578 -0
- htmlgraph/api/templates/partials/metrics-redesign.html +346 -0
- htmlgraph/api/templates/partials/metrics.html +346 -0
- htmlgraph/api/templates/partials/orchestration-redesign.html +443 -0
- htmlgraph/api/templates/partials/orchestration.html +198 -0
- htmlgraph/api/templates/partials/spawners.html +375 -0
- htmlgraph/api/templates/partials/work-items.html +613 -0
- htmlgraph/api/websocket.py +538 -0
- htmlgraph/archive/__init__.py +24 -0
- htmlgraph/archive/bloom.py +234 -0
- htmlgraph/archive/fts.py +297 -0
- htmlgraph/archive/manager.py +583 -0
- htmlgraph/archive/search.py +244 -0
- htmlgraph/atomic_ops.py +560 -0
- htmlgraph/attribute_index.py +208 -0
- htmlgraph/bounded_paths.py +539 -0
- htmlgraph/builders/__init__.py +14 -0
- htmlgraph/builders/base.py +118 -29
- htmlgraph/builders/bug.py +150 -0
- htmlgraph/builders/chore.py +119 -0
- htmlgraph/builders/epic.py +150 -0
- htmlgraph/builders/feature.py +31 -6
- htmlgraph/builders/insight.py +195 -0
- htmlgraph/builders/metric.py +217 -0
- htmlgraph/builders/pattern.py +202 -0
- htmlgraph/builders/phase.py +162 -0
- htmlgraph/builders/spike.py +52 -19
- htmlgraph/builders/track.py +148 -72
- htmlgraph/cigs/__init__.py +81 -0
- htmlgraph/cigs/autonomy.py +385 -0
- htmlgraph/cigs/cost.py +475 -0
- htmlgraph/cigs/messages_basic.py +472 -0
- htmlgraph/cigs/messaging.py +365 -0
- htmlgraph/cigs/models.py +771 -0
- htmlgraph/cigs/pattern_storage.py +427 -0
- htmlgraph/cigs/patterns.py +503 -0
- htmlgraph/cigs/posttool_analyzer.py +234 -0
- htmlgraph/cigs/reporter.py +818 -0
- htmlgraph/cigs/tracker.py +317 -0
- htmlgraph/cli/.htmlgraph/.session-warning-state.json +6 -0
- htmlgraph/cli/.htmlgraph/agents.json +72 -0
- htmlgraph/cli/.htmlgraph/htmlgraph.db +0 -0
- htmlgraph/cli/__init__.py +42 -0
- htmlgraph/cli/__main__.py +6 -0
- htmlgraph/cli/analytics.py +1424 -0
- htmlgraph/cli/base.py +685 -0
- htmlgraph/cli/constants.py +206 -0
- htmlgraph/cli/core.py +954 -0
- htmlgraph/cli/main.py +147 -0
- htmlgraph/cli/models.py +475 -0
- htmlgraph/cli/templates/__init__.py +1 -0
- htmlgraph/cli/templates/cost_dashboard.py +399 -0
- htmlgraph/cli/work/__init__.py +239 -0
- htmlgraph/cli/work/browse.py +115 -0
- htmlgraph/cli/work/features.py +568 -0
- htmlgraph/cli/work/orchestration.py +676 -0
- htmlgraph/cli/work/report.py +728 -0
- htmlgraph/cli/work/sessions.py +466 -0
- htmlgraph/cli/work/snapshot.py +559 -0
- htmlgraph/cli/work/tracks.py +486 -0
- htmlgraph/cli_commands/__init__.py +1 -0
- htmlgraph/cli_commands/feature.py +195 -0
- htmlgraph/cli_framework.py +115 -0
- htmlgraph/collections/__init__.py +18 -0
- htmlgraph/collections/base.py +415 -98
- htmlgraph/collections/bug.py +53 -0
- htmlgraph/collections/chore.py +53 -0
- htmlgraph/collections/epic.py +53 -0
- htmlgraph/collections/feature.py +12 -26
- htmlgraph/collections/insight.py +100 -0
- htmlgraph/collections/metric.py +92 -0
- htmlgraph/collections/pattern.py +97 -0
- htmlgraph/collections/phase.py +53 -0
- htmlgraph/collections/session.py +194 -0
- htmlgraph/collections/spike.py +56 -16
- htmlgraph/collections/task_delegation.py +241 -0
- htmlgraph/collections/todo.py +511 -0
- htmlgraph/collections/traces.py +487 -0
- htmlgraph/config/cost_models.json +56 -0
- htmlgraph/config.py +190 -0
- htmlgraph/context_analytics.py +344 -0
- htmlgraph/converter.py +216 -28
- htmlgraph/cost_analysis/__init__.py +5 -0
- htmlgraph/cost_analysis/analyzer.py +438 -0
- htmlgraph/dashboard.html +2406 -307
- htmlgraph/dashboard.html.backup +6592 -0
- htmlgraph/dashboard.html.bak +7181 -0
- htmlgraph/dashboard.html.bak2 +7231 -0
- htmlgraph/dashboard.html.bak3 +7232 -0
- htmlgraph/db/__init__.py +38 -0
- htmlgraph/db/queries.py +790 -0
- htmlgraph/db/schema.py +1788 -0
- htmlgraph/decorators.py +317 -0
- htmlgraph/dependency_models.py +19 -2
- htmlgraph/deploy.py +142 -125
- htmlgraph/deployment_models.py +474 -0
- htmlgraph/docs/API_REFERENCE.md +841 -0
- htmlgraph/docs/HTTP_API.md +750 -0
- htmlgraph/docs/INTEGRATION_GUIDE.md +752 -0
- htmlgraph/docs/ORCHESTRATION_PATTERNS.md +717 -0
- htmlgraph/docs/README.md +532 -0
- htmlgraph/docs/__init__.py +77 -0
- htmlgraph/docs/docs_version.py +55 -0
- htmlgraph/docs/metadata.py +93 -0
- htmlgraph/docs/migrations.py +232 -0
- htmlgraph/docs/template_engine.py +143 -0
- htmlgraph/docs/templates/_sections/cli_reference.md.j2 +52 -0
- htmlgraph/docs/templates/_sections/core_concepts.md.j2 +29 -0
- htmlgraph/docs/templates/_sections/sdk_basics.md.j2 +69 -0
- htmlgraph/docs/templates/base_agents.md.j2 +78 -0
- htmlgraph/docs/templates/example_user_override.md.j2 +47 -0
- htmlgraph/docs/version_check.py +163 -0
- htmlgraph/edge_index.py +182 -27
- htmlgraph/error_handler.py +544 -0
- htmlgraph/event_log.py +100 -52
- htmlgraph/event_migration.py +13 -4
- htmlgraph/exceptions.py +49 -0
- htmlgraph/file_watcher.py +101 -28
- htmlgraph/find_api.py +75 -63
- htmlgraph/git_events.py +145 -63
- htmlgraph/graph.py +1122 -106
- htmlgraph/hooks/.htmlgraph/.session-warning-state.json +6 -0
- htmlgraph/hooks/.htmlgraph/agents.json +72 -0
- htmlgraph/hooks/.htmlgraph/index.sqlite +0 -0
- htmlgraph/hooks/__init__.py +45 -0
- htmlgraph/hooks/bootstrap.py +169 -0
- htmlgraph/hooks/cigs_pretool_enforcer.py +354 -0
- htmlgraph/hooks/concurrent_sessions.py +208 -0
- htmlgraph/hooks/context.py +350 -0
- htmlgraph/hooks/drift_handler.py +525 -0
- htmlgraph/hooks/event_tracker.py +1314 -0
- htmlgraph/hooks/git_commands.py +175 -0
- htmlgraph/hooks/hooks-config.example.json +12 -0
- htmlgraph/hooks/installer.py +343 -0
- htmlgraph/hooks/orchestrator.py +674 -0
- htmlgraph/hooks/orchestrator_reflector.py +223 -0
- htmlgraph/hooks/post-checkout.sh +28 -0
- htmlgraph/hooks/post-commit.sh +24 -0
- htmlgraph/hooks/post-merge.sh +26 -0
- htmlgraph/hooks/post_tool_use_failure.py +273 -0
- htmlgraph/hooks/post_tool_use_handler.py +257 -0
- htmlgraph/hooks/posttooluse.py +408 -0
- htmlgraph/hooks/pre-commit.sh +94 -0
- htmlgraph/hooks/pre-push.sh +28 -0
- htmlgraph/hooks/pretooluse.py +819 -0
- htmlgraph/hooks/prompt_analyzer.py +637 -0
- htmlgraph/hooks/session_handler.py +668 -0
- htmlgraph/hooks/session_summary.py +395 -0
- htmlgraph/hooks/state_manager.py +504 -0
- htmlgraph/hooks/subagent_detection.py +202 -0
- htmlgraph/hooks/subagent_stop.py +369 -0
- htmlgraph/hooks/task_enforcer.py +255 -0
- htmlgraph/hooks/task_validator.py +177 -0
- htmlgraph/hooks/validator.py +628 -0
- htmlgraph/ids.py +41 -27
- htmlgraph/index.d.ts +286 -0
- htmlgraph/learning.py +767 -0
- htmlgraph/mcp_server.py +69 -23
- htmlgraph/models.py +1586 -87
- htmlgraph/operations/README.md +62 -0
- htmlgraph/operations/__init__.py +79 -0
- htmlgraph/operations/analytics.py +339 -0
- htmlgraph/operations/bootstrap.py +289 -0
- htmlgraph/operations/events.py +244 -0
- htmlgraph/operations/fastapi_server.py +231 -0
- htmlgraph/operations/hooks.py +350 -0
- htmlgraph/operations/initialization.py +597 -0
- htmlgraph/operations/initialization.py.backup +228 -0
- htmlgraph/operations/server.py +303 -0
- htmlgraph/orchestration/__init__.py +58 -0
- htmlgraph/orchestration/claude_launcher.py +179 -0
- htmlgraph/orchestration/command_builder.py +72 -0
- htmlgraph/orchestration/headless_spawner.py +281 -0
- htmlgraph/orchestration/live_events.py +377 -0
- htmlgraph/orchestration/model_selection.py +327 -0
- htmlgraph/orchestration/plugin_manager.py +140 -0
- htmlgraph/orchestration/prompts.py +137 -0
- htmlgraph/orchestration/spawner_event_tracker.py +383 -0
- htmlgraph/orchestration/spawners/__init__.py +16 -0
- htmlgraph/orchestration/spawners/base.py +194 -0
- htmlgraph/orchestration/spawners/claude.py +173 -0
- htmlgraph/orchestration/spawners/codex.py +435 -0
- htmlgraph/orchestration/spawners/copilot.py +294 -0
- htmlgraph/orchestration/spawners/gemini.py +471 -0
- htmlgraph/orchestration/subprocess_runner.py +36 -0
- htmlgraph/orchestration/task_coordination.py +343 -0
- htmlgraph/orchestration.md +563 -0
- htmlgraph/orchestrator-system-prompt-optimized.txt +863 -0
- htmlgraph/orchestrator.py +669 -0
- htmlgraph/orchestrator_config.py +357 -0
- htmlgraph/orchestrator_mode.py +328 -0
- htmlgraph/orchestrator_validator.py +133 -0
- htmlgraph/parallel.py +646 -0
- htmlgraph/parser.py +160 -35
- htmlgraph/path_query.py +608 -0
- htmlgraph/pattern_matcher.py +636 -0
- htmlgraph/planning.py +147 -52
- htmlgraph/pydantic_models.py +476 -0
- htmlgraph/quality_gates.py +350 -0
- htmlgraph/query_builder.py +109 -72
- htmlgraph/query_composer.py +509 -0
- htmlgraph/reflection.py +443 -0
- htmlgraph/refs.py +344 -0
- htmlgraph/repo_hash.py +512 -0
- htmlgraph/repositories/__init__.py +292 -0
- htmlgraph/repositories/analytics_repository.py +455 -0
- htmlgraph/repositories/analytics_repository_standard.py +628 -0
- htmlgraph/repositories/feature_repository.py +581 -0
- htmlgraph/repositories/feature_repository_htmlfile.py +668 -0
- htmlgraph/repositories/feature_repository_memory.py +607 -0
- htmlgraph/repositories/feature_repository_sqlite.py +858 -0
- htmlgraph/repositories/filter_service.py +620 -0
- htmlgraph/repositories/filter_service_standard.py +445 -0
- htmlgraph/repositories/shared_cache.py +621 -0
- htmlgraph/repositories/shared_cache_memory.py +395 -0
- htmlgraph/repositories/track_repository.py +552 -0
- htmlgraph/repositories/track_repository_htmlfile.py +619 -0
- htmlgraph/repositories/track_repository_memory.py +508 -0
- htmlgraph/repositories/track_repository_sqlite.py +711 -0
- htmlgraph/routing.py +8 -19
- htmlgraph/scripts/deploy.py +1 -2
- htmlgraph/sdk/__init__.py +398 -0
- htmlgraph/sdk/__init__.pyi +14 -0
- htmlgraph/sdk/analytics/__init__.py +19 -0
- htmlgraph/sdk/analytics/engine.py +155 -0
- htmlgraph/sdk/analytics/helpers.py +178 -0
- htmlgraph/sdk/analytics/registry.py +109 -0
- htmlgraph/sdk/base.py +484 -0
- htmlgraph/sdk/constants.py +216 -0
- htmlgraph/sdk/core.pyi +308 -0
- htmlgraph/sdk/discovery.py +120 -0
- htmlgraph/sdk/help/__init__.py +12 -0
- htmlgraph/sdk/help/mixin.py +699 -0
- htmlgraph/sdk/mixins/__init__.py +15 -0
- htmlgraph/sdk/mixins/attribution.py +113 -0
- htmlgraph/sdk/mixins/mixin.py +410 -0
- htmlgraph/sdk/operations/__init__.py +12 -0
- htmlgraph/sdk/operations/mixin.py +427 -0
- htmlgraph/sdk/orchestration/__init__.py +17 -0
- htmlgraph/sdk/orchestration/coordinator.py +203 -0
- htmlgraph/sdk/orchestration/spawner.py +204 -0
- htmlgraph/sdk/planning/__init__.py +19 -0
- htmlgraph/sdk/planning/bottlenecks.py +93 -0
- htmlgraph/sdk/planning/mixin.py +211 -0
- htmlgraph/sdk/planning/parallel.py +186 -0
- htmlgraph/sdk/planning/queue.py +210 -0
- htmlgraph/sdk/planning/recommendations.py +87 -0
- htmlgraph/sdk/planning/smart_planning.py +319 -0
- htmlgraph/sdk/session/__init__.py +19 -0
- htmlgraph/sdk/session/continuity.py +57 -0
- htmlgraph/sdk/session/handoff.py +110 -0
- htmlgraph/sdk/session/info.py +309 -0
- htmlgraph/sdk/session/manager.py +103 -0
- htmlgraph/sdk/strategic/__init__.py +26 -0
- htmlgraph/sdk/strategic/mixin.py +563 -0
- htmlgraph/server.py +685 -180
- htmlgraph/services/__init__.py +10 -0
- htmlgraph/services/claiming.py +199 -0
- htmlgraph/session_hooks.py +300 -0
- htmlgraph/session_manager.py +1392 -175
- htmlgraph/session_registry.py +587 -0
- htmlgraph/session_state.py +436 -0
- htmlgraph/session_warning.py +201 -0
- htmlgraph/sessions/__init__.py +23 -0
- htmlgraph/sessions/handoff.py +756 -0
- htmlgraph/setup.py +34 -17
- htmlgraph/spike_index.py +143 -0
- htmlgraph/sync_docs.py +12 -15
- htmlgraph/system_prompts.py +450 -0
- htmlgraph/templates/AGENTS.md.template +366 -0
- htmlgraph/templates/CLAUDE.md.template +97 -0
- htmlgraph/templates/GEMINI.md.template +87 -0
- htmlgraph/templates/orchestration-view.html +350 -0
- htmlgraph/track_builder.py +146 -15
- htmlgraph/track_manager.py +69 -21
- htmlgraph/transcript.py +890 -0
- htmlgraph/transcript_analytics.py +699 -0
- htmlgraph/types.py +323 -0
- htmlgraph/validation.py +115 -0
- htmlgraph/watch.py +8 -5
- htmlgraph/work_type_utils.py +3 -2
- {htmlgraph-0.9.3.data → htmlgraph-0.27.5.data}/data/htmlgraph/dashboard.html +2406 -307
- htmlgraph-0.27.5.data/data/htmlgraph/templates/AGENTS.md.template +366 -0
- htmlgraph-0.27.5.data/data/htmlgraph/templates/CLAUDE.md.template +97 -0
- htmlgraph-0.27.5.data/data/htmlgraph/templates/GEMINI.md.template +87 -0
- {htmlgraph-0.9.3.dist-info → htmlgraph-0.27.5.dist-info}/METADATA +97 -64
- htmlgraph-0.27.5.dist-info/RECORD +337 -0
- {htmlgraph-0.9.3.dist-info → htmlgraph-0.27.5.dist-info}/entry_points.txt +1 -1
- htmlgraph/cli.py +0 -2688
- htmlgraph/sdk.py +0 -709
- htmlgraph-0.9.3.dist-info/RECORD +0 -61
- {htmlgraph-0.9.3.data → htmlgraph-0.27.5.data}/data/htmlgraph/styles.css +0 -0
- {htmlgraph-0.9.3.dist-info → htmlgraph-0.27.5.dist-info}/WHEEL +0 -0
|
@@ -0,0 +1,669 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
"""
|
|
4
|
+
SubagentOrchestrator for context-preserving delegation.
|
|
5
|
+
|
|
6
|
+
IMPERATIVE USAGE INSTRUCTIONS
|
|
7
|
+
=============================
|
|
8
|
+
|
|
9
|
+
As an orchestrator, you MUST follow these steps:
|
|
10
|
+
|
|
11
|
+
1. INITIALIZE
|
|
12
|
+
```python
|
|
13
|
+
from htmlgraph import SDK
|
|
14
|
+
sdk = SDK(agent="claude")
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
2. SPAWN EXPLORER (for codebase discovery)
|
|
18
|
+
```python
|
|
19
|
+
explorer = sdk.spawn_explorer(
|
|
20
|
+
task="Find all API endpoints",
|
|
21
|
+
scope="src/api/"
|
|
22
|
+
)
|
|
23
|
+
# Use with Task tool:
|
|
24
|
+
# Task(prompt=explorer["prompt"], subagent_type=explorer["subagent_type"])
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
3. SPAWN CODER (for implementation)
|
|
28
|
+
```python
|
|
29
|
+
coder = sdk.spawn_coder(
|
|
30
|
+
feature_id="feat-123",
|
|
31
|
+
context="Explorer found endpoints in src/api/routes.py",
|
|
32
|
+
test_command="uv run pytest"
|
|
33
|
+
)
|
|
34
|
+
# Use with Task tool:
|
|
35
|
+
# Task(prompt=coder["prompt"], subagent_type=coder["subagent_type"])
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
4. FULL ORCHESTRATION (explore + implement)
|
|
39
|
+
```python
|
|
40
|
+
prompts = sdk.orchestrate(
|
|
41
|
+
feature_id="feat-123",
|
|
42
|
+
exploration_scope="src/",
|
|
43
|
+
test_command="uv run pytest"
|
|
44
|
+
)
|
|
45
|
+
# Returns: {"explorer": {...}, "coder": {...}}
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
DECISION GUIDE
|
|
49
|
+
==============
|
|
50
|
+
|
|
51
|
+
| Scenario | Method |
|
|
52
|
+
|----------|--------|
|
|
53
|
+
| Unknown codebase | spawn_explorer first, then spawn_coder |
|
|
54
|
+
| Known codebase | spawn_coder directly |
|
|
55
|
+
| Complex feature | orchestrate for full workflow |
|
|
56
|
+
| Multiple features | spawn_coder in parallel |
|
|
57
|
+
|
|
58
|
+
ANTI-PATTERNS
|
|
59
|
+
=============
|
|
60
|
+
|
|
61
|
+
NEVER:
|
|
62
|
+
- Implement without exploration on unknown codebases
|
|
63
|
+
- Spawn coder without feature_id (create feature first!)
|
|
64
|
+
- Edit code yourself when you should delegate
|
|
65
|
+
|
|
66
|
+
ALWAYS:
|
|
67
|
+
- Create work item before spawning coder
|
|
68
|
+
- Pass explorer context to coder
|
|
69
|
+
- Let subagents do the heavy lifting
|
|
70
|
+
|
|
71
|
+
Available Classes
|
|
72
|
+
=================
|
|
73
|
+
|
|
74
|
+
SubagentType: Enum of subagent types (EXPLORER, CODER, REVIEWER, TESTER)
|
|
75
|
+
SubagentPrompt: Prepared prompt for spawning subagent via Task tool
|
|
76
|
+
SubagentResult: Parsed results from subagent execution
|
|
77
|
+
SubagentOrchestrator: Main orchestration class
|
|
78
|
+
|
|
79
|
+
Key Patterns
|
|
80
|
+
============
|
|
81
|
+
|
|
82
|
+
1. Two-phase workflow: Explorer discovers → Coder implements
|
|
83
|
+
2. Stateless subagents: Each spawned agent is ephemeral and task-focused
|
|
84
|
+
3. Context efficiency: Main session reserves context for orchestration
|
|
85
|
+
4. Parallel execution: Multiple subagents can work simultaneously
|
|
86
|
+
"""
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
from dataclasses import dataclass, field
|
|
90
|
+
from datetime import datetime
|
|
91
|
+
from enum import Enum
|
|
92
|
+
from typing import TYPE_CHECKING, Any
|
|
93
|
+
|
|
94
|
+
if TYPE_CHECKING:
|
|
95
|
+
from htmlgraph.sdk import SDK
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
class SubagentType(Enum):
|
|
99
|
+
"""Types of specialized subagents."""
|
|
100
|
+
|
|
101
|
+
EXPLORER = "explorer"
|
|
102
|
+
CODER = "coder"
|
|
103
|
+
REVIEWER = "reviewer"
|
|
104
|
+
TESTER = "tester"
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
@dataclass
|
|
108
|
+
class SubagentPrompt:
|
|
109
|
+
"""A prepared prompt for spawning a subagent via Task tool."""
|
|
110
|
+
|
|
111
|
+
prompt: str
|
|
112
|
+
description: str
|
|
113
|
+
subagent_type: str
|
|
114
|
+
task_id: str | None = None
|
|
115
|
+
|
|
116
|
+
# Expected outputs
|
|
117
|
+
expected_sections: list[str] = field(default_factory=list)
|
|
118
|
+
|
|
119
|
+
# Retry configuration
|
|
120
|
+
max_retries: int = 2
|
|
121
|
+
retry_delay_seconds: int = 5
|
|
122
|
+
|
|
123
|
+
def to_task_kwargs(self) -> dict[str, Any]:
|
|
124
|
+
"""Convert to kwargs for Task tool invocation."""
|
|
125
|
+
return {
|
|
126
|
+
"prompt": self.prompt,
|
|
127
|
+
"description": self.description,
|
|
128
|
+
"subagent_type": self.subagent_type,
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
|
|
132
|
+
@dataclass
|
|
133
|
+
class SubagentResult:
|
|
134
|
+
"""Parsed result from a subagent execution."""
|
|
135
|
+
|
|
136
|
+
subagent_type: SubagentType
|
|
137
|
+
task_id: str | None
|
|
138
|
+
success: bool
|
|
139
|
+
|
|
140
|
+
# Parsed outputs
|
|
141
|
+
summary: str = ""
|
|
142
|
+
files_found: list[str] = field(default_factory=list)
|
|
143
|
+
files_modified: list[str] = field(default_factory=list)
|
|
144
|
+
patterns_discovered: dict[str, list[str]] = field(default_factory=dict)
|
|
145
|
+
blockers: list[str] = field(default_factory=list)
|
|
146
|
+
recommendations: list[str] = field(default_factory=list)
|
|
147
|
+
|
|
148
|
+
# Raw output for debugging
|
|
149
|
+
raw_output: str = ""
|
|
150
|
+
|
|
151
|
+
# Metrics
|
|
152
|
+
duration_seconds: float = 0.0
|
|
153
|
+
tool_calls: int = 0
|
|
154
|
+
|
|
155
|
+
|
|
156
|
+
class SubagentOrchestrator:
|
|
157
|
+
"""
|
|
158
|
+
Orchestrates specialized subagents for exploration and coding tasks.
|
|
159
|
+
|
|
160
|
+
Benefits:
|
|
161
|
+
- Main session context reserved for orchestration decisions
|
|
162
|
+
- Parallel exploration and coding via ephemeral subagents
|
|
163
|
+
- Better context efficiency (subagents are stateless)
|
|
164
|
+
- More tasks completed before main context fills up
|
|
165
|
+
|
|
166
|
+
Example:
|
|
167
|
+
>>> orchestrator = SubagentOrchestrator(sdk)
|
|
168
|
+
>>>
|
|
169
|
+
>>> # Phase 1: Explore codebase
|
|
170
|
+
>>> explorer = orchestrator.spawn_explorer(
|
|
171
|
+
... task="Map the authentication system",
|
|
172
|
+
... scope="src/auth/",
|
|
173
|
+
... )
|
|
174
|
+
>>> # Execute with Task tool, get results
|
|
175
|
+
>>>
|
|
176
|
+
>>> # Phase 2: Implement changes
|
|
177
|
+
>>> coder = orchestrator.spawn_coder(
|
|
178
|
+
... feature_id="feat-auth-fix",
|
|
179
|
+
... context=explorer_results,
|
|
180
|
+
... )
|
|
181
|
+
"""
|
|
182
|
+
|
|
183
|
+
def __init__(self, sdk: SDK):
|
|
184
|
+
"""
|
|
185
|
+
Initialize orchestrator.
|
|
186
|
+
|
|
187
|
+
Args:
|
|
188
|
+
sdk: Parent SDK instance for accessing features and tracking
|
|
189
|
+
"""
|
|
190
|
+
self.sdk = sdk
|
|
191
|
+
self._directory = sdk._directory
|
|
192
|
+
|
|
193
|
+
def spawn_explorer(
|
|
194
|
+
self,
|
|
195
|
+
task: str,
|
|
196
|
+
scope: str | None = None,
|
|
197
|
+
patterns: list[str] | None = None,
|
|
198
|
+
questions: list[str] | None = None,
|
|
199
|
+
max_files: int = 50,
|
|
200
|
+
include_tests: bool = False,
|
|
201
|
+
) -> SubagentPrompt:
|
|
202
|
+
"""
|
|
203
|
+
Spawn an explorer subagent for codebase discovery and analysis.
|
|
204
|
+
|
|
205
|
+
Explorer agents are optimized for:
|
|
206
|
+
- Finding files matching patterns
|
|
207
|
+
- Searching for code patterns
|
|
208
|
+
- Mapping dependencies and relationships
|
|
209
|
+
- Answering architectural questions
|
|
210
|
+
|
|
211
|
+
Args:
|
|
212
|
+
task: What to explore/discover
|
|
213
|
+
scope: Directory scope (e.g., "src/", "tests/")
|
|
214
|
+
patterns: Glob patterns to focus on (e.g., ["**/*.py"])
|
|
215
|
+
questions: Specific questions to answer
|
|
216
|
+
max_files: Maximum files to read in detail
|
|
217
|
+
include_tests: Whether to include test files
|
|
218
|
+
|
|
219
|
+
Returns:
|
|
220
|
+
SubagentPrompt ready for Task tool
|
|
221
|
+
|
|
222
|
+
Example:
|
|
223
|
+
>>> prompt = orchestrator.spawn_explorer(
|
|
224
|
+
... task="Find all database models and their relationships",
|
|
225
|
+
... scope="src/models/",
|
|
226
|
+
... patterns=["**/*.py"],
|
|
227
|
+
... questions=["What ORM is used?", "How are relationships defined?"]
|
|
228
|
+
... )
|
|
229
|
+
"""
|
|
230
|
+
# Build scope directive
|
|
231
|
+
scope_directive = ""
|
|
232
|
+
if scope:
|
|
233
|
+
scope_directive = f"Focus on: {scope}"
|
|
234
|
+
if patterns:
|
|
235
|
+
scope_directive += f"\nPatterns: {', '.join(patterns)}"
|
|
236
|
+
|
|
237
|
+
# Build questions section
|
|
238
|
+
questions_section = ""
|
|
239
|
+
if questions:
|
|
240
|
+
questions_section = "## Questions to Answer\n" + "\n".join(
|
|
241
|
+
f"- {q}" for q in questions
|
|
242
|
+
)
|
|
243
|
+
|
|
244
|
+
prompt = f"""# Explorer Task: {task}
|
|
245
|
+
|
|
246
|
+
You are an EXPLORER subagent. Your job is to discover and analyze code, NOT modify it.
|
|
247
|
+
|
|
248
|
+
## Scope
|
|
249
|
+
{scope_directive or "Entire codebase"}
|
|
250
|
+
Max files to read in detail: {max_files}
|
|
251
|
+
Include tests: {include_tests}
|
|
252
|
+
|
|
253
|
+
{questions_section}
|
|
254
|
+
|
|
255
|
+
## Efficient Exploration Strategy
|
|
256
|
+
|
|
257
|
+
1. **Start with Glob** to find relevant files:
|
|
258
|
+
- Use Glob with patterns like "{patterns[0] if patterns else "**/*.py"}"
|
|
259
|
+
- This is faster than recursive directory exploration
|
|
260
|
+
|
|
261
|
+
2. **Use Grep for targeted search**:
|
|
262
|
+
- Search for keywords, class names, function signatures
|
|
263
|
+
- This finds exact locations without reading entire files
|
|
264
|
+
|
|
265
|
+
3. **Read strategically**:
|
|
266
|
+
- Only read files that Grep identified as relevant
|
|
267
|
+
- Read imports and class definitions first
|
|
268
|
+
- Skip boilerplate and generated code
|
|
269
|
+
|
|
270
|
+
4. **Map relationships**:
|
|
271
|
+
- Note imports and dependencies
|
|
272
|
+
- Identify inheritance and composition
|
|
273
|
+
- Document API boundaries
|
|
274
|
+
|
|
275
|
+
## Output Format
|
|
276
|
+
|
|
277
|
+
Return your findings in this exact format:
|
|
278
|
+
|
|
279
|
+
## Summary
|
|
280
|
+
[2-3 sentence overview of what you found]
|
|
281
|
+
|
|
282
|
+
## Files Found
|
|
283
|
+
- file1.py: [brief description]
|
|
284
|
+
- file2.py: [brief description]
|
|
285
|
+
...
|
|
286
|
+
|
|
287
|
+
## Key Patterns
|
|
288
|
+
### Pattern Name
|
|
289
|
+
- Description of pattern
|
|
290
|
+
- Where it's used
|
|
291
|
+
- Example code
|
|
292
|
+
|
|
293
|
+
## Answers
|
|
294
|
+
[Answer each question from Questions to Answer section]
|
|
295
|
+
|
|
296
|
+
## Recommendations
|
|
297
|
+
- [Suggestion for the coder agent]
|
|
298
|
+
- [Potential issues to watch for]
|
|
299
|
+
"""
|
|
300
|
+
|
|
301
|
+
return SubagentPrompt(
|
|
302
|
+
prompt=prompt,
|
|
303
|
+
description=f"Explore: {task[:40]}",
|
|
304
|
+
subagent_type="Explore", # Use the Explore agent type
|
|
305
|
+
expected_sections=["Summary", "Files Found", "Key Patterns"],
|
|
306
|
+
max_retries=1,
|
|
307
|
+
)
|
|
308
|
+
|
|
309
|
+
def spawn_coder(
|
|
310
|
+
self,
|
|
311
|
+
feature_id: str,
|
|
312
|
+
context: str | SubagentResult | None = None,
|
|
313
|
+
files_to_modify: list[str] | None = None,
|
|
314
|
+
test_command: str | None = None,
|
|
315
|
+
style_guide: str | None = None,
|
|
316
|
+
) -> SubagentPrompt:
|
|
317
|
+
"""
|
|
318
|
+
Spawn a coder subagent for implementing changes.
|
|
319
|
+
|
|
320
|
+
Coder agents are optimized for:
|
|
321
|
+
- Reading and modifying specific files
|
|
322
|
+
- Following patterns from exploration
|
|
323
|
+
- Running and fixing tests
|
|
324
|
+
- Maintaining code quality
|
|
325
|
+
|
|
326
|
+
Args:
|
|
327
|
+
feature_id: Feature being implemented
|
|
328
|
+
context: Results from explorer (string or SubagentResult)
|
|
329
|
+
files_to_modify: Specific files to change
|
|
330
|
+
test_command: Command to verify changes
|
|
331
|
+
style_guide: Code style guidelines
|
|
332
|
+
|
|
333
|
+
Returns:
|
|
334
|
+
SubagentPrompt ready for Task tool
|
|
335
|
+
|
|
336
|
+
Example:
|
|
337
|
+
>>> prompt = orchestrator.spawn_coder(
|
|
338
|
+
... feature_id="feat-add-auth",
|
|
339
|
+
... context=explorer_results,
|
|
340
|
+
... test_command="uv run pytest tests/auth/"
|
|
341
|
+
... )
|
|
342
|
+
"""
|
|
343
|
+
# Get feature details
|
|
344
|
+
feature = self.sdk.features.get(feature_id)
|
|
345
|
+
if not feature:
|
|
346
|
+
raise ValueError(f"Feature not found: {feature_id}")
|
|
347
|
+
|
|
348
|
+
# Build context section
|
|
349
|
+
context_section = ""
|
|
350
|
+
if isinstance(context, SubagentResult):
|
|
351
|
+
context_section = f"""## Context from Explorer
|
|
352
|
+
|
|
353
|
+
### Summary
|
|
354
|
+
{context.summary}
|
|
355
|
+
|
|
356
|
+
### Files to Consider
|
|
357
|
+
{chr(10).join(f"- {f}" for f in context.files_found[:20])}
|
|
358
|
+
|
|
359
|
+
### Patterns Discovered
|
|
360
|
+
{chr(10).join(f"- {k}: {v}" for k, v in list(context.patterns_discovered.items())[:5])}
|
|
361
|
+
|
|
362
|
+
### Recommendations
|
|
363
|
+
{chr(10).join(f"- {r}" for r in context.recommendations)}
|
|
364
|
+
"""
|
|
365
|
+
elif isinstance(context, str):
|
|
366
|
+
context_section = f"## Context from Explorer\n\n{context}"
|
|
367
|
+
|
|
368
|
+
# Build files section
|
|
369
|
+
files_section = ""
|
|
370
|
+
if files_to_modify:
|
|
371
|
+
files_section = "## Target Files\n" + "\n".join(
|
|
372
|
+
f"- {f}" for f in files_to_modify
|
|
373
|
+
)
|
|
374
|
+
|
|
375
|
+
# Build test section
|
|
376
|
+
test_section = ""
|
|
377
|
+
if test_command:
|
|
378
|
+
test_section = f"""## Testing
|
|
379
|
+
|
|
380
|
+
Run tests after changes:
|
|
381
|
+
```bash
|
|
382
|
+
{test_command}
|
|
383
|
+
```
|
|
384
|
+
|
|
385
|
+
If tests fail, fix the issues before completing.
|
|
386
|
+
"""
|
|
387
|
+
|
|
388
|
+
# Build style section
|
|
389
|
+
style_section = ""
|
|
390
|
+
if style_guide:
|
|
391
|
+
style_section = f"## Style Guide\n\n{style_guide}"
|
|
392
|
+
|
|
393
|
+
# Get feature steps
|
|
394
|
+
steps_section = ""
|
|
395
|
+
if feature.steps:
|
|
396
|
+
steps_lines = []
|
|
397
|
+
for i, step in enumerate(feature.steps, 1):
|
|
398
|
+
status = "✅" if step.completed else "⏳"
|
|
399
|
+
steps_lines.append(f"{i}. {status} {step.description}")
|
|
400
|
+
steps_section = "## Implementation Steps\n" + "\n".join(steps_lines)
|
|
401
|
+
|
|
402
|
+
prompt = f"""# Coder Task: {feature.title}
|
|
403
|
+
|
|
404
|
+
You are a CODER subagent. Your job is to implement changes efficiently.
|
|
405
|
+
|
|
406
|
+
Feature ID: {feature_id}
|
|
407
|
+
Priority: {feature.priority}
|
|
408
|
+
Status: {feature.status}
|
|
409
|
+
|
|
410
|
+
{context_section}
|
|
411
|
+
|
|
412
|
+
{files_section}
|
|
413
|
+
|
|
414
|
+
{steps_section}
|
|
415
|
+
|
|
416
|
+
{style_section}
|
|
417
|
+
|
|
418
|
+
## Efficient Implementation Strategy
|
|
419
|
+
|
|
420
|
+
1. **Read before Edit**:
|
|
421
|
+
- Read the target file first
|
|
422
|
+
- Understand existing patterns
|
|
423
|
+
- Plan your changes
|
|
424
|
+
|
|
425
|
+
2. **Batch Edits**:
|
|
426
|
+
- Make multiple related changes in sequence
|
|
427
|
+
- Don't switch between files unnecessarily
|
|
428
|
+
|
|
429
|
+
3. **Test incrementally**:
|
|
430
|
+
- Run tests after significant changes
|
|
431
|
+
- Fix issues immediately
|
|
432
|
+
|
|
433
|
+
4. **Update feature tracking**:
|
|
434
|
+
- Mark steps as complete as you go
|
|
435
|
+
- Note any blockers
|
|
436
|
+
|
|
437
|
+
{test_section}
|
|
438
|
+
|
|
439
|
+
## Output Format
|
|
440
|
+
|
|
441
|
+
Return your results in this exact format:
|
|
442
|
+
|
|
443
|
+
## Summary
|
|
444
|
+
[What was implemented]
|
|
445
|
+
|
|
446
|
+
## Files Modified
|
|
447
|
+
- file1.py: [what changed]
|
|
448
|
+
- file2.py: [what changed]
|
|
449
|
+
|
|
450
|
+
## Tests
|
|
451
|
+
[Test results - PASS/FAIL with details]
|
|
452
|
+
|
|
453
|
+
## Blockers
|
|
454
|
+
[Any issues preventing completion, or "None"]
|
|
455
|
+
|
|
456
|
+
## Status
|
|
457
|
+
[COMPLETE or IN_PROGRESS with next steps]
|
|
458
|
+
"""
|
|
459
|
+
|
|
460
|
+
return SubagentPrompt(
|
|
461
|
+
prompt=prompt,
|
|
462
|
+
description=f"Code: {feature.title[:40]}",
|
|
463
|
+
subagent_type="general-purpose",
|
|
464
|
+
task_id=feature_id,
|
|
465
|
+
expected_sections=["Summary", "Files Modified", "Status"],
|
|
466
|
+
max_retries=2,
|
|
467
|
+
)
|
|
468
|
+
|
|
469
|
+
def parse_explorer_result(self, output: str) -> SubagentResult:
|
|
470
|
+
"""
|
|
471
|
+
Parse the output from an explorer subagent.
|
|
472
|
+
|
|
473
|
+
Args:
|
|
474
|
+
output: Raw output text from the explorer
|
|
475
|
+
|
|
476
|
+
Returns:
|
|
477
|
+
Structured SubagentResult
|
|
478
|
+
"""
|
|
479
|
+
result = SubagentResult(
|
|
480
|
+
subagent_type=SubagentType.EXPLORER,
|
|
481
|
+
task_id=None,
|
|
482
|
+
success=True,
|
|
483
|
+
raw_output=output,
|
|
484
|
+
)
|
|
485
|
+
|
|
486
|
+
# Parse sections
|
|
487
|
+
current_section = ""
|
|
488
|
+
current_content: list[str] = []
|
|
489
|
+
|
|
490
|
+
for line in output.split("\n"):
|
|
491
|
+
if line.startswith("## "):
|
|
492
|
+
# Save previous section
|
|
493
|
+
if current_section == "Summary":
|
|
494
|
+
result.summary = "\n".join(current_content).strip()
|
|
495
|
+
elif current_section == "Files Found":
|
|
496
|
+
result.files_found = [
|
|
497
|
+
l.split(":")[0].strip("- ").strip()
|
|
498
|
+
for l in current_content
|
|
499
|
+
if l.strip().startswith("-")
|
|
500
|
+
]
|
|
501
|
+
elif current_section == "Recommendations":
|
|
502
|
+
result.recommendations = [
|
|
503
|
+
l.strip("- ").strip()
|
|
504
|
+
for l in current_content
|
|
505
|
+
if l.strip().startswith("-")
|
|
506
|
+
]
|
|
507
|
+
|
|
508
|
+
# Start new section
|
|
509
|
+
current_section = line[3:].strip()
|
|
510
|
+
current_content = []
|
|
511
|
+
else:
|
|
512
|
+
current_content.append(line)
|
|
513
|
+
|
|
514
|
+
# Don't forget last section
|
|
515
|
+
if current_section == "Summary":
|
|
516
|
+
result.summary = "\n".join(current_content).strip()
|
|
517
|
+
elif current_section == "Files Found":
|
|
518
|
+
result.files_found = [
|
|
519
|
+
l.split(":")[0].strip("- ").strip()
|
|
520
|
+
for l in current_content
|
|
521
|
+
if l.strip().startswith("-")
|
|
522
|
+
]
|
|
523
|
+
elif current_section == "Recommendations":
|
|
524
|
+
result.recommendations = [
|
|
525
|
+
l.strip("- ").strip()
|
|
526
|
+
for l in current_content
|
|
527
|
+
if l.strip().startswith("-")
|
|
528
|
+
]
|
|
529
|
+
|
|
530
|
+
return result
|
|
531
|
+
|
|
532
|
+
def parse_coder_result(self, output: str) -> SubagentResult:
|
|
533
|
+
"""
|
|
534
|
+
Parse the output from a coder subagent.
|
|
535
|
+
|
|
536
|
+
Args:
|
|
537
|
+
output: Raw output text from the coder
|
|
538
|
+
|
|
539
|
+
Returns:
|
|
540
|
+
Structured SubagentResult
|
|
541
|
+
"""
|
|
542
|
+
result = SubagentResult(
|
|
543
|
+
subagent_type=SubagentType.CODER,
|
|
544
|
+
task_id=None,
|
|
545
|
+
success="COMPLETE" in output.upper(),
|
|
546
|
+
raw_output=output,
|
|
547
|
+
)
|
|
548
|
+
|
|
549
|
+
# Parse sections
|
|
550
|
+
current_section = ""
|
|
551
|
+
current_content: list[str] = []
|
|
552
|
+
|
|
553
|
+
for line in output.split("\n"):
|
|
554
|
+
if line.startswith("## "):
|
|
555
|
+
# Save previous section
|
|
556
|
+
if current_section == "Summary":
|
|
557
|
+
result.summary = "\n".join(current_content).strip()
|
|
558
|
+
elif current_section == "Files Modified":
|
|
559
|
+
result.files_modified = [
|
|
560
|
+
l.split(":")[0].strip("- ").strip()
|
|
561
|
+
for l in current_content
|
|
562
|
+
if l.strip().startswith("-")
|
|
563
|
+
]
|
|
564
|
+
elif current_section == "Blockers":
|
|
565
|
+
blockers = "\n".join(current_content).strip()
|
|
566
|
+
if blockers.lower() != "none":
|
|
567
|
+
result.blockers = [blockers]
|
|
568
|
+
result.success = False
|
|
569
|
+
|
|
570
|
+
# Start new section
|
|
571
|
+
current_section = line[3:].strip()
|
|
572
|
+
current_content = []
|
|
573
|
+
else:
|
|
574
|
+
current_content.append(line)
|
|
575
|
+
|
|
576
|
+
return result
|
|
577
|
+
|
|
578
|
+
def update_feature_from_result(
|
|
579
|
+
self,
|
|
580
|
+
feature_id: str,
|
|
581
|
+
result: SubagentResult,
|
|
582
|
+
) -> None:
|
|
583
|
+
"""
|
|
584
|
+
Update a feature based on coder subagent results.
|
|
585
|
+
|
|
586
|
+
Args:
|
|
587
|
+
feature_id: Feature to update
|
|
588
|
+
result: Result from coder subagent
|
|
589
|
+
"""
|
|
590
|
+
feature = self.sdk.features.get(feature_id)
|
|
591
|
+
if not feature:
|
|
592
|
+
return
|
|
593
|
+
|
|
594
|
+
with self.sdk.features.edit(feature_id) as f:
|
|
595
|
+
# Update status based on result
|
|
596
|
+
if result.success:
|
|
597
|
+
f.status = "done"
|
|
598
|
+
f.properties["completed_at"] = datetime.now().isoformat()
|
|
599
|
+
elif result.blockers:
|
|
600
|
+
f.status = "blocked"
|
|
601
|
+
f.properties["blockers"] = result.blockers
|
|
602
|
+
else:
|
|
603
|
+
f.status = "in-progress"
|
|
604
|
+
|
|
605
|
+
# Store implementation details
|
|
606
|
+
f.properties["files_modified"] = result.files_modified
|
|
607
|
+
f.properties["implementation_summary"] = result.summary
|
|
608
|
+
|
|
609
|
+
def orchestrate_feature(
|
|
610
|
+
self,
|
|
611
|
+
feature_id: str,
|
|
612
|
+
exploration_scope: str | None = None,
|
|
613
|
+
test_command: str | None = None,
|
|
614
|
+
) -> dict[str, SubagentPrompt]:
|
|
615
|
+
"""
|
|
616
|
+
Generate prompts for full feature orchestration (explore then code).
|
|
617
|
+
|
|
618
|
+
This is a convenience method that creates both explorer and coder
|
|
619
|
+
prompts for a complete feature implementation workflow.
|
|
620
|
+
|
|
621
|
+
Args:
|
|
622
|
+
feature_id: Feature to implement
|
|
623
|
+
exploration_scope: Directory to explore (optional)
|
|
624
|
+
test_command: Test command for verification
|
|
625
|
+
|
|
626
|
+
Returns:
|
|
627
|
+
Dict with 'explorer' and 'coder' prompts
|
|
628
|
+
|
|
629
|
+
Example:
|
|
630
|
+
>>> prompts = orchestrator.orchestrate_feature(
|
|
631
|
+
... "feat-add-caching",
|
|
632
|
+
... exploration_scope="src/cache/",
|
|
633
|
+
... test_command="uv run pytest tests/cache/"
|
|
634
|
+
... )
|
|
635
|
+
>>> # Execute explorer first
|
|
636
|
+
>>> explorer_result = execute_task(prompts['explorer'])
|
|
637
|
+
>>> # Then execute coder with explorer results
|
|
638
|
+
>>> coder_prompt = orchestrator.spawn_coder(
|
|
639
|
+
... feature_id,
|
|
640
|
+
... context=explorer_result
|
|
641
|
+
... )
|
|
642
|
+
"""
|
|
643
|
+
feature = self.sdk.features.get(feature_id)
|
|
644
|
+
if not feature:
|
|
645
|
+
raise ValueError(f"Feature not found: {feature_id}")
|
|
646
|
+
|
|
647
|
+
# Generate explorer prompt
|
|
648
|
+
explorer = self.spawn_explorer(
|
|
649
|
+
task=f"Explore codebase for: {feature.title}",
|
|
650
|
+
scope=exploration_scope,
|
|
651
|
+
questions=[
|
|
652
|
+
"What existing code is relevant?",
|
|
653
|
+
"What patterns should be followed?",
|
|
654
|
+
"What files need modification?",
|
|
655
|
+
],
|
|
656
|
+
)
|
|
657
|
+
|
|
658
|
+
# Note: coder prompt should be generated after explorer results
|
|
659
|
+
# We provide a placeholder that can be used once explorer completes
|
|
660
|
+
coder = self.spawn_coder(
|
|
661
|
+
feature_id=feature_id,
|
|
662
|
+
context="[Insert explorer results here]",
|
|
663
|
+
test_command=test_command,
|
|
664
|
+
)
|
|
665
|
+
|
|
666
|
+
return {
|
|
667
|
+
"explorer": explorer,
|
|
668
|
+
"coder": coder,
|
|
669
|
+
}
|