65 lines
2.3 KiB
Go
65 lines
2.3 KiB
Go
package controllers
|
|
|
|
import (
|
|
"time"
|
|
|
|
"doormile/db"
|
|
"doormile/internal/ai/telemetry"
|
|
"doormile/models"
|
|
"doormile/utils"
|
|
|
|
"github.com/gofiber/fiber/v2"
|
|
)
|
|
|
|
// GetAIInsights — GET /admin/ai/insights?days=7
|
|
//
|
|
// What AI_engine's agents did over the window: runs and failures per agent
|
|
// (aiagentruns, from telemetry.task), decisions by type and outcome
|
|
// (agent_decisions), and each agent's latest heartbeat (Redis). `receiving`
|
|
// says whether this backend is subscribed to the telemetry at all, so an
|
|
// empty page can tell "not connected" from "nothing happened".
|
|
func GetAIInsights(c *fiber.Ctx) error {
|
|
days := telemetry.ClampDays(c.QueryInt("days", 7))
|
|
// A real instant: aiagentruns.receivedat and agent_decisions.created_at are
|
|
// both timestamptz (see telemetry.NewRecorder on why not utils.DBNow).
|
|
since := time.Now().AddDate(0, 0, -days)
|
|
|
|
runs, err := telemetry.RunStats(db.DB, since)
|
|
if err != nil {
|
|
utils.Error("ai insights: runs", "error", err.Error())
|
|
return utils.Internal(c, "failed to read agent runs")
|
|
}
|
|
decisions, err := telemetry.DecisionCounts(db.DB, since)
|
|
if err != nil {
|
|
utils.Error("ai insights: decisions", "error", err.Error())
|
|
return utils.Internal(c, "failed to read agent decisions")
|
|
}
|
|
|
|
var engineAgents []string
|
|
if err := db.DB.Model(&models.AIAgent{}).Where("runtime = ?", "engine").Order("sortorder").Pluck("agentid", &engineAgents).Error; err != nil {
|
|
utils.Error("ai insights: agents", "error", err.Error())
|
|
}
|
|
|
|
return utils.OK(c, telemetry.Insights{
|
|
Days: days,
|
|
Since: since,
|
|
Receiving: telemetry.Receiving.Load(),
|
|
Runs: telemetry.SummariseRuns(runs),
|
|
Decisions: telemetry.SummariseDecisions(decisions),
|
|
Live: telemetry.LiveStates(db.Rdb, engineAgents),
|
|
})
|
|
}
|
|
|
|
// GetAIDecisions — GET /admin/ai/decisions?type=&before=&limit=
|
|
//
|
|
// Recent agent decisions, newest first, keyset-paged by id. Reasoning is
|
|
// trimmed and the context column is left out (it can hold rider data).
|
|
func GetAIDecisions(c *fiber.Ctx) error {
|
|
rows, err := telemetry.RecentDecisions(db.DB, c.Query("type"), uint64(c.QueryInt("before", 0)), c.QueryInt("limit", 25))
|
|
if err != nil {
|
|
utils.Error("ai insights: recent decisions", "error", err.Error())
|
|
return utils.Internal(c, "failed to read agent decisions")
|
|
}
|
|
return utils.List(c, rows, int64(len(rows)))
|
|
}
|