@@ -17,6 +17,7 @@ import type {
1717 JsonObject ,
1818 JsonSchemaProperties ,
1919 RpcExecuteConfig ,
20+ SearchConfig ,
2021 ToolParameters ,
2122} from './types' ;
2223import { StackOneError } from './utils/error-stackone' ;
@@ -129,6 +130,17 @@ type AccountConfig = SimplifyDeep<MergeExclusive<SingleAccountConfig, MultipleAc
129130interface StackOneToolSetBaseConfig extends BaseToolSetConfig {
130131 apiKey ?: string ;
131132 strict ?: boolean ;
133+ /**
134+ * Search configuration. Controls default search behavior for `searchTools()`,
135+ * `getSearchTool()`, and `searchActionNames()`.
136+ *
137+ * - Omit or pass `undefined` → search enabled with defaults (`method: 'auto'`)
138+ * - Pass `null` → search disabled
139+ * - Pass `{ method, topK, minSimilarity }` → search enabled with custom defaults
140+ *
141+ * Per-call options always override these defaults.
142+ */
143+ search ?: SearchConfig | null ;
132144}
133145
134146/**
@@ -215,24 +227,27 @@ export interface SearchActionNamesOptions {
215227 */
216228export class SearchTool {
217229 private readonly toolset : StackOneToolSet ;
218- private readonly defaultSearch : SearchMode ;
230+ private readonly defaultConfig : SearchConfig ;
219231
220- constructor ( toolset : StackOneToolSet , search : SearchMode = 'auto' ) {
232+ constructor ( toolset : StackOneToolSet , config : SearchConfig = { } ) {
221233 this . toolset = toolset ;
222- this . defaultSearch = search ;
234+ this . defaultConfig = config ;
223235 }
224236
225237 /**
226238 * Search for tools using natural language.
227239 *
228240 * @param query - Natural language description of needed functionality
229- * @param options - Search options (connector, topK, minSimilarity, accountIds, search)
241+ * @param options - Search options (connector, topK, minSimilarity, accountIds, search).
242+ * Per-call options override the defaults from the constructor config.
230243 * @returns Tools collection with matched tools
231244 */
232245 async search ( query : string , options ?: SearchToolsOptions ) : Promise < Tools > {
233246 return this . toolset . searchTools ( query , {
234247 ...options ,
235- search : options ?. search ?? this . defaultSearch ,
248+ search : options ?. search ?? this . defaultConfig . method ,
249+ topK : options ?. topK ?? this . defaultConfig . topK ,
250+ minSimilarity : options ?. minSimilarity ?? this . defaultConfig . minSimilarity ,
236251 } ) ;
237252 }
238253}
@@ -245,6 +260,7 @@ export class StackOneToolSet {
245260 private authentication ?: AuthenticationConfig ;
246261 private headers : Record < string , string > ;
247262 private rpcClient ?: RpcClient ;
263+ private readonly searchConfig : SearchConfig | null ;
248264
249265 /**
250266 * Account ID for StackOne API
@@ -301,6 +317,9 @@ export class StackOneToolSet {
301317 this . accountId = accountId ;
302318 this . accountIds = config ?. accountIds ?? [ ] ;
303319
320+ // Resolve search config: undefined → defaults, null → disabled, object → custom
321+ this . searchConfig = config ?. search === null ? null : { method : 'auto' , ...config ?. search } ;
322+
304323 // Set Authentication headers if provided
305324 if ( this . authentication ) {
306325 // Only set auth headers if they don't already exist in custom headers
@@ -400,7 +419,17 @@ export class StackOneToolSet {
400419 * ```
401420 */
402421 getSearchTool ( options ?: { search ?: SearchMode } ) : SearchTool {
403- return new SearchTool ( this , options ?. search ?? 'auto' ) ;
422+ if ( this . searchConfig === null ) {
423+ throw new ToolSetConfigError (
424+ 'Search is disabled. Initialize StackOneToolSet with a search config to enable.' ,
425+ ) ;
426+ }
427+
428+ const config : SearchConfig = options ?. search
429+ ? { ...this . searchConfig , method : options . search }
430+ : this . searchConfig ;
431+
432+ return new SearchTool ( this , config ) ;
404433 }
405434
406435 /**
@@ -433,8 +462,18 @@ export class StackOneToolSet {
433462 * ```
434463 */
435464 async searchTools ( query : string , options ?: SearchToolsOptions ) : Promise < Tools > {
436- const search = options ?. search ?? 'auto' ;
437- const allTools = await this . fetchTools ( { accountIds : options ?. accountIds } ) ;
465+ if ( this . searchConfig === null ) {
466+ throw new ToolSetConfigError (
467+ 'Search is disabled. Initialize StackOneToolSet with a search config to enable.' ,
468+ ) ;
469+ }
470+
471+ const search = options ?. search ?? this . searchConfig . method ?? 'auto' ;
472+ const topK = options ?. topK ?? this . searchConfig . topK ;
473+ const minSimilarity = options ?. minSimilarity ?? this . searchConfig . minSimilarity ;
474+ const mergedOptions = { ...options , search, topK, minSimilarity } ;
475+
476+ const allTools = await this . fetchTools ( { accountIds : mergedOptions . accountIds } ) ;
438477 const availableConnectors = allTools . getConnectors ( ) ;
439478
440479 if ( availableConnectors . size === 0 ) {
@@ -443,14 +482,14 @@ export class StackOneToolSet {
443482
444483 // Local-only search — skip semantic API entirely
445484 if ( search === 'local' ) {
446- return this . localSearch ( query , allTools , options ) ;
485+ return this . localSearch ( query , allTools , mergedOptions ) ;
447486 }
448487
449488 try {
450489 // Determine which connectors to search
451490 let connectorsToSearch : Set < string > ;
452- if ( options ? .connector ) {
453- const connectorLower = options . connector . toLowerCase ( ) ;
491+ if ( mergedOptions . connector ) {
492+ const connectorLower = mergedOptions . connector . toLowerCase ( ) ;
454493 connectorsToSearch = availableConnectors . has ( connectorLower )
455494 ? new Set ( [ connectorLower ] )
456495 : new Set ( ) ;
@@ -468,7 +507,7 @@ export class StackOneToolSet {
468507 client = this . getSemanticClient ( ) ;
469508 } catch ( error ) {
470509 if ( search === 'auto' && error instanceof ToolSetConfigError ) {
471- return this . localSearch ( query , allTools , options ) ;
510+ return this . localSearch ( query , allTools , mergedOptions ) ;
472511 }
473512 throw error ;
474513 }
@@ -479,8 +518,8 @@ export class StackOneToolSet {
479518 try {
480519 const response = await client . search ( query , {
481520 connector,
482- topK : options ? .topK ,
483- minSimilarity : options ? .minSimilarity ,
521+ topK : mergedOptions . topK ,
522+ minSimilarity : mergedOptions . minSimilarity ,
484523 } ) ;
485524 return response . results ;
486525 } catch ( error ) {
@@ -504,7 +543,7 @@ export class StackOneToolSet {
504543
505544 // Sort by score, apply topK
506545 allResults . sort ( ( a , b ) => b . similarityScore - a . similarityScore ) ;
507- const topResults = options ? .topK != null ? allResults . slice ( 0 , options . topK ) : allResults ;
546+ const topResults = mergedOptions . topK != null ? allResults . slice ( 0 , mergedOptions . topK ) : allResults ;
508547
509548 if ( topResults . length === 0 ) {
510549 return new Tools ( [ ] ) ;
@@ -530,7 +569,7 @@ export class StackOneToolSet {
530569 }
531570
532571 // Auto mode: silently fall back to local search
533- return this . localSearch ( query , allTools , options ) ;
572+ return this . localSearch ( query , allTools , mergedOptions ) ;
534573 }
535574 throw error ;
536575 }
@@ -565,6 +604,15 @@ export class StackOneToolSet {
565604 query : string ,
566605 options ?: SearchActionNamesOptions ,
567606 ) : Promise < SemanticSearchResult [ ] > {
607+ if ( this . searchConfig === null ) {
608+ throw new ToolSetConfigError (
609+ 'Search is disabled. Initialize StackOneToolSet with a search config to enable.' ,
610+ ) ;
611+ }
612+
613+ const effectiveTopK = options ?. topK ?? this . searchConfig . topK ;
614+ const effectiveMinSimilarity = options ?. minSimilarity ?? this . searchConfig . minSimilarity ;
615+
568616 // Resolve available connectors from account IDs
569617 let availableConnectors : Set < string > | undefined ;
570618 const effectiveAccountIds = options ?. accountIds || this . accountIds ;
@@ -596,8 +644,8 @@ export class StackOneToolSet {
596644 try {
597645 const response = await client . search ( query , {
598646 connector,
599- topK : options ?. topK ,
600- minSimilarity : options ?. minSimilarity ,
647+ topK : effectiveTopK ,
648+ minSimilarity : effectiveMinSimilarity ,
601649 } ) ;
602650 return response . results ;
603651 } catch {
@@ -613,8 +661,8 @@ export class StackOneToolSet {
613661 // No account filtering — single global search
614662 const response = await client . search ( query , {
615663 connector : options ?. connector ,
616- topK : options ?. topK ,
617- minSimilarity : options ?. minSimilarity ,
664+ topK : effectiveTopK ,
665+ minSimilarity : effectiveMinSimilarity ,
618666 } ) ;
619667 allResults = response . results ;
620668 }
@@ -626,7 +674,7 @@ export class StackOneToolSet {
626674 actionName : normalizeActionName ( r . actionName ) ,
627675 } ) ) ;
628676
629- return options ?. topK != null ? normalized . slice ( 0 , options . topK ) : normalized ;
677+ return effectiveTopK != null ? normalized . slice ( 0 , effectiveTopK ) : normalized ;
630678 } catch ( error ) {
631679 if ( error instanceof SemanticSearchError ) {
632680 return [ ] ;
0 commit comments