perf(db): batch skill-words + reports queries for scoreCandidate (P1-18)

This commit is contained in:
ZacharyZhang-NY committed 2026-04-16 22:53:39 -04:00
1 parent bb397dff02
commit 3deb1c00ac
1 file changed
+47 -35
+47 -35
View File
@@ -38,51 +38,50 @@ function getProjectDepartment(
return lead?.department ?? null;
}
function getAgentSkillWords(
db: DatabaseSync,
function loadSkillWordsForAgents(
readAll: ReadAll,
companyId: string,
agentId: string,
): string[] {
const skills = readAll<{ name: string; description: string | null; slug: string }>(
`select cs.name, cs.description, cs.slug
agentIds: string[],
): Map<string, string[]> {
const result = new Map<string, string[]>();
if (agentIds.length === 0) return result;
const placeholders = agentIds.map(() => "?").join(",");
const rows = readAll<{ agentId: string; name: string; description: string | null; slug: string }>(
`select asa.agent_id as agentId, cs.name, cs.description, cs.slug
from company_skills cs
join agent_skill_assignments asa on asa.skill_id = cs.id
where asa.agent_id = ? and cs.company_id = ?`,
agentId,
where cs.company_id = ? and asa.agent_id in (${placeholders})`,
companyId,
...agentIds,
);
return tokenize(skills.map((skill) => `${skill.name} ${skill.description ?? ""} ${skill.slug}`).join(" "));
const grouped = new Map<string, string[]>();
for (const row of rows) {
const blob = `${row.name} ${row.description ?? ""} ${row.slug}`;
const existing = grouped.get(row.agentId);
if (existing) existing.push(blob);
else grouped.set(row.agentId, [blob]);
}
for (const agentId of agentIds) {
result.set(agentId, tokenize((grouped.get(agentId) ?? []).join(" ")));
}
return result;
}
function scoreCandidate(
db: DatabaseSync,
function loadAgentsWithReports(
readAll: ReadAll,
companyId: string,
taskWords: string[],
projectDept: string | null,
candidate: AssignmentCandidate,
): number {
const capabilityWords = tokenize(candidate.capabilities);
const skillWords = getAgentSkillWords(db, readAll, companyId, candidate.id);
const capabilityOverlap = taskWords.filter((word) => capabilityWords.includes(word)).length;
const skillOverlap = taskWords.filter((word) => skillWords.includes(word)).length;
let score = capabilityOverlap * 10 + skillOverlap * 12 - candidate.taskCount * 5;
if (projectDept && candidate.department === projectDept) {
score += 15;
}
const hasReports = readAll<{ id: string }>(
"select id from agents where reports_to = ? and company_id = ? limit 1",
candidate.id,
agentIds: string[],
): Set<string> {
const result = new Set<string>();
if (agentIds.length === 0) return result;
const placeholders = agentIds.map(() => "?").join(",");
const rows = readAll<{ reportsTo: string }>(
`select distinct reports_to as reportsTo from agents where company_id = ? and reports_to in (${placeholders})`,
companyId,
).length > 0;
if (!hasReports) {
score += 5;
}
return score;
...agentIds,
);
for (const row of rows) result.add(row.reportsTo);
return result;
}
export function chooseBestTaskAssignee(
@@ -105,12 +104,25 @@ export function chooseBestTaskAssignee(
const taskWords = tokenize(`${task.title} ${task.description}`);
const projectDept = getProjectDepartment(getDb(), companyId, task.projectId);
const eligibleIds = eligibleCandidates.map((candidate) => candidate.id);
const skillWordsByAgent = loadSkillWordsForAgents(readAll, companyId, eligibleIds);
const agentsWithReports = loadAgentsWithReports(readAll, companyId, eligibleIds);
let bestAgentId: string | null = null;
let bestScore = -Infinity;
for (const candidate of eligibleCandidates) {
const score = scoreCandidate(getDb(), readAll, companyId, taskWords, projectDept, candidate);
const capabilityWords = tokenize(candidate.capabilities);
const skillWords = skillWordsByAgent.get(candidate.id) ?? [];
const capabilityOverlap = taskWords.filter((word) => capabilityWords.includes(word)).length;
const skillOverlap = taskWords.filter((word) => skillWords.includes(word)).length;
let score = capabilityOverlap * 10 + skillOverlap * 12 - candidate.taskCount * 5;
if (projectDept && candidate.department === projectDept) {
score += 15;
}
if (!agentsWithReports.has(candidate.id)) {
score += 5;
}
if (
score > bestScore ||
(score === bestScore &&