@@ -262,3 +262,119 @@ describe('createExecuteTool', () => {
262262 expect ( result ) . toEqual ( { ok : true } ) ;
263263 } ) ;
264264} ) ;
265+
266+ describe ( 'StackOneToolSet.openai()' , ( ) => {
267+ function createMockToolSetInstance ( options ?: {
268+ executeConfig ?: { accountIds ?: string [ ] } ;
269+ searchConfig ?: Record < string , unknown > ;
270+ } ) : {
271+ toolset : {
272+ fetchTools : ReturnType < typeof vi . fn > ;
273+ getMetaTools : ReturnType < typeof vi . fn > ;
274+ openai : ( opts ?: { mode ?: 'search_and_execute' ; accountIds ?: string [ ] } ) => Promise < unknown [ ] > ;
275+ } ;
276+ } {
277+ const mockTool = new BaseTool (
278+ 'test_tool' ,
279+ 'A test tool' ,
280+ { type : 'object' , properties : { } } satisfies ToolParameters ,
281+ { kind : 'local' , identifier : 'test:mock' } ,
282+ ) ;
283+ const tools = new Tools ( [ mockTool ] ) ;
284+
285+ const metaSearchTool = new BaseTool (
286+ 'tool_search' ,
287+ 'Search for tools' ,
288+ { type : 'object' , properties : { query : { type : 'string' } } } satisfies ToolParameters ,
289+ { kind : 'local' , identifier : 'meta:search' } ,
290+ ) ;
291+ const metaExecuteTool = new BaseTool (
292+ 'tool_execute' ,
293+ 'Execute a tool' ,
294+ { type : 'object' , properties : { tool_name : { type : 'string' } } } satisfies ToolParameters ,
295+ { kind : 'local' , identifier : 'meta:execute' } ,
296+ ) ;
297+ const metaTools = new Tools ( [ metaSearchTool , metaExecuteTool ] ) ;
298+
299+ const fetchTools = vi . fn ( ) . mockResolvedValue ( tools ) ;
300+ const getMetaTools = vi . fn ( ) . mockReturnValue ( metaTools ) ;
301+
302+ const executeConfig = options ?. executeConfig ;
303+
304+ const toolset = {
305+ fetchTools,
306+ getMetaTools,
307+ async openai ( opts ?: { mode ?: 'search_and_execute' ; accountIds ?: string [ ] } ) : Promise < unknown [ ] > {
308+ const effectiveAccountIds = opts ?. accountIds ?? executeConfig ?. accountIds ;
309+
310+ if ( opts ?. mode === 'search_and_execute' ) {
311+ return getMetaTools ( { accountIds : effectiveAccountIds } ) . toOpenAI ( ) ;
312+ }
313+
314+ const fetchedTools = await fetchTools ( { accountIds : effectiveAccountIds } ) ;
315+ return fetchedTools . toOpenAI ( ) ;
316+ } ,
317+ } ;
318+
319+ return { toolset } ;
320+ }
321+
322+ it ( 'default fetches all tools' , async ( ) => {
323+ const { toolset } = createMockToolSetInstance ( ) ;
324+
325+ const result = await toolset . openai ( ) ;
326+
327+ expect ( toolset . fetchTools ) . toHaveBeenCalledOnce ( ) ;
328+ expect ( toolset . fetchTools ) . toHaveBeenCalledWith ( { accountIds : undefined } ) ;
329+ expect ( result ) . toHaveLength ( 1 ) ;
330+ expect ( result [ 0 ] ) . toHaveProperty ( 'type' , 'function' ) ;
331+ } ) ;
332+
333+ it ( 'search_and_execute returns meta tools' , async ( ) => {
334+ const { toolset } = createMockToolSetInstance ( ) ;
335+
336+ const result = await toolset . openai ( { mode : 'search_and_execute' } ) ;
337+
338+ expect ( toolset . getMetaTools ) . toHaveBeenCalledOnce ( ) ;
339+ expect ( toolset . fetchTools ) . not . toHaveBeenCalled ( ) ;
340+ expect ( result ) . toHaveLength ( 2 ) ;
341+ } ) ;
342+
343+ it ( 'passes accountIds to fetchTools' , async ( ) => {
344+ const { toolset } = createMockToolSetInstance ( ) ;
345+
346+ await toolset . openai ( { accountIds : [ 'acc-1' ] } ) ;
347+
348+ expect ( toolset . fetchTools ) . toHaveBeenCalledWith ( { accountIds : [ 'acc-1' ] } ) ;
349+ } ) ;
350+
351+ it ( 'uses executeConfig.accountIds as fallback' , async ( ) => {
352+ const { toolset } = createMockToolSetInstance ( {
353+ executeConfig : { accountIds : [ 'default-acc' ] } ,
354+ } ) ;
355+
356+ await toolset . openai ( ) ;
357+
358+ expect ( toolset . fetchTools ) . toHaveBeenCalledWith ( { accountIds : [ 'default-acc' ] } ) ;
359+ } ) ;
360+
361+ it ( 'accountIds overrides executeConfig' , async ( ) => {
362+ const { toolset } = createMockToolSetInstance ( {
363+ executeConfig : { accountIds : [ 'default-acc' ] } ,
364+ } ) ;
365+
366+ await toolset . openai ( { accountIds : [ 'override-acc' ] } ) ;
367+
368+ expect ( toolset . fetchTools ) . toHaveBeenCalledWith ( { accountIds : [ 'override-acc' ] } ) ;
369+ } ) ;
370+
371+ it ( 'search_and_execute with executeConfig passes accountIds to getMetaTools' , async ( ) => {
372+ const { toolset } = createMockToolSetInstance ( {
373+ executeConfig : { accountIds : [ 'meta-acc' ] } ,
374+ } ) ;
375+
376+ await toolset . openai ( { mode : 'search_and_execute' } ) ;
377+
378+ expect ( toolset . getMetaTools ) . toHaveBeenCalledWith ( { accountIds : [ 'meta-acc' ] } ) ;
379+ } ) ;
380+ } ) ;
0 commit comments