@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.
Files changed (150) hide show
  1. package/.console-log-whitelist.json +14 -0
  2. package/.github/workflows/check-console-log.yml +117 -0
  3. package/.github/workflows/desktop-pr-build.yml +4 -4
  4. package/.github/workflows/release-desktop-beta.yml +4 -4
  5. package/.github/workflows/release.yml +1 -1
  6. package/.github/workflows/test.yml +5 -5
  7. package/CHANGELOG.md +58 -0
  8. package/apps/desktop/src/main/services/__tests__/fileSrv.test.ts +603 -0
  9. package/changelog/v1.json +21 -0
  10. package/codecov.yml +1 -0
  11. package/docs/development/database-schema.dbml +1 -0
  12. package/e2e/package.json +1 -1
  13. package/locales/ar/file.json +9 -11
  14. package/locales/ar/plugin.json +34 -22
  15. package/locales/ar/tool.json +8 -0
  16. package/locales/bg-BG/file.json +8 -10
  17. package/locales/bg-BG/plugin.json +34 -22
  18. package/locales/bg-BG/tool.json +8 -0
  19. package/locales/de-DE/file.json +9 -11
  20. package/locales/de-DE/plugin.json +34 -22
  21. package/locales/de-DE/tool.json +8 -0
  22. package/locales/en-US/file.json +12 -14
  23. package/locales/en-US/plugin.json +34 -22
  24. package/locales/en-US/tool.json +8 -0
  25. package/locales/es-ES/file.json +7 -9
  26. package/locales/es-ES/plugin.json +34 -22
  27. package/locales/es-ES/tool.json +8 -0
  28. package/locales/fa-IR/file.json +9 -11
  29. package/locales/fa-IR/plugin.json +34 -22
  30. package/locales/fa-IR/tool.json +8 -0
  31. package/locales/fr-FR/file.json +6 -8
  32. package/locales/fr-FR/plugin.json +34 -22
  33. package/locales/fr-FR/tool.json +8 -0
  34. package/locales/it-IT/file.json +8 -10
  35. package/locales/it-IT/plugin.json +34 -22
  36. package/locales/it-IT/tool.json +8 -0
  37. package/locales/ja-JP/file.json +10 -12
  38. package/locales/ja-JP/plugin.json +34 -22
  39. package/locales/ja-JP/tool.json +8 -0
  40. package/locales/ko-KR/file.json +8 -10
  41. package/locales/ko-KR/plugin.json +34 -22
  42. package/locales/ko-KR/tool.json +8 -0
  43. package/locales/nl-NL/file.json +8 -10
  44. package/locales/nl-NL/plugin.json +34 -22
  45. package/locales/nl-NL/tool.json +8 -0
  46. package/locales/pl-PL/file.json +7 -9
  47. package/locales/pl-PL/plugin.json +34 -22
  48. package/locales/pl-PL/tool.json +8 -0
  49. package/locales/pt-BR/file.json +7 -9
  50. package/locales/pt-BR/plugin.json +34 -22
  51. package/locales/pt-BR/tool.json +8 -0
  52. package/locales/ru-RU/file.json +9 -11
  53. package/locales/ru-RU/plugin.json +34 -22
  54. package/locales/ru-RU/tool.json +8 -0
  55. package/locales/tr-TR/file.json +8 -10
  56. package/locales/tr-TR/plugin.json +34 -22
  57. package/locales/tr-TR/tool.json +8 -0
  58. package/locales/vi-VN/file.json +9 -11
  59. package/locales/vi-VN/plugin.json +34 -22
  60. package/locales/vi-VN/tool.json +8 -0
  61. package/locales/zh-CN/file.json +10 -12
  62. package/locales/zh-CN/plugin.json +34 -22
  63. package/locales/zh-CN/tool.json +8 -0
  64. package/locales/zh-TW/file.json +10 -12
  65. package/locales/zh-TW/plugin.json +34 -22
  66. package/locales/zh-TW/tool.json +8 -0
  67. package/package.json +3 -2
  68. package/packages/database/migrations/0047_add_slug_document.sql +6 -0
  69. package/packages/database/migrations/meta/0047_snapshot.json +7891 -0
  70. package/packages/database/migrations/meta/_journal.json +7 -0
  71. package/packages/database/src/core/migrations.json +16 -7
  72. package/packages/database/src/models/__tests__/document.test.ts +149 -0
  73. package/packages/database/src/models/chunk.ts +3 -1
  74. package/packages/database/src/models/document.ts +10 -4
  75. package/packages/database/src/schemas/file.ts +7 -1
  76. package/packages/model-bank/src/aiModels/qwen.ts +5 -3
  77. package/packages/model-runtime/src/core/openaiCompatibleFactory/index.ts +21 -21
  78. package/packages/obervability-otel/package.json +2 -2
  79. package/packages/prompts/src/prompts/knowledgeBaseQA/__snapshots__/formatFileContents.test.ts.snap +75 -0
  80. package/packages/prompts/src/prompts/knowledgeBaseQA/__snapshots__/formatNoSearchResults.test.ts.snap +45 -0
  81. package/packages/prompts/src/prompts/knowledgeBaseQA/__snapshots__/formatSearchResults.test.ts.snap +82 -0
  82. package/packages/prompts/src/prompts/knowledgeBaseQA/formatFileContents.test.ts +118 -0
  83. package/packages/prompts/src/prompts/knowledgeBaseQA/formatFileContents.ts +31 -0
  84. package/packages/prompts/src/prompts/knowledgeBaseQA/formatNoSearchResults.test.ts +25 -0
  85. package/packages/prompts/src/prompts/knowledgeBaseQA/formatNoSearchResults.ts +13 -0
  86. package/packages/prompts/src/prompts/knowledgeBaseQA/formatSearchResults.test.ts +191 -0
  87. package/packages/prompts/src/prompts/knowledgeBaseQA/formatSearchResults.ts +50 -0
  88. package/packages/prompts/src/prompts/knowledgeBaseQA/index.ts +6 -0
  89. package/packages/types/src/rag.ts +13 -4
  90. package/scripts/checkConsoleLog.mts +148 -0
  91. package/scripts/prebuild.mts +5 -5
  92. package/src/app/[variants]/(main)/changelog/index.tsx +1 -1
  93. package/src/app/[variants]/(main)/settings/_layout/Desktop/index.tsx +20 -16
  94. package/src/app/[variants]/(main)/settings/provider/(list)/ProviderGrid/Card.tsx +6 -3
  95. package/src/app/[variants]/(main)/settings/provider/(list)/index.tsx +3 -2
  96. package/src/app/[variants]/(main)/settings/provider/detail/index.tsx +14 -4
  97. package/src/app/[variants]/desktopRouter.config.tsx +23 -0
  98. package/src/app/[variants]/mobileRouter.config.tsx +23 -0
  99. package/src/features/ChatInput/ActionBar/Token/TokenTag.tsx +2 -2
  100. package/src/features/ChatInput/ActionBar/Token/TokenTagForGroupChat.tsx +2 -2
  101. package/src/features/ChatList/Messages/Group/Tool/Inspector/ToolTitle.tsx +5 -23
  102. package/src/features/ChatList/Messages/Tool/Inspector/ToolTitle.tsx +5 -25
  103. package/src/features/KnowledgeManager/DocumentExplorer/NoteEditorModal.tsx +0 -20
  104. package/src/features/KnowledgeManager/DocumentExplorer/index.tsx +3 -3
  105. package/src/features/KnowledgeManager/FileExplorer/MasonryFileItem/index.tsx +0 -20
  106. package/src/features/KnowledgeManager/Header/AddButton.tsx +0 -1
  107. package/src/features/KnowledgeManager/Header/NewNoteButton.tsx +1 -1
  108. package/src/features/KnowledgeManager/Header/TogglePanelButton.tsx +2 -2
  109. package/src/features/KnowledgeManager/Home/UploadEntries.tsx +2 -2
  110. package/src/features/KnowledgeManager/Home/index.tsx +4 -4
  111. package/src/features/PluginsUI/Render/BuiltinType/index.tsx +1 -1
  112. package/src/features/User/UserPanel/useMenu.tsx +7 -3
  113. package/src/helpers/toolEngineering/index.test.ts +3 -3
  114. package/src/helpers/toolEngineering/index.ts +17 -4
  115. package/src/libs/trpc/client/lambda.ts +0 -6
  116. package/src/locales/default/file.ts +11 -13
  117. package/src/locales/default/plugin.ts +34 -22
  118. package/src/locales/default/tool.ts +13 -5
  119. package/src/server/routers/lambda/chunk.ts +168 -41
  120. package/src/services/chat/chat.test.ts +3 -3
  121. package/src/services/chat/index.ts +2 -2
  122. package/src/services/rag.ts +6 -2
  123. package/src/store/chat/agents/__tests__/createAgentExecutors/helpers/testExecutor.ts +1 -4
  124. package/src/store/chat/slices/aiChat/actions/__tests__/conversationLifecycle.test.ts +11 -0
  125. package/src/store/chat/slices/aiChat/actions/__tests__/rag.test.ts +0 -87
  126. package/src/store/chat/slices/aiChat/actions/__tests__/streamingExecutor.test.ts +2 -69
  127. package/src/store/chat/slices/aiChat/actions/conversationLifecycle.ts +0 -2
  128. package/src/store/chat/slices/aiChat/actions/rag.ts +0 -47
  129. package/src/store/chat/slices/aiChat/actions/streamingExecutor.ts +8 -69
  130. package/src/store/chat/slices/builtinTool/actions/index.ts +4 -1
  131. package/src/store/chat/slices/builtinTool/actions/knowledgeBase.ts +174 -0
  132. package/src/store/chat/slices/operation/types.ts +1 -0
  133. package/src/store/chat/slices/thread/action.test.ts +0 -1
  134. package/src/store/chat/slices/thread/action.ts +0 -1
  135. package/src/tools/executionRuntimes.ts +3 -0
  136. package/src/tools/identifiers.ts +13 -0
  137. package/src/tools/index.ts +7 -0
  138. package/src/tools/knowledge-base/ExecutionRuntime/index.ts +96 -0
  139. package/src/tools/knowledge-base/Render/ReadKnowledge/FileCard.tsx +135 -0
  140. package/src/tools/knowledge-base/Render/ReadKnowledge/index.tsx +27 -0
  141. package/src/tools/knowledge-base/Render/SearchKnowledgeBase/Item/index.tsx +54 -0
  142. package/src/tools/knowledge-base/Render/SearchKnowledgeBase/Item/style.ts +51 -0
  143. package/src/tools/knowledge-base/Render/SearchKnowledgeBase/index.tsx +23 -0
  144. package/src/tools/knowledge-base/Render/index.ts +7 -0
  145. package/src/tools/knowledge-base/index.ts +64 -0
  146. package/src/tools/knowledge-base/systemRole.ts +102 -0
  147. package/src/tools/knowledge-base/type.ts +25 -0
  148. package/src/tools/local-system/Intervention/WriteFile/index.tsx +1 -1
  149. package/src/tools/renders.ts +4 -0
  150. package/src/store/chat/agents/createToolEngine.ts +0 -22
