@lobehub/chat 1.136.11 → 1.136.13
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.github/workflows/claude-translator.yml +13 -1
- package/CHANGELOG.md +60 -0
- package/changelog/v1.json +21 -0
- package/locales/ar/modelProvider.json +12 -0
- package/locales/ar/models.json +39 -24
- package/locales/bg-BG/modelProvider.json +12 -0
- package/locales/bg-BG/models.json +39 -24
- package/locales/de-DE/modelProvider.json +12 -0
- package/locales/de-DE/models.json +39 -24
- package/locales/en-US/modelProvider.json +12 -0
- package/locales/en-US/models.json +39 -24
- package/locales/es-ES/modelProvider.json +12 -0
- package/locales/es-ES/models.json +39 -24
- package/locales/fa-IR/modelProvider.json +12 -0
- package/locales/fa-IR/models.json +39 -24
- package/locales/fr-FR/modelProvider.json +12 -0
- package/locales/fr-FR/models.json +39 -24
- package/locales/it-IT/modelProvider.json +12 -0
- package/locales/it-IT/models.json +39 -24
- package/locales/ja-JP/modelProvider.json +12 -0
- package/locales/ja-JP/models.json +39 -24
- package/locales/ko-KR/modelProvider.json +12 -0
- package/locales/ko-KR/models.json +39 -24
- package/locales/nl-NL/modelProvider.json +12 -0
- package/locales/nl-NL/models.json +39 -24
- package/locales/pl-PL/modelProvider.json +12 -0
- package/locales/pl-PL/models.json +39 -24
- package/locales/pt-BR/modelProvider.json +12 -0
- package/locales/pt-BR/models.json +39 -24
- package/locales/ru-RU/modelProvider.json +12 -0
- package/locales/ru-RU/models.json +39 -24
- package/locales/tr-TR/modelProvider.json +12 -0
- package/locales/tr-TR/models.json +39 -24
- package/locales/vi-VN/modelProvider.json +12 -0
- package/locales/vi-VN/models.json +39 -24
- package/locales/zh-CN/modelProvider.json +12 -0
- package/locales/zh-CN/models.json +39 -24
- package/locales/zh-TW/modelProvider.json +12 -0
- package/locales/zh-TW/models.json +39 -24
- package/package.json +3 -3
- package/packages/const/src/settings/index.ts +1 -0
- package/packages/database/package.json +7 -5
- package/packages/electron-client-ipc/src/events/index.ts +2 -2
- package/packages/electron-client-ipc/src/events/{localFile.ts → localSystem.ts} +25 -6
- package/packages/electron-client-ipc/src/types/index.ts +1 -1
- package/packages/electron-client-ipc/src/types/{localFile.ts → localSystem.ts} +89 -4
- package/packages/file-loaders/package.json +1 -2
- package/packages/file-loaders/src/loadFile.ts +4 -1
- package/packages/file-loaders/src/loaders/doc/__snapshots__/index.test.ts.snap +46 -0
- package/packages/file-loaders/src/loaders/doc/index.test.ts +38 -0
- package/packages/file-loaders/src/loaders/doc/index.ts +57 -0
- package/packages/file-loaders/src/loaders/docx/index.ts +36 -45
- package/packages/file-loaders/src/loaders/index.ts +2 -0
- package/packages/file-loaders/src/types/word-extractor.d.ts +9 -0
- package/packages/file-loaders/src/types.ts +1 -1
- package/packages/model-bank/src/aiModels/infiniai.ts +465 -174
- package/packages/model-bank/src/aiModels/modelscope.ts +10 -20
- package/packages/model-bank/src/aiModels/novita.ts +2 -2
- package/packages/model-runtime/src/core/openaiCompatibleFactory/index.test.ts +267 -38
- package/packages/model-runtime/src/core/openaiCompatibleFactory/index.ts +45 -0
- package/packages/model-runtime/src/providerTestUtils.ts +0 -5
- package/packages/model-runtime/src/providers/anthropic/generateObject.test.ts +57 -44
- package/packages/model-runtime/src/providers/anthropic/generateObject.ts +28 -20
- package/packages/model-runtime/src/providers/deepseek/index.ts +5 -0
- package/packages/model-runtime/src/providers/infiniai/index.ts +8 -54
- package/packages/model-runtime/src/providers/openai/index.test.ts +0 -5
- package/packages/model-runtime/src/providers/openrouter/index.test.ts +3 -3
- package/packages/model-runtime/src/providers/openrouter/index.ts +32 -20
- package/packages/model-runtime/src/providers/openrouter/type.ts +25 -24
- package/packages/model-runtime/src/providers/zhipu/index.test.ts +0 -1
- package/packages/model-runtime/src/types/structureOutput.ts +13 -1
- package/packages/model-runtime/src/utils/handleOpenAIError.test.ts +0 -5
- package/packages/model-runtime/src/utils/handleOpenAIError.ts +2 -2
- package/packages/types/src/aiChat.ts +13 -1
- package/packages/types/src/index.ts +1 -0
- package/src/app/[variants]/(main)/settings/provider/detail/bedrock/index.tsx +36 -2
- package/src/config/modelProviders/infiniai.ts +2 -25
- package/src/config/modelProviders/modelscope.ts +1 -17
- package/src/features/ChatInput/InputEditor/index.tsx +39 -26
- package/src/features/Conversation/Messages/Assistant/Tool/Render/LoadingPlaceholder/index.tsx +1 -1
- package/src/server/routers/lambda/agent.ts +2 -3
- package/src/server/routers/lambda/aiChat.ts +33 -1
- package/src/server/routers/lambda/chunk.ts +2 -2
- package/src/services/electron/file.ts +1 -2
- package/src/services/electron/localFileService.ts +40 -0
- package/src/tools/local-system/Placeholder/ListFiles.tsx +23 -0
- package/src/tools/local-system/Placeholder/ReadLocalFile.tsx +9 -0
- package/src/tools/local-system/Placeholder/SearchFiles.tsx +55 -0
- package/src/tools/local-system/Placeholder/index.tsx +25 -0
- package/src/tools/placeholders.ts +3 -0
|
@@ -48,7 +48,6 @@ describe('handleOpenAIError', () => {
|
|
|
48
48
|
|
|
49
49
|
expect(result.errorResult).toEqual({
|
|
50
50
|
headers: { headers, status: 401 },
|
|
51
|
-
stack: apiError.stack,
|
|
52
51
|
status: 472,
|
|
53
52
|
});
|
|
54
53
|
expect(result.RuntimeError).toBeUndefined();
|
|
@@ -84,7 +83,6 @@ describe('handleOpenAIError', () => {
|
|
|
84
83
|
cause: { details: 'Error details' },
|
|
85
84
|
message: 'Generic error',
|
|
86
85
|
name: 'Error',
|
|
87
|
-
stack: error.stack,
|
|
88
86
|
},
|
|
89
87
|
});
|
|
90
88
|
});
|
|
@@ -100,7 +98,6 @@ describe('handleOpenAIError', () => {
|
|
|
100
98
|
cause: undefined,
|
|
101
99
|
message: 'Simple error',
|
|
102
100
|
name: 'Error',
|
|
103
|
-
stack: error.stack,
|
|
104
101
|
},
|
|
105
102
|
});
|
|
106
103
|
});
|
|
@@ -122,7 +119,6 @@ describe('handleOpenAIError', () => {
|
|
|
122
119
|
cause: undefined,
|
|
123
120
|
message: 'Custom error message',
|
|
124
121
|
name: 'CustomError',
|
|
125
|
-
stack: error.stack,
|
|
126
122
|
},
|
|
127
123
|
});
|
|
128
124
|
});
|
|
@@ -141,7 +137,6 @@ describe('handleOpenAIError', () => {
|
|
|
141
137
|
cause: undefined,
|
|
142
138
|
message: 'Object error',
|
|
143
139
|
name: undefined,
|
|
144
|
-
stack: undefined,
|
|
145
140
|
},
|
|
146
141
|
});
|
|
147
142
|
});
|
|
@@ -20,7 +20,7 @@ export const handleOpenAIError = (
|
|
|
20
20
|
}
|
|
21
21
|
// if there is no other request error, the error object is a Response like object
|
|
22
22
|
else {
|
|
23
|
-
errorResult = { headers: error.headers,
|
|
23
|
+
errorResult = { headers: error.headers, status: error.status };
|
|
24
24
|
}
|
|
25
25
|
|
|
26
26
|
return {
|
|
@@ -29,7 +29,7 @@ export const handleOpenAIError = (
|
|
|
29
29
|
} else {
|
|
30
30
|
const err = error as Error;
|
|
31
31
|
|
|
32
|
-
errorResult = { cause: err.cause, message: err.message, name: err.name
|
|
32
|
+
errorResult = { cause: err.cause, message: err.message, name: err.name };
|
|
33
33
|
|
|
34
34
|
return {
|
|
35
35
|
RuntimeError: AgentRuntimeErrorType.AgentRuntimeError,
|
|
@@ -54,12 +54,24 @@ export interface SendMessageServerResponse {
|
|
|
54
54
|
userMessageId: string;
|
|
55
55
|
}
|
|
56
56
|
|
|
57
|
+
export const StructureSchema = z.object({
|
|
58
|
+
description: z.string().optional(),
|
|
59
|
+
name: z.string(),
|
|
60
|
+
schema: z.object({
|
|
61
|
+
additionalProperties: z.boolean().optional(),
|
|
62
|
+
properties: z.record(z.string(), z.any()),
|
|
63
|
+
required: z.array(z.string()).optional(),
|
|
64
|
+
type: z.literal('object'),
|
|
65
|
+
}),
|
|
66
|
+
strict: z.boolean().optional(),
|
|
67
|
+
});
|
|
68
|
+
|
|
57
69
|
export const StructureOutputSchema = z.object({
|
|
58
70
|
keyVaultsPayload: z.string(),
|
|
59
71
|
messages: z.array(z.any()),
|
|
60
72
|
model: z.string(),
|
|
61
73
|
provider: z.string(),
|
|
62
|
-
schema:
|
|
74
|
+
schema: StructureSchema,
|
|
63
75
|
});
|
|
64
76
|
|
|
65
77
|
export interface StructureOutputParams {
|
|
@@ -15,6 +15,40 @@ import ProviderDetail from '../default';
|
|
|
15
15
|
|
|
16
16
|
const providerKey: GlobalLLMProviderKey = 'bedrock';
|
|
17
17
|
|
|
18
|
+
const AWS_REGIONS: string[] = [
|
|
19
|
+
'us-east-1',
|
|
20
|
+
'us-east-2',
|
|
21
|
+
'us-west-1',
|
|
22
|
+
'us-west-2',
|
|
23
|
+
'ca-central-1',
|
|
24
|
+
'us-gov-east-1',
|
|
25
|
+
'us-gov-west-1',
|
|
26
|
+
'sa-east-1',
|
|
27
|
+
'eu-north-1',
|
|
28
|
+
'eu-west-1',
|
|
29
|
+
'eu-west-2',
|
|
30
|
+
'eu-west-3',
|
|
31
|
+
'eu-central-1',
|
|
32
|
+
'eu-central-2',
|
|
33
|
+
'eu-south-1',
|
|
34
|
+
'eu-south-2',
|
|
35
|
+
'me-south-1',
|
|
36
|
+
'me-central-1',
|
|
37
|
+
'af-south-1',
|
|
38
|
+
'ap-south-1',
|
|
39
|
+
'ap-south-2',
|
|
40
|
+
'ap-east-1',
|
|
41
|
+
'ap-southeast-1',
|
|
42
|
+
'ap-southeast-2',
|
|
43
|
+
'ap-southeast-3',
|
|
44
|
+
'ap-southeast-4',
|
|
45
|
+
'ap-northeast-1',
|
|
46
|
+
'ap-northeast-2',
|
|
47
|
+
'ap-northeast-3',
|
|
48
|
+
'cn-north-1',
|
|
49
|
+
'cn-northwest-1',
|
|
50
|
+
];
|
|
51
|
+
|
|
18
52
|
const useBedrockCard = (): ProviderItem => {
|
|
19
53
|
const { t } = useTranslation('modelProvider');
|
|
20
54
|
|
|
@@ -68,11 +102,11 @@ const useBedrockCard = (): ProviderItem => {
|
|
|
68
102
|
) : (
|
|
69
103
|
<Select
|
|
70
104
|
allowClear
|
|
71
|
-
options={
|
|
105
|
+
options={AWS_REGIONS.map((i) => ({
|
|
72
106
|
label: i,
|
|
73
107
|
value: i,
|
|
74
108
|
}))}
|
|
75
|
-
placeholder={
|
|
109
|
+
placeholder={AWS_REGIONS[0]}
|
|
76
110
|
/>
|
|
77
111
|
),
|
|
78
112
|
desc: t(`${providerKey}.region.desc`),
|
|
@@ -76,32 +76,8 @@ const InfiniAI: ModelProviderCard = {
|
|
|
76
76
|
enabled: true,
|
|
77
77
|
id: 'qwen2.5-7b-instruct',
|
|
78
78
|
},
|
|
79
|
-
{
|
|
80
|
-
contextWindowTokens: 32_768,
|
|
81
|
-
description:
|
|
82
|
-
'Qwen2 是 Qwen 团队推出的新一代大型语言模型系列。它基于 Transformer 架构,并采用 SwiGLU 激活函数、注意力 QKV 偏置(attention QKV bias)、群组查询注意力(group query attention)、滑动窗口注意力(mixture of sliding window attention)与全注意力的混合等技术。此外,Qwen 团队还改进了适应多种自然语言和代码的分词器。',
|
|
83
|
-
displayName: 'Qwen 2 72B Instruct',
|
|
84
|
-
enabled: true,
|
|
85
|
-
id: 'qwen2-72b-instruct',
|
|
86
|
-
},
|
|
87
|
-
{
|
|
88
|
-
contextWindowTokens: 32_768,
|
|
89
|
-
description:
|
|
90
|
-
'Qwen2 是 Qwen 团队推出的新一代大型语言模型系列。它基于 Transformer 架构,并采用 SwiGLU 激活函数、注意力 QKV 偏置(attention QKV bias)、群组查询注意力(group query attention)、滑动窗口注意力(mixture of sliding window attention)与全注意力的混合等技术。此外,Qwen 团队还改进了适应多种自然语言和代码的分词器。',
|
|
91
|
-
displayName: 'Qwen 2 7B Instruct',
|
|
92
|
-
enabled: true,
|
|
93
|
-
id: 'qwen2-7b-instruct',
|
|
94
|
-
},
|
|
95
|
-
{
|
|
96
|
-
contextWindowTokens: 4096,
|
|
97
|
-
description:
|
|
98
|
-
'Yi-1.5 是 Yi 的升级版本。 它使用 500B Tokens 的高质量语料库在 Yi 上持续进行预训练,并在 3M 个多样化的微调样本上进行微调。',
|
|
99
|
-
displayName: 'Yi-1.5 34B Chat',
|
|
100
|
-
enabled: true,
|
|
101
|
-
id: 'yi-1.5-34b-chat',
|
|
102
|
-
},
|
|
103
79
|
],
|
|
104
|
-
checkModel: '
|
|
80
|
+
checkModel: 'qwen3-8b',
|
|
105
81
|
description:
|
|
106
82
|
'为应用开发者提供高性能、易上手、安全可靠的大模型服务,覆盖从大模型开发到大模型服务化部署的全流程。',
|
|
107
83
|
id: 'infiniai',
|
|
@@ -109,6 +85,7 @@ const InfiniAI: ModelProviderCard = {
|
|
|
109
85
|
modelsUrl: 'https://cloud.infini-ai.com/genstudio/model',
|
|
110
86
|
name: 'InfiniAI',
|
|
111
87
|
settings: {
|
|
88
|
+
disableBrowserRequest: true,
|
|
112
89
|
proxyUrl: {
|
|
113
90
|
placeholder: 'https://cloud.infini-ai.com/maas/v1',
|
|
114
91
|
},
|
|
@@ -12,22 +12,6 @@ const ModelScope: ModelProviderCard = {
|
|
|
12
12
|
functionCall: true,
|
|
13
13
|
id: 'deepseek-ai/DeepSeek-R1-0528',
|
|
14
14
|
},
|
|
15
|
-
{
|
|
16
|
-
contextWindowTokens: 131_072,
|
|
17
|
-
description: 'DeepSeek-V3是DeepSeek第三代模型的最新版本,具有强大的推理和对话能力。',
|
|
18
|
-
displayName: 'DeepSeek-V3',
|
|
19
|
-
enabled: true,
|
|
20
|
-
functionCall: true,
|
|
21
|
-
id: 'deepseek-ai/DeepSeek-V3',
|
|
22
|
-
},
|
|
23
|
-
{
|
|
24
|
-
contextWindowTokens: 131_072,
|
|
25
|
-
description: 'DeepSeek-R1是DeepSeek最新的推理模型,专注于复杂推理任务。',
|
|
26
|
-
displayName: 'DeepSeek-R1',
|
|
27
|
-
enabled: true,
|
|
28
|
-
functionCall: true,
|
|
29
|
-
id: 'deepseek-ai/DeepSeek-R1',
|
|
30
|
-
},
|
|
31
15
|
{
|
|
32
16
|
contextWindowTokens: 131_072,
|
|
33
17
|
description: 'Qwen3-235B-A22B是通义千问3代超大规模模型,提供顶级的AI能力。',
|
|
@@ -45,7 +29,7 @@ const ModelScope: ModelProviderCard = {
|
|
|
45
29
|
id: 'Qwen/Qwen3-32B',
|
|
46
30
|
},
|
|
47
31
|
],
|
|
48
|
-
checkModel: 'Qwen/Qwen3-
|
|
32
|
+
checkModel: 'Qwen/Qwen3-4B',
|
|
49
33
|
description: 'ModelScope是阿里云推出的模型即服务平台,提供丰富的AI模型和推理服务。',
|
|
50
34
|
id: 'modelscope',
|
|
51
35
|
modelList: { showModelFetcher: true },
|
|
@@ -62,30 +62,45 @@ const InputEditor = memo<{ defaultRows?: number }>(() => {
|
|
|
62
62
|
};
|
|
63
63
|
}, [state.isEmpty]);
|
|
64
64
|
|
|
65
|
-
const
|
|
66
|
-
|
|
65
|
+
const enableRichRender = useUserStore(preferenceSelectors.inputMarkdownRender);
|
|
66
|
+
|
|
67
|
+
const richRenderProps = useMemo(
|
|
67
68
|
() =>
|
|
68
|
-
!
|
|
69
|
-
?
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
69
|
+
!enableRichRender
|
|
70
|
+
? {
|
|
71
|
+
enablePasteMarkdown: false,
|
|
72
|
+
markdownOption: {
|
|
73
|
+
bold: false,
|
|
74
|
+
code: false,
|
|
75
|
+
header: false,
|
|
76
|
+
italic: false,
|
|
77
|
+
quote: false,
|
|
78
|
+
strikethrough: false,
|
|
79
|
+
underline: false,
|
|
80
|
+
underlineStrikethrough: false,
|
|
81
|
+
},
|
|
82
|
+
}
|
|
83
|
+
: {
|
|
84
|
+
plugins: [
|
|
85
|
+
ReactListPlugin,
|
|
86
|
+
ReactLinkPlugin,
|
|
87
|
+
ReactCodePlugin,
|
|
88
|
+
ReactCodeblockPlugin,
|
|
89
|
+
ReactHRPlugin,
|
|
90
|
+
ReactTablePlugin,
|
|
91
|
+
Editor.withProps(ReactMathPlugin, {
|
|
92
|
+
renderComp: expand
|
|
93
|
+
? undefined
|
|
94
|
+
: (props) => (
|
|
95
|
+
<FloatMenu
|
|
96
|
+
{...props}
|
|
97
|
+
getPopupContainer={() => (slashMenuRef as any)?.current}
|
|
98
|
+
/>
|
|
99
|
+
),
|
|
100
|
+
}),
|
|
101
|
+
],
|
|
102
|
+
},
|
|
103
|
+
[enableRichRender],
|
|
89
104
|
);
|
|
90
105
|
|
|
91
106
|
return (
|
|
@@ -94,8 +109,7 @@ const InputEditor = memo<{ defaultRows?: number }>(() => {
|
|
|
94
109
|
className={className}
|
|
95
110
|
content={''}
|
|
96
111
|
editor={editor}
|
|
97
|
-
|
|
98
|
-
markdownOption={enableMarkdown}
|
|
112
|
+
{...richRenderProps}
|
|
99
113
|
onBlur={() => {
|
|
100
114
|
disableScope(HotkeyEnum.AddUserMessage);
|
|
101
115
|
}}
|
|
@@ -145,7 +159,6 @@ const InputEditor = memo<{ defaultRows?: number }>(() => {
|
|
|
145
159
|
}
|
|
146
160
|
}}
|
|
147
161
|
placeholder={<Placeholder />}
|
|
148
|
-
plugins={plugins}
|
|
149
162
|
slashOption={{
|
|
150
163
|
items: slashItems,
|
|
151
164
|
renderComp: expand
|
package/src/features/Conversation/Messages/Assistant/Tool/Render/LoadingPlaceholder/index.tsx
CHANGED
|
@@ -16,7 +16,7 @@ const LoadingPlaceholder = memo<LoadingPlaceholderProps>(
|
|
|
16
16
|
({ identifier, requestArgs, apiName, loading }) => {
|
|
17
17
|
const Render = BuiltinToolPlaceholders[identifier || ''];
|
|
18
18
|
|
|
19
|
-
if (identifier) {
|
|
19
|
+
if (identifier && Render) {
|
|
20
20
|
return (
|
|
21
21
|
<Render apiName={apiName} args={safeParseJSON(requestArgs) || {}} identifier={identifier} />
|
|
22
22
|
);
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
+
import { DEFAULT_AGENT_CONFIG, INBOX_SESSION_ID } from '@lobechat/const';
|
|
2
|
+
import { KnowledgeItem, KnowledgeType } from '@lobechat/types';
|
|
1
3
|
import { z } from 'zod';
|
|
2
4
|
|
|
3
|
-
import { INBOX_SESSION_ID } from '@/const/session';
|
|
4
|
-
import { DEFAULT_AGENT_CONFIG } from '@/const/settings';
|
|
5
5
|
import { AgentModel } from '@/database/models/agent';
|
|
6
6
|
import { FileModel } from '@/database/models/file';
|
|
7
7
|
import { KnowledgeBaseModel } from '@/database/models/knowledgeBase';
|
|
@@ -11,7 +11,6 @@ import { pino } from '@/libs/logger';
|
|
|
11
11
|
import { authedProcedure, router } from '@/libs/trpc/lambda';
|
|
12
12
|
import { serverDatabase } from '@/libs/trpc/lambda/middleware';
|
|
13
13
|
import { AgentService } from '@/server/services/agent';
|
|
14
|
-
import { KnowledgeItem, KnowledgeType } from '@/types/knowledgeBase';
|
|
15
14
|
|
|
16
15
|
const agentProcedure = authedProcedure.use(serverDatabase).use(async (opts) => {
|
|
17
16
|
const { ctx } = opts;
|
|
@@ -4,6 +4,7 @@ import {
|
|
|
4
4
|
StructureOutputSchema,
|
|
5
5
|
} from '@lobechat/types';
|
|
6
6
|
import { TRPCError } from '@trpc/server';
|
|
7
|
+
import debug from 'debug';
|
|
7
8
|
|
|
8
9
|
import { LOADING_FLAT } from '@/const/message';
|
|
9
10
|
import { MessageModel } from '@/database/models/message';
|
|
@@ -15,6 +16,8 @@ import { AiChatService } from '@/server/services/aiChat';
|
|
|
15
16
|
import { FileService } from '@/server/services/file';
|
|
16
17
|
import { getXorPayload } from '@/utils/server';
|
|
17
18
|
|
|
19
|
+
const log = debug('lobe-lambda-router:ai-chat');
|
|
20
|
+
|
|
18
21
|
const aiChatProcedure = authedProcedure.use(serverDatabase).use(async (opts) => {
|
|
19
22
|
const { ctx } = opts;
|
|
20
23
|
|
|
@@ -30,30 +33,45 @@ const aiChatProcedure = authedProcedure.use(serverDatabase).use(async (opts) =>
|
|
|
30
33
|
|
|
31
34
|
export const aiChatRouter = router({
|
|
32
35
|
outputJSON: aiChatProcedure.input(StructureOutputSchema).mutation(async ({ input }) => {
|
|
36
|
+
log('outputJSON called with provider: %s, model: %s', input.provider, input.model);
|
|
37
|
+
log('messages count: %d', input.messages.length);
|
|
38
|
+
log('schema: %O', input.schema);
|
|
39
|
+
|
|
33
40
|
let payload: object | undefined;
|
|
34
41
|
|
|
35
42
|
try {
|
|
36
43
|
payload = getXorPayload(input.keyVaultsPayload);
|
|
44
|
+
log('payload parsed successfully');
|
|
37
45
|
} catch (e) {
|
|
46
|
+
log('payload parse error: %O', e);
|
|
38
47
|
console.warn('user payload parse error', e);
|
|
39
48
|
}
|
|
40
49
|
|
|
41
50
|
if (!payload) {
|
|
51
|
+
log('payload is empty, throwing error');
|
|
42
52
|
throw new TRPCError({ code: 'BAD_REQUEST', message: 'keyVaultsPayload is not correct' });
|
|
43
53
|
}
|
|
44
54
|
|
|
55
|
+
log('initializing model runtime with provider: %s', input.provider);
|
|
45
56
|
const modelRuntime = initModelRuntimeWithUserPayload(input.provider, payload);
|
|
46
57
|
|
|
47
|
-
|
|
58
|
+
log('calling generateObject');
|
|
59
|
+
const result = await modelRuntime.generateObject({
|
|
48
60
|
messages: input.messages,
|
|
49
61
|
model: input.model,
|
|
50
62
|
schema: input.schema,
|
|
51
63
|
});
|
|
64
|
+
|
|
65
|
+
log('generateObject completed, result: %O', result);
|
|
66
|
+
return result;
|
|
52
67
|
}),
|
|
53
68
|
|
|
54
69
|
sendMessageInServer: aiChatProcedure
|
|
55
70
|
.input(AiSendMessageServerSchema)
|
|
56
71
|
.mutation(async ({ input, ctx }) => {
|
|
72
|
+
log('sendMessageInServer called for sessionId: %s', input.sessionId);
|
|
73
|
+
log('topicId: %s, newTopic: %O', input.topicId, input.newTopic);
|
|
74
|
+
|
|
57
75
|
let messageId: string;
|
|
58
76
|
let topicId = input.topicId!;
|
|
59
77
|
|
|
@@ -61,6 +79,7 @@ export const aiChatRouter = router({
|
|
|
61
79
|
|
|
62
80
|
// create topic if there should be a new topic
|
|
63
81
|
if (input.newTopic) {
|
|
82
|
+
log('creating new topic with title: %s', input.newTopic.title);
|
|
64
83
|
const topicItem = await ctx.topicModel.create({
|
|
65
84
|
messages: input.newTopic.topicMessageIds,
|
|
66
85
|
sessionId: input.sessionId,
|
|
@@ -68,9 +87,11 @@ export const aiChatRouter = router({
|
|
|
68
87
|
});
|
|
69
88
|
topicId = topicItem.id;
|
|
70
89
|
isCreatNewTopic = true;
|
|
90
|
+
log('new topic created with id: %s', topicId);
|
|
71
91
|
}
|
|
72
92
|
|
|
73
93
|
// create user message
|
|
94
|
+
log('creating user message with content length: %d', input.newUserMessage.content.length);
|
|
74
95
|
const userMessageItem = await ctx.messageModel.create({
|
|
75
96
|
content: input.newUserMessage.content,
|
|
76
97
|
files: input.newUserMessage.files,
|
|
@@ -80,7 +101,14 @@ export const aiChatRouter = router({
|
|
|
80
101
|
});
|
|
81
102
|
|
|
82
103
|
messageId = userMessageItem.id;
|
|
104
|
+
log('user message created with id: %s', messageId);
|
|
105
|
+
|
|
83
106
|
// create assistant message
|
|
107
|
+
log(
|
|
108
|
+
'creating assistant message with model: %s, provider: %s',
|
|
109
|
+
input.newAssistantMessage.model,
|
|
110
|
+
input.newAssistantMessage.provider,
|
|
111
|
+
);
|
|
84
112
|
const assistantMessageItem = await ctx.messageModel.create({
|
|
85
113
|
content: LOADING_FLAT,
|
|
86
114
|
fromModel: input.newAssistantMessage.model,
|
|
@@ -90,14 +118,18 @@ export const aiChatRouter = router({
|
|
|
90
118
|
sessionId: input.sessionId!,
|
|
91
119
|
topicId,
|
|
92
120
|
});
|
|
121
|
+
log('assistant message created with id: %s', assistantMessageItem.id);
|
|
93
122
|
|
|
94
123
|
// retrieve latest messages and topic with
|
|
124
|
+
log('retrieving messages and topics');
|
|
95
125
|
const { messages, topics } = await ctx.aiChatService.getMessagesAndTopics({
|
|
96
126
|
includeTopic: isCreatNewTopic,
|
|
97
127
|
sessionId: input.sessionId,
|
|
98
128
|
topicId,
|
|
99
129
|
});
|
|
100
130
|
|
|
131
|
+
log('retrieved %d messages, %d topics', messages.length, topics?.length ?? 0);
|
|
132
|
+
|
|
101
133
|
return {
|
|
102
134
|
assistantMessageId: assistantMessageItem.id,
|
|
103
135
|
isCreatNewTopic,
|
|
@@ -1,8 +1,9 @@
|
|
|
1
|
+
import { DEFAULT_FILE_EMBEDDING_MODEL_ITEM } from '@lobechat/const';
|
|
2
|
+
import { SemanticSearchSchema } from '@lobechat/types';
|
|
1
3
|
import { TRPCError } from '@trpc/server';
|
|
2
4
|
import { inArray } from 'drizzle-orm';
|
|
3
5
|
import { z } from 'zod';
|
|
4
6
|
|
|
5
|
-
import { DEFAULT_FILE_EMBEDDING_MODEL_ITEM } from '@/const/settings/knowledge';
|
|
6
7
|
import { AsyncTaskModel } from '@/database/models/asyncTask';
|
|
7
8
|
import { ChunkModel } from '@/database/models/chunk';
|
|
8
9
|
import { EmbeddingModel } from '@/database/models/embedding';
|
|
@@ -14,7 +15,6 @@ import { keyVaults, serverDatabase } from '@/libs/trpc/lambda/middleware';
|
|
|
14
15
|
import { getServerDefaultFilesConfig } from '@/server/globalConfig';
|
|
15
16
|
import { initModelRuntimeWithUserPayload } from '@/server/modules/ModelRuntime';
|
|
16
17
|
import { ChunkService } from '@/server/services/chunk';
|
|
17
|
-
import { SemanticSearchSchema } from '@/types/rag';
|
|
18
18
|
|
|
19
19
|
const chunkProcedure = authedProcedure
|
|
20
20
|
.use(serverDatabase)
|
|
@@ -1,4 +1,14 @@
|
|
|
1
1
|
import {
|
|
2
|
+
EditLocalFileParams,
|
|
3
|
+
EditLocalFileResult,
|
|
4
|
+
GetCommandOutputParams,
|
|
5
|
+
GetCommandOutputResult,
|
|
6
|
+
GlobFilesParams,
|
|
7
|
+
GlobFilesResult,
|
|
8
|
+
GrepContentParams,
|
|
9
|
+
GrepContentResult,
|
|
10
|
+
KillCommandParams,
|
|
11
|
+
KillCommandResult,
|
|
2
12
|
ListLocalFileParams,
|
|
3
13
|
LocalFileItem,
|
|
4
14
|
LocalMoveFilesResultItem,
|
|
@@ -10,11 +20,14 @@ import {
|
|
|
10
20
|
OpenLocalFileParams,
|
|
11
21
|
OpenLocalFolderParams,
|
|
12
22
|
RenameLocalFileParams,
|
|
23
|
+
RunCommandParams,
|
|
24
|
+
RunCommandResult,
|
|
13
25
|
WriteLocalFileParams,
|
|
14
26
|
dispatch,
|
|
15
27
|
} from '@lobechat/electron-client-ipc';
|
|
16
28
|
|
|
17
29
|
class LocalFileService {
|
|
30
|
+
// File Operations
|
|
18
31
|
async listLocalFiles(params: ListLocalFileParams): Promise<LocalFileItem[]> {
|
|
19
32
|
return dispatch('listLocalFiles', params);
|
|
20
33
|
}
|
|
@@ -51,6 +64,33 @@ class LocalFileService {
|
|
|
51
64
|
return dispatch('writeLocalFile', params);
|
|
52
65
|
}
|
|
53
66
|
|
|
67
|
+
async editLocalFile(params: EditLocalFileParams): Promise<EditLocalFileResult> {
|
|
68
|
+
return dispatch('editLocalFile', params);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
// Shell Commands
|
|
72
|
+
async runCommand(params: RunCommandParams): Promise<RunCommandResult> {
|
|
73
|
+
return dispatch('runCommand', params);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
async getCommandOutput(params: GetCommandOutputParams): Promise<GetCommandOutputResult> {
|
|
77
|
+
return dispatch('getCommandOutput', params);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
async killCommand(params: KillCommandParams): Promise<KillCommandResult> {
|
|
81
|
+
return dispatch('killCommand', params);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// Search & Find
|
|
85
|
+
async grepContent(params: GrepContentParams): Promise<GrepContentResult> {
|
|
86
|
+
return dispatch('grepContent', params);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
async globFiles(params: GlobFilesParams): Promise<GlobFilesResult> {
|
|
90
|
+
return dispatch('globLocalFiles', params);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
// Helper methods
|
|
54
94
|
async openLocalFileOrFolder(path: string, isDirectory: boolean) {
|
|
55
95
|
if (isDirectory) {
|
|
56
96
|
return this.openLocalFolder({ isDirectory, path });
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { ListLocalFileParams } from '@lobechat/electron-client-ipc';
|
|
2
|
+
import { Skeleton } from 'antd';
|
|
3
|
+
import React, { memo } from 'react';
|
|
4
|
+
import { Flexbox } from 'react-layout-kit';
|
|
5
|
+
|
|
6
|
+
import { LocalFolder } from '@/features/LocalFile';
|
|
7
|
+
|
|
8
|
+
interface ListFilesProps {
|
|
9
|
+
args: ListLocalFileParams;
|
|
10
|
+
}
|
|
11
|
+
export const ListFiles = memo<ListFilesProps>(({ args }) => {
|
|
12
|
+
return (
|
|
13
|
+
<Flexbox gap={8}>
|
|
14
|
+
<LocalFolder path={args.path} />
|
|
15
|
+
<Flexbox gap={4}>
|
|
16
|
+
<Skeleton.Button active block style={{ height: 16 }} />
|
|
17
|
+
<Skeleton.Button active block style={{ height: 16 }} />
|
|
18
|
+
<Skeleton.Button active block style={{ height: 16 }} />
|
|
19
|
+
<Skeleton.Button active block style={{ height: 16 }} />
|
|
20
|
+
</Flexbox>
|
|
21
|
+
</Flexbox>
|
|
22
|
+
);
|
|
23
|
+
});
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { LocalSearchFilesParams } from '@lobechat/electron-client-ipc';
|
|
2
|
+
import { Icon } from '@lobehub/ui';
|
|
3
|
+
import { Skeleton } from 'antd';
|
|
4
|
+
import { createStyles } from 'antd-style';
|
|
5
|
+
import { SearchIcon } from 'lucide-react';
|
|
6
|
+
import { memo } from 'react';
|
|
7
|
+
import { Flexbox } from 'react-layout-kit';
|
|
8
|
+
|
|
9
|
+
const useStyles = createStyles(({ css, token, cx }) => ({
|
|
10
|
+
query: cx(css`
|
|
11
|
+
padding-block: 4px;
|
|
12
|
+
padding-inline: 8px;
|
|
13
|
+
border-radius: 8px;
|
|
14
|
+
|
|
15
|
+
font-size: 12px;
|
|
16
|
+
color: ${token.colorTextSecondary};
|
|
17
|
+
|
|
18
|
+
&:hover {
|
|
19
|
+
background: ${token.colorFillTertiary};
|
|
20
|
+
}
|
|
21
|
+
`),
|
|
22
|
+
}));
|
|
23
|
+
|
|
24
|
+
interface SearchFilesProps {
|
|
25
|
+
args: LocalSearchFilesParams;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const SearchFiles = memo<SearchFilesProps>(({ args }) => {
|
|
29
|
+
const { styles } = useStyles();
|
|
30
|
+
|
|
31
|
+
return (
|
|
32
|
+
<Flexbox gap={8}>
|
|
33
|
+
<Flexbox align={'center'} distribution={'space-between'} gap={40} height={32} horizontal>
|
|
34
|
+
<Flexbox align={'center'} className={styles.query} gap={8} horizontal>
|
|
35
|
+
<Icon icon={SearchIcon} />
|
|
36
|
+
{args.keywords ? (
|
|
37
|
+
args.keywords
|
|
38
|
+
) : (
|
|
39
|
+
<Skeleton.Node active style={{ height: 20, width: 40 }} />
|
|
40
|
+
)}
|
|
41
|
+
</Flexbox>
|
|
42
|
+
|
|
43
|
+
<Skeleton.Node active style={{ height: 20, width: 40 }} />
|
|
44
|
+
</Flexbox>
|
|
45
|
+
<Flexbox gap={4}>
|
|
46
|
+
<Skeleton.Button active block style={{ height: 16 }} />
|
|
47
|
+
<Skeleton.Button active block style={{ height: 16 }} />
|
|
48
|
+
<Skeleton.Button active block style={{ height: 16 }} />
|
|
49
|
+
<Skeleton.Button active block style={{ height: 16 }} />
|
|
50
|
+
</Flexbox>
|
|
51
|
+
</Flexbox>
|
|
52
|
+
);
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
export default SearchFiles;
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { BuiltinPlaceholderProps } from '@lobechat/types';
|
|
2
|
+
import { memo } from 'react';
|
|
3
|
+
|
|
4
|
+
import { LocalSystemApiName } from '@/tools/local-system';
|
|
5
|
+
|
|
6
|
+
import { ListFiles } from './ListFiles';
|
|
7
|
+
import ReadLocalFile from './ReadLocalFile';
|
|
8
|
+
import SearchFiles from './SearchFiles';
|
|
9
|
+
|
|
10
|
+
const RenderMap = {
|
|
11
|
+
[LocalSystemApiName.searchLocalFiles]: SearchFiles,
|
|
12
|
+
[LocalSystemApiName.listLocalFiles]: ListFiles,
|
|
13
|
+
[LocalSystemApiName.readLocalFile]: ReadLocalFile,
|
|
14
|
+
// [LocalSystemApiName.renameLocalFile]: RenameLocalFile,
|
|
15
|
+
// [LocalSystemApiName.writeLocalFile]: WriteFile,
|
|
16
|
+
};
|
|
17
|
+
const Placeholder = memo<BuiltinPlaceholderProps>(({ apiName, args }) => {
|
|
18
|
+
const Render = RenderMap[apiName as any];
|
|
19
|
+
|
|
20
|
+
if (!Render) return;
|
|
21
|
+
|
|
22
|
+
return <Render args={(args || {}) as any} />;
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
export default Placeholder;
|
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
import { BuiltinPlaceholder } from '@lobechat/types';
|
|
2
2
|
|
|
3
|
+
import { LocalSystemManifest } from './local-system';
|
|
4
|
+
import LocalSystem from './local-system/Placeholder';
|
|
3
5
|
import { WebBrowsingManifest } from './web-browsing';
|
|
4
6
|
import WebBrowsing from './web-browsing/Placeholder';
|
|
5
7
|
|
|
6
8
|
export const BuiltinToolPlaceholders: Record<string, BuiltinPlaceholder> = {
|
|
7
9
|
[WebBrowsingManifest.identifier]: WebBrowsing as BuiltinPlaceholder,
|
|
10
|
+
[LocalSystemManifest.identifier]: LocalSystem as BuiltinPlaceholder,
|
|
8
11
|
};
|