universal-llm-client 4.1.0 → 4.3.0

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 (103) hide show
  1. package/CHANGELOG.md +139 -103
  2. package/LICENSE +21 -21
  3. package/README.md +591 -591
  4. package/dist/ai-model.js.map +1 -1
  5. package/dist/auditor.js.map +1 -1
  6. package/dist/client.js.map +1 -1
  7. package/dist/http.js.map +1 -1
  8. package/dist/index.d.ts +1 -1
  9. package/dist/index.d.ts.map +1 -1
  10. package/dist/index.js +1 -1
  11. package/dist/index.js.map +1 -1
  12. package/dist/interfaces.d.ts +20 -0
  13. package/dist/interfaces.d.ts.map +1 -1
  14. package/dist/interfaces.js.map +1 -1
  15. package/dist/mcp.js.map +1 -1
  16. package/dist/providers/anthropic.js.map +1 -1
  17. package/dist/providers/google.d.ts.map +1 -1
  18. package/dist/providers/google.js +2 -0
  19. package/dist/providers/google.js.map +1 -1
  20. package/dist/providers/index.js.map +1 -1
  21. package/dist/providers/ollama.js.map +1 -1
  22. package/dist/providers/openai.js.map +1 -1
  23. package/dist/router.js.map +1 -1
  24. package/dist/stream-decoder.js.map +1 -1
  25. package/dist/structured-output.d.ts +24 -1
  26. package/dist/structured-output.d.ts.map +1 -1
  27. package/dist/structured-output.js +58 -5
  28. package/dist/structured-output.js.map +1 -1
  29. package/dist/tools.js.map +1 -1
  30. package/dist/zod-adapter.js.map +1 -1
  31. package/package.json +115 -116
  32. package/src/ai-model.ts +0 -350
  33. package/src/auditor.ts +0 -213
  34. package/src/client.ts +0 -402
  35. package/src/debug/debug-google-streaming.ts +0 -97
  36. package/src/debug/debug-tool-execution.ts +0 -86
  37. package/src/debug/test-lmstudio-tools.ts +0 -155
  38. package/src/demos/README.md +0 -47
  39. package/src/demos/basic/universal-llm-examples.ts +0 -161
  40. package/src/demos/mcp/astrid-memory-demo.ts +0 -295
  41. package/src/demos/mcp/astrid-persona-memory.ts +0 -357
  42. package/src/demos/mcp/mcp-mongodb-demo.ts +0 -275
  43. package/src/demos/mcp/simple-astrid-memory.ts +0 -148
  44. package/src/demos/mcp/simple-mcp-demo.ts +0 -68
  45. package/src/demos/mcp/working-mcp-demo.ts +0 -62
  46. package/src/demos/model-alias-demo.ts +0 -0
  47. package/src/demos/tools/RAG_MEMORY_INTEGRATION.md +0 -267
  48. package/src/demos/tools/astrid-memory-demo.ts +0 -270
  49. package/src/demos/tools/astrid-production-memory-clean.ts +0 -785
  50. package/src/demos/tools/astrid-production-memory.ts +0 -558
  51. package/src/demos/tools/basic-translation-test.ts +0 -66
  52. package/src/demos/tools/chromadb-similarity-tuning.ts +0 -390
  53. package/src/demos/tools/clean-multilingual-conversation.ts +0 -209
  54. package/src/demos/tools/clean-translation-test.ts +0 -119
  55. package/src/demos/tools/clean-universal-multilingual-test.ts +0 -131
  56. package/src/demos/tools/complete-rag-demo.ts +0 -369
  57. package/src/demos/tools/complete-tool-demo.ts +0 -132
  58. package/src/demos/tools/demo-tool-calling.ts +0 -124
  59. package/src/demos/tools/dynamic-language-switching-test.ts +0 -251
  60. package/src/demos/tools/hybrid-thinking-test.ts +0 -154
  61. package/src/demos/tools/memory-integration-test.ts +0 -420
  62. package/src/demos/tools/multilingual-memory-system.ts +0 -802
  63. package/src/demos/tools/ondemand-translation-demo.ts +0 -655
  64. package/src/demos/tools/production-tool-demo.ts +0 -245
  65. package/src/demos/tools/revolutionary-multilingual-test.ts +0 -151
  66. package/src/demos/tools/rigorous-language-analysis.ts +0 -218
  67. package/src/demos/tools/test-universal-memory-system.ts +0 -126
  68. package/src/demos/tools/translation-integration-guide.ts +0 -346
  69. package/src/demos/tools/universal-memory-system.ts +0 -560
  70. package/src/http.ts +0 -247
  71. package/src/index.ts +0 -160
  72. package/src/interfaces.ts +0 -657
  73. package/src/mcp.ts +0 -345
  74. package/src/providers/anthropic.ts +0 -762
  75. package/src/providers/google.ts +0 -620
  76. package/src/providers/index.ts +0 -8
  77. package/src/providers/ollama.ts +0 -469
  78. package/src/providers/openai.ts +0 -392
  79. package/src/router.ts +0 -780
  80. package/src/stream-decoder.ts +0 -361
  81. package/src/structured-output.ts +0 -702
  82. package/src/test-scripts/test-advanced-tools.ts +0 -310
  83. package/src/test-scripts/test-google-streaming-enhanced.ts +0 -147
  84. package/src/test-scripts/test-google-streaming.ts +0 -63
  85. package/src/test-scripts/test-google-system-prompt-comprehensive.ts +0 -189
  86. package/src/test-scripts/test-mcp-config.ts +0 -28
  87. package/src/test-scripts/test-mcp-connection.ts +0 -29
  88. package/src/test-scripts/test-system-message-positions.ts +0 -163
  89. package/src/test-scripts/test-system-prompt-improvement-demo.ts +0 -83
  90. package/src/test-scripts/test-tool-calling.ts +0 -231
  91. package/src/tests/ai-model.test.ts +0 -1614
  92. package/src/tests/auditor.test.ts +0 -224
  93. package/src/tests/http.test.ts +0 -200
  94. package/src/tests/interfaces.test.ts +0 -117
  95. package/src/tests/providers/google.test.ts +0 -660
  96. package/src/tests/providers/ollama.test.ts +0 -954
  97. package/src/tests/providers/openai.test.ts +0 -1122
  98. package/src/tests/router.test.ts +0 -254
  99. package/src/tests/stream-decoder.test.ts +0 -179
  100. package/src/tests/structured-output.test.ts +0 -1340
  101. package/src/tests/tools.test.ts +0 -175
  102. package/src/tools.ts +0 -246
  103. package/src/zod-adapter.ts +0 -72
