File size: 3,042 Bytes
64648ce
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
import { and, desc, eq } from "drizzle-orm";
import type { Db } from "@paperclipai/db";
import { companySkills, skillChangeLog } from "@paperclipai/db";

export interface SkillSnapshot {
  skillId: string;
  name: string;
  key: string;
  content: string;
}

export function skillResolverService(db: Db) {
  return {
    async resolveSkills(
      agentId: string,
      companyId: string,
      desiredSkills?: string[],
    ): Promise<SkillSnapshot[]> {
      // Get all company skills
      const allSkills = await db
        .select()
        .from(companySkills)
        .where(eq(companySkills.companyId, companyId));

      // If desiredSkills specified, filter to those
      let matched = allSkills;
      if (desiredSkills && desiredSkills.length > 0) {
        matched = allSkills.filter(
          (s) => desiredSkills.includes(s.key) || desiredSkills.includes(s.slug),
        );
      }

      return matched.map((s) => ({
        skillId: s.id,
        name: s.name,
        key: s.key,
        content: s.markdown,
      }));
    },

    async detectSkillChanges(
      beforeSnapshots: SkillSnapshot[],
      afterSnapshots: SkillSnapshot[],
      agentId: string,
      companyId: string,
      runId?: string | null,
    ) {
      const changes: Array<{
        skillId: string;
        changeNotes: string;
        previousContent: string;
        newContent: string;
      }> = [];

      const beforeMap = new Map(beforeSnapshots.map((s) => [s.skillId, s]));

      for (const after of afterSnapshots) {
        const before = beforeMap.get(after.skillId);

        if (!before) {
          // New skill appeared
          changes.push({
            skillId: after.skillId,
            changeNotes: `Skill "${after.name}" was added`,
            previousContent: "",
            newContent: after.content,
          });
          continue;
        }

        if (before.content !== after.content) {
          changes.push({
            skillId: after.skillId,
            changeNotes: `Skill "${after.name}" content was modified`,
            previousContent: before.content,
            newContent: after.content,
          });
        }
      }

      // Log changes to skill_change_log
      for (const change of changes) {
        await db.insert(skillChangeLog).values({
          companyId,
          skillId: change.skillId,
          agentId,
          changeNotes: change.changeNotes,
          previousContent: change.previousContent,
          newContent: change.newContent,
          runId: runId ?? null,
        });
      }

      return changes;
    },

    async listChangesForSkill(skillId: string) {
      return db
        .select()
        .from(skillChangeLog)
        .where(eq(skillChangeLog.skillId, skillId))
        .orderBy(desc(skillChangeLog.createdAt));
    },

    async listChangesByAgent(agentId: string) {
      return db
        .select()
        .from(skillChangeLog)
        .where(eq(skillChangeLog.agentId, agentId))
        .orderBy(desc(skillChangeLog.createdAt));
    },
  };
}