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.
- htmlgraph/.htmlgraph/.session-warning-state.json +6 -0
- htmlgraph/.htmlgraph/agents.json +72 -0
- htmlgraph/.htmlgraph/htmlgraph.db +0 -0
- htmlgraph/__init__.py +51 -1
- htmlgraph/__init__.pyi +123 -0
- htmlgraph/agent_detection.py +26 -10
- htmlgraph/agent_registry.py +2 -1
- htmlgraph/analytics/__init__.py +8 -1
- htmlgraph/analytics/cli.py +86 -20
- htmlgraph/analytics/cost_analyzer.py +391 -0
- htmlgraph/analytics/cost_monitor.py +664 -0
- htmlgraph/analytics/cost_reporter.py +675 -0
- htmlgraph/analytics/cross_session.py +617 -0
- htmlgraph/analytics/dependency.py +10 -6
- htmlgraph/analytics/pattern_learning.py +771 -0
- htmlgraph/analytics/session_graph.py +707 -0
- htmlgraph/analytics/strategic/__init__.py +80 -0
- htmlgraph/analytics/strategic/cost_optimizer.py +611 -0
- htmlgraph/analytics/strategic/pattern_detector.py +876 -0
- htmlgraph/analytics/strategic/preference_manager.py +709 -0
- htmlgraph/analytics/strategic/suggestion_engine.py +747 -0
- htmlgraph/analytics/work_type.py +67 -27
- htmlgraph/analytics_index.py +53 -20
- htmlgraph/api/__init__.py +3 -0
- htmlgraph/api/cost_alerts_websocket.py +416 -0
- htmlgraph/api/main.py +2498 -0
- htmlgraph/api/static/htmx.min.js +1 -0
- htmlgraph/api/static/style-redesign.css +1344 -0
- htmlgraph/api/static/style.css +1079 -0
- htmlgraph/api/templates/dashboard-redesign.html +1366 -0
- htmlgraph/api/templates/dashboard.html +794 -0
- htmlgraph/api/templates/partials/activity-feed-hierarchical.html +326 -0
- htmlgraph/api/templates/partials/activity-feed.html +1100 -0
- htmlgraph/api/templates/partials/agents-redesign.html +317 -0
- htmlgraph/api/templates/partials/agents.html +317 -0
- htmlgraph/api/templates/partials/event-traces.html +373 -0
- htmlgraph/api/templates/partials/features-kanban-redesign.html +509 -0
- htmlgraph/api/templates/partials/features.html +578 -0
- htmlgraph/api/templates/partials/metrics-redesign.html +346 -0
- htmlgraph/api/templates/partials/metrics.html +346 -0
- htmlgraph/api/templates/partials/orchestration-redesign.html +443 -0
- htmlgraph/api/templates/partials/orchestration.html +198 -0
- htmlgraph/api/templates/partials/spawners.html +375 -0
- htmlgraph/api/templates/partials/work-items.html +613 -0
- htmlgraph/api/websocket.py +538 -0
- htmlgraph/archive/__init__.py +24 -0
- htmlgraph/archive/bloom.py +234 -0
- htmlgraph/archive/fts.py +297 -0
- htmlgraph/archive/manager.py +583 -0
- htmlgraph/archive/search.py +244 -0
- htmlgraph/atomic_ops.py +560 -0
- htmlgraph/attribute_index.py +2 -1
- htmlgraph/bounded_paths.py +539 -0
- htmlgraph/builders/base.py +57 -2
- htmlgraph/builders/bug.py +19 -3
- htmlgraph/builders/chore.py +19 -3
- htmlgraph/builders/epic.py +19 -3
- htmlgraph/builders/feature.py +27 -3
- htmlgraph/builders/insight.py +2 -1
- htmlgraph/builders/metric.py +2 -1
- htmlgraph/builders/pattern.py +2 -1
- htmlgraph/builders/phase.py +19 -3
- htmlgraph/builders/spike.py +29 -3
- htmlgraph/builders/track.py +42 -1
- htmlgraph/cigs/__init__.py +81 -0
- htmlgraph/cigs/autonomy.py +385 -0
- htmlgraph/cigs/cost.py +475 -0
- htmlgraph/cigs/messages_basic.py +472 -0
- htmlgraph/cigs/messaging.py +365 -0
- htmlgraph/cigs/models.py +771 -0
- htmlgraph/cigs/pattern_storage.py +427 -0
- htmlgraph/cigs/patterns.py +503 -0
- htmlgraph/cigs/posttool_analyzer.py +234 -0
- htmlgraph/cigs/reporter.py +818 -0
- htmlgraph/cigs/tracker.py +317 -0
- htmlgraph/cli/.htmlgraph/.session-warning-state.json +6 -0
- htmlgraph/cli/.htmlgraph/agents.json +72 -0
- htmlgraph/cli/.htmlgraph/htmlgraph.db +0 -0
- htmlgraph/cli/__init__.py +42 -0
- htmlgraph/cli/__main__.py +6 -0
- htmlgraph/cli/analytics.py +1424 -0
- htmlgraph/cli/base.py +685 -0
- htmlgraph/cli/constants.py +206 -0
- htmlgraph/cli/core.py +954 -0
- htmlgraph/cli/main.py +147 -0
- htmlgraph/cli/models.py +475 -0
- htmlgraph/cli/templates/__init__.py +1 -0
- htmlgraph/cli/templates/cost_dashboard.py +399 -0
- htmlgraph/cli/work/__init__.py +239 -0
- htmlgraph/cli/work/browse.py +115 -0
- htmlgraph/cli/work/features.py +568 -0
- htmlgraph/cli/work/orchestration.py +676 -0
- htmlgraph/cli/work/report.py +728 -0
- htmlgraph/cli/work/sessions.py +466 -0
- htmlgraph/cli/work/snapshot.py +559 -0
- htmlgraph/cli/work/tracks.py +486 -0
- htmlgraph/cli_commands/__init__.py +1 -0
- htmlgraph/cli_commands/feature.py +195 -0
- htmlgraph/cli_framework.py +115 -0
- htmlgraph/collections/__init__.py +2 -0
- htmlgraph/collections/base.py +197 -14
- htmlgraph/collections/bug.py +2 -1
- htmlgraph/collections/chore.py +2 -1
- htmlgraph/collections/epic.py +2 -1
- htmlgraph/collections/feature.py +2 -1
- htmlgraph/collections/insight.py +2 -1
- htmlgraph/collections/metric.py +2 -1
- htmlgraph/collections/pattern.py +2 -1
- htmlgraph/collections/phase.py +2 -1
- htmlgraph/collections/session.py +194 -0
- htmlgraph/collections/spike.py +13 -2
- htmlgraph/collections/task_delegation.py +241 -0
- htmlgraph/collections/todo.py +14 -1
- htmlgraph/collections/traces.py +487 -0
- htmlgraph/config/cost_models.json +56 -0
- htmlgraph/config.py +190 -0
- htmlgraph/context_analytics.py +2 -1
- htmlgraph/converter.py +116 -7
- htmlgraph/cost_analysis/__init__.py +5 -0
- htmlgraph/cost_analysis/analyzer.py +438 -0
- htmlgraph/dashboard.html +2246 -248
- htmlgraph/dashboard.html.backup +6592 -0
- htmlgraph/dashboard.html.bak +7181 -0
- htmlgraph/dashboard.html.bak2 +7231 -0
- htmlgraph/dashboard.html.bak3 +7232 -0
- htmlgraph/db/__init__.py +38 -0
- htmlgraph/db/queries.py +790 -0
- htmlgraph/db/schema.py +1788 -0
- htmlgraph/decorators.py +317 -0
- htmlgraph/dependency_models.py +2 -1
- htmlgraph/deploy.py +26 -27
- htmlgraph/docs/API_REFERENCE.md +841 -0
- htmlgraph/docs/HTTP_API.md +750 -0
- htmlgraph/docs/INTEGRATION_GUIDE.md +752 -0
- htmlgraph/docs/ORCHESTRATION_PATTERNS.md +717 -0
- htmlgraph/docs/README.md +532 -0
- htmlgraph/docs/__init__.py +77 -0
- htmlgraph/docs/docs_version.py +55 -0
- htmlgraph/docs/metadata.py +93 -0
- htmlgraph/docs/migrations.py +232 -0
- htmlgraph/docs/template_engine.py +143 -0
- htmlgraph/docs/templates/_sections/cli_reference.md.j2 +52 -0
- htmlgraph/docs/templates/_sections/core_concepts.md.j2 +29 -0
- htmlgraph/docs/templates/_sections/sdk_basics.md.j2 +69 -0
- htmlgraph/docs/templates/base_agents.md.j2 +78 -0
- htmlgraph/docs/templates/example_user_override.md.j2 +47 -0
- htmlgraph/docs/version_check.py +163 -0
- htmlgraph/edge_index.py +2 -1
- htmlgraph/error_handler.py +544 -0
- htmlgraph/event_log.py +86 -37
- htmlgraph/event_migration.py +2 -1
- htmlgraph/file_watcher.py +12 -8
- htmlgraph/find_api.py +2 -1
- htmlgraph/git_events.py +67 -9
- htmlgraph/hooks/.htmlgraph/.session-warning-state.json +6 -0
- htmlgraph/hooks/.htmlgraph/agents.json +72 -0
- htmlgraph/hooks/.htmlgraph/index.sqlite +0 -0
- htmlgraph/hooks/__init__.py +8 -0
- htmlgraph/hooks/bootstrap.py +169 -0
- htmlgraph/hooks/cigs_pretool_enforcer.py +354 -0
- htmlgraph/hooks/concurrent_sessions.py +208 -0
- htmlgraph/hooks/context.py +350 -0
- htmlgraph/hooks/drift_handler.py +525 -0
- htmlgraph/hooks/event_tracker.py +790 -99
- htmlgraph/hooks/git_commands.py +175 -0
- htmlgraph/hooks/installer.py +5 -1
- htmlgraph/hooks/orchestrator.py +327 -76
- htmlgraph/hooks/orchestrator_reflector.py +31 -4
- htmlgraph/hooks/post_tool_use_failure.py +32 -7
- htmlgraph/hooks/post_tool_use_handler.py +257 -0
- htmlgraph/hooks/posttooluse.py +92 -19
- htmlgraph/hooks/pretooluse.py +527 -7
- htmlgraph/hooks/prompt_analyzer.py +637 -0
- htmlgraph/hooks/session_handler.py +668 -0
- htmlgraph/hooks/session_summary.py +395 -0
- htmlgraph/hooks/state_manager.py +504 -0
- htmlgraph/hooks/subagent_detection.py +202 -0
- htmlgraph/hooks/subagent_stop.py +369 -0
- htmlgraph/hooks/task_enforcer.py +99 -4
- htmlgraph/hooks/validator.py +212 -91
- htmlgraph/ids.py +2 -1
- htmlgraph/learning.py +125 -100
- htmlgraph/mcp_server.py +2 -1
- htmlgraph/models.py +217 -18
- htmlgraph/operations/README.md +62 -0
- htmlgraph/operations/__init__.py +79 -0
- htmlgraph/operations/analytics.py +339 -0
- htmlgraph/operations/bootstrap.py +289 -0
- htmlgraph/operations/events.py +244 -0
- htmlgraph/operations/fastapi_server.py +231 -0
- htmlgraph/operations/hooks.py +350 -0
- htmlgraph/operations/initialization.py +597 -0
- htmlgraph/operations/initialization.py.backup +228 -0
- htmlgraph/operations/server.py +303 -0
- htmlgraph/orchestration/__init__.py +58 -0
- htmlgraph/orchestration/claude_launcher.py +179 -0
- htmlgraph/orchestration/command_builder.py +72 -0
- htmlgraph/orchestration/headless_spawner.py +281 -0
- htmlgraph/orchestration/live_events.py +377 -0
- htmlgraph/orchestration/model_selection.py +327 -0
- htmlgraph/orchestration/plugin_manager.py +140 -0
- htmlgraph/orchestration/prompts.py +137 -0
- htmlgraph/orchestration/spawner_event_tracker.py +383 -0
- htmlgraph/orchestration/spawners/__init__.py +16 -0
- htmlgraph/orchestration/spawners/base.py +194 -0
- htmlgraph/orchestration/spawners/claude.py +173 -0
- htmlgraph/orchestration/spawners/codex.py +435 -0
- htmlgraph/orchestration/spawners/copilot.py +294 -0
- htmlgraph/orchestration/spawners/gemini.py +471 -0
- htmlgraph/orchestration/subprocess_runner.py +36 -0
- htmlgraph/{orchestration.py → orchestration/task_coordination.py} +16 -8
- htmlgraph/orchestration.md +563 -0
- htmlgraph/orchestrator-system-prompt-optimized.txt +863 -0
- htmlgraph/orchestrator.py +2 -1
- htmlgraph/orchestrator_config.py +357 -0
- htmlgraph/orchestrator_mode.py +115 -4
- htmlgraph/parallel.py +2 -1
- htmlgraph/parser.py +86 -6
- htmlgraph/path_query.py +608 -0
- htmlgraph/pattern_matcher.py +636 -0
- htmlgraph/pydantic_models.py +476 -0
- htmlgraph/quality_gates.py +350 -0
- htmlgraph/query_builder.py +2 -1
- htmlgraph/query_composer.py +509 -0
- htmlgraph/reflection.py +443 -0
- htmlgraph/refs.py +344 -0
- htmlgraph/repo_hash.py +512 -0
- htmlgraph/repositories/__init__.py +292 -0
- htmlgraph/repositories/analytics_repository.py +455 -0
- htmlgraph/repositories/analytics_repository_standard.py +628 -0
- htmlgraph/repositories/feature_repository.py +581 -0
- htmlgraph/repositories/feature_repository_htmlfile.py +668 -0
- htmlgraph/repositories/feature_repository_memory.py +607 -0
- htmlgraph/repositories/feature_repository_sqlite.py +858 -0
- htmlgraph/repositories/filter_service.py +620 -0
- htmlgraph/repositories/filter_service_standard.py +445 -0
- htmlgraph/repositories/shared_cache.py +621 -0
- htmlgraph/repositories/shared_cache_memory.py +395 -0
- htmlgraph/repositories/track_repository.py +552 -0
- htmlgraph/repositories/track_repository_htmlfile.py +619 -0
- htmlgraph/repositories/track_repository_memory.py +508 -0
- htmlgraph/repositories/track_repository_sqlite.py +711 -0
- htmlgraph/sdk/__init__.py +398 -0
- htmlgraph/sdk/__init__.pyi +14 -0
- htmlgraph/sdk/analytics/__init__.py +19 -0
- htmlgraph/sdk/analytics/engine.py +155 -0
- htmlgraph/sdk/analytics/helpers.py +178 -0
- htmlgraph/sdk/analytics/registry.py +109 -0
- htmlgraph/sdk/base.py +484 -0
- htmlgraph/sdk/constants.py +216 -0
- htmlgraph/sdk/core.pyi +308 -0
- htmlgraph/sdk/discovery.py +120 -0
- htmlgraph/sdk/help/__init__.py +12 -0
- htmlgraph/sdk/help/mixin.py +699 -0
- htmlgraph/sdk/mixins/__init__.py +15 -0
- htmlgraph/sdk/mixins/attribution.py +113 -0
- htmlgraph/sdk/mixins/mixin.py +410 -0
- htmlgraph/sdk/operations/__init__.py +12 -0
- htmlgraph/sdk/operations/mixin.py +427 -0
- htmlgraph/sdk/orchestration/__init__.py +17 -0
- htmlgraph/sdk/orchestration/coordinator.py +203 -0
- htmlgraph/sdk/orchestration/spawner.py +204 -0
- htmlgraph/sdk/planning/__init__.py +19 -0
- htmlgraph/sdk/planning/bottlenecks.py +93 -0
- htmlgraph/sdk/planning/mixin.py +211 -0
- htmlgraph/sdk/planning/parallel.py +186 -0
- htmlgraph/sdk/planning/queue.py +210 -0
- htmlgraph/sdk/planning/recommendations.py +87 -0
- htmlgraph/sdk/planning/smart_planning.py +319 -0
- htmlgraph/sdk/session/__init__.py +19 -0
- htmlgraph/sdk/session/continuity.py +57 -0
- htmlgraph/sdk/session/handoff.py +110 -0
- htmlgraph/sdk/session/info.py +309 -0
- htmlgraph/sdk/session/manager.py +103 -0
- htmlgraph/sdk/strategic/__init__.py +26 -0
- htmlgraph/sdk/strategic/mixin.py +563 -0
- htmlgraph/server.py +295 -107
- htmlgraph/session_hooks.py +300 -0
- htmlgraph/session_manager.py +285 -3
- htmlgraph/session_registry.py +587 -0
- htmlgraph/session_state.py +436 -0
- htmlgraph/session_warning.py +2 -1
- htmlgraph/sessions/__init__.py +23 -0
- htmlgraph/sessions/handoff.py +756 -0
- htmlgraph/system_prompts.py +450 -0
- htmlgraph/templates/orchestration-view.html +350 -0
- htmlgraph/track_builder.py +33 -1
- htmlgraph/track_manager.py +38 -0
- htmlgraph/transcript.py +18 -5
- htmlgraph/validation.py +115 -0
- htmlgraph/watch.py +2 -1
- htmlgraph/work_type_utils.py +2 -1
- {htmlgraph-0.20.1.data → htmlgraph-0.27.5.data}/data/htmlgraph/dashboard.html +2246 -248
- {htmlgraph-0.20.1.dist-info → htmlgraph-0.27.5.dist-info}/METADATA +95 -64
- htmlgraph-0.27.5.dist-info/RECORD +337 -0
- {htmlgraph-0.20.1.dist-info → htmlgraph-0.27.5.dist-info}/entry_points.txt +1 -1
- htmlgraph/cli.py +0 -4839
- htmlgraph/sdk.py +0 -2359
- htmlgraph-0.20.1.dist-info/RECORD +0 -118
- {htmlgraph-0.20.1.data → htmlgraph-0.27.5.data}/data/htmlgraph/styles.css +0 -0
- {htmlgraph-0.20.1.data → htmlgraph-0.27.5.data}/data/htmlgraph/templates/AGENTS.md.template +0 -0
- {htmlgraph-0.20.1.data → htmlgraph-0.27.5.data}/data/htmlgraph/templates/CLAUDE.md.template +0 -0
- {htmlgraph-0.20.1.data → htmlgraph-0.27.5.data}/data/htmlgraph/templates/GEMINI.md.template +0 -0
- {htmlgraph-0.20.1.dist-info → htmlgraph-0.27.5.dist-info}/WHEEL +0 -0
htmlgraph/db/queries.py
ADDED
|
@@ -0,0 +1,790 @@
|
|
|
1
|
+
"""
|
|
2
|
+
HtmlGraph Query Builders - SQLite Query Construction
|
|
3
|
+
|
|
4
|
+
Provides high-level query builders for common operations on HtmlGraph data:
|
|
5
|
+
- Event queries (agent activity, tool usage, error tracking)
|
|
6
|
+
- Feature queries (work item status, priority filtering)
|
|
7
|
+
- Session queries (agent metrics, collaboration tracking)
|
|
8
|
+
- Track queries (initiative progress, feature dependencies)
|
|
9
|
+
- Collaboration queries (handoffs, parallel work)
|
|
10
|
+
|
|
11
|
+
All builders return SQL and parameters for safe parameterized queries.
|
|
12
|
+
"""
|
|
13
|
+
|
|
14
|
+
from datetime import datetime
|
|
15
|
+
from enum import Enum
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class EventType(Enum):
|
|
19
|
+
"""Types of events that can be recorded."""
|
|
20
|
+
|
|
21
|
+
TOOL_CALL = "tool_call"
|
|
22
|
+
TOOL_RESULT = "tool_result"
|
|
23
|
+
ERROR = "error"
|
|
24
|
+
DELEGATION = "delegation"
|
|
25
|
+
COMPLETION = "completion"
|
|
26
|
+
START = "start"
|
|
27
|
+
END = "end"
|
|
28
|
+
CHECK_POINT = "check_point"
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
class FeatureType(Enum):
|
|
32
|
+
"""Types of work items."""
|
|
33
|
+
|
|
34
|
+
FEATURE = "feature"
|
|
35
|
+
BUG = "bug"
|
|
36
|
+
SPIKE = "spike"
|
|
37
|
+
CHORE = "chore"
|
|
38
|
+
EPIC = "epic"
|
|
39
|
+
TASK = "task"
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
class FeatureStatus(Enum):
|
|
43
|
+
"""Possible feature statuses."""
|
|
44
|
+
|
|
45
|
+
TODO = "todo"
|
|
46
|
+
IN_PROGRESS = "in_progress"
|
|
47
|
+
BLOCKED = "blocked"
|
|
48
|
+
DONE = "done"
|
|
49
|
+
CANCELLED = "cancelled"
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
class Priority(Enum):
|
|
53
|
+
"""Priority levels."""
|
|
54
|
+
|
|
55
|
+
LOW = "low"
|
|
56
|
+
MEDIUM = "medium"
|
|
57
|
+
HIGH = "high"
|
|
58
|
+
CRITICAL = "critical"
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
class Queries:
|
|
62
|
+
"""Query builders for HtmlGraph SQLite backend."""
|
|
63
|
+
|
|
64
|
+
# ========== AGENT EVENTS QUERIES ==========
|
|
65
|
+
|
|
66
|
+
@staticmethod
|
|
67
|
+
def get_events_by_session(session_id: str) -> tuple[str, tuple]:
|
|
68
|
+
"""
|
|
69
|
+
Get all events for a session ordered by timestamp.
|
|
70
|
+
|
|
71
|
+
Args:
|
|
72
|
+
session_id: Session ID to query
|
|
73
|
+
|
|
74
|
+
Returns:
|
|
75
|
+
Tuple of (SQL query, parameters)
|
|
76
|
+
"""
|
|
77
|
+
sql = """
|
|
78
|
+
SELECT * FROM agent_events
|
|
79
|
+
WHERE session_id = ?
|
|
80
|
+
ORDER BY timestamp ASC
|
|
81
|
+
"""
|
|
82
|
+
return sql, (session_id,)
|
|
83
|
+
|
|
84
|
+
@staticmethod
|
|
85
|
+
def get_events_by_agent(
|
|
86
|
+
agent_id: str,
|
|
87
|
+
start_time: datetime | None = None,
|
|
88
|
+
end_time: datetime | None = None,
|
|
89
|
+
) -> tuple[str, tuple]:
|
|
90
|
+
"""
|
|
91
|
+
Get all events generated by a specific agent.
|
|
92
|
+
|
|
93
|
+
Args:
|
|
94
|
+
agent_id: Agent identifier
|
|
95
|
+
start_time: Optional start time filter
|
|
96
|
+
end_time: Optional end time filter
|
|
97
|
+
|
|
98
|
+
Returns:
|
|
99
|
+
Tuple of (SQL query, parameters)
|
|
100
|
+
"""
|
|
101
|
+
sql = """
|
|
102
|
+
SELECT * FROM agent_events
|
|
103
|
+
WHERE agent_id = ?
|
|
104
|
+
"""
|
|
105
|
+
params = [agent_id]
|
|
106
|
+
|
|
107
|
+
if start_time:
|
|
108
|
+
sql += " AND timestamp >= ?"
|
|
109
|
+
params.append(start_time.isoformat())
|
|
110
|
+
|
|
111
|
+
if end_time:
|
|
112
|
+
sql += " AND timestamp <= ?"
|
|
113
|
+
params.append(end_time.isoformat())
|
|
114
|
+
|
|
115
|
+
sql += " ORDER BY timestamp DESC"
|
|
116
|
+
return sql, tuple(params)
|
|
117
|
+
|
|
118
|
+
@staticmethod
|
|
119
|
+
def get_events_by_type(
|
|
120
|
+
event_type: str,
|
|
121
|
+
session_id: str | None = None,
|
|
122
|
+
) -> tuple[str, tuple]:
|
|
123
|
+
"""
|
|
124
|
+
Get events filtered by type (tool_call, error, delegation, etc.).
|
|
125
|
+
|
|
126
|
+
Args:
|
|
127
|
+
event_type: Type of event to filter
|
|
128
|
+
session_id: Optional session filter
|
|
129
|
+
|
|
130
|
+
Returns:
|
|
131
|
+
Tuple of (SQL query, parameters)
|
|
132
|
+
"""
|
|
133
|
+
sql = "SELECT * FROM agent_events WHERE event_type = ?"
|
|
134
|
+
params = [event_type]
|
|
135
|
+
|
|
136
|
+
if session_id:
|
|
137
|
+
sql += " AND session_id = ?"
|
|
138
|
+
params.append(session_id)
|
|
139
|
+
|
|
140
|
+
sql += " ORDER BY timestamp DESC"
|
|
141
|
+
return sql, tuple(params)
|
|
142
|
+
|
|
143
|
+
@staticmethod
|
|
144
|
+
def get_tool_usage_summary(
|
|
145
|
+
session_id: str,
|
|
146
|
+
) -> tuple[str, tuple]:
|
|
147
|
+
"""
|
|
148
|
+
Get summary of tool usage in a session.
|
|
149
|
+
|
|
150
|
+
Returns tool calls grouped by tool name with counts.
|
|
151
|
+
|
|
152
|
+
Args:
|
|
153
|
+
session_id: Session to analyze
|
|
154
|
+
|
|
155
|
+
Returns:
|
|
156
|
+
Tuple of (SQL query, parameters)
|
|
157
|
+
"""
|
|
158
|
+
sql = """
|
|
159
|
+
SELECT
|
|
160
|
+
tool_name,
|
|
161
|
+
COUNT(*) as call_count,
|
|
162
|
+
SUM(cost_tokens) as total_tokens,
|
|
163
|
+
COUNT(CASE WHEN event_type = 'error' THEN 1 END) as error_count,
|
|
164
|
+
MIN(timestamp) as first_call,
|
|
165
|
+
MAX(timestamp) as last_call
|
|
166
|
+
FROM agent_events
|
|
167
|
+
WHERE session_id = ? AND tool_name IS NOT NULL
|
|
168
|
+
GROUP BY tool_name
|
|
169
|
+
ORDER BY call_count DESC
|
|
170
|
+
"""
|
|
171
|
+
return sql, (session_id,)
|
|
172
|
+
|
|
173
|
+
@staticmethod
|
|
174
|
+
def get_events_with_errors(
|
|
175
|
+
session_id: str,
|
|
176
|
+
) -> tuple[str, tuple]:
|
|
177
|
+
"""
|
|
178
|
+
Get all error events in a session with context.
|
|
179
|
+
|
|
180
|
+
Args:
|
|
181
|
+
session_id: Session to analyze
|
|
182
|
+
|
|
183
|
+
Returns:
|
|
184
|
+
Tuple of (SQL query, parameters)
|
|
185
|
+
"""
|
|
186
|
+
sql = """
|
|
187
|
+
SELECT
|
|
188
|
+
event_id,
|
|
189
|
+
agent_id,
|
|
190
|
+
timestamp,
|
|
191
|
+
tool_name,
|
|
192
|
+
output_summary as error_message,
|
|
193
|
+
context
|
|
194
|
+
FROM agent_events
|
|
195
|
+
WHERE session_id = ? AND event_type = 'error'
|
|
196
|
+
ORDER BY timestamp ASC
|
|
197
|
+
"""
|
|
198
|
+
return sql, (session_id,)
|
|
199
|
+
|
|
200
|
+
@staticmethod
|
|
201
|
+
def get_delegation_chain(
|
|
202
|
+
session_id: str,
|
|
203
|
+
) -> tuple[str, tuple]:
|
|
204
|
+
"""
|
|
205
|
+
Get the chain of delegations in a session.
|
|
206
|
+
|
|
207
|
+
Shows parent-child relationships between delegated events.
|
|
208
|
+
|
|
209
|
+
Args:
|
|
210
|
+
session_id: Session to analyze
|
|
211
|
+
|
|
212
|
+
Returns:
|
|
213
|
+
Tuple of (SQL query, parameters)
|
|
214
|
+
"""
|
|
215
|
+
sql = """
|
|
216
|
+
SELECT
|
|
217
|
+
event_id,
|
|
218
|
+
parent_event_id,
|
|
219
|
+
agent_id,
|
|
220
|
+
parent_agent_id,
|
|
221
|
+
event_type,
|
|
222
|
+
timestamp,
|
|
223
|
+
tool_name
|
|
224
|
+
FROM agent_events
|
|
225
|
+
WHERE session_id = ? AND (parent_agent_id IS NOT NULL OR event_type = 'delegation')
|
|
226
|
+
ORDER BY timestamp ASC
|
|
227
|
+
"""
|
|
228
|
+
return sql, (session_id,)
|
|
229
|
+
|
|
230
|
+
# ========== FEATURES QUERIES ==========
|
|
231
|
+
|
|
232
|
+
@staticmethod
|
|
233
|
+
def get_features_by_status(
|
|
234
|
+
status: str,
|
|
235
|
+
limit: int | None = None,
|
|
236
|
+
) -> tuple[str, tuple]:
|
|
237
|
+
"""
|
|
238
|
+
Get features filtered by status.
|
|
239
|
+
|
|
240
|
+
Args:
|
|
241
|
+
status: Status to filter by (todo, in_progress, done, etc.)
|
|
242
|
+
limit: Optional limit on results
|
|
243
|
+
|
|
244
|
+
Returns:
|
|
245
|
+
Tuple of (SQL query, parameters)
|
|
246
|
+
"""
|
|
247
|
+
sql = """
|
|
248
|
+
SELECT * FROM features
|
|
249
|
+
WHERE status = ?
|
|
250
|
+
ORDER BY priority DESC, created_at DESC
|
|
251
|
+
"""
|
|
252
|
+
params: list[str | int] = [status]
|
|
253
|
+
|
|
254
|
+
if limit:
|
|
255
|
+
sql += " LIMIT ?"
|
|
256
|
+
params.append(limit)
|
|
257
|
+
|
|
258
|
+
return sql, tuple(params)
|
|
259
|
+
|
|
260
|
+
@staticmethod
|
|
261
|
+
def get_features_by_track(
|
|
262
|
+
track_id: str,
|
|
263
|
+
) -> tuple[str, tuple]:
|
|
264
|
+
"""
|
|
265
|
+
Get all features linked to a track.
|
|
266
|
+
|
|
267
|
+
Args:
|
|
268
|
+
track_id: Track ID
|
|
269
|
+
|
|
270
|
+
Returns:
|
|
271
|
+
Tuple of (SQL query, parameters)
|
|
272
|
+
"""
|
|
273
|
+
sql = """
|
|
274
|
+
SELECT * FROM features
|
|
275
|
+
WHERE track_id = ?
|
|
276
|
+
ORDER BY priority DESC, created_at ASC
|
|
277
|
+
"""
|
|
278
|
+
return sql, (track_id,)
|
|
279
|
+
|
|
280
|
+
@staticmethod
|
|
281
|
+
def get_features_assigned_to(
|
|
282
|
+
agent_id: str,
|
|
283
|
+
) -> tuple[str, tuple]:
|
|
284
|
+
"""
|
|
285
|
+
Get all features assigned to an agent.
|
|
286
|
+
|
|
287
|
+
Args:
|
|
288
|
+
agent_id: Agent identifier
|
|
289
|
+
|
|
290
|
+
Returns:
|
|
291
|
+
Tuple of (SQL query, parameters)
|
|
292
|
+
"""
|
|
293
|
+
sql = """
|
|
294
|
+
SELECT * FROM features
|
|
295
|
+
WHERE assigned_to = ?
|
|
296
|
+
ORDER BY priority DESC, created_at DESC
|
|
297
|
+
"""
|
|
298
|
+
return sql, (agent_id,)
|
|
299
|
+
|
|
300
|
+
@staticmethod
|
|
301
|
+
def get_feature_progress(
|
|
302
|
+
feature_id: str,
|
|
303
|
+
) -> tuple[str, tuple]:
|
|
304
|
+
"""
|
|
305
|
+
Get progress info for a feature (steps completed, estimated vs actual time).
|
|
306
|
+
|
|
307
|
+
Args:
|
|
308
|
+
feature_id: Feature ID
|
|
309
|
+
|
|
310
|
+
Returns:
|
|
311
|
+
Tuple of (SQL query, parameters)
|
|
312
|
+
"""
|
|
313
|
+
sql = """
|
|
314
|
+
SELECT
|
|
315
|
+
id,
|
|
316
|
+
title,
|
|
317
|
+
type,
|
|
318
|
+
status,
|
|
319
|
+
steps_total,
|
|
320
|
+
steps_completed,
|
|
321
|
+
CASE WHEN steps_total > 0 THEN (steps_completed * 100.0 / steps_total) ELSE 0 END as progress_percent,
|
|
322
|
+
created_at,
|
|
323
|
+
completed_at,
|
|
324
|
+
CASE WHEN completed_at IS NOT NULL
|
|
325
|
+
THEN CAST((julianday(completed_at) - julianday(created_at)) * 24 AS INT)
|
|
326
|
+
ELSE NULL
|
|
327
|
+
END as hours_elapsed
|
|
328
|
+
FROM features
|
|
329
|
+
WHERE id = ?
|
|
330
|
+
"""
|
|
331
|
+
return sql, (feature_id,)
|
|
332
|
+
|
|
333
|
+
@staticmethod
|
|
334
|
+
def get_high_priority_features(
|
|
335
|
+
limit: int = 10,
|
|
336
|
+
) -> tuple[str, tuple]:
|
|
337
|
+
"""
|
|
338
|
+
Get all high/critical priority features not yet done.
|
|
339
|
+
|
|
340
|
+
Args:
|
|
341
|
+
limit: Maximum results to return
|
|
342
|
+
|
|
343
|
+
Returns:
|
|
344
|
+
Tuple of (SQL query, parameters)
|
|
345
|
+
"""
|
|
346
|
+
sql = """
|
|
347
|
+
SELECT * FROM features
|
|
348
|
+
WHERE priority IN ('high', 'critical')
|
|
349
|
+
AND status != 'done'
|
|
350
|
+
ORDER BY priority DESC, created_at ASC
|
|
351
|
+
LIMIT ?
|
|
352
|
+
"""
|
|
353
|
+
return sql, (limit,)
|
|
354
|
+
|
|
355
|
+
@staticmethod
|
|
356
|
+
def get_blocked_features() -> tuple[str, tuple]:
|
|
357
|
+
"""
|
|
358
|
+
Get all currently blocked features.
|
|
359
|
+
|
|
360
|
+
Returns:
|
|
361
|
+
Tuple of (SQL query, parameters)
|
|
362
|
+
"""
|
|
363
|
+
sql = """
|
|
364
|
+
SELECT id, title, type, assigned_to, created_at
|
|
365
|
+
FROM features
|
|
366
|
+
WHERE status = 'blocked'
|
|
367
|
+
ORDER BY created_at ASC
|
|
368
|
+
"""
|
|
369
|
+
return sql, ()
|
|
370
|
+
|
|
371
|
+
@staticmethod
|
|
372
|
+
def get_feature_dependency_tree(
|
|
373
|
+
feature_id: str,
|
|
374
|
+
) -> tuple[str, tuple]:
|
|
375
|
+
"""
|
|
376
|
+
Get feature dependency tree (parent-child relationships).
|
|
377
|
+
|
|
378
|
+
Args:
|
|
379
|
+
feature_id: Root feature ID
|
|
380
|
+
|
|
381
|
+
Returns:
|
|
382
|
+
Tuple of (SQL query, parameters)
|
|
383
|
+
"""
|
|
384
|
+
sql = """
|
|
385
|
+
WITH RECURSIVE feature_tree AS (
|
|
386
|
+
-- Base case: start with the requested feature
|
|
387
|
+
SELECT id, title, parent_feature_id, type, status, 0 as depth
|
|
388
|
+
FROM features
|
|
389
|
+
WHERE id = ?
|
|
390
|
+
|
|
391
|
+
UNION ALL
|
|
392
|
+
|
|
393
|
+
-- Recursive case: get all child features
|
|
394
|
+
SELECT f.id, f.title, f.parent_feature_id, f.type, f.status, ft.depth + 1
|
|
395
|
+
FROM features f
|
|
396
|
+
INNER JOIN feature_tree ft ON f.parent_feature_id = ft.id
|
|
397
|
+
WHERE ft.depth < 10 -- Prevent infinite loops
|
|
398
|
+
)
|
|
399
|
+
SELECT * FROM feature_tree
|
|
400
|
+
ORDER BY depth ASC, id
|
|
401
|
+
"""
|
|
402
|
+
return sql, (feature_id,)
|
|
403
|
+
|
|
404
|
+
# ========== SESSIONS QUERIES ==========
|
|
405
|
+
|
|
406
|
+
@staticmethod
|
|
407
|
+
def get_session_metrics(
|
|
408
|
+
session_id: str,
|
|
409
|
+
) -> tuple[str, tuple]:
|
|
410
|
+
"""
|
|
411
|
+
Get comprehensive metrics for a session.
|
|
412
|
+
|
|
413
|
+
Includes event count, token usage, features worked on, etc.
|
|
414
|
+
|
|
415
|
+
Args:
|
|
416
|
+
session_id: Session ID
|
|
417
|
+
|
|
418
|
+
Returns:
|
|
419
|
+
Tuple of (SQL query, parameters)
|
|
420
|
+
"""
|
|
421
|
+
sql = """
|
|
422
|
+
SELECT
|
|
423
|
+
s.session_id,
|
|
424
|
+
s.agent_assigned,
|
|
425
|
+
s.created_at,
|
|
426
|
+
s.completed_at,
|
|
427
|
+
CASE WHEN s.completed_at IS NOT NULL
|
|
428
|
+
THEN CAST((julianday(s.completed_at) - julianday(s.created_at)) * 24 * 60 AS INT)
|
|
429
|
+
ELSE CAST((julianday(CURRENT_TIMESTAMP) - julianday(s.created_at)) * 24 * 60 AS INT)
|
|
430
|
+
END as duration_minutes,
|
|
431
|
+
COUNT(DISTINCT e.event_id) as total_events,
|
|
432
|
+
COUNT(DISTINCT CASE WHEN e.event_type = 'error' THEN e.event_id END) as error_count,
|
|
433
|
+
COUNT(DISTINCT CASE WHEN e.event_type = 'delegation' THEN e.event_id END) as delegation_count,
|
|
434
|
+
SUM(e.cost_tokens) as total_tokens,
|
|
435
|
+
s.status,
|
|
436
|
+
s.is_subagent
|
|
437
|
+
FROM sessions s
|
|
438
|
+
LEFT JOIN agent_events e ON s.session_id = e.session_id
|
|
439
|
+
WHERE s.session_id = ?
|
|
440
|
+
GROUP BY s.session_id
|
|
441
|
+
"""
|
|
442
|
+
return sql, (session_id,)
|
|
443
|
+
|
|
444
|
+
@staticmethod
|
|
445
|
+
def get_agent_sessions(
|
|
446
|
+
agent_id: str,
|
|
447
|
+
limit: int = 10,
|
|
448
|
+
) -> tuple[str, tuple]:
|
|
449
|
+
"""
|
|
450
|
+
Get all sessions for an agent (most recent first).
|
|
451
|
+
|
|
452
|
+
Args:
|
|
453
|
+
agent_id: Agent identifier
|
|
454
|
+
limit: Maximum sessions to return
|
|
455
|
+
|
|
456
|
+
Returns:
|
|
457
|
+
Tuple of (SQL query, parameters)
|
|
458
|
+
"""
|
|
459
|
+
sql = """
|
|
460
|
+
SELECT
|
|
461
|
+
session_id,
|
|
462
|
+
agent_assigned,
|
|
463
|
+
created_at,
|
|
464
|
+
completed_at,
|
|
465
|
+
total_events,
|
|
466
|
+
total_tokens_used,
|
|
467
|
+
status,
|
|
468
|
+
is_subagent
|
|
469
|
+
FROM sessions
|
|
470
|
+
WHERE agent_assigned = ?
|
|
471
|
+
ORDER BY created_at DESC
|
|
472
|
+
LIMIT ?
|
|
473
|
+
"""
|
|
474
|
+
return sql, (agent_id, limit)
|
|
475
|
+
|
|
476
|
+
@staticmethod
|
|
477
|
+
def get_active_sessions() -> tuple[str, tuple]:
|
|
478
|
+
"""
|
|
479
|
+
Get all currently active sessions.
|
|
480
|
+
|
|
481
|
+
Returns:
|
|
482
|
+
Tuple of (SQL query, parameters)
|
|
483
|
+
"""
|
|
484
|
+
sql = """
|
|
485
|
+
SELECT
|
|
486
|
+
session_id,
|
|
487
|
+
agent_assigned,
|
|
488
|
+
created_at,
|
|
489
|
+
total_events,
|
|
490
|
+
total_tokens_used,
|
|
491
|
+
status
|
|
492
|
+
FROM sessions
|
|
493
|
+
WHERE status = 'active'
|
|
494
|
+
ORDER BY created_at DESC
|
|
495
|
+
"""
|
|
496
|
+
return sql, ()
|
|
497
|
+
|
|
498
|
+
@staticmethod
|
|
499
|
+
def get_subagent_sessions(
|
|
500
|
+
parent_session_id: str,
|
|
501
|
+
) -> tuple[str, tuple]:
|
|
502
|
+
"""
|
|
503
|
+
Get all subagent sessions spawned from a parent session.
|
|
504
|
+
|
|
505
|
+
Args:
|
|
506
|
+
parent_session_id: Parent session ID
|
|
507
|
+
|
|
508
|
+
Returns:
|
|
509
|
+
Tuple of (SQL query, parameters)
|
|
510
|
+
"""
|
|
511
|
+
sql = """
|
|
512
|
+
SELECT
|
|
513
|
+
session_id,
|
|
514
|
+
agent_assigned,
|
|
515
|
+
created_at,
|
|
516
|
+
completed_at,
|
|
517
|
+
total_events,
|
|
518
|
+
total_tokens_used,
|
|
519
|
+
status
|
|
520
|
+
FROM sessions
|
|
521
|
+
WHERE parent_session_id = ?
|
|
522
|
+
ORDER BY created_at ASC
|
|
523
|
+
"""
|
|
524
|
+
return sql, (parent_session_id,)
|
|
525
|
+
|
|
526
|
+
@staticmethod
|
|
527
|
+
def get_context_drift(
|
|
528
|
+
session_id: str,
|
|
529
|
+
) -> tuple[str, tuple]:
|
|
530
|
+
"""
|
|
531
|
+
Get context drift metric for a session.
|
|
532
|
+
|
|
533
|
+
Higher drift indicates context loss across session.
|
|
534
|
+
|
|
535
|
+
Args:
|
|
536
|
+
session_id: Session ID
|
|
537
|
+
|
|
538
|
+
Returns:
|
|
539
|
+
Tuple of (SQL query, parameters)
|
|
540
|
+
"""
|
|
541
|
+
sql = """
|
|
542
|
+
SELECT
|
|
543
|
+
session_id,
|
|
544
|
+
context_drift,
|
|
545
|
+
total_events,
|
|
546
|
+
CASE WHEN total_events > 0 THEN (context_drift / total_events) ELSE 0 END as drift_per_event
|
|
547
|
+
FROM sessions
|
|
548
|
+
WHERE session_id = ?
|
|
549
|
+
"""
|
|
550
|
+
return sql, (session_id,)
|
|
551
|
+
|
|
552
|
+
# ========== TRACKS QUERIES ==========
|
|
553
|
+
|
|
554
|
+
@staticmethod
|
|
555
|
+
def get_track_status(
|
|
556
|
+
track_id: str,
|
|
557
|
+
) -> tuple[str, tuple]:
|
|
558
|
+
"""
|
|
559
|
+
Get comprehensive status of a track and its features.
|
|
560
|
+
|
|
561
|
+
Args:
|
|
562
|
+
track_id: Track ID
|
|
563
|
+
|
|
564
|
+
Returns:
|
|
565
|
+
Tuple of (SQL query, parameters)
|
|
566
|
+
"""
|
|
567
|
+
sql = """
|
|
568
|
+
SELECT
|
|
569
|
+
t.track_id,
|
|
570
|
+
t.title,
|
|
571
|
+
t.status,
|
|
572
|
+
t.priority,
|
|
573
|
+
t.created_at,
|
|
574
|
+
t.completed_at,
|
|
575
|
+
COUNT(DISTINCT f.id) as total_features,
|
|
576
|
+
COUNT(DISTINCT CASE WHEN f.status = 'done' THEN f.id END) as completed_features,
|
|
577
|
+
COUNT(DISTINCT CASE WHEN f.status = 'in_progress' THEN f.id END) as in_progress_features,
|
|
578
|
+
COUNT(DISTINCT CASE WHEN f.status = 'blocked' THEN f.id END) as blocked_features,
|
|
579
|
+
CASE WHEN COUNT(f.id) > 0
|
|
580
|
+
THEN CAST(COUNT(CASE WHEN f.status = 'done' THEN f.id END) * 100.0 / COUNT(f.id) AS INT)
|
|
581
|
+
ELSE 0
|
|
582
|
+
END as completion_percent
|
|
583
|
+
FROM tracks t
|
|
584
|
+
LEFT JOIN features f ON t.track_id = f.track_id
|
|
585
|
+
WHERE t.track_id = ?
|
|
586
|
+
GROUP BY t.track_id
|
|
587
|
+
"""
|
|
588
|
+
return sql, (track_id,)
|
|
589
|
+
|
|
590
|
+
@staticmethod
|
|
591
|
+
def get_active_tracks(
|
|
592
|
+
limit: int = 10,
|
|
593
|
+
) -> tuple[str, tuple]:
|
|
594
|
+
"""
|
|
595
|
+
Get all active (in-progress) tracks.
|
|
596
|
+
|
|
597
|
+
Args:
|
|
598
|
+
limit: Maximum tracks to return
|
|
599
|
+
|
|
600
|
+
Returns:
|
|
601
|
+
Tuple of (SQL query, parameters)
|
|
602
|
+
"""
|
|
603
|
+
sql = """
|
|
604
|
+
SELECT
|
|
605
|
+
t.track_id,
|
|
606
|
+
t.title,
|
|
607
|
+
t.priority,
|
|
608
|
+
COUNT(f.id) as feature_count,
|
|
609
|
+
COUNT(CASE WHEN f.status = 'done' THEN f.id END) as completed_count
|
|
610
|
+
FROM tracks t
|
|
611
|
+
LEFT JOIN features f ON t.track_id = f.track_id
|
|
612
|
+
WHERE t.status = 'in_progress'
|
|
613
|
+
GROUP BY t.track_id
|
|
614
|
+
ORDER BY t.priority DESC, t.created_at DESC
|
|
615
|
+
LIMIT ?
|
|
616
|
+
"""
|
|
617
|
+
return sql, (limit,)
|
|
618
|
+
|
|
619
|
+
# ========== COLLABORATION QUERIES ==========
|
|
620
|
+
|
|
621
|
+
@staticmethod
|
|
622
|
+
def get_handoffs(
|
|
623
|
+
session_id: str,
|
|
624
|
+
) -> tuple[str, tuple]:
|
|
625
|
+
"""
|
|
626
|
+
Get all handoffs (delegations) in a session.
|
|
627
|
+
|
|
628
|
+
Args:
|
|
629
|
+
session_id: Session ID
|
|
630
|
+
|
|
631
|
+
Returns:
|
|
632
|
+
Tuple of (SQL query, parameters)
|
|
633
|
+
"""
|
|
634
|
+
sql = """
|
|
635
|
+
SELECT
|
|
636
|
+
handoff_id,
|
|
637
|
+
from_agent,
|
|
638
|
+
to_agent,
|
|
639
|
+
timestamp,
|
|
640
|
+
feature_id,
|
|
641
|
+
handoff_type,
|
|
642
|
+
status,
|
|
643
|
+
reason
|
|
644
|
+
FROM agent_collaboration
|
|
645
|
+
WHERE session_id = ?
|
|
646
|
+
ORDER BY timestamp ASC
|
|
647
|
+
"""
|
|
648
|
+
return sql, (session_id,)
|
|
649
|
+
|
|
650
|
+
@staticmethod
|
|
651
|
+
def get_agent_collaboration_summary() -> tuple[str, tuple]:
|
|
652
|
+
"""
|
|
653
|
+
Get summary of agent collaboration patterns.
|
|
654
|
+
|
|
655
|
+
Shows which agents delegate to whom most frequently.
|
|
656
|
+
|
|
657
|
+
Returns:
|
|
658
|
+
Tuple of (SQL query, parameters)
|
|
659
|
+
"""
|
|
660
|
+
sql = """
|
|
661
|
+
SELECT
|
|
662
|
+
from_agent,
|
|
663
|
+
to_agent,
|
|
664
|
+
COUNT(*) as handoff_count,
|
|
665
|
+
COUNT(CASE WHEN status = 'completed' THEN 1 END) as successful_handoffs,
|
|
666
|
+
COUNT(CASE WHEN status = 'failed' THEN 1 END) as failed_handoffs,
|
|
667
|
+
COUNT(DISTINCT feature_id) as unique_features
|
|
668
|
+
FROM agent_collaboration
|
|
669
|
+
GROUP BY from_agent, to_agent
|
|
670
|
+
ORDER BY handoff_count DESC
|
|
671
|
+
"""
|
|
672
|
+
return sql, ()
|
|
673
|
+
|
|
674
|
+
@staticmethod
|
|
675
|
+
def get_parallel_work(
|
|
676
|
+
session_id: str,
|
|
677
|
+
) -> tuple[str, tuple]:
|
|
678
|
+
"""
|
|
679
|
+
Get instances of parallel work in a session.
|
|
680
|
+
|
|
681
|
+
Returns:
|
|
682
|
+
Tuple of (SQL query, parameters)
|
|
683
|
+
"""
|
|
684
|
+
sql = """
|
|
685
|
+
SELECT
|
|
686
|
+
handoff_id,
|
|
687
|
+
from_agent,
|
|
688
|
+
to_agent,
|
|
689
|
+
feature_id,
|
|
690
|
+
timestamp,
|
|
691
|
+
status
|
|
692
|
+
FROM agent_collaboration
|
|
693
|
+
WHERE session_id = ? AND handoff_type = 'parallel'
|
|
694
|
+
ORDER BY timestamp ASC
|
|
695
|
+
"""
|
|
696
|
+
return sql, (session_id,)
|
|
697
|
+
|
|
698
|
+
# ========== ANALYTICAL QUERIES ==========
|
|
699
|
+
|
|
700
|
+
@staticmethod
|
|
701
|
+
def get_system_statistics() -> tuple[str, tuple]:
|
|
702
|
+
"""
|
|
703
|
+
Get system-wide statistics across all data.
|
|
704
|
+
|
|
705
|
+
Returns:
|
|
706
|
+
Tuple of (SQL query, parameters)
|
|
707
|
+
"""
|
|
708
|
+
sql = """
|
|
709
|
+
SELECT
|
|
710
|
+
(SELECT COUNT(*) FROM agent_events) as total_events,
|
|
711
|
+
(SELECT COUNT(*) FROM features) as total_features,
|
|
712
|
+
(SELECT COUNT(*) FROM sessions) as total_sessions,
|
|
713
|
+
(SELECT COUNT(*) FROM tracks) as total_tracks,
|
|
714
|
+
(SELECT COUNT(DISTINCT agent_id) FROM agent_events) as unique_agents,
|
|
715
|
+
(SELECT SUM(cost_tokens) FROM agent_events) as total_tokens,
|
|
716
|
+
(SELECT COUNT(*) FROM features WHERE status = 'done') as completed_features,
|
|
717
|
+
(SELECT COUNT(*) FROM features WHERE status = 'blocked') as blocked_features,
|
|
718
|
+
(SELECT COUNT(*) FROM agent_collaboration) as total_handoffs
|
|
719
|
+
"""
|
|
720
|
+
return sql, ()
|
|
721
|
+
|
|
722
|
+
@staticmethod
|
|
723
|
+
def get_agent_performance_metrics() -> tuple[str, tuple]:
|
|
724
|
+
"""
|
|
725
|
+
Get performance metrics per agent.
|
|
726
|
+
|
|
727
|
+
Includes event counts, token usage, error rates, etc.
|
|
728
|
+
|
|
729
|
+
Returns:
|
|
730
|
+
Tuple of (SQL query, parameters)
|
|
731
|
+
"""
|
|
732
|
+
sql = """
|
|
733
|
+
SELECT
|
|
734
|
+
e.agent_id,
|
|
735
|
+
COUNT(*) as total_events,
|
|
736
|
+
COUNT(DISTINCT e.session_id) as total_sessions,
|
|
737
|
+
COUNT(DISTINCT CASE WHEN e.event_type = 'error' THEN e.event_id END) as error_count,
|
|
738
|
+
CAST(
|
|
739
|
+
COUNT(DISTINCT CASE WHEN e.event_type = 'error' THEN e.event_id END) * 100.0
|
|
740
|
+
/ COUNT(*) AS DECIMAL(5, 2)
|
|
741
|
+
) as error_rate,
|
|
742
|
+
SUM(e.cost_tokens) as total_tokens,
|
|
743
|
+
ROUND(AVG(e.cost_tokens), 2) as avg_tokens_per_event,
|
|
744
|
+
COUNT(DISTINCT CASE WHEN e.tool_name IS NOT NULL THEN e.tool_name END) as unique_tools_used
|
|
745
|
+
FROM agent_events e
|
|
746
|
+
GROUP BY e.agent_id
|
|
747
|
+
ORDER BY total_events DESC
|
|
748
|
+
"""
|
|
749
|
+
return sql, ()
|
|
750
|
+
|
|
751
|
+
@staticmethod
|
|
752
|
+
def get_events_timeline(
|
|
753
|
+
start_date: datetime,
|
|
754
|
+
end_date: datetime,
|
|
755
|
+
bucket_minutes: int = 60,
|
|
756
|
+
) -> tuple[str, tuple]:
|
|
757
|
+
"""
|
|
758
|
+
Get timeline of events grouped by time bucket.
|
|
759
|
+
|
|
760
|
+
Useful for visualizing activity over time.
|
|
761
|
+
|
|
762
|
+
Args:
|
|
763
|
+
start_date: Start of time range
|
|
764
|
+
end_date: End of time range
|
|
765
|
+
bucket_minutes: Group events into buckets of this size
|
|
766
|
+
|
|
767
|
+
Returns:
|
|
768
|
+
Tuple of (SQL query, parameters)
|
|
769
|
+
"""
|
|
770
|
+
sql = f"""
|
|
771
|
+
SELECT
|
|
772
|
+
strftime('%Y-%m-%d %H:%M', datetime(
|
|
773
|
+
(julianday(timestamp) - julianday(?)) * 24 * 60 / {bucket_minutes}
|
|
774
|
+
* {bucket_minutes} / 24 / 60 + julianday(?)
|
|
775
|
+
)) as time_bucket,
|
|
776
|
+
COUNT(*) as event_count,
|
|
777
|
+
COUNT(DISTINCT agent_id) as unique_agents,
|
|
778
|
+
COUNT(DISTINCT session_id) as unique_sessions,
|
|
779
|
+
SUM(cost_tokens) as total_tokens
|
|
780
|
+
FROM agent_events
|
|
781
|
+
WHERE timestamp BETWEEN ? AND ?
|
|
782
|
+
GROUP BY time_bucket
|
|
783
|
+
ORDER BY time_bucket ASC
|
|
784
|
+
"""
|
|
785
|
+
return sql, (
|
|
786
|
+
start_date.isoformat(),
|
|
787
|
+
start_date.isoformat(),
|
|
788
|
+
start_date.isoformat(),
|
|
789
|
+
end_date.isoformat(),
|
|
790
|
+
)
|