genai-lite 0.1.1 → 0.1.3

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.
@@ -0,0 +1,279 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const LLMService_1 = require("./LLMService");
4
+ describe('LLMService', () => {
5
+ let service;
6
+ let mockApiKeyProvider;
7
+ beforeEach(() => {
8
+ // Reset all mocks
9
+ jest.clearAllMocks();
10
+ // Create mock API key provider
11
+ mockApiKeyProvider = jest.fn(async (providerId) => `mock-key-for-${providerId}`);
12
+ // Create service instance
13
+ service = new LLMService_1.LLMService(mockApiKeyProvider);
14
+ });
15
+ describe('constructor and initialization', () => {
16
+ it('should initialize with the provided API key provider', () => {
17
+ expect(service).toBeDefined();
18
+ // The service should be ready to use
19
+ });
20
+ it('should lazy-load client adapters on first use', async () => {
21
+ mockApiKeyProvider.mockResolvedValueOnce('sk-test-key-12345678901234567890');
22
+ // First request should create the adapter
23
+ const request = {
24
+ providerId: 'openai',
25
+ modelId: 'gpt-4.1',
26
+ messages: [{ role: 'user', content: 'Hello' }]
27
+ };
28
+ await service.sendMessage(request);
29
+ // Verify API key provider was called
30
+ expect(mockApiKeyProvider).toHaveBeenCalledWith('openai');
31
+ });
32
+ });
33
+ describe('sendMessage', () => {
34
+ describe('request validation', () => {
35
+ it('should return validation error for unsupported provider', async () => {
36
+ const request = {
37
+ providerId: 'unsupported-provider',
38
+ modelId: 'some-model',
39
+ messages: [{ role: 'user', content: 'Hello' }]
40
+ };
41
+ const response = await service.sendMessage(request);
42
+ expect(response.object).toBe('error');
43
+ const errorResponse = response;
44
+ expect(errorResponse.error.code).toBe('UNSUPPORTED_PROVIDER');
45
+ expect(errorResponse.error.message).toContain('Unsupported provider');
46
+ });
47
+ it('should return validation error for unsupported model', async () => {
48
+ const request = {
49
+ providerId: 'openai',
50
+ modelId: 'unsupported-model',
51
+ messages: [{ role: 'user', content: 'Hello' }]
52
+ };
53
+ const response = await service.sendMessage(request);
54
+ expect(response.object).toBe('error');
55
+ const errorResponse = response;
56
+ expect(errorResponse.error.code).toBe('UNSUPPORTED_MODEL');
57
+ expect(errorResponse.error.message).toContain('Unsupported model');
58
+ });
59
+ it('should return validation error for empty messages', async () => {
60
+ const request = {
61
+ providerId: 'openai',
62
+ modelId: 'gpt-4.1',
63
+ messages: []
64
+ };
65
+ const response = await service.sendMessage(request);
66
+ expect(response.object).toBe('error');
67
+ const errorResponse = response;
68
+ expect(errorResponse.error.code).toBe('INVALID_REQUEST');
69
+ expect(errorResponse.error.message).toContain('Request must contain at least one message');
70
+ });
71
+ it('should return validation error for invalid message role', async () => {
72
+ const request = {
73
+ providerId: 'openai',
74
+ modelId: 'gpt-4.1',
75
+ messages: [{ role: 'invalid', content: 'Hello' }]
76
+ };
77
+ const response = await service.sendMessage(request);
78
+ expect(response.object).toBe('error');
79
+ const errorResponse = response;
80
+ expect(errorResponse.error.code).toBe('INVALID_MESSAGE_ROLE');
81
+ expect(errorResponse.error.message).toContain('Invalid message role');
82
+ });
83
+ it('should return validation error for empty message content', async () => {
84
+ const request = {
85
+ providerId: 'openai',
86
+ modelId: 'gpt-4.1',
87
+ messages: [{ role: 'user', content: '' }]
88
+ };
89
+ const response = await service.sendMessage(request);
90
+ expect(response.object).toBe('error');
91
+ const errorResponse = response;
92
+ expect(errorResponse.error.code).toBe('INVALID_MESSAGE');
93
+ expect(errorResponse.error.message).toContain('Message at index 0 must have both');
94
+ });
95
+ });
96
+ describe('API key handling', () => {
97
+ it('should return error when API key provider returns null', async () => {
98
+ mockApiKeyProvider.mockResolvedValueOnce(null);
99
+ const request = {
100
+ providerId: 'openai',
101
+ modelId: 'gpt-4.1',
102
+ messages: [{ role: 'user', content: 'Hello' }]
103
+ };
104
+ const response = await service.sendMessage(request);
105
+ expect(response.object).toBe('error');
106
+ const errorResponse = response;
107
+ expect(errorResponse.error.code).toBe('API_KEY_ERROR');
108
+ expect(errorResponse.error.message).toContain('API key for provider');
109
+ });
110
+ it('should return error when API key provider throws', async () => {
111
+ mockApiKeyProvider.mockRejectedValueOnce(new Error('Key provider error'));
112
+ const request = {
113
+ providerId: 'openai',
114
+ modelId: 'gpt-4.1',
115
+ messages: [{ role: 'user', content: 'Hello' }]
116
+ };
117
+ const response = await service.sendMessage(request);
118
+ expect(response.object).toBe('error');
119
+ const errorResponse = response;
120
+ expect(errorResponse.error.code).toBe('PROVIDER_ERROR');
121
+ expect(errorResponse.error.message).toContain('Key provider error');
122
+ });
123
+ it('should return error for invalid API key format', async () => {
124
+ mockApiKeyProvider.mockResolvedValueOnce('invalid-key');
125
+ const request = {
126
+ providerId: 'openai',
127
+ modelId: 'gpt-4.1',
128
+ messages: [{ role: 'user', content: 'Hello' }]
129
+ };
130
+ const response = await service.sendMessage(request);
131
+ // OpenAI adapter expects keys starting with 'sk-'
132
+ expect(response.object).toBe('error');
133
+ const errorResponse = response;
134
+ expect(errorResponse.error.code).toBe('INVALID_API_KEY');
135
+ });
136
+ });
137
+ describe('adapter routing', () => {
138
+ it('should route request to correct adapter based on provider', async () => {
139
+ mockApiKeyProvider.mockResolvedValueOnce('sk-test-key-12345678901234567890');
140
+ const request = {
141
+ providerId: 'openai',
142
+ modelId: 'gpt-4.1',
143
+ messages: [{ role: 'user', content: 'Test routing' }]
144
+ };
145
+ const response = await service.sendMessage(request);
146
+ // This will fail with a network error since we're not mocking the actual API
147
+ expect(response.object).toBe('error');
148
+ const errorResponse = response;
149
+ // We should get a network error or similar since we're not mocking the HTTP request
150
+ expect(errorResponse.provider).toBe('openai');
151
+ });
152
+ it('should reuse existing adapter for same provider', async () => {
153
+ const request = {
154
+ providerId: 'mock',
155
+ modelId: 'mock-model',
156
+ messages: [{ role: 'user', content: 'First request' }]
157
+ };
158
+ // First request
159
+ await service.sendMessage(request);
160
+ // Second request to same provider
161
+ request.messages = [{ role: 'user', content: 'Second request' }];
162
+ await service.sendMessage(request);
163
+ // API key provider should be called for each request with mock provider
164
+ expect(mockApiKeyProvider).toHaveBeenCalledTimes(0); // Mock provider doesn't need API keys
165
+ });
166
+ });
167
+ describe('settings management', () => {
168
+ it('should apply default settings when none provided', async () => {
169
+ mockApiKeyProvider.mockResolvedValueOnce('sk-test-key-12345678901234567890');
170
+ const request = {
171
+ providerId: 'openai',
172
+ modelId: 'gpt-4.1',
173
+ messages: [{ role: 'user', content: 'Hello' }]
174
+ };
175
+ const response = await service.sendMessage(request);
176
+ // We'll get a network error but can still verify the request was attempted
177
+ expect(response.object).toBe('error');
178
+ expect(mockApiKeyProvider).toHaveBeenCalledWith('openai');
179
+ });
180
+ it('should merge user settings with defaults', async () => {
181
+ mockApiKeyProvider.mockResolvedValueOnce('sk-test-key-12345678901234567890');
182
+ const request = {
183
+ providerId: 'openai',
184
+ modelId: 'gpt-4.1',
185
+ messages: [{ role: 'user', content: 'Hello' }],
186
+ settings: {
187
+ temperature: 0.9,
188
+ maxTokens: 500
189
+ }
190
+ };
191
+ const response = await service.sendMessage(request);
192
+ // We'll get a network error but the settings should still be validated
193
+ expect(response.object).toBe('error');
194
+ });
195
+ it('should validate temperature setting', async () => {
196
+ const request = {
197
+ providerId: 'openai',
198
+ modelId: 'gpt-4.1',
199
+ messages: [{ role: 'user', content: 'Hello' }],
200
+ settings: {
201
+ temperature: 2.5 // Out of range
202
+ }
203
+ };
204
+ const response = await service.sendMessage(request);
205
+ expect(response.object).toBe('error');
206
+ const errorResponse = response;
207
+ expect(errorResponse.error.code).toBe('INVALID_SETTINGS');
208
+ expect(errorResponse.error.message).toContain('temperature must be a number between');
209
+ });
210
+ it('should validate maxTokens setting', async () => {
211
+ const request = {
212
+ providerId: 'openai',
213
+ modelId: 'gpt-4.1',
214
+ messages: [{ role: 'user', content: 'Hello' }],
215
+ settings: {
216
+ maxTokens: 0 // Invalid
217
+ }
218
+ };
219
+ const response = await service.sendMessage(request);
220
+ expect(response.object).toBe('error');
221
+ const errorResponse = response;
222
+ expect(errorResponse.error.code).toBe('INVALID_SETTINGS');
223
+ expect(errorResponse.error.message).toContain('maxTokens must be an integer between');
224
+ });
225
+ it('should validate topP setting', async () => {
226
+ const request = {
227
+ providerId: 'openai',
228
+ modelId: 'gpt-4.1',
229
+ messages: [{ role: 'user', content: 'Hello' }],
230
+ settings: {
231
+ topP: -0.1 // Out of range
232
+ }
233
+ };
234
+ const response = await service.sendMessage(request);
235
+ expect(response.object).toBe('error');
236
+ const errorResponse = response;
237
+ expect(errorResponse.error.code).toBe('INVALID_SETTINGS');
238
+ expect(errorResponse.error.message).toContain('topP must be a number between 0 and 1');
239
+ });
240
+ });
241
+ });
242
+ describe('getProviders', () => {
243
+ it('should return all supported providers', async () => {
244
+ const providers = await service.getProviders();
245
+ expect(providers).toHaveLength(4);
246
+ expect(providers.find(p => p.id === 'openai')).toBeDefined();
247
+ expect(providers.find(p => p.id === 'anthropic')).toBeDefined();
248
+ expect(providers.find(p => p.id === 'gemini')).toBeDefined();
249
+ expect(providers.find(p => p.id === 'mistral')).toBeDefined();
250
+ });
251
+ it('should include provider metadata', async () => {
252
+ const providers = await service.getProviders();
253
+ const openai = providers.find(p => p.id === 'openai');
254
+ expect(openai).toMatchObject({
255
+ id: 'openai',
256
+ name: 'OpenAI'
257
+ });
258
+ });
259
+ });
260
+ describe('getModels', () => {
261
+ it('should return all models for a provider', async () => {
262
+ const models = await service.getModels('openai');
263
+ expect(models.length).toBeGreaterThan(0);
264
+ expect(models.some(m => m.id.includes('gpt-4'))).toBe(true);
265
+ expect(models.some(m => m.id.includes('o4-mini'))).toBe(true);
266
+ });
267
+ it('should return empty array for invalid provider', async () => {
268
+ const models = await service.getModels('invalid-provider');
269
+ expect(models).toEqual([]);
270
+ });
271
+ it('should include model metadata', async () => {
272
+ const models = await service.getModels('openai');
273
+ const gpt4 = models.find(m => m.id === 'gpt-4.1');
274
+ expect(gpt4).toBeDefined();
275
+ expect(gpt4.contextWindow).toBeGreaterThan(0);
276
+ expect(gpt4.maxTokens).toBeGreaterThan(0);
277
+ });
278
+ });
279
+ });
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,263 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ const sdk_1 = __importDefault(require("@anthropic-ai/sdk"));
7
+ const AnthropicClientAdapter_1 = require("./AnthropicClientAdapter");
8
+ const types_1 = require("./types");
9
+ // Mock the entire '@anthropic-ai/sdk' module
10
+ jest.mock('@anthropic-ai/sdk');
11
+ // Cast the mocked module to allow setting up mock implementations
12
+ const MockAnthropic = sdk_1.default;
13
+ describe('AnthropicClientAdapter', () => {
14
+ let adapter;
15
+ let mockCreate;
16
+ let basicRequest;
17
+ beforeEach(() => {
18
+ // Reset mocks before each test
19
+ MockAnthropic.mockClear();
20
+ mockCreate = jest.fn();
21
+ // Mock the messages.create method
22
+ MockAnthropic.prototype.messages = {
23
+ create: mockCreate,
24
+ };
25
+ adapter = new AnthropicClientAdapter_1.AnthropicClientAdapter();
26
+ basicRequest = {
27
+ providerId: 'anthropic',
28
+ modelId: 'claude-3-5-sonnet-20241022',
29
+ messages: [{ role: 'user', content: 'Hello' }],
30
+ settings: {
31
+ temperature: 0.7,
32
+ maxTokens: 100,
33
+ topP: 1,
34
+ frequencyPenalty: 0,
35
+ presencePenalty: 0,
36
+ stopSequences: [],
37
+ user: 'test-user',
38
+ geminiSafetySettings: [],
39
+ supportsSystemMessage: true
40
+ }
41
+ };
42
+ });
43
+ describe('sendMessage', () => {
44
+ it('should format the request correctly and call the Anthropic API', async () => {
45
+ // Setup mock response
46
+ mockCreate.mockResolvedValueOnce({
47
+ id: 'msg_123',
48
+ type: 'message',
49
+ role: 'assistant',
50
+ model: 'claude-3-5-sonnet-20241022',
51
+ content: [{
52
+ type: 'text',
53
+ text: 'Hello! How can I help you today?'
54
+ }],
55
+ stop_reason: 'end_turn',
56
+ stop_sequence: null,
57
+ usage: {
58
+ input_tokens: 10,
59
+ output_tokens: 20
60
+ }
61
+ });
62
+ const response = await adapter.sendMessage(basicRequest, 'test-api-key');
63
+ // Verify Anthropic was instantiated with the API key
64
+ expect(MockAnthropic).toHaveBeenCalledWith({
65
+ apiKey: 'test-api-key',
66
+ baseURL: undefined
67
+ });
68
+ // Verify the create method was called with correct parameters
69
+ expect(mockCreate).toHaveBeenCalledWith({
70
+ model: 'claude-3-5-sonnet-20241022',
71
+ messages: [{ role: 'user', content: 'Hello' }],
72
+ max_tokens: 100,
73
+ temperature: 0.7,
74
+ top_p: 1
75
+ });
76
+ // Verify the response
77
+ expect(response.object).toBe('chat.completion');
78
+ const successResponse = response;
79
+ expect(successResponse.id).toBe('msg_123');
80
+ expect(successResponse.provider).toBe('anthropic');
81
+ expect(successResponse.model).toBe('claude-3-5-sonnet-20241022');
82
+ expect(successResponse.choices[0].message.content).toBe('Hello! How can I help you today?');
83
+ expect(successResponse.usage?.total_tokens).toBe(30);
84
+ });
85
+ it('should handle system messages by merging into first user message', async () => {
86
+ basicRequest.messages = [
87
+ { role: 'system', content: 'You are a helpful assistant.' },
88
+ { role: 'user', content: 'Hello' }
89
+ ];
90
+ mockCreate.mockResolvedValueOnce({
91
+ id: 'msg_123',
92
+ type: 'message',
93
+ role: 'assistant',
94
+ model: 'claude-3-5-sonnet-20241022',
95
+ content: [{ type: 'text', text: 'Hello!' }],
96
+ stop_reason: 'end_turn',
97
+ usage: { input_tokens: 15, output_tokens: 5 }
98
+ });
99
+ await adapter.sendMessage(basicRequest, 'test-api-key');
100
+ // System message should be sent as separate system parameter
101
+ expect(mockCreate).toHaveBeenCalledWith(expect.objectContaining({
102
+ system: 'You are a helpful assistant.',
103
+ messages: [{
104
+ role: 'user',
105
+ content: 'Hello'
106
+ }]
107
+ }));
108
+ });
109
+ it('should handle stop sequences correctly', async () => {
110
+ basicRequest.settings.stopSequences = ['END', 'STOP'];
111
+ mockCreate.mockResolvedValueOnce({
112
+ id: 'msg_123',
113
+ type: 'message',
114
+ role: 'assistant',
115
+ model: 'claude-3-5-sonnet-20241022',
116
+ content: [{ type: 'text', text: 'Response' }],
117
+ stop_reason: 'end_turn',
118
+ usage: { input_tokens: 10, output_tokens: 10 }
119
+ });
120
+ await adapter.sendMessage(basicRequest, 'test-api-key');
121
+ expect(mockCreate).toHaveBeenCalledWith(expect.objectContaining({
122
+ stop_sequences: ['END', 'STOP']
123
+ }));
124
+ });
125
+ it('should handle multi-turn conversations', async () => {
126
+ basicRequest.messages = [
127
+ { role: 'user', content: 'Hello' },
128
+ { role: 'assistant', content: 'Hi there!' },
129
+ { role: 'user', content: 'How are you?' }
130
+ ];
131
+ mockCreate.mockResolvedValueOnce({
132
+ id: 'msg_123',
133
+ type: 'message',
134
+ role: 'assistant',
135
+ model: 'claude-3-5-sonnet-20241022',
136
+ content: [{ type: 'text', text: "I'm doing well, thanks!" }],
137
+ stop_reason: 'end_turn',
138
+ usage: { input_tokens: 20, output_tokens: 10 }
139
+ });
140
+ await adapter.sendMessage(basicRequest, 'test-api-key');
141
+ expect(mockCreate).toHaveBeenCalledWith(expect.objectContaining({
142
+ messages: [
143
+ { role: 'user', content: 'Hello' },
144
+ { role: 'assistant', content: 'Hi there!' },
145
+ { role: 'user', content: 'How are you?' }
146
+ ]
147
+ }));
148
+ });
149
+ it('should map stop_reason correctly', async () => {
150
+ const stopReasons = [
151
+ { anthropic: 'end_turn', expected: 'stop' },
152
+ { anthropic: 'max_tokens', expected: 'length' },
153
+ { anthropic: 'stop_sequence', expected: 'stop' },
154
+ { anthropic: 'unknown_reason', expected: 'other' }
155
+ ];
156
+ for (const { anthropic, expected } of stopReasons) {
157
+ mockCreate.mockResolvedValueOnce({
158
+ id: 'msg_123',
159
+ type: 'message',
160
+ role: 'assistant',
161
+ model: 'claude-3-5-sonnet-20241022',
162
+ content: [{ type: 'text', text: 'Response' }],
163
+ stop_reason: anthropic,
164
+ usage: { input_tokens: 10, output_tokens: 10 }
165
+ });
166
+ const response = await adapter.sendMessage(basicRequest, 'test-api-key');
167
+ const successResponse = response;
168
+ expect(successResponse.choices[0].finish_reason).toBe(expected);
169
+ }
170
+ });
171
+ describe('error handling', () => {
172
+ it('should handle authentication errors (401)', async () => {
173
+ const apiError = new Error('Invalid API key');
174
+ apiError.status = 401;
175
+ mockCreate.mockRejectedValueOnce(apiError);
176
+ const response = await adapter.sendMessage(basicRequest, 'invalid-key');
177
+ expect(response.object).toBe('error');
178
+ const errorResponse = response;
179
+ expect(errorResponse.error.code).toBe(types_1.ADAPTER_ERROR_CODES.INVALID_API_KEY);
180
+ expect(errorResponse.error.type).toBe('authentication_error');
181
+ });
182
+ it('should handle rate limit errors (429)', async () => {
183
+ const apiError = new Error('Rate limit exceeded');
184
+ apiError.status = 429;
185
+ mockCreate.mockRejectedValueOnce(apiError);
186
+ const response = await adapter.sendMessage(basicRequest, 'test-key');
187
+ const errorResponse = response;
188
+ expect(errorResponse.error.code).toBe(types_1.ADAPTER_ERROR_CODES.RATE_LIMIT_EXCEEDED);
189
+ expect(errorResponse.error.type).toBe('rate_limit_error');
190
+ });
191
+ it('should handle context length errors', async () => {
192
+ // Create a mock error that simulates Anthropic.APIError
193
+ const apiError = Object.assign(new Error('Message is too long'), {
194
+ status: 400,
195
+ constructor: { name: 'APIError' }
196
+ });
197
+ Object.setPrototypeOf(apiError, sdk_1.default.APIError.prototype);
198
+ mockCreate.mockRejectedValueOnce(apiError);
199
+ const response = await adapter.sendMessage(basicRequest, 'test-key');
200
+ const errorResponse = response;
201
+ expect(errorResponse.error.code).toBe(types_1.ADAPTER_ERROR_CODES.CONTEXT_LENGTH_EXCEEDED);
202
+ expect(errorResponse.error.type).toBe('invalid_request_error');
203
+ });
204
+ it('should handle invalid model errors', async () => {
205
+ const apiError = new Error('Model not found');
206
+ apiError.status = 404;
207
+ mockCreate.mockRejectedValueOnce(apiError);
208
+ const response = await adapter.sendMessage(basicRequest, 'test-key');
209
+ const errorResponse = response;
210
+ expect(errorResponse.error.code).toBe(types_1.ADAPTER_ERROR_CODES.MODEL_NOT_FOUND);
211
+ expect(errorResponse.error.type).toBe('invalid_request_error');
212
+ });
213
+ it('should handle credit errors', async () => {
214
+ const apiError = new Error('Insufficient credits');
215
+ apiError.status = 402;
216
+ mockCreate.mockRejectedValueOnce(apiError);
217
+ const response = await adapter.sendMessage(basicRequest, 'test-key');
218
+ const errorResponse = response;
219
+ expect(errorResponse.error.code).toBe(types_1.ADAPTER_ERROR_CODES.INSUFFICIENT_CREDITS);
220
+ expect(errorResponse.error.type).toBe('rate_limit_error');
221
+ });
222
+ it('should handle server errors (500)', async () => {
223
+ const apiError = new Error('Internal server error');
224
+ apiError.status = 500;
225
+ mockCreate.mockRejectedValueOnce(apiError);
226
+ const response = await adapter.sendMessage(basicRequest, 'test-key');
227
+ const errorResponse = response;
228
+ expect(errorResponse.error.code).toBe(types_1.ADAPTER_ERROR_CODES.PROVIDER_ERROR);
229
+ expect(errorResponse.error.type).toBe('server_error');
230
+ });
231
+ it('should handle network errors', async () => {
232
+ const networkError = new Error('Network error');
233
+ networkError.code = 'ENOTFOUND';
234
+ mockCreate.mockRejectedValueOnce(networkError);
235
+ const response = await adapter.sendMessage(basicRequest, 'test-key');
236
+ const errorResponse = response;
237
+ expect(errorResponse.error.code).toBe(types_1.ADAPTER_ERROR_CODES.NETWORK_ERROR);
238
+ expect(errorResponse.error.type).toBe('connection_error');
239
+ });
240
+ });
241
+ });
242
+ describe('validateApiKey', () => {
243
+ it('should validate API key format', () => {
244
+ // Valid Anthropic API key format - must start with 'sk-ant-' and be at least 30 chars
245
+ expect(adapter.validateApiKey('sk-ant-api01-test123456789012345')).toBe(true);
246
+ expect(adapter.validateApiKey('sk-ant-api03-test123456789012345')).toBe(true);
247
+ // Invalid formats
248
+ expect(adapter.validateApiKey('invalid')).toBe(false);
249
+ expect(adapter.validateApiKey('')).toBe(false);
250
+ expect(adapter.validateApiKey('sk-test')).toBe(false); // OpenAI format
251
+ expect(adapter.validateApiKey('sk-ant-test123')).toBe(false); // Too short
252
+ });
253
+ });
254
+ describe('getAdapterInfo', () => {
255
+ it('should return correct adapter information', () => {
256
+ const info = adapter.getAdapterInfo();
257
+ expect(info.providerId).toBe('anthropic');
258
+ expect(info.name).toBe('Anthropic Client Adapter');
259
+ expect(info.version).toBeDefined();
260
+ // supportedModels is not part of the interface
261
+ });
262
+ });
263
+ });
@@ -0,0 +1 @@
1
+ export {};