@lobehub/lobehub 2.0.0-next.50 → 2.0.0-next.51
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +25 -0
- package/apps/desktop/src/main/controllers/ShellCommandCtr.ts +242 -0
- package/apps/desktop/src/main/controllers/__tests__/ShellCommandCtr.test.ts +499 -0
- package/changelog/v1.json +9 -0
- package/locales/ar/chat.json +20 -0
- package/locales/ar/common.json +1 -0
- package/locales/ar/components.json +6 -0
- package/locales/ar/plugin.json +1 -0
- package/locales/bg-BG/chat.json +20 -0
- package/locales/bg-BG/common.json +1 -0
- package/locales/bg-BG/components.json +6 -0
- package/locales/bg-BG/plugin.json +1 -0
- package/locales/de-DE/chat.json +20 -0
- package/locales/de-DE/common.json +1 -0
- package/locales/de-DE/components.json +6 -0
- package/locales/de-DE/plugin.json +1 -0
- package/locales/en-US/chat.json +20 -0
- package/locales/en-US/common.json +1 -0
- package/locales/en-US/components.json +6 -0
- package/locales/en-US/plugin.json +1 -0
- package/locales/es-ES/chat.json +20 -0
- package/locales/es-ES/common.json +1 -0
- package/locales/es-ES/components.json +6 -0
- package/locales/es-ES/plugin.json +1 -0
- package/locales/fa-IR/chat.json +20 -0
- package/locales/fa-IR/common.json +1 -0
- package/locales/fa-IR/components.json +6 -0
- package/locales/fa-IR/plugin.json +1 -0
- package/locales/fr-FR/chat.json +20 -0
- package/locales/fr-FR/common.json +1 -0
- package/locales/fr-FR/components.json +6 -0
- package/locales/fr-FR/plugin.json +1 -0
- package/locales/it-IT/chat.json +20 -0
- package/locales/it-IT/common.json +1 -0
- package/locales/it-IT/components.json +6 -0
- package/locales/it-IT/plugin.json +1 -0
- package/locales/ja-JP/chat.json +20 -0
- package/locales/ja-JP/common.json +1 -0
- package/locales/ja-JP/components.json +6 -0
- package/locales/ja-JP/plugin.json +1 -0
- package/locales/ko-KR/chat.json +20 -0
- package/locales/ko-KR/common.json +1 -0
- package/locales/ko-KR/components.json +6 -0
- package/locales/ko-KR/plugin.json +1 -0
- package/locales/nl-NL/chat.json +20 -0
- package/locales/nl-NL/common.json +1 -0
- package/locales/nl-NL/components.json +6 -0
- package/locales/nl-NL/plugin.json +1 -0
- package/locales/pl-PL/chat.json +20 -0
- package/locales/pl-PL/common.json +1 -0
- package/locales/pl-PL/components.json +6 -0
- package/locales/pl-PL/plugin.json +1 -0
- package/locales/pt-BR/chat.json +20 -0
- package/locales/pt-BR/common.json +1 -0
- package/locales/pt-BR/components.json +6 -0
- package/locales/pt-BR/plugin.json +1 -0
- package/locales/ru-RU/chat.json +20 -0
- package/locales/ru-RU/common.json +1 -0
- package/locales/ru-RU/components.json +6 -0
- package/locales/ru-RU/plugin.json +1 -0
- package/locales/tr-TR/chat.json +20 -0
- package/locales/tr-TR/common.json +1 -0
- package/locales/tr-TR/components.json +6 -0
- package/locales/tr-TR/plugin.json +1 -0
- package/locales/vi-VN/chat.json +20 -0
- package/locales/vi-VN/common.json +1 -0
- package/locales/vi-VN/components.json +6 -0
- package/locales/vi-VN/plugin.json +1 -0
- package/locales/zh-CN/chat.json +20 -0
- package/locales/zh-CN/common.json +1 -0
- package/locales/zh-CN/components.json +6 -0
- package/locales/zh-CN/plugin.json +1 -0
- package/locales/zh-TW/chat.json +20 -0
- package/locales/zh-TW/common.json +1 -0
- package/locales/zh-TW/components.json +6 -0
- package/locales/zh-TW/plugin.json +1 -0
- package/package.json +1 -1
- package/packages/agent-runtime/src/core/InterventionChecker.ts +1 -1
- package/packages/agent-runtime/src/core/__tests__/InterventionChecker.test.ts +23 -23
- package/packages/agent-runtime/src/types/state.ts +7 -1
- package/packages/const/src/settings/tool.ts +1 -5
- package/packages/file-loaders/src/loaders/docx/index.ts +1 -1
- package/packages/model-bank/src/aiModels/wenxin.ts +1348 -291
- package/packages/model-runtime/src/providers/wenxin/index.ts +22 -1
- package/packages/model-runtime/src/utils/modelParse.ts +6 -0
- package/packages/types/src/tool/builtin.ts +9 -0
- package/packages/types/src/tool/intervention.ts +32 -2
- package/packages/types/src/user/settings/tool.ts +3 -27
- package/src/config/modelProviders/wenxin.ts +2 -3
- package/src/features/Conversation/MarkdownElements/remarkPlugins/__snapshots__/createRemarkSelfClosingTagPlugin.test.ts.snap +133 -0
- package/src/features/Conversation/MarkdownElements/remarkPlugins/createRemarkSelfClosingTagPlugin.test.ts +48 -0
- package/src/features/Conversation/MarkdownElements/remarkPlugins/createRemarkSelfClosingTagPlugin.ts +2 -1
- package/src/features/Conversation/Messages/Group/Tool/Render/Intervention/Fallback.tsx +98 -0
- package/src/features/Conversation/Messages/Group/Tool/Render/Intervention/ModeSelector.tsx +5 -6
- package/src/features/Conversation/Messages/Group/Tool/Render/Intervention/index.tsx +40 -36
- package/src/features/Conversation/Messages/Group/Tool/Render/index.tsx +25 -18
- package/src/features/LocalFile/LocalFile.tsx +55 -5
- package/src/locales/default/components.ts +6 -0
- package/src/locales/default/plugin.ts +1 -0
- package/src/services/electron/localFileService.ts +4 -0
- package/src/store/chat/agents/GeneralChatAgent.ts +26 -1
- package/src/store/chat/agents/__tests__/GeneralChatAgent.test.ts +173 -0
- package/src/store/chat/slices/aiChat/actions/conversationControl.ts +8 -40
- package/src/store/chat/slices/aiChat/actions/streamingExecutor.ts +91 -34
- package/src/store/user/selectors.ts +1 -0
- package/src/store/user/slices/settings/action.ts +12 -0
- package/src/store/user/slices/settings/selectors/__snapshots__/settings.test.ts.snap +0 -7
- package/src/store/user/slices/settings/selectors/index.ts +1 -0
- package/src/store/user/slices/settings/selectors/settings.test.ts +0 -37
- package/src/store/user/slices/settings/selectors/settings.ts +0 -5
- package/src/store/user/slices/settings/selectors/toolIntervention.ts +17 -0
- package/src/tools/interventions.ts +8 -0
- package/src/tools/local-system/Intervention/RunCommand/index.tsx +56 -0
- package/src/tools/local-system/Intervention/index.tsx +17 -0
- package/src/tools/local-system/Render/RunCommand/index.tsx +100 -21
- package/src/tools/local-system/Render/index.tsx +2 -0
- package/src/tools/local-system/index.ts +180 -0
- package/src/tools/local-system/systemRole.ts +61 -7
|
@@ -4,12 +4,17 @@ import {
|
|
|
4
4
|
OpenAICompatibleFactoryOptions,
|
|
5
5
|
createOpenAICompatibleRuntime,
|
|
6
6
|
} from '../../core/openaiCompatibleFactory';
|
|
7
|
+
import { processMultiProviderModelList } from '../../utils/modelParse';
|
|
8
|
+
|
|
9
|
+
export interface WenxinModelCard {
|
|
10
|
+
id: string;
|
|
11
|
+
}
|
|
7
12
|
|
|
8
13
|
export const params = {
|
|
9
14
|
baseURL: 'https://qianfan.baidubce.com/v2',
|
|
10
15
|
chatCompletion: {
|
|
11
16
|
handlePayload: (payload) => {
|
|
12
|
-
const { enabledSearch, ...rest } = payload;
|
|
17
|
+
const { enabledSearch, thinking, ...rest } = payload;
|
|
13
18
|
|
|
14
19
|
return {
|
|
15
20
|
...rest,
|
|
@@ -21,12 +26,28 @@ export const params = {
|
|
|
21
26
|
enable_trace: true,
|
|
22
27
|
},
|
|
23
28
|
}),
|
|
29
|
+
...(thinking && {
|
|
30
|
+
enable_thinking: { disabled: false, enabled: true }[thinking.type],
|
|
31
|
+
...(thinking?.budget_tokens !== 0 && {
|
|
32
|
+
thinking_budget: Math.min(Math.max(thinking?.budget_tokens, 100), 16_384),
|
|
33
|
+
}),
|
|
34
|
+
}),
|
|
24
35
|
} as any;
|
|
25
36
|
},
|
|
26
37
|
},
|
|
27
38
|
debug: {
|
|
28
39
|
chatCompletion: () => process.env.DEBUG_WENXIN_CHAT_COMPLETION === '1',
|
|
29
40
|
},
|
|
41
|
+
models: async ({ client }) => {
|
|
42
|
+
const modelsPage = (await client.models.list()) as any;
|
|
43
|
+
const modelList: WenxinModelCard[] = modelsPage.data;
|
|
44
|
+
|
|
45
|
+
const standardModelList = modelList.map((model) => ({
|
|
46
|
+
id: model.id,
|
|
47
|
+
}));
|
|
48
|
+
|
|
49
|
+
return processMultiProviderModelList(standardModelList, 'wenxin');
|
|
50
|
+
},
|
|
30
51
|
provider: ModelProvider.Wenxin,
|
|
31
52
|
} satisfies OpenAICompatibleFactoryOptions;
|
|
32
53
|
|
|
@@ -98,6 +98,11 @@ export const MODEL_LIST_CONFIGS = {
|
|
|
98
98
|
reasoningKeywords: ['thinking', 'seed', 'ui-tars'],
|
|
99
99
|
visionKeywords: ['vision', '-m', 'seed', 'ui-tars'],
|
|
100
100
|
},
|
|
101
|
+
wenxin: {
|
|
102
|
+
functionCallKeywords: ['ernie-5', 'ernie-x1', 'pro', 'ernie-4.5-21b-a3b-thinking'],
|
|
103
|
+
reasoningKeywords: ['thinking', 'ernie-x', 'ernie-4.5-vl-28b-a3b'],
|
|
104
|
+
visionKeywords: ['-vl', 'ernie-5.0', 'picocr', 'qianfan-composition'],
|
|
105
|
+
},
|
|
101
106
|
xai: {
|
|
102
107
|
functionCallKeywords: ['grok'],
|
|
103
108
|
reasoningKeywords: ['mini', 'grok-4', 'grok-code-fast', '!non-reasoning'],
|
|
@@ -129,6 +134,7 @@ export const MODEL_OWNER_DETECTION_CONFIG = {
|
|
|
129
134
|
qwen: ['qwen', 'qwq', 'qvq'],
|
|
130
135
|
v0: ['v0'],
|
|
131
136
|
volcengine: ['doubao'],
|
|
137
|
+
wenxin: ['ernie', 'qianfan'],
|
|
132
138
|
xai: ['grok'],
|
|
133
139
|
zeroone: ['yi-'],
|
|
134
140
|
zhipu: ['glm'],
|
|
@@ -151,3 +151,12 @@ export interface BuiltinServerRuntimeOutput {
|
|
|
151
151
|
state?: any;
|
|
152
152
|
success: boolean;
|
|
153
153
|
}
|
|
154
|
+
|
|
155
|
+
export interface BuiltinInterventionProps<Arguments = any> {
|
|
156
|
+
apiName?: string;
|
|
157
|
+
args: Arguments;
|
|
158
|
+
identifier?: string;
|
|
159
|
+
messageId: string;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
export type BuiltinIntervention = (props: BuiltinInterventionProps) => ReactNode;
|
|
@@ -5,9 +5,9 @@ import { z } from 'zod';
|
|
|
5
5
|
*/
|
|
6
6
|
export type HumanInterventionPolicy =
|
|
7
7
|
| 'never' // Never intervene, auto-execute
|
|
8
|
-
| '
|
|
8
|
+
| 'required'; // Always require intervention
|
|
9
9
|
|
|
10
|
-
export const HumanInterventionPolicySchema = z.enum(['never', '
|
|
10
|
+
export const HumanInterventionPolicySchema = z.enum(['never', 'required']);
|
|
11
11
|
|
|
12
12
|
/**
|
|
13
13
|
* Argument Matcher for parameter-level filtering
|
|
@@ -116,6 +116,36 @@ export const HumanInterventionResponseSchema = z.object({
|
|
|
116
116
|
.optional(),
|
|
117
117
|
});
|
|
118
118
|
|
|
119
|
+
/**
|
|
120
|
+
* User's global intervention configuration
|
|
121
|
+
* Applied across all tools in the session
|
|
122
|
+
*/
|
|
123
|
+
export interface UserInterventionConfig {
|
|
124
|
+
/**
|
|
125
|
+
* Allow list of approved tools (used in 'allow-list' mode)
|
|
126
|
+
* Format: "identifier/apiName"
|
|
127
|
+
*
|
|
128
|
+
* Examples:
|
|
129
|
+
* - "bash/bash"
|
|
130
|
+
* - "web-browsing/crawlSinglePage"
|
|
131
|
+
* - "search/search"
|
|
132
|
+
*/
|
|
133
|
+
allowList?: string[];
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* Tool approval mode
|
|
137
|
+
* - auto-run: Automatically approve all tools without user consent
|
|
138
|
+
* - allow-list: Only approve tools in the allow list
|
|
139
|
+
* - manual: Use tool's own humanIntervention config (default)
|
|
140
|
+
*/
|
|
141
|
+
approvalMode: 'auto-run' | 'allow-list' | 'manual';
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
export const UserInterventionConfigSchema = z.object({
|
|
145
|
+
allowList: z.array(z.string()).optional(),
|
|
146
|
+
approvalMode: z.enum(['auto-run', 'allow-list', 'manual']),
|
|
147
|
+
});
|
|
148
|
+
|
|
119
149
|
/**
|
|
120
150
|
* Parameters for shouldIntervene method
|
|
121
151
|
*/
|
|
@@ -1,29 +1,5 @@
|
|
|
1
|
-
|
|
2
|
-
/**
|
|
3
|
-
* Tool approval mode
|
|
4
|
-
* - auto-run: Automatically approve all tools without user consent
|
|
5
|
-
* - allow-list: Only approve tools in the allow list
|
|
6
|
-
* - manual: Require manual approval for each tool execution
|
|
7
|
-
*/
|
|
8
|
-
approvalMode?: 'auto-run' | 'allow-list' | 'manual';
|
|
9
|
-
|
|
10
|
-
dalle: {
|
|
11
|
-
autoGenerate: boolean;
|
|
12
|
-
};
|
|
1
|
+
import { UserInterventionConfig } from '../../tool';
|
|
13
2
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
*/
|
|
17
|
-
humanIntervention?: {
|
|
18
|
-
/**
|
|
19
|
-
* Allow list of approved tools (used in 'allow-list' mode)
|
|
20
|
-
* Format: "identifier/apiName"
|
|
21
|
-
*
|
|
22
|
-
* Examples:
|
|
23
|
-
* - "web-browsing/crawlSinglePage"
|
|
24
|
-
* - "bash/bash"
|
|
25
|
-
* - "search/search"
|
|
26
|
-
*/
|
|
27
|
-
allowList?: string[];
|
|
28
|
-
};
|
|
3
|
+
export interface UserToolConfig {
|
|
4
|
+
humanIntervention?: UserInterventionConfig;
|
|
29
5
|
}
|
|
@@ -1,13 +1,12 @@
|
|
|
1
1
|
import { ModelProviderCard } from '@/types/llm';
|
|
2
2
|
|
|
3
|
-
// ref https://cloud.baidu.com/doc/WENXINWORKSHOP/s/Nlks5zkzu
|
|
4
3
|
const BaiduWenxin: ModelProviderCard = {
|
|
5
4
|
chatModels: [],
|
|
6
|
-
checkModel: 'ernie-
|
|
5
|
+
checkModel: 'ernie-4.5-turbo-latest',
|
|
7
6
|
description:
|
|
8
7
|
'企业级一站式大模型与AI原生应用开发及服务平台,提供最全面易用的生成式人工智能模型开发、应用开发全流程工具链',
|
|
9
8
|
id: 'wenxin',
|
|
10
|
-
modelsUrl: 'https://
|
|
9
|
+
modelsUrl: 'https://console.bce.baidu.com/qianfan/modelcenter/model/buildIn/list',
|
|
11
10
|
name: 'Wenxin',
|
|
12
11
|
settings: {
|
|
13
12
|
proxyUrl: {
|
|
@@ -1,5 +1,138 @@
|
|
|
1
1
|
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
|
|
2
2
|
|
|
3
|
+
exports[`createRemarkSelfClosingTagPlugin > should handle multiple tags in unordered list with directories and files 1`] = `
|
|
4
|
+
{
|
|
5
|
+
"children": [
|
|
6
|
+
{
|
|
7
|
+
"children": [
|
|
8
|
+
{
|
|
9
|
+
"position": {
|
|
10
|
+
"end": {
|
|
11
|
+
"column": 32,
|
|
12
|
+
"line": 1,
|
|
13
|
+
"offset": 31,
|
|
14
|
+
},
|
|
15
|
+
"start": {
|
|
16
|
+
"column": 1,
|
|
17
|
+
"line": 1,
|
|
18
|
+
"offset": 0,
|
|
19
|
+
},
|
|
20
|
+
},
|
|
21
|
+
"type": "text",
|
|
22
|
+
"value": "我已查看了你桌面上 test 文件夹的目录,里面包含以下项目:",
|
|
23
|
+
},
|
|
24
|
+
],
|
|
25
|
+
"position": {
|
|
26
|
+
"end": {
|
|
27
|
+
"column": 32,
|
|
28
|
+
"line": 1,
|
|
29
|
+
"offset": 31,
|
|
30
|
+
},
|
|
31
|
+
"start": {
|
|
32
|
+
"column": 1,
|
|
33
|
+
"line": 1,
|
|
34
|
+
"offset": 0,
|
|
35
|
+
},
|
|
36
|
+
},
|
|
37
|
+
"type": "paragraph",
|
|
38
|
+
},
|
|
39
|
+
{
|
|
40
|
+
"children": [
|
|
41
|
+
{
|
|
42
|
+
"checked": null,
|
|
43
|
+
"children": [
|
|
44
|
+
{
|
|
45
|
+
"data": {
|
|
46
|
+
"hName": "localFile",
|
|
47
|
+
"hProperties": {
|
|
48
|
+
"isDirectory": true,
|
|
49
|
+
"name": ".config",
|
|
50
|
+
"path": "/Users/user/Desktop/test/.config",
|
|
51
|
+
},
|
|
52
|
+
},
|
|
53
|
+
"type": "localFile",
|
|
54
|
+
},
|
|
55
|
+
],
|
|
56
|
+
"position": {
|
|
57
|
+
"end": {
|
|
58
|
+
"column": 87,
|
|
59
|
+
"line": 3,
|
|
60
|
+
"offset": 119,
|
|
61
|
+
},
|
|
62
|
+
"start": {
|
|
63
|
+
"column": 1,
|
|
64
|
+
"line": 3,
|
|
65
|
+
"offset": 33,
|
|
66
|
+
},
|
|
67
|
+
},
|
|
68
|
+
"spread": false,
|
|
69
|
+
"type": "listItem",
|
|
70
|
+
},
|
|
71
|
+
{
|
|
72
|
+
"checked": null,
|
|
73
|
+
"children": [
|
|
74
|
+
{
|
|
75
|
+
"data": {
|
|
76
|
+
"hName": "localFile",
|
|
77
|
+
"hProperties": {
|
|
78
|
+
"isDirectory": true,
|
|
79
|
+
"name": ".venv",
|
|
80
|
+
"path": "/Users/user/Desktop/test/.venv",
|
|
81
|
+
},
|
|
82
|
+
},
|
|
83
|
+
"type": "localFile",
|
|
84
|
+
},
|
|
85
|
+
],
|
|
86
|
+
"position": {
|
|
87
|
+
"end": {
|
|
88
|
+
"column": 79,
|
|
89
|
+
"line": 4,
|
|
90
|
+
"offset": 198,
|
|
91
|
+
},
|
|
92
|
+
"start": {
|
|
93
|
+
"column": 1,
|
|
94
|
+
"line": 4,
|
|
95
|
+
"offset": 120,
|
|
96
|
+
},
|
|
97
|
+
},
|
|
98
|
+
"spread": false,
|
|
99
|
+
"type": "listItem",
|
|
100
|
+
},
|
|
101
|
+
],
|
|
102
|
+
"ordered": false,
|
|
103
|
+
"position": {
|
|
104
|
+
"end": {
|
|
105
|
+
"column": 79,
|
|
106
|
+
"line": 4,
|
|
107
|
+
"offset": 198,
|
|
108
|
+
},
|
|
109
|
+
"start": {
|
|
110
|
+
"column": 1,
|
|
111
|
+
"line": 3,
|
|
112
|
+
"offset": 33,
|
|
113
|
+
},
|
|
114
|
+
},
|
|
115
|
+
"spread": false,
|
|
116
|
+
"start": null,
|
|
117
|
+
"type": "list",
|
|
118
|
+
},
|
|
119
|
+
],
|
|
120
|
+
"position": {
|
|
121
|
+
"end": {
|
|
122
|
+
"column": 79,
|
|
123
|
+
"line": 4,
|
|
124
|
+
"offset": 198,
|
|
125
|
+
},
|
|
126
|
+
"start": {
|
|
127
|
+
"column": 1,
|
|
128
|
+
"line": 1,
|
|
129
|
+
"offset": 0,
|
|
130
|
+
},
|
|
131
|
+
},
|
|
132
|
+
"type": "root",
|
|
133
|
+
}
|
|
134
|
+
`;
|
|
135
|
+
|
|
3
136
|
exports[`createRemarkSelfClosingTagPlugin > should handle tag within a list item and generate snapshot 1`] = `
|
|
4
137
|
{
|
|
5
138
|
"children": [
|
|
@@ -201,4 +201,52 @@ describe('createRemarkSelfClosingTagPlugin', () => {
|
|
|
201
201
|
const tree = processMarkdown(markdown, tagName);
|
|
202
202
|
expect(tree).toMatchSnapshot();
|
|
203
203
|
});
|
|
204
|
+
|
|
205
|
+
it('should handle multiple tags in unordered list with directories and files', () => {
|
|
206
|
+
const markdown = [
|
|
207
|
+
'我已查看了你桌面上 test 文件夹的目录,里面包含以下项目:',
|
|
208
|
+
'',
|
|
209
|
+
'- <localFile name=".config" path="/Users/user/Desktop/test/.config" isDirectory /> ', // 注意:行尾有 4 个空格
|
|
210
|
+
'- <localFile name=".venv" path="/Users/user/Desktop/test/.venv" isDirectory />',
|
|
211
|
+
].join('\n');
|
|
212
|
+
const tree = processMarkdown(markdown, tagName);
|
|
213
|
+
|
|
214
|
+
// Should have 2 children: a paragraph and a list
|
|
215
|
+
expect(tree.children).toHaveLength(2);
|
|
216
|
+
|
|
217
|
+
// First child should be the introductory paragraph
|
|
218
|
+
expect(tree.children[0].type).toBe('paragraph');
|
|
219
|
+
|
|
220
|
+
// Second child should be the unordered list
|
|
221
|
+
const listNode = tree.children[1];
|
|
222
|
+
expect(listNode.type).toBe('list');
|
|
223
|
+
expect(listNode.ordered).toBe(false);
|
|
224
|
+
|
|
225
|
+
// The list should have 2 items
|
|
226
|
+
expect(listNode.children).toHaveLength(2);
|
|
227
|
+
|
|
228
|
+
// Verify first item (.config directory) - this one has trailing spaces after />
|
|
229
|
+
// When a tag is standalone in a list item, remark doesn't wrap it in a paragraph
|
|
230
|
+
const firstItem = listNode.children[0];
|
|
231
|
+
expect(firstItem.type).toBe('listItem');
|
|
232
|
+
const firstTag = firstItem.children[0];
|
|
233
|
+
expect(firstTag.type).toBe(tagName);
|
|
234
|
+
expect(firstTag.data?.hProperties).toEqual({
|
|
235
|
+
name: '.config',
|
|
236
|
+
path: '/Users/user/Desktop/test/.config',
|
|
237
|
+
isDirectory: true,
|
|
238
|
+
});
|
|
239
|
+
|
|
240
|
+
// Verify second item (.venv directory)
|
|
241
|
+
const secondItem = listNode.children[1];
|
|
242
|
+
const secondTag = secondItem.children[0];
|
|
243
|
+
expect(secondTag.type).toBe(tagName);
|
|
244
|
+
expect(secondTag.data?.hProperties).toEqual({
|
|
245
|
+
name: '.venv',
|
|
246
|
+
path: '/Users/user/Desktop/test/.venv',
|
|
247
|
+
isDirectory: true,
|
|
248
|
+
});
|
|
249
|
+
|
|
250
|
+
expect(tree).toMatchSnapshot();
|
|
251
|
+
});
|
|
204
252
|
});
|
package/src/features/Conversation/MarkdownElements/remarkPlugins/createRemarkSelfClosingTagPlugin.ts
CHANGED
|
@@ -25,7 +25,8 @@ export const createRemarkSelfClosingTagPlugin =
|
|
|
25
25
|
(tagName: string): Plugin<[], any> =>
|
|
26
26
|
() => {
|
|
27
27
|
// Regex for the specific tag, ensure it matches the entire string for HTML check
|
|
28
|
-
|
|
28
|
+
// Allow trailing whitespace after /> to handle cases where markdown parsers include it
|
|
29
|
+
const exactTagRegex = new RegExp(`^<${tagName}(\\s+[^>]*?)?\\s*\\/>\\s*$`);
|
|
29
30
|
// Regex for finding tags within text
|
|
30
31
|
const textTagRegex = new RegExp(`<${tagName}(\\s+[^>]*?)?\\s*\\/>`, 'g');
|
|
31
32
|
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import { safeParseJSON } from '@lobechat/utils';
|
|
2
|
+
import { ActionIcon } from '@lobehub/ui';
|
|
3
|
+
import { Edit3Icon } from 'lucide-react';
|
|
4
|
+
import { Suspense, memo, useCallback, useState } from 'react';
|
|
5
|
+
import { useTranslation } from 'react-i18next';
|
|
6
|
+
import { Flexbox } from 'react-layout-kit';
|
|
7
|
+
|
|
8
|
+
import { useChatStore } from '@/store/chat';
|
|
9
|
+
import { useUserStore } from '@/store/user';
|
|
10
|
+
import { toolInterventionSelectors } from '@/store/user/selectors';
|
|
11
|
+
|
|
12
|
+
import Arguments from '../Arguments';
|
|
13
|
+
import ApprovalActions from './ApprovalActions';
|
|
14
|
+
import KeyValueEditor from './KeyValueEditor';
|
|
15
|
+
import ModeSelector from './ModeSelector';
|
|
16
|
+
|
|
17
|
+
interface FallbackInterventionProps {
|
|
18
|
+
apiName: string;
|
|
19
|
+
id: string;
|
|
20
|
+
identifier: string;
|
|
21
|
+
requestArgs: string;
|
|
22
|
+
toolCallId: string;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
const FallbackIntervention = memo<FallbackInterventionProps>(
|
|
26
|
+
({ requestArgs, id, identifier, apiName, toolCallId }) => {
|
|
27
|
+
const { t } = useTranslation('chat');
|
|
28
|
+
const approvalMode = useUserStore(toolInterventionSelectors.approvalMode);
|
|
29
|
+
const [isEditing, setIsEditing] = useState(false);
|
|
30
|
+
const [optimisticUpdatePluginArguments] = useChatStore((s) => [
|
|
31
|
+
s.optimisticUpdatePluginArguments,
|
|
32
|
+
]);
|
|
33
|
+
|
|
34
|
+
const handleCancel = useCallback(() => {
|
|
35
|
+
setIsEditing(false);
|
|
36
|
+
}, []);
|
|
37
|
+
|
|
38
|
+
const handleFinish = useCallback(
|
|
39
|
+
async (editedObject: Record<string, any>) => {
|
|
40
|
+
if (!id) return;
|
|
41
|
+
|
|
42
|
+
try {
|
|
43
|
+
const newArgsString = JSON.stringify(editedObject, null, 2);
|
|
44
|
+
|
|
45
|
+
if (newArgsString !== requestArgs) {
|
|
46
|
+
await optimisticUpdatePluginArguments(id, editedObject, true);
|
|
47
|
+
}
|
|
48
|
+
setIsEditing(false);
|
|
49
|
+
} catch (error) {
|
|
50
|
+
console.error('Error stringifying arguments:', error);
|
|
51
|
+
}
|
|
52
|
+
},
|
|
53
|
+
[requestArgs, id],
|
|
54
|
+
);
|
|
55
|
+
|
|
56
|
+
if (isEditing)
|
|
57
|
+
return (
|
|
58
|
+
<Suspense fallback={<Arguments arguments={requestArgs} />}>
|
|
59
|
+
<KeyValueEditor
|
|
60
|
+
initialValue={safeParseJSON(requestArgs || '')}
|
|
61
|
+
onCancel={handleCancel}
|
|
62
|
+
onFinish={handleFinish}
|
|
63
|
+
/>
|
|
64
|
+
</Suspense>
|
|
65
|
+
);
|
|
66
|
+
|
|
67
|
+
return (
|
|
68
|
+
<Flexbox gap={12}>
|
|
69
|
+
<Arguments
|
|
70
|
+
actions={
|
|
71
|
+
<ActionIcon
|
|
72
|
+
icon={Edit3Icon}
|
|
73
|
+
onClick={() => {
|
|
74
|
+
setIsEditing(true);
|
|
75
|
+
}}
|
|
76
|
+
size={'small'}
|
|
77
|
+
title={t('edit', { ns: 'common' })}
|
|
78
|
+
/>
|
|
79
|
+
}
|
|
80
|
+
arguments={requestArgs}
|
|
81
|
+
/>
|
|
82
|
+
|
|
83
|
+
<Flexbox horizontal justify={'space-between'}>
|
|
84
|
+
<ModeSelector />
|
|
85
|
+
<ApprovalActions
|
|
86
|
+
apiName={apiName}
|
|
87
|
+
approvalMode={approvalMode}
|
|
88
|
+
identifier={identifier}
|
|
89
|
+
messageId={id}
|
|
90
|
+
toolCallId={toolCallId}
|
|
91
|
+
/>
|
|
92
|
+
</Flexbox>
|
|
93
|
+
</Flexbox>
|
|
94
|
+
);
|
|
95
|
+
},
|
|
96
|
+
);
|
|
97
|
+
|
|
98
|
+
export default FallbackIntervention;
|
|
@@ -6,6 +6,7 @@ import { useTranslation } from 'react-i18next';
|
|
|
6
6
|
import { Center } from 'react-layout-kit';
|
|
7
7
|
|
|
8
8
|
import { useUserStore } from '@/store/user';
|
|
9
|
+
import { toolInterventionSelectors } from '@/store/user/selectors';
|
|
9
10
|
|
|
10
11
|
import { ApprovalMode } from './index';
|
|
11
12
|
|
|
@@ -39,10 +40,8 @@ const useStyles = createStyles(({ css, token }) => ({
|
|
|
39
40
|
const ModeSelector = memo(() => {
|
|
40
41
|
const { t } = useTranslation('chat');
|
|
41
42
|
const { styles } = useStyles();
|
|
42
|
-
const
|
|
43
|
-
|
|
44
|
-
s.setSettings,
|
|
45
|
-
]);
|
|
43
|
+
const approvalMode = useUserStore(toolInterventionSelectors.approvalMode);
|
|
44
|
+
const updateHumanIntervention = useUserStore((s) => s.updateHumanIntervention);
|
|
46
45
|
|
|
47
46
|
const modeLabels = useMemo(
|
|
48
47
|
() => ({
|
|
@@ -55,9 +54,9 @@ const ModeSelector = memo(() => {
|
|
|
55
54
|
|
|
56
55
|
const handleModeChange = useCallback(
|
|
57
56
|
async (mode: ApprovalMode) => {
|
|
58
|
-
await
|
|
57
|
+
await updateHumanIntervention({ approvalMode: mode });
|
|
59
58
|
},
|
|
60
|
-
[
|
|
59
|
+
[updateHumanIntervention],
|
|
61
60
|
);
|
|
62
61
|
|
|
63
62
|
const menuItems = useMemo<MenuProps['items']>(
|
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
import { safeParseJSON } from '@lobechat/utils';
|
|
2
|
-
import { ActionIcon } from '@lobehub/ui';
|
|
3
|
-
import { Edit3Icon } from 'lucide-react';
|
|
4
2
|
import { Suspense, memo, useCallback, useState } from 'react';
|
|
5
|
-
import { useTranslation } from 'react-i18next';
|
|
6
3
|
import { Flexbox } from 'react-layout-kit';
|
|
7
4
|
|
|
8
5
|
import { useChatStore } from '@/store/chat';
|
|
9
6
|
import { useUserStore } from '@/store/user';
|
|
7
|
+
import { toolInterventionSelectors } from '@/store/user/selectors';
|
|
8
|
+
import { BuiltinToolInterventions } from '@/tools/interventions';
|
|
10
9
|
|
|
11
10
|
import Arguments from '../Arguments';
|
|
12
11
|
import ApprovalActions from './ApprovalActions';
|
|
12
|
+
import Fallback from './Fallback';
|
|
13
13
|
import KeyValueEditor from './KeyValueEditor';
|
|
14
14
|
import ModeSelector from './ModeSelector';
|
|
15
15
|
|
|
@@ -25,8 +25,7 @@ interface InterventionProps {
|
|
|
25
25
|
|
|
26
26
|
const Intervention = memo<InterventionProps>(
|
|
27
27
|
({ requestArgs, id, identifier, apiName, toolCallId }) => {
|
|
28
|
-
const
|
|
29
|
-
const approvalMode = useUserStore((s) => s.settings.tool?.approvalMode || 'manual');
|
|
28
|
+
const approvalMode = useUserStore(toolInterventionSelectors.approvalMode);
|
|
30
29
|
const [isEditing, setIsEditing] = useState(false);
|
|
31
30
|
const [optimisticUpdatePluginArguments] = useChatStore((s) => [
|
|
32
31
|
s.optimisticUpdatePluginArguments,
|
|
@@ -53,45 +52,50 @@ const Intervention = memo<InterventionProps>(
|
|
|
53
52
|
},
|
|
54
53
|
[requestArgs, id],
|
|
55
54
|
);
|
|
55
|
+
const BuiltinToolInterventionRender = BuiltinToolInterventions[identifier];
|
|
56
56
|
|
|
57
|
-
if (
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
<
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
</Suspense>
|
|
66
|
-
);
|
|
67
|
-
|
|
68
|
-
return (
|
|
69
|
-
<Flexbox gap={12}>
|
|
70
|
-
<Arguments
|
|
71
|
-
actions={
|
|
72
|
-
<ActionIcon
|
|
73
|
-
icon={Edit3Icon}
|
|
74
|
-
onClick={() => {
|
|
75
|
-
setIsEditing(true);
|
|
76
|
-
}}
|
|
77
|
-
size={'small'}
|
|
78
|
-
title={t('edit', { ns: 'common' })}
|
|
57
|
+
if (BuiltinToolInterventionRender) {
|
|
58
|
+
if (isEditing)
|
|
59
|
+
return (
|
|
60
|
+
<Suspense fallback={<Arguments arguments={requestArgs} />}>
|
|
61
|
+
<KeyValueEditor
|
|
62
|
+
initialValue={safeParseJSON(requestArgs || '')}
|
|
63
|
+
onCancel={handleCancel}
|
|
64
|
+
onFinish={handleFinish}
|
|
79
65
|
/>
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
/>
|
|
66
|
+
</Suspense>
|
|
67
|
+
);
|
|
83
68
|
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
<
|
|
69
|
+
return (
|
|
70
|
+
<Flexbox gap={12}>
|
|
71
|
+
<BuiltinToolInterventionRender
|
|
87
72
|
apiName={apiName}
|
|
88
|
-
|
|
73
|
+
args={safeParseJSON(requestArgs || '')}
|
|
89
74
|
identifier={identifier}
|
|
90
75
|
messageId={id}
|
|
91
|
-
toolCallId={toolCallId}
|
|
92
76
|
/>
|
|
77
|
+
<Flexbox horizontal justify={'space-between'}>
|
|
78
|
+
<ModeSelector />
|
|
79
|
+
<ApprovalActions
|
|
80
|
+
apiName={apiName}
|
|
81
|
+
approvalMode={approvalMode}
|
|
82
|
+
identifier={identifier}
|
|
83
|
+
messageId={id}
|
|
84
|
+
toolCallId={toolCallId}
|
|
85
|
+
/>
|
|
86
|
+
</Flexbox>
|
|
93
87
|
</Flexbox>
|
|
94
|
-
|
|
88
|
+
);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
return (
|
|
92
|
+
<Fallback
|
|
93
|
+
apiName={apiName}
|
|
94
|
+
id={id}
|
|
95
|
+
identifier={identifier}
|
|
96
|
+
requestArgs={requestArgs}
|
|
97
|
+
toolCallId={toolCallId}
|
|
98
|
+
/>
|
|
95
99
|
);
|
|
96
100
|
},
|
|
97
101
|
);
|