@lobehub/lobehub 2.0.0-next.295 → 2.0.0-next.296

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 (87) hide show
  1. package/CHANGELOG.md +25 -0
  2. package/changelog/v1.json +9 -0
  3. package/locales/en-US/plugin.json +4 -0
  4. package/locales/zh-CN/plugin.json +4 -0
  5. package/package.json +1 -1
  6. package/packages/agent-runtime/src/core/__tests__/runtime.test.ts +5 -5
  7. package/packages/agent-runtime/src/utils/stepContextComputer.test.ts +5 -5
  8. package/packages/builtin-tool-gtd/src/client/Inspector/index.ts +0 -4
  9. package/packages/builtin-tool-gtd/src/client/Intervention/AddTodo.tsx +1 -1
  10. package/packages/builtin-tool-gtd/src/client/Render/TodoList/index.tsx +39 -10
  11. package/packages/builtin-tool-gtd/src/client/Render/index.ts +0 -2
  12. package/packages/builtin-tool-gtd/src/client/components/SortableTodoList/TodoItemRow.tsx +26 -12
  13. package/packages/builtin-tool-gtd/src/client/components/SortableTodoList/store/actions.ts +5 -5
  14. package/packages/builtin-tool-gtd/src/client/components/SortableTodoList/store/store.test.ts +14 -8
  15. package/packages/builtin-tool-gtd/src/executor/index.test.ts +48 -227
  16. package/packages/builtin-tool-gtd/src/executor/index.ts +15 -158
  17. package/packages/builtin-tool-gtd/src/manifest.ts +12 -42
  18. package/packages/builtin-tool-gtd/src/systemRole.ts +14 -8
  19. package/packages/builtin-tool-gtd/src/types.ts +47 -41
  20. package/packages/builtin-tool-memory/package.json +8 -0
  21. package/packages/builtin-tool-memory/src/client/Inspector/AddContextMemory/index.tsx +60 -0
  22. package/packages/builtin-tool-memory/src/client/Inspector/AddExperienceMemory/index.tsx +60 -0
  23. package/packages/builtin-tool-memory/src/client/Inspector/AddIdentityMemory/index.tsx +60 -0
  24. package/packages/builtin-tool-memory/src/client/Inspector/AddPreferenceMemory/index.tsx +60 -0
  25. package/packages/builtin-tool-memory/src/client/Inspector/RemoveIdentityMemory/index.tsx +60 -0
  26. package/packages/builtin-tool-memory/src/client/Inspector/SearchUserMemory/index.tsx +67 -0
  27. package/packages/builtin-tool-memory/src/client/Inspector/UpdateIdentityMemory/index.tsx +60 -0
  28. package/packages/builtin-tool-memory/src/client/Inspector/index.ts +35 -0
  29. package/packages/builtin-tool-memory/src/client/Intervention/AddExperienceMemory/index.tsx +17 -0
  30. package/packages/builtin-tool-memory/src/client/Intervention/index.ts +13 -0
  31. package/packages/builtin-tool-memory/src/client/Render/AddExperienceMemory/index.tsx +17 -0
  32. package/packages/builtin-tool-memory/src/client/Render/SearchUserMemory/index.tsx +217 -0
  33. package/packages/builtin-tool-memory/src/client/Render/index.ts +15 -0
  34. package/packages/builtin-tool-memory/src/client/Streaming/AddExperienceMemory/index.tsx +17 -0
  35. package/packages/builtin-tool-memory/src/client/Streaming/index.ts +18 -0
  36. package/packages/builtin-tool-memory/src/client/components/ExperienceMemoryCard.tsx +231 -0
  37. package/packages/builtin-tool-memory/src/client/components/index.ts +1 -0
  38. package/packages/builtin-tool-memory/src/client/index.ts +27 -0
  39. package/packages/builtin-tool-memory/src/executor/index.ts +9 -1
  40. package/packages/builtin-tool-memory/src/types.ts +61 -0
  41. package/packages/context-engine/src/providers/GTDTodoInjector.ts +15 -7
  42. package/packages/conversation-flow/src/__tests__/fixtures/outputs/assistantGroup/tools-with-branches.json +4 -0
  43. package/packages/conversation-flow/src/transformation/FlatListBuilder.ts +1 -0
  44. package/packages/prompts/src/prompts/gtd/index.test.ts +32 -16
  45. package/packages/prompts/src/prompts/gtd/index.ts +9 -5
  46. package/packages/types/src/stepContext.ts +4 -1
  47. package/src/app/[variants]/(main)/community/(detail)/assistant/features/Details/Versions/index.tsx +2 -2
  48. package/src/app/[variants]/(main)/community/features/Search.tsx +1 -1
  49. package/src/app/[variants]/(main)/resource/features/DndContextWrapper.tsx +4 -2
  50. package/src/app/[variants]/(main)/resource/library/_layout/Header/LibraryHead.tsx +30 -35
  51. package/src/app/[variants]/(main)/resource/library/_layout/Header/index.tsx +9 -11
  52. package/src/features/Conversation/Messages/AssistantGroup/Tool/Actions/index.tsx +11 -17
  53. package/src/features/Conversation/Messages/AssistantGroup/Tool/{Render → Detail}/LoadingPlaceholder/index.tsx +13 -3
  54. package/src/features/Conversation/Messages/AssistantGroup/Tool/Detail/Render/CustomRender.tsx +43 -0
  55. package/src/features/Conversation/Messages/AssistantGroup/Tool/Detail/Render/FallbacktArgumentRender.tsx +59 -0
  56. package/src/features/Conversation/Messages/AssistantGroup/Tool/Detail/Render/index.tsx +46 -0
  57. package/src/features/Conversation/Messages/AssistantGroup/Tool/{Render → Detail}/index.tsx +13 -19
  58. package/src/features/Conversation/Messages/AssistantGroup/Tool/index.tsx +17 -17
  59. package/src/features/Conversation/Messages/Tool/Tool/index.tsx +10 -9
  60. package/src/features/Conversation/TodoProgress/index.tsx +56 -23
  61. package/src/features/PluginsUI/Render/MCPType/index.tsx +1 -1
  62. package/src/features/ResourceManager/components/Explorer/Header/index.tsx +57 -4
  63. package/src/features/ResourceManager/components/Explorer/ListView/ListItem/index.tsx +6 -4
  64. package/src/features/ResourceManager/components/Explorer/ListView/index.tsx +16 -5
  65. package/src/features/ResourceManager/components/LibraryHierarchy/styles.ts +5 -4
  66. package/src/hooks/useActiveTabKey.ts +1 -2
  67. package/src/locales/default/plugin.ts +1 -0
  68. package/src/store/chat/slices/message/selectors/dbMessage.test.ts +11 -11
  69. package/src/store/file/slices/resource/action.ts +4 -2
  70. package/src/tools/inspectors.ts +2 -0
  71. package/src/tools/interventions.ts +2 -0
  72. package/src/tools/renders.ts +3 -1
  73. package/src/tools/streamings.ts +2 -0
  74. package/packages/builtin-tool-gtd/src/client/Inspector/CompleteTodos/index.tsx +0 -52
  75. package/packages/builtin-tool-gtd/src/client/Inspector/RemoveTodos/index.tsx +0 -52
  76. package/src/features/Conversation/Messages/AssistantGroup/Tool/Render/CustomRender.tsx +0 -113
  77. package/src/features/Conversation/Messages/Tool/Tool/Render.tsx +0 -47
  78. /package/src/features/Conversation/Messages/AssistantGroup/Tool/{Render → Detail}/AbortResponse.tsx +0 -0
  79. /package/src/features/Conversation/Messages/AssistantGroup/Tool/{Render → Detail}/Arguments/index.tsx +0 -0
  80. /package/src/features/Conversation/Messages/AssistantGroup/Tool/{Render → Detail}/ErrorResponse.tsx +0 -0
  81. /package/src/features/Conversation/Messages/AssistantGroup/Tool/{Render → Detail}/Intervention/ApprovalActions.tsx +0 -0
  82. /package/src/features/Conversation/Messages/AssistantGroup/Tool/{Render → Detail}/Intervention/Fallback.tsx +0 -0
  83. /package/src/features/Conversation/Messages/AssistantGroup/Tool/{Render → Detail}/Intervention/KeyValueEditor.tsx +0 -0
  84. /package/src/features/Conversation/Messages/AssistantGroup/Tool/{Render → Detail}/Intervention/ModeSelector.tsx +0 -0
  85. /package/src/features/Conversation/Messages/AssistantGroup/Tool/{Render → Detail}/Intervention/index.tsx +0 -0
  86. /package/src/features/Conversation/Messages/AssistantGroup/Tool/{Render → Detail}/PluginSettings.tsx +0 -0
  87. /package/src/features/Conversation/Messages/AssistantGroup/Tool/{Render → Detail}/RejectedResponse.tsx +0 -0
