aicodeswitch 1.5.1 → 1.6.0
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.
|
@@ -814,6 +814,49 @@ class ProxyServer {
|
|
|
814
814
|
}
|
|
815
815
|
return undefined;
|
|
816
816
|
}
|
|
817
|
+
/**
|
|
818
|
+
* 根据源工具类型和目标API类型,映射请求路径
|
|
819
|
+
* @param sourceTool 源工具类型 (claude-code 或 codex)
|
|
820
|
+
* @param targetSourceType 目标API的数据格式类型
|
|
821
|
+
* @param originalPath 原始请求路径(已去除工具前缀)
|
|
822
|
+
* @returns 映射后的目标路径
|
|
823
|
+
*/
|
|
824
|
+
mapRequestPath(sourceTool, targetSourceType, originalPath) {
|
|
825
|
+
// Claude Code 发起的请求
|
|
826
|
+
if (sourceTool === 'claude-code') {
|
|
827
|
+
// Claude Code 默认使用 Claude API 格式
|
|
828
|
+
if (this.isClaudeSource(targetSourceType)) {
|
|
829
|
+
// Claude → Claude: 直接透传路径
|
|
830
|
+
return originalPath;
|
|
831
|
+
}
|
|
832
|
+
else if (this.isOpenAIChatSource(targetSourceType)) {
|
|
833
|
+
// Claude → OpenAI Chat: /v1/messages → /v1/chat/completions
|
|
834
|
+
return originalPath.replace(/\/v1\/messages\b/, '/v1/chat/completions');
|
|
835
|
+
}
|
|
836
|
+
else if (this.isOpenAIResponsesSource(targetSourceType)) {
|
|
837
|
+
// Claude → OpenAI Responses: /v1/messages → /v1/responses/completions
|
|
838
|
+
return originalPath.replace(/\/v1\/messages\b/, '/v1/responses/completions');
|
|
839
|
+
}
|
|
840
|
+
}
|
|
841
|
+
// Codex 发起的请求
|
|
842
|
+
if (sourceTool === 'codex') {
|
|
843
|
+
// Codex 默认使用 OpenAI Responses API 格式
|
|
844
|
+
if (this.isOpenAIResponsesSource(targetSourceType)) {
|
|
845
|
+
// OpenAI Responses → OpenAI Responses: 直接透传路径
|
|
846
|
+
return originalPath;
|
|
847
|
+
}
|
|
848
|
+
else if (this.isOpenAIChatSource(targetSourceType)) {
|
|
849
|
+
// OpenAI Responses → OpenAI Chat: /v1/responses/completions → /v1/chat/completions
|
|
850
|
+
return originalPath.replace(/\/v1\/responses\/completions\b/, '/v1/chat/completions');
|
|
851
|
+
}
|
|
852
|
+
else if (this.isClaudeSource(targetSourceType)) {
|
|
853
|
+
// OpenAI Responses → Claude: /v1/responses/completions → /v1/messages
|
|
854
|
+
return originalPath.replace(/\/v1\/responses\/completions\b/, '/v1/messages');
|
|
855
|
+
}
|
|
856
|
+
}
|
|
857
|
+
// 默认:直接返回原始路径
|
|
858
|
+
return originalPath;
|
|
859
|
+
}
|
|
817
860
|
proxyRequest(req, res, route, rule, service) {
|
|
818
861
|
return __awaiter(this, void 0, void 0, function* () {
|
|
819
862
|
var _a;
|
|
@@ -828,6 +871,7 @@ class ProxyServer {
|
|
|
828
871
|
let responseHeadersForLog;
|
|
829
872
|
let responseBodyForLog;
|
|
830
873
|
let streamChunksForLog;
|
|
874
|
+
let upstreamRequestForLog;
|
|
831
875
|
const finalizeLog = (statusCode, error) => __awaiter(this, void 0, void 0, function* () {
|
|
832
876
|
var _a, _b;
|
|
833
877
|
if (logged || !((_a = this.config) === null || _a === void 0 ? void 0 : _a.enableLogging))
|
|
@@ -860,6 +904,7 @@ class ProxyServer {
|
|
|
860
904
|
responseHeaders: responseHeadersForLog,
|
|
861
905
|
responseBody: responseBodyForLog,
|
|
862
906
|
streamChunks: streamChunksForLog,
|
|
907
|
+
upstreamRequest: upstreamRequestForLog,
|
|
863
908
|
});
|
|
864
909
|
});
|
|
865
910
|
try {
|
|
@@ -904,9 +949,11 @@ class ProxyServer {
|
|
|
904
949
|
else if (route.targetType === 'codex' && req.path.startsWith('/codex')) {
|
|
905
950
|
pathToAppend = req.path.slice('/codex'.length);
|
|
906
951
|
}
|
|
952
|
+
// 根据源工具类型和目标API类型,映射请求路径
|
|
953
|
+
const mappedPath = this.mapRequestPath(route.targetType, sourceType, pathToAppend);
|
|
907
954
|
const config = {
|
|
908
955
|
method: req.method,
|
|
909
|
-
url: `${service.apiUrl}${
|
|
956
|
+
url: `${service.apiUrl}${mappedPath}`,
|
|
910
957
|
headers: this.buildUpstreamHeaders(req, service, sourceType, streamRequested),
|
|
911
958
|
timeout: service.timeout || 30000,
|
|
912
959
|
validateStatus: () => true,
|
|
@@ -918,6 +965,11 @@ class ProxyServer {
|
|
|
918
965
|
if (['POST', 'PUT', 'PATCH'].includes(req.method.toUpperCase())) {
|
|
919
966
|
config.data = requestBody;
|
|
920
967
|
}
|
|
968
|
+
// 记录实际发出的请求信息作为日志的一部分
|
|
969
|
+
upstreamRequestForLog = {
|
|
970
|
+
url: `${service.apiUrl}${mappedPath}`,
|
|
971
|
+
model: (requestBody === null || requestBody === void 0 ? void 0 : requestBody.model) || '',
|
|
972
|
+
};
|
|
921
973
|
const response = yield (0, axios_1.default)(config);
|
|
922
974
|
const responseHeaders = response.headers || {};
|
|
923
975
|
const contentType = typeof responseHeaders['content-type'] === 'string' ? responseHeaders['content-type'] : '';
|