@lobehub/lobehub 2.0.0-next.201 → 2.0.0-next.202

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 (129) hide show
  1. package/CHANGELOG.md +25 -0
  2. package/changelog/v1.json +9 -0
  3. package/locales/ar/chat.json +2 -0
  4. package/locales/ar/models.json +64 -7
  5. package/locales/ar/plugin.json +2 -1
  6. package/locales/ar/providers.json +1 -0
  7. package/locales/bg-BG/chat.json +2 -0
  8. package/locales/bg-BG/models.json +49 -5
  9. package/locales/bg-BG/plugin.json +2 -1
  10. package/locales/bg-BG/providers.json +1 -0
  11. package/locales/de-DE/chat.json +2 -0
  12. package/locales/de-DE/models.json +36 -7
  13. package/locales/de-DE/plugin.json +2 -1
  14. package/locales/de-DE/providers.json +1 -0
  15. package/locales/en-US/chat.json +2 -0
  16. package/locales/en-US/models.json +10 -10
  17. package/locales/en-US/plugin.json +2 -1
  18. package/locales/en-US/providers.json +1 -0
  19. package/locales/es-ES/chat.json +2 -0
  20. package/locales/es-ES/models.json +106 -7
  21. package/locales/es-ES/plugin.json +2 -1
  22. package/locales/es-ES/providers.json +1 -0
  23. package/locales/fa-IR/chat.json +2 -0
  24. package/locales/fa-IR/models.json +83 -5
  25. package/locales/fa-IR/plugin.json +2 -1
  26. package/locales/fa-IR/providers.json +1 -0
  27. package/locales/fr-FR/chat.json +2 -0
  28. package/locales/fr-FR/models.json +38 -7
  29. package/locales/fr-FR/plugin.json +2 -1
  30. package/locales/fr-FR/providers.json +1 -0
  31. package/locales/it-IT/chat.json +2 -0
  32. package/locales/it-IT/models.json +40 -5
  33. package/locales/it-IT/plugin.json +2 -1
  34. package/locales/it-IT/providers.json +1 -0
  35. package/locales/ja-JP/chat.json +2 -0
  36. package/locales/ja-JP/models.json +84 -7
  37. package/locales/ja-JP/plugin.json +2 -1
  38. package/locales/ja-JP/providers.json +1 -0
  39. package/locales/ko-KR/chat.json +2 -0
  40. package/locales/ko-KR/models.json +65 -7
  41. package/locales/ko-KR/plugin.json +2 -1
  42. package/locales/ko-KR/providers.json +1 -0
  43. package/locales/nl-NL/chat.json +2 -0
  44. package/locales/nl-NL/models.json +62 -5
  45. package/locales/nl-NL/plugin.json +2 -1
  46. package/locales/nl-NL/providers.json +1 -0
  47. package/locales/pl-PL/chat.json +2 -0
  48. package/locales/pl-PL/models.json +85 -0
  49. package/locales/pl-PL/plugin.json +2 -1
  50. package/locales/pl-PL/providers.json +1 -0
  51. package/locales/pt-BR/chat.json +2 -0
  52. package/locales/pt-BR/models.json +37 -6
  53. package/locales/pt-BR/plugin.json +2 -1
  54. package/locales/pt-BR/providers.json +1 -0
  55. package/locales/ru-RU/chat.json +2 -0
  56. package/locales/ru-RU/models.json +36 -7
  57. package/locales/ru-RU/plugin.json +2 -1
  58. package/locales/ru-RU/providers.json +1 -0
  59. package/locales/tr-TR/chat.json +2 -0
  60. package/locales/tr-TR/models.json +28 -7
  61. package/locales/tr-TR/plugin.json +2 -1
  62. package/locales/tr-TR/providers.json +1 -0
  63. package/locales/vi-VN/chat.json +2 -0
  64. package/locales/vi-VN/models.json +62 -5
  65. package/locales/vi-VN/plugin.json +2 -1
  66. package/locales/vi-VN/providers.json +1 -0
  67. package/locales/zh-CN/chat.json +2 -0
  68. package/locales/zh-CN/models.json +87 -6
  69. package/locales/zh-CN/plugin.json +2 -1
  70. package/locales/zh-CN/providers.json +1 -0
  71. package/locales/zh-TW/chat.json +2 -0
  72. package/locales/zh-TW/models.json +71 -7
  73. package/locales/zh-TW/plugin.json +2 -1
  74. package/locales/zh-TW/providers.json +1 -0
  75. package/package.json +1 -1
  76. package/packages/builtin-tool-gtd/src/client/Inspector/ExecTask/index.tsx +30 -15
  77. package/packages/builtin-tool-gtd/src/manifest.ts +1 -1
  78. package/packages/model-runtime/src/core/ModelRuntime.test.ts +44 -86
  79. package/packages/types/src/aiChat.ts +0 -1
  80. package/packages/types/src/message/ui/chat.ts +1 -1
  81. package/src/app/(backend)/middleware/auth/index.ts +16 -2
  82. package/src/app/(backend)/webapi/chat/[provider]/route.test.ts +30 -15
  83. package/src/app/(backend)/webapi/chat/[provider]/route.ts +44 -40
  84. package/src/app/(backend)/webapi/models/[provider]/pull/route.ts +4 -3
  85. package/src/app/(backend)/webapi/models/[provider]/route.test.ts +36 -13
  86. package/src/app/(backend)/webapi/models/[provider]/route.ts +4 -11
  87. package/src/features/Conversation/Messages/AssistantGroup/Tool/Render/index.tsx +21 -23
  88. package/src/features/Conversation/Messages/AssistantGroup/components/ContentBlock.tsx +16 -3
  89. package/src/features/Conversation/Messages/Task/TaskDetailPanel/index.tsx +17 -20
  90. package/src/features/Conversation/Messages/Tasks/shared/ErrorState.tsx +16 -11
  91. package/src/features/Conversation/Messages/Tasks/shared/InitializingState.tsx +6 -20
  92. package/src/features/Conversation/Messages/Tasks/shared/ProcessingState.tsx +10 -20
  93. package/src/features/User/DataStatistics.tsx +4 -4
  94. package/src/hooks/useQueryParam.ts +0 -2
  95. package/src/libs/trpc/async/asyncAuth.ts +0 -2
  96. package/src/libs/trpc/async/context.ts +3 -11
  97. package/src/locales/default/chat.ts +2 -0
  98. package/src/locales/default/plugin.ts +2 -1
  99. package/src/server/modules/AgentRuntime/RuntimeExecutors.ts +6 -6
  100. package/src/server/modules/AgentRuntime/__tests__/RuntimeExecutors.test.ts +3 -3
  101. package/src/server/modules/AgentRuntime/factory.ts +39 -20
  102. package/src/server/modules/ModelRuntime/index.ts +138 -1
  103. package/src/server/routers/async/__tests__/caller.test.ts +22 -27
  104. package/src/server/routers/async/caller.ts +4 -6
  105. package/src/server/routers/async/file.ts +10 -5
  106. package/src/server/routers/async/image.ts +5 -4
  107. package/src/server/routers/async/ragEval.ts +7 -5
  108. package/src/server/routers/lambda/__tests__/aiChat.test.ts +8 -37
  109. package/src/server/routers/lambda/aiChat.ts +5 -21
  110. package/src/server/routers/lambda/chunk.ts +9 -28
  111. package/src/server/routers/lambda/image.ts +1 -7
  112. package/src/server/routers/lambda/ragEval.ts +1 -1
  113. package/src/server/routers/lambda/userMemories/reembed.ts +4 -1
  114. package/src/server/routers/lambda/userMemories/search.ts +7 -7
  115. package/src/server/routers/lambda/userMemories/shared.ts +8 -10
  116. package/src/server/routers/lambda/userMemories/tools.ts +140 -118
  117. package/src/server/routers/lambda/userMemories.test.ts +3 -7
  118. package/src/server/routers/lambda/userMemories.ts +44 -29
  119. package/src/server/services/agentRuntime/AgentRuntimeService.test.ts +87 -0
  120. package/src/server/services/agentRuntime/AgentRuntimeService.ts +53 -2
  121. package/src/server/services/agentRuntime/__tests__/executeSync.test.ts +2 -6
  122. package/src/server/services/agentRuntime/__tests__/stepLifecycleCallbacks.test.ts +1 -1
  123. package/src/server/services/chunk/index.ts +6 -5
  124. package/src/server/services/toolExecution/types.ts +1 -2
  125. package/src/services/__tests__/_url.test.ts +0 -1
  126. package/src/services/_url.ts +0 -3
  127. package/src/services/aiChat.ts +5 -12
  128. package/src/store/chat/slices/aiChat/actions/streamingExecutor.ts +0 -2
  129. package/src/app/(backend)/webapi/text-to-image/[provider]/route.ts +0 -74
