perf(database): replace listSnapshot+JS filter with scoped SQL in getCompanyMetrics
Replace 17-table snapshot fetch + 50+ JS filters per agent with five
scoped aggregation queries:
- tasks GROUP BY assignee_agent_id with conditional sums for done /
assigned / cancelled counts
- runs (within cutoff) GROUP BY agent_id with conditional sums for
succeeded / failed counts
- runs GROUP BY agent_id over started_at/finished_at for avg duration
+ max(created_at) as last active
- cost_entries GROUP BY agent_id for total cost
- activity GROUP BY actor restricted to status-change actions for
review cycle count
Company-level totals also collapse to single COUNT/SUM queries instead
of in-memory reductions over the full snapshot. Return shape unchanged.
This commit is contained in:
1 parent
47731f61a0
commit
659a2026de
1 file changed
+143
-82
@@ -2,6 +2,7 @@ import type { DatabaseSync } from "node:sqlite";
|
||||
import type {
|
||||
CompanyMetrics,
|
||||
AgentMetrics,
|
||||
InboxItem,
|
||||
ProfileSnapshot,
|
||||
RunStatus,
|
||||
StandupReport,
|
||||
@@ -21,104 +22,164 @@ export function buildCompanySettingsMethods(
|
||||
) {
|
||||
return {
|
||||
getCompanyMetrics(companyId: string, days: number = 30): CompanyMetrics {
|
||||
const snapshot = deps.listSnapshot({ companyId });
|
||||
const agents = snapshot.agents;
|
||||
const tasks = snapshot.tasks;
|
||||
const runs = snapshot.runs;
|
||||
const costs = snapshot.costs;
|
||||
|
||||
const cutoff = new Date(Date.now() - days * 24 * 60 * 60 * 1000).toISOString();
|
||||
const recentRuns = runs.filter((r) => r.createdAt > cutoff);
|
||||
const recentTasks = tasks.filter((t) => t.status === "done" && t.updatedAt > cutoff);
|
||||
const db = getDb();
|
||||
|
||||
const successfulRuns = recentRuns.filter((r) => r.status === "succeeded").length;
|
||||
const failedRuns = recentRuns.filter(
|
||||
(r) => r.status === "failed" || r.status === "timed_out",
|
||||
const agentRows = readAll<{
|
||||
id: string; name: string; status: string;
|
||||
}>(
|
||||
`select id, name, status from agents where company_id = ? order by created_at asc`,
|
||||
companyId,
|
||||
);
|
||||
const activeAgentRows = agentRows.filter(
|
||||
(a) => a.status !== "pending_approval" && a.status !== "terminated",
|
||||
);
|
||||
|
||||
const totalAgents = activeAgentRows.length;
|
||||
const activeAgents = agentRows.filter(
|
||||
(a) => a.status === "active" || a.status === "running",
|
||||
).length;
|
||||
const totalCost = costs.reduce((sum, c) => sum + (c.amountUsd ?? 0), 0);
|
||||
const completedTasks = tasks.filter((t) => t.status === "done").length;
|
||||
|
||||
const agentMetrics: AgentMetrics[] = agents
|
||||
.filter((a) => a.status !== "pending_approval" && a.status !== "terminated")
|
||||
.map((agent) => {
|
||||
const agentTasks = tasks.filter((t) => t.assigneeAgentId === agent.id);
|
||||
const agentRuns = runs.filter((r) => r.agentId === agent.id);
|
||||
const agentRecentRuns = agentRuns.filter((r) => r.createdAt > cutoff);
|
||||
const agentCosts = costs.filter((c) => c.agentId === agent.id);
|
||||
const totalTasks = (db.prepare(
|
||||
"select count(*) as c from tasks where company_id = ?",
|
||||
).get(companyId) as { c: number }).c;
|
||||
const completedTasks = (db.prepare(
|
||||
"select count(*) as c from tasks where company_id = ? and status = 'done'",
|
||||
).get(companyId) as { c: number }).c;
|
||||
const blockedTasks = (db.prepare(
|
||||
"select count(*) as c from tasks where company_id = ? and status = 'blocked'",
|
||||
).get(companyId) as { c: number }).c;
|
||||
|
||||
const agentSucceeded = agentRecentRuns.filter((r) => r.status === "succeeded").length;
|
||||
const agentFailed = agentRecentRuns.filter(
|
||||
(r) => r.status === "failed" || r.status === "timed_out",
|
||||
).length;
|
||||
const recentRunStats = db.prepare(
|
||||
`select
|
||||
count(*) as totalRuns,
|
||||
sum(case when status = 'succeeded' then 1 else 0 end) as successful,
|
||||
sum(case when status = 'failed' or status = 'timed_out' then 1 else 0 end) as failed
|
||||
from runs where company_id = ? and created_at > ?`,
|
||||
).get(companyId, cutoff) as { totalRuns: number; successful: number | null; failed: number | null };
|
||||
const totalRuns = recentRunStats.totalRuns ?? 0;
|
||||
const successfulRuns = recentRunStats.successful ?? 0;
|
||||
const failedRuns = recentRunStats.failed ?? 0;
|
||||
|
||||
// Avg run duration
|
||||
const finishedRuns = agentRuns.filter(
|
||||
(r): r is typeof r & { startedAt: string; finishedAt: string } =>
|
||||
Boolean(r.startedAt && r.finishedAt),
|
||||
);
|
||||
const avgDuration =
|
||||
finishedRuns.length > 0
|
||||
? finishedRuns.reduce(
|
||||
(sum, r) =>
|
||||
sum +
|
||||
(new Date(r.finishedAt).getTime() - new Date(r.startedAt).getTime()) / 1000,
|
||||
0,
|
||||
) / finishedRuns.length
|
||||
: 0;
|
||||
const totalCost = (db.prepare(
|
||||
"select coalesce(sum(amount_usd), 0) as s from cost_entries where company_id = ?",
|
||||
).get(companyId) as { s: number }).s;
|
||||
|
||||
// Review cycles: count task status transitions by this agent
|
||||
// Actual action strings: "task.status_changed" (api-server), "task.updated" (index.ts), "task.auto_assigned" (database)
|
||||
const reviewCycles = snapshot.activity.filter(
|
||||
(a) =>
|
||||
a.companyId === companyId &&
|
||||
a.actor === agent.id &&
|
||||
(a.action === "task.status_changed" ||
|
||||
a.action === "task.updated" ||
|
||||
a.action === "task.auto_assigned"),
|
||||
).length;
|
||||
const recentTasksDone = (db.prepare(
|
||||
"select count(*) as c from tasks where company_id = ? and status = 'done' and updated_at > ?",
|
||||
).get(companyId, cutoff) as { c: number }).c;
|
||||
|
||||
const lastRun = agentRuns.sort(
|
||||
(a, b) => new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime(),
|
||||
)[0];
|
||||
const taskAggRows = readAll<{
|
||||
agentId: string;
|
||||
done: number;
|
||||
assigned: number;
|
||||
cancelled: number;
|
||||
}>(
|
||||
`select assignee_agent_id as agentId,
|
||||
sum(case when status = 'done' then 1 else 0 end) as done,
|
||||
sum(case when status != 'done' and status != 'cancelled' then 1 else 0 end) as assigned,
|
||||
sum(case when status = 'cancelled' then 1 else 0 end) as cancelled
|
||||
from tasks
|
||||
where company_id = ? and assignee_agent_id is not null
|
||||
group by assignee_agent_id`,
|
||||
companyId,
|
||||
);
|
||||
const taskAggMap = new Map(taskAggRows.map((row) => [row.agentId, row]));
|
||||
|
||||
return {
|
||||
agentId: agent.id,
|
||||
agentName: agent.name,
|
||||
tasksCompleted: agentTasks.filter((t) => t.status === "done").length,
|
||||
tasksAssigned: agentTasks.filter(
|
||||
(t) => t.status !== "done" && t.status !== "cancelled",
|
||||
).length,
|
||||
tasksFailed: agentTasks.filter((t) => t.status === "cancelled").length,
|
||||
successRate:
|
||||
agentRecentRuns.length > 0
|
||||
? Math.round((agentSucceeded / agentRecentRuns.length) * 100)
|
||||
: 0,
|
||||
avgRunDurationSec: Math.round(avgDuration),
|
||||
totalCostUsd: agentCosts.reduce((sum, c) => sum + (c.amountUsd ?? 0), 0),
|
||||
runsTotal: agentRecentRuns.length,
|
||||
runsSucceeded: agentSucceeded,
|
||||
runsFailed: agentFailed,
|
||||
reviewCycles,
|
||||
lastActiveAt: lastRun?.createdAt ?? null,
|
||||
};
|
||||
});
|
||||
const runRecentAggRows = readAll<{
|
||||
agentId: string;
|
||||
total: number;
|
||||
succeeded: number;
|
||||
failed: number;
|
||||
}>(
|
||||
`select agent_id as agentId,
|
||||
count(*) as total,
|
||||
sum(case when status = 'succeeded' then 1 else 0 end) as succeeded,
|
||||
sum(case when status = 'failed' or status = 'timed_out' then 1 else 0 end) as failed
|
||||
from runs
|
||||
where company_id = ? and created_at > ?
|
||||
group by agent_id`,
|
||||
companyId,
|
||||
cutoff,
|
||||
);
|
||||
const runRecentAggMap = new Map(runRecentAggRows.map((row) => [row.agentId, row]));
|
||||
|
||||
const runDurationRows = readAll<{
|
||||
agentId: string;
|
||||
avgDurationSec: number | null;
|
||||
lastActiveAt: string | null;
|
||||
}>(
|
||||
`select agent_id as agentId,
|
||||
avg((julianday(finished_at) - julianday(started_at)) * 86400.0) as avgDurationSec,
|
||||
max(created_at) as lastActiveAt
|
||||
from runs
|
||||
where company_id = ? and started_at is not null and finished_at is not null
|
||||
group by agent_id`,
|
||||
companyId,
|
||||
);
|
||||
const runDurationMap = new Map(runDurationRows.map((row) => [row.agentId, row]));
|
||||
|
||||
const lastActiveRows = readAll<{ agentId: string; lastActiveAt: string }>(
|
||||
`select agent_id as agentId, max(created_at) as lastActiveAt
|
||||
from runs where company_id = ? group by agent_id`,
|
||||
companyId,
|
||||
);
|
||||
const lastActiveMap = new Map(lastActiveRows.map((row) => [row.agentId, row.lastActiveAt]));
|
||||
|
||||
const costAggRows = readAll<{ agentId: string; totalCost: number }>(
|
||||
`select agent_id as agentId, coalesce(sum(amount_usd), 0) as totalCost
|
||||
from cost_entries where company_id = ? and agent_id is not null
|
||||
group by agent_id`,
|
||||
companyId,
|
||||
);
|
||||
const costAggMap = new Map(costAggRows.map((row) => [row.agentId, row.totalCost]));
|
||||
|
||||
const reviewCycleRows = readAll<{ actor: string; cycles: number }>(
|
||||
`select actor, count(*) as cycles
|
||||
from activity
|
||||
where company_id = ?
|
||||
and action in ('task.status_changed', 'task.updated', 'task.auto_assigned')
|
||||
group by actor`,
|
||||
companyId,
|
||||
);
|
||||
const reviewCycleMap = new Map(reviewCycleRows.map((row) => [row.actor, row.cycles]));
|
||||
|
||||
const agentMetrics: AgentMetrics[] = activeAgentRows.map((agent) => {
|
||||
const taskAgg = taskAggMap.get(agent.id);
|
||||
const runRecent = runRecentAggMap.get(agent.id);
|
||||
const runDur = runDurationMap.get(agent.id);
|
||||
const succeeded = runRecent?.succeeded ?? 0;
|
||||
const total = runRecent?.total ?? 0;
|
||||
return {
|
||||
agentId: agent.id,
|
||||
agentName: agent.name,
|
||||
tasksCompleted: taskAgg?.done ?? 0,
|
||||
tasksAssigned: taskAgg?.assigned ?? 0,
|
||||
tasksFailed: taskAgg?.cancelled ?? 0,
|
||||
successRate: total > 0 ? Math.round((succeeded / total) * 100) : 0,
|
||||
avgRunDurationSec: Math.round(runDur?.avgDurationSec ?? 0),
|
||||
totalCostUsd: costAggMap.get(agent.id) ?? 0,
|
||||
runsTotal: total,
|
||||
runsSucceeded: succeeded,
|
||||
runsFailed: runRecent?.failed ?? 0,
|
||||
reviewCycles: reviewCycleMap.get(agent.id) ?? 0,
|
||||
lastActiveAt: lastActiveMap.get(agent.id) ?? null,
|
||||
};
|
||||
});
|
||||
|
||||
return {
|
||||
totalAgents: agents.filter(
|
||||
(a) => a.status !== "pending_approval" && a.status !== "terminated",
|
||||
).length,
|
||||
activeAgents: agents.filter((a) => a.status === "active" || a.status === "running").length,
|
||||
totalTasks: tasks.length,
|
||||
totalAgents,
|
||||
activeAgents,
|
||||
totalTasks,
|
||||
completedTasks,
|
||||
blockedTasks: tasks.filter((t) => t.status === "blocked").length,
|
||||
totalRuns: recentRuns.length,
|
||||
blockedTasks,
|
||||
totalRuns,
|
||||
successfulRuns,
|
||||
failedRuns,
|
||||
overallSuccessRate:
|
||||
recentRuns.length > 0 ? Math.round((successfulRuns / recentRuns.length) * 100) : 0,
|
||||
overallSuccessRate: totalRuns > 0 ? Math.round((successfulRuns / totalRuns) * 100) : 0,
|
||||
totalCostUsd: totalCost,
|
||||
avgCostPerTask: completedTasks > 0 ? totalCost / completedTasks : 0,
|
||||
throughputTasksPerDay: days > 0 ? recentTasks.length / days : 0,
|
||||
throughputTasksPerDay: days > 0 ? recentTasksDone / days : 0,
|
||||
agentMetrics,
|
||||
};
|
||||
},
|
||||
|
||||
Reference in new issue
Block a user