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,343 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
|
|
3
|
+
logger = logging.getLogger(__name__)
|
|
4
|
+
|
|
5
|
+
"""
|
|
6
|
+
Orchestration helpers for reliable parallel task coordination.
|
|
7
|
+
|
|
8
|
+
Provides Task ID pattern for retrieving results from parallel delegations.
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
import time
|
|
12
|
+
import uuid
|
|
13
|
+
from datetime import datetime, timedelta
|
|
14
|
+
from typing import TYPE_CHECKING, Any
|
|
15
|
+
|
|
16
|
+
if TYPE_CHECKING:
|
|
17
|
+
from htmlgraph.sdk import SDK
|
|
18
|
+
else:
|
|
19
|
+
# Avoid circular import during module initialization
|
|
20
|
+
SDK = None
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def generate_task_id() -> str:
|
|
24
|
+
"""
|
|
25
|
+
Generate unique task ID for traceability.
|
|
26
|
+
|
|
27
|
+
Returns:
|
|
28
|
+
Unique task ID (e.g., "task-a3f8b29c")
|
|
29
|
+
"""
|
|
30
|
+
return f"task-{uuid.uuid4().hex[:8]}"
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def delegate_with_id(
|
|
34
|
+
description: str,
|
|
35
|
+
prompt: str,
|
|
36
|
+
subagent_type: str = "general-purpose",
|
|
37
|
+
) -> tuple[str, str]:
|
|
38
|
+
"""
|
|
39
|
+
Delegate task with unique ID for result retrieval.
|
|
40
|
+
|
|
41
|
+
Args:
|
|
42
|
+
description: Human-readable task description
|
|
43
|
+
prompt: Task instructions for subagent
|
|
44
|
+
subagent_type: Type of subagent to use
|
|
45
|
+
|
|
46
|
+
Returns:
|
|
47
|
+
tuple[task_id, enhanced_prompt]: Unique identifier and enhanced prompt
|
|
48
|
+
|
|
49
|
+
Example:
|
|
50
|
+
task_id, enhanced_prompt = delegate_with_id(
|
|
51
|
+
"Implement authentication",
|
|
52
|
+
"Add JWT auth to API...",
|
|
53
|
+
"general-purpose"
|
|
54
|
+
)
|
|
55
|
+
# Orchestrator calls: Task(prompt=enhanced_prompt, ...)
|
|
56
|
+
results = get_results_by_task_id(sdk, task_id)
|
|
57
|
+
"""
|
|
58
|
+
task_id = generate_task_id()
|
|
59
|
+
|
|
60
|
+
# Inject task ID into prompt for traceability
|
|
61
|
+
# Note: Orchestrator will capture results and save to HtmlGraph, NOT the subagent
|
|
62
|
+
enhanced_prompt = f"""
|
|
63
|
+
TASK_ID: {task_id}
|
|
64
|
+
TASK_DESCRIPTION: {description}
|
|
65
|
+
|
|
66
|
+
{prompt}
|
|
67
|
+
|
|
68
|
+
📝 Note: This task has ID {task_id} for tracking purposes.
|
|
69
|
+
Provide detailed findings in your response.
|
|
70
|
+
"""
|
|
71
|
+
|
|
72
|
+
# The orchestrator will:
|
|
73
|
+
# 1. Call: Task(prompt=enhanced_prompt, description=f"{task_id}: {description}")
|
|
74
|
+
# 2. Capture the result from Task() function return
|
|
75
|
+
# 3. Optionally validate/test the result
|
|
76
|
+
# 4. Save to HtmlGraph spike using save_task_results()
|
|
77
|
+
# 5. Link to work items (features, tracks, etc.)
|
|
78
|
+
|
|
79
|
+
return task_id, enhanced_prompt
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
def get_results_by_task_id(
|
|
83
|
+
sdk: "SDK",
|
|
84
|
+
task_id: str,
|
|
85
|
+
timeout: int = 60,
|
|
86
|
+
poll_interval: int = 2,
|
|
87
|
+
) -> dict[str, Any]:
|
|
88
|
+
"""
|
|
89
|
+
Retrieve task results by task ID with polling.
|
|
90
|
+
|
|
91
|
+
Polls HtmlGraph spikes for results with task ID in title.
|
|
92
|
+
Works with parallel tasks - each has unique ID.
|
|
93
|
+
|
|
94
|
+
Args:
|
|
95
|
+
sdk: HtmlGraph SDK instance
|
|
96
|
+
task_id: Task ID returned by delegate_with_id()
|
|
97
|
+
timeout: Maximum seconds to wait for results
|
|
98
|
+
poll_interval: Seconds between polling attempts
|
|
99
|
+
|
|
100
|
+
Returns:
|
|
101
|
+
Results dict with:
|
|
102
|
+
- success: bool
|
|
103
|
+
- task_id: str
|
|
104
|
+
- spike_id: str (if found)
|
|
105
|
+
- findings: str (if found)
|
|
106
|
+
- error: str (if not found)
|
|
107
|
+
|
|
108
|
+
Example:
|
|
109
|
+
results = get_results_by_task_id(sdk, "task-a3f8b29c", timeout=120)
|
|
110
|
+
if results["success"]:
|
|
111
|
+
print(results["findings"])
|
|
112
|
+
"""
|
|
113
|
+
deadline = datetime.utcnow() + timedelta(seconds=timeout)
|
|
114
|
+
attempts = 0
|
|
115
|
+
|
|
116
|
+
while datetime.utcnow() < deadline:
|
|
117
|
+
attempts += 1
|
|
118
|
+
|
|
119
|
+
# Get all spikes and search for task ID in title
|
|
120
|
+
spikes = sdk.spikes.all()
|
|
121
|
+
matching = [s for s in spikes if task_id in s.title]
|
|
122
|
+
|
|
123
|
+
if matching:
|
|
124
|
+
spike = matching[0]
|
|
125
|
+
# Access findings attribute (available on Spike nodes)
|
|
126
|
+
findings = getattr(spike, "findings", None)
|
|
127
|
+
return {
|
|
128
|
+
"success": True,
|
|
129
|
+
"task_id": task_id,
|
|
130
|
+
"spike_id": spike.id,
|
|
131
|
+
"title": spike.title,
|
|
132
|
+
"findings": findings,
|
|
133
|
+
"attempts": attempts,
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
# Wait before next poll
|
|
137
|
+
time.sleep(poll_interval)
|
|
138
|
+
|
|
139
|
+
# Timeout - no results found
|
|
140
|
+
return {
|
|
141
|
+
"success": False,
|
|
142
|
+
"task_id": task_id,
|
|
143
|
+
"error": f"No results found for task {task_id} within {timeout}s",
|
|
144
|
+
"attempts": attempts,
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
|
|
148
|
+
def parallel_delegate(
|
|
149
|
+
sdk: "SDK",
|
|
150
|
+
tasks: list[dict[str, str]],
|
|
151
|
+
timeout: int = 120,
|
|
152
|
+
) -> dict[str, dict[str, Any]]:
|
|
153
|
+
"""
|
|
154
|
+
Coordinate multiple parallel tasks with result retrieval.
|
|
155
|
+
|
|
156
|
+
Args:
|
|
157
|
+
sdk: HtmlGraph SDK instance
|
|
158
|
+
tasks: List of task dicts with keys: description, prompt, subagent_type
|
|
159
|
+
timeout: Maximum seconds to wait for all results
|
|
160
|
+
|
|
161
|
+
Returns:
|
|
162
|
+
Dict mapping task_id to results for each task
|
|
163
|
+
|
|
164
|
+
Example:
|
|
165
|
+
results = parallel_delegate(sdk, [
|
|
166
|
+
{"description": "Implement auth", "prompt": "...", "subagent_type": "general-purpose"},
|
|
167
|
+
{"description": "Write tests", "prompt": "...", "subagent_type": "general-purpose"},
|
|
168
|
+
{"description": "Update docs", "prompt": "...", "subagent_type": "general-purpose"},
|
|
169
|
+
])
|
|
170
|
+
|
|
171
|
+
for task_id, result in results.items():
|
|
172
|
+
logger.info(f"{task_id}: {result['findings']}")
|
|
173
|
+
"""
|
|
174
|
+
# Generate task IDs and enhanced prompts
|
|
175
|
+
task_mapping = {}
|
|
176
|
+
for task in tasks:
|
|
177
|
+
task_id, enhanced_prompt = delegate_with_id(
|
|
178
|
+
task["description"],
|
|
179
|
+
task["prompt"],
|
|
180
|
+
task.get("subagent_type", "general-purpose"),
|
|
181
|
+
)
|
|
182
|
+
task_mapping[task_id] = {
|
|
183
|
+
"description": task["description"],
|
|
184
|
+
"prompt": enhanced_prompt,
|
|
185
|
+
"subagent_type": task.get("subagent_type", "general-purpose"),
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
# Note: Orchestrator should spawn all Task() calls here in parallel
|
|
189
|
+
# This function returns the mapping for orchestrator to use
|
|
190
|
+
|
|
191
|
+
# Wait for all results
|
|
192
|
+
results = {}
|
|
193
|
+
for task_id in task_mapping:
|
|
194
|
+
results[task_id] = get_results_by_task_id(sdk, task_id, timeout=timeout)
|
|
195
|
+
|
|
196
|
+
return results
|
|
197
|
+
|
|
198
|
+
|
|
199
|
+
def save_task_results(
|
|
200
|
+
sdk: "SDK",
|
|
201
|
+
task_id: str,
|
|
202
|
+
description: str,
|
|
203
|
+
results: str,
|
|
204
|
+
feature_id: str | None = None,
|
|
205
|
+
status: str = "completed",
|
|
206
|
+
) -> str:
|
|
207
|
+
"""
|
|
208
|
+
Save task results to HtmlGraph spike (orchestrator-side).
|
|
209
|
+
|
|
210
|
+
This is the recommended pattern for saving delegation results.
|
|
211
|
+
The orchestrator captures Task() output and saves it, rather than
|
|
212
|
+
relying on subagents to save their own results.
|
|
213
|
+
|
|
214
|
+
Args:
|
|
215
|
+
sdk: HtmlGraph SDK instance
|
|
216
|
+
task_id: Task ID from delegate_with_id()
|
|
217
|
+
description: Task description
|
|
218
|
+
results: Task results (from Task() function return)
|
|
219
|
+
feature_id: Optional feature ID to link
|
|
220
|
+
status: Task status (completed, failed, partial)
|
|
221
|
+
|
|
222
|
+
Returns:
|
|
223
|
+
Spike ID
|
|
224
|
+
|
|
225
|
+
Example:
|
|
226
|
+
task_id, prompt = delegate_with_id("Implement auth", "Add JWT...")
|
|
227
|
+
|
|
228
|
+
# Call Task() and capture result
|
|
229
|
+
result = Task(prompt=prompt, description=f"{task_id}: Implement auth")
|
|
230
|
+
|
|
231
|
+
# Orchestrator saves the result
|
|
232
|
+
spike_id = save_task_results(
|
|
233
|
+
sdk, task_id, "Implement auth", result,
|
|
234
|
+
feature_id="feat-123", status="completed"
|
|
235
|
+
)
|
|
236
|
+
"""
|
|
237
|
+
# Create spike with task results (chain all calls)
|
|
238
|
+
findings = f"""
|
|
239
|
+
# Task: {description}
|
|
240
|
+
# Task ID: {task_id}
|
|
241
|
+
# Status: {status}
|
|
242
|
+
|
|
243
|
+
## Results
|
|
244
|
+
|
|
245
|
+
{results}
|
|
246
|
+
|
|
247
|
+
## Linked Work Items
|
|
248
|
+
{f"- Feature: {feature_id}" if feature_id else "None"}
|
|
249
|
+
|
|
250
|
+
## Metadata
|
|
251
|
+
- Saved by: orchestrator
|
|
252
|
+
- Task pattern: delegate_with_id
|
|
253
|
+
"""
|
|
254
|
+
|
|
255
|
+
spike = (
|
|
256
|
+
sdk.spikes.create(f"Results: {task_id} - {description}")
|
|
257
|
+
.set_findings(findings)
|
|
258
|
+
.save()
|
|
259
|
+
)
|
|
260
|
+
|
|
261
|
+
# Link to feature if provided
|
|
262
|
+
if feature_id:
|
|
263
|
+
try:
|
|
264
|
+
with sdk.features.edit(feature_id) as _:
|
|
265
|
+
# Add activity log entry when method is available
|
|
266
|
+
pass
|
|
267
|
+
except Exception:
|
|
268
|
+
pass # Feature linking is optional
|
|
269
|
+
|
|
270
|
+
return str(spike.id)
|
|
271
|
+
|
|
272
|
+
|
|
273
|
+
def validate_and_save(
|
|
274
|
+
sdk: "SDK",
|
|
275
|
+
task_id: str,
|
|
276
|
+
description: str,
|
|
277
|
+
results: str,
|
|
278
|
+
validation_prompt: str | None = None,
|
|
279
|
+
feature_id: str | None = None,
|
|
280
|
+
) -> dict[str, Any]:
|
|
281
|
+
"""
|
|
282
|
+
Validate task results and save to HtmlGraph.
|
|
283
|
+
|
|
284
|
+
Optionally delegates validation to a testing agent before saving.
|
|
285
|
+
This implements quality gates in the orchestration pattern.
|
|
286
|
+
|
|
287
|
+
Args:
|
|
288
|
+
sdk: HtmlGraph SDK instance
|
|
289
|
+
task_id: Task ID from delegate_with_id()
|
|
290
|
+
description: Task description
|
|
291
|
+
results: Task results to validate
|
|
292
|
+
validation_prompt: Optional prompt for validation agent
|
|
293
|
+
feature_id: Optional feature ID to link
|
|
294
|
+
|
|
295
|
+
Returns:
|
|
296
|
+
Dict with:
|
|
297
|
+
- validated: bool
|
|
298
|
+
- spike_id: str
|
|
299
|
+
- validation_results: str (if validation performed)
|
|
300
|
+
|
|
301
|
+
Example:
|
|
302
|
+
# Delegate implementation
|
|
303
|
+
impl_id, impl_prompt = delegate_with_id("Add auth", "Implement JWT...")
|
|
304
|
+
impl_result = Task(prompt=impl_prompt, ...)
|
|
305
|
+
|
|
306
|
+
# Validate and save
|
|
307
|
+
outcome = validate_and_save(
|
|
308
|
+
sdk, impl_id, "Add auth", impl_result,
|
|
309
|
+
validation_prompt="Run tests and verify auth works",
|
|
310
|
+
feature_id="feat-auth"
|
|
311
|
+
)
|
|
312
|
+
|
|
313
|
+
if outcome["validated"]:
|
|
314
|
+
logger.info(f"✅ Saved to spike: {outcome['spike_id']}")
|
|
315
|
+
"""
|
|
316
|
+
validated = True
|
|
317
|
+
validation_results = None
|
|
318
|
+
|
|
319
|
+
# Optional validation step
|
|
320
|
+
if validation_prompt:
|
|
321
|
+
test_id, test_prompt = delegate_with_id(
|
|
322
|
+
f"Validate: {description}",
|
|
323
|
+
f"{validation_prompt}\n\nResults to validate:\n{results}",
|
|
324
|
+
"general-purpose",
|
|
325
|
+
)
|
|
326
|
+
|
|
327
|
+
# Note: Orchestrator should call Task() here to run validation
|
|
328
|
+
# validation_results = Task(prompt=test_prompt, ...)
|
|
329
|
+
# For now, we'll assume validation happens externally
|
|
330
|
+
|
|
331
|
+
# Determine status based on validation
|
|
332
|
+
status = "completed" if validated else "needs-review"
|
|
333
|
+
|
|
334
|
+
# Save results
|
|
335
|
+
spike_id = save_task_results(
|
|
336
|
+
sdk, task_id, description, results, feature_id=feature_id, status=status
|
|
337
|
+
)
|
|
338
|
+
|
|
339
|
+
return {
|
|
340
|
+
"validated": validated,
|
|
341
|
+
"spike_id": spike_id,
|
|
342
|
+
"validation_results": validation_results,
|
|
343
|
+
}
|