@kaitranntt/ccs 7.71.0-dev.1 → 7.71.0-dev.10

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.
Files changed (261) hide show
  1. package/README.md +34 -0
  2. package/config/base-codebuddy.settings.json +10 -0
  3. package/config/base-cursor.settings.json +10 -0
  4. package/config/base-gitlab.settings.json +10 -0
  5. package/config/base-kilo.settings.json +10 -0
  6. package/dist/auth/profile-detector.d.ts +2 -3
  7. package/dist/auth/profile-detector.d.ts.map +1 -1
  8. package/dist/auth/profile-detector.js +19 -19
  9. package/dist/auth/profile-detector.js.map +1 -1
  10. package/dist/ccs.js +66 -4
  11. package/dist/ccs.js.map +1 -1
  12. package/dist/cliproxy/accounts/email-account-identity.d.ts.map +1 -1
  13. package/dist/cliproxy/accounts/email-account-identity.js +22 -2
  14. package/dist/cliproxy/accounts/email-account-identity.js.map +1 -1
  15. package/dist/cliproxy/auth/auth-types.d.ts +10 -0
  16. package/dist/cliproxy/auth/auth-types.d.ts.map +1 -1
  17. package/dist/cliproxy/auth/auth-types.js +32 -0
  18. package/dist/cliproxy/auth/auth-types.js.map +1 -1
  19. package/dist/cliproxy/auth/gitlab-pat-response.d.ts +9 -0
  20. package/dist/cliproxy/auth/gitlab-pat-response.d.ts.map +1 -0
  21. package/dist/cliproxy/auth/gitlab-pat-response.js +64 -0
  22. package/dist/cliproxy/auth/gitlab-pat-response.js.map +1 -0
  23. package/dist/cliproxy/auth/kiro-import.js +1 -1
  24. package/dist/cliproxy/auth/kiro-import.js.map +1 -1
  25. package/dist/cliproxy/auth/oauth-handler.d.ts +3 -0
  26. package/dist/cliproxy/auth/oauth-handler.d.ts.map +1 -1
  27. package/dist/cliproxy/auth/oauth-handler.js +120 -4
  28. package/dist/cliproxy/auth/oauth-handler.js.map +1 -1
  29. package/dist/cliproxy/binary/lifecycle.d.ts.map +1 -1
  30. package/dist/cliproxy/binary/lifecycle.js +12 -1
  31. package/dist/cliproxy/binary/lifecycle.js.map +1 -1
  32. package/dist/cliproxy/binary-manager.d.ts +5 -1
  33. package/dist/cliproxy/binary-manager.d.ts.map +1 -1
  34. package/dist/cliproxy/binary-manager.js +10 -2
  35. package/dist/cliproxy/binary-manager.js.map +1 -1
  36. package/dist/cliproxy/config/env-builder.d.ts +5 -0
  37. package/dist/cliproxy/config/env-builder.d.ts.map +1 -1
  38. package/dist/cliproxy/config/env-builder.js +56 -4
  39. package/dist/cliproxy/config/env-builder.js.map +1 -1
  40. package/dist/cliproxy/config/path-resolver.d.ts +21 -0
  41. package/dist/cliproxy/config/path-resolver.d.ts.map +1 -1
  42. package/dist/cliproxy/config/path-resolver.js +42 -2
  43. package/dist/cliproxy/config/path-resolver.js.map +1 -1
  44. package/dist/cliproxy/executor/index.d.ts +1 -0
  45. package/dist/cliproxy/executor/index.d.ts.map +1 -1
  46. package/dist/cliproxy/executor/index.js +32 -2
  47. package/dist/cliproxy/executor/index.js.map +1 -1
  48. package/dist/cliproxy/model-config.js +4 -4
  49. package/dist/cliproxy/model-config.js.map +1 -1
  50. package/dist/cliproxy/provider-capabilities.d.ts.map +1 -1
  51. package/dist/cliproxy/provider-capabilities.js +48 -0
  52. package/dist/cliproxy/provider-capabilities.js.map +1 -1
  53. package/dist/cliproxy/quota-fetcher-claude-normalizer.d.ts +1 -5
  54. package/dist/cliproxy/quota-fetcher-claude-normalizer.d.ts.map +1 -1
  55. package/dist/cliproxy/quota-fetcher-claude-normalizer.js +33 -6
  56. package/dist/cliproxy/quota-fetcher-claude-normalizer.js.map +1 -1
  57. package/dist/cliproxy/quota-fetcher-claude.d.ts +2 -2
  58. package/dist/cliproxy/quota-fetcher-claude.d.ts.map +1 -1
  59. package/dist/cliproxy/quota-fetcher-claude.js +18 -32
  60. package/dist/cliproxy/quota-fetcher-claude.js.map +1 -1
  61. package/dist/cliproxy/quota-fetcher-codex.d.ts.map +1 -1
  62. package/dist/cliproxy/quota-fetcher-codex.js +2 -0
  63. package/dist/cliproxy/quota-fetcher-codex.js.map +1 -1
  64. package/dist/cliproxy/quota-types.d.ts +2 -2
  65. package/dist/cliproxy/quota-types.d.ts.map +1 -1
  66. package/dist/cliproxy/service-manager.d.ts.map +1 -1
  67. package/dist/cliproxy/service-manager.js +4 -1
  68. package/dist/cliproxy/service-manager.js.map +1 -1
  69. package/dist/cliproxy/types.d.ts +11 -3
  70. package/dist/cliproxy/types.d.ts.map +1 -1
  71. package/dist/cliproxy/types.js +8 -1
  72. package/dist/cliproxy/types.js.map +1 -1
  73. package/dist/commands/command-catalog.d.ts +2 -1
  74. package/dist/commands/command-catalog.d.ts.map +1 -1
  75. package/dist/commands/command-catalog.js +21 -4
  76. package/dist/commands/command-catalog.js.map +1 -1
  77. package/dist/commands/completion-backend.d.ts.map +1 -1
  78. package/dist/commands/completion-backend.js +4 -0
  79. package/dist/commands/completion-backend.js.map +1 -1
  80. package/dist/commands/cursor-command-display.d.ts.map +1 -1
  81. package/dist/commands/cursor-command-display.js +43 -30
  82. package/dist/commands/cursor-command-display.js.map +1 -1
  83. package/dist/commands/cursor-command.d.ts.map +1 -1
  84. package/dist/commands/cursor-command.js +30 -13
  85. package/dist/commands/cursor-command.js.map +1 -1
  86. package/dist/commands/help-command.d.ts +2 -0
  87. package/dist/commands/help-command.d.ts.map +1 -1
  88. package/dist/commands/help-command.js +55 -2
  89. package/dist/commands/help-command.js.map +1 -1
  90. package/dist/commands/index.d.ts +1 -0
  91. package/dist/commands/index.d.ts.map +1 -1
  92. package/dist/commands/index.js +3 -1
  93. package/dist/commands/index.js.map +1 -1
  94. package/dist/commands/proxy-command.d.ts +2 -0
  95. package/dist/commands/proxy-command.d.ts.map +1 -0
  96. package/dist/commands/proxy-command.js +156 -0
  97. package/dist/commands/proxy-command.js.map +1 -0
  98. package/dist/commands/root-command-router.d.ts.map +1 -1
  99. package/dist/commands/root-command-router.js +7 -0
  100. package/dist/commands/root-command-router.js.map +1 -1
  101. package/dist/config/reserved-names.d.ts +1 -1
  102. package/dist/config/reserved-names.d.ts.map +1 -1
  103. package/dist/config/reserved-names.js +10 -0
  104. package/dist/config/reserved-names.js.map +1 -1
  105. package/dist/config/unified-config-loader.d.ts.map +1 -1
  106. package/dist/config/unified-config-loader.js +19 -0
  107. package/dist/config/unified-config-loader.js.map +1 -1
  108. package/dist/config/unified-config-types.d.ts +14 -0
  109. package/dist/config/unified-config-types.d.ts.map +1 -1
  110. package/dist/config/unified-config-types.js +11 -1
  111. package/dist/config/unified-config-types.js.map +1 -1
  112. package/dist/cursor/constants.d.ts +3 -0
  113. package/dist/cursor/constants.d.ts.map +1 -1
  114. package/dist/cursor/constants.js +26 -1
  115. package/dist/cursor/constants.js.map +1 -1
  116. package/dist/cursor/cursor-anthropic-response.d.ts +1 -6
  117. package/dist/cursor/cursor-anthropic-response.d.ts.map +1 -1
  118. package/dist/cursor/cursor-anthropic-response.js +3 -186
  119. package/dist/cursor/cursor-anthropic-response.js.map +1 -1
  120. package/dist/cursor/cursor-daemon-entry.js +2 -2
  121. package/dist/cursor/cursor-daemon-entry.js.map +1 -1
  122. package/dist/cursor/cursor-profile-executor.js +4 -4
  123. package/dist/cursor/cursor-profile-executor.js.map +1 -1
  124. package/dist/cursor/cursor-runtime-probe.js +3 -3
  125. package/dist/cursor/cursor-runtime-probe.js.map +1 -1
  126. package/dist/glmt/sse-parser.d.ts.map +1 -1
  127. package/dist/glmt/sse-parser.js +46 -41
  128. package/dist/glmt/sse-parser.js.map +1 -1
  129. package/dist/management/shared-manager.d.ts +2 -0
  130. package/dist/management/shared-manager.d.ts.map +1 -1
  131. package/dist/management/shared-manager.js +25 -10
  132. package/dist/management/shared-manager.js.map +1 -1
  133. package/dist/proxy/index.d.ts +8 -0
  134. package/dist/proxy/index.d.ts.map +1 -0
  135. package/dist/proxy/index.js +24 -0
  136. package/dist/proxy/index.js.map +1 -0
  137. package/dist/proxy/profile-router.d.ts +28 -0
  138. package/dist/proxy/profile-router.d.ts.map +1 -0
  139. package/dist/proxy/profile-router.js +43 -0
  140. package/dist/proxy/profile-router.js.map +1 -0
  141. package/dist/proxy/proxy-daemon-entry.d.ts +2 -0
  142. package/dist/proxy/proxy-daemon-entry.d.ts.map +1 -0
  143. package/dist/proxy/proxy-daemon-entry.js +68 -0
  144. package/dist/proxy/proxy-daemon-entry.js.map +1 -0
  145. package/dist/proxy/proxy-daemon-paths.d.ts +6 -0
  146. package/dist/proxy/proxy-daemon-paths.d.ts.map +1 -0
  147. package/dist/proxy/proxy-daemon-paths.js +43 -0
  148. package/dist/proxy/proxy-daemon-paths.js.map +1 -0
  149. package/dist/proxy/proxy-daemon-state.d.ts +18 -0
  150. package/dist/proxy/proxy-daemon-state.d.ts.map +1 -0
  151. package/dist/proxy/proxy-daemon-state.js +92 -0
  152. package/dist/proxy/proxy-daemon-state.js.map +1 -0
  153. package/dist/proxy/proxy-daemon.d.ts +26 -0
  154. package/dist/proxy/proxy-daemon.d.ts.map +1 -0
  155. package/dist/proxy/proxy-daemon.js +350 -0
  156. package/dist/proxy/proxy-daemon.js.map +1 -0
  157. package/dist/proxy/proxy-env.d.ts +3 -0
  158. package/dist/proxy/proxy-env.d.ts.map +1 -0
  159. package/dist/proxy/proxy-env.js +26 -0
  160. package/dist/proxy/proxy-env.js.map +1 -0
  161. package/dist/proxy/request-router.d.ts +12 -0
  162. package/dist/proxy/request-router.d.ts.map +1 -0
  163. package/dist/proxy/request-router.js +163 -0
  164. package/dist/proxy/request-router.js.map +1 -0
  165. package/dist/proxy/routing-config.d.ts +10 -0
  166. package/dist/proxy/routing-config.d.ts.map +1 -0
  167. package/dist/proxy/routing-config.js +79 -0
  168. package/dist/proxy/routing-config.js.map +1 -0
  169. package/dist/proxy/server/http-helpers.d.ts +8 -0
  170. package/dist/proxy/server/http-helpers.d.ts.map +1 -0
  171. package/dist/proxy/server/http-helpers.js +73 -0
  172. package/dist/proxy/server/http-helpers.js.map +1 -0
  173. package/dist/proxy/server/messages-route.d.ts +12 -0
  174. package/dist/proxy/server/messages-route.d.ts.map +1 -0
  175. package/dist/proxy/server/messages-route.js +208 -0
  176. package/dist/proxy/server/messages-route.js.map +1 -0
  177. package/dist/proxy/server/proxy-server.d.ts +12 -0
  178. package/dist/proxy/server/proxy-server.d.ts.map +1 -0
  179. package/dist/proxy/server/proxy-server.js +110 -0
  180. package/dist/proxy/server/proxy-server.js.map +1 -0
  181. package/dist/proxy/transformers/request-transformer.d.ts +52 -0
  182. package/dist/proxy/transformers/request-transformer.d.ts.map +1 -0
  183. package/dist/proxy/transformers/request-transformer.js +254 -0
  184. package/dist/proxy/transformers/request-transformer.js.map +1 -0
  185. package/dist/proxy/transformers/sse-stream-transformer.d.ts +11 -0
  186. package/dist/proxy/transformers/sse-stream-transformer.d.ts.map +1 -0
  187. package/dist/proxy/transformers/sse-stream-transformer.js +199 -0
  188. package/dist/proxy/transformers/sse-stream-transformer.js.map +1 -0
  189. package/dist/proxy/upstream-url.d.ts +3 -0
  190. package/dist/proxy/upstream-url.d.ts.map +1 -0
  191. package/dist/proxy/upstream-url.js +35 -0
  192. package/dist/proxy/upstream-url.js.map +1 -0
  193. package/dist/shared/claude-extension-setup.js +1 -1
  194. package/dist/shared/claude-extension-setup.js.map +1 -1
  195. package/dist/targets/droid-provider.d.ts.map +1 -1
  196. package/dist/targets/droid-provider.js +2 -0
  197. package/dist/targets/droid-provider.js.map +1 -1
  198. package/dist/types/config.d.ts +13 -0
  199. package/dist/types/config.d.ts.map +1 -1
  200. package/dist/types/config.js.map +1 -1
  201. package/dist/types/index.d.ts +1 -1
  202. package/dist/types/index.d.ts.map +1 -1
  203. package/dist/types/index.js.map +1 -1
  204. package/dist/ui/assets/{accounts-B8EmUjf7.js → accounts-Cr7W1buT.js} +1 -1
  205. package/dist/ui/assets/{alert-dialog-zvnFuSZG.js → alert-dialog-C96SrxIc.js} +1 -1
  206. package/dist/ui/assets/{api-vTHvDFg5.js → api-DYkus27c.js} +1 -1
  207. package/dist/ui/assets/{auth-section-Dg3AdWQR.js → auth-section-CxMIfDdS.js} +1 -1
  208. package/dist/ui/assets/{backups-section-CuRlCk7U.js → backups-section-2mpHmgVy.js} +1 -1
  209. package/dist/ui/assets/{channels-ByIXpMal.js → channels-D525HeAb.js} +1 -1
  210. package/dist/ui/assets/{checkbox-DoV2JinM.js → checkbox-CQ1Ps6GL.js} +1 -1
  211. package/dist/ui/assets/{claude-extension-B-Ofp87Z.js → claude-extension-Etkm5mj8.js} +1 -1
  212. package/dist/ui/assets/cliproxy-CtGOikbg.js +3 -0
  213. package/dist/ui/assets/{cliproxy-ai-providers-BVOtMT7b.js → cliproxy-ai-providers-OsVlLpCW.js} +1 -1
  214. package/dist/ui/assets/{cliproxy-control-panel-qL0R878z.js → cliproxy-control-panel-Ds5WBaJL.js} +1 -1
  215. package/dist/ui/assets/{codex-BCHZ-0dx.js → codex-Cjj2T2eA.js} +1 -1
  216. package/dist/ui/assets/{confirm-dialog-BcfzKHj3.js → confirm-dialog-BWtF62KB.js} +1 -1
  217. package/dist/ui/assets/{copilot-Dti40Uv-.js → copilot-jL0eEQoq.js} +1 -1
  218. package/dist/ui/assets/cursor-CCc4tTX_.js +1 -0
  219. package/dist/ui/assets/{droid-BmuIeDFh.js → droid-DqCUCvdJ.js} +2 -2
  220. package/dist/ui/assets/{globalenv-section-CGbpkbpW.js → globalenv-section-psU6xwvx.js} +1 -1
  221. package/dist/ui/assets/{health-DryU1jzv.js → health-ChHRngKH.js} +1 -1
  222. package/dist/ui/assets/{index-Cu--MLG0.js → index-CIIjSQmj.js} +1 -1
  223. package/dist/ui/assets/{index-DUCkRc_D.js → index-CsS3wNix.js} +1 -1
  224. package/dist/ui/assets/index-CsgUrwXk.js +1 -0
  225. package/dist/ui/assets/index-DzJi9m-K.css +1 -0
  226. package/dist/ui/assets/{index-B_vdNMI1.js → index-SYCXM7Jq.js} +1 -1
  227. package/dist/ui/assets/{index-Dgu-LYP_.js → index-a2T7PPUI.js} +1 -1
  228. package/dist/ui/assets/index-lHI_E9S9.js +72 -0
  229. package/dist/ui/assets/{logs-CtIgaS7y.js → logs-DntALG8B.js} +1 -1
  230. package/dist/ui/assets/{masked-input-Dm8T-Vtr.js → masked-input-CYdjMOZg.js} +1 -1
  231. package/dist/ui/assets/providers/codebuddy.png +0 -0
  232. package/dist/ui/assets/providers/cursor.svg +5 -0
  233. package/dist/ui/assets/providers/gitlab.svg +22 -0
  234. package/dist/ui/assets/providers/kilo.png +0 -0
  235. package/dist/ui/assets/{proxy-status-widget-BXghaDz7.js → proxy-status-widget-CLsv7grw.js} +1 -1
  236. package/dist/ui/assets/{raw-json-settings-editor-panel-DhhcWn5Q.js → raw-json-settings-editor-panel-BZlH8urA.js} +1 -1
  237. package/dist/ui/assets/{searchable-select-DiGUiefs.js → searchable-select-D-ry9mQV.js} +1 -1
  238. package/dist/ui/assets/{separator-DnQqlaL0.js → separator-DKvhcyfD.js} +1 -1
  239. package/dist/ui/assets/{shared-BPuiJsYO.js → shared-Z5QeA443.js} +1 -1
  240. package/dist/ui/assets/{table-BDsTJlxT.js → table-DHcccdh4.js} +1 -1
  241. package/dist/ui/assets/{updates-DQxYQBCf.js → updates-B78utNho.js} +1 -1
  242. package/dist/ui/index.html +2 -2
  243. package/dist/utils/hooks/image-analysis-backend-resolver.js +1 -1
  244. package/dist/utils/hooks/image-analysis-backend-resolver.js.map +1 -1
  245. package/dist/web-server/routes/cliproxy-auth-routes.d.ts.map +1 -1
  246. package/dist/web-server/routes/cliproxy-auth-routes.js +124 -1
  247. package/dist/web-server/routes/cliproxy-auth-routes.js.map +1 -1
  248. package/dist/web-server/routes/config-routes.d.ts.map +1 -1
  249. package/dist/web-server/routes/config-routes.js +3 -0
  250. package/dist/web-server/routes/config-routes.js.map +1 -1
  251. package/dist/web-server/routes/index.js +1 -0
  252. package/dist/web-server/routes/index.js.map +1 -1
  253. package/dist/web-server/routes/settings-routes.d.ts.map +1 -1
  254. package/dist/web-server/routes/settings-routes.js +8 -0
  255. package/dist/web-server/routes/settings-routes.js.map +1 -1
  256. package/package.json +1 -1
  257. package/dist/ui/assets/cliproxy-Bhu0JvIb.js +0 -3
  258. package/dist/ui/assets/cursor-BG0Y8Z5F.js +0 -1
  259. package/dist/ui/assets/index-B1mN7ZR-.js +0 -72
  260. package/dist/ui/assets/index-BBVoDJnl.js +0 -1
  261. package/dist/ui/assets/index-BMC5Tudw.css +0 -1
