feat: add GitHub node types and filter entity search by userId

This commit is contained in:
Manoj K 2025-06-23 16:20:44 +05:30
parent 4a91b281e5
commit 923c7e6549
4 changed files with 117 additions and 243 deletions

View File

@ -63,12 +63,14 @@ export async function findSimilarEntities(params: {
queryEmbedding: number[];
limit: number;
threshold: number;
userId: string;
}): Promise<EntityNode[]> {
const query = `
MATCH (entity:Entity)
WHERE entity.nameEmbedding IS NOT NULL
WITH entity, vector.similarity.cosine($queryEmbedding, entity.nameEmbedding) AS score
WHERE score >= $threshold
AND entity.userId = $userId
RETURN entity, score
ORDER BY score DESC
`;

View File

@ -74,16 +74,19 @@ export class KnowledgeGraphService {
sessionId: params.sessionId,
});
const normalizedEpisodeBody = await this.normalizeEpisodeBody(
params.episodeBody,
params.source,
params.userId,
);
// const normalizedEpisodeBody = await this.normalizeEpisodeBody(
// params.episodeBody,
// params.source,
// params.userId,
// );
if (normalizedEpisodeBody === "NOTHING_TO_REMEMBER") {
logger.log("Nothing to remember");
return;
}
const normalizedEpisodeBody = `- Harshith Mullapudi requested the assistant to retrieve details from a specific task description, use the claude_code tool, create a new branch named "harshith/image-fix," and push changes to that branch.
- The assistant initiated actions to get the task details and to use the claude_code tool as instructed by Harshith Mullapudi.`;
// if (normalizedEpisodeBody === "NOTHING_TO_REMEMBER") {
// logger.log("Nothing to remember");
// return;
// }
// Step 2: Episode Creation - Create or retrieve the episode
const episode: EpisodicNode = {
@ -206,27 +209,25 @@ export class KnowledgeGraphService {
);
// Convert to EntityNode objects
const entities: EntityNode[] = [];
let entities: EntityNode[] = [];
const outputMatch = responseText.match(/<output>([\s\S]*?)<\/output>/);
if (outputMatch && outputMatch[1]) {
responseText = outputMatch[1].trim();
const extractedEntities = JSON.parse(responseText || "{}").entities || [];
entities.push(
...(await Promise.all(
extractedEntities.map(async (entity: any) => ({
uuid: crypto.randomUUID(),
name: entity.name,
type: entity.type,
attributes: entity.attributes || {},
nameEmbedding: await this.getEmbedding(
`${entity.type}: ${entity.name}`,
),
createdAt: new Date(),
userId: episode.userId,
})),
)),
entities = await Promise.all(
extractedEntities.map(async (entity: any) => ({
uuid: crypto.randomUUID(),
name: entity.name,
type: entity.type,
attributes: entity.attributes || {},
nameEmbedding: await this.getEmbedding(
`${entity.type}: ${entity.name}`,
),
createdAt: new Date(),
userId: episode.userId,
})),
);
}
@ -269,6 +270,7 @@ export class KnowledgeGraphService {
},
);
console.log(responseText);
const outputMatch = responseText.match(/<output>([\s\S]*?)<\/output>/);
if (outputMatch && outputMatch[1]) {
responseText = outputMatch[1].trim();
@ -422,6 +424,7 @@ export class KnowledgeGraphService {
queryEmbedding: entity.nameEmbedding,
limit: 5,
threshold: 0.85,
userId: episode.userId,
});
return {
entity,
@ -507,14 +510,14 @@ export class KnowledgeGraphService {
const entityResolutionMap = new Map<string, EntityNode>();
nodeResolutions.forEach((resolution: any, index: number) => {
const originalEntity = uniqueEntities[resolution.id ?? index];
const originalEntity = allEntityResults[resolution.id ?? index];
if (!originalEntity) return;
const duplicateIdx = resolution.duplicate_idx ?? -1;
// Get the corresponding result from allEntityResults
const resultEntry = allEntityResults.find(
(result) => result.entity.uuid === originalEntity.uuid,
(result) => result.entity.uuid === originalEntity.entity.uuid,
);
if (!resultEntry) return;
@ -523,7 +526,7 @@ export class KnowledgeGraphService {
const resolvedEntity =
duplicateIdx >= 0 && duplicateIdx < resultEntry.similarEntities.length
? resultEntry.similarEntities[duplicateIdx]
: originalEntity;
: originalEntity.entity;
// Update name if provided
if (resolution.name) {
@ -531,7 +534,7 @@ export class KnowledgeGraphService {
}
// Map original UUID to resolved entity
entityResolutionMap.set(originalEntity.uuid, resolvedEntity);
entityResolutionMap.set(originalEntity.entity.uuid, resolvedEntity);
});
// Step 7: Reconstruct triples with resolved entities

View File

@ -2,12 +2,14 @@ export enum Apps {
LINEAR = "LINEAR",
SLACK = "SLACK",
SOL = "SOL",
GITHUB = "GITHUB",
}
export const AppNames = {
[Apps.LINEAR]: "Linear",
[Apps.SLACK]: "Slack",
[Apps.SOL]: "Sol",
[Apps.GITHUB]: "GitHub",
} as const;
// Define attribute structure
@ -97,7 +99,7 @@ export const GENERAL_NODE_TYPES = {
},
ALIAS: {
name: "Alias",
description: "An alternative name or identifier for an entity",
description: "An alternative name or identifier for nouns and pronouns",
attributes: [
{
name: "originalName",
@ -111,6 +113,24 @@ export const GENERAL_NODE_TYPES = {
},
],
},
FILE: {
name: "File",
description: "A document, image or other file shared in an app",
attributes: [
{
name: "fileId",
description: "Unique identifier for the file",
type: "string",
required: true,
},
{
name: "source",
description: "The source of the file",
type: "string",
required: true,
},
],
},
} as const;
// App-specific node types
@ -127,32 +147,6 @@ export const APP_NODE_TYPES = {
type: "string",
required: true,
},
{
name: "title",
description: "The title of the task",
type: "string",
required: true,
},
{
name: "description",
description: "The description of the task",
type: "string",
},
{
name: "status",
description: "The current status of the task",
type: "string",
},
{
name: "dueDate",
description: "The due date of the task",
type: "date",
},
{
name: "priority",
description: "The priority level of the task",
type: "string",
},
],
},
LIST: {
@ -166,22 +160,6 @@ export const APP_NODE_TYPES = {
type: "string",
required: true,
},
{
name: "title",
description: "The title of the list",
type: "string",
required: true,
},
{
name: "description",
description: "The description of the list",
type: "string",
},
{
name: "itemCount",
description: "The number of items in the list",
type: "number",
},
],
},
PREFERENCE: {
@ -203,25 +181,6 @@ export const APP_NODE_TYPES = {
},
],
},
COMMAND: {
name: "Sol Command",
description:
"A user-issued command or trigger phrase, often starting with '/', that directs the system or an app to perform a specific action. Commands should always be extracted as distinct, important user actions.",
attributes: [
{
name: "commandId",
description: "Unique identifier for the command",
type: "string",
required: true,
},
{
name: "commandName",
description: "The name of the command",
type: "string",
required: true,
},
],
},
AUTOMATION: {
name: "Sol Automation",
description:
@ -233,18 +192,6 @@ export const APP_NODE_TYPES = {
type: "string",
required: true,
},
{
name: "trigger",
description: "The event that triggers this automation",
type: "string",
required: true,
},
{
name: "action",
description: "The action performed by this automation",
type: "string",
required: true,
},
],
},
},
@ -259,27 +206,6 @@ export const APP_NODE_TYPES = {
type: "string",
required: true,
},
{
name: "title",
description: "The title of the issue",
type: "string",
required: true,
},
{
name: "status",
description: "The current status of the issue",
type: "string",
},
{
name: "priority",
description: "The priority level of the issue",
type: "number",
},
{
name: "assignee",
description: "The person assigned to the issue",
type: "string",
},
],
},
PROJECT: {
@ -292,27 +218,6 @@ export const APP_NODE_TYPES = {
type: "string",
required: true,
},
{
name: "name",
description: "The name of the project",
type: "string",
required: true,
},
{
name: "status",
description: "The current status of the project",
type: "string",
},
{
name: "startDate",
description: "The start date of the project",
type: "date",
},
{
name: "targetDate",
description: "The target completion date of the project",
type: "date",
},
],
},
CYCLE: {
@ -325,24 +230,6 @@ export const APP_NODE_TYPES = {
type: "string",
required: true,
},
{
name: "name",
description: "The name of the cycle",
type: "string",
required: true,
},
{
name: "startDate",
description: "The start date of the cycle",
type: "date",
required: true,
},
{
name: "endDate",
description: "The end date of the cycle",
type: "date",
required: true,
},
],
},
TEAM: {
@ -355,22 +242,6 @@ export const APP_NODE_TYPES = {
type: "string",
required: true,
},
{
name: "name",
description: "The name of the team",
type: "string",
required: true,
},
{
name: "key",
description: "The team's key or shorthand",
type: "string",
},
{
name: "memberCount",
description: "Number of members in the team",
type: "number",
},
],
},
LABEL: {
@ -383,17 +254,6 @@ export const APP_NODE_TYPES = {
type: "string",
required: true,
},
{
name: "name",
description: "The name of the label",
type: "string",
required: true,
},
{
name: "color",
description: "The color of the label",
type: "string",
},
],
},
},
@ -408,22 +268,12 @@ export const APP_NODE_TYPES = {
type: "string",
required: true,
},
{
name: "name",
description: "The name of the channel",
type: "string",
required: true,
},
{
name: "isPrivate",
description: "Whether the channel is private",
type: "boolean",
},
{
name: "memberCount",
description: "The number of members in the channel",
type: "number",
},
],
},
THREAD: {
@ -442,11 +292,6 @@ export const APP_NODE_TYPES = {
type: "string",
required: true,
},
{
name: "replyCount",
description: "Number of replies in the thread",
type: "number",
},
],
},
MESSAGE: {
@ -459,23 +304,6 @@ export const APP_NODE_TYPES = {
type: "string",
required: true,
},
{
name: "content",
description: "The content of the message",
type: "string",
required: true,
},
{
name: "timestamp",
description: "When the message was sent",
type: "date",
required: true,
},
{
name: "reactions",
description: "Reactions to the message",
type: "array",
},
],
},
REACTION: {
@ -488,39 +316,79 @@ export const APP_NODE_TYPES = {
type: "string",
required: true,
},
{
name: "count",
description: "Number of users who reacted with this emoji",
type: "number",
required: true,
},
],
},
FILE: {
name: "Slack File",
description: "A document, image or other file shared in Slack",
},
[Apps.GITHUB]: {
REPOSITORY: {
name: "GitHub Repository",
description: "A code repository hosted on GitHub",
attributes: [
{
name: "fileId",
description: "Unique identifier for the file",
name: "repoId",
description: "Unique identifier for the repository",
type: "string",
required: true,
},
{
name: "name",
description: "The name of the file",
description: "The name of the repository",
type: "string",
required: true,
},
{
name: "type",
description: "The file type or format",
name: "owner",
description: "Owner (user or organization) of the repository",
type: "string",
required: true,
},
],
},
ISSUE: {
name: "GitHub Issue",
description: "An issue created to track bugs, tasks, or feature requests",
attributes: [
{
name: "size",
description: "The size of the file in bytes",
type: "number",
name: "issueId",
description: "Unique identifier for the issue",
type: "string",
required: true,
},
],
},
PULL_REQUEST: {
name: "GitHub Pull Request",
description: "A pull request to propose changes to a repository",
attributes: [
{
name: "PR number",
description: "Unique number for the pull request",
type: "string",
required: true,
},
],
},
COMMIT: {
name: "GitHub Commit",
description: "A commit representing a set of changes in a repository",
attributes: [
{
name: "commitSha",
description: "SHA hash of the commit",
type: "string",
required: true,
},
],
},
BRANCH: {
name: "GitHub Branch",
description: "A branch in a GitHub repository",
attributes: [
{
name: "branchName",
description: "Name of the branch",
type: "string",
required: true,
},
],
},

View File

@ -1,10 +1,11 @@
{
"name": "core",
"private": true,
"version": "0.1.3",
"workspaces":
[ "apps/*", "packages/*" ]
,
"version": "0.1.5",
"workspaces": [
"apps/*",
"packages/*"
],
"scripts": {
"build": "dotenv -- turbo run build",
"dev": "dotenv -- turbo run dev",