Fix: activity flow and invalidation in knowledge graph

This commit is contained in:
Manoj K 2025-07-17 21:44:49 +05:30 committed by Harshith Mullapudi
parent e82e7c1db2
commit aa7ae14f95
10 changed files with 277 additions and 132 deletions

View File

@ -9,7 +9,9 @@ import {
import { openai } from "@ai-sdk/openai";
import { logger } from "~/services/logger.service";
import { env } from "~/env.server";
import { createOllama } from "ollama-ai-provider";
import { createOllama, type OllamaProvider } from "ollama-ai-provider";
import { anthropic } from "@ai-sdk/anthropic";
import { google } from "@ai-sdk/google";
export async function makeModelCall(
stream: boolean,
@ -19,44 +21,41 @@ export async function makeModelCall(
) {
let modelInstance;
const model = env.MODEL;
let finalModel: string = "unknown";
// const ollamaUrl = process.env.OLLAMA_URL;
const ollamaUrl = undefined;
const ollamaUrl = process.env.OLLAMA_URL;
let ollama: OllamaProvider | undefined;
if (ollamaUrl) {
const ollama = createOllama({
ollama = createOllama({
baseURL: ollamaUrl,
});
modelInstance = ollama(model);
} else {
switch (model) {
case LLMModelEnum.GPT35TURBO:
case LLMModelEnum.GPT4TURBO:
case LLMModelEnum.GPT4O:
case LLMModelEnum.GPT41:
case LLMModelEnum.GPT41MINI:
case LLMModelEnum.GPT41NANO:
finalModel = LLMMappings[model];
modelInstance = openai(finalModel, { ...options });
break;
}
case LLMModelEnum.CLAUDEOPUS:
case LLMModelEnum.CLAUDESONNET:
case LLMModelEnum.CLAUDEHAIKU:
finalModel = LLMMappings[model];
break;
switch (model) {
case "gpt-4.1-2025-04-14":
case "gpt-4.1-mini-2025-04-14":
case "gpt-4.1-nano-2025-04-14":
modelInstance = openai(model, { ...options });
break;
case LLMModelEnum.GEMINI25FLASH:
case LLMModelEnum.GEMINI25PRO:
case LLMModelEnum.GEMINI20FLASH:
case LLMModelEnum.GEMINI20FLASHLITE:
finalModel = LLMMappings[model];
break;
case "claude-3-7-sonnet-20250219":
case "claude-3-opus-20240229":
case "claude-3-5-haiku-20241022":
modelInstance = anthropic(model, { ...options });
break;
default:
logger.warn(`Unsupported model type: ${model}`);
break;
}
case "gemini-2.5-flash-preview-04-17":
case "gemini-2.5-pro-preview-03-25":
case "gemini-2.0-flash":
case "gemini-2.0-flash-lite":
modelInstance = google(model, { ...options });
break;
default:
if (ollama) {
modelInstance = ollama(model);
}
logger.warn(`Unsupported model type: ${model}`);
break;
}
if (stream) {
@ -64,7 +63,7 @@ export async function makeModelCall(
model: modelInstance as LanguageModelV1,
messages,
onFinish: async ({ text }) => {
onFinish(text, finalModel);
onFinish(text, model);
},
});
}
@ -74,7 +73,7 @@ export async function makeModelCall(
messages,
});
onFinish(text, finalModel);
onFinish(text, model);
return text;
}

View File

@ -56,12 +56,6 @@ const { action, loader } = createActionApiRoute(
episodeBody: body.text,
referenceTime: new Date().toISOString(),
source: body.source,
metadata: {
activityId: activity.id,
integrationAccountId: body.integrationAccountId || "",
taskId: body.taskId || "",
type: "activity",
},
};
const queueResponse = await addToQueue(

View File

@ -309,3 +309,32 @@ export async function getRelatedEpisodesEntities(params: {
})
.filter((entity): entity is EntityNode => entity !== null);
}
export async function getEpisodeStatements(params: {
episodeUuid: string;
userId: string;
}) {
const query = `
MATCH (episode:Episode {uuid: $episodeUuid, userId: $userId})-[:HAS_PROVENANCE]->(stmt:Statement)
RETURN stmt
`;
const result = await runQuery(query, {
episodeUuid: params.episodeUuid,
userId: params.userId,
});
return result.map((record) => {
const stmt = record.get("stmt").properties;
return {
uuid: stmt.uuid,
fact: stmt.fact,
factEmbedding: stmt.factEmbedding,
createdAt: new Date(stmt.createdAt),
validAt: new Date(stmt.validAt),
invalidAt: stmt.invalidAt ? new Date(stmt.invalidAt) : null,
attributes: stmt.attributesJson ? JSON.parse(stmt.attributesJson) : {},
userId: stmt.userId,
};
});
}

View File

@ -20,6 +20,7 @@ import {
resolveStatementPrompt,
} from "./prompts/statements";
import {
getEpisodeStatements,
getRecentEpisodes,
getRelatedEpisodesEntities,
searchEpisodesByEmbedding,
@ -122,13 +123,15 @@ export class KnowledgeGraphService {
);
// Step 3.2: Handle preset type logic - expand entities for statement extraction
const entitiesForStatementExtraction =
await this.expandEntitiesForStatements(extractedNodes, episode);
const categorizedEntities = await this.expandEntitiesForStatements(
extractedNodes,
episode,
);
// Step 4: Statement Extraction - Extract statements (triples) instead of direct edges
// Step 4: Statement Extrraction - Extract statements (triples) instead of direct edges
const extractedStatements = await this.extractStatements(
episode,
entitiesForStatementExtraction,
categorizedEntities,
previousEpisodes,
);
@ -141,7 +144,11 @@ export class KnowledgeGraphService {
// Step 6: Statement Resolution - Resolve statements and detect contradictions
const { resolvedStatements, invalidatedStatements } =
await this.resolveStatements(resolvedTriples, episode);
await this.resolveStatements(
resolvedTriples,
episode,
previousEpisodes,
);
// Step 7: ADd attributes to entity nodes
const updatedTriples = await this.addAttributesToEntities(
@ -261,7 +268,10 @@ export class KnowledgeGraphService {
*/
private async extractStatements(
episode: EpisodicNode,
extractedEntities: EntityNode[],
categorizedEntities: {
primary: EntityNode[];
expanded: EntityNode[];
},
previousEpisodes: EpisodicNode[],
): Promise<Triple[]> {
// Use the prompt library to get the appropriate prompts
@ -271,10 +281,16 @@ export class KnowledgeGraphService {
content: ep.content,
createdAt: ep.createdAt.toISOString(),
})),
entities: extractedEntities.map((node) => ({
name: node.name,
type: node.type,
})),
entities: {
primary: categorizedEntities.primary.map((node) => ({
name: node.name,
type: node.type,
})),
expanded: categorizedEntities.expanded.map((node) => ({
name: node.name,
type: node.type,
})),
},
referenceTime: episode.validAt.toISOString(),
};
@ -319,17 +335,23 @@ export class KnowledgeGraphService {
}
}
// Combine primary and expanded entities for entity matching
const allEntities = [
...categorizedEntities.primary,
...categorizedEntities.expanded,
];
// Convert extracted triples to Triple objects with Statement nodes
const triples = await Promise.all(
extractedTriples.map(async (triple: ExtractedTripleData) => {
// Find the subject and object nodes by matching both name and type
const subjectNode = extractedEntities.find(
const subjectNode = allEntities.find(
(node) =>
node.name.toLowerCase() === triple.source.toLowerCase() &&
node.type.toLowerCase() === triple.sourceType.toLowerCase(),
);
const objectNode = extractedEntities.find(
const objectNode = allEntities.find(
(node) =>
node.name.toLowerCase() === triple.target.toLowerCase() &&
node.type.toLowerCase() === triple.targetType.toLowerCase(),
@ -373,9 +395,12 @@ export class KnowledgeGraphService {
private async expandEntitiesForStatements(
extractedNodes: EntityNode[],
episode: EpisodicNode,
): Promise<EntityNode[]> {
): Promise<{
primary: EntityNode[];
expanded: EntityNode[];
}> {
const allAppEnumValues = Object.values(Apps);
const expandedEntities = [...extractedNodes];
const expandedEntities: EntityNode[] = [];
// For each extracted entity, check if we need to add existing preset entities
for (const entity of extractedNodes) {
@ -385,7 +410,7 @@ export class KnowledgeGraphService {
const similarEntities = await findSimilarEntities({
queryEmbedding: entity.nameEmbedding,
limit: 5,
threshold: 0.7,
threshold: 0.8,
userId: episode.userId,
});
@ -405,7 +430,27 @@ export class KnowledgeGraphService {
}
}
return expandedEntities;
// Deduplicate by name AND type combination
const deduplicateEntities = (entities: EntityNode[]) => {
const seen = new Map<string, EntityNode>();
return entities.filter((entity) => {
const key = `${entity.name.toLowerCase()}_${entity.type.toLowerCase()}`;
if (seen.has(key)) {
return false;
}
seen.set(key, entity);
return true;
});
};
return {
primary: deduplicateEntities(extractedNodes),
expanded: deduplicateEntities(
expandedEntities.filter(
(e) => !extractedNodes.some((primary) => primary.uuid === e.uuid),
),
),
};
}
/**
@ -436,9 +481,6 @@ export class KnowledgeGraphService {
if (newIsPreset && !existingIsPreset) {
// New is preset, existing is custom - evolve existing entity to preset type
console.log(
`Evolving entity: ${existingEntity.name} from ${existingEntity.type} to ${newEntity.type}`,
);
existingEntityIds.push(existingEntity.uuid);
}
});
@ -665,6 +707,7 @@ export class KnowledgeGraphService {
private async resolveStatements(
triples: Triple[],
episode: EpisodicNode,
previousEpisodes: EpisodicNode[],
): Promise<{
resolvedStatements: Triple[];
invalidatedStatements: string[];
@ -704,7 +747,7 @@ export class KnowledgeGraphService {
// Phase 2: Find semantically similar statements
const semanticMatches = await findSimilarStatements({
factEmbedding: triple.statement.factEmbedding,
threshold: 0.85,
threshold: 0.7,
excludeIds: checkedStatementIds,
userId: triple.provenance.userId,
});
@ -713,10 +756,35 @@ export class KnowledgeGraphService {
potentialMatches.push(...semanticMatches);
}
// Phase 3: Check related memories for contradictory statements
const previousEpisodesStatements: StatementNode[] = [];
await Promise.all(
previousEpisodes.map(async (episode) => {
const statements = await getEpisodeStatements({
episodeUuid: episode.uuid,
userId: episode.userId,
});
previousEpisodesStatements.push(...statements);
}),
);
if (previousEpisodesStatements && previousEpisodesStatements.length > 0) {
// Filter out facts we've already checked
const newRelatedFacts = previousEpisodesStatements
.flat()
.filter((fact) => !checkedStatementIds.includes(fact.uuid));
if (newRelatedFacts.length > 0) {
potentialMatches.push(...newRelatedFacts);
}
}
if (potentialMatches.length > 0) {
logger.info(
`Found ${potentialMatches.length} potential matches for: ${triple.statement.fact}`,
);
allPotentialMatches.set(triple.statement.uuid, potentialMatches);
// Get full triple information for each potential match
@ -947,9 +1015,12 @@ export class KnowledgeGraphService {
}
const entityTypes = getNodeTypesString(appEnumValues);
const relatedMemories = await this.getRelatedMemories(episodeBody, userId);
// Fetch ingestion rules for this source
const ingestionRules = await this.getIngestionRulesForSource(source, userId);
const ingestionRules = await this.getIngestionRulesForSource(
source,
userId,
);
const context = {
episodeContent: episodeBody,

View File

@ -21,6 +21,17 @@ CRITICAL REQUIREMENT:
- DO NOT create, invent, or modify any entity names.
- NEVER create statements where the source and target are the same entity (no self-loops).
ENTITY PRIORITIZATION:
- **PRIMARY ENTITIES**: Directly extracted from the current episode - these are your main focus
- **EXPANDED ENTITIES**: From related contexts - only use if they're explicitly mentioned or contextually relevant
RELATIONSHIP FORMATION RULES:
1. **PRIMARY-PRIMARY**: Always consider relationships between primary entities
2. **PRIMARY-EXPANDED**: Only if the expanded entity is mentioned in the episode content
3. **EXPANDED-EXPANDED**: Avoid unless there's explicit connection in the episode
FOCUS: Create relationships that ADD VALUE to understanding the current episode, not just because entities are available.
## PRIMARY MISSION: EXTRACT NEW RELATIONSHIPS
Focus on extracting factual statements that ADD NEW VALUE to the knowledge graph:
- **PRIORITIZE**: New relationships not already captured in previous episodes
@ -136,7 +147,13 @@ ${JSON.stringify(context.previousEpisodes, null, 2)}
</PREVIOUS_EPISODES>
<AVAILABLE_ENTITIES>
${JSON.stringify(context.entities, null, 2)}
<PRIMARY_ENTITIES>
${JSON.stringify(context.entities.primary, null, 2)}
</PRIMARY_ENTITIES>
<EXPANDED_ENTITIES>
${JSON.stringify(context.entities.expanded, null, 2)}
</EXPANDED_ENTITIES>
</AVAILABLE_ENTITIES>
`,
},

View File

@ -126,7 +126,6 @@ const executeCLICommand = async (
args.push("--config", JSON.stringify(config || {}));
args.push("--state", JSON.stringify(state || {}));
break;
default:
throw new Error(`Unsupported event type: ${eventType}`);
}

View File

@ -1,5 +1,6 @@
import { PrismaClient } from "@prisma/client";
import { Activity, PrismaClient } from "@prisma/client";
import { type Message } from "@core/types";
import { addToQueue } from "~/lib/ingest.server";
const prisma = new PrismaClient();
@ -111,20 +112,42 @@ export const createActivities = async ({
where: {
id: integrationAccountId,
},
include: {
integrationDefinition: true,
},
});
if (!integrationAccount) {
return [];
}
return await prisma.activity.createMany({
data: messages.map((message) => {
return await Promise.all(
messages.map(async (message) => {
const activity = await prisma.activity.create({
data: {
text: message.data.text,
sourceURL: message.data.sourceURL,
integrationAccountId,
workspaceId: integrationAccount?.workspaceId,
},
});
const ingestData = {
episodeBody: message.data.text,
referenceTime: new Date().toISOString(),
source: integrationAccount?.integrationDefinition.slug,
};
const queueResponse = await addToQueue(
ingestData,
integrationAccount?.integratedById,
activity.id,
);
return {
text: message.data.text,
sourceURL: message.data.sourceURL,
integrationAccountId,
workspaceId: integrationAccount?.workspaceId,
activityId: activity.id,
queueId: queueResponse.id,
};
}),
});
);
};

View File

@ -256,6 +256,19 @@ export const APP_NODE_TYPES = {
},
],
},
STATUS: {
name: "Linear Status",
description:
"A status or state of a Linear issue (e.g., Todo, In Progress, Done, Completed)",
attributes: [
{
name: "statusName",
description: "The name of the status",
type: "string",
required: true,
},
],
},
},
[Apps.SLACK]: {
CHANNEL: {

View File

@ -28,7 +28,7 @@ function createActivityMessage(params: LinearActivityCreateParams) {
/**
* Fetches user information from Linear
*/
async function fetchUserInfo(accessToken: string) {
async function fetchUserInfo(apiKey: string) {
try {
const query = `
query {
@ -46,7 +46,7 @@ async function fetchUserInfo(accessToken: string) {
{
headers: {
'Content-Type': 'application/json',
Authorization: accessToken,
Authorization: apiKey,
},
},
);
@ -60,7 +60,7 @@ async function fetchUserInfo(accessToken: string) {
/**
* Fetches recent issues relevant to the user (created, assigned, or subscribed)
*/
async function fetchRecentIssues(accessToken: string, lastSyncTime: string) {
async function fetchRecentIssues(apiKey: string, lastSyncTime: string) {
try {
const query = `
query RecentIssues($lastSyncTime: DateTimeOrDuration) {
@ -138,7 +138,7 @@ async function fetchRecentIssues(accessToken: string, lastSyncTime: string) {
{
headers: {
'Content-Type': 'application/json',
Authorization: accessToken,
Authorization: apiKey,
},
},
);
@ -152,7 +152,7 @@ async function fetchRecentIssues(accessToken: string, lastSyncTime: string) {
/**
* Fetches recent comments on issues relevant to the user
*/
async function fetchRecentComments(accessToken: string, lastSyncTime: string) {
async function fetchRecentComments(apiKey: string, lastSyncTime: string) {
try {
const query = `
query RecentComments($lastSyncTime: DateTimeOrDuration) {
@ -216,7 +216,7 @@ async function fetchRecentComments(accessToken: string, lastSyncTime: string) {
{
headers: {
'Content-Type': 'application/json',
Authorization: accessToken,
Authorization: apiKey,
},
},
);
@ -444,7 +444,7 @@ export async function handleSchedule(config: any, state: any) {
const integrationConfiguration = config;
// Check if we have a valid access token
if (!integrationConfiguration?.accessToken) {
if (!integrationConfiguration?.apiKey) {
return [];
}
@ -458,7 +458,7 @@ export async function handleSchedule(config: any, state: any) {
// Fetch user info to identify activities relevant to them
let user;
try {
user = await fetchUserInfo(integrationConfiguration.accessToken);
user = await fetchUserInfo(integrationConfiguration.apiKey);
} catch (error) {
return [];
}
@ -472,7 +472,7 @@ export async function handleSchedule(config: any, state: any) {
// Process all issue activities (created, assigned, updated, etc.)
try {
const issues = await fetchRecentIssues(integrationConfiguration.accessToken, lastIssuesSync);
const issues = await fetchRecentIssues(integrationConfiguration.apiKey, lastIssuesSync);
if (issues && issues.nodes) {
const issueActivities = await processIssueActivities(issues.nodes, user.id);
messages.push(...issueActivities);
@ -483,10 +483,7 @@ export async function handleSchedule(config: any, state: any) {
// Process all comment activities
try {
const comments = await fetchRecentComments(
integrationConfiguration.accessToken,
lastCommentsSync,
);
const comments = await fetchRecentComments(integrationConfiguration.apiKey, lastCommentsSync);
if (comments && comments.nodes) {
const commentActivities = await processCommentActivities(comments.nodes, user.id, user);
messages.push(...commentActivities);

97
pnpm-lock.yaml generated
View File

@ -257,7 +257,7 @@ importers:
version: link:../../packages/emails
exa-js:
specifier: ^1.8.20
version: 1.8.20(encoding@0.1.13)(ws@8.17.1)
version: 1.8.20(encoding@0.1.13)
execa:
specifier: ^9.6.0
version: 9.6.0
@ -381,7 +381,7 @@ importers:
devDependencies:
'@remix-run/dev':
specifier: 2.16.7
version: 2.16.7(@remix-run/react@2.16.7(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.8.3))(@remix-run/serve@2.16.7(typescript@5.8.3))(@types/node@22.16.0)(jiti@2.4.2)(lightningcss@1.30.1)(terser@5.42.0)(typescript@5.8.3)(vite@6.3.5(@types/node@22.16.0)(jiti@2.4.2)(lightningcss@1.30.1)(terser@5.42.0)(yaml@2.8.0))(yaml@2.8.0)
version: 2.16.7(@remix-run/react@2.16.7(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.8.3))(@remix-run/serve@2.16.7(typescript@5.8.3))(@types/node@24.0.0)(jiti@2.4.2)(lightningcss@1.30.1)(terser@5.42.0)(typescript@5.8.3)(vite@6.3.5(@types/node@24.0.0)(jiti@2.4.2)(lightningcss@1.30.1)(terser@5.42.0)(yaml@2.8.0))(yaml@2.8.0)
'@remix-run/eslint-config':
specifier: 2.16.7
version: 2.16.7(eslint@8.57.1)(react@18.3.1)(typescript@5.8.3)
@ -396,7 +396,7 @@ importers:
version: 0.5.16(tailwindcss@4.1.7)
'@tailwindcss/vite':
specifier: ^4.1.7
version: 4.1.9(vite@6.3.5(@types/node@22.16.0)(jiti@2.4.2)(lightningcss@1.30.1)(terser@5.42.0)(yaml@2.8.0))
version: 4.1.9(vite@6.3.5(@types/node@24.0.0)(jiti@2.4.2)(lightningcss@1.30.1)(terser@5.42.0)(yaml@2.8.0))
'@trigger.dev/build':
specifier: ^4.0.0-v4-beta.22
version: 4.0.0-v4-beta.22(typescript@5.8.3)
@ -492,10 +492,10 @@ importers:
version: 5.8.3
vite:
specifier: ^6.0.0
version: 6.3.5(@types/node@22.16.0)(jiti@2.4.2)(lightningcss@1.30.1)(terser@5.42.0)(yaml@2.8.0)
version: 6.3.5(@types/node@24.0.0)(jiti@2.4.2)(lightningcss@1.30.1)(terser@5.42.0)(yaml@2.8.0)
vite-tsconfig-paths:
specifier: ^4.2.1
version: 4.3.2(typescript@5.8.3)(vite@6.3.5(@types/node@22.16.0)(jiti@2.4.2)(lightningcss@1.30.1)(terser@5.42.0)(yaml@2.8.0))
version: 4.3.2(typescript@5.8.3)(vite@6.3.5(@types/node@24.0.0)(jiti@2.4.2)(lightningcss@1.30.1)(terser@5.42.0)(yaml@2.8.0))
packages/database:
dependencies:
@ -598,7 +598,7 @@ importers:
version: 20.19.7
tsup:
specifier: ^8.0.1
version: 8.5.0(@swc/core@1.3.101(@swc/helpers@0.5.17))(jiti@2.4.2)(postcss@8.5.5)(typescript@5.8.3)(yaml@2.8.0)
version: 8.5.0(@swc/core@1.3.101)(jiti@2.4.2)(postcss@8.5.5)(typescript@5.8.3)(yaml@2.8.0)
typescript:
specifier: ^5.0.0
version: 5.8.3
@ -635,7 +635,7 @@ importers:
version: 6.0.1
tsup:
specifier: ^8.0.1
version: 8.5.0(@swc/core@1.3.101(@swc/helpers@0.5.17))(jiti@2.4.2)(postcss@8.5.5)(typescript@5.8.3)(yaml@2.8.0)
version: 8.5.0(@swc/core@1.3.101)(jiti@2.4.2)(postcss@8.5.5)(typescript@5.8.3)(yaml@2.8.0)
typescript:
specifier: ^5.3.0
version: 5.8.3
@ -12052,7 +12052,7 @@ snapshots:
react-dom: 18.3.1(react@18.3.1)
optionalDependencies:
'@types/react': 18.2.47
'@types/react-dom': 18.3.7(@types/react@18.2.69)
'@types/react-dom': 18.3.7(@types/react@18.2.47)
'@radix-ui/react-arrow@1.1.7(@types/react-dom@18.3.7(@types/react@18.2.69))(@types/react@18.2.69)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)':
dependencies:
@ -12106,7 +12106,7 @@ snapshots:
react-dom: 18.3.1(react@18.3.1)
optionalDependencies:
'@types/react': 18.2.47
'@types/react-dom': 18.3.7(@types/react@18.2.69)
'@types/react-dom': 18.3.7(@types/react@18.2.47)
'@radix-ui/react-collapsible@1.1.11(@types/react-dom@18.3.7(@types/react@18.2.69))(@types/react@18.2.69)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)':
dependencies:
@ -12134,7 +12134,7 @@ snapshots:
react-dom: 18.3.1(react@18.3.1)
optionalDependencies:
'@types/react': 18.2.47
'@types/react-dom': 18.3.7(@types/react@18.2.69)
'@types/react-dom': 18.3.7(@types/react@18.2.47)
'@radix-ui/react-collection@1.1.7(@types/react-dom@18.3.7(@types/react@18.2.69))(@types/react@18.2.69)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)':
dependencies:
@ -12267,7 +12267,7 @@ snapshots:
react-dom: 18.3.1(react@18.3.1)
optionalDependencies:
'@types/react': 18.2.47
'@types/react-dom': 18.3.7(@types/react@18.2.69)
'@types/react-dom': 18.3.7(@types/react@18.2.47)
'@radix-ui/react-dismissable-layer@1.1.10(@types/react-dom@18.3.7(@types/react@18.2.69))(@types/react@18.2.69)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)':
dependencies:
@ -12332,7 +12332,7 @@ snapshots:
react-dom: 18.3.1(react@18.3.1)
optionalDependencies:
'@types/react': 18.2.47
'@types/react-dom': 18.3.7(@types/react@18.2.69)
'@types/react-dom': 18.3.7(@types/react@18.2.47)
'@radix-ui/react-focus-scope@1.1.7(@types/react-dom@18.3.7(@types/react@18.2.69))(@types/react@18.2.69)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)':
dependencies:
@ -12425,7 +12425,7 @@ snapshots:
react-remove-scroll: 2.5.7(@types/react@18.2.47)(react@18.3.1)
optionalDependencies:
'@types/react': 18.2.47
'@types/react-dom': 18.3.7(@types/react@18.2.69)
'@types/react-dom': 18.3.7(@types/react@18.2.47)
'@radix-ui/react-popover@1.1.14(@types/react-dom@18.3.7(@types/react@18.2.69))(@types/react@18.2.69)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)':
dependencies:
@ -12466,7 +12466,7 @@ snapshots:
react-dom: 18.3.1(react@18.3.1)
optionalDependencies:
'@types/react': 18.2.47
'@types/react-dom': 18.3.7(@types/react@18.2.69)
'@types/react-dom': 18.3.7(@types/react@18.2.47)
'@radix-ui/react-popper@1.2.7(@types/react-dom@18.3.7(@types/react@18.2.69))(@types/react@18.2.69)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)':
dependencies:
@ -12501,7 +12501,7 @@ snapshots:
react-dom: 18.3.1(react@18.3.1)
optionalDependencies:
'@types/react': 18.2.47
'@types/react-dom': 18.3.7(@types/react@18.2.69)
'@types/react-dom': 18.3.7(@types/react@18.2.47)
'@radix-ui/react-portal@1.1.9(@types/react-dom@18.3.7(@types/react@18.2.69))(@types/react@18.2.69)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)':
dependencies:
@ -12529,7 +12529,7 @@ snapshots:
react-dom: 18.3.1(react@18.3.1)
optionalDependencies:
'@types/react': 18.2.47
'@types/react-dom': 18.3.7(@types/react@18.2.69)
'@types/react-dom': 18.3.7(@types/react@18.2.47)
'@radix-ui/react-presence@1.1.4(@types/react-dom@18.3.7(@types/react@18.2.69))(@types/react@18.2.69)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)':
dependencies:
@ -12555,7 +12555,7 @@ snapshots:
react-dom: 18.3.1(react@18.3.1)
optionalDependencies:
'@types/react': 18.2.47
'@types/react-dom': 18.3.7(@types/react@18.2.69)
'@types/react-dom': 18.3.7(@types/react@18.2.47)
'@radix-ui/react-primitive@2.1.3(@types/react-dom@18.3.7(@types/react@18.2.69))(@types/react@18.2.69)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)':
dependencies:
@ -12581,7 +12581,7 @@ snapshots:
react-dom: 18.3.1(react@18.3.1)
optionalDependencies:
'@types/react': 18.2.47
'@types/react-dom': 18.3.7(@types/react@18.2.69)
'@types/react-dom': 18.3.7(@types/react@18.2.47)
'@radix-ui/react-roving-focus@1.1.10(@types/react-dom@18.3.7(@types/react@18.2.69))(@types/react@18.2.69)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)':
dependencies:
@ -12747,7 +12747,7 @@ snapshots:
react-dom: 18.3.1(react@18.3.1)
optionalDependencies:
'@types/react': 18.2.47
'@types/react-dom': 18.3.7(@types/react@18.2.69)
'@types/react-dom': 18.3.7(@types/react@18.2.47)
'@radix-ui/react-toggle@1.1.0(@types/react-dom@18.3.7(@types/react@18.2.47))(@types/react@18.2.47)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)':
dependencies:
@ -12758,7 +12758,7 @@ snapshots:
react-dom: 18.3.1(react@18.3.1)
optionalDependencies:
'@types/react': 18.2.47
'@types/react-dom': 18.3.7(@types/react@18.2.69)
'@types/react-dom': 18.3.7(@types/react@18.2.47)
'@radix-ui/react-tooltip@1.1.1(@types/react-dom@18.3.7(@types/react@18.2.47))(@types/react@18.2.47)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)':
dependencies:
@ -12778,7 +12778,7 @@ snapshots:
react-dom: 18.3.1(react@18.3.1)
optionalDependencies:
'@types/react': 18.2.47
'@types/react-dom': 18.3.7(@types/react@18.2.69)
'@types/react-dom': 18.3.7(@types/react@18.2.47)
'@radix-ui/react-tooltip@1.2.7(@types/react-dom@18.3.7(@types/react@18.2.69))(@types/react@18.2.69)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)':
dependencies:
@ -12930,7 +12930,7 @@ snapshots:
react-dom: 18.3.1(react@18.3.1)
optionalDependencies:
'@types/react': 18.2.47
'@types/react-dom': 18.3.7(@types/react@18.2.69)
'@types/react-dom': 18.3.7(@types/react@18.2.47)
'@radix-ui/react-visually-hidden@1.2.3(@types/react-dom@18.3.7(@types/react@18.2.69))(@types/react@18.2.69)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)':
dependencies:
@ -13082,7 +13082,7 @@ snapshots:
transitivePeerDependencies:
- encoding
'@remix-run/dev@2.16.7(@remix-run/react@2.16.7(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.8.3))(@remix-run/serve@2.16.7(typescript@5.8.3))(@types/node@22.16.0)(jiti@2.4.2)(lightningcss@1.30.1)(terser@5.42.0)(typescript@5.8.3)(vite@6.3.5(@types/node@22.16.0)(jiti@2.4.2)(lightningcss@1.30.1)(terser@5.42.0)(yaml@2.8.0))(yaml@2.8.0)':
'@remix-run/dev@2.16.7(@remix-run/react@2.16.7(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.8.3))(@remix-run/serve@2.16.7(typescript@5.8.3))(@types/node@24.0.0)(jiti@2.4.2)(lightningcss@1.30.1)(terser@5.42.0)(typescript@5.8.3)(vite@6.3.5(@types/node@24.0.0)(jiti@2.4.2)(lightningcss@1.30.1)(terser@5.42.0)(yaml@2.8.0))(yaml@2.8.0)':
dependencies:
'@babel/core': 7.27.4
'@babel/generator': 7.27.5
@ -13099,7 +13099,7 @@ snapshots:
'@remix-run/router': 1.23.0
'@remix-run/server-runtime': 2.16.7(typescript@5.8.3)
'@types/mdx': 2.0.13
'@vanilla-extract/integration': 6.5.0(@types/node@22.16.0)(lightningcss@1.30.1)(terser@5.42.0)
'@vanilla-extract/integration': 6.5.0(@types/node@24.0.0)(lightningcss@1.30.1)(terser@5.42.0)
arg: 5.0.2
cacache: 17.1.4
chalk: 4.1.2
@ -13139,12 +13139,12 @@ snapshots:
tar-fs: 2.1.3
tsconfig-paths: 4.2.0
valibot: 0.41.0(typescript@5.8.3)
vite-node: 3.2.3(@types/node@22.16.0)(jiti@2.4.2)(lightningcss@1.30.1)(terser@5.42.0)(yaml@2.8.0)
vite-node: 3.2.3(@types/node@24.0.0)(jiti@2.4.2)(lightningcss@1.30.1)(terser@5.42.0)(yaml@2.8.0)
ws: 7.5.10
optionalDependencies:
'@remix-run/serve': 2.16.7(typescript@5.8.3)
typescript: 5.8.3
vite: 6.3.5(@types/node@22.16.0)(jiti@2.4.2)(lightningcss@1.30.1)(terser@5.42.0)(yaml@2.8.0)
vite: 6.3.5(@types/node@24.0.0)(jiti@2.4.2)(lightningcss@1.30.1)(terser@5.42.0)(yaml@2.8.0)
transitivePeerDependencies:
- '@types/node'
- babel-plugin-macros
@ -13883,12 +13883,12 @@ snapshots:
postcss-selector-parser: 6.0.10
tailwindcss: 4.1.7
'@tailwindcss/vite@4.1.9(vite@6.3.5(@types/node@22.16.0)(jiti@2.4.2)(lightningcss@1.30.1)(terser@5.42.0)(yaml@2.8.0))':
'@tailwindcss/vite@4.1.9(vite@6.3.5(@types/node@24.0.0)(jiti@2.4.2)(lightningcss@1.30.1)(terser@5.42.0)(yaml@2.8.0))':
dependencies:
'@tailwindcss/node': 4.1.9
'@tailwindcss/oxide': 4.1.9
tailwindcss: 4.1.9
vite: 6.3.5(@types/node@22.16.0)(jiti@2.4.2)(lightningcss@1.30.1)(terser@5.42.0)(yaml@2.8.0)
vite: 6.3.5(@types/node@24.0.0)(jiti@2.4.2)(lightningcss@1.30.1)(terser@5.42.0)(yaml@2.8.0)
'@tanstack/react-table@8.21.3(react-dom@18.3.1(react@18.3.1))(react@18.3.1)':
dependencies:
@ -14497,6 +14497,10 @@ snapshots:
'@types/range-parser@1.2.7': {}
'@types/react-dom@18.3.7(@types/react@18.2.47)':
dependencies:
'@types/react': 18.2.47
'@types/react-dom@18.3.7(@types/react@18.2.69)':
dependencies:
'@types/react': 18.2.69
@ -14816,7 +14820,7 @@ snapshots:
transitivePeerDependencies:
- babel-plugin-macros
'@vanilla-extract/integration@6.5.0(@types/node@22.16.0)(lightningcss@1.30.1)(terser@5.42.0)':
'@vanilla-extract/integration@6.5.0(@types/node@24.0.0)(lightningcss@1.30.1)(terser@5.42.0)':
dependencies:
'@babel/core': 7.27.4
'@babel/plugin-syntax-typescript': 7.27.1(@babel/core@7.27.4)
@ -14829,8 +14833,8 @@ snapshots:
lodash: 4.17.21
mlly: 1.7.4
outdent: 0.8.0
vite: 5.4.19(@types/node@22.16.0)(lightningcss@1.30.1)(terser@5.42.0)
vite-node: 1.6.1(@types/node@22.16.0)(lightningcss@1.30.1)(terser@5.42.0)
vite: 5.4.19(@types/node@24.0.0)(lightningcss@1.30.1)(terser@5.42.0)
vite-node: 1.6.1(@types/node@24.0.0)(lightningcss@1.30.1)(terser@5.42.0)
transitivePeerDependencies:
- '@types/node'
- babel-plugin-macros
@ -16727,11 +16731,11 @@ snapshots:
run-exclusive: 2.2.19
tsafe: 1.8.5
exa-js@1.8.20(encoding@0.1.13)(ws@8.17.1):
exa-js@1.8.20(encoding@0.1.13):
dependencies:
cross-fetch: 4.1.0(encoding@0.1.13)
dotenv: 16.4.7
openai: 5.9.0(ws@8.17.1)(zod@3.23.8)
openai: 5.9.0(zod@3.23.8)
zod: 3.23.8
zod-to-json-schema: 3.24.5(zod@3.23.8)
transitivePeerDependencies:
@ -18939,9 +18943,8 @@ snapshots:
dependencies:
mimic-fn: 4.0.0
openai@5.9.0(ws@8.17.1)(zod@3.23.8):
openai@5.9.0(zod@3.23.8):
optionalDependencies:
ws: 8.17.1
zod: 3.23.8
optionator@0.9.4:
@ -19614,7 +19617,7 @@ snapshots:
'@radix-ui/react-tooltip': 1.1.1(@types/react-dom@18.3.7(@types/react@18.2.47))(@types/react@18.2.47)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
'@swc/core': 1.3.101(@swc/helpers@0.5.17)
'@types/react': 18.2.47
'@types/react-dom': 18.3.7(@types/react@18.2.69)
'@types/react-dom': 18.3.7(@types/react@18.2.47)
'@types/webpack': 5.28.5(@swc/core@1.3.101(@swc/helpers@0.5.17))(esbuild@0.19.11)
autoprefixer: 10.4.14(postcss@8.4.38)
chalk: 4.1.2
@ -20903,7 +20906,7 @@ snapshots:
tslib@2.8.1: {}
tsup@8.5.0(@swc/core@1.3.101(@swc/helpers@0.5.17))(jiti@2.4.2)(postcss@8.5.5)(typescript@5.8.3)(yaml@2.8.0):
tsup@8.5.0(@swc/core@1.3.101)(jiti@2.4.2)(postcss@8.5.5)(typescript@5.8.3)(yaml@2.8.0):
dependencies:
bundle-require: 5.1.0(esbuild@0.25.5)
cac: 6.7.14
@ -21297,13 +21300,13 @@ snapshots:
'@types/unist': 3.0.3
vfile-message: 4.0.2
vite-node@1.6.1(@types/node@22.16.0)(lightningcss@1.30.1)(terser@5.42.0):
vite-node@1.6.1(@types/node@24.0.0)(lightningcss@1.30.1)(terser@5.42.0):
dependencies:
cac: 6.7.14
debug: 4.4.1
pathe: 1.1.2
picocolors: 1.1.1
vite: 5.4.19(@types/node@22.16.0)(lightningcss@1.30.1)(terser@5.42.0)
vite: 5.4.19(@types/node@24.0.0)(lightningcss@1.30.1)(terser@5.42.0)
transitivePeerDependencies:
- '@types/node'
- less
@ -21315,13 +21318,13 @@ snapshots:
- supports-color
- terser
vite-node@3.2.3(@types/node@22.16.0)(jiti@2.4.2)(lightningcss@1.30.1)(terser@5.42.0)(yaml@2.8.0):
vite-node@3.2.3(@types/node@24.0.0)(jiti@2.4.2)(lightningcss@1.30.1)(terser@5.42.0)(yaml@2.8.0):
dependencies:
cac: 6.7.14
debug: 4.4.1
es-module-lexer: 1.7.0
pathe: 2.0.3
vite: 6.3.5(@types/node@22.16.0)(jiti@2.4.2)(lightningcss@1.30.1)(terser@5.42.0)(yaml@2.8.0)
vite: 6.3.5(@types/node@24.0.0)(jiti@2.4.2)(lightningcss@1.30.1)(terser@5.42.0)(yaml@2.8.0)
transitivePeerDependencies:
- '@types/node'
- jiti
@ -21336,29 +21339,29 @@ snapshots:
- tsx
- yaml
vite-tsconfig-paths@4.3.2(typescript@5.8.3)(vite@6.3.5(@types/node@22.16.0)(jiti@2.4.2)(lightningcss@1.30.1)(terser@5.42.0)(yaml@2.8.0)):
vite-tsconfig-paths@4.3.2(typescript@5.8.3)(vite@6.3.5(@types/node@24.0.0)(jiti@2.4.2)(lightningcss@1.30.1)(terser@5.42.0)(yaml@2.8.0)):
dependencies:
debug: 4.4.1
globrex: 0.1.2
tsconfck: 3.1.6(typescript@5.8.3)
optionalDependencies:
vite: 6.3.5(@types/node@22.16.0)(jiti@2.4.2)(lightningcss@1.30.1)(terser@5.42.0)(yaml@2.8.0)
vite: 6.3.5(@types/node@24.0.0)(jiti@2.4.2)(lightningcss@1.30.1)(terser@5.42.0)(yaml@2.8.0)
transitivePeerDependencies:
- supports-color
- typescript
vite@5.4.19(@types/node@22.16.0)(lightningcss@1.30.1)(terser@5.42.0):
vite@5.4.19(@types/node@24.0.0)(lightningcss@1.30.1)(terser@5.42.0):
dependencies:
esbuild: 0.21.5
postcss: 8.5.5
rollup: 4.43.0
optionalDependencies:
'@types/node': 22.16.0
'@types/node': 24.0.0
fsevents: 2.3.3
lightningcss: 1.30.1
terser: 5.42.0
vite@6.3.5(@types/node@22.16.0)(jiti@2.4.2)(lightningcss@1.30.1)(terser@5.42.0)(yaml@2.8.0):
vite@6.3.5(@types/node@24.0.0)(jiti@2.4.2)(lightningcss@1.30.1)(terser@5.42.0)(yaml@2.8.0):
dependencies:
esbuild: 0.25.5
fdir: 6.4.6(picomatch@4.0.2)
@ -21367,7 +21370,7 @@ snapshots:
rollup: 4.43.0
tinyglobby: 0.2.14
optionalDependencies:
'@types/node': 22.16.0
'@types/node': 24.0.0
fsevents: 2.3.3
jiti: 2.4.2
lightningcss: 1.30.1