@lobehub/lobehub 2.0.0-next.335 → 2.0.0-next.336

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 (32) hide show
  1. package/CHANGELOG.md +33 -0
  2. package/changelog/v1.json +12 -0
  3. package/package.json +1 -1
  4. package/packages/builtin-tool-group-management/src/manifest.ts +54 -53
  5. package/packages/builtin-tool-group-management/src/systemRole.ts +43 -111
  6. package/packages/context-engine/src/engine/tools/ToolArgumentsRepairer.ts +129 -0
  7. package/packages/context-engine/src/engine/tools/__tests__/ToolArgumentsRepairer.test.ts +186 -0
  8. package/packages/context-engine/src/engine/tools/index.ts +3 -0
  9. package/packages/conversation-flow/src/__tests__/fixtures/inputs/tasks/index.ts +2 -0
  10. package/packages/conversation-flow/src/__tests__/fixtures/inputs/tasks/with-assistant-group.json +156 -0
  11. package/packages/conversation-flow/src/__tests__/parse.test.ts +22 -0
  12. package/packages/conversation-flow/src/transformation/FlatListBuilder.ts +88 -11
  13. package/packages/types/src/openai/chat.ts +0 -4
  14. package/src/app/[variants]/(main)/community/(detail)/user/features/DetailProvider.tsx +5 -1
  15. package/src/app/[variants]/(main)/community/(detail)/user/features/UserAgentCard.tsx +8 -8
  16. package/src/app/[variants]/(main)/community/(detail)/user/features/UserGroupCard.tsx +142 -15
  17. package/src/app/[variants]/(main)/community/(detail)/user/features/useUserDetail.ts +45 -20
  18. package/src/server/routers/lambda/market/agentGroup.ts +179 -1
  19. package/src/server/services/discover/index.ts +4 -0
  20. package/src/services/chat/chat.test.ts +109 -104
  21. package/src/services/chat/index.ts +13 -32
  22. package/src/services/chat/mecha/agentConfigResolver.test.ts +113 -0
  23. package/src/services/chat/mecha/agentConfigResolver.ts +15 -5
  24. package/src/services/marketApi.ts +14 -0
  25. package/src/store/chat/agents/__tests__/createAgentExecutors/helpers/testExecutor.ts +13 -0
  26. package/src/store/chat/agents/createAgentExecutors.ts +13 -1
  27. package/src/store/chat/slices/aiChat/actions/__tests__/conversationControl.test.ts +5 -1
  28. package/src/store/chat/slices/aiChat/actions/__tests__/fixtures.ts +14 -0
  29. package/src/store/chat/slices/aiChat/actions/__tests__/streamingExecutor.test.ts +131 -7
  30. package/src/store/chat/slices/aiChat/actions/streamingExecutor.ts +61 -62
  31. package/src/store/chat/slices/plugin/action.test.ts +71 -0
  32. package/src/store/chat/slices/plugin/actions/internals.ts +14 -5
@@ -1,8 +1,28 @@
1
1
  'use client';
2
2
 
3
- import { Avatar, Block, Flexbox, Icon, Tag, Text, Tooltip, TooltipGroup } from '@lobehub/ui';
4
- import { createStaticStyles } from 'antd-style';
5
- import { ClockIcon, DownloadIcon, UsersIcon } from 'lucide-react';
3
+ import {
4
+ Tag as AntTag,
5
+ Avatar,
6
+ Block,
7
+ DropdownMenu,
8
+ Flexbox,
9
+ Icon,
10
+ Tag,
11
+ Text,
12
+ Tooltip,
13
+ TooltipGroup,
14
+ } from '@lobehub/ui';
15
+ import { createStaticStyles, cx } from 'antd-style';
16
+ import {
17
+ AlertTriangle,
18
+ ClockIcon,
19
+ DownloadIcon,
20
+ Eye,
21
+ EyeOff,
22
+ MoreVerticalIcon,
23
+ Pencil,
24
+ UsersIcon,
25
+ } from 'lucide-react';
6
26
  import qs from 'query-string';
7
27
  import { memo, useCallback } from 'react';
8
28
  import { useTranslation } from 'react-i18next';
@@ -10,9 +30,31 @@ import { Link, useNavigate } from 'react-router-dom';
10
30
  import urlJoin from 'url-join';
11
31
 
12
32
  import PublishedTime from '@/components/PublishedTime';
