fix: add cascade to all files, return 401 when session is cleared

This commit is contained in:
Harshith Mullapudi 2025-10-24 22:10:41 +05:30
parent 6f1037e8e1
commit b78713df41
11 changed files with 108 additions and 44 deletions

View File

@ -284,33 +284,37 @@ export const Graph = forwardRef<GraphRef, GraphProps>(
// More nodes = need more space to prevent overcrowding
let scalingRatio: number;
if (nodeCount < 10) {
scalingRatio = 15; // Tight for small graphs
scalingRatio = 20; // Slightly wider for small graphs
} else if (nodeCount < 50) {
scalingRatio = 20 + (nodeCount - 10) * 0.5; // Gradual increase
scalingRatio = 30 + (nodeCount - 10) * 1.0; // Faster increase
} else if (nodeCount < 200) {
scalingRatio = 40 + (nodeCount - 50) * 0.2; // Slower increase
scalingRatio = 70 + (nodeCount - 50) * 0.5; // More spread
} else if (nodeCount < 500) {
scalingRatio = 145 + (nodeCount - 200) * 0.3; // Continue spreading
} else {
scalingRatio = Math.min(80, 70 + (nodeCount - 200) * 0.05); // Cap at 80
scalingRatio = Math.min(300, 235 + (nodeCount - 500) * 0.1); // Cap at 300
}
// Calculate optimal gravity based on density and node count
let gravity: number;
if (density > 0.3) {
// Dense graphs need less gravity to prevent overcrowding
gravity = 1 + density * 2;
gravity = 0.5 + density * 1.5;
} else if (density > 0.1) {
// Medium density graphs
gravity = 3 + density * 5;
gravity = 2 + density * 3;
} else {
// Sparse graphs need more gravity to keep components together
gravity = Math.min(8, 5 + (1 - density) * 3);
gravity = Math.min(6, 4 + (1 - density) * 2);
}
// Adjust gravity based on node count
// Adjust gravity based on node count - more aggressive reduction for large graphs
if (nodeCount < 20) {
gravity *= 1.5; // Smaller graphs benefit from stronger gravity
} else if (nodeCount > 100) {
gravity *= 0.8; // Larger graphs need gentler gravity
gravity *= 0.5; // Larger graphs need much gentler gravity
} else if (nodeCount > 200) {
gravity *= 0.3; // Very large graphs need very gentle gravity
}
// Calculate iterations based on complexity
@ -374,10 +378,10 @@ export const Graph = forwardRef<GraphRef, GraphProps>(
settings: {
...settings,
barnesHutOptimize: true,
strongGravityMode: true,
strongGravityMode: false, // Disable strong gravity for more spread
gravity: optimalParams.gravity,
scalingRatio: optimalParams.scalingRatio,
slowDown: 3,
slowDown: 1.5, // Reduced slowDown for better spreading
},
});

View File

@ -2,12 +2,9 @@ import { Prisma, PrismaClient } from "@core/database";
import invariant from "tiny-invariant";
import { z } from "zod";
import { env } from "./env.server";
import { logger } from "./services/logger.service";
import { isValidDatabaseUrl } from "./utils/db";
import { singleton } from "./utils/singleton";
import { type Span } from "@opentelemetry/api";
export { Prisma };
export const prisma = singleton("prisma", getClient);

View File

