Assign default skills when a hire is approved
The CEO's operating prompt instructed the model to inspect each direct report every wake, compare assigned skills to role, and POST missing ones — business logic routed through the LLM at O(reports) API calls per heartbeat. The guarantee was unreliable and expensive. Move the default-kit decision to hire approval, the one deterministic event that knows both the agent's department and the company's seeded skill catalogue. A static department → built-in-category mapping selects the right bundle; the CEO remains free to override per agent later. Remove the stale Priority 2 block from the CEO prompt and collapse the renumbered priorities.
This commit is contained in:
1 parent
5dd74a477d
commit
a3006f0b38
3 files changed
+119
-17
No files matched your search
@@ -0,0 +1,89 @@
|
||||
import type { AppDatabase } from "../database";
|
||||
import type { DepartmentId } from "@shared/types";
|
||||
|
||||
/**
|
||||
* Server-side default skill assignment at hire approval time.
|
||||
*
|
||||
* Before this module existed, the CEO's operating prompt was explicitly
|
||||
* told to inspect every direct report every wake, fetch the skill
|
||||
* catalogue, and POST /agents/{id}/skills for any unassigned role-
|
||||
* relevant entry. That is business logic routed through an LLM — wasted
|
||||
* tokens and an unreliable guarantee. The hire approval is the
|
||||
* deterministic moment to give a fresh agent a sensible default kit;
|
||||
* the CEO is still free to add or remove skills later.
|
||||
*
|
||||
* The mapping is department → built-in skill categories. Each seeded
|
||||
* company skill carries its category in `metadata.builtinCategory`
|
||||
* (see `skills/runtime.ts#seedBuiltinSkills`); we match against that
|
||||
* tag so a company that imported extra skills under the same category
|
||||
* inherits them too, and deletes remove the assignment pool cleanly.
|
||||
*/
|
||||
|
||||
const CATEGORIES_BY_DEPARTMENT: Record<DepartmentId, readonly string[]> = {
|
||||
executive: ["basic-for-all", "document-process"],
|
||||
engineering: ["software-engineer", "basic-for-all"],
|
||||
product: ["frontend-design", "basic-for-all", "document-process"],
|
||||
design: ["frontend-design", "basic-for-all"],
|
||||
marketing: ["marketing", "basic-for-all", "document-process"],
|
||||
sales: ["marketing", "basic-for-all", "document-process"],
|
||||
hr: ["basic-for-all", "document-process"],
|
||||
finance: ["basic-for-all", "document-process"],
|
||||
legal: ["basic-for-all", "document-process"],
|
||||
operations: ["software-engineer", "basic-for-all", "document-process"],
|
||||
customer_support: ["basic-for-all", "document-process"],
|
||||
research: ["basic-for-all", "document-process"],
|
||||
};
|
||||
|
||||
function readBuiltinCategory(metadata: unknown): string | null {
|
||||
if (!metadata) return null;
|
||||
if (typeof metadata === "string") {
|
||||
try {
|
||||
const parsed = JSON.parse(metadata) as Record<string, unknown>;
|
||||
const value = parsed?.builtinCategory;
|
||||
return typeof value === "string" ? value : null;
|
||||
} catch {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
if (typeof metadata === "object") {
|
||||
const value = (metadata as Record<string, unknown>).builtinCategory;
|
||||
return typeof value === "string" ? value : null;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
export interface AutoAssignSkillsInput {
|
||||
agentId: string;
|
||||
companyId: string;
|
||||
department: DepartmentId | string | null | undefined;
|
||||
}
|
||||
|
||||
export interface AutoAssignSkillsResult {
|
||||
assignedSkillIds: string[];
|
||||
}
|
||||
|
||||
export function autoAssignSkillsForHire(
|
||||
db: AppDatabase,
|
||||
input: AutoAssignSkillsInput,
|
||||
): AutoAssignSkillsResult {
|
||||
const department = (input.department ?? "") as DepartmentId;
|
||||
const categories = CATEGORIES_BY_DEPARTMENT[department];
|
||||
if (!categories || categories.length === 0) {
|
||||
return { assignedSkillIds: [] };
|
||||
}
|
||||
|
||||
const alreadyAssigned = new Set(db.listAgentSkillAssignments(input.agentId));
|
||||
const wanted = new Set(categories);
|
||||
const catalogue = db.listCompanySkills(input.companyId);
|
||||
|
||||
const assigned: string[] = [];
|
||||
for (const skill of catalogue) {
|
||||
if (alreadyAssigned.has(skill.id)) continue;
|
||||
const category = readBuiltinCategory(skill.metadata);
|
||||
if (!category || !wanted.has(category)) continue;
|
||||
db.assignSkillToAgent(input.agentId, skill.id);
|
||||
assigned.push(skill.id);
|
||||
}
|
||||
|
||||
return { assignedSkillIds: assigned };
|
||||
}
|
||||
Reference in new issue
Block a user