@@ -0,0 +1,208 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.handleProxyModelsRequest = exports.handleProxyMessagesRequest = exports.attachDisconnectAbortHandlers = exports.validateIncomingProxyAuth = exports.extractIncomingProxyToken = void 0;
4
+ const request_router_1 = require("../request-router");
5
+ const request_transformer_1 = require("../transformers/request-transformer");
6
+ const sse_stream_transformer_1 = require("../transformers/sse-stream-transformer");
7
+ const upstream_url_1 = require("../upstream-url");
8
+ const logging_1 = require("../../services/logging");
9
+ const http_helpers_1 = require("./http-helpers");
10
+ const REQUEST_TIMEOUT_MS = 600000;
11
+ const logger = (0, logging_1.createLogger)('proxy:openai-compat:messages');
12
+ class ProxyInputError extends Error {
13
+ constructor(message) {
14
+ super(message);
15
+ this.name = 'ProxyInputError';
16
+ }
17
+ }
18
+ function buildUpstreamHeaders(profile) {
19
+ return {
20
+ 'Content-Type': 'application/json',
21
+ Authorization: `Bearer ${profile.apiKey}`,
22
+ 'User-Agent': 'CCS-OpenAI-Compat-Proxy/1.0',
23
+ };
24
+ }
25
+ function buildUpstreamRequest(profile, rawBody) {
26
+ let transformed;
27
+ try {
28
+ const transformer = new request_transformer_1.ProxyRequestTransformer();
29
+ transformed = transformer.transform(rawBody);
30
+ }
31
+ catch (error) {
32
+ const message = error instanceof Error ? error.message : 'Invalid Anthropic request';
33
+ throw new ProxyInputError(message);
34
+ }
35
+ const route = (0, request_router_1.resolveProxyRequestRoute)(profile, transformed);
36
+ const body = {
37
+ ...transformed,
38
+ model: route.model || route.profile.model,
39
+ stream: transformed.stream === true,
40
+ };
41
+ return { body: JSON.stringify(body), route };
42
+ }
43
+ function extractIncomingProxyToken(headers) {
44
+ const xApiKey = headers['x-api-key'];
45
+ if (typeof xApiKey === 'string' && xApiKey.trim().length > 0) {
46
+ return xApiKey.trim();
47
+ }
48
+ const anthropicApiKey = headers['anthropic-api-key'];
49
+ if (typeof anthropicApiKey === 'string' && anthropicApiKey.trim().length > 0) {
50
+ return anthropicApiKey.trim();
51
+ }
52
+ const authHeader = headers.authorization;
53
+ if (typeof authHeader === 'string' && authHeader.trim().length > 0) {
54
+ const trimmed = authHeader.trim();
55
+ const bearerPrefix = 'Bearer ';
56
+ return trimmed.startsWith(bearerPrefix) ? trimmed.slice(bearerPrefix.length).trim() : trimmed;
57
+ }
58
+ return null;
59
+ }
60
+ exports.extractIncomingProxyToken = extractIncomingProxyToken;
61
+ function validateIncomingProxyAuth(headers, expectedToken) {
62
+ return extractIncomingProxyToken(headers) === expectedToken;
63
+ }
64
+ exports.validateIncomingProxyAuth = validateIncomingProxyAuth;
65
+ function buildFetchInit(profile, body, signal, insecureDispatcher) {
66
+ const init = {
67
+ method: 'POST',
68
+ headers: buildUpstreamHeaders(profile),
69
+ body,
70
+ signal,
71
+ };
72
+ if (insecureDispatcher) {
73
+ init.dispatcher = insecureDispatcher;
74
+ }
75
+ return init;
76
+ }
77
+ function getRequestTimeoutMs() {
78
+ const rawValue = process.env.CCS_OPENAI_PROXY_REQUEST_TIMEOUT_MS;
79
+ if (!rawValue) {
80
+ return REQUEST_TIMEOUT_MS;
81
+ }
82
+ const parsed = Number.parseInt(rawValue, 10);
83
+ return Number.isFinite(parsed) && parsed > 0 ? parsed : REQUEST_TIMEOUT_MS;
84
+ }
85
+ function formatTimeoutDuration(timeoutMs) {
86
+ return timeoutMs % 1000 === 0 ? `${timeoutMs / 1000} seconds` : `${timeoutMs}ms`;
87
+ }
88
+ function registerOnceListener(emitter, event, handler) {
89
+ if (!emitter) {
90
+ return () => { };
91
+ }
92
+ emitter.once(event, handler);
93
+ return () => {
94
+ emitter.removeListener(event, handler);
95
+ };
96
+ }
97
+ function attachDisconnectAbortHandlers(req, res, controller, onDisconnect) {
98
+ const abortOnDisconnect = (source) => {
99
+ if (!controller.signal.aborted && !res.writableEnded) {
100
+ onDisconnect(source);
101
+ controller.abort();
102
+ }
103
+ };
104
+ const cleanupFns = [
105
+ registerOnceListener(req, 'aborted', () => abortOnDisconnect('req.aborted')),
106
+ registerOnceListener(req, 'close', () => abortOnDisconnect('req.close')),
107
+ registerOnceListener(req.socket, 'close', () => abortOnDisconnect('req.socket.close')),
108
+ registerOnceListener(res, 'close', () => abortOnDisconnect('res.close')),
109
+ registerOnceListener(res.socket, 'close', () => abortOnDisconnect('res.socket.close')),
110
+ ];
111
+ const disconnectPoll = setInterval(() => {
112
+ if (req.destroyed ||
113
+ res.destroyed ||
114
+ req.socket?.destroyed === true ||
115
+ res.socket?.destroyed === true) {
116
+ abortOnDisconnect('poll.destroyed');
117
+ }
118
+ }, 50);
119
+ return () => {
120
+ clearInterval(disconnectPoll);
121
+ for (const cleanup of cleanupFns) {
122
+ cleanup();
123
+ }
124
+ };
125
+ }
126
+ exports.attachDisconnectAbortHandlers = attachDisconnectAbortHandlers;
127
+ async function handleProxyMessagesRequest(req, res, profile, expectedAuthToken, insecureDispatcher) {
128
+ const transformer = new sse_stream_transformer_1.ProxySseStreamTransformer();
129
+ if (!validateIncomingProxyAuth(req.headers, expectedAuthToken)) {
130
+ logger.warn('auth.invalid', 'Rejected proxy message request with invalid auth token', {
131
+ remoteAddress: req.socket.remoteAddress || null,
132
+ });
133
+ await (0, http_helpers_1.pipeWebResponseToNode)(transformer.error(401, 'authentication_error', 'Missing or invalid local proxy token'), res);
134
+ return;
135
+ }
136
+ let timeoutMs = REQUEST_TIMEOUT_MS;
137
+ try {
138
+ const rawBody = await (0, http_helpers_1.readJsonBody)(req);
139
+ const upstream = buildUpstreamRequest(profile, rawBody);
140
+ logger.info('request.forward', 'Forwarding Anthropic request to OpenAI-compatible upstream', {
141
+ profileName: upstream.route.profile.profileName,
142
+ provider: upstream.route.profile.provider,
143
+ baseUrl: upstream.route.profile.baseUrl,
144
+ model: upstream.route.model || upstream.route.profile.model || null,
145
+ routeSource: upstream.route.source,
146
+ scenario: upstream.route.scenario || null,
147
+ estimatedTokens: upstream.route.estimatedTokens,
148
+ });
149
+ const controller = new AbortController();
150
+ timeoutMs = getRequestTimeoutMs();
151
+ const timeout = setTimeout(() => controller.abort(), timeoutMs);
152
+ const cleanupDisconnectHandlers = attachDisconnectAbortHandlers(req, res, controller, (source) => {
153
+ logger.info('request.disconnect', 'Aborting upstream request after local client disconnect', {
154
+ profileName: profile.profileName,
155
+ source,
156
+ });
157
+ });
158
+ try {
159
+ const upstreamResponse = await fetch((0, upstream_url_1.resolveOpenAIChatCompletionsUrl)(upstream.route.profile.baseUrl), buildFetchInit(upstream.route.profile, upstream.body, controller.signal, insecureDispatcher));
160
+ logger.info('response.received', 'Received upstream response', {
161
+ profileName: profile.profileName,
162
+ routedProfileName: upstream.route.profile.profileName,
163
+ status: upstreamResponse.status,
164
+ });
165
+ const response = await transformer.transform(upstreamResponse);
166
+ await (0, http_helpers_1.pipeWebResponseToNode)(response, res);
167
+ }
168
+ finally {
169
+ clearTimeout(timeout);
170
+ cleanupDisconnectHandlers();
171
+ }
172
+ }
173
+ catch (error) {
174
+ const message = error instanceof Error ? error.message : 'Unknown proxy error';
175
+ logger.error('request.failed', 'Proxy message request failed', {
176
+ profileName: profile.profileName,
177
+ error: message,
178
+ abort: error instanceof Error && error.name === 'AbortError',
179
+ });
180
+ const status = error instanceof Error && error.name === 'AbortError'
181
+ ? 502
182
+ : error instanceof ProxyInputError
183
+ ? 400
184
+ : message.includes('Request body too large')
185
+ ? 413
186
+ : message.includes('Invalid JSON')
187
+ ? 400
188
+ : 502;
189
+ const type = status >= 500 ? 'api_error' : 'invalid_request_error';
190
+ await (0, http_helpers_1.pipeWebResponseToNode)(transformer.error(status, type, error instanceof Error && error.name === 'AbortError'
191
+ ? `The upstream provider did not respond within ${formatTimeoutDuration(timeoutMs)}`
192
+ : message), res);
193
+ }
194
+ }
195
+ exports.handleProxyMessagesRequest = handleProxyMessagesRequest;
196
+ function handleProxyModelsRequest(res, profile) {
197
+ const data = [profile.model, profile.opusModel, profile.sonnetModel, profile.haikuModel]
198
+ .filter((value) => typeof value === 'string' && value.length > 0)
199
+ .map((id) => ({
200
+ id,
201
+ object: 'model',
202
+ created: 0,
203
+ owned_by: profile.provider,
204
+ }));
205
+ (0, http_helpers_1.writeJson)(res, 200, { object: 'list', data });
206
+ }
207
+ exports.handleProxyModelsRequest = handleProxyModelsRequest;
208
+ //# sourceMappingURL=messages-route.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"messages-route.js","sourceRoot":"","sources":["../../../src/proxy/server/messages-route.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,12 @@
1
+ /// <reference types="node" />
2
+ import * as http from 'http';
3
+ import type { OpenAICompatProfileConfig } from '../profile-router';
4
+ export interface OpenAICompatProxyServerOptions {
5
+ profile: OpenAICompatProfileConfig;
6
+ host?: string;
7
+ port: number;
8
+ authToken: string;
9
+ insecure?: boolean;
10
+ }
11
+ export declare function startOpenAICompatProxyServer(options: OpenAICompatProxyServerOptions): http.Server;
12
+ //# sourceMappingURL=proxy-server.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"proxy-server.d.ts","sourceRoot":"","sources":["../../../src/proxy/server/proxy-server.ts"],"names":[],"mappings":";AAAA,OAAO,KAAK,IAAI,MAAM,MAAM,CAAC;AAE7B,OAAO,KAAK,EAAE,yBAAyB,EAAE,MAAM,mBAAmB,CAAC;AAUnE,MAAM,WAAW,8BAA8B;IAC7C,OAAO,EAAE,yBAAyB,CAAC;IACnC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAED,wBAAgB,4BAA4B,CAAC,OAAO,EAAE,8BAA8B,GAAG,IAAI,CAAC,MAAM,CAyFjG"}
@@ -0,0 +1,110 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || function (mod) {
19
+ if (mod && mod.__esModule) return mod;
20
+ var result = {};
21
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22
+ __setModuleDefault(result, mod);
23
+ return result;
24
+ };
25
+ Object.defineProperty(exports, "__esModule", { value: true });
26
+ exports.startOpenAICompatProxyServer = void 0;
27
+ const http = __importStar(require("http"));
28
+ const undici_1 = require("undici");
29
+ const proxy_daemon_paths_1 = require("../proxy-daemon-paths");
30
+ const logging_1 = require("../../services/logging");
31
+ const messages_route_1 = require("./messages-route");
32
+ const http_helpers_1 = require("./http-helpers");
33
+ function startOpenAICompatProxyServer(options) {
34
+ const host = options.host?.trim() || '127.0.0.1';
35
+ const logger = (0, logging_1.createLogger)('proxy:openai-compat', {
36
+ profileName: options.profile.profileName,
37
+ host,
38
+ port: options.port,
39
+ });
40
+ const insecureDispatcher = options.insecure
41
+ ? new undici_1.Agent({ connect: { rejectUnauthorized: false } })
42
+ : undefined;
43
+ const server = http.createServer(async (req, res) => {
44
+ const method = req.method || 'GET';
45
+ const requestUrl = req.url || '/';
46
+ const parsedUrl = new URL(requestUrl, 'http://127.0.0.1');
47
+ const pathname = parsedUrl.pathname.length > 1 ? parsedUrl.pathname.replace(/\/+$/, '') : parsedUrl.pathname;
48
+ if (method === 'GET' && pathname === '/health') {
49
+ (0, http_helpers_1.writeJson)(res, 200, {
50
+ ok: true,
51
+ service: proxy_daemon_paths_1.OPENAI_COMPAT_PROXY_SERVICE_NAME,
52
+ host,
53
+ profile: options.profile.profileName,
54
+ port: options.port,
55
+ });
56
+ return;
57
+ }
58
+ if (method === 'GET' && pathname === '/') {
59
+ (0, http_helpers_1.writeJson)(res, 200, {
60
+ ok: true,
61
+ service: proxy_daemon_paths_1.OPENAI_COMPAT_PROXY_SERVICE_NAME,
62
+ bind: {
63
+ host,
64
+ port: options.port,
65
+ },
66
+ profile: {
67
+ name: options.profile.profileName,
68
+ provider: options.profile.provider,
69
+ model: options.profile.model || null,
70
+ },
71
+ endpoints: ['/health', '/v1/messages', '/v1/models'],
72
+ });
73
+ return;
74
+ }
75
+ if (method === 'GET' && pathname === '/v1/models') {
76
+ if (!(0, messages_route_1.validateIncomingProxyAuth)(req.headers, options.authToken)) {
77
+ (0, http_helpers_1.writeJson)(res, 401, {
78
+ type: 'error',
79
+ error: {
80
+ type: 'authentication_error',
81
+ message: 'Missing or invalid local proxy token',
82
+ },
83
+ });
84
+ return;
85
+ }
86
+ (0, messages_route_1.handleProxyModelsRequest)(res, options.profile);
87
+ return;
88
+ }
89
+ if (method === 'POST' && pathname === '/v1/messages') {
90
+ await (0, messages_route_1.handleProxyMessagesRequest)(req, res, options.profile, options.authToken, insecureDispatcher);
91
+ return;
92
+ }
93
+ logger.warn('http.not_found', 'Rejected unknown proxy route', {
94
+ method,
95
+ pathname,
96
+ });
97
+ (0, http_helpers_1.writeJson)(res, 404, { error: 'Not found' });
98
+ });
99
+ logger.info('server.start', 'OpenAI-compatible proxy server listening', {
100
+ baseUrl: `http://${host}:${options.port}`,
101
+ });
102
+ server.on('close', () => {
103
+ logger.info('server.stop', 'OpenAI-compatible proxy server stopped');
104
+ void insecureDispatcher?.close();
105
+ });
106
+ server.listen(options.port, host);
107
+ return server;
108
+ }
109
+ exports.startOpenAICompatProxyServer = startOpenAICompatProxyServer;
110
+ //# sourceMappingURL=proxy-server.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"proxy-server.js","sourceRoot":"","sources":["../../../src/proxy/server/proxy-server.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,52 @@
1
+ interface OpenAITextPart {
2
+ type: 'text';
3
+ text: string;
4
+ }
5
+ interface OpenAIImagePart {
6
+ type: 'image_url';
7
+ image_url: {
8
+ url: string;
9
+ };
10
+ }
11
+ type OpenAIContentPart = OpenAITextPart | OpenAIImagePart;
12
+ interface OpenAIMessage {
13
+ role: 'system' | 'user' | 'assistant' | 'tool';
14
+ content: string | OpenAIContentPart[] | null;
15
+ tool_call_id?: string;
16
+ tool_calls?: Array<{
17
+ id: string;
18
+ type: 'function';
19
+ function: {
20
+ name: string;
21
+ arguments: string;
22
+ };
23
+ }>;
24
+ }
25
+ export interface ProxyOpenAIRequest {
26
+ model?: string;
27
+ stream: boolean;
28
+ reasoning_effort?: string;
29
+ reasoning?: {
30
+ enabled: boolean;
31
+ effort: string;
32
+ };
33
+ tools?: Array<{
34
+ type: 'function';
35
+ function: {
36
+ name: string;
37
+ description?: string;
38
+ parameters: Record<string, unknown>;
39
+ };
40
+ }>;
41
+ messages: OpenAIMessage[];
42
+ max_tokens?: number;
43
+ temperature?: number;
44
+ top_p?: number;
45
+ stop?: string[];
46
+ metadata?: Record<string, unknown>;
47
+ }
48
+ export declare class ProxyRequestTransformer {
49
+ transform(raw: unknown): ProxyOpenAIRequest;
50
+ }
51
+ export {};
52
+ //# sourceMappingURL=request-transformer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"request-transformer.d.ts","sourceRoot":"","sources":["../../../src/proxy/transformers/request-transformer.ts"],"names":[],"mappings":"AA0DA,UAAU,cAAc;IACtB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;CACd;AAED,UAAU,eAAe;IACvB,IAAI,EAAE,WAAW,CAAC;IAClB,SAAS,EAAE;QACT,GAAG,EAAE,MAAM,CAAC;KACb,CAAC;CACH;AAED,KAAK,iBAAiB,GAAG,cAAc,GAAG,eAAe,CAAC;AAE1D,UAAU,aAAa;IACrB,IAAI,EAAE,QAAQ,GAAG,MAAM,GAAG,WAAW,GAAG,MAAM,CAAC;IAC/C,OAAO,EAAE,MAAM,GAAG,iBAAiB,EAAE,GAAG,IAAI,CAAC;IAC7C,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,UAAU,CAAC,EAAE,KAAK,CAAC;QACjB,EAAE,EAAE,MAAM,CAAC;QACX,IAAI,EAAE,UAAU,CAAC;QACjB,QAAQ,EAAE;YACR,IAAI,EAAE,MAAM,CAAC;YACb,SAAS,EAAE,MAAM,CAAC;SACnB,CAAC;KACH,CAAC,CAAC;CACJ;AAED,MAAM,WAAW,kBAAkB;IACjC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,OAAO,CAAC;IAChB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,SAAS,CAAC,EAAE;QACV,OAAO,EAAE,OAAO,CAAC;QACjB,MAAM,EAAE,MAAM,CAAC;KAChB,CAAC;IACF,KAAK,CAAC,EAAE,KAAK,CAAC;QACZ,IAAI,EAAE,UAAU,CAAC;QACjB,QAAQ,EAAE;YACR,IAAI,EAAE,MAAM,CAAC;YACb,WAAW,CAAC,EAAE,MAAM,CAAC;YACrB,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;SACrC,CAAC;KACH,CAAC,CAAC;IACH,QAAQ,EAAE,aAAa,EAAE,CAAC;IAC1B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACpC;AAiSD,qBAAa,uBAAuB;IAClC,SAAS,CAAC,GAAG,EAAE,OAAO,GAAG,kBAAkB;CA4B5C"}
@@ -0,0 +1,254 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ProxyRequestTransformer = void 0;
4
+ const TOOL_RESULT_SERIALIZATION_FALLBACK = '[unserializable content]';
5
+ const TOOL_USE_ARGUMENTS_FALLBACK = '{}';
6
+ function assertObject(value, label) {
7
+ if (typeof value !== 'object' || value === null) {
8
+ throw new Error(`${label} must be an object`);
9
+ }
10
+ return value;
11
+ }
12
+ function asNumber(value) {
13
+ return typeof value === 'number' && Number.isFinite(value) ? value : undefined;
14
+ }
15
+ function asStringArray(value) {
16
+ if (!Array.isArray(value)) {
17
+ return undefined;
18
+ }
19
+ const result = value.filter((entry) => typeof entry === 'string' && entry.length > 0);
20
+ return result.length > 0 ? result : undefined;
21
+ }
22
+ function asMetadata(value) {
23
+ return typeof value === 'object' && value !== null && !Array.isArray(value)
24
+ ? value
25
+ : undefined;
26
+ }
27
+ function safeJsonStringify(value, fallback) {
28
+ try {
29
+ const serialized = JSON.stringify(value);
30
+ return typeof serialized === 'string' ? serialized : fallback;
31
+ }
32
+ catch {
33
+ return fallback;
34
+ }
35
+ }
36
+ function flattenTextContent(content, label) {
37
+ if (typeof content === 'string') {
38
+ return content;
39
+ }
40
+ if (!Array.isArray(content)) {
41
+ throw new Error(`${label} must be a string or content block array`);
42
+ }
43
+ return content
44
+ .map((block, index) => {
45
+ const parsed = assertObject(block, `${label}[${index}]`);
46
+ if (parsed.type !== 'text') {
47
+ throw new Error(`${label}[${index}].type "${String(parsed.type)}" is not supported`);
48
+ }
49
+ return typeof parsed.text === 'string' ? parsed.text : '';
50
+ })
51
+ .join('\n');
52
+ }
53
+ function toToolResultContent(content, label) {
54
+ if (content === undefined) {
55
+ return '';
56
+ }
57
+ if (typeof content === 'string') {
58
+ return content;
59
+ }
60
+ if (Array.isArray(content)) {
61
+ return flattenTextContent(content, label);
62
+ }
63
+ return safeJsonStringify(content, TOOL_RESULT_SERIALIZATION_FALLBACK);
64
+ }
65
+ function createFallbackToolId(messageIndex, blockIndex) {
66
+ return `toolu_proxy_fallback_${messageIndex}_${blockIndex}`;
67
+ }
68
+ function toImagePart(block, label) {
69
+ const source = block.source;
70
+ if (!source || source.type !== 'base64' || !source.media_type || !source.data) {
71
+ throw new Error(`${label}.source must be a base64 image payload`);
72
+ }
73
+ return {
74
+ type: 'image_url',
75
+ image_url: {
76
+ url: `data:${source.media_type};base64,${source.data}`,
77
+ },
78
+ };
79
+ }
80
+ function isImageBlock(block) {
81
+ return block.type === 'image';
82
+ }
83
+ function isToolUseBlock(block) {
84
+ return block.type === 'tool_use';
85
+ }
86
+ function isToolResultBlock(block) {
87
+ return block.type === 'tool_result';
88
+ }
89
+ function flushUserContent(messages, parts) {
90
+ if (parts.length === 0) {
91
+ return;
92
+ }
93
+ const onlyText = parts.every((part) => part.type === 'text');
94
+ messages.push({
95
+ role: 'user',
96
+ content: onlyText ? parts.map((part) => part.text).join('\n') : [...parts],
97
+ });
98
+ parts.length = 0;
99
+ }
100
+ function transformTools(value) {
101
+ if (!Array.isArray(value)) {
102
+ return undefined;
103
+ }
104
+ const tools = value
105
+ .filter((entry) => typeof entry === 'object' && entry !== null)
106
+ .map((entry) => ({
107
+ type: 'function',
108
+ function: {
109
+ name: typeof entry.name === 'string' ? entry.name : 'tool',
110
+ ...(typeof entry.description === 'string' ? { description: entry.description } : {}),
111
+ parameters: typeof entry.input_schema === 'object' && entry.input_schema !== null
112
+ ? entry.input_schema
113
+ : { type: 'object', properties: {} },
114
+ },
115
+ }));
116
+ return tools.length > 0 ? tools : undefined;
117
+ }
118
+ function mapThinkingToReasoning(thinking) {
119
+ if (!thinking || thinking.type === 'disabled') {
120
+ return {};
121
+ }
122
+ if (thinking.type !== 'enabled') {
123
+ throw new Error('thinking.type must be "enabled" or "disabled"');
124
+ }
125
+ const effort = typeof thinking.budget_tokens === 'number' && thinking.budget_tokens >= 8192
126
+ ? 'high'
127
+ : 'medium';
128
+ return {
129
+ reasoning_effort: effort,
130
+ reasoning: {
131
+ enabled: true,
132
+ effort,
133
+ },
134
+ };
135
+ }
136
+ function transformMessages(messagesValue) {
137
+ if (!Array.isArray(messagesValue)) {
138
+ throw new Error('messages must be an array');
139
+ }
140
+ const translatedMessages = [];
141
+ messagesValue.forEach((message, messageIndex) => {
142
+ const parsedMessage = assertObject(message, `messages[${messageIndex}]`);
143
+ const role = parsedMessage.role;
144
+ if (role !== 'user' && role !== 'assistant') {
145
+ throw new Error(`messages[${messageIndex}].role must be "user" or "assistant"`);
146
+ }
147
+ const content = parsedMessage.content;
148
+ if (typeof content === 'string') {
149
+ translatedMessages.push({ role, content });
150
+ return;
151
+ }
152
+ if (!Array.isArray(content)) {
153
+ throw new Error(`messages[${messageIndex}].content must be a string or array`);
154
+ }
155
+ const userParts = [];
156
+ const assistantTextParts = [];
157
+ const toolCalls = [];
158
+ let sawToolResult = false;
159
+ content.forEach((block, blockIndex) => {
160
+ const parsed = assertObject(block, `messages[${messageIndex}].content[${blockIndex}]`);
161
+ if (parsed.type === 'text') {
162
+ const text = typeof parsed.text === 'string' ? parsed.text : '';
163
+ if (role === 'user') {
164
+ userParts.push({ type: 'text', text });
165
+ }
166
+ else {
167
+ assistantTextParts.push(text);
168
+ }
169
+ return;
170
+ }
171
+ if (isImageBlock(parsed)) {
172
+ if (role !== 'user') {
173
+ throw new Error(`messages[${messageIndex}].content[${blockIndex}] image requires user role`);
174
+ }
175
+ userParts.push(toImagePart(parsed, `messages[${messageIndex}].content[${blockIndex}]`));
176
+ return;
177
+ }
178
+ if (isToolUseBlock(parsed)) {
179
+ if (role !== 'assistant') {
180
+ throw new Error(`messages[${messageIndex}].content[${blockIndex}] tool_use requires assistant role`);
181
+ }
182
+ toolCalls.push({
183
+ id: typeof parsed.id === 'string' && parsed.id.length > 0
184
+ ? parsed.id
185
+ : createFallbackToolId(messageIndex, blockIndex),
186
+ type: 'function',
187
+ function: {
188
+ name: typeof parsed.name === 'string' ? parsed.name : 'tool',
189
+ arguments: safeJsonStringify(parsed.input ?? {}, TOOL_USE_ARGUMENTS_FALLBACK),
190
+ },
191
+ });
192
+ return;
193
+ }
194
+ if (isToolResultBlock(parsed)) {
195
+ if (role !== 'user') {
196
+ throw new Error(`messages[${messageIndex}].content[${blockIndex}] tool_result requires user role`);
197
+ }
198
+ if (typeof parsed.tool_use_id !== 'string' || parsed.tool_use_id.trim().length === 0) {
199
+ throw new Error(`messages[${messageIndex}].content[${blockIndex}].tool_use_id must be a non-empty string`);
200
+ }
201
+ sawToolResult = true;
202
+ flushUserContent(translatedMessages, userParts);
203
+ translatedMessages.push({
204
+ role: 'tool',
205
+ tool_call_id: parsed.tool_use_id,
206
+ content: toToolResultContent(parsed.content, `messages[${messageIndex}].content[${blockIndex}].content`),
207
+ });
208
+ return;
209
+ }
210
+ throw new Error(`messages[${messageIndex}].content[${blockIndex}].type "${String(parsed.type)}" is not supported`);
211
+ });
212
+ if (role === 'assistant') {
213
+ translatedMessages.push({
214
+ role: 'assistant',
215
+ content: assistantTextParts.join('\n'),
216
+ tool_calls: toolCalls.length > 0 ? toolCalls : undefined,
217
+ });
218
+ return;
219
+ }
220
+ if (userParts.length > 0 || !sawToolResult) {
221
+ flushUserContent(translatedMessages, userParts);
222
+ }
223
+ });
224
+ return translatedMessages;
225
+ }
226
+ class ProxyRequestTransformer {
227
+ transform(raw) {
228
+ const source = assertObject(raw || {}, 'request');
229
+ const messages = transformMessages(source.messages);
230
+ const system = source.system;
231
+ const allMessages = system !== undefined
232
+ ? [
233
+ { role: 'system', content: flattenTextContent(system, 'system') },
234
+ ...messages,
235
+ ]
236
+ : messages;
237
+ return {
238
+ model: typeof source.model === 'string' && source.model.trim().length > 0
239
+ ? source.model.trim()
240
+ : undefined,
241
+ stream: source.stream === true,
242
+ messages: allMessages,
243
+ max_tokens: asNumber(source.max_tokens),
244
+ temperature: asNumber(source.temperature),
245
+ top_p: asNumber(source.top_p),
246
+ stop: asStringArray(source.stop_sequences),
247
+ metadata: asMetadata(source.metadata),
248
+ tools: transformTools(source.tools),
249
+ ...mapThinkingToReasoning(source.thinking),
250
+ };
251
+ }
252
+ }
253
+ exports.ProxyRequestTransformer = ProxyRequestTransformer;
254
+ //# sourceMappingURL=request-transformer.js.map