From aa7ae14f954df2a86e21f19ba6b724bfad279d6d Mon Sep 17 00:00:00 2001 From: Manoj K Date: Thu, 17 Jul 2025 21:44:49 +0530 Subject: [PATCH] Fix: activity flow and invalidation in knowledge graph --- apps/webapp/app/lib/model.server.ts | 67 +++++----- apps/webapp/app/routes/api.v1.activity.tsx | 6 - .../app/services/graphModels/episode.ts | 29 +++++ .../app/services/knowledgeGraph.server.ts | 115 ++++++++++++++---- .../webapp/app/services/prompts/statements.ts | 19 ++- .../trigger/integrations/integration-run.ts | 1 - .../webapp/app/trigger/utils/message-utils.ts | 39 ++++-- apps/webapp/app/utils/presets/nodes.ts | 13 ++ integrations/linear/src/schedule.ts | 23 ++-- pnpm-lock.yaml | 97 ++++++++------- 10 files changed, 277 insertions(+), 132 deletions(-) diff --git a/apps/webapp/app/lib/model.server.ts b/apps/webapp/app/lib/model.server.ts index 8cb1ab1..3e0b29b 100644 --- a/apps/webapp/app/lib/model.server.ts +++ b/apps/webapp/app/lib/model.server.ts @@ -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; } diff --git a/apps/webapp/app/routes/api.v1.activity.tsx b/apps/webapp/app/routes/api.v1.activity.tsx index 2ef4116..a741bdf 100644 --- a/apps/webapp/app/routes/api.v1.activity.tsx +++ b/apps/webapp/app/routes/api.v1.activity.tsx @@ -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( diff --git a/apps/webapp/app/services/graphModels/episode.ts b/apps/webapp/app/services/graphModels/episode.ts index 6396197..450e33a 100644 --- a/apps/webapp/app/services/graphModels/episode.ts +++ b/apps/webapp/app/services/graphModels/episode.ts @@ -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, + }; + }); +} diff --git a/apps/webapp/app/services/knowledgeGraph.server.ts b/apps/webapp/app/services/knowledgeGraph.server.ts index 46fac96..109e018 100644 --- a/apps/webapp/app/services/knowledgeGraph.server.ts +++ b/apps/webapp/app/services/knowledgeGraph.server.ts @@ -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 { // 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 { + ): 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(); + 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, diff --git a/apps/webapp/app/services/prompts/statements.ts b/apps/webapp/app/services/prompts/statements.ts index f5daec3..38c5f07 100644 --- a/apps/webapp/app/services/prompts/statements.ts +++ b/apps/webapp/app/services/prompts/statements.ts @@ -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)} -${JSON.stringify(context.entities, null, 2)} + +${JSON.stringify(context.entities.primary, null, 2)} + + + +${JSON.stringify(context.entities.expanded, null, 2)} + `, }, diff --git a/apps/webapp/app/trigger/integrations/integration-run.ts b/apps/webapp/app/trigger/integrations/integration-run.ts index 5893993..bda1d9b 100644 --- a/apps/webapp/app/trigger/integrations/integration-run.ts +++ b/apps/webapp/app/trigger/integrations/integration-run.ts @@ -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}`); } diff --git a/apps/webapp/app/trigger/utils/message-utils.ts b/apps/webapp/app/trigger/utils/message-utils.ts index f10966a..73eda49 100644 --- a/apps/webapp/app/trigger/utils/message-utils.ts +++ b/apps/webapp/app/trigger/utils/message-utils.ts @@ -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, }; }), - }); + ); }; diff --git a/apps/webapp/app/utils/presets/nodes.ts b/apps/webapp/app/utils/presets/nodes.ts index a4806c6..46e0659 100644 --- a/apps/webapp/app/utils/presets/nodes.ts +++ b/apps/webapp/app/utils/presets/nodes.ts @@ -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: { diff --git a/integrations/linear/src/schedule.ts b/integrations/linear/src/schedule.ts index ae49d38..ba5f456 100644 --- a/integrations/linear/src/schedule.ts +++ b/integrations/linear/src/schedule.ts @@ -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); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index cc383f0..e07f98a 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -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