@agents-at-scale/ark 0.1.53 → 0.1.55

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.
Files changed (115) hide show
  1. package/dist/commands/export/index.js +6 -4
  2. package/dist/commands/generate/generators/agent.js +2 -0
  3. package/dist/commands/generate/generators/marketplace.js +2 -0
  4. package/dist/commands/generate/generators/mcpserver.js +2 -0
  5. package/dist/commands/generate/generators/project.js +9 -2
  6. package/dist/commands/generate/generators/query.js +2 -0
  7. package/dist/commands/generate/generators/team.js +2 -0
  8. package/dist/commands/generate/templateDiscovery.js +1 -0
  9. package/dist/commands/generate/templateEngine.js +1 -3
  10. package/dist/commands/import/index.js +1 -1
  11. package/dist/commands/install/index.js +2 -1
  12. package/dist/commands/models/kubernetes/manifest-builder.js +27 -10
  13. package/dist/commands/models/providers/azure.d.ts +10 -7
  14. package/dist/commands/models/providers/azure.js +83 -21
  15. package/dist/commands/uninstall/index.js +1 -1
  16. package/dist/components/ChatUI.js +17 -16
  17. package/dist/components/statusChecker.js +3 -3
  18. package/dist/lib/arkApiClient.js +11 -9
  19. package/dist/lib/arkApiProxy.js +1 -0
  20. package/dist/lib/arkServiceProxy.js +5 -1
  21. package/dist/lib/chatClient.js +9 -0
  22. package/dist/lib/config.js +8 -3
  23. package/dist/lib/errors.js +3 -0
  24. package/dist/ui/asyncOperations/connectingToArk.js +2 -2
  25. package/package.json +16 -12
  26. package/dist/arkServices.spec.d.ts +0 -1
  27. package/dist/arkServices.spec.js +0 -138
  28. package/dist/commands/agents/index.spec.d.ts +0 -1
  29. package/dist/commands/agents/index.spec.js +0 -67
  30. package/dist/commands/cluster/get.spec.d.ts +0 -1
  31. package/dist/commands/cluster/get.spec.js +0 -92
  32. package/dist/commands/cluster/index.spec.d.ts +0 -1
  33. package/dist/commands/cluster/index.spec.js +0 -24
  34. package/dist/commands/completion/index.spec.d.ts +0 -1
  35. package/dist/commands/completion/index.spec.js +0 -34
  36. package/dist/commands/config/index.spec.d.ts +0 -1
  37. package/dist/commands/config/index.spec.js +0 -78
  38. package/dist/commands/evaluation/index.spec.d.ts +0 -1
  39. package/dist/commands/evaluation/index.spec.js +0 -161
  40. package/dist/commands/export/index.spec.d.ts +0 -1
  41. package/dist/commands/export/index.spec.js +0 -145
  42. package/dist/commands/import/index.spec.d.ts +0 -1
  43. package/dist/commands/import/index.spec.js +0 -46
  44. package/dist/commands/install/index.spec.d.ts +0 -1
  45. package/dist/commands/install/index.spec.js +0 -286
  46. package/dist/commands/marketplace/index.spec.d.ts +0 -1
  47. package/dist/commands/marketplace/index.spec.js +0 -88
  48. package/dist/commands/memory/index.spec.d.ts +0 -1
  49. package/dist/commands/memory/index.spec.js +0 -124
  50. package/dist/commands/models/create.spec.d.ts +0 -1
  51. package/dist/commands/models/create.spec.js +0 -167
  52. package/dist/commands/models/index.spec.d.ts +0 -1
  53. package/dist/commands/models/index.spec.js +0 -96
  54. package/dist/commands/models/providers/azure.spec.d.ts +0 -1
  55. package/dist/commands/models/providers/azure.spec.js +0 -232
  56. package/dist/commands/models/providers/bedrock.spec.d.ts +0 -1
  57. package/dist/commands/models/providers/bedrock.spec.js +0 -241
  58. package/dist/commands/models/providers/openai.spec.d.ts +0 -1
  59. package/dist/commands/models/providers/openai.spec.js +0 -180
  60. package/dist/commands/queries/delete.spec.d.ts +0 -1
  61. package/dist/commands/queries/delete.spec.js +0 -74
  62. package/dist/commands/queries/index.spec.d.ts +0 -1
  63. package/dist/commands/queries/index.spec.js +0 -167
  64. package/dist/commands/queries/list.spec.d.ts +0 -1
  65. package/dist/commands/queries/list.spec.js +0 -170
  66. package/dist/commands/queries/validation.spec.d.ts +0 -1
  67. package/dist/commands/queries/validation.spec.js +0 -27
  68. package/dist/commands/query/index.spec.d.ts +0 -1
  69. package/dist/commands/query/index.spec.js +0 -104
  70. package/dist/commands/targets/index.spec.d.ts +0 -1
  71. package/dist/commands/targets/index.spec.js +0 -154
  72. package/dist/commands/teams/index.spec.d.ts +0 -1
  73. package/dist/commands/teams/index.spec.js +0 -70
  74. package/dist/commands/tools/index.spec.d.ts +0 -1
  75. package/dist/commands/tools/index.spec.js +0 -70
  76. package/dist/commands/uninstall/index.spec.d.ts +0 -1
  77. package/dist/commands/uninstall/index.spec.js +0 -125
  78. package/dist/lib/arkServiceProxy.spec.d.ts +0 -1
  79. package/dist/lib/arkServiceProxy.spec.js +0 -100
  80. package/dist/lib/arkStatus.spec.d.ts +0 -1
  81. package/dist/lib/arkStatus.spec.js +0 -49
  82. package/dist/lib/chatClient.spec.d.ts +0 -1
  83. package/dist/lib/chatClient.spec.js +0 -108
  84. package/dist/lib/cluster.spec.d.ts +0 -1
  85. package/dist/lib/cluster.spec.js +0 -338
  86. package/dist/lib/commands.spec.d.ts +0 -1
  87. package/dist/lib/commands.spec.js +0 -146
  88. package/dist/lib/config.spec.d.ts +0 -1
  89. package/dist/lib/config.spec.js +0 -202
  90. package/dist/lib/duration.spec.d.ts +0 -1
  91. package/dist/lib/duration.spec.js +0 -13
  92. package/dist/lib/errors.spec.d.ts +0 -1
  93. package/dist/lib/errors.spec.js +0 -221
  94. package/dist/lib/executeQuery.spec.d.ts +0 -1
  95. package/dist/lib/executeQuery.spec.js +0 -325
  96. package/dist/lib/kubectl.spec.d.ts +0 -1
  97. package/dist/lib/kubectl.spec.js +0 -192
  98. package/dist/lib/marketplaceFetcher.spec.d.ts +0 -1
  99. package/dist/lib/marketplaceFetcher.spec.js +0 -225
  100. package/dist/lib/nextSteps.spec.d.ts +0 -1
  101. package/dist/lib/nextSteps.spec.js +0 -59
  102. package/dist/lib/output.spec.d.ts +0 -1
  103. package/dist/lib/output.spec.js +0 -123
  104. package/dist/lib/startup.spec.d.ts +0 -1
  105. package/dist/lib/startup.spec.js +0 -152
  106. package/dist/lib/stdin.spec.d.ts +0 -1
  107. package/dist/lib/stdin.spec.js +0 -82
  108. package/dist/lib/timeout.spec.d.ts +0 -1
  109. package/dist/lib/timeout.spec.js +0 -14
  110. package/dist/lib/waitForReady.spec.d.ts +0 -1
  111. package/dist/lib/waitForReady.spec.js +0 -104
  112. package/dist/marketplaceServices.spec.d.ts +0 -1
  113. package/dist/marketplaceServices.spec.js +0 -74
  114. package/dist/ui/statusFormatter.spec.d.ts +0 -1
  115. package/dist/ui/statusFormatter.spec.js +0 -58