@@ -1,6 +1,7 @@
1
1
  'use client';
2
2
 
3
3
  import { useResponsive, useTheme } from 'antd-style';
4
+ import useMergedState from 'rc-util/lib/hooks/useMergedState';
4
5
  import { memo, useEffect, useRef } from 'react';
5
6
  import { Flexbox } from 'react-layout-kit';
6
7
  import { useSearchParams } from 'react-router-dom';
@@ -13,7 +14,6 @@ import SettingsContent from '../SettingsContent';
13
14
  import { LayoutProps } from '../type';
14
15
  import Header from './Header';
15
16
  import SideBar from './SideBar';
16
- import useMergedState from 'rc-util/lib/hooks/useMergedState';
17
17
 
18
18
  const Layout = memo<LayoutProps>(() => {
19
19
  const ref = useRef<HTMLDivElement | null>(null);
@@ -22,21 +22,23 @@ const Layout = memo<LayoutProps>(() => {
22
22
 
23
23
  const [searchParams, setSearchParams] = useSearchParams();
24
24
 
25
- const [activeTabState, setActiveTabState] = useMergedState({
26
- active: searchParams.get('active') as SettingsTabs ? searchParams.get('active') as SettingsTabs : SettingsTabs.Common,
27
- }, {
28
- onChange: (obj: {
29
- active: SettingsTabs;
30
- provider?: string;
31
- }) => {
32
- if (obj.provider) {
33
- setSearchParams({ active: obj.active, provider: obj.provider });
34
- } else {
35
- searchParams.delete('provider');
36
- setSearchParams({ active: obj.active });
37
- }
25
+ const [activeTabState, setActiveTabState] = useMergedState(
26
+ {
27
+ active: (searchParams.get('active') as SettingsTabs)
28
+ ? (searchParams.get('active') as SettingsTabs)
29
+ : SettingsTabs.Common,
30
+ },
31
+ {
32
+ onChange: (obj: { active: SettingsTabs; provider?: string }) => {
33
+ if (obj.provider) {
34
+ setSearchParams({ active: obj.active, provider: obj.provider });
35
+ } else {
36
+ searchParams.delete('provider');
37
+ setSearchParams({ active: obj.active });
38
+ }
39
+ },
38
40
  },
39
- });
41
+ );
40
42
 
41
43
  const setActiveTab = (tab: SettingsTabs) => {
42
44
  if (tab === SettingsTabs.Provider) {
@@ -57,7 +59,9 @@ const Layout = memo<LayoutProps>(() => {
57
59
  };
58
60
  }, []);
59
61
 
60
- const category = <CategoryContent activeTab={activeTabState.active} onMenuSelect={setActiveTab} />;
62
+ const category = (
63
+ <CategoryContent activeTab={activeTabState.active} onMenuSelect={setActiveTab} />
64
+ );
61
65
 
62
66
  return (
63
67
  <Flexbox
@@ -33,9 +33,12 @@ const ProviderCard = memo<ProviderCardProps>(
33
33
  return (
34
34
  <Flexbox className={cx(styles.container)} gap={24}>
35
35
  <Flexbox gap={12} padding={16} width={'100%'}>
36
- <div onClick={() => {
37
- onProviderSelect(id);
38
- }} style={{ cursor: 'pointer' }}>
36
+ <div
37
+ onClick={() => {
38
+ onProviderSelect(id);
39
+ }}
40
+ style={{ cursor: 'pointer' }}
41
+ >
39
42
  <Flexbox gap={12} width={'100%'}>
40
43
  <Flexbox align={'center'} horizontal justify={'space-between'}>
41
44
  {source === 'builtin' ? (
@@ -1,13 +1,14 @@
1
1
  'use client';
2
2
 
3
+ import { useMemo, useState } from 'react';
4
+ import { useSearchParams } from 'react-router-dom';
5
+
3
6
  import { isCustomBranding } from '@/const/version';
4
7
 
5
8
  import DesktopLayout from '../_layout/Desktop';
6
9
  import MobileLayout from '../_layout/Mobile';
7
10
  import ProviderDetailPage from '../detail';
8
11
  import Footer from './Footer';
9
- import { useMemo, useState } from 'react';
10
- import { useSearchParams } from 'react-router-dom';
11
12
 
12
13
  const Page = (props: { mobile?: boolean }) => {
13
14
  const [SearchParams, setSearchParams] = useSearchParams();
@@ -1,4 +1,5 @@
1
1
  import dynamic from 'next/dynamic';
2
+
2
3
  import Loading from '@/components/Loading/BrandTextLoading';
3
4
 
4
5
  const NewAPI = dynamic(() => import('./newapi'), { loading: () => <Loading />, ssr: false });
@@ -7,17 +8,26 @@ const VertexAI = dynamic(() => import('./vertexai'), { loading: () => <Loading /
7
8
  const GitHub = dynamic(() => import('./github'), { loading: () => <Loading />, ssr: false });
8
9
  const Ollama = dynamic(() => import('./ollama'), { loading: () => <Loading />, ssr: false });
9
10
  const ComfyUI = dynamic(() => import('./comfyui'), { loading: () => <Loading />, ssr: false });
10
- const Cloudflare = dynamic(() => import('./cloudflare'), { loading: () => <Loading />, ssr: false });
11
+ const Cloudflare = dynamic(() => import('./cloudflare'), {
12
+ loading: () => <Loading />,
13
+ ssr: false,
14
+ });
11
15
  const Bedrock = dynamic(() => import('./bedrock'), { loading: () => <Loading />, ssr: false });
12
16
  const AzureAI = dynamic(() => import('./azureai'), { loading: () => <Loading />, ssr: false });
13
17
  const Azure = dynamic(() => import('./azure'), { loading: () => <Loading />, ssr: false });
14
- const ProviderGrid = dynamic(() => import('../(list)/ProviderGrid'), { loading: () => <Loading />, ssr: false });
15
- const DefaultPage = dynamic(() => import('./default/ProviderDetialPage'), { loading: () => <Loading />, ssr: false });
18
+ const ProviderGrid = dynamic(() => import('../(list)/ProviderGrid'), {
19
+ loading: () => <Loading />,
20
+ ssr: false,
21
+ });
22
+ const DefaultPage = dynamic(() => import('./default/ProviderDetialPage'), {
23
+ loading: () => <Loading />,
24
+ ssr: false,
25
+ });
16
26
 
17
27
  type ProviderDetailPageProps = {
18
28
  id?: string | null;
19
29
  onProviderSelect: (provider: string) => void;
20
- }
30
+ };
21
31
 
22
32
  const ProviderDetailPage = (props: ProviderDetailPageProps) => {
23
33
  const { id, onProviderSelect } = props;
@@ -40,6 +40,16 @@ const ChatLayout = dynamic(() => import('./(main)/chat/_layout/Desktop'), {
40
40
  ssr: false,
41
41
  });
42
42
 
43
+ // Changelog components
44
+ const ChangelogPage = dynamic(() => import('./(main)/changelog/index').then((m) => m.DesktopPage), {
45
+ loading: () => <Loading />,
46
+ ssr: false,
47
+ });
48
+ const ChangelogLayout = dynamic(() => import('./(main)/changelog/_layout/Desktop'), {
49
+ loading: () => <Loading />,
50
+ ssr: false,
51
+ });
52
+
43
53
  // Discover List components
44
54
  const DesktopHomePage = dynamic(
45
55
  () => import('./(main)/discover/(list)/(home)/index').then((m) => m.DesktopHomePage),
@@ -256,6 +266,7 @@ const KnowledgeErrorBoundary = createErrorBoundary('/knowledge');
256
266
  const SettingsErrorBoundary = createErrorBoundary('/settings');
257
267
  const ImageErrorBoundary = createErrorBoundary('/image');
258
268
  const ProfileErrorBoundary = createErrorBoundary('/profile');
269
+ const ChangelogErrorBoundary = createErrorBoundary('/changelog');
259
270
  const RootErrorBoundary = createErrorBoundary('/chat'); // Root level falls back to chat
260
271
 
261
272
  // Root layout wrapper component
@@ -455,6 +466,18 @@ export const createDesktopRouter = (locale: Locales) =>
455
466
  path: 'profile',
456
467
  },
457
468
 
469
+ // changelog routes
470
+ {
471
+ children: [
472
+ {
473
+ element: <ChangelogPage />,
474
+ index: true,
475
+ },
476
+ ],
477
+ element: <ChangelogLayout locale={locale} />,
478
+ errorElement: <ChangelogErrorBoundary />,
479
+ path: 'changelog',
480
+ },
458
481
  // Default route - redirect to chat
459
482
  {
460
483
  index: true,
@@ -41,6 +41,15 @@ const ChatLayout = dynamic(() => import('./(main)/chat/_layout/Mobile'), {
41
41
  ssr: false,
42
42
  });
43
43
 
44
+ // Changelog components
45
+ const ChangelogPage = dynamic(() => import('./(main)/changelog/index').then((m) => m.MobilePage), {
46
+ loading: () => <Loading />,
47
+ ssr: false,
48
+ });
49
+ const ChangelogLayout = dynamic(() => import('./(main)/changelog/_layout/Mobile'), {
50
+ loading: () => <Loading />,
51
+ ssr: false,
52
+ });
44
53
  // Discover List components
45
54
  const MobileHomePage = dynamic(
46
55
  () => import('./(main)/discover/(list)/(home)/index').then((m) => m.MobileHomePage),
@@ -272,6 +281,7 @@ const createErrorBoundary = (resetPath: string) => {
272
281
  // Create error boundaries for each route
273
282
  const ChatErrorBoundary = createErrorBoundary('/chat');
274
283
  const DiscoverErrorBoundary = createErrorBoundary('/discover');
284
+ const ChangelogErrorBoundary = createErrorBoundary('/changelog');
275
285
  const KnowledgeErrorBoundary = createErrorBoundary('/knowledge');
276
286
  const SettingsErrorBoundary = createErrorBoundary('/settings');
277
287
  const ImageErrorBoundary = createErrorBoundary('/image');
@@ -499,6 +509,19 @@ export const createMobileRouter = (locale: Locales) =>
499
509
  path: 'me',
500
510
  },
501
511
 
512
+ // changelog routes
513
+ {
514
+ children: [
515
+ {
516
+ element: <ChangelogPage />,
517
+ index: true,
518
+ },
519
+ ],
520
+ element: <ChangelogLayout locale={locale} />,
521
+ errorElement: <ChangelogErrorBoundary />,
522
+ path: 'changelog',
523
+ },
524
+
502
525
  // Default route - redirect to chat
503
526
  {
504
527
  index: true,
@@ -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 { createChatToolsEngine } from '@/helpers/toolEngineering';
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 = createChatToolsEngine({ model, provider });
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 { createChatToolsEngine } from '@/helpers/toolEngineering';
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 = createChatToolsEngine({ model, provider });
79
+ const toolsEngine = createAgentToolsEngine({ model, provider });
80
80
 
81
81
  const { tools, enabledToolIds } = toolsEngine.generateToolsDetailed({
82
82
  model,
@@ -2,15 +2,14 @@ import { Icon } from '@lobehub/ui';
2
2
  import { createStyles } from 'antd-style';
3
3
  import isEqual from 'fast-deep-equal';
4
4
  import { ChevronRight } from 'lucide-react';
5
- import { memo, useMemo } from 'react';
5
+ import { memo } from 'react';
6
6
  import { useTranslation } from 'react-i18next';
7
7
  import { Flexbox } from 'react-layout-kit';
8
8
 
9
9
  import { pluginHelpers, useToolStore } from '@/store/tool';
10
10
  import { toolSelectors } from '@/store/tool/selectors';
11
11
  import { shinyTextStylish } from '@/styles/loading';
12
- import { LocalSystemManifest } from '@/tools/local-system';
13
- import { WebBrowsingManifest } from '@/tools/web-browsing';
12
+ import { builtinToolIdentifiers } from '@/tools/identifiers';
14
13
 
15
14
  import BuiltinPluginTitle from './BuiltinPluginTitle';
16
15
 
@@ -49,33 +48,16 @@ const ToolTitle = memo<ToolTitleProps>(
49
48
 
50
49
  const pluginMeta = useToolStore(toolSelectors.getMetaById(identifier), isEqual);
51
50
 
52
- const plugins = useMemo(
53
- () => [
54
- {
55
- apiName: t(`search.apiName.${apiName}`, apiName),
56
- id: WebBrowsingManifest.identifier,
57
- title: t('search.title'),
58
- },
59
- {
60
- apiName: t(`localSystem.apiName.${apiName}`, apiName),
61
- id: LocalSystemManifest.identifier,
62
- title: t('localSystem.title'),
63
- },
64
- ],
65
- [],
66
- );
67
-
68
- const builtinPluginTitle = plugins.find((item) => item.id === identifier);
69
-
70
- if (!!builtinPluginTitle) {
51
+ if (builtinToolIdentifiers.includes(identifier)) {
71
52
  return (
72
53
  <BuiltinPluginTitle
73
- {...builtinPluginTitle}
54
+ apiName={t(`builtins.${identifier}.apiName.${apiName}`, apiName)}
74
55
  identifier={identifier}
75
56
  index={index}
76
57
  isExpanded={isExpanded}
77
58
  isLoading={isLoading}
78
59
  messageId={messageId}
60
+ title={t(`builtins.${identifier}.title`, identifier)}
79
61
  toolCallId={toolCallId}
80
62
  />
81
63
  );
@@ -2,15 +2,14 @@ import { Icon } from '@lobehub/ui';
2
2
  import { createStyles } from 'antd-style';
3
3
  import isEqual from 'fast-deep-equal';
4
4
  import { ChevronRight } from 'lucide-react';
5
- import { memo, useMemo } from 'react';
5
+ import { memo } from 'react';
6
6
  import { useTranslation } from 'react-i18next';
7
7
  import { Flexbox } from 'react-layout-kit';
8
8
 
9
9
  import { pluginHelpers, useToolStore } from '@/store/tool';
10
10
  import { toolSelectors } from '@/store/tool/selectors';
11
11
  import { shinyTextStylish } from '@/styles/loading';
12
- import { LocalSystemManifest } from '@/tools/local-system';
13
- import { WebBrowsingManifest } from '@/tools/web-browsing';
12
+ import { builtinToolIdentifiers } from '@/tools/identifiers';
14
13
 
15
14
  import BuiltinPluginTitle from './BuiltinPluginTitle';
16
15
 
@@ -43,33 +42,14 @@ const ToolTitle = memo<ToolTitleProps>(({ identifier, messageId, index, apiName,
43
42
 
44
43
  const pluginMeta = useToolStore(toolSelectors.getMetaById(identifier), isEqual);
45
44
 
46
- const plugins = useMemo(
47
- () => [
48
- {
49
- apiName: t(`search.apiName.${apiName}`, apiName),
50
- // icon: <Icon icon={Globe} size={13} />,
51
- id: WebBrowsingManifest.identifier,
52
- title: t('search.title'),
53
- },
54
- {
55
- apiName: t(`localSystem.apiName.${apiName}`, apiName),
56
- // icon: <Icon icon={Laptop} size={13} />,
57
- id: LocalSystemManifest.identifier,
58
- title: t('localSystem.title'),
59
- },
60
- ],
61
- [],
62
- );
63
-
64
- const builtinPluginTitle = plugins.find((item) => item.id === identifier);
65
-
66
- if (!!builtinPluginTitle) {
45
+ if (builtinToolIdentifiers.includes(identifier)) {
67
46
  return (
68
47
  <BuiltinPluginTitle
69
- {...builtinPluginTitle}
48
+ apiName={t(`builtins.${identifier}.apiName.${apiName}`, apiName)}
70
49
  identifier={identifier}
71
50
  index={index}
72
51
  messageId={messageId}
52
+ title={t(`builtins.${identifier}.title`, identifier)}
73
53
  toolCallId={toolCallId}
74
54
  />
75
55
  );
@@ -143,40 +143,20 @@ const NoteEditorModal = memo<NoteEditorModalProps>(
143
143
  const handleOpenChange = (isOpen: boolean) => {
144
144
  // When modal opens, load document content if in edit mode
145
145
  if (isOpen && documentId && editor) {
146
- console.log('[NoteEditorModal] Loading content:', {
147
- cachedEditorDataPreview: cachedEditorData
148
- ? JSON.stringify(cachedEditorData).slice(0, 100)
149
- : null,
150
- cachedEditorDataType: typeof cachedEditorData,
151
- documentId,
152
- documentTitle,
153
- hasCachedEditorData: !!cachedEditorData,
154
- });
155
-
156
146
  // If editorData is already cached (from list), use it directly
157
147
  if (cachedEditorData) {
158
- console.log('[NoteEditorModal] Using cached editorData', cachedEditorData);
159
148
  setNoteTitle(documentTitle || '');
160
149
  editor.setDocument('json', JSON.stringify(cachedEditorData));
161
150
  return;
162
151
  }
163
152
 
164
153
  // Otherwise, fetch full content from API
165
- console.log('[NoteEditorModal] Fetching from API');
166
154
  documentService
167
155
  .getDocumentById(documentId)
168
156
  .then((doc) => {
169
157
  if (doc && doc.content) {
170
158
  setNoteTitle(doc.title || doc.filename || '');
171
159
 
172
- console.log('[NoteEditorModal] Fetched doc.editorData:', {
173
- editorDataPreview: doc.editorData
174
- ? JSON.stringify(doc.editorData).slice(0, 100)
175
- : null,
176
- editorDataType: typeof doc.editorData,
177
- hasEditorData: !!doc.editorData,
178
- });
179
-
180
160
  editor.setDocument('json', doc.editorData);
181
161
  }
182
162
  })
@@ -228,7 +228,7 @@ const DocumentExplorer = memo<DocumentExplorerProps>(({ knowledgeBaseId, documen
228
228
  <SearchBar
229
229
  allowClear
230
230
  onChange={(e) => setSearchKeywords(e.target.value)}
231
- placeholder={t('searchDocumentPlaceholder')}
231
+ placeholder={t('searchPagePlaceholder')}
232
232
  style={{ flex: 1 }}
233
233
  value={searchKeywords}
234
234
  variant={'borderless'}
@@ -236,7 +236,7 @@ const DocumentExplorer = memo<DocumentExplorerProps>(({ knowledgeBaseId, documen
236
236
  <ActionIcon
237
237
  icon={PlusIcon}
238
238
  onClick={handleNewDocument}
239
- title={t('header.newDocumentButton')}
239
+ title={t('header.newPageButton')}
240
240
  />
241
241
  </div>
242
242
  <div className={styles.documentList}>
@@ -252,7 +252,7 @@ const DocumentExplorer = memo<DocumentExplorerProps>(({ knowledgeBaseId, documen
252
252
  Footer: () => (
253
253
  <Center style={{ paddingBlock: 16 }}>
254
254
  <Text style={{ fontSize: 12 }} type={'secondary'}>
255
- {t('documentList.documentCount', { count: filteredDocuments.length })}
255
+ {t('documentList.pageCount', { count: filteredDocuments.length })}
256
256
  </Text>
257
257
  </Center>
258
258
  ),
@@ -177,19 +177,6 @@ const MasonryFileItem = memo<MasonryFileItemProps>(
177
177
  const isMarkdown = isMarkdownFile(name, fileType);
178
178
  const isNote = isCustomNote(fileType);
179
179
 
180
- // Debug: Log editorData for notes
181
- useEffect(() => {
182
- if (isNote) {
183
- console.log('[MasonryFileItem] Note item:', {
184
- editorDataPreview: editorData ? JSON.stringify(editorData).slice(0, 100) : null,
185
- editorDataType: typeof editorData,
186
- hasEditorData: !!editorData,
187
- id,
188
- name,
189
- });
190
- }
191
- }, [isNote, id, name, editorData]);
192
-
193
180
  const cardRef = useRef<HTMLDivElement>(null);
194
181
  const [isInView, setIsInView] = useState(false);
195
182
 
@@ -288,12 +275,6 @@ const MasonryFileItem = memo<MasonryFileItemProps>(
288
275
  )}
289
276
  onClick={() => {
290
277
  if (isNote) {
291
- console.log('[MasonryFileItem] Opening note modal with:', {
292
- editorDataType: typeof editorData,
293
- hasEditorData: !!editorData,
294
- id,
295
- name,
296
- });
297
278
  setIsNoteModalOpen(true);
298
279
  } else {
299
280
  onOpen(id);
@@ -384,7 +365,6 @@ const MasonryFileItem = memo<MasonryFileItemProps>(
384
365
  editorData={editorData}
385
366
  knowledgeBaseId={knowledgeBaseId}
386
367
  onClose={() => {
387
- console.log('[MasonryFileItem] Closing note modal');
388
368
  setIsNoteModalOpen(false);
389
369
  }}
390
370
  open={isNoteModalOpen}
@@ -36,7 +36,6 @@ const AddButton = ({ knowledgeBaseId }: { knowledgeBaseId?: string }) => {
36
36
 
37
37
  const handleCreateFolder = () => {
38
38
  setIsModalOpen(false);
39
- console.log('create folder');
40
39
  };
41
40
 
42
41
  const items = useMemo<MenuProps['items']>(
@@ -22,7 +22,7 @@ const NewNoteButton = ({ knowledgeBaseId }: { knowledgeBaseId?: string }) => {
22
22
  return (
23
23
  <>
24
24
  <Button icon={FilePenLine} onClick={handleOpen} type="primary">
25
- {t('header.newDocumentButton')}
25
+ {t('header.newPageButton')}
26
26
  </Button>
27
27
 
28
28
  <NoteEditorModal knowledgeBaseId={knowledgeBaseId} onClose={handleClose} open={isModalOpen} />
@@ -17,13 +17,13 @@ export const TOOGLE_PANEL_BUTTON_ID = 'toggle-panel-button';
17
17
  const TogglePanelButton = memo(() => {
18
18
  const hotkey = useUserStore(settingsSelectors.getHotkeyById(HotkeyEnum.ToggleLeftPanel));
19
19
 
20
- const { t } = useTranslation(['file', 'hotkey']);
20
+ const { t } = useTranslation(['file']);
21
21
 
22
22
  const showFilePanel = useGlobalStore(systemStatusSelectors.showFilePanel);
23
23
  const updateSystemStatus = useGlobalStore((s) => s.updateSystemStatus);
24
24
 
25
25
  return (
26
- <Tooltip hotkey={hotkey} title={t('toggleLeftPanel.title', { ns: 'hotkey' })}>
26
+ <Tooltip hotkey={hotkey} title={t('toggleLeftPanel')}>
27
27
  <ActionIcon
28
28
  icon={showFilePanel ? PanelLeftClose : PanelLeftOpen}
29
29
  id={TOOGLE_PANEL_BUTTON_ID}
@@ -97,7 +97,7 @@ const UploadEntries = memo<UploadEntriesProps>(({ knowledgeBaseId }) => {
97
97
  const newDoc = await createDocument({
98
98
  content: '',
99
99
  knowledgeBaseId,
100
- title: t('home.uploadEntries.newDocument.title'),
100
+ title: t('home.uploadEntries.newPage.title'),
101
101
  });
102
102
  // Navigate to the newly created document
103
103
  // The KnowledgeHomePage will automatically set category to 'documents' when it detects the id param
@@ -137,7 +137,7 @@ const UploadEntries = memo<UploadEntriesProps>(({ knowledgeBaseId }) => {
137
137
  <div className={styles.grid}>
138
138
  {/* Create New Note */}
139
139
  <Flexbox className={styles.card} onClick={handleCreateNote} padding={16}>
140
- <span className={styles.actionTitle}>{t('home.uploadEntries.newDocument.title')}</span>
140
+ <span className={styles.actionTitle}>{t('home.uploadEntries.newPage.title')}</span>
141
141
  <div className={styles.glow} style={{ background: theme.purple }} />
142
142
  <FileTypeIcon
143
143
  className={styles.icon}
@@ -165,7 +165,7 @@ const Home = memo<HomeProps>(({ knowledgeBaseId, onOpenFile }) => {
165
165
  </div>
166
166
  )}
167
167
 
168
- {/* Recent Documents Section */}
168
+ {/* Recent Pages Section */}
169
169
  {(isLoading || topRecentDocuments.length > 0) && (
170
170
  <div
171
171
  className={styles.section}
@@ -179,7 +179,7 @@ const Home = memo<HomeProps>(({ knowledgeBaseId, onOpenFile }) => {
179
179
  <div className={styles.sectionTitleWrapper}>
180
180
  <Text className={styles.sectionTitle} style={{ marginBottom: 0 }}>
181
181
  <FileTextIcon size={18} />
182
- {t('home.recentDocuments')}
182
+ {t('home.recentPages')}
183
183
  </Text>
184
184
  <div
185
185
  className={styles.sectionActions}
@@ -192,9 +192,9 @@ const Home = memo<HomeProps>(({ knowledgeBaseId, onOpenFile }) => {
192
192
  items: [
193
193
  {
194
194
  key: 'all-documents',
195
- label: t('menu.allDocuments'),
195
+ label: t('menu.allPages'),
196
196
  onClick: () => {
197
- setActiveKey(FilesTabs.Documents);
197
+ setActiveKey(FilesTabs.Pages);
198
198
  },
199
199
  },
200
200
  ],
@@ -37,7 +37,7 @@ const BuiltinType = memo<BuiltinTypeProps>(
37
37
  return (
38
38
  <Render
39
39
  apiName={apiName}
40
- args={args}
40
+ args={args || {}}
41
41
  content={data}
42
42
  identifier={identifier}
43
43
  messageId={id}
@@ -17,8 +17,8 @@ import {
17
17
  } from 'lucide-react';
18
18
  import { PropsWithChildren, memo } from 'react';
19
19
  import { useTranslation } from 'react-i18next';
20
- import { Link } from 'react-router-dom';
21
20
  import { Flexbox } from 'react-layout-kit';
21
+ import { Link } from 'react-router-dom';
22
22
 
23
23
  import type { MenuProps } from '@/components/Menu';
24
24
  import { enableAuth } from '@/const/auth';
@@ -135,7 +135,11 @@ export const useMenu = () => {
135
135
  icon: <Icon icon={Cloudy} />,
136
136
  key: 'cloud',
137
137
  label: (
138
- <a href={`${OFFICIAL_URL}?utm_source=${UTM_SOURCE}`} rel="noopener noreferrer" target="_blank">
138
+ <a
139
+ href={`${OFFICIAL_URL}?utm_source=${UTM_SOURCE}`}
140
+ rel="noopener noreferrer"
141
+ target="_blank"
142
+ >
139
143
  {t('userPanel.cloud', { name: LOBE_CHAT_CLOUD })}
140
144
  </a>
141
145
  ),
@@ -148,7 +152,7 @@ export const useMenu = () => {
148
152
  {t('changelog')}
149
153
  </a>
150
154
  ) : (
151
- <Link to="/changelog/modal">{t('changelog')}</Link>
155
+ <Link to="/changelog">{t('changelog')}</Link>
152
156
  ),
153
157
  },
154
158
  {
@@ -1,7 +1,7 @@
1
1
  import { LobeChatPluginManifest } from '@lobehub/chat-plugin-sdk';
2
2
  import { beforeEach, describe, expect, it, vi } from 'vitest';
3
3
 
4
- import { createChatToolsEngine, createToolsEngine, getEnabledTools } from './index';
4
+ import { createAgentToolsEngine, createToolsEngine, getEnabledTools } from './index';
5
5
 
6
6
  // Mock the store and helper dependencies
7
7
  vi.mock('@/store/tool', () => ({
@@ -137,7 +137,7 @@ describe('toolEngineering', () => {
137
137
 
138
138
  describe('createChatToolsEngine', () => {
139
139
  it('should include web browsing tool as default when no tools are provided', () => {
140
- const toolsEngine = createChatToolsEngine({
140
+ const toolsEngine = createAgentToolsEngine({
141
141
  model: 'gpt-4',
142
142
  provider: 'openai',
143
143
  });
@@ -152,7 +152,7 @@ describe('toolEngineering', () => {
152
152
  });
153
153
 
154
154
  it('should include web browsing tool alongside user-provided tools', () => {
155
- const toolsEngine = createChatToolsEngine({
155
+ const toolsEngine = createAgentToolsEngine({
156
156
  model: 'gpt-4',
157
157
  provider: 'openai',
158
158
  });