@lobehub/lobehub 2.0.0-next.98 → 2.0.0-next.99
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 +25 -0
- package/apps/desktop/src/main/services/__tests__/fileSrv.test.ts +603 -0
- package/changelog/v1.json +9 -0
- package/codecov.yml +1 -0
- package/locales/ar/plugin.json +34 -22
- package/locales/ar/tool.json +8 -0
- package/locales/bg-BG/plugin.json +34 -22
- package/locales/bg-BG/tool.json +8 -0
- package/locales/de-DE/plugin.json +34 -22
- package/locales/de-DE/tool.json +8 -0
- package/locales/en-US/plugin.json +34 -22
- package/locales/en-US/tool.json +8 -0
- package/locales/es-ES/plugin.json +34 -22
- package/locales/es-ES/tool.json +8 -0
- package/locales/fa-IR/plugin.json +34 -22
- package/locales/fa-IR/tool.json +8 -0
- package/locales/fr-FR/plugin.json +34 -22
- package/locales/fr-FR/tool.json +8 -0
- package/locales/it-IT/plugin.json +34 -22
- package/locales/it-IT/tool.json +8 -0
- package/locales/ja-JP/plugin.json +34 -22
- package/locales/ja-JP/tool.json +8 -0
- package/locales/ko-KR/plugin.json +34 -22
- package/locales/ko-KR/tool.json +8 -0
- package/locales/nl-NL/plugin.json +34 -22
- package/locales/nl-NL/tool.json +8 -0
- package/locales/pl-PL/plugin.json +34 -22
- package/locales/pl-PL/tool.json +8 -0
- package/locales/pt-BR/plugin.json +34 -22
- package/locales/pt-BR/tool.json +8 -0
- package/locales/ru-RU/plugin.json +34 -22
- package/locales/ru-RU/tool.json +8 -0
- package/locales/tr-TR/plugin.json +34 -22
- package/locales/tr-TR/tool.json +8 -0
- package/locales/vi-VN/plugin.json +34 -22
- package/locales/vi-VN/tool.json +8 -0
- package/locales/zh-CN/plugin.json +34 -22
- package/locales/zh-CN/tool.json +8 -0
- package/locales/zh-TW/plugin.json +34 -22
- package/locales/zh-TW/tool.json +8 -0
- package/package.json +1 -1
- package/packages/database/src/models/__tests__/document.test.ts +149 -0
- package/packages/database/src/models/chunk.ts +3 -1
- package/packages/database/src/models/document.ts +8 -2
- package/packages/prompts/src/prompts/knowledgeBaseQA/__snapshots__/formatFileContents.test.ts.snap +75 -0
- package/packages/prompts/src/prompts/knowledgeBaseQA/__snapshots__/formatNoSearchResults.test.ts.snap +45 -0
- package/packages/prompts/src/prompts/knowledgeBaseQA/__snapshots__/formatSearchResults.test.ts.snap +82 -0
- package/packages/prompts/src/prompts/knowledgeBaseQA/formatFileContents.test.ts +118 -0
- package/packages/prompts/src/prompts/knowledgeBaseQA/formatFileContents.ts +31 -0
- package/packages/prompts/src/prompts/knowledgeBaseQA/formatNoSearchResults.test.ts +25 -0
- package/packages/prompts/src/prompts/knowledgeBaseQA/formatNoSearchResults.ts +13 -0
- package/packages/prompts/src/prompts/knowledgeBaseQA/formatSearchResults.test.ts +191 -0
- package/packages/prompts/src/prompts/knowledgeBaseQA/formatSearchResults.ts +50 -0
- package/packages/prompts/src/prompts/knowledgeBaseQA/index.ts +6 -0
- package/packages/types/src/rag.ts +13 -4
- package/src/features/ChatInput/ActionBar/Token/TokenTag.tsx +2 -2
- package/src/features/ChatInput/ActionBar/Token/TokenTagForGroupChat.tsx +2 -2
- package/src/features/ChatList/Messages/Group/Tool/Inspector/ToolTitle.tsx +5 -23
- package/src/features/ChatList/Messages/Tool/Inspector/ToolTitle.tsx +5 -25
- package/src/features/PluginsUI/Render/BuiltinType/index.tsx +1 -1
- package/src/helpers/toolEngineering/index.test.ts +3 -3
- package/src/helpers/toolEngineering/index.ts +17 -4
- package/src/libs/trpc/client/lambda.ts +0 -6
- package/src/locales/default/plugin.ts +34 -22
- package/src/locales/default/tool.ts +13 -5
- package/src/server/routers/lambda/chunk.ts +168 -41
- package/src/services/chat/chat.test.ts +3 -3
- package/src/services/chat/index.ts +2 -2
- package/src/services/rag.ts +6 -2
- package/src/store/chat/slices/aiChat/actions/__tests__/conversationLifecycle.test.ts +11 -0
- package/src/store/chat/slices/aiChat/actions/__tests__/rag.test.ts +0 -87
- package/src/store/chat/slices/aiChat/actions/__tests__/streamingExecutor.test.ts +2 -69
- package/src/store/chat/slices/aiChat/actions/conversationLifecycle.ts +0 -2
- package/src/store/chat/slices/aiChat/actions/rag.ts +0 -47
- package/src/store/chat/slices/aiChat/actions/streamingExecutor.ts +8 -69
- package/src/store/chat/slices/builtinTool/actions/index.ts +4 -1
- package/src/store/chat/slices/builtinTool/actions/knowledgeBase.ts +174 -0
- package/src/store/chat/slices/operation/types.ts +1 -0
- package/src/store/chat/slices/thread/action.test.ts +0 -1
- package/src/store/chat/slices/thread/action.ts +0 -1
- package/src/tools/executionRuntimes.ts +3 -0
- package/src/tools/identifiers.ts +13 -0
- package/src/tools/index.ts +7 -0
- package/src/tools/knowledge-base/ExecutionRuntime/index.ts +96 -0
- package/src/tools/knowledge-base/Render/ReadKnowledge/FileCard.tsx +135 -0
- package/src/tools/knowledge-base/Render/ReadKnowledge/index.tsx +27 -0
- package/src/tools/knowledge-base/Render/SearchKnowledgeBase/Item/index.tsx +54 -0
- package/src/tools/knowledge-base/Render/SearchKnowledgeBase/Item/style.ts +51 -0
- package/src/tools/knowledge-base/Render/SearchKnowledgeBase/index.tsx +23 -0
- package/src/tools/knowledge-base/Render/index.ts +7 -0
- package/src/tools/knowledge-base/index.ts +64 -0
- package/src/tools/knowledge-base/systemRole.ts +102 -0
- package/src/tools/knowledge-base/type.ts +25 -0
- package/src/tools/local-system/Intervention/WriteFile/index.tsx +1 -1
- package/src/tools/renders.ts +4 -0
- package/src/store/chat/agents/createToolEngine.ts +0 -22
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
|
|
2
|
+
|
|
3
|
+
exports[`promptNoSearchResults > should format no search results with complex query 1`] = `
|
|
4
|
+
"<knowledge_base_search_results query="API authentication with OAuth 2.0" totalCount="0">
|
|
5
|
+
<instruction>No relevant files found in the knowledge base for this query.</instruction>
|
|
6
|
+
<suggestions>
|
|
7
|
+
<suggestion>Try rephrasing your question with different keywords</suggestion>
|
|
8
|
+
<suggestion>Check if the information exists in the uploaded documents</suggestion>
|
|
9
|
+
<suggestion>Ask the user to provide more context or upload relevant documents</suggestion>
|
|
10
|
+
</suggestions>
|
|
11
|
+
</knowledge_base_search_results>"
|
|
12
|
+
`;
|
|
13
|
+
|
|
14
|
+
exports[`promptNoSearchResults > should format no search results with non-English query 1`] = `
|
|
15
|
+
"<knowledge_base_search_results query="如何配置数据库连接" totalCount="0">
|
|
16
|
+
<instruction>No relevant files found in the knowledge base for this query.</instruction>
|
|
17
|
+
<suggestions>
|
|
18
|
+
<suggestion>Try rephrasing your question with different keywords</suggestion>
|
|
19
|
+
<suggestion>Check if the information exists in the uploaded documents</suggestion>
|
|
20
|
+
<suggestion>Ask the user to provide more context or upload relevant documents</suggestion>
|
|
21
|
+
</suggestions>
|
|
22
|
+
</knowledge_base_search_results>"
|
|
23
|
+
`;
|
|
24
|
+
|
|
25
|
+
exports[`promptNoSearchResults > should format no search results with simple query 1`] = `
|
|
26
|
+
"<knowledge_base_search_results query="how to install" totalCount="0">
|
|
27
|
+
<instruction>No relevant files found in the knowledge base for this query.</instruction>
|
|
28
|
+
<suggestions>
|
|
29
|
+
<suggestion>Try rephrasing your question with different keywords</suggestion>
|
|
30
|
+
<suggestion>Check if the information exists in the uploaded documents</suggestion>
|
|
31
|
+
<suggestion>Ask the user to provide more context or upload relevant documents</suggestion>
|
|
32
|
+
</suggestions>
|
|
33
|
+
</knowledge_base_search_results>"
|
|
34
|
+
`;
|
|
35
|
+
|
|
36
|
+
exports[`promptNoSearchResults > should format no search results with special characters 1`] = `
|
|
37
|
+
"<knowledge_base_search_results query="How to use fetchData<T> with async/await?" totalCount="0">
|
|
38
|
+
<instruction>No relevant files found in the knowledge base for this query.</instruction>
|
|
39
|
+
<suggestions>
|
|
40
|
+
<suggestion>Try rephrasing your question with different keywords</suggestion>
|
|
41
|
+
<suggestion>Check if the information exists in the uploaded documents</suggestion>
|
|
42
|
+
<suggestion>Ask the user to provide more context or upload relevant documents</suggestion>
|
|
43
|
+
</suggestions>
|
|
44
|
+
</knowledge_base_search_results>"
|
|
45
|
+
`;
|
package/packages/prompts/src/prompts/knowledgeBaseQA/__snapshots__/formatSearchResults.test.ts.snap
ADDED
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
|
|
2
|
+
|
|
3
|
+
exports[`formatSearchResults > should format file with special characters in name 1`] = `
|
|
4
|
+
"<knowledge_base_search_results query="password reset" totalCount="1">
|
|
5
|
+
<instruction>Here are the search results from the knowledge base. Use the readKnowledge tool with file IDs to get complete content.</instruction>
|
|
6
|
+
<file id="special-123" name="FAQ: Common Questions & Answers (2024).md" relevanceScore="0.88">
|
|
7
|
+
<chunk fileId="special-123" fileName="FAQ: Common Questions & Answers (2024).md" similarity="0.9">Q: How do I reset my password? A: Click on the "Forgot Password" link on the login page.</chunk>
|
|
8
|
+
</file>
|
|
9
|
+
</knowledge_base_search_results>"
|
|
10
|
+
`;
|
|
11
|
+
|
|
12
|
+
exports[`formatSearchResults > should format long text chunks without truncation 1`] = `
|
|
13
|
+
"<knowledge_base_search_results query="documentation details" totalCount="1">
|
|
14
|
+
<instruction>Here are the search results from the knowledge base. Use the readKnowledge tool with file IDs to get complete content.</instruction>
|
|
15
|
+
<file id="long-doc" name="Detailed Documentation.md" relevanceScore="0.91">
|
|
16
|
+
<chunk fileId="long-doc" fileName="Detailed Documentation.md" similarity="0.93">Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</chunk>
|
|
17
|
+
</file>
|
|
18
|
+
</knowledge_base_search_results>"
|
|
19
|
+
`;
|
|
20
|
+
|
|
21
|
+
exports[`formatSearchResults > should format multiple files with varying relevance scores 1`] = `
|
|
22
|
+
"<knowledge_base_search_results query="API authentication security" totalCount="3">
|
|
23
|
+
<instruction>Here are the search results from the knowledge base. Use the readKnowledge tool with file IDs to get complete content.</instruction>
|
|
24
|
+
<file id="doc-001" name="API Reference.md" relevanceScore="0.95">
|
|
25
|
+
<chunk fileId="doc-001" fileName="API Reference.md" similarity="0.98">The Authentication API provides endpoints for user login, logout, and token refresh. All endpoints require HTTPS and proper API keys.</chunk>
|
|
26
|
+
<chunk fileId="doc-001" fileName="API Reference.md" similarity="0.92">To authenticate a user, send a POST request to /api/auth/login with username and password in the request body.</chunk>
|
|
27
|
+
</file>
|
|
28
|
+
<file id="doc-002" name="Security Best Practices.md" relevanceScore="0.87">
|
|
29
|
+
<chunk fileId="doc-002" fileName="Security Best Practices.md" similarity="0.89">Always use environment variables to store sensitive information like API keys and database credentials. Never commit these to version control.</chunk>
|
|
30
|
+
<chunk fileId="doc-002" fileName="Security Best Practices.md" similarity="0.85">Implement rate limiting on all public endpoints to prevent abuse and DDoS attacks.</chunk>
|
|
31
|
+
</file>
|
|
32
|
+
<file id="doc-003" name="Troubleshooting Guide.md" relevanceScore="0.73">
|
|
33
|
+
<chunk fileId="doc-003" fileName="Troubleshooting Guide.md" similarity="0.75">If you encounter authentication errors, first verify that your API key is valid and has not expired.</chunk>
|
|
34
|
+
</file>
|
|
35
|
+
</knowledge_base_search_results>"
|
|
36
|
+
`;
|
|
37
|
+
|
|
38
|
+
exports[`formatSearchResults > should format query with special characters 1`] = `
|
|
39
|
+
"<knowledge_base_search_results query="How to use fetchData<T> with async/await?" totalCount="1">
|
|
40
|
+
<instruction>Here are the search results from the knowledge base. Use the readKnowledge tool with file IDs to get complete content.</instruction>
|
|
41
|
+
<file id="code-sample" name="Code Examples.md" relevanceScore="0.94">
|
|
42
|
+
<chunk fileId="code-sample" fileName="Code Examples.md" similarity="0.96">Use the following TypeScript code: const result = await fetchData<T>({ url, params });</chunk>
|
|
43
|
+
</file>
|
|
44
|
+
</knowledge_base_search_results>"
|
|
45
|
+
`;
|
|
46
|
+
|
|
47
|
+
exports[`formatSearchResults > should format single file with multiple chunks 1`] = `
|
|
48
|
+
"<knowledge_base_search_results query="how to install the application" totalCount="1">
|
|
49
|
+
<instruction>Here are the search results from the knowledge base. Use the readKnowledge tool with file IDs to get complete content.</instruction>
|
|
50
|
+
<file id="file-123" name="Getting Started Guide.md" relevanceScore="0.92">
|
|
51
|
+
<chunk fileId="file-123" fileName="Getting Started Guide.md" similarity="0.95">To get started with the application, first install all dependencies using npm install or yarn install. Make sure you have Node.js version 16 or higher installed on your system.</chunk>
|
|
52
|
+
<chunk fileId="file-123" fileName="Getting Started Guide.md" similarity="0.88">After installation, you can run the development server with npm run dev. The application will be available at http://localhost:3000 by default.</chunk>
|
|
53
|
+
</file>
|
|
54
|
+
</knowledge_base_search_results>"
|
|
55
|
+
`;
|
|
56
|
+
|
|
57
|
+
exports[`formatSearchResults > should handle empty file results 1`] = `
|
|
58
|
+
"<knowledge_base_search_results query="no results query" totalCount="0">
|
|
59
|
+
<instruction>No relevant files found in the knowledge base for this query.</instruction>
|
|
60
|
+
</knowledge_base_search_results>"
|
|
61
|
+
`;
|
|
62
|
+
|
|
63
|
+
exports[`formatSearchResults > should handle file with multiple high-similarity chunks 1`] = `
|
|
64
|
+
"<knowledge_base_search_results query="project setup steps" totalCount="1">
|
|
65
|
+
<instruction>Here are the search results from the knowledge base. Use the readKnowledge tool with file IDs to get complete content.</instruction>
|
|
66
|
+
<file id="comprehensive-guide" name="Complete Tutorial.md" relevanceScore="0.96">
|
|
67
|
+
<chunk fileId="comprehensive-guide" fileName="Complete Tutorial.md" similarity="0.98">Step 1: Initialize the project with the configuration file.</chunk>
|
|
68
|
+
<chunk fileId="comprehensive-guide" fileName="Complete Tutorial.md" similarity="0.97">Step 2: Configure the environment variables for your deployment.</chunk>
|
|
69
|
+
<chunk fileId="comprehensive-guide" fileName="Complete Tutorial.md" similarity="0.96">Step 3: Run the migration scripts to set up the database schema.</chunk>
|
|
70
|
+
<chunk fileId="comprehensive-guide" fileName="Complete Tutorial.md" similarity="0.95">Step 4: Start the development server and verify everything is working.</chunk>
|
|
71
|
+
</file>
|
|
72
|
+
</knowledge_base_search_results>"
|
|
73
|
+
`;
|
|
74
|
+
|
|
75
|
+
exports[`formatSearchResults > should handle files with low relevance scores 1`] = `
|
|
76
|
+
"<knowledge_base_search_results query="specific technical query" totalCount="1">
|
|
77
|
+
<instruction>Here are the search results from the knowledge base. Use the readKnowledge tool with file IDs to get complete content.</instruction>
|
|
78
|
+
<file id="low-relevance" name="Tangentially Related.md" relevanceScore="0.32">
|
|
79
|
+
<chunk fileId="low-relevance" fileName="Tangentially Related.md" similarity="0.35">This document contains some loosely related information that might be helpful.</chunk>
|
|
80
|
+
</file>
|
|
81
|
+
</knowledge_base_search_results>"
|
|
82
|
+
`;
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
import { describe, expect, it } from 'vitest';
|
|
2
|
+
|
|
3
|
+
import { promptFileContents } from './formatFileContents';
|
|
4
|
+
import type { FileContent } from './formatFileContents';
|
|
5
|
+
|
|
6
|
+
describe('promptFileContents', () => {
|
|
7
|
+
it('should format single file content', () => {
|
|
8
|
+
const fileContents: FileContent[] = [
|
|
9
|
+
{
|
|
10
|
+
content: 'This is the file content with some important information.',
|
|
11
|
+
fileId: 'file-001',
|
|
12
|
+
filename: 'document.md',
|
|
13
|
+
},
|
|
14
|
+
];
|
|
15
|
+
|
|
16
|
+
const result = promptFileContents(fileContents);
|
|
17
|
+
expect(result).toMatchSnapshot();
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
it('should format multiple file contents', () => {
|
|
21
|
+
const fileContents: FileContent[] = [
|
|
22
|
+
{
|
|
23
|
+
content: 'First file content about API authentication.',
|
|
24
|
+
fileId: 'file-001',
|
|
25
|
+
filename: 'auth-guide.md',
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
content: 'Second file content about database setup and configuration.',
|
|
29
|
+
fileId: 'file-002',
|
|
30
|
+
filename: 'db-setup.md',
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
content: 'Third file content with deployment instructions.',
|
|
34
|
+
fileId: 'file-003',
|
|
35
|
+
filename: 'deployment.md',
|
|
36
|
+
},
|
|
37
|
+
];
|
|
38
|
+
|
|
39
|
+
const result = promptFileContents(fileContents);
|
|
40
|
+
expect(result).toMatchSnapshot();
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
it('should handle file with error', () => {
|
|
44
|
+
const fileContents: FileContent[] = [
|
|
45
|
+
{
|
|
46
|
+
content: '',
|
|
47
|
+
error: 'File not found',
|
|
48
|
+
fileId: 'file-404',
|
|
49
|
+
filename: 'missing.md',
|
|
50
|
+
},
|
|
51
|
+
];
|
|
52
|
+
|
|
53
|
+
const result = promptFileContents(fileContents);
|
|
54
|
+
expect(result).toMatchSnapshot();
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
it('should handle mixed successful and error files', () => {
|
|
58
|
+
const fileContents: FileContent[] = [
|
|
59
|
+
{
|
|
60
|
+
content: 'Successfully loaded content from this file.',
|
|
61
|
+
fileId: 'file-001',
|
|
62
|
+
filename: 'success.md',
|
|
63
|
+
},
|
|
64
|
+
{
|
|
65
|
+
content: '',
|
|
66
|
+
error: 'Permission denied',
|
|
67
|
+
fileId: 'file-002',
|
|
68
|
+
filename: 'restricted.md',
|
|
69
|
+
},
|
|
70
|
+
{
|
|
71
|
+
content: 'Another successfully loaded file with more content.',
|
|
72
|
+
fileId: 'file-003',
|
|
73
|
+
filename: 'another-success.md',
|
|
74
|
+
},
|
|
75
|
+
];
|
|
76
|
+
|
|
77
|
+
const result = promptFileContents(fileContents);
|
|
78
|
+
expect(result).toMatchSnapshot();
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
it('should handle file with special characters in name', () => {
|
|
82
|
+
const fileContents: FileContent[] = [
|
|
83
|
+
{
|
|
84
|
+
content: 'Content from a file with special characters in the name.',
|
|
85
|
+
fileId: 'file-special',
|
|
86
|
+
filename: 'FAQ: Q&A (2024).md',
|
|
87
|
+
},
|
|
88
|
+
];
|
|
89
|
+
|
|
90
|
+
const result = promptFileContents(fileContents);
|
|
91
|
+
expect(result).toMatchSnapshot();
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
it('should handle file with long content', () => {
|
|
95
|
+
const fileContents: FileContent[] = [
|
|
96
|
+
{
|
|
97
|
+
content: `# Comprehensive Guide
|
|
98
|
+
|
|
99
|
+
## Introduction
|
|
100
|
+
This is a very long document with multiple sections and detailed information.
|
|
101
|
+
|
|
102
|
+
## Section 1
|
|
103
|
+
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
|
|
104
|
+
|
|
105
|
+
## Section 2
|
|
106
|
+
Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.
|
|
107
|
+
|
|
108
|
+
## Conclusion
|
|
109
|
+
Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.`,
|
|
110
|
+
fileId: 'file-long',
|
|
111
|
+
filename: 'comprehensive-guide.md',
|
|
112
|
+
},
|
|
113
|
+
];
|
|
114
|
+
|
|
115
|
+
const result = promptFileContents(fileContents);
|
|
116
|
+
expect(result).toMatchSnapshot();
|
|
117
|
+
});
|
|
118
|
+
});
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
export interface FileContent {
|
|
2
|
+
content: string;
|
|
3
|
+
error?: string;
|
|
4
|
+
fileId: string;
|
|
5
|
+
filename: string;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Formats a single file content with XML tags
|
|
10
|
+
*/
|
|
11
|
+
const formatFileContent = (file: FileContent): string => {
|
|
12
|
+
if (file.error) {
|
|
13
|
+
return `<file id="${file.fileId}" name="${file.filename}" error="${file.error}" />`;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
return `<file id="${file.fileId}" name="${file.filename}">
|
|
17
|
+
${file.content}
|
|
18
|
+
</file>`;
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Format file contents prompt for AI consumption using XML structure
|
|
23
|
+
*/
|
|
24
|
+
export const promptFileContents = (fileContents: FileContent[]): string => {
|
|
25
|
+
const filesXml = fileContents.map((file) => formatFileContent(file)).join('\n');
|
|
26
|
+
|
|
27
|
+
return `<knowledge_base_files totalCount="${fileContents.length}">
|
|
28
|
+
<instruction>Use the information from these files to answer the user's question. Always cite the source files.</instruction>
|
|
29
|
+
${filesXml}
|
|
30
|
+
</knowledge_base_files>`;
|
|
31
|
+
};
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { describe, expect, it } from 'vitest';
|
|
2
|
+
|
|
3
|
+
import { promptNoSearchResults } from './formatNoSearchResults';
|
|
4
|
+
|
|
5
|
+
describe('promptNoSearchResults', () => {
|
|
6
|
+
it('should format no search results with simple query', () => {
|
|
7
|
+
const result = promptNoSearchResults('how to install');
|
|
8
|
+
expect(result).toMatchSnapshot();
|
|
9
|
+
});
|
|
10
|
+
|
|
11
|
+
it('should format no search results with complex query', () => {
|
|
12
|
+
const result = promptNoSearchResults('API authentication with OAuth 2.0');
|
|
13
|
+
expect(result).toMatchSnapshot();
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
it('should format no search results with special characters', () => {
|
|
17
|
+
const result = promptNoSearchResults('How to use fetchData<T> with async/await?');
|
|
18
|
+
expect(result).toMatchSnapshot();
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
it('should format no search results with non-English query', () => {
|
|
22
|
+
const result = promptNoSearchResults('如何配置数据库连接');
|
|
23
|
+
expect(result).toMatchSnapshot();
|
|
24
|
+
});
|
|
25
|
+
});
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Format prompt when no search results found using XML structure
|
|
3
|
+
*/
|
|
4
|
+
export const promptNoSearchResults = (query: string): string => {
|
|
5
|
+
return `<knowledge_base_search_results query="${query}" totalCount="0">
|
|
6
|
+
<instruction>No relevant files found in the knowledge base for this query.</instruction>
|
|
7
|
+
<suggestions>
|
|
8
|
+
<suggestion>Try rephrasing your question with different keywords</suggestion>
|
|
9
|
+
<suggestion>Check if the information exists in the uploaded documents</suggestion>
|
|
10
|
+
<suggestion>Ask the user to provide more context or upload relevant documents</suggestion>
|
|
11
|
+
</suggestions>
|
|
12
|
+
</knowledge_base_search_results>`;
|
|
13
|
+
};
|
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
import { describe, expect, it } from 'vitest';
|
|
2
|
+
|
|
3
|
+
import { formatSearchResults } from './formatSearchResults';
|
|
4
|
+
import type { FileSearchResult } from './formatSearchResults';
|
|
5
|
+
|
|
6
|
+
describe('formatSearchResults', () => {
|
|
7
|
+
it('should format single file with multiple chunks', () => {
|
|
8
|
+
const fileResults: FileSearchResult[] = [
|
|
9
|
+
{
|
|
10
|
+
fileId: 'file-123',
|
|
11
|
+
fileName: 'Getting Started Guide.md',
|
|
12
|
+
relevanceScore: 0.92,
|
|
13
|
+
topChunks: [
|
|
14
|
+
{
|
|
15
|
+
similarity: 0.95,
|
|
16
|
+
text: 'To get started with the application, first install all dependencies using npm install or yarn install. Make sure you have Node.js version 16 or higher installed on your system.',
|
|
17
|
+
},
|
|
18
|
+
{
|
|
19
|
+
similarity: 0.88,
|
|
20
|
+
text: 'After installation, you can run the development server with npm run dev. The application will be available at http://localhost:3000 by default.',
|
|
21
|
+
},
|
|
22
|
+
],
|
|
23
|
+
},
|
|
24
|
+
];
|
|
25
|
+
|
|
26
|
+
const result = formatSearchResults(fileResults, 'how to install the application');
|
|
27
|
+
expect(result).toMatchSnapshot();
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
it('should format multiple files with varying relevance scores', () => {
|
|
31
|
+
const fileResults: FileSearchResult[] = [
|
|
32
|
+
{
|
|
33
|
+
fileId: 'doc-001',
|
|
34
|
+
fileName: 'API Reference.md',
|
|
35
|
+
relevanceScore: 0.95,
|
|
36
|
+
topChunks: [
|
|
37
|
+
{
|
|
38
|
+
similarity: 0.98,
|
|
39
|
+
text: 'The Authentication API provides endpoints for user login, logout, and token refresh. All endpoints require HTTPS and proper API keys.',
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
similarity: 0.92,
|
|
43
|
+
text: 'To authenticate a user, send a POST request to /api/auth/login with username and password in the request body.',
|
|
44
|
+
},
|
|
45
|
+
],
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
fileId: 'doc-002',
|
|
49
|
+
fileName: 'Security Best Practices.md',
|
|
50
|
+
relevanceScore: 0.87,
|
|
51
|
+
topChunks: [
|
|
52
|
+
{
|
|
53
|
+
similarity: 0.89,
|
|
54
|
+
text: 'Always use environment variables to store sensitive information like API keys and database credentials. Never commit these to version control.',
|
|
55
|
+
},
|
|
56
|
+
{
|
|
57
|
+
similarity: 0.85,
|
|
58
|
+
text: 'Implement rate limiting on all public endpoints to prevent abuse and DDoS attacks.',
|
|
59
|
+
},
|
|
60
|
+
],
|
|
61
|
+
},
|
|
62
|
+
{
|
|
63
|
+
fileId: 'doc-003',
|
|
64
|
+
fileName: 'Troubleshooting Guide.md',
|
|
65
|
+
relevanceScore: 0.73,
|
|
66
|
+
topChunks: [
|
|
67
|
+
{
|
|
68
|
+
similarity: 0.75,
|
|
69
|
+
text: 'If you encounter authentication errors, first verify that your API key is valid and has not expired.',
|
|
70
|
+
},
|
|
71
|
+
],
|
|
72
|
+
},
|
|
73
|
+
];
|
|
74
|
+
|
|
75
|
+
const result = formatSearchResults(fileResults, 'API authentication security');
|
|
76
|
+
expect(result).toMatchSnapshot();
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
it('should format long text chunks without truncation', () => {
|
|
80
|
+
const fileResults: FileSearchResult[] = [
|
|
81
|
+
{
|
|
82
|
+
fileId: 'long-doc',
|
|
83
|
+
fileName: 'Detailed Documentation.md',
|
|
84
|
+
relevanceScore: 0.91,
|
|
85
|
+
topChunks: [
|
|
86
|
+
{
|
|
87
|
+
similarity: 0.93,
|
|
88
|
+
text: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.',
|
|
89
|
+
},
|
|
90
|
+
],
|
|
91
|
+
},
|
|
92
|
+
];
|
|
93
|
+
|
|
94
|
+
const result = formatSearchResults(fileResults, 'documentation details');
|
|
95
|
+
expect(result).toMatchSnapshot();
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
it('should handle empty file results', () => {
|
|
99
|
+
const fileResults: FileSearchResult[] = [];
|
|
100
|
+
const result = formatSearchResults(fileResults, 'no results query');
|
|
101
|
+
expect(result).toMatchSnapshot();
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
it('should format file with special characters in name', () => {
|
|
105
|
+
const fileResults: FileSearchResult[] = [
|
|
106
|
+
{
|
|
107
|
+
fileId: 'special-123',
|
|
108
|
+
fileName: 'FAQ: Common Questions & Answers (2024).md',
|
|
109
|
+
relevanceScore: 0.88,
|
|
110
|
+
topChunks: [
|
|
111
|
+
{
|
|
112
|
+
similarity: 0.9,
|
|
113
|
+
text: 'Q: How do I reset my password? A: Click on the "Forgot Password" link on the login page.',
|
|
114
|
+
},
|
|
115
|
+
],
|
|
116
|
+
},
|
|
117
|
+
];
|
|
118
|
+
|
|
119
|
+
const result = formatSearchResults(fileResults, 'password reset');
|
|
120
|
+
expect(result).toMatchSnapshot();
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
it('should handle files with low relevance scores', () => {
|
|
124
|
+
const fileResults: FileSearchResult[] = [
|
|
125
|
+
{
|
|
126
|
+
fileId: 'low-relevance',
|
|
127
|
+
fileName: 'Tangentially Related.md',
|
|
128
|
+
relevanceScore: 0.32,
|
|
129
|
+
topChunks: [
|
|
130
|
+
{
|
|
131
|
+
similarity: 0.35,
|
|
132
|
+
text: 'This document contains some loosely related information that might be helpful.',
|
|
133
|
+
},
|
|
134
|
+
],
|
|
135
|
+
},
|
|
136
|
+
];
|
|
137
|
+
|
|
138
|
+
const result = formatSearchResults(fileResults, 'specific technical query');
|
|
139
|
+
expect(result).toMatchSnapshot();
|
|
140
|
+
});
|
|
141
|
+
|
|
142
|
+
it('should format query with special characters', () => {
|
|
143
|
+
const fileResults: FileSearchResult[] = [
|
|
144
|
+
{
|
|
145
|
+
fileId: 'code-sample',
|
|
146
|
+
fileName: 'Code Examples.md',
|
|
147
|
+
relevanceScore: 0.94,
|
|
148
|
+
topChunks: [
|
|
149
|
+
{
|
|
150
|
+
similarity: 0.96,
|
|
151
|
+
text: 'Use the following TypeScript code: const result = await fetchData<T>({ url, params });',
|
|
152
|
+
},
|
|
153
|
+
],
|
|
154
|
+
},
|
|
155
|
+
];
|
|
156
|
+
|
|
157
|
+
const result = formatSearchResults(fileResults, 'How to use fetchData<T> with async/await?');
|
|
158
|
+
expect(result).toMatchSnapshot();
|
|
159
|
+
});
|
|
160
|
+
|
|
161
|
+
it('should handle file with multiple high-similarity chunks', () => {
|
|
162
|
+
const fileResults: FileSearchResult[] = [
|
|
163
|
+
{
|
|
164
|
+
fileId: 'comprehensive-guide',
|
|
165
|
+
fileName: 'Complete Tutorial.md',
|
|
166
|
+
relevanceScore: 0.96,
|
|
167
|
+
topChunks: [
|
|
168
|
+
{
|
|
169
|
+
similarity: 0.98,
|
|
170
|
+
text: 'Step 1: Initialize the project with the configuration file.',
|
|
171
|
+
},
|
|
172
|
+
{
|
|
173
|
+
similarity: 0.97,
|
|
174
|
+
text: 'Step 2: Configure the environment variables for your deployment.',
|
|
175
|
+
},
|
|
176
|
+
{
|
|
177
|
+
similarity: 0.96,
|
|
178
|
+
text: 'Step 3: Run the migration scripts to set up the database schema.',
|
|
179
|
+
},
|
|
180
|
+
{
|
|
181
|
+
similarity: 0.95,
|
|
182
|
+
text: 'Step 4: Start the development server and verify everything is working.',
|
|
183
|
+
},
|
|
184
|
+
],
|
|
185
|
+
},
|
|
186
|
+
];
|
|
187
|
+
|
|
188
|
+
const result = formatSearchResults(fileResults, 'project setup steps');
|
|
189
|
+
expect(result).toMatchSnapshot();
|
|
190
|
+
});
|
|
191
|
+
});
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
export interface FileSearchResultChunk {
|
|
2
|
+
similarity: number;
|
|
3
|
+
text: string;
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
export interface FileSearchResult {
|
|
7
|
+
fileId: string;
|
|
8
|
+
fileName: string;
|
|
9
|
+
relevanceScore: number;
|
|
10
|
+
topChunks: FileSearchResultChunk[];
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Formats a single chunk with XML tags
|
|
15
|
+
*/
|
|
16
|
+
const formatChunk = (chunk: FileSearchResultChunk, fileId: string, fileName: string): string => {
|
|
17
|
+
return `<chunk fileId="${fileId}" fileName="${fileName}" similarity="${chunk.similarity}">${chunk.text}</chunk>`;
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Formats a single file search result with XML tags
|
|
22
|
+
*/
|
|
23
|
+
const formatFile = (file: FileSearchResult): string => {
|
|
24
|
+
const chunks = file.topChunks.map((chunk) => formatChunk(chunk, file.fileId, file.fileName));
|
|
25
|
+
|
|
26
|
+
return `<file id="${file.fileId}" name="${file.fileName}" relevanceScore="${file.relevanceScore}">
|
|
27
|
+
${chunks.join('\n')}
|
|
28
|
+
</file>`;
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Formats knowledge base search results into an XML structure
|
|
33
|
+
* @param fileResults - Array of file search results with relevance scores and chunks
|
|
34
|
+
* @param query - The original search query
|
|
35
|
+
* @returns Formatted XML string with search results
|
|
36
|
+
*/
|
|
37
|
+
export const formatSearchResults = (fileResults: FileSearchResult[], query: string): string => {
|
|
38
|
+
if (fileResults.length === 0) {
|
|
39
|
+
return `<knowledge_base_search_results query="${query}" totalCount="0">
|
|
40
|
+
<instruction>No relevant files found in the knowledge base for this query.</instruction>
|
|
41
|
+
</knowledge_base_search_results>`;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
const filesXml = fileResults.map((file) => formatFile(file)).join('\n');
|
|
45
|
+
|
|
46
|
+
return `<knowledge_base_search_results query="${query}" totalCount="${fileResults.length}">
|
|
47
|
+
<instruction>Here are the search results from the knowledge base. Use the readKnowledge tool with file IDs to get complete content.</instruction>
|
|
48
|
+
${filesXml}
|
|
49
|
+
</knowledge_base_search_results>`;
|
|
50
|
+
};
|
|
@@ -4,6 +4,12 @@ import { chunkPrompts } from './chunk';
|
|
|
4
4
|
import { knowledgePrompts } from './knowledge';
|
|
5
5
|
import { userQueryPrompt } from './userQuery';
|
|
6
6
|
|
|
7
|
+
export type { FileContent } from './formatFileContents';
|
|
8
|
+
export { promptFileContents } from './formatFileContents';
|
|
9
|
+
export { promptNoSearchResults } from './formatNoSearchResults';
|
|
10
|
+
export type { FileSearchResult, FileSearchResultChunk } from './formatSearchResults';
|
|
11
|
+
export { formatSearchResults } from './formatSearchResults';
|
|
12
|
+
|
|
7
13
|
export const knowledgeBaseQAPrompts = ({
|
|
8
14
|
chunks,
|
|
9
15
|
knowledge,
|
|
@@ -5,12 +5,21 @@ import { ChatSemanticSearchChunk } from './chunk';
|
|
|
5
5
|
export const SemanticSearchSchema = z.object({
|
|
6
6
|
fileIds: z.array(z.string()).optional(),
|
|
7
7
|
knowledgeIds: z.array(z.string()).optional(),
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
rewriteQuery: z.string(),
|
|
11
|
-
userQuery: z.string(),
|
|
8
|
+
query: z.string(),
|
|
9
|
+
topK: z.number().optional(),
|
|
12
10
|
});
|
|
13
11
|
|
|
14
12
|
export type SemanticSearchSchemaType = z.infer<typeof SemanticSearchSchema>;
|
|
15
13
|
|
|
16
14
|
export type MessageSemanticSearchChunk = Pick<ChatSemanticSearchChunk, 'id' | 'similarity'>;
|
|
15
|
+
|
|
16
|
+
export interface FileSearchResult {
|
|
17
|
+
fileId: string;
|
|
18
|
+
fileName: string;
|
|
19
|
+
relevanceScore: number;
|
|
20
|
+
topChunks: Array<{
|
|
21
|
+
id: string;
|
|
22
|
+
similarity: number;
|
|
23
|
+
text: string;
|
|
24
|
+
}>;
|
|
25
|
+
}
|
|
@@ -6,7 +6,7 @@ import { memo, useMemo } from 'react';
|
|
|
6
6
|
import { useTranslation } from 'react-i18next';
|
|
7
7
|
import { Center, Flexbox } from 'react-layout-kit';
|
|
8
8
|
|
|
9
|
-
import {
|
|
9
|
+
import { createAgentToolsEngine } from '@/helpers/toolEngineering';
|
|
10
10
|
import { useModelContextWindowTokens } from '@/hooks/useModelContextWindowTokens';
|
|
11
11
|
import { useModelSupportToolUse } from '@/hooks/useModelSupportToolUse';
|
|
12
12
|
import { useTokenCount } from '@/hooks/useTokenCount';
|
|
@@ -57,7 +57,7 @@ const Token = memo<TokenTagProps>(({ total: messageString }) => {
|
|
|
57
57
|
const pluginIds = useAgentStore(agentSelectors.currentAgentPlugins);
|
|
58
58
|
|
|
59
59
|
const toolsString = useToolStore((s) => {
|
|
60
|
-
const toolsEngine =
|
|
60
|
+
const toolsEngine = createAgentToolsEngine({ model, provider });
|
|
61
61
|
|
|
62
62
|
const { tools, enabledToolIds } = toolsEngine.generateToolsDetailed({
|
|
63
63
|
model,
|
|
@@ -7,7 +7,7 @@ import { memo, useMemo } from 'react';
|
|
|
7
7
|
import { useTranslation } from 'react-i18next';
|
|
8
8
|
import { Center, Flexbox } from 'react-layout-kit';
|
|
9
9
|
|
|
10
|
-
import {
|
|
10
|
+
import { createAgentToolsEngine } from '@/helpers/toolEngineering';
|
|
11
11
|
import { useModelContextWindowTokens } from '@/hooks/useModelContextWindowTokens';
|
|
12
12
|
import { useModelSupportToolUse } from '@/hooks/useModelSupportToolUse';
|
|
13
13
|
import { useTokenCount } from '@/hooks/useTokenCount';
|
|
@@ -76,7 +76,7 @@ const TokenTagForGroupChat = memo<TokenTagForGroupChatProps>(({ total: messageSt
|
|
|
76
76
|
const pluginIds = allGroupPlugins.map((plugin) => plugin.id);
|
|
77
77
|
|
|
78
78
|
const toolsString = useToolStore((s) => {
|
|
79
|
-
const toolsEngine =
|
|
79
|
+
const toolsEngine = createAgentToolsEngine({ model, provider });
|
|
80
80
|
|
|
81
81
|
const { tools, enabledToolIds } = toolsEngine.generateToolsDetailed({
|
|
82
82
|
model,
|