@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.
- package/dist/commands/export/index.js +6 -4
- package/dist/commands/generate/generators/agent.js +2 -0
- package/dist/commands/generate/generators/marketplace.js +2 -0
- package/dist/commands/generate/generators/mcpserver.js +2 -0
- package/dist/commands/generate/generators/project.js +9 -2
- package/dist/commands/generate/generators/query.js +2 -0
- package/dist/commands/generate/generators/team.js +2 -0
- package/dist/commands/generate/templateDiscovery.js +1 -0
- package/dist/commands/generate/templateEngine.js +1 -3
- package/dist/commands/import/index.js +1 -1
- package/dist/commands/install/index.js +2 -1
- package/dist/commands/models/kubernetes/manifest-builder.js +27 -10
- package/dist/commands/models/providers/azure.d.ts +10 -7
- package/dist/commands/models/providers/azure.js +83 -21
- package/dist/commands/uninstall/index.js +1 -1
- package/dist/components/ChatUI.js +17 -16
- package/dist/components/statusChecker.js +3 -3
- package/dist/lib/arkApiClient.js +11 -9
- package/dist/lib/arkApiProxy.js +1 -0
- package/dist/lib/arkServiceProxy.js +5 -1
- package/dist/lib/chatClient.js +9 -0
- package/dist/lib/config.js +8 -3
- package/dist/lib/errors.js +3 -0
- package/dist/ui/asyncOperations/connectingToArk.js +2 -2
- package/package.json +16 -12
- package/dist/arkServices.spec.d.ts +0 -1
- package/dist/arkServices.spec.js +0 -138
- package/dist/commands/agents/index.spec.d.ts +0 -1
- package/dist/commands/agents/index.spec.js +0 -67
- package/dist/commands/cluster/get.spec.d.ts +0 -1
- package/dist/commands/cluster/get.spec.js +0 -92
- package/dist/commands/cluster/index.spec.d.ts +0 -1
- package/dist/commands/cluster/index.spec.js +0 -24
- package/dist/commands/completion/index.spec.d.ts +0 -1
- package/dist/commands/completion/index.spec.js +0 -34
- package/dist/commands/config/index.spec.d.ts +0 -1
- package/dist/commands/config/index.spec.js +0 -78
- package/dist/commands/evaluation/index.spec.d.ts +0 -1
- package/dist/commands/evaluation/index.spec.js +0 -161
- package/dist/commands/export/index.spec.d.ts +0 -1
- package/dist/commands/export/index.spec.js +0 -145
- package/dist/commands/import/index.spec.d.ts +0 -1
- package/dist/commands/import/index.spec.js +0 -46
- package/dist/commands/install/index.spec.d.ts +0 -1
- package/dist/commands/install/index.spec.js +0 -286
- package/dist/commands/marketplace/index.spec.d.ts +0 -1
- package/dist/commands/marketplace/index.spec.js +0 -88
- package/dist/commands/memory/index.spec.d.ts +0 -1
- package/dist/commands/memory/index.spec.js +0 -124
- package/dist/commands/models/create.spec.d.ts +0 -1
- package/dist/commands/models/create.spec.js +0 -167
- package/dist/commands/models/index.spec.d.ts +0 -1
- package/dist/commands/models/index.spec.js +0 -96
- package/dist/commands/models/providers/azure.spec.d.ts +0 -1
- package/dist/commands/models/providers/azure.spec.js +0 -232
- package/dist/commands/models/providers/bedrock.spec.d.ts +0 -1
- package/dist/commands/models/providers/bedrock.spec.js +0 -241
- package/dist/commands/models/providers/openai.spec.d.ts +0 -1
- package/dist/commands/models/providers/openai.spec.js +0 -180
- package/dist/commands/queries/delete.spec.d.ts +0 -1
- package/dist/commands/queries/delete.spec.js +0 -74
- package/dist/commands/queries/index.spec.d.ts +0 -1
- package/dist/commands/queries/index.spec.js +0 -167
- package/dist/commands/queries/list.spec.d.ts +0 -1
- package/dist/commands/queries/list.spec.js +0 -170
- package/dist/commands/queries/validation.spec.d.ts +0 -1
- package/dist/commands/queries/validation.spec.js +0 -27
- package/dist/commands/query/index.spec.d.ts +0 -1
- package/dist/commands/query/index.spec.js +0 -104
- package/dist/commands/targets/index.spec.d.ts +0 -1
- package/dist/commands/targets/index.spec.js +0 -154
- package/dist/commands/teams/index.spec.d.ts +0 -1
- package/dist/commands/teams/index.spec.js +0 -70
- package/dist/commands/tools/index.spec.d.ts +0 -1
- package/dist/commands/tools/index.spec.js +0 -70
- package/dist/commands/uninstall/index.spec.d.ts +0 -1
- package/dist/commands/uninstall/index.spec.js +0 -125
- package/dist/lib/arkServiceProxy.spec.d.ts +0 -1
- package/dist/lib/arkServiceProxy.spec.js +0 -100
- package/dist/lib/arkStatus.spec.d.ts +0 -1
- package/dist/lib/arkStatus.spec.js +0 -49
- package/dist/lib/chatClient.spec.d.ts +0 -1
- package/dist/lib/chatClient.spec.js +0 -108
- package/dist/lib/cluster.spec.d.ts +0 -1
- package/dist/lib/cluster.spec.js +0 -338
- package/dist/lib/commands.spec.d.ts +0 -1
- package/dist/lib/commands.spec.js +0 -146
- package/dist/lib/config.spec.d.ts +0 -1
- package/dist/lib/config.spec.js +0 -202
- package/dist/lib/duration.spec.d.ts +0 -1
- package/dist/lib/duration.spec.js +0 -13
- package/dist/lib/errors.spec.d.ts +0 -1
- package/dist/lib/errors.spec.js +0 -221
- package/dist/lib/executeQuery.spec.d.ts +0 -1
- package/dist/lib/executeQuery.spec.js +0 -325
- package/dist/lib/kubectl.spec.d.ts +0 -1
- package/dist/lib/kubectl.spec.js +0 -192
- package/dist/lib/marketplaceFetcher.spec.d.ts +0 -1
- package/dist/lib/marketplaceFetcher.spec.js +0 -225
- package/dist/lib/nextSteps.spec.d.ts +0 -1
- package/dist/lib/nextSteps.spec.js +0 -59
- package/dist/lib/output.spec.d.ts +0 -1
- package/dist/lib/output.spec.js +0 -123
- package/dist/lib/startup.spec.d.ts +0 -1
- package/dist/lib/startup.spec.js +0 -152
- package/dist/lib/stdin.spec.d.ts +0 -1
- package/dist/lib/stdin.spec.js +0 -82
- package/dist/lib/timeout.spec.d.ts +0 -1
- package/dist/lib/timeout.spec.js +0 -14
- package/dist/lib/waitForReady.spec.d.ts +0 -1
- package/dist/lib/waitForReady.spec.js +0 -104
- package/dist/marketplaceServices.spec.d.ts +0 -1
- package/dist/marketplaceServices.spec.js +0 -74
- package/dist/ui/statusFormatter.spec.d.ts +0 -1
- 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 {};
|