Fix: clustering UI

This commit is contained in:
Harshith Mullapudi 2025-08-04 12:26:26 +05:30
parent 7a890d4e13
commit c9fbb0375b
10 changed files with 112 additions and 306 deletions

View File

@ -62,7 +62,6 @@
"clean": "rimraf dist .tshy .tshy-build .turbo",
"typecheck": "tsc -p tsconfig.src.json --noEmit",
"build": "tshy",
"dev": "tshy --watch",
"test": "vitest",
"test:e2e": "vitest --run -c ./e2e/vitest.config.ts"
},

View File

@ -9,6 +9,7 @@ const EnvironmentSchema = z.object({
z.literal("production"),
z.literal("test"),
]),
POSTGRES_DB: z.string(),
DATABASE_URL: z
.string()
.refine(

View File

@ -1,17 +1,22 @@
import { json, type ActionFunctionArgs, type LoaderFunctionArgs } from "@remix-run/node";
import { json } from "@remix-run/node";
import { z } from "zod";
import { logger } from "~/services/logger.service";
import { createActionApiRoute } from "~/services/routeBuilders/apiBuilder.server";
import {
createActionApiRoute,
createLoaderApiRoute,
} from "~/services/routeBuilders/apiBuilder.server";
import { ClusteringService } from "~/services/clustering.server";
const clusteringService = new ClusteringService();
const { action, loader } = createActionApiRoute(
const { action } = createActionApiRoute(
{
body: z.object({
mode: z.enum(['auto', 'incremental', 'complete']).optional().default('auto'),
forceComplete: z.boolean().optional().default(false)
mode: z
.enum(["auto", "incremental", "complete"])
.optional()
.default("auto"),
forceComplete: z.boolean().optional().default(false),
}),
allowJWT: true,
authorization: {
@ -20,52 +25,73 @@ const { action, loader } = createActionApiRoute(
corsStrategy: "all",
},
async ({ body, authentication, request }) => {
console.log(request.method, "asd");
try {
if (request.method === "POST") {
let result;
switch (body.mode) {
case 'incremental':
result = await clusteringService.performIncrementalClustering(authentication.userId);
case "incremental":
result = await clusteringService.performIncrementalClustering(
authentication.userId,
);
break;
case 'complete':
result = await clusteringService.performCompleteClustering(authentication.userId);
case "complete":
result = await clusteringService.performCompleteClustering(
authentication.userId,
);
break;
case 'auto':
case "auto":
default:
result = await clusteringService.performClustering(authentication.userId, body.forceComplete);
result = await clusteringService.performClustering(
authentication.userId,
body.forceComplete,
);
break;
}
return json({
success: true,
data: result
data: result,
});
} else if (request.method === "GET") {
const clusters = await clusteringService.getClusters(authentication.userId);
const clusters = await clusteringService.getClusters(
authentication.userId,
);
return json({
success: true,
data: clusters
data: clusters,
});
}
return json(
{ success: false, error: "Method not allowed" },
{ status: 405 }
{ status: 405 },
);
} catch (error) {
logger.error("Error in clustering action:", { error });
return json(
{
success: false,
error: error instanceof Error ? error.message : "Unknown error"
{
success: false,
error: error instanceof Error ? error.message : "Unknown error",
},
{ status: 500 }
{ status: 500 },
);
}
},
);
export { action, loader };
const loader = createLoaderApiRoute(
{
allowJWT: true,
findResource: async () => 1,
},
async ({ authentication }) => {
const clusters = await clusteringService.getClusters(authentication.userId);
return json({
success: true,
data: clusters,
});
},
);
export { action, loader };

View File

@ -18,36 +18,31 @@ export default function Dashboard() {
// State for nodeLinks and loading
const [nodeLinks, setNodeLinks] = useState<any[] | null>(null);
const [loading, setLoading] = useState(true);
const [loading, setLoading] = useState(false);
useEffect(() => {
let cancelled = false;
async function fetchNodeLinks() {
setLoading(true);
try {
const res = await fetch(
"/node-links?userId=" +
encodeURIComponent("cmc0x85jv0000nu1wiu1yla73"),
);
if (!res.ok) throw new Error("Failed to fetch node links");
const data = await res.json();
if (!cancelled) {
setNodeLinks(data);
setLoading(false);
}
} catch (e) {
if (!cancelled) {
setNodeLinks([]);
setLoading(false);
}
}
if (!loading && userId) {
fetchNodeLinks();
}
fetchNodeLinks();
return () => {
cancelled = true;
};
}, [userId]);
const fetchNodeLinks = async () => {
setLoading(true);
try {
const res = await fetch(
"/node-links?userId=" + encodeURIComponent(userId),
);
if (!res.ok) throw new Error("Failed to fetch node links");
const data = await res.json();
setNodeLinks(data);
setLoading(false);
} catch (e) {
setNodeLinks([]);
setLoading(false);
}
};
return (
<>
<PageHeader title="Memory graph" />

View File

@ -25,6 +25,7 @@ import { requireUserId } from "~/services/session.server";
import { updateUser } from "~/models/user.server";
import { Copy, Check } from "lucide-react";
import { addToQueue } from "~/lib/ingest.server";
import { cn } from "~/lib/utils";
const ONBOARDING_STEP_COOKIE = "onboardingStep";
const onboardingStepCookie = createCookie(ONBOARDING_STEP_COOKIE, {
@ -108,6 +109,9 @@ export default function Onboarding() {
const navigate = useNavigate();
const [copied, setCopied] = useState(false);
const [selectedSource, setSelectedSource] = useState<
"Claude" | "Cursor" | "Other"
>("Claude");
const [form, fields] = useForm({
lastSubmission: lastSubmission as any,
@ -117,7 +121,12 @@ export default function Onboarding() {
},
});
const memoryUrl = "https://core.heysol.ai/api/v1/mcp/memory";
const getMemoryUrl = (source: "Claude" | "Cursor" | "Other") => {
const baseUrl = "https://core.heysol.ai/api/v1/mcp/memory";
return `${baseUrl}?Source=${source}`;
};
const memoryUrl = getMemoryUrl(selectedSource);
const copyToClipboard = async () => {
try {
@ -144,7 +153,25 @@ export default function Onboarding() {
<CardContent className="pt-2 text-base">
<div className="space-y-4">
<div>
<div className="space-y-3">
<div className="bg-grayAlpha-100 flex space-x-1 rounded-lg p-1">
{(["Claude", "Cursor", "Other"] as const).map((source) => (
<Button
key={source}
onClick={() => setSelectedSource(source)}
variant="ghost"
className={cn(
"flex-1 rounded-md px-3 py-1.5 transition-all",
selectedSource === source
? "bg-accent text-accent-foreground shadow-sm"
: "text-muted-foreground hover:text-foreground",
)}
>
{source}
</Button>
))}
</div>
<div className="bg-background-3 flex items-center rounded">
<Input
type="text"

View File

@ -1,6 +1,6 @@
export type AuthorizationAction = "read" | "write" | string; // Add more actions as needed
const ResourceTypes = ["spaces"] as const;
const ResourceTypes = ["clusters"] as const;
export type AuthorizationResources = {
[key in (typeof ResourceTypes)[number]]?: string | string[];

View File

@ -108,7 +108,7 @@ const Keys = [
export async function addEnvVariablesInTrigger() {
const {
APP_ORIGIN,
TRIGGER_DB,
POSTGRES_DB,
EMBEDDING_MODEL,
MODEL,
ENCRYPTION_KEY,
@ -121,7 +121,7 @@ export async function addEnvVariablesInTrigger() {
TRIGGER_SECRET_KEY,
} = env;
const DATABASE_URL = getDatabaseUrl(TRIGGER_DB);
const DATABASE_URL = getDatabaseUrl(POSTGRES_DB);
// Helper to replace 'localhost' with 'host.docker.internal'
function replaceLocalhost(val: string | undefined): string | undefined {

View File

@ -76,8 +76,13 @@ services:
image: neo4j:5
environment:
- NEO4J_AUTH=${NEO4J_AUTH}
- NEO4J_dbms_security_procedures_unrestricted=gds.*
- NEO4J_dbms_security_procedures_allowlist=gds.*
- NEO4J_dbms_security_procedures_unrestricted=gds.*,apoc.*
- NEO4J_dbms_security_procedures_allowlist=gds.*,apoc.*
- NEO4J_apoc_export_file_enabled=true # Enable file export
- NEO4J_apoc_import_file_enabled=true # Enable file import
- NEO4J_apoc_import_file_use_neo4j_config=true
- NEO4J_dbms_memory_heap_initial__size=2G
- NEO4J_dbms_memory_heap_max__size=4G
ports:
- "7474:7474"
- "7687:7687"

View File

@ -8,7 +8,7 @@
],
"scripts": {
"build": "dotenv -- turbo run build",
"dev": "dotenv -- turbo run dev --filter=!@redplanethq/core",
"dev": "dotenv -- turbo run dev",
"lint": "dotenv -- turbo run lint",
"format": "dotenv -- prettier --write \"**/*.{ts,tsx,md}\"",
"check-types": "dotenv -- turbo run check-types",

247
pnpm-lock.yaml generated
View File

@ -747,253 +747,6 @@ importers:
specifier: ^4.2.1
version: 4.3.2(typescript@5.8.3)(vite@6.3.5(@types/node@20.19.7)(jiti@2.4.2)(less@4.4.0)(lightningcss@1.30.1)(sass@1.89.2)(terser@5.42.0)(tsx@4.17.0)(yaml@2.8.0))
packages/core-cli:
dependencies:
'@clack/prompts':
specifier: ^0.10.0
version: 0.10.1
'@depot/cli':
specifier: 0.0.1-cli.2.80.0
version: 0.0.1-cli.2.80.0
'@opentelemetry/api':
specifier: 1.9.0
version: 1.9.0
'@opentelemetry/api-logs':
specifier: 0.52.1
version: 0.52.1
'@opentelemetry/exporter-logs-otlp-http':
specifier: 0.52.1
version: 0.52.1(@opentelemetry/api@1.9.0)
'@opentelemetry/exporter-trace-otlp-http':
specifier: 0.52.1
version: 0.52.1(@opentelemetry/api@1.9.0)
'@opentelemetry/instrumentation':
specifier: 0.52.1
version: 0.52.1(@opentelemetry/api@1.9.0)(supports-color@10.0.0)
'@opentelemetry/instrumentation-fetch':
specifier: 0.52.1
version: 0.52.1(@opentelemetry/api@1.9.0)(supports-color@10.0.0)
'@opentelemetry/resources':
specifier: 1.25.1
version: 1.25.1(@opentelemetry/api@1.9.0)
'@opentelemetry/sdk-logs':
specifier: 0.52.1
version: 0.52.1(@opentelemetry/api@1.9.0)
'@opentelemetry/sdk-node':
specifier: 0.52.1
version: 0.52.1(@opentelemetry/api@1.9.0)(supports-color@10.0.0)
'@opentelemetry/sdk-trace-base':
specifier: 1.25.1
version: 1.25.1(@opentelemetry/api@1.9.0)
'@opentelemetry/sdk-trace-node':
specifier: 1.25.1
version: 1.25.1(@opentelemetry/api@1.9.0)
'@opentelemetry/semantic-conventions':
specifier: 1.25.1
version: 1.25.1
ansi-escapes:
specifier: ^7.0.0
version: 7.0.0
braces:
specifier: ^3.0.3
version: 3.0.3
c12:
specifier: ^1.11.1
version: 1.11.2(magicast@0.3.5)
chalk:
specifier: ^5.2.0
version: 5.4.1
chokidar:
specifier: ^3.6.0
version: 3.6.0
cli-table3:
specifier: ^0.6.3
version: 0.6.5
commander:
specifier: ^9.4.1
version: 9.5.0
defu:
specifier: ^6.1.4
version: 6.1.4
dotenv:
specifier: ^16.4.5
version: 16.5.0
dotenv-expand:
specifier: ^12.0.2
version: 12.0.2
esbuild:
specifier: ^0.23.0
version: 0.23.1
eventsource:
specifier: ^3.0.2
version: 3.0.7
evt:
specifier: ^2.4.13
version: 2.5.9
fast-npm-meta:
specifier: ^0.2.2
version: 0.2.2
git-last-commit:
specifier: ^1.0.1
version: 1.0.1
gradient-string:
specifier: ^2.0.2
version: 2.0.2
has-flag:
specifier: ^5.0.1
version: 5.0.1
import-in-the-middle:
specifier: 1.11.0
version: 1.11.0
import-meta-resolve:
specifier: ^4.1.0
version: 4.1.0
ini:
specifier: ^5.0.0
version: 5.0.0
jsonc-parser:
specifier: 3.2.1
version: 3.2.1
knex:
specifier: 3.1.0
version: 3.1.0(pg@8.16.3)(supports-color@10.0.0)
magicast:
specifier: ^0.3.4
version: 0.3.5
minimatch:
specifier: ^10.0.1
version: 10.0.2
mlly:
specifier: ^1.7.1
version: 1.7.4
nanoid:
specifier: 3.3.8
version: 3.3.8
nypm:
specifier: ^0.5.4
version: 0.5.4
object-hash:
specifier: ^3.0.0
version: 3.0.0
open:
specifier: ^10.0.3
version: 10.2.0
p-limit:
specifier: ^6.2.0
version: 6.2.0
p-retry:
specifier: ^6.1.0
version: 6.2.1
partysocket:
specifier: ^1.0.2
version: 1.1.4
pg:
specifier: 8.16.3
version: 8.16.3
pkg-types:
specifier: ^1.1.3
version: 1.3.1
polka:
specifier: ^0.5.2
version: 0.5.2
resolve:
specifier: ^1.22.8
version: 1.22.10
semver:
specifier: ^7.5.0
version: 7.7.2
signal-exit:
specifier: ^4.1.0
version: 4.1.0
source-map-support:
specifier: 0.5.21
version: 0.5.21
std-env:
specifier: ^3.7.0
version: 3.9.0
supports-color:
specifier: ^10.0.0
version: 10.0.0
tiny-invariant:
specifier: ^1.2.0
version: 1.3.3
tinyexec:
specifier: ^0.3.1
version: 0.3.2
tinyglobby:
specifier: ^0.2.10
version: 0.2.14
uuid:
specifier: 11.1.0
version: 11.1.0
ws:
specifier: ^8.18.0
version: 8.18.3
xdg-app-paths:
specifier: ^8.3.0
version: 8.3.0
zod:
specifier: 3.23.8
version: 3.23.8
zod-validation-error:
specifier: ^1.5.0
version: 1.5.0(zod@3.23.8)
devDependencies:
'@epic-web/test-server':
specifier: ^0.1.0
version: 0.1.6
'@types/gradient-string':
specifier: ^1.1.2
version: 1.1.6
'@types/ini':
specifier: ^4.1.1
version: 4.1.1
'@types/object-hash':
specifier: 3.0.6
version: 3.0.6
'@types/polka':
specifier: ^0.5.7
version: 0.5.7
'@types/react':
specifier: ^18.2.48
version: 18.2.69
'@types/resolve':
specifier: ^1.20.6
version: 1.20.6
'@types/rimraf':
specifier: ^4.0.5
version: 4.0.5
'@types/semver':
specifier: ^7.5.0
version: 7.7.0
'@types/source-map-support':
specifier: 0.5.10
version: 0.5.10
'@types/ws':
specifier: ^8.5.3
version: 8.18.1
cpy-cli:
specifier: ^5.0.0
version: 5.0.0
execa:
specifier: ^8.0.1
version: 8.0.1
find-up:
specifier: ^7.0.0
version: 7.0.0
rimraf:
specifier: ^5.0.7
version: 5.0.10
ts-essentials:
specifier: 10.0.1
version: 10.0.1(typescript@5.8.3)
tshy:
specifier: ^3.0.2
version: 3.0.2
tsx:
specifier: 4.17.0
version: 4.17.0
packages/database:
dependencies:
'@prisma/client':