@lobehub/chat 1.106.1 → 1.106.3
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 +59 -0
- package/changelog/v1.json +21 -0
- package/package.json +2 -2
- package/src/app/(backend)/oidc/callback/desktop/route.ts +59 -8
- package/src/app/(backend)/oidc/consent/route.ts +10 -13
- package/src/config/aiModels/google.ts +0 -48
- package/src/config/aiModels/groq.ts +4 -0
- package/src/config/aiModels/hunyuan.ts +22 -0
- package/src/config/aiModels/moonshot.ts +0 -36
- package/src/config/aiModels/qwen.ts +110 -11
- package/src/config/aiModels/siliconcloud.ts +101 -0
- package/src/config/aiModels/stepfun.ts +0 -53
- package/src/config/aiModels/volcengine.ts +21 -0
- package/src/config/aiModels/zhipu.ts +132 -11
- package/src/config/modelProviders/moonshot.ts +1 -0
- package/src/libs/model-runtime/moonshot/index.ts +10 -1
- package/src/libs/model-runtime/utils/modelParse.ts +2 -2
- package/src/libs/model-runtime/zhipu/index.ts +57 -1
- package/src/utils/server/correctOIDCUrl.ts +61 -0
@@ -7,7 +7,7 @@ export interface ModelProcessorConfig {
|
|
7
7
|
visionKeywords?: readonly string[];
|
8
8
|
}
|
9
9
|
|
10
|
-
//
|
10
|
+
// 模型能力标签关键词配置
|
11
11
|
export const MODEL_LIST_CONFIGS = {
|
12
12
|
anthropic: {
|
13
13
|
functionCallKeywords: ['claude'],
|
@@ -64,7 +64,7 @@ export const MODEL_LIST_CONFIGS = {
|
|
64
64
|
},
|
65
65
|
zhipu: {
|
66
66
|
functionCallKeywords: ['glm-4', 'glm-z1'],
|
67
|
-
reasoningKeywords: ['glm-zero', 'glm-z1'],
|
67
|
+
reasoningKeywords: ['glm-zero', 'glm-z1', 'glm-4.5'],
|
68
68
|
visionKeywords: ['glm-4v'],
|
69
69
|
},
|
70
70
|
} as const;
|
@@ -1,6 +1,8 @@
|
|
1
1
|
import { ModelProvider } from '../types';
|
2
2
|
import { MODEL_LIST_CONFIGS, processModelList } from '../utils/modelParse';
|
3
3
|
import { createOpenAICompatibleRuntime } from '../utils/openaiCompatibleFactory';
|
4
|
+
import { OpenAIStream } from '../utils/streams/openai';
|
5
|
+
import { convertIterableToStream } from '../utils/streams/protocol';
|
4
6
|
|
5
7
|
export interface ZhipuModelCard {
|
6
8
|
description: string;
|
@@ -12,7 +14,8 @@ export const LobeZhipuAI = createOpenAICompatibleRuntime({
|
|
12
14
|
baseURL: 'https://open.bigmodel.cn/api/paas/v4',
|
13
15
|
chatCompletion: {
|
14
16
|
handlePayload: (payload) => {
|
15
|
-
const { enabledSearch, max_tokens, model, temperature, tools, top_p, ...rest } =
|
17
|
+
const { enabledSearch, max_tokens, model, temperature, thinking, tools, top_p, ...rest } =
|
18
|
+
payload;
|
16
19
|
|
17
20
|
const zhipuTools = enabledSearch
|
18
21
|
? [
|
@@ -39,6 +42,7 @@ export const LobeZhipuAI = createOpenAICompatibleRuntime({
|
|
39
42
|
max_tokens,
|
40
43
|
model,
|
41
44
|
stream: true,
|
45
|
+
thinking: model.includes('-4.5') ? { type: thinking?.type } : undefined,
|
42
46
|
tools: zhipuTools,
|
43
47
|
...(model === 'glm-4-alltools'
|
44
48
|
? {
|
@@ -54,6 +58,58 @@ export const LobeZhipuAI = createOpenAICompatibleRuntime({
|
|
54
58
|
}),
|
55
59
|
} as any;
|
56
60
|
},
|
61
|
+
handleStream: (stream, { callbacks, inputStartAt }) => {
|
62
|
+
const readableStream =
|
63
|
+
stream instanceof ReadableStream ? stream : convertIterableToStream(stream);
|
64
|
+
|
65
|
+
// GLM-4.5 系列模型在 tool_calls 中返回的 index 为 -1,需要在进入 OpenAIStream 之前修正
|
66
|
+
// 因为 OpenAIStream 内部会过滤掉 index < 0 的 tool_calls (openai.ts:58-60)
|
67
|
+
const preprocessedStream = readableStream.pipeThrough(
|
68
|
+
new TransformStream({
|
69
|
+
transform(chunk, controller) {
|
70
|
+
// 处理原始的 OpenAI ChatCompletionChunk 格式
|
71
|
+
if (chunk.choices && chunk.choices[0]) {
|
72
|
+
const choice = chunk.choices[0];
|
73
|
+
if (choice.delta?.tool_calls && Array.isArray(choice.delta.tool_calls)) {
|
74
|
+
// 修正负数 index,将 -1 转换为基于数组位置的正数 index
|
75
|
+
const fixedToolCalls = choice.delta.tool_calls.map(
|
76
|
+
(toolCall: any, globalIndex: number) => ({
|
77
|
+
...toolCall,
|
78
|
+
index: toolCall.index < 0 ? globalIndex : toolCall.index,
|
79
|
+
}),
|
80
|
+
);
|
81
|
+
|
82
|
+
// 创建修正后的 chunk
|
83
|
+
const fixedChunk = {
|
84
|
+
...chunk,
|
85
|
+
choices: [
|
86
|
+
{
|
87
|
+
...choice,
|
88
|
+
delta: {
|
89
|
+
...choice.delta,
|
90
|
+
tool_calls: fixedToolCalls,
|
91
|
+
},
|
92
|
+
},
|
93
|
+
],
|
94
|
+
};
|
95
|
+
|
96
|
+
controller.enqueue(fixedChunk);
|
97
|
+
} else {
|
98
|
+
controller.enqueue(chunk);
|
99
|
+
}
|
100
|
+
} else {
|
101
|
+
controller.enqueue(chunk);
|
102
|
+
}
|
103
|
+
},
|
104
|
+
}),
|
105
|
+
);
|
106
|
+
|
107
|
+
return OpenAIStream(preprocessedStream, {
|
108
|
+
callbacks,
|
109
|
+
inputStartAt,
|
110
|
+
provider: 'zhipu',
|
111
|
+
});
|
112
|
+
},
|
57
113
|
},
|
58
114
|
debug: {
|
59
115
|
chatCompletion: () => process.env.DEBUG_ZHIPU_CHAT_COMPLETION === '1',
|
@@ -0,0 +1,61 @@
|
|
1
|
+
import debug from 'debug';
|
2
|
+
import { NextRequest } from 'next/server';
|
3
|
+
|
4
|
+
const log = debug('lobe-oidc:correctOIDCUrl');
|
5
|
+
|
6
|
+
/**
|
7
|
+
* 修复 OIDC 重定向 URL 在代理环境下的问题
|
8
|
+
* @param req - Next.js 请求对象
|
9
|
+
* @param url - 要修复的 URL 对象
|
10
|
+
* @returns 修复后的 URL 对象
|
11
|
+
*/
|
12
|
+
export const correctOIDCUrl = (req: NextRequest, url: URL): URL => {
|
13
|
+
const requestHost = req.headers.get('host');
|
14
|
+
const forwardedHost = req.headers.get('x-forwarded-host');
|
15
|
+
const forwardedProto =
|
16
|
+
req.headers.get('x-forwarded-proto') || req.headers.get('x-forwarded-protocol');
|
17
|
+
|
18
|
+
log('Input URL: %s', url.toString());
|
19
|
+
log(
|
20
|
+
'Request headers - host: %s, x-forwarded-host: %s, x-forwarded-proto: %s',
|
21
|
+
requestHost,
|
22
|
+
forwardedHost,
|
23
|
+
forwardedProto,
|
24
|
+
);
|
25
|
+
|
26
|
+
// 确定实际的主机名和协议,提供后备值
|
27
|
+
const actualHost = forwardedHost || requestHost;
|
28
|
+
const actualProto = forwardedProto || (url.protocol === 'https:' ? 'https' : 'http');
|
29
|
+
|
30
|
+
// 如果无法确定有效的主机名,直接返回原URL
|
31
|
+
if (!actualHost || actualHost === 'null') {
|
32
|
+
log('Warning: Cannot determine valid host, returning original URL');
|
33
|
+
return url;
|
34
|
+
}
|
35
|
+
|
36
|
+
// 如果 URL 指向本地地址,或者主机名与实际请求主机不匹配,则修正 URL
|
37
|
+
const needsCorrection =
|
38
|
+
url.hostname === 'localhost' ||
|
39
|
+
url.hostname === '127.0.0.1' ||
|
40
|
+
url.hostname === '0.0.0.0' ||
|
41
|
+
url.hostname !== actualHost;
|
42
|
+
|
43
|
+
if (needsCorrection) {
|
44
|
+
log('URL needs correction. Original hostname: %s, correcting to: %s', url.hostname, actualHost);
|
45
|
+
|
46
|
+
try {
|
47
|
+
const correctedUrl = new URL(url.toString());
|
48
|
+
correctedUrl.protocol = actualProto + ':';
|
49
|
+
correctedUrl.host = actualHost;
|
50
|
+
|
51
|
+
log('Corrected URL: %s', correctedUrl.toString());
|
52
|
+
return correctedUrl;
|
53
|
+
} catch (error) {
|
54
|
+
log('Error creating corrected URL, returning original: %O', error);
|
55
|
+
return url;
|
56
|
+
}
|
57
|
+
}
|
58
|
+
|
59
|
+
log('URL does not need correction, returning original: %s', url.toString());
|
60
|
+
return url;
|
61
|
+
};
|