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}${pathToAppend}`,
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'] : '';