@lobehub/chat 1.136.13 → 1.137.1
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/.cursor/rules/add-setting-env.mdc +175 -0
- package/.cursor/rules/db-migrations.mdc +25 -0
- package/.env.example +7 -0
- package/CHANGELOG.md +50 -0
- package/Dockerfile +3 -2
- package/Dockerfile.database +15 -3
- package/Dockerfile.pglite +3 -2
- package/changelog/v1.json +18 -0
- package/docs/development/database-schema.dbml +1 -0
- package/docs/self-hosting/advanced/feature-flags.mdx +25 -15
- package/docs/self-hosting/advanced/feature-flags.zh-CN.mdx +25 -15
- package/docs/self-hosting/environment-variables/basic.mdx +12 -0
- package/docs/self-hosting/environment-variables/basic.zh-CN.mdx +12 -0
- package/locales/ar/setting.json +8 -0
- package/locales/bg-BG/setting.json +8 -0
- package/locales/de-DE/setting.json +8 -0
- package/locales/en-US/setting.json +8 -0
- package/locales/es-ES/setting.json +8 -0
- package/locales/fa-IR/setting.json +8 -0
- package/locales/fr-FR/setting.json +8 -0
- package/locales/it-IT/setting.json +8 -0
- package/locales/ja-JP/setting.json +8 -0
- package/locales/ko-KR/setting.json +8 -0
- package/locales/nl-NL/setting.json +8 -0
- package/locales/pl-PL/setting.json +8 -0
- package/locales/pt-BR/setting.json +8 -0
- package/locales/ru-RU/setting.json +8 -0
- package/locales/tr-TR/setting.json +8 -0
- package/locales/vi-VN/setting.json +8 -0
- package/locales/zh-CN/setting.json +8 -0
- package/locales/zh-TW/setting.json +8 -0
- package/package.json +1 -1
- package/packages/agent-runtime/examples/tools-calling.ts +4 -3
- package/packages/agent-runtime/src/core/__tests__/runtime.test.ts +559 -29
- package/packages/agent-runtime/src/core/runtime.ts +171 -43
- package/packages/agent-runtime/src/types/instruction.ts +32 -6
- package/packages/agent-runtime/src/types/runtime.ts +2 -2
- package/packages/agent-runtime/src/types/state.ts +1 -8
- package/packages/agent-runtime/vitest.config.mts +14 -0
- package/packages/const/src/settings/image.ts +8 -0
- package/packages/const/src/settings/index.ts +3 -0
- package/packages/context-engine/src/__tests__/pipeline.test.ts +485 -0
- package/packages/context-engine/src/base/__tests__/BaseProcessor.test.ts +381 -0
- package/packages/context-engine/src/base/__tests__/BaseProvider.test.ts +392 -0
- package/packages/context-engine/src/processors/__tests__/MessageCleanup.test.ts +346 -0
- package/packages/context-engine/src/processors/__tests__/ToolCall.test.ts +552 -0
- package/packages/database/migrations/0038_add_image_user_settings.sql +1 -0
- package/packages/database/migrations/meta/0038_snapshot.json +7580 -0
- package/packages/database/migrations/meta/_journal.json +7 -0
- package/packages/database/src/core/migrations.json +6 -0
- package/packages/database/src/models/user.ts +3 -1
- package/packages/database/src/schemas/user.ts +1 -0
- package/packages/file-loaders/src/loaders/docx/index.test.ts +0 -1
- package/packages/file-loaders/src/loaders/excel/__snapshots__/index.test.ts.snap +30 -0
- package/packages/file-loaders/src/loaders/excel/index.test.ts +8 -0
- package/packages/file-loaders/src/loaders/pptx/index.test.ts +25 -0
- package/packages/file-loaders/src/utils/parser-utils.test.ts +155 -0
- package/packages/file-loaders/vitest.config.mts +8 -0
- package/packages/model-runtime/CLAUDE.md +5 -0
- package/packages/model-runtime/docs/test-coverage.md +706 -0
- package/packages/model-runtime/src/core/ModelRuntime.test.ts +231 -0
- package/packages/model-runtime/src/core/RouterRuntime/createRuntime.ts +1 -1
- package/packages/model-runtime/src/core/openaiCompatibleFactory/createImage.test.ts +799 -0
- package/packages/model-runtime/src/core/openaiCompatibleFactory/index.test.ts +188 -4
- package/packages/model-runtime/src/core/openaiCompatibleFactory/index.ts +41 -10
- package/packages/model-runtime/src/core/streams/openai/__snapshots__/responsesStream.test.ts.snap +439 -0
- package/packages/model-runtime/src/core/streams/openai/openai.test.ts +789 -0
- package/packages/model-runtime/src/core/streams/openai/responsesStream.test.ts +551 -0
- package/packages/model-runtime/src/core/usageConverters/utils/computeChatCost.test.ts +230 -0
- package/packages/model-runtime/src/core/usageConverters/utils/computeImageCost.test.ts +334 -37
- package/packages/model-runtime/src/providerTestUtils.ts +148 -145
- package/packages/model-runtime/src/providers/ai302/index.test.ts +60 -0
- package/packages/model-runtime/src/providers/ai302/index.ts +9 -4
- package/packages/model-runtime/src/providers/ai360/index.test.ts +1213 -1
- package/packages/model-runtime/src/providers/ai360/index.ts +9 -4
- package/packages/model-runtime/src/providers/aihubmix/index.test.ts +73 -0
- package/packages/model-runtime/src/providers/aihubmix/index.ts +6 -9
- package/packages/model-runtime/src/providers/akashchat/index.test.ts +433 -3
- package/packages/model-runtime/src/providers/akashchat/index.ts +12 -7
- package/packages/model-runtime/src/providers/anthropic/generateObject.test.ts +183 -29
- package/packages/model-runtime/src/providers/anthropic/generateObject.ts +40 -24
- package/packages/model-runtime/src/providers/azureai/index.test.ts +102 -0
- package/packages/model-runtime/src/providers/baichuan/index.test.ts +416 -26
- package/packages/model-runtime/src/providers/baichuan/index.ts +23 -20
- package/packages/model-runtime/src/providers/bedrock/index.test.ts +420 -2
- package/packages/model-runtime/src/providers/cerebras/index.test.ts +465 -0
- package/packages/model-runtime/src/providers/cerebras/index.ts +8 -3
- package/packages/model-runtime/src/providers/cohere/index.test.ts +1074 -1
- package/packages/model-runtime/src/providers/cohere/index.ts +8 -3
- package/packages/model-runtime/src/providers/cometapi/index.test.ts +439 -3
- package/packages/model-runtime/src/providers/cometapi/index.ts +8 -3
- package/packages/model-runtime/src/providers/deepseek/index.test.ts +116 -1
- package/packages/model-runtime/src/providers/deepseek/index.ts +8 -3
- package/packages/model-runtime/src/providers/fireworksai/index.test.ts +264 -3
- package/packages/model-runtime/src/providers/fireworksai/index.ts +8 -3
- package/packages/model-runtime/src/providers/giteeai/index.test.ts +325 -3
- package/packages/model-runtime/src/providers/giteeai/index.ts +23 -6
- package/packages/model-runtime/src/providers/github/index.test.ts +532 -3
- package/packages/model-runtime/src/providers/github/index.ts +8 -3
- package/packages/model-runtime/src/providers/groq/index.test.ts +344 -31
- package/packages/model-runtime/src/providers/groq/index.ts +8 -3
- package/packages/model-runtime/src/providers/higress/index.test.ts +142 -0
- package/packages/model-runtime/src/providers/higress/index.ts +8 -3
- package/packages/model-runtime/src/providers/huggingface/index.test.ts +612 -1
- package/packages/model-runtime/src/providers/huggingface/index.ts +9 -4
- package/packages/model-runtime/src/providers/hunyuan/index.test.ts +365 -1
- package/packages/model-runtime/src/providers/hunyuan/index.ts +9 -3
- package/packages/model-runtime/src/providers/infiniai/index.test.ts +71 -0
- package/packages/model-runtime/src/providers/internlm/index.test.ts +369 -2
- package/packages/model-runtime/src/providers/internlm/index.ts +10 -5
- package/packages/model-runtime/src/providers/jina/index.test.ts +164 -3
- package/packages/model-runtime/src/providers/jina/index.ts +8 -3
- package/packages/model-runtime/src/providers/lmstudio/index.test.ts +182 -3
- package/packages/model-runtime/src/providers/lmstudio/index.ts +8 -3
- package/packages/model-runtime/src/providers/mistral/index.test.ts +779 -27
- package/packages/model-runtime/src/providers/mistral/index.ts +8 -3
- package/packages/model-runtime/src/providers/modelscope/index.test.ts +232 -1
- package/packages/model-runtime/src/providers/modelscope/index.ts +8 -3
- package/packages/model-runtime/src/providers/moonshot/index.test.ts +489 -2
- package/packages/model-runtime/src/providers/moonshot/index.ts +8 -3
- package/packages/model-runtime/src/providers/nebius/index.test.ts +381 -3
- package/packages/model-runtime/src/providers/nebius/index.ts +8 -3
- package/packages/model-runtime/src/providers/newapi/index.test.ts +667 -3
- package/packages/model-runtime/src/providers/newapi/index.ts +6 -3
- package/packages/model-runtime/src/providers/nvidia/index.test.ts +168 -1
- package/packages/model-runtime/src/providers/nvidia/index.ts +12 -7
- package/packages/model-runtime/src/providers/ollama/index.test.ts +797 -1
- package/packages/model-runtime/src/providers/ollama/index.ts +8 -0
- package/packages/model-runtime/src/providers/ollamacloud/index.test.ts +411 -0
- package/packages/model-runtime/src/providers/ollamacloud/index.ts +8 -3
- package/packages/model-runtime/src/providers/openai/index.test.ts +171 -2
- package/packages/model-runtime/src/providers/openai/index.ts +8 -3
- package/packages/model-runtime/src/providers/openrouter/index.test.ts +1647 -95
- package/packages/model-runtime/src/providers/openrouter/index.ts +12 -7
- package/packages/model-runtime/src/providers/qiniu/index.test.ts +294 -1
- package/packages/model-runtime/src/providers/qiniu/index.ts +8 -3
- package/packages/model-runtime/src/providers/search1api/index.test.ts +1131 -11
- package/packages/model-runtime/src/providers/search1api/index.ts +10 -4
- package/packages/model-runtime/src/providers/sensenova/index.test.ts +1069 -1
- package/packages/model-runtime/src/providers/sensenova/index.ts +8 -3
- package/packages/model-runtime/src/providers/siliconcloud/index.test.ts +196 -0
- package/packages/model-runtime/src/providers/siliconcloud/index.ts +8 -3
- package/packages/model-runtime/src/providers/spark/index.test.ts +293 -1
- package/packages/model-runtime/src/providers/spark/index.ts +8 -3
- package/packages/model-runtime/src/providers/stepfun/index.test.ts +322 -3
- package/packages/model-runtime/src/providers/stepfun/index.ts +8 -3
- package/packages/model-runtime/src/providers/tencentcloud/index.test.ts +182 -3
- package/packages/model-runtime/src/providers/tencentcloud/index.ts +8 -3
- package/packages/model-runtime/src/providers/togetherai/index.test.ts +359 -4
- package/packages/model-runtime/src/providers/togetherai/index.ts +12 -5
- package/packages/model-runtime/src/providers/v0/index.test.ts +341 -0
- package/packages/model-runtime/src/providers/v0/index.ts +20 -6
- package/packages/model-runtime/src/providers/vercelaigateway/index.test.ts +710 -0
- package/packages/model-runtime/src/providers/vercelaigateway/index.ts +19 -13
- package/packages/model-runtime/src/providers/vllm/index.test.ts +45 -1
- package/packages/model-runtime/src/providers/volcengine/index.test.ts +75 -0
- package/packages/model-runtime/src/providers/wenxin/index.test.ts +144 -1
- package/packages/model-runtime/src/providers/wenxin/index.ts +8 -3
- package/packages/model-runtime/src/providers/xai/index.test.ts +105 -1
- package/packages/model-runtime/src/providers/xinference/index.test.ts +70 -1
- package/packages/model-runtime/src/providers/zeroone/index.test.ts +327 -3
- package/packages/model-runtime/src/providers/zeroone/index.ts +23 -6
- package/packages/model-runtime/src/providers/zhipu/index.test.ts +908 -236
- package/packages/model-runtime/src/providers/zhipu/index.ts +8 -3
- package/packages/model-runtime/src/types/structureOutput.ts +5 -1
- package/packages/model-runtime/vitest.config.mts +7 -1
- package/packages/types/src/aiChat.ts +20 -2
- package/packages/types/src/serverConfig.ts +7 -1
- package/packages/types/src/tool/index.ts +1 -0
- package/packages/types/src/tool/tool.ts +33 -0
- package/packages/types/src/user/settings/image.ts +3 -0
- package/packages/types/src/user/settings/index.ts +3 -0
- package/src/app/[variants]/(main)/settings/_layout/SettingsContent.tsx +3 -0
- package/src/app/[variants]/(main)/settings/hooks/useCategory.tsx +8 -3
- package/src/app/[variants]/(main)/settings/image/index.tsx +74 -0
- package/src/components/FormInput/FormSliderWithInput.tsx +40 -0
- package/src/components/FormInput/index.ts +1 -0
- package/src/envs/image.ts +27 -0
- package/src/features/Conversation/Messages/Assistant/index.tsx +1 -1
- package/src/features/Conversation/Messages/User/index.tsx +2 -2
- package/src/hooks/useFetchAiImageConfig.ts +12 -17
- package/src/locales/default/setting.ts +8 -0
- package/src/server/globalConfig/index.ts +5 -0
- package/src/server/routers/lambda/aiChat.ts +2 -0
- package/src/store/global/initialState.ts +1 -0
- package/src/store/image/slices/generationConfig/action.test.ts +17 -0
- package/src/store/image/slices/generationConfig/action.ts +18 -21
- package/src/store/image/slices/generationConfig/initialState.ts +3 -2
- package/src/store/user/slices/common/action.ts +1 -0
- package/src/store/user/slices/settings/selectors/settings.ts +3 -0
|
@@ -1,11 +1,14 @@
|
|
|
1
1
|
// @vitest-environment node
|
|
2
|
-
import {
|
|
2
|
+
import {
|
|
3
|
+
InvokeModelCommand,
|
|
4
|
+
InvokeModelWithResponseStreamCommand,
|
|
5
|
+
} from '@aws-sdk/client-bedrock-runtime';
|
|
3
6
|
import { AgentRuntimeErrorType } from '@lobechat/model-runtime';
|
|
4
7
|
import { ModelProvider } from 'model-bank';
|
|
5
8
|
import { Mock, afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
|
|
6
9
|
|
|
7
10
|
import * as debugStreamModule from '../../utils/debugStream';
|
|
8
|
-
import { LobeBedrockAI } from './index';
|
|
11
|
+
import { LobeBedrockAI, experimental_buildLlama2Prompt } from './index';
|
|
9
12
|
|
|
10
13
|
const provider = 'bedrock';
|
|
11
14
|
|
|
@@ -16,6 +19,7 @@ vi.mock('@aws-sdk/client-bedrock-runtime', async (importOriginal) => {
|
|
|
16
19
|
const module = await importOriginal();
|
|
17
20
|
return {
|
|
18
21
|
...(module as any),
|
|
22
|
+
InvokeModelCommand: vi.fn(),
|
|
19
23
|
InvokeModelWithResponseStreamCommand: vi.fn(),
|
|
20
24
|
};
|
|
21
25
|
});
|
|
@@ -45,6 +49,59 @@ describe('LobeBedrockAI', () => {
|
|
|
45
49
|
accessKeySecret: 'test-access-key-secret',
|
|
46
50
|
});
|
|
47
51
|
expect(instance).toBeInstanceOf(LobeBedrockAI);
|
|
52
|
+
expect(instance.region).toBe('us-west-2');
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
it('should use default region if not provided', () => {
|
|
56
|
+
const instance = new LobeBedrockAI({
|
|
57
|
+
accessKeyId: 'test-access-key-id',
|
|
58
|
+
accessKeySecret: 'test-access-key-secret',
|
|
59
|
+
});
|
|
60
|
+
expect(instance.region).toBe('us-east-1');
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
it('should correctly initialize with session token', () => {
|
|
64
|
+
const instance = new LobeBedrockAI({
|
|
65
|
+
region: 'us-west-2',
|
|
66
|
+
accessKeyId: 'test-access-key-id',
|
|
67
|
+
accessKeySecret: 'test-access-key-secret',
|
|
68
|
+
sessionToken: 'test-session-token',
|
|
69
|
+
});
|
|
70
|
+
expect(instance).toBeInstanceOf(LobeBedrockAI);
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
it('should throw InvalidBedrockCredentials if accessKeyId is missing', () => {
|
|
74
|
+
expect(() => {
|
|
75
|
+
new LobeBedrockAI({
|
|
76
|
+
accessKeySecret: 'test-access-key-secret',
|
|
77
|
+
});
|
|
78
|
+
}).toThrow(
|
|
79
|
+
expect.objectContaining({
|
|
80
|
+
errorType: AgentRuntimeErrorType.InvalidBedrockCredentials,
|
|
81
|
+
}),
|
|
82
|
+
);
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
it('should throw InvalidBedrockCredentials if accessKeySecret is missing', () => {
|
|
86
|
+
expect(() => {
|
|
87
|
+
new LobeBedrockAI({
|
|
88
|
+
accessKeyId: 'test-access-key-id',
|
|
89
|
+
});
|
|
90
|
+
}).toThrow(
|
|
91
|
+
expect.objectContaining({
|
|
92
|
+
errorType: AgentRuntimeErrorType.InvalidBedrockCredentials,
|
|
93
|
+
}),
|
|
94
|
+
);
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
it('should throw InvalidBedrockCredentials if both credentials are missing', () => {
|
|
98
|
+
expect(() => {
|
|
99
|
+
new LobeBedrockAI({});
|
|
100
|
+
}).toThrow(
|
|
101
|
+
expect.objectContaining({
|
|
102
|
+
errorType: AgentRuntimeErrorType.InvalidBedrockCredentials,
|
|
103
|
+
}),
|
|
104
|
+
);
|
|
48
105
|
});
|
|
49
106
|
});
|
|
50
107
|
|
|
@@ -201,6 +258,83 @@ describe('LobeBedrockAI', () => {
|
|
|
201
258
|
expect(result).toBeInstanceOf(Response);
|
|
202
259
|
});
|
|
203
260
|
|
|
261
|
+
it('should handle tools parameter', async () => {
|
|
262
|
+
// Arrange
|
|
263
|
+
const mockStream = new ReadableStream({
|
|
264
|
+
start(controller) {
|
|
265
|
+
controller.enqueue('Hello, world!');
|
|
266
|
+
controller.close();
|
|
267
|
+
},
|
|
268
|
+
});
|
|
269
|
+
const mockResponse = Promise.resolve(mockStream);
|
|
270
|
+
(instance['client'].send as Mock).mockResolvedValue(mockResponse);
|
|
271
|
+
|
|
272
|
+
const tools = [
|
|
273
|
+
{
|
|
274
|
+
function: {
|
|
275
|
+
description: 'Get weather information',
|
|
276
|
+
name: 'get_weather',
|
|
277
|
+
parameters: {
|
|
278
|
+
properties: {
|
|
279
|
+
location: {
|
|
280
|
+
description: 'City name',
|
|
281
|
+
type: 'string',
|
|
282
|
+
},
|
|
283
|
+
},
|
|
284
|
+
required: ['location'],
|
|
285
|
+
type: 'object',
|
|
286
|
+
},
|
|
287
|
+
},
|
|
288
|
+
type: 'function' as const,
|
|
289
|
+
},
|
|
290
|
+
];
|
|
291
|
+
|
|
292
|
+
// Act
|
|
293
|
+
await instance.chat({
|
|
294
|
+
messages: [{ content: 'Hello', role: 'user' }],
|
|
295
|
+
model: 'anthropic.claude-v2:1',
|
|
296
|
+
temperature: 0.5,
|
|
297
|
+
tools,
|
|
298
|
+
});
|
|
299
|
+
|
|
300
|
+
// Assert
|
|
301
|
+
const callArgs = (InvokeModelWithResponseStreamCommand as any as Mock).mock.calls[0][0];
|
|
302
|
+
const bodyContent = JSON.parse(callArgs.body);
|
|
303
|
+
expect(bodyContent.tools).toBeDefined();
|
|
304
|
+
});
|
|
305
|
+
|
|
306
|
+
it('should use default max_tokens when not provided', async () => {
|
|
307
|
+
// Arrange
|
|
308
|
+
const mockStream = new ReadableStream({
|
|
309
|
+
start(controller) {
|
|
310
|
+
controller.enqueue('Hello, world!');
|
|
311
|
+
controller.close();
|
|
312
|
+
},
|
|
313
|
+
});
|
|
314
|
+
const mockResponse = Promise.resolve(mockStream);
|
|
315
|
+
(instance['client'].send as Mock).mockResolvedValue(mockResponse);
|
|
316
|
+
|
|
317
|
+
// Act
|
|
318
|
+
await instance.chat({
|
|
319
|
+
messages: [{ content: 'Hello', role: 'user' }],
|
|
320
|
+
model: 'anthropic.claude-v2:1',
|
|
321
|
+
temperature: 0,
|
|
322
|
+
});
|
|
323
|
+
|
|
324
|
+
// Assert
|
|
325
|
+
expect(InvokeModelWithResponseStreamCommand).toHaveBeenCalledWith({
|
|
326
|
+
accept: 'application/json',
|
|
327
|
+
body: JSON.stringify({
|
|
328
|
+
anthropic_version: 'bedrock-2023-05-31',
|
|
329
|
+
max_tokens: 4096,
|
|
330
|
+
messages: [{ content: 'Hello', role: 'user' }],
|
|
331
|
+
temperature: 0,
|
|
332
|
+
}),
|
|
333
|
+
contentType: 'application/json',
|
|
334
|
+
modelId: 'anthropic.claude-v2:1',
|
|
335
|
+
});
|
|
336
|
+
});
|
|
337
|
+
|
|
204
338
|
it('should call Anthropic model without unsupported opions', async () => {
|
|
205
339
|
// Arrange
|
|
206
340
|
const mockStream = new ReadableStream({
|
|
@@ -457,6 +591,17 @@ describe('LobeBedrockAI', () => {
|
|
|
457
591
|
});
|
|
458
592
|
|
|
459
593
|
describe('Llama Model', () => {
|
|
594
|
+
it('should return a Response on successful API call', async () => {
|
|
595
|
+
const result = await instance.chat({
|
|
596
|
+
messages: [{ content: 'Hello', role: 'user' }],
|
|
597
|
+
model: 'meta.llama:1',
|
|
598
|
+
temperature: 0,
|
|
599
|
+
});
|
|
600
|
+
|
|
601
|
+
// Assert
|
|
602
|
+
expect(result).toBeInstanceOf(Response);
|
|
603
|
+
});
|
|
604
|
+
|
|
460
605
|
it('should call Llama model with valid payload', async () => {
|
|
461
606
|
// Arrange
|
|
462
607
|
const mockStream = new ReadableStream({
|
|
@@ -538,6 +683,69 @@ describe('LobeBedrockAI', () => {
|
|
|
538
683
|
// Clean up
|
|
539
684
|
delete process.env.DEBUG_BEDROCK_CHAT_COMPLETION;
|
|
540
685
|
});
|
|
686
|
+
|
|
687
|
+
it('should use default max_tokens (400) when not provided', async () => {
|
|
688
|
+
// Arrange
|
|
689
|
+
const mockStream = new ReadableStream({
|
|
690
|
+
start(controller) {
|
|
691
|
+
controller.enqueue('Hello, world!');
|
|
692
|
+
controller.close();
|
|
693
|
+
},
|
|
694
|
+
});
|
|
695
|
+
const mockResponse = Promise.resolve(mockStream);
|
|
696
|
+
(instance['client'].send as Mock).mockResolvedValue(mockResponse);
|
|
697
|
+
|
|
698
|
+
// Act
|
|
699
|
+
await instance.chat({
|
|
700
|
+
messages: [{ content: 'Hello', role: 'user' }],
|
|
701
|
+
model: 'meta.llama:1',
|
|
702
|
+
temperature: 0,
|
|
703
|
+
});
|
|
704
|
+
|
|
705
|
+
// Assert
|
|
706
|
+
expect(InvokeModelWithResponseStreamCommand).toHaveBeenCalledWith({
|
|
707
|
+
accept: 'application/json',
|
|
708
|
+
body: JSON.stringify({
|
|
709
|
+
max_gen_len: 400,
|
|
710
|
+
prompt: '<s>[INST] Hello [/INST]',
|
|
711
|
+
}),
|
|
712
|
+
contentType: 'application/json',
|
|
713
|
+
modelId: 'meta.llama:1',
|
|
714
|
+
});
|
|
715
|
+
});
|
|
716
|
+
|
|
717
|
+
it('should handle system message in Llama prompt', async () => {
|
|
718
|
+
// Arrange
|
|
719
|
+
const mockStream = new ReadableStream({
|
|
720
|
+
start(controller) {
|
|
721
|
+
controller.enqueue('Hello, world!');
|
|
722
|
+
controller.close();
|
|
723
|
+
},
|
|
724
|
+
});
|
|
725
|
+
const mockResponse = Promise.resolve(mockStream);
|
|
726
|
+
(instance['client'].send as Mock).mockResolvedValue(mockResponse);
|
|
727
|
+
|
|
728
|
+
// Act
|
|
729
|
+
await instance.chat({
|
|
730
|
+
messages: [
|
|
731
|
+
{ content: 'You are a helpful assistant', role: 'system' },
|
|
732
|
+
{ content: 'Hello', role: 'user' },
|
|
733
|
+
],
|
|
734
|
+
model: 'meta.llama2-70b-chat-v1',
|
|
735
|
+
temperature: 0,
|
|
736
|
+
});
|
|
737
|
+
|
|
738
|
+
// Assert
|
|
739
|
+
expect(InvokeModelWithResponseStreamCommand).toHaveBeenCalledWith({
|
|
740
|
+
accept: 'application/json',
|
|
741
|
+
body: JSON.stringify({
|
|
742
|
+
max_gen_len: 400,
|
|
743
|
+
prompt: '<s>[INST] <<SYS>>\nYou are a helpful assistant\n<</SYS>>\n\nHello [/INST]',
|
|
744
|
+
}),
|
|
745
|
+
contentType: 'application/json',
|
|
746
|
+
modelId: 'meta.llama2-70b-chat-v1',
|
|
747
|
+
});
|
|
748
|
+
});
|
|
541
749
|
});
|
|
542
750
|
|
|
543
751
|
it('should call options.callback when provided', async () => {
|
|
@@ -558,4 +766,214 @@ describe('LobeBedrockAI', () => {
|
|
|
558
766
|
expect(onStart).toHaveBeenCalled();
|
|
559
767
|
});
|
|
560
768
|
});
|
|
769
|
+
|
|
770
|
+
describe('embeddings', () => {
|
|
771
|
+
it('should handle single input string', async () => {
|
|
772
|
+
// Arrange
|
|
773
|
+
const mockEmbedding = [0.1, 0.2, 0.3];
|
|
774
|
+
const mockResponse = {
|
|
775
|
+
body: new TextEncoder().encode(JSON.stringify({ embedding: mockEmbedding })),
|
|
776
|
+
};
|
|
777
|
+
(instance['client'].send as Mock).mockResolvedValue(mockResponse);
|
|
778
|
+
|
|
779
|
+
// Act
|
|
780
|
+
const result = await instance.embeddings({
|
|
781
|
+
input: 'test input',
|
|
782
|
+
model: 'amazon.titan-embed-text-v1',
|
|
783
|
+
});
|
|
784
|
+
|
|
785
|
+
// Assert
|
|
786
|
+
expect(result).toHaveLength(1);
|
|
787
|
+
expect(result[0]).toEqual(mockEmbedding);
|
|
788
|
+
expect(InvokeModelCommand).toHaveBeenCalledWith({
|
|
789
|
+
accept: 'application/json',
|
|
790
|
+
body: JSON.stringify({
|
|
791
|
+
inputText: 'test input',
|
|
792
|
+
normalize: true,
|
|
793
|
+
}),
|
|
794
|
+
contentType: 'application/json',
|
|
795
|
+
modelId: 'amazon.titan-embed-text-v1',
|
|
796
|
+
});
|
|
797
|
+
});
|
|
798
|
+
|
|
799
|
+
it('should handle multiple input strings', async () => {
|
|
800
|
+
// Arrange
|
|
801
|
+
const mockEmbedding1 = [0.1, 0.2, 0.3];
|
|
802
|
+
const mockEmbedding2 = [0.4, 0.5, 0.6];
|
|
803
|
+
const mockResponse1 = {
|
|
804
|
+
body: new TextEncoder().encode(JSON.stringify({ embedding: mockEmbedding1 })),
|
|
805
|
+
};
|
|
806
|
+
const mockResponse2 = {
|
|
807
|
+
body: new TextEncoder().encode(JSON.stringify({ embedding: mockEmbedding2 })),
|
|
808
|
+
};
|
|
809
|
+
(instance['client'].send as Mock)
|
|
810
|
+
.mockResolvedValueOnce(mockResponse1)
|
|
811
|
+
.mockResolvedValueOnce(mockResponse2);
|
|
812
|
+
|
|
813
|
+
// Act
|
|
814
|
+
const result = await instance.embeddings({
|
|
815
|
+
input: ['test input 1', 'test input 2'],
|
|
816
|
+
model: 'amazon.titan-embed-text-v1',
|
|
817
|
+
});
|
|
818
|
+
|
|
819
|
+
// Assert
|
|
820
|
+
expect(result).toHaveLength(2);
|
|
821
|
+
expect(result[0]).toEqual(mockEmbedding1);
|
|
822
|
+
expect(result[1]).toEqual(mockEmbedding2);
|
|
823
|
+
expect(InvokeModelCommand).toHaveBeenCalledTimes(2);
|
|
824
|
+
});
|
|
825
|
+
|
|
826
|
+
it('should handle dimensions parameter', async () => {
|
|
827
|
+
// Arrange
|
|
828
|
+
const mockEmbedding = [0.1, 0.2, 0.3];
|
|
829
|
+
const mockResponse = {
|
|
830
|
+
body: new TextEncoder().encode(JSON.stringify({ embedding: mockEmbedding })),
|
|
831
|
+
};
|
|
832
|
+
(instance['client'].send as Mock).mockResolvedValue(mockResponse);
|
|
833
|
+
|
|
834
|
+
// Act
|
|
835
|
+
const result = await instance.embeddings({
|
|
836
|
+
dimensions: 512,
|
|
837
|
+
input: 'test input',
|
|
838
|
+
model: 'amazon.titan-embed-text-v1',
|
|
839
|
+
});
|
|
840
|
+
|
|
841
|
+
// Assert
|
|
842
|
+
expect(result).toHaveLength(1);
|
|
843
|
+
expect(InvokeModelCommand).toHaveBeenCalledWith({
|
|
844
|
+
accept: 'application/json',
|
|
845
|
+
body: JSON.stringify({
|
|
846
|
+
dimensions: 512,
|
|
847
|
+
inputText: 'test input',
|
|
848
|
+
normalize: true,
|
|
849
|
+
}),
|
|
850
|
+
contentType: 'application/json',
|
|
851
|
+
modelId: 'amazon.titan-embed-text-v1',
|
|
852
|
+
});
|
|
853
|
+
});
|
|
854
|
+
|
|
855
|
+
it('should handle abort signal', async () => {
|
|
856
|
+
// Arrange
|
|
857
|
+
const mockEmbedding = [0.1, 0.2, 0.3];
|
|
858
|
+
const mockResponse = {
|
|
859
|
+
body: new TextEncoder().encode(JSON.stringify({ embedding: mockEmbedding })),
|
|
860
|
+
};
|
|
861
|
+
const sendSpy = vi.spyOn(instance['client'], 'send').mockResolvedValue(mockResponse as any);
|
|
862
|
+
const abortController = new AbortController();
|
|
863
|
+
|
|
864
|
+
// Act
|
|
865
|
+
await instance.embeddings(
|
|
866
|
+
{
|
|
867
|
+
input: 'test input',
|
|
868
|
+
model: 'amazon.titan-embed-text-v1',
|
|
869
|
+
},
|
|
870
|
+
{ signal: abortController.signal },
|
|
871
|
+
);
|
|
872
|
+
|
|
873
|
+
// Assert
|
|
874
|
+
expect(sendSpy).toHaveBeenCalledWith(expect.any(InvokeModelCommand), {
|
|
875
|
+
abortSignal: abortController.signal,
|
|
876
|
+
});
|
|
877
|
+
});
|
|
878
|
+
|
|
879
|
+
it('should throw AgentRuntimeError on API error', async () => {
|
|
880
|
+
// Arrange
|
|
881
|
+
const errorMessage = 'Embedding API error';
|
|
882
|
+
const errorMetadata = { statusCode: 400 };
|
|
883
|
+
const mockError = new Error(errorMessage);
|
|
884
|
+
(mockError as any).$metadata = errorMetadata;
|
|
885
|
+
(instance['client'].send as Mock).mockRejectedValue(mockError);
|
|
886
|
+
|
|
887
|
+
// Act & Assert
|
|
888
|
+
await expect(
|
|
889
|
+
instance.embeddings({
|
|
890
|
+
input: 'test input',
|
|
891
|
+
model: 'amazon.titan-embed-text-v1',
|
|
892
|
+
}),
|
|
893
|
+
).rejects.toThrow(
|
|
894
|
+
expect.objectContaining({
|
|
895
|
+
error: {
|
|
896
|
+
body: errorMetadata,
|
|
897
|
+
message: errorMessage,
|
|
898
|
+
type: 'Error',
|
|
899
|
+
},
|
|
900
|
+
errorType: AgentRuntimeErrorType.ProviderBizError,
|
|
901
|
+
provider: ModelProvider.Bedrock,
|
|
902
|
+
region: 'us-west-2',
|
|
903
|
+
}),
|
|
904
|
+
);
|
|
905
|
+
});
|
|
906
|
+
});
|
|
907
|
+
|
|
908
|
+
describe('experimental_buildLlama2Prompt', () => {
|
|
909
|
+
it('should build prompt with user message only', () => {
|
|
910
|
+
const messages = [{ content: 'Hello', role: 'user' }];
|
|
911
|
+
const result = experimental_buildLlama2Prompt(messages);
|
|
912
|
+
expect(result).toBe('<s>[INST] Hello [/INST]');
|
|
913
|
+
});
|
|
914
|
+
|
|
915
|
+
it('should build prompt with system and user messages', () => {
|
|
916
|
+
const messages = [
|
|
917
|
+
{ content: 'You are a helpful assistant', role: 'system' },
|
|
918
|
+
{ content: 'Hello', role: 'user' },
|
|
919
|
+
];
|
|
920
|
+
const result = experimental_buildLlama2Prompt(messages);
|
|
921
|
+
expect(result).toBe(
|
|
922
|
+
'<s>[INST] <<SYS>>\nYou are a helpful assistant\n<</SYS>>\n\nHello [/INST]',
|
|
923
|
+
);
|
|
924
|
+
});
|
|
925
|
+
|
|
926
|
+
it('should build prompt with conversation history', () => {
|
|
927
|
+
const messages = [
|
|
928
|
+
{ content: 'Hello', role: 'user' },
|
|
929
|
+
{ content: 'Hi there!', role: 'assistant' },
|
|
930
|
+
{ content: 'How are you?', role: 'user' },
|
|
931
|
+
];
|
|
932
|
+
const result = experimental_buildLlama2Prompt(messages);
|
|
933
|
+
expect(result).toBe('<s>[INST] Hello [/INST] Hi there!</s><s>[INST] How are you? [/INST]');
|
|
934
|
+
});
|
|
935
|
+
|
|
936
|
+
it('should build prompt with system, user, and assistant messages', () => {
|
|
937
|
+
const messages = [
|
|
938
|
+
{ content: 'You are a helpful assistant', role: 'system' },
|
|
939
|
+
{ content: 'Hello', role: 'user' },
|
|
940
|
+
{ content: 'Hi there!', role: 'assistant' },
|
|
941
|
+
{ content: 'How are you?', role: 'user' },
|
|
942
|
+
];
|
|
943
|
+
const result = experimental_buildLlama2Prompt(messages);
|
|
944
|
+
expect(result).toBe(
|
|
945
|
+
'<s>[INST] <<SYS>>\nYou are a helpful assistant\n<</SYS>>\n\nHello [/INST] Hi there!</s><s>[INST] How are you? [/INST]',
|
|
946
|
+
);
|
|
947
|
+
});
|
|
948
|
+
|
|
949
|
+
it('should trim user messages', () => {
|
|
950
|
+
const messages = [{ content: ' Hello ', role: 'user' }];
|
|
951
|
+
const result = experimental_buildLlama2Prompt(messages);
|
|
952
|
+
expect(result).toBe('<s>[INST] Hello [/INST]');
|
|
953
|
+
});
|
|
954
|
+
|
|
955
|
+
it('should throw error for function messages', () => {
|
|
956
|
+
const messages = [{ content: 'function call', role: 'function' }];
|
|
957
|
+
expect(() => experimental_buildLlama2Prompt(messages)).toThrow(
|
|
958
|
+
'Llama 2 does not support function calls.',
|
|
959
|
+
);
|
|
960
|
+
});
|
|
961
|
+
|
|
962
|
+
it('should throw error for invalid role', () => {
|
|
963
|
+
const messages = [{ content: 'invalid', role: 'invalid' }];
|
|
964
|
+
expect(() => experimental_buildLlama2Prompt(messages)).toThrow(
|
|
965
|
+
'Invalid message role: invalid',
|
|
966
|
+
);
|
|
967
|
+
});
|
|
968
|
+
|
|
969
|
+
it('should throw error for system message not at index 0', () => {
|
|
970
|
+
const messages = [
|
|
971
|
+
{ content: 'Hello', role: 'user' },
|
|
972
|
+
{ content: 'You are a helpful assistant', role: 'system' },
|
|
973
|
+
];
|
|
974
|
+
expect(() => experimental_buildLlama2Prompt(messages)).toThrow(
|
|
975
|
+
'Invalid message role: system',
|
|
976
|
+
);
|
|
977
|
+
});
|
|
978
|
+
});
|
|
561
979
|
});
|