13
- import { type DiscoverGroupAgentItem } from '@/types/discover';
33
+ import { type DiscoverGroupAgentItem, type GroupAgentStatus } from '@/types/discover';
14
34
  import { formatIntergerNumber } from '@/utils/format';
15
35
 
36
+ import { useUserDetailContext } from './DetailProvider';
37
+
38
+ const getStatusTagColor = (status?: GroupAgentStatus) => {
39
+ switch (status) {
40
+ case 'published': {
41
+ return 'green';
42
+ }
43
+ case 'unpublished': {
44
+ return 'orange';
45
+ }
46
+ case 'deprecated': {
47
+ return 'red';
48
+ }
49
+ case 'archived': {
50
+ return 'default';
51
+ }
52
+ default: {
53
+ return 'default';
54
+ }
55
+ }
56
+ };
57
+
16
58
  const styles = createStaticStyles(({ css, cssVar }) => {
17
59
  return {
18
60
  desc: css`
@@ -25,6 +67,16 @@ const styles = createStaticStyles(({ css, cssVar }) => {
25
67
  border-block-start: 1px dashed ${cssVar.colorBorder};
26
68
  background: ${cssVar.colorBgContainer};
27
69
  `,
70
+ moreButton: css`
71
+ position: absolute;
72
+ z-index: 10;
73
+ inset-block-start: 12px;
74
+ inset-inline-end: 12px;
75
+
76
+ opacity: 0;
77
+
78
+ transition: opacity 0.2s;
79
+ `,
28
80
  secondaryDesc: css`
29
81
  font-size: 12px;
30
82
  color: ${cssVar.colorTextDescription};
@@ -47,15 +99,31 @@ const styles = createStaticStyles(({ css, cssVar }) => {
47
99
  color: ${cssVar.colorLink};
48
100
  }
49
101
  `,
102
+ wrapper: css`
103
+ &:hover .more-button {
104
+ opacity: 1;
105
+ }
106
+ `,
50
107
  };
51
108
  });
52
109
 
53
110
  type UserGroupCardProps = DiscoverGroupAgentItem;
54
111
 
