htmlgraph 0.20.1__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 (304) 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 +51 -1
  5. htmlgraph/__init__.pyi +123 -0
  6. htmlgraph/agent_detection.py +26 -10
  7. htmlgraph/agent_registry.py +2 -1
  8. htmlgraph/analytics/__init__.py +8 -1
  9. htmlgraph/analytics/cli.py +86 -20
  10. htmlgraph/analytics/cost_analyzer.py +391 -0
  11. htmlgraph/analytics/cost_monitor.py +664 -0
  12. htmlgraph/analytics/cost_reporter.py +675 -0
  13. htmlgraph/analytics/cross_session.py +617 -0
  14. htmlgraph/analytics/dependency.py +10 -6
  15. htmlgraph/analytics/pattern_learning.py +771 -0
  16. htmlgraph/analytics/session_graph.py +707 -0
  17. htmlgraph/analytics/strategic/__init__.py +80 -0
  18. htmlgraph/analytics/strategic/cost_optimizer.py +611 -0
  19. htmlgraph/analytics/strategic/pattern_detector.py +876 -0
  20. htmlgraph/analytics/strategic/preference_manager.py +709 -0
  21. htmlgraph/analytics/strategic/suggestion_engine.py +747 -0
  22. htmlgraph/analytics/work_type.py +67 -27
  23. htmlgraph/analytics_index.py +53 -20
  24. htmlgraph/api/__init__.py +3 -0
  25. htmlgraph/api/cost_alerts_websocket.py +416 -0
  26. htmlgraph/api/main.py +2498 -0
  27. htmlgraph/api/static/htmx.min.js +1 -0
  28. htmlgraph/api/static/style-redesign.css +1344 -0
  29. htmlgraph/api/static/style.css +1079 -0
  30. htmlgraph/api/templates/dashboard-redesign.html +1366 -0
  31. htmlgraph/api/templates/dashboard.html +794 -0
  32. htmlgraph/api/templates/partials/activity-feed-hierarchical.html +326 -0
  33. htmlgraph/api/templates/partials/activity-feed.html +1100 -0
  34. htmlgraph/api/templates/partials/agents-redesign.html +317 -0
  35. htmlgraph/api/templates/partials/agents.html +317 -0
  36. htmlgraph/api/templates/partials/event-traces.html +373 -0
  37. htmlgraph/api/templates/partials/features-kanban-redesign.html +509 -0
  38. htmlgraph/api/templates/partials/features.html +578 -0
  39. htmlgraph/api/templates/partials/metrics-redesign.html +346 -0
  40. htmlgraph/api/templates/partials/metrics.html +346 -0
  41. htmlgraph/api/templates/partials/orchestration-redesign.html +443 -0
  42. htmlgraph/api/templates/partials/orchestration.html +198 -0
  43. htmlgraph/api/templates/partials/spawners.html +375 -0
  44. htmlgraph/api/templates/partials/work-items.html +613 -0
  45. htmlgraph/api/websocket.py +538 -0
  46. htmlgraph/archive/__init__.py +24 -0
  47. htmlgraph/archive/bloom.py +234 -0
  48. htmlgraph/archive/fts.py +297 -0
  49. htmlgraph/archive/manager.py +583 -0
  50. htmlgraph/archive/search.py +244 -0
  51. htmlgraph/atomic_ops.py +560 -0
  52. htmlgraph/attribute_index.py +2 -1
  53. htmlgraph/bounded_paths.py +539 -0
  54. htmlgraph/builders/base.py +57 -2
  55. htmlgraph/builders/bug.py +19 -3
  56. htmlgraph/builders/chore.py +19 -3
  57. htmlgraph/builders/epic.py +19 -3
  58. htmlgraph/builders/feature.py +27 -3
  59. htmlgraph/builders/insight.py +2 -1
  60. htmlgraph/builders/metric.py +2 -1
  61. htmlgraph/builders/pattern.py +2 -1
  62. htmlgraph/builders/phase.py +19 -3
  63. htmlgraph/builders/spike.py +29 -3
  64. htmlgraph/builders/track.py +42 -1
  65. htmlgraph/cigs/__init__.py +81 -0
  66. htmlgraph/cigs/autonomy.py +385 -0
  67. htmlgraph/cigs/cost.py +475 -0
  68. htmlgraph/cigs/messages_basic.py +472 -0
  69. htmlgraph/cigs/messaging.py +365 -0
  70. htmlgraph/cigs/models.py +771 -0
  71. htmlgraph/cigs/pattern_storage.py +427 -0
  72. htmlgraph/cigs/patterns.py +503 -0
  73. htmlgraph/cigs/posttool_analyzer.py +234 -0
  74. htmlgraph/cigs/reporter.py +818 -0
  75. htmlgraph/cigs/tracker.py +317 -0
  76. htmlgraph/cli/.htmlgraph/.session-warning-state.json +6 -0
  77. htmlgraph/cli/.htmlgraph/agents.json +72 -0
  78. htmlgraph/cli/.htmlgraph/htmlgraph.db +0 -0
  79. htmlgraph/cli/__init__.py +42 -0
  80. htmlgraph/cli/__main__.py +6 -0
  81. htmlgraph/cli/analytics.py +1424 -0
  82. htmlgraph/cli/base.py +685 -0
  83. htmlgraph/cli/constants.py +206 -0
  84. htmlgraph/cli/core.py +954 -0
  85. htmlgraph/cli/main.py +147 -0
  86. htmlgraph/cli/models.py +475 -0
  87. htmlgraph/cli/templates/__init__.py +1 -0
  88. htmlgraph/cli/templates/cost_dashboard.py +399 -0
  89. htmlgraph/cli/work/__init__.py +239 -0
  90. htmlgraph/cli/work/browse.py +115 -0
  91. htmlgraph/cli/work/features.py +568 -0
  92. htmlgraph/cli/work/orchestration.py +676 -0
  93. htmlgraph/cli/work/report.py +728 -0
  94. htmlgraph/cli/work/sessions.py +466 -0
  95. htmlgraph/cli/work/snapshot.py +559 -0
  96. htmlgraph/cli/work/tracks.py +486 -0
  97. htmlgraph/cli_commands/__init__.py +1 -0
  98. htmlgraph/cli_commands/feature.py +195 -0
  99. htmlgraph/cli_framework.py +115 -0
  100. htmlgraph/collections/__init__.py +2 -0
  101. htmlgraph/collections/base.py +197 -14
  102. htmlgraph/collections/bug.py +2 -1
  103. htmlgraph/collections/chore.py +2 -1
  104. htmlgraph/collections/epic.py +2 -1
  105. htmlgraph/collections/feature.py +2 -1
  106. htmlgraph/collections/insight.py +2 -1
  107. htmlgraph/collections/metric.py +2 -1
  108. htmlgraph/collections/pattern.py +2 -1
  109. htmlgraph/collections/phase.py +2 -1
  110. htmlgraph/collections/session.py +194 -0
  111. htmlgraph/collections/spike.py +13 -2
  112. htmlgraph/collections/task_delegation.py +241 -0
  113. htmlgraph/collections/todo.py +14 -1
  114. htmlgraph/collections/traces.py +487 -0
  115. htmlgraph/config/cost_models.json +56 -0
  116. htmlgraph/config.py +190 -0
  117. htmlgraph/context_analytics.py +2 -1
  118. htmlgraph/converter.py +116 -7
  119. htmlgraph/cost_analysis/__init__.py +5 -0
  120. htmlgraph/cost_analysis/analyzer.py +438 -0
  121. htmlgraph/dashboard.html +2246 -248
  122. htmlgraph/dashboard.html.backup +6592 -0
  123. htmlgraph/dashboard.html.bak +7181 -0
  124. htmlgraph/dashboard.html.bak2 +7231 -0
  125. htmlgraph/dashboard.html.bak3 +7232 -0
  126. htmlgraph/db/__init__.py +38 -0
  127. htmlgraph/db/queries.py +790 -0
  128. htmlgraph/db/schema.py +1788 -0
  129. htmlgraph/decorators.py +317 -0
  130. htmlgraph/dependency_models.py +2 -1
  131. htmlgraph/deploy.py +26 -27
  132. htmlgraph/docs/API_REFERENCE.md +841 -0
  133. htmlgraph/docs/HTTP_API.md +750 -0
  134. htmlgraph/docs/INTEGRATION_GUIDE.md +752 -0
  135. htmlgraph/docs/ORCHESTRATION_PATTERNS.md +717 -0
  136. htmlgraph/docs/README.md +532 -0
  137. htmlgraph/docs/__init__.py +77 -0
  138. htmlgraph/docs/docs_version.py +55 -0
  139. htmlgraph/docs/metadata.py +93 -0
  140. htmlgraph/docs/migrations.py +232 -0
  141. htmlgraph/docs/template_engine.py +143 -0
  142. htmlgraph/docs/templates/_sections/cli_reference.md.j2 +52 -0
  143. htmlgraph/docs/templates/_sections/core_concepts.md.j2 +29 -0
  144. htmlgraph/docs/templates/_sections/sdk_basics.md.j2 +69 -0
  145. htmlgraph/docs/templates/base_agents.md.j2 +78 -0
  146. htmlgraph/docs/templates/example_user_override.md.j2 +47 -0
  147. htmlgraph/docs/version_check.py +163 -0
  148. htmlgraph/edge_index.py +2 -1
  149. htmlgraph/error_handler.py +544 -0
  150. htmlgraph/event_log.py +86 -37
  151. htmlgraph/event_migration.py +2 -1
  152. htmlgraph/file_watcher.py +12 -8
  153. htmlgraph/find_api.py +2 -1
  154. htmlgraph/git_events.py +67 -9
  155. htmlgraph/hooks/.htmlgraph/.session-warning-state.json +6 -0
  156. htmlgraph/hooks/.htmlgraph/agents.json +72 -0
  157. htmlgraph/hooks/.htmlgraph/index.sqlite +0 -0
  158. htmlgraph/hooks/__init__.py +8 -0
  159. htmlgraph/hooks/bootstrap.py +169 -0
  160. htmlgraph/hooks/cigs_pretool_enforcer.py +354 -0
  161. htmlgraph/hooks/concurrent_sessions.py +208 -0
  162. htmlgraph/hooks/context.py +350 -0
  163. htmlgraph/hooks/drift_handler.py +525 -0
  164. htmlgraph/hooks/event_tracker.py +790 -99
  165. htmlgraph/hooks/git_commands.py +175 -0
  166. htmlgraph/hooks/installer.py +5 -1
  167. htmlgraph/hooks/orchestrator.py +327 -76
  168. htmlgraph/hooks/orchestrator_reflector.py +31 -4
  169. htmlgraph/hooks/post_tool_use_failure.py +32 -7
  170. htmlgraph/hooks/post_tool_use_handler.py +257 -0
  171. htmlgraph/hooks/posttooluse.py +92 -19
  172. htmlgraph/hooks/pretooluse.py +527 -7
  173. htmlgraph/hooks/prompt_analyzer.py +637 -0
  174. htmlgraph/hooks/session_handler.py +668 -0
  175. htmlgraph/hooks/session_summary.py +395 -0
  176. htmlgraph/hooks/state_manager.py +504 -0
  177. htmlgraph/hooks/subagent_detection.py +202 -0
  178. htmlgraph/hooks/subagent_stop.py +369 -0
  179. htmlgraph/hooks/task_enforcer.py +99 -4
  180. htmlgraph/hooks/validator.py +212 -91
  181. htmlgraph/ids.py +2 -1
  182. htmlgraph/learning.py +125 -100
  183. htmlgraph/mcp_server.py +2 -1
  184. htmlgraph/models.py +217 -18
  185. htmlgraph/operations/README.md +62 -0
  186. htmlgraph/operations/__init__.py +79 -0
  187. htmlgraph/operations/analytics.py +339 -0
  188. htmlgraph/operations/bootstrap.py +289 -0
  189. htmlgraph/operations/events.py +244 -0
  190. htmlgraph/operations/fastapi_server.py +231 -0
  191. htmlgraph/operations/hooks.py +350 -0
  192. htmlgraph/operations/initialization.py +597 -0
  193. htmlgraph/operations/initialization.py.backup +228 -0
  194. htmlgraph/operations/server.py +303 -0
  195. htmlgraph/orchestration/__init__.py +58 -0
  196. htmlgraph/orchestration/claude_launcher.py +179 -0
  197. htmlgraph/orchestration/command_builder.py +72 -0
  198. htmlgraph/orchestration/headless_spawner.py +281 -0
  199. htmlgraph/orchestration/live_events.py +377 -0
  200. htmlgraph/orchestration/model_selection.py +327 -0
  201. htmlgraph/orchestration/plugin_manager.py +140 -0
  202. htmlgraph/orchestration/prompts.py +137 -0
  203. htmlgraph/orchestration/spawner_event_tracker.py +383 -0
  204. htmlgraph/orchestration/spawners/__init__.py +16 -0
  205. htmlgraph/orchestration/spawners/base.py +194 -0
  206. htmlgraph/orchestration/spawners/claude.py +173 -0
  207. htmlgraph/orchestration/spawners/codex.py +435 -0
  208. htmlgraph/orchestration/spawners/copilot.py +294 -0
  209. htmlgraph/orchestration/spawners/gemini.py +471 -0
  210. htmlgraph/orchestration/subprocess_runner.py +36 -0
  211. htmlgraph/{orchestration.py → orchestration/task_coordination.py} +16 -8
  212. htmlgraph/orchestration.md +563 -0
  213. htmlgraph/orchestrator-system-prompt-optimized.txt +863 -0
  214. htmlgraph/orchestrator.py +2 -1
  215. htmlgraph/orchestrator_config.py +357 -0
  216. htmlgraph/orchestrator_mode.py +115 -4
  217. htmlgraph/parallel.py +2 -1
  218. htmlgraph/parser.py +86 -6
  219. htmlgraph/path_query.py +608 -0
  220. htmlgraph/pattern_matcher.py +636 -0
  221. htmlgraph/pydantic_models.py +476 -0
  222. htmlgraph/quality_gates.py +350 -0
  223. htmlgraph/query_builder.py +2 -1
  224. htmlgraph/query_composer.py +509 -0
  225. htmlgraph/reflection.py +443 -0
  226. htmlgraph/refs.py +344 -0
  227. htmlgraph/repo_hash.py +512 -0
  228. htmlgraph/repositories/__init__.py +292 -0
  229. htmlgraph/repositories/analytics_repository.py +455 -0
  230. htmlgraph/repositories/analytics_repository_standard.py +628 -0
  231. htmlgraph/repositories/feature_repository.py +581 -0
  232. htmlgraph/repositories/feature_repository_htmlfile.py +668 -0
  233. htmlgraph/repositories/feature_repository_memory.py +607 -0
  234. htmlgraph/repositories/feature_repository_sqlite.py +858 -0
  235. htmlgraph/repositories/filter_service.py +620 -0
  236. htmlgraph/repositories/filter_service_standard.py +445 -0
  237. htmlgraph/repositories/shared_cache.py +621 -0
  238. htmlgraph/repositories/shared_cache_memory.py +395 -0
  239. htmlgraph/repositories/track_repository.py +552 -0
  240. htmlgraph/repositories/track_repository_htmlfile.py +619 -0
  241. htmlgraph/repositories/track_repository_memory.py +508 -0
  242. htmlgraph/repositories/track_repository_sqlite.py +711 -0
  243. htmlgraph/sdk/__init__.py +398 -0
  244. htmlgraph/sdk/__init__.pyi +14 -0
  245. htmlgraph/sdk/analytics/__init__.py +19 -0
  246. htmlgraph/sdk/analytics/engine.py +155 -0
  247. htmlgraph/sdk/analytics/helpers.py +178 -0
  248. htmlgraph/sdk/analytics/registry.py +109 -0
  249. htmlgraph/sdk/base.py +484 -0
  250. htmlgraph/sdk/constants.py +216 -0
  251. htmlgraph/sdk/core.pyi +308 -0
  252. htmlgraph/sdk/discovery.py +120 -0
  253. htmlgraph/sdk/help/__init__.py +12 -0
  254. htmlgraph/sdk/help/mixin.py +699 -0
  255. htmlgraph/sdk/mixins/__init__.py +15 -0
  256. htmlgraph/sdk/mixins/attribution.py +113 -0
  257. htmlgraph/sdk/mixins/mixin.py +410 -0
  258. htmlgraph/sdk/operations/__init__.py +12 -0
  259. htmlgraph/sdk/operations/mixin.py +427 -0
  260. htmlgraph/sdk/orchestration/__init__.py +17 -0
  261. htmlgraph/sdk/orchestration/coordinator.py +203 -0
  262. htmlgraph/sdk/orchestration/spawner.py +204 -0
  263. htmlgraph/sdk/planning/__init__.py +19 -0
  264. htmlgraph/sdk/planning/bottlenecks.py +93 -0
  265. htmlgraph/sdk/planning/mixin.py +211 -0
  266. htmlgraph/sdk/planning/parallel.py +186 -0
  267. htmlgraph/sdk/planning/queue.py +210 -0
  268. htmlgraph/sdk/planning/recommendations.py +87 -0
  269. htmlgraph/sdk/planning/smart_planning.py +319 -0
  270. htmlgraph/sdk/session/__init__.py +19 -0
  271. htmlgraph/sdk/session/continuity.py +57 -0
  272. htmlgraph/sdk/session/handoff.py +110 -0
  273. htmlgraph/sdk/session/info.py +309 -0
  274. htmlgraph/sdk/session/manager.py +103 -0
  275. htmlgraph/sdk/strategic/__init__.py +26 -0
  276. htmlgraph/sdk/strategic/mixin.py +563 -0
  277. htmlgraph/server.py +295 -107
  278. htmlgraph/session_hooks.py +300 -0
  279. htmlgraph/session_manager.py +285 -3
  280. htmlgraph/session_registry.py +587 -0
  281. htmlgraph/session_state.py +436 -0
  282. htmlgraph/session_warning.py +2 -1
  283. htmlgraph/sessions/__init__.py +23 -0
  284. htmlgraph/sessions/handoff.py +756 -0
  285. htmlgraph/system_prompts.py +450 -0
  286. htmlgraph/templates/orchestration-view.html +350 -0
  287. htmlgraph/track_builder.py +33 -1
  288. htmlgraph/track_manager.py +38 -0
  289. htmlgraph/transcript.py +18 -5
  290. htmlgraph/validation.py +115 -0
  291. htmlgraph/watch.py +2 -1
  292. htmlgraph/work_type_utils.py +2 -1
  293. {htmlgraph-0.20.1.data → htmlgraph-0.27.5.data}/data/htmlgraph/dashboard.html +2246 -248
  294. {htmlgraph-0.20.1.dist-info → htmlgraph-0.27.5.dist-info}/METADATA +95 -64
  295. htmlgraph-0.27.5.dist-info/RECORD +337 -0
  296. {htmlgraph-0.20.1.dist-info → htmlgraph-0.27.5.dist-info}/entry_points.txt +1 -1
  297. htmlgraph/cli.py +0 -4839
  298. htmlgraph/sdk.py +0 -2359
  299. htmlgraph-0.20.1.dist-info/RECORD +0 -118
  300. {htmlgraph-0.20.1.data → htmlgraph-0.27.5.data}/data/htmlgraph/styles.css +0 -0
  301. {htmlgraph-0.20.1.data → htmlgraph-0.27.5.data}/data/htmlgraph/templates/AGENTS.md.template +0 -0
  302. {htmlgraph-0.20.1.data → htmlgraph-0.27.5.data}/data/htmlgraph/templates/CLAUDE.md.template +0 -0
  303. {htmlgraph-0.20.1.data → htmlgraph-0.27.5.data}/data/htmlgraph/templates/GEMINI.md.template +0 -0
  304. {htmlgraph-0.20.1.dist-info → htmlgraph-0.27.5.dist-info}/WHEEL +0 -0
