diff --git a/packages/search/.env.example b/packages/search/.env.example index 557ac82..647f4a0 100644 --- a/packages/search/.env.example +++ b/packages/search/.env.example @@ -1,2 +1,2 @@ -VECTOR_STORE_ID= +STORE_ID= MXBAI_API_KEY= \ No newline at end of file diff --git a/packages/search/package.json b/packages/search/package.json index afdefc3..4676197 100644 --- a/packages/search/package.json +++ b/packages/search/package.json @@ -11,7 +11,7 @@ "check-types": "tsc --noEmit" }, "dependencies": { - "@mixedbread/sdk": "^0.26.0", + "@mixedbread/sdk": "^0.78.0", "@radix-ui/react-dialog": "^1.1.14", "@radix-ui/react-scroll-area": "^1.2.9", "@radix-ui/react-slot": "^1.2.3", diff --git a/packages/search/src/app/api/search/route.ts b/packages/search/src/app/api/search/route.ts index f4c7a5d..f18c042 100644 --- a/packages/search/src/app/api/search/route.ts +++ b/packages/search/src/app/api/search/route.ts @@ -9,10 +9,10 @@ interface SearchMetadata { export const GET = adapters.nextAppHandler({ transform: (results) => { return results.map((result) => { - const metadata = result.chunks?.[0].generated_metadata as SearchMetadata; + const metadata = (result.generated_metadata ?? {}) as SearchMetadata; return { - id: result.id, + id: result.file_id, url: metadata.url || "#", title: metadata.title || "Untitled", tag: metadata.tag || "", diff --git a/packages/search/src/search/lib/fumadocs.ts b/packages/search/src/search/lib/fumadocs.ts index 73e67aa..6b162f9 100644 --- a/packages/search/src/search/lib/fumadocs.ts +++ b/packages/search/src/search/lib/fumadocs.ts @@ -1,12 +1,12 @@ import type Mixedbread from "@mixedbread/sdk"; -import type { VectorStoreSearchResponse } from "@mixedbread/sdk/resources/vector-stores"; +import type { StoreSearchResponse } from "@mixedbread/sdk/resources/stores"; import type { SearchMetadata } from "./types"; export interface MixedbreadOptions { /** * The ID of the store to search in */ - vectorStoreId: string; + storeId: string; /** * The Mixedbread SDK client instance @@ -31,7 +31,7 @@ interface SortedResult { url: string; } -type VectorStoreSearchResult = VectorStoreSearchResponse["data"][number] & { +type StoreSearchResult = StoreSearchResponse["data"][number] & { generated_metadata: SearchMetadata; }; @@ -39,22 +39,22 @@ export async function search( query: string, options: MixedbreadOptions ): Promise { - const { client, vectorStoreId, tag } = options; + const { client, storeId, tag } = options; if (!query.trim()) { return []; } - const res = await client.vectorStores.search({ + const res = await client.stores.search({ query, - vector_store_identifiers: [vectorStoreId], + store_identifiers: [storeId], top_k: 10, search_options: { return_metadata: true, }, }); - const results = (res.data as VectorStoreSearchResult[]) + const results = (res.data as StoreSearchResult[]) .filter((item) => { const metadata = item.generated_metadata; return !tag || metadata.tag === tag; diff --git a/packages/search/src/search/lib/search.ts b/packages/search/src/search/lib/search.ts index 00dfd4e..928eb10 100644 --- a/packages/search/src/search/lib/search.ts +++ b/packages/search/src/search/lib/search.ts @@ -7,7 +7,7 @@ export async function search( rawParams: Record, transform?: TransformFunc ): Promise { - if (!process.env.MXBAI_API_KEY || !process.env.VECTOR_STORE_ID) { + if (!process.env.MXBAI_API_KEY || !process.env.STORE_ID) { throw new InternalServerError("Environment setup failed"); } @@ -22,24 +22,29 @@ export async function search( const { query, topK } = data; - const res = await mxbai.vectorStores.files.search({ + const res = await mxbai.stores.search({ query, - vector_store_identifiers: [process.env.VECTOR_STORE_ID], + store_identifiers: [process.env.STORE_ID], top_k: topK, search_options: { return_metadata: true, - return_chunks: true, }, }); + // Chunks come back best-first, so the first one per file is its best match + const files = res.data.filter( + (item, index) => + res.data.findIndex((other) => other.file_id === item.file_id) === index + ); + if (transform) { - return transform(res.data); + return transform(files); } - const results = res.data.map((item) => { + const results = files.map((item) => { const metadata = item.metadata as SearchMetadata; return { - id: item.id, + id: item.file_id, url: metadata?.url || "#", title: metadata?.title || "Untitled", tag: metadata?.tag || "all", diff --git a/packages/search/src/search/lib/types.ts b/packages/search/src/search/lib/types.ts index 7a1b747..a18385b 100644 --- a/packages/search/src/search/lib/types.ts +++ b/packages/search/src/search/lib/types.ts @@ -1,4 +1,4 @@ -import type { FileSearchResponse } from "@mixedbread/sdk/resources/vector-stores.mjs"; +import type { StoreSearchResponse } from "@mixedbread/sdk/resources/stores"; import type { z } from "zod"; import type { SearchQuerySchema } from "./validations"; @@ -21,7 +21,7 @@ export interface Result { export type SearchQuery = z.infer; -export type TransformFunc = (results: FileSearchResponse["data"]) => Result[]; +export type TransformFunc = (results: StoreSearchResponse["data"]) => Result[]; export type Message = | { diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 5c18bd1..921e100 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -103,8 +103,8 @@ importers: packages/search: dependencies: '@mixedbread/sdk': - specifier: ^0.26.0 - version: 0.26.0 + specifier: ^0.78.0 + version: 0.78.0 '@radix-ui/react-dialog': specifier: ^1.1.14 version: 1.1.15(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) @@ -755,14 +755,14 @@ packages: '@manypkg/get-packages@1.1.3': resolution: {integrity: sha512-fo+QhuU3qE/2TQMQmbVMqaQ6EWbMhi4ABWP+O4AM1NqPBuy0OrApV5LO6BrrgnhtAHS2NH6RrVk9OL181tTi8A==} - '@mixedbread/sdk@0.26.0': - resolution: {integrity: sha512-B0Un0thpz4UKN69QVmgdVsCIgiz+jR4V+nxuCOgdm/P0Iie1NctqY092VQ/iobY/FSMzhHJofXij086y/9E5rg==} - hasBin: true - '@mixedbread/sdk@0.77.0': resolution: {integrity: sha512-OxVkpVoJpdCGSo1v1Nu6tDiSv7M17LXT9A0LOT97WnkiGaHTranfeTioUI1XuQYfqXiAftPWC6eznswW9AB0DA==} hasBin: true + '@mixedbread/sdk@0.78.0': + resolution: {integrity: sha512-gd5F8jaMt+mwRPzPBkLuXwP8jbR5dQQul5uuJomHrxGaO6Msff92Zu4rMXjZRyI8JYhQIDbzGqy9uSxjSz1YWA==} + hasBin: true + '@napi-rs/wasm-runtime@0.2.12': resolution: {integrity: sha512-ZVWUcfwY4E/yPitQJl481FjFo3K22D6qF0DuFH6Y/nbnE11GY5uguDxZMGXPQ8WQ0128MXQD7TnfHyK4oWoIJQ==} @@ -4103,10 +4103,10 @@ snapshots: globby: 11.1.0 read-yaml-file: 1.1.0 - '@mixedbread/sdk@0.26.0': {} - '@mixedbread/sdk@0.77.0': {} + '@mixedbread/sdk@0.78.0': {} + '@napi-rs/wasm-runtime@0.2.12': dependencies: '@emnapi/core': 1.8.1