55
112
  const UserGroupCard = memo<UserGroupCardProps>(
56
- ({ avatar, title, description, createdAt, category, installCount, identifier, memberCount }) => {
57
- const { t } = useTranslation(['discover']);
113
+ ({
114
+ avatar,
115
+ title,
116
+ description,
117
+ createdAt,
118
+ category,
119
+ installCount,
120
+ identifier,
121
+ memberCount,
122
+ status,
123
+ }) => {
124
+ const { t } = useTranslation(['discover', 'setting']);
58
125
  const navigate = useNavigate();
126
+ const { isOwner, onStatusChange } = useUserDetailContext();
59
127
 
60
128
  const link = qs.stringifyUrl(
61
129
  {
@@ -65,12 +133,55 @@ const UserGroupCard = memo<UserGroupCardProps>(
65
133
  { skipNull: true },
66
134
  );
67
135
 
136
+ const isPublished = status === 'published';
137
+
68
138
  const handleCardClick = useCallback(() => {
69
139
  navigate(link);
70
140
  }, [link, navigate]);
71
141
 
142
+ const handleEdit = useCallback(() => {
143
+ navigate(urlJoin('/group', identifier, 'profile'));
144
+ }, [identifier, navigate]);
145
+
146
+ const handleStatusAction = useCallback(
147
+ (action: 'publish' | 'unpublish' | 'deprecate') => {
148
+ onStatusChange?.(identifier, action, 'group');
149
+ },
150
+ [identifier, onStatusChange],
151
+ );
152
+
153
+ const menuItems = isOwner
154
+ ? [
155
+ {
156
+ icon: <Icon icon={Pencil} />,
157
+ key: 'edit',
158
+ label: t('setting:myAgents.actions.edit'),
159
+ onClick: handleEdit,
160
+ },
161
+ {
162
+ type: 'divider' as const,
163
+ },
164
+ {
165
+ icon: <Icon icon={isPublished ? EyeOff : Eye} />,
166
+ key: 'togglePublish',
167
+ label: isPublished
168
+ ? t('setting:myAgents.actions.unpublish')
169
+ : t('setting:myAgents.actions.publish'),
170
+ onClick: () => handleStatusAction(isPublished ? 'unpublish' : 'publish'),
171
+ },
172
+ {
173
+ danger: true,
174
+ icon: <Icon icon={AlertTriangle} />,
175
+ key: 'deprecate',
176
+ label: t('setting:myAgents.actions.deprecate'),
177
+ onClick: () => handleStatusAction('deprecate'),
178
+ },
179
+ ]
180
+ : [];
181
+
72
182
  return (
73
183
  <Block
184
+ className={styles.wrapper}
74
185
  clickable
75
186
  height={'100%'}
76
187
  onClick={handleCardClick}
@@ -82,6 +193,15 @@ const UserGroupCard = memo<UserGroupCardProps>(
82
193
  variant={'outlined'}
83
194
  width={'100%'}
84
195
  >
196
+ {isOwner && (
197
+ <div onClick={(e) => e.stopPropagation()}>
198
+ <DropdownMenu items={menuItems as any}>
199
+ <div className={cx('more-button', styles.moreButton)}>
200
+ <Icon icon={MoreVerticalIcon} size={16} style={{ cursor: 'pointer' }} />
201
+ </div>
202
+ </DropdownMenu>
203
+ </div>
204
+ )}
85
205
  <Flexbox
86
206
  align={'flex-start'}
87
207
  gap={16}
@@ -105,15 +225,22 @@ const UserGroupCard = memo<UserGroupCardProps>(
105
225
  overflow: 'hidden',
106
226
  }}
107
227
  >
108
- <Link
109
- onClick={(e) => e.stopPropagation()}
110
- style={{ color: 'inherit', flex: 1, overflow: 'hidden' }}
111
- to={link}
112
- >
113
- <Text as={'h3'} className={styles.title} ellipsis style={{ flex: 1 }}>
114
- {title}
115
- </Text>
116
- </Link>
228
+ <Flexbox align={'center'} gap={8} horizontal>
229
+ <Link
230
+ onClick={(e) => e.stopPropagation()}
231
+ style={{ color: 'inherit', flex: 1, overflow: 'hidden' }}
232
+ to={link}
233
+ >
234
+ <Text as={'h3'} className={styles.title} ellipsis style={{ flex: 1 }}>
235
+ {title}
236
+ </Text>
237
+ </Link>
238
+ {isOwner && status && (
239
+ <AntTag color={getStatusTagColor(status)} style={{ flexShrink: 0, margin: 0 }}>
240
+ {t(`setting:myAgents.status.${status}`)}
241
+ </AntTag>
242
+ )}
243
+ </Flexbox>
117
244
  </Flexbox>
118
245
  </Flexbox>
119
246
  </Flexbox>
@@ -6,8 +6,10 @@ import { useTranslation } from 'react-i18next';
6
6
 
7
7
  import { useMarketAuth } from '@/layout/AuthProvider/MarketAuth';
8
8
  import { marketApiService } from '@/services/marketApi';
9
+ import { serverConfigSelectors, useServerConfigStore } from '@/store/serverConfig';
9
10
 
10
11
  export type AgentStatusAction = 'publish' | 'unpublish' | 'deprecate';
12
+ export type EntityType = 'agent' | 'group';
11
13
 
12
14
  interface UseUserDetailOptions {
13
15
  onMutate?: () => void;
@@ -17,43 +19,67 @@ export const useUserDetail = ({ onMutate }: UseUserDetailOptions = {}) => {
17
19
  const { t } = useTranslation('setting');
18
20
  const { message, modal } = App.useApp();
19
21
  const { session } = useMarketAuth();
22
+ const enableMarketTrustedClient = useServerConfigStore(
23
+ serverConfigSelectors.enableMarketTrustedClient,
24
+ );
20
25
 
21
26
  const handleStatusChange = useCallback(
22
- async (identifier: string, action: AgentStatusAction) => {
23
- if (!session?.accessToken) {
27
+ async (identifier: string, action: AgentStatusAction, type: EntityType = 'agent') => {
28
+ if (!enableMarketTrustedClient && !session?.accessToken) {
24
29
  message.error(t('myAgents.errors.notAuthenticated'));
25
30
  return;
26
31
  }
27
32
 
28
- const messageKey = `agent-status-${action}`;
33
+ const messageKey = `${type}-status-${action}`;
29
34
  const loadingText = t(`myAgents.actions.${action}Loading` as any);
30
35
  const successText = t(`myAgents.actions.${action}Success` as any);
31
36
  const errorText = t(`myAgents.actions.${action}Error` as any);
32
37
 
33
- async function executeStatusChange(identifier: string, action: AgentStatusAction) {
38
+ async function executeStatusChange(
39
+ identifier: string,
40
+ action: AgentStatusAction,
41
+ type: EntityType,
42
+ ) {
34
43
  try {
35
44
  message.loading({ content: loadingText, key: messageKey });
36
45
  marketApiService.setAccessToken(session!.accessToken);
37
46
 
38
- switch (action) {
39
- case 'publish': {
40
- await marketApiService.publishAgent(identifier);
41
- break;
42
- }
43
- case 'unpublish': {
44
- await marketApiService.unpublishAgent(identifier);
45
- break;
47
+ if (type === 'group') {
48
+ switch (action) {
49
+ case 'publish': {
50
+ await marketApiService.publishAgentGroup(identifier);
51
+ break;
52
+ }
53
+ case 'unpublish': {
54
+ await marketApiService.unpublishAgentGroup(identifier);
55
+ break;
56
+ }
57
+ case 'deprecate': {
58
+ await marketApiService.deprecateAgentGroup(identifier);
59
+ break;
60
+ }
46
61
  }
47
- case 'deprecate': {
48
- await marketApiService.deprecateAgent(identifier);
49
- break;
62
+ } else {
63
+ switch (action) {
64
+ case 'publish': {
65
+ await marketApiService.publishAgent(identifier);
66
+ break;
67
+ }
68
+ case 'unpublish': {
69
+ await marketApiService.unpublishAgent(identifier);
70
+ break;
71
+ }
72
+ case 'deprecate': {
73
+ await marketApiService.deprecateAgent(identifier);
74
+ break;
75
+ }
50
76
  }
51
77
  }
52
78
 
53
79
  message.success({ content: successText, key: messageKey });
54
80
  onMutate?.();
55
81
  } catch (error) {
56
- console.error(`[useUserDetail] ${action} agent error:`, error);
82
+ console.error(`[useUserDetail] ${action} ${type} error:`, error);
57
83
  message.error({
58
84
  content: `${errorText}: ${error instanceof Error ? error.message : 'Unknown error'}`,
59
85
  key: messageKey,
@@ -61,7 +87,6 @@ export const useUserDetail = ({ onMutate }: UseUserDetailOptions = {}) => {
61
87
  }
62
88
  }
63
89
 
64
- // For deprecate action, show confirmation dialog first
65
90
  if (action === 'deprecate') {
66
91
  modal.confirm({
67
92
  cancelText: t('myAgents.actions.cancel'),
@@ -69,16 +94,16 @@ export const useUserDetail = ({ onMutate }: UseUserDetailOptions = {}) => {
69
94
  okButtonProps: { danger: true },
70
95
  okText: t('myAgents.actions.confirmDeprecate'),
71
96
  onOk: async () => {
72
- await executeStatusChange(identifier, action);
97
+ await executeStatusChange(identifier, action, type);
73
98
  },
74
99
  title: t('myAgents.actions.deprecateConfirmTitle'),
75
100
  });
76
101
  return;
77
102
  }
78
103
 
79
- await executeStatusChange(identifier, action);
104
+ await executeStatusChange(identifier, action, type);
80
105
  },
81
- [session?.accessToken, message, modal, t, onMutate],
106
+ [enableMarketTrustedClient, session?.accessToken, message, modal, t, onMutate],
82
107
  );
83
108
 
84
109
  return {
@@ -202,6 +202,66 @@ export const agentGroupRouter = router({
202
202
 
203
203
 
204
204
  /**
205
+ * Deprecate agent group
206
+ * POST /market/agent-group/:identifier/deprecate
207
+ */
208
+ deprecateAgentGroup: agentGroupProcedure
209
+ .input(z.object({ identifier: z.string() }))
210
+ .mutation(async ({ input, ctx }) => {
211
+ log('deprecateAgentGroup input: %O', input);
212
+
213
+ try {
214
+ const deprecateUrl = `${MARKET_BASE_URL}/api/v1/agent-groups/${input.identifier}/deprecate`;
215
+
216
+ const headers: Record<string, string> = {
217
+ 'Content-Type': 'application/json',
218
+ };
219
+
220
+ const userInfo = ctx.marketUserInfo as TrustedClientUserInfo | undefined;
221
+ const accessToken = (ctx as { marketOidcAccessToken?: string }).marketOidcAccessToken;
222
+
223
+ if (userInfo) {
224
+ const trustedClientToken = generateTrustedClientToken(userInfo);
225
+ if (trustedClientToken) {
226
+ headers['x-lobe-trust-token'] = trustedClientToken;
227
+ }
228
+ }
229
+
230
+ if (!headers['x-lobe-trust-token'] && accessToken) {
231
+ headers['Authorization'] = `Bearer ${accessToken}`;
232
+ }
233
+
234
+ const response = await fetch(deprecateUrl, {
235
+ headers,
236
+ method: 'POST',
237
+ });
238
+
239
+ if (!response.ok) {
240
+ const errorText = await response.text();
241
+ log(
242
+ 'Deprecate agent group failed: %s %s - %s',
243
+ response.status,
244
+ response.statusText,
245
+ errorText,
246
+ );
247
+ throw new Error(`Failed to deprecate agent group: ${response.statusText}`);
248
+ }
249
+
250
+ log('Deprecate agent group success');
251
+ return { success: true };
252
+ } catch (error) {
253
+ log('Error deprecating agent group: %O', error);
254
+ throw new TRPCError({
255
+ cause: error,
256
+ code: 'INTERNAL_SERVER_ERROR',
257
+ message: error instanceof Error ? error.message : 'Failed to deprecate agent group',
258
+ });
259
+ }
260
+ }),
261
+
262
+
263
+
264
+ /**
205
265
  * Fork an agent group
206
266
  * POST /market/agent-group/:identifier/fork
207
267
  */
@@ -340,7 +400,6 @@ getAgentGroupForkSource: agentGroupProcedure
340
400
 
341
401
 
342
402
 
343
-
344
403
  /**
345
404
  * Get all forks of an agent group
346
405
  * GET /market/agent-group/:identifier/forks
@@ -401,6 +460,66 @@ getAgentGroupForks: agentGroupProcedure
401
460
 
402
461
 
403
462
 
463
+ /**
464
+ * Publish agent group
465
+ * POST /market/agent-group/:identifier/publish
466
+ */
467
+ publishAgentGroup: agentGroupProcedure
468
+ .input(z.object({ identifier: z.string() }))
469
+ .mutation(async ({ input, ctx }) => {
470
+ log('publishAgentGroup input: %O', input);
471
+
472
+ try {
473
+ const publishUrl = `${MARKET_BASE_URL}/api/v1/agent-groups/${input.identifier}/publish`;
474
+
475
+ const headers: Record<string, string> = {
476
+ 'Content-Type': 'application/json',
477
+ };
478
+
479
+ const userInfo = ctx.marketUserInfo as TrustedClientUserInfo | undefined;
480
+ const accessToken = (ctx as { marketOidcAccessToken?: string }).marketOidcAccessToken;
481
+
482
+ if (userInfo) {
483
+ const trustedClientToken = generateTrustedClientToken(userInfo);
484
+ if (trustedClientToken) {
485
+ headers['x-lobe-trust-token'] = trustedClientToken;
486
+ }
487
+ }
488
+
489
+ if (!headers['x-lobe-trust-token'] && accessToken) {
490
+ headers['Authorization'] = `Bearer ${accessToken}`;
491
+ }
492
+
493
+ const response = await fetch(publishUrl, {
494
+ headers,
495
+ method: 'POST',
496
+ });
497
+
498
+ if (!response.ok) {
499
+ const errorText = await response.text();
500
+ log(
501
+ 'Publish agent group failed: %s %s - %s',
502
+ response.status,
503
+ response.statusText,
504
+ errorText,
505
+ );
506
+ throw new Error(`Failed to publish agent group: ${response.statusText}`);
507
+ }
508
+
509
+ log('Publish agent group success');
510
+ return { success: true };
511
+ } catch (error) {
512
+ log('Error publishing agent group: %O', error);
513
+ throw new TRPCError({
514
+ cause: error,
515
+ code: 'INTERNAL_SERVER_ERROR',
516
+ message: error instanceof Error ? error.message : 'Failed to publish agent group',
517
+ });
518
+ }
519
+ }),
520
+
521
+
522
+
404
523
  /**
405
524
  * Unified publish or create agent group flow
406
525
  * 1. Check if identifier exists and if current user is owner
@@ -494,6 +613,65 @@ publishOrCreate: agentGroupProcedure
494
613
  });
495
614
  }
496
615
  }),
616
+
617
+
618
+ /**
619
+ * Unpublish agent group
620
+ * POST /market/agent-group/:identifier/unpublish
621
+ */
622
+ unpublishAgentGroup: agentGroupProcedure
623
+ .input(z.object({ identifier: z.string() }))
624
+ .mutation(async ({ input, ctx }) => {
625
+ log('unpublishAgentGroup input: %O', input);
626
+
627
+ try {
628
+ const unpublishUrl = `${MARKET_BASE_URL}/api/v1/agent-groups/${input.identifier}/unpublish`;
629
+
630
+ const headers: Record<string, string> = {
631
+ 'Content-Type': 'application/json',
632
+ };
633
+
634
+ const userInfo = ctx.marketUserInfo as TrustedClientUserInfo | undefined;
635
+ const accessToken = (ctx as { marketOidcAccessToken?: string }).marketOidcAccessToken;
636
+
637
+ if (userInfo) {
638
+ const trustedClientToken = generateTrustedClientToken(userInfo);
639
+ if (trustedClientToken) {
640
+ headers['x-lobe-trust-token'] = trustedClientToken;
641
+ }
642
+ }
643
+
644
+ if (!headers['x-lobe-trust-token'] && accessToken) {
645
+ headers['Authorization'] = `Bearer ${accessToken}`;
646
+ }
647
+
648
+ const response = await fetch(unpublishUrl, {
649
+ headers,
650
+ method: 'POST',
651
+ });
652
+
653
+ if (!response.ok) {
654
+ const errorText = await response.text();
655
+ log(
656
+ 'Unpublish agent group failed: %s %s - %s',
657
+ response.status,
658
+ response.statusText,
659
+ errorText,
660
+ );
661
+ throw new Error(`Failed to unpublish agent group: ${response.statusText}`);
662
+ }
663
+
664
+ log('Unpublish agent group success');
665
+ return { success: true };
666
+ } catch (error) {
667
+ log('Error unpublishing agent group: %O', error);
668
+ throw new TRPCError({
669
+ cause: error,
670
+ code: 'INTERNAL_SERVER_ERROR',
671
+ message: error instanceof Error ? error.message : 'Failed to unpublish agent group',
672
+ });
673
+ }
674
+ }),
497
675
  });
498
676
 
499
677
  export type AgentGroupRouter = typeof agentGroupRouter;
@@ -1761,6 +1761,7 @@ export class DiscoverService {
1761
1761
  knowledgeCount: agent.knowledgeCount || 0,
1762
1762
  pluginCount: agent.pluginCount || 0,
1763
1763
  schemaVersion: 1,
1764
+ status: agent.status,
1764
1765
  tags: agent.tags || [],
1765
1766
  title: agent.name || agent.identifier,
1766
1767
  tokenUsage: agent.tokenUsage || 0,
@@ -1780,6 +1781,7 @@ export class DiscoverService {
1780
1781
  isOfficial: group.isOfficial || false,
1781
1782
  memberCount: 0, // Will be populated from memberAgents in detail view
1782
1783
  schemaVersion: 1,
1784
+ status: group.status,
1783
1785
  tags: group.tags || [],
1784
1786
  title: group.name || group.identifier,
1785
1787
  updatedAt: group.updatedAt,
@@ -1802,6 +1804,7 @@ export class DiscoverService {
1802
1804
  knowledgeCount: agent.knowledgeCount || 0,
1803
1805
  pluginCount: agent.pluginCount || 0,
1804
1806
  schemaVersion: 1,
1807
+ status: agent.status,
1805
1808
  tags: agent.tags || [],
1806
1809
  title: agent.name || agent.identifier,
1807
1810
  tokenUsage: agent.tokenUsage || 0,
@@ -1824,6 +1827,7 @@ export class DiscoverService {
1824
1827
  isOfficial: group.isOfficial || false,
1825
1828
  memberCount: 0, // Will be populated from memberAgents in detail view
1826
1829
  schemaVersion: 1,
1830
+ status: group.status,
1827
1831
  tags: group.tags || [],
1828
1832
  title: group.name || group.identifier,
1829
1833
  updatedAt: group.updatedAt,