@agents-at-scale/ark 0.1.52 → 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 (116) hide show
  1. package/dist/arkServices.js +11 -7
  2. package/dist/commands/export/index.js +6 -4
  3. package/dist/commands/generate/generators/agent.js +2 -0
  4. package/dist/commands/generate/generators/marketplace.js +2 -0
  5. package/dist/commands/generate/generators/mcpserver.js +2 -0
  6. package/dist/commands/generate/generators/project.js +9 -2
  7. package/dist/commands/generate/generators/query.js +2 -0
  8. package/dist/commands/generate/generators/team.js +2 -0
  9. package/dist/commands/generate/templateDiscovery.js +1 -0
  10. package/dist/commands/generate/templateEngine.js +1 -3
  11. package/dist/commands/import/index.js +1 -1
  12. package/dist/commands/install/index.js +2 -1
  13. package/dist/commands/models/kubernetes/manifest-builder.js +27 -10
  14. package/dist/commands/models/providers/azure.d.ts +10 -7
  15. package/dist/commands/models/providers/azure.js +83 -21
  16. package/dist/commands/uninstall/index.js +1 -1
  17. package/dist/components/ChatUI.js +17 -16
  18. package/dist/components/statusChecker.js +3 -3
  19. package/dist/lib/arkApiClient.js +11 -9
  20. package/dist/lib/arkApiProxy.js +1 -0
  21. package/dist/lib/arkServiceProxy.js +5 -1
  22. package/dist/lib/chatClient.js +9 -0
  23. package/dist/lib/config.js +8 -3
  24. package/dist/lib/errors.js +3 -0
  25. package/dist/ui/asyncOperations/connectingToArk.js +2 -2
  26. package/package.json +17 -13
  27. package/dist/arkServices.spec.d.ts +0 -1
  28. package/dist/arkServices.spec.js +0 -138
  29. package/dist/commands/agents/index.spec.d.ts +0 -1
  30. package/dist/commands/agents/index.spec.js +0 -67
  31. package/dist/commands/cluster/get.spec.d.ts +0 -1
  32. package/dist/commands/cluster/get.spec.js +0 -92
  33. package/dist/commands/cluster/index.spec.d.ts +0 -1
  34. package/dist/commands/cluster/index.spec.js +0 -24
  35. package/dist/commands/completion/index.spec.d.ts +0 -1
  36. package/dist/commands/completion/index.spec.js +0 -34
  37. package/dist/commands/config/index.spec.d.ts +0 -1
  38. package/dist/commands/config/index.spec.js +0 -78
  39. package/dist/commands/evaluation/index.spec.d.ts +0 -1
  40. package/dist/commands/evaluation/index.spec.js +0 -161
  41. package/dist/commands/export/index.spec.d.ts +0 -1
  42. package/dist/commands/export/index.spec.js +0 -145
  43. package/dist/commands/import/index.spec.d.ts +0 -1
  44. package/dist/commands/import/index.spec.js +0 -46
  45. package/dist/commands/install/index.spec.d.ts +0 -1
  46. package/dist/commands/install/index.spec.js +0 -286
  47. package/dist/commands/marketplace/index.spec.d.ts +0 -1
  48. package/dist/commands/marketplace/index.spec.js +0 -88
  49. package/dist/commands/memory/index.spec.d.ts +0 -1
  50. package/dist/commands/memory/index.spec.js +0 -124
  51. package/dist/commands/models/create.spec.d.ts +0 -1
  52. package/dist/commands/models/create.spec.js +0 -167
  53. package/dist/commands/models/index.spec.d.ts +0 -1
  54. package/dist/commands/models/index.spec.js +0 -96
  55. package/dist/commands/models/providers/azure.spec.d.ts +0 -1
  56. package/dist/commands/models/providers/azure.spec.js +0 -232
  57. package/dist/commands/models/providers/bedrock.spec.d.ts +0 -1
  58. package/dist/commands/models/providers/bedrock.spec.js +0 -241
  59. package/dist/commands/models/providers/openai.spec.d.ts +0 -1
  60. package/dist/commands/models/providers/openai.spec.js +0 -180
  61. package/dist/commands/queries/delete.spec.d.ts +0 -1
  62. package/dist/commands/queries/delete.spec.js +0 -74
  63. package/dist/commands/queries/index.spec.d.ts +0 -1
  64. package/dist/commands/queries/index.spec.js +0 -167
  65. package/dist/commands/queries/list.spec.d.ts +0 -1
  66. package/dist/commands/queries/list.spec.js +0 -170
  67. package/dist/commands/queries/validation.spec.d.ts +0 -1
  68. package/dist/commands/queries/validation.spec.js +0 -27
  69. package/dist/commands/query/index.spec.d.ts +0 -1
  70. package/dist/commands/query/index.spec.js +0 -104
  71. package/dist/commands/targets/index.spec.d.ts +0 -1
  72. package/dist/commands/targets/index.spec.js +0 -154
  73. package/dist/commands/teams/index.spec.d.ts +0 -1
  74. package/dist/commands/teams/index.spec.js +0 -70
  75. package/dist/commands/tools/index.spec.d.ts +0 -1
  76. package/dist/commands/tools/index.spec.js +0 -70
  77. package/dist/commands/uninstall/index.spec.d.ts +0 -1
  78. package/dist/commands/uninstall/index.spec.js +0 -125
  79. package/dist/lib/arkServiceProxy.spec.d.ts +0 -1
  80. package/dist/lib/arkServiceProxy.spec.js +0 -100
  81. package/dist/lib/arkStatus.spec.d.ts +0 -1
  82. package/dist/lib/arkStatus.spec.js +0 -49
  83. package/dist/lib/chatClient.spec.d.ts +0 -1
  84. package/dist/lib/chatClient.spec.js +0 -108
  85. package/dist/lib/cluster.spec.d.ts +0 -1
  86. package/dist/lib/cluster.spec.js +0 -338
  87. package/dist/lib/commands.spec.d.ts +0 -1
  88. package/dist/lib/commands.spec.js +0 -146
  89. package/dist/lib/config.spec.d.ts +0 -1
  90. package/dist/lib/config.spec.js +0 -202
  91. package/dist/lib/duration.spec.d.ts +0 -1
  92. package/dist/lib/duration.spec.js +0 -13
  93. package/dist/lib/errors.spec.d.ts +0 -1
  94. package/dist/lib/errors.spec.js +0 -221
  95. package/dist/lib/executeQuery.spec.d.ts +0 -1
  96. package/dist/lib/executeQuery.spec.js +0 -325
  97. package/dist/lib/kubectl.spec.d.ts +0 -1
  98. package/dist/lib/kubectl.spec.js +0 -192
  99. package/dist/lib/marketplaceFetcher.spec.d.ts +0 -1
  100. package/dist/lib/marketplaceFetcher.spec.js +0 -225
  101. package/dist/lib/nextSteps.spec.d.ts +0 -1
  102. package/dist/lib/nextSteps.spec.js +0 -59
  103. package/dist/lib/output.spec.d.ts +0 -1
  104. package/dist/lib/output.spec.js +0 -123
  105. package/dist/lib/startup.spec.d.ts +0 -1
  106. package/dist/lib/startup.spec.js +0 -152
  107. package/dist/lib/stdin.spec.d.ts +0 -1
  108. package/dist/lib/stdin.spec.js +0 -82
  109. package/dist/lib/timeout.spec.d.ts +0 -1
  110. package/dist/lib/timeout.spec.js +0 -14
  111. package/dist/lib/waitForReady.spec.d.ts +0 -1
  112. package/dist/lib/waitForReady.spec.js +0 -104
  113. package/dist/marketplaceServices.spec.d.ts +0 -1
  114. package/dist/marketplaceServices.spec.js +0 -74
  115. package/dist/ui/statusFormatter.spec.d.ts +0 -1
  116. 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 {};