672f2b1f26
* feat(stats): add avg turn duration and messages per turn to averages card Adds two new metrics to the workspace stats Averages card: mean turn duration and mean message count per turn. Both exclude outliers — turns shorter than 1s (no-op/aborted), longer than 1h (zombie turns where completed_at was backfilled across an agent restart), and turns with no messages — so the displayed means reflect typical work rather than tail skew. On a ~4k-turn sample the filter drops avg duration from ~1062s to ~289s. * fix(stats): exclude exact 1h turns and use Tooltip for averages help text Address PR feedback: the BETWEEN bound was inclusive so turns exactly at the 1h ceiling were retained, contradicting the documented half-open range. Also swap the title attribute on the new Averages rows for the shared Tooltip component so the help text is reachable via keyboard and screen readers. * fix(stats): align turn-row zero state with em-dash convention Address PR feedback: avg_messages_per_turn rendered "0.0" while avg_turn_duration_ms rendered "—" under the same empty-data condition. Also corrects the GetGlobalStats docstring to acknowledge that clean_turn_agg adds one correlated per-turn lookup on top of the four single-scan CTEs. * test(stats): cover exact 1h turn boundary in clean-turn exclusion test Add a turn of exactly 3,600,000ms (cleanTurnMaxDurationMs) to TestGetGlobalStats_CleanTurnExcludesOutliers so the exclusive upper bound is exercised directly, not just via the 2h zombie turn that sits well above the boundary. --------- Co-authored-by: Kandev Agent <agent@kandev.dev>
92 lines
3.7 KiB
Go
92 lines
3.7 KiB
Go
package models
|
|
|
|
import "time"
|
|
|
|
// TaskStats represents aggregated statistics for a single task
|
|
type TaskStats struct {
|
|
TaskID string `json:"task_id"`
|
|
TaskTitle string `json:"task_title"`
|
|
WorkspaceID string `json:"workspace_id"`
|
|
WorkflowID string `json:"workflow_id"`
|
|
State string `json:"state"`
|
|
SessionCount int `json:"session_count"`
|
|
TurnCount int `json:"turn_count"`
|
|
MessageCount int `json:"message_count"`
|
|
UserMessageCount int `json:"user_message_count"`
|
|
ToolCallCount int `json:"tool_call_count"`
|
|
TotalDurationMs int64 `json:"total_duration_ms"`
|
|
ActiveDurationMs int64 `json:"active_duration_ms"`
|
|
ElapsedSpanMs int64 `json:"elapsed_span_ms"`
|
|
CreatedAt time.Time `json:"created_at"`
|
|
CompletedAt *time.Time `json:"completed_at,omitempty"`
|
|
}
|
|
|
|
// GlobalStats represents workspace-wide aggregated statistics
|
|
type GlobalStats struct {
|
|
TotalTasks int `json:"total_tasks"`
|
|
CompletedTasks int `json:"completed_tasks"`
|
|
InProgressTasks int `json:"in_progress_tasks"`
|
|
TotalSessions int `json:"total_sessions"`
|
|
TotalTurns int `json:"total_turns"`
|
|
TotalMessages int `json:"total_messages"`
|
|
TotalUserMessages int `json:"total_user_messages"`
|
|
TotalToolCalls int `json:"total_tool_calls"`
|
|
TotalDurationMs int64 `json:"total_duration_ms"`
|
|
AvgTurnsPerTask float64 `json:"avg_turns_per_task"`
|
|
AvgMessagesPerTask float64 `json:"avg_messages_per_task"`
|
|
AvgDurationMsPerTask int64 `json:"avg_duration_ms_per_task"`
|
|
AvgTurnDurationMs int64 `json:"avg_turn_duration_ms"`
|
|
AvgMessagesPerTurn float64 `json:"avg_messages_per_turn"`
|
|
}
|
|
|
|
// DailyActivity represents activity statistics for a single day
|
|
type DailyActivity struct {
|
|
Date string `json:"date"` // YYYY-MM-DD format
|
|
TurnCount int `json:"turn_count"`
|
|
MessageCount int `json:"message_count"`
|
|
TaskCount int `json:"task_count"`
|
|
}
|
|
|
|
// CompletedTaskActivity represents completed task counts for a day
|
|
type CompletedTaskActivity struct {
|
|
Date string `json:"date"` // YYYY-MM-DD format
|
|
CompletedTasks int `json:"completed_tasks"`
|
|
}
|
|
|
|
// AgentUsage represents usage statistics for a single agent profile
|
|
type AgentUsage struct {
|
|
AgentProfileID string `json:"agent_profile_id"`
|
|
AgentProfileName string `json:"agent_profile_name"`
|
|
AgentModel string `json:"agent_model"`
|
|
SessionCount int `json:"session_count"`
|
|
TurnCount int `json:"turn_count"`
|
|
TotalDurationMs int64 `json:"total_duration_ms"`
|
|
}
|
|
|
|
// RepositoryStats represents aggregated statistics for a repository in a workspace
|
|
type RepositoryStats struct {
|
|
RepositoryID string `json:"repository_id"`
|
|
RepositoryName string `json:"repository_name"`
|
|
TotalTasks int `json:"total_tasks"`
|
|
CompletedTasks int `json:"completed_tasks"`
|
|
InProgressTasks int `json:"in_progress_tasks"`
|
|
SessionCount int `json:"session_count"`
|
|
TurnCount int `json:"turn_count"`
|
|
MessageCount int `json:"message_count"`
|
|
UserMessageCount int `json:"user_message_count"`
|
|
ToolCallCount int `json:"tool_call_count"`
|
|
TotalDurationMs int64 `json:"total_duration_ms"`
|
|
TotalCommits int `json:"total_commits"`
|
|
TotalFilesChanged int `json:"total_files_changed"`
|
|
TotalInsertions int `json:"total_insertions"`
|
|
TotalDeletions int `json:"total_deletions"`
|
|
}
|
|
|
|
// GitStats represents aggregated git statistics for a workspace
|
|
type GitStats struct {
|
|
TotalCommits int `json:"total_commits"`
|
|
TotalFilesChanged int `json:"total_files_changed"`
|
|
TotalInsertions int `json:"total_insertions"`
|
|
TotalDeletions int `json:"total_deletions"`
|
|
}
|