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.
Files changed (331) hide show
  1. htmlgraph/.htmlgraph/.session-warning-state.json +6 -0
  2. htmlgraph/.htmlgraph/agents.json +72 -0
  3. htmlgraph/.htmlgraph/htmlgraph.db +0 -0
  4. htmlgraph/__init__.py +173 -17
  5. htmlgraph/__init__.pyi +123 -0
  6. htmlgraph/agent_detection.py +127 -0
  7. htmlgraph/agent_registry.py +45 -30
  8. htmlgraph/agents.py +160 -107
  9. htmlgraph/analytics/__init__.py +9 -2
  10. htmlgraph/analytics/cli.py +190 -51
  11. htmlgraph/analytics/cost_analyzer.py +391 -0
  12. htmlgraph/analytics/cost_monitor.py +664 -0
  13. htmlgraph/analytics/cost_reporter.py +675 -0
  14. htmlgraph/analytics/cross_session.py +617 -0
  15. htmlgraph/analytics/dependency.py +192 -100
  16. htmlgraph/analytics/pattern_learning.py +771 -0
  17. htmlgraph/analytics/session_graph.py +707 -0
  18. htmlgraph/analytics/strategic/__init__.py +80 -0
  19. htmlgraph/analytics/strategic/cost_optimizer.py +611 -0
  20. htmlgraph/analytics/strategic/pattern_detector.py +876 -0
  21. htmlgraph/analytics/strategic/preference_manager.py +709 -0
  22. htmlgraph/analytics/strategic/suggestion_engine.py +747 -0
  23. htmlgraph/analytics/work_type.py +190 -14
  24. htmlgraph/analytics_index.py +135 -51
  25. htmlgraph/api/__init__.py +3 -0
  26. htmlgraph/api/cost_alerts_websocket.py +416 -0
  27. htmlgraph/api/main.py +2498 -0
  28. htmlgraph/api/static/htmx.min.js +1 -0
  29. htmlgraph/api/static/style-redesign.css +1344 -0
  30. htmlgraph/api/static/style.css +1079 -0
  31. htmlgraph/api/templates/dashboard-redesign.html +1366 -0
  32. htmlgraph/api/templates/dashboard.html +794 -0
  33. htmlgraph/api/templates/partials/activity-feed-hierarchical.html +326 -0
  34. htmlgraph/api/templates/partials/activity-feed.html +1100 -0
  35. htmlgraph/api/templates/partials/agents-redesign.html +317 -0
  36. htmlgraph/api/templates/partials/agents.html +317 -0
  37. htmlgraph/api/templates/partials/event-traces.html +373 -0
  38. htmlgraph/api/templates/partials/features-kanban-redesign.html +509 -0
  39. htmlgraph/api/templates/partials/features.html +578 -0
  40. htmlgraph/api/templates/partials/metrics-redesign.html +346 -0
  41. htmlgraph/api/templates/partials/metrics.html +346 -0
  42. htmlgraph/api/templates/partials/orchestration-redesign.html +443 -0
  43. htmlgraph/api/templates/partials/orchestration.html +198 -0
  44. htmlgraph/api/templates/partials/spawners.html +375 -0
  45. htmlgraph/api/templates/partials/work-items.html +613 -0
  46. htmlgraph/api/websocket.py +538 -0
  47. htmlgraph/archive/__init__.py +24 -0
  48. htmlgraph/archive/bloom.py +234 -0
  49. htmlgraph/archive/fts.py +297 -0
  50. htmlgraph/archive/manager.py +583 -0
  51. htmlgraph/archive/search.py +244 -0
  52. htmlgraph/atomic_ops.py +560 -0
  53. htmlgraph/attribute_index.py +208 -0
  54. htmlgraph/bounded_paths.py +539 -0
  55. htmlgraph/builders/__init__.py +14 -0
  56. htmlgraph/builders/base.py +118 -29
  57. htmlgraph/builders/bug.py +150 -0
  58. htmlgraph/builders/chore.py +119 -0
  59. htmlgraph/builders/epic.py +150 -0
  60. htmlgraph/builders/feature.py +31 -6
  61. htmlgraph/builders/insight.py +195 -0
  62. htmlgraph/builders/metric.py +217 -0
  63. htmlgraph/builders/pattern.py +202 -0
  64. htmlgraph/builders/phase.py +162 -0
  65. htmlgraph/builders/spike.py +52 -19
  66. htmlgraph/builders/track.py +148 -72
  67. htmlgraph/cigs/__init__.py +81 -0
  68. htmlgraph/cigs/autonomy.py +385 -0
  69. htmlgraph/cigs/cost.py +475 -0
  70. htmlgraph/cigs/messages_basic.py +472 -0
  71. htmlgraph/cigs/messaging.py +365 -0
  72. htmlgraph/cigs/models.py +771 -0
  73. htmlgraph/cigs/pattern_storage.py +427 -0
  74. htmlgraph/cigs/patterns.py +503 -0
  75. htmlgraph/cigs/posttool_analyzer.py +234 -0
  76. htmlgraph/cigs/reporter.py +818 -0
  77. htmlgraph/cigs/tracker.py +317 -0
  78. htmlgraph/cli/.htmlgraph/.session-warning-state.json +6 -0
  79. htmlgraph/cli/.htmlgraph/agents.json +72 -0
  80. htmlgraph/cli/.htmlgraph/htmlgraph.db +0 -0
  81. htmlgraph/cli/__init__.py +42 -0
  82. htmlgraph/cli/__main__.py +6 -0
  83. htmlgraph/cli/analytics.py +1424 -0
  84. htmlgraph/cli/base.py +685 -0
  85. htmlgraph/cli/constants.py +206 -0
  86. htmlgraph/cli/core.py +954 -0
  87. htmlgraph/cli/main.py +147 -0
  88. htmlgraph/cli/models.py +475 -0
  89. htmlgraph/cli/templates/__init__.py +1 -0
  90. htmlgraph/cli/templates/cost_dashboard.py +399 -0
  91. htmlgraph/cli/work/__init__.py +239 -0
  92. htmlgraph/cli/work/browse.py +115 -0
  93. htmlgraph/cli/work/features.py +568 -0
  94. htmlgraph/cli/work/orchestration.py +676 -0
  95. htmlgraph/cli/work/report.py +728 -0
  96. htmlgraph/cli/work/sessions.py +466 -0
  97. htmlgraph/cli/work/snapshot.py +559 -0
  98. htmlgraph/cli/work/tracks.py +486 -0
  99. htmlgraph/cli_commands/__init__.py +1 -0
  100. htmlgraph/cli_commands/feature.py +195 -0
  101. htmlgraph/cli_framework.py +115 -0
  102. htmlgraph/collections/__init__.py +18 -0
  103. htmlgraph/collections/base.py +415 -98
  104. htmlgraph/collections/bug.py +53 -0
  105. htmlgraph/collections/chore.py +53 -0
  106. htmlgraph/collections/epic.py +53 -0
  107. htmlgraph/collections/feature.py +12 -26
  108. htmlgraph/collections/insight.py +100 -0
  109. htmlgraph/collections/metric.py +92 -0
  110. htmlgraph/collections/pattern.py +97 -0
  111. htmlgraph/collections/phase.py +53 -0
  112. htmlgraph/collections/session.py +194 -0
  113. htmlgraph/collections/spike.py +56 -16
  114. htmlgraph/collections/task_delegation.py +241 -0
  115. htmlgraph/collections/todo.py +511 -0
  116. htmlgraph/collections/traces.py +487 -0
  117. htmlgraph/config/cost_models.json +56 -0
  118. htmlgraph/config.py +190 -0
  119. htmlgraph/context_analytics.py +344 -0
  120. htmlgraph/converter.py +216 -28
  121. htmlgraph/cost_analysis/__init__.py +5 -0
  122. htmlgraph/cost_analysis/analyzer.py +438 -0
  123. htmlgraph/dashboard.html +2406 -307
  124. htmlgraph/dashboard.html.backup +6592 -0
  125. htmlgraph/dashboard.html.bak +7181 -0
  126. htmlgraph/dashboard.html.bak2 +7231 -0
  127. htmlgraph/dashboard.html.bak3 +7232 -0
  128. htmlgraph/db/__init__.py +38 -0
  129. htmlgraph/db/queries.py +790 -0
  130. htmlgraph/db/schema.py +1788 -0
  131. htmlgraph/decorators.py +317 -0
  132. htmlgraph/dependency_models.py +19 -2
  133. htmlgraph/deploy.py +142 -125
  134. htmlgraph/deployment_models.py +474 -0
  135. htmlgraph/docs/API_REFERENCE.md +841 -0
  136. htmlgraph/docs/HTTP_API.md +750 -0
  137. htmlgraph/docs/INTEGRATION_GUIDE.md +752 -0
  138. htmlgraph/docs/ORCHESTRATION_PATTERNS.md +717 -0
  139. htmlgraph/docs/README.md +532 -0
  140. htmlgraph/docs/__init__.py +77 -0
  141. htmlgraph/docs/docs_version.py +55 -0
  142. htmlgraph/docs/metadata.py +93 -0
  143. htmlgraph/docs/migrations.py +232 -0
  144. htmlgraph/docs/template_engine.py +143 -0
  145. htmlgraph/docs/templates/_sections/cli_reference.md.j2 +52 -0
  146. htmlgraph/docs/templates/_sections/core_concepts.md.j2 +29 -0
  147. htmlgraph/docs/templates/_sections/sdk_basics.md.j2 +69 -0
  148. htmlgraph/docs/templates/base_agents.md.j2 +78 -0
  149. htmlgraph/docs/templates/example_user_override.md.j2 +47 -0
  150. htmlgraph/docs/version_check.py +163 -0
  151. htmlgraph/edge_index.py +182 -27
  152. htmlgraph/error_handler.py +544 -0
  153. htmlgraph/event_log.py +100 -52
  154. htmlgraph/event_migration.py +13 -4
  155. htmlgraph/exceptions.py +49 -0
  156. htmlgraph/file_watcher.py +101 -28
  157. htmlgraph/find_api.py +75 -63
  158. htmlgraph/git_events.py +145 -63
  159. htmlgraph/graph.py +1122 -106
  160. htmlgraph/hooks/.htmlgraph/.session-warning-state.json +6 -0
  161. htmlgraph/hooks/.htmlgraph/agents.json +72 -0
  162. htmlgraph/hooks/.htmlgraph/index.sqlite +0 -0
  163. htmlgraph/hooks/__init__.py +45 -0
  164. htmlgraph/hooks/bootstrap.py +169 -0
  165. htmlgraph/hooks/cigs_pretool_enforcer.py +354 -0
  166. htmlgraph/hooks/concurrent_sessions.py +208 -0
  167. htmlgraph/hooks/context.py +350 -0
  168. htmlgraph/hooks/drift_handler.py +525 -0
  169. htmlgraph/hooks/event_tracker.py +1314 -0
  170. htmlgraph/hooks/git_commands.py +175 -0
  171. htmlgraph/hooks/hooks-config.example.json +12 -0
  172. htmlgraph/hooks/installer.py +343 -0
  173. htmlgraph/hooks/orchestrator.py +674 -0
  174. htmlgraph/hooks/orchestrator_reflector.py +223 -0
  175. htmlgraph/hooks/post-checkout.sh +28 -0
  176. htmlgraph/hooks/post-commit.sh +24 -0
  177. htmlgraph/hooks/post-merge.sh +26 -0
  178. htmlgraph/hooks/post_tool_use_failure.py +273 -0
  179. htmlgraph/hooks/post_tool_use_handler.py +257 -0
  180. htmlgraph/hooks/posttooluse.py +408 -0
  181. htmlgraph/hooks/pre-commit.sh +94 -0
  182. htmlgraph/hooks/pre-push.sh +28 -0
  183. htmlgraph/hooks/pretooluse.py +819 -0
  184. htmlgraph/hooks/prompt_analyzer.py +637 -0
  185. htmlgraph/hooks/session_handler.py +668 -0
  186. htmlgraph/hooks/session_summary.py +395 -0
  187. htmlgraph/hooks/state_manager.py +504 -0
  188. htmlgraph/hooks/subagent_detection.py +202 -0
  189. htmlgraph/hooks/subagent_stop.py +369 -0
  190. htmlgraph/hooks/task_enforcer.py +255 -0
  191. htmlgraph/hooks/task_validator.py +177 -0
  192. htmlgraph/hooks/validator.py +628 -0
  193. htmlgraph/ids.py +41 -27
  194. htmlgraph/index.d.ts +286 -0
  195. htmlgraph/learning.py +767 -0
  196. htmlgraph/mcp_server.py +69 -23
  197. htmlgraph/models.py +1586 -87
  198. htmlgraph/operations/README.md +62 -0
  199. htmlgraph/operations/__init__.py +79 -0
  200. htmlgraph/operations/analytics.py +339 -0
  201. htmlgraph/operations/bootstrap.py +289 -0
  202. htmlgraph/operations/events.py +244 -0
  203. htmlgraph/operations/fastapi_server.py +231 -0
  204. htmlgraph/operations/hooks.py +350 -0
  205. htmlgraph/operations/initialization.py +597 -0
  206. htmlgraph/operations/initialization.py.backup +228 -0
  207. htmlgraph/operations/server.py +303 -0
  208. htmlgraph/orchestration/__init__.py +58 -0
  209. htmlgraph/orchestration/claude_launcher.py +179 -0
  210. htmlgraph/orchestration/command_builder.py +72 -0
  211. htmlgraph/orchestration/headless_spawner.py +281 -0
  212. htmlgraph/orchestration/live_events.py +377 -0
  213. htmlgraph/orchestration/model_selection.py +327 -0
  214. htmlgraph/orchestration/plugin_manager.py +140 -0
  215. htmlgraph/orchestration/prompts.py +137 -0
  216. htmlgraph/orchestration/spawner_event_tracker.py +383 -0
  217. htmlgraph/orchestration/spawners/__init__.py +16 -0
  218. htmlgraph/orchestration/spawners/base.py +194 -0
  219. htmlgraph/orchestration/spawners/claude.py +173 -0
  220. htmlgraph/orchestration/spawners/codex.py +435 -0
  221. htmlgraph/orchestration/spawners/copilot.py +294 -0
  222. htmlgraph/orchestration/spawners/gemini.py +471 -0
  223. htmlgraph/orchestration/subprocess_runner.py +36 -0
  224. htmlgraph/orchestration/task_coordination.py +343 -0
  225. htmlgraph/orchestration.md +563 -0
  226. htmlgraph/orchestrator-system-prompt-optimized.txt +863 -0
  227. htmlgraph/orchestrator.py +669 -0
  228. htmlgraph/orchestrator_config.py +357 -0
  229. htmlgraph/orchestrator_mode.py +328 -0
  230. htmlgraph/orchestrator_validator.py +133 -0
  231. htmlgraph/parallel.py +646 -0
  232. htmlgraph/parser.py +160 -35
  233. htmlgraph/path_query.py +608 -0
  234. htmlgraph/pattern_matcher.py +636 -0
  235. htmlgraph/planning.py +147 -52
  236. htmlgraph/pydantic_models.py +476 -0
  237. htmlgraph/quality_gates.py +350 -0
  238. htmlgraph/query_builder.py +109 -72
  239. htmlgraph/query_composer.py +509 -0
  240. htmlgraph/reflection.py +443 -0
  241. htmlgraph/refs.py +344 -0
  242. htmlgraph/repo_hash.py +512 -0
  243. htmlgraph/repositories/__init__.py +292 -0
  244. htmlgraph/repositories/analytics_repository.py +455 -0
  245. htmlgraph/repositories/analytics_repository_standard.py +628 -0
  246. htmlgraph/repositories/feature_repository.py +581 -0
  247. htmlgraph/repositories/feature_repository_htmlfile.py +668 -0
  248. htmlgraph/repositories/feature_repository_memory.py +607 -0
  249. htmlgraph/repositories/feature_repository_sqlite.py +858 -0
  250. htmlgraph/repositories/filter_service.py +620 -0
  251. htmlgraph/repositories/filter_service_standard.py +445 -0
  252. htmlgraph/repositories/shared_cache.py +621 -0
  253. htmlgraph/repositories/shared_cache_memory.py +395 -0
  254. htmlgraph/repositories/track_repository.py +552 -0
  255. htmlgraph/repositories/track_repository_htmlfile.py +619 -0
  256. htmlgraph/repositories/track_repository_memory.py +508 -0
  257. htmlgraph/repositories/track_repository_sqlite.py +711 -0
  258. htmlgraph/routing.py +8 -19
  259. htmlgraph/scripts/deploy.py +1 -2
  260. htmlgraph/sdk/__init__.py +398 -0
  261. htmlgraph/sdk/__init__.pyi +14 -0
  262. htmlgraph/sdk/analytics/__init__.py +19 -0
  263. htmlgraph/sdk/analytics/engine.py +155 -0
  264. htmlgraph/sdk/analytics/helpers.py +178 -0
  265. htmlgraph/sdk/analytics/registry.py +109 -0
  266. htmlgraph/sdk/base.py +484 -0
  267. htmlgraph/sdk/constants.py +216 -0
  268. htmlgraph/sdk/core.pyi +308 -0
  269. htmlgraph/sdk/discovery.py +120 -0
  270. htmlgraph/sdk/help/__init__.py +12 -0
  271. htmlgraph/sdk/help/mixin.py +699 -0
  272. htmlgraph/sdk/mixins/__init__.py +15 -0
  273. htmlgraph/sdk/mixins/attribution.py +113 -0
  274. htmlgraph/sdk/mixins/mixin.py +410 -0
  275. htmlgraph/sdk/operations/__init__.py +12 -0
  276. htmlgraph/sdk/operations/mixin.py +427 -0
  277. htmlgraph/sdk/orchestration/__init__.py +17 -0
  278. htmlgraph/sdk/orchestration/coordinator.py +203 -0
  279. htmlgraph/sdk/orchestration/spawner.py +204 -0
  280. htmlgraph/sdk/planning/__init__.py +19 -0
  281. htmlgraph/sdk/planning/bottlenecks.py +93 -0
  282. htmlgraph/sdk/planning/mixin.py +211 -0
  283. htmlgraph/sdk/planning/parallel.py +186 -0
  284. htmlgraph/sdk/planning/queue.py +210 -0
  285. htmlgraph/sdk/planning/recommendations.py +87 -0
  286. htmlgraph/sdk/planning/smart_planning.py +319 -0
  287. htmlgraph/sdk/session/__init__.py +19 -0
  288. htmlgraph/sdk/session/continuity.py +57 -0
  289. htmlgraph/sdk/session/handoff.py +110 -0
  290. htmlgraph/sdk/session/info.py +309 -0
  291. htmlgraph/sdk/session/manager.py +103 -0
  292. htmlgraph/sdk/strategic/__init__.py +26 -0
  293. htmlgraph/sdk/strategic/mixin.py +563 -0
  294. htmlgraph/server.py +685 -180
  295. htmlgraph/services/__init__.py +10 -0
  296. htmlgraph/services/claiming.py +199 -0
  297. htmlgraph/session_hooks.py +300 -0
  298. htmlgraph/session_manager.py +1392 -175
  299. htmlgraph/session_registry.py +587 -0
  300. htmlgraph/session_state.py +436 -0
  301. htmlgraph/session_warning.py +201 -0
  302. htmlgraph/sessions/__init__.py +23 -0
  303. htmlgraph/sessions/handoff.py +756 -0
  304. htmlgraph/setup.py +34 -17
  305. htmlgraph/spike_index.py +143 -0
  306. htmlgraph/sync_docs.py +12 -15
  307. htmlgraph/system_prompts.py +450 -0
  308. htmlgraph/templates/AGENTS.md.template +366 -0
  309. htmlgraph/templates/CLAUDE.md.template +97 -0
  310. htmlgraph/templates/GEMINI.md.template +87 -0
  311. htmlgraph/templates/orchestration-view.html +350 -0
  312. htmlgraph/track_builder.py +146 -15
  313. htmlgraph/track_manager.py +69 -21
  314. htmlgraph/transcript.py +890 -0
  315. htmlgraph/transcript_analytics.py +699 -0
  316. htmlgraph/types.py +323 -0
  317. htmlgraph/validation.py +115 -0
  318. htmlgraph/watch.py +8 -5
  319. htmlgraph/work_type_utils.py +3 -2
  320. {htmlgraph-0.9.3.data → htmlgraph-0.27.5.data}/data/htmlgraph/dashboard.html +2406 -307
  321. htmlgraph-0.27.5.data/data/htmlgraph/templates/AGENTS.md.template +366 -0
  322. htmlgraph-0.27.5.data/data/htmlgraph/templates/CLAUDE.md.template +97 -0
  323. htmlgraph-0.27.5.data/data/htmlgraph/templates/GEMINI.md.template +87 -0
  324. {htmlgraph-0.9.3.dist-info → htmlgraph-0.27.5.dist-info}/METADATA +97 -64
  325. htmlgraph-0.27.5.dist-info/RECORD +337 -0
  326. {htmlgraph-0.9.3.dist-info → htmlgraph-0.27.5.dist-info}/entry_points.txt +1 -1
  327. htmlgraph/cli.py +0 -2688
  328. htmlgraph/sdk.py +0 -709
  329. htmlgraph-0.9.3.dist-info/RECORD +0 -61
  330. {htmlgraph-0.9.3.data → htmlgraph-0.27.5.data}/data/htmlgraph/styles.css +0 -0
  331. {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
+ }