@@ -0,0 +1,391 @@
1
+ import logging
2
+
3
+ logger = logging.getLogger(__name__)
4
+
5
+ """
6
+ CostAnalyzer for OTEL ROI Analysis - Phase 1.
7
+
8
+ Analyzes cost attribution of Task() delegations vs direct tool execution.
9
+ Provides insights into which delegations are most expensive and their ROI.
10
+
11
+ Components:
12
+ 1. get_task_delegations() - Query all task_delegation events with hierarchy
13
+ 2. calculate_task_cost(event_id) - Sum token costs of all child tool calls
14
+ 3. get_cost_by_subagent_type() - Group costs by subagent type
15
+ 4. get_cost_by_tool_type() - Show which tools cost most
16
+ 5. get_roi_stats() - Calculate parallelization savings and benefits
17
+
18
+ Usage:
19
+ from htmlgraph.analytics.cost_analyzer import CostAnalyzer
20
+ analyzer = CostAnalyzer()
21
+ delegations = analyzer.get_task_delegations_with_costs()
22
+ logger.info(f"Total delegation cost: ${delegations['total_cost_usd']:.2f}")
23
+ """
24
+
25
+ import sqlite3
26
+ from dataclasses import dataclass, field
27
+ from datetime import datetime
28
+ from pathlib import Path
29
+ from typing import Any
30
+
31
+ from htmlgraph.cigs.cost import CostCalculator
32
+
33
+
34
+ @dataclass
35
+ class TaskDelegation:
36
+ """Represents a single Task delegation with cost analysis."""
37
+
38
+ event_id: str
39
+ session_id: str
40
+ timestamp: datetime
41
+ subagent_type: str
42
+ parent_event_id: str | None
43
+ tool_count: int = 0
44
+ total_cost_tokens: int = 0
45
+ child_events: list[dict[str, Any]] = field(default_factory=list)
46
+
47
+ def to_dict(self) -> dict[str, Any]:
48
+ """Convert to dictionary."""
49
+ return {
50
+ "event_id": self.event_id,
51
+ "session_id": self.session_id,
52
+ "timestamp": self.timestamp.isoformat(),
53
+ "subagent_type": self.subagent_type,
54
+ "parent_event_id": self.parent_event_id,
55
+ "tool_count": self.tool_count,
56
+ "total_cost_tokens": self.total_cost_tokens,
57
+ "child_events": self.child_events,
58
+ }
59
+
60
+
61
+ @dataclass
62
+ class CostBreakdown:
63
+ """Cost breakdown analysis."""
64
+
65
+ by_subagent: dict[str, int] = field(default_factory=dict)
66
+ by_tool: dict[str, int] = field(default_factory=dict)
67
+ total_cost_tokens: int = 0
68
+ total_delegations: int = 0
69
+ avg_cost_per_delegation: float = 0.0
70
+
71
+
72
+ @dataclass
73
+ class ROIStats:
74
+ """Return-on-Investment statistics."""
75
+
76
+ total_delegation_cost: int = 0
77
+ estimated_direct_cost: int = 0
78
+ estimated_savings: int = 0
79
+ savings_percentage: float = 0.0
80
+ avg_parallelization_factor: float = 1.0
81
+ context_preservation_benefit: float = 0.0
82
+ total_delegations: int = 0
83
+ avg_cost_per_delegation: float = 0.0
84
+
85
+
86
+ class CostAnalyzer:
87
+ """
88
+ Analyze cost attribution of Task delegations.
89
+
90
+ Queries the agent_events database to calculate:
91
+ - Total cost of each Task delegation (sum of child tool calls)
92
+ - Cost breakdown by subagent type and tool type
93
+ - ROI statistics comparing direct vs delegated execution
94
+ """
95
+
96
+ def __init__(self, graph_dir: Path | None = None):
97
+ """
98
+ Initialize CostAnalyzer.
99
+
100
+ Args:
101
+ graph_dir: Root directory for HtmlGraph (defaults to .htmlgraph)
102
+ """
103
+ if graph_dir is None:
104
+ graph_dir = Path.cwd() / ".htmlgraph"
105
+
106
+ self.graph_dir = Path(graph_dir)
107
+ self.db_path = self.graph_dir / "htmlgraph.db"
108
+ self.cost_calculator = CostCalculator()
109
+
110
+ if not self.db_path.exists():
111
+ raise FileNotFoundError(f"Database not found at {self.db_path}")
112
+
113
+ def _get_connection(self) -> sqlite3.Connection:
114
+ """Get database connection with row factory."""
115
+ conn = sqlite3.connect(str(self.db_path))
116
+ conn.row_factory = sqlite3.Row
117
+ return conn
118
+
119
+ def get_task_delegations(self) -> list[TaskDelegation]:
120
+ """
121
+ Query all task_delegation events from the database.
122
+
123
+ Returns:
124
+ List of TaskDelegation objects ordered by timestamp (newest first)
125
+ """
126
+ conn = self._get_connection()
127
+ try:
128
+ cursor = conn.cursor()
129
+ cursor.execute(
130
+ """
131
+ SELECT
132
+ event_id,
133
+ session_id,
134
+ timestamp,
135
+ subagent_type,
136
+ parent_event_id
137
+ FROM agent_events
138
+ WHERE event_type = 'task_delegation'
139
+ ORDER BY timestamp DESC
140
+ """
141
+ )
142
+
143
+ delegations = []
144
+ for row in cursor.fetchall():
145
+ timestamp = (
146
+ datetime.fromisoformat(row["timestamp"])
147
+ if isinstance(row["timestamp"], str)
148
+ else row["timestamp"]
149
+ )
150
+ delegations.append(
151
+ TaskDelegation(
152
+ event_id=row["event_id"],
153
+ session_id=row["session_id"],
154
+ timestamp=timestamp,
155
+ subagent_type=row["subagent_type"] or "unknown",
156
+ parent_event_id=row["parent_event_id"],
157
+ )
158
+ )
159
+
160
+ return delegations
161
+ finally:
162
+ conn.close()
163
+
164
+ def calculate_task_cost(self, event_id: str) -> tuple[int, list[dict[str, Any]]]:
165
+ """
166
+ Calculate total cost of a Task delegation.
167
+
168
+ Sums all token costs of child tool calls using cost_tokens field.
169
+ Falls back to CIGS cost estimation if cost_tokens is not available.
170
+
171
+ Args:
172
+ event_id: Task delegation event ID
173
+
174
+ Returns:
175
+ Tuple of (total_cost_tokens, child_events_list)
176
+ """
177
+ conn = self._get_connection()
178
+ try:
179
+ cursor = conn.cursor()
180
+
181
+ # Get all children of this task
182
+ cursor.execute(
183
+ """
184
+ SELECT
185
+ event_id,
186
+ tool_name,
187
+ cost_tokens,
188
+ input_summary,
189
+ output_summary,
190
+ timestamp
191
+ FROM agent_events
192
+ WHERE parent_event_id = ?
193
+ AND event_type IN ('tool_call', 'tool_result')
194
+ ORDER BY timestamp ASC
195
+ """,
196
+ (event_id,),
197
+ )
198
+
199
+ total_cost = 0
200
+ child_events = []
201
+
202
+ for row in cursor.fetchall():
203
+ cost = row["cost_tokens"] if row["cost_tokens"] else 0
204
+
205
+ # If no stored cost, estimate based on tool type
206
+ if cost == 0 and row["tool_name"]:
207
+ cost = self.cost_calculator.predict_cost(row["tool_name"], {})
208
+
209
+ total_cost += cost
210
+
211
+ child_events.append(
212
+ {
213
+ "event_id": row["event_id"],
214
+ "tool_name": row["tool_name"],
215
+ "cost_tokens": cost,
216
+ "timestamp": row["timestamp"],
217
+ }
218
+ )
219
+
220
+ return total_cost, child_events
221
+ finally:
222
+ conn.close()
223
+
224
+ def get_task_delegations_with_costs(self) -> dict[str, Any]:
225
+ """
226
+ Get all task delegations with calculated costs.
227
+
228
+ Returns:
229
+ Dictionary with:
230
+ - delegations: List of TaskDelegation with costs
231
+ - total_cost_tokens: Sum of all delegation costs
232
+ - total_delegations: Count of delegations
233
+ - by_subagent_type: Cost breakdown by subagent
234
+ - by_tool_type: Cost breakdown by tool
235
+ """
236
+ delegations = self.get_task_delegations()
237
+
238
+ total_cost = 0
239
+ by_subagent: dict[str, int] = {}
240
+ by_tool: dict[str, int] = {}
241
+
242
+ for delegation in delegations:
243
+ cost, child_events = self.calculate_task_cost(delegation.event_id)
244
+ delegation.total_cost_tokens = cost
245
+ delegation.child_events = child_events
246
+ delegation.tool_count = len(child_events)
247
+
248
+ total_cost += cost
249
+
250
+ # Track by subagent type
251
+ subagent = delegation.subagent_type
252
+ by_subagent[subagent] = by_subagent.get(subagent, 0) + cost
253
+
254
+ # Track by tool type
255
+ for child in child_events:
256
+ tool = child["tool_name"] or "unknown"
257
+ by_tool[tool] = by_tool.get(tool, 0) + child["cost_tokens"]
258
+
259
+ # Convert to USD (approximation: 1M tokens ~ $3 for input, $6 for output)
260
+ # Average: ~$4.50 per 1M tokens
261
+ total_cost_usd = total_cost * 0.0000045
262
+
263
+ return {
264
+ "delegations": delegations,
265
+ "total_cost_tokens": total_cost,
266
+ "total_cost_usd": total_cost_usd,
267
+ "total_delegations": len(delegations),
268
+ "avg_cost_per_delegation": (
269
+ total_cost / len(delegations) if delegations else 0
270
+ ),
271
+ "by_subagent_type": by_subagent,
272
+ "by_tool_type": by_tool,
273
+ }
274
+
275
+ def get_cost_by_subagent_type(self) -> dict[str, int]:
276
+ """
277
+ Group delegation costs by subagent type.
278
+
279
+ Returns:
280
+ Dictionary mapping subagent_type to total tokens spent
281
+ """
282
+ data = self.get_task_delegations_with_costs()
283
+ result = data.get("by_subagent_type", {})
284
+ if isinstance(result, dict):
285
+ return result
286
+ return {}
287
+
288
+ def get_cost_by_tool_type(self) -> dict[str, int]:
289
+ """
290
+ Show which tools cost most across all delegations.
291
+
292
+ Returns:
293
+ Dictionary mapping tool_name to total tokens spent
294
+ """
295
+ data = self.get_task_delegations_with_costs()
296
+ result = data.get("by_tool_type", {})
297
+ if isinstance(result, dict):
298
+ return result
299
+ return {}
300
+
301
+ def get_roi_stats(self) -> ROIStats:
302
+ """
303
+ Calculate ROI statistics comparing delegation vs direct execution.
304
+
305
+ Assumptions:
306
+ - Direct execution: Tokens spent directly on main agent
307
+ - Delegated execution: Tokens in child subagents (already counted)
308
+ - Savings: Context preservation + parallelization benefits
309
+ - Parallelization factor: 1.2-1.5x (subagents can work more efficiently)
310
+ - Context preservation: ~30% token savings from better focus
311
+
312
+ Returns:
313
+ ROIStats with cost and savings analysis
314
+ """
315
+ data = self.get_task_delegations_with_costs()
316
+
317
+ total_delegation_cost = data["total_cost_tokens"]
318
+ total_delegations = data["total_delegations"]
319
+
320
+ # Estimate direct execution cost
321
+ # Assumption: direct execution would cost 2.5x due to context overhead
322
+ estimated_direct_cost = int(total_delegation_cost * 2.5)
323
+
324
+ # Estimate savings
325
+ # Parallelization benefit: 1.2x efficiency
326
+ # Context preservation: 30% savings
327
+ parallelization_factor = 1.2
328
+ context_benefit = 0.30
329
+
330
+ estimated_savings = int(
331
+ estimated_direct_cost
332
+ - (total_delegation_cost * parallelization_factor * (1.0 - context_benefit))
333
+ )
334
+
335
+ savings_percentage = (
336
+ (estimated_savings / estimated_direct_cost * 100)
337
+ if estimated_direct_cost > 0
338
+ else 0.0
339
+ )
340
+
341
+ return ROIStats(
342
+ total_delegation_cost=total_delegation_cost,
343
+ estimated_direct_cost=estimated_direct_cost,
344
+ estimated_savings=estimated_savings,
345
+ savings_percentage=savings_percentage,
346
+ avg_parallelization_factor=parallelization_factor,
347
+ context_preservation_benefit=context_benefit,
348
+ total_delegations=total_delegations,
349
+ avg_cost_per_delegation=(
350
+ total_delegation_cost / total_delegations
351
+ if total_delegations > 0
352
+ else 0.0
353
+ ),
354
+ )
355
+
356
+ def get_top_delegations(self, limit: int = 10) -> list[TaskDelegation]:
357
+ """
358
+ Get the most expensive Task delegations.
359
+
360
+ Args:
361
+ limit: Number of delegations to return (default: 10)
362
+
363
+ Returns:
364
+ List of TaskDelegation sorted by cost (descending)
365
+ """
366
+ data = self.get_task_delegations_with_costs()
367
+ delegations = data["delegations"]
368
+
369
+ # Sort by cost descending
370
+ sorted_delegations = sorted(
371
+ delegations, key=lambda d: d.total_cost_tokens, reverse=True
372
+ )
373
+
374
+ return sorted_delegations[:limit]
375
+
376
+ def get_cost_breakdown(self) -> CostBreakdown:
377
+ """
378
+ Get comprehensive cost breakdown.
379
+
380
+ Returns:
381
+ CostBreakdown with by_subagent and by_tool analysis
382
+ """
383
+ data = self.get_task_delegations_with_costs()
384
+
385
+ return CostBreakdown(
386
+ by_subagent=data["by_subagent_type"],
387
+ by_tool=data["by_tool_type"],
388
+ total_cost_tokens=data["total_cost_tokens"],
389
+ total_delegations=data["total_delegations"],
390
+ avg_cost_per_delegation=data["avg_cost_per_delegation"],
391
+ )