From a1b4b17c5bf106a097251eadac85687fc30d2f31 Mon Sep 17 00:00:00 2001 From: ahmedriad1 Date: Tue, 30 Sep 2025 17:04:48 +0300 Subject: [PATCH 1/8] move search to a standalone page & add it to the sidebar --- .../[namespaceSlug]/playground/page.tsx | 22 +- .../playground/search/page.client.tsx | 361 +++++++++++++++--- .../playground/search/page.tsx | 34 +- apps/web/src/components/app-sidebar/links.ts | 13 +- apps/web/src/server/api/routers/search.ts | 87 +++++ 5 files changed, 408 insertions(+), 109 deletions(-) diff --git a/apps/web/src/app/app.agentset.ai/(dashboard)/[slug]/[namespaceSlug]/playground/page.tsx b/apps/web/src/app/app.agentset.ai/(dashboard)/[slug]/[namespaceSlug]/playground/page.tsx index 2fa70c5f..b8295b3e 100644 --- a/apps/web/src/app/app.agentset.ai/(dashboard)/[slug]/[namespaceSlug]/playground/page.tsx +++ b/apps/web/src/app/app.agentset.ai/(dashboard)/[slug]/[namespaceSlug]/playground/page.tsx @@ -1,35 +1,15 @@ "use client"; -import Link from "next/link"; -import { useParams } from "next/navigation"; import Chat from "@/components/chat"; import DashboardPageWrapper from "@/components/dashboard-page-wrapper"; -import { Tabs, TabsList, TabsTrigger } from "@agentset/ui"; - import ChatActions from "./chat-actions"; export default function PlaygroundPage() { - const { slug, namespaceSlug } = useParams(); - return ( - - - Chat - - - - Search - - - - - } actions={} requireNamespace > diff --git a/apps/web/src/app/app.agentset.ai/(dashboard)/[slug]/[namespaceSlug]/playground/search/page.client.tsx b/apps/web/src/app/app.agentset.ai/(dashboard)/[slug]/[namespaceSlug]/playground/search/page.client.tsx index d6f0a4d1..0e844567 100644 --- a/apps/web/src/app/app.agentset.ai/(dashboard)/[slug]/[namespaceSlug]/playground/search/page.client.tsx +++ b/apps/web/src/app/app.agentset.ai/(dashboard)/[slug]/[namespaceSlug]/playground/search/page.client.tsx @@ -6,21 +6,62 @@ import { useNamespace } from "@/hooks/use-namespace"; import { logEvent } from "@/lib/analytics"; import { useTRPC } from "@/trpc/react"; import { useQuery } from "@tanstack/react-query"; -import { SearchIcon } from "lucide-react"; +import { FilterIcon, SearchIcon, SettingsIcon } from "lucide-react"; -import { Button, EmptyState, Input, Skeleton } from "@agentset/ui"; +import { + Badge, + Button, + Card, + CardContent, + CardHeader, + CardTitle, + Collapsible, + CollapsibleContent, + CollapsibleTrigger, + EmptyState, + Input, + Label, + Select, + SelectContent, + SelectItem, + SelectTrigger, + SelectValue, + Skeleton, + Slider, + Switch, +} from "@agentset/ui"; -export default function SearchPageClient() { +interface ChunkExplorerFilters { + mode: "semantic" | "keyword"; + topK: number; + minScore?: number; + rerank: boolean; + rerankLimit?: number; + includeMetadata: boolean; + includeRelationships: boolean; + filter?: Record; +} + +export default function ChunkExplorerPageClient() { const namespace = useNamespace(); const [query, setQuery] = useState(""); const [searchQuery, setSearchQuery] = useState(""); + const [showFilters, setShowFilters] = useState(false); + const [filters, setFilters] = useState({ + mode: "semantic", + topK: 20, + rerank: true, + includeMetadata: true, + includeRelationships: false, + }); const trpc = useTRPC(); - const { data, isLoading, isFetching } = useQuery( - trpc.search.search.queryOptions( + const { data, isLoading, isFetching, error } = useQuery( + trpc.search.exploreChunks.queryOptions( { namespaceId: namespace.id, query: searchQuery, + ...filters, }, { enabled: searchQuery.length > 0, @@ -33,70 +74,265 @@ export default function SearchPageClient() { const handleSubmit = (e: React.FormEvent) => { e.preventDefault(); if (!query.trim()) return; - logEvent("playground_search_performed", { + logEvent("playground_chunk_exploration", { namespaceId: namespace.id, query, + mode: filters.mode, + topK: filters.topK, }); setSearchQuery(query); }; + const handleFilterChange = (key: keyof ChunkExplorerFilters, value: any) => { + setFilters((prev) => ({ ...prev, [key]: value })); + }; + return ( -
-
- setQuery(e.target.value)} - placeholder="Enter your search query..." - className="flex-1" - /> - -
- -
- {isFetching ? ( -
-
-

Queries performed:

-
- - - - +
+ {/* Search Form */} + + +
+
+ setQuery(e.target.value)} + placeholder="Enter your search query to explore chunks..." + className="flex-1" + /> + +
+ + {/* Quick Filters */} +
+
+ + +
+ +
+ +
+ +
-
- - - - - + {/* Advanced Filters */} + + +
+
+ + + handleFilterChange( + "minScore", + value && value > 0 ? value : undefined, + ) + } + max={1} + min={0} + step={0.01} + className="w-full" + /> +
+ + {filters.mode === "semantic" && ( + <> +
+ + + handleFilterChange("rerankLimit", value) + } + max={filters.topK} + min={1} + step={1} + disabled={!filters.rerank} + className="w-full" + /> +
+ + )} + +
+ + handleFilterChange("rerank", checked) + } + disabled={filters.mode === "keyword"} + /> + +
+ +
+ + handleFilterChange("includeMetadata", checked) + } + /> + +
+ +
+ + handleFilterChange("includeRelationships", checked) + } + /> + +
+
+
+
+ + + + + {/* Results */} +
+ {isFetching ? ( +
+ + + + + +
+ {Array.from({ length: 5 }).map((_, idx) => ( + + ))}
+ ) : error ? ( + + +
+

Error occurred

+

+ {error.message} +

+
+
+
) : data ? ( -
-
-

Queries performed:

-

- {data.queries.map((q, idx) => ( - - {q.query} - {idx !== data.queries.length - 1 ? ", " : ""} - - ))} -

-
+
+ {/* Results Header */} + + +
+ + Chunk Explorer Results + +
+ {data.mode} + + {data.totalResults} chunks found + +
+
+
+

+ Query: {data.query} +

+
+ Top K: {data.parameters.topK} + {data.parameters.minScore && ( + + Min Score: {data.parameters.minScore.toFixed(2)} + + )} + {data.parameters.rerank && ( + + Reranked:{" "} + {data.parameters.rerankLimit || data.parameters.topK} + + )} +
+
+
+
-
+ {/* Chunks */} +
{data.results.length > 0 ? ( - data.results.map((result) => ( + data.results.map((result: any) => ( )) ) : ( -

No results found

+ + +
+

+ No chunks found matching your criteria +

+

+ Try adjusting your query or filters +

+
+
+
)}
) : ( )} diff --git a/apps/web/src/app/app.agentset.ai/(dashboard)/[slug]/[namespaceSlug]/playground/search/page.tsx b/apps/web/src/app/app.agentset.ai/(dashboard)/[slug]/[namespaceSlug]/playground/search/page.tsx index afeb1516..f71d71fc 100644 --- a/apps/web/src/app/app.agentset.ai/(dashboard)/[slug]/[namespaceSlug]/playground/search/page.tsx +++ b/apps/web/src/app/app.agentset.ai/(dashboard)/[slug]/[namespaceSlug]/playground/search/page.tsx @@ -1,37 +1,11 @@ -"use client"; - -import Link from "next/link"; -import { useParams } from "next/navigation"; import DashboardPageWrapper from "@/components/dashboard-page-wrapper"; -import { Tabs, TabsList, TabsTrigger } from "@agentset/ui"; - -import SearchPageClient from "./page.client"; - -export default function SearchPage() { - const { slug, namespaceSlug } = useParams(); +import ChunkExplorerPageClient from "./page.client"; +export default function ChunkExplorerPage() { return ( - - - - Chat - - - - - Search - - - - - } - requireNamespace - > - + + ); } diff --git a/apps/web/src/components/app-sidebar/links.ts b/apps/web/src/components/app-sidebar/links.ts index d05b9ba2..572444c1 100644 --- a/apps/web/src/components/app-sidebar/links.ts +++ b/apps/web/src/components/app-sidebar/links.ts @@ -9,6 +9,7 @@ import { MessagesSquareIcon, ReceiptIcon, RocketIcon, + SearchIcon, SettingsIcon, UnplugIcon, UsersIcon, @@ -88,8 +89,18 @@ export const namespaceItems: SidebarItemType[] = [ }, { title: "Playground", - url: createNamespaceUrl("/playground"), icon: MessagesSquareIcon, + items: [ + { + title: "Chat", + url: createNamespaceUrl("/playground"), + exact: true, + }, + { + title: "Chunk Explorer", + url: createNamespaceUrl("/playground/search"), + }, + ], }, { title: "Hosting", diff --git a/apps/web/src/server/api/routers/search.ts b/apps/web/src/server/api/routers/search.ts index 2fc2ce8b..337a7364 100644 --- a/apps/web/src/server/api/routers/search.ts +++ b/apps/web/src/server/api/routers/search.ts @@ -5,8 +5,24 @@ import { createTRPCRouter, protectedProcedure } from "@/server/api/trpc"; import { TRPCError } from "@trpc/server"; import { z } from "zod/v4"; +import { KeywordStore } from "@agentset/engine"; +import { queryVectorStore } from "@agentset/engine/vector-store/parse"; + import { getNamespaceByUser } from "../auth"; +const chunkExplorerInputSchema = z.object({ + namespaceId: z.string(), + query: z.string().min(1, "Query is required"), + mode: z.enum(["semantic", "keyword"]).default("semantic"), + topK: z.number().min(1).max(100).default(20), + minScore: z.number().min(0).max(1).optional(), + rerank: z.boolean().default(true), + rerankLimit: z.number().min(1).max(100).optional(), + filter: z.record(z.string(), z.any()).optional(), + includeMetadata: z.boolean().default(true), + includeRelationships: z.boolean().default(false), +}); + export const searchRouter = createTRPCRouter({ search: protectedProcedure .input( @@ -45,4 +61,75 @@ export const searchRouter = createTRPCRouter({ queries: results.queries, }; }), + + exploreChunks: protectedProcedure + .input(chunkExplorerInputSchema) + .query(async ({ ctx, input }) => { + const namespace = await getNamespaceByUser(ctx, { + id: input.namespaceId, + }); + + if (!namespace) { + throw new TRPCError({ code: "NOT_FOUND" }); + } + + // Check if keyword search is enabled when using keyword mode + if (input.mode === "keyword" && !namespace.keywordEnabled) { + throw new TRPCError({ + code: "BAD_REQUEST", + message: "Keyword search is not enabled for this namespace", + }); + } + + let results; + let queryPerformed = input.query; + + if (input.mode === "semantic") { + const queryResult = await queryVectorStore(namespace, { + query: input.query, + topK: input.topK, + minScore: input.minScore, + filter: input.filter, + includeMetadata: input.includeMetadata, + includeRelationships: input.includeRelationships, + rerankLimit: input.rerankLimit, + rerank: input.rerank, + }); + + if (!queryResult) { + results = []; + } else { + results = queryResult.results; + } + } else { + // Keyword search + const keywordStore = new KeywordStore(namespace.id); + const keywordResult = await keywordStore.search(input.query, { + limit: input.topK, + minScore: input.minScore, + includeMetadata: input.includeMetadata, + includeRelationships: input.includeRelationships, + filter: input.filter, + }); + + results = keywordResult.results; + } + + // Track search usage + incrementSearchUsage(namespace.id, 1); + + return { + results, + query: queryPerformed, + mode: input.mode, + totalResults: results.length, + parameters: { + topK: input.topK, + minScore: input.minScore, + rerank: input.rerank, + rerankLimit: input.rerankLimit, + filter: input.filter, + }, + }; + }), }); From 7bf5af42a5c6d7e35b42ba5c06a88f38708b3508 Mon Sep 17 00:00:00 2001 From: ahmedriad1 Date: Tue, 30 Sep 2025 19:27:20 +0300 Subject: [PATCH 2/8] fix import --- apps/web/src/server/api/routers/search.ts | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/apps/web/src/server/api/routers/search.ts b/apps/web/src/server/api/routers/search.ts index 337a7364..74235aff 100644 --- a/apps/web/src/server/api/routers/search.ts +++ b/apps/web/src/server/api/routers/search.ts @@ -5,8 +5,11 @@ import { createTRPCRouter, protectedProcedure } from "@/server/api/trpc"; import { TRPCError } from "@trpc/server"; import { z } from "zod/v4"; -import { KeywordStore } from "@agentset/engine"; -import { queryVectorStore } from "@agentset/engine/vector-store/parse"; +import { + KeywordStore, + queryVectorStore, + QueryVectorStoreResult, +} from "@agentset/engine"; import { getNamespaceByUser } from "../auth"; @@ -81,7 +84,7 @@ export const searchRouter = createTRPCRouter({ }); } - let results; + let results: QueryVectorStoreResult["results"] | undefined = []; let queryPerformed = input.query; if (input.mode === "semantic") { @@ -109,7 +112,8 @@ export const searchRouter = createTRPCRouter({ minScore: input.minScore, includeMetadata: input.includeMetadata, includeRelationships: input.includeRelationships, - filter: input.filter, + // TODO: convert pinecone filter to azure filter + // filter: input.filter, }); results = keywordResult.results; From 426a8edb47972021d7aed5293eea2f92fca8c122 Mon Sep 17 00:00:00 2001 From: ahmedriad1 Date: Wed, 1 Oct 2025 14:13:14 +0300 Subject: [PATCH 3/8] rename prisma output --- packages/db/prisma/schema/schema.prisma | 2 +- packages/db/src/client.ts | 2 +- packages/db/src/index.ts | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/db/prisma/schema/schema.prisma b/packages/db/prisma/schema/schema.prisma index 18b1aed0..4d16ddf9 100644 --- a/packages/db/prisma/schema/schema.prisma +++ b/packages/db/prisma/schema/schema.prisma @@ -8,7 +8,7 @@ generator client { provider = "prisma-client-js" - output = "../../generated/client" + output = "../../generated/prisma" } generator json { diff --git a/packages/db/src/client.ts b/packages/db/src/client.ts index 58bb2bf2..265c808a 100644 --- a/packages/db/src/client.ts +++ b/packages/db/src/client.ts @@ -3,7 +3,7 @@ import { PrismaNeon } from "@prisma/adapter-neon"; // import ws from "ws"; -import { PrismaClient } from "../generated/client"; +import { PrismaClient } from "../generated/prisma"; const createPrismaClient = () => { if (typeof WebSocket === "undefined") { diff --git a/packages/db/src/index.ts b/packages/db/src/index.ts index 1f9f9ee1..9c4700e1 100644 --- a/packages/db/src/index.ts +++ b/packages/db/src/index.ts @@ -1,4 +1,4 @@ export { db } from "./client"; export * from "./types/prisma"; -export * from "../generated/client"; +export * from "../generated/prisma"; From f94ae2b65afe1429e38ecadacb1071e22835156d Mon Sep 17 00:00:00 2001 From: ahmedriad1 Date: Wed, 1 Oct 2025 14:13:47 +0300 Subject: [PATCH 4/8] add jiti to import env validation, and disable turbopack for development --- apps/web/next.config.ts | 96 +++++++++++++++-------------- apps/web/package.json | 3 +- pnpm-lock.yaml | 133 +++++++++++++++++++++------------------- 3 files changed, 124 insertions(+), 108 deletions(-) diff --git a/apps/web/next.config.ts b/apps/web/next.config.ts index 4cace37e..92ad6327 100644 --- a/apps/web/next.config.ts +++ b/apps/web/next.config.ts @@ -2,56 +2,62 @@ * Run `build` or `dev` with `SKIP_ENV_VALIDATION` to skip env validation. This is especially useful * for Docker builds. */ +import { fileURLToPath } from "node:url"; import type { NextConfig } from "next"; // @ts-expect-error - no types import { PrismaPlugin } from "@prisma/nextjs-monorepo-workaround-plugin"; -import "./src/env"; +const makeConfig = async (): Promise => { + const { createJiti } = await import("jiti"); + await createJiti(fileURLToPath(import.meta.url)).import("./src/env.ts"); -const config: NextConfig = { - images: { - remotePatterns: [ - { - hostname: "assets.agentset.ai", - }, + return { + poweredByHeader: false, + + images: { + remotePatterns: [ + { + hostname: "assets.agentset.ai", + }, + ], + }, + + /** Enables hot reloading for local packages without a build step */ + transpilePackages: [ + "@agentset/db", + "@agentset/emails", + "@agentset/engine", + "@agentset/jobs", + "@agentset/storage", + "@agentset/stripe", + "@agentset/ui", + "@agentset/utils", + "@agentset/validation", ], - }, - - /** Enables hot reloading for local packages without a build step */ - transpilePackages: [ - "@agentset/db", - "@agentset/emails", - "@agentset/engine", - "@agentset/jobs", - "@agentset/storage", - "@agentset/stripe", - "@agentset/ui", - "@agentset/utils", - "@agentset/validation", - ], - - /** We already do linting and typechecking as separate tasks in CI */ - eslint: { ignoreDuringBuilds: true }, - typescript: { ignoreBuildErrors: true }, - - webpack: (config, { isServer }) => { - if (isServer) config.plugins = [...config.plugins, new PrismaPlugin()]; - return config; - }, - - async rewrites() { - return [ - // for posthog proxy - { - source: "/_proxy/posthog/ingest/static/:path*", - destination: "https://us-assets.i.posthog.com/static/:path*", - }, - { - source: "/_proxy/posthog/ingest/:path*", - destination: "https://us.i.posthog.com/:path*", - }, - ]; - }, + + /** We already do linting and typechecking as separate tasks in CI */ + eslint: { ignoreDuringBuilds: true }, + typescript: { ignoreBuildErrors: true }, + + webpack: (config, { isServer }) => { + if (isServer) config.plugins = [...config.plugins, new PrismaPlugin()]; + return config; + }, + + async rewrites() { + return [ + // for posthog proxy + { + source: "/_proxy/posthog/ingest/static/:path*", + destination: "https://us-assets.i.posthog.com/static/:path*", + }, + { + source: "/_proxy/posthog/ingest/:path*", + destination: "https://us.i.posthog.com/:path*", + }, + ]; + }, + }; }; -export default config; +export default makeConfig(); diff --git a/apps/web/package.json b/apps/web/package.json index 6167e29a..67eec6c2 100644 --- a/apps/web/package.json +++ b/apps/web/package.json @@ -7,7 +7,7 @@ "build": "pnpm with-env next build", "clean": "git clean -xdf .cache .next .turbo node_modules", "check": "pnpm lint && tsc --noEmit", - "dev": "pnpm with-env next dev --turbopack", + "dev": "pnpm with-env next dev", "format": "prettier --check . --ignore-path ../../.gitignore", "lint": "eslint", "lint:fix": "pnpm lint --fix", @@ -49,6 +49,7 @@ "fast-deep-equal": "^3.1.3", "file-type": "^21.0.0", "framer-motion": "^12.4.10", + "jiti": "^2.6.1", "next": "15.5.2", "posthog-js": "^1.260.1", "posthog-node": "^5.8.1", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 8c7a2760..c15f0f97 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -174,6 +174,9 @@ importers: framer-motion: specifier: ^12.4.10 version: 12.5.0(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + jiti: + specifier: ^2.6.1 + version: 2.6.1 next: specifier: 15.5.2 version: 15.5.2(@opentelemetry/api@1.9.0)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) @@ -252,7 +255,7 @@ importers: version: 8.0.0 eslint: specifier: 'catalog:' - version: 9.35.0(jiti@2.5.1) + version: 9.35.0(jiti@2.6.1) postcss: specifier: ^8.4.39 version: 8.5.3 @@ -301,7 +304,7 @@ importers: version: 8.0.0 eslint: specifier: 'catalog:' - version: 9.35.0(jiti@2.5.1) + version: 9.35.0(jiti@2.6.1) prettier: specifier: 'catalog:' version: 3.6.2 @@ -347,7 +350,7 @@ importers: version: 8.0.0 eslint: specifier: 'catalog:' - version: 9.35.0(jiti@2.5.1) + version: 9.35.0(jiti@2.6.1) prettier: specifier: 'catalog:' version: 3.6.2 @@ -417,7 +420,7 @@ importers: version: link:../../tooling/typescript eslint: specifier: 'catalog:' - version: 9.35.0(jiti@2.5.1) + version: 9.35.0(jiti@2.6.1) prettier: specifier: 'catalog:' version: 3.6.2 @@ -475,7 +478,7 @@ importers: version: 8.0.0 eslint: specifier: 'catalog:' - version: 9.35.0(jiti@2.5.1) + version: 9.35.0(jiti@2.6.1) prettier: specifier: 'catalog:' version: 3.6.2 @@ -515,7 +518,7 @@ importers: version: link:../../tooling/typescript eslint: specifier: 'catalog:' - version: 9.35.0(jiti@2.5.1) + version: 9.35.0(jiti@2.6.1) prettier: specifier: 'catalog:' version: 3.6.2 @@ -555,7 +558,7 @@ importers: version: link:../../tooling/typescript eslint: specifier: 'catalog:' - version: 9.35.0(jiti@2.5.1) + version: 9.35.0(jiti@2.6.1) prettier: specifier: 'catalog:' version: 3.6.2 @@ -643,7 +646,7 @@ importers: version: 15.5.13 eslint: specifier: 'catalog:' - version: 9.35.0(jiti@2.5.1) + version: 9.35.0(jiti@2.6.1) prettier: specifier: 'catalog:' version: 3.6.2 @@ -668,7 +671,7 @@ importers: version: link:../../tooling/typescript eslint: specifier: 'catalog:' - version: 9.35.0(jiti@2.5.1) + version: 9.35.0(jiti@2.6.1) prettier: specifier: 'catalog:' version: 3.6.2 @@ -693,7 +696,7 @@ importers: version: link:../../tooling/typescript eslint: specifier: 'catalog:' - version: 9.35.0(jiti@2.5.1) + version: 9.35.0(jiti@2.6.1) prettier: specifier: 'catalog:' version: 3.6.2 @@ -705,31 +708,31 @@ importers: dependencies: '@eslint/compat': specifier: ^1.3.2 - version: 1.3.2(eslint@9.35.0(jiti@2.5.1)) + version: 1.3.2(eslint@9.35.0(jiti@2.6.1)) '@next/eslint-plugin-next': specifier: ^15.5.3 version: 15.5.3 eslint-plugin-import: specifier: ^2.32.0 - version: 2.32.0(@typescript-eslint/parser@8.44.0(eslint@9.35.0(jiti@2.5.1))(typescript@5.9.2))(eslint@9.35.0(jiti@2.5.1)) + version: 2.32.0(@typescript-eslint/parser@8.44.0(eslint@9.35.0(jiti@2.6.1))(typescript@5.9.2))(eslint@9.35.0(jiti@2.6.1)) eslint-plugin-jsx-a11y: specifier: ^6.10.2 - version: 6.10.2(eslint@9.35.0(jiti@2.5.1)) + version: 6.10.2(eslint@9.35.0(jiti@2.6.1)) eslint-plugin-react: specifier: ^7.37.5 - version: 7.37.5(eslint@9.35.0(jiti@2.5.1)) + version: 7.37.5(eslint@9.35.0(jiti@2.6.1)) eslint-plugin-react-compiler: specifier: beta - version: 19.0.0-beta-af1b7da-20250417(eslint@9.35.0(jiti@2.5.1)) + version: 19.0.0-beta-af1b7da-20250417(eslint@9.35.0(jiti@2.6.1)) eslint-plugin-react-hooks: specifier: ^5.2.0 - version: 5.2.0(eslint@9.35.0(jiti@2.5.1)) + version: 5.2.0(eslint@9.35.0(jiti@2.6.1)) eslint-plugin-turbo: specifier: ^2.5.6 - version: 2.5.6(eslint@9.35.0(jiti@2.5.1))(turbo@2.4.4) + version: 2.5.6(eslint@9.35.0(jiti@2.6.1))(turbo@2.4.4) typescript-eslint: specifier: ^8.44.0 - version: 8.44.0(eslint@9.35.0(jiti@2.5.1))(typescript@5.9.2) + version: 8.44.0(eslint@9.35.0(jiti@2.6.1))(typescript@5.9.2) devDependencies: '@agentset/prettier-config': specifier: workspace:* @@ -739,7 +742,7 @@ importers: version: link:../typescript eslint: specifier: 'catalog:' - version: 9.35.0(jiti@2.5.1) + version: 9.35.0(jiti@2.6.1) prettier: specifier: 'catalog:' version: 3.6.2 @@ -5927,6 +5930,10 @@ packages: resolution: {integrity: sha512-twQoecYPiVA5K/h6SxtORw/Bs3ar+mLUtoPSc7iMXzQzK8d7eJ/R09wmTwAjiamETn1cXYPGfNnu7DMoHgu12w==} hasBin: true + jiti@2.6.1: + resolution: {integrity: sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ==} + hasBin: true + jose@5.10.0: resolution: {integrity: sha512-s+3Al/p9g32Iq+oqXxkW//7jk2Vig6FF1CFqzVXoTUXt2qz89YWbL+OwS17NFYEvxC35n0FKeGO2LGYSxeM2Gg==} @@ -9665,16 +9672,16 @@ snapshots: '@esbuild/win32-x64@0.25.1': optional: true - '@eslint-community/eslint-utils@4.9.0(eslint@9.35.0(jiti@2.5.1))': + '@eslint-community/eslint-utils@4.9.0(eslint@9.35.0(jiti@2.6.1))': dependencies: - eslint: 9.35.0(jiti@2.5.1) + eslint: 9.35.0(jiti@2.6.1) eslint-visitor-keys: 3.4.3 '@eslint-community/regexpp@4.12.1': {} - '@eslint/compat@1.3.2(eslint@9.35.0(jiti@2.5.1))': + '@eslint/compat@1.3.2(eslint@9.35.0(jiti@2.6.1))': optionalDependencies: - eslint: 9.35.0(jiti@2.5.1) + eslint: 9.35.0(jiti@2.6.1) '@eslint/config-array@0.21.0': dependencies: @@ -11768,7 +11775,7 @@ snapshots: dependencies: '@jridgewell/remapping': 2.3.5 enhanced-resolve: 5.18.3 - jiti: 2.5.1 + jiti: 2.6.1 lightningcss: 1.30.1 magic-string: 0.30.17 source-map-js: 1.2.1 @@ -12138,15 +12145,15 @@ snapshots: dependencies: '@types/node': 22.18.4 - '@typescript-eslint/eslint-plugin@8.44.0(@typescript-eslint/parser@8.44.0(eslint@9.35.0(jiti@2.5.1))(typescript@5.9.2))(eslint@9.35.0(jiti@2.5.1))(typescript@5.9.2)': + '@typescript-eslint/eslint-plugin@8.44.0(@typescript-eslint/parser@8.44.0(eslint@9.35.0(jiti@2.6.1))(typescript@5.9.2))(eslint@9.35.0(jiti@2.6.1))(typescript@5.9.2)': dependencies: '@eslint-community/regexpp': 4.12.1 - '@typescript-eslint/parser': 8.44.0(eslint@9.35.0(jiti@2.5.1))(typescript@5.9.2) + '@typescript-eslint/parser': 8.44.0(eslint@9.35.0(jiti@2.6.1))(typescript@5.9.2) '@typescript-eslint/scope-manager': 8.44.0 - '@typescript-eslint/type-utils': 8.44.0(eslint@9.35.0(jiti@2.5.1))(typescript@5.9.2) - '@typescript-eslint/utils': 8.44.0(eslint@9.35.0(jiti@2.5.1))(typescript@5.9.2) + '@typescript-eslint/type-utils': 8.44.0(eslint@9.35.0(jiti@2.6.1))(typescript@5.9.2) + '@typescript-eslint/utils': 8.44.0(eslint@9.35.0(jiti@2.6.1))(typescript@5.9.2) '@typescript-eslint/visitor-keys': 8.44.0 - eslint: 9.35.0(jiti@2.5.1) + eslint: 9.35.0(jiti@2.6.1) graphemer: 1.4.0 ignore: 7.0.5 natural-compare: 1.4.0 @@ -12155,14 +12162,14 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/parser@8.44.0(eslint@9.35.0(jiti@2.5.1))(typescript@5.9.2)': + '@typescript-eslint/parser@8.44.0(eslint@9.35.0(jiti@2.6.1))(typescript@5.9.2)': dependencies: '@typescript-eslint/scope-manager': 8.44.0 '@typescript-eslint/types': 8.44.0 '@typescript-eslint/typescript-estree': 8.44.0(typescript@5.9.2) '@typescript-eslint/visitor-keys': 8.44.0 debug: 4.4.1(supports-color@10.0.0) - eslint: 9.35.0(jiti@2.5.1) + eslint: 9.35.0(jiti@2.6.1) typescript: 5.9.2 transitivePeerDependencies: - supports-color @@ -12185,13 +12192,13 @@ snapshots: dependencies: typescript: 5.9.2 - '@typescript-eslint/type-utils@8.44.0(eslint@9.35.0(jiti@2.5.1))(typescript@5.9.2)': + '@typescript-eslint/type-utils@8.44.0(eslint@9.35.0(jiti@2.6.1))(typescript@5.9.2)': dependencies: '@typescript-eslint/types': 8.44.0 '@typescript-eslint/typescript-estree': 8.44.0(typescript@5.9.2) - '@typescript-eslint/utils': 8.44.0(eslint@9.35.0(jiti@2.5.1))(typescript@5.9.2) + '@typescript-eslint/utils': 8.44.0(eslint@9.35.0(jiti@2.6.1))(typescript@5.9.2) debug: 4.4.1(supports-color@10.0.0) - eslint: 9.35.0(jiti@2.5.1) + eslint: 9.35.0(jiti@2.6.1) ts-api-utils: 2.1.0(typescript@5.9.2) typescript: 5.9.2 transitivePeerDependencies: @@ -12215,13 +12222,13 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/utils@8.44.0(eslint@9.35.0(jiti@2.5.1))(typescript@5.9.2)': + '@typescript-eslint/utils@8.44.0(eslint@9.35.0(jiti@2.6.1))(typescript@5.9.2)': dependencies: - '@eslint-community/eslint-utils': 4.9.0(eslint@9.35.0(jiti@2.5.1)) + '@eslint-community/eslint-utils': 4.9.0(eslint@9.35.0(jiti@2.6.1)) '@typescript-eslint/scope-manager': 8.44.0 '@typescript-eslint/types': 8.44.0 '@typescript-eslint/typescript-estree': 8.44.0(typescript@5.9.2) - eslint: 9.35.0(jiti@2.5.1) + eslint: 9.35.0(jiti@2.6.1) typescript: 5.9.2 transitivePeerDependencies: - supports-color @@ -13518,17 +13525,17 @@ snapshots: transitivePeerDependencies: - supports-color - eslint-module-utils@2.12.1(@typescript-eslint/parser@8.44.0(eslint@9.35.0(jiti@2.5.1))(typescript@5.9.2))(eslint-import-resolver-node@0.3.9)(eslint@9.35.0(jiti@2.5.1)): + eslint-module-utils@2.12.1(@typescript-eslint/parser@8.44.0(eslint@9.35.0(jiti@2.6.1))(typescript@5.9.2))(eslint-import-resolver-node@0.3.9)(eslint@9.35.0(jiti@2.6.1)): dependencies: debug: 3.2.7 optionalDependencies: - '@typescript-eslint/parser': 8.44.0(eslint@9.35.0(jiti@2.5.1))(typescript@5.9.2) - eslint: 9.35.0(jiti@2.5.1) + '@typescript-eslint/parser': 8.44.0(eslint@9.35.0(jiti@2.6.1))(typescript@5.9.2) + eslint: 9.35.0(jiti@2.6.1) eslint-import-resolver-node: 0.3.9 transitivePeerDependencies: - supports-color - eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.44.0(eslint@9.35.0(jiti@2.5.1))(typescript@5.9.2))(eslint@9.35.0(jiti@2.5.1)): + eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.44.0(eslint@9.35.0(jiti@2.6.1))(typescript@5.9.2))(eslint@9.35.0(jiti@2.6.1)): dependencies: '@rtsao/scc': 1.1.0 array-includes: 3.1.9 @@ -13537,9 +13544,9 @@ snapshots: array.prototype.flatmap: 1.3.3 debug: 3.2.7 doctrine: 2.1.0 - eslint: 9.35.0(jiti@2.5.1) + eslint: 9.35.0(jiti@2.6.1) eslint-import-resolver-node: 0.3.9 - eslint-module-utils: 2.12.1(@typescript-eslint/parser@8.44.0(eslint@9.35.0(jiti@2.5.1))(typescript@5.9.2))(eslint-import-resolver-node@0.3.9)(eslint@9.35.0(jiti@2.5.1)) + eslint-module-utils: 2.12.1(@typescript-eslint/parser@8.44.0(eslint@9.35.0(jiti@2.6.1))(typescript@5.9.2))(eslint-import-resolver-node@0.3.9)(eslint@9.35.0(jiti@2.6.1)) hasown: 2.0.2 is-core-module: 2.16.1 is-glob: 4.0.3 @@ -13551,13 +13558,13 @@ snapshots: string.prototype.trimend: 1.0.9 tsconfig-paths: 3.15.0 optionalDependencies: - '@typescript-eslint/parser': 8.44.0(eslint@9.35.0(jiti@2.5.1))(typescript@5.9.2) + '@typescript-eslint/parser': 8.44.0(eslint@9.35.0(jiti@2.6.1))(typescript@5.9.2) transitivePeerDependencies: - eslint-import-resolver-typescript - eslint-import-resolver-webpack - supports-color - eslint-plugin-jsx-a11y@6.10.2(eslint@9.35.0(jiti@2.5.1)): + eslint-plugin-jsx-a11y@6.10.2(eslint@9.35.0(jiti@2.6.1)): dependencies: aria-query: 5.3.2 array-includes: 3.1.8 @@ -13567,7 +13574,7 @@ snapshots: axobject-query: 4.1.0 damerau-levenshtein: 1.0.8 emoji-regex: 9.2.2 - eslint: 9.35.0(jiti@2.5.1) + eslint: 9.35.0(jiti@2.6.1) hasown: 2.0.2 jsx-ast-utils: 3.3.5 language-tags: 1.0.9 @@ -13576,23 +13583,23 @@ snapshots: safe-regex-test: 1.1.0 string.prototype.includes: 2.0.1 - eslint-plugin-react-compiler@19.0.0-beta-af1b7da-20250417(eslint@9.35.0(jiti@2.5.1)): + eslint-plugin-react-compiler@19.0.0-beta-af1b7da-20250417(eslint@9.35.0(jiti@2.6.1)): dependencies: '@babel/core': 7.26.10 '@babel/parser': 7.26.10 '@babel/plugin-proposal-private-methods': 7.18.6(@babel/core@7.26.10) - eslint: 9.35.0(jiti@2.5.1) + eslint: 9.35.0(jiti@2.6.1) hermes-parser: 0.25.1 zod: 3.25.76 zod-validation-error: 3.4.0(zod@3.25.76) transitivePeerDependencies: - supports-color - eslint-plugin-react-hooks@5.2.0(eslint@9.35.0(jiti@2.5.1)): + eslint-plugin-react-hooks@5.2.0(eslint@9.35.0(jiti@2.6.1)): dependencies: - eslint: 9.35.0(jiti@2.5.1) + eslint: 9.35.0(jiti@2.6.1) - eslint-plugin-react@7.37.5(eslint@9.35.0(jiti@2.5.1)): + eslint-plugin-react@7.37.5(eslint@9.35.0(jiti@2.6.1)): dependencies: array-includes: 3.1.8 array.prototype.findlast: 1.2.5 @@ -13600,7 +13607,7 @@ snapshots: array.prototype.tosorted: 1.1.4 doctrine: 2.1.0 es-iterator-helpers: 1.2.1 - eslint: 9.35.0(jiti@2.5.1) + eslint: 9.35.0(jiti@2.6.1) estraverse: 5.3.0 hasown: 2.0.2 jsx-ast-utils: 3.3.5 @@ -13614,10 +13621,10 @@ snapshots: string.prototype.matchall: 4.0.12 string.prototype.repeat: 1.0.0 - eslint-plugin-turbo@2.5.6(eslint@9.35.0(jiti@2.5.1))(turbo@2.4.4): + eslint-plugin-turbo@2.5.6(eslint@9.35.0(jiti@2.6.1))(turbo@2.4.4): dependencies: dotenv: 16.0.3 - eslint: 9.35.0(jiti@2.5.1) + eslint: 9.35.0(jiti@2.6.1) turbo: 2.4.4 eslint-scope@8.4.0: @@ -13629,9 +13636,9 @@ snapshots: eslint-visitor-keys@4.2.1: {} - eslint@9.35.0(jiti@2.5.1): + eslint@9.35.0(jiti@2.6.1): dependencies: - '@eslint-community/eslint-utils': 4.9.0(eslint@9.35.0(jiti@2.5.1)) + '@eslint-community/eslint-utils': 4.9.0(eslint@9.35.0(jiti@2.6.1)) '@eslint-community/regexpp': 4.12.1 '@eslint/config-array': 0.21.0 '@eslint/config-helpers': 0.3.1 @@ -13667,7 +13674,7 @@ snapshots: natural-compare: 1.4.0 optionator: 0.9.4 optionalDependencies: - jiti: 2.5.1 + jiti: 2.6.1 transitivePeerDependencies: - supports-color @@ -14623,6 +14630,8 @@ snapshots: jiti@2.5.1: {} + jiti@2.6.1: {} + jose@5.10.0: {} joycon@3.1.1: {} @@ -17310,13 +17319,13 @@ snapshots: possible-typed-array-names: 1.1.0 reflect.getprototypeof: 1.0.10 - typescript-eslint@8.44.0(eslint@9.35.0(jiti@2.5.1))(typescript@5.9.2): + typescript-eslint@8.44.0(eslint@9.35.0(jiti@2.6.1))(typescript@5.9.2): dependencies: - '@typescript-eslint/eslint-plugin': 8.44.0(@typescript-eslint/parser@8.44.0(eslint@9.35.0(jiti@2.5.1))(typescript@5.9.2))(eslint@9.35.0(jiti@2.5.1))(typescript@5.9.2) - '@typescript-eslint/parser': 8.44.0(eslint@9.35.0(jiti@2.5.1))(typescript@5.9.2) + '@typescript-eslint/eslint-plugin': 8.44.0(@typescript-eslint/parser@8.44.0(eslint@9.35.0(jiti@2.6.1))(typescript@5.9.2))(eslint@9.35.0(jiti@2.6.1))(typescript@5.9.2) + '@typescript-eslint/parser': 8.44.0(eslint@9.35.0(jiti@2.6.1))(typescript@5.9.2) '@typescript-eslint/typescript-estree': 8.44.0(typescript@5.9.2) - '@typescript-eslint/utils': 8.44.0(eslint@9.35.0(jiti@2.5.1))(typescript@5.9.2) - eslint: 9.35.0(jiti@2.5.1) + '@typescript-eslint/utils': 8.44.0(eslint@9.35.0(jiti@2.6.1))(typescript@5.9.2) + eslint: 9.35.0(jiti@2.6.1) typescript: 5.9.2 transitivePeerDependencies: - supports-color From f277341bc9875ea67824a3006c4a5a9b724098ce Mon Sep 17 00:00:00 2001 From: ahmedriad1 Date: Wed, 1 Oct 2025 14:14:06 +0300 Subject: [PATCH 5/8] polish playground search --- .../playground/search/page.client.tsx | 307 +++++++----------- .../playground/search/page.tsx | 4 +- apps/web/src/components/app-sidebar/links.ts | 2 +- 3 files changed, 122 insertions(+), 191 deletions(-) diff --git a/apps/web/src/app/app.agentset.ai/(dashboard)/[slug]/[namespaceSlug]/playground/search/page.client.tsx b/apps/web/src/app/app.agentset.ai/(dashboard)/[slug]/[namespaceSlug]/playground/search/page.client.tsx index 0e844567..7c8dc148 100644 --- a/apps/web/src/app/app.agentset.ai/(dashboard)/[slug]/[namespaceSlug]/playground/search/page.client.tsx +++ b/apps/web/src/app/app.agentset.ai/(dashboard)/[slug]/[namespaceSlug]/playground/search/page.client.tsx @@ -6,7 +6,7 @@ import { useNamespace } from "@/hooks/use-namespace"; import { logEvent } from "@/lib/analytics"; import { useTRPC } from "@/trpc/react"; import { useQuery } from "@tanstack/react-query"; -import { FilterIcon, SearchIcon, SettingsIcon } from "lucide-react"; +import { SearchIcon } from "lucide-react"; import { Badge, @@ -15,9 +15,6 @@ import { CardContent, CardHeader, CardTitle, - Collapsible, - CollapsibleContent, - CollapsibleTrigger, EmptyState, Input, Label, @@ -37,8 +34,6 @@ interface ChunkExplorerFilters { minScore?: number; rerank: boolean; rerankLimit?: number; - includeMetadata: boolean; - includeRelationships: boolean; filter?: Record; } @@ -46,14 +41,11 @@ export default function ChunkExplorerPageClient() { const namespace = useNamespace(); const [query, setQuery] = useState(""); const [searchQuery, setSearchQuery] = useState(""); - const [showFilters, setShowFilters] = useState(false); - const [filters, setFilters] = useState({ - mode: "semantic", - topK: 20, - rerank: true, - includeMetadata: true, - includeRelationships: false, - }); + const [mode, setMode] = useState<"semantic" | "keyword">("semantic"); + const [topK, setTopK] = useState(20); + const [rerank, setRerank] = useState(true); + const [rerankLimit, setRerankLimit] = useState(20); + const [minScore, setMinScore] = useState(0); const trpc = useTRPC(); const { data, isLoading, isFetching, error } = useQuery( @@ -61,7 +53,11 @@ export default function ChunkExplorerPageClient() { { namespaceId: namespace.id, query: searchQuery, - ...filters, + mode, + topK, + rerank, + rerankLimit, + minScore, }, { enabled: searchQuery.length > 0, @@ -74,19 +70,18 @@ export default function ChunkExplorerPageClient() { const handleSubmit = (e: React.FormEvent) => { e.preventDefault(); if (!query.trim()) return; - logEvent("playground_chunk_exploration", { + logEvent("playground_search", { namespaceId: namespace.id, query, - mode: filters.mode, - topK: filters.topK, + mode, + topK, + rerank, + rerankLimit, + minScore, }); setSearchQuery(query); }; - const handleFilterChange = (key: keyof ChunkExplorerFilters, value: any) => { - setFilters((prev) => ({ ...prev, [key]: value })); - }; - return (
{/* Search Form */} @@ -112,38 +107,33 @@ export default function ChunkExplorerPageClient() { {/* Quick Filters */}
-
- - -
+ {namespace.keywordEnabled && ( +
+ + +
+ )}
- -
- - {/* Advanced Filters */} - - -
-
- - - handleFilterChange( - "minScore", - value && value > 0 ? value : undefined, - ) - } - max={1} - min={0} - step={0.01} - className="w-full" - /> -
- - {filters.mode === "semantic" && ( - <> -
- - - handleFilterChange("rerankLimit", value) - } - max={filters.topK} - min={1} - step={1} - disabled={!filters.rerank} - className="w-full" - /> -
- - )} - -
- - handleFilterChange("rerank", checked) - } - disabled={filters.mode === "keyword"} - /> - -
- -
- - handleFilterChange("includeMetadata", checked) - } - /> - -
+
+ setRerank(checked)} + /> + +
-
- - handleFilterChange("includeRelationships", checked) - } - /> - -
+ {rerank && ( +
+ +
- - + )} +
+ + {/* Filters */} +
+
+ + + setMinScore(value && value > 0 ? value : 0) + } + max={1} + min={0} + step={0.01} + className="w-full" + /> +
+
@@ -293,41 +233,32 @@ export default function ChunkExplorerPageClient() { ) : data ? (
- {/* Results Header */} - - -
- - Chunk Explorer Results - -
- {data.mode} - - {data.totalResults} chunks found - -
-
-
-

- Query: {data.query} -

-
- Top K: {data.parameters.topK} - {data.parameters.minScore && ( - - Min Score: {data.parameters.minScore.toFixed(2)} - - )} - {data.parameters.rerank && ( - - Reranked:{" "} - {data.parameters.rerankLimit || data.parameters.topK} - - )} -
-
-
-
+
+ Search Results +
+ {data.mode} + + {data.totalResults} chunks found + +
+
+
+

+ Query: {data.query} +

+
+ Top K: {data.parameters.topK} + {data.parameters.minScore && ( + Min Score: {data.parameters.minScore.toFixed(2)} + )} + {data.parameters.rerank && ( + + Reranked:{" "} + {data.parameters.rerankLimit || data.parameters.topK} + + )} +
+
{/* Chunks */}
@@ -358,7 +289,7 @@ export default function ChunkExplorerPageClient() {
) : ( diff --git a/apps/web/src/app/app.agentset.ai/(dashboard)/[slug]/[namespaceSlug]/playground/search/page.tsx b/apps/web/src/app/app.agentset.ai/(dashboard)/[slug]/[namespaceSlug]/playground/search/page.tsx index f71d71fc..604bce29 100644 --- a/apps/web/src/app/app.agentset.ai/(dashboard)/[slug]/[namespaceSlug]/playground/search/page.tsx +++ b/apps/web/src/app/app.agentset.ai/(dashboard)/[slug]/[namespaceSlug]/playground/search/page.tsx @@ -2,9 +2,9 @@ import DashboardPageWrapper from "@/components/dashboard-page-wrapper"; import ChunkExplorerPageClient from "./page.client"; -export default function ChunkExplorerPage() { +export default function SearchPage() { return ( - + ); diff --git a/apps/web/src/components/app-sidebar/links.ts b/apps/web/src/components/app-sidebar/links.ts index 572444c1..4121cf63 100644 --- a/apps/web/src/components/app-sidebar/links.ts +++ b/apps/web/src/components/app-sidebar/links.ts @@ -97,7 +97,7 @@ export const namespaceItems: SidebarItemType[] = [ exact: true, }, { - title: "Chunk Explorer", + title: "Search", url: createNamespaceUrl("/playground/search"), }, ], From faea1744f257de3362ed9a48a6bc3ef221fae1f5 Mon Sep 17 00:00:00 2001 From: ahmedriad1 Date: Wed, 15 Oct 2025 09:46:07 +0300 Subject: [PATCH 6/8] finalize search page --- .../playground/search/page.client.tsx | 221 +++++++----------- .../components/chat/chat-settings.store.ts | 3 +- apps/web/src/server/api/routers/search.ts | 131 ++--------- 3 files changed, 102 insertions(+), 253 deletions(-) diff --git a/apps/web/src/app/app.agentset.ai/(dashboard)/[slug]/[namespaceSlug]/playground/search/page.client.tsx b/apps/web/src/app/app.agentset.ai/(dashboard)/[slug]/[namespaceSlug]/playground/search/page.client.tsx index 7c8dc148..c80000a1 100644 --- a/apps/web/src/app/app.agentset.ai/(dashboard)/[slug]/[namespaceSlug]/playground/search/page.client.tsx +++ b/apps/web/src/app/app.agentset.ai/(dashboard)/[slug]/[namespaceSlug]/playground/search/page.client.tsx @@ -1,6 +1,7 @@ "use client"; import { useState } from "react"; +import { RerankerSelector } from "@/components/reranker-selector"; import SearchChunk from "@/components/search-chunk"; import { useNamespace } from "@/hooks/use-namespace"; import { logEvent } from "@/lib/analytics"; @@ -8,6 +9,7 @@ import { useTRPC } from "@/trpc/react"; import { useQuery } from "@tanstack/react-query"; import { SearchIcon } from "lucide-react"; +import type { RerankingModel } from "@agentset/validation"; import { Badge, Button, @@ -24,15 +26,15 @@ import { SelectTrigger, SelectValue, Skeleton, - Slider, Switch, } from "@agentset/ui"; +import { DEFAULT_RERANKER } from "@agentset/validation"; interface ChunkExplorerFilters { mode: "semantic" | "keyword"; topK: number; - minScore?: number; rerank: boolean; + rerankModel?: RerankingModel; rerankLimit?: number; filter?: Record; } @@ -41,23 +43,23 @@ export default function ChunkExplorerPageClient() { const namespace = useNamespace(); const [query, setQuery] = useState(""); const [searchQuery, setSearchQuery] = useState(""); - const [mode, setMode] = useState<"semantic" | "keyword">("semantic"); + const [topK, setTopK] = useState(20); const [rerank, setRerank] = useState(true); + const [rerankModel, setRerankModel] = + useState(DEFAULT_RERANKER); const [rerankLimit, setRerankLimit] = useState(20); - const [minScore, setMinScore] = useState(0); const trpc = useTRPC(); const { data, isLoading, isFetching, error } = useQuery( - trpc.search.exploreChunks.queryOptions( + trpc.search.search.queryOptions( { namespaceId: namespace.id, query: searchQuery, - mode, topK, rerank, + rerankModel, rerankLimit, - minScore, }, { enabled: searchQuery.length > 0, @@ -73,140 +75,102 @@ export default function ChunkExplorerPageClient() { logEvent("playground_search", { namespaceId: namespace.id, query, - mode, topK, rerank, + rerankModel, rerankLimit, - minScore, }); setSearchQuery(query); }; return ( -
- {/* Search Form */} - - -
-
- setQuery(e.target.value)} - placeholder="Enter your search query to explore chunks..." - className="flex-1" - /> - -
+
+ +
+ setQuery(e.target.value)} + placeholder="Enter your search query to explore chunks..." + className="flex-1" + /> + +
- {/* Quick Filters */} -
- {namespace.keywordEnabled && ( -
- - -
- )} +
+
+ + +
+ +
+ setRerank(checked)} + /> + +
+ + {rerank && ( + <> +
+ + +
- +
- -
- setRerank(checked)} - /> - -
- - {rerank && ( -
- - -
- )} -
- - {/* Filters */} -
-
- - - setMinScore(value && value > 0 ? value : 0) - } - max={1} - min={0} - step={0.01} - className="w-full" - /> -
-
- - - + + )} +
+ {/* Results */} -
+
{isFetching ? (
@@ -236,31 +200,12 @@ export default function ChunkExplorerPageClient() {
Search Results
- {data.mode} {data.totalResults} chunks found
-
-

- Query: {data.query} -

-
- Top K: {data.parameters.topK} - {data.parameters.minScore && ( - Min Score: {data.parameters.minScore.toFixed(2)} - )} - {data.parameters.rerank && ( - - Reranked:{" "} - {data.parameters.rerankLimit || data.parameters.topK} - - )} -
-
- {/* Chunks */}
{data.results.length > 0 ? ( data.results.map((result: any) => ( diff --git a/apps/web/src/components/chat/chat-settings.store.ts b/apps/web/src/components/chat/chat-settings.store.ts index af3ae5cb..a84740c6 100644 --- a/apps/web/src/components/chat/chat-settings.store.ts +++ b/apps/web/src/components/chat/chat-settings.store.ts @@ -49,6 +49,7 @@ const updateNamespace = ( namespaces: { ...state.namespaces, [namespaceId]: { + ...defaultState, ...state.namespaces[namespaceId], ...(update as NamespaceState), }, @@ -57,7 +58,7 @@ const updateNamespace = ( export const useChatSettings = create()( persist( - (set, get) => ({ + (set) => ({ namespaces: {}, setSettings: (namespaceId: string, newState: Partial) => set((state) => updateNamespace(state, namespaceId, newState)), diff --git a/apps/web/src/server/api/routers/search.ts b/apps/web/src/server/api/routers/search.ts index c3e5b79e..0176735f 100644 --- a/apps/web/src/server/api/routers/search.ts +++ b/apps/web/src/server/api/routers/search.ts @@ -1,4 +1,3 @@ -import { agenticSearch } from "@/lib/agentic/search"; import { incrementSearchUsage } from "@/lib/api/usage"; import { createTRPCRouter, protectedProcedure } from "@/server/api/trpc"; import { TRPCError } from "@trpc/server"; @@ -6,79 +5,25 @@ import { z } from "zod/v4"; import { getNamespaceEmbeddingModel, - getNamespaceLanguageModel, getNamespaceVectorStore, - KeywordStore, queryVectorStore, - QueryVectorStoreResult, } from "@agentset/engine"; +import { rerankerSchema } from "@agentset/validation"; import { getNamespaceByUser } from "../auth"; const chunkExplorerInputSchema = z.object({ namespaceId: z.string(), - query: z.string().min(1, "Query is required"), - mode: z.enum(["semantic", "keyword"]).default("semantic"), + query: z.string().min(1), topK: z.number().min(1).max(100).default(20), - minScore: z.number().min(0).max(1).optional(), rerank: z.boolean().default(true), + rerankModel: rerankerSchema, rerankLimit: z.number().min(1).max(100).optional(), filter: z.record(z.string(), z.any()).optional(), - includeMetadata: z.boolean().default(true), - includeRelationships: z.boolean().default(false), }); export const searchRouter = createTRPCRouter({ search: protectedProcedure - .input( - z.object({ - namespaceId: z.string(), - query: z.string(), - }), - ) - .query(async ({ ctx, input }) => { - const namespace = await getNamespaceByUser(ctx, { - id: input.namespaceId, - }); - - if (!namespace) { - throw new TRPCError({ code: "NOT_FOUND" }); - } - - const [model, vectorStore, embeddingModel] = await Promise.all([ - getNamespaceLanguageModel("openai:gpt-4.1"), - getNamespaceVectorStore(namespace), - getNamespaceEmbeddingModel(namespace, "query"), - ]); - - const results = await agenticSearch({ - model, - queryOptions: { - embeddingModel, - vectorStore, - topK: 50, - rerank: { model: "cohere:rerank-v3.5", limit: 15 }, - includeMetadata: true, - }, - messages: [ - { - role: "user", - content: input.query, - }, - ], - }); - - incrementSearchUsage(namespace.id, results.totalQueries); - - const chunks = Object.values(results.chunks); - - return { - results: chunks, - queries: results.queries, - }; - }), - - exploreChunks: protectedProcedure .input(chunkExplorerInputSchema) .query(async ({ ctx, input }) => { const namespace = await getNamespaceByUser(ctx, { @@ -89,72 +34,30 @@ export const searchRouter = createTRPCRouter({ throw new TRPCError({ code: "NOT_FOUND" }); } - // Check if keyword search is enabled when using keyword mode - if (input.mode === "keyword" && !namespace.keywordEnabled) { - throw new TRPCError({ - code: "BAD_REQUEST", - message: "Keyword search is not enabled for this namespace", - }); - } - const [embeddingModel, vectorStore] = await Promise.all([ getNamespaceEmbeddingModel(namespace, "query"), getNamespaceVectorStore(namespace), ]); - let results: QueryVectorStoreResult["results"] | undefined = []; - let queryPerformed = input.query; - - if (input.mode === "semantic") { - const queryResult = await queryVectorStore({ - query: input.query, - topK: input.topK, - minScore: input.minScore, - filter: input.filter, - includeMetadata: input.includeMetadata, - includeRelationships: input.includeRelationships, - rerank: input.rerank - ? { model: "cohere:rerank-v3.5", limit: input.rerankLimit } - : false, - embeddingModel, - vectorStore, - }); - - if (!queryResult) { - results = []; - } else { - results = queryResult.results; - } - } else { - // Keyword search - const keywordStore = new KeywordStore(namespace.id); - const keywordResult = await keywordStore.search(input.query, { - limit: input.topK, - minScore: input.minScore, - includeMetadata: input.includeMetadata, - includeRelationships: input.includeRelationships, - // TODO: convert pinecone filter to azure filter - // filter: input.filter, - }); - - results = keywordResult.results; - } + const queryResult = await queryVectorStore({ + query: input.query, + topK: input.topK, + filter: input.filter, + includeMetadata: true, + rerank: input.rerank + ? { model: input.rerankModel, limit: input.rerankLimit } + : false, + embeddingModel, + vectorStore, + }); // Track search usage incrementSearchUsage(namespace.id, 1); return { - results, - query: queryPerformed, - mode: input.mode, - totalResults: results?.length ?? 0, - parameters: { - topK: input.topK, - minScore: input.minScore, - rerank: input.rerank, - rerankLimit: input.rerankLimit, - filter: input.filter, - }, + results: queryResult.results, + query: queryResult.query, + totalResults: queryResult.results.length, }; }), }); From 9c534ef8e71bc1083ec1ce86a4a1b974ea33bbb1 Mon Sep 17 00:00:00 2001 From: ahmedriad1 Date: Wed, 15 Oct 2025 09:49:12 +0300 Subject: [PATCH 7/8] revert prisma output change --- packages/db/prisma/schema/schema.prisma | 2 +- packages/db/src/client.ts | 2 +- packages/db/src/index.ts | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/db/prisma/schema/schema.prisma b/packages/db/prisma/schema/schema.prisma index 4d16ddf9..18b1aed0 100644 --- a/packages/db/prisma/schema/schema.prisma +++ b/packages/db/prisma/schema/schema.prisma @@ -8,7 +8,7 @@ generator client { provider = "prisma-client-js" - output = "../../generated/prisma" + output = "../../generated/client" } generator json { diff --git a/packages/db/src/client.ts b/packages/db/src/client.ts index 265c808a..58bb2bf2 100644 --- a/packages/db/src/client.ts +++ b/packages/db/src/client.ts @@ -3,7 +3,7 @@ import { PrismaNeon } from "@prisma/adapter-neon"; // import ws from "ws"; -import { PrismaClient } from "../generated/prisma"; +import { PrismaClient } from "../generated/client"; const createPrismaClient = () => { if (typeof WebSocket === "undefined") { diff --git a/packages/db/src/index.ts b/packages/db/src/index.ts index 9c4700e1..1f9f9ee1 100644 --- a/packages/db/src/index.ts +++ b/packages/db/src/index.ts @@ -1,4 +1,4 @@ export { db } from "./client"; export * from "./types/prisma"; -export * from "../generated/prisma"; +export * from "../generated/client"; From 4b180fe3eb4b0eb93ee2278e00ed80b388276336 Mon Sep 17 00:00:00 2001 From: ahmedriad1 Date: Wed, 15 Oct 2025 10:01:26 +0300 Subject: [PATCH 8/8] refactor --- .../playground/search/page.client.tsx | 138 +++++++++--------- apps/web/src/server/api/routers/search.ts | 12 +- 2 files changed, 72 insertions(+), 78 deletions(-) diff --git a/apps/web/src/app/app.agentset.ai/(dashboard)/[slug]/[namespaceSlug]/playground/search/page.client.tsx b/apps/web/src/app/app.agentset.ai/(dashboard)/[slug]/[namespaceSlug]/playground/search/page.client.tsx index c80000a1..a7d1e3e9 100644 --- a/apps/web/src/app/app.agentset.ai/(dashboard)/[slug]/[namespaceSlug]/playground/search/page.client.tsx +++ b/apps/web/src/app/app.agentset.ai/(dashboard)/[slug]/[namespaceSlug]/playground/search/page.client.tsx @@ -15,8 +15,8 @@ import { Button, Card, CardContent, - CardHeader, CardTitle, + DataWrapper, EmptyState, Input, Label, @@ -30,15 +30,6 @@ import { } from "@agentset/ui"; import { DEFAULT_RERANKER } from "@agentset/validation"; -interface ChunkExplorerFilters { - mode: "semantic" | "keyword"; - topK: number; - rerank: boolean; - rerankModel?: RerankingModel; - rerankLimit?: number; - filter?: Record; -} - export default function ChunkExplorerPageClient() { const namespace = useNamespace(); const [query, setQuery] = useState(""); @@ -51,7 +42,7 @@ export default function ChunkExplorerPageClient() { const [rerankLimit, setRerankLimit] = useState(20); const trpc = useTRPC(); - const { data, isLoading, isFetching, error } = useQuery( + const { data, isLoading, isFetching, error, isEnabled } = useQuery( trpc.search.search.queryOptions( { namespaceId: namespace.id, @@ -171,67 +162,74 @@ export default function ChunkExplorerPageClient() { {/* Results */}
- {isFetching ? ( -
- - - - - -
- {Array.from({ length: 5 }).map((_, idx) => ( - - ))} -
-
- ) : error ? ( - - -
-

Error occurred

-

- {error.message} -

-
-
-
- ) : data ? ( -
-
- Search Results -
- - {data.totalResults} chunks found - + {isEnabled ? ( + +
+ Search Results +
+ +
+
+
+ {Array.from({ length: 5 }).map((_, idx) => ( + + ))} +
-
+ } + errorState={ + + +
+

Error occurred

+
+
+
+ } + emptyState={ + + +
+

+ No chunks found matching your criteria +

+

+ Try adjusting your query +

+
+
+
+ } + > + {(results) => ( +
+
+ Search Results +
+ + {results.length} chunks found + +
+
-
- {data.results.length > 0 ? ( - data.results.map((result: any) => ( - - )) - ) : ( - - -
-

- No chunks found matching your criteria -

-

- Try adjusting your query or filters -

-
-
-
- )} -
-
+
+ {results.map((result) => ( + + ))} +
+
+ )} + ) : (