@@ -53,8 +53,28 @@ const Render = memo<RenderProps>(
53
53
  toolMessageId,
54
54
  isArgumentsStreaming,
55
55
  }) => {
56
+ if (toolMessageId && intervention?.status === 'pending') {
57
+ return (
58
+ <Intervention
59
+ apiName={apiName}
60
+ id={toolMessageId}
61
+ identifier={identifier}
62
+ requestArgs={requestArgs || ''}
63
+ toolCallId={toolCallId}
64
+ />
65
+ );
66
+ }
67
+
68
+ if (intervention?.status === 'rejected') {
69
+ return <RejectedResponse reason={intervention.rejectedReason} />;
70
+ }
71
+
72
+ if (intervention?.status === 'aborted') {
73
+ return <AbortResponse />;
74
+ }
75
+
56
76
  // Handle arguments streaming state
57
- if (isArgumentsStreaming) {
77
+ if (isArgumentsStreaming || !result) {
58
78
  // Check if there's a custom streaming renderer for this tool
59
79
  const StreamingRenderer = getBuiltinStreaming(identifier, apiName);
60
80
 
@@ -76,28 +96,6 @@ const Render = memo<RenderProps>(
76
96
  return null;
77
97
  }
78
98
 
79
- if (toolMessageId && intervention?.status === 'pending') {
80
- return (
81
- <Intervention
82
- apiName={apiName}
83
- id={toolMessageId}
84
- identifier={identifier}
85
- requestArgs={requestArgs || ''}
86
- toolCallId={toolCallId}
87
- />
88
- );
89
- }
90
-
91
- if (intervention?.status === 'rejected') {
92
- return <RejectedResponse reason={intervention.rejectedReason} />;
93
- }
94
-
95
- if (intervention?.status === 'aborted') {
96
- return <AbortResponse />;
97
- }
98
-
99
- if (!result) return null;
100
-
101
99
  // Handle error state
102
100
  if (result.error) {
103
101
  return (
@@ -1,4 +1,4 @@
1
- import { Flexbox } from '@lobehub/ui';
1
+ import { Flexbox, Highlighter } from '@lobehub/ui';
2
2
  import { memo, useCallback } from 'react';
3
3
 
4
4
  import { LOADING_FLAT } from '@/const/message';
@@ -33,18 +33,31 @@ const ContentBlock = memo<ContentBlockProps>(
33
33
  continueGeneration(assistantId);
34
34
  }, [id]);
35
35
 
36
- if (error && (content === LOADING_FLAT || !content))
36
+ if (error && (content === LOADING_FLAT || !content)) {
37
37
  return (
38
38
  <ErrorContent
39
39
  error={
40
40
  errorContent && error && (content === LOADING_FLAT || !content)
41
- ? errorContent
41
+ ? {
42
+ ...errorContent,
43
+ extra: error?.body && (
44
+ <Highlighter
45
+ actionIconSize={'small'}
46
+ language={'json'}
47
+ padding={8}
48
+ variant={'borderless'}
49
+ >
50
+ {JSON.stringify(error?.body, null, 2)}
51
+ </Highlighter>
52
+ ),
53
+ }
42
54
  : undefined
43
55
  }
44
56
  id={id}
45
57
  onRegenerate={handleRegenerate}
46
58
  />
47
59
  );
60
+ }
48
61
 
49
62
  return (
50
63
  <Flexbox gap={8} id={id}>
@@ -1,6 +1,5 @@
1
1
  'use client';
2
2
 
3
- import { Block, Text } from '@lobehub/ui';
4
3
  import { memo } from 'react';
5
4
 
6
5
  import { type TaskDetail } from '@/types/index';
@@ -17,25 +16,23 @@ interface TaskDetailPanelProps {
17
16
  taskDetail?: TaskDetail;
18
17
  }
19
18
 
20
- const TaskDetailPanel = memo<TaskDetailPanelProps>(
21
- ({ taskDetail, instruction, content, messageId }) => {
22
- return (
23
- <>
24
- {/* Instruction Header */}
25
- {instruction && (
26
- <Block padding={12}>
27
- <Text fontSize={13} type={'secondary'}>
28
- {instruction}
29
- </Text>
30
- </Block>
31
- )}
32
-
33
- {/* Status Content */}
34
- <StatusContent content={content} messageId={messageId} taskDetail={taskDetail} />
35
- </>
36
- );
37
- },
38
- );
19
+ const TaskDetailPanel = memo<TaskDetailPanelProps>(({ taskDetail, content, messageId }) => {
20
+ return (
21
+ <>
22
+ {/* Instruction Header */}
23
+ {/*{instruction && (*/}
24
+ {/* <Block padding={12}>*/}
25
+ {/* <Text fontSize={13} type={'secondary'}>*/}
26
+ {/* {instruction}*/}
27
+ {/* </Text>*/}
28
+ {/* </Block>*/}
29
+ {/*)}*/}
30
+
31
+ {/* Status Content */}
32
+ <StatusContent content={content} messageId={messageId} taskDetail={taskDetail} />
33
+ </>
34
+ );
35
+ });
39
36
 
40
37
  TaskDetailPanel.displayName = 'TaskDetailPanel';
41
38
 
@@ -1,6 +1,6 @@
1
1
  'use client';
2
2
 
3
- import { Alert, Flexbox } from '@lobehub/ui';
3
+ import { Alert, Flexbox, Highlighter } from '@lobehub/ui';
4
4
  import { createStaticStyles } from 'antd-style';
5
5
  import { MessageSquare, Timer, Wrench } from 'lucide-react';
6
6
  import { memo, useMemo } from 'react';
@@ -49,23 +49,28 @@ const ErrorState = memo<ErrorStateProps>(({ taskDetail }) => {
49
49
  const formattedDuration = useMemo(() => formatDuration(duration), [duration]);
50
50
  const formattedCost = useMemo(() => formatCost(totalCost), [totalCost]);
51
51
 
52
- const hasMetrics = formattedDuration || totalToolCalls || totalMessages || formattedCost;
52
+ const hasMetrics = !!(formattedDuration || totalToolCalls || totalMessages || formattedCost);
53
53
 
54
54
  return (
55
55
  <Flexbox gap={12}>
56
56
  {/* Error Content */}
57
57
  <Alert
58
- description={error}
59
- title={
60
- isCancelled
61
- ? t('task.status.cancelled', { defaultValue: 'Cancelled' })
62
- : t('task.status.failed', { defaultValue: 'Failed' })
58
+ extra={
59
+ error?.error?.body && (
60
+ <Highlighter
61
+ actionIconSize={'small'}
62
+ language={'json'}
63
+ padding={8}
64
+ variant={'borderless'}
65
+ >
66
+ {JSON.stringify(error?.error?.body, null, 2)}
67
+ </Highlighter>
68
+ )
63
69
  }
70
+ title={isCancelled ? t('task.status.cancelled') : t('task.status.failed')}
64
71
  type={'secondary'}
65
72
  />
66
-
67
- {/* Footer with metrics */}
68
- {hasMetrics && (
73
+ {hasMetrics ? (
69
74
  <Flexbox align="center" gap={12} horizontal wrap="wrap">
70
75
  {/* Duration */}
71
76
  {formattedDuration && <MetricItem icon={Timer} value={formattedDuration} />}
@@ -102,7 +107,7 @@ const ErrorState = memo<ErrorStateProps>(({ taskDetail }) => {
102
107
  </>
103
108
  )}
104
109
  </Flexbox>
105
- )}
110
+ ) : null}
106
111
  </Flexbox>
107
112
  );
108
113
  });
@@ -2,10 +2,12 @@
2
2
 
3
3
  import { Flexbox, Text } from '@lobehub/ui';
4
4
  import { createStaticStyles, keyframes } from 'antd-style';
5
- import { Loader2 } from 'lucide-react';
6
5
  import { memo } from 'react';
7
6
  import { useTranslation } from 'react-i18next';
8
7
 
8
+ import NeuralNetworkLoading from '@/components/NeuralNetworkLoading';
9
+ import { shinyTextStyles } from '@/styles';
10
+
9
11
  const shimmer = keyframes`
10
12
  0% {
11
13
  transform: translateX(-100%);
@@ -16,20 +18,9 @@ const shimmer = keyframes`
16
18
  }
17
19
  `;
18
20
 
19
- const spin = keyframes`
20
- from {
21
- transform: rotate(0deg);
22
- }
23
-
24
- to {
25
- transform: rotate(360deg);
26
- }
27
- `;
28
-
29
21
  const styles = createStaticStyles(({ css, cssVar }) => ({
30
22
  container: css`
31
23
  padding-block: 12px;
32
- padding-inline: 16px;
33
24
  `,
34
25
  progress: css`
35
26
  position: relative;
@@ -53,9 +44,6 @@ const styles = createStaticStyles(({ css, cssVar }) => ({
53
44
 
54
45
  animation: ${shimmer} 2s infinite;
55
46
  `,
56
- spin: css`
57
- animation: ${spin} 1s linear infinite;
58
- `,
59
47
  }));
60
48
 
61
49
  const InitializingState = memo(() => {
@@ -63,15 +51,13 @@ const InitializingState = memo(() => {
63
51
 
64
52
  return (
65
53
  <Flexbox className={styles.container} gap={12}>
66
- {/* Status Row */}
67
54
  <Flexbox align="center" gap={8} horizontal>
68
- <Loader2 className={styles.spin} size={14} />
69
- <Text fontSize={13} type={'secondary'} weight={500}>
70
- {t('task.status.initializing', { defaultValue: 'Starting task...' })}
55
+ <NeuralNetworkLoading size={14} />
56
+ <Text className={shinyTextStyles.shinyText} weight={500}>
57
+ {t('task.status.initializing')}
71
58
  </Text>
72
59
  </Flexbox>
73
60
 
74
- {/* Progress Bar (indeterminate) */}
75
61
  <div className={styles.progress}>
76
62
  <div className={styles.progressShimmer} />
77
63
  </div>
@@ -3,10 +3,11 @@
3
3
  import { type TaskDetail } from '@lobechat/types';
4
4
  import { Flexbox, Text } from '@lobehub/ui';
5
5
  import { createStaticStyles, keyframes } from 'antd-style';
6
- import { Footprints, Loader2, Timer, Wrench } from 'lucide-react';
6
+ import { Footprints, Timer, Wrench } from 'lucide-react';
7
7
  import { memo, useEffect, useState } from 'react';
8
8
  import { useTranslation } from 'react-i18next';
9
9
 
10
+ import NeuralNetworkLoading from '@/components/NeuralNetworkLoading';
10
11
  import { useChatStore } from '@/store/chat';
11
12
 
12
13
  import { MAX_PROGRESS, PROGRESS_INCREMENT, PROGRESS_INTERVAL } from './constants';
@@ -22,16 +23,6 @@ const shimmer = keyframes`
22
23
  }
23
24
  `;
24
25
 
25
- const spin = keyframes`
26
- from {
27
- transform: rotate(0deg);
28
- }
29
-
30
- to {
31
- transform: rotate(360deg);
32
- }
33
- `;
34
-
35
26
  const styles = createStaticStyles(({ css, cssVar }) => ({
36
27
  activityRow: css`
37
28
  display: flex;
@@ -52,7 +43,7 @@ const styles = createStaticStyles(({ css, cssVar }) => ({
52
43
 
53
44
  height: 3px;
54
45
  margin-block: 12px;
55
- margin-inline: 16px;
46
+ margin-inline: 8px;
56
47
  border-radius: 2px;
57
48
 
58
49
  background: ${cssVar.colorFillSecondary};
@@ -97,9 +88,6 @@ const styles = createStaticStyles(({ css, cssVar }) => ({
97
88
  border-radius: 50%;
98
89
  background: ${cssVar.colorTextQuaternary};
99
90
  `,
100
- spin: css`
101
- animation: ${spin} 1s linear infinite;
102
- `,
103
91
  }));
104
92
 
105
93
  export type ProcessingStateVariant = 'detail' | 'compact';
@@ -215,10 +203,12 @@ const ProcessingState = memo<ProcessingStateProps>(
215
203
  {/* Current Activity */}
216
204
  {currentActivity && (
217
205
  <div className={styles.activityRow}>
218
- <Text as={'span'} fontSize={12} type={'secondary'}>
219
- <Loader2 className={styles.spin} size={12} />
220
- <span>{renderActivityText()}</span>
221
- </Text>
206
+ <Flexbox align={'center'} gap={4} horizontal>
207
+ <NeuralNetworkLoading size={14} />
208
+ <Text as={'span'} fontSize={12} type={'secondary'}>
209
+ {renderActivityText()}
210
+ </Text>
211
+ </Flexbox>
222
212
  {currentActivity.contentPreview && (
223
213
  <Text
224
214
  as={'span'}
@@ -297,7 +287,7 @@ const ProcessingState = memo<ProcessingStateProps>(
297
287
  {/* Current Activity */}
298
288
  {currentActivity && (
299
289
  <Flexbox align="center" gap={8} horizontal>
300
- <Loader2 className={styles.spin} size={12} />
290
+ <NeuralNetworkLoading size={14} />
301
291
  <Text
302
292
  as={'span'}
303
293
  ellipsis
@@ -1,13 +1,13 @@
1
1
  'use client';
2
2
 
3
- import { Flexbox, type FlexboxProps, Icon, Tooltip } from '@lobehub/ui';
3
+ import { Flexbox, type FlexboxProps, Tooltip } from '@lobehub/ui';
4
4
  import { Badge } from 'antd';
5
5
  import { createStaticStyles, cssVar } from 'antd-style';
6
6
  import { isUndefined } from 'es-toolkit/compat';
7
- import { LoaderCircle } from 'lucide-react';
8
- import { memo, useMemo } from 'react';
7
+ import { memo } from 'react';
9
8
  import { useTranslation } from 'react-i18next';
10
9
 
10
+ import NeuralNetworkLoading from '@/components/NeuralNetworkLoading';
11
11
  import { useClientDataSWR } from '@/libs/swr';
12
12
  import { messageService } from '@/services/message';
13
13
  import { sessionService } from '@/services/session';
@@ -65,7 +65,7 @@ const DataStatistics = memo<Omit<FlexboxProps, 'children'>>(({ style, ...rest })
65
65
 
66
66
  const { t } = useTranslation('common');
67
67
 
68
- const loading = useMemo(() => <Icon icon={LoaderCircle} spin />, []);
68
+ const loading = <NeuralNetworkLoading size={20} />;
69
69
 
70
70
  const items = [
71
71
  {
@@ -103,8 +103,6 @@ export function useQueryParam<T>(
103
103
  newSearchParams.set(key, serialized);
104
104
  }
105
105
 
106
- console.log('updateParams', newSearchParams.toString());
107
-
108
106
  return newSearchParams;
109
107
  },
110
108
  { replace: currentHistory === 'replace' },
@@ -43,11 +43,9 @@ export const asyncAuth = asyncTrpc.middleware(async (opts) => {
43
43
  }
44
44
 
45
45
  log('User authentication successful: %s', ctx.userId);
46
- log('Passing jwtPayload keys: %O', Object.keys(ctx.jwtPayload || {}));
47
46
 
48
47
  return opts.next({
49
48
  ctx: {
50
- jwtPayload: ctx.jwtPayload,
51
49
  userId: ctx.userId,
52
50
  },
53
51
  });
@@ -1,5 +1,4 @@
1
1
  import { type LobeChatDatabase } from '@lobechat/database';
2
- import { type ClientSecretPayload } from '@lobechat/types';
3
2
  import debug from 'debug';
4
3
  import { type NextRequest } from 'next/server';
5
4
 
@@ -10,7 +9,6 @@ const log = debug('lobe-async:context');
10
9
 
11
10
  export interface AsyncAuthContext {
12
11
  authorizationToken?: string;
13
- jwtPayload: ClientSecretPayload;
14
12
  serverDB?: LobeChatDatabase;
15
13
  userId?: string | null;
16
14
  }
@@ -21,11 +19,9 @@ export interface AsyncAuthContext {
21
19
  */
22
20
  export const createAsyncContextInner = async (params?: {
23
21
  authorizationToken?: string;
24
- jwtPayload?: ClientSecretPayload;
25
22
  userId?: string | null;
26
23
  }): Promise<AsyncAuthContext> => ({
27
24
  authorizationToken: params?.authorizationToken,
28
- jwtPayload: params?.jwtPayload || {},
29
25
  userId: params?.userId,
30
26
  });
31
27
 
@@ -60,15 +56,11 @@ export const createAsyncRouteContext = async (request: NextRequest): Promise<Asy
60
56
  const { plaintext } = await gateKeeper.decrypt(lobeChatAuthorization);
61
57
 
62
58
  log('Parsing decrypted authorization data');
63
- const { userId, payload } = JSON.parse(plaintext);
59
+ const { userId } = JSON.parse(plaintext);
64
60
 
65
- log(
66
- 'Successfully parsed authorization data - userId: %s, payload keys: %O',
67
- userId,
68
- Object.keys(payload || {}),
69
- );
61
+ log('Successfully parsed authorization data - userId: %s', userId);
70
62
 
71
- return createAsyncContextInner({ authorizationToken: authorization, jwtPayload: payload, userId });
63
+ return createAsyncContextInner({ authorizationToken: authorization, userId });
72
64
  } catch (error) {
73
65
  log('Error creating async route context: %O', error);
74
66
  throw error;
@@ -322,6 +322,8 @@ export default {
322
322
  'task.batchTasks': '{{count}} Batch Subtasks',
323
323
  'task.metrics.stepsShort': 'steps',
324
324
  'task.metrics.toolCallsShort': 'tool uses',
325
+ 'task.status.cancelled': 'Task Cancelled',
326
+ 'task.status.failed': 'Task Failed',
325
327
  'task.status.initializing': 'Initializing task...',
326
328
  'task.subtask': 'Subtask',
327
329
  'thread.divider': 'Subtopic',
@@ -63,7 +63,8 @@ export default {
63
63
  'builtins.lobe-gtd.apiName.createPlan.result': 'Create plan: <goal>{{goal}}</goal>',
64
64
  'builtins.lobe-gtd.apiName.createTodos': 'Create todos',
65
65
  'builtins.lobe-gtd.apiName.execTask': 'Execute task',
66
- 'builtins.lobe-gtd.apiName.execTask.result': 'Execute: <desc>{{description}}</desc>',
66
+ 'builtins.lobe-gtd.apiName.execTask.completed': 'Task created: ',
67
+ 'builtins.lobe-gtd.apiName.execTask.loading': 'Creating task: ',
67
68
  'builtins.lobe-gtd.apiName.execTasks': 'Execute tasks',
68
69
  'builtins.lobe-gtd.apiName.removeTodos': 'Delete todos',
69
70
  'builtins.lobe-gtd.apiName.updatePlan': 'Update plan',
@@ -8,12 +8,13 @@ import {
8
8
  } from '@lobechat/agent-runtime';
9
9
  import { ToolNameResolver } from '@lobechat/context-engine';
10
10
  import { consumeStreamUntilDone } from '@lobechat/model-runtime';
11
- import { type ChatToolPayload, type ClientSecretPayload, type MessageToolCall } from '@lobechat/types';
11
+ import { type ChatToolPayload, type MessageToolCall } from '@lobechat/types';
12
12
  import { serializePartsForStorage } from '@lobechat/utils';
13
13
  import debug from 'debug';
14
14
 
15
15
  import { type MessageModel } from '@/database/models/message';
16
- import { initModelRuntimeWithUserPayload } from '@/server/modules/ModelRuntime';
16
+ import { type LobeChatDatabase } from '@/database/type';
17
+ import { initModelRuntimeFromDB } from '@/server/modules/ModelRuntime';
17
18
  import { type ToolExecutionService } from '@/server/services/toolExecution';
18
19
 
19
20
  import type { IStreamEventManager } from './types';
@@ -31,11 +32,11 @@ export interface RuntimeExecutorContext {
31
32
  fileService?: any;
32
33
  messageModel: MessageModel;
33
34
  operationId: string;
35
+ serverDB: LobeChatDatabase;
34
36
  stepIndex: number;
35
37
  streamManager: IStreamEventManager;
36
38
  toolExecutionService: ToolExecutionService;
37
39
  userId?: string;
38
- userPayload?: ClientSecretPayload;
39
40
  }
40
41
 
41
42
  export const createRuntimeExecutors = (
@@ -120,8 +121,8 @@ export const createRuntimeExecutors = (
120
121
  let hasContentImages = false;
121
122
  let hasReasoningImages = false;
122
123
 
123
- // 初始化 ModelRuntime
124
- const modelRuntime = initModelRuntimeWithUserPayload(provider, ctx.userPayload || {});
124
+ // 初始化 ModelRuntime (从数据库读取用户的 keyVaults)
125
+ const modelRuntime = await initModelRuntimeFromDB(ctx.serverDB, ctx.userId!, provider);
125
126
 
126
127
  // 构造 ChatStreamPayload
127
128
  const chatPayload = {
@@ -467,7 +468,6 @@ export const createRuntimeExecutors = (
467
468
  const executionResult = await toolExecutionService.executeTool(chatToolPayload, {
468
469
  toolManifestMap: state.toolManifestMap,
469
470
  userId: ctx.userId,
470
- userPayload: ctx.userPayload,
471
471
  });
472
472
 
473
473
  const executionTime = executionResult.executionTime;
@@ -5,13 +5,13 @@ import { RuntimeExecutorContext, createRuntimeExecutors } from '../RuntimeExecut
5
5
 
6
6
  // Mock dependencies
7
7
  vi.mock('@/server/modules/ModelRuntime', () => ({
8
- initModelRuntimeWithUserPayload: vi.fn(() => ({
8
+ initModelRuntimeFromDB: vi.fn().mockResolvedValue({
9
9
  chat: vi.fn().mockResolvedValue({
10
10
  [Symbol.asyncIterator]: async function* () {
11
11
  yield { type: 'text', text: 'Hello' };
12
12
  },
13
13
  }),
14
- })),
14
+ }),
15
15
  }));
16
16
 
17
17
  vi.mock('@lobechat/model-runtime', () => ({
@@ -50,11 +50,11 @@ describe('RuntimeExecutors', () => {
50
50
  ctx = {
51
51
  messageModel: mockMessageModel,
52
52
  operationId: 'op-123',
53
+ serverDB: {} as any, // Mock serverDB
53
54
  stepIndex: 0,
54
55
  streamManager: mockStreamManager,
55
56
  toolExecutionService: mockToolExecutionService,
56
57
  userId: 'user-123',
57
- userPayload: {},
58
58
  };
59
59
  });
60
60
 
@@ -1,10 +1,10 @@
1
1
  import debug from 'debug';
2
2
 
3
+ import { appEnv } from '@/envs/app';
4
+
3
5
  import { AgentStateManager } from './AgentStateManager';
4
6
  import { inMemoryAgentStateManager } from './InMemoryAgentStateManager';
5
- import {
6
- inMemoryStreamEventManager,
7
- } from './InMemoryStreamEventManager';
7
+ import { inMemoryStreamEventManager } from './InMemoryStreamEventManager';
8
8
  import { StreamEventManager } from './StreamEventManager';
9
9
  import { getAgentRuntimeRedisClient } from './redis';
10
10
  import type { IAgentStateManager, IStreamEventManager } from './types';
@@ -19,33 +19,52 @@ export const isRedisAvailable = (): boolean => {
19
19
  };
20
20
 
21
21
  /**
22
- * Create AgentStateManager based on Redis availability
23
- *
24
- * - Redis available: RedisAgentStateManager
25
- * - Redis not available: InMemoryAgentStateManager (for local development)
22
+ * Check if queue-based agent runtime is enabled
23
+ * When disabled (default), use InMemory implementations for local/simple deployments
24
+ */
25
+ const isQueueModeEnabled = (): boolean => {
26
+ return appEnv.enableQueueAgentRuntime === true;
27
+ };
28
+
29
+ /**
30
+ * Create AgentStateManager based on configuration
26
31
  */
27
32
  export const createAgentStateManager = (): IAgentStateManager => {
28
- if (isRedisAvailable()) {
29
- log('Creating Redis-based AgentStateManager');
30
- return new AgentStateManager();
33
+ // When queue mode is disabled, always use InMemory for simplicity
34
+ if (!isQueueModeEnabled()) {
35
+ log('Queue mode disabled, using InMemoryAgentStateManager');
36
+ return inMemoryAgentStateManager;
37
+ }
38
+
39
+ // Queue mode enabled, Redis is required
40
+ if (!isRedisAvailable()) {
41
+ throw new Error(
42
+ 'Redis is required when AGENT_RUNTIME_MODE=queue. Please configure `REDIS_URL`.',
43
+ );
31
44
  }
32
45
 
33
- log('Redis not available, using InMemoryAgentStateManager for local development');
34
- return inMemoryAgentStateManager;
46
+ return new AgentStateManager();
35
47
  };
36
48
 
37
49
  /**
38
- * Create StreamEventManager based on Redis availability
50
+ * Create StreamEventManager based on configuration
39
51
  *
40
- * - Redis available: RedisStreamEventManager
41
- * - Redis not available: InMemoryStreamEventManager (for local development)
52
+ * - If enableQueueAgentRuntime=false (default): InMemoryStreamEventManager
53
+ * - If enableQueueAgentRuntime=true: RedisStreamEventManager (requires Redis)
42
54
  */
43
55
  export const createStreamEventManager = (): IStreamEventManager => {
44
- if (isRedisAvailable()) {
45
- log('Creating Redis-based StreamEventManager');
46
- return new StreamEventManager();
56
+ // When queue mode is disabled, always use InMemory for simplicity
57
+ if (!isQueueModeEnabled()) {
58
+ log('Queue mode disabled, using InMemoryStreamEventManager');
59
+ return inMemoryStreamEventManager;
60
+ }
61
+
62
+ // Queue mode enabled, Redis is required
63
+ if (!isRedisAvailable()) {
64
+ throw new Error(
65
+ 'Redis is required when AGENT_RUNTIME_MODE=queue. Please configure `REDIS_URL`.',
66
+ );
47
67
  }
48
68
 
49
- log('Redis not available, using InMemoryStreamEventManager for local development');
50
- return inMemoryStreamEventManager;
69
+ return new StreamEventManager();
51
70
  };