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,194 @@
1
+ from __future__ import annotations
2
+
3
+ import logging
4
+
5
+ logger = logging.getLogger(__name__)
6
+
7
+ """
8
+ SessionCollection - Session state and management interface.
9
+
10
+ Provides methods to:
11
+ - Get current session state automatically
12
+ - Set up environment variables automatically
13
+ - Track session metadata
14
+ - Detect post-compact sessions
15
+
16
+ Integration with SessionStart hook:
17
+ sdk = SDK()
18
+ state = sdk.sessions.get_current_state()
19
+ sdk.sessions.setup_environment_variables(state)
20
+ """
21
+
22
+
23
+ from typing import TYPE_CHECKING
24
+
25
+ from htmlgraph.collections.base import BaseCollection
26
+ from htmlgraph.session_state import SessionState, SessionStateManager
27
+
28
+ if TYPE_CHECKING:
29
+ from htmlgraph.sdk import SDK
30
+
31
+
32
+ class SessionCollection(BaseCollection):
33
+ """
34
+ Collection interface for session state management.
35
+
36
+ Extends BaseCollection with session-specific state management operations.
37
+
38
+ Provides:
39
+ - Automatic session state detection (post-compact, delegation status)
40
+ - Environment variable setup (CLAUDE_SESSION_ID, CLAUDE_DELEGATION_ENABLED, etc.)
41
+ - Session metadata recording and retrieval
42
+ - Compact detection
43
+
44
+ Example:
45
+ >>> sdk = SDK(agent="claude")
46
+ >>> state = sdk.sessions.get_current_state()
47
+ >>> sdk.sessions.setup_environment_variables(state)
48
+ # All environment variables automatically set
49
+ """
50
+
51
+ _collection_name = "sessions"
52
+ _node_type = "session"
53
+
54
+ def __init__(self, sdk: SDK):
55
+ """
56
+ Initialize SessionCollection.
57
+
58
+ Args:
59
+ sdk: Parent SDK instance
60
+ """
61
+ super().__init__(sdk, "sessions", "session")
62
+ self._state_manager = SessionStateManager(sdk._directory)
63
+
64
+ def get_current_state(self) -> SessionState:
65
+ """
66
+ Get current session state with automatic detection.
67
+
68
+ Automatically detects:
69
+ - Current session ID
70
+ - Session source (startup, resume, compact, clear)
71
+ - Post-compact status
72
+ - Delegation enable/disable
73
+ - Session validity
74
+
75
+ Returns:
76
+ SessionState dict with:
77
+ - session_id: Current session identifier
78
+ - session_source: "startup", "resume", "compact", "clear"
79
+ - is_post_compact: True if this is post-compact session
80
+ - previous_session_id: Previous session ID if available
81
+ - delegation_enabled: Should delegation be active
82
+ - prompt_injected: Was orchestrator prompt injected
83
+ - session_valid: Is session valid for tracking
84
+ - timestamp: Current UTC timestamp
85
+ - compact_metadata: Compact detection details
86
+
87
+ Example:
88
+ >>> sdk = SDK()
89
+ >>> state = sdk.sessions.get_current_state()
90
+ >>> logger.info(f"Session: {state['session_id']}")
91
+ >>> logger.info(f"Post-compact: {state['is_post_compact']}")
92
+ >>> logger.info(f"Delegation enabled: {state['delegation_enabled']}")
93
+ """
94
+ return self._state_manager.get_current_state()
95
+
96
+ def setup_environment_variables(
97
+ self,
98
+ session_state: SessionState | None = None,
99
+ auto_detect_compact: bool = True,
100
+ ) -> dict[str, str]:
101
+ """
102
+ Automatically set up environment variables for session state.
103
+
104
+ Sets up environment variables that persist across context boundaries:
105
+ - CLAUDE_SESSION_ID: Current session identifier
106
+ - CLAUDE_SESSION_SOURCE: "startup|resume|compact|clear"
107
+ - CLAUDE_SESSION_COMPACTED: "true|false"
108
+ - CLAUDE_DELEGATION_ENABLED: "true|false"
109
+ - CLAUDE_PREVIOUS_SESSION_ID: Previous session ID
110
+ - CLAUDE_ORCHESTRATOR_ACTIVE: "true|false"
111
+ - CLAUDE_PROMPT_PERSISTENCE_VERSION: "1.0"
112
+
113
+ Args:
114
+ session_state: Session state dict (auto-detected if not provided)
115
+ auto_detect_compact: Whether to auto-detect post-compact state
116
+
117
+ Returns:
118
+ Dict of environment variables that were set
119
+
120
+ Example:
121
+ >>> sdk = SDK()
122
+ >>> state = sdk.sessions.get_current_state()
123
+ >>> env_vars = sdk.sessions.setup_environment_variables(state)
124
+ >>> logger.info(f"CLAUDE_SESSION_ID: {env_vars['CLAUDE_SESSION_ID']}")
125
+ >>> logger.info(f"CLAUDE_DELEGATION_ENABLED: {env_vars['CLAUDE_DELEGATION_ENABLED']}")
126
+ """
127
+ return self._state_manager.setup_environment_variables(
128
+ session_state=session_state, auto_detect_compact=auto_detect_compact
129
+ )
130
+
131
+ def record_state(
132
+ self,
133
+ session_id: str,
134
+ source: str,
135
+ is_post_compact: bool,
136
+ delegation_enabled: bool,
137
+ environment_vars: dict[str, str] | None = None,
138
+ ) -> None:
139
+ """
140
+ Store session state metadata for future reference.
141
+
142
+ Args:
143
+ session_id: Current session ID
144
+ source: Session source ("startup", "resume", "compact", "clear")
145
+ is_post_compact: Whether this is post-compact
146
+ delegation_enabled: Whether delegation is enabled
147
+ environment_vars: Environment variables that were set
148
+
149
+ Example:
150
+ >>> sdk = SDK()
151
+ >>> sdk.sessions.record_state(
152
+ ... session_id="sess-123",
153
+ ... source="compact",
154
+ ... is_post_compact=True,
155
+ ... delegation_enabled=True
156
+ ... )
157
+ """
158
+ self._state_manager.record_state(
159
+ session_id=session_id,
160
+ source=source,
161
+ is_post_compact=is_post_compact,
162
+ delegation_enabled=delegation_enabled,
163
+ environment_vars=environment_vars,
164
+ )
165
+
166
+ def detect_compact_automatically(self) -> bool:
167
+ """
168
+ Auto-detect if this is post-compact by comparing session IDs.
169
+
170
+ Returns:
171
+ True if this is a post-compact session
172
+
173
+ Example:
174
+ >>> sdk = SDK()
175
+ >>> if sdk.sessions.detect_compact_automatically():
176
+ ... logger.info("This is a post-compact session")
177
+ """
178
+ return self._state_manager.detect_compact_automatically()
179
+
180
+ def get_state_manager(self) -> SessionStateManager:
181
+ """
182
+ Get the underlying SessionStateManager.
183
+
184
+ Use this for advanced session state operations.
185
+
186
+ Returns:
187
+ SessionStateManager instance
188
+
189
+ Example:
190
+ >>> sdk = SDK()
191
+ >>> manager = sdk.sessions.get_state_manager()
192
+ >>> state = manager.get_current_state()
193
+ """
194
+ return self._state_manager
@@ -1,20 +1,26 @@
1
+ from __future__ import annotations
2
+
3
+ import logging
4
+
5
+ logger = logging.getLogger(__name__)
6
+
1
7
  """
2
8
  Spike collection for managing investigation and research spikes.
3
9
 
4
10
  Extends BaseCollection with spike-specific builder support.
5
11
  """
