@optimizely-opal/opal-tool-ocp-sdk 0.0.0-OCP-1487.9 → 0.0.0-OCP-1487.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +29 -70
- package/dist/decorator/Decorator.d.ts +0 -6
- package/dist/decorator/Decorator.d.ts.map +1 -1
- package/dist/decorator/Decorator.js +2 -32
- package/dist/decorator/Decorator.js.map +1 -1
- package/dist/decorator/Decorator.test.js +11 -205
- package/dist/decorator/Decorator.test.js.map +1 -1
- package/dist/index.d.ts +0 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +0 -1
- package/dist/index.js.map +1 -1
- package/dist/service/Service.d.ts +2 -20
- package/dist/service/Service.d.ts.map +1 -1
- package/dist/service/Service.js +4 -41
- package/dist/service/Service.js.map +1 -1
- package/dist/service/Service.test.js +1 -92
- package/dist/service/Service.test.js.map +1 -1
- package/package.json +1 -1
- package/src/decorator/Decorator.test.ts +10 -305
- package/src/decorator/Decorator.ts +2 -44
- package/src/index.ts +0 -1
- package/src/service/Service.test.ts +1 -170
- package/src/service/Service.ts +4 -46
- package/dist/utils/ImportUtils.d.ts +0 -15
- package/dist/utils/ImportUtils.d.ts.map +0 -1
- package/dist/utils/ImportUtils.js +0 -77
- package/dist/utils/ImportUtils.js.map +0 -1
- package/src/utils/ImportUtils.ts +0 -45
|
@@ -9,9 +9,6 @@ jest.mock('../service/Service', () => ({
|
|
|
9
9
|
registerInteraction: jest.fn()
|
|
10
10
|
}
|
|
11
11
|
}));
|
|
12
|
-
|
|
13
|
-
// Mock base class for testing auto-detection
|
|
14
|
-
class GlobalToolFunction {}
|
|
15
12
|
describe('Decorators', () => {
|
|
16
13
|
beforeEach(() => {
|
|
17
14
|
jest.clearAllMocks();
|
|
@@ -39,8 +36,7 @@ describe('Decorators', () => {
|
|
|
39
36
|
expect.any(Function),
|
|
40
37
|
[],
|
|
41
38
|
'/test-tool',
|
|
42
|
-
[]
|
|
43
|
-
false
|
|
39
|
+
[]
|
|
44
40
|
);
|
|
45
41
|
|
|
46
42
|
// Ensure TestClass is considered "used" by TypeScript
|
|
@@ -82,8 +78,7 @@ describe('Decorators', () => {
|
|
|
82
78
|
})
|
|
83
79
|
]),
|
|
84
80
|
'/tool-with-params',
|
|
85
|
-
[]
|
|
86
|
-
false
|
|
81
|
+
[]
|
|
87
82
|
);
|
|
88
83
|
|
|
89
84
|
// Ensure TestClass is considered "used" by TypeScript
|
|
@@ -124,8 +119,7 @@ describe('Decorators', () => {
|
|
|
124
119
|
scopeBundle: 'calendar',
|
|
125
120
|
required: true
|
|
126
121
|
})
|
|
127
|
-
])
|
|
128
|
-
false
|
|
122
|
+
])
|
|
129
123
|
);
|
|
130
124
|
|
|
131
125
|
// Ensure TestClass is considered "used" by TypeScript
|
|
@@ -206,8 +200,7 @@ describe('Decorators', () => {
|
|
|
206
200
|
scopeBundle: 'drive',
|
|
207
201
|
required: false
|
|
208
202
|
})
|
|
209
|
-
])
|
|
210
|
-
false
|
|
203
|
+
])
|
|
211
204
|
);
|
|
212
205
|
|
|
213
206
|
// Ensure TestClass is considered "used" by TypeScript
|
|
@@ -235,8 +228,7 @@ describe('Decorators', () => {
|
|
|
235
228
|
expect.any(Function),
|
|
236
229
|
[],
|
|
237
230
|
'/empty-params',
|
|
238
|
-
[]
|
|
239
|
-
false
|
|
231
|
+
[]
|
|
240
232
|
);
|
|
241
233
|
|
|
242
234
|
expect(TestClass).toBeDefined();
|
|
@@ -264,8 +256,7 @@ describe('Decorators', () => {
|
|
|
264
256
|
expect.any(Function),
|
|
265
257
|
[],
|
|
266
258
|
'/no-auth',
|
|
267
|
-
[]
|
|
268
|
-
false
|
|
259
|
+
[]
|
|
269
260
|
);
|
|
270
261
|
|
|
271
262
|
expect(TestClass).toBeDefined();
|
|
@@ -332,8 +323,7 @@ describe('Decorators', () => {
|
|
|
332
323
|
expect.objectContaining({ name: 'dictParam', type: ParameterType.Dictionary })
|
|
333
324
|
]),
|
|
334
325
|
'/multi-type',
|
|
335
|
-
[]
|
|
336
|
-
false
|
|
326
|
+
[]
|
|
337
327
|
);
|
|
338
328
|
});
|
|
339
329
|
});
|
|
@@ -452,8 +442,7 @@ describe('Decorators', () => {
|
|
|
452
442
|
})
|
|
453
443
|
]),
|
|
454
444
|
'/mixed-tool',
|
|
455
|
-
[]
|
|
456
|
-
false
|
|
445
|
+
[]
|
|
457
446
|
);
|
|
458
447
|
|
|
459
448
|
expect(toolsService.registerInteraction).toHaveBeenCalledWith(
|
|
@@ -500,8 +489,7 @@ describe('Decorators', () => {
|
|
|
500
489
|
scopeBundle: 'calendar',
|
|
501
490
|
required: true // Should default to true
|
|
502
491
|
})
|
|
503
|
-
])
|
|
504
|
-
false
|
|
492
|
+
])
|
|
505
493
|
);
|
|
506
494
|
});
|
|
507
495
|
|
|
@@ -527,8 +515,7 @@ describe('Decorators', () => {
|
|
|
527
515
|
expect.any(Function),
|
|
528
516
|
[], // Should be empty array when parameters is undefined
|
|
529
517
|
'/undefined-arrays',
|
|
530
|
-
[]
|
|
531
|
-
false
|
|
518
|
+
[] // Should be empty array when authRequirements is undefined
|
|
532
519
|
);
|
|
533
520
|
});
|
|
534
521
|
});
|
|
@@ -658,287 +645,5 @@ describe('Decorators', () => {
|
|
|
658
645
|
expect(TestClass).toBeDefined();
|
|
659
646
|
});
|
|
660
647
|
});
|
|
661
|
-
|
|
662
|
-
describe('global tool registration', () => {
|
|
663
|
-
it('should auto-detect global tools when class extends GlobalToolFunction', () => {
|
|
664
|
-
const config: ToolConfig = {
|
|
665
|
-
name: 'autoGlobalTool',
|
|
666
|
-
description: 'An auto-detected global tool',
|
|
667
|
-
parameters: [],
|
|
668
|
-
endpoint: '/auto-global-tool'
|
|
669
|
-
};
|
|
670
|
-
|
|
671
|
-
class TestGlobalClass extends GlobalToolFunction {
|
|
672
|
-
@tool(config)
|
|
673
|
-
public async testTool(): Promise<{ result: string }> {
|
|
674
|
-
return { result: 'global-tool-result' };
|
|
675
|
-
}
|
|
676
|
-
}
|
|
677
|
-
|
|
678
|
-
expect(toolsService.registerTool).toHaveBeenCalledWith(
|
|
679
|
-
'autoGlobalTool',
|
|
680
|
-
'An auto-detected global tool',
|
|
681
|
-
expect.any(Function),
|
|
682
|
-
[],
|
|
683
|
-
'/auto-global-tool',
|
|
684
|
-
[],
|
|
685
|
-
true
|
|
686
|
-
);
|
|
687
|
-
|
|
688
|
-
expect(TestGlobalClass).toBeDefined();
|
|
689
|
-
});
|
|
690
|
-
|
|
691
|
-
it('should register regular tools when class does not extend GlobalToolFunction', () => {
|
|
692
|
-
const config: ToolConfig = {
|
|
693
|
-
name: 'regularTool',
|
|
694
|
-
description: 'A regular tool',
|
|
695
|
-
parameters: [],
|
|
696
|
-
endpoint: '/regular-tool'
|
|
697
|
-
};
|
|
698
|
-
|
|
699
|
-
class TestRegularClass {
|
|
700
|
-
@tool(config)
|
|
701
|
-
public async testTool(): Promise<{ result: string }> {
|
|
702
|
-
return { result: 'regular-tool-result' };
|
|
703
|
-
}
|
|
704
|
-
}
|
|
705
|
-
|
|
706
|
-
expect(toolsService.registerTool).toHaveBeenCalledWith(
|
|
707
|
-
'regularTool',
|
|
708
|
-
'A regular tool',
|
|
709
|
-
expect.any(Function),
|
|
710
|
-
[],
|
|
711
|
-
'/regular-tool',
|
|
712
|
-
[],
|
|
713
|
-
false
|
|
714
|
-
);
|
|
715
|
-
|
|
716
|
-
expect(TestRegularClass).toBeDefined();
|
|
717
|
-
});
|
|
718
|
-
|
|
719
|
-
it('should register tools as global when import context is set', () => {
|
|
720
|
-
// Set global import context
|
|
721
|
-
globalThis.__IMPORT_CONTEXT = 'global';
|
|
722
|
-
|
|
723
|
-
const config: ToolConfig = {
|
|
724
|
-
name: 'importedGlobalTool',
|
|
725
|
-
description: 'A tool imported as global',
|
|
726
|
-
parameters: [],
|
|
727
|
-
endpoint: '/imported-global-tool'
|
|
728
|
-
};
|
|
729
|
-
|
|
730
|
-
class TestImportedClass {
|
|
731
|
-
@tool(config)
|
|
732
|
-
public async testTool(): Promise<{ result: string }> {
|
|
733
|
-
return { result: 'imported-global-tool-result' };
|
|
734
|
-
}
|
|
735
|
-
}
|
|
736
|
-
|
|
737
|
-
expect(toolsService.registerTool).toHaveBeenCalledWith(
|
|
738
|
-
'importedGlobalTool',
|
|
739
|
-
'A tool imported as global',
|
|
740
|
-
expect.any(Function),
|
|
741
|
-
[],
|
|
742
|
-
'/imported-global-tool',
|
|
743
|
-
[],
|
|
744
|
-
true
|
|
745
|
-
);
|
|
746
|
-
|
|
747
|
-
// Clean up
|
|
748
|
-
globalThis.__IMPORT_CONTEXT = undefined;
|
|
749
|
-
expect(TestImportedClass).toBeDefined();
|
|
750
|
-
});
|
|
751
|
-
|
|
752
|
-
it('should register tools as regular when import context is set to regular', () => {
|
|
753
|
-
// Set regular import context
|
|
754
|
-
globalThis.__IMPORT_CONTEXT = 'regular';
|
|
755
|
-
|
|
756
|
-
const config: ToolConfig = {
|
|
757
|
-
name: 'importedRegularTool',
|
|
758
|
-
description: 'A tool imported as regular',
|
|
759
|
-
parameters: [],
|
|
760
|
-
endpoint: '/imported-regular-tool'
|
|
761
|
-
};
|
|
762
|
-
|
|
763
|
-
class TestImportedClass {
|
|
764
|
-
@tool(config)
|
|
765
|
-
public async testTool(): Promise<{ result: string }> {
|
|
766
|
-
return { result: 'imported-regular-tool-result' };
|
|
767
|
-
}
|
|
768
|
-
}
|
|
769
|
-
|
|
770
|
-
expect(toolsService.registerTool).toHaveBeenCalledWith(
|
|
771
|
-
'importedRegularTool',
|
|
772
|
-
'A tool imported as regular',
|
|
773
|
-
expect.any(Function),
|
|
774
|
-
[],
|
|
775
|
-
'/imported-regular-tool',
|
|
776
|
-
[],
|
|
777
|
-
false
|
|
778
|
-
);
|
|
779
|
-
|
|
780
|
-
// Clean up
|
|
781
|
-
globalThis.__IMPORT_CONTEXT = undefined;
|
|
782
|
-
expect(TestImportedClass).toBeDefined();
|
|
783
|
-
});
|
|
784
|
-
|
|
785
|
-
it('should handle mixed imports - both regular and global tools together', () => {
|
|
786
|
-
// Test importing regular tools first
|
|
787
|
-
globalThis.__IMPORT_CONTEXT = 'regular';
|
|
788
|
-
|
|
789
|
-
const regularConfig: ToolConfig = {
|
|
790
|
-
name: 'mixedRegularTool',
|
|
791
|
-
description: 'A regular tool in mixed scenario',
|
|
792
|
-
parameters: [],
|
|
793
|
-
endpoint: '/mixed-regular-tool'
|
|
794
|
-
};
|
|
795
|
-
|
|
796
|
-
class RegularToolClass {
|
|
797
|
-
@tool(regularConfig)
|
|
798
|
-
public async regularTool(): Promise<{ result: string }> {
|
|
799
|
-
return { result: 'mixed-regular-result' };
|
|
800
|
-
}
|
|
801
|
-
}
|
|
802
|
-
|
|
803
|
-
// Switch to global context
|
|
804
|
-
globalThis.__IMPORT_CONTEXT = 'global';
|
|
805
|
-
|
|
806
|
-
const globalConfig: ToolConfig = {
|
|
807
|
-
name: 'mixedGlobalTool',
|
|
808
|
-
description: 'A global tool in mixed scenario',
|
|
809
|
-
parameters: [],
|
|
810
|
-
endpoint: '/mixed-global-tool'
|
|
811
|
-
};
|
|
812
|
-
|
|
813
|
-
class GlobalToolClass {
|
|
814
|
-
@tool(globalConfig)
|
|
815
|
-
public async globalTool(): Promise<{ result: string }> {
|
|
816
|
-
return { result: 'mixed-global-result' };
|
|
817
|
-
}
|
|
818
|
-
}
|
|
819
|
-
|
|
820
|
-
// Clear context
|
|
821
|
-
globalThis.__IMPORT_CONTEXT = undefined;
|
|
822
|
-
|
|
823
|
-
// Verify regular tool was registered as regular
|
|
824
|
-
expect(toolsService.registerTool).toHaveBeenCalledWith(
|
|
825
|
-
'mixedRegularTool',
|
|
826
|
-
'A regular tool in mixed scenario',
|
|
827
|
-
expect.any(Function),
|
|
828
|
-
[],
|
|
829
|
-
'/mixed-regular-tool',
|
|
830
|
-
[],
|
|
831
|
-
false
|
|
832
|
-
);
|
|
833
|
-
|
|
834
|
-
// Verify global tool was registered as global
|
|
835
|
-
expect(toolsService.registerTool).toHaveBeenCalledWith(
|
|
836
|
-
'mixedGlobalTool',
|
|
837
|
-
'A global tool in mixed scenario',
|
|
838
|
-
expect.any(Function),
|
|
839
|
-
[],
|
|
840
|
-
'/mixed-global-tool',
|
|
841
|
-
[],
|
|
842
|
-
true
|
|
843
|
-
);
|
|
844
|
-
|
|
845
|
-
expect(RegularToolClass).toBeDefined();
|
|
846
|
-
expect(GlobalToolClass).toBeDefined();
|
|
847
|
-
});
|
|
848
|
-
|
|
849
|
-
it('should handle context switching correctly within same test', () => {
|
|
850
|
-
let callCount = 0;
|
|
851
|
-
const originalRegisterTool = jest.mocked(toolsService.registerTool);
|
|
852
|
-
|
|
853
|
-
// Track call order and contexts
|
|
854
|
-
originalRegisterTool.mockImplementation(() => {
|
|
855
|
-
callCount++;
|
|
856
|
-
// Store the isGlobal flag from each call for verification
|
|
857
|
-
});
|
|
858
|
-
|
|
859
|
-
// First: Import as regular
|
|
860
|
-
globalThis.__IMPORT_CONTEXT = 'regular';
|
|
861
|
-
|
|
862
|
-
class FirstClass {
|
|
863
|
-
@tool({
|
|
864
|
-
name: 'contextTest1',
|
|
865
|
-
description: 'First context test',
|
|
866
|
-
parameters: [],
|
|
867
|
-
endpoint: '/context-test-1'
|
|
868
|
-
})
|
|
869
|
-
public async tool1() {
|
|
870
|
-
return { result: 'test1' };
|
|
871
|
-
}
|
|
872
|
-
}
|
|
873
|
-
|
|
874
|
-
// Second: Switch to global
|
|
875
|
-
globalThis.__IMPORT_CONTEXT = 'global';
|
|
876
|
-
|
|
877
|
-
class SecondClass {
|
|
878
|
-
@tool({
|
|
879
|
-
name: 'contextTest2',
|
|
880
|
-
description: 'Second context test',
|
|
881
|
-
parameters: [],
|
|
882
|
-
endpoint: '/context-test-2'
|
|
883
|
-
})
|
|
884
|
-
public async tool2() {
|
|
885
|
-
return { result: 'test2' };
|
|
886
|
-
}
|
|
887
|
-
}
|
|
888
|
-
|
|
889
|
-
// Third: Clear context (should fallback to class inheritance)
|
|
890
|
-
globalThis.__IMPORT_CONTEXT = undefined;
|
|
891
|
-
|
|
892
|
-
class ThirdClass {
|
|
893
|
-
@tool({
|
|
894
|
-
name: 'contextTest3',
|
|
895
|
-
description: 'Third context test',
|
|
896
|
-
parameters: [],
|
|
897
|
-
endpoint: '/context-test-3'
|
|
898
|
-
})
|
|
899
|
-
public async tool3() {
|
|
900
|
-
return { result: 'test3' };
|
|
901
|
-
}
|
|
902
|
-
}
|
|
903
|
-
|
|
904
|
-
// Verify the sequence of calls
|
|
905
|
-
expect(toolsService.registerTool).toHaveBeenNthCalledWith(
|
|
906
|
-
callCount - 2, // First call
|
|
907
|
-
'contextTest1',
|
|
908
|
-
'First context test',
|
|
909
|
-
expect.any(Function),
|
|
910
|
-
[],
|
|
911
|
-
'/context-test-1',
|
|
912
|
-
[],
|
|
913
|
-
false // Should be regular
|
|
914
|
-
);
|
|
915
|
-
|
|
916
|
-
expect(toolsService.registerTool).toHaveBeenNthCalledWith(
|
|
917
|
-
callCount - 1, // Second call
|
|
918
|
-
'contextTest2',
|
|
919
|
-
'Second context test',
|
|
920
|
-
expect.any(Function),
|
|
921
|
-
[],
|
|
922
|
-
'/context-test-2',
|
|
923
|
-
[],
|
|
924
|
-
true // Should be global
|
|
925
|
-
);
|
|
926
|
-
|
|
927
|
-
expect(toolsService.registerTool).toHaveBeenNthCalledWith(
|
|
928
|
-
callCount, // Third call
|
|
929
|
-
'contextTest3',
|
|
930
|
-
'Third context test',
|
|
931
|
-
expect.any(Function),
|
|
932
|
-
[],
|
|
933
|
-
'/context-test-3',
|
|
934
|
-
[],
|
|
935
|
-
false // Should be regular (fallback to class check, ThirdClass doesn't extend GlobalToolFunction)
|
|
936
|
-
);
|
|
937
|
-
|
|
938
|
-
expect(FirstClass).toBeDefined();
|
|
939
|
-
expect(SecondClass).toBeDefined();
|
|
940
|
-
expect(ThirdClass).toBeDefined();
|
|
941
|
-
});
|
|
942
|
-
});
|
|
943
648
|
});
|
|
944
649
|
|
|
@@ -1,44 +1,6 @@
|
|
|
1
1
|
import { Parameter, AuthRequirement, ParameterType } from '../types/Models';
|
|
2
2
|
import { toolsService } from '../service/Service';
|
|
3
3
|
|
|
4
|
-
/**
|
|
5
|
-
* Global context flag to track import context
|
|
6
|
-
*/
|
|
7
|
-
declare global {
|
|
8
|
-
var __IMPORT_CONTEXT: 'global' | 'regular' | undefined;
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
/**
|
|
12
|
-
* Helper function to check if a class extends GlobalToolFunction
|
|
13
|
-
*/
|
|
14
|
-
function isGlobalToolFunction(constructor: any): boolean {
|
|
15
|
-
// Walk up the prototype chain to check for GlobalToolFunction
|
|
16
|
-
let currentConstructor = constructor;
|
|
17
|
-
while (currentConstructor) {
|
|
18
|
-
if (currentConstructor.name === 'GlobalToolFunction') {
|
|
19
|
-
return true;
|
|
20
|
-
}
|
|
21
|
-
currentConstructor = Object.getPrototypeOf(currentConstructor);
|
|
22
|
-
}
|
|
23
|
-
return false;
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
/**
|
|
27
|
-
* Determine if tool should be registered as global based on definition context or import context
|
|
28
|
-
*/
|
|
29
|
-
function shouldRegisterAsGlobal(targetConstructor: any): boolean {
|
|
30
|
-
// First check if there's an active import context
|
|
31
|
-
if (globalThis.__IMPORT_CONTEXT === 'global') {
|
|
32
|
-
return true;
|
|
33
|
-
}
|
|
34
|
-
if (globalThis.__IMPORT_CONTEXT === 'regular') {
|
|
35
|
-
return false;
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
// Fallback to checking where the tool is defined
|
|
39
|
-
return isGlobalToolFunction(targetConstructor);
|
|
40
|
-
}
|
|
41
|
-
|
|
42
4
|
/**
|
|
43
5
|
* Configuration for @tool decorator
|
|
44
6
|
*/
|
|
@@ -107,18 +69,14 @@ export function tool(config: ToolConfig) {
|
|
|
107
69
|
return originalMethod.call(instance, params, authData);
|
|
108
70
|
};
|
|
109
71
|
|
|
110
|
-
//
|
|
111
|
-
const isGlobal = shouldRegisterAsGlobal(target.constructor);
|
|
112
|
-
|
|
113
|
-
// Register tool with global flag based on where it's defined or imported
|
|
72
|
+
// Immediately register with global ToolsService
|
|
114
73
|
toolsService.registerTool(
|
|
115
74
|
config.name,
|
|
116
75
|
config.description,
|
|
117
76
|
boundHandler,
|
|
118
77
|
parameters,
|
|
119
78
|
config.endpoint,
|
|
120
|
-
authRequirements
|
|
121
|
-
isGlobal
|
|
79
|
+
authRequirements
|
|
122
80
|
);
|
|
123
81
|
};
|
|
124
82
|
}
|
package/src/index.ts
CHANGED
|
@@ -3,5 +3,4 @@ export * from './function/GlobalToolFunction';
|
|
|
3
3
|
export * from './types/Models';
|
|
4
4
|
export * from './decorator/Decorator';
|
|
5
5
|
export * from './auth/TokenVerifier';
|
|
6
|
-
export * from './utils/ImportUtils';
|
|
7
6
|
export { Tool, Interaction, InteractionResult } from './service/Service';
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { toolsService, Tool, Interaction } from './Service';
|
|
2
2
|
import { Parameter, ParameterType, AuthRequirement, OptiIdAuthDataCredentials, OptiIdAuthData } from '../types/Models';
|
|
3
3
|
import { ToolFunction } from '../function/ToolFunction';
|
|
4
|
-
import { GlobalToolFunction } from '../function/GlobalToolFunction';
|
|
5
4
|
import { logger } from '@zaiusinc/app-sdk';
|
|
6
5
|
|
|
7
6
|
// Mock the logger and other app-sdk exports
|
|
@@ -12,9 +11,6 @@ jest.mock('@zaiusinc/app-sdk', () => ({
|
|
|
12
11
|
Function: class {
|
|
13
12
|
public constructor(public request: any) {}
|
|
14
13
|
},
|
|
15
|
-
GlobalFunction: class {
|
|
16
|
-
public constructor(public request: any) {}
|
|
17
|
-
},
|
|
18
14
|
Response: jest.fn().mockImplementation((status, data) => ({
|
|
19
15
|
status,
|
|
20
16
|
data,
|
|
@@ -27,7 +23,6 @@ describe('ToolsService', () => {
|
|
|
27
23
|
let mockTool: Tool<unknown>;
|
|
28
24
|
let mockInteraction: Interaction<unknown>;
|
|
29
25
|
let mockToolFunction: ToolFunction;
|
|
30
|
-
let mockGlobalToolFunction: GlobalToolFunction;
|
|
31
26
|
|
|
32
27
|
beforeEach(() => {
|
|
33
28
|
// Clear registered functions and interactions before each test
|
|
@@ -45,18 +40,6 @@ describe('ToolsService', () => {
|
|
|
45
40
|
request: {} as any
|
|
46
41
|
} as any;
|
|
47
42
|
|
|
48
|
-
// Create mock GlobalToolFunction - use actual class for instanceof check
|
|
49
|
-
class MockGlobalToolFunction extends GlobalToolFunction {
|
|
50
|
-
public ready = jest.fn().mockResolvedValue(true);
|
|
51
|
-
public perform = jest.fn();
|
|
52
|
-
public validateBearerToken = jest.fn().mockReturnValue(true);
|
|
53
|
-
|
|
54
|
-
public constructor() {
|
|
55
|
-
super({} as any);
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
mockGlobalToolFunction = new MockGlobalToolFunction();
|
|
59
|
-
|
|
60
43
|
// Create mock tool handler
|
|
61
44
|
const mockToolHandler = jest.fn().mockResolvedValue({ result: 'success' });
|
|
62
45
|
|
|
@@ -111,7 +94,6 @@ describe('ToolsService', () => {
|
|
|
111
94
|
describe('processRequest', () => {
|
|
112
95
|
describe('discovery endpoint', () => {
|
|
113
96
|
it('should return registered functions for discovery endpoint', async () => {
|
|
114
|
-
// Register a regular (non-global) tool
|
|
115
97
|
toolsService.registerTool(
|
|
116
98
|
mockTool.name,
|
|
117
99
|
mockTool.description,
|
|
@@ -120,17 +102,6 @@ describe('ToolsService', () => {
|
|
|
120
102
|
mockTool.endpoint
|
|
121
103
|
);
|
|
122
104
|
|
|
123
|
-
// Register a global tool (should not be included for regular ToolFunction)
|
|
124
|
-
toolsService.registerTool(
|
|
125
|
-
'globalTool',
|
|
126
|
-
'Global tool description',
|
|
127
|
-
jest.fn().mockResolvedValue({ result: 'global' }),
|
|
128
|
-
[new Parameter('param1', ParameterType.String, 'Test parameter', true)],
|
|
129
|
-
'/global-tool',
|
|
130
|
-
undefined,
|
|
131
|
-
true // global tool
|
|
132
|
-
);
|
|
133
|
-
|
|
134
105
|
const discoveryRequest = createMockRequest({ path: '/discovery' });
|
|
135
106
|
const response = await toolsService.processRequest(discoveryRequest, mockToolFunction);
|
|
136
107
|
|
|
@@ -142,11 +113,9 @@ describe('ToolsService', () => {
|
|
|
142
113
|
const responseData = response.bodyJSON as { functions: unknown[] };
|
|
143
114
|
expect(responseData).toHaveProperty('functions');
|
|
144
115
|
expect(Array.isArray(responseData.functions)).toBe(true);
|
|
145
|
-
|
|
146
|
-
// Should only return the non-global tool (global tool should be filtered out)
|
|
147
116
|
expect(responseData.functions).toHaveLength(1);
|
|
148
117
|
|
|
149
|
-
// Test the registered function structure
|
|
118
|
+
// Test the registered function structure
|
|
150
119
|
const registeredFunction = responseData.functions[0];
|
|
151
120
|
expect(registeredFunction).toEqual({
|
|
152
121
|
name: mockTool.name,
|
|
@@ -156,11 +125,6 @@ describe('ToolsService', () => {
|
|
|
156
125
|
http_method: 'POST',
|
|
157
126
|
auth_requirements: [{ provider: 'OptiID', scope_bundle: 'default', required: true }]
|
|
158
127
|
});
|
|
159
|
-
|
|
160
|
-
// Verify the global tool is not included
|
|
161
|
-
const toolNames = responseData.functions.map((f: any) => f.name);
|
|
162
|
-
expect(toolNames).toContain(mockTool.name);
|
|
163
|
-
expect(toolNames).not.toContain('globalTool');
|
|
164
128
|
});
|
|
165
129
|
|
|
166
130
|
it('should return empty functions array when no tools are registered', async () => {
|
|
@@ -236,139 +200,6 @@ describe('ToolsService', () => {
|
|
|
236
200
|
});
|
|
237
201
|
});
|
|
238
202
|
|
|
239
|
-
describe('global discovery endpoint', () => {
|
|
240
|
-
it('should return only global tools when called from GlobalToolFunction', async () => {
|
|
241
|
-
// Register a regular tool (non-global)
|
|
242
|
-
toolsService.registerTool(
|
|
243
|
-
'regularTool',
|
|
244
|
-
'Regular tool description',
|
|
245
|
-
jest.fn().mockResolvedValue({ result: 'regular' }),
|
|
246
|
-
[new Parameter('param1', ParameterType.String, 'Test parameter', true)],
|
|
247
|
-
'/regular-tool',
|
|
248
|
-
undefined,
|
|
249
|
-
false // not global
|
|
250
|
-
);
|
|
251
|
-
|
|
252
|
-
// Register a global tool
|
|
253
|
-
toolsService.registerTool(
|
|
254
|
-
'globalTool',
|
|
255
|
-
'Global tool description',
|
|
256
|
-
jest.fn().mockResolvedValue({ result: 'global' }),
|
|
257
|
-
[new Parameter('param1', ParameterType.String, 'Test parameter', true)],
|
|
258
|
-
'/global-tool',
|
|
259
|
-
undefined,
|
|
260
|
-
true // global
|
|
261
|
-
);
|
|
262
|
-
|
|
263
|
-
const discoveryRequest = createMockRequest({ path: '/discovery' });
|
|
264
|
-
const response = await toolsService.processRequest(discoveryRequest, mockGlobalToolFunction);
|
|
265
|
-
|
|
266
|
-
expect(response.status).toBe(200);
|
|
267
|
-
expect(response).toHaveProperty('bodyJSON');
|
|
268
|
-
|
|
269
|
-
// Test the actual response structure
|
|
270
|
-
const responseData = response.bodyJSON as { functions: any[] };
|
|
271
|
-
expect(responseData).toHaveProperty('functions');
|
|
272
|
-
expect(Array.isArray(responseData.functions)).toBe(true);
|
|
273
|
-
|
|
274
|
-
// Should only return the global tool
|
|
275
|
-
expect(responseData.functions).toHaveLength(1);
|
|
276
|
-
expect(responseData.functions[0].name).toBe('globalTool');
|
|
277
|
-
expect(responseData.functions[0].endpoint).toBe('/global-tool');
|
|
278
|
-
});
|
|
279
|
-
|
|
280
|
-
it('should return empty array when no global tools are registered ' +
|
|
281
|
-
'and called from GlobalToolFunction', async () => {
|
|
282
|
-
// Register only regular tools (non-global)
|
|
283
|
-
toolsService.registerTool(
|
|
284
|
-
'regularTool1',
|
|
285
|
-
'Regular tool 1 description',
|
|
286
|
-
jest.fn().mockResolvedValue({ result: 'regular1' }),
|
|
287
|
-
[new Parameter('param1', ParameterType.String, 'Test parameter', true)],
|
|
288
|
-
'/regular-tool-1',
|
|
289
|
-
undefined,
|
|
290
|
-
false // not global
|
|
291
|
-
);
|
|
292
|
-
|
|
293
|
-
toolsService.registerTool(
|
|
294
|
-
'regularTool2',
|
|
295
|
-
'Regular tool 2 description',
|
|
296
|
-
jest.fn().mockResolvedValue({ result: 'regular2' }),
|
|
297
|
-
[new Parameter('param1', ParameterType.String, 'Test parameter', true)],
|
|
298
|
-
'/regular-tool-2',
|
|
299
|
-
undefined,
|
|
300
|
-
false // not global
|
|
301
|
-
);
|
|
302
|
-
|
|
303
|
-
const discoveryRequest = createMockRequest({ path: '/discovery' });
|
|
304
|
-
const response = await toolsService.processRequest(discoveryRequest, mockGlobalToolFunction);
|
|
305
|
-
|
|
306
|
-
expect(response.status).toBe(200);
|
|
307
|
-
expect(response).toHaveProperty('bodyJSON');
|
|
308
|
-
|
|
309
|
-
// Test the actual response structure
|
|
310
|
-
const responseData = response.bodyJSON as { functions: any[] };
|
|
311
|
-
expect(responseData).toHaveProperty('functions');
|
|
312
|
-
expect(Array.isArray(responseData.functions)).toBe(true);
|
|
313
|
-
|
|
314
|
-
// Should return empty array since no global tools are registered
|
|
315
|
-
expect(responseData.functions).toHaveLength(0);
|
|
316
|
-
});
|
|
317
|
-
|
|
318
|
-
it('should return multiple global tools when called from GlobalToolFunction', async () => {
|
|
319
|
-
// Register multiple global tools
|
|
320
|
-
toolsService.registerTool(
|
|
321
|
-
'globalTool1',
|
|
322
|
-
'Global tool 1 description',
|
|
323
|
-
jest.fn().mockResolvedValue({ result: 'global1' }),
|
|
324
|
-
[new Parameter('param1', ParameterType.String, 'Test parameter', true)],
|
|
325
|
-
'/global-tool-1',
|
|
326
|
-
undefined,
|
|
327
|
-
true // global
|
|
328
|
-
);
|
|
329
|
-
|
|
330
|
-
toolsService.registerTool(
|
|
331
|
-
'globalTool2',
|
|
332
|
-
'Global tool 2 description',
|
|
333
|
-
jest.fn().mockResolvedValue({ result: 'global2' }),
|
|
334
|
-
[new Parameter('param1', ParameterType.String, 'Test parameter', true)],
|
|
335
|
-
'/global-tool-2',
|
|
336
|
-
undefined,
|
|
337
|
-
true // global
|
|
338
|
-
);
|
|
339
|
-
|
|
340
|
-
// Register a regular tool (should not be included)
|
|
341
|
-
toolsService.registerTool(
|
|
342
|
-
'regularTool',
|
|
343
|
-
'Regular tool description',
|
|
344
|
-
jest.fn().mockResolvedValue({ result: 'regular' }),
|
|
345
|
-
[new Parameter('param1', ParameterType.String, 'Test parameter', true)],
|
|
346
|
-
'/regular-tool',
|
|
347
|
-
undefined,
|
|
348
|
-
false // not global
|
|
349
|
-
);
|
|
350
|
-
|
|
351
|
-
const discoveryRequest = createMockRequest({ path: '/discovery' });
|
|
352
|
-
const response = await toolsService.processRequest(discoveryRequest, mockGlobalToolFunction);
|
|
353
|
-
|
|
354
|
-
expect(response.status).toBe(200);
|
|
355
|
-
expect(response).toHaveProperty('bodyJSON');
|
|
356
|
-
|
|
357
|
-
// Test the actual response structure
|
|
358
|
-
const responseData = response.bodyJSON as { functions: any[] };
|
|
359
|
-
expect(responseData).toHaveProperty('functions');
|
|
360
|
-
expect(Array.isArray(responseData.functions)).toBe(true);
|
|
361
|
-
|
|
362
|
-
// Should return only the 2 global tools
|
|
363
|
-
expect(responseData.functions).toHaveLength(2);
|
|
364
|
-
|
|
365
|
-
const toolNames = responseData.functions.map((f) => f.name);
|
|
366
|
-
expect(toolNames).toContain('globalTool1');
|
|
367
|
-
expect(toolNames).toContain('globalTool2');
|
|
368
|
-
expect(toolNames).not.toContain('regularTool');
|
|
369
|
-
});
|
|
370
|
-
});
|
|
371
|
-
|
|
372
203
|
describe('tool execution', () => {
|
|
373
204
|
beforeEach(() => {
|
|
374
205
|
toolsService.registerTool(
|