@lobehub/lobehub 2.0.0-next.187 → 2.0.0-next.189
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +50 -0
- package/changelog/v1.json +18 -0
- package/e2e/CLAUDE.md +109 -2
- package/e2e/docs/llm-mock.md +68 -0
- package/e2e/docs/local-setup.md +354 -0
- package/e2e/docs/testing-tips.md +94 -0
- package/e2e/src/features/journeys/agent/agent-conversation.feature +0 -32
- package/e2e/src/mocks/llm/index.ts +6 -6
- package/e2e/src/steps/agent/conversation.steps.ts +3 -471
- package/locales/ar/models.json +89 -5
- package/locales/ar/plugin.json +5 -0
- package/locales/ar/providers.json +1 -0
- package/locales/bg-BG/models.json +68 -0
- package/locales/bg-BG/plugin.json +5 -0
- package/locales/bg-BG/providers.json +1 -0
- package/locales/de-DE/models.json +85 -0
- package/locales/de-DE/plugin.json +5 -0
- package/locales/de-DE/providers.json +1 -0
- package/locales/en-US/models.json +11 -10
- package/locales/en-US/plugin.json +5 -0
- package/locales/en-US/providers.json +1 -0
- package/locales/es-ES/models.json +72 -0
- package/locales/es-ES/plugin.json +5 -0
- package/locales/es-ES/providers.json +1 -0
- package/locales/fa-IR/models.json +86 -0
- package/locales/fa-IR/plugin.json +5 -0
- package/locales/fa-IR/providers.json +1 -0
- package/locales/fr-FR/models.json +49 -0
- package/locales/fr-FR/plugin.json +5 -0
- package/locales/fr-FR/providers.json +1 -0
- package/locales/it-IT/models.json +82 -0
- package/locales/it-IT/plugin.json +5 -0
- package/locales/it-IT/providers.json +1 -0
- package/locales/ja-JP/models.json +42 -5
- package/locales/ja-JP/plugin.json +5 -0
- package/locales/ja-JP/providers.json +1 -0
- package/locales/ko-KR/models.json +54 -0
- package/locales/ko-KR/plugin.json +5 -0
- package/locales/ko-KR/providers.json +1 -0
- package/locales/nl-NL/models.json +12 -1
- package/locales/nl-NL/plugin.json +5 -0
- package/locales/nl-NL/providers.json +1 -0
- package/locales/pl-PL/models.json +46 -0
- package/locales/pl-PL/plugin.json +5 -0
- package/locales/pl-PL/providers.json +1 -0
- package/locales/pt-BR/models.json +59 -0
- package/locales/pt-BR/plugin.json +5 -0
- package/locales/pt-BR/providers.json +1 -0
- package/locales/ru-RU/models.json +85 -0
- package/locales/ru-RU/plugin.json +5 -0
- package/locales/ru-RU/providers.json +1 -0
- package/locales/tr-TR/models.json +81 -0
- package/locales/tr-TR/plugin.json +5 -0
- package/locales/tr-TR/providers.json +1 -0
- package/locales/vi-VN/models.json +54 -0
- package/locales/vi-VN/plugin.json +5 -0
- package/locales/vi-VN/providers.json +1 -0
- package/locales/zh-CN/models.json +42 -5
- package/locales/zh-CN/plugin.json +5 -0
- package/locales/zh-CN/providers.json +1 -0
- package/locales/zh-TW/models.json +85 -0
- package/locales/zh-TW/plugin.json +5 -0
- package/locales/zh-TW/providers.json +1 -0
- package/package.json +2 -2
- package/packages/builtin-tool-gtd/src/manifest.ts +13 -8
- package/packages/builtin-tool-gtd/src/systemRole.ts +54 -19
- package/packages/builtin-tool-knowledge-base/package.json +1 -0
- package/packages/builtin-tool-knowledge-base/src/client/Inspector/ReadKnowledge/index.tsx +97 -0
- package/packages/builtin-tool-knowledge-base/src/client/Inspector/SearchKnowledgeBase/index.tsx +75 -0
- package/packages/builtin-tool-knowledge-base/src/client/Inspector/index.ts +11 -0
- package/packages/builtin-tool-knowledge-base/src/client/Render/ReadKnowledge/FileCard.tsx +12 -12
- package/packages/builtin-tool-knowledge-base/src/client/Render/ReadKnowledge/index.tsx +16 -25
- package/packages/builtin-tool-knowledge-base/src/client/Render/SearchKnowledgeBase/Item/index.tsx +21 -47
- package/packages/builtin-tool-knowledge-base/src/client/Render/SearchKnowledgeBase/index.tsx +19 -31
- package/packages/builtin-tool-knowledge-base/src/client/Render/index.ts +0 -5
- package/packages/builtin-tool-knowledge-base/src/client/index.ts +5 -1
- package/packages/builtin-tool-knowledge-base/src/executor/index.ts +119 -0
- package/packages/builtin-tool-local-system/package.json +1 -0
- package/packages/builtin-tool-local-system/src/client/Inspector/EditLocalFile/index.tsx +44 -29
- package/packages/builtin-tool-local-system/src/client/Inspector/GrepContent/index.tsx +20 -18
- package/packages/builtin-tool-local-system/src/client/Inspector/ListLocalFiles/index.tsx +76 -0
- package/packages/builtin-tool-local-system/src/client/Inspector/ReadLocalFile/index.tsx +8 -32
- package/packages/builtin-tool-local-system/src/client/Inspector/RenameLocalFile/index.tsx +62 -0
- package/packages/builtin-tool-local-system/src/client/Inspector/SearchLocalFiles/index.tsx +17 -11
- package/packages/builtin-tool-local-system/src/client/Inspector/WriteLocalFile/index.tsx +61 -0
- package/packages/builtin-tool-local-system/src/client/Inspector/index.ts +6 -0
- package/packages/builtin-tool-local-system/src/client/Render/EditLocalFile/index.tsx +6 -1
- package/packages/builtin-tool-local-system/src/client/Render/SearchFiles/SearchQuery/SearchView.tsx +19 -31
- package/packages/builtin-tool-local-system/src/client/Render/SearchFiles/SearchQuery/index.tsx +2 -42
- package/packages/builtin-tool-local-system/src/client/Render/index.ts +0 -2
- package/packages/builtin-tool-local-system/src/client/components/FilePathDisplay.tsx +56 -0
- package/packages/builtin-tool-local-system/src/client/components/index.ts +2 -0
- package/packages/builtin-tool-local-system/src/executor/index.ts +435 -0
- package/packages/builtin-tool-web-browsing/src/client/Inspector/Search/index.tsx +32 -5
- package/packages/model-runtime/src/core/contextBuilders/google.test.ts +84 -0
- package/packages/model-runtime/src/core/contextBuilders/google.ts +37 -1
- package/src/app/[variants]/(main)/chat/_layout/Sidebar/Topic/List/Item/Actions.tsx +4 -13
- package/src/app/[variants]/(main)/chat/_layout/Sidebar/Topic/List/Item/index.tsx +23 -29
- package/src/app/[variants]/(main)/chat/_layout/Sidebar/Topic/List/Item/useDropdownMenu.tsx +3 -3
- package/src/app/[variants]/(main)/chat/_layout/Sidebar/Topic/TopicListContent/ThreadList/ThreadItem/Actions.tsx +4 -13
- package/src/app/[variants]/(main)/chat/_layout/Sidebar/Topic/TopicListContent/ThreadList/ThreadItem/index.tsx +10 -18
- package/src/app/[variants]/(main)/chat/_layout/Sidebar/Topic/TopicListContent/ThreadList/ThreadItem/useDropdownMenu.tsx +3 -3
- package/src/app/[variants]/(main)/community/(detail)/assistant/features/Sidebar/ActionButton/AddAgent.tsx +47 -27
- package/src/app/[variants]/(main)/community/(detail)/user/features/UserAgentCard.tsx +4 -3
- package/src/app/[variants]/(main)/group/_layout/Sidebar/Topic/List/Item/Actions.tsx +4 -13
- package/src/app/[variants]/(main)/group/_layout/Sidebar/Topic/List/Item/index.tsx +23 -29
- package/src/app/[variants]/(main)/group/_layout/Sidebar/Topic/List/Item/useDropdownMenu.tsx +3 -3
- package/src/app/[variants]/(main)/group/_layout/Sidebar/Topic/TopicListContent/ThreadList/ThreadItem/Actions.tsx +4 -13
- package/src/app/[variants]/(main)/group/_layout/Sidebar/Topic/TopicListContent/ThreadList/ThreadItem/index.tsx +10 -18
- package/src/app/[variants]/(main)/group/_layout/Sidebar/Topic/TopicListContent/ThreadList/ThreadItem/useDropdownMenu.tsx +3 -3
- package/src/app/[variants]/(main)/group/profile/features/AgentBuilder/TopicSelector.tsx +18 -20
- package/src/app/[variants]/(main)/home/_layout/Body/Agent/List/AgentGroupItem/index.tsx +19 -25
- package/src/app/[variants]/(main)/home/_layout/Body/Agent/List/AgentItem/index.tsx +21 -26
- package/src/app/[variants]/(main)/home/_layout/Body/Agent/List/Item/Actions.tsx +4 -13
- package/src/app/[variants]/(main)/home/_layout/Body/Agent/List/Item/useDropdownMenu.tsx +3 -3
- package/src/app/[variants]/(main)/home/_layout/Body/Project/List/Actions.tsx +4 -13
- package/src/app/[variants]/(main)/home/_layout/Body/Project/List/Item.tsx +8 -15
- package/src/app/[variants]/(main)/home/_layout/Body/Project/List/useDropdownMenu.tsx +3 -3
- package/src/app/[variants]/(main)/home/_layout/Header/components/AddButton.tsx +3 -4
- package/src/app/[variants]/(main)/page/_layout/Body/List/Item/Actions.tsx +4 -13
- package/src/app/[variants]/(main)/page/_layout/Body/List/Item/index.tsx +13 -20
- package/src/app/[variants]/(main)/page/_layout/Body/List/Item/useDropdownMenu.tsx +3 -3
- package/src/app/[variants]/(main)/resource/(home)/_layout/Body/LibraryList/List/Item/Actions.tsx +4 -13
- package/src/app/[variants]/(main)/resource/(home)/_layout/Body/LibraryList/List/Item/index.tsx +16 -23
- package/src/app/[variants]/(main)/resource/(home)/_layout/Body/LibraryList/List/Item/useDropdownMenu.tsx +3 -3
- package/src/app/[variants]/(main)/resource/library/_layout/Header/LibraryHead.tsx +4 -6
- package/src/features/AgentBuilder/TopicSelector.tsx +18 -17
- package/src/features/Conversation/ChatItem/style.ts +7 -0
- package/src/features/Conversation/Messages/Assistant/Actions/Error.tsx +1 -3
- package/src/features/Conversation/Messages/Assistant/Actions/index.tsx +37 -16
- package/src/features/Conversation/Messages/AssistantGroup/Actions/index.tsx +36 -17
- package/src/features/Conversation/Messages/Supervisor/Actions/index.tsx +36 -17
- package/src/features/Conversation/Messages/Task/Actions/Error.tsx +1 -3
- package/src/features/Conversation/Messages/Task/Actions/index.tsx +31 -15
- package/src/features/Conversation/Messages/User/Actions/index.tsx +1 -1
- package/src/features/Conversation/Messages/index.tsx +8 -59
- package/src/features/Conversation/components/ShareMessageModal/index.tsx +1 -1
- package/src/features/Conversation/hooks/useChatItemContextMenu.tsx +313 -83
- package/src/features/NavPanel/components/NavItem.tsx +33 -3
- package/src/features/PageEditor/Copilot/TopicSelector/Actions.tsx +6 -14
- package/src/features/PageEditor/Copilot/TopicSelector/TopicItem.tsx +1 -0
- package/src/features/PageEditor/Copilot/TopicSelector/useDropdownMenu.tsx +6 -3
- package/src/features/ResourceManager/components/Explorer/ItemDropdown/DropdownMenu.tsx +12 -35
- package/src/features/ResourceManager/components/Explorer/ItemDropdown/useFileItemDropdown.tsx +4 -8
- package/src/features/ResourceManager/components/Explorer/ListView/ListItem/index.tsx +162 -160
- package/src/features/ResourceManager/components/Explorer/MasonryView/MasonryFileItem/index.tsx +16 -8
- package/src/features/ResourceManager/components/Explorer/ToolBar/ActionIconWithChevron.tsx +4 -3
- package/src/features/ResourceManager/components/Explorer/ToolBar/BatchActionsDropdown.tsx +6 -12
- package/src/features/ResourceManager/components/Explorer/ToolBar/SortDropdown.tsx +8 -8
- package/src/features/ResourceManager/components/Explorer/ToolBar/ViewSwitcher.tsx +8 -11
- package/src/features/ResourceManager/components/Tree/index.tsx +121 -122
- package/src/helpers/toolEngineering/index.ts +1 -1
- package/src/layout/GlobalProvider/index.tsx +5 -2
- package/src/locales/default/plugin.ts +6 -0
- package/src/server/modules/Mecha/AgentToolsEngine/__tests__/index.test.ts +1 -1
- package/src/server/modules/Mecha/AgentToolsEngine/index.ts +1 -1
- package/src/store/chat/slices/builtinTool/actions/index.ts +1 -11
- package/src/store/tool/slices/builtin/executors/index.ts +4 -0
- package/src/styles/global.ts +6 -0
- package/src/styles/text.ts +1 -1
- package/src/tools/executionRuntimes.ts +3 -8
- package/src/tools/identifiers.ts +1 -1
- package/src/tools/index.ts +1 -1
- package/src/tools/inspectors.ts +5 -0
- package/src/tools/renders.ts +6 -12
- package/packages/builtin-tool-local-system/src/client/Render/RenameLocalFile/index.tsx +0 -37
- package/src/features/Conversation/components/ContextMenu.tsx +0 -418
- package/src/store/chat/slices/builtinTool/actions/__tests__/localSystem.test.ts +0 -201
- package/src/store/chat/slices/builtinTool/actions/knowledgeBase.ts +0 -163
- package/src/store/chat/slices/builtinTool/actions/localSystem.ts +0 -241
- package/src/tools/knowledge-base/ExecutionRuntime/index.ts +0 -25
- package/src/tools/knowledge-base/Render/ReadKnowledge/index.tsx +0 -29
- package/src/tools/knowledge-base/Render/SearchKnowledgeBase/index.tsx +0 -29
- package/src/tools/knowledge-base/Render/index.ts +0 -7
- package/src/tools/knowledge-base/index.ts +0 -12
- package/src/tools/local-system/ExecutionRuntime/index.ts +0 -9
- package/src/tools/local-system/systemRole.ts +0 -1
|
@@ -0,0 +1,435 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
EditLocalFileParams,
|
|
3
|
+
EditLocalFileResult,
|
|
4
|
+
GetCommandOutputParams,
|
|
5
|
+
GetCommandOutputResult,
|
|
6
|
+
GlobFilesParams,
|
|
7
|
+
GlobFilesResult,
|
|
8
|
+
GrepContentParams,
|
|
9
|
+
GrepContentResult,
|
|
10
|
+
KillCommandParams,
|
|
11
|
+
KillCommandResult,
|
|
12
|
+
ListLocalFileParams,
|
|
13
|
+
LocalFileItem,
|
|
14
|
+
LocalMoveFilesResultItem,
|
|
15
|
+
LocalReadFileParams,
|
|
16
|
+
LocalReadFileResult,
|
|
17
|
+
LocalReadFilesParams,
|
|
18
|
+
LocalSearchFilesParams,
|
|
19
|
+
MoveLocalFilesParams,
|
|
20
|
+
RenameLocalFileParams,
|
|
21
|
+
RenameLocalFileResult,
|
|
22
|
+
RunCommandParams,
|
|
23
|
+
RunCommandResult,
|
|
24
|
+
WriteLocalFileParams,
|
|
25
|
+
} from '@lobechat/electron-client-ipc';
|
|
26
|
+
import { BaseExecutor, type BuiltinToolResult } from '@lobechat/types';
|
|
27
|
+
|
|
28
|
+
import { localFileService } from '@/services/electron/localFileService';
|
|
29
|
+
|
|
30
|
+
import {
|
|
31
|
+
type EditLocalFileState,
|
|
32
|
+
type GetCommandOutputState,
|
|
33
|
+
type GlobFilesState,
|
|
34
|
+
type GrepContentState,
|
|
35
|
+
type KillCommandState,
|
|
36
|
+
type LocalFileListState,
|
|
37
|
+
type LocalFileSearchState,
|
|
38
|
+
type LocalMoveFilesState,
|
|
39
|
+
type LocalReadFileState,
|
|
40
|
+
type LocalReadFilesState,
|
|
41
|
+
type LocalRenameFileState,
|
|
42
|
+
LocalSystemIdentifier,
|
|
43
|
+
type RunCommandState,
|
|
44
|
+
} from '../types';
|
|
45
|
+
|
|
46
|
+
const LocalSystemApiEnum = {
|
|
47
|
+
editLocalFile: 'editLocalFile' as const,
|
|
48
|
+
getCommandOutput: 'getCommandOutput' as const,
|
|
49
|
+
globLocalFiles: 'globLocalFiles' as const,
|
|
50
|
+
grepContent: 'grepContent' as const,
|
|
51
|
+
killCommand: 'killCommand' as const,
|
|
52
|
+
listLocalFiles: 'listLocalFiles' as const,
|
|
53
|
+
moveLocalFiles: 'moveLocalFiles' as const,
|
|
54
|
+
readLocalFile: 'readLocalFile' as const,
|
|
55
|
+
readLocalFiles: 'readLocalFiles' as const,
|
|
56
|
+
renameLocalFile: 'renameLocalFile' as const,
|
|
57
|
+
runCommand: 'runCommand' as const,
|
|
58
|
+
searchLocalFiles: 'searchLocalFiles' as const,
|
|
59
|
+
writeLocalFile: 'writeLocalFile' as const,
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Local System Tool Executor
|
|
64
|
+
*
|
|
65
|
+
* Handles all local file system operations including file CRUD, shell commands, and search.
|
|
66
|
+
*/
|
|
67
|
+
class LocalSystemExecutor extends BaseExecutor<typeof LocalSystemApiEnum> {
|
|
68
|
+
readonly identifier = LocalSystemIdentifier;
|
|
69
|
+
protected readonly apiEnum = LocalSystemApiEnum;
|
|
70
|
+
|
|
71
|
+
// ==================== File Operations ====================
|
|
72
|
+
|
|
73
|
+
listLocalFiles = async (params: ListLocalFileParams): Promise<BuiltinToolResult> => {
|
|
74
|
+
try {
|
|
75
|
+
const result: LocalFileItem[] = await localFileService.listLocalFiles(params);
|
|
76
|
+
|
|
77
|
+
const state: LocalFileListState = { listResults: result };
|
|
78
|
+
|
|
79
|
+
return {
|
|
80
|
+
content: JSON.stringify(result),
|
|
81
|
+
state,
|
|
82
|
+
success: true,
|
|
83
|
+
};
|
|
84
|
+
} catch (error) {
|
|
85
|
+
return {
|
|
86
|
+
content: (error as Error).message,
|
|
87
|
+
error: { body: error, message: (error as Error).message, type: 'PluginServerError' },
|
|
88
|
+
success: false,
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
};
|
|
92
|
+
|
|
93
|
+
readLocalFile = async (params: LocalReadFileParams): Promise<BuiltinToolResult> => {
|
|
94
|
+
try {
|
|
95
|
+
const result: LocalReadFileResult = await localFileService.readLocalFile(params);
|
|
96
|
+
|
|
97
|
+
const state: LocalReadFileState = { fileContent: result };
|
|
98
|
+
|
|
99
|
+
return {
|
|
100
|
+
content: JSON.stringify(result),
|
|
101
|
+
state,
|
|
102
|
+
success: true,
|
|
103
|
+
};
|
|
104
|
+
} catch (error) {
|
|
105
|
+
return {
|
|
106
|
+
content: (error as Error).message,
|
|
107
|
+
error: { body: error, message: (error as Error).message, type: 'PluginServerError' },
|
|
108
|
+
success: false,
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
};
|
|
112
|
+
|
|
113
|
+
readLocalFiles = async (params: LocalReadFilesParams): Promise<BuiltinToolResult> => {
|
|
114
|
+
try {
|
|
115
|
+
const results: LocalReadFileResult[] = await localFileService.readLocalFiles(params);
|
|
116
|
+
|
|
117
|
+
const state: LocalReadFilesState = { filesContent: results };
|
|
118
|
+
|
|
119
|
+
return {
|
|
120
|
+
content: JSON.stringify(results),
|
|
121
|
+
state,
|
|
122
|
+
success: true,
|
|
123
|
+
};
|
|
124
|
+
} catch (error) {
|
|
125
|
+
return {
|
|
126
|
+
content: (error as Error).message,
|
|
127
|
+
error: { body: error, message: (error as Error).message, type: 'PluginServerError' },
|
|
128
|
+
success: false,
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
};
|
|
132
|
+
|
|
133
|
+
searchLocalFiles = async (params: LocalSearchFilesParams): Promise<BuiltinToolResult> => {
|
|
134
|
+
try {
|
|
135
|
+
const result: LocalFileItem[] = await localFileService.searchLocalFiles(params);
|
|
136
|
+
|
|
137
|
+
const state: LocalFileSearchState = { searchResults: result };
|
|
138
|
+
|
|
139
|
+
return {
|
|
140
|
+
content: JSON.stringify(result),
|
|
141
|
+
state,
|
|
142
|
+
success: true,
|
|
143
|
+
};
|
|
144
|
+
} catch (error) {
|
|
145
|
+
return {
|
|
146
|
+
content: (error as Error).message,
|
|
147
|
+
error: { body: error, message: (error as Error).message, type: 'PluginServerError' },
|
|
148
|
+
success: false,
|
|
149
|
+
};
|
|
150
|
+
}
|
|
151
|
+
};
|
|
152
|
+
|
|
153
|
+
moveLocalFiles = async (params: MoveLocalFilesParams): Promise<BuiltinToolResult> => {
|
|
154
|
+
try {
|
|
155
|
+
const results: LocalMoveFilesResultItem[] = await localFileService.moveLocalFiles(params);
|
|
156
|
+
|
|
157
|
+
const allSucceeded = results.every((r) => r.success);
|
|
158
|
+
const someFailed = results.some((r) => !r.success);
|
|
159
|
+
const successCount = results.filter((r) => r.success).length;
|
|
160
|
+
const failedCount = results.length - successCount;
|
|
161
|
+
|
|
162
|
+
let message = '';
|
|
163
|
+
|
|
164
|
+
if (allSucceeded) {
|
|
165
|
+
message = `Successfully moved ${results.length} item(s).`;
|
|
166
|
+
} else if (someFailed) {
|
|
167
|
+
message = `Moved ${successCount} item(s) successfully. Failed to move ${failedCount} item(s).`;
|
|
168
|
+
} else {
|
|
169
|
+
message = `Failed to move all ${results.length} item(s).`;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
const state: LocalMoveFilesState = {
|
|
173
|
+
results,
|
|
174
|
+
successCount,
|
|
175
|
+
totalCount: results.length,
|
|
176
|
+
};
|
|
177
|
+
|
|
178
|
+
return {
|
|
179
|
+
content: JSON.stringify({ message, results }),
|
|
180
|
+
state,
|
|
181
|
+
success: true,
|
|
182
|
+
};
|
|
183
|
+
} catch (error) {
|
|
184
|
+
return {
|
|
185
|
+
content: (error as Error).message,
|
|
186
|
+
error: { body: error, message: (error as Error).message, type: 'PluginServerError' },
|
|
187
|
+
success: false,
|
|
188
|
+
};
|
|
189
|
+
}
|
|
190
|
+
};
|
|
191
|
+
|
|
192
|
+
renameLocalFile = async (params: RenameLocalFileParams): Promise<BuiltinToolResult> => {
|
|
193
|
+
try {
|
|
194
|
+
const result: RenameLocalFileResult = await localFileService.renameLocalFile(params);
|
|
195
|
+
|
|
196
|
+
if (!result.success) {
|
|
197
|
+
const state: LocalRenameFileState = {
|
|
198
|
+
error: result.error,
|
|
199
|
+
newPath: '',
|
|
200
|
+
oldPath: params.path,
|
|
201
|
+
success: false,
|
|
202
|
+
};
|
|
203
|
+
|
|
204
|
+
return {
|
|
205
|
+
content: JSON.stringify({ message: result.error, success: false }),
|
|
206
|
+
state,
|
|
207
|
+
success: false,
|
|
208
|
+
};
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
const state: LocalRenameFileState = {
|
|
212
|
+
newPath: result.newPath!,
|
|
213
|
+
oldPath: params.path,
|
|
214
|
+
success: true,
|
|
215
|
+
};
|
|
216
|
+
|
|
217
|
+
return {
|
|
218
|
+
content: JSON.stringify({
|
|
219
|
+
message: `Successfully renamed file ${params.path} to ${params.newName}.`,
|
|
220
|
+
success: true,
|
|
221
|
+
}),
|
|
222
|
+
state,
|
|
223
|
+
success: true,
|
|
224
|
+
};
|
|
225
|
+
} catch (error) {
|
|
226
|
+
return {
|
|
227
|
+
content: (error as Error).message,
|
|
228
|
+
error: { body: error, message: (error as Error).message, type: 'PluginServerError' },
|
|
229
|
+
success: false,
|
|
230
|
+
};
|
|
231
|
+
}
|
|
232
|
+
};
|
|
233
|
+
|
|
234
|
+
writeLocalFile = async (params: WriteLocalFileParams): Promise<BuiltinToolResult> => {
|
|
235
|
+
try {
|
|
236
|
+
const result = await localFileService.writeFile(params);
|
|
237
|
+
|
|
238
|
+
if (!result.success) {
|
|
239
|
+
return {
|
|
240
|
+
content: JSON.stringify({
|
|
241
|
+
message: result.error || 'Failed to write file',
|
|
242
|
+
success: false,
|
|
243
|
+
}),
|
|
244
|
+
error: { message: result.error || 'Failed to write file', type: 'PluginServerError' },
|
|
245
|
+
success: false,
|
|
246
|
+
};
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
return {
|
|
250
|
+
content: JSON.stringify({
|
|
251
|
+
message: `Successfully wrote file ${params.path}`,
|
|
252
|
+
success: true,
|
|
253
|
+
}),
|
|
254
|
+
success: true,
|
|
255
|
+
};
|
|
256
|
+
} catch (error) {
|
|
257
|
+
return {
|
|
258
|
+
content: (error as Error).message,
|
|
259
|
+
error: { body: error, message: (error as Error).message, type: 'PluginServerError' },
|
|
260
|
+
success: false,
|
|
261
|
+
};
|
|
262
|
+
}
|
|
263
|
+
};
|
|
264
|
+
|
|
265
|
+
editLocalFile = async (params: EditLocalFileParams): Promise<BuiltinToolResult> => {
|
|
266
|
+
try {
|
|
267
|
+
const result: EditLocalFileResult = await localFileService.editLocalFile(params);
|
|
268
|
+
|
|
269
|
+
if (!result.success) {
|
|
270
|
+
return {
|
|
271
|
+
content: `Edit failed: ${result.error}`,
|
|
272
|
+
success: false,
|
|
273
|
+
};
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
const statsText =
|
|
277
|
+
result.linesAdded || result.linesDeleted
|
|
278
|
+
? ` (+${result.linesAdded || 0} -${result.linesDeleted || 0})`
|
|
279
|
+
: '';
|
|
280
|
+
const message = `Successfully replaced ${result.replacements} occurrence(s) in ${params.file_path}${statsText}`;
|
|
281
|
+
|
|
282
|
+
const state: EditLocalFileState = {
|
|
283
|
+
diffText: result.diffText,
|
|
284
|
+
linesAdded: result.linesAdded,
|
|
285
|
+
linesDeleted: result.linesDeleted,
|
|
286
|
+
replacements: result.replacements,
|
|
287
|
+
};
|
|
288
|
+
|
|
289
|
+
return {
|
|
290
|
+
content: message,
|
|
291
|
+
state,
|
|
292
|
+
success: true,
|
|
293
|
+
};
|
|
294
|
+
} catch (error) {
|
|
295
|
+
return {
|
|
296
|
+
content: (error as Error).message,
|
|
297
|
+
error: { body: error, message: (error as Error).message, type: 'PluginServerError' },
|
|
298
|
+
success: false,
|
|
299
|
+
};
|
|
300
|
+
}
|
|
301
|
+
};
|
|
302
|
+
|
|
303
|
+
// ==================== Shell Commands ====================
|
|
304
|
+
|
|
305
|
+
runCommand = async (params: RunCommandParams): Promise<BuiltinToolResult> => {
|
|
306
|
+
try {
|
|
307
|
+
const result: RunCommandResult = await localFileService.runCommand(params);
|
|
308
|
+
|
|
309
|
+
let message: string;
|
|
310
|
+
|
|
311
|
+
if (result.success) {
|
|
312
|
+
if (result.shell_id) {
|
|
313
|
+
message = `Command started in background with shell_id: ${result.shell_id}`;
|
|
314
|
+
} else {
|
|
315
|
+
message = `Command completed successfully.`;
|
|
316
|
+
}
|
|
317
|
+
} else {
|
|
318
|
+
message = `Command failed: ${result.error}`;
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
const state: RunCommandState = { message, result };
|
|
322
|
+
|
|
323
|
+
return {
|
|
324
|
+
content: JSON.stringify(result),
|
|
325
|
+
state,
|
|
326
|
+
success: result.success,
|
|
327
|
+
};
|
|
328
|
+
} catch (error) {
|
|
329
|
+
return {
|
|
330
|
+
content: (error as Error).message,
|
|
331
|
+
error: { body: error, message: (error as Error).message, type: 'PluginServerError' },
|
|
332
|
+
success: false,
|
|
333
|
+
};
|
|
334
|
+
}
|
|
335
|
+
};
|
|
336
|
+
|
|
337
|
+
getCommandOutput = async (params: GetCommandOutputParams): Promise<BuiltinToolResult> => {
|
|
338
|
+
try {
|
|
339
|
+
const result: GetCommandOutputResult = await localFileService.getCommandOutput(params);
|
|
340
|
+
|
|
341
|
+
const message = result.success
|
|
342
|
+
? `Output retrieved. Running: ${result.running}`
|
|
343
|
+
: `Failed: ${result.error}`;
|
|
344
|
+
|
|
345
|
+
const state: GetCommandOutputState = { message, result };
|
|
346
|
+
|
|
347
|
+
return {
|
|
348
|
+
content: JSON.stringify(result),
|
|
349
|
+
state,
|
|
350
|
+
success: result.success,
|
|
351
|
+
};
|
|
352
|
+
} catch (error) {
|
|
353
|
+
return {
|
|
354
|
+
content: (error as Error).message,
|
|
355
|
+
error: { body: error, message: (error as Error).message, type: 'PluginServerError' },
|
|
356
|
+
success: false,
|
|
357
|
+
};
|
|
358
|
+
}
|
|
359
|
+
};
|
|
360
|
+
|
|
361
|
+
killCommand = async (params: KillCommandParams): Promise<BuiltinToolResult> => {
|
|
362
|
+
try {
|
|
363
|
+
const result: KillCommandResult = await localFileService.killCommand(params);
|
|
364
|
+
|
|
365
|
+
const message = result.success
|
|
366
|
+
? `Successfully killed shell: ${params.shell_id}`
|
|
367
|
+
: `Failed to kill shell: ${result.error}`;
|
|
368
|
+
|
|
369
|
+
const state: KillCommandState = { message, result };
|
|
370
|
+
|
|
371
|
+
return {
|
|
372
|
+
content: JSON.stringify(result),
|
|
373
|
+
state,
|
|
374
|
+
success: result.success,
|
|
375
|
+
};
|
|
376
|
+
} catch (error) {
|
|
377
|
+
return {
|
|
378
|
+
content: (error as Error).message,
|
|
379
|
+
error: { body: error, message: (error as Error).message, type: 'PluginServerError' },
|
|
380
|
+
success: false,
|
|
381
|
+
};
|
|
382
|
+
}
|
|
383
|
+
};
|
|
384
|
+
|
|
385
|
+
// ==================== Search & Find ====================
|
|
386
|
+
|
|
387
|
+
grepContent = async (params: GrepContentParams): Promise<BuiltinToolResult> => {
|
|
388
|
+
try {
|
|
389
|
+
const result: GrepContentResult = await localFileService.grepContent(params);
|
|
390
|
+
|
|
391
|
+
const message = result.success
|
|
392
|
+
? `Found ${result.total_matches} matches in ${result.matches.length} locations`
|
|
393
|
+
: 'Search failed';
|
|
394
|
+
|
|
395
|
+
const state: GrepContentState = { message, result };
|
|
396
|
+
|
|
397
|
+
return {
|
|
398
|
+
content: JSON.stringify(result),
|
|
399
|
+
state,
|
|
400
|
+
success: result.success,
|
|
401
|
+
};
|
|
402
|
+
} catch (error) {
|
|
403
|
+
return {
|
|
404
|
+
content: (error as Error).message,
|
|
405
|
+
error: { body: error, message: (error as Error).message, type: 'PluginServerError' },
|
|
406
|
+
success: false,
|
|
407
|
+
};
|
|
408
|
+
}
|
|
409
|
+
};
|
|
410
|
+
|
|
411
|
+
globLocalFiles = async (params: GlobFilesParams): Promise<BuiltinToolResult> => {
|
|
412
|
+
try {
|
|
413
|
+
const result: GlobFilesResult = await localFileService.globFiles(params);
|
|
414
|
+
|
|
415
|
+
const message = result.success ? `Found ${result.total_files} files` : 'Glob search failed';
|
|
416
|
+
|
|
417
|
+
const state: GlobFilesState = { message, result };
|
|
418
|
+
|
|
419
|
+
return {
|
|
420
|
+
content: JSON.stringify(result),
|
|
421
|
+
state,
|
|
422
|
+
success: result.success,
|
|
423
|
+
};
|
|
424
|
+
} catch (error) {
|
|
425
|
+
return {
|
|
426
|
+
content: (error as Error).message,
|
|
427
|
+
error: { body: error, message: (error as Error).message, type: 'PluginServerError' },
|
|
428
|
+
success: false,
|
|
429
|
+
};
|
|
430
|
+
}
|
|
431
|
+
};
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
// Export the executor instance for registration
|
|
435
|
+
export const localSystemExecutor = new LocalSystemExecutor();
|
|
@@ -1,7 +1,12 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
|
|
3
|
-
import {
|
|
4
|
-
|
|
3
|
+
import {
|
|
4
|
+
type BuiltinInspectorProps,
|
|
5
|
+
type SearchQuery,
|
|
6
|
+
type UniformSearchResponse,
|
|
7
|
+
} from '@lobechat/types';
|
|
8
|
+
import { Text } from '@lobehub/ui';
|
|
9
|
+
import { createStaticStyles, cssVar, cx } from 'antd-style';
|
|
5
10
|
import { memo } from 'react';
|
|
6
11
|
import { useTranslation } from 'react-i18next';
|
|
7
12
|
|
|
@@ -18,11 +23,13 @@ const styles = createStaticStyles(({ css, cssVar }) => ({
|
|
|
18
23
|
`,
|
|
19
24
|
}));
|
|
20
25
|
|
|
21
|
-
export const SearchInspector = memo<BuiltinInspectorProps<SearchQuery>>(
|
|
22
|
-
({ args, partialArgs, isArgumentsStreaming }) => {
|
|
26
|
+
export const SearchInspector = memo<BuiltinInspectorProps<SearchQuery, UniformSearchResponse>>(
|
|
27
|
+
({ args, partialArgs, isArgumentsStreaming, isLoading, pluginState }) => {
|
|
23
28
|
const { t } = useTranslation('plugin');
|
|
24
29
|
|
|
25
30
|
const query = args?.query || partialArgs?.query || '';
|
|
31
|
+
const resultCount = pluginState?.results?.length ?? 0;
|
|
32
|
+
const hasResults = resultCount > 0;
|
|
26
33
|
|
|
27
34
|
if (isArgumentsStreaming && !query) {
|
|
28
35
|
return (
|
|
@@ -33,9 +40,29 @@ export const SearchInspector = memo<BuiltinInspectorProps<SearchQuery>>(
|
|
|
33
40
|
}
|
|
34
41
|
|
|
35
42
|
return (
|
|
36
|
-
<div
|
|
43
|
+
<div
|
|
44
|
+
className={cx(
|
|
45
|
+
styles.root,
|
|
46
|
+
(isArgumentsStreaming || isLoading) && shinyTextStyles.shinyText,
|
|
47
|
+
)}
|
|
48
|
+
>
|
|
37
49
|
<span>{t('builtins.lobe-web-browsing.apiName.search')}: </span>
|
|
38
50
|
{query && <span className={highlightTextStyles.gold}>{query}</span>}
|
|
51
|
+
{!isLoading &&
|
|
52
|
+
!isArgumentsStreaming &&
|
|
53
|
+
pluginState?.results &&
|
|
54
|
+
(hasResults ? (
|
|
55
|
+
<span style={{ marginInlineStart: 4 }}>({resultCount})</span>
|
|
56
|
+
) : (
|
|
57
|
+
<Text
|
|
58
|
+
as={'span'}
|
|
59
|
+
color={cssVar.colorTextDescription}
|
|
60
|
+
fontSize={12}
|
|
61
|
+
style={{ marginInlineStart: 4 }}
|
|
62
|
+
>
|
|
63
|
+
({t('builtins.lobe-web-browsing.inspector.noResults')})
|
|
64
|
+
</Text>
|
|
65
|
+
))}
|
|
39
66
|
</div>
|
|
40
67
|
);
|
|
41
68
|
},
|
|
@@ -1028,6 +1028,90 @@ describe('google contextBuilders', () => {
|
|
|
1028
1028
|
|
|
1029
1029
|
expect(result.parameters?.description).toBe('Test parameters');
|
|
1030
1030
|
});
|
|
1031
|
+
|
|
1032
|
+
it('should convert const to enum for Google compatibility', () => {
|
|
1033
|
+
const tool: ChatCompletionTool = {
|
|
1034
|
+
function: {
|
|
1035
|
+
description: 'A tool with const values',
|
|
1036
|
+
name: 'constTool',
|
|
1037
|
+
parameters: {
|
|
1038
|
+
properties: {
|
|
1039
|
+
action: { const: 'insert', type: 'string' },
|
|
1040
|
+
nested: {
|
|
1041
|
+
properties: {
|
|
1042
|
+
operation: { const: 'create', type: 'string' },
|
|
1043
|
+
},
|
|
1044
|
+
type: 'object',
|
|
1045
|
+
},
|
|
1046
|
+
},
|
|
1047
|
+
type: 'object',
|
|
1048
|
+
},
|
|
1049
|
+
},
|
|
1050
|
+
type: 'function',
|
|
1051
|
+
};
|
|
1052
|
+
|
|
1053
|
+
const result = buildGoogleTool(tool);
|
|
1054
|
+
|
|
1055
|
+
// const should be converted to enum with single value
|
|
1056
|
+
expect(result.parameters?.properties).toEqual({
|
|
1057
|
+
action: { enum: ['insert'], type: 'string' },
|
|
1058
|
+
nested: {
|
|
1059
|
+
properties: {
|
|
1060
|
+
operation: { enum: ['create'], type: 'string' },
|
|
1061
|
+
},
|
|
1062
|
+
type: 'object',
|
|
1063
|
+
},
|
|
1064
|
+
});
|
|
1065
|
+
});
|
|
1066
|
+
|
|
1067
|
+
it('should handle oneOf with const values (like page-agent modifyNodes)', () => {
|
|
1068
|
+
const tool: ChatCompletionTool = {
|
|
1069
|
+
function: {
|
|
1070
|
+
description: 'Modify nodes operation',
|
|
1071
|
+
name: 'modifyNodes',
|
|
1072
|
+
parameters: {
|
|
1073
|
+
properties: {
|
|
1074
|
+
operations: {
|
|
1075
|
+
items: {
|
|
1076
|
+
oneOf: [
|
|
1077
|
+
{
|
|
1078
|
+
properties: {
|
|
1079
|
+
action: { const: 'insert', type: 'string' },
|
|
1080
|
+
beforeId: { type: 'string' },
|
|
1081
|
+
},
|
|
1082
|
+
type: 'object',
|
|
1083
|
+
},
|
|
1084
|
+
{
|
|
1085
|
+
properties: {
|
|
1086
|
+
action: { const: 'modify', type: 'string' },
|
|
1087
|
+
content: { type: 'string' },
|
|
1088
|
+
},
|
|
1089
|
+
type: 'object',
|
|
1090
|
+
},
|
|
1091
|
+
],
|
|
1092
|
+
},
|
|
1093
|
+
type: 'array',
|
|
1094
|
+
},
|
|
1095
|
+
},
|
|
1096
|
+
type: 'object',
|
|
1097
|
+
},
|
|
1098
|
+
},
|
|
1099
|
+
type: 'function',
|
|
1100
|
+
};
|
|
1101
|
+
|
|
1102
|
+
const result = buildGoogleTool(tool);
|
|
1103
|
+
|
|
1104
|
+
// All const values in nested oneOf should be converted to enum
|
|
1105
|
+
const operations = result.parameters?.properties?.operations as any;
|
|
1106
|
+
expect(operations.items.oneOf[0].properties.action).toEqual({
|
|
1107
|
+
enum: ['insert'],
|
|
1108
|
+
type: 'string',
|
|
1109
|
+
});
|
|
1110
|
+
expect(operations.items.oneOf[1].properties.action).toEqual({
|
|
1111
|
+
enum: ['modify'],
|
|
1112
|
+
type: 'string',
|
|
1113
|
+
});
|
|
1114
|
+
});
|
|
1031
1115
|
});
|
|
1032
1116
|
|
|
1033
1117
|
describe('buildGoogleTools', () => {
|
|
@@ -209,6 +209,39 @@ export const buildGoogleMessages = async (messages: OpenAIChatMessage[]): Promis
|
|
|
209
209
|
return filteredContents;
|
|
210
210
|
};
|
|
211
211
|
|
|
212
|
+
/**
|
|
213
|
+
* Sanitize JSON Schema for Google GenAI compatibility
|
|
214
|
+
* Google's API doesn't support certain JSON Schema keywords like 'const'
|
|
215
|
+
* This function recursively processes the schema and converts unsupported keywords
|
|
216
|
+
*/
|
|
217
|
+
const sanitizeSchemaForGoogle = (schema: Record<string, any>): Record<string, any> => {
|
|
218
|
+
if (!schema || typeof schema !== 'object') return schema;
|
|
219
|
+
|
|
220
|
+
// Handle arrays
|
|
221
|
+
if (Array.isArray(schema)) {
|
|
222
|
+
return schema.map((item) => sanitizeSchemaForGoogle(item));
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
const result: Record<string, any> = {};
|
|
226
|
+
|
|
227
|
+
for (const [key, value] of Object.entries(schema)) {
|
|
228
|
+
// Convert 'const' to 'enum' with single value (Google doesn't support 'const')
|
|
229
|
+
if (key === 'const') {
|
|
230
|
+
result['enum'] = [value];
|
|
231
|
+
continue;
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
// Recursively process nested objects
|
|
235
|
+
if (value && typeof value === 'object') {
|
|
236
|
+
result[key] = sanitizeSchemaForGoogle(value);
|
|
237
|
+
} else {
|
|
238
|
+
result[key] = value;
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
return result;
|
|
243
|
+
};
|
|
244
|
+
|
|
212
245
|
/**
|
|
213
246
|
* Convert ChatCompletionTool to Google FunctionDeclaration
|
|
214
247
|
*/
|
|
@@ -216,11 +249,14 @@ export const buildGoogleTool = (tool: ChatCompletionTool): FunctionDeclaration =
|
|
|
216
249
|
const functionDeclaration = tool.function;
|
|
217
250
|
const parameters = functionDeclaration.parameters;
|
|
218
251
|
// refs: https://github.com/lobehub/lobe-chat/pull/5002
|
|
219
|
-
const
|
|
252
|
+
const rawProperties =
|
|
220
253
|
parameters?.properties && Object.keys(parameters.properties).length > 0
|
|
221
254
|
? parameters.properties
|
|
222
255
|
: { dummy: { type: 'string' } }; // dummy property to avoid empty object
|
|
223
256
|
|
|
257
|
+
// Sanitize properties to remove unsupported JSON Schema keywords for Google
|
|
258
|
+
const properties = sanitizeSchemaForGoogle(rawProperties);
|
|
259
|
+
|
|
224
260
|
return {
|
|
225
261
|
description: functionDeclaration.description,
|
|
226
262
|
name: functionDeclaration.name,
|
|
@@ -1,25 +1,16 @@
|
|
|
1
|
-
import { ActionIcon,
|
|
1
|
+
import { ActionIcon, type DropdownItem, DropdownMenu } from '@lobehub/ui';
|
|
2
2
|
import { MoreHorizontalIcon } from 'lucide-react';
|
|
3
3
|
import { memo } from 'react';
|
|
4
4
|
|
|
5
5
|
interface ActionProps {
|
|
6
|
-
dropdownMenu:
|
|
6
|
+
dropdownMenu: DropdownItem[] | (() => DropdownItem[]);
|
|
7
7
|
}
|
|
8
8
|
|
|
9
9
|
const Actions = memo<ActionProps>(({ dropdownMenu }) => {
|
|
10
10
|
return (
|
|
11
|
-
<
|
|
12
|
-
arrow={false}
|
|
13
|
-
menu={{
|
|
14
|
-
items: dropdownMenu,
|
|
15
|
-
onClick: ({ domEvent }) => {
|
|
16
|
-
domEvent.stopPropagation();
|
|
17
|
-
},
|
|
18
|
-
}}
|
|
19
|
-
trigger={['click']}
|
|
20
|
-
>
|
|
11
|
+
<DropdownMenu items={dropdownMenu}>
|
|
21
12
|
<ActionIcon icon={MoreHorizontalIcon} size={'small'} />
|
|
22
|
-
</
|
|
13
|
+
</DropdownMenu>
|
|
23
14
|
);
|
|
24
15
|
});
|
|
25
16
|
|