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,487 @@
1
+ from __future__ import annotations
2
+
3
+ import logging
4
+
5
+ logger = logging.getLogger(__name__)
6
+
7
+ """
8
+ Tool Execution Traces Collection
9
+
10
+ Provides query interface for tool execution traces stored in tool_traces table.
11
+ Enables analysis of tool performance, error patterns, and execution hierarchies.
12
+
13
+ Example:
14
+ >>> from htmlgraph.sdk import SDK
15
+ >>> sdk = SDK(agent="claude")
16
+ >>>
17
+ >>> # Get traces for current session
18
+ >>> traces = sdk.traces.get_traces(session_id="sess-abc123")
19
+ >>> for trace in traces:
20
+ ... logger.info(f"{trace.tool_name}: {trace.duration_ms}ms")
21
+ >>>
22
+ >>> # Find slow tool calls
23
+ >>> slow = sdk.traces.get_slow_traces(threshold_ms=1000)
24
+ >>>
25
+ >>> # Get hierarchical view (parent-child relationships)
26
+ >>> tree = sdk.traces.get_trace_tree(trace_id="trace-xyz")
27
+ >>> logger.info(f"Root: {tree.root.tool_name}")
28
+ >>> logger.info(f"Children: {len(tree.children)}")
29
+ >>>
30
+ >>> # Get error traces for debugging
31
+ >>> errors = sdk.traces.get_error_traces(session_id="sess-abc123")
32
+ """
33
+
34
+
35
+ from dataclasses import dataclass
36
+ from datetime import datetime, timezone
37
+ from typing import TYPE_CHECKING
38
+
39
+ from htmlgraph.db.schema import HtmlGraphDB
40
+
41
+ if TYPE_CHECKING:
42
+ from htmlgraph.sdk import SDK
43
+
44
+
45
+ @dataclass
46
+ class TraceRecord:
47
+ """
48
+ Single tool execution trace.
49
+
50
+ Represents one complete execution of a tool with timing, input, output, and status.
51
+ Parent-child relationships via parent_tool_use_id enable hierarchical analysis.
52
+
53
+ Attributes:
54
+ tool_use_id: Unique identifier for this tool execution (UUID v4)
55
+ trace_id: Parent trace ID for grouping related executions
56
+ session_id: Session this execution belongs to
57
+ tool_name: Name of the tool executed (e.g., "Bash", "Read", "Write")
58
+ tool_input: Input parameters passed to the tool (dict, may be None)
59
+ tool_output: Result returned by the tool (dict, may be None if not yet complete)
60
+ start_time: When execution started (UTC datetime)
61
+ end_time: When execution ended (UTC datetime, None if still running)
62
+ duration_ms: Milliseconds to complete (None if still running or error)
63
+ status: Execution status (started, completed, failed, timeout, cancelled)
64
+ error_message: Error details if status is 'failed'
65
+ parent_tool_use_id: tool_use_id of parent tool if nested (None if top-level)
66
+ """
67
+
68
+ tool_use_id: str
69
+ trace_id: str
70
+ session_id: str
71
+ tool_name: str
72
+ tool_input: dict | None
73
+ tool_output: dict | None
74
+ start_time: datetime
75
+ end_time: datetime | None
76
+ duration_ms: int | None
77
+ status: str | None
78
+ error_message: str | None
79
+ parent_tool_use_id: str | None
80
+
81
+
82
+ @dataclass
83
+ class TraceTree:
84
+ """
85
+ Hierarchical view of traces (parent-child relationships).
86
+
87
+ Enables analysis of nested tool executions where one tool invokes others.
88
+ Example: Bash tool calls may invoke other tools as nested executions.
89
+
90
+ Attributes:
91
+ root: Root trace record (this execution)
92
+ children: List of child traces (tools invoked by this tool)
93
+ """
94
+
95
+ root: TraceRecord
96
+ children: list[TraceTree]
97
+
98
+
99
+ class TraceCollection:
100
+ """
101
+ Query interface for tool execution traces.
102
+
103
+ Provides methods to retrieve, filter, and analyze tool execution traces
104
+ stored in the tool_traces database table. Supports querying by session,
105
+ tool name, performance thresholds, and error status.
106
+
107
+ All queries return data sorted by start_time DESC (newest first).
108
+
109
+ Example:
110
+ >>> sdk = SDK(agent="claude")
111
+ >>> traces = sdk.traces
112
+ >>>
113
+ >>> # Single trace
114
+ >>> trace = traces.get_trace("tool-use-id-123")
115
+ >>>
116
+ >>> # All traces for session
117
+ >>> all_traces = traces.get_traces("sess-123")
118
+ >>>
119
+ >>> # By tool name
120
+ >>> bash_traces = traces.get_traces_by_tool("Bash")
121
+ >>>
122
+ >>> # Performance analysis
123
+ >>> slow = traces.get_slow_traces(threshold_ms=1000)
124
+ >>> errors = traces.get_error_traces("sess-123")
125
+ >>>
126
+ >>> # Hierarchical view
127
+ >>> tree = traces.get_trace_tree("trace-id-123")
128
+ """
129
+
130
+ def __init__(self, sdk: SDK):
131
+ """
132
+ Initialize traces collection.
133
+
134
+ Args:
135
+ sdk: Parent SDK instance
136
+ """
137
+ self._sdk = sdk
138
+ self._db = HtmlGraphDB()
139
+
140
+ def _row_to_trace(self, row: tuple) -> TraceRecord:
141
+ """
142
+ Convert database row to TraceRecord dataclass.
143
+
144
+ Args:
145
+ row: SQLite row tuple from tool_traces query
146
+
147
+ Returns:
148
+ TraceRecord with parsed fields
149
+ """
150
+ import json
151
+
152
+ # Unpack tuple: (tool_use_id, trace_id, session_id, tool_name, tool_input,
153
+ # tool_output, start_time, end_time, duration_ms, status,
154
+ # error_message, parent_tool_use_id)
155
+ (
156
+ tool_use_id,
157
+ trace_id,
158
+ session_id,
159
+ tool_name,
160
+ tool_input_json,
161
+ tool_output_json,
162
+ start_time_iso,
163
+ end_time_iso,
164
+ duration_ms,
165
+ status,
166
+ error_message,
167
+ parent_tool_use_id,
168
+ ) = row
169
+
170
+ # Parse JSON fields
171
+ tool_input = None
172
+ if tool_input_json:
173
+ try:
174
+ tool_input = json.loads(tool_input_json)
175
+ except (json.JSONDecodeError, TypeError):
176
+ tool_input = None
177
+
178
+ tool_output = None
179
+ if tool_output_json:
180
+ try:
181
+ tool_output = json.loads(tool_output_json)
182
+ except (json.JSONDecodeError, TypeError):
183
+ tool_output = None
184
+
185
+ # Parse timestamps
186
+ start_time: datetime | None = None
187
+ if start_time_iso:
188
+ try:
189
+ start_time = datetime.fromisoformat(
190
+ start_time_iso.replace("Z", "+00:00")
191
+ )
192
+ except (ValueError, AttributeError):
193
+ start_time = None
194
+
195
+ end_time: datetime | None = None
196
+ if end_time_iso:
197
+ try:
198
+ end_time = datetime.fromisoformat(end_time_iso.replace("Z", "+00:00"))
199
+ except (ValueError, AttributeError):
200
+ end_time = None
201
+
202
+ # Use current time if start_time is missing
203
+ if start_time is None:
204
+ start_time = datetime.now(timezone.utc)
205
+
206
+ return TraceRecord(
207
+ tool_use_id=tool_use_id,
208
+ trace_id=trace_id,
209
+ session_id=session_id,
210
+ tool_name=tool_name,
211
+ tool_input=tool_input,
212
+ tool_output=tool_output,
213
+ start_time=start_time,
214
+ end_time=end_time,
215
+ duration_ms=duration_ms,
216
+ status=status,
217
+ error_message=error_message,
218
+ parent_tool_use_id=parent_tool_use_id,
219
+ )
220
+
221
+ def get_trace(self, tool_use_id: str) -> TraceRecord | None:
222
+ """
223
+ Get single trace by tool_use_id.
224
+
225
+ Args:
226
+ tool_use_id: Unique tool execution ID (UUID v4)
227
+
228
+ Returns:
229
+ TraceRecord if found, None otherwise
230
+ """
231
+ try:
232
+ if not self._db.connection:
233
+ self._db.connect()
234
+
235
+ cursor = self._db.connection.cursor() # type: ignore[union-attr]
236
+ cursor.execute(
237
+ """
238
+ SELECT tool_use_id, trace_id, session_id, tool_name, tool_input,
239
+ tool_output, start_time, end_time, duration_ms, status,
240
+ error_message, parent_tool_use_id
241
+ FROM tool_traces
242
+ WHERE tool_use_id = ?
243
+ """,
244
+ (tool_use_id,),
245
+ )
246
+
247
+ row = cursor.fetchone()
248
+ if row:
249
+ return self._row_to_trace(row)
250
+
251
+ return None
252
+ except Exception as e:
253
+ logger.info(f"Error getting trace {tool_use_id}: {e}")
254
+ return None
255
+
256
+ def get_traces(
257
+ self,
258
+ session_id: str,
259
+ limit: int = 100,
260
+ start_time: datetime | None = None,
261
+ ) -> list[TraceRecord]:
262
+ """
263
+ Get traces for a session, ordered by start_time DESC (newest first).
264
+
265
+ Args:
266
+ session_id: Session to query
267
+ limit: Maximum traces to return (default 100)
268
+ start_time: Optional filter - only traces after this time
269
+
270
+ Returns:
271
+ List of TraceRecord objects, newest first
272
+ """
273
+ try:
274
+ if not self._db.connection:
275
+ self._db.connect()
276
+
277
+ cursor = self._db.connection.cursor() # type: ignore[union-attr]
278
+
279
+ if start_time:
280
+ start_time_iso = start_time.isoformat()
281
+ cursor.execute(
282
+ """
283
+ SELECT tool_use_id, trace_id, session_id, tool_name, tool_input,
284
+ tool_output, start_time, end_time, duration_ms, status,
285
+ error_message, parent_tool_use_id
286
+ FROM tool_traces
287
+ WHERE session_id = ? AND start_time >= ?
288
+ ORDER BY start_time DESC
289
+ LIMIT ?
290
+ """,
291
+ (session_id, start_time_iso, limit),
292
+ )
293
+ else:
294
+ cursor.execute(
295
+ """
296
+ SELECT tool_use_id, trace_id, session_id, tool_name, tool_input,
297
+ tool_output, start_time, end_time, duration_ms, status,
298
+ error_message, parent_tool_use_id
299
+ FROM tool_traces
300
+ WHERE session_id = ?
301
+ ORDER BY start_time DESC
302
+ LIMIT ?
303
+ """,
304
+ (session_id, limit),
305
+ )
306
+
307
+ rows = cursor.fetchall()
308
+ return [self._row_to_trace(row) for row in rows]
309
+ except Exception as e:
310
+ logger.info(f"Error getting traces for session {session_id}: {e}")
311
+ return []
312
+
313
+ def get_traces_by_tool(self, tool_name: str, limit: int = 100) -> list[TraceRecord]:
314
+ """
315
+ Get traces for specific tool name.
316
+
317
+ Args:
318
+ tool_name: Name of the tool (e.g., "Bash", "Read", "Write")
319
+ limit: Maximum traces to return (default 100)
320
+
321
+ Returns:
322
+ List of TraceRecord objects, newest first
323
+ """
324
+ try:
325
+ if not self._db.connection:
326
+ self._db.connect()
327
+
328
+ cursor = self._db.connection.cursor() # type: ignore[union-attr]
329
+ cursor.execute(
330
+ """
331
+ SELECT tool_use_id, trace_id, session_id, tool_name, tool_input,
332
+ tool_output, start_time, end_time, duration_ms, status,
333
+ error_message, parent_tool_use_id
334
+ FROM tool_traces
335
+ WHERE tool_name = ?
336
+ ORDER BY start_time DESC
337
+ LIMIT ?
338
+ """,
339
+ (tool_name, limit),
340
+ )
341
+
342
+ rows = cursor.fetchall()
343
+ return [self._row_to_trace(row) for row in rows]
344
+ except Exception as e:
345
+ logger.info(f"Error getting traces for tool {tool_name}: {e}")
346
+ return []
347
+
348
+ def get_trace_tree(self, trace_id: str) -> TraceTree | None:
349
+ """
350
+ Get hierarchical view with parent-child relationships.
351
+
352
+ Recursively builds a tree of traces where each node can have children
353
+ (tools invoked by that tool). Useful for understanding nested execution.
354
+
355
+ Args:
356
+ trace_id: Root trace_id to build tree from
357
+
358
+ Returns:
359
+ TraceTree with root and children, or None if not found
360
+ """
361
+ try:
362
+ if not self._db.connection:
363
+ self._db.connect()
364
+
365
+ cursor = self._db.connection.cursor() # type: ignore[union-attr]
366
+
367
+ # Get root trace
368
+ cursor.execute(
369
+ """
370
+ SELECT tool_use_id, trace_id, session_id, tool_name, tool_input,
371
+ tool_output, start_time, end_time, duration_ms, status,
372
+ error_message, parent_tool_use_id
373
+ FROM tool_traces
374
+ WHERE trace_id = ?
375
+ ORDER BY start_time DESC
376
+ LIMIT 1
377
+ """,
378
+ (trace_id,),
379
+ )
380
+
381
+ root_row = cursor.fetchone()
382
+ if not root_row:
383
+ return None
384
+
385
+ root = self._row_to_trace(root_row)
386
+
387
+ # Recursively get children
388
+ def build_tree(parent_trace: TraceRecord) -> TraceTree:
389
+ cursor.execute(
390
+ """
391
+ SELECT tool_use_id, trace_id, session_id, tool_name, tool_input,
392
+ tool_output, start_time, end_time, duration_ms, status,
393
+ error_message, parent_tool_use_id
394
+ FROM tool_traces
395
+ WHERE parent_tool_use_id = ?
396
+ ORDER BY start_time ASC
397
+ """,
398
+ (parent_trace.tool_use_id,),
399
+ )
400
+
401
+ child_rows = cursor.fetchall()
402
+ children = []
403
+ for child_row in child_rows:
404
+ child = self._row_to_trace(child_row)
405
+ children.append(build_tree(child))
406
+
407
+ return TraceTree(root=parent_trace, children=children)
408
+
409
+ return build_tree(root)
410
+ except Exception as e:
411
+ logger.info(f"Error getting trace tree for {trace_id}: {e}")
412
+ return None
413
+
414
+ def get_slow_traces(self, threshold_ms: int, limit: int = 100) -> list[TraceRecord]:
415
+ """
416
+ Find traces exceeding duration threshold.
417
+
418
+ Useful for identifying performance bottlenecks.
419
+
420
+ Args:
421
+ threshold_ms: Minimum duration in milliseconds
422
+ limit: Maximum traces to return (default 100)
423
+
424
+ Returns:
425
+ List of slow TraceRecord objects, slowest first
426
+ """
427
+ try:
428
+ if not self._db.connection:
429
+ self._db.connect()
430
+
431
+ cursor = self._db.connection.cursor() # type: ignore[union-attr]
432
+ cursor.execute(
433
+ """
434
+ SELECT tool_use_id, trace_id, session_id, tool_name, tool_input,
435
+ tool_output, start_time, end_time, duration_ms, status,
436
+ error_message, parent_tool_use_id
437
+ FROM tool_traces
438
+ WHERE duration_ms IS NOT NULL AND duration_ms >= ?
439
+ ORDER BY duration_ms DESC
440
+ LIMIT ?
441
+ """,
442
+ (threshold_ms, limit),
443
+ )
444
+
445
+ rows = cursor.fetchall()
446
+ return [self._row_to_trace(row) for row in rows]
447
+ except Exception as e:
448
+ logger.info(f"Error getting slow traces: {e}")
449
+ return []
450
+
451
+ def get_error_traces(self, session_id: str, limit: int = 100) -> list[TraceRecord]:
452
+ """
453
+ Get traces with errors/failures.
454
+
455
+ Filters for traces with status='failed' or error_message is not null.
456
+
457
+ Args:
458
+ session_id: Session to query
459
+ limit: Maximum traces to return (default 100)
460
+
461
+ Returns:
462
+ List of error TraceRecord objects, newest first
463
+ """
464
+ try:
465
+ if not self._db.connection:
466
+ self._db.connect()
467
+
468
+ cursor = self._db.connection.cursor() # type: ignore[union-attr]
469
+ cursor.execute(
470
+ """
471
+ SELECT tool_use_id, trace_id, session_id, tool_name, tool_input,
472
+ tool_output, start_time, end_time, duration_ms, status,
473
+ error_message, parent_tool_use_id
474
+ FROM tool_traces
475
+ WHERE session_id = ? AND (status IN ('failed', 'timeout', 'cancelled')
476
+ OR error_message IS NOT NULL)
477
+ ORDER BY start_time DESC
478
+ LIMIT ?
479
+ """,
480
+ (session_id, limit),
481
+ )
482
+
483
+ rows = cursor.fetchall()
484
+ return [self._row_to_trace(row) for row in rows]
485
+ except Exception as e:
486
+ logger.info(f"Error getting error traces: {e}")
487
+ return []
@@ -0,0 +1,56 @@
1
+ {
2
+ "description": "Model pricing configuration for cost tracking",
3
+ "last_updated": "2026-01-16",
4
+ "models": {
5
+ "claude-haiku-4-5-20251001": {
6
+ "name": "Claude Haiku",
7
+ "display_name": "Haiku 4.5",
8
+ "input_cost_per_mtok": 0.80,
9
+ "output_cost_per_mtok": 4.00,
10
+ "description": "Fast, efficient model for routine tasks"
11
+ },
12
+ "claude-sonnet-4-20250514": {
13
+ "name": "Claude Sonnet",
14
+ "display_name": "Sonnet 4",
15
+ "input_cost_per_mtok": 3.00,
16
+ "output_cost_per_mtok": 15.00,
17
+ "description": "Balanced model for most tasks"
18
+ },
19
+ "claude-opus-4-1-20250805": {
20
+ "name": "Claude Opus",
21
+ "display_name": "Opus 4.1",
22
+ "input_cost_per_mtok": 15.00,
23
+ "output_cost_per_mtok": 75.00,
24
+ "description": "Most capable model for complex reasoning"
25
+ }
26
+ },
27
+ "gemini_models": {
28
+ "gemini-2.0-flash": {
29
+ "name": "Gemini 2.0 Flash",
30
+ "input_cost_per_mtok": 0.075,
31
+ "output_cost_per_mtok": 0.30,
32
+ "description": "Fast multimodal model"
33
+ },
34
+ "gemini-2.0-pro": {
35
+ "name": "Gemini 2.0 Pro",
36
+ "input_cost_per_mtok": 1.50,
37
+ "output_cost_per_mtok": 6.00,
38
+ "description": "Advanced reasoning model"
39
+ }
40
+ },
41
+ "defaults": {
42
+ "input_cost_per_mtok": 2.00,
43
+ "output_cost_per_mtok": 10.00
44
+ },
45
+ "alert_thresholds": {
46
+ "budget_warning_percent": 80,
47
+ "budget_critical_percent": 95,
48
+ "model_overage_multiplier": 1.5,
49
+ "trajectory_overage_multiplier": 1.3
50
+ },
51
+ "tracking": {
52
+ "accuracy_target_percent": 5,
53
+ "cost_calculation_method": "token_based",
54
+ "rounding_precision": 4
55
+ }
56
+ }