aicodeswitch 1.10.2 → 2.0.1
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 +2 -0
- package/bin/cli.js +7 -9
- package/bin/restart.js +7 -229
- package/bin/restore.js +1 -1
- package/bin/start.js +75 -87
- package/bin/stop.js +77 -14
- package/bin/ui.js +19 -134
- package/bin/update.js +1 -1
- package/bin/utils/get-server.js +58 -0
- package/bin/utils/port-utils.js +118 -0
- package/bin/version.js +1 -1
- package/dist/server/database.js +196 -116
- package/dist/server/main.js +116 -22
- package/dist/server/proxy-server.js +334 -158
- package/dist/server/transformers/claude-openai.js +86 -3
- package/dist/server/transformers/streaming.js +4 -1
- package/dist/server/utils.js +16 -0
- package/dist/ui/assets/index-BLqGemLn.js +423 -0
- package/dist/ui/assets/index-IVPeH7yC.css +1 -0
- package/dist/ui/index.html +2 -2
- package/dist/ui/migration.md +7 -0
- package/package.json +3 -2
- package/public/migration.md +7 -0
- package/dist/ui/assets/index-D6RrKKB5.js +0 -391
- package/dist/ui/assets/index-DU8EG0kT.css +0 -1
|
@@ -51,19 +51,99 @@ const mapStopReason = (finishReason) => {
|
|
|
51
51
|
}
|
|
52
52
|
};
|
|
53
53
|
exports.mapStopReason = mapStopReason;
|
|
54
|
+
/**
|
|
55
|
+
* 检查模型是否需要使用 developer 角色而不是 system 角色
|
|
56
|
+
* 某些 OpenAI 兼容的 API (如 DeepSeek) 不支持 system 角色,需要使用 developer
|
|
57
|
+
*/
|
|
58
|
+
const shouldUseDeveloperRole = (model) => {
|
|
59
|
+
if (!model)
|
|
60
|
+
return false;
|
|
61
|
+
const lowerModel = model.toLowerCase();
|
|
62
|
+
// DeepSeek 模型使用 developer 角色
|
|
63
|
+
if (lowerModel.includes('deepseek')) {
|
|
64
|
+
return true;
|
|
65
|
+
}
|
|
66
|
+
// 其他可能需要 developer 角色的模型可以在这里添加
|
|
67
|
+
// 例如:某些国内的 GPT 兼容 API
|
|
68
|
+
return false;
|
|
69
|
+
};
|
|
70
|
+
/**
|
|
71
|
+
* 智能修复 messages 数组,确保最后一条消息是 role: user
|
|
72
|
+
* OpenAI Chat API 要求对话必须以用户消息结束
|
|
73
|
+
*
|
|
74
|
+
* 处理场景:
|
|
75
|
+
* 1. 最后是 assistant 消息(带 tool_calls):添加用户消息请求执行工具
|
|
76
|
+
* 2. 最后是 assistant 消息(不带 tool_calls):添加用户继续提示
|
|
77
|
+
* 3. 最后是 tool 消息:添加用户消息请求处理工具结果
|
|
78
|
+
* 4. 最后是 system/developer 消息:添加初始用户消息
|
|
79
|
+
* 5. 最后已经是 user 消息:不处理
|
|
80
|
+
*/
|
|
81
|
+
const ensureLastMessageIsUser = (messages) => {
|
|
82
|
+
if (!messages || messages.length === 0) {
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
85
|
+
const lastMessage = messages[messages.length - 1];
|
|
86
|
+
const lastRole = lastMessage === null || lastMessage === void 0 ? void 0 : lastMessage.role;
|
|
87
|
+
// 如果最后一条已经是 user,无需处理
|
|
88
|
+
if (lastRole === 'user') {
|
|
89
|
+
return;
|
|
90
|
+
}
|
|
91
|
+
// 场景1: 最后是 assistant 消息且带有 tool_calls
|
|
92
|
+
// 这种情况下,通常后面应该跟 tool 消息,但如果没有,我们需要添加一个用户消息
|
|
93
|
+
if (lastRole === 'assistant' && lastMessage.tool_calls && Array.isArray(lastMessage.tool_calls) && lastMessage.tool_calls.length > 0) {
|
|
94
|
+
messages.push({
|
|
95
|
+
role: 'user',
|
|
96
|
+
content: 'Please proceed with the tool calls.'
|
|
97
|
+
});
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
100
|
+
// 场景2: 最后是 assistant 消息(不带 tool_calls)
|
|
101
|
+
if (lastRole === 'assistant') {
|
|
102
|
+
messages.push({
|
|
103
|
+
role: 'user',
|
|
104
|
+
content: 'Please continue.'
|
|
105
|
+
});
|
|
106
|
+
return;
|
|
107
|
+
}
|
|
108
|
+
// 场景3: 最后是 tool 消息
|
|
109
|
+
if (lastRole === 'tool') {
|
|
110
|
+
messages.push({
|
|
111
|
+
role: 'user',
|
|
112
|
+
content: 'Please analyze the tool results and continue.'
|
|
113
|
+
});
|
|
114
|
+
return;
|
|
115
|
+
}
|
|
116
|
+
// 场景4: 最后是 system/developer 消息
|
|
117
|
+
if (lastRole === 'system' || lastRole === 'developer') {
|
|
118
|
+
messages.push({
|
|
119
|
+
role: 'user',
|
|
120
|
+
content: 'Hello, I need your assistance.'
|
|
121
|
+
});
|
|
122
|
+
return;
|
|
123
|
+
}
|
|
124
|
+
// 其他未知角色,添加通用用户消息
|
|
125
|
+
messages.push({
|
|
126
|
+
role: 'user',
|
|
127
|
+
content: 'Please continue.'
|
|
128
|
+
});
|
|
129
|
+
};
|
|
54
130
|
const transformClaudeRequestToOpenAIChat = (body, targetModel) => {
|
|
55
131
|
var _a;
|
|
56
132
|
const messages = [];
|
|
133
|
+
const useDeveloperRole = shouldUseDeveloperRole(targetModel);
|
|
134
|
+
const systemRoleName = useDeveloperRole ? 'developer' : 'system';
|
|
57
135
|
if (body.system) {
|
|
58
136
|
const systemText = toTextContent(body.system);
|
|
59
137
|
if (systemText) {
|
|
60
|
-
messages.push({ role:
|
|
138
|
+
messages.push({ role: systemRoleName, content: systemText });
|
|
61
139
|
}
|
|
62
140
|
}
|
|
63
141
|
if (Array.isArray(body.messages)) {
|
|
64
142
|
for (const message of body.messages) {
|
|
143
|
+
// 映射 system 角色到 developer (如果需要)
|
|
144
|
+
const mappedRole = (message.role === 'system' && useDeveloperRole) ? 'developer' : message.role;
|
|
65
145
|
if (typeof message.content === 'string' || message.content === null) {
|
|
66
|
-
messages.push({ role:
|
|
146
|
+
messages.push({ role: mappedRole, content: message.content });
|
|
67
147
|
continue;
|
|
68
148
|
}
|
|
69
149
|
if (Array.isArray(message.content)) {
|
|
@@ -101,7 +181,7 @@ const transformClaudeRequestToOpenAIChat = (body, targetModel) => {
|
|
|
101
181
|
}
|
|
102
182
|
const content = textParts.length > 0 ? textParts.join('') : null;
|
|
103
183
|
const openaiMessage = {
|
|
104
|
-
role:
|
|
184
|
+
role: mappedRole,
|
|
105
185
|
content,
|
|
106
186
|
};
|
|
107
187
|
if (toolCalls.length > 0) {
|
|
@@ -112,6 +192,9 @@ const transformClaudeRequestToOpenAIChat = (body, targetModel) => {
|
|
|
112
192
|
}
|
|
113
193
|
}
|
|
114
194
|
}
|
|
195
|
+
// 智能修复:确保最后一条消息是 role: user
|
|
196
|
+
// OpenAI API 要求对话必须以用户消息结束
|
|
197
|
+
ensureLastMessageIsUser(messages);
|
|
115
198
|
const openaiBody = {
|
|
116
199
|
model: targetModel || body.model,
|
|
117
200
|
messages,
|
|
@@ -88,7 +88,10 @@ class SSEParserTransform extends stream_1.Transform {
|
|
|
88
88
|
exports.SSEParserTransform = SSEParserTransform;
|
|
89
89
|
class SSESerializerTransform extends stream_1.Transform {
|
|
90
90
|
constructor() {
|
|
91
|
-
super({
|
|
91
|
+
super({
|
|
92
|
+
writableObjectMode: true, // 接收对象
|
|
93
|
+
readableObjectMode: false, // 输出字符串/Buffer
|
|
94
|
+
});
|
|
92
95
|
}
|
|
93
96
|
_transform(event, _encoding, callback) {
|
|
94
97
|
var _a;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.checkPortUsable = checkPortUsable;
|
|
4
|
+
const net = require('net');
|
|
5
|
+
function checkPortUsable(port) {
|
|
6
|
+
return new Promise((resolve) => {
|
|
7
|
+
const server = net.createConnection({ port });
|
|
8
|
+
server.on('connect', () => {
|
|
9
|
+
server.end();
|
|
10
|
+
resolve(false);
|
|
11
|
+
});
|
|
12
|
+
server.on('error', () => {
|
|
13
|
+
resolve(true);
|
|
14
|
+
});
|
|
15
|
+
});
|
|
16
|
+
}
|