@lobehub/chat 1.138.2 → 1.138.4
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/CHANGELOG.md +50 -0
- package/changelog/v1.json +18 -0
- package/docker-compose/local/docker-compose.yml +1 -1
- package/docker-compose/local/grafana/docker-compose.yml +1 -1
- package/docker-compose/production/grafana/docker-compose.yml +1 -1
- package/package.json +1 -1
- package/packages/database/src/models/topic.ts +0 -1
- package/packages/database/src/repositories/aiInfra/index.test.ts +656 -0
- package/packages/database/src/repositories/aiInfra/index.ts +19 -13
- package/packages/model-runtime/src/core/contextBuilders/google.test.ts +585 -0
- package/packages/model-runtime/src/core/contextBuilders/google.ts +201 -0
- package/packages/model-runtime/src/core/openaiCompatibleFactory/index.test.ts +191 -179
- package/packages/model-runtime/src/core/openaiCompatibleFactory/index.ts +305 -47
- package/packages/model-runtime/src/providers/anthropic/generateObject.test.ts +93 -84
- package/packages/model-runtime/src/providers/anthropic/generateObject.ts +3 -3
- package/packages/model-runtime/src/providers/google/generateObject.test.ts +588 -83
- package/packages/model-runtime/src/providers/google/generateObject.ts +104 -6
- package/packages/model-runtime/src/providers/google/index.test.ts +0 -395
- package/packages/model-runtime/src/providers/google/index.ts +28 -194
- package/packages/model-runtime/src/providers/openai/index.test.ts +18 -17
- package/packages/model-runtime/src/types/structureOutput.ts +3 -4
- package/packages/obervability-otel/package.json +4 -4
- package/packages/prompts/CLAUDE.md +289 -43
- package/packages/prompts/package.json +2 -1
- package/packages/prompts/promptfoo/supervisor/productive/eval.yaml +51 -0
- package/packages/prompts/promptfoo/supervisor/productive/prompt.ts +18 -0
- package/packages/prompts/promptfoo/supervisor/productive/tests/basic-case.ts +54 -0
- package/packages/prompts/promptfoo/supervisor/productive/tests/role.ts +58 -0
- package/packages/prompts/promptfoo/supervisor/productive/tools.json +80 -0
- package/packages/prompts/src/contexts/index.ts +1 -0
- package/packages/prompts/src/contexts/supervisor/index.ts +2 -0
- package/packages/prompts/src/contexts/supervisor/makeDecision.ts +68 -0
- package/packages/prompts/src/contexts/supervisor/tools.ts +102 -0
- package/packages/prompts/src/index.ts +1 -0
- package/packages/types/src/aiChat.ts +9 -4
- package/src/server/routers/lambda/aiChat.ts +0 -1
- package/src/server/services/aiChat/index.test.ts +1 -1
- package/src/server/services/aiChat/index.ts +1 -1
- package/src/services/topic/client.ts +1 -1
- package/src/store/chat/slices/message/supervisor.test.ts +12 -5
- package/src/store/chat/slices/message/supervisor.ts +16 -129
|
@@ -119,11 +119,11 @@ describe('LobeOpenAICompatibleFactory', () => {
|
|
|
119
119
|
max_tokens: 1024,
|
|
120
120
|
messages: [{ content: 'Hello', role: 'user' }],
|
|
121
121
|
model: 'mistralai/mistral-7b-instruct:free',
|
|
122
|
-
temperature: 0.7,
|
|
123
122
|
stream: true,
|
|
124
123
|
stream_options: {
|
|
125
124
|
include_usage: true,
|
|
126
125
|
},
|
|
126
|
+
temperature: 0.7,
|
|
127
127
|
top_p: 1,
|
|
128
128
|
},
|
|
129
129
|
{ headers: { Accept: '*/*' } },
|
|
@@ -136,14 +136,14 @@ describe('LobeOpenAICompatibleFactory', () => {
|
|
|
136
136
|
const mockStream = new ReadableStream({
|
|
137
137
|
start(controller) {
|
|
138
138
|
controller.enqueue({
|
|
139
|
+
choices: [
|
|
140
|
+
{ delta: { content: 'hello' }, finish_reason: null, index: 0, logprobs: null },
|
|
141
|
+
],
|
|
142
|
+
created: 1_709_125_675,
|
|
139
143
|
id: 'a',
|
|
140
|
-
object: 'chat.completion.chunk',
|
|
141
|
-
created: 1709125675,
|
|
142
144
|
model: 'mistralai/mistral-7b-instruct:free',
|
|
145
|
+
object: 'chat.completion.chunk',
|
|
143
146
|
system_fingerprint: 'fp_86156a94a0',
|
|
144
|
-
choices: [
|
|
145
|
-
{ index: 0, delta: { content: 'hello' }, logprobs: null, finish_reason: null },
|
|
146
|
-
],
|
|
147
147
|
});
|
|
148
148
|
controller.close();
|
|
149
149
|
},
|
|
@@ -163,6 +163,7 @@ describe('LobeOpenAICompatibleFactory', () => {
|
|
|
163
163
|
|
|
164
164
|
// Collect all chunks
|
|
165
165
|
const chunks = [];
|
|
166
|
+
// eslint-disable-next-line no-constant-condition
|
|
166
167
|
while (true) {
|
|
167
168
|
const { value, done } = await reader.read();
|
|
168
169
|
if (done) break;
|
|
@@ -185,13 +186,13 @@ describe('LobeOpenAICompatibleFactory', () => {
|
|
|
185
186
|
object: '',
|
|
186
187
|
prompt_filter_results: [
|
|
187
188
|
{
|
|
188
|
-
prompt_index: 0,
|
|
189
189
|
content_filter_results: {
|
|
190
190
|
hate: { filtered: false, severity: 'safe' },
|
|
191
191
|
self_harm: { filtered: false, severity: 'safe' },
|
|
192
192
|
sexual: { filtered: false, severity: 'safe' },
|
|
193
193
|
violence: { filtered: false, severity: 'safe' },
|
|
194
194
|
},
|
|
195
|
+
prompt_index: 0,
|
|
195
196
|
},
|
|
196
197
|
],
|
|
197
198
|
},
|
|
@@ -204,7 +205,7 @@ describe('LobeOpenAICompatibleFactory', () => {
|
|
|
204
205
|
logprobs: null,
|
|
205
206
|
},
|
|
206
207
|
],
|
|
207
|
-
created:
|
|
208
|
+
created: 1_717_249_403,
|
|
208
209
|
id: 'chatcmpl-9VJIxA3qNM2C2YdAnNYA2KgDYfFnX',
|
|
209
210
|
model: 'gpt-4o-2024-05-13',
|
|
210
211
|
object: 'chat.completion.chunk',
|
|
@@ -212,7 +213,7 @@ describe('LobeOpenAICompatibleFactory', () => {
|
|
|
212
213
|
},
|
|
213
214
|
{
|
|
214
215
|
choices: [{ delta: { content: '1' }, finish_reason: null, index: 0, logprobs: null }],
|
|
215
|
-
created:
|
|
216
|
+
created: 1_717_249_403,
|
|
216
217
|
id: 'chatcmpl-9VJIxA3qNM2C2YdAnNYA2KgDYfFnX',
|
|
217
218
|
model: 'gpt-4o-2024-05-13',
|
|
218
219
|
object: 'chat.completion.chunk',
|
|
@@ -220,7 +221,7 @@ describe('LobeOpenAICompatibleFactory', () => {
|
|
|
220
221
|
},
|
|
221
222
|
{
|
|
222
223
|
choices: [{ delta: {}, finish_reason: 'stop', index: 0, logprobs: null }],
|
|
223
|
-
created:
|
|
224
|
+
created: 1_717_249_403,
|
|
224
225
|
id: 'chatcmpl-9VJIxA3qNM2C2YdAnNYA2KgDYfFnX',
|
|
225
226
|
model: 'gpt-4o-2024-05-13',
|
|
226
227
|
object: 'chat.completion.chunk',
|
|
@@ -229,7 +230,7 @@ describe('LobeOpenAICompatibleFactory', () => {
|
|
|
229
230
|
{
|
|
230
231
|
choices: [
|
|
231
232
|
{
|
|
232
|
-
content_filter_offsets: { check_offset: 35,
|
|
233
|
+
content_filter_offsets: { check_offset: 35, end_offset: 36, start_offset: 35 },
|
|
233
234
|
content_filter_results: {
|
|
234
235
|
hate: { filtered: false, severity: 'safe' },
|
|
235
236
|
self_harm: { filtered: false, severity: 'safe' },
|
|
@@ -268,6 +269,7 @@ describe('LobeOpenAICompatibleFactory', () => {
|
|
|
268
269
|
const decoder = new TextDecoder();
|
|
269
270
|
const reader = result.body!.getReader();
|
|
270
271
|
|
|
272
|
+
// eslint-disable-next-line no-constant-condition
|
|
271
273
|
while (true) {
|
|
272
274
|
const { value, done } = await reader.read();
|
|
273
275
|
if (done) break;
|
|
@@ -278,7 +280,7 @@ describe('LobeOpenAICompatibleFactory', () => {
|
|
|
278
280
|
[
|
|
279
281
|
'id: ',
|
|
280
282
|
'event: data',
|
|
281
|
-
'data: {"choices":[],"created":0,"id":"","model":"","object":"","prompt_filter_results":[{"
|
|
283
|
+
'data: {"choices":[],"created":0,"id":"","model":"","object":"","prompt_filter_results":[{"content_filter_results":{"hate":{"filtered":false,"severity":"safe"},"self_harm":{"filtered":false,"severity":"safe"},"sexual":{"filtered":false,"severity":"safe"},"violence":{"filtered":false,"severity":"safe"}},"prompt_index":0}]}\n',
|
|
282
284
|
'id: chatcmpl-9VJIxA3qNM2C2YdAnNYA2KgDYfFnX',
|
|
283
285
|
'event: text',
|
|
284
286
|
'data: ""\n',
|
|
@@ -299,21 +301,21 @@ describe('LobeOpenAICompatibleFactory', () => {
|
|
|
299
301
|
vi.useFakeTimers();
|
|
300
302
|
|
|
301
303
|
const mockResponse = {
|
|
302
|
-
id: 'a',
|
|
303
|
-
object: 'chat.completion',
|
|
304
|
-
created: 123,
|
|
305
|
-
model: 'mistralai/mistral-7b-instruct:free',
|
|
306
304
|
choices: [
|
|
307
305
|
{
|
|
308
|
-
index: 0,
|
|
309
|
-
message: { role: 'assistant', content: 'Hello' },
|
|
310
306
|
finish_reason: 'stop',
|
|
307
|
+
index: 0,
|
|
311
308
|
logprobs: null,
|
|
309
|
+
message: { content: 'Hello', role: 'assistant' },
|
|
312
310
|
},
|
|
313
311
|
],
|
|
312
|
+
created: 123,
|
|
313
|
+
id: 'a',
|
|
314
|
+
model: 'mistralai/mistral-7b-instruct:free',
|
|
315
|
+
object: 'chat.completion',
|
|
314
316
|
usage: {
|
|
315
|
-
prompt_tokens: 5,
|
|
316
317
|
completion_tokens: 5,
|
|
318
|
+
prompt_tokens: 5,
|
|
317
319
|
total_tokens: 10,
|
|
318
320
|
},
|
|
319
321
|
} as OpenAI.ChatCompletion;
|
|
@@ -324,8 +326,8 @@ describe('LobeOpenAICompatibleFactory', () => {
|
|
|
324
326
|
const chatPromise = instance.chat({
|
|
325
327
|
messages: [{ content: 'Hello', role: 'user' }],
|
|
326
328
|
model: 'mistralai/mistral-7b-instruct:free',
|
|
327
|
-
temperature: 0,
|
|
328
329
|
stream: false,
|
|
330
|
+
temperature: 0,
|
|
329
331
|
});
|
|
330
332
|
|
|
331
333
|
// Advance time to simulate processing delay
|
|
@@ -337,6 +339,7 @@ describe('LobeOpenAICompatibleFactory', () => {
|
|
|
337
339
|
const reader = result.body!.getReader();
|
|
338
340
|
const stream: string[] = [];
|
|
339
341
|
|
|
342
|
+
// eslint-disable-next-line no-constant-condition
|
|
340
343
|
while (true) {
|
|
341
344
|
const { value, done } = await reader.read();
|
|
342
345
|
if (done) break;
|
|
@@ -352,13 +355,14 @@ describe('LobeOpenAICompatibleFactory', () => {
|
|
|
352
355
|
'data: {"inputTextTokens":5,"outputTextTokens":5,"totalInputTokens":5,"totalOutputTokens":5,"totalTokens":10}\n\n',
|
|
353
356
|
'id: output_speed\n',
|
|
354
357
|
'event: speed\n',
|
|
355
|
-
expect.stringMatching(/^data:
|
|
358
|
+
expect.stringMatching(/^data: {.*"tps":.*,"ttft":.*}\n\n$/), // tps ttft should be calculated with elapsed time
|
|
356
359
|
'id: a\n',
|
|
357
360
|
'event: stop\n',
|
|
358
361
|
'data: "stop"\n\n',
|
|
359
362
|
]);
|
|
360
363
|
|
|
361
|
-
|
|
364
|
+
const finalRead = await reader.read();
|
|
365
|
+
expect(finalRead.done).toBe(true);
|
|
362
366
|
|
|
363
367
|
vi.useRealTimers();
|
|
364
368
|
});
|
|
@@ -367,25 +371,25 @@ describe('LobeOpenAICompatibleFactory', () => {
|
|
|
367
371
|
vi.useFakeTimers();
|
|
368
372
|
|
|
369
373
|
const mockResponse = {
|
|
370
|
-
id: 'a',
|
|
371
|
-
object: 'chat.completion',
|
|
372
|
-
created: 123,
|
|
373
|
-
model: 'deepseek/deepseek-reasoner',
|
|
374
374
|
choices: [
|
|
375
375
|
{
|
|
376
|
+
finish_reason: 'stop',
|
|
376
377
|
index: 0,
|
|
378
|
+
logprobs: null,
|
|
377
379
|
message: {
|
|
378
|
-
role: 'assistant',
|
|
379
380
|
content: 'Hello',
|
|
380
381
|
reasoning_content: 'Thinking content',
|
|
382
|
+
role: 'assistant',
|
|
381
383
|
},
|
|
382
|
-
finish_reason: 'stop',
|
|
383
|
-
logprobs: null,
|
|
384
384
|
},
|
|
385
385
|
],
|
|
386
|
+
created: 123,
|
|
387
|
+
id: 'a',
|
|
388
|
+
model: 'deepseek/deepseek-reasoner',
|
|
389
|
+
object: 'chat.completion',
|
|
386
390
|
usage: {
|
|
387
|
-
prompt_tokens: 5,
|
|
388
391
|
completion_tokens: 5,
|
|
392
|
+
prompt_tokens: 5,
|
|
389
393
|
total_tokens: 10,
|
|
390
394
|
},
|
|
391
395
|
} as unknown as OpenAI.ChatCompletion;
|
|
@@ -396,8 +400,8 @@ describe('LobeOpenAICompatibleFactory', () => {
|
|
|
396
400
|
const chatPromise = instance.chat({
|
|
397
401
|
messages: [{ content: 'Hello', role: 'user' }],
|
|
398
402
|
model: 'deepseek/deepseek-reasoner',
|
|
399
|
-
temperature: 0,
|
|
400
403
|
stream: false,
|
|
404
|
+
temperature: 0,
|
|
401
405
|
});
|
|
402
406
|
|
|
403
407
|
// Advance time to simulate processing delay
|
|
@@ -409,6 +413,7 @@ describe('LobeOpenAICompatibleFactory', () => {
|
|
|
409
413
|
const reader = result.body!.getReader();
|
|
410
414
|
const stream: string[] = [];
|
|
411
415
|
|
|
416
|
+
// eslint-disable-next-line no-constant-condition
|
|
412
417
|
while (true) {
|
|
413
418
|
const { value, done } = await reader.read();
|
|
414
419
|
if (done) break;
|
|
@@ -427,13 +432,14 @@ describe('LobeOpenAICompatibleFactory', () => {
|
|
|
427
432
|
'data: {"inputTextTokens":5,"outputTextTokens":5,"totalInputTokens":5,"totalOutputTokens":5,"totalTokens":10}\n\n',
|
|
428
433
|
'id: output_speed\n',
|
|
429
434
|
'event: speed\n',
|
|
430
|
-
expect.stringMatching(/^data:
|
|
435
|
+
expect.stringMatching(/^data: {.*"tps":.*,"ttft":.*}\n\n$/), // tps ttft should be calculated with elapsed time
|
|
431
436
|
'id: a\n',
|
|
432
437
|
'event: stop\n',
|
|
433
438
|
'data: "stop"\n\n',
|
|
434
439
|
]);
|
|
435
440
|
|
|
436
|
-
|
|
441
|
+
const finalRead = await reader.read();
|
|
442
|
+
expect(finalRead.done).toBe(true);
|
|
437
443
|
|
|
438
444
|
vi.useRealTimers();
|
|
439
445
|
});
|
|
@@ -607,10 +613,10 @@ describe('LobeOpenAICompatibleFactory', () => {
|
|
|
607
613
|
const apiError = new OpenAI.APIError(
|
|
608
614
|
400,
|
|
609
615
|
{
|
|
610
|
-
status: 400,
|
|
611
616
|
error: {
|
|
612
617
|
message: 'Bad Request',
|
|
613
618
|
},
|
|
619
|
+
status: 400,
|
|
614
620
|
},
|
|
615
621
|
'Error message',
|
|
616
622
|
{},
|
|
@@ -770,13 +776,13 @@ describe('LobeOpenAICompatibleFactory', () => {
|
|
|
770
776
|
} catch (e) {
|
|
771
777
|
expect(e).toEqual({
|
|
772
778
|
endpoint: defaultBaseURL,
|
|
773
|
-
errorType: 'AgentRuntimeError',
|
|
774
|
-
provider,
|
|
775
779
|
error: {
|
|
776
|
-
name: genericError.name,
|
|
777
780
|
cause: genericError.cause,
|
|
778
781
|
message: genericError.message,
|
|
782
|
+
name: genericError.name,
|
|
779
783
|
},
|
|
784
|
+
errorType: 'AgentRuntimeError',
|
|
785
|
+
provider,
|
|
780
786
|
});
|
|
781
787
|
}
|
|
782
788
|
});
|
|
@@ -791,14 +797,14 @@ describe('LobeOpenAICompatibleFactory', () => {
|
|
|
791
797
|
new ReadableStream({
|
|
792
798
|
start(controller) {
|
|
793
799
|
controller.enqueue({
|
|
800
|
+
choices: [
|
|
801
|
+
{ delta: { content: 'hello' }, finish_reason: null, index: 0, logprobs: null },
|
|
802
|
+
],
|
|
803
|
+
created: 1_709_125_675,
|
|
794
804
|
id: 'chatcmpl-8xDx5AETP8mESQN7UB30GxTN2H1SO',
|
|
795
|
-
object: 'chat.completion.chunk',
|
|
796
|
-
created: 1709125675,
|
|
797
805
|
model: 'mistralai/mistral-7b-instruct:free',
|
|
806
|
+
object: 'chat.completion.chunk',
|
|
798
807
|
system_fingerprint: 'fp_86156a94a0',
|
|
799
|
-
choices: [
|
|
800
|
-
{ index: 0, delta: { content: 'hello' }, logprobs: null, finish_reason: null },
|
|
801
|
-
],
|
|
802
808
|
});
|
|
803
809
|
controller.close();
|
|
804
810
|
},
|
|
@@ -807,8 +813,8 @@ describe('LobeOpenAICompatibleFactory', () => {
|
|
|
807
813
|
|
|
808
814
|
// Prepare callback and headers
|
|
809
815
|
const mockCallback: ChatStreamCallbacks = {
|
|
810
|
-
onStart: vi.fn(),
|
|
811
816
|
onCompletion: vi.fn(),
|
|
817
|
+
onStart: vi.fn(),
|
|
812
818
|
};
|
|
813
819
|
const mockHeaders = { 'Custom-Header': 'TestValue' };
|
|
814
820
|
|
|
@@ -848,6 +854,7 @@ describe('LobeOpenAICompatibleFactory', () => {
|
|
|
848
854
|
const reader = readableStream.getReader();
|
|
849
855
|
const process = async () => {
|
|
850
856
|
try {
|
|
857
|
+
// eslint-disable-next-line no-constant-condition
|
|
851
858
|
while (true) {
|
|
852
859
|
const { done, value } = await reader.read();
|
|
853
860
|
if (done) break;
|
|
@@ -877,9 +884,9 @@ describe('LobeOpenAICompatibleFactory', () => {
|
|
|
877
884
|
const mockStream = new ReadableStream({
|
|
878
885
|
start(controller) {
|
|
879
886
|
controller.enqueue({
|
|
880
|
-
id: 'test-id',
|
|
881
887
|
choices: [{ delta: { content: 'Hello' }, index: 0 }],
|
|
882
888
|
created: Date.now(),
|
|
889
|
+
id: 'test-id',
|
|
883
890
|
model: 'test-model',
|
|
884
891
|
object: 'chat.completion.chunk',
|
|
885
892
|
});
|
|
@@ -908,12 +915,12 @@ describe('LobeOpenAICompatibleFactory', () => {
|
|
|
908
915
|
start(controller) {
|
|
909
916
|
// Transform the completion to chunk format
|
|
910
917
|
controller.enqueue({
|
|
911
|
-
id: data.id,
|
|
912
918
|
choices: data.choices.map((choice) => ({
|
|
913
919
|
delta: { content: choice.message.content },
|
|
914
920
|
index: choice.index,
|
|
915
921
|
})),
|
|
916
922
|
created: data.created,
|
|
923
|
+
id: data.id,
|
|
917
924
|
model: data.model,
|
|
918
925
|
object: 'chat.completion.chunk',
|
|
919
926
|
});
|
|
@@ -933,20 +940,20 @@ describe('LobeOpenAICompatibleFactory', () => {
|
|
|
933
940
|
const instance = new LobeMockProvider({ apiKey: 'test' });
|
|
934
941
|
|
|
935
942
|
const mockResponse: OpenAI.ChatCompletion = {
|
|
936
|
-
id: 'test-id',
|
|
937
943
|
choices: [
|
|
938
944
|
{
|
|
945
|
+
finish_reason: 'stop',
|
|
939
946
|
index: 0,
|
|
947
|
+
logprobs: null,
|
|
940
948
|
message: {
|
|
941
|
-
role: 'assistant',
|
|
942
949
|
content: 'Test response',
|
|
943
950
|
refusal: null,
|
|
951
|
+
role: 'assistant',
|
|
944
952
|
},
|
|
945
|
-
logprobs: null,
|
|
946
|
-
finish_reason: 'stop',
|
|
947
953
|
},
|
|
948
954
|
],
|
|
949
955
|
created: Date.now(),
|
|
956
|
+
id: 'test-id',
|
|
950
957
|
model: 'test-model',
|
|
951
958
|
object: 'chat.completion',
|
|
952
959
|
usage: { completion_tokens: 2, prompt_tokens: 1, total_tokens: 3 },
|
|
@@ -959,8 +966,8 @@ describe('LobeOpenAICompatibleFactory', () => {
|
|
|
959
966
|
const payload: ChatStreamPayload = {
|
|
960
967
|
messages: [{ content: 'Test', role: 'user' }],
|
|
961
968
|
model: 'test-model',
|
|
962
|
-
temperature: 0.7,
|
|
963
969
|
stream: false,
|
|
970
|
+
temperature: 0.7,
|
|
964
971
|
};
|
|
965
972
|
|
|
966
973
|
await instance.chat(payload);
|
|
@@ -1110,8 +1117,8 @@ describe('LobeOpenAICompatibleFactory', () => {
|
|
|
1110
1117
|
model: 'dall-e-3',
|
|
1111
1118
|
params: {
|
|
1112
1119
|
prompt: 'A beautiful sunset',
|
|
1113
|
-
size: '1024x1024',
|
|
1114
1120
|
quality: 'standard',
|
|
1121
|
+
size: '1024x1024',
|
|
1115
1122
|
},
|
|
1116
1123
|
};
|
|
1117
1124
|
|
|
@@ -1121,9 +1128,9 @@ describe('LobeOpenAICompatibleFactory', () => {
|
|
|
1121
1128
|
model: 'dall-e-3',
|
|
1122
1129
|
n: 1,
|
|
1123
1130
|
prompt: 'A beautiful sunset',
|
|
1124
|
-
size: '1024x1024',
|
|
1125
1131
|
quality: 'standard',
|
|
1126
1132
|
response_format: 'b64_json',
|
|
1133
|
+
size: '1024x1024',
|
|
1127
1134
|
});
|
|
1128
1135
|
|
|
1129
1136
|
expect(result).toEqual({
|
|
@@ -1200,9 +1207,9 @@ describe('LobeOpenAICompatibleFactory', () => {
|
|
|
1200
1207
|
const payload = {
|
|
1201
1208
|
model: 'dall-e-2',
|
|
1202
1209
|
params: {
|
|
1203
|
-
prompt: 'Add a rainbow to this image',
|
|
1204
1210
|
imageUrls: ['https://example.com/image1.jpg'],
|
|
1205
1211
|
mask: 'https://example.com/mask.jpg',
|
|
1212
|
+
prompt: 'Add a rainbow to this image',
|
|
1206
1213
|
},
|
|
1207
1214
|
};
|
|
1208
1215
|
|
|
@@ -1212,13 +1219,13 @@ describe('LobeOpenAICompatibleFactory', () => {
|
|
|
1212
1219
|
'https://example.com/image1.jpg',
|
|
1213
1220
|
);
|
|
1214
1221
|
expect(instance['client'].images.edit).toHaveBeenCalledWith({
|
|
1222
|
+
image: expect.any(File),
|
|
1223
|
+
input_fidelity: 'high',
|
|
1224
|
+
mask: 'https://example.com/mask.jpg',
|
|
1215
1225
|
model: 'dall-e-2',
|
|
1216
1226
|
n: 1,
|
|
1217
1227
|
prompt: 'Add a rainbow to this image',
|
|
1218
|
-
image: expect.any(File),
|
|
1219
|
-
mask: 'https://example.com/mask.jpg',
|
|
1220
1228
|
response_format: 'b64_json',
|
|
1221
|
-
input_fidelity: 'high',
|
|
1222
1229
|
});
|
|
1223
1230
|
|
|
1224
1231
|
expect(result).toEqual({
|
|
@@ -1243,8 +1250,8 @@ describe('LobeOpenAICompatibleFactory', () => {
|
|
|
1243
1250
|
const payload = {
|
|
1244
1251
|
model: 'dall-e-2',
|
|
1245
1252
|
params: {
|
|
1246
|
-
prompt: 'Merge these images',
|
|
1247
1253
|
imageUrls: ['https://example.com/image1.jpg', 'https://example.com/image2.jpg'],
|
|
1254
|
+
prompt: 'Merge these images',
|
|
1248
1255
|
},
|
|
1249
1256
|
};
|
|
1250
1257
|
|
|
@@ -1259,12 +1266,12 @@ describe('LobeOpenAICompatibleFactory', () => {
|
|
|
1259
1266
|
);
|
|
1260
1267
|
|
|
1261
1268
|
expect(instance['client'].images.edit).toHaveBeenCalledWith({
|
|
1269
|
+
image: [mockFile1, mockFile2],
|
|
1270
|
+
input_fidelity: 'high',
|
|
1262
1271
|
model: 'dall-e-2',
|
|
1263
1272
|
n: 1,
|
|
1264
1273
|
prompt: 'Merge these images',
|
|
1265
|
-
image: [mockFile1, mockFile2],
|
|
1266
1274
|
response_format: 'b64_json',
|
|
1267
|
-
input_fidelity: 'high',
|
|
1268
1275
|
});
|
|
1269
1276
|
|
|
1270
1277
|
expect(result).toEqual({
|
|
@@ -1280,8 +1287,8 @@ describe('LobeOpenAICompatibleFactory', () => {
|
|
|
1280
1287
|
const payload = {
|
|
1281
1288
|
model: 'dall-e-2',
|
|
1282
1289
|
params: {
|
|
1283
|
-
prompt: 'Edit this image',
|
|
1284
1290
|
imageUrls: ['https://invalid-url.com/image.jpg'],
|
|
1291
|
+
prompt: 'Edit this image',
|
|
1285
1292
|
},
|
|
1286
1293
|
};
|
|
1287
1294
|
|
|
@@ -1379,22 +1386,22 @@ describe('LobeOpenAICompatibleFactory', () => {
|
|
|
1379
1386
|
const payload = {
|
|
1380
1387
|
model: 'dall-e-2',
|
|
1381
1388
|
params: {
|
|
1382
|
-
prompt: 'Test prompt',
|
|
1383
|
-
imageUrls: ['https://example.com/image.jpg'],
|
|
1384
1389
|
customParam: 'should remain unchanged',
|
|
1390
|
+
imageUrls: ['https://example.com/image.jpg'],
|
|
1391
|
+
prompt: 'Test prompt',
|
|
1385
1392
|
},
|
|
1386
1393
|
};
|
|
1387
1394
|
|
|
1388
1395
|
await (instance as any).createImage(payload);
|
|
1389
1396
|
|
|
1390
1397
|
expect(instance['client'].images.edit).toHaveBeenCalledWith({
|
|
1398
|
+
customParam: 'should remain unchanged',
|
|
1399
|
+
image: expect.any(File),
|
|
1400
|
+
input_fidelity: 'high',
|
|
1391
1401
|
model: 'dall-e-2',
|
|
1392
1402
|
n: 1,
|
|
1393
1403
|
prompt: 'Test prompt',
|
|
1394
|
-
image: expect.any(File),
|
|
1395
|
-
customParam: 'should remain unchanged',
|
|
1396
1404
|
response_format: 'b64_json',
|
|
1397
|
-
input_fidelity: 'high',
|
|
1398
1405
|
});
|
|
1399
1406
|
});
|
|
1400
1407
|
|
|
@@ -1421,8 +1428,8 @@ describe('LobeOpenAICompatibleFactory', () => {
|
|
|
1421
1428
|
n: 1,
|
|
1422
1429
|
prompt: 'Test prompt',
|
|
1423
1430
|
quality: 'hd',
|
|
1424
|
-
style: 'vivid',
|
|
1425
1431
|
response_format: 'b64_json',
|
|
1432
|
+
style: 'vivid',
|
|
1426
1433
|
});
|
|
1427
1434
|
});
|
|
1428
1435
|
});
|
|
@@ -1438,17 +1445,17 @@ describe('LobeOpenAICompatibleFactory', () => {
|
|
|
1438
1445
|
|
|
1439
1446
|
const payload = {
|
|
1440
1447
|
messages: [{ content: 'Generate a person object', role: 'user' as const }],
|
|
1448
|
+
model: 'gpt-4o',
|
|
1449
|
+
responseApi: true,
|
|
1441
1450
|
schema: {
|
|
1442
|
-
name: 'person_extractor',
|
|
1443
1451
|
description: 'Extract person information',
|
|
1452
|
+
name: 'person_extractor',
|
|
1444
1453
|
schema: {
|
|
1454
|
+
properties: { age: { type: 'number' }, name: { type: 'string' } },
|
|
1445
1455
|
type: 'object' as const,
|
|
1446
|
-
properties: { name: { type: 'string' }, age: { type: 'number' } },
|
|
1447
1456
|
},
|
|
1448
1457
|
strict: true,
|
|
1449
1458
|
},
|
|
1450
|
-
model: 'gpt-4o',
|
|
1451
|
-
responseApi: true,
|
|
1452
1459
|
};
|
|
1453
1460
|
|
|
1454
1461
|
const result = await instance.generateObject(payload);
|
|
@@ -1464,7 +1471,7 @@ describe('LobeOpenAICompatibleFactory', () => {
|
|
|
1464
1471
|
{ headers: undefined, signal: undefined },
|
|
1465
1472
|
);
|
|
1466
1473
|
|
|
1467
|
-
expect(result).toEqual({ name: 'John'
|
|
1474
|
+
expect(result).toEqual({ age: 30, name: 'John' });
|
|
1468
1475
|
});
|
|
1469
1476
|
|
|
1470
1477
|
it('should handle options correctly', async () => {
|
|
@@ -1476,18 +1483,18 @@ describe('LobeOpenAICompatibleFactory', () => {
|
|
|
1476
1483
|
|
|
1477
1484
|
const payload = {
|
|
1478
1485
|
messages: [{ content: 'Generate status', role: 'user' as const }],
|
|
1486
|
+
model: 'gpt-4o',
|
|
1487
|
+
responseApi: true,
|
|
1479
1488
|
schema: {
|
|
1480
1489
|
name: 'status_extractor',
|
|
1481
|
-
schema: {
|
|
1490
|
+
schema: { properties: { status: { type: 'string' } }, type: 'object' as const },
|
|
1482
1491
|
},
|
|
1483
|
-
model: 'gpt-4o',
|
|
1484
|
-
responseApi: true,
|
|
1485
1492
|
};
|
|
1486
1493
|
|
|
1487
1494
|
const options = {
|
|
1488
1495
|
headers: { 'Custom-Header': 'test-value' },
|
|
1489
|
-
user: 'test-user',
|
|
1490
1496
|
signal: new AbortController().signal,
|
|
1497
|
+
user: 'test-user',
|
|
1491
1498
|
};
|
|
1492
1499
|
|
|
1493
1500
|
const result = await instance.generateObject(payload, options);
|
|
@@ -1516,12 +1523,12 @@ describe('LobeOpenAICompatibleFactory', () => {
|
|
|
1516
1523
|
|
|
1517
1524
|
const payload = {
|
|
1518
1525
|
messages: [{ content: 'Generate data', role: 'user' as const }],
|
|
1526
|
+
model: 'gpt-4o',
|
|
1527
|
+
responseApi: true,
|
|
1519
1528
|
schema: {
|
|
1520
1529
|
name: 'test_tool',
|
|
1521
|
-
schema: { type: 'object' as const
|
|
1530
|
+
schema: { properties: {}, type: 'object' as const },
|
|
1522
1531
|
},
|
|
1523
|
-
model: 'gpt-4o',
|
|
1524
|
-
responseApi: true,
|
|
1525
1532
|
};
|
|
1526
1533
|
|
|
1527
1534
|
const result = await instance.generateObject(payload);
|
|
@@ -1542,12 +1549,12 @@ describe('LobeOpenAICompatibleFactory', () => {
|
|
|
1542
1549
|
|
|
1543
1550
|
const payload = {
|
|
1544
1551
|
messages: [{ content: 'Generate data', role: 'user' as const }],
|
|
1552
|
+
model: 'gpt-4o',
|
|
1553
|
+
responseApi: true,
|
|
1545
1554
|
schema: {
|
|
1546
1555
|
name: 'test_tool',
|
|
1547
|
-
schema: { type: 'object' as const
|
|
1556
|
+
schema: { properties: {}, type: 'object' as const },
|
|
1548
1557
|
},
|
|
1549
|
-
model: 'gpt-4o',
|
|
1550
|
-
responseApi: true,
|
|
1551
1558
|
};
|
|
1552
1559
|
|
|
1553
1560
|
const result = await instance.generateObject(payload);
|
|
@@ -1568,35 +1575,38 @@ describe('LobeOpenAICompatibleFactory', () => {
|
|
|
1568
1575
|
|
|
1569
1576
|
const payload = {
|
|
1570
1577
|
messages: [{ content: 'Generate complex user data', role: 'user' as const }],
|
|
1578
|
+
model: 'gpt-4o',
|
|
1579
|
+
responseApi: true,
|
|
1571
1580
|
schema: {
|
|
1572
1581
|
name: 'user_extractor',
|
|
1573
1582
|
schema: {
|
|
1574
|
-
type: 'object' as const,
|
|
1575
1583
|
properties: {
|
|
1584
|
+
metadata: { type: 'object' },
|
|
1576
1585
|
user: {
|
|
1577
|
-
type: 'object',
|
|
1578
1586
|
properties: {
|
|
1579
1587
|
name: { type: 'string' },
|
|
1580
1588
|
profile: {
|
|
1581
|
-
type: 'object',
|
|
1582
1589
|
properties: {
|
|
1583
1590
|
age: { type: 'number' },
|
|
1584
|
-
preferences: {
|
|
1591
|
+
preferences: { items: { type: 'string' }, type: 'array' },
|
|
1585
1592
|
},
|
|
1593
|
+
type: 'object',
|
|
1586
1594
|
},
|
|
1587
1595
|
},
|
|
1596
|
+
type: 'object',
|
|
1588
1597
|
},
|
|
1589
|
-
metadata: { type: 'object' },
|
|
1590
1598
|
},
|
|
1599
|
+
type: 'object' as const,
|
|
1591
1600
|
},
|
|
1592
1601
|
},
|
|
1593
|
-
model: 'gpt-4o',
|
|
1594
|
-
responseApi: true,
|
|
1595
1602
|
};
|
|
1596
1603
|
|
|
1597
1604
|
const result = await instance.generateObject(payload);
|
|
1598
1605
|
|
|
1599
1606
|
expect(result).toEqual({
|
|
1607
|
+
metadata: {
|
|
1608
|
+
created: '2024-01-01',
|
|
1609
|
+
},
|
|
1600
1610
|
user: {
|
|
1601
1611
|
name: 'Alice',
|
|
1602
1612
|
profile: {
|
|
@@ -1604,9 +1614,6 @@ describe('LobeOpenAICompatibleFactory', () => {
|
|
|
1604
1614
|
preferences: ['music', 'sports'],
|
|
1605
1615
|
},
|
|
1606
1616
|
},
|
|
1607
|
-
metadata: {
|
|
1608
|
-
created: '2024-01-01',
|
|
1609
|
-
},
|
|
1610
1617
|
});
|
|
1611
1618
|
});
|
|
1612
1619
|
|
|
@@ -1617,12 +1624,12 @@ describe('LobeOpenAICompatibleFactory', () => {
|
|
|
1617
1624
|
|
|
1618
1625
|
const payload = {
|
|
1619
1626
|
messages: [{ content: 'Generate data', role: 'user' as const }],
|
|
1627
|
+
model: 'gpt-4o',
|
|
1628
|
+
responseApi: true,
|
|
1620
1629
|
schema: {
|
|
1621
1630
|
name: 'test_tool',
|
|
1622
|
-
schema: { type: 'object' as const
|
|
1631
|
+
schema: { properties: {}, type: 'object' as const },
|
|
1623
1632
|
},
|
|
1624
|
-
model: 'gpt-4o',
|
|
1625
|
-
responseApi: true,
|
|
1626
1633
|
};
|
|
1627
1634
|
|
|
1628
1635
|
await expect(instance.generateObject(payload)).rejects.toThrow(
|
|
@@ -1648,14 +1655,14 @@ describe('LobeOpenAICompatibleFactory', () => {
|
|
|
1648
1655
|
|
|
1649
1656
|
const payload = {
|
|
1650
1657
|
messages: [{ content: 'Generate a person object', role: 'user' as const }],
|
|
1658
|
+
model: 'gpt-4o',
|
|
1651
1659
|
schema: {
|
|
1652
1660
|
name: 'person_extractor',
|
|
1653
1661
|
schema: {
|
|
1662
|
+
properties: { age: { type: 'number' }, name: { type: 'string' } },
|
|
1654
1663
|
type: 'object' as const,
|
|
1655
|
-
properties: { name: { type: 'string' }, age: { type: 'number' } },
|
|
1656
1664
|
},
|
|
1657
1665
|
},
|
|
1658
|
-
model: 'gpt-4o',
|
|
1659
1666
|
// responseApi: false or undefined - uses chat completions API
|
|
1660
1667
|
};
|
|
1661
1668
|
|
|
@@ -1671,7 +1678,7 @@ describe('LobeOpenAICompatibleFactory', () => {
|
|
|
1671
1678
|
{ headers: undefined, signal: undefined },
|
|
1672
1679
|
);
|
|
1673
1680
|
|
|
1674
|
-
expect(result).toEqual({ name: 'Bob'
|
|
1681
|
+
expect(result).toEqual({ age: 25, name: 'Bob' });
|
|
1675
1682
|
});
|
|
1676
1683
|
|
|
1677
1684
|
it('should handle options correctly with chat completions API', async () => {
|
|
@@ -1691,18 +1698,18 @@ describe('LobeOpenAICompatibleFactory', () => {
|
|
|
1691
1698
|
|
|
1692
1699
|
const payload = {
|
|
1693
1700
|
messages: [{ content: 'Generate status', role: 'user' as const }],
|
|
1701
|
+
model: 'gpt-4o',
|
|
1702
|
+
responseApi: false,
|
|
1694
1703
|
schema: {
|
|
1695
1704
|
name: 'status_extractor',
|
|
1696
|
-
schema: {
|
|
1705
|
+
schema: { properties: { status: { type: 'string' } }, type: 'object' as const },
|
|
1697
1706
|
},
|
|
1698
|
-
model: 'gpt-4o',
|
|
1699
|
-
responseApi: false,
|
|
1700
1707
|
};
|
|
1701
1708
|
|
|
1702
1709
|
const options = {
|
|
1703
1710
|
headers: { Authorization: 'Bearer token' },
|
|
1704
|
-
user: 'test-user-123',
|
|
1705
1711
|
signal: new AbortController().signal,
|
|
1712
|
+
user: 'test-user-123',
|
|
1706
1713
|
};
|
|
1707
1714
|
|
|
1708
1715
|
const result = await instance.generateObject(payload, options);
|
|
@@ -1738,12 +1745,12 @@ describe('LobeOpenAICompatibleFactory', () => {
|
|
|
1738
1745
|
|
|
1739
1746
|
const payload = {
|
|
1740
1747
|
messages: [{ content: 'Generate data', role: 'user' as const }],
|
|
1748
|
+
model: 'gpt-4o',
|
|
1749
|
+
responseApi: false,
|
|
1741
1750
|
schema: {
|
|
1742
1751
|
name: 'test_tool',
|
|
1743
|
-
schema: { type: 'object' as const
|
|
1752
|
+
schema: { properties: {}, type: 'object' as const },
|
|
1744
1753
|
},
|
|
1745
|
-
model: 'gpt-4o',
|
|
1746
|
-
responseApi: false,
|
|
1747
1754
|
};
|
|
1748
1755
|
|
|
1749
1756
|
const result = await instance.generateObject(payload);
|
|
@@ -1772,12 +1779,12 @@ describe('LobeOpenAICompatibleFactory', () => {
|
|
|
1772
1779
|
|
|
1773
1780
|
const payload = {
|
|
1774
1781
|
messages: [{ content: 'Generate data', role: 'user' as const }],
|
|
1782
|
+
model: 'gpt-4o',
|
|
1783
|
+
responseApi: false,
|
|
1775
1784
|
schema: {
|
|
1776
1785
|
name: 'test_tool',
|
|
1777
|
-
schema: { type: 'object' as const
|
|
1786
|
+
schema: { properties: {}, type: 'object' as const },
|
|
1778
1787
|
},
|
|
1779
|
-
model: 'gpt-4o',
|
|
1780
|
-
responseApi: false,
|
|
1781
1788
|
};
|
|
1782
1789
|
|
|
1783
1790
|
const result = await instance.generateObject(payload);
|
|
@@ -1806,26 +1813,26 @@ describe('LobeOpenAICompatibleFactory', () => {
|
|
|
1806
1813
|
|
|
1807
1814
|
const payload = {
|
|
1808
1815
|
messages: [{ content: 'Generate items list', role: 'user' as const }],
|
|
1816
|
+
model: 'gpt-4o',
|
|
1809
1817
|
schema: {
|
|
1810
1818
|
name: 'abc',
|
|
1811
1819
|
schema: {
|
|
1812
|
-
type: 'object' as const,
|
|
1813
1820
|
properties: {
|
|
1814
1821
|
items: {
|
|
1815
|
-
type: 'array',
|
|
1816
1822
|
items: {
|
|
1817
|
-
type: 'object',
|
|
1818
1823
|
properties: {
|
|
1819
1824
|
id: { type: 'number' },
|
|
1820
1825
|
name: { type: 'string' },
|
|
1821
1826
|
},
|
|
1827
|
+
type: 'object',
|
|
1822
1828
|
},
|
|
1829
|
+
type: 'array',
|
|
1823
1830
|
},
|
|
1824
1831
|
total: { type: 'number' },
|
|
1825
1832
|
},
|
|
1833
|
+
type: 'object' as const,
|
|
1826
1834
|
},
|
|
1827
1835
|
},
|
|
1828
|
-
model: 'gpt-4o',
|
|
1829
1836
|
};
|
|
1830
1837
|
|
|
1831
1838
|
const result = await instance.generateObject(payload);
|
|
@@ -1846,9 +1853,9 @@ describe('LobeOpenAICompatibleFactory', () => {
|
|
|
1846
1853
|
|
|
1847
1854
|
const payload = {
|
|
1848
1855
|
messages: [{ content: 'Generate data', role: 'user' as const }],
|
|
1849
|
-
schema: { name: 'abc', schema: { type: 'object' } as any },
|
|
1850
1856
|
model: 'gpt-4o',
|
|
1851
1857
|
responseApi: false,
|
|
1858
|
+
schema: { name: 'abc', schema: { type: 'object' } as any },
|
|
1852
1859
|
};
|
|
1853
1860
|
|
|
1854
1861
|
await expect(instance.generateObject(payload)).rejects.toThrow(
|
|
@@ -1865,18 +1872,18 @@ describe('LobeOpenAICompatibleFactory', () => {
|
|
|
1865
1872
|
message: {
|
|
1866
1873
|
tool_calls: [
|
|
1867
1874
|
{
|
|
1868
|
-
type: 'function' as const,
|
|
1869
1875
|
function: {
|
|
1870
|
-
name: 'get_weather',
|
|
1871
1876
|
arguments: '{"city":"Tokyo","unit":"celsius"}',
|
|
1877
|
+
name: 'get_weather',
|
|
1872
1878
|
},
|
|
1879
|
+
type: 'function' as const,
|
|
1873
1880
|
},
|
|
1874
1881
|
{
|
|
1875
|
-
type: 'function' as const,
|
|
1876
1882
|
function: {
|
|
1877
|
-
name: 'get_time',
|
|
1878
1883
|
arguments: '{"timezone":"Asia/Tokyo"}',
|
|
1884
|
+
name: 'get_time',
|
|
1879
1885
|
},
|
|
1886
|
+
type: 'function' as const,
|
|
1880
1887
|
},
|
|
1881
1888
|
],
|
|
1882
1889
|
},
|
|
@@ -1890,32 +1897,38 @@ describe('LobeOpenAICompatibleFactory', () => {
|
|
|
1890
1897
|
|
|
1891
1898
|
const payload = {
|
|
1892
1899
|
messages: [{ content: 'What is the weather and time in Tokyo?', role: 'user' as const }],
|
|
1900
|
+
model: 'gpt-4o',
|
|
1893
1901
|
tools: [
|
|
1894
1902
|
{
|
|
1895
|
-
|
|
1896
|
-
|
|
1897
|
-
|
|
1898
|
-
|
|
1899
|
-
|
|
1900
|
-
|
|
1901
|
-
|
|
1903
|
+
function: {
|
|
1904
|
+
description: 'Get weather information',
|
|
1905
|
+
name: 'get_weather',
|
|
1906
|
+
parameters: {
|
|
1907
|
+
properties: {
|
|
1908
|
+
city: { type: 'string' },
|
|
1909
|
+
unit: { type: 'string' },
|
|
1910
|
+
},
|
|
1911
|
+
required: ['city'],
|
|
1912
|
+
type: 'object' as const,
|
|
1902
1913
|
},
|
|
1903
|
-
required: ['city'],
|
|
1904
1914
|
},
|
|
1915
|
+
type: 'function' as const,
|
|
1905
1916
|
},
|
|
1906
1917
|
{
|
|
1907
|
-
|
|
1908
|
-
|
|
1909
|
-
|
|
1910
|
-
|
|
1911
|
-
|
|
1912
|
-
|
|
1918
|
+
function: {
|
|
1919
|
+
description: 'Get current time',
|
|
1920
|
+
name: 'get_time',
|
|
1921
|
+
parameters: {
|
|
1922
|
+
properties: {
|
|
1923
|
+
timezone: { type: 'string' },
|
|
1924
|
+
},
|
|
1925
|
+
required: ['timezone'],
|
|
1926
|
+
type: 'object' as const,
|
|
1913
1927
|
},
|
|
1914
|
-
required: ['timezone'],
|
|
1915
1928
|
},
|
|
1929
|
+
type: 'function' as const,
|
|
1916
1930
|
},
|
|
1917
1931
|
],
|
|
1918
|
-
model: 'gpt-4o',
|
|
1919
1932
|
};
|
|
1920
1933
|
|
|
1921
1934
|
const result = await instance.generateObject(payload);
|
|
@@ -1927,33 +1940,33 @@ describe('LobeOpenAICompatibleFactory', () => {
|
|
|
1927
1940
|
tool_choice: 'required',
|
|
1928
1941
|
tools: [
|
|
1929
1942
|
{
|
|
1930
|
-
type: 'function',
|
|
1931
1943
|
function: {
|
|
1932
|
-
name: 'get_weather',
|
|
1933
1944
|
description: 'Get weather information',
|
|
1945
|
+
name: 'get_weather',
|
|
1934
1946
|
parameters: {
|
|
1935
|
-
type: 'object',
|
|
1936
1947
|
properties: {
|
|
1937
1948
|
city: { type: 'string' },
|
|
1938
1949
|
unit: { type: 'string' },
|
|
1939
1950
|
},
|
|
1940
1951
|
required: ['city'],
|
|
1952
|
+
type: 'object',
|
|
1941
1953
|
},
|
|
1942
1954
|
},
|
|
1955
|
+
type: 'function',
|
|
1943
1956
|
},
|
|
1944
1957
|
{
|
|
1945
|
-
type: 'function',
|
|
1946
1958
|
function: {
|
|
1947
|
-
name: 'get_time',
|
|
1948
1959
|
description: 'Get current time',
|
|
1960
|
+
name: 'get_time',
|
|
1949
1961
|
parameters: {
|
|
1950
|
-
type: 'object',
|
|
1951
1962
|
properties: {
|
|
1952
1963
|
timezone: { type: 'string' },
|
|
1953
1964
|
},
|
|
1954
1965
|
required: ['timezone'],
|
|
1966
|
+
type: 'object',
|
|
1955
1967
|
},
|
|
1956
1968
|
},
|
|
1969
|
+
type: 'function',
|
|
1957
1970
|
},
|
|
1958
1971
|
],
|
|
1959
1972
|
user: undefined,
|
|
@@ -1974,11 +1987,11 @@ describe('LobeOpenAICompatibleFactory', () => {
|
|
|
1974
1987
|
message: {
|
|
1975
1988
|
tool_calls: [
|
|
1976
1989
|
{
|
|
1977
|
-
type: 'function' as const,
|
|
1978
1990
|
function: {
|
|
1979
|
-
name: 'calculate',
|
|
1980
1991
|
arguments: '{"result":8}',
|
|
1992
|
+
name: 'calculate',
|
|
1981
1993
|
},
|
|
1994
|
+
type: 'function' as const,
|
|
1982
1995
|
},
|
|
1983
1996
|
],
|
|
1984
1997
|
},
|
|
@@ -1992,31 +2005,30 @@ describe('LobeOpenAICompatibleFactory', () => {
|
|
|
1992
2005
|
|
|
1993
2006
|
const payload = {
|
|
1994
2007
|
messages: [{ content: 'Add 5 and 3', role: 'user' as const }],
|
|
2008
|
+
model: 'gpt-4o',
|
|
1995
2009
|
tools: [
|
|
1996
2010
|
{
|
|
1997
|
-
|
|
1998
|
-
|
|
1999
|
-
|
|
2000
|
-
|
|
2001
|
-
|
|
2002
|
-
|
|
2011
|
+
function: {
|
|
2012
|
+
description: 'Perform calculation',
|
|
2013
|
+
name: 'calculate',
|
|
2014
|
+
parameters: {
|
|
2015
|
+
properties: {
|
|
2016
|
+
result: { type: 'number' },
|
|
2017
|
+
},
|
|
2018
|
+
required: ['result'],
|
|
2019
|
+
type: 'object' as const,
|
|
2003
2020
|
},
|
|
2004
|
-
required: ['result'],
|
|
2005
2021
|
},
|
|
2022
|
+
type: 'function' as const,
|
|
2006
2023
|
},
|
|
2007
2024
|
],
|
|
2008
|
-
systemRole: 'You are a helpful calculator',
|
|
2009
|
-
model: 'gpt-4o',
|
|
2010
2025
|
};
|
|
2011
2026
|
|
|
2012
2027
|
const result = await instance.generateObject(payload);
|
|
2013
2028
|
|
|
2014
2029
|
expect(instance['client'].chat.completions.create).toHaveBeenCalledWith(
|
|
2015
2030
|
expect.objectContaining({
|
|
2016
|
-
messages: [
|
|
2017
|
-
{ content: 'Add 5 and 3', role: 'user' },
|
|
2018
|
-
{ content: 'You are a helpful calculator', role: 'system' },
|
|
2019
|
-
],
|
|
2031
|
+
messages: [{ content: 'Add 5 and 3', role: 'user' }],
|
|
2020
2032
|
}),
|
|
2021
2033
|
expect.any(Object),
|
|
2022
2034
|
);
|
|
@@ -2058,11 +2070,11 @@ describe('LobeOpenAICompatibleFactory', () => {
|
|
|
2058
2070
|
message: {
|
|
2059
2071
|
tool_calls: [
|
|
2060
2072
|
{
|
|
2061
|
-
type: 'function' as const,
|
|
2062
2073
|
function: {
|
|
2063
|
-
name: 'person_extractor',
|
|
2064
2074
|
arguments: '{"name":"Alice","age":28}',
|
|
2075
|
+
name: 'person_extractor',
|
|
2065
2076
|
},
|
|
2077
|
+
type: 'function' as const,
|
|
2066
2078
|
},
|
|
2067
2079
|
],
|
|
2068
2080
|
},
|
|
@@ -2076,15 +2088,15 @@ describe('LobeOpenAICompatibleFactory', () => {
|
|
|
2076
2088
|
|
|
2077
2089
|
const payload = {
|
|
2078
2090
|
messages: [{ content: 'Extract person info', role: 'user' as const }],
|
|
2091
|
+
model: 'test-model',
|
|
2079
2092
|
schema: {
|
|
2080
|
-
name: 'person_extractor',
|
|
2081
2093
|
description: 'Extract person information',
|
|
2094
|
+
name: 'person_extractor',
|
|
2082
2095
|
schema: {
|
|
2096
|
+
properties: { age: { type: 'number' }, name: { type: 'string' } },
|
|
2083
2097
|
type: 'object' as const,
|
|
2084
|
-
properties: { name: { type: 'string' }, age: { type: 'number' } },
|
|
2085
2098
|
},
|
|
2086
2099
|
},
|
|
2087
|
-
model: 'test-model',
|
|
2088
2100
|
};
|
|
2089
2101
|
|
|
2090
2102
|
const result = await instanceWithToolCalling.generateObject(payload);
|
|
@@ -2093,24 +2105,24 @@ describe('LobeOpenAICompatibleFactory', () => {
|
|
|
2093
2105
|
{
|
|
2094
2106
|
messages: payload.messages,
|
|
2095
2107
|
model: payload.model,
|
|
2108
|
+
tool_choice: { function: { name: 'person_extractor' }, type: 'function' },
|
|
2096
2109
|
tools: [
|
|
2097
2110
|
{
|
|
2098
|
-
type: 'function',
|
|
2099
2111
|
function: {
|
|
2100
|
-
name: 'person_extractor',
|
|
2101
2112
|
description: 'Extract person information',
|
|
2113
|
+
name: 'person_extractor',
|
|
2102
2114
|
parameters: payload.schema.schema,
|
|
2103
2115
|
},
|
|
2116
|
+
type: 'function',
|
|
2104
2117
|
},
|
|
2105
2118
|
],
|
|
2106
|
-
tool_choice: { type: 'function', function: { name: 'person_extractor' } },
|
|
2107
2119
|
user: undefined,
|
|
2108
2120
|
},
|
|
2109
2121
|
{ headers: undefined, signal: undefined },
|
|
2110
2122
|
);
|
|
2111
2123
|
|
|
2112
2124
|
expect(result).toEqual([
|
|
2113
|
-
{ arguments: { name: 'Alice'
|
|
2125
|
+
{ arguments: { age: 28, name: 'Alice' }, name: 'person_extractor' },
|
|
2114
2126
|
]);
|
|
2115
2127
|
});
|
|
2116
2128
|
|
|
@@ -2132,11 +2144,11 @@ describe('LobeOpenAICompatibleFactory', () => {
|
|
|
2132
2144
|
|
|
2133
2145
|
const payload = {
|
|
2134
2146
|
messages: [{ content: 'Generate data', role: 'user' as const }],
|
|
2147
|
+
model: 'test-model',
|
|
2135
2148
|
schema: {
|
|
2136
2149
|
name: 'test_tool',
|
|
2137
|
-
schema: { type: 'object' as const
|
|
2150
|
+
schema: { properties: {}, type: 'object' as const },
|
|
2138
2151
|
},
|
|
2139
|
-
model: 'test-model',
|
|
2140
2152
|
};
|
|
2141
2153
|
|
|
2142
2154
|
const result = await instanceWithToolCalling.generateObject(payload);
|
|
@@ -2154,11 +2166,11 @@ describe('LobeOpenAICompatibleFactory', () => {
|
|
|
2154
2166
|
message: {
|
|
2155
2167
|
tool_calls: [
|
|
2156
2168
|
{
|
|
2157
|
-
type: 'function' as const,
|
|
2158
2169
|
function: {
|
|
2159
|
-
name: 'test_tool',
|
|
2160
2170
|
arguments: 'invalid json',
|
|
2171
|
+
name: 'test_tool',
|
|
2161
2172
|
},
|
|
2173
|
+
type: 'function' as const,
|
|
2162
2174
|
},
|
|
2163
2175
|
],
|
|
2164
2176
|
},
|
|
@@ -2173,11 +2185,11 @@ describe('LobeOpenAICompatibleFactory', () => {
|
|
|
2173
2185
|
|
|
2174
2186
|
const payload = {
|
|
2175
2187
|
messages: [{ content: 'Generate data', role: 'user' as const }],
|
|
2188
|
+
model: 'test-model',
|
|
2176
2189
|
schema: {
|
|
2177
2190
|
name: 'test_tool',
|
|
2178
|
-
schema: { type: 'object' as const
|
|
2191
|
+
schema: { properties: {}, type: 'object' as const },
|
|
2179
2192
|
},
|
|
2180
|
-
model: 'test-model',
|
|
2181
2193
|
};
|
|
2182
2194
|
|
|
2183
2195
|
const result = await instanceWithToolCalling.generateObject(payload);
|
|
@@ -2198,11 +2210,11 @@ describe('LobeOpenAICompatibleFactory', () => {
|
|
|
2198
2210
|
message: {
|
|
2199
2211
|
tool_calls: [
|
|
2200
2212
|
{
|
|
2201
|
-
type: 'function' as const,
|
|
2202
2213
|
function: {
|
|
2203
|
-
name: 'data_extractor',
|
|
2204
2214
|
arguments: '{"data":"test"}',
|
|
2215
|
+
name: 'data_extractor',
|
|
2205
2216
|
},
|
|
2217
|
+
type: 'function' as const,
|
|
2206
2218
|
},
|
|
2207
2219
|
],
|
|
2208
2220
|
},
|
|
@@ -2216,17 +2228,17 @@ describe('LobeOpenAICompatibleFactory', () => {
|
|
|
2216
2228
|
|
|
2217
2229
|
const payload = {
|
|
2218
2230
|
messages: [{ content: 'Extract data', role: 'user' as const }],
|
|
2231
|
+
model: 'test-model',
|
|
2219
2232
|
schema: {
|
|
2220
2233
|
name: 'data_extractor',
|
|
2221
|
-
schema: {
|
|
2234
|
+
schema: { properties: { data: { type: 'string' } }, type: 'object' as const },
|
|
2222
2235
|
},
|
|
2223
|
-
model: 'test-model',
|
|
2224
2236
|
};
|
|
2225
2237
|
|
|
2226
2238
|
const options = {
|
|
2227
2239
|
headers: { 'X-Custom': 'header' },
|
|
2228
|
-
user: 'test-user',
|
|
2229
2240
|
signal: new AbortController().signal,
|
|
2241
|
+
user: 'test-user',
|
|
2230
2242
|
};
|
|
2231
2243
|
|
|
2232
2244
|
const result = await instanceWithToolCalling.generateObject(payload, options);
|
|
@@ -2245,10 +2257,10 @@ describe('LobeOpenAICompatibleFactory', () => {
|
|
|
2245
2257
|
it('should get models with third party model list', async () => {
|
|
2246
2258
|
vi.spyOn(instance['client'].models, 'list').mockResolvedValue({
|
|
2247
2259
|
data: [
|
|
2248
|
-
{ id: 'gpt-4o', object: 'model'
|
|
2260
|
+
{ created: 1_698_218_177, id: 'gpt-4o', object: 'model' },
|
|
2249
2261
|
{ id: 'claude-3-haiku-20240307', object: 'model' },
|
|
2250
|
-
{ id: 'gpt-4o-mini', object: 'model'
|
|
2251
|
-
{ id: 'gemini', object: 'model'
|
|
2262
|
+
{ created: 1_698_318_177 * 1000, id: 'gpt-4o-mini', object: 'model' },
|
|
2263
|
+
{ created: 1_736_499_509_125, id: 'gemini', object: 'model' },
|
|
2252
2264
|
],
|
|
2253
2265
|
} as any);
|
|
2254
2266
|
|
|
@@ -2263,7 +2275,7 @@ describe('LobeOpenAICompatibleFactory', () => {
|
|
|
2263
2275
|
config: {
|
|
2264
2276
|
deploymentName: 'gpt-4o',
|
|
2265
2277
|
},
|
|
2266
|
-
contextWindowTokens:
|
|
2278
|
+
contextWindowTokens: 128_000,
|
|
2267
2279
|
description:
|
|
2268
2280
|
'ChatGPT-4o 是一款动态模型,实时更新以保持当前最新版本。它结合了强大的语言理解与生成能力,适合于大规模应用场景,包括客户服务、教育和技术支持。',
|
|
2269
2281
|
displayName: 'GPT-4o',
|
|
@@ -2302,7 +2314,7 @@ describe('LobeOpenAICompatibleFactory', () => {
|
|
|
2302
2314
|
functionCall: true,
|
|
2303
2315
|
vision: true,
|
|
2304
2316
|
},
|
|
2305
|
-
contextWindowTokens:
|
|
2317
|
+
contextWindowTokens: 200_000,
|
|
2306
2318
|
description:
|
|
2307
2319
|
'Claude 3 Haiku 是 Anthropic 的最快且最紧凑的模型,旨在实现近乎即时的响应。它具有快速且准确的定向性能。',
|
|
2308
2320
|
displayName: 'Claude 3 Haiku',
|
|
@@ -2359,7 +2371,7 @@ describe('LobeOpenAICompatibleFactory', () => {
|
|
|
2359
2371
|
config: {
|
|
2360
2372
|
deploymentName: 'gpt-4o-mini',
|
|
2361
2373
|
},
|
|
2362
|
-
contextWindowTokens:
|
|
2374
|
+
contextWindowTokens: 128_000,
|
|
2363
2375
|
description: 'GPT-4o Mini,小型高效模型,具备与GPT-4o相似的卓越性能。',
|
|
2364
2376
|
displayName: 'GPT 4o Mini',
|
|
2365
2377
|
enabled: false,
|