@@ -0,0 +1,43 @@
1
+ import { type ChatPluginPayload } from '@/types/index';
2
+ import { Flexbox } from '@lobehub/ui';
3
+ import { memo } from 'react';
4
+
5
+ import PluginRender from '@/features/PluginsUI/Render';
6
+
7
+ interface CustomRenderProps {
8
+ content: string;
9
+ /**
10
+ * The real message ID (tool message ID)
11
+ */
12
+ messageId?: string;
13
+ plugin?: ChatPluginPayload;
14
+ pluginState?: any;
15
+ /**
16
+ * The tool call ID from the assistant message
17
+ */
18
+ toolCallId: string;
19
+ }
20
+
21
+ const CustomRender = memo<CustomRenderProps>(
22
+ ({ toolCallId, messageId, content, pluginState, plugin }) => {
23
+ return (
24
+ <Flexbox gap={12} id={toolCallId} width={'100%'}>
25
+ <PluginRender
26
+ arguments={plugin?.arguments}
27
+ content={content}
28
+ identifier={plugin?.identifier}
29
+ loading={false}
30
+ messageId={messageId}
31
+ payload={plugin}
32
+ pluginState={pluginState}
33
+ toolCallId={toolCallId}
34
+ type={plugin?.type}
35
+ />
36
+ </Flexbox>
37
+ );
38
+ },
39
+ );
40
+
41
+ CustomRender.displayName = 'GroupCustomRender';
42
+
43
+ export default CustomRender;
@@ -0,0 +1,59 @@
1
+ import { Block, Flexbox, Highlighter, Text } from '@lobehub/ui';
2
+ import { Divider } from 'antd';
3
+ import { memo, useMemo } from 'react';
4
+ import { useTranslation } from 'react-i18next';
5
+
6
+ import Arguments from '../Arguments';
7
+
8
+ interface FallbackArgumentRenderProps {
9
+ content: string;
10
+ requestArgs?: string;
11
+ toolCallId: string;
12
+ }
13
+
14
+ export const FallbackArgumentRender = memo<FallbackArgumentRenderProps>(
15
+ ({ toolCallId, content, requestArgs }) => {
16
+ const { t } = useTranslation('plugin');
17
+
18
+ // Parse and display result content
19
+ const { data, language } = useMemo(() => {
20
+ try {
21
+ const parsed = JSON.parse(content || '');
22
+ // If parsed result is a string, return it directly
23
+ if (typeof parsed === 'string') {
24
+ return { data: parsed, language: 'plaintext' };
25
+ }
26
+ return { data: JSON.stringify(parsed, null, 2), language: 'json' };
27
+ } catch {
28
+ return { data: content || '', language: 'plaintext' };
29
+ }
30
+ }, [content]);
31
+
32
+ // Default render: show arguments and result
33
+ return (
34
+ <Block id={toolCallId} variant={'outlined'} width={'100%'}>
35
+ <Arguments arguments={requestArgs} />
36
+ {content && (
37
+ <>
38
+ <Divider style={{ marginBlock: 0 }} />
39
+ <Flexbox paddingBlock={'8px 0'} paddingInline={16}>
40
+ <Text>{t('debug.response')}</Text>
41
+ </Flexbox>
42
+ <Highlighter
43
+ language={language}
44
+ style={{
45
+ background: 'transparent',
46
+ borderRadius: 0,
47
+ maxHeight: 300,
48
+ overflow: 'auto',
49
+ }}
50
+ variant={'filled'}
51
+ >
52
+ {data}
53
+ </Highlighter>
54
+ </>
55
+ )}
56
+ </Block>
57
+ );
58
+ },
59
+ );
@@ -0,0 +1,46 @@
1
+ import { type ChatPluginPayload } from '@lobechat/types';
2
+ import { memo } from 'react';
3
+
4
+ import { getBuiltinRender } from '@/tools/renders';
5
+
6
+ import CustomRender from './CustomRender';
7
+ import { FallbackArgumentRender } from './FallbacktArgumentRender';
8
+
9
+ interface ToolRenderProps {
10
+ content: string;
11
+ messageId?: string;
12
+ plugin?: ChatPluginPayload;
13
+ pluginState?: any;
14
+ showCustomToolRender?: boolean;
15
+ toolCallId: string;
16
+ }
17
+
18
+ const ToolRender = memo<ToolRenderProps>(
19
+ ({ showCustomToolRender, content, messageId, plugin, pluginState, toolCallId }) => {
20
+ const hasCustomRender = !!getBuiltinRender(plugin?.identifier, plugin?.apiName);
21
+
22
+ if (hasCustomRender && showCustomToolRender) {
23
+ return (
24
+ <CustomRender
25
+ content={content}
26
+ messageId={messageId}
27
+ plugin={plugin}
28
+ pluginState={pluginState}
29
+ toolCallId={toolCallId}
30
+ />
31
+ );
32
+ }
33
+
34
+ return (
35
+ <FallbackArgumentRender
36
+ content={content}
37
+ requestArgs={plugin?.arguments}
38
+ toolCallId={toolCallId}
39
+ />
40
+ );
41
+ },
42
+ );
43
+
44
+ ToolRender.displayName = 'ToolResultRender';
45
+
46
+ export default ToolRender;
@@ -6,12 +6,12 @@ import { Suspense, memo } from 'react';
6
6
  import { getBuiltinStreaming } from '@/tools/streamings';
