@lobehub/chat 1.134.3 → 1.134.5
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/.github/workflows/docker-database.yml +2 -0
- package/.github/workflows/docker-pglite.yml +2 -0
- package/.github/workflows/docker.yml +2 -0
- package/.github/workflows/release.yml +6 -0
- package/.github/workflows/sync-database-schema.yml +2 -0
- package/CHANGELOG.md +50 -0
- package/changelog/v1.json +14 -0
- package/docs/development/database-schema.dbml +27 -0
- package/package.json +3 -2
- package/packages/database/migrations/0036_add_group_messages.sql +21 -0
- package/packages/database/migrations/meta/0036_snapshot.json +6772 -0
- package/packages/database/migrations/meta/_journal.json +7 -0
- package/packages/database/package.json +1 -1
- package/packages/database/src/core/migrations.json +15 -0
- package/packages/database/src/models/__tests__/aiModel.test.ts +43 -0
- package/packages/database/src/models/aiModel.ts +25 -1
- package/packages/database/src/repositories/tableViewer/index.test.ts +1 -1
- package/packages/database/src/schemas/_helpers.ts +3 -1
- package/packages/database/src/schemas/message.ts +55 -4
- package/packages/database/src/schemas/relations.ts +24 -1
- package/packages/database/src/utils/idGenerator.ts +1 -0
- package/packages/prompts/CLAUDE.md +329 -0
- package/packages/prompts/README.md +224 -0
- package/packages/prompts/package.json +14 -1
- package/packages/prompts/promptfoo/emoji-picker/eval.yaml +170 -0
- package/packages/prompts/promptfoo/emoji-picker/prompt.ts +16 -0
- package/packages/prompts/promptfoo/knowledge-qa/eval.yaml +89 -0
- package/packages/prompts/promptfoo/knowledge-qa/prompt.ts +26 -0
- package/packages/prompts/promptfoo/language-detection/eval.yaml +65 -0
- package/packages/prompts/promptfoo/language-detection/prompt.ts +16 -0
- package/packages/prompts/promptfoo/summary-title/eval.yaml +85 -0
- package/packages/prompts/promptfoo/summary-title/prompt.ts +18 -0
- package/packages/prompts/promptfoo/translate/eval.yaml +79 -0
- package/packages/prompts/promptfoo/translate/prompt.ts +18 -0
- package/packages/prompts/promptfooconfig.yaml +35 -0
- package/packages/prompts/src/chains/__tests__/__snapshots__/answerWithContext.test.ts.snap +164 -0
- package/packages/prompts/src/chains/__tests__/__snapshots__/pickEmoji.test.ts.snap +58 -0
- package/packages/prompts/src/chains/__tests__/__snapshots__/summaryTitle.test.ts.snap +26 -0
- package/packages/prompts/src/chains/__tests__/__snapshots__/translate.test.ts.snap +22 -0
- package/packages/prompts/src/chains/__tests__/answerWithContext.test.ts +18 -63
- package/packages/prompts/src/chains/__tests__/pickEmoji.test.ts +2 -37
- package/packages/prompts/src/chains/__tests__/summaryTitle.test.ts +2 -16
- package/packages/prompts/src/chains/__tests__/translate.test.ts +1 -12
- package/packages/prompts/src/chains/answerWithContext.ts +45 -21
- package/packages/prompts/src/chains/pickEmoji.ts +20 -6
- package/packages/prompts/src/chains/summaryTitle.ts +20 -15
- package/packages/prompts/src/chains/translate.ts +8 -2
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
description: Test summary title generation for different conversation types
|
|
2
|
+
|
|
3
|
+
providers:
|
|
4
|
+
- openai:chat:gpt-5-mini
|
|
5
|
+
- openai:chat:claude-3-5-haiku-latest
|
|
6
|
+
- openai:chat:gemini-flash-latest
|
|
7
|
+
- openai:chat:deepseek-chat
|
|
8
|
+
|
|
9
|
+
prompts:
|
|
10
|
+
- file://promptfoo/summary-title/prompt.ts
|
|
11
|
+
|
|
12
|
+
tests:
|
|
13
|
+
- vars:
|
|
14
|
+
messages:
|
|
15
|
+
- role: "user"
|
|
16
|
+
content: "How do I install Node.js on my computer?"
|
|
17
|
+
- role: "assistant"
|
|
18
|
+
content: "To install Node.js, you can download it from the official website nodejs.org and follow the installation instructions for your operating system."
|
|
19
|
+
- role: "user"
|
|
20
|
+
content: "What about using a version manager?"
|
|
21
|
+
- role: "assistant"
|
|
22
|
+
content: "Yes! I recommend using nvm (Node Version Manager) which allows you to install and switch between different Node.js versions easily."
|
|
23
|
+
locale: "en-US"
|
|
24
|
+
assert:
|
|
25
|
+
- type: llm-rubric
|
|
26
|
+
provider: openai:gpt-5-mini
|
|
27
|
+
value: "The response should be a concise title (10 words or less) that summarizes the conversation about Node.js installation"
|
|
28
|
+
- type: regex
|
|
29
|
+
value: "^.{1,50}$" # Title should be between 1-50 characters
|
|
30
|
+
- type: not-contains
|
|
31
|
+
value: "标点符号" # Should not contain punctuation as requested in Chinese
|
|
32
|
+
|
|
33
|
+
- vars:
|
|
34
|
+
messages:
|
|
35
|
+
- role: "user"
|
|
36
|
+
content: "我想学习做蛋炒饭"
|
|
37
|
+
- role: "assistant"
|
|
38
|
+
content: "蛋炒饭是很经典的家常菜!你需要准备鸡蛋、米饭、葱花、盐和生抽等基本材料。"
|
|
39
|
+
- role: "user"
|
|
40
|
+
content: "具体步骤是什么?"
|
|
41
|
+
- role: "assistant"
|
|
42
|
+
content: "首先打散鸡蛋炒熟盛起,然后下米饭炒散,最后加入鸡蛋和调料炒匀即可。"
|
|
43
|
+
locale: "zh-CN"
|
|
44
|
+
assert:
|
|
45
|
+
- type: llm-rubric
|
|
46
|
+
provider: openai:gpt-5-mini
|
|
47
|
+
value: "The response should be a Chinese title summarizing the conversation about fried rice cooking"
|
|
48
|
+
- type: regex
|
|
49
|
+
value: "^.{1,30}$" # Chinese titles can be shorter
|
|
50
|
+
- type: contains-any
|
|
51
|
+
value: ["蛋炒饭", "做饭", "烹饪", "料理"]
|
|
52
|
+
|
|
53
|
+
- vars:
|
|
54
|
+
messages:
|
|
55
|
+
- role: "user"
|
|
56
|
+
content: "Can you help me debug this Python error?"
|
|
57
|
+
- role: "assistant"
|
|
58
|
+
content: "Of course! Please share the error message and the relevant code."
|
|
59
|
+
- role: "user"
|
|
60
|
+
content: "I'm getting 'AttributeError: 'NoneType' object has no attribute 'split''"
|
|
61
|
+
- role: "assistant"
|
|
62
|
+
content: "This error occurs when you're trying to call .split() on a None value. The variable is likely None instead of a string."
|
|
63
|
+
locale: "en-US"
|
|
64
|
+
assert:
|
|
65
|
+
- type: llm-rubric
|
|
66
|
+
provider: openai:gpt-5-mini
|
|
67
|
+
|
|
68
|
+
value: "The response should be a title about Python debugging or error resolution"
|
|
69
|
+
- type: contains-any
|
|
70
|
+
value: ["Python", "debug", "error", "AttributeError", "code"]
|
|
71
|
+
|
|
72
|
+
- vars:
|
|
73
|
+
messages:
|
|
74
|
+
- role: "user"
|
|
75
|
+
content: "¿Cómo está el tiempo hoy?"
|
|
76
|
+
- role: "assistant"
|
|
77
|
+
content: "No tengo acceso a información meteorológica en tiempo real, pero puedes consultar el clima en tu área usando aplicaciones como Weather.com o tu app del tiempo local."
|
|
78
|
+
locale: "es-ES"
|
|
79
|
+
assert:
|
|
80
|
+
- type: llm-rubric
|
|
81
|
+
provider: openai:gpt-5-mini
|
|
82
|
+
|
|
83
|
+
value: "The response should be a Spanish title about weather inquiry"
|
|
84
|
+
- type: regex
|
|
85
|
+
value: "^.{1,50}$"
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
// TypeScript prompt wrapper that uses actual chain implementation
|
|
2
|
+
import { chainSummaryTitle } from '@lobechat/prompts';
|
|
3
|
+
import type { OpenAIChatMessage } from '@lobechat/types';
|
|
4
|
+
|
|
5
|
+
interface PromptVars {
|
|
6
|
+
locale: string;
|
|
7
|
+
messages: OpenAIChatMessage[];
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export default function generatePrompt({ vars }: { vars: PromptVars }) {
|
|
11
|
+
const { messages, locale } = vars;
|
|
12
|
+
|
|
13
|
+
// Use the actual chain function from src
|
|
14
|
+
const result = chainSummaryTitle(messages, locale);
|
|
15
|
+
|
|
16
|
+
// Return messages array as expected by promptfoo
|
|
17
|
+
return result.messages || [];
|
|
18
|
+
}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
description: Test translation accuracy between different languages
|
|
2
|
+
|
|
3
|
+
providers:
|
|
4
|
+
- openai:chat:gpt-5-mini
|
|
5
|
+
- openai:chat:claude-3-5-haiku-latest
|
|
6
|
+
- openai:chat:gemini-flash-latest
|
|
7
|
+
- openai:chat:deepseek-chat
|
|
8
|
+
|
|
9
|
+
prompts:
|
|
10
|
+
- file://promptfoo/translate/prompt.ts
|
|
11
|
+
|
|
12
|
+
tests:
|
|
13
|
+
- vars:
|
|
14
|
+
content: 'Hello, how are you?'
|
|
15
|
+
from: 'en-US'
|
|
16
|
+
to: 'zh-CN'
|
|
17
|
+
assert:
|
|
18
|
+
- type: contains-any
|
|
19
|
+
value: ['你好', '您好']
|
|
20
|
+
- type: not-contains
|
|
21
|
+
value: 'Hello'
|
|
22
|
+
|
|
23
|
+
- vars:
|
|
24
|
+
content: '你好,你怎么样?'
|
|
25
|
+
from: 'zh-CN'
|
|
26
|
+
to: 'en-US'
|
|
27
|
+
assert:
|
|
28
|
+
- type: contains-any
|
|
29
|
+
value: ['Hello', 'Hi', 'how are you', 'How are you']
|
|
30
|
+
- type: not-contains
|
|
31
|
+
value: '你好'
|
|
32
|
+
|
|
33
|
+
- vars:
|
|
34
|
+
content: 'Je suis content de vous rencontrer'
|
|
35
|
+
from: 'fr-FR'
|
|
36
|
+
to: 'en-US'
|
|
37
|
+
assert:
|
|
38
|
+
- type: contains-any
|
|
39
|
+
value: ['pleased', 'happy', 'glad', 'meet', 'meeting']
|
|
40
|
+
- type: not-contains
|
|
41
|
+
value: 'Je suis'
|
|
42
|
+
|
|
43
|
+
- vars:
|
|
44
|
+
content: 'The weather is beautiful today'
|
|
45
|
+
from: 'en-US'
|
|
46
|
+
to: 'es-ES'
|
|
47
|
+
assert:
|
|
48
|
+
- type: contains-any
|
|
49
|
+
value: ['tiempo', 'clima', 'hermoso', 'bonito', 'hoy', 'día', 'precioso']
|
|
50
|
+
- type: not-contains
|
|
51
|
+
value: 'weather'
|
|
52
|
+
|
|
53
|
+
- vars:
|
|
54
|
+
content: 'I love programming with TypeScript'
|
|
55
|
+
from: 'en-US'
|
|
56
|
+
to: 'ja-JP'
|
|
57
|
+
assert:
|
|
58
|
+
- type: contains
|
|
59
|
+
value: 'TypeScript' # Technical terms often remain unchanged
|
|
60
|
+
- type: not-contains
|
|
61
|
+
value: 'I love'
|
|
62
|
+
|
|
63
|
+
- vars:
|
|
64
|
+
content: 'Machine learning is revolutionizing technology'
|
|
65
|
+
from: 'en-US'
|
|
66
|
+
to: 'de-DE'
|
|
67
|
+
assert:
|
|
68
|
+
- type: contains-any
|
|
69
|
+
value: ['Technologie', 'revolutioniert', 'maschinelles', 'Lernen']
|
|
70
|
+
- type: not-contains
|
|
71
|
+
value: 'Machine learning'
|
|
72
|
+
|
|
73
|
+
- vars:
|
|
74
|
+
content: 'API_KEY_12345'
|
|
75
|
+
from: 'en-US'
|
|
76
|
+
to: 'zh-CN'
|
|
77
|
+
assert:
|
|
78
|
+
- type: contains
|
|
79
|
+
value: 'API_KEY_12345'
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
// TypeScript prompt wrapper that uses actual chain implementation
|
|
2
|
+
import { chainTranslate } from '@lobechat/prompts';
|
|
3
|
+
|
|
4
|
+
interface PromptVars {
|
|
5
|
+
content: string;
|
|
6
|
+
from: string;
|
|
7
|
+
to: string;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export default function generatePrompt({ vars }: { vars: PromptVars }) {
|
|
11
|
+
const { content, to } = vars;
|
|
12
|
+
|
|
13
|
+
// Use the actual chain function from src
|
|
14
|
+
const result = chainTranslate(content, to);
|
|
15
|
+
|
|
16
|
+
// Return messages array as expected by promptfoo
|
|
17
|
+
return result.messages || [];
|
|
18
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
description: LobeHub Prompts Testing Suite
|
|
2
|
+
|
|
3
|
+
# Test configurations - run all prompt tests
|
|
4
|
+
testPaths:
|
|
5
|
+
- promptfoo/translate/eval.yaml
|
|
6
|
+
- promptfoo/summary-title/eval.yaml
|
|
7
|
+
- promptfoo/language-detection/eval.yaml
|
|
8
|
+
- promptfoo/emoji-picker/eval.yaml
|
|
9
|
+
- promptfoo/knowledge-qa/eval.yaml
|
|
10
|
+
|
|
11
|
+
# Output configuration
|
|
12
|
+
outputPath: promptfoo-results.json
|
|
13
|
+
|
|
14
|
+
# Default test settings
|
|
15
|
+
defaultTest:
|
|
16
|
+
assert:
|
|
17
|
+
- type: llm-rubric
|
|
18
|
+
provider: openai:gpt-5-mini
|
|
19
|
+
value: "The response should be relevant and well-formatted"
|
|
20
|
+
- type: cost
|
|
21
|
+
threshold: 0.01 # Maximum cost per test in USD
|
|
22
|
+
|
|
23
|
+
# Environment variables for API keys
|
|
24
|
+
env:
|
|
25
|
+
OPENAI_API_KEY: ${OPENAI_API_KEY}
|
|
26
|
+
ANTHROPIC_API_KEY: ${ANTHROPIC_API_KEY}
|
|
27
|
+
|
|
28
|
+
# Evaluation settings
|
|
29
|
+
evaluateOptions:
|
|
30
|
+
maxConcurrency: 5
|
|
31
|
+
delay: 100
|
|
32
|
+
|
|
33
|
+
# TypeScript support
|
|
34
|
+
transforms:
|
|
35
|
+
- "typescript"
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
|
|
2
|
+
|
|
3
|
+
exports[`chainAnswerWithContext > should filter out empty context strings 1`] = `
|
|
4
|
+
{
|
|
5
|
+
"messages": [
|
|
6
|
+
{
|
|
7
|
+
"content": "You are a helpful assistant specialized in Test. Your task is to answer questions based on the provided context passages.
|
|
8
|
+
|
|
9
|
+
IMPORTANT RULES:
|
|
10
|
+
- First, check if the context is relevant to the question topic
|
|
11
|
+
- If the context is about a COMPLETELY DIFFERENT topic than the question:
|
|
12
|
+
* State what topic the context is about
|
|
13
|
+
* Clearly state "The provided context does not contain information about [question topic]"
|
|
14
|
+
* Do NOT answer using your general knowledge
|
|
15
|
+
- If the context is related to the question topic (even if information is limited):
|
|
16
|
+
* ALWAYS use the context information as a foundation
|
|
17
|
+
* You SHOULD supplement with your general knowledge to provide a complete, helpful answer
|
|
18
|
+
* For "how to" questions, MUST provide practical, actionable steps combining context + your expertise
|
|
19
|
+
* The context provides the topic relevance - you provide the comprehensive answer
|
|
20
|
+
* Example: If context mentions "Docker is for containerization", and question is "How to deploy with Docker?", you should explain deployment steps using your knowledge
|
|
21
|
+
- Answer in the same language as the question
|
|
22
|
+
- Use markdown formatting for better readability
|
|
23
|
+
|
|
24
|
+
The provided context passages:
|
|
25
|
+
|
|
26
|
+
<context>
|
|
27
|
+
Valid context
|
|
28
|
+
Another valid context
|
|
29
|
+
</context>
|
|
30
|
+
|
|
31
|
+
Question to answer:
|
|
32
|
+
|
|
33
|
+
Test question",
|
|
34
|
+
"role": "user",
|
|
35
|
+
},
|
|
36
|
+
],
|
|
37
|
+
}
|
|
38
|
+
`;
|
|
39
|
+
|
|
40
|
+
exports[`chainAnswerWithContext > should generate correct payload with context and knowledge 1`] = `
|
|
41
|
+
{
|
|
42
|
+
"messages": [
|
|
43
|
+
{
|
|
44
|
+
"content": "You are a helpful assistant specialized in AI/Machine Learning. Your task is to answer questions based on the provided context passages.
|
|
45
|
+
|
|
46
|
+
IMPORTANT RULES:
|
|
47
|
+
- First, check if the context is relevant to the question topic
|
|
48
|
+
- If the context is about a COMPLETELY DIFFERENT topic than the question:
|
|
49
|
+
* State what topic the context is about
|
|
50
|
+
* Clearly state "The provided context does not contain information about [question topic]"
|
|
51
|
+
* Do NOT answer using your general knowledge
|
|
52
|
+
- If the context is related to the question topic (even if information is limited):
|
|
53
|
+
* ALWAYS use the context information as a foundation
|
|
54
|
+
* You SHOULD supplement with your general knowledge to provide a complete, helpful answer
|
|
55
|
+
* For "how to" questions, MUST provide practical, actionable steps combining context + your expertise
|
|
56
|
+
* The context provides the topic relevance - you provide the comprehensive answer
|
|
57
|
+
* Example: If context mentions "Docker is for containerization", and question is "How to deploy with Docker?", you should explain deployment steps using your knowledge
|
|
58
|
+
- Answer in the same language as the question
|
|
59
|
+
- Use markdown formatting for better readability
|
|
60
|
+
|
|
61
|
+
The provided context passages:
|
|
62
|
+
|
|
63
|
+
<context>
|
|
64
|
+
Context passage 1
|
|
65
|
+
Context passage 2
|
|
66
|
+
</context>
|
|
67
|
+
|
|
68
|
+
Question to answer:
|
|
69
|
+
|
|
70
|
+
What is artificial intelligence?",
|
|
71
|
+
"role": "user",
|
|
72
|
+
},
|
|
73
|
+
],
|
|
74
|
+
}
|
|
75
|
+
`;
|
|
76
|
+
|
|
77
|
+
exports[`chainAnswerWithContext > should handle empty context array 1`] = `
|
|
78
|
+
{
|
|
79
|
+
"messages": [
|
|
80
|
+
{
|
|
81
|
+
"content": "You are a helpful assistant specialized in AI. Please answer the following question using your knowledge.
|
|
82
|
+
|
|
83
|
+
Answer in the same language as the question and use markdown formatting for better readability.
|
|
84
|
+
|
|
85
|
+
Question to answer:
|
|
86
|
+
|
|
87
|
+
What is AI?",
|
|
88
|
+
"role": "user",
|
|
89
|
+
},
|
|
90
|
+
],
|
|
91
|
+
}
|
|
92
|
+
`;
|
|
93
|
+
|
|
94
|
+
exports[`chainAnswerWithContext > should handle multiple knowledge areas 1`] = `
|
|
95
|
+
{
|
|
96
|
+
"messages": [
|
|
97
|
+
{
|
|
98
|
+
"content": "You are a helpful assistant specialized in AI/ML/NLP/Computer Vision. Your task is to answer questions based on the provided context passages.
|
|
99
|
+
|
|
100
|
+
IMPORTANT RULES:
|
|
101
|
+
- First, check if the context is relevant to the question topic
|
|
102
|
+
- If the context is about a COMPLETELY DIFFERENT topic than the question:
|
|
103
|
+
* State what topic the context is about
|
|
104
|
+
* Clearly state "The provided context does not contain information about [question topic]"
|
|
105
|
+
* Do NOT answer using your general knowledge
|
|
106
|
+
- If the context is related to the question topic (even if information is limited):
|
|
107
|
+
* ALWAYS use the context information as a foundation
|
|
108
|
+
* You SHOULD supplement with your general knowledge to provide a complete, helpful answer
|
|
109
|
+
* For "how to" questions, MUST provide practical, actionable steps combining context + your expertise
|
|
110
|
+
* The context provides the topic relevance - you provide the comprehensive answer
|
|
111
|
+
* Example: If context mentions "Docker is for containerization", and question is "How to deploy with Docker?", you should explain deployment steps using your knowledge
|
|
112
|
+
- Answer in the same language as the question
|
|
113
|
+
- Use markdown formatting for better readability
|
|
114
|
+
|
|
115
|
+
The provided context passages:
|
|
116
|
+
|
|
117
|
+
<context>
|
|
118
|
+
Context
|
|
119
|
+
</context>
|
|
120
|
+
|
|
121
|
+
Question to answer:
|
|
122
|
+
|
|
123
|
+
Tell me about these fields",
|
|
124
|
+
"role": "user",
|
|
125
|
+
},
|
|
126
|
+
],
|
|
127
|
+
}
|
|
128
|
+
`;
|
|
129
|
+
|
|
130
|
+
exports[`chainAnswerWithContext > should handle single knowledge area 1`] = `
|
|
131
|
+
{
|
|
132
|
+
"messages": [
|
|
133
|
+
{
|
|
134
|
+
"content": "You are a helpful assistant specialized in Technology. Your task is to answer questions based on the provided context passages.
|
|
135
|
+
|
|
136
|
+
IMPORTANT RULES:
|
|
137
|
+
- First, check if the context is relevant to the question topic
|
|
138
|
+
- If the context is about a COMPLETELY DIFFERENT topic than the question:
|
|
139
|
+
* State what topic the context is about
|
|
140
|
+
* Clearly state "The provided context does not contain information about [question topic]"
|
|
141
|
+
* Do NOT answer using your general knowledge
|
|
142
|
+
- If the context is related to the question topic (even if information is limited):
|
|
143
|
+
* ALWAYS use the context information as a foundation
|
|
144
|
+
* You SHOULD supplement with your general knowledge to provide a complete, helpful answer
|
|
145
|
+
* For "how to" questions, MUST provide practical, actionable steps combining context + your expertise
|
|
146
|
+
* The context provides the topic relevance - you provide the comprehensive answer
|
|
147
|
+
* Example: If context mentions "Docker is for containerization", and question is "How to deploy with Docker?", you should explain deployment steps using your knowledge
|
|
148
|
+
- Answer in the same language as the question
|
|
149
|
+
- Use markdown formatting for better readability
|
|
150
|
+
|
|
151
|
+
The provided context passages:
|
|
152
|
+
|
|
153
|
+
<context>
|
|
154
|
+
Single context
|
|
155
|
+
</context>
|
|
156
|
+
|
|
157
|
+
Question to answer:
|
|
158
|
+
|
|
159
|
+
How does it work?",
|
|
160
|
+
"role": "user",
|
|
161
|
+
},
|
|
162
|
+
],
|
|
163
|
+
}
|
|
164
|
+
`;
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
|
|
2
|
+
|
|
3
|
+
exports[`chainPickEmoji > should return a payload with the correct structure and embedded user content 1`] = `
|
|
4
|
+
{
|
|
5
|
+
"messages": [
|
|
6
|
+
{
|
|
7
|
+
"content": "You are an emoji expert who selects the most appropriate emoji to represent concepts, emotions, or topics.
|
|
8
|
+
|
|
9
|
+
Rules:
|
|
10
|
+
- Output ONLY a single emoji (1-2 characters maximum)
|
|
11
|
+
- Focus on the CONTENT meaning, not the language it's written in
|
|
12
|
+
- Choose an emoji that best represents the core topic, activity, or subject matter
|
|
13
|
+
- Prioritize topic-specific emojis over generic emotion emojis (e.g., for sports, use 🏃 instead of 😅)
|
|
14
|
+
- For work/projects, use work-related emojis (💼, 🚀, 💪) not cultural symbols
|
|
15
|
+
- For pure emotions without specific topics, use face emojis (happy: 🎉, sad: 😢, thinking: 🤔)
|
|
16
|
+
- For activities or subjects, use object or symbol emojis that represent the main topic
|
|
17
|
+
- No explanations or additional text",
|
|
18
|
+
"role": "system",
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
"content": "I am a copywriting master who helps name design and art works with literary depth",
|
|
22
|
+
"role": "user",
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
"content": "✒️",
|
|
26
|
+
"role": "assistant",
|
|
27
|
+
},
|
|
28
|
+
{
|
|
29
|
+
"content": "I am a code wizard who converts JavaScript code to TypeScript",
|
|
30
|
+
"role": "user",
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
"content": "🧙♂️",
|
|
34
|
+
"role": "assistant",
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
"content": "I just got a promotion at work",
|
|
38
|
+
"role": "user",
|
|
39
|
+
},
|
|
40
|
+
{
|
|
41
|
+
"content": "🎉",
|
|
42
|
+
"role": "assistant",
|
|
43
|
+
},
|
|
44
|
+
{
|
|
45
|
+
"content": "I am a business plan expert who helps with startup strategies and marketing",
|
|
46
|
+
"role": "user",
|
|
47
|
+
},
|
|
48
|
+
{
|
|
49
|
+
"content": "🚀",
|
|
50
|
+
"role": "assistant",
|
|
51
|
+
},
|
|
52
|
+
{
|
|
53
|
+
"content": "你是一名星际探索者",
|
|
54
|
+
"role": "user",
|
|
55
|
+
},
|
|
56
|
+
],
|
|
57
|
+
}
|
|
58
|
+
`;
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
|
|
2
|
+
|
|
3
|
+
exports[`chainSummaryTitle > should use the default model if the token count is below the GPT-3.5 limit 1`] = `
|
|
4
|
+
{
|
|
5
|
+
"messages": [
|
|
6
|
+
{
|
|
7
|
+
"content": "You are a professional conversation summarizer. Generate a concise title that captures the essence of the conversation.
|
|
8
|
+
|
|
9
|
+
Rules:
|
|
10
|
+
- Output ONLY the title text, no explanations or additional context
|
|
11
|
+
- Maximum 10 words
|
|
12
|
+
- Maximum 50 characters
|
|
13
|
+
- No punctuation marks
|
|
14
|
+
- Use the language specified by the locale code: en-US
|
|
15
|
+
- The title should accurately reflect the main topic of the conversation
|
|
16
|
+
- Keep it short and to the point",
|
|
17
|
+
"role": "system",
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
"content": "assistant: Hello, how can I assist you?
|
|
21
|
+
user: I need help with my account.",
|
|
22
|
+
"role": "user",
|
|
23
|
+
},
|
|
24
|
+
],
|
|
25
|
+
}
|
|
26
|
+
`;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
|
|
2
|
+
|
|
3
|
+
exports[`chainTranslate > should create a payload with system and user messages for translation 1`] = `
|
|
4
|
+
{
|
|
5
|
+
"messages": [
|
|
6
|
+
{
|
|
7
|
+
"content": "You are a professional translator. Translate the input text to zh-CN.
|
|
8
|
+
|
|
9
|
+
Rules:
|
|
10
|
+
- Output ONLY the translated text, no explanations or additional context
|
|
11
|
+
- Preserve technical terms, code identifiers, API keys, and proper nouns exactly as they appear
|
|
12
|
+
- Maintain the original formatting and structure
|
|
13
|
+
- Use natural, idiomatic expressions in the target language",
|
|
14
|
+
"role": "system",
|
|
15
|
+
},
|
|
16
|
+
{
|
|
17
|
+
"content": "This is a test sentence.",
|
|
18
|
+
"role": "user",
|
|
19
|
+
},
|
|
20
|
+
],
|
|
21
|
+
}
|
|
22
|
+
`;
|
|
@@ -3,98 +3,53 @@ import { describe, expect, it } from 'vitest';
|
|
|
3
3
|
import { chainAnswerWithContext } from '../answerWithContext';
|
|
4
4
|
|
|
5
5
|
describe('chainAnswerWithContext', () => {
|
|
6
|
-
it('should generate correct
|
|
7
|
-
const
|
|
6
|
+
it('should generate correct payload with context and knowledge', () => {
|
|
7
|
+
const result = chainAnswerWithContext({
|
|
8
8
|
context: ['Context passage 1', 'Context passage 2'],
|
|
9
9
|
knowledge: ['AI', 'Machine Learning'],
|
|
10
10
|
question: 'What is artificial intelligence?',
|
|
11
|
-
};
|
|
11
|
+
});
|
|
12
12
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
expect(result.messages).toHaveLength(1);
|
|
16
|
-
expect(result.messages![0].role).toBe('user');
|
|
17
|
-
expect(result.messages![0].content).toContain('AI/Machine Learning');
|
|
18
|
-
expect(result.messages![0].content).toContain('Context passage 1');
|
|
19
|
-
expect(result.messages![0].content).toContain('Context passage 2');
|
|
20
|
-
expect(result.messages![0].content).toContain('What is artificial intelligence?');
|
|
13
|
+
expect(result).toMatchSnapshot();
|
|
21
14
|
});
|
|
22
15
|
|
|
23
16
|
it('should handle single knowledge area', () => {
|
|
24
|
-
const
|
|
17
|
+
const result = chainAnswerWithContext({
|
|
25
18
|
context: ['Single context'],
|
|
26
19
|
knowledge: ['Technology'],
|
|
27
20
|
question: 'How does it work?',
|
|
28
|
-
};
|
|
29
|
-
|
|
30
|
-
const result = chainAnswerWithContext(testParams);
|
|
21
|
+
});
|
|
31
22
|
|
|
32
|
-
expect(result
|
|
23
|
+
expect(result).toMatchSnapshot();
|
|
33
24
|
});
|
|
34
25
|
|
|
35
26
|
it('should handle multiple knowledge areas', () => {
|
|
36
|
-
const
|
|
27
|
+
const result = chainAnswerWithContext({
|
|
37
28
|
context: ['Context'],
|
|
38
29
|
knowledge: ['AI', 'ML', 'NLP', 'Computer Vision'],
|
|
39
30
|
question: 'Tell me about these fields',
|
|
40
|
-
};
|
|
31
|
+
});
|
|
41
32
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
expect(result.messages![0].content).toContain('AI/ML/NLP/Computer Vision');
|
|
33
|
+
expect(result).toMatchSnapshot();
|
|
45
34
|
});
|
|
46
35
|
|
|
47
36
|
it('should handle empty context array', () => {
|
|
48
|
-
const
|
|
37
|
+
const result = chainAnswerWithContext({
|
|
49
38
|
context: [],
|
|
50
39
|
knowledge: ['AI'],
|
|
51
40
|
question: 'What is AI?',
|
|
52
|
-
};
|
|
53
|
-
|
|
54
|
-
const result = chainAnswerWithContext(testParams);
|
|
41
|
+
});
|
|
55
42
|
|
|
56
|
-
expect(result
|
|
57
|
-
expect(result.messages![0].content).toContain('</Context>');
|
|
43
|
+
expect(result).toMatchSnapshot();
|
|
58
44
|
});
|
|
59
45
|
|
|
60
|
-
it('should
|
|
61
|
-
const
|
|
62
|
-
context: ['
|
|
46
|
+
it('should filter out empty context strings', () => {
|
|
47
|
+
const result = chainAnswerWithContext({
|
|
48
|
+
context: ['Valid context', '', ' ', 'Another valid context'],
|
|
63
49
|
knowledge: ['Test'],
|
|
64
50
|
question: 'Test question',
|
|
65
|
-
};
|
|
66
|
-
|
|
67
|
-
const result = chainAnswerWithContext(testParams);
|
|
68
|
-
|
|
69
|
-
expect(result.messages![0].content).toContain(
|
|
70
|
-
'<Context>\nFirst passage\nSecond passage\n</Context>',
|
|
71
|
-
);
|
|
72
|
-
});
|
|
73
|
-
|
|
74
|
-
it('should include proper instructions about using passages', () => {
|
|
75
|
-
const testParams = {
|
|
76
|
-
context: ['Context'],
|
|
77
|
-
knowledge: ['Knowledge'],
|
|
78
|
-
question: 'Question',
|
|
79
|
-
};
|
|
80
|
-
|
|
81
|
-
const result = chainAnswerWithContext(testParams);
|
|
82
|
-
const content = result.messages![0].content;
|
|
83
|
-
|
|
84
|
-
expect(content).toContain('passages might not be relevant');
|
|
85
|
-
expect(content).toContain('please only use the passages that are relevant');
|
|
86
|
-
expect(content).toContain('answer using your knowledge');
|
|
87
|
-
});
|
|
88
|
-
|
|
89
|
-
it('should include markdown formatting instruction', () => {
|
|
90
|
-
const testParams = {
|
|
91
|
-
context: ['Context'],
|
|
92
|
-
knowledge: ['Knowledge'],
|
|
93
|
-
question: 'Question',
|
|
94
|
-
};
|
|
95
|
-
|
|
96
|
-
const result = chainAnswerWithContext(testParams);
|
|
51
|
+
});
|
|
97
52
|
|
|
98
|
-
expect(result
|
|
53
|
+
expect(result).toMatchSnapshot();
|
|
99
54
|
});
|
|
100
55
|
});
|
|
@@ -1,46 +1,11 @@
|
|
|
1
|
-
import { ChatStreamPayload } from '@lobechat/types';
|
|
2
1
|
import { describe, expect, it } from 'vitest';
|
|
3
2
|
|
|
4
3
|
import { chainPickEmoji } from '../pickEmoji';
|
|
5
4
|
|
|
6
|
-
// 描述测试块
|
|
7
5
|
describe('chainPickEmoji', () => {
|
|
8
|
-
// 测试用例:验证函数返回的结构
|
|
9
6
|
it('should return a payload with the correct structure and embedded user content', () => {
|
|
10
|
-
|
|
11
|
-
const userContent = '你是一名星际探索者';
|
|
7
|
+
const result = chainPickEmoji('你是一名星际探索者');
|
|
12
8
|
|
|
13
|
-
|
|
14
|
-
const expectedPayload: Partial<ChatStreamPayload> = {
|
|
15
|
-
messages: [
|
|
16
|
-
{
|
|
17
|
-
content:
|
|
18
|
-
'你是一名擅长进行概念抽象的设计师与 Emoji 专家,你需要根据角色能力的描述抽象出一个表达物理实体的概念 Emoji 作为角色头像, 格式要求如下:\n输入: {文本作为JSON引用字符串}\n输出: {一个Emoji}',
|
|
19
|
-
role: 'system',
|
|
20
|
-
},
|
|
21
|
-
{
|
|
22
|
-
content: `输入: {你是一名文案大师,帮我为一些设计 / 艺术作品起名,名字需要有文学内涵,注重精炼和赋子意境,表达作品的情景氛国,使名称既简洁又富有诗意。}`,
|
|
23
|
-
role: 'user',
|
|
24
|
-
},
|
|
25
|
-
{ content: '✒️', role: 'assistant' },
|
|
26
|
-
{
|
|
27
|
-
content: `输入: {你是一名代码巫师,请将下面的代码转成 ts,不要修改实现。如果原本 js 中没有定义的全局变量,需要补充 declare 的类型声明。}`,
|
|
28
|
-
role: 'user',
|
|
29
|
-
},
|
|
30
|
-
{ content: '🧙♂️', role: 'assistant' },
|
|
31
|
-
{
|
|
32
|
-
content: `输入: {你是一名创业计划撰写专家,可以提供包括创意名称、简短的标语、目标用户画像、用户痛点、主要价值主张、销售/营销渠道、收入流、成本结构等计划生成。}`,
|
|
33
|
-
role: 'user',
|
|
34
|
-
},
|
|
35
|
-
{ content: '🚀', role: 'assistant' },
|
|
36
|
-
{ content: `输入: {${userContent}}`, role: 'user' },
|
|
37
|
-
],
|
|
38
|
-
};
|
|
39
|
-
|
|
40
|
-
// 执行函数并获取结果
|
|
41
|
-
const result = chainPickEmoji(userContent);
|
|
42
|
-
|
|
43
|
-
// 断言结果是否符合预期
|
|
44
|
-
expect(result).toEqual(expectedPayload);
|
|
9
|
+
expect(result).toMatchSnapshot();
|
|
45
10
|
});
|
|
46
11
|
});
|