6
12
 
7
- from __future__ import annotations
13
+
14
+ from datetime import datetime
8
15
  from typing import TYPE_CHECKING
9
16
 
10
17
  if TYPE_CHECKING:
11
18
  from htmlgraph.sdk import SDK
12
- from htmlgraph.builders import SpikeBuilder
13
19
 
14
20
  from htmlgraph.collections.base import BaseCollection
15
21
 
16
22
 
17
- class SpikeCollection(BaseCollection['SpikeCollection']):
23
+ class SpikeCollection(BaseCollection["SpikeCollection"]):
18
24
  """
19
25
  Collection interface for spikes with builder support.
20
26
 
@@ -37,7 +43,7 @@ class SpikeCollection(BaseCollection['SpikeCollection']):
37
43
  _collection_name = "spikes"
38
44
  _node_type = "spike"
39
45
 
40
- def __init__(self, sdk: 'SDK'):
46
+ def __init__(self, sdk: SDK):
41
47
  """
42
48
  Initialize spike collection.
43
49
 
@@ -47,23 +53,57 @@ class SpikeCollection(BaseCollection['SpikeCollection']):
47
53
  super().__init__(sdk, "spikes", "spike")
48
54
  self._sdk = sdk
49
55
 
50
- def create(self, title: str, **kwargs) -> SpikeBuilder:
56
+ # Set builder class for create() method
57
+ from htmlgraph.builders import SpikeBuilder
58
+
59
+ self._builder_class = SpikeBuilder
60
+
61
+ def get_latest(self, agent: str | None = None, limit: int = 1) -> list:
51
62
  """
52
- Create a new spike with fluent interface.
63
+ Get the most recent spike(s), optionally filtered by agent.
64
+
65
+ Useful for retrieving subagent findings after delegation.
53
66
 
54
67
  Args:
55
- title: Spike title
56
- **kwargs: Additional spike properties
68
+ agent: Filter by agent_assigned (optional)
69
+ limit: Maximum number of spikes to return (default: 1)
57
70
 
58
71
  Returns:
59
- SpikeBuilder for method chaining
72
+ List of most recent Spike nodes (newest first)
60
73
 
61
74
  Example:
62
- >>> spike = sdk.spikes.create("Investigate Database Options") \\
63
- ... .set_spike_type(SpikeType.TECHNICAL) \\
64
- ... .set_timebox_hours(2) \\
65
- ... .add_steps(["Research PostgreSQL", "Research MongoDB"]) \\
66
- ... .save()
75
+ >>> # Get latest spike from explorer subagent
76
+ >>> sdk = SDK(agent="orchestrator")
77
+ >>> findings = sdk.spikes.get_latest(agent="explorer")
78
+ >>> if findings:
79
+ ... print(findings[0].findings)
80
+ >>>
81
+ >>> # Get latest 5 spikes from any agent
82
+ >>> recent = sdk.spikes.get_latest(limit=5)
67
83
  """
