@lobehub/lobehub 2.0.0-next.94 → 2.0.0-next.96
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/.github/workflows/issue-auto-comments.yml +0 -19
- package/CHANGELOG.md +50 -0
- package/changelog/v1.json +18 -0
- package/locales/ar/common.json +21 -0
- package/locales/ar/hotkey.json +4 -0
- package/locales/bg-BG/common.json +21 -0
- package/locales/bg-BG/hotkey.json +4 -0
- package/locales/de-DE/common.json +21 -0
- package/locales/de-DE/hotkey.json +4 -0
- package/locales/en-US/common.json +21 -0
- package/locales/en-US/hotkey.json +4 -0
- package/locales/es-ES/common.json +21 -0
- package/locales/es-ES/hotkey.json +4 -0
- package/locales/fa-IR/common.json +21 -0
- package/locales/fa-IR/hotkey.json +4 -0
- package/locales/fr-FR/common.json +21 -0
- package/locales/fr-FR/hotkey.json +4 -0
- package/locales/it-IT/common.json +21 -0
- package/locales/it-IT/hotkey.json +4 -0
- package/locales/ja-JP/common.json +21 -0
- package/locales/ja-JP/hotkey.json +4 -0
- package/locales/ko-KR/common.json +21 -0
- package/locales/ko-KR/hotkey.json +4 -0
- package/locales/nl-NL/common.json +21 -0
- package/locales/nl-NL/hotkey.json +4 -0
- package/locales/pl-PL/common.json +21 -0
- package/locales/pl-PL/hotkey.json +4 -0
- package/locales/pt-BR/common.json +21 -0
- package/locales/pt-BR/hotkey.json +4 -0
- package/locales/ru-RU/common.json +21 -0
- package/locales/ru-RU/hotkey.json +4 -0
- package/locales/tr-TR/common.json +21 -0
- package/locales/tr-TR/hotkey.json +4 -0
- package/locales/vi-VN/common.json +21 -0
- package/locales/vi-VN/hotkey.json +4 -0
- package/locales/zh-CN/common.json +21 -0
- package/locales/zh-CN/hotkey.json +4 -0
- package/locales/zh-TW/common.json +21 -0
- package/locales/zh-TW/hotkey.json +4 -0
- package/package.json +3 -1
- package/packages/agent-runtime/src/core/InterventionChecker.ts +85 -0
- package/packages/agent-runtime/src/core/__tests__/InterventionChecker.test.ts +492 -22
- package/packages/agent-runtime/src/core/defaultSecurityBlacklist.ts +335 -0
- package/packages/agent-runtime/src/core/index.ts +1 -0
- package/packages/agent-runtime/src/types/state.ts +10 -1
- package/packages/const/src/hotkeys.ts +6 -0
- package/packages/conversation-flow/src/__tests__/indexing.test.ts +513 -0
- package/packages/conversation-flow/src/__tests__/structuring.test.ts +600 -0
- package/packages/types/src/hotkey.ts +1 -0
- package/packages/types/src/tool/intervention.ts +38 -0
- package/src/app/[variants]/(main)/settings/_layout/Desktop/index.tsx +41 -8
- package/src/app/[variants]/(main)/settings/provider/(list)/ProviderGrid/Card.tsx +6 -4
- package/src/app/[variants]/(main)/settings/provider/(list)/ProviderGrid/index.tsx +16 -4
- package/src/app/[variants]/(main)/settings/provider/(list)/index.tsx +15 -3
- package/src/app/[variants]/(main)/settings/provider/detail/index.tsx +23 -15
- package/src/features/Conversation/MarkdownElements/remarkPlugins/createRemarkSelfClosingTagPlugin.test.ts +25 -0
- package/src/features/Conversation/MarkdownElements/remarkPlugins/createRemarkSelfClosingTagPlugin.ts +28 -0
- package/src/layout/GlobalProvider/Cmdk.tsx +470 -0
- package/src/layout/GlobalProvider/CmdkLazy.tsx +17 -0
- package/src/layout/GlobalProvider/index.tsx +2 -0
- package/src/locales/default/common.ts +21 -0
- package/src/locales/default/hotkey.ts +4 -0
- package/src/store/chat/agents/GeneralChatAgent.ts +22 -8
|
@@ -0,0 +1,470 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import { Tag } from '@lobehub/ui';
|
|
4
|
+
import { createStyles } from 'antd-style';
|
|
5
|
+
import { Command } from 'cmdk';
|
|
6
|
+
import {
|
|
7
|
+
ArrowLeft,
|
|
8
|
+
ArrowUpDown,
|
|
9
|
+
BookOpen,
|
|
10
|
+
Bot,
|
|
11
|
+
Compass,
|
|
12
|
+
CornerDownLeft,
|
|
13
|
+
Github,
|
|
14
|
+
MessageCircle,
|
|
15
|
+
Monitor,
|
|
16
|
+
Moon,
|
|
17
|
+
Palette,
|
|
18
|
+
Settings,
|
|
19
|
+
Star,
|
|
20
|
+
Sun,
|
|
21
|
+
} from 'lucide-react';
|
|
22
|
+
import { usePathname, useRouter } from 'next/navigation';
|
|
23
|
+
import { memo, useEffect, useState } from 'react';
|
|
24
|
+
import { createPortal } from 'react-dom';
|
|
25
|
+
import { useTranslation } from 'react-i18next';
|
|
26
|
+
|
|
27
|
+
import { useHotkeyById } from '@/hooks/useHotkeys/useHotkeyById';
|
|
28
|
+
import { useGlobalStore } from '@/store/global';
|
|
29
|
+
import { featureFlagsSelectors, useServerConfigStore } from '@/store/serverConfig';
|
|
30
|
+
import { useSessionStore } from '@/store/session';
|
|
31
|
+
import { HotkeyEnum } from '@/types/hotkey';
|
|
32
|
+
|
|
33
|
+
const useStyles = createStyles(({ css, token }) => ({
|
|
34
|
+
backTag: css`
|
|
35
|
+
cursor: pointer;
|
|
36
|
+
|
|
37
|
+
&:hover {
|
|
38
|
+
opacity: 0.8;
|
|
39
|
+
}
|
|
40
|
+
`,
|
|
41
|
+
commandFooter: css`
|
|
42
|
+
display: flex;
|
|
43
|
+
gap: 16px;
|
|
44
|
+
align-items: center;
|
|
45
|
+
justify-content: flex-end;
|
|
46
|
+
|
|
47
|
+
padding-block: 8px;
|
|
48
|
+
padding-inline: 16px;
|
|
49
|
+
border-block-start: 1px solid ${token.colorBorderSecondary};
|
|
50
|
+
|
|
51
|
+
background: ${token.colorBgContainer};
|
|
52
|
+
`,
|
|
53
|
+
commandRoot: css`
|
|
54
|
+
overflow: hidden;
|
|
55
|
+
display: flex;
|
|
56
|
+
flex-direction: column;
|
|
57
|
+
|
|
58
|
+
width: min(640px, 90vw);
|
|
59
|
+
max-height: min(500px, 70vh);
|
|
60
|
+
border-radius: ${token.borderRadiusLG}px;
|
|
61
|
+
|
|
62
|
+
background: ${token.colorBgElevated};
|
|
63
|
+
box-shadow: ${token.boxShadowSecondary};
|
|
64
|
+
|
|
65
|
+
animation: slide-down 0.12s ease-out;
|
|
66
|
+
|
|
67
|
+
@keyframes slide-down {
|
|
68
|
+
from {
|
|
69
|
+
transform: translateY(-20px) scale(0.96);
|
|
70
|
+
opacity: 0;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
to {
|
|
74
|
+
transform: translateY(0) scale(1);
|
|
75
|
+
opacity: 1;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
[cmdk-input] {
|
|
80
|
+
flex: 1;
|
|
81
|
+
|
|
82
|
+
min-width: 0;
|
|
83
|
+
padding: 0;
|
|
84
|
+
border: none;
|
|
85
|
+
|
|
86
|
+
font-family: inherit;
|
|
87
|
+
font-size: 16px;
|
|
88
|
+
color: ${token.colorText};
|
|
89
|
+
|
|
90
|
+
background: transparent;
|
|
91
|
+
outline: none;
|
|
92
|
+
|
|
93
|
+
&::placeholder {
|
|
94
|
+
color: ${token.colorTextPlaceholder};
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
[cmdk-list] {
|
|
99
|
+
overflow-y: auto;
|
|
100
|
+
max-height: 400px;
|
|
101
|
+
padding: 8px;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
[cmdk-empty] {
|
|
105
|
+
padding-block: 32px;
|
|
106
|
+
padding-inline: 16px;
|
|
107
|
+
|
|
108
|
+
font-size: 14px;
|
|
109
|
+
color: ${token.colorTextTertiary};
|
|
110
|
+
text-align: center;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
[cmdk-item] {
|
|
114
|
+
cursor: pointer;
|
|
115
|
+
user-select: none;
|
|
116
|
+
|
|
117
|
+
display: flex;
|
|
118
|
+
gap: 12px;
|
|
119
|
+
align-items: center;
|
|
120
|
+
|
|
121
|
+
padding-block: 12px;
|
|
122
|
+
padding-inline: 16px;
|
|
123
|
+
border-radius: ${token.borderRadius}px;
|
|
124
|
+
|
|
125
|
+
color: ${token.colorText};
|
|
126
|
+
|
|
127
|
+
transition: all 0.15s ease;
|
|
128
|
+
|
|
129
|
+
&[aria-selected='true'] {
|
|
130
|
+
background: ${token.colorBgTextHover};
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
&:hover {
|
|
134
|
+
background: ${token.colorBgTextHover};
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
[cmdk-group-heading] {
|
|
139
|
+
user-select: none;
|
|
140
|
+
|
|
141
|
+
padding-block: 8px;
|
|
142
|
+
padding-inline: 16px;
|
|
143
|
+
|
|
144
|
+
font-size: 12px;
|
|
145
|
+
font-weight: 500;
|
|
146
|
+
color: ${token.colorTextSecondary};
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
[cmdk-separator] {
|
|
150
|
+
height: 1px;
|
|
151
|
+
margin-block: 4px;
|
|
152
|
+
background: ${token.colorBorderSecondary};
|
|
153
|
+
}
|
|
154
|
+
`,
|
|
155
|
+
icon: css`
|
|
156
|
+
flex-shrink: 0;
|
|
157
|
+
width: 20px;
|
|
158
|
+
height: 20px;
|
|
159
|
+
color: ${token.colorTextSecondary};
|
|
160
|
+
`,
|
|
161
|
+
inputWrapper: css`
|
|
162
|
+
display: flex;
|
|
163
|
+
gap: 8px;
|
|
164
|
+
align-items: center;
|
|
165
|
+
|
|
166
|
+
padding: 16px;
|
|
167
|
+
border-block-end: 1px solid ${token.colorBorderSecondary};
|
|
168
|
+
`,
|
|
169
|
+
itemContent: css`
|
|
170
|
+
flex: 1;
|
|
171
|
+
min-width: 0;
|
|
172
|
+
`,
|
|
173
|
+
itemDescription: css`
|
|
174
|
+
margin-block-start: 2px;
|
|
175
|
+
font-size: 12px;
|
|
176
|
+
line-height: 1.4;
|
|
177
|
+
color: ${token.colorTextTertiary};
|
|
178
|
+
`,
|
|
179
|
+
itemLabel: css`
|
|
180
|
+
font-size: 14px;
|
|
181
|
+
font-weight: 500;
|
|
182
|
+
line-height: 1.4;
|
|
183
|
+
`,
|
|
184
|
+
kbd: css`
|
|
185
|
+
display: inline-flex;
|
|
186
|
+
gap: 4px;
|
|
187
|
+
align-items: center;
|
|
188
|
+
|
|
189
|
+
padding-block: 2px;
|
|
190
|
+
padding-inline: 6px;
|
|
191
|
+
border-radius: ${token.borderRadiusSM}px;
|
|
192
|
+
|
|
193
|
+
font-size: 11px;
|
|
194
|
+
font-weight: 500;
|
|
195
|
+
line-height: 1.2;
|
|
196
|
+
color: ${token.colorTextSecondary};
|
|
197
|
+
|
|
198
|
+
background: ${token.colorFillQuaternary};
|
|
199
|
+
`,
|
|
200
|
+
kbdIcon: css`
|
|
201
|
+
width: 12px;
|
|
202
|
+
height: 12px;
|
|
203
|
+
`,
|
|
204
|
+
overlay: css`
|
|
205
|
+
position: fixed;
|
|
206
|
+
z-index: 9999;
|
|
207
|
+
inset: 0;
|
|
208
|
+
|
|
209
|
+
display: flex;
|
|
210
|
+
justify-content: center;
|
|
211
|
+
|
|
212
|
+
padding-block-start: 15vh;
|
|
213
|
+
|
|
214
|
+
background: ${token.colorBgMask};
|
|
215
|
+
|
|
216
|
+
animation: fade-in 0.1s ease-in-out;
|
|
217
|
+
|
|
218
|
+
@keyframes fade-in {
|
|
219
|
+
from {
|
|
220
|
+
opacity: 0;
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
to {
|
|
224
|
+
opacity: 1;
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
`,
|
|
228
|
+
}));
|
|
229
|
+
|
|
230
|
+
const Cmdk = memo(() => {
|
|
231
|
+
const [open, setOpen] = useState(false);
|
|
232
|
+
const [mounted, setMounted] = useState(false);
|
|
233
|
+
const [search, setSearch] = useState('');
|
|
234
|
+
const [pages, setPages] = useState<string[]>([]);
|
|
235
|
+
const router = useRouter();
|
|
236
|
+
const pathname = usePathname();
|
|
237
|
+
const { t } = useTranslation('common');
|
|
238
|
+
const { styles } = useStyles();
|
|
239
|
+
const switchThemeMode = useGlobalStore((s) => s.switchThemeMode);
|
|
240
|
+
const createSession = useSessionStore((s) => s.createSession);
|
|
241
|
+
const { showCreateSession } = useServerConfigStore(featureFlagsSelectors);
|
|
242
|
+
|
|
243
|
+
const page = pages.at(-1);
|
|
244
|
+
|
|
245
|
+
// Ensure we're mounted on the client
|
|
246
|
+
useEffect(() => {
|
|
247
|
+
setMounted(true);
|
|
248
|
+
}, []);
|
|
249
|
+
|
|
250
|
+
// Register Cmd+K / Ctrl+K hotkey
|
|
251
|
+
useHotkeyById(HotkeyEnum.CommandPalette, () => {
|
|
252
|
+
setOpen((prev) => !prev);
|
|
253
|
+
});
|
|
254
|
+
|
|
255
|
+
// Close on Escape key and prevent body scroll
|
|
256
|
+
useEffect(() => {
|
|
257
|
+
if (open) {
|
|
258
|
+
const originalStyle = window.getComputedStyle(document.body).overflow;
|
|
259
|
+
document.body.style.overflow = 'hidden';
|
|
260
|
+
|
|
261
|
+
return () => {
|
|
262
|
+
document.body.style.overflow = originalStyle;
|
|
263
|
+
};
|
|
264
|
+
}
|
|
265
|
+
}, [open]);
|
|
266
|
+
|
|
267
|
+
// Reset pages and search when opening/closing
|
|
268
|
+
useEffect(() => {
|
|
269
|
+
if (open) {
|
|
270
|
+
setPages([]);
|
|
271
|
+
setSearch('');
|
|
272
|
+
}
|
|
273
|
+
}, [open]);
|
|
274
|
+
|
|
275
|
+
const handleNavigate = (path: string) => {
|
|
276
|
+
router.push(path);
|
|
277
|
+
setOpen(false);
|
|
278
|
+
};
|
|
279
|
+
|
|
280
|
+
const handleExternalLink = (url: string) => {
|
|
281
|
+
window.open(url, '_blank', 'noopener,noreferrer');
|
|
282
|
+
setOpen(false);
|
|
283
|
+
};
|
|
284
|
+
|
|
285
|
+
const handleThemeChange = (theme: 'light' | 'dark' | 'auto') => {
|
|
286
|
+
switchThemeMode(theme);
|
|
287
|
+
setOpen(false);
|
|
288
|
+
};
|
|
289
|
+
|
|
290
|
+
if (!mounted || !open) return null;
|
|
291
|
+
|
|
292
|
+
return createPortal(
|
|
293
|
+
<div className={styles.overlay} onClick={() => setOpen(false)}>
|
|
294
|
+
<div onClick={(e) => e.stopPropagation()}>
|
|
295
|
+
<Command
|
|
296
|
+
className={styles.commandRoot}
|
|
297
|
+
onKeyDown={(e) => {
|
|
298
|
+
// Escape goes to previous page or closes
|
|
299
|
+
if (e.key === 'Escape') {
|
|
300
|
+
e.preventDefault();
|
|
301
|
+
if (pages.length > 0) {
|
|
302
|
+
setPages((prev) => prev.slice(0, -1));
|
|
303
|
+
} else {
|
|
304
|
+
setOpen(false);
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
// Backspace goes to previous page when search is empty
|
|
308
|
+
if (e.key === 'Backspace' && !search && pages.length > 0) {
|
|
309
|
+
e.preventDefault();
|
|
310
|
+
setPages((prev) => prev.slice(0, -1));
|
|
311
|
+
}
|
|
312
|
+
}}
|
|
313
|
+
shouldFilter={true}
|
|
314
|
+
>
|
|
315
|
+
<div className={styles.inputWrapper}>
|
|
316
|
+
{pages.length > 0 && (
|
|
317
|
+
<Tag
|
|
318
|
+
className={styles.backTag}
|
|
319
|
+
icon={<ArrowLeft size={12} />}
|
|
320
|
+
onClick={() => setPages((prev) => prev.slice(0, -1))}
|
|
321
|
+
/>
|
|
322
|
+
)}
|
|
323
|
+
<Command.Input
|
|
324
|
+
autoFocus
|
|
325
|
+
onValueChange={setSearch}
|
|
326
|
+
placeholder={t('cmdk.searchPlaceholder')}
|
|
327
|
+
value={search}
|
|
328
|
+
/>
|
|
329
|
+
<Tag>ESC</Tag>
|
|
330
|
+
</div>
|
|
331
|
+
<Command.List>
|
|
332
|
+
<Command.Empty>{t('cmdk.noResults')}</Command.Empty>
|
|
333
|
+
|
|
334
|
+
{!page && (
|
|
335
|
+
<>
|
|
336
|
+
{showCreateSession && (
|
|
337
|
+
<Command.Item
|
|
338
|
+
onSelect={() => {
|
|
339
|
+
createSession();
|
|
340
|
+
setOpen(false);
|
|
341
|
+
}}
|
|
342
|
+
value="new-agent"
|
|
343
|
+
>
|
|
344
|
+
<Bot className={styles.icon} />
|
|
345
|
+
<div className={styles.itemContent}>
|
|
346
|
+
<div className={styles.itemLabel}>{t('cmdk.newAgent')}</div>
|
|
347
|
+
</div>
|
|
348
|
+
</Command.Item>
|
|
349
|
+
)}
|
|
350
|
+
|
|
351
|
+
{!pathname?.startsWith('/settings') && (
|
|
352
|
+
<Command.Item onSelect={() => handleNavigate('/settings')} value="settings">
|
|
353
|
+
<Settings className={styles.icon} />
|
|
354
|
+
<div className={styles.itemContent}>
|
|
355
|
+
<div className={styles.itemLabel}>{t('cmdk.settings')}</div>
|
|
356
|
+
</div>
|
|
357
|
+
</Command.Item>
|
|
358
|
+
)}
|
|
359
|
+
|
|
360
|
+
<Command.Item onSelect={() => setPages([...pages, 'theme'])} value="theme">
|
|
361
|
+
<Monitor className={styles.icon} />
|
|
362
|
+
<div className={styles.itemContent}>
|
|
363
|
+
<div className={styles.itemLabel}>{t('cmdk.theme')}</div>
|
|
364
|
+
</div>
|
|
365
|
+
</Command.Item>
|
|
366
|
+
|
|
367
|
+
<Command.Group heading={t('cmdk.navigate')}>
|
|
368
|
+
{!pathname?.startsWith('/discover') && (
|
|
369
|
+
<Command.Item onSelect={() => handleNavigate('/discover')} value="discover">
|
|
370
|
+
<Compass className={styles.icon} />
|
|
371
|
+
<div className={styles.itemContent}>
|
|
372
|
+
<div className={styles.itemLabel}>{t('cmdk.discover')}</div>
|
|
373
|
+
</div>
|
|
374
|
+
</Command.Item>
|
|
375
|
+
)}
|
|
376
|
+
{!pathname?.startsWith('/image') && (
|
|
377
|
+
<Command.Item onSelect={() => handleNavigate('/image')} value="painting">
|
|
378
|
+
<Palette className={styles.icon} />
|
|
379
|
+
<div className={styles.itemContent}>
|
|
380
|
+
<div className={styles.itemLabel}>{t('cmdk.painting')}</div>
|
|
381
|
+
</div>
|
|
382
|
+
</Command.Item>
|
|
383
|
+
)}
|
|
384
|
+
{!pathname?.startsWith('/knowledge') && (
|
|
385
|
+
<Command.Item onSelect={() => handleNavigate('/knowledge')} value="knowledge">
|
|
386
|
+
<BookOpen className={styles.icon} />
|
|
387
|
+
<div className={styles.itemContent}>
|
|
388
|
+
<div className={styles.itemLabel}>{t('cmdk.knowledgeBase')}</div>
|
|
389
|
+
</div>
|
|
390
|
+
</Command.Item>
|
|
391
|
+
)}
|
|
392
|
+
</Command.Group>
|
|
393
|
+
|
|
394
|
+
<Command.Group heading={t('cmdk.about')}>
|
|
395
|
+
<Command.Item
|
|
396
|
+
onSelect={() =>
|
|
397
|
+
handleExternalLink('https://github.com/lobehub/lobe-chat/issues/new/choose')
|
|
398
|
+
}
|
|
399
|
+
value="submit-issue"
|
|
400
|
+
>
|
|
401
|
+
<Github className={styles.icon} />
|
|
402
|
+
<div className={styles.itemContent}>
|
|
403
|
+
<div className={styles.itemLabel}>{t('cmdk.submitIssue')}</div>
|
|
404
|
+
</div>
|
|
405
|
+
</Command.Item>
|
|
406
|
+
<Command.Item
|
|
407
|
+
onSelect={() => handleExternalLink('https://github.com/lobehub/lobe-chat')}
|
|
408
|
+
value="star-github"
|
|
409
|
+
>
|
|
410
|
+
<Star className={styles.icon} />
|
|
411
|
+
<div className={styles.itemContent}>
|
|
412
|
+
<div className={styles.itemLabel}>{t('cmdk.starOnGitHub')}</div>
|
|
413
|
+
</div>
|
|
414
|
+
</Command.Item>
|
|
415
|
+
<Command.Item
|
|
416
|
+
onSelect={() => handleExternalLink('https://discord.gg/AYFPHvv2jT')}
|
|
417
|
+
value="discord"
|
|
418
|
+
>
|
|
419
|
+
<MessageCircle className={styles.icon} />
|
|
420
|
+
<div className={styles.itemContent}>
|
|
421
|
+
<div className={styles.itemLabel}>{t('cmdk.communitySupport')}</div>
|
|
422
|
+
</div>
|
|
423
|
+
</Command.Item>
|
|
424
|
+
</Command.Group>
|
|
425
|
+
</>
|
|
426
|
+
)}
|
|
427
|
+
|
|
428
|
+
{page === 'theme' && (
|
|
429
|
+
<>
|
|
430
|
+
<Command.Item onSelect={() => handleThemeChange('light')} value="theme-light">
|
|
431
|
+
<Sun className={styles.icon} />
|
|
432
|
+
<div className={styles.itemContent}>
|
|
433
|
+
<div className={styles.itemLabel}>{t('cmdk.themeLight')}</div>
|
|
434
|
+
</div>
|
|
435
|
+
</Command.Item>
|
|
436
|
+
<Command.Item onSelect={() => handleThemeChange('dark')} value="theme-dark">
|
|
437
|
+
<Moon className={styles.icon} />
|
|
438
|
+
<div className={styles.itemContent}>
|
|
439
|
+
<div className={styles.itemLabel}>{t('cmdk.themeDark')}</div>
|
|
440
|
+
</div>
|
|
441
|
+
</Command.Item>
|
|
442
|
+
<Command.Item onSelect={() => handleThemeChange('auto')} value="theme-auto">
|
|
443
|
+
<Monitor className={styles.icon} />
|
|
444
|
+
<div className={styles.itemContent}>
|
|
445
|
+
<div className={styles.itemLabel}>{t('cmdk.themeAuto')}</div>
|
|
446
|
+
</div>
|
|
447
|
+
</Command.Item>
|
|
448
|
+
</>
|
|
449
|
+
)}
|
|
450
|
+
</Command.List>
|
|
451
|
+
<div className={styles.commandFooter}>
|
|
452
|
+
<div className={styles.kbd}>
|
|
453
|
+
<CornerDownLeft className={styles.kbdIcon} />
|
|
454
|
+
<span>{t('cmdk.toOpen')}</span>
|
|
455
|
+
</div>
|
|
456
|
+
<div className={styles.kbd}>
|
|
457
|
+
<ArrowUpDown className={styles.kbdIcon} />
|
|
458
|
+
<span>{t('cmdk.toSelect')}</span>
|
|
459
|
+
</div>
|
|
460
|
+
</div>
|
|
461
|
+
</Command>
|
|
462
|
+
</div>
|
|
463
|
+
</div>,
|
|
464
|
+
document.body,
|
|
465
|
+
);
|
|
466
|
+
});
|
|
467
|
+
|
|
468
|
+
Cmdk.displayName = 'Cmdk';
|
|
469
|
+
|
|
470
|
+
export default Cmdk;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import dynamic from 'next/dynamic';
|
|
4
|
+
import { memo } from 'react';
|
|
5
|
+
|
|
6
|
+
// Lazy load the CMDK component with Next.js dynamic import
|
|
7
|
+
// This splits the CMDK code into a separate chunk that only loads when needed
|
|
8
|
+
// ssr: false ensures it only loads on the client side
|
|
9
|
+
const CmdkComponent = dynamic(() => import('./Cmdk'), {
|
|
10
|
+
ssr: false,
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
const CmdkLazy = memo(() => <CmdkComponent />);
|
|
14
|
+
|
|
15
|
+
CmdkLazy.displayName = 'CmdkLazy';
|
|
16
|
+
|
|
17
|
+
export default CmdkLazy;
|
|
@@ -10,6 +10,7 @@ import { getAntdLocale } from '@/utils/locale';
|
|
|
10
10
|
|
|
11
11
|
import AntdV5MonkeyPatch from './AntdV5MonkeyPatch';
|
|
12
12
|
import AppTheme from './AppTheme';
|
|
13
|
+
import CmdkLazy from './CmdkLazy';
|
|
13
14
|
import ImportSettings from './ImportSettings';
|
|
14
15
|
import Locale from './Locale';
|
|
15
16
|
import QueryProvider from './Query';
|
|
@@ -65,6 +66,7 @@ const GlobalLayout = async ({
|
|
|
65
66
|
<ImportSettings />
|
|
66
67
|
{process.env.NODE_ENV === 'development' && <DevPanel />}
|
|
67
68
|
</Suspense>
|
|
69
|
+
<CmdkLazy />
|
|
68
70
|
</ServerConfigStoreProvider>
|
|
69
71
|
</AppTheme>
|
|
70
72
|
</Locale>
|
|
@@ -138,6 +138,27 @@ export default {
|
|
|
138
138
|
},
|
|
139
139
|
},
|
|
140
140
|
close: '关闭',
|
|
141
|
+
cmdk: {
|
|
142
|
+
about: '关于',
|
|
143
|
+
communitySupport: '社区支持',
|
|
144
|
+
discover: '发现',
|
|
145
|
+
knowledgeBase: '知识库',
|
|
146
|
+
navigate: '导航',
|
|
147
|
+
newAgent: '新建助手',
|
|
148
|
+
noResults: '未找到相关结果',
|
|
149
|
+
openSettings: '打开设置',
|
|
150
|
+
painting: 'AI 绘画',
|
|
151
|
+
searchPlaceholder: '输入命令或搜索...',
|
|
152
|
+
settings: '设置',
|
|
153
|
+
starOnGitHub: '在 GitHub 上给我们 Star',
|
|
154
|
+
submitIssue: '提交问题',
|
|
155
|
+
theme: '主题',
|
|
156
|
+
themeAuto: '跟随系统',
|
|
157
|
+
themeDark: '深色模式',
|
|
158
|
+
themeLight: '浅色模式',
|
|
159
|
+
toOpen: '打开',
|
|
160
|
+
toSelect: '选择',
|
|
161
|
+
},
|
|
141
162
|
confirm: '确认',
|
|
142
163
|
contact: '联系我们',
|
|
143
164
|
copy: '复制',
|
|
@@ -3,6 +3,7 @@ import {
|
|
|
3
3
|
AgentInstruction,
|
|
4
4
|
AgentRuntimeContext,
|
|
5
5
|
AgentState,
|
|
6
|
+
DEFAULT_SECURITY_BLACKLIST,
|
|
6
7
|
GeneralAgentCallLLMInstructionPayload,
|
|
7
8
|
GeneralAgentCallLLMResultPayload,
|
|
8
9
|
GeneralAgentCallToolResultPayload,
|
|
@@ -65,6 +66,9 @@ export class GeneralChatAgent implements Agent {
|
|
|
65
66
|
const toolsNeedingIntervention: ChatToolPayload[] = [];
|
|
66
67
|
const toolsToExecute: ChatToolPayload[] = [];
|
|
67
68
|
|
|
69
|
+
// Get security blacklist (use default if not provided)
|
|
70
|
+
const securityBlacklist = state.securityBlacklist ?? DEFAULT_SECURITY_BLACKLIST;
|
|
71
|
+
|
|
68
72
|
// Get user config (default to 'manual' mode)
|
|
69
73
|
const userConfig = state.userInterventionConfig || { approvalMode: 'manual' };
|
|
70
74
|
const { approvalMode, allowList = [] } = userConfig;
|
|
@@ -73,6 +77,23 @@ export class GeneralChatAgent implements Agent {
|
|
|
73
77
|
const { identifier, apiName } = toolCalling;
|
|
74
78
|
const toolKey = `${identifier}/${apiName}`;
|
|
75
79
|
|
|
80
|
+
// Parse arguments for intervention checking
|
|
81
|
+
let toolArgs: Record<string, any> = {};
|
|
82
|
+
try {
|
|
83
|
+
toolArgs = JSON.parse(toolCalling.arguments || '{}');
|
|
84
|
+
} catch {
|
|
85
|
+
// Invalid JSON, treat as empty args
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
// Priority 0: CRITICAL - Check security blacklist FIRST
|
|
89
|
+
// This overrides ALL other settings, including auto-run mode
|
|
90
|
+
const securityCheck = InterventionChecker.checkSecurityBlacklist(securityBlacklist, toolArgs);
|
|
91
|
+
if (securityCheck.blocked) {
|
|
92
|
+
// Security blacklist always requires intervention
|
|
93
|
+
toolsNeedingIntervention.push(toolCalling);
|
|
94
|
+
continue;
|
|
95
|
+
}
|
|
96
|
+
|
|
76
97
|
// Priority 1: User config is 'auto-run', all tools execute directly
|
|
77
98
|
if (approvalMode === 'auto-run') {
|
|
78
99
|
toolsToExecute.push(toolCalling);
|
|
@@ -92,16 +113,9 @@ export class GeneralChatAgent implements Agent {
|
|
|
92
113
|
// Priority 3: User config is 'manual' (default), use tool's own config
|
|
93
114
|
const config = this.getToolInterventionConfig(toolCalling, state);
|
|
94
115
|
|
|
95
|
-
// Parse arguments for intervention checking
|
|
96
|
-
let toolArgs: Record<string, any> = {};
|
|
97
|
-
try {
|
|
98
|
-
toolArgs = JSON.parse(toolCalling.arguments || '{}');
|
|
99
|
-
} catch {
|
|
100
|
-
// Invalid JSON, treat as empty args
|
|
101
|
-
}
|
|
102
|
-
|
|
103
116
|
const policy = InterventionChecker.shouldIntervene({
|
|
104
117
|
config,
|
|
118
|
+
securityBlacklist,
|
|
105
119
|
toolArgs,
|
|
106
120
|
});
|
|
107
121
|
|