@@ -2,6 +2,14 @@ import type { AuthStrategy } from '../auth/types.js';
22import type { RetryConfig } from '../config.js' ;
33import { createConfig } from '../config.js' ;
44import { HttpTransport } from '../http.js' ;
5+ import type {
6+ HybridConfig ,
7+ SearchRequest ,
8+ VectorBoostConfig ,
9+ VectorFieldSearch ,
10+ VectorSearch ,
11+ } from './models.js' ;
12+ import { SearchMode , buildSearchBody , mergeExtra } from './models.js' ;
513
614function cleanPrefix ( prefix : string ) : string {
715 const value = prefix . replace ( / ^ \/ + | \/ + $ / g, '' ) ;
@@ -24,6 +32,65 @@ export interface FluxClientOptions {
2432 defaultHeaders ?: Record < string , string > ;
2533}
2634
35+ export interface VectorSearchOptions {
36+ query : string ;
37+ fields ?: string [ ] ;
38+ top_k ?: number ;
39+ similarity_threshold ?: number ;
40+ limit ?: number ;
41+ offset ?: number ;
42+ [ extra : string ] : any ;
43+ }
44+
45+ export interface VectorFieldSearchOptions {
46+ field : string ;
47+ query_vector : number [ ] ;
48+ top_k ?: number ;
49+ similarity_threshold ?: number ;
50+ limit ?: number ;
51+ offset ?: number ;
52+ [ extra : string ] : any ;
53+ }
54+
55+ export interface HybridSearchOptions {
56+ query : string ;
57+ find_text : Record < string , any > ;
58+ fields ?: string [ ] ;
59+ top_k ?: number ;
60+ similarity_threshold ?: number ;
61+ vector_weight ?: number ;
62+ text_weight ?: number ;
63+ rerank_results ?: boolean ;
64+ limit ?: number ;
65+ offset ?: number ;
66+ [ extra : string ] : any ;
67+ }
68+
69+ export interface BoostedSearchOptions {
70+ find_text : Record < string , any > ;
71+ query ?: string ;
72+ field ?: string ;
73+ query_vector ?: number [ ] ;
74+ top_k ?: number ;
75+ similarity_threshold ?: number ;
76+ boost_factor ?: number ;
77+ boost_similarity_threshold ?: number ;
78+ max_boost_results ?: number ;
79+ limit ?: number ;
80+ offset ?: number ;
81+ [ extra : string ] : any ;
82+ }
83+
84+ function stripUndefined ( obj : Record < string , any > ) : Record < string , any > {
85+ const result : Record < string , any > = { } ;
86+ for ( const [ key , value ] of Object . entries ( obj ) ) {
87+ if ( value !== undefined ) {
88+ result [ key ] = value ;
89+ }
90+ }
91+ return result ;
92+ }
93+
2794/**
2895 * Client for FoxNose Flux delivery APIs.
2996 *
@@ -72,6 +139,138 @@ export class FluxClient {
72139 return this . transport . request ( 'POST' , path , { jsonBody : body } ) ;
73140 }
74141
142+ /** Semantic search using auto-generated embeddings. */
143+ async vectorSearch < T = any > ( folderPath : string , options : VectorSearchOptions ) : Promise < T > {
144+ const { query, fields, top_k = 10 , similarity_threshold, limit, offset, ...rest } = options ;
145+ const extra = stripUndefined ( rest ) ;
146+ const vs : VectorSearch = { query, fields, top_k, similarity_threshold } ;
147+ const req : SearchRequest = {
148+ search_mode : SearchMode . VECTOR ,
149+ vector_search : vs ,
150+ limit,
151+ offset,
152+ } ;
153+ const body = mergeExtra ( buildSearchBody ( req ) , extra ) ;
154+ return this . search ( folderPath , body ) ;
155+ }
156+
157+ /** Search using custom pre-computed embeddings. */
158+ async vectorFieldSearch < T = any > (
159+ folderPath : string ,
160+ options : VectorFieldSearchOptions ,
161+ ) : Promise < T > {
162+ const {
163+ field,
164+ query_vector,
165+ top_k = 10 ,
166+ similarity_threshold,
167+ limit,
168+ offset,
169+ ...rest
170+ } = options ;
171+ const extra = stripUndefined ( rest ) ;
172+ const vfs : VectorFieldSearch = { field, query_vector, top_k, similarity_threshold } ;
173+ const req : SearchRequest = {
174+ search_mode : SearchMode . VECTOR ,
175+ vector_field_search : vfs ,
176+ limit,
177+ offset,
178+ } ;
179+ const body = mergeExtra ( buildSearchBody ( req ) , extra ) ;
180+ return this . search ( folderPath , body ) ;
181+ }
182+
183+ /** Blended text + vector search with configurable weights. */
184+ async hybridSearch < T = any > ( folderPath : string , options : HybridSearchOptions ) : Promise < T > {
185+ const {
186+ query,
187+ find_text,
188+ fields,
189+ top_k = 10 ,
190+ similarity_threshold,
191+ vector_weight = 0.6 ,
192+ text_weight = 0.4 ,
193+ rerank_results = true ,
194+ limit,
195+ offset,
196+ ...rest
197+ } = options ;
198+ const extra = stripUndefined ( rest ) ;
199+ const vs : VectorSearch = { query, fields, top_k, similarity_threshold } ;
200+ const hybrid : HybridConfig = { vector_weight, text_weight, rerank_results } ;
201+ const req : SearchRequest = {
202+ search_mode : SearchMode . HYBRID ,
203+ find_text,
204+ vector_search : vs ,
205+ hybrid_config : hybrid ,
206+ limit,
207+ offset,
208+ } ;
209+ const body = mergeExtra ( buildSearchBody ( req ) , extra ) ;
210+ return this . search ( folderPath , body ) ;
211+ }
212+
213+ /** Text search with results boosted by vector similarity. */
214+ async boostedSearch < T = any > ( folderPath : string , options : BoostedSearchOptions ) : Promise < T > {
215+ const {
216+ find_text,
217+ query,
218+ field,
219+ query_vector,
220+ top_k = 10 ,
221+ similarity_threshold,
222+ boost_factor = 1.5 ,
223+ boost_similarity_threshold,
224+ max_boost_results = 20 ,
225+ limit,
226+ offset,
227+ ...rest
228+ } = options ;
229+ const extra = stripUndefined ( rest ) ;
230+
231+ const hasAuto = query != null ;
232+ const hasCustom = field != null || query_vector != null ;
233+
234+ if ( hasAuto && hasCustom ) {
235+ throw new Error (
236+ "Provide either 'query' for auto-generated embeddings " +
237+ "or 'field' + 'query_vector' for custom embeddings, not both" ,
238+ ) ;
239+ }
240+
241+ let vs : VectorSearch | undefined ;
242+ let vfs : VectorFieldSearch | undefined ;
243+
244+ if ( hasAuto ) {
245+ vs = { query : query ! , top_k, similarity_threshold } ;
246+ } else if ( field != null && query_vector != null ) {
247+ vfs = { field, query_vector, top_k, similarity_threshold } ;
248+ } else {
249+ throw new Error (
250+ "Provide either 'query' for auto-generated embeddings " +
251+ "or 'field' + 'query_vector' for custom embeddings" ,
252+ ) ;
253+ }
254+
255+ const boostConfig : VectorBoostConfig = {
256+ boost_factor,
257+ similarity_threshold : boost_similarity_threshold ,
258+ max_boost_results,
259+ } ;
260+
261+ const req : SearchRequest = {
262+ search_mode : SearchMode . VECTOR_BOOSTED ,
263+ find_text,
264+ vector_search : vs ,
265+ vector_field_search : vfs ,
266+ vector_boost_config : boostConfig ,
267+ limit,
268+ offset,
269+ } ;
270+ const body = mergeExtra ( buildSearchBody ( req ) , extra ) ;
271+ return this . search ( folderPath , body ) ;
272+ }
273+
75274 async getRouter < T = any > ( ) : Promise < T > {
76275 const path = `/${ this . apiPrefix } /_router` ;
77276 return this . transport . request ( 'GET' , path ) ;
0 commit comments