@lobehub/lobehub 2.0.0-next.97 → 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/.console-log-whitelist.json +14 -0
- package/.github/workflows/check-console-log.yml +117 -0
- package/.github/workflows/desktop-pr-build.yml +4 -4
- package/.github/workflows/release-desktop-beta.yml +4 -4
- package/.github/workflows/release.yml +1 -1
- package/.github/workflows/test.yml +5 -5
- package/CHANGELOG.md +58 -0
- package/apps/desktop/src/main/services/__tests__/fileSrv.test.ts +603 -0
- package/changelog/v1.json +21 -0
- package/codecov.yml +1 -0
- package/docs/development/database-schema.dbml +1 -0
- package/e2e/package.json +1 -1
- package/locales/ar/file.json +9 -11
- package/locales/ar/plugin.json +34 -22
- package/locales/ar/tool.json +8 -0
- package/locales/bg-BG/file.json +8 -10
- package/locales/bg-BG/plugin.json +34 -22
- package/locales/bg-BG/tool.json +8 -0
- package/locales/de-DE/file.json +9 -11
- package/locales/de-DE/plugin.json +34 -22
- package/locales/de-DE/tool.json +8 -0
- package/locales/en-US/file.json +12 -14
- package/locales/en-US/plugin.json +34 -22
- package/locales/en-US/tool.json +8 -0
- package/locales/es-ES/file.json +7 -9
- package/locales/es-ES/plugin.json +34 -22
- package/locales/es-ES/tool.json +8 -0
- package/locales/fa-IR/file.json +9 -11
- package/locales/fa-IR/plugin.json +34 -22
- package/locales/fa-IR/tool.json +8 -0
- package/locales/fr-FR/file.json +6 -8
- package/locales/fr-FR/plugin.json +34 -22
- package/locales/fr-FR/tool.json +8 -0
- package/locales/it-IT/file.json +8 -10
- package/locales/it-IT/plugin.json +34 -22
- package/locales/it-IT/tool.json +8 -0
- package/locales/ja-JP/file.json +10 -12
- package/locales/ja-JP/plugin.json +34 -22
- package/locales/ja-JP/tool.json +8 -0
- package/locales/ko-KR/file.json +8 -10
- package/locales/ko-KR/plugin.json +34 -22
- package/locales/ko-KR/tool.json +8 -0
- package/locales/nl-NL/file.json +8 -10
- package/locales/nl-NL/plugin.json +34 -22
- package/locales/nl-NL/tool.json +8 -0
- package/locales/pl-PL/file.json +7 -9
- package/locales/pl-PL/plugin.json +34 -22
- package/locales/pl-PL/tool.json +8 -0
- package/locales/pt-BR/file.json +7 -9
- package/locales/pt-BR/plugin.json +34 -22
- package/locales/pt-BR/tool.json +8 -0
- package/locales/ru-RU/file.json +9 -11
- package/locales/ru-RU/plugin.json +34 -22
- package/locales/ru-RU/tool.json +8 -0
- package/locales/tr-TR/file.json +8 -10
- package/locales/tr-TR/plugin.json +34 -22
- package/locales/tr-TR/tool.json +8 -0
- package/locales/vi-VN/file.json +9 -11
- package/locales/vi-VN/plugin.json +34 -22
- package/locales/vi-VN/tool.json +8 -0
- package/locales/zh-CN/file.json +10 -12
- package/locales/zh-CN/plugin.json +34 -22
- package/locales/zh-CN/tool.json +8 -0
- package/locales/zh-TW/file.json +10 -12
- package/locales/zh-TW/plugin.json +34 -22
- package/locales/zh-TW/tool.json +8 -0
- package/package.json +3 -2
- package/packages/database/migrations/0047_add_slug_document.sql +6 -0
- package/packages/database/migrations/meta/0047_snapshot.json +7891 -0
- package/packages/database/migrations/meta/_journal.json +7 -0
- package/packages/database/src/core/migrations.json +16 -7
- 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 +10 -4
- package/packages/database/src/schemas/file.ts +7 -1
- package/packages/model-bank/src/aiModels/qwen.ts +5 -3
- package/packages/model-runtime/src/core/openaiCompatibleFactory/index.ts +21 -21
- package/packages/obervability-otel/package.json +2 -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/scripts/checkConsoleLog.mts +148 -0
- package/scripts/prebuild.mts +5 -5
- package/src/app/[variants]/(main)/changelog/index.tsx +1 -1
- package/src/app/[variants]/(main)/settings/_layout/Desktop/index.tsx +20 -16
- package/src/app/[variants]/(main)/settings/provider/(list)/ProviderGrid/Card.tsx +6 -3
- package/src/app/[variants]/(main)/settings/provider/(list)/index.tsx +3 -2
- package/src/app/[variants]/(main)/settings/provider/detail/index.tsx +14 -4
- package/src/app/[variants]/desktopRouter.config.tsx +23 -0
- package/src/app/[variants]/mobileRouter.config.tsx +23 -0
- 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/KnowledgeManager/DocumentExplorer/NoteEditorModal.tsx +0 -20
- package/src/features/KnowledgeManager/DocumentExplorer/index.tsx +3 -3
- package/src/features/KnowledgeManager/FileExplorer/MasonryFileItem/index.tsx +0 -20
- package/src/features/KnowledgeManager/Header/AddButton.tsx +0 -1
- package/src/features/KnowledgeManager/Header/NewNoteButton.tsx +1 -1
- package/src/features/KnowledgeManager/Header/TogglePanelButton.tsx +2 -2
- package/src/features/KnowledgeManager/Home/UploadEntries.tsx +2 -2
- package/src/features/KnowledgeManager/Home/index.tsx +4 -4
- package/src/features/PluginsUI/Render/BuiltinType/index.tsx +1 -1
- package/src/features/User/UserPanel/useMenu.tsx +7 -3
- 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/file.ts +11 -13
- 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/agents/__tests__/createAgentExecutors/helpers/testExecutor.ts +1 -4
- 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
|
@@ -62,93 +62,6 @@ describe('chatRAG actions', () => {
|
|
|
62
62
|
});
|
|
63
63
|
});
|
|
64
64
|
|
|
65
|
-
describe('internal_retrieveChunks', () => {
|
|
66
|
-
it('should retrieve chunks with existing ragQuery', async () => {
|
|
67
|
-
const { result } = renderHook(() => useChatStore());
|
|
68
|
-
const messageId = 'message-id';
|
|
69
|
-
const existingRagQuery = 'existing-query';
|
|
70
|
-
const userQuery = 'user-query';
|
|
71
|
-
|
|
72
|
-
// Mock the message with existing ragQuery
|
|
73
|
-
vi.spyOn(dbMessageSelectors, 'getDbMessageById').mockReturnValue(
|
|
74
|
-
() =>
|
|
75
|
-
({
|
|
76
|
-
id: messageId,
|
|
77
|
-
ragQuery: existingRagQuery,
|
|
78
|
-
}) as UIChatMessage,
|
|
79
|
-
);
|
|
80
|
-
|
|
81
|
-
// Mock the semantic search response
|
|
82
|
-
(ragService.semanticSearchForChat as Mock).mockResolvedValue({
|
|
83
|
-
chunks: [{ id: 'chunk-1' }],
|
|
84
|
-
queryId: 'query-id',
|
|
85
|
-
});
|
|
86
|
-
|
|
87
|
-
vi.spyOn(agentSelectors, 'currentKnowledgeIds').mockReturnValue({
|
|
88
|
-
fileIds: [],
|
|
89
|
-
knowledgeBaseIds: [],
|
|
90
|
-
});
|
|
91
|
-
|
|
92
|
-
const result1 = await act(async () => {
|
|
93
|
-
return await result.current.internal_retrieveChunks(messageId, userQuery, []);
|
|
94
|
-
});
|
|
95
|
-
|
|
96
|
-
expect(result1).toEqual({
|
|
97
|
-
chunks: [{ id: 'chunk-1' }],
|
|
98
|
-
queryId: 'query-id',
|
|
99
|
-
rewriteQuery: existingRagQuery,
|
|
100
|
-
});
|
|
101
|
-
expect(ragService.semanticSearchForChat).toHaveBeenCalledWith(
|
|
102
|
-
expect.objectContaining({
|
|
103
|
-
rewriteQuery: existingRagQuery,
|
|
104
|
-
userQuery,
|
|
105
|
-
}),
|
|
106
|
-
);
|
|
107
|
-
});
|
|
108
|
-
|
|
109
|
-
it('should rewrite query if no existing ragQuery', async () => {
|
|
110
|
-
const { result } = renderHook(() => useChatStore());
|
|
111
|
-
const messageId = 'message-id';
|
|
112
|
-
const userQuery = 'user-query';
|
|
113
|
-
const rewrittenQuery = 'rewritten-query';
|
|
114
|
-
|
|
115
|
-
// Mock the message without ragQuery
|
|
116
|
-
vi.spyOn(dbMessageSelectors, 'getDbMessageById').mockReturnValue(
|
|
117
|
-
() =>
|
|
118
|
-
({
|
|
119
|
-
id: messageId,
|
|
120
|
-
}) as UIChatMessage,
|
|
121
|
-
);
|
|
122
|
-
|
|
123
|
-
// Mock the rewrite query function
|
|
124
|
-
vi.spyOn(result.current, 'internal_rewriteQuery').mockResolvedValueOnce(rewrittenQuery);
|
|
125
|
-
|
|
126
|
-
// Mock the semantic search response
|
|
127
|
-
(ragService.semanticSearchForChat as Mock).mockResolvedValue({
|
|
128
|
-
chunks: [{ id: 'chunk-1' }],
|
|
129
|
-
queryId: 'query-id',
|
|
130
|
-
});
|
|
131
|
-
|
|
132
|
-
vi.spyOn(agentSelectors, 'currentKnowledgeIds').mockReturnValue({
|
|
133
|
-
fileIds: [],
|
|
134
|
-
knowledgeBaseIds: [],
|
|
135
|
-
});
|
|
136
|
-
|
|
137
|
-
const result2 = await act(async () => {
|
|
138
|
-
return await result.current.internal_retrieveChunks(messageId, userQuery, ['message']);
|
|
139
|
-
});
|
|
140
|
-
|
|
141
|
-
expect(result2).toEqual({
|
|
142
|
-
chunks: [{ id: 'chunk-1' }],
|
|
143
|
-
queryId: 'query-id',
|
|
144
|
-
rewriteQuery: rewrittenQuery,
|
|
145
|
-
});
|
|
146
|
-
expect(result.current.internal_rewriteQuery).toHaveBeenCalledWith(messageId, userQuery, [
|
|
147
|
-
'message',
|
|
148
|
-
]);
|
|
149
|
-
});
|
|
150
|
-
});
|
|
151
|
-
|
|
152
65
|
describe('internal_rewriteQuery', () => {
|
|
153
66
|
it('should return original content if query rewrite is disabled', async () => {
|
|
154
67
|
const { result } = renderHook(() => useChatStore());
|
|
@@ -712,75 +712,8 @@ describe('StreamingExecutor actions', () => {
|
|
|
712
712
|
);
|
|
713
713
|
});
|
|
714
714
|
|
|
715
|
-
//
|
|
716
|
-
//
|
|
717
|
-
it.skip('should pass context to optimisticUpdateMessageRAG', async () => {
|
|
718
|
-
act(() => {
|
|
719
|
-
useChatStore.setState({
|
|
720
|
-
internal_execAgentRuntime: realExecAgentRuntime,
|
|
721
|
-
activeId: 'active-session',
|
|
722
|
-
activeTopicId: 'active-topic',
|
|
723
|
-
});
|
|
724
|
-
});
|
|
725
|
-
|
|
726
|
-
const { result } = renderHook(() => useChatStore());
|
|
727
|
-
|
|
728
|
-
const contextSessionId = 'context-session';
|
|
729
|
-
const contextTopicId = 'context-topic';
|
|
730
|
-
const userMessage = {
|
|
731
|
-
id: TEST_IDS.USER_MESSAGE_ID,
|
|
732
|
-
role: 'user',
|
|
733
|
-
content: TEST_CONTENT.USER_MESSAGE,
|
|
734
|
-
sessionId: contextSessionId,
|
|
735
|
-
topicId: contextTopicId,
|
|
736
|
-
} as UIChatMessage;
|
|
737
|
-
|
|
738
|
-
const ragMetadata = {
|
|
739
|
-
ragQueryId: 'query-id',
|
|
740
|
-
fileChunks: [{ id: 'chunk-1', similarity: 0.9 }],
|
|
741
|
-
};
|
|
742
|
-
|
|
743
|
-
const assistantMessageId = 'assistant-msg-id';
|
|
744
|
-
const assistantMessage = {
|
|
745
|
-
id: assistantMessageId,
|
|
746
|
-
role: 'assistant',
|
|
747
|
-
content: TEST_CONTENT.AI_RESPONSE,
|
|
748
|
-
sessionId: contextSessionId,
|
|
749
|
-
topicId: contextTopicId,
|
|
750
|
-
} as UIChatMessage;
|
|
751
|
-
|
|
752
|
-
// Mock createMessage to return the assistant message
|
|
753
|
-
vi.spyOn(messageService, 'createMessage').mockResolvedValue({
|
|
754
|
-
id: assistantMessageId,
|
|
755
|
-
messages: [userMessage, assistantMessage],
|
|
756
|
-
});
|
|
757
|
-
|
|
758
|
-
const updateRAGSpy = vi.spyOn(result.current, 'optimisticUpdateMessageRAG');
|
|
759
|
-
const streamSpy = vi
|
|
760
|
-
.spyOn(chatService, 'createAssistantMessageStream')
|
|
761
|
-
.mockImplementation(async ({ onFinish }) => {
|
|
762
|
-
await onFinish?.(TEST_CONTENT.AI_RESPONSE, {});
|
|
763
|
-
});
|
|
764
|
-
|
|
765
|
-
await act(async () => {
|
|
766
|
-
await result.current.internal_execAgentRuntime({
|
|
767
|
-
messages: [userMessage],
|
|
768
|
-
parentMessageId: userMessage.id,
|
|
769
|
-
parentMessageType: 'user',
|
|
770
|
-
sessionId: contextSessionId,
|
|
771
|
-
topicId: contextTopicId,
|
|
772
|
-
ragMetadata,
|
|
773
|
-
});
|
|
774
|
-
});
|
|
775
|
-
|
|
776
|
-
// Verify optimisticUpdateMessageRAG was called with context
|
|
777
|
-
expect(updateRAGSpy).toHaveBeenCalledWith(expect.any(String), ragMetadata, {
|
|
778
|
-
sessionId: contextSessionId,
|
|
779
|
-
topicId: contextTopicId,
|
|
780
|
-
});
|
|
781
|
-
|
|
782
|
-
streamSpy.mockRestore();
|
|
783
|
-
});
|
|
715
|
+
// Note: RAG metadata functionality has been removed
|
|
716
|
+
// RAG is now handled by Knowledge Base Tools (searchKnowledgeBase and readKnowledge)
|
|
784
717
|
});
|
|
785
718
|
|
|
786
719
|
describe('StreamingExecutor OptimisticUpdateContext isolation', () => {
|
|
@@ -272,7 +272,6 @@ export const conversationLifecycle: StateCreator<
|
|
|
272
272
|
sessionId: activeId,
|
|
273
273
|
topicId: data.topicId ?? activeTopicId,
|
|
274
274
|
parentOperationId: operationId, // Pass as parent operation
|
|
275
|
-
ragQuery: get().internal_shouldUseRAG() ? message : undefined,
|
|
276
275
|
threadId: activeThreadId,
|
|
277
276
|
skipCreateFirstMessage: true,
|
|
278
277
|
});
|
|
@@ -338,7 +337,6 @@ export const conversationLifecycle: StateCreator<
|
|
|
338
337
|
sessionId: activeId,
|
|
339
338
|
topicId: activeTopicId,
|
|
340
339
|
traceId,
|
|
341
|
-
ragQuery: get().internal_shouldUseRAG() ? item.content : undefined,
|
|
342
340
|
threadId: activeThreadId,
|
|
343
341
|
parentOperationId: operationId,
|
|
344
342
|
});
|
|
@@ -10,18 +10,9 @@ import { dbMessageSelectors, displayMessageSelectors } from '@/store/chat/select
|
|
|
10
10
|
import { toggleBooleanList } from '@/store/chat/utils';
|
|
11
11
|
import { useUserStore } from '@/store/user';
|
|
12
12
|
import { systemAgentSelectors } from '@/store/user/selectors';
|
|
13
|
-
import { ChatSemanticSearchChunk } from '@/types/chunk';
|
|
14
13
|
|
|
15
14
|
export interface ChatRAGAction {
|
|
16
15
|
deleteUserMessageRagQuery: (id: string) => Promise<void>;
|
|
17
|
-
/**
|
|
18
|
-
* Retrieve chunks from semantic search
|
|
19
|
-
*/
|
|
20
|
-
internal_retrieveChunks: (
|
|
21
|
-
id: string,
|
|
22
|
-
userQuery: string,
|
|
23
|
-
messages: string[],
|
|
24
|
-
) => Promise<{ chunks: ChatSemanticSearchChunk[]; queryId?: string; rewriteQuery?: string }>;
|
|
25
16
|
/**
|
|
26
17
|
* Rewrite user content to better RAG query
|
|
27
18
|
*/
|
|
@@ -35,7 +26,6 @@ export interface ChatRAGAction {
|
|
|
35
26
|
rewriteQuery: (id: string) => Promise<void>;
|
|
36
27
|
}
|
|
37
28
|
|
|
38
|
-
const knowledgeIds = () => agentSelectors.currentKnowledgeIds(useAgentStore.getState());
|
|
39
29
|
const hasEnabledKnowledge = () => agentSelectors.hasEnabledKnowledge(useAgentStore.getState());
|
|
40
30
|
|
|
41
31
|
export const chatRag: StateCreator<ChatStore, [['zustand/devtools', never]], [], ChatRAGAction> = (
|
|
@@ -58,43 +48,6 @@ export const chatRag: StateCreator<ChatStore, [['zustand/devtools', never]], [],
|
|
|
58
48
|
await get().refreshMessages();
|
|
59
49
|
},
|
|
60
50
|
|
|
61
|
-
internal_retrieveChunks: async (id, userQuery, messages) => {
|
|
62
|
-
get().internal_toggleMessageRAGLoading(true, id);
|
|
63
|
-
|
|
64
|
-
const message = dbMessageSelectors.getDbMessageById(id)(get());
|
|
65
|
-
|
|
66
|
-
// 1. get the rewrite query
|
|
67
|
-
let rewriteQuery = message?.ragQuery as string | undefined;
|
|
68
|
-
|
|
69
|
-
// if there is no ragQuery and there is a chat history
|
|
70
|
-
// we need to rewrite the user message to get better results
|
|
71
|
-
if (!message?.ragQuery && messages.length > 0) {
|
|
72
|
-
rewriteQuery = await get().internal_rewriteQuery(id, userQuery, messages);
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
// 2. retrieve chunks from semantic search
|
|
76
|
-
const files = dbMessageSelectors
|
|
77
|
-
.dbUserFiles(get())
|
|
78
|
-
.map((f) => f?.id)
|
|
79
|
-
.filter(Boolean) as string[];
|
|
80
|
-
try {
|
|
81
|
-
const { chunks, queryId } = await ragService.semanticSearchForChat({
|
|
82
|
-
fileIds: knowledgeIds().fileIds.concat(files),
|
|
83
|
-
knowledgeIds: knowledgeIds().knowledgeBaseIds,
|
|
84
|
-
messageId: id,
|
|
85
|
-
rewriteQuery: rewriteQuery || userQuery,
|
|
86
|
-
userQuery,
|
|
87
|
-
});
|
|
88
|
-
|
|
89
|
-
get().internal_toggleMessageRAGLoading(false, id);
|
|
90
|
-
|
|
91
|
-
return { chunks, queryId, rewriteQuery };
|
|
92
|
-
} catch {
|
|
93
|
-
get().internal_toggleMessageRAGLoading(false, id);
|
|
94
|
-
|
|
95
|
-
return { chunks: [] };
|
|
96
|
-
}
|
|
97
|
-
},
|
|
98
51
|
internal_rewriteQuery: async (id, content, messages) => {
|
|
99
52
|
let rewriteQuery = content;
|
|
100
53
|
|
|
@@ -2,7 +2,6 @@
|
|
|
2
2
|
// Disable the auto sort key eslint rule to make the code more logic and readable
|
|
3
3
|
import { AgentRuntime, type AgentRuntimeContext, type AgentState } from '@lobechat/agent-runtime';
|
|
4
4
|
import { isDesktop } from '@lobechat/const';
|
|
5
|
-
import { knowledgeBaseQAPrompts } from '@lobechat/prompts';
|
|
6
5
|
import {
|
|
7
6
|
ChatImageItem,
|
|
8
7
|
ChatToolPayload,
|
|
@@ -11,19 +10,18 @@ import {
|
|
|
11
10
|
TraceNameMap,
|
|
12
11
|
UIChatMessage,
|
|
13
12
|
} from '@lobechat/types';
|
|
14
|
-
import type { MessageSemanticSearchChunk } from '@lobechat/types';
|
|
15
13
|
import debug from 'debug';
|
|
16
14
|
import { t } from 'i18next';
|
|
17
15
|
import { throttle } from 'lodash-es';
|
|
18
16
|
import { StateCreator } from 'zustand/vanilla';
|
|
19
17
|
|
|
18
|
+
import { createAgentToolsEngine } from '@/helpers/toolEngineering';
|
|
20
19
|
import { chatService } from '@/services/chat';
|
|
21
20
|
import { messageService } from '@/services/message';
|
|
22
21
|
import { agentChatConfigSelectors, agentSelectors } from '@/store/agent/selectors';
|
|
23
22
|
import { getAgentStoreState } from '@/store/agent/store';
|
|
24
23
|
import { GeneralChatAgent } from '@/store/chat/agents/GeneralChatAgent';
|
|
25
24
|
import { createAgentExecutors } from '@/store/chat/agents/createAgentExecutors';
|
|
26
|
-
import { createAgentToolsEngine } from '@/store/chat/agents/createToolEngine';
|
|
27
25
|
import { ChatStore } from '@/store/chat/store';
|
|
28
26
|
import { getFileStoreState } from '@/store/file/store';
|
|
29
27
|
import { toolInterventionSelectors } from '@/store/user/selectors';
|
|
@@ -104,15 +102,10 @@ export interface StreamingExecutorAction {
|
|
|
104
102
|
*/
|
|
105
103
|
parentOperationId?: string;
|
|
106
104
|
inSearchWorkflow?: boolean;
|
|
107
|
-
/**
|
|
108
|
-
* the RAG query content, should be embedding and used in the semantic search
|
|
109
|
-
*/
|
|
110
|
-
ragQuery?: string;
|
|
111
105
|
threadId?: string;
|
|
112
106
|
inPortalThread?: boolean;
|
|
113
107
|
skipCreateFirstMessage?: boolean;
|
|
114
108
|
traceId?: string;
|
|
115
|
-
ragMetadata?: { ragQueryId: string; fileChunks: MessageSemanticSearchChunk[] };
|
|
116
109
|
/**
|
|
117
110
|
* Initial agent state (for resuming execution from a specific point)
|
|
118
111
|
*/
|
|
@@ -624,59 +617,17 @@ export const streamingExecutor: StateCreator<
|
|
|
624
617
|
const provider = agentConfigData.provider;
|
|
625
618
|
|
|
626
619
|
// ===========================================
|
|
627
|
-
// Step 1:
|
|
620
|
+
// Step 1: Knowledge Base Tool Integration
|
|
628
621
|
// ===========================================
|
|
629
|
-
//
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
log('[internal_execAgentRuntime] RAG preprocessing start');
|
|
633
|
-
|
|
634
|
-
// Get relevant chunks from semantic search
|
|
635
|
-
const {
|
|
636
|
-
chunks,
|
|
637
|
-
queryId: ragQueryId,
|
|
638
|
-
rewriteQuery,
|
|
639
|
-
} = await get().internal_retrieveChunks(
|
|
640
|
-
userMessageId,
|
|
641
|
-
params.ragQuery,
|
|
642
|
-
// Skip the last message content when building context
|
|
643
|
-
messages.map((m) => m.content).slice(0, messages.length - 1),
|
|
644
|
-
);
|
|
645
|
-
|
|
646
|
-
log('[internal_execAgentRuntime] RAG chunks retrieved: %d chunks', chunks.length);
|
|
647
|
-
|
|
648
|
-
const lastMsg = messages.pop() as UIChatMessage;
|
|
649
|
-
|
|
650
|
-
// Build RAG context and append to user query
|
|
651
|
-
const knowledgeBaseQAContext = knowledgeBaseQAPrompts({
|
|
652
|
-
chunks,
|
|
653
|
-
userQuery: lastMsg.content,
|
|
654
|
-
rewriteQuery,
|
|
655
|
-
knowledge: agentSelectors.currentEnabledKnowledge(agentStoreState),
|
|
656
|
-
});
|
|
657
|
-
|
|
658
|
-
messages.push({
|
|
659
|
-
...lastMsg,
|
|
660
|
-
content: (lastMsg.content + '\n\n' + knowledgeBaseQAContext).trim(),
|
|
661
|
-
});
|
|
622
|
+
// RAG retrieval is now handled by the Knowledge Base Tool
|
|
623
|
+
// The AI will decide when to call searchKnowledgeBase and readKnowledge tools
|
|
624
|
+
// based on the conversation context and available knowledge bases
|
|
662
625
|
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
id: c.id,
|
|
666
|
-
similarity: c.similarity,
|
|
667
|
-
}));
|
|
668
|
-
|
|
669
|
-
if (fileChunks.length > 0) {
|
|
670
|
-
// Note: RAG metadata will be updated after assistant message is created by call_llm executor
|
|
671
|
-
// Store RAG data temporarily in params for later use
|
|
672
|
-
params.ragMetadata = { ragQueryId: ragQueryId!, fileChunks };
|
|
673
|
-
}
|
|
674
|
-
|
|
675
|
-
log('[internal_execAgentRuntime] RAG preprocessing completed');
|
|
676
|
-
}
|
|
626
|
+
// TODO: Implement selected files full-text injection if needed
|
|
627
|
+
// User-selected files should be handled differently from knowledge base files
|
|
677
628
|
|
|
678
629
|
// ===========================================
|
|
679
|
-
// Step
|
|
630
|
+
// Step 2: Create and Execute Agent Runtime
|
|
680
631
|
// ===========================================
|
|
681
632
|
log('[internal_execAgentRuntime] Creating agent runtime');
|
|
682
633
|
|
|
@@ -829,18 +780,6 @@ export const streamingExecutor: StateCreator<
|
|
|
829
780
|
stepCount,
|
|
830
781
|
);
|
|
831
782
|
|
|
832
|
-
// Update RAG metadata if available
|
|
833
|
-
if (params.ragMetadata) {
|
|
834
|
-
const finalMessages = get().messagesMap[messageKey] || [];
|
|
835
|
-
const assistantMessage = finalMessages.findLast((m) => m.role === 'assistant');
|
|
836
|
-
if (assistantMessage) {
|
|
837
|
-
await get().optimisticUpdateMessageRAG(assistantMessage.id, params.ragMetadata, {
|
|
838
|
-
operationId,
|
|
839
|
-
});
|
|
840
|
-
log('[internal_execAgentRuntime] RAG metadata updated for assistant message');
|
|
841
|
-
}
|
|
842
|
-
}
|
|
843
|
-
|
|
844
783
|
// Complete operation
|
|
845
784
|
if (state.status === 'done') {
|
|
846
785
|
get().completeOperation(operationId);
|
|
@@ -3,13 +3,15 @@ import { StateCreator } from 'zustand/vanilla';
|
|
|
3
3
|
import { ChatStore } from '@/store/chat/store';
|
|
4
4
|
|
|
5
5
|
import { ChatCodeInterpreterAction, codeInterpreterSlice } from './interpreter';
|
|
6
|
+
import { KnowledgeBaseAction, knowledgeBaseSlice } from './knowledgeBase';
|
|
6
7
|
import { LocalFileAction, localSystemSlice } from './localSystem';
|
|
7
8
|
import { SearchAction, searchSlice } from './search';
|
|
8
9
|
|
|
9
10
|
export interface ChatBuiltinToolAction
|
|
10
11
|
extends SearchAction,
|
|
11
12
|
LocalFileAction,
|
|
12
|
-
ChatCodeInterpreterAction
|
|
13
|
+
ChatCodeInterpreterAction,
|
|
14
|
+
KnowledgeBaseAction {}
|
|
13
15
|
|
|
14
16
|
export const chatToolSlice: StateCreator<
|
|
15
17
|
ChatStore,
|
|
@@ -20,4 +22,5 @@ export const chatToolSlice: StateCreator<
|
|
|
20
22
|
...searchSlice(...params),
|
|
21
23
|
...localSystemSlice(...params),
|
|
22
24
|
...codeInterpreterSlice(...params),
|
|
25
|
+
...knowledgeBaseSlice(...params),
|
|
23
26
|
});
|
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
import debug from 'debug';
|
|
2
|
+
import { StateCreator } from 'zustand/vanilla';
|
|
3
|
+
|
|
4
|
+
import { agentSelectors } from '@/store/agent/selectors';
|
|
5
|
+
import { getAgentStoreState } from '@/store/agent/store';
|
|
6
|
+
import { ChatStore } from '@/store/chat/store';
|
|
7
|
+
import { KnowledgeBaseExecutionRuntime } from '@/tools/knowledge-base/ExecutionRuntime';
|
|
8
|
+
|
|
9
|
+
import { dbMessageSelectors } from '../../message/selectors';
|
|
10
|
+
|
|
11
|
+
const log = debug('lobe-store:builtin-tool:knowledge-base');
|
|
12
|
+
|
|
13
|
+
export interface KnowledgeBaseAction {
|
|
14
|
+
internal_triggerKnowledgeBaseToolCalling: (
|
|
15
|
+
id: string,
|
|
16
|
+
callingService: () => Promise<{ content: string; error?: any; state?: any; success: boolean }>,
|
|
17
|
+
) => Promise<boolean>;
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Read full content of specific files from knowledge base
|
|
21
|
+
*/
|
|
22
|
+
readKnowledge: (
|
|
23
|
+
id: string,
|
|
24
|
+
params: {
|
|
25
|
+
fileIds: string[];
|
|
26
|
+
},
|
|
27
|
+
) => Promise<boolean>;
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Search knowledge base for relevant files and chunks
|
|
31
|
+
*/
|
|
32
|
+
searchKnowledgeBase: (
|
|
33
|
+
id: string,
|
|
34
|
+
params: {
|
|
35
|
+
query: string;
|
|
36
|
+
topK?: number;
|
|
37
|
+
},
|
|
38
|
+
) => Promise<boolean>;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
const runtime = new KnowledgeBaseExecutionRuntime();
|
|
42
|
+
|
|
43
|
+
/* eslint-disable sort-keys-fix/sort-keys-fix */
|
|
44
|
+
export const knowledgeBaseSlice: StateCreator<
|
|
45
|
+
ChatStore,
|
|
46
|
+
[['zustand/devtools', never]],
|
|
47
|
+
[],
|
|
48
|
+
KnowledgeBaseAction
|
|
49
|
+
> = (set, get) => ({
|
|
50
|
+
readKnowledge: async (id, params) => {
|
|
51
|
+
return get().internal_triggerKnowledgeBaseToolCalling(id, async () => {
|
|
52
|
+
return await runtime.readKnowledge(params);
|
|
53
|
+
});
|
|
54
|
+
},
|
|
55
|
+
|
|
56
|
+
searchKnowledgeBase: async (id, params) => {
|
|
57
|
+
// Get knowledge base IDs and file IDs from agent store
|
|
58
|
+
const agentState = getAgentStoreState();
|
|
59
|
+
const knowledgeIds = agentSelectors.currentKnowledgeIds(agentState);
|
|
60
|
+
|
|
61
|
+
// Get user-selected files from messages
|
|
62
|
+
const userFiles = dbMessageSelectors
|
|
63
|
+
.dbUserFiles(get())
|
|
64
|
+
.map((f) => f?.id)
|
|
65
|
+
.filter(Boolean) as string[];
|
|
66
|
+
|
|
67
|
+
// Merge knowledge base files and user-selected files
|
|
68
|
+
const options = {
|
|
69
|
+
fileIds: [...knowledgeIds.fileIds, ...userFiles],
|
|
70
|
+
knowledgeBaseIds: knowledgeIds.knowledgeBaseIds,
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
return get().internal_triggerKnowledgeBaseToolCalling(id, async () => {
|
|
74
|
+
return await runtime.searchKnowledgeBase(params, {
|
|
75
|
+
fileIds: options.fileIds,
|
|
76
|
+
knowledgeBaseIds: options.knowledgeBaseIds,
|
|
77
|
+
messageId: id,
|
|
78
|
+
});
|
|
79
|
+
});
|
|
80
|
+
},
|
|
81
|
+
|
|
82
|
+
// ==================== utils ====================
|
|
83
|
+
|
|
84
|
+
internal_triggerKnowledgeBaseToolCalling: async (id, callingService) => {
|
|
85
|
+
// Get parent operationId from messageOperationMap (should be executeToolCall)
|
|
86
|
+
const parentOperationId = get().messageOperationMap[id];
|
|
87
|
+
|
|
88
|
+
// Create child operation for knowledge base execution
|
|
89
|
+
// Auto-associates message with this operation via messageId in context
|
|
90
|
+
const { operationId: knowledgeBaseOpId, abortController } = get().startOperation({
|
|
91
|
+
context: {
|
|
92
|
+
messageId: id,
|
|
93
|
+
},
|
|
94
|
+
metadata: {
|
|
95
|
+
startTime: Date.now(),
|
|
96
|
+
},
|
|
97
|
+
parentOperationId,
|
|
98
|
+
type: 'builtinToolKnowledgeBase',
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
log(
|
|
102
|
+
'[knowledgeBase] messageId=%s, parentOpId=%s, knowledgeBaseOpId=%s, aborted=%s',
|
|
103
|
+
id,
|
|
104
|
+
parentOperationId,
|
|
105
|
+
knowledgeBaseOpId,
|
|
106
|
+
abortController.signal.aborted,
|
|
107
|
+
);
|
|
108
|
+
|
|
109
|
+
const context = { operationId: knowledgeBaseOpId };
|
|
110
|
+
|
|
111
|
+
try {
|
|
112
|
+
const { state, content, success, error } = await callingService();
|
|
113
|
+
|
|
114
|
+
// Complete knowledge base operation
|
|
115
|
+
get().completeOperation(knowledgeBaseOpId);
|
|
116
|
+
|
|
117
|
+
if (success) {
|
|
118
|
+
if (state) {
|
|
119
|
+
await get().optimisticUpdatePluginState(id, state, context);
|
|
120
|
+
}
|
|
121
|
+
await get().optimisticUpdateMessageContent(id, content, undefined, context);
|
|
122
|
+
} else {
|
|
123
|
+
await get().optimisticUpdateMessagePluginError(
|
|
124
|
+
id,
|
|
125
|
+
{
|
|
126
|
+
body: error,
|
|
127
|
+
message: error?.message || 'Operation failed',
|
|
128
|
+
type: 'PluginServerError',
|
|
129
|
+
},
|
|
130
|
+
context,
|
|
131
|
+
);
|
|
132
|
+
// Still update content even if failed, to show error message
|
|
133
|
+
await get().optimisticUpdateMessageContent(id, content, undefined, context);
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
return true;
|
|
137
|
+
} catch (error) {
|
|
138
|
+
const err = error as Error;
|
|
139
|
+
|
|
140
|
+
log('[knowledgeBase] Error: messageId=%s, error=%s', id, err.message);
|
|
141
|
+
|
|
142
|
+
// Check if it's an abort error
|
|
143
|
+
if (err.message.includes('The user aborted a request.') || err.name === 'AbortError') {
|
|
144
|
+
log('[knowledgeBase] Request aborted: messageId=%s', id);
|
|
145
|
+
// Fail knowledge base operation for abort
|
|
146
|
+
get().failOperation(knowledgeBaseOpId, {
|
|
147
|
+
message: 'User cancelled the request',
|
|
148
|
+
type: 'UserAborted',
|
|
149
|
+
});
|
|
150
|
+
// Don't update error message for user aborts
|
|
151
|
+
return false;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
// Fail knowledge base operation for other errors
|
|
155
|
+
get().failOperation(knowledgeBaseOpId, {
|
|
156
|
+
message: err.message,
|
|
157
|
+
type: 'PluginServerError',
|
|
158
|
+
});
|
|
159
|
+
|
|
160
|
+
// For other errors, update message
|
|
161
|
+
await get().optimisticUpdateMessagePluginError(
|
|
162
|
+
id,
|
|
163
|
+
{
|
|
164
|
+
body: error,
|
|
165
|
+
message: err.message,
|
|
166
|
+
type: 'PluginServerError',
|
|
167
|
+
},
|
|
168
|
+
context,
|
|
169
|
+
);
|
|
170
|
+
|
|
171
|
+
return false;
|
|
172
|
+
}
|
|
173
|
+
},
|
|
174
|
+
});
|
|
@@ -36,6 +36,7 @@ export type OperationType =
|
|
|
36
36
|
| 'builtinToolSearch' // Builtin tool: search
|
|
37
37
|
| 'builtinToolInterpreter' // Builtin tool: code interpreter
|
|
38
38
|
| 'builtinToolLocalSystem' // Builtin tool: local system
|
|
39
|
+
| 'builtinToolKnowledgeBase' // Builtin tool: knowledge base
|
|
39
40
|
|
|
40
41
|
// === Group Chat ===
|
|
41
42
|
| 'supervisorDecision' // Supervisor decision
|
|
@@ -178,7 +178,6 @@ export const chatThreadMessage: StateCreator<
|
|
|
178
178
|
parentMessageType: 'user',
|
|
179
179
|
sessionId: get().activeId,
|
|
180
180
|
topicId: get().activeTopicId,
|
|
181
|
-
ragQuery: get().internal_shouldUseRAG() ? message : undefined,
|
|
182
181
|
threadId: get().portalThreadId,
|
|
183
182
|
inPortalThread: true,
|
|
184
183
|
});
|
|
@@ -1,9 +1,12 @@
|
|
|
1
|
+
import { KnowledgeBaseManifest } from './knowledge-base';
|
|
2
|
+
import { KnowledgeBaseExecutionRuntime } from './knowledge-base/ExecutionRuntime';
|
|
1
3
|
import { LocalSystemManifest } from './local-system';
|
|
2
4
|
import { LocalSystemExecutionRuntime } from './local-system/ExecutionRuntime';
|
|
3
5
|
import { WebBrowsingManifest } from './web-browsing';
|
|
4
6
|
import { WebBrowsingExecutionRuntime } from './web-browsing/ExecutionRuntime';
|
|
5
7
|
|
|
6
8
|
export const BuiltinToolServerRuntimes: Record<string, any> = {
|
|
9
|
+
[KnowledgeBaseManifest.identifier]: KnowledgeBaseExecutionRuntime,
|
|
7
10
|
[LocalSystemManifest.identifier]: LocalSystemExecutionRuntime,
|
|
8
11
|
[WebBrowsingManifest.identifier]: WebBrowsingExecutionRuntime,
|
|
9
12
|
};
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { ArtifactsManifest } from './artifacts';
|
|
2
|
+
import { CodeInterpreterManifest } from './code-interpreter';
|
|
3
|
+
import { KnowledgeBaseManifest } from './knowledge-base';
|
|
4
|
+
import { LocalSystemManifest } from './local-system';
|
|
5
|
+
import { WebBrowsingManifest } from './web-browsing';
|
|
6
|
+
|
|
7
|
+
export const builtinToolIdentifiers: string[] = [
|
|
8
|
+
ArtifactsManifest.identifier,
|
|
9
|
+
LocalSystemManifest.identifier,
|
|
10
|
+
WebBrowsingManifest.identifier,
|
|
11
|
+
KnowledgeBaseManifest.identifier,
|
|
12
|
+
CodeInterpreterManifest.identifier,
|
|
13
|
+
];
|
package/src/tools/index.ts
CHANGED
|
@@ -4,6 +4,7 @@ import { isDesktop } from '@/const/version';
|
|
|
4
4
|
|
|
5
5
|
import { ArtifactsManifest } from './artifacts';
|
|
6
6
|
import { CodeInterpreterManifest } from './code-interpreter';
|
|
7
|
+
import { KnowledgeBaseManifest } from './knowledge-base';
|
|
7
8
|
import { LocalSystemManifest } from './local-system';
|
|
8
9
|
import { WebBrowsingManifest } from './web-browsing';
|
|
9
10
|
|
|
@@ -30,4 +31,10 @@ export const builtinTools: LobeBuiltinTool[] = [
|
|
|
30
31
|
manifest: CodeInterpreterManifest,
|
|
31
32
|
type: 'builtin',
|
|
32
33
|
},
|
|
34
|
+
{
|
|
35
|
+
hidden: true,
|
|
36
|
+
identifier: KnowledgeBaseManifest.identifier,
|
|
37
|
+
manifest: KnowledgeBaseManifest,
|
|
38
|
+
type: 'builtin',
|
|
39
|
+
},
|
|
33
40
|
];
|