@@ -1,224 +0,0 @@
1
- /**
2
- * Tests for auditor.ts — Observability implementations
3
- */
4
- import { describe, it, expect } from 'bun:test';
5
- import { NoopAuditor, ConsoleAuditor, BufferedAuditor, type AuditEvent } from '../auditor.js';
6
-
7
- describe('NoopAuditor', () => {
8
- it('accepts events without error', () => {
9
- const auditor = new NoopAuditor();
10
- expect(() => {
11
- auditor.record({
12
- timestamp: Date.now(),
13
- type: 'request',
14
- provider: 'test',
15
- });
16
- }).not.toThrow();
17
- });
18
-
19
- it('accepts structured output events without error', () => {
20
- const auditor = new NoopAuditor();
21
- expect(() => {
22
- auditor.record({
23
- timestamp: Date.now(),
24
- type: 'structured_request',
25
- provider: 'test',
26
- schemaName: 'User',
27
- });
28
- }).not.toThrow();
29
- });
30
- });
31
-
32
- describe('ConsoleAuditor', () => {
33
- it('creates with default prefix', () => {
34
- const auditor = new ConsoleAuditor();
35
- expect(auditor).toBeDefined();
36
- });
37
-
38
- it('creates with custom prefix', () => {
39
- const auditor = new ConsoleAuditor('[TEST]');
40
- expect(auditor).toBeDefined();
41
- });
42
-
43
- it('records all event types without error', () => {
44
- const auditor = new ConsoleAuditor('[TEST]');
45
- const types: AuditEvent['type'][] = [
46
- 'request', 'response', 'stream_start', 'stream_end',
47
- 'tool_call', 'tool_result', 'error', 'retry', 'failover',
48
- 'structured_request', 'structured_response', 'structured_validation_error',
49
- ];
50
-
51
- for (const type of types) {
52
- expect(() => {
53
- auditor.record({
54
- timestamp: Date.now(),
55
- type,
56
- provider: 'test',
57
- model: 'test-model',
58
- duration: 100,
59
- usage: { inputTokens: 10, outputTokens: 20, totalTokens: 30 },
60
- error: type === 'error' || type === 'structured_validation_error' ? 'test error' : undefined,
61
- metadata: type === 'failover' ? { nextProvider: 'backup' } : undefined,
62
- schemaName: type.startsWith('structured') ? 'User' : undefined,
63
- rawOutput: type === 'structured_validation_error' ? '{"name": "invalid"}' : undefined,
64
- });
65
- }).not.toThrow();
66
- }
67
- });
68
-
69
- it('logs structured_request with schema name', () => {
70
- const auditor = new ConsoleAuditor('[TEST]');
71
- // Should not throw when logging structured request
72
- expect(() => {
73
- auditor.record({
74
- timestamp: Date.now(),
75
- type: 'structured_request',
76
- provider: 'ollama',
77
- schemaName: 'User',
78
- });
79
- }).not.toThrow();
80
- });
81
-
82
- it('logs structured_response with duration and schema name', () => {
83
- const auditor = new ConsoleAuditor('[TEST]');
84
- expect(() => {
85
- auditor.record({
86
- timestamp: Date.now(),
87
- type: 'structured_response',
88
- provider: 'google',
89
- model: 'gemini-2.0-flash',
90
- duration: 150,
91
- schemaName: 'User',
92
- usage: { inputTokens: 100, outputTokens: 50, totalTokens: 150 },
93
- });
94
- }).not.toThrow();
95
- });
96
-
97
- it('logs structured_validation_error with schema name and error', () => {
98
- const auditor = new ConsoleAuditor('[TEST]');
99
- expect(() => {
100
- auditor.record({
101
- timestamp: Date.now(),
102
- type: 'structured_validation_error',
103
- provider: 'openai',
104
- schemaName: 'User',
105
- error: 'Validation failed: name is required',
106
- rawOutput: '{"age": 30}',
107
- });
108
- }).not.toThrow();
109
- });
110
- });
111
-
112
- describe('BufferedAuditor', () => {
113
- it('buffers events', () => {
114
- const auditor = new BufferedAuditor();
115
- const event: AuditEvent = {
116
- timestamp: Date.now(),
117
- type: 'request',
118
- provider: 'test',
119
- };
120
-
121
- auditor.record(event);
122
- auditor.record(event);
123
- auditor.record(event);
124
-
125
- expect(auditor.getEvents()).toHaveLength(3);
126
- });
127
-
128
- it('buffers structured output events', () => {
129
- const auditor = new BufferedAuditor();
130
-
131
- auditor.record({
132
- timestamp: Date.now(),
133
- type: 'structured_request',
134
- provider: 'ollama',
135
- schemaName: 'User',
136
- });
137
- auditor.record({
138
- timestamp: Date.now(),
139
- type: 'structured_response',
140
- provider: 'ollama',
141
- schemaName: 'User',
142
- duration: 100,
143
- });
144
-
145
- const events = auditor.getEvents();
146
- expect(events).toHaveLength(2);
147
- expect(events[0]?.type).toBe('structured_request');
148
- expect(events[0]?.schemaName).toBe('User');
149
- expect(events[1]?.type).toBe('structured_response');
150
- });
151
-
152
- it('buffers structured_validation_error events', () => {
153
- const auditor = new BufferedAuditor();
154
-
155
- auditor.record({
156
- timestamp: Date.now(),
157
- type: 'structured_validation_error',
158
- provider: 'openai',
159
- schemaName: 'User',
160
- error: 'Validation failed',
161
- rawOutput: '{"invalid": true}',
162
- });
163
-
164
- const events = auditor.getEvents();
165
- expect(events).toHaveLength(1);
166
- expect(events[0]?.type).toBe('structured_validation_error');
167
- expect(events[0]?.schemaName).toBe('User');
168
- expect(events[0]?.error).toBe('Validation failed');
169
- expect(events[0]?.rawOutput).toBe('{"invalid": true}');
170
- });
171
-
172
- it('flushes events to callback', async () => {
173
- const flushed: AuditEvent[][] = [];
174
- const auditor = new BufferedAuditor({
175
- onFlush: async (events) => {
176
- flushed.push([...events]);
177
- },
178
- });
179
-
180
- auditor.record({ timestamp: 1, type: 'request' });
181
- auditor.record({ timestamp: 2, type: 'response' });
182
-
183
- await auditor.flush();
184
-
185
- expect(flushed).toHaveLength(1);
186
- expect(flushed[0]).toHaveLength(2);
187
- expect(auditor.getEvents()).toHaveLength(0);
188
- });
189
-
190
- it('auto-flushes when buffer is full', async () => {
191
- let flushCount = 0;
192
- const auditor = new BufferedAuditor({
193
- maxBufferSize: 3,
194
- onFlush: async () => { flushCount++; },
195
- });
196
-
197
- auditor.record({ timestamp: 1, type: 'request' });
198
- auditor.record({ timestamp: 2, type: 'request' });
199
- auditor.record({ timestamp: 3, type: 'request' }); // triggers auto-flush
200
-
201
- // Give auto-flush time to complete
202
- await new Promise(r => setTimeout(r, 50));
203
- expect(flushCount).toBe(1);
204
- });
205
-
206
- it('clears without flushing', () => {
207
- const auditor = new BufferedAuditor();
208
- auditor.record({ timestamp: 1, type: 'request' });
209
- auditor.record({ timestamp: 2, type: 'response' });
210
-
211
- auditor.clear();
212
- expect(auditor.getEvents()).toHaveLength(0);
213
- });
214
-
215
- it('flush with no events is a no-op', async () => {
216
- let flushed = false;
217
- const auditor = new BufferedAuditor({
218
- onFlush: async () => { flushed = true; },
219
- });
220
-
221
- await auditor.flush();
222
- expect(flushed).toBe(false);
223
- });
224
- });
@@ -1,200 +0,0 @@
1
- /**
2
- * Tests for http.ts — Universal HTTP utilities
3
- */
4
- import { describe, it, expect, mock, beforeEach, afterEach } from 'bun:test';
5
- import { httpRequest, parseNDJSON, parseSSE, buildHeaders } from '../http.js';
6
- import { AIModelApiType } from '../interfaces.js';
7
-
8
- describe('httpRequest', () => {
9
- const originalFetch = globalThis.fetch;
10
-
11
- afterEach(() => {
12
- globalThis.fetch = originalFetch;
13
- });
14
-
15
- it('makes a GET request and parses JSON', async () => {
16
- globalThis.fetch = mock(async () =>
17
- new Response(JSON.stringify({ ok: true }), {
18
- status: 200,
19
- headers: { 'Content-Type': 'application/json' },
20
- })
21
- ) as typeof fetch;
22
-
23
- const result = await httpRequest<{ ok: boolean }>('http://test.com/api');
24
- expect(result.ok).toBe(true);
25
- expect(result.status).toBe(200);
26
- expect(result.data.ok).toBe(true);
27
- });
28
-
29
- it('makes a POST request with body', async () => {
30
- let capturedBody: string | undefined;
31
- globalThis.fetch = mock(async (_url: string | URL | Request, init?: RequestInit) => {
32
- capturedBody = init?.body as string;
33
- return new Response(JSON.stringify({ received: true }), {
34
- status: 200,
35
- headers: { 'Content-Type': 'application/json' },
36
- });
37
- }) as typeof fetch;
38
-
39
- await httpRequest('http://test.com/api', {
40
- method: 'POST',
41
- body: { message: 'hello' },
42
- });
43
-
44
- expect(capturedBody).toBe(JSON.stringify({ message: 'hello' }));
45
- });
46
-
47
- it('throws on non-OK response', async () => {
48
- globalThis.fetch = mock(async () =>
49
- new Response('Unauthorized', { status: 401 })
50
- ) as typeof fetch;
51
-
52
- expect(httpRequest('http://test.com/api')).rejects.toThrow('HTTP 401');
53
- });
54
-
55
- it('includes custom headers', async () => {
56
- let capturedHeaders: HeadersInit | undefined;
57
- globalThis.fetch = mock(async (_url: string | URL | Request, init?: RequestInit) => {
58
- capturedHeaders = init?.headers;
59
- return new Response(JSON.stringify({}), { status: 200 });
60
- }) as typeof fetch;
61
-
62
- await httpRequest('http://test.com/api', {
63
- headers: { 'X-Custom': 'value' },
64
- });
65
-
66
- expect(capturedHeaders).toHaveProperty('X-Custom', 'value');
67
- });
68
- });
69
-
70
- describe('parseNDJSON', () => {
71
- it('parses newline-delimited JSON', async () => {
72
- async function* source(): AsyncGenerator<string> {
73
- yield '{"a":1}\n{"b":2}\n';
74
- }
75
-
76
- const results: Record<string, number>[] = [];
77
- for await (const item of parseNDJSON<Record<string, number>>(source())) {
78
- results.push(item);
79
- }
80
-
81
- expect(results).toHaveLength(2);
82
- expect(results[0]).toEqual({ a: 1 });
83
- expect(results[1]).toEqual({ b: 2 });
84
- });
85
-
86
- it('handles chunks split across JSON boundaries', async () => {
87
- async function* source(): AsyncGenerator<string> {
88
- yield '{"a":';
89
- yield '1}\n{"b":2';
90
- yield '}\n';
91
- }
92
-
93
- const results: unknown[] = [];
94
- for await (const item of parseNDJSON(source())) {
95
- results.push(item);
96
- }
97
-
98
- expect(results).toHaveLength(2);
99
- });
100
-
101
- it('skips empty lines', async () => {
102
- async function* source(): AsyncGenerator<string> {
103
- yield '{"a":1}\n\n\n{"b":2}\n';
104
- }
105
-
106
- const results: unknown[] = [];
107
- for await (const item of parseNDJSON(source())) {
108
- results.push(item);
109
- }
110
-
111
- expect(results).toHaveLength(2);
112
- });
113
-
114
- it('handles remaining buffer content', async () => {
115
- async function* source(): AsyncGenerator<string> {
116
- yield '{"a":1}';
117
- }
118
-
119
- const results: unknown[] = [];
120
- for await (const item of parseNDJSON(source())) {
121
- results.push(item);
122
- }
123
-
124
- expect(results).toHaveLength(1);
125
- });
126
- });
127
-
128
- describe('parseSSE', () => {
129
- it('parses server-sent events', async () => {
130
- async function* source(): AsyncGenerator<string> {
131
- yield 'data: {"content":"hello"}\n\ndata: {"content":"world"}\n\n';
132
- }
133
-
134
- const results: { event?: string; data: string }[] = [];
135
- for await (const event of parseSSE(source())) {
136
- results.push(event);
137
- }
138
-
139
- expect(results).toHaveLength(2);
140
- expect(results[0]!.data).toBe('{"content":"hello"}');
141
- expect(results[1]!.data).toBe('{"content":"world"}');
142
- });
143
-
144
- it('skips [DONE] events', async () => {
145
- async function* source(): AsyncGenerator<string> {
146
- yield 'data: {"content":"hello"}\n\ndata: [DONE]\n\n';
147
- }
148
-
149
- const results: unknown[] = [];
150
- for await (const event of parseSSE(source())) {
151
- results.push(event);
152
- }
153
-
154
- expect(results).toHaveLength(1);
155
- });
156
-
157
- it('extracts event type', async () => {
158
- async function* source(): AsyncGenerator<string> {
159
- yield 'event: custom\ndata: {"test":true}\n\n';
160
- }
161
-
162
- const results: { event?: string; data: string }[] = [];
163
- for await (const event of parseSSE(source())) {
164
- results.push(event);
165
- }
166
-
167
- expect(results).toHaveLength(1);
168
- expect(results[0]!.event).toBe('custom');
169
- });
170
- });
171
-
172
- describe('buildHeaders', () => {
173
- it('returns Content-Type header', () => {
174
- const headers = buildHeaders({
175
- model: 'test',
176
- url: 'http://test.com',
177
- apiType: AIModelApiType.Ollama,
178
- });
179
- expect(headers['Content-Type']).toBe('application/json');
180
- });
181
-
182
- it('adds Authorization header when apiKey is set', () => {
183
- const headers = buildHeaders({
184
- model: 'test',
185
- url: 'http://test.com',
186
- apiType: AIModelApiType.OpenAI,
187
- apiKey: 'sk-test',
188
- });
189
- expect(headers['Authorization']).toBe('Bearer sk-test');
190
- });
191
-
192
- it('omits Authorization when no apiKey', () => {
193
- const headers = buildHeaders({
194
- model: 'test',
195
- url: 'http://test.com',
196
- apiType: AIModelApiType.Ollama,
197
- });
198
- expect(headers['Authorization']).toBeUndefined();
199
- });
200
- });
@@ -1,117 +0,0 @@
1
- /**
2
- * Tests for interfaces.ts — Helper functions and type utilities
3
- */
4
- import { describe, it, expect } from 'bun:test';
5
- import {
6
- textContent,
7
- imageContent,
8
- multimodalMessage,
9
- extractTextContent,
10
- hasImages,
11
- AIModelApiType,
12
- AIModelType,
13
- } from '../interfaces.js';
14
-
15
- describe('Helper Functions', () => {
16
- describe('textContent', () => {
17
- it('creates a text content part', () => {
18
- const result = textContent('Hello');
19
- expect(result).toEqual({ type: 'text', text: 'Hello' });
20
- });
21
- });
22
-
23
- describe('imageContent', () => {
24
- it('creates an image content part from base64', () => {
25
- const result = imageContent('abc123');
26
- expect(result.type).toBe('image_url');
27
- expect(result.image_url.url).toBe('data:image/jpeg;base64,abc123');
28
- });
29
-
30
- it('creates an image content part from URL', () => {
31
- const result = imageContent('https://example.com/image.jpg');
32
- expect(result.image_url.url).toBe('https://example.com/image.jpg');
33
- });
34
-
35
- it('creates an image content part from data URI', () => {
36
- const result = imageContent('data:image/png;base64,abc');
37
- expect(result.image_url.url).toBe('data:image/png;base64,abc');
38
- });
39
-
40
- it('respects custom mimeType', () => {
41
- const result = imageContent('abc123', 'image/png');
42
- expect(result.image_url.url).toBe('data:image/png;base64,abc123');
43
- });
44
-
45
- it('includes detail parameter', () => {
46
- const result = imageContent('https://example.com/img.jpg', 'image/jpeg', 'low');
47
- expect(result.image_url.detail).toBe('low');
48
- });
49
- });
50
-
51
- describe('multimodalMessage', () => {
52
- it('creates a user message with text and images', () => {
53
- const msg = multimodalMessage('Describe this', ['base64img']);
54
- expect(msg.role).toBe('user');
55
- expect(Array.isArray(msg.content)).toBe(true);
56
- const parts = msg.content as Array<{ type: string }>;
57
- expect(parts).toHaveLength(2);
58
- expect(parts[0]!.type).toBe('text');
59
- expect(parts[1]!.type).toBe('image_url');
60
- });
61
-
62
- it('handles multiple images', () => {
63
- const msg = multimodalMessage('Compare', ['img1', 'img2', 'img3']);
64
- const parts = msg.content as Array<{ type: string }>;
65
- expect(parts).toHaveLength(4); // 1 text + 3 images
66
- });
67
- });
68
-
69
- describe('extractTextContent', () => {
70
- it('extracts text from string content', () => {
71
- expect(extractTextContent('Hello')).toBe('Hello');
72
- });
73
-
74
- it('extracts text from content parts array', () => {
75
- const content = [
76
- textContent('Hello'),
77
- imageContent('img'),
78
- textContent(' World'),
79
- ];
80
- expect(extractTextContent(content)).toBe('Hello World');
81
- });
82
-
83
- it('returns empty string from image-only content', () => {
84
- const content = [imageContent('img')];
85
- expect(extractTextContent(content)).toBe('');
86
- });
87
- });
88
-
89
- describe('hasImages', () => {
90
- it('returns false for string content', () => {
91
- expect(hasImages('Hello')).toBe(false);
92
- });
93
-
94
- it('returns false for text-only content parts', () => {
95
- expect(hasImages([textContent('Hello')])).toBe(false);
96
- });
97
-
98
- it('returns true for content with images', () => {
99
- expect(hasImages([textContent('Hello'), imageContent('img')])).toBe(true);
100
- });
101
- });
102
- });
103
-
104
- describe('Enums', () => {
105
- it('AIModelApiType has expected values', () => {
106
- expect(AIModelApiType.Ollama).toBe('ollama');
107
- expect(AIModelApiType.OpenAI).toBe('openai');
108
- expect(AIModelApiType.Google).toBe('google');
109
- expect(AIModelApiType.Vertex).toBe('vertex');
110
- expect(AIModelApiType.LlamaCpp).toBe('llamacpp');
111
- });
112
-
113
- it('AIModelType has expected values', () => {
114
- expect(AIModelType.Chat).toBe('chat');
115
- expect(AIModelType.Embedding).toBe('embedding');
116
- });
117
- });