@@ -1,232 +0,0 @@
1
- import { jest } from '@jest/globals';
2
- const mockInquirer = {
3
- prompt: jest.fn(),
4
- };
5
- jest.unstable_mockModule('inquirer', () => ({
6
- default: mockInquirer,
7
- }));
8
- const { AzureConfigCollector } = await import('./azure.js');
9
- describe('AzureConfigCollector', () => {
10
- let collector;
11
- beforeEach(() => {
12
- collector = new AzureConfigCollector();
13
- jest.clearAllMocks();
14
- });
15
- describe('collectConfig', () => {
16
- it('uses provided options without prompting', async () => {
17
- const options = {
18
- model: 'gpt-4o-mini',
19
- baseUrl: 'https://my-resource.openai.azure.com',
20
- apiKey: 'azure-key-12345',
21
- apiVersion: '2024-12-01-preview',
22
- };
23
- const config = await collector.collectConfig(options);
24
- expect(mockInquirer.prompt).not.toHaveBeenCalled();
25
- expect(config).toEqual({
26
- type: 'azure',
27
- modelValue: 'gpt-4o-mini',
28
- secretName: '',
29
- baseUrl: 'https://my-resource.openai.azure.com',
30
- apiKey: 'azure-key-12345',
31
- apiVersion: '2024-12-01-preview',
32
- });
33
- });
34
- it('uses default apiVersion when not provided', async () => {
35
- mockInquirer.prompt.mockResolvedValueOnce({
36
- apiVersion: '2024-12-01-preview',
37
- });
38
- mockInquirer.prompt.mockResolvedValueOnce({ apiKey: 'azure-key' });
39
- const options = {
40
- model: 'gpt-4',
41
- baseUrl: 'https://my-resource.openai.azure.com',
42
- };
43
- const config = await collector.collectConfig(options);
44
- expect(mockInquirer.prompt).toHaveBeenCalledWith([
45
- expect.objectContaining({
46
- type: 'input',
47
- name: 'apiVersion',
48
- message: 'Azure API version:',
49
- default: '2024-12-01-preview',
50
- }),
51
- ]);
52
- expect(config.apiVersion).toBe('2024-12-01-preview');
53
- });
54
- it('prompts for missing baseUrl', async () => {
55
- mockInquirer.prompt.mockResolvedValueOnce({
56
- baseUrl: 'https://contoso.openai.azure.com',
57
- });
58
- mockInquirer.prompt.mockResolvedValueOnce({ apiVersion: '2024-10-01' });
59
- mockInquirer.prompt.mockResolvedValueOnce({ apiKey: 'azure-key' });
60
- const options = {
61
- model: 'gpt-4',
62
- };
63
- const config = await collector.collectConfig(options);
64
- expect(mockInquirer.prompt).toHaveBeenCalledWith([
65
- expect.objectContaining({
66
- type: 'input',
67
- name: 'baseUrl',
68
- message: 'base URL:',
69
- validate: expect.any(Function),
70
- }),
71
- ]);
72
- expect(config.baseUrl).toBe('https://contoso.openai.azure.com');
73
- });
74
- it('validates baseUrl is required', async () => {
75
- mockInquirer.prompt.mockResolvedValueOnce({ baseUrl: '' });
76
- const options = {
77
- model: 'gpt-4',
78
- };
79
- await expect(collector.collectConfig(options)).rejects.toThrow('base URL is required');
80
- });
81
- it('validates baseUrl is a valid URL', async () => {
82
- const options = {
83
- model: 'gpt-4',
84
- };
85
- // Get the validate function from the prompt call
86
- mockInquirer.prompt.mockImplementationOnce(async (questions) => {
87
- const validate = questions[0].validate;
88
- // Test invalid URL
89
- expect(validate('not-a-url')).toBe('please enter a valid URL');
90
- // Test empty string
91
- expect(validate('')).toBe('base URL is required');
92
- // Test valid URL
93
- expect(validate('https://test.openai.azure.com')).toBe(true);
94
- return { baseUrl: 'https://test.openai.azure.com' };
95
- });
96
- mockInquirer.prompt.mockResolvedValueOnce({
97
- apiVersion: '2024-12-01-preview',
98
- });
99
- mockInquirer.prompt.mockResolvedValueOnce({ apiKey: 'azure-key' });
100
- await collector.collectConfig(options);
101
- });
102
- it('removes trailing slash from baseUrl', async () => {
103
- const options = {
104
- model: 'gpt-4',
105
- baseUrl: 'https://my-resource.openai.azure.com/',
106
- apiKey: 'azure-key',
107
- apiVersion: '2024-12-01-preview',
108
- };
109
- const config = await collector.collectConfig(options);
110
- expect(config.baseUrl).toBe('https://my-resource.openai.azure.com');
111
- });
112
- it('prompts for missing apiKey as password field', async () => {
113
- mockInquirer.prompt.mockResolvedValueOnce({
114
- apiKey: 'azure-secret-key',
115
- });
116
- const options = {
117
- model: 'gpt-4',
118
- baseUrl: 'https://my-resource.openai.azure.com',
119
- apiVersion: '2024-12-01-preview',
120
- };
121
- const config = await collector.collectConfig(options);
122
- expect(mockInquirer.prompt).toHaveBeenCalledWith([
123
- expect.objectContaining({
124
- type: 'password',
125
- name: 'apiKey',
126
- message: 'API key:',
127
- mask: '*',
128
- validate: expect.any(Function),
129
- }),
130
- ]);
131
- expect(config.apiKey).toBe('azure-secret-key');
132
- });
133
- it('validates apiKey is required', async () => {
134
- mockInquirer.prompt.mockResolvedValueOnce({ apiKey: '' });
135
- const options = {
136
- model: 'gpt-4',
137
- baseUrl: 'https://my-resource.openai.azure.com',
138
- apiVersion: '2024-12-01-preview',
139
- };
140
- await expect(collector.collectConfig(options)).rejects.toThrow('API key is required');
141
- });
142
- it('tests apiKey validation function', async () => {
143
- const options = {
144
- model: 'gpt-4',
145
- baseUrl: 'https://my-resource.openai.azure.com',
146
- apiVersion: '2024-12-01-preview',
147
- };
148
- // Get the validate function from the prompt call
149
- mockInquirer.prompt.mockImplementationOnce(async (questions) => {
150
- const validate = questions[0].validate;
151
- // Test empty string
152
- expect(validate('')).toBe('API key is required');
153
- // Test valid key
154
- expect(validate('valid-azure-key')).toBe(true);
155
- return { apiKey: 'valid-azure-key' };
156
- });
157
- await collector.collectConfig(options);
158
- });
159
- it('collects full configuration through interactive prompts', async () => {
160
- mockInquirer.prompt.mockResolvedValueOnce({
161
- baseUrl: 'https://eastus.openai.azure.com/',
162
- });
163
- mockInquirer.prompt.mockResolvedValueOnce({
164
- apiVersion: '2024-08-01-preview',
165
- });
166
- mockInquirer.prompt.mockResolvedValueOnce({
167
- apiKey: 'abc123def456',
168
- });
169
- const options = {
170
- model: 'gpt-4o',
171
- };
172
- const config = await collector.collectConfig(options);
173
- expect(config).toEqual({
174
- type: 'azure',
175
- modelValue: 'gpt-4o',
176
- secretName: '',
177
- baseUrl: 'https://eastus.openai.azure.com',
178
- apiKey: 'abc123def456',
179
- apiVersion: '2024-08-01-preview',
180
- });
181
- });
182
- it('mixes CLI options and interactive prompts', async () => {
183
- mockInquirer.prompt.mockResolvedValueOnce({
184
- apiKey: 'prompted-key',
185
- });
186
- const options = {
187
- model: 'gpt-35-turbo',
188
- baseUrl: 'https://westeurope.openai.azure.com',
189
- apiVersion: '2024-06-01',
190
- };
191
- const config = await collector.collectConfig(options);
192
- expect(config).toEqual({
193
- type: 'azure',
194
- modelValue: 'gpt-35-turbo',
195
- secretName: '',
196
- baseUrl: 'https://westeurope.openai.azure.com',
197
- apiKey: 'prompted-key',
198
- apiVersion: '2024-06-01',
199
- });
200
- });
201
- it('accepts custom apiVersion', async () => {
202
- const options = {
203
- model: 'gpt-4',
204
- baseUrl: 'https://my-resource.openai.azure.com',
205
- apiKey: 'azure-key',
206
- apiVersion: '2023-05-15',
207
- };
208
- const config = await collector.collectConfig(options);
209
- expect(config.apiVersion).toBe('2023-05-15');
210
- });
211
- it('prompts for apiVersion when only baseUrl is provided', async () => {
212
- mockInquirer.prompt.mockResolvedValueOnce({
213
- apiVersion: '2024-12-01-preview',
214
- });
215
- mockInquirer.prompt.mockResolvedValueOnce({ apiKey: 'azure-key' });
216
- const options = {
217
- model: 'gpt-4',
218
- baseUrl: 'https://my-resource.openai.azure.com',
219
- };
220
- const config = await collector.collectConfig(options);
221
- expect(mockInquirer.prompt).toHaveBeenCalledWith([
222
- expect.objectContaining({
223
- type: 'input',
224
- name: 'apiVersion',
225
- message: 'Azure API version:',
226
- default: '2024-12-01-preview',
227
- }),
228
- ]);
229
- expect(config.apiVersion).toBe('2024-12-01-preview');
230
- });
231
- });
232
- });
@@ -1 +0,0 @@
1
- export {};
@@ -1,241 +0,0 @@
1
- import { jest } from '@jest/globals';
2
- const mockInquirer = {
3
- prompt: jest.fn(),
4
- };
5
- jest.unstable_mockModule('inquirer', () => ({
6
- default: mockInquirer,
7
- }));
8
- const { BedrockConfigCollector } = await import('./bedrock.js');
9
- describe('BedrockConfigCollector', () => {
10
- let collector;
11
- beforeEach(() => {
12
- collector = new BedrockConfigCollector();
13
- jest.clearAllMocks();
14
- });
15
- describe('collectConfig', () => {
16
- it('uses provided options without prompting', async () => {
17
- const options = {
18
- model: 'anthropic.claude-3-sonnet-20240229-v1:0',
19
- region: 'us-west-2',
20
- accessKeyId: 'AKIAIOSFODNN7EXAMPLE',
21
- secretAccessKey: 'wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY',
22
- sessionToken: 'session-token-123',
23
- modelArn: 'arn:aws:bedrock:us-west-2:123456789012:model/test',
24
- };
25
- const config = await collector.collectConfig(options);
26
- expect(mockInquirer.prompt).not.toHaveBeenCalled();
27
- expect(config).toEqual({
28
- type: 'bedrock',
29
- modelValue: 'anthropic.claude-3-sonnet-20240229-v1:0',
30
- secretName: '',
31
- region: 'us-west-2',
32
- accessKeyId: 'AKIAIOSFODNN7EXAMPLE',
33
- secretAccessKey: 'wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY',
34
- sessionToken: 'session-token-123',
35
- modelArn: 'arn:aws:bedrock:us-west-2:123456789012:model/test',
36
- });
37
- });
38
- it('prompts for missing region with default', async () => {
39
- mockInquirer.prompt.mockResolvedValueOnce({ region: 'us-east-1' });
40
- mockInquirer.prompt.mockResolvedValueOnce({ accessKeyId: 'AKIATEST' });
41
- mockInquirer.prompt.mockResolvedValueOnce({ secretAccessKey: 'secret' });
42
- mockInquirer.prompt.mockResolvedValueOnce({ sessionToken: '' });
43
- mockInquirer.prompt.mockResolvedValueOnce({ modelArn: '' });
44
- const options = {
45
- model: 'test-model',
46
- };
47
- const config = await collector.collectConfig(options);
48
- expect(mockInquirer.prompt).toHaveBeenCalledWith([
49
- expect.objectContaining({
50
- type: 'input',
51
- name: 'region',
52
- message: 'AWS region:',
53
- default: 'us-east-1',
54
- }),
55
- ]);
56
- expect(config.region).toBe('us-east-1');
57
- });
58
- it('throws error if region is missing after prompt', async () => {
59
- mockInquirer.prompt.mockResolvedValueOnce({ region: '' });
60
- const options = {
61
- model: 'test-model',
62
- };
63
- await expect(collector.collectConfig(options)).rejects.toThrow('region is required');
64
- });
65
- it('prompts for missing accessKeyId', async () => {
66
- mockInquirer.prompt.mockResolvedValueOnce({
67
- accessKeyId: 'AKIAIOSFODNN7EXAMPLE',
68
- });
69
- mockInquirer.prompt.mockResolvedValueOnce({ secretAccessKey: 'secret' });
70
- mockInquirer.prompt.mockResolvedValueOnce({ sessionToken: '' });
71
- mockInquirer.prompt.mockResolvedValueOnce({ modelArn: '' });
72
- const options = {
73
- model: 'test-model',
74
- region: 'us-west-2',
75
- };
76
- const config = await collector.collectConfig(options);
77
- expect(mockInquirer.prompt).toHaveBeenCalledWith([
78
- expect.objectContaining({
79
- type: 'input',
80
- name: 'accessKeyId',
81
- message: 'AWS access key ID:',
82
- validate: expect.any(Function),
83
- }),
84
- ]);
85
- expect(config.accessKeyId).toBe('AKIAIOSFODNN7EXAMPLE');
86
- });
87
- it('validates accessKeyId is required', async () => {
88
- mockInquirer.prompt.mockResolvedValueOnce({ accessKeyId: '' });
89
- const options = {
90
- model: 'test-model',
91
- region: 'us-west-2',
92
- };
93
- await expect(collector.collectConfig(options)).rejects.toThrow('access key ID is required');
94
- });
95
- it('prompts for missing secretAccessKey as password field', async () => {
96
- mockInquirer.prompt.mockResolvedValueOnce({
97
- secretAccessKey: 'wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY',
98
- });
99
- mockInquirer.prompt.mockResolvedValueOnce({ sessionToken: '' });
100
- mockInquirer.prompt.mockResolvedValueOnce({ modelArn: '' });
101
- const options = {
102
- model: 'test-model',
103
- region: 'us-west-2',
104
- accessKeyId: 'AKIAIOSFODNN7EXAMPLE',
105
- };
106
- const config = await collector.collectConfig(options);
107
- expect(mockInquirer.prompt).toHaveBeenCalledWith([
108
- expect.objectContaining({
109
- type: 'password',
110
- name: 'secretAccessKey',
111
- message: 'AWS secret access key:',
112
- mask: '*',
113
- validate: expect.any(Function),
114
- }),
115
- ]);
116
- expect(config.secretAccessKey).toBe('wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY');
117
- });
118
- it('validates secretAccessKey is required', async () => {
119
- mockInquirer.prompt.mockResolvedValueOnce({ secretAccessKey: '' });
120
- const options = {
121
- model: 'test-model',
122
- region: 'us-west-2',
123
- accessKeyId: 'AKIAIOSFODNN7EXAMPLE',
124
- };
125
- await expect(collector.collectConfig(options)).rejects.toThrow('secret access key is required');
126
- });
127
- it('prompts for optional sessionToken', async () => {
128
- mockInquirer.prompt.mockResolvedValueOnce({
129
- sessionToken: 'optional-token',
130
- });
131
- mockInquirer.prompt.mockResolvedValueOnce({ modelArn: '' });
132
- const options = {
133
- model: 'test-model',
134
- region: 'us-west-2',
135
- accessKeyId: 'AKIAIOSFODNN7EXAMPLE',
136
- secretAccessKey: 'wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY',
137
- };
138
- const config = await collector.collectConfig(options);
139
- expect(mockInquirer.prompt).toHaveBeenCalledWith([
140
- expect.objectContaining({
141
- type: 'password',
142
- name: 'sessionToken',
143
- message: 'AWS session token (optional, press enter to skip):',
144
- mask: '*',
145
- }),
146
- ]);
147
- expect(config.sessionToken).toBe('optional-token');
148
- });
149
- it('sets sessionToken to undefined when empty', async () => {
150
- mockInquirer.prompt.mockResolvedValueOnce({ sessionToken: '' });
151
- mockInquirer.prompt.mockResolvedValueOnce({ modelArn: '' });
152
- const options = {
153
- model: 'test-model',
154
- region: 'us-west-2',
155
- accessKeyId: 'AKIAIOSFODNN7EXAMPLE',
156
- secretAccessKey: 'wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY',
157
- };
158
- const config = await collector.collectConfig(options);
159
- expect(config.sessionToken).toBeUndefined();
160
- });
161
- it('prompts for optional modelArn', async () => {
162
- mockInquirer.prompt.mockResolvedValueOnce({ sessionToken: '' });
163
- mockInquirer.prompt.mockResolvedValueOnce({
164
- modelArn: 'arn:aws:bedrock:us-west-2:123456789012:model/test',
165
- });
166
- const options = {
167
- model: 'test-model',
168
- region: 'us-west-2',
169
- accessKeyId: 'AKIAIOSFODNN7EXAMPLE',
170
- secretAccessKey: 'wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY',
171
- };
172
- const config = await collector.collectConfig(options);
173
- expect(mockInquirer.prompt).toHaveBeenCalledWith([
174
- expect.objectContaining({
175
- type: 'input',
176
- name: 'modelArn',
177
- message: 'Model ARN (optional, press enter to skip):',
178
- }),
179
- ]);
180
- expect(config.modelArn).toBe('arn:aws:bedrock:us-west-2:123456789012:model/test');
181
- });
182
- it('sets modelArn to undefined when empty', async () => {
183
- mockInquirer.prompt.mockResolvedValueOnce({ sessionToken: '' });
184
- mockInquirer.prompt.mockResolvedValueOnce({ modelArn: '' });
185
- const options = {
186
- model: 'test-model',
187
- region: 'us-west-2',
188
- accessKeyId: 'AKIAIOSFODNN7EXAMPLE',
189
- secretAccessKey: 'wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY',
190
- };
191
- const config = await collector.collectConfig(options);
192
- expect(config.modelArn).toBeUndefined();
193
- });
194
- it('collects full configuration through interactive prompts', async () => {
195
- mockInquirer.prompt.mockResolvedValueOnce({ region: 'eu-west-1' });
196
- mockInquirer.prompt.mockResolvedValueOnce({ accessKeyId: 'AKIATEST' });
197
- mockInquirer.prompt.mockResolvedValueOnce({ secretAccessKey: 'secret123' });
198
- mockInquirer.prompt.mockResolvedValueOnce({ sessionToken: 'token456' });
199
- mockInquirer.prompt.mockResolvedValueOnce({
200
- modelArn: 'arn:aws:bedrock:eu-west-1:123:model/claude',
201
- });
202
- const options = {
203
- model: 'anthropic.claude-v2',
204
- };
205
- const config = await collector.collectConfig(options);
206
- expect(config).toEqual({
207
- type: 'bedrock',
208
- modelValue: 'anthropic.claude-v2',
209
- secretName: '',
210
- region: 'eu-west-1',
211
- accessKeyId: 'AKIATEST',
212
- secretAccessKey: 'secret123',
213
- sessionToken: 'token456',
214
- modelArn: 'arn:aws:bedrock:eu-west-1:123:model/claude',
215
- });
216
- });
217
- it('mixes CLI options and interactive prompts', async () => {
218
- mockInquirer.prompt.mockResolvedValueOnce({
219
- accessKeyId: 'AKIAPROMPTED',
220
- });
221
- mockInquirer.prompt.mockResolvedValueOnce({ sessionToken: '' });
222
- mockInquirer.prompt.mockResolvedValueOnce({ modelArn: '' });
223
- const options = {
224
- model: 'test-model',
225
- region: 'ap-south-1',
226
- secretAccessKey: 'providedSecret',
227
- };
228
- const config = await collector.collectConfig(options);
229
- expect(config).toEqual({
230
- type: 'bedrock',
231
- modelValue: 'test-model',
232
- secretName: '',
233
- region: 'ap-south-1',
234
- accessKeyId: 'AKIAPROMPTED',
235
- secretAccessKey: 'providedSecret',
236
- sessionToken: undefined,
237
- modelArn: undefined,
238
- });
239
- });
240
- });
241
- });
@@ -1 +0,0 @@
1
- export {};
@@ -1,180 +0,0 @@
1
- import { jest } from '@jest/globals';
2
- const mockInquirer = {
3
- prompt: jest.fn(),
4
- };
5
- jest.unstable_mockModule('inquirer', () => ({
6
- default: mockInquirer,
7
- }));
8
- const { OpenAIConfigCollector } = await import('./openai.js');
9
- describe('OpenAIConfigCollector', () => {
10
- let collector;
11
- beforeEach(() => {
12
- collector = new OpenAIConfigCollector();
13
- jest.clearAllMocks();
14
- });
15
- describe('collectConfig', () => {
16
- it('uses provided options without prompting', async () => {
17
- const options = {
18
- model: 'gpt-4o-mini',
19
- baseUrl: 'https://api.openai.com/v1',
20
- apiKey: 'sk-test-key-12345',
21
- };
22
- const config = await collector.collectConfig(options);
23
- expect(mockInquirer.prompt).not.toHaveBeenCalled();
24
- expect(config).toEqual({
25
- type: 'openai',
26
- modelValue: 'gpt-4o-mini',
27
- secretName: '',
28
- baseUrl: 'https://api.openai.com/v1',
29
- apiKey: 'sk-test-key-12345',
30
- });
31
- });
32
- it('prompts for missing baseUrl', async () => {
33
- mockInquirer.prompt.mockResolvedValueOnce({
34
- baseUrl: 'https://custom-openai.com',
35
- });
36
- mockInquirer.prompt.mockResolvedValueOnce({ apiKey: 'sk-custom-key' });
37
- const options = {
38
- model: 'gpt-4',
39
- };
40
- const config = await collector.collectConfig(options);
41
- expect(mockInquirer.prompt).toHaveBeenCalledWith([
42
- expect.objectContaining({
43
- type: 'input',
44
- name: 'baseUrl',
45
- message: 'base URL:',
46
- validate: expect.any(Function),
47
- }),
48
- ]);
49
- expect(config.baseUrl).toBe('https://custom-openai.com');
50
- });
51
- it('validates baseUrl is required', async () => {
52
- mockInquirer.prompt.mockResolvedValueOnce({ baseUrl: '' });
53
- const options = {
54
- model: 'gpt-4',
55
- };
56
- // The validation happens in the prompt, but we test the final check
57
- await expect(collector.collectConfig(options)).rejects.toThrow('base URL is required');
58
- });
59
- it('validates baseUrl is a valid URL', async () => {
60
- const options = {
61
- model: 'gpt-4',
62
- };
63
- // Get the validate function from the prompt call
64
- mockInquirer.prompt.mockImplementationOnce(async (questions) => {
65
- const validate = questions[0].validate;
66
- // Test invalid URL
67
- expect(validate('not-a-url')).toBe('please enter a valid URL');
68
- // Test empty string
69
- expect(validate('')).toBe('base URL is required');
70
- // Test valid URL
71
- expect(validate('https://api.openai.com')).toBe(true);
72
- return { baseUrl: 'https://api.openai.com' };
73
- });
74
- mockInquirer.prompt.mockResolvedValueOnce({ apiKey: 'sk-key' });
75
- await collector.collectConfig(options);
76
- });
77
- it('removes trailing slash from baseUrl', async () => {
78
- const options = {
79
- model: 'gpt-4',
80
- baseUrl: 'https://api.openai.com/v1/',
81
- apiKey: 'sk-test-key',
82
- };
83
- const config = await collector.collectConfig(options);
84
- expect(config.baseUrl).toBe('https://api.openai.com/v1');
85
- });
86
- it('prompts for missing apiKey as password field', async () => {
87
- mockInquirer.prompt.mockResolvedValueOnce({ apiKey: 'sk-secret-key' });
88
- const options = {
89
- model: 'gpt-4',
90
- baseUrl: 'https://api.openai.com/v1',
91
- };
92
- const config = await collector.collectConfig(options);
93
- expect(mockInquirer.prompt).toHaveBeenCalledWith([
94
- expect.objectContaining({
95
- type: 'password',
96
- name: 'apiKey',
97
- message: 'API key:',
98
- mask: '*',
99
- validate: expect.any(Function),
100
- }),
101
- ]);
102
- expect(config.apiKey).toBe('sk-secret-key');
103
- });
104
- it('validates apiKey is required', async () => {
105
- mockInquirer.prompt.mockResolvedValueOnce({ apiKey: '' });
106
- const options = {
107
- model: 'gpt-4',
108
- baseUrl: 'https://api.openai.com/v1',
109
- };
110
- await expect(collector.collectConfig(options)).rejects.toThrow('API key is required');
111
- });
112
- it('tests apiKey validation function', async () => {
113
- const options = {
114
- model: 'gpt-4',
115
- baseUrl: 'https://api.openai.com/v1',
116
- };
117
- // Get the validate function from the prompt call
118
- mockInquirer.prompt.mockImplementationOnce(async (questions) => {
119
- const validate = questions[0].validate;
120
- // Test empty string
121
- expect(validate('')).toBe('API key is required');
122
- // Test valid key
123
- expect(validate('sk-valid-key')).toBe(true);
124
- return { apiKey: 'sk-valid-key' };
125
- });
126
- await collector.collectConfig(options);
127
- });
128
- it('collects full configuration through interactive prompts', async () => {
129
- mockInquirer.prompt.mockResolvedValueOnce({
130
- baseUrl: 'https://api.openai.com/v1/',
131
- });
132
- mockInquirer.prompt.mockResolvedValueOnce({
133
- apiKey: 'sk-proj-abc123',
134
- });
135
- const options = {
136
- model: 'gpt-4o',
137
- };
138
- const config = await collector.collectConfig(options);
139
- expect(config).toEqual({
140
- type: 'openai',
141
- modelValue: 'gpt-4o',
142
- secretName: '',
143
- baseUrl: 'https://api.openai.com/v1',
144
- apiKey: 'sk-proj-abc123',
145
- });
146
- });
147
- it('mixes CLI options and interactive prompts', async () => {
148
- mockInquirer.prompt.mockResolvedValueOnce({
149
- apiKey: 'sk-prompted-key',
150
- });
151
- const options = {
152
- model: 'gpt-3.5-turbo',
153
- baseUrl: 'https://custom-api.com/v1',
154
- };
155
- const config = await collector.collectConfig(options);
156
- expect(config).toEqual({
157
- type: 'openai',
158
- modelValue: 'gpt-3.5-turbo',
159
- secretName: '',
160
- baseUrl: 'https://custom-api.com/v1',
161
- apiKey: 'sk-prompted-key',
162
- });
163
- });
164
- it('handles custom OpenAI-compatible endpoints', async () => {
165
- const options = {
166
- model: 'llama-3-8b',
167
- baseUrl: 'https://localhost:8080/v1',
168
- apiKey: 'local-key-123',
169
- };
170
- const config = await collector.collectConfig(options);
171
- expect(config).toEqual({
172
- type: 'openai',
173
- modelValue: 'llama-3-8b',
174
- secretName: '',
175
- baseUrl: 'https://localhost:8080/v1',
176
- apiKey: 'local-key-123',
177
- });
178
- });
179
- });
180
- });
@@ -1 +0,0 @@
1
- export {};