68
- from htmlgraph.builders import SpikeBuilder
69
- return SpikeBuilder(self._sdk, title, **kwargs)
84
+ from datetime import timezone
85
+
86
+ # Get all spikes
87
+ all_spikes = self.all()
88
+
89
+ # Filter by agent if specified
90
+ # Check both agent_assigned and model_name fields
91
+ if agent:
92
+ all_spikes = [
93
+ s
94
+ for s in all_spikes
95
+ if (s.agent_assigned and agent.lower() in s.agent_assigned.lower())
96
+ or (s.model_name and agent.lower() in s.model_name.lower())
97
+ ]
98
+
99
+ # Normalize to UTC for comparison
100
+ def to_comparable(dt: datetime) -> datetime:
101
+ if dt.tzinfo is None:
102
+ return dt.replace(tzinfo=timezone.utc)
103
+ return dt
104
+
105
+ # Sort by created timestamp (newest first)
106
+ all_spikes.sort(key=lambda s: to_comparable(s.created), reverse=True)
107
+
108
+ # Return limited results
109
+ return all_spikes[:limit]
@@ -0,0 +1,241 @@
1
+ from __future__ import annotations
2
+
3
+ import logging
4
+
5
+ logger = logging.getLogger(__name__)
6
+
7
+ """
8
+ Task delegation collection for tracking spawned agent work.
9
+
10
+ Captures observability data for Task() calls:
11
+ - Which agent was spawned (gemini-spawner, codex-spawner, copilot-spawner, haiku)
12
+ - What task was assigned
13
+ - How long it took
14
+ - What was the output/result
15
+ - Cost (tokens used)
16
+ - Success/failure status
17
+
18
+ This data proves multi-agent orchestration works and enables dashboard attribution.
19
+ """
20
+
21
+
22
+ from datetime import datetime
23
+ from typing import TYPE_CHECKING, Any
24
+
25
+ if TYPE_CHECKING:
26
+ from htmlgraph.sdk import SDK
27
+
28
+ from htmlgraph.collections.base import BaseCollection
29
+
30
+
31
+ class TaskDelegationCollection(BaseCollection["TaskDelegationCollection"]):
32
+ """
33
+ Collection interface for task delegations.
34
+
35
+ Tracks all spawned agent work with metrics:
36
+ - Agent type (gemini-spawner, codex-spawner, copilot-spawner, haiku)
37
+ - Task description
38
+ - Start and end timestamps
39
+ - Duration in seconds
40
+ - Tokens used
41
+ - Cost in USD
42
+ - Status (success/failure)
43
+ - Result summary
44
+
45
+ Example:
46
+ >>> sdk = SDK(agent="orchestrator")
47
+ >>> delegations = sdk.task_delegations.where(agent_type="codex-spawner")
48
+ >>> for d in delegations:
49
+ ... logger.info(f"{d.agent_type}: {d.task_description} ({d.duration_seconds}s)")
50
+ >>>
51
+ >>> # Get all delegations for a specific agent
52
+ >>> gemini_work = sdk.task_delegations.where(agent_type="gemini-spawner")
53
+ >>>
54
+ >>> # Calculate total cost
55
+ >>> total_cost = sum(float(d.cost_usd or 0) for d in sdk.task_delegations.all())
56
+ """
57
+
58
+ _collection_name = "task-delegations"
59
+ _node_type = "task-delegation"
60
+
61
+ def __init__(self, sdk: SDK):
62
+ """
63
+ Initialize task delegation collection.
64
+
65
+ Args:
66
+ sdk: Parent SDK instance
67
+ """
68
+ super().__init__(sdk, "task-delegations", "task-delegation")
69
+ self._sdk = sdk
70
+
71
+ def create_delegation(
72
+ self,
73
+ agent_type: str,
74
+ task_description: str,
75
+ timestamp_start: datetime | None = None,
76
+ tokens_used: int = 0,
77
+ cost_usd: float = 0.0,
78
+ status: str = "pending",
79
+ result_summary: str = "",
80
+ ) -> Any:
81
+ """
82
+ Record a task delegation.
83
+
84
+ Args:
85
+ agent_type: Type of spawned agent (gemini-spawner, codex-spawner, copilot-spawner, haiku)
86
+ task_description: Human-readable task description
87
+ timestamp_start: When delegation started (defaults to now)
88
+ tokens_used: Number of tokens used by the agent
89
+ cost_usd: Cost in USD for this delegation
90
+ status: success/failure/pending
91
+ result_summary: Brief summary of the result
92
+
93
+ Returns:
94
+ Created task delegation node
95
+ """
96
+ if timestamp_start is None:
97
+ timestamp_start = datetime.utcnow()
98
+
99
+ # Create delegation record via base collection
100
+ return self.create(
101
+ title=f"{agent_type}: {task_description[:50]}...",
102
+ ).set_metadata(
103
+ {
104
+ "agent_type": agent_type,
105
+ "task_description": task_description,
106
+ "timestamp_start": timestamp_start.isoformat(),
107
+ "tokens_used": tokens_used,
108
+ "cost_usd": cost_usd,
109
+ "status": status,
110
+ "result_summary": result_summary,
111
+ }
112
+ )
113
+
114
+ def update_delegation(
115
+ self,
116
+ delegation_id: str,
117
+ timestamp_end: datetime | None = None,
118
+ tokens_used: int | None = None,
119
+ cost_usd: float | None = None,
120
+ status: str | None = None,
121
+ result_summary: str | None = None,
122
+ ) -> Any:
123
+ """
124
+ Update a delegation record with completion info.
125
+
126
+ Args:
127
+ delegation_id: ID of the delegation to update
128
+ timestamp_end: When delegation completed
129
+ tokens_used: Updated token count
130
+ cost_usd: Updated cost
131
+ status: Updated status
132
+ result_summary: Updated result summary
133
+
134
+ Returns:
135
+ Updated delegation node
136
+ """
137
+ if timestamp_end is None:
138
+ timestamp_end = datetime.utcnow()
139
+
140
+ with self.edit(delegation_id) as delegation:
141
+ if timestamp_end:
142
+ delegation.timestamp_end = timestamp_end.isoformat() # type: ignore[attr-defined]
143
+
144
+ # Calculate duration if we have start time
145
+ if hasattr(delegation, "timestamp_start") and timestamp_end:
146
+ start = datetime.fromisoformat(str(delegation.timestamp_start))
147
+ duration = (timestamp_end - start).total_seconds()
148
+ delegation.duration_seconds = int(duration) # type: ignore[attr-defined]
149
+
150
+ if tokens_used is not None:
151
+ delegation.tokens_used = tokens_used # type: ignore[attr-defined]
152
+ if cost_usd is not None:
153
+ delegation.cost_usd = cost_usd # type: ignore[attr-defined]
154
+ if status is not None:
155
+ delegation.status = status # type: ignore[assignment]
156
+ if result_summary is not None:
157
+ delegation.result_summary = result_summary # type: ignore[attr-defined]
158
+
159
+ return delegation
160
+
161
+ def get_by_agent_type(self, agent_type: str) -> list:
162
+ """
163
+ Get all delegations for a specific agent type.
164
+
165
+ Args:
166
+ agent_type: Type of agent (gemini-spawner, codex-spawner, etc.)
167
+
168
+ Returns:
169
+ List of delegations for that agent type
170
+ """
171
+ return self.where(agent_type=agent_type)
172
+
173
+ def get_by_status(self, status: str) -> list:
174
+ """
175
+ Get all delegations with a specific status.
176
+
177
+ Args:
178
+ status: Status to filter by (success/failure/pending)
179
+
180
+ Returns:
181
+ List of delegations with that status
182
+ """
183
+ return self.where(status=status)
184
+
185
+ def get_stats(self) -> dict:
186
+ """
187
+ Get aggregated statistics about delegations.
188
+
189
+ Returns:
190
+ Dictionary with:
191
+ - total_delegations: Count of all delegations
192
+ - by_agent_type: Count per agent type
193
+ - by_status: Count per status
194
+ - total_tokens: Sum of all tokens used
195
+ - total_cost: Sum of all costs in USD
196
+ - average_duration: Average duration in seconds
197
+ """
198
+ all_delegations = self.all()
199
+
200
+ if not all_delegations:
201
+ return {
202
+ "total_delegations": 0,
203
+ "by_agent_type": {},
204
+ "by_status": {},
205
+ "total_tokens": 0,
206
+ "total_cost": 0.0,
207
+ "average_duration": 0.0,
208
+ }
209
+
210
+ # Count by agent type
211
+ by_agent_type: dict[str, int] = {}
212
+ for d in all_delegations:
213
+ agent = getattr(d, "agent_type", "unknown")
214
+ by_agent_type[agent] = by_agent_type.get(agent, 0) + 1
215
+
216
+ # Count by status
217
+ by_status: dict[str, int] = {}
218
+ for d in all_delegations:
219
+ status = getattr(d, "status", "unknown")
220
+ by_status[status] = by_status.get(status, 0) + 1
221
+
222
+ # Sum tokens and cost
223
+ total_tokens = sum(getattr(d, "tokens_used", 0) for d in all_delegations)
224
+ total_cost = sum(float(getattr(d, "cost_usd", 0) or 0) for d in all_delegations)
225
+
226
+ # Average duration
227
+ durations = [
228
+ getattr(d, "duration_seconds", 0)
229
+ for d in all_delegations
230
+ if hasattr(d, "duration_seconds")
231
+ ]
232
+ average_duration = sum(durations) / len(durations) if durations else 0.0
233
+
234
+ return {
235
+ "total_delegations": len(all_delegations),
236
+ "by_agent_type": by_agent_type,
237
+ "by_status": by_status,
238
+ "total_tokens": total_tokens,
239
+ "total_cost": round(total_cost, 4),
240
+ "average_duration": round(average_duration, 2),
241
+ }