@ -113,17 +113,25 @@ export const getClusteredGraphData = async (userId: string) => {
const session = driver.session();
try {
// Get the simplified graph structure: Episode, Subject, Object with Predicate as edge
// Only include entities that are connected to more than 1 episode
const result = await session.run(
`// Get all statements with their episode and entity connections
MATCH (e:Episode)-[:HAS_PROVENANCE]->(s:Statement)
WHERE s.userId = $userId
`// Find entities connected to more than 1 episode
MATCH (e:Episode)-[:HAS_PROVENANCE]->(s:Statement {userId: $userId})
MATCH (s)-[:HAS_SUBJECT|HAS_OBJECT|HAS_PREDICATE]->(ent:Entity)
WITH ent, count(DISTINCT e) as episodeCount
WHERE episodeCount > 1
WITH collect(ent.uuid) as validEntityUuids
// Get subject and object entities
// Get statements where all entities are in the valid set
MATCH (e:Episode)-[:HAS_PROVENANCE]->(s:Statement {userId: $userId})
MATCH (s)-[:HAS_SUBJECT]->(subj:Entity)
WHERE subj.uuid IN validEntityUuids
MATCH (s)-[:HAS_PREDICATE]->(pred:Entity)
WHERE pred.uuid IN validEntityUuids
MATCH (s)-[:HAS_OBJECT]->(obj:Entity)
WHERE obj.uuid IN validEntityUuids
// Return Episode, Subject, and Object as nodes with Predicate as edge label
// Build relationships
WITH e, s, subj, pred, obj
UNWIND [
// Episode -> Subject

View File

@ -1,5 +1,4 @@
import { json, type ActionFunctionArgs } from "@remix-run/node";
import { requireUser } from "~/services/session.server";
import { json } from "@remix-run/node";
import { deleteUser, getUserById } from "~/models/user.server";
import { sessionStorage } from "~/services/sessionStorage.server";
import { cancelSubscriptionImmediately } from "~/services/stripe.server";

View File

@ -110,7 +110,7 @@ export default function SingleConversation() {
}
}, [run]);
const getConversations = () => {
const conversations = React.useMemo(() => {
const lastConversationHistoryId =
conversationResponse?.conversationHistoryId;
@ -124,15 +124,17 @@ export default function SingleConversation() {
);
// Filter out any conversation history items that come after the lastConversationHistoryId
const filteredConversationHistory = lastConversationHistoryId
return lastConversationHistoryId
? sortedConversationHistory.filter((_ch, currentIndex: number) => {
return currentIndex <= lastIndex;
})
: sortedConversationHistory;
}, [conversationResponse, conversationHistory]);
const getConversations = () => {
return (
<>
{filteredConversationHistory.map((ch: ConversationHistory) => {
{conversations.map((ch: ConversationHistory) => {
return <ConversationItem key={ch.id} conversationHistory={ch} />;
})}
</>

View File

@ -266,7 +266,7 @@ export const handleSessionRequest = async (
await transport.handleRequest(req, res);
} else {
res.status(400).send("Invalid or missing session ID");
res.status(401).send("Invalid or missing session ID");
return;
}
} else {

View File

@ -153,7 +153,11 @@ export const ingestTask = task({
// Handle space assignment after successful ingestion
try {
// If spaceIds were explicitly provided, immediately assign the episode to those spaces
if (episodeBody.spaceIds && episodeBody.spaceIds.length > 0 && episodeDetails.episodeUuid) {
if (
episodeBody.spaceIds &&
episodeBody.spaceIds.length > 0 &&
episodeDetails.episodeUuid
) {
logger.info(`Assigning episode to explicitly provided spaces`, {
userId: payload.userId,
episodeId: episodeDetails.episodeUuid,
@ -205,7 +209,10 @@ export const ingestTask = task({
// Auto-trigger session compaction if episode has sessionId
try {
if (episodeBody.sessionId && currentStatus === IngestionStatus.COMPLETED) {
if (
episodeBody.sessionId &&
currentStatus === IngestionStatus.COMPLETED
) {
logger.info(`Checking if session compaction should be triggered`, {
userId: payload.userId,
sessionId: episodeBody.sessionId,

View File

@ -442,7 +442,7 @@ async function handleGetSpace(args: any) {
const spaceDetails = {
id: space.id,
name: space.name,
summary: space.summary,
description: space.description,
};
return {

View File

@ -20,7 +20,7 @@ model Activity {
// Used to link the task or activity to external apps
sourceURL String?
integrationAccount IntegrationAccount? @relation(fields: [integrationAccountId], references: [id])
integrationAccount IntegrationAccount? @relation(fields: [integrationAccountId], references: [id], onDelete: Cascade)
integrationAccountId String?
rejectionReason String?
@ -83,7 +83,7 @@ model ConversationExecutionStep {
metadata Json? @default("{}")
conversationHistory ConversationHistory @relation(fields: [conversationHistoryId], references: [id])
conversationHistory ConversationHistory @relation(fields: [conversationHistoryId], references: [id], onDelete: Cascade)
conversationHistoryId String
}
@ -96,7 +96,7 @@ model ConversationHistory {
message String
userType UserType
activity Activity? @relation(fields: [activityId], references: [id])
activity Activity? @relation(fields: [activityId], references: [id], onDelete: Cascade)
activityId String?
context Json?
@ -105,7 +105,7 @@ model ConversationHistory {
user User? @relation(fields: [userId], references: [id], onDelete: Cascade)
userId String?
conversation Conversation @relation(fields: [conversationId], references: [id])
conversation Conversation @relation(fields: [conversationId], references: [id], onDelete: Cascade)
conversationId String
ConversationExecutionStep ConversationExecutionStep[]
}
@ -124,7 +124,7 @@ model IngestionQueue {
workspaceId String
workspace Workspace @relation(fields: [workspaceId], references: [id], onDelete: Cascade)
activity Activity? @relation(fields: [activityId], references: [id])
activity Activity? @relation(fields: [activityId], references: [id], onDelete: Cascade)
activityId String?
// Error handling
@ -168,7 +168,7 @@ model IntegrationAccount {
integratedBy User @relation(references: [id], fields: [integratedById], onDelete: Cascade)
integratedById String
integrationDefinition IntegrationDefinitionV2 @relation(references: [id], fields: [integrationDefinitionId])
integrationDefinition IntegrationDefinitionV2 @relation(references: [id], fields: [integrationDefinitionId], onDelete: Cascade)
integrationDefinitionId String
workspace Workspace @relation(references: [id], fields: [workspaceId], onDelete: Cascade)
workspaceId String
@ -304,7 +304,7 @@ model OAuthClient {
workspaceId String?
// Created by user (for audit trail)
createdBy User? @relation(fields: [createdById], references: [id], onDelete: SetNull)
createdBy User? @relation(fields: [createdById], references: [id], onDelete: Cascade)
createdById String?
// Relations
@ -594,7 +594,7 @@ model WebhookConfiguration {
secret String?
isActive Boolean @default(true)
eventTypes String[] // List of event types this webhook is interested in, e.g. ["activity.created"]
user User? @relation(fields: [userId], references: [id])
user User? @relation(fields: [userId], references: [id], onDelete: Cascade)
userId String?
workspace Workspace? @relation(fields: [workspaceId], references: [id], onDelete: Cascade)
workspaceId String?

View File

@ -0,0 +1,47 @@
-- DropForeignKey
ALTER TABLE "Activity" DROP CONSTRAINT "Activity_integrationAccountId_fkey";
-- DropForeignKey
ALTER TABLE "ConversationExecutionStep" DROP CONSTRAINT "ConversationExecutionStep_conversationHistoryId_fkey";
-- DropForeignKey
ALTER TABLE "ConversationHistory" DROP CONSTRAINT "ConversationHistory_activityId_fkey";
-- DropForeignKey
ALTER TABLE "ConversationHistory" DROP CONSTRAINT "ConversationHistory_conversationId_fkey";
-- DropForeignKey
ALTER TABLE "IngestionQueue" DROP CONSTRAINT "IngestionQueue_activityId_fkey";
-- DropForeignKey
ALTER TABLE "IntegrationAccount" DROP CONSTRAINT "IntegrationAccount_integrationDefinitionId_fkey";
-- DropForeignKey
ALTER TABLE "OAuthClient" DROP CONSTRAINT "OAuthClient_createdById_fkey";
-- DropForeignKey
ALTER TABLE "WebhookConfiguration" DROP CONSTRAINT "WebhookConfiguration_userId_fkey";
-- AddForeignKey
ALTER TABLE "Activity" ADD CONSTRAINT "Activity_integrationAccountId_fkey" FOREIGN KEY ("integrationAccountId") REFERENCES "IntegrationAccount"("id") ON DELETE CASCADE ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "ConversationExecutionStep" ADD CONSTRAINT "ConversationExecutionStep_conversationHistoryId_fkey" FOREIGN KEY ("conversationHistoryId") REFERENCES "ConversationHistory"("id") ON DELETE CASCADE ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "ConversationHistory" ADD CONSTRAINT "ConversationHistory_activityId_fkey" FOREIGN KEY ("activityId") REFERENCES "Activity"("id") ON DELETE CASCADE ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "ConversationHistory" ADD CONSTRAINT "ConversationHistory_conversationId_fkey" FOREIGN KEY ("conversationId") REFERENCES "Conversation"("id") ON DELETE CASCADE ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "IngestionQueue" ADD CONSTRAINT "IngestionQueue_activityId_fkey" FOREIGN KEY ("activityId") REFERENCES "Activity"("id") ON DELETE CASCADE ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "IntegrationAccount" ADD CONSTRAINT "IntegrationAccount_integrationDefinitionId_fkey" FOREIGN KEY ("integrationDefinitionId") REFERENCES "IntegrationDefinitionV2"("id") ON DELETE CASCADE ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "OAuthClient" ADD CONSTRAINT "OAuthClient_createdById_fkey" FOREIGN KEY ("createdById") REFERENCES "User"("id") ON DELETE CASCADE ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "WebhookConfiguration" ADD CONSTRAINT "WebhookConfiguration_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE CASCADE ON UPDATE CASCADE;

View File

@ -20,7 +20,7 @@ model Activity {
// Used to link the task or activity to external apps
sourceURL String?
integrationAccount IntegrationAccount? @relation(fields: [integrationAccountId], references: [id])
integrationAccount IntegrationAccount? @relation(fields: [integrationAccountId], references: [id], onDelete: Cascade)
integrationAccountId String?
rejectionReason String?
@ -83,7 +83,7 @@ model ConversationExecutionStep {
metadata Json? @default("{}")
conversationHistory ConversationHistory @relation(fields: [conversationHistoryId], references: [id])
conversationHistory ConversationHistory @relation(fields: [conversationHistoryId], references: [id], onDelete: Cascade)
conversationHistoryId String
}
@ -96,7 +96,7 @@ model ConversationHistory {
message String
userType UserType
activity Activity? @relation(fields: [activityId], references: [id])
activity Activity? @relation(fields: [activityId], references: [id], onDelete: Cascade)
activityId String?
context Json?
@ -105,7 +105,7 @@ model ConversationHistory {
user User? @relation(fields: [userId], references: [id], onDelete: Cascade)
userId String?
conversation Conversation @relation(fields: [conversationId], references: [id])
conversation Conversation @relation(fields: [conversationId], references: [id], onDelete: Cascade)
conversationId String
ConversationExecutionStep ConversationExecutionStep[]
}
@ -124,7 +124,7 @@ model IngestionQueue {
workspaceId String
workspace Workspace @relation(fields: [workspaceId], references: [id], onDelete: Cascade)
activity Activity? @relation(fields: [activityId], references: [id])
activity Activity? @relation(fields: [activityId], references: [id], onDelete: Cascade)
activityId String?
// Error handling
@ -168,7 +168,7 @@ model IntegrationAccount {
integratedBy User @relation(references: [id], fields: [integratedById], onDelete: Cascade)
integratedById String
integrationDefinition IntegrationDefinitionV2 @relation(references: [id], fields: [integrationDefinitionId])
integrationDefinition IntegrationDefinitionV2 @relation(references: [id], fields: [integrationDefinitionId], onDelete: Cascade)
integrationDefinitionId String
workspace Workspace @relation(references: [id], fields: [workspaceId], onDelete: Cascade)
workspaceId String
@ -304,7 +304,7 @@ model OAuthClient {
workspaceId String?
// Created by user (for audit trail)
createdBy User? @relation(fields: [createdById], references: [id], onDelete: SetNull)
createdBy User? @relation(fields: [createdById], references: [id], onDelete: Cascade)
createdById String?
// Relations
@ -594,7 +594,7 @@ model WebhookConfiguration {
secret String?
isActive Boolean @default(true)
eventTypes String[] // List of event types this webhook is interested in, e.g. ["activity.created"]
user User? @relation(fields: [userId], references: [id])
user User? @relation(fields: [userId], references: [id], onDelete: Cascade)
userId String?
workspace Workspace? @relation(fields: [workspaceId], references: [id], onDelete: Cascade)
workspaceId String?