@lobehub/lobehub 2.0.0-next.295 → 2.0.0-next.297
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/locales/en-US/plugin.json +4 -0
- package/locales/zh-CN/plugin.json +4 -0
- package/package.json +2 -2
- package/packages/agent-runtime/src/core/__tests__/runtime.test.ts +5 -5
- package/packages/agent-runtime/src/utils/stepContextComputer.test.ts +5 -5
- package/packages/builtin-tool-gtd/src/client/Inspector/index.ts +0 -4
- package/packages/builtin-tool-gtd/src/client/Intervention/AddTodo.tsx +1 -1
- package/packages/builtin-tool-gtd/src/client/Render/TodoList/index.tsx +39 -10
- package/packages/builtin-tool-gtd/src/client/Render/index.ts +0 -2
- package/packages/builtin-tool-gtd/src/client/components/SortableTodoList/TodoItemRow.tsx +26 -12
- package/packages/builtin-tool-gtd/src/client/components/SortableTodoList/store/actions.ts +5 -5
- package/packages/builtin-tool-gtd/src/client/components/SortableTodoList/store/store.test.ts +14 -8
- package/packages/builtin-tool-gtd/src/executor/index.test.ts +48 -227
- package/packages/builtin-tool-gtd/src/executor/index.ts +15 -158
- package/packages/builtin-tool-gtd/src/manifest.ts +12 -42
- package/packages/builtin-tool-gtd/src/systemRole.ts +14 -8
- package/packages/builtin-tool-gtd/src/types.ts +47 -41
- package/packages/builtin-tool-memory/package.json +8 -0
- package/packages/builtin-tool-memory/src/client/Inspector/AddContextMemory/index.tsx +60 -0
- package/packages/builtin-tool-memory/src/client/Inspector/AddExperienceMemory/index.tsx +60 -0
- package/packages/builtin-tool-memory/src/client/Inspector/AddIdentityMemory/index.tsx +60 -0
- package/packages/builtin-tool-memory/src/client/Inspector/AddPreferenceMemory/index.tsx +60 -0
- package/packages/builtin-tool-memory/src/client/Inspector/RemoveIdentityMemory/index.tsx +60 -0
- package/packages/builtin-tool-memory/src/client/Inspector/SearchUserMemory/index.tsx +67 -0
- package/packages/builtin-tool-memory/src/client/Inspector/UpdateIdentityMemory/index.tsx +60 -0
- package/packages/builtin-tool-memory/src/client/Inspector/index.ts +35 -0
- package/packages/builtin-tool-memory/src/client/Intervention/AddExperienceMemory/index.tsx +17 -0
- package/packages/builtin-tool-memory/src/client/Intervention/index.ts +13 -0
- package/packages/builtin-tool-memory/src/client/Render/AddExperienceMemory/index.tsx +17 -0
- package/packages/builtin-tool-memory/src/client/Render/SearchUserMemory/index.tsx +217 -0
- package/packages/builtin-tool-memory/src/client/Render/index.ts +15 -0
- package/packages/builtin-tool-memory/src/client/Streaming/AddExperienceMemory/index.tsx +17 -0
- package/packages/builtin-tool-memory/src/client/Streaming/index.ts +18 -0
- package/packages/builtin-tool-memory/src/client/components/ExperienceMemoryCard.tsx +231 -0
- package/packages/builtin-tool-memory/src/client/components/index.ts +1 -0
- package/packages/builtin-tool-memory/src/client/index.ts +27 -0
- package/packages/builtin-tool-memory/src/executor/index.ts +9 -1
- package/packages/builtin-tool-memory/src/types.ts +61 -0
- package/packages/context-engine/src/providers/GTDTodoInjector.ts +15 -7
- package/packages/conversation-flow/src/__tests__/fixtures/outputs/assistantGroup/tools-with-branches.json +4 -0
- package/packages/conversation-flow/src/transformation/FlatListBuilder.ts +1 -0
- package/packages/prompts/src/prompts/gtd/index.test.ts +32 -16
- package/packages/prompts/src/prompts/gtd/index.ts +9 -5
- package/packages/types/package.json +1 -1
- package/packages/types/src/discover/assistants.ts +4 -0
- package/packages/types/src/discover/groupAgents.ts +196 -0
- package/packages/types/src/discover/index.ts +5 -1
- package/packages/types/src/stepContext.ts +4 -1
- package/src/app/[variants]/(main)/community/(detail)/assistant/features/Details/Versions/index.tsx +2 -2
- package/src/app/[variants]/(main)/community/(detail)/group_agent/features/DetailProvider.tsx +19 -0
- package/src/app/[variants]/(main)/community/(detail)/group_agent/features/Details/Members/index.tsx +137 -0
- package/src/app/[variants]/(main)/community/(detail)/group_agent/features/Details/Nav.tsx +88 -0
- package/src/app/[variants]/(main)/community/(detail)/group_agent/features/Details/Overview/index.tsx +213 -0
- package/src/app/[variants]/(main)/community/(detail)/group_agent/features/Details/Related/index.tsx +85 -0
- package/src/app/[variants]/(main)/community/(detail)/group_agent/features/Details/SystemRole/TagList.tsx +20 -0
- package/src/app/[variants]/(main)/community/(detail)/group_agent/features/Details/SystemRole/index.tsx +71 -0
- package/src/app/[variants]/(main)/community/(detail)/group_agent/features/Details/Versions/index.tsx +119 -0
- package/src/app/[variants]/(main)/community/(detail)/group_agent/features/Details/index.tsx +51 -0
- package/src/app/[variants]/(main)/community/(detail)/group_agent/features/Header.tsx +253 -0
- package/src/app/[variants]/(main)/community/(detail)/group_agent/features/Sidebar/ActionButton/AddGroupAgent.tsx +222 -0
- package/src/app/[variants]/(main)/community/(detail)/group_agent/features/Sidebar/ActionButton/index.tsx +34 -0
- package/src/app/[variants]/(main)/community/(detail)/group_agent/features/Sidebar/Summary/index.tsx +42 -0
- package/src/app/[variants]/(main)/community/(detail)/group_agent/features/Sidebar/index.tsx +41 -0
- package/src/app/[variants]/(main)/community/(detail)/group_agent/features/StatusPage/index.tsx +104 -0
- package/src/app/[variants]/(main)/community/(detail)/group_agent/index.tsx +103 -0
- package/src/app/[variants]/(main)/community/(detail)/group_agent/loading.tsx +1 -0
- package/src/app/[variants]/(main)/community/(detail)/user/features/DetailProvider.tsx +7 -1
- package/src/app/[variants]/(main)/community/(detail)/user/features/UserContent.tsx +2 -0
- package/src/app/[variants]/(main)/community/(detail)/user/features/UserGroupCard.tsx +186 -0
- package/src/app/[variants]/(main)/community/(detail)/user/features/UserGroupList.tsx +59 -0
- package/src/app/[variants]/(main)/community/(detail)/user/index.tsx +3 -1
- package/src/app/[variants]/(main)/community/(list)/assistant/features/List/Item.tsx +26 -8
- package/src/app/[variants]/(main)/community/(list)/assistant/index.tsx +1 -0
- package/src/app/[variants]/(main)/community/features/Search.tsx +1 -1
- package/src/app/[variants]/(main)/group/profile/features/GroupProfile/index.tsx +2 -0
- package/src/app/[variants]/(main)/group/profile/features/Header/AgentPublishButton/PublishResultModal.tsx +2 -1
- package/src/app/[variants]/(main)/group/profile/features/Header/GroupPublishButton/GroupForkConfirmModal.tsx +60 -0
- package/src/app/[variants]/(main)/group/profile/features/Header/GroupPublishButton/GroupPublishResultModal.tsx +62 -0
- package/src/app/[variants]/(main)/group/profile/features/Header/GroupPublishButton/PublishButton.tsx +122 -0
- package/src/app/[variants]/(main)/group/profile/features/Header/GroupPublishButton/index.tsx +46 -0
- package/src/app/[variants]/(main)/group/profile/features/Header/GroupPublishButton/types.ts +12 -0
- package/src/app/[variants]/(main)/group/profile/features/Header/GroupPublishButton/useMarketGroupPublish.ts +211 -0
- package/src/app/[variants]/(main)/group/profile/features/Header/GroupPublishButton/utils.ts +22 -0
- package/src/app/[variants]/(main)/resource/features/DndContextWrapper.tsx +4 -2
- package/src/app/[variants]/(main)/resource/library/_layout/Header/LibraryHead.tsx +30 -35
- package/src/app/[variants]/(main)/resource/library/_layout/Header/index.tsx +9 -11
- package/src/app/[variants]/router/desktopRouter.config.tsx +7 -0
- package/src/features/Conversation/Messages/AssistantGroup/Tool/Actions/index.tsx +11 -17
- package/src/features/Conversation/Messages/AssistantGroup/Tool/{Render → Detail}/LoadingPlaceholder/index.tsx +13 -3
- package/src/features/Conversation/Messages/AssistantGroup/Tool/Detail/Render/CustomRender.tsx +43 -0
- package/src/features/Conversation/Messages/AssistantGroup/Tool/Detail/Render/FallbacktArgumentRender.tsx +59 -0
- package/src/features/Conversation/Messages/AssistantGroup/Tool/Detail/Render/index.tsx +46 -0
- package/src/features/Conversation/Messages/AssistantGroup/Tool/{Render → Detail}/index.tsx +13 -19
- package/src/features/Conversation/Messages/AssistantGroup/Tool/index.tsx +17 -17
- package/src/features/Conversation/Messages/Tool/Tool/index.tsx +10 -9
- package/src/features/Conversation/TodoProgress/index.tsx +56 -23
- package/src/features/PluginsUI/Render/MCPType/index.tsx +1 -1
- package/src/features/ResourceManager/components/Explorer/Header/index.tsx +57 -4
- package/src/features/ResourceManager/components/Explorer/ListView/ListItem/index.tsx +6 -4
- package/src/features/ResourceManager/components/Explorer/ListView/index.tsx +16 -5
- package/src/features/ResourceManager/components/LibraryHierarchy/styles.ts +5 -4
- package/src/hooks/useActiveTabKey.ts +1 -2
- package/src/locales/default/plugin.ts +1 -0
- package/src/locales/default/setting.ts +12 -0
- package/src/server/routers/lambda/market/agentGroup.ts +296 -0
- package/src/server/routers/lambda/market/index.ts +134 -4
- package/src/server/services/discover/index.ts +123 -7
- package/src/services/discover.ts +55 -0
- package/src/store/chat/slices/message/selectors/dbMessage.test.ts +11 -11
- package/src/store/discover/slices/groupAgent/action.ts +80 -0
- package/src/store/discover/store.ts +3 -0
- package/src/store/file/slices/resource/action.ts +4 -2
- package/src/tools/inspectors.ts +2 -0
- package/src/tools/interventions.ts +2 -0
- package/src/tools/renders.ts +3 -1
- package/src/tools/streamings.ts +2 -0
- package/packages/builtin-tool-gtd/src/client/Inspector/CompleteTodos/index.tsx +0 -52
- package/packages/builtin-tool-gtd/src/client/Inspector/RemoveTodos/index.tsx +0 -52
- package/src/features/Conversation/Messages/AssistantGroup/Tool/Render/CustomRender.tsx +0 -113
- package/src/features/Conversation/Messages/Tool/Tool/Render.tsx +0 -47
- /package/src/features/Conversation/Messages/AssistantGroup/Tool/{Render → Detail}/AbortResponse.tsx +0 -0
- /package/src/features/Conversation/Messages/AssistantGroup/Tool/{Render → Detail}/Arguments/index.tsx +0 -0
- /package/src/features/Conversation/Messages/AssistantGroup/Tool/{Render → Detail}/ErrorResponse.tsx +0 -0
- /package/src/features/Conversation/Messages/AssistantGroup/Tool/{Render → Detail}/Intervention/ApprovalActions.tsx +0 -0
- /package/src/features/Conversation/Messages/AssistantGroup/Tool/{Render → Detail}/Intervention/Fallback.tsx +0 -0
- /package/src/features/Conversation/Messages/AssistantGroup/Tool/{Render → Detail}/Intervention/KeyValueEditor.tsx +0 -0
- /package/src/features/Conversation/Messages/AssistantGroup/Tool/{Render → Detail}/Intervention/ModeSelector.tsx +0 -0
- /package/src/features/Conversation/Messages/AssistantGroup/Tool/{Render → Detail}/Intervention/index.tsx +0 -0
- /package/src/features/Conversation/Messages/AssistantGroup/Tool/{Render → Detail}/PluginSettings.tsx +0 -0
- /package/src/features/Conversation/Messages/AssistantGroup/Tool/{Render → Detail}/RejectedResponse.tsx +0 -0
|
@@ -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
|
-
|
|
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
|
|
119
|
-
const currentPendingTask =
|
|
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
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
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/
|
|
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 =
|
|
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={
|
|
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
|
-
|
|
52
|
-
|
|
51
|
+
outline: 1px dashed ${cssVar.colorPrimaryBorder};
|
|
52
|
+
outline-offset: -2px;
|
|
53
53
|
|
|
54
|
-
|
|
55
|
-
|
|
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 &&
|
|
@@ -34,7 +34,7 @@ const styles = createStaticStyles(({ css }) => ({
|
|
|
34
34
|
`,
|
|
35
35
|
dropZoneActive: css`
|
|
36
36
|
background: ${cssVar.colorPrimaryBg};
|
|
37
|
-
outline:
|
|
37
|
+
outline: 1px dashed ${cssVar.colorPrimaryBorder};
|
|
38
38
|
outline-offset: -4px;
|
|
39
39
|
`,
|
|
40
40
|
header: css`
|
|
@@ -330,9 +330,15 @@ const ListView = memo(function ListView() {
|
|
|
330
330
|
|
|
331
331
|
// Memoize footer component to show skeleton loaders when loading more
|
|
332
332
|
const Footer = useCallback(() => {
|
|
333
|
-
if (
|
|
334
|
-
|
|
335
|
-
|
|
333
|
+
if (isLoadingMore && fileListHasMore) return <ListViewSkeleton columnWidths={columnWidths} />;
|
|
334
|
+
|
|
335
|
+
// Leave some padding at the end when there are no more pages,
|
|
336
|
+
// so users can clearly feel they've reached the end of the list.
|
|
337
|
+
if (fileListHasMore === false && dataLength > 0)
|
|
338
|
+
return <div aria-hidden style={{ height: 96 }} />;
|
|
339
|
+
|
|
340
|
+
return null;
|
|
341
|
+
}, [columnWidths, dataLength, fileListHasMore, isLoadingMore]);
|
|
336
342
|
|
|
337
343
|
if (showSkeleton) return <ListViewSkeleton columnWidths={columnWidths} />;
|
|
338
344
|
|
|
@@ -369,7 +375,12 @@ const ListView = memo(function ListView() {
|
|
|
369
375
|
width: columnWidths.name,
|
|
370
376
|
}}
|
|
371
377
|
>
|
|
372
|
-
{
|
|
378
|
+
{selectFileIds.length > 0
|
|
379
|
+
? t('FileManager.total.selectedCount', {
|
|
380
|
+
count: selectFileIds.length,
|
|
381
|
+
ns: 'components',
|
|
382
|
+
})
|
|
383
|
+
: t('FileManager.title.title')}
|
|
373
384
|
<ColumnResizeHandle
|
|
374
385
|
column="name"
|
|
375
386
|
currentWidth={columnWidths.name}
|
|
@@ -6,11 +6,12 @@ export const styles = createStaticStyles(({ css, cssVar }) => ({
|
|
|
6
6
|
opacity: 0.5;
|
|
7
7
|
`,
|
|
8
8
|
fileItemDragOver: css`
|
|
9
|
-
|
|
10
|
-
|
|
9
|
+
outline: 1px dashed ${cssVar.colorPrimaryBorder};
|
|
10
|
+
outline-offset: -2px;
|
|
11
11
|
|
|
12
|
-
|
|
13
|
-
|
|
12
|
+
&,
|
|
13
|
+
&:hover {
|
|
14
|
+
background: ${cssVar.colorPrimaryBg};
|
|
14
15
|
}
|
|
15
16
|
`,
|
|
16
17
|
treeItem: css`
|
|
@@ -174,6 +174,7 @@ export default {
|
|
|
174
174
|
'builtins.lobe-user-memory.apiName.removeIdentityMemory': 'Delete identity memory',
|
|
175
175
|
'builtins.lobe-user-memory.apiName.searchUserMemory': 'Search memory',
|
|
176
176
|
'builtins.lobe-user-memory.apiName.updateIdentityMemory': 'Update identity memory',
|
|
177
|
+
'builtins.lobe-user-memory.inspector.noResults': 'No results',
|
|
177
178
|
'builtins.lobe-user-memory.title': 'Memory',
|
|
178
179
|
'builtins.lobe-web-browsing.apiName.crawlMultiPages': 'Read multiple pages',
|
|
179
180
|
'builtins.lobe-web-browsing.apiName.crawlSinglePage': 'Read page content',
|
|
@@ -187,9 +187,13 @@ export default {
|
|
|
187
187
|
'llm.waitingForMoreLinkAriaLabel': 'Open the Provider request form',
|
|
188
188
|
'marketPublish.forkConfirm.by': 'by {{author}}',
|
|
189
189
|
'marketPublish.forkConfirm.confirm': 'Confirm Publish',
|
|
190
|
+
'marketPublish.forkConfirm.confirmGroup': 'Confirm Publish',
|
|
190
191
|
'marketPublish.forkConfirm.description':
|
|
191
192
|
'You are about to publish a derivative version based on an existing agent from the community. Your new agent will be created as a separate entry in the marketplace.',
|
|
193
|
+
'marketPublish.forkConfirm.descriptionGroup':
|
|
194
|
+
'You are about to publish a derivative version based on an existing group from the community. Your new group will be created as a separate entry in the marketplace.',
|
|
192
195
|
'marketPublish.forkConfirm.title': 'Publish Derivative Agent',
|
|
196
|
+
'marketPublish.forkConfirm.titleGroup': 'Publish Derivative Group',
|
|
193
197
|
'marketPublish.modal.changelog.extra':
|
|
194
198
|
'Describe the key changes and improvements in this version',
|
|
195
199
|
'marketPublish.modal.changelog.label': 'Changelog',
|
|
@@ -209,11 +213,14 @@ export default {
|
|
|
209
213
|
'marketPublish.modal.identifier.required': 'Please enter the agent identifier',
|
|
210
214
|
'marketPublish.modal.loading.fetchingRemote': 'Loading remote data...',
|
|
211
215
|
'marketPublish.modal.loading.submit': 'Submitting Agent...',
|
|
216
|
+
'marketPublish.modal.loading.submitGroup': 'Submitting Group...',
|
|
212
217
|
'marketPublish.modal.loading.upload': 'Publishing new version...',
|
|
218
|
+
'marketPublish.modal.loading.uploadGroup': 'Publishing new group version...',
|
|
213
219
|
'marketPublish.modal.messages.createVersionFailed': 'Failed to create version: {{message}}',
|
|
214
220
|
'marketPublish.modal.messages.fetchRemoteFailed': 'Failed to fetch remote agent data',
|
|
215
221
|
'marketPublish.modal.messages.missingIdentifier':
|
|
216
222
|
'This Agent doesn’t have a Community identifier yet.',
|
|
223
|
+
'marketPublish.modal.messages.noGroup': 'No group selected',
|
|
217
224
|
'marketPublish.modal.messages.notAuthenticated': 'Sign in to your Community account first.',
|
|
218
225
|
'marketPublish.modal.messages.publishFailed': 'Publish failed: {{message}}',
|
|
219
226
|
'marketPublish.modal.submitButton': 'Publish',
|
|
@@ -221,12 +228,16 @@ export default {
|
|
|
221
228
|
'marketPublish.modal.title.upload': 'Publish New Version',
|
|
222
229
|
'marketPublish.resultModal.message':
|
|
223
230
|
'Your Agent has been submitted for review. Once approved, it will go live automatically.',
|
|
231
|
+
'marketPublish.resultModal.messageGroup':
|
|
232
|
+
'Your Group has been submitted for review. Once approved, it will go live automatically.',
|
|
224
233
|
'marketPublish.resultModal.title': 'Submission Successful',
|
|
225
234
|
'marketPublish.resultModal.view': 'View in Community',
|
|
226
235
|
'marketPublish.submit.button': 'Share to Community',
|
|
227
236
|
'marketPublish.submit.tooltip': 'Share this Agent to the Community',
|
|
237
|
+
'marketPublish.submitGroup.tooltip': 'Share this Group to the Community',
|
|
228
238
|
'marketPublish.upload.button': 'Publish New Version',
|
|
229
239
|
'marketPublish.upload.tooltip': 'Publish a new version to Agent Community',
|
|
240
|
+
'marketPublish.uploadGroup.tooltip': 'Publish a new version to Group Community',
|
|
230
241
|
'memory.enabled.desc':
|
|
231
242
|
'Allow LobeHub to extract preferences and info from conversations and use them later. You can view, edit, or clear memory anytime.',
|
|
232
243
|
'memory.enabled.title': 'Enable Memory',
|
|
@@ -551,6 +562,7 @@ export default {
|
|
|
551
562
|
'submitAgentModal.placeholder': 'Enter a unique identifier for the agent, e.g. web-development',
|
|
552
563
|
'submitAgentModal.success': 'Agent submitted successfully',
|
|
553
564
|
'submitAgentModal.tooltips': 'Share to Agent Community',
|
|
565
|
+
'submitGroupModal.tooltips': 'Share to Group Community',
|
|
554
566
|
'sync.device.deviceName.hint': 'Add a name for easy identification',
|
|
555
567
|
'sync.device.deviceName.placeholder': 'Enter device name',
|
|
556
568
|
'sync.device.deviceName.title': 'Device Name',
|
|
@@ -0,0 +1,296 @@
|
|
|
1
|
+
import { TRPCError } from '@trpc/server';
|
|
2
|
+
import debug from 'debug';
|
|
3
|
+
import { customAlphabet } from 'nanoid/non-secure';
|
|
4
|
+
import { z } from 'zod';
|
|
5
|
+
|
|
6
|
+
import { authedProcedure, router } from '@/libs/trpc/lambda';
|
|
7
|
+
import { marketSDK, marketUserInfo, serverDatabase } from '@/libs/trpc/lambda/middleware';
|
|
8
|
+
import { type TrustedClientUserInfo, generateTrustedClientToken } from '@/libs/trusted-client';
|
|
9
|
+
|
|
10
|
+
const MARKET_BASE_URL = process.env.NEXT_PUBLIC_MARKET_BASE_URL || 'https://market.lobehub.com';
|
|
11
|
+
|
|
12
|
+
interface MarketUserInfo {
|
|
13
|
+
accountId: number;
|
|
14
|
+
sub: string;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
const log = debug('lambda-router:market:agent-group');
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Generate a market identifier (8-character lowercase alphanumeric string)
|
|
21
|
+
* Format: [a-z0-9]{8}
|
|
22
|
+
*/
|
|
23
|
+
const generateMarketIdentifier = () => {
|
|
24
|
+
const alphabet = '0123456789abcdefghijklmnopqrstuvwxyz';
|
|
25
|
+
const generate = customAlphabet(alphabet, 8);
|
|
26
|
+
return generate();
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
interface FetchMarketUserInfoOptions {
|
|
30
|
+
accessToken?: string;
|
|
31
|
+
userInfo?: TrustedClientUserInfo;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Fetch Market user info using either trustedClientToken or accessToken
|
|
36
|
+
* Returns the Market accountId which is different from LobeChat userId
|
|
37
|
+
*/
|
|
38
|
+
const fetchMarketUserInfo = async (
|
|
39
|
+
options: FetchMarketUserInfoOptions,
|
|
40
|
+
): Promise<MarketUserInfo | null> => {
|
|
41
|
+
const { userInfo, accessToken } = options;
|
|
42
|
+
|
|
43
|
+
try {
|
|
44
|
+
const userInfoUrl = `${MARKET_BASE_URL}/lobehub-oidc/userinfo`;
|
|
45
|
+
const headers: Record<string, string> = {
|
|
46
|
+
'Content-Type': 'application/json',
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
if (userInfo) {
|
|
50
|
+
const trustedClientToken = generateTrustedClientToken(userInfo);
|
|
51
|
+
if (trustedClientToken) {
|
|
52
|
+
headers['x-lobe-trust-token'] = trustedClientToken;
|
|
53
|
+
log('Using trustedClientToken for user info fetch');
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
if (!headers['x-lobe-trust-token'] && accessToken) {
|
|
58
|
+
headers['Authorization'] = `Bearer ${accessToken}`;
|
|
59
|
+
log('Using accessToken for user info fetch');
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
if (!headers['x-lobe-trust-token'] && !headers['Authorization']) {
|
|
63
|
+
log('No authentication method available for fetching user info');
|
|
64
|
+
return null;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
const response = await fetch(userInfoUrl, {
|
|
68
|
+
headers,
|
|
69
|
+
method: 'GET',
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
if (!response.ok) {
|
|
73
|
+
log('Failed to fetch Market user info: %s %s', response.status, response.statusText);
|
|
74
|
+
return null;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
return (await response.json()) as MarketUserInfo;
|
|
78
|
+
} catch (error) {
|
|
79
|
+
log('Error fetching Market user info: %O', error);
|
|
80
|
+
return null;
|
|
81
|
+
}
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
// Authenticated procedure for agent group management
|
|
85
|
+
const agentGroupProcedure = authedProcedure
|
|
86
|
+
.use(serverDatabase)
|
|
87
|
+
.use(marketUserInfo)
|
|
88
|
+
.use(marketSDK)
|
|
89
|
+
.use(async ({ ctx, next }) => {
|
|
90
|
+
const { UserModel } = await import('@/database/models/user');
|
|
91
|
+
const userModel = new UserModel(ctx.serverDB, ctx.userId);
|
|
92
|
+
|
|
93
|
+
let marketOidcAccessToken: string | undefined;
|
|
94
|
+
try {
|
|
95
|
+
const userState = await userModel.getUserState(async () => ({}));
|
|
96
|
+
marketOidcAccessToken = userState.settings?.market?.accessToken;
|
|
97
|
+
log('marketOidcAccessToken from DB exists=%s', !!marketOidcAccessToken);
|
|
98
|
+
} catch (error) {
|
|
99
|
+
log('Failed to get marketOidcAccessToken from DB: %O', error);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
return next({
|
|
103
|
+
ctx: {
|
|
104
|
+
marketOidcAccessToken,
|
|
105
|
+
},
|
|
106
|
+
});
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
// Schema definitions
|
|
110
|
+
const memberAgentSchema = z.object({
|
|
111
|
+
avatar: z.string().nullish(),
|
|
112
|
+
category: z.string().optional(),
|
|
113
|
+
config: z.record(z.any()),
|
|
114
|
+
description: z.string(),
|
|
115
|
+
displayOrder: z.number().optional(),
|
|
116
|
+
identifier: z.string(),
|
|
117
|
+
name: z.string(),
|
|
118
|
+
role: z.enum(['supervisor', 'participant']),
|
|
119
|
+
url: z.string(),
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
const publishOrCreateGroupSchema = z.object({
|
|
123
|
+
avatar: z.string().nullish(),
|
|
124
|
+
backgroundColor: z.string().nullish(),
|
|
125
|
+
category: z.string().optional(),
|
|
126
|
+
changelog: z.string().optional(),
|
|
127
|
+
config: z
|
|
128
|
+
.object({
|
|
129
|
+
allowDM: z.boolean().optional(),
|
|
130
|
+
openingMessage: z.string().optional(),
|
|
131
|
+
openingQuestions: z.array(z.string()).optional(),
|
|
132
|
+
revealDM: z.boolean().optional(),
|
|
133
|
+
systemPrompt: z.string().optional(),
|
|
134
|
+
})
|
|
135
|
+
.optional(),
|
|
136
|
+
description: z.string(),
|
|
137
|
+
identifier: z.string().optional(),
|
|
138
|
+
memberAgents: z.array(memberAgentSchema),
|
|
139
|
+
name: z.string(),
|
|
140
|
+
visibility: z.enum(['public', 'private', 'internal']).optional(),
|
|
141
|
+
});
|
|
142
|
+
|
|
143
|
+
export const agentGroupRouter = router({
|
|
144
|
+
/**
|
|
145
|
+
* Check if current user owns the specified group
|
|
146
|
+
*/
|
|
147
|
+
checkOwnership: agentGroupProcedure
|
|
148
|
+
.input(z.object({ identifier: z.string() }))
|
|
149
|
+
.query(async ({ input, ctx }) => {
|
|
150
|
+
log('checkOwnership input: %O', input);
|
|
151
|
+
|
|
152
|
+
try {
|
|
153
|
+
const groupDetail = await ctx.marketSDK.agentGroups.getAgentGroupDetail(input.identifier);
|
|
154
|
+
|
|
155
|
+
if (!groupDetail) {
|
|
156
|
+
return {
|
|
157
|
+
exists: false,
|
|
158
|
+
isOwner: false,
|
|
159
|
+
originalGroup: null,
|
|
160
|
+
};
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
const userInfo = ctx.marketUserInfo as TrustedClientUserInfo | undefined;
|
|
164
|
+
const accessToken = (ctx as { marketOidcAccessToken?: string }).marketOidcAccessToken;
|
|
165
|
+
let currentAccountId: number | null = null;
|
|
166
|
+
|
|
167
|
+
const marketUserInfoResult = await fetchMarketUserInfo({ accessToken, userInfo });
|
|
168
|
+
currentAccountId = marketUserInfoResult?.accountId ?? null;
|
|
169
|
+
|
|
170
|
+
const ownerId = groupDetail.group.ownerId;
|
|
171
|
+
const isOwner = currentAccountId !== null && `${ownerId}` === `${currentAccountId}`;
|
|
172
|
+
|
|
173
|
+
log(
|
|
174
|
+
'checkOwnership result: isOwner=%s, currentAccountId=%s, ownerId=%s',
|
|
175
|
+
isOwner,
|
|
176
|
+
currentAccountId,
|
|
177
|
+
ownerId,
|
|
178
|
+
);
|
|
179
|
+
|
|
180
|
+
return {
|
|
181
|
+
exists: true,
|
|
182
|
+
isOwner,
|
|
183
|
+
originalGroup: isOwner
|
|
184
|
+
? null
|
|
185
|
+
: {
|
|
186
|
+
// TODO: Add author info from group detail
|
|
187
|
+
author: undefined,
|
|
188
|
+
avatar: groupDetail.group.avatar,
|
|
189
|
+
identifier: groupDetail.group.identifier,
|
|
190
|
+
name: groupDetail.group.name,
|
|
191
|
+
},
|
|
192
|
+
};
|
|
193
|
+
} catch (error) {
|
|
194
|
+
log('Error checking ownership: %O', error);
|
|
195
|
+
return {
|
|
196
|
+
exists: false,
|
|
197
|
+
isOwner: false,
|
|
198
|
+
originalGroup: null,
|
|
199
|
+
};
|
|
200
|
+
}
|
|
201
|
+
}),
|
|
202
|
+
|
|
203
|
+
/**
|
|
204
|
+
* Unified publish or create agent group flow
|
|
205
|
+
* 1. Check if identifier exists and if current user is owner
|
|
206
|
+
* 2. If not owner or no identifier, create new group
|
|
207
|
+
* 3. Create new version for the group if updating
|
|
208
|
+
*/
|
|
209
|
+
publishOrCreate: agentGroupProcedure
|
|
210
|
+
.input(publishOrCreateGroupSchema)
|
|
211
|
+
.mutation(async ({ input, ctx }) => {
|
|
212
|
+
log('publishOrCreate input: %O', input);
|
|
213
|
+
|
|
214
|
+
const { identifier: inputIdentifier, name, memberAgents, ...groupData } = input;
|
|
215
|
+
let finalIdentifier = inputIdentifier;
|
|
216
|
+
let isNewGroup = false;
|
|
217
|
+
|
|
218
|
+
try {
|
|
219
|
+
// Step 1: Check ownership if identifier is provided
|
|
220
|
+
if (inputIdentifier) {
|
|
221
|
+
try {
|
|
222
|
+
const groupDetail =
|
|
223
|
+
await ctx.marketSDK.agentGroups.getAgentGroupDetail(inputIdentifier);
|
|
224
|
+
log('Group detail for ownership check: ownerId=%s', groupDetail?.group.ownerId);
|
|
225
|
+
|
|
226
|
+
const userInfo = ctx.marketUserInfo as TrustedClientUserInfo | undefined;
|
|
227
|
+
const accessToken = (ctx as { marketOidcAccessToken?: string }).marketOidcAccessToken;
|
|
228
|
+
let currentAccountId: number | null = null;
|
|
229
|
+
|
|
230
|
+
const marketUserInfoResult = await fetchMarketUserInfo({ accessToken, userInfo });
|
|
231
|
+
currentAccountId = marketUserInfoResult?.accountId ?? null;
|
|
232
|
+
log('Market user info: accountId=%s', currentAccountId);
|
|
233
|
+
|
|
234
|
+
const ownerId = groupDetail?.group.ownerId;
|
|
235
|
+
|
|
236
|
+
log('Ownership check: currentAccountId=%s, ownerId=%s', currentAccountId, ownerId);
|
|
237
|
+
|
|
238
|
+
if (!currentAccountId || `${ownerId}` !== `${currentAccountId}`) {
|
|
239
|
+
// Not the owner, need to create a new group
|
|
240
|
+
log('User is not owner, will create new group');
|
|
241
|
+
finalIdentifier = undefined;
|
|
242
|
+
isNewGroup = true;
|
|
243
|
+
}
|
|
244
|
+
} catch (detailError) {
|
|
245
|
+
// Group not found or error, create new
|
|
246
|
+
log('Group not found or error, will create new: %O', detailError);
|
|
247
|
+
finalIdentifier = undefined;
|
|
248
|
+
isNewGroup = true;
|
|
249
|
+
}
|
|
250
|
+
} else {
|
|
251
|
+
isNewGroup = true;
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
// Step 2: Create new group or update existing
|
|
255
|
+
if (!finalIdentifier || isNewGroup) {
|
|
256
|
+
// Generate a unique 8-character identifier
|
|
257
|
+
finalIdentifier = generateMarketIdentifier();
|
|
258
|
+
isNewGroup = true;
|
|
259
|
+
|
|
260
|
+
log('Creating new group with identifier: %s', finalIdentifier);
|
|
261
|
+
|
|
262
|
+
await ctx.marketSDK.agentGroups.createAgentGroup({
|
|
263
|
+
...groupData,
|
|
264
|
+
identifier: finalIdentifier,
|
|
265
|
+
// @ts-ignore
|
|
266
|
+
memberAgents,
|
|
267
|
+
name,
|
|
268
|
+
});
|
|
269
|
+
} else {
|
|
270
|
+
// Update existing group - create new version
|
|
271
|
+
log('Creating new version for group: %s', finalIdentifier);
|
|
272
|
+
|
|
273
|
+
await ctx.marketSDK.agentGroups.createAgentGroupVersion({
|
|
274
|
+
...groupData,
|
|
275
|
+
identifier: finalIdentifier,
|
|
276
|
+
// @ts-ignore
|
|
277
|
+
memberAgents,
|
|
278
|
+
name,
|
|
279
|
+
});
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
return {
|
|
283
|
+
identifier: finalIdentifier,
|
|
284
|
+
isNewGroup,
|
|
285
|
+
success: true,
|
|
286
|
+
};
|
|
287
|
+
} catch (error) {
|
|
288
|
+
log('Error in publishOrCreate: %O', error);
|
|
289
|
+
throw new TRPCError({
|
|
290
|
+
cause: error,
|
|
291
|
+
code: 'INTERNAL_SERVER_ERROR',
|
|
292
|
+
message: error instanceof Error ? error.message : 'Failed to publish group',
|
|
293
|
+
});
|
|
294
|
+
}
|
|
295
|
+
}),
|
|
296
|
+
});
|