7
7
 
8
8
  import AbortResponse from './AbortResponse';
9
- import CustomRender from './CustomRender';
10
9
  import ErrorResponse from './ErrorResponse';
11
10
  import Intervention from './Intervention';
12
11
  import ModeSelector from './Intervention/ModeSelector';
13
12
  import LoadingPlaceholder from './LoadingPlaceholder';
14
13
  import RejectedResponse from './RejectedResponse';
14
+ import ToolRender from './Render';
15
15
 
16
16
  interface RenderProps {
17
17
  apiName: string;
@@ -26,8 +26,7 @@ interface RenderProps {
26
26
  */
27
27
  messageId: string;
28
28
  result?: ChatToolResult;
29
- setShowPluginRender: (show: boolean) => void;
30
- showPluginRender: boolean;
29
+ showCustomToolRender?: boolean;
31
30
  toolCallId: string;
32
31
  toolMessageId?: string;
33
32
  type?: string;
@@ -45,8 +44,6 @@ const Render = memo<RenderProps>(
45
44
  messageId,
46
45
  arguments: requestArgs,
47
46
  disableEditing,
48
- showPluginRender,
49
- setShowPluginRender,
50
47
  identifier,
51
48
  apiName,
52
49
  result,
@@ -55,6 +52,7 @@ const Render = memo<RenderProps>(
55
52
  toolMessageId,
56
53
  isArgumentsStreaming,
57
54
  isToolCalling,
55
+ showCustomToolRender,
58
56
  }) => {
59
57
  if (toolMessageId && intervention?.status === 'pending' && !disableEditing) {
60
58
  return (
@@ -124,7 +122,9 @@ const Render = memo<RenderProps>(
124
122
  apiName={apiName}
125
123
  identifier={identifier}
126
124
  loading
125
+ messageId={messageId}
127
126
  requestArgs={requestArgs}
127
+ toolCallId={toolCallId}
128
128
  />
129
129
  );
130
130
 
@@ -133,23 +133,17 @@ const Render = memo<RenderProps>(
133
133
  return (
134
134
  <Suspense fallback={placeholder}>
135
135
  <Flexbox gap={8}>
136
- <CustomRender
136
+ <ToolRender
137
137
  content={result.content || ''}
138
138
  messageId={toolMessageId}
139
- plugin={
140
- type
141
- ? ({
142
- apiName,
143
- arguments: requestArgs || '',
144
- identifier,
145
- type,
146
- } as any)
147
- : undefined
148
- }
139
+ plugin={{
140
+ apiName,
141
+ arguments: requestArgs || '',
142
+ identifier,
143
+ type: type as any,
144
+ }}
149
145
  pluginState={result.state}
150
- requestArgs={requestArgs}
151
- setShowPluginRender={setShowPluginRender}
152
- showPluginRender={showPluginRender}
146
+ showCustomToolRender={showCustomToolRender}
153
147
  toolCallId={toolCallId}
154
148
  />
155
149
  {!disableEditing && (
@@ -21,7 +21,7 @@ const Debug = dynamic(() => import('./Debug'), {
21
21
  ssr: false,
22
22
  });
23
23
 
24
- const Render = dynamic(() => import('./Render'), {
24
+ const Detail = dynamic(() => import('./Detail'), {
25
25
  loading: () => <Skeleton.Block active height={120} width={'100%'} />,
26
26
  ssr: false,
27
27
  });
@@ -57,7 +57,9 @@ const Tool = memo<GroupToolProps>(
57
57
  toolSelectors.getRenderDisplayControl(identifier, apiName),
58
58
  );
59
59
  const [showDebug, setShowDebug] = useState(false);
60
- const [showPluginRender, setShowPluginRender] = useState(false);
60
+ const [showToolRender, setShowToolRender] = useState(false);
61
+ // Controls switching between custom render and fallback ArgumentRender
62
+ const [showCustomToolRender, setShowCustomToolRender] = useState(true);
61
63
 
62
64
  const isPending = intervention?.status === 'pending';
63
65
  const isReject = intervention?.status === 'rejected';
@@ -65,8 +67,6 @@ const Tool = memo<GroupToolProps>(
65
67
  const needExpand = renderDisplayControl !== 'collapsed' || isPending;
66
68
  const isAlwaysExpand = renderDisplayControl === 'alwaysExpand';
67
69
 
68
- const showCustomPluginRender = !isPending && !isReject && !isAbort;
69
-
70
70
  let isArgumentsStreaming = false;
71
71
  try {
72
72
  JSON.parse(requestArgs || '{}');
@@ -88,14 +88,16 @@ const Tool = memo<GroupToolProps>(
88
88
  const isToolCalling = isToolCallingFromOperation || isToolCallingFallback;
89
89
 
90
90
  const hasCustomRender = !!getBuiltinRender(identifier, apiName);
91
+ // Only allow toggle when has custom render and not in pending/reject/abort state
92
+ const canToggleCustomToolRender = hasCustomRender && !isPending && !isReject && !isAbort;
91
93
 
92
- // Handle expand state changes with showPluginRender
94
+ // Handle expand state changes
93
95
  const handleExpand = (expand?: boolean) => {
94
96
  // Block collapse action when alwaysExpand is set
95
97
  if (isAlwaysExpand && expand === false) {
96
98
  return;
97
99
  }
98
- setShowPluginRender(!!expand);
100
+ setShowToolRender(!!expand);
99
101
  };
100
102
 
101
103
  useEffect(() => {
@@ -104,27 +106,26 @@ const Tool = memo<GroupToolProps>(
104
106
  }
105
107
  }, [needExpand]);
106
108
 
107
- const isToolRenderExpand = forceShowStreamingRender || showPluginRender;
109
+ const isToolDetailExpand = forceShowStreamingRender || showToolRender || showDebug;
110
+
108
111
  return (
109
112
  <AccordionItem
110
113
  action={
111
114
  !disableEditing && (
112
115
  <Actions
113
116
  assistantMessageId={assistantMessageId}
114
- handleExpand={handleExpand}
117
+ canToggleCustomToolRender={canToggleCustomToolRender}
115
118
  identifier={identifier}
119
+ setShowCustomToolRender={setShowCustomToolRender}
116
120
  setShowDebug={setShowDebug}
117
- setShowPluginRender={setShowPluginRender}
118
- showCustomPluginRender={showCustomPluginRender}
121
+ showCustomToolRender={showCustomToolRender}
119
122
  showDebug={showDebug}
120
- showPluginRender={showPluginRender}
121
123
  />
122
124
  )
123
125
  }
124
- allowExpand={hasCustomRender}
125
- expand={isToolRenderExpand}
126
+ expand={isToolDetailExpand}
126
127
  itemKey={id}
127
- onExpandChange={setShowPluginRender}
128
+ onExpandChange={handleExpand}
128
129
  paddingBlock={4}
129
130
  paddingInline={4}
130
131
  title={
@@ -151,7 +152,7 @@ const Tool = memo<GroupToolProps>(
151
152
  />
152
153
  )}
153
154
  <ToolErrorBoundary apiName={apiName} identifier={identifier}>
154
- <Render
155
+ <Detail
155
156
  apiName={apiName}
156
157
  arguments={requestArgs}
157
158
  disableEditing={disableEditing}
@@ -161,8 +162,7 @@ const Tool = memo<GroupToolProps>(
161
162
  isToolCalling={isToolCalling}
162
163
  messageId={assistantMessageId}
163
164
  result={result}
164
- setShowPluginRender={setShowPluginRender}
165
- showPluginRender={showPluginRender}
165
+ showCustomToolRender={showCustomToolRender}
166
166
  toolCallId={id}
167
167
  toolMessageId={toolMessageId}
168
168
  type={type}
@@ -3,6 +3,7 @@ import { type CSSProperties, memo, useState } from 'react';
3
3
 
4
4
  import Actions from '@/features/Conversation/Messages/AssistantGroup/Tool/Actions';
5
5
  import dynamic from '@/libs/next/dynamic';
6
+ import { getBuiltinRender } from '@/tools/renders';
6
7
 
7
8
  import { dataSelectors, messageStateSelectors, useConversationStore } from '../../../store';
8
9
  import Inspectors from '../../AssistantGroup/Tool/Inspector';
@@ -12,7 +13,7 @@ const Debug = dynamic(() => import('../../AssistantGroup/Tool/Debug'), {
12
13
  ssr: false,
13
14
  });
14
15
 
15
- const Render = dynamic(() => import('../../AssistantGroup/Tool/Render'), {
16
+ const Detail = dynamic(() => import('../../AssistantGroup/Tool/Detail'), {
16
17
  loading: () => <Skeleton.Block active height={120} width={'100%'} />,
17
18
  ssr: false,
18
19
  });
@@ -44,7 +45,7 @@ const Tool = memo<InspectorProps>(
44
45
  type,
45
46
  }) => {
46
47
  const [showDebug, setShowDebug] = useState(false);
47
- const [showPluginRender, setShowPluginRender] = useState(false);
48
+ const [showCustomToolRender, setShowCustomToolRender] = useState(true);
48
49
  const [expand, setExpand] = useState(true);
49
50
 
50
51
  // Fetch tool message from store
@@ -68,6 +69,8 @@ const Tool = memo<InspectorProps>(
68
69
  // Don't render if still loading and no message yet
69
70
  if (loading && !toolMessage) return null;
70
71
 
72
+ const hasCustomRender = !!getBuiltinRender(identifier, apiName);
73
+
71
74
  return (
72
75
  <Accordion
73
76
  expandedKeys={expand ? ['tool'] : []}
@@ -79,13 +82,12 @@ const Tool = memo<InspectorProps>(
79
82
  !disableEditing && (
80
83
  <Actions
81
84
  assistantMessageId={messageId}
82
- handleExpand={(expand) => setExpand(!!expand)}
85
+ canToggleCustomToolRender={hasCustomRender}
83
86
  identifier={identifier}
87
+ setShowCustomToolRender={setShowCustomToolRender}
84
88
  setShowDebug={setShowDebug}
85
- setShowPluginRender={setShowPluginRender}
86
- showCustomPluginRender={false}
89
+ showCustomToolRender={showCustomToolRender}
87
90
  showDebug={showDebug}
88
- showPluginRender={showPluginRender}
89
91
  />
90
92
  )
91
93
  }
@@ -105,15 +107,14 @@ const Tool = memo<InspectorProps>(
105
107
  type={type}
106
108
  />
107
109
  )}
108
- <Render
110
+ <Detail
109
111
  apiName={apiName}
110
112
  arguments={requestArgs}
111
113
  disableEditing={disableEditing}
112
114
  identifier={identifier}
113
115
  messageId={messageId}
114
116
  result={result}
115
- setShowPluginRender={setShowPluginRender}
116
- showPluginRender={showPluginRender}
117
+ showCustomToolRender={showCustomToolRender}
117
118
  toolCallId={toolCallId}
118
119
  type={type}
119
120
  />
@@ -3,7 +3,7 @@
3
3
  import { type StepContextTodos } from '@lobechat/types';
4
4
  import { Checkbox, Flexbox, Icon, Tag } from '@lobehub/ui';
5
5
  import { createStaticStyles, cssVar, cx } from 'antd-style';
6
- import { ChevronDown, ChevronUp, ListTodo } from 'lucide-react';
6
+ import { ChevronDown, ChevronUp, CircleArrowRight, ListTodo } from 'lucide-react';
7
7
  import { memo, useMemo, useState } from 'react';
8
8
  import { useTranslation } from 'react-i18next';
9
9
 
@@ -73,6 +73,11 @@ const styles = createStaticStyles(({ css, cssVar }) => ({
73
73
  opacity 0.2s ${cssVar.motionEaseInOut},
74
74
  padding 0.2s ${cssVar.motionEaseInOut};
75
75
  `,
76
+ processingRow: css`
77
+ display: flex;
78
+ gap: 6px;
79
+ align-items: center;
80
+ `,
76
81
  progress: css`
77
82
  flex: 1;
78
83
  height: 4px;
@@ -85,10 +90,16 @@ const styles = createStaticStyles(({ css, cssVar }) => ({
85
90
  background: ${cssVar.colorSuccess};
86
91
  transition: width 0.3s ${cssVar.motionEaseInOut};
87
92
  `,
88
- textChecked: css`
93
+ textCompleted: css`
89
94
  color: ${cssVar.colorTextQuaternary};
90
95
  text-decoration: line-through;
91
96
  `,
97
+ textProcessing: css`
98
+ color: ${cssVar.colorText};
99
+ `,
100
+ textTodo: css`
101
+ color: ${cssVar.colorTextSecondary};
102
+ `,
92
103
  }));
93
104
 
94
105
  interface TodoProgressProps {
@@ -112,11 +123,13 @@ const TodoProgress = memo<TodoProgressProps>(({ className }) => {
112
123
  // Calculate progress
113
124
  const items = todos?.items || [];
114
125
  const total = items.length;
115
- const completed = items.filter((item) => item.completed).length;
126
+ const completed = items.filter((item) => item.status === 'completed').length;
116
127
  const progressPercent = total > 0 ? (completed / total) * 100 : 0;
117
128
 
118
- // Find current pending task (first incomplete item)
119
- const currentPendingTask = items.find((item) => !item.completed);
129
+ // Find current pending task (first non-completed item, prioritize processing)
130
+ const currentPendingTask =
131
+ items.find((item) => item.status === 'processing') ||
132
+ items.find((item) => item.status === 'todo');
120
133
 
121
134
  // Don't render if no todos
122
135
  if (total === 0) return null;
@@ -156,24 +169,44 @@ const TodoProgress = memo<TodoProgressProps>(({ className }) => {
156
169
 
157
170
  {/* Expandable Todo List */}
158
171
  <div className={cx(styles.listContainer, expanded ? styles.expanded : styles.collapsed)}>
159
- {items.map((item, index) => (
160
- <Checkbox
161
- backgroundColor={cssVar.colorSuccess}
162
- checked={item.completed}
163
- classNames={{
164
- text: item.completed ? styles.textChecked : undefined,
165
- wrapper: styles.itemRow,
166
- }}
167
- key={index}
168
- shape="circle"
169
- style={{ borderWidth: 1.5, cursor: 'default', pointerEvents: 'none' }}
170
- textProps={{
171
- type: item.completed ? 'secondary' : undefined,
172
- }}
173
- >
174
- {item.text}
175
- </Checkbox>
176
- ))}
172
+ {items.map((item, index) => {
173
+ const isCompleted = item.status === 'completed';
174
+ const isProcessing = item.status === 'processing';
175
+
176
+ // Processing state uses CircleArrowRight icon
177
+ if (isProcessing) {
178
+ return (
179
+ <div className={cx(styles.itemRow, styles.processingRow)} key={index}>
180
+ <Icon
181
+ icon={CircleArrowRight}
182
+ size={17}
183
+ style={{ color: cssVar.colorTextSecondary }}
184
+ />
185
+ <span className={styles.textProcessing}>{item.text}</span>
186
+ </div>
187
+ );
188
+ }
189
+
190
+ // Todo and completed states use Checkbox
191
+ return (
192
+ <Checkbox
193
+ backgroundColor={cssVar.colorSuccess}
194
+ checked={isCompleted}
195
+ classNames={{
196
+ text: cx(styles.textTodo, isCompleted && styles.textCompleted),
197
+ wrapper: styles.itemRow,
198
+ }}
199
+ key={index}
200
+ shape="circle"
201
+ style={{ borderWidth: 1.5, cursor: 'default', pointerEvents: 'none' }}
202
+ textProps={{
203
+ type: isCompleted ? 'secondary' : undefined,
204
+ }}
205
+ >
206
+ {item.text}
207
+ </Checkbox>
208
+ );
209
+ })}
177
210
  </div>
178
211
  </div>
179
212
  </WideScreenContainer>
@@ -1,7 +1,7 @@
1
1
  import { Flexbox, Image, Markdown } from '@lobehub/ui';
2
2
  import { memo } from 'react';
3
3
 
4
- import Arguments from '@/features/Conversation/Messages/AssistantGroup/Tool/Render/Arguments';
4
+ import Arguments from '@/features/Conversation/Messages/AssistantGroup/Tool/Detail/Arguments';
5
5
  import { type ToolCallResult } from '@/libs/mcp';
6
6
 
7
7
  export interface MCPTypeProps {
@@ -1,8 +1,9 @@
1
1
  'use client';
2
2
 
3
3
  import { ActionIcon, Flexbox } from '@lobehub/ui';
4
+ import { App } from 'antd';
4
5
  import { cssVar } from 'antd-style';
5
- import { SearchIcon } from 'lucide-react';
6
+ import { BookMinusIcon, FileBoxIcon, SearchIcon, Trash2Icon } from 'lucide-react';
6
7
  import { memo } from 'react';
7
8
  import { useTranslation } from 'react-i18next';
8
9
 
@@ -18,7 +19,8 @@ import ViewSwitcher from '../ToolBar/ViewSwitcher';
18
19
  import Breadcrumb from './Breadcrumb';
19
20
 
20
21
  const Header = memo(() => {
21
- const { t } = useTranslation('file');
22
+ const { t } = useTranslation(['components', 'common', 'file', 'knowledgeBase']);
23
+ const { modal, message } = App.useApp();
22
24
 
23
25
  // Get state and actions from store
24
26
  const [libraryId, category, onActionClick, selectFileIds] = useResourceManagerStore((s) => [
@@ -29,8 +31,59 @@ const Header = memo(() => {
29
31
  ]);
30
32
  const toggleCommandMenu = useGlobalStore((s) => s.toggleCommandMenu);
31
33
 
34
+ const selectCount = selectFileIds.length;
35
+ const isMultiSelected = selectCount > 1;
36
+
32
37
  // If no libraryId, show category name or "Resource" for All
33
- const leftContent = !libraryId ? (
38
+ const leftContent = isMultiSelected ? (
39
+ <Flexbox align={'center'} gap={8} horizontal style={{ marginLeft: 0 }}>
40
+ {libraryId ? (
41
+ <ActionIcon
42
+ icon={BookMinusIcon}
43
+ onClick={() => {
44
+ modal.confirm({
45
+ okButtonProps: {
46
+ danger: true,
47
+ },
48
+ onOk: async () => {
49
+ await onActionClick('removeFromKnowledgeBase');
50
+ message.success(t('FileManager.actions.removeFromKnowledgeBaseSuccess'));
51
+ },
52
+ title: t('FileManager.actions.confirmRemoveFromKnowledgeBase', {
53
+ count: selectCount,
54
+ }),
55
+ });
56
+ }}
57
+ title={t('FileManager.actions.removeFromKnowledgeBase')}
58
+ />
59
+ ) : null}
60
+
61
+ <ActionIcon
62
+ icon={FileBoxIcon}
63
+ onClick={async () => {
64
+ await onActionClick('batchChunking');
65
+ }}
66
+ title={t('FileManager.actions.batchChunking')}
67
+ />
68
+
69
+ <ActionIcon
70
+ icon={Trash2Icon}
71
+ onClick={() => {
72
+ modal.confirm({
73
+ okButtonProps: {
74
+ danger: true,
75
+ },
76
+ onOk: async () => {
77
+ await onActionClick('delete');
78
+ message.success(t('FileManager.actions.deleteSuccess'));
79
+ },
80
+ title: t('FileManager.actions.confirmDeleteMultiFiles', { count: selectCount }),
81
+ });
82
+ }}
83
+ title={t('delete', { ns: 'common' })}
84
+ />
85
+ </Flexbox>
86
+ ) : !libraryId ? (
34
87
  <Flexbox style={{ marginLeft: 8 }}>
35
88
  {category === FilesTabs.All
36
89
  ? t('resource', { defaultValue: 'Resource' })
@@ -49,7 +102,7 @@ const Header = memo(() => {
49
102
  <>
50
103
  <ActionIcon icon={SearchIcon} onClick={() => toggleCommandMenu(true)} />
51
104
  <SortDropdown />
52
- <BatchActionsDropdown onActionClick={onActionClick} selectCount={selectFileIds.length} />
105
+ <BatchActionsDropdown onActionClick={onActionClick} selectCount={selectCount} />
53
106
  <ViewSwitcher />
54
107
  <Flexbox style={{ marginLeft: 8 }}>
55
108
  <AddButton />
@@ -48,11 +48,12 @@ const styles = createStaticStyles(({ css }) => {
48
48
  `,
49
49
 
50
50
  dragOver: css`
51
- color: ${cssVar.colorBgElevated} !important;
52
- background-color: ${cssVar.colorText} !important;
51
+ outline: 1px dashed ${cssVar.colorPrimaryBorder};
52
+ outline-offset: -2px;
53
53
 
54
- * {
55
- color: ${cssVar.colorBgElevated} !important;
54
+ &,
55
+ &:hover {
56
+ background: ${cssVar.colorPrimaryBg};
56
57
  }
57
58
  `,
58
59
 
@@ -510,6 +511,7 @@ const FileListItem = memo<FileListItemProps>(
510
511
  e.stopPropagation();
511
512
  }}
512
513
  onPointerDown={(e) => e.stopPropagation()}
514
+ paddingInline={8}
513
515
  >
514
516
  {!isFolder &&
515
517
  !isPage &&