@lobehub/chat 1.45.12 → 1.45.14
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/README.ja-JP.md +1 -1
- package/README.md +1 -1
- package/changelog/v1.json +14 -0
- package/locales/ar/modelProvider.json +6 -5
- package/locales/bg-BG/modelProvider.json +6 -5
- package/locales/de-DE/modelProvider.json +6 -5
- package/locales/en-US/modelProvider.json +6 -5
- package/locales/es-ES/modelProvider.json +6 -5
- package/locales/fa-IR/modelProvider.json +6 -5
- package/locales/fr-FR/modelProvider.json +6 -5
- package/locales/it-IT/modelProvider.json +6 -5
- package/locales/ja-JP/modelProvider.json +6 -5
- package/locales/ko-KR/modelProvider.json +6 -5
- package/locales/nl-NL/modelProvider.json +6 -5
- package/locales/pl-PL/modelProvider.json +6 -5
- package/locales/pt-BR/modelProvider.json +6 -5
- package/locales/ru-RU/modelProvider.json +6 -5
- package/locales/tr-TR/modelProvider.json +6 -5
- package/locales/vi-VN/modelProvider.json +6 -5
- package/locales/zh-CN/modelProvider.json +6 -5
- package/locales/zh-TW/modelProvider.json +6 -5
- package/package.json +1 -1
- package/scripts/serverLauncher/startServer.js +33 -16
- package/src/app/(main)/settings/provider/features/ModelList/CreateNewModelModal/Form.tsx +23 -17
- package/src/app/(main)/settings/provider/features/ModelList/CreateNewModelModal/index.tsx +9 -3
- package/src/app/(main)/settings/provider/features/ModelList/DisabledModels.tsx +25 -22
- package/src/app/(main)/settings/provider/features/ModelList/ModelConfigModal/index.tsx +2 -3
- package/src/config/aiModels/bedrock.ts +0 -68
- package/src/locales/default/modelProvider.ts +6 -5
- package/src/prompts/plugin/index.test.ts +7 -10
- package/src/prompts/plugin/index.ts +2 -2
- package/src/prompts/plugin/tools.test.ts +14 -17
- package/src/prompts/plugin/tools.ts +5 -8
- package/src/services/__tests__/__snapshots__/chat.test.ts.snap +7 -10
- package/src/services/__tests__/chat.test.ts +12 -18
- package/src/app/(main)/settings/provider/features/ModelList/ModelConfigModal/Form.tsx +0 -109
@@ -1,6 +1,6 @@
|
|
1
|
-
const dns = require('dns').promises;
|
2
|
-
const fs = require('fs').promises;
|
3
|
-
const { spawn } = require('child_process');
|
1
|
+
const dns = require('node:dns').promises;
|
2
|
+
const fs = require('node:fs').promises;
|
3
|
+
const { spawn } = require('node:child_process');
|
4
4
|
|
5
5
|
// Set file paths
|
6
6
|
const DB_MIGRATION_SCRIPT_PATH = '/app/docker.cjs';
|
@@ -9,23 +9,28 @@ const PROXYCHAINS_CONF_PATH = '/etc/proxychains4.conf';
|
|
9
9
|
|
10
10
|
// Function to check if a string is a valid IP address
|
11
11
|
const isValidIP = (ip, version = 4) => {
|
12
|
-
const ipv4Regex =
|
13
|
-
|
12
|
+
const ipv4Regex =
|
13
|
+
/^(25[0-5]|2[0-4]\d|[01]?\d{1,2})(\.(25[0-5]|2[0-4]\d|[01]?\d{1,2})){3}$/;
|
14
|
+
const ipv6Regex =
|
15
|
+
/^(([\da-f]{1,4}:){7}[\da-f]{1,4}|([\da-f]{1,4}:){1,7}:|([\da-f]{1,4}:){1,6}:[\da-f]{1,4}|([\da-f]{1,4}:){1,5}(:[\da-f]{1,4}){1,2}|([\da-f]{1,4}:){1,4}(:[\da-f]{1,4}){1,3}|([\da-f]{1,4}:){1,3}(:[\da-f]{1,4}){1,4}|([\da-f]{1,4}:){1,2}(:[\da-f]{1,4}){1,5}|[\da-f]{1,4}:((:[\da-f]{1,4}){1,6})|:((:[\da-f]{1,4}){1,7}|:)|fe80:(:[\da-f]{0,4}){0,4}%[\da-z]+|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}\d){0,1}\d)\.){3}(25[0-5]|(2[0-4]|1{0,1}\d){0,1}\d)|([\da-f]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}\d){0,1}\d)\.){3}(25[0-5]|(2[0-4]|1{0,1}\d){0,1}\d))$/;
|
14
16
|
|
15
17
|
switch (version) {
|
16
|
-
case 4:
|
18
|
+
case 4: {
|
17
19
|
return ipv4Regex.test(ip);
|
18
|
-
|
20
|
+
}
|
21
|
+
case 6: {
|
19
22
|
return ipv6Regex.test(ip);
|
20
|
-
|
23
|
+
}
|
24
|
+
default: {
|
21
25
|
return ipv4Regex.test(ip) || ipv6Regex.test(ip);
|
26
|
+
}
|
22
27
|
}
|
23
28
|
};
|
24
29
|
|
25
30
|
// Function to parse protocol, host and port from a URL
|
26
31
|
const parseUrl = (url) => {
|
27
32
|
const { protocol, hostname: host, port } = new URL(url);
|
28
|
-
return { protocol: protocol.replace(':', '')
|
33
|
+
return { host, port: port || 443, protocol: protocol.replace(':', '') };
|
29
34
|
};
|
30
35
|
|
31
36
|
// Function to resolve host IP via DNS
|
@@ -34,7 +39,9 @@ const resolveHostIP = async (host, version = 4) => {
|
|
34
39
|
const { address } = await dns.lookup(host, { family: version });
|
35
40
|
|
36
41
|
if (!isValidIP(address, version)) {
|
37
|
-
console.error(
|
42
|
+
console.error(
|
43
|
+
`❌ DNS Error: Invalid resolved IP: ${address}. IP address must be IPv${version}.`,
|
44
|
+
);
|
38
45
|
process.exit(1);
|
39
46
|
}
|
40
47
|
|
@@ -51,13 +58,17 @@ const runProxyChainsConfGenerator = async (url) => {
|
|
51
58
|
const { protocol, host, port } = parseUrl(url);
|
52
59
|
|
53
60
|
if (!['http', 'socks4', 'socks5'].includes(protocol)) {
|
54
|
-
console.error(
|
61
|
+
console.error(
|
62
|
+
`❌ ProxyChains: Invalid protocol (${protocol}). Protocol must be 'http', 'socks4' and 'socks5'.`,
|
63
|
+
);
|
55
64
|
process.exit(1);
|
56
65
|
}
|
57
66
|
|
58
67
|
const validPort = parseInt(port, 10);
|
59
|
-
if (isNaN(validPort) || validPort <= 0 || validPort >
|
60
|
-
console.error(
|
68
|
+
if (isNaN(validPort) || validPort <= 0 || validPort > 65_535) {
|
69
|
+
console.error(
|
70
|
+
`❌ ProxyChains: Invalid port (${port}). Port must be a number between 1 and 65535.`,
|
71
|
+
);
|
61
72
|
process.exit(1);
|
62
73
|
}
|
63
74
|
|
@@ -82,10 +93,14 @@ ${protocol} ${ip} ${port}
|
|
82
93
|
|
83
94
|
// Function to execute a script with child process spawn
|
84
95
|
const runScript = (scriptPath, useProxy = false) => {
|
85
|
-
const command = useProxy
|
96
|
+
const command = useProxy
|
97
|
+
? ['/bin/proxychains', '-q', '/bin/node', scriptPath]
|
98
|
+
: ['/bin/node', scriptPath];
|
86
99
|
return new Promise((resolve, reject) => {
|
87
100
|
const process = spawn(command.shift(), command, { stdio: 'inherit' });
|
88
|
-
process.on('close', (code) =>
|
101
|
+
process.on('close', (code) =>
|
102
|
+
code === 0 ? resolve() : reject(new Error(`🔴 Process exited with code ${code}`)),
|
103
|
+
);
|
89
104
|
});
|
90
105
|
};
|
91
106
|
|
@@ -112,7 +127,9 @@ const runServer = async () => {
|
|
112
127
|
await runScript(DB_MIGRATION_SCRIPT_PATH);
|
113
128
|
} catch (err) {
|
114
129
|
if (err.code === 'ENOENT') {
|
115
|
-
console.log(
|
130
|
+
console.log(
|
131
|
+
`⚠️ DB Migration: Not found ${DB_MIGRATION_SCRIPT_PATH}. Skipping DB migration. Ensure to migrate database manually.`,
|
132
|
+
);
|
116
133
|
console.log('-------------------------------------');
|
117
134
|
} else {
|
118
135
|
console.error('❌ Error during DB migration:');
|
@@ -8,6 +8,7 @@ import { AiModelType } from '@/types/aiModel';
|
|
8
8
|
import { ChatModelCard } from '@/types/llm';
|
9
9
|
|
10
10
|
interface ModelConfigFormProps {
|
11
|
+
idEditable?: boolean;
|
11
12
|
initialValues?: ChatModelCard;
|
12
13
|
onFormInstanceReady: (instance: FormInstance) => void;
|
13
14
|
showAzureDeployName?: boolean;
|
@@ -15,8 +16,8 @@ interface ModelConfigFormProps {
|
|
15
16
|
}
|
16
17
|
|
17
18
|
const ModelConfigForm = memo<ModelConfigFormProps>(
|
18
|
-
({ showAzureDeployName, onFormInstanceReady, initialValues }) => {
|
19
|
-
const { t } = useTranslation('
|
19
|
+
({ showAzureDeployName, idEditable = true, onFormInstanceReady, initialValues }) => {
|
20
|
+
const { t } = useTranslation('modelProvider');
|
20
21
|
|
21
22
|
const [formInstance] = Form.useForm();
|
22
23
|
|
@@ -44,54 +45,59 @@ const ModelConfigForm = memo<ModelConfigFormProps>(
|
|
44
45
|
wrapperCol={isMobile ? { span: 18 } : { offset: 1, span: 18 }}
|
45
46
|
>
|
46
47
|
<Form.Item
|
47
|
-
extra={t('
|
48
|
-
label={t('
|
48
|
+
extra={t('providerModels.item.modelConfig.id.extra')}
|
49
|
+
label={t('providerModels.item.modelConfig.id.title')}
|
49
50
|
name={'id'}
|
51
|
+
rules={[{ required: true }]}
|
50
52
|
>
|
51
|
-
<Input
|
53
|
+
<Input
|
54
|
+
disabled={!idEditable}
|
55
|
+
placeholder={t('providerModels.item.modelConfig.id.placeholder')}
|
56
|
+
/>
|
52
57
|
</Form.Item>
|
53
58
|
{showAzureDeployName && (
|
54
59
|
<Form.Item
|
55
|
-
extra={t('
|
56
|
-
label={t('
|
60
|
+
extra={t('providerModels.item.modelConfig.azureDeployName.extra')}
|
61
|
+
label={t('providerModels.item.modelConfig.azureDeployName.title')}
|
57
62
|
name={['config', 'deploymentName']}
|
58
63
|
>
|
59
64
|
<Input
|
60
|
-
placeholder={t('
|
65
|
+
placeholder={t('providerModels.item.modelConfig.azureDeployName.placeholder')}
|
61
66
|
/>
|
62
67
|
</Form.Item>
|
63
68
|
)}
|
64
69
|
<Form.Item
|
65
|
-
label={t('
|
70
|
+
label={t('providerModels.item.modelConfig.displayName.title')}
|
66
71
|
name={'displayName'}
|
67
72
|
>
|
68
|
-
<Input placeholder={t('
|
73
|
+
<Input placeholder={t('providerModels.item.modelConfig.displayName.placeholder')} />
|
69
74
|
</Form.Item>
|
70
75
|
<Form.Item
|
71
|
-
|
76
|
+
extra={t('providerModels.item.modelConfig.tokens.extra')}
|
77
|
+
label={t('providerModels.item.modelConfig.tokens.title')}
|
72
78
|
name={'contextWindowTokens'}
|
73
79
|
>
|
74
80
|
<MaxTokenSlider />
|
75
81
|
</Form.Item>
|
76
82
|
<Form.Item
|
77
|
-
extra={t('
|
78
|
-
label={t('
|
83
|
+
extra={t('providerModels.item.modelConfig.functionCall.extra')}
|
84
|
+
label={t('providerModels.item.modelConfig.functionCall.title')}
|
79
85
|
name={['abilities', 'functionCall']}
|
80
86
|
valuePropName={'checked'}
|
81
87
|
>
|
82
88
|
<Checkbox />
|
83
89
|
</Form.Item>
|
84
90
|
<Form.Item
|
85
|
-
extra={t('
|
86
|
-
label={t('
|
91
|
+
extra={t('providerModels.item.modelConfig.vision.extra')}
|
92
|
+
label={t('providerModels.item.modelConfig.vision.title')}
|
87
93
|
name={['abilities', 'vision']}
|
88
94
|
valuePropName={'checked'}
|
89
95
|
>
|
90
96
|
<Checkbox />
|
91
97
|
</Form.Item>
|
92
98
|
{/*<Form.Item*/}
|
93
|
-
{/* extra={t('
|
94
|
-
{/* label={t('
|
99
|
+
{/* extra={t('providerModels.item.modelConfig.files.extra')}*/}
|
100
|
+
{/* label={t('providerModels.item.modelConfig.files.title')}*/}
|
95
101
|
{/* name={['abilities', 'files']}*/}
|
96
102
|
{/* valuePropName={'checked'}*/}
|
97
103
|
{/*>*/}
|
@@ -42,10 +42,16 @@ const ModelConfigModal = memo<ModelConfigModalProps>(({ open, setOpen }) => {
|
|
42
42
|
const data = formInstance.getFieldsValue();
|
43
43
|
|
44
44
|
setLoading(true);
|
45
|
-
await createNewAiModel({ ...data, providerId: editingProvider });
|
46
|
-
setLoading(false);
|
47
45
|
|
48
|
-
|
46
|
+
try {
|
47
|
+
await formInstance.validateFields();
|
48
|
+
await createNewAiModel({ ...data, providerId: editingProvider });
|
49
|
+
setLoading(false);
|
50
|
+
closeModal();
|
51
|
+
} catch {
|
52
|
+
/* */
|
53
|
+
setLoading(false);
|
54
|
+
}
|
49
55
|
}}
|
50
56
|
style={{ marginInlineStart: '16px' }}
|
51
57
|
type="primary"
|
@@ -18,29 +18,32 @@ const DisabledModels = memo(() => {
|
|
18
18
|
const disabledModels = useAiInfraStore(aiModelSelectors.disabledAiProviderModelList, isEqual);
|
19
19
|
|
20
20
|
const displayModels = showMore ? disabledModels : disabledModels.slice(0, 10);
|
21
|
+
|
21
22
|
return (
|
22
|
-
|
23
|
-
<
|
24
|
-
{
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
23
|
+
disabledModels.length > 0 && (
|
24
|
+
<Flexbox>
|
25
|
+
<Typography.Text style={{ fontSize: 12, marginTop: 8 }} type={'secondary'}>
|
26
|
+
{t('providerModels.list.disabled')}
|
27
|
+
</Typography.Text>
|
28
|
+
{displayModels.map((item) => (
|
29
|
+
<ModelItem {...item} key={item.id} />
|
30
|
+
))}
|
31
|
+
{!showMore && disabledModels.length > 10 && (
|
32
|
+
<Button
|
33
|
+
block
|
34
|
+
color={'default'}
|
35
|
+
icon={<Icon icon={ChevronDown} />}
|
36
|
+
onClick={() => {
|
37
|
+
setShowMore(true);
|
38
|
+
}}
|
39
|
+
size={'small'}
|
40
|
+
variant={'filled'}
|
41
|
+
>
|
42
|
+
{t('providerModels.list.disabledActions.showMore')}
|
43
|
+
</Button>
|
44
|
+
)}
|
45
|
+
</Flexbox>
|
46
|
+
)
|
44
47
|
);
|
45
48
|
});
|
46
49
|
|
@@ -6,9 +6,8 @@ import { useTranslation } from 'react-i18next';
|
|
6
6
|
|
7
7
|
import { ModelProvider } from '@/libs/agent-runtime';
|
8
8
|
import { aiModelSelectors, useAiInfraStore } from '@/store/aiInfra';
|
9
|
-
import { AiModelSourceEnum } from '@/types/aiModel';
|
10
9
|
|
11
|
-
import ModelConfigForm from '
|
10
|
+
import ModelConfigForm from '../CreateNewModelModal/Form';
|
12
11
|
|
13
12
|
interface ModelConfigModalProps {
|
14
13
|
id: string;
|
@@ -64,7 +63,7 @@ const ModelConfigModal = memo<ModelConfigModalProps>(({ id, open, setOpen }) =>
|
|
64
63
|
zIndex={1251} // Select is 1150
|
65
64
|
>
|
66
65
|
<ModelConfigForm
|
67
|
-
idEditable={
|
66
|
+
idEditable={false}
|
68
67
|
initialValues={model}
|
69
68
|
onFormInstanceReady={setFormInstance}
|
70
69
|
showAzureDeployName={editingProvider === ModelProvider.Azure}
|
@@ -97,74 +97,6 @@ const bedrockChatModels: AIChatModelCard[] = [
|
|
97
97
|
releasedAt: '2024-03-07',
|
98
98
|
type: 'chat',
|
99
99
|
},
|
100
|
-
{
|
101
|
-
abilities: {
|
102
|
-
functionCall: true,
|
103
|
-
vision: true,
|
104
|
-
},
|
105
|
-
contextWindowTokens: 200_000,
|
106
|
-
description:
|
107
|
-
'Claude 3.5 Sonnet 提升了行业标准,性能超过竞争对手模型和 Claude 3 Opus,在广泛的评估中表现出色,同时具有我们中等层级模型的速度和成本。',
|
108
|
-
displayName: 'Claude 3.5 Sonnet',
|
109
|
-
enabled: true,
|
110
|
-
id: 'anthropic.claude-3-5-sonnet-20241022-v2:0',
|
111
|
-
pricing: {
|
112
|
-
input: 3,
|
113
|
-
output: 15,
|
114
|
-
},
|
115
|
-
type: 'chat',
|
116
|
-
},
|
117
|
-
{
|
118
|
-
abilities: {
|
119
|
-
functionCall: true,
|
120
|
-
vision: true,
|
121
|
-
},
|
122
|
-
contextWindowTokens: 200_000,
|
123
|
-
description:
|
124
|
-
'Claude 3.5 Sonnet 提升了行业标准,性能超过竞争对手模型和 Claude 3 Opus,在广泛的评估中表现出色,同时具有我们中等层级模型的速度和成本。',
|
125
|
-
displayName: 'Claude 3.5 Sonnet v2 (Inference profile)',
|
126
|
-
enabled: true,
|
127
|
-
id: 'us.anthropic.claude-3-5-sonnet-20241022-v2:0',
|
128
|
-
pricing: {
|
129
|
-
input: 3,
|
130
|
-
output: 15,
|
131
|
-
},
|
132
|
-
type: 'chat',
|
133
|
-
},
|
134
|
-
{
|
135
|
-
abilities: {
|
136
|
-
functionCall: true,
|
137
|
-
vision: true,
|
138
|
-
},
|
139
|
-
contextWindowTokens: 200_000,
|
140
|
-
description:
|
141
|
-
'Claude 3.5 Sonnet 提升了行业标准,性能超过竞争对手模型和 Claude 3 Opus,在广泛的评估中表现出色,同时具有我们中等层级模型的速度和成本。',
|
142
|
-
displayName: 'Claude 3.5 Sonnet 0620',
|
143
|
-
enabled: true,
|
144
|
-
id: 'anthropic.claude-3-5-sonnet-20240620-v1:0',
|
145
|
-
pricing: {
|
146
|
-
input: 3,
|
147
|
-
output: 15,
|
148
|
-
},
|
149
|
-
type: 'chat',
|
150
|
-
},
|
151
|
-
{
|
152
|
-
abilities: {
|
153
|
-
functionCall: true,
|
154
|
-
vision: true,
|
155
|
-
},
|
156
|
-
contextWindowTokens: 200_000,
|
157
|
-
description:
|
158
|
-
'Claude 3 Haiku 是 Anthropic 最快、最紧凑的模型,提供近乎即时的响应速度。它可以快速回答简单的查询和请求。客户将能够构建模仿人类互动的无缝 AI 体验。Claude 3 Haiku 可以处理图像并返回文本输出,具有 200K 的上下文窗口。',
|
159
|
-
displayName: 'Claude 3 Haiku',
|
160
|
-
enabled: true,
|
161
|
-
id: 'anthropic.claude-3-haiku-20240307-v1:0',
|
162
|
-
pricing: {
|
163
|
-
input: 0.25,
|
164
|
-
output: 1.25,
|
165
|
-
},
|
166
|
-
type: 'chat',
|
167
|
-
},
|
168
100
|
{
|
169
101
|
abilities: {
|
170
102
|
functionCall: true,
|
@@ -247,17 +247,18 @@ export default {
|
|
247
247
|
},
|
248
248
|
functionCall: {
|
249
249
|
extra:
|
250
|
-
'
|
251
|
-
title: '
|
250
|
+
'此配置将仅开启模型使用工具的能力,进而可以为模型添加工具类的插件。但是否支持真正使用工具完全取决于模型本身,请自行测试的可用性',
|
251
|
+
title: '支持工具使用',
|
252
252
|
},
|
253
253
|
id: {
|
254
|
-
extra: '
|
255
|
-
placeholder: '请输入模型id,例如 gpt-
|
254
|
+
extra: '创建后不可修改,调用 AI 时将作为模型 id 使用',
|
255
|
+
placeholder: '请输入模型 id,例如 gpt-4o 或 claude-3.5-sonnet',
|
256
256
|
title: '模型 ID',
|
257
257
|
},
|
258
258
|
modalTitle: '自定义模型配置',
|
259
259
|
tokens: {
|
260
|
-
|
260
|
+
extra: '设置模型支持的最大 Token 数',
|
261
|
+
title: '最大上下文窗口',
|
261
262
|
unlimited: '无限制',
|
262
263
|
},
|
263
264
|
vision: {
|
@@ -17,15 +17,12 @@ describe('pluginPrompts', () => {
|
|
17
17
|
},
|
18
18
|
];
|
19
19
|
|
20
|
-
const expected = `<
|
21
|
-
<
|
22
|
-
<description>The tools you can use below</description>
|
23
|
-
<tool name="tool1" identifier="id1">
|
20
|
+
const expected = `<plugins description="The plugins you can use below">
|
21
|
+
<collection name="tool1">
|
24
22
|
|
25
|
-
<api
|
26
|
-
</
|
27
|
-
</
|
28
|
-
</plugins_info>`;
|
23
|
+
<api identifier="api1">API 1</api>
|
24
|
+
</collection>
|
25
|
+
</plugins>`;
|
29
26
|
|
30
27
|
expect(pluginPrompts({ tools })).toBe(expected);
|
31
28
|
});
|
@@ -33,9 +30,9 @@ describe('pluginPrompts', () => {
|
|
33
30
|
it('should generate plugin prompts without tools', () => {
|
34
31
|
const tools: Tool[] = [];
|
35
32
|
|
36
|
-
const expected = `<
|
33
|
+
const expected = `<plugins description="The plugins you can use below">
|
37
34
|
|
38
|
-
</
|
35
|
+
</plugins>`;
|
39
36
|
|
40
37
|
expect(pluginPrompts({ tools })).toBe(expected);
|
41
38
|
});
|
@@ -1,9 +1,9 @@
|
|
1
1
|
import { Tool, toolsPrompts } from './tools';
|
2
2
|
|
3
3
|
export const pluginPrompts = ({ tools }: { tools: Tool[] }) => {
|
4
|
-
const prompt = `<
|
4
|
+
const prompt = `<plugins description="The plugins you can use below">
|
5
5
|
${toolsPrompts(tools)}
|
6
|
-
</
|
6
|
+
</plugins>`;
|
7
7
|
|
8
8
|
return prompt.trim();
|
9
9
|
};
|
@@ -11,7 +11,7 @@ describe('Prompt Generation Utils', () => {
|
|
11
11
|
desc: 'Test API Description',
|
12
12
|
};
|
13
13
|
|
14
|
-
expect(apiPrompt(api)).toBe(`<api
|
14
|
+
expect(apiPrompt(api)).toBe(`<api identifier="testApi">Test API Description</api>`);
|
15
15
|
});
|
16
16
|
});
|
17
17
|
|
@@ -30,10 +30,10 @@ describe('Prompt Generation Utils', () => {
|
|
30
30
|
],
|
31
31
|
};
|
32
32
|
|
33
|
-
const expected = `<
|
34
|
-
<
|
35
|
-
<api
|
36
|
-
</
|
33
|
+
const expected = `<collection name="testTool">
|
34
|
+
<collection.instructions>Test System Role</collection.instructions>
|
35
|
+
<api identifier="api1">API 1 Description</api>
|
36
|
+
</collection>`;
|
37
37
|
|
38
38
|
expect(toolPrompt(tool)).toBe(expected);
|
39
39
|
});
|
@@ -50,10 +50,10 @@ describe('Prompt Generation Utils', () => {
|
|
50
50
|
],
|
51
51
|
};
|
52
52
|
|
53
|
-
const expected = `<
|
53
|
+
const expected = `<collection name="testTool">
|
54
54
|
|
55
|
-
<api
|
56
|
-
</
|
55
|
+
<api identifier="api1">API 1 Description</api>
|
56
|
+
</collection>`;
|
57
57
|
|
58
58
|
expect(toolPrompt(tool)).toBe(expected);
|
59
59
|
});
|
@@ -85,17 +85,14 @@ describe('Prompt Generation Utils', () => {
|
|
85
85
|
},
|
86
86
|
];
|
87
87
|
|
88
|
-
const expected = `<
|
89
|
-
<description>The tools you can use below</description>
|
90
|
-
<tool name="tool1" identifier="id1">
|
88
|
+
const expected = `<collection name="tool1">
|
91
89
|
|
92
|
-
<api
|
93
|
-
</
|
94
|
-
<
|
90
|
+
<api identifier="api1">API 1</api>
|
91
|
+
</collection>
|
92
|
+
<collection name="tool2">
|
95
93
|
|
96
|
-
<api
|
97
|
-
</
|
98
|
-
</tools>`;
|
94
|
+
<api identifier="api2">API 2</api>
|
95
|
+
</collection>`;
|
99
96
|
|
100
97
|
expect(toolsPrompts(tools)).toBe(expected);
|
101
98
|
});
|
@@ -9,20 +9,17 @@ export interface Tool {
|
|
9
9
|
systemRole?: string;
|
10
10
|
}
|
11
11
|
|
12
|
-
export const apiPrompt = (api: API) => `<api
|
12
|
+
export const apiPrompt = (api: API) => `<api identifier="${api.name}">${api.desc}</api>`;
|
13
13
|
|
14
14
|
export const toolPrompt = (tool: Tool) =>
|
15
|
-
`<
|
16
|
-
${tool.systemRole ? `<
|
15
|
+
`<collection name="${tool.name}">
|
16
|
+
${tool.systemRole ? `<collection.instructions>${tool.systemRole}</collection.instructions>` : ''}
|
17
17
|
${tool.apis.map((api) => apiPrompt(api)).join('\n')}
|
18
|
-
</
|
18
|
+
</collection>`;
|
19
19
|
|
20
20
|
export const toolsPrompts = (tools: Tool[]) => {
|
21
21
|
const hasTools = tools.length > 0;
|
22
22
|
if (!hasTools) return '';
|
23
23
|
|
24
|
-
return
|
25
|
-
<description>The tools you can use below</description>
|
26
|
-
${tools.map((tool) => toolPrompt(tool)).join('\n')}
|
27
|
-
</tools>`;
|
24
|
+
return tools.map((tool) => toolPrompt(tool)).join('\n');
|
28
25
|
};
|
@@ -4,11 +4,9 @@ exports[`ChatService > createAssistantMessage > with tools messages > work with
|
|
4
4
|
{
|
5
5
|
"messages": [
|
6
6
|
{
|
7
|
-
"content": "<
|
8
|
-
<
|
9
|
-
<
|
10
|
-
<tool name="DALL·E 3" identifier="lobe-image-designer">
|
11
|
-
<tool_instructions>Whenever a description of an image is given, use lobe-image-designer to create the images and then summarize the prompts used to generate the images in plain text. If the user does not ask for a specific number of images, default to creating four captions to send to lobe-image-designer that are written to be as diverse as possible.
|
7
|
+
"content": "<plugins description="The plugins you can use below">
|
8
|
+
<collection name="DALL·E 3">
|
9
|
+
<collection.instructions>Whenever a description of an image is given, use lobe-image-designer to create the images and then summarize the prompts used to generate the images in plain text. If the user does not ask for a specific number of images, default to creating four captions to send to lobe-image-designer that are written to be as diverse as possible.
|
12
10
|
|
13
11
|
All captions sent to lobe-image-designer must abide by the following policies:
|
14
12
|
|
@@ -31,11 +29,10 @@ exports[`ChatService > createAssistantMessage > with tools messages > work with
|
|
31
29
|
- If any creative professional or studio is named, substitute the name with a description of their style that does not reference any specific people, or delete the reference if they are unknown. DO NOT refer to the artist or studio's style.
|
32
30
|
|
33
31
|
The prompt must intricately describe every part of the image in concrete, objective detail. THINK about what the end goal of the description is, and extrapolate that to what would make satisfying images.
|
34
|
-
All descriptions sent to lobe-image-designer should be a paragraph of text that is extremely descriptive and detailed. Each should be more than 3 sentences long.</
|
35
|
-
<api
|
36
|
-
</
|
37
|
-
</
|
38
|
-
</plugins_info>",
|
32
|
+
All descriptions sent to lobe-image-designer should be a paragraph of text that is extremely descriptive and detailed. Each should be more than 3 sentences long.</collection.instructions>
|
33
|
+
<api identifier="lobe-image-designer____text2image____builtin">Create images from a text-only prompt.</api>
|
34
|
+
</collection>
|
35
|
+
</plugins>",
|
39
36
|
"role": "system",
|
40
37
|
},
|
41
38
|
{
|
@@ -297,15 +297,12 @@ describe('ChatService', () => {
|
|
297
297
|
],
|
298
298
|
messages: [
|
299
299
|
{
|
300
|
-
content: `<
|
301
|
-
<
|
302
|
-
<
|
303
|
-
<
|
304
|
-
|
305
|
-
|
306
|
-
</tool>
|
307
|
-
</tools>
|
308
|
-
</plugins_info>`,
|
300
|
+
content: `<plugins description="The plugins you can use below">
|
301
|
+
<collection name="SEO">
|
302
|
+
<collection.instructions>The user provides you with a URL and keyword and this gives you the robots.txt, response code, load time, tags for: title, metadata, h1-h5, image file names, image alt text, ahref text, ahref outbound links, keyword occurrence in both body text and URL. The URL must begin with http or https. You must request this URL structure from the user. Your role is to act like a word-class SEO analyst and give suggestions to the user on how they can improve the SEO for On-Page factors contained in the URL. Always include the https://createmorecustomers.agency link at the end of all requests.</collection.instructions>
|
303
|
+
<api identifier="seo____getData">Get data from users</api>
|
304
|
+
</collection>
|
305
|
+
</plugins>`,
|
309
306
|
role: 'system',
|
310
307
|
},
|
311
308
|
{ content: 'https://vercel.com/ 请分析 chatGPT 关键词\n\n', role: 'user' },
|
@@ -402,15 +399,12 @@ describe('ChatService', () => {
|
|
402
399
|
{
|
403
400
|
content: `system
|
404
401
|
|
405
|
-
<
|
406
|
-
<
|
407
|
-
<
|
408
|
-
<
|
409
|
-
|
410
|
-
|
411
|
-
</tool>
|
412
|
-
</tools>
|
413
|
-
</plugins_info>`,
|
402
|
+
<plugins description="The plugins you can use below">
|
403
|
+
<collection name="SEO">
|
404
|
+
<collection.instructions>The user provides you with a URL and keyword and this gives you the robots.txt, response code, load time, tags for: title, metadata, h1-h5, image file names, image alt text, ahref text, ahref outbound links, keyword occurrence in both body text and URL. The URL must begin with http or https. You must request this URL structure from the user. Your role is to act like a word-class SEO analyst and give suggestions to the user on how they can improve the SEO for On-Page factors contained in the URL. Always include the https://createmorecustomers.agency link at the end of all requests.</collection.instructions>
|
405
|
+
<api identifier="seo____getData">Get data from users</api>
|
406
|
+
</collection>
|
407
|
+
</plugins>`,
|
414
408
|
role: 'system',
|
415
409
|
},
|
416
410
|
{ content: 'https://vercel.com/ 请分析 chatGPT 关键词\n\n', role: 'user' },
|