@omnicross/core 0.1.1 → 0.1.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.
Files changed (259) hide show
  1. package/dist/ApiConverter.cjs +3 -778
  2. package/dist/ApiConverter.js +12 -751
  3. package/dist/{CompletionService-DtOF_War.d.cts → CompletionService-D3a47vdU.d.cts} +2 -1
  4. package/dist/{CompletionService-7fCmKAP3.d.ts → CompletionService-DdWaAxq0.d.ts} +2 -1
  5. package/dist/auth/GeminiCodeAssistProjectResolver.cjs +32 -60
  6. package/dist/auth/GeminiCodeAssistProjectResolver.js +11 -10
  7. package/dist/builtin-web-fetch-77JZUZGM.cjs +100 -0
  8. package/dist/builtin-web-fetch-IGLBX2XY.js +100 -0
  9. package/dist/chunk-2DCNB7DF.cjs +514 -0
  10. package/dist/chunk-2FMI2B6V.cjs +6196 -0
  11. package/dist/chunk-3OPYJG76.cjs +266 -0
  12. package/dist/chunk-3QOSDDNI.cjs +130 -0
  13. package/dist/chunk-46RLHI7D.js +0 -0
  14. package/dist/chunk-46ZIFWYG.cjs +277 -0
  15. package/dist/chunk-4DECIFU7.js +6196 -0
  16. package/dist/chunk-4IH4EL7M.cjs +9 -0
  17. package/dist/chunk-4VAVYUZS.cjs +991 -0
  18. package/dist/chunk-5ENKBSWO.js +311 -0
  19. package/dist/chunk-5ERIZW3D.js +44 -0
  20. package/dist/chunk-5HTVET6E.js +514 -0
  21. package/dist/chunk-5ZQBEOMD.js +764 -0
  22. package/dist/chunk-6RPZADX3.cjs +92 -0
  23. package/dist/chunk-7VU7V2E4.js +0 -0
  24. package/dist/chunk-7YN22L2H.cjs +87 -0
  25. package/dist/chunk-A2YMUCBT.cjs +105 -0
  26. package/dist/chunk-AEOZIDEB.cjs +32 -0
  27. package/dist/chunk-AQ5TNQB7.js +13 -0
  28. package/dist/chunk-AVYJ4YBN.js +58 -0
  29. package/dist/chunk-BO4RFWBR.js +89 -0
  30. package/dist/chunk-C72S6TTV.cjs +49 -0
  31. package/dist/chunk-C7PSERMH.js +87 -0
  32. package/dist/chunk-CDHS2QDC.js +179 -0
  33. package/dist/chunk-CWM2ZDU5.js +130 -0
  34. package/dist/chunk-CZHZGRU7.js +383 -0
  35. package/dist/chunk-DK4A7DLE.js +266 -0
  36. package/dist/chunk-DQ5VAYZ6.cjs +42 -0
  37. package/dist/chunk-DRWHTIIZ.js +13 -0
  38. package/dist/chunk-DWKQZ2SK.cjs +254 -0
  39. package/dist/chunk-EYZYXJTJ.cjs +1 -0
  40. package/dist/chunk-FFALUUZZ.cjs +235 -0
  41. package/dist/chunk-FMOBD2OQ.js +39 -0
  42. package/dist/chunk-FTQ7IQUC.js +991 -0
  43. package/dist/chunk-FZ46M34D.cjs +1 -0
  44. package/dist/chunk-G2UTNSGU.js +277 -0
  45. package/dist/chunk-GBHYAGX3.cjs +26 -0
  46. package/dist/chunk-GMMT7RVN.cjs +39 -0
  47. package/dist/chunk-H5JUT3KV.js +105 -0
  48. package/dist/chunk-HQP3K7PU.cjs +431 -0
  49. package/dist/chunk-HUZZZ3JL.js +32 -0
  50. package/dist/chunk-IAXWICZU.js +69 -0
  51. package/dist/chunk-JMJBSACD.cjs +147 -0
  52. package/dist/chunk-JO5NLTLY.js +46 -0
  53. package/dist/chunk-JWC6APFQ.js +23 -0
  54. package/dist/chunk-KUU2RNG6.cjs +46 -0
  55. package/dist/chunk-L74VDN4A.cjs +32 -0
  56. package/dist/chunk-MQNDWYPN.js +235 -0
  57. package/dist/chunk-MZNPGW5Q.js +26 -0
  58. package/dist/chunk-N5QFKSDO.js +56 -0
  59. package/dist/chunk-NYUNU75A.cjs +44 -0
  60. package/dist/chunk-NZYN7C3P.cjs +179 -0
  61. package/dist/chunk-Q27JY5RG.cjs +126 -0
  62. package/dist/chunk-QBZJ7P2T.cjs +13 -0
  63. package/dist/chunk-QWBWGODS.cjs +69 -0
  64. package/dist/chunk-QXD4MV2X.cjs +23 -0
  65. package/dist/chunk-R3HK6R4B.cjs +13 -0
  66. package/dist/chunk-RPII3E6Z.cjs +145 -0
  67. package/dist/chunk-RSJ3TWJQ.cjs +186 -0
  68. package/dist/chunk-S4WBV25P.js +913 -0
  69. package/dist/chunk-S6JGLF3G.cjs +89 -0
  70. package/dist/chunk-SUEGJ75D.cjs +764 -0
  71. package/dist/chunk-SVNDB62D.cjs +58 -0
  72. package/dist/chunk-SVXC36MU.cjs +383 -0
  73. package/dist/chunk-TKJMZBAH.js +32 -0
  74. package/dist/chunk-UBWEBKRC.js +42 -0
  75. package/dist/chunk-UNEFIWXI.cjs +32 -0
  76. package/dist/chunk-VQY5W4YW.cjs +311 -0
  77. package/dist/chunk-VVEHS2LI.js +431 -0
  78. package/dist/chunk-WNY4WMRF.js +32 -0
  79. package/dist/chunk-XEKD23J5.js +9 -0
  80. package/dist/chunk-XTEI64OU.js +145 -0
  81. package/dist/chunk-XX6NQJMA.js +92 -0
  82. package/dist/chunk-Y6OM7EV7.cjs +56 -0
  83. package/dist/chunk-Y7FO65VT.js +147 -0
  84. package/dist/chunk-YGXJGRFI.cjs +913 -0
  85. package/dist/chunk-YMFAJFQT.cjs +173 -0
  86. package/dist/chunk-Z7LUNECE.js +49 -0
  87. package/dist/chunk-Z7Y2NPHY.js +186 -0
  88. package/dist/chunk-ZJZAOKI7.js +254 -0
  89. package/dist/chunk-ZLX3KGXX.js +173 -0
  90. package/dist/chunk-ZY6KU6P3.js +126 -0
  91. package/dist/completion/ApiKeyPoolService.cjs +23 -48
  92. package/dist/completion/ApiKeyPoolService.d.cts +150 -2
  93. package/dist/completion/ApiKeyPoolService.d.ts +150 -2
  94. package/dist/completion/BuiltinToolExecutor.cjs +9 -324
  95. package/dist/completion/BuiltinToolExecutor.js +6 -290
  96. package/dist/completion/CompletionService.cjs +45 -3487
  97. package/dist/completion/CompletionService.d.cts +3 -2
  98. package/dist/completion/CompletionService.d.ts +3 -2
  99. package/dist/completion/CompletionService.js +41 -3457
  100. package/dist/completion/NativeSearchInjector.cjs +8 -192
  101. package/dist/completion/NativeSearchInjector.js +7 -162
  102. package/dist/completion/ProviderSearchInjector.cjs +12 -39
  103. package/dist/completion/native-search-types.cjs +13 -66
  104. package/dist/completion/native-search-types.js +7 -31
  105. package/dist/completion/openrouter-headers.cjs +12 -71
  106. package/dist/completion/openrouter-headers.d.cts +9 -12
  107. package/dist/completion/openrouter-headers.d.ts +9 -12
  108. package/dist/completion/openrouter-headers.js +7 -36
  109. package/dist/completion/openrouter-models.cjs +11 -67
  110. package/dist/completion/openrouter-models.js +5 -34
  111. package/dist/completion/types.cjs +1 -18
  112. package/dist/completion/url-builder.cjs +24 -138
  113. package/dist/completion/url-builder.js +12 -92
  114. package/dist/completion.cjs +62 -3989
  115. package/dist/completion.d.cts +3 -2
  116. package/dist/completion.d.ts +3 -2
  117. package/dist/completion.js +70 -3953
  118. package/dist/index.cjs +319 -10429
  119. package/dist/index.d.cts +49 -12
  120. package/dist/index.d.ts +49 -12
  121. package/dist/index.js +248 -10269
  122. package/dist/logger-4GvQNzhE.d.cts +22 -0
  123. package/dist/logger-4GvQNzhE.d.ts +22 -0
  124. package/dist/outbound-api/routeResolver.cjs +10 -217
  125. package/dist/outbound-api/routeResolver.d.cts +10 -3
  126. package/dist/outbound-api/routeResolver.d.ts +10 -3
  127. package/dist/outbound-api/routeResolver.js +9 -187
  128. package/dist/outbound-api/subscriptionRegistryPort.cjs +7 -37
  129. package/dist/outbound-api/subscriptionRegistryPort.d.cts +2 -1
  130. package/dist/outbound-api/subscriptionRegistryPort.d.ts +2 -1
  131. package/dist/outbound-api/subscriptionRegistryPort.js +4 -8
  132. package/dist/outbound-api/types.cjs +5 -17
  133. package/dist/outbound-api/types.d.cts +12 -144
  134. package/dist/outbound-api/types.d.ts +12 -144
  135. package/dist/outbound-api/types.js +6 -0
  136. package/dist/outbound-api.cjs +197 -5265
  137. package/dist/outbound-api.d.cts +787 -25
  138. package/dist/outbound-api.d.ts +787 -25
  139. package/dist/outbound-api.js +173 -5195
  140. package/dist/pipeline/AuthSource.cjs +1 -18
  141. package/dist/pipeline/AuthSource.d.cts +23 -1
  142. package/dist/pipeline/AuthSource.d.ts +23 -1
  143. package/dist/pipeline/LlmConfigProviderAuth.cjs +5 -166
  144. package/dist/pipeline/LlmConfigProviderAuth.d.cts +2 -1
  145. package/dist/pipeline/LlmConfigProviderAuth.d.ts +2 -1
  146. package/dist/pipeline/LlmConfigProviderAuth.js +5 -139
  147. package/dist/pipeline/SubscriptionAccountHealth.cjs +22 -0
  148. package/dist/pipeline/SubscriptionAccountHealth.d.cts +235 -0
  149. package/dist/pipeline/SubscriptionAccountHealth.d.ts +235 -0
  150. package/dist/pipeline/SubscriptionAccountHealth.js +22 -0
  151. package/dist/pipeline/SubscriptionAuthSource.cjs +6 -128
  152. package/dist/pipeline/SubscriptionAuthSource.d.cts +3 -2
  153. package/dist/pipeline/SubscriptionAuthSource.d.ts +3 -2
  154. package/dist/pipeline/SubscriptionAuthSource.js +5 -99
  155. package/dist/pipeline/SubscriptionAuthStrategy.cjs +1 -18
  156. package/dist/pipeline/SubscriptionAuthStrategy.d.cts +24 -1
  157. package/dist/pipeline/SubscriptionAuthStrategy.d.ts +24 -1
  158. package/dist/pipeline/auditSink.cjs +14 -0
  159. package/dist/pipeline/auditSink.d.cts +48 -0
  160. package/dist/pipeline/auditSink.d.ts +48 -0
  161. package/dist/pipeline/auditSink.js +14 -0
  162. package/dist/pipeline/billingEmit.cjs +14 -0
  163. package/dist/pipeline/billingEmit.d.cts +49 -0
  164. package/dist/pipeline/billingEmit.d.ts +49 -0
  165. package/dist/pipeline/billingEmit.js +14 -0
  166. package/dist/pipeline/executeProviderCall.cjs +5 -69
  167. package/dist/pipeline/executeProviderCall.js +3 -42
  168. package/dist/pipeline/resolveProviderChain.cjs +5 -46
  169. package/dist/pipeline/resolveProviderChain.js +3 -19
  170. package/dist/pipeline/resolveSubscriptionChain.cjs +5 -67
  171. package/dist/pipeline/resolveSubscriptionChain.js +3 -40
  172. package/dist/ports/gemini-code-assist-resolver.cjs +7 -37
  173. package/dist/ports/gemini-code-assist-resolver.js +4 -8
  174. package/dist/ports/pricing-store.cjs +1 -0
  175. package/dist/ports/pricing-store.d.cts +50 -0
  176. package/dist/ports/pricing-store.d.ts +50 -0
  177. package/dist/ports/pricing-store.js +0 -0
  178. package/dist/ports/provider-config-source.cjs +1 -18
  179. package/dist/ports/usage-event-store.cjs +1 -0
  180. package/dist/ports/usage-event-store.d.cts +54 -0
  181. package/dist/ports/usage-event-store.d.ts +54 -0
  182. package/dist/ports/usage-event-store.js +0 -0
  183. package/dist/ports/web-search-backend.cjs +1 -18
  184. package/dist/ports.cjs +1 -18
  185. package/dist/ports.d.cts +13 -2
  186. package/dist/ports.d.ts +13 -2
  187. package/dist/provider-proxy/ProviderProxy.cjs +47 -4643
  188. package/dist/provider-proxy/ProviderProxy.d.cts +2 -1
  189. package/dist/provider-proxy/ProviderProxy.d.ts +2 -1
  190. package/dist/provider-proxy/ProviderProxy.js +42 -4613
  191. package/dist/provider-proxy/identity/SubscriptionIdentityStore.cjs +15 -0
  192. package/dist/provider-proxy/identity/SubscriptionIdentityStore.d.cts +121 -0
  193. package/dist/provider-proxy/identity/SubscriptionIdentityStore.d.ts +121 -0
  194. package/dist/provider-proxy/identity/SubscriptionIdentityStore.js +15 -0
  195. package/dist/provider-proxy/identity/fingerprintHeaders.cjs +20 -0
  196. package/dist/provider-proxy/identity/fingerprintHeaders.d.cts +89 -0
  197. package/dist/provider-proxy/identity/fingerprintHeaders.d.ts +89 -0
  198. package/dist/provider-proxy/identity/fingerprintHeaders.js +20 -0
  199. package/dist/provider-proxy/ingress/providerProxyShared.cjs +42 -2941
  200. package/dist/provider-proxy/ingress/providerProxyShared.d.cts +13 -3
  201. package/dist/provider-proxy/ingress/providerProxyShared.d.ts +13 -3
  202. package/dist/provider-proxy/ingress/providerProxyShared.js +48 -2914
  203. package/dist/provider-proxy/matchText.cjs +13 -72
  204. package/dist/provider-proxy/matchText.d.cts +14 -1
  205. package/dist/provider-proxy/matchText.d.ts +14 -1
  206. package/dist/provider-proxy/matchText.js +8 -39
  207. package/dist/provider-proxy/types.cjs +1 -18
  208. package/dist/provider-proxy/types.d.cts +25 -1
  209. package/dist/provider-proxy/types.d.ts +25 -1
  210. package/dist/provider-proxy.cjs +42 -4655
  211. package/dist/provider-proxy.d.cts +2 -1
  212. package/dist/provider-proxy.d.ts +2 -1
  213. package/dist/provider-proxy.js +46 -4628
  214. package/dist/{routeResolver-HE-ZO0fO.d.ts → routeResolver-B1NglTfe.d.ts} +36 -10
  215. package/dist/{routeResolver-BrbK6ja9.d.cts → routeResolver-CbG5uBgm.d.cts} +36 -10
  216. package/dist/serializeError.cjs +5 -81
  217. package/dist/serializeError.js +3 -54
  218. package/dist/sse-parser.cjs +7 -455
  219. package/dist/sse-parser.js +4 -426
  220. package/dist/transformer/TransformerChainExecutor.cjs +4 -318
  221. package/dist/transformer/TransformerChainExecutor.js +4 -291
  222. package/dist/transformer/TransformerService.cjs +5 -289
  223. package/dist/transformer/TransformerService.js +3 -262
  224. package/dist/transformer/anthropicBetaInject.cjs +7 -50
  225. package/dist/transformer/anthropicBetaInject.js +4 -21
  226. package/dist/transformer/transformers/AnthropicTransformer.cjs +3 -1014
  227. package/dist/transformer/transformers/AnthropicTransformer.js +3 -987
  228. package/dist/transformer/transformers/GeminiCodeAssistTransformer.cjs +4 -1106
  229. package/dist/transformer/transformers/GeminiCodeAssistTransformer.js +7 -1079
  230. package/dist/transformer/transformers/GeminiTransformer.cjs +4 -1010
  231. package/dist/transformer/transformers/GeminiTransformer.js +4 -983
  232. package/dist/transformer/transformers/OpenAIResponseTransformer.cjs +3 -535
  233. package/dist/transformer/transformers/OpenAIResponseTransformer.js +3 -510
  234. package/dist/transformer/transformers/OpenCodeGoTransformer.cjs +5 -72
  235. package/dist/transformer/transformers/OpenCodeGoTransformer.js +3 -45
  236. package/dist/transformer/transformers/ReasoningTransformer.cjs +3 -270
  237. package/dist/transformer/transformers/ReasoningTransformer.js +2 -249
  238. package/dist/transformer/transformers.cjs +10 -3177
  239. package/dist/transformer/transformers.js +23 -3158
  240. package/dist/transformer/types.cjs +1 -18
  241. package/dist/transformer.cjs +13 -3726
  242. package/dist/transformer.js +17 -3706
  243. package/dist/types-6OUY_xfA.d.ts +830 -0
  244. package/dist/types-aBFFXoBz.d.cts +830 -0
  245. package/dist/usage/pricing-engine.cjs +6 -0
  246. package/dist/usage/pricing-engine.d.cts +83 -0
  247. package/dist/usage/pricing-engine.d.ts +83 -0
  248. package/dist/usage/pricing-engine.js +6 -0
  249. package/dist/usage/usage-recorder.cjs +6 -0
  250. package/dist/usage/usage-recorder.d.cts +91 -0
  251. package/dist/usage/usage-recorder.d.ts +91 -0
  252. package/dist/usage/usage-recorder.js +6 -0
  253. package/dist/usage.cjs +11 -0
  254. package/dist/usage.d.cts +8 -0
  255. package/dist/usage.d.ts +8 -0
  256. package/dist/usage.js +11 -0
  257. package/package.json +4 -2
  258. package/dist/ApiKeyPoolService-BmMkau07.d.cts +0 -170
  259. package/dist/ApiKeyPoolService-BmMkau07.d.ts +0 -170
@@ -1,3206 +1,39 @@
1
- "use strict";
2
- var __defProp = Object.defineProperty;
3
- var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
- var __getOwnPropNames = Object.getOwnPropertyNames;
5
- var __hasOwnProp = Object.prototype.hasOwnProperty;
6
- var __export = (target, all) => {
7
- for (var name in all)
8
- __defProp(target, name, { get: all[name], enumerable: true });
9
- };
10
- var __copyProps = (to, from, except, desc) => {
11
- if (from && typeof from === "object" || typeof from === "function") {
12
- for (let key of __getOwnPropNames(from))
13
- if (!__hasOwnProp.call(to, key) && key !== except)
14
- __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
- }
16
- return to;
17
- };
18
- var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
1
+ "use strict";Object.defineProperty(exports, "__esModule", {value: true});
19
2
 
20
- // src/transformer/transformers/index.ts
21
- var transformers_exports = {};
22
- __export(transformers_exports, {
23
- AnthropicTransformer: () => AnthropicTransformer,
24
- BUILTIN_TRANSFORMER_NAMES: () => BUILTIN_TRANSFORMER_NAMES,
25
- BuiltinTransformers: () => BuiltinTransformers,
26
- DeepseekTransformer: () => DeepseekTransformer,
27
- GeminiCodeAssistTransformer: () => GeminiCodeAssistTransformer,
28
- GeminiTransformer: () => GeminiTransformer,
29
- OpenAIResponseTransformer: () => OpenAIResponseTransformer,
30
- OpenCodeGoTransformer: () => OpenCodeGoTransformer,
31
- ReasoningTransformer: () => ReasoningTransformer,
32
- getBuiltinTransformers: () => getBuiltinTransformers,
33
- registerBuiltinTransformers: () => registerBuiltinTransformers
34
- });
35
- module.exports = __toCommonJS(transformers_exports);
36
3
 
37
- // src/transformer/transformers/AnthropicToolHandling.ts
38
- function isServerSideTool(tool) {
39
- const type = String(tool.type || "");
40
- return type.startsWith("web_search_") || type.startsWith("code_execution_") || type.startsWith("text_editor_") || type.startsWith("memory_") || type.startsWith("web_fetch_") || type.startsWith("search_tool_");
41
- }
42
- function convertAnthropicToolsToOpenAI(tools) {
43
- return tools.filter((tool) => !isServerSideTool(tool)).map((tool) => ({
44
- type: "function",
45
- function: {
46
- name: String(tool.name),
47
- description: String(tool.description || ""),
48
- parameters: tool.input_schema
49
- }
50
- }));
51
- }
52
4
 
53
- // src/transformer/transformers/AnthropicTypes.ts
54
- function getThinkLevel(budgetTokens) {
55
- if (!budgetTokens || budgetTokens <= 0) return "none";
56
- if (budgetTokens < 4096) return "low";
57
- if (budgetTokens < 16384) return "medium";
58
- return "high";
59
- }
60
- function formatBase64(data, mediaType) {
61
- if (data.startsWith("data:")) return data;
62
- return `data:${mediaType || "image/png"};base64,${data}`;
63
- }
64
5
 
65
- // src/transformer/transformers/AnthropicRequestBuilder.ts
66
- function buildAnthropicRequestBody(request) {
67
- let systemContent;
68
- const anthropicMessages = [];
69
- for (let i = 0; i < request.messages.length; i++) {
70
- const msg = request.messages[i];
71
- if (msg.role === "system") {
72
- if (typeof msg.content === "string") {
73
- systemContent = msg.content;
74
- } else if (Array.isArray(msg.content)) {
75
- systemContent = msg.content.filter((c) => c.type === "text").map((c) => ({
76
- type: "text",
77
- text: c.text,
78
- ...c.cache_control ? { cache_control: c.cache_control } : {}
79
- }));
80
- }
81
- continue;
82
- }
83
- if (msg.role === "assistant") {
84
- const content = [];
85
- if (msg.thinking?.content) {
86
- const block = {
87
- type: "thinking",
88
- thinking: msg.thinking.content
89
- };
90
- if (msg.thinking.signature) {
91
- block.signature = msg.thinking.signature;
92
- }
93
- content.push(block);
94
- }
95
- if (msg.content) {
96
- const text = typeof msg.content === "string" ? msg.content : msg.content.filter((c) => c.type === "text").map((c) => c.text).join("\n");
97
- if (text) {
98
- content.push({ type: "text", text });
99
- }
100
- }
101
- if (msg.tool_calls?.length) {
102
- for (const tc of msg.tool_calls) {
103
- let input;
104
- try {
105
- input = typeof tc.function.arguments === "string" ? JSON.parse(tc.function.arguments) : tc.function.arguments;
106
- } catch {
107
- input = { text: tc.function.arguments || "" };
108
- }
109
- content.push({
110
- type: "tool_use",
111
- id: tc.id,
112
- name: tc.function.name,
113
- input
114
- });
115
- }
116
- }
117
- anthropicMessages.push({
118
- role: "assistant",
119
- content: content.length > 0 ? content : ""
120
- });
121
- continue;
122
- }
123
- if (msg.role === "tool") {
124
- const toolResults = [];
125
- let j = i;
126
- while (j < request.messages.length && request.messages[j].role === "tool") {
127
- const t = request.messages[j];
128
- toolResults.push({
129
- type: "tool_result",
130
- tool_use_id: t.tool_call_id || "",
131
- content: typeof t.content === "string" ? t.content : JSON.stringify(t.content),
132
- ...t.cache_control ? { cache_control: t.cache_control } : {}
133
- });
134
- j++;
135
- }
136
- anthropicMessages.push({ role: "user", content: toolResults });
137
- i = j - 1;
138
- continue;
139
- }
140
- if (typeof msg.content === "string") {
141
- anthropicMessages.push({ role: "user", content: msg.content });
142
- } else if (Array.isArray(msg.content)) {
143
- const content = msg.content.map((part) => {
144
- if (part.type === "image_url") {
145
- const url = part.image_url.url;
146
- if (url.startsWith("data:")) {
147
- const match = url.match(/^data:([^;]+);base64,(.+)$/);
148
- if (match) {
149
- return {
150
- type: "image",
151
- source: { type: "base64", media_type: match[1], data: match[2] }
152
- };
153
- }
154
- }
155
- return {
156
- type: "image",
157
- source: { type: "url", url }
158
- };
159
- }
160
- return { type: "text", text: part.text };
161
- });
162
- anthropicMessages.push({ role: "user", content });
163
- }
164
- }
165
- const body = {
166
- model: request.model,
167
- messages: anthropicMessages,
168
- max_tokens: request.max_tokens || 4096,
169
- stream: request.stream ?? false
170
- };
171
- if (request.temperature !== void 0) {
172
- body.temperature = request.temperature;
173
- }
174
- if (systemContent !== void 0) {
175
- body.system = systemContent;
176
- }
177
- if (request.tools?.length) {
178
- body.tools = request.tools.map((tool) => ({
179
- name: tool.function.name,
180
- description: tool.function.description || "",
181
- input_schema: tool.function.parameters
182
- }));
183
- }
184
- const serverSideTools = request._serverSideTools;
185
- if (serverSideTools?.length) {
186
- body.tools = [...body.tools || [], ...serverSideTools];
187
- }
188
- if (request.tool_choice) {
189
- if (typeof request.tool_choice === "string") {
190
- if (request.tool_choice === "required") {
191
- body.tool_choice = { type: "any" };
192
- } else if (request.tool_choice !== "none") {
193
- body.tool_choice = { type: request.tool_choice };
194
- }
195
- } else if (typeof request.tool_choice === "object" && "function" in request.tool_choice) {
196
- body.tool_choice = { type: "tool", name: request.tool_choice.function.name };
197
- }
198
- }
199
- if (request.reasoning?.enabled) {
200
- const budgetMap = { low: 2048, medium: 8192, high: 32768 };
201
- const budget = request.reasoning.max_tokens || budgetMap[request.reasoning.effort || "medium"] || 8192;
202
- body.thinking = { type: "enabled", budget_tokens: budget };
203
- body.temperature = 1;
204
- }
205
- return body;
206
- }
207
6
 
208
- // src/transformer/transformers/AnthropicResponseConversion.ts
209
- function convertAnthropicResponseToOpenAI(anthropicResponse) {
210
- const content = anthropicResponse.content || [];
211
- const textParts = content.filter((c) => c.type === "text").map((c) => c.text);
212
- const toolUses = content.filter((c) => c.type === "tool_use" || c.type === "server_tool_use");
213
- const thinkingBlock = content.find((c) => c.type === "thinking");
214
- const searchResults = content.filter((c) => c.type === "web_search_tool_result");
215
- for (const sr of searchResults) {
216
- const searches = sr.content;
217
- if (searches?.length) {
218
- const formatted = searches.map((s) => `[${s.title}](${s.url}): ${s.page_content || s.snippet || ""}`).join("\n");
219
- textParts.push(`
7
+ var _chunkFFALUUZZcjs = require('../chunk-FFALUUZZ.cjs');
220
8
 
221
- **Search Results:**
222
- ${formatted}`);
223
- }
224
- }
225
- const message = {
226
- role: "assistant",
227
- content: textParts.join("") || null
228
- };
229
- if (toolUses.length > 0) {
230
- message.tool_calls = toolUses.map((tc) => ({
231
- id: tc.id,
232
- type: "function",
233
- function: {
234
- name: tc.name,
235
- arguments: JSON.stringify(tc.input || {})
236
- }
237
- }));
238
- }
239
- if (thinkingBlock) {
240
- message.thinking = {
241
- content: thinkingBlock.thinking,
242
- signature: thinkingBlock.signature
243
- };
244
- }
245
- const stopReasonMapping = {
246
- end_turn: "stop",
247
- max_tokens: "length",
248
- tool_use: "tool_calls",
249
- stop_sequence: "stop"
250
- };
251
- const usage = anthropicResponse.usage;
252
- return {
253
- id: anthropicResponse.id || `chatcmpl-${Date.now()}`,
254
- object: "chat.completion",
255
- created: Math.floor(Date.now() / 1e3),
256
- model: anthropicResponse.model || "unknown",
257
- choices: [{
258
- index: 0,
259
- message,
260
- finish_reason: stopReasonMapping[anthropicResponse.stop_reason] || "stop"
261
- }],
262
- usage: usage ? {
263
- prompt_tokens: usage.input_tokens || 0,
264
- completion_tokens: usage.output_tokens || 0,
265
- total_tokens: (usage.input_tokens || 0) + (usage.output_tokens || 0)
266
- } : void 0
267
- };
268
- }
269
- function convertOpenAIResponseToAnthropic(openaiResponse) {
270
- const choice = openaiResponse.choices?.[0];
271
- if (!choice) {
272
- throw new Error("No choices found in OpenAI response");
273
- }
274
- const message = choice.message;
275
- const content = [];
276
- if (message.content) {
277
- content.push({
278
- type: "text",
279
- text: message.content
280
- });
281
- }
282
- const toolCalls = message.tool_calls;
283
- if (toolCalls?.length) {
284
- for (const toolCall of toolCalls) {
285
- const func = toolCall.function;
286
- let parsedInput = {};
287
- try {
288
- const args = func.arguments;
289
- parsedInput = typeof args === "string" ? JSON.parse(args) : args;
290
- } catch {
291
- parsedInput = { text: func.arguments || "" };
292
- }
293
- content.push({
294
- type: "tool_use",
295
- id: toolCall.id,
296
- name: func.name,
297
- input: parsedInput
298
- });
299
- }
300
- }
301
- const thinking = message.thinking;
302
- if (thinking?.content) {
303
- content.push({
304
- type: "thinking",
305
- thinking: thinking.content,
306
- signature: thinking.signature
307
- });
308
- }
309
- const finishReason = choice.finish_reason;
310
- const stopReasonMapping = {
311
- stop: "end_turn",
312
- length: "max_tokens",
313
- tool_calls: "tool_use",
314
- content_filter: "stop_sequence"
315
- };
316
- const usage = openaiResponse.usage;
317
- const usageDetails = usage?.prompt_tokens_details;
318
- return {
319
- id: openaiResponse.id,
320
- type: "message",
321
- role: "assistant",
322
- model: openaiResponse.model,
323
- content,
324
- stop_reason: stopReasonMapping[finishReason] || "end_turn",
325
- stop_sequence: null,
326
- usage: {
327
- input_tokens: (usage?.prompt_tokens || 0) - (usageDetails?.cached_tokens || 0),
328
- output_tokens: usage?.completion_tokens || 0,
329
- cache_read_input_tokens: usageDetails?.cached_tokens || 0
330
- }
331
- };
332
- }
333
9
 
334
- // src/transformer/transformers/AnthropicConversion.ts
335
- function transformAnthropicRequestToUnified(request) {
336
- const anthropicRequest = request;
337
- const messages = [];
338
- if (anthropicRequest.system) {
339
- if (typeof anthropicRequest.system === "string") {
340
- messages.push({
341
- role: "system",
342
- content: anthropicRequest.system
343
- });
344
- } else if (Array.isArray(anthropicRequest.system)) {
345
- const textParts = anthropicRequest.system.filter((item) => item.type === "text" && item.text).map((item) => ({
346
- type: "text",
347
- text: item.text,
348
- cache_control: item.cache_control
349
- }));
350
- if (textParts.length > 0) {
351
- messages.push({
352
- role: "system",
353
- content: textParts
354
- });
355
- }
356
- }
357
- }
358
- const requestMessages = JSON.parse(JSON.stringify(anthropicRequest.messages || []));
359
- for (const msg of requestMessages) {
360
- if (msg.role !== "user" && msg.role !== "assistant") continue;
361
- if (typeof msg.content === "string") {
362
- messages.push({
363
- role: msg.role,
364
- content: msg.content
365
- });
366
- continue;
367
- }
368
- if (Array.isArray(msg.content)) {
369
- if (msg.role === "user") {
370
- const toolParts = msg.content.filter(
371
- (c) => c.type === "tool_result" && c.tool_use_id
372
- );
373
- for (const tool of toolParts) {
374
- messages.push({
375
- role: "tool",
376
- content: typeof tool.content === "string" ? tool.content : JSON.stringify(tool.content),
377
- tool_call_id: tool.tool_use_id,
378
- cache_control: tool.cache_control
379
- });
380
- }
381
- const textAndMediaParts = msg.content.filter(
382
- (c) => c.type === "text" && c.text || c.type === "image" && c.source
383
- );
384
- if (textAndMediaParts.length > 0) {
385
- messages.push({
386
- role: "user",
387
- content: textAndMediaParts.map((part) => {
388
- if (part.type === "image") {
389
- const imagePart = part;
390
- return {
391
- type: "image_url",
392
- image_url: {
393
- url: imagePart.source.type === "base64" ? formatBase64(imagePart.source.data || "", imagePart.source.media_type) : imagePart.source.url || ""
394
- },
395
- media_type: imagePart.source.media_type
396
- };
397
- }
398
- return {
399
- type: "text",
400
- text: part.text
401
- };
402
- })
403
- });
404
- }
405
- } else if (msg.role === "assistant") {
406
- const assistantMessage = {
407
- role: "assistant",
408
- content: ""
409
- };
410
- const textParts = msg.content.filter(
411
- (c) => c.type === "text" && c.text
412
- );
413
- if (textParts.length > 0) {
414
- assistantMessage.content = textParts.map((t) => t.text).join("\n");
415
- }
416
- const toolCallParts = msg.content.filter(
417
- (c) => c.type === "tool_use" && c.id
418
- );
419
- if (toolCallParts.length > 0) {
420
- assistantMessage.tool_calls = toolCallParts.map((tool) => ({
421
- id: tool.id,
422
- type: "function",
423
- function: {
424
- name: tool.name,
425
- arguments: JSON.stringify(tool.input || {})
426
- }
427
- }));
428
- }
429
- const thinkingPart = msg.content.find(
430
- (c) => c.type === "thinking"
431
- );
432
- if (thinkingPart?.thinking) {
433
- assistantMessage.thinking = {
434
- content: thinkingPart.thinking,
435
- signature: thinkingPart.signature
436
- };
437
- }
438
- messages.push(assistantMessage);
439
- }
440
- }
441
- }
442
- const rawTools = anthropicRequest.tools || [];
443
- const serverSideTools = rawTools.filter((t) => isServerSideTool(t));
444
- const functionTools = rawTools.length > 0 ? convertAnthropicToolsToOpenAI(rawTools) : void 0;
445
- const result = {
446
- messages,
447
- model: anthropicRequest.model,
448
- max_tokens: anthropicRequest.max_tokens,
449
- temperature: anthropicRequest.temperature,
450
- stream: anthropicRequest.stream,
451
- tools: functionTools?.length ? functionTools : void 0
452
- };
453
- if (serverSideTools.length > 0) {
454
- result._serverSideTools = serverSideTools;
455
- }
456
- if (anthropicRequest.thinking) {
457
- result.reasoning = {
458
- effort: getThinkLevel(anthropicRequest.thinking.budget_tokens),
459
- enabled: anthropicRequest.thinking.type === "enabled"
460
- };
461
- }
462
- if (anthropicRequest.tool_choice) {
463
- if (anthropicRequest.tool_choice.type === "tool" && anthropicRequest.tool_choice.name) {
464
- result.tool_choice = {
465
- type: "function",
466
- function: { name: anthropicRequest.tool_choice.name }
467
- };
468
- } else {
469
- result.tool_choice = anthropicRequest.tool_choice.type;
470
- }
471
- }
472
- return result;
473
- }
10
+ var _chunkC72S6TTVcjs = require('../chunk-C72S6TTV.cjs');
474
11
 
475
- // src/transformer/transformers/AnthropicAnthropicToOpenAIStream.ts
476
- function convertAnthropicStreamToOpenAI(anthropicStream, logger) {
477
- const decoder = new TextDecoder();
478
- const encoder = new TextEncoder();
479
- const activeToolCalls = /* @__PURE__ */ new Map();
480
- let toolCallCounter = 0;
481
- let model = "unknown";
482
- let messageId = `chatcmpl-${Date.now()}`;
483
- return new ReadableStream({
484
- start: async (controller) => {
485
- const reader = anthropicStream.getReader();
486
- let buffer = "";
487
- let isClosed = false;
488
- const safeEnqueue = (data) => {
489
- if (!isClosed) {
490
- try {
491
- controller.enqueue(encoder.encode(data));
492
- } catch {
493
- isClosed = true;
494
- }
495
- }
496
- };
497
- try {
498
- while (true) {
499
- const { done, value } = await reader.read();
500
- if (done) break;
501
- buffer += decoder.decode(value, { stream: true });
502
- const lines = buffer.split("\n");
503
- buffer = lines.pop() || "";
504
- for (const line of lines) {
505
- if (isClosed) break;
506
- if (!line.startsWith("data:")) continue;
507
- const data = line.slice(5).trim();
508
- if (!data || data === "[DONE]") continue;
509
- try {
510
- const event = JSON.parse(data);
511
- if (event.type === "message_start" && event.message) {
512
- model = event.message.model || model;
513
- messageId = event.message.id || messageId;
514
- }
515
- if (event.type === "content_block_delta" && event.delta) {
516
- const chunk = {
517
- id: messageId,
518
- object: "chat.completion.chunk",
519
- created: Math.floor(Date.now() / 1e3),
520
- model,
521
- choices: [{ index: 0, delta: {}, finish_reason: null }]
522
- };
523
- const delta = chunk.choices[0].delta;
524
- if (event.delta.type === "text_delta") {
525
- delta.content = event.delta.text;
526
- } else if (event.delta.type === "input_json_delta") {
527
- const toolInfo = activeToolCalls.get(event.index);
528
- if (toolInfo) {
529
- delta.tool_calls = [{
530
- index: toolInfo.index,
531
- function: { arguments: event.delta.partial_json }
532
- }];
533
- }
534
- } else if (event.delta.type === "thinking_delta") {
535
- delta.thinking = { content: event.delta.thinking };
536
- } else if (event.delta.type === "signature_delta") {
537
- delta.thinking = { signature: event.delta.signature };
538
- } else {
539
- continue;
540
- }
541
- safeEnqueue(`data: ${JSON.stringify(chunk)}
542
12
 
543
- `);
544
- }
545
- if (event.type === "content_block_start" && event.content_block) {
546
- if (event.content_block.type === "tool_use" || event.content_block.type === "server_tool_use") {
547
- const tcIndex = toolCallCounter++;
548
- activeToolCalls.set(event.index, {
549
- id: event.content_block.id,
550
- name: event.content_block.name,
551
- index: tcIndex
552
- });
553
- const chunk = {
554
- id: messageId,
555
- object: "chat.completion.chunk",
556
- created: Math.floor(Date.now() / 1e3),
557
- model,
558
- choices: [{
559
- index: 0,
560
- delta: {
561
- tool_calls: [{
562
- index: tcIndex,
563
- id: event.content_block.id,
564
- type: "function",
565
- function: { name: event.content_block.name, arguments: "" }
566
- }]
567
- },
568
- finish_reason: null
569
- }]
570
- };
571
- safeEnqueue(`data: ${JSON.stringify(chunk)}
13
+ var _chunkDWKQZ2SKcjs = require('../chunk-DWKQZ2SK.cjs');
572
14
 
573
- `);
574
- } else if (event.content_block.type === "web_search_tool_result") {
575
- const searches = event.content_block.content;
576
- if (searches?.length) {
577
- const formatted = searches.map((s) => `[${s.title}](${s.url}): ${s.page_content || s.snippet || ""}`).join("\n");
578
- const chunk = {
579
- id: messageId,
580
- object: "chat.completion.chunk",
581
- created: Math.floor(Date.now() / 1e3),
582
- model,
583
- choices: [{
584
- index: 0,
585
- delta: { content: `
586
15
 
587
- **Search Results:**
588
- ${formatted}` },
589
- finish_reason: null
590
- }]
591
- };
592
- safeEnqueue(`data: ${JSON.stringify(chunk)}
16
+ var _chunk4VAVYUZScjs = require('../chunk-4VAVYUZS.cjs');
593
17
 
594
- `);
595
- }
596
- }
597
- }
598
- if (event.type === "message_delta" && event.delta) {
599
- const stopReasonMapping = {
600
- end_turn: "stop",
601
- max_tokens: "length",
602
- tool_use: "tool_calls",
603
- stop_sequence: "stop"
604
- };
605
- const chunk = {
606
- id: messageId,
607
- object: "chat.completion.chunk",
608
- created: Math.floor(Date.now() / 1e3),
609
- model,
610
- choices: [{
611
- index: 0,
612
- delta: {},
613
- finish_reason: stopReasonMapping[event.delta.stop_reason] || "stop"
614
- }]
615
- };
616
- if (event.usage) {
617
- chunk.usage = {
618
- prompt_tokens: event.usage.input_tokens || 0,
619
- completion_tokens: event.usage.output_tokens || 0,
620
- total_tokens: (event.usage.input_tokens || 0) + (event.usage.output_tokens || 0)
621
- };
622
- }
623
- safeEnqueue(`data: ${JSON.stringify(chunk)}
624
18
 
625
- `);
626
- }
627
- } catch (e) {
628
- logger?.error("Error parsing Anthropic stream event:", e);
629
- }
630
- }
631
- }
632
- } catch (e) {
633
- if (!isClosed) {
634
- controller.error(e);
635
- }
636
- } finally {
637
- safeEnqueue("data: [DONE]\n\n");
638
- if (!isClosed) {
639
- try {
640
- controller.close();
641
- } catch {
642
- }
643
- }
644
- reader.releaseLock();
645
- }
646
- }
647
- });
648
- }
19
+ var _chunk7YN22L2Hcjs = require('../chunk-7YN22L2H.cjs');
649
20
 
650
- // src/transformer/transformers/AnthropicOpenAIToAnthropicStream.ts
651
- function convertOpenAIStreamToAnthropic(openaiStream, _context, logger) {
652
- const decoder = new TextDecoder();
653
- const encoder = new TextEncoder();
654
- let hasStarted = false;
655
- let hasTextContentStarted = false;
656
- let isThinkingStarted = false;
657
- let contentIndex = 0;
658
- let currentContentBlockIndex = -1;
659
- const toolCallIndexToContentBlockIndex = /* @__PURE__ */ new Map();
660
- return new ReadableStream({
661
- start: async (controller) => {
662
- const reader = openaiStream.getReader();
663
- let buffer = "";
664
- const messageId = `msg_${Date.now()}`;
665
- let model = "unknown";
666
- let isClosed = false;
667
- let stopReasonDelta = null;
668
- const safeEnqueue = (data) => {
669
- if (!isClosed) {
670
- try {
671
- controller.enqueue(encoder.encode(data));
672
- } catch (_e) {
673
- isClosed = true;
674
- }
675
- }
676
- };
677
- const assignContentBlockIndex = () => {
678
- return contentIndex++;
679
- };
680
- const safeClose = () => {
681
- if (isClosed) return;
682
- if (currentContentBlockIndex >= 0) {
683
- safeEnqueue(`event: content_block_stop
684
- data: ${JSON.stringify({
685
- type: "content_block_stop",
686
- index: currentContentBlockIndex
687
- })}
688
21
 
689
- `);
690
- }
691
- if (stopReasonDelta) {
692
- safeEnqueue(`event: message_delta
693
- data: ${JSON.stringify(stopReasonDelta)}
22
+ var _chunk2DCNB7DFcjs = require('../chunk-2DCNB7DF.cjs');
694
23
 
695
- `);
696
- } else {
697
- safeEnqueue(`event: message_delta
698
- data: ${JSON.stringify({
699
- type: "message_delta",
700
- delta: { stop_reason: "end_turn", stop_sequence: null },
701
- usage: { input_tokens: 0, output_tokens: 0 }
702
- })}
703
24
 
704
- `);
705
- }
706
- safeEnqueue(`event: message_stop
707
- data: ${JSON.stringify({ type: "message_stop" })}
25
+ var _chunkRSJ3TWJQcjs = require('../chunk-RSJ3TWJQ.cjs');
26
+ require('../chunk-YGXJGRFI.cjs');
708
27
 
709
- `);
710
- try {
711
- controller.close();
712
- } catch (_e) {
713
- }
714
- isClosed = true;
715
- };
716
- try {
717
- while (true) {
718
- const { done, value } = await reader.read();
719
- if (done) break;
720
- buffer += decoder.decode(value, { stream: true });
721
- const lines = buffer.split("\n");
722
- buffer = lines.pop() || "";
723
- for (const line of lines) {
724
- if (isClosed) break;
725
- if (!line.startsWith("data:")) continue;
726
- const data = line.slice(5).trim();
727
- if (data === "[DONE]") continue;
728
- try {
729
- const chunk = JSON.parse(data);
730
- if (chunk.error) {
731
- safeEnqueue(`event: error
732
- data: ${JSON.stringify({
733
- type: "error",
734
- message: { type: "api_error", message: JSON.stringify(chunk.error) }
735
- })}
736
28
 
737
- `);
738
- continue;
739
- }
740
- model = chunk.model || model;
741
- if (!hasStarted) {
742
- hasStarted = true;
743
- safeEnqueue(`event: message_start
744
- data: ${JSON.stringify({
745
- type: "message_start",
746
- message: {
747
- id: messageId,
748
- type: "message",
749
- role: "assistant",
750
- content: [],
751
- model,
752
- stop_reason: null,
753
- stop_sequence: null,
754
- usage: { input_tokens: 0, output_tokens: 0 }
755
- }
756
- })}
757
29
 
758
- `);
759
- }
760
- const choice = chunk.choices?.[0];
761
- if (!choice) continue;
762
- if (chunk.usage) {
763
- stopReasonDelta = {
764
- type: "message_delta",
765
- delta: { stop_reason: "end_turn", stop_sequence: null },
766
- usage: {
767
- input_tokens: (chunk.usage.prompt_tokens || 0) - (chunk.usage.prompt_tokens_details?.cached_tokens || 0),
768
- output_tokens: chunk.usage.completion_tokens || 0,
769
- cache_read_input_tokens: chunk.usage.prompt_tokens_details?.cached_tokens || 0
770
- }
771
- };
772
- }
773
- if (choice.delta?.thinking) {
774
- if (!isThinkingStarted) {
775
- const thinkingBlockIndex = assignContentBlockIndex();
776
- safeEnqueue(`event: content_block_start
777
- data: ${JSON.stringify({
778
- type: "content_block_start",
779
- index: thinkingBlockIndex,
780
- content_block: { type: "thinking", thinking: "" }
781
- })}
782
30
 
783
- `);
784
- currentContentBlockIndex = thinkingBlockIndex;
785
- isThinkingStarted = true;
786
- }
787
- if (choice.delta.thinking.signature) {
788
- safeEnqueue(`event: content_block_delta
789
- data: ${JSON.stringify({
790
- type: "content_block_delta",
791
- index: currentContentBlockIndex,
792
- delta: { type: "signature_delta", signature: choice.delta.thinking.signature }
793
- })}
794
31
 
795
- `);
796
- safeEnqueue(`event: content_block_stop
797
- data: ${JSON.stringify({
798
- type: "content_block_stop",
799
- index: currentContentBlockIndex
800
- })}
801
32
 
802
- `);
803
- currentContentBlockIndex = -1;
804
- } else if (choice.delta.thinking.content) {
805
- safeEnqueue(`event: content_block_delta
806
- data: ${JSON.stringify({
807
- type: "content_block_delta",
808
- index: currentContentBlockIndex,
809
- delta: { type: "thinking_delta", thinking: choice.delta.thinking.content }
810
- })}
811
33
 
812
- `);
813
- }
814
- }
815
- if (choice.delta?.content) {
816
- if (!hasTextContentStarted) {
817
- if (currentContentBlockIndex >= 0 && isThinkingStarted) {
818
- safeEnqueue(`event: content_block_stop
819
- data: ${JSON.stringify({
820
- type: "content_block_stop",
821
- index: currentContentBlockIndex
822
- })}
823
34
 
824
- `);
825
- }
826
- hasTextContentStarted = true;
827
- const textBlockIndex = assignContentBlockIndex();
828
- safeEnqueue(`event: content_block_start
829
- data: ${JSON.stringify({
830
- type: "content_block_start",
831
- index: textBlockIndex,
832
- content_block: { type: "text", text: "" }
833
- })}
834
35
 
835
- `);
836
- currentContentBlockIndex = textBlockIndex;
837
- }
838
- safeEnqueue(`event: content_block_delta
839
- data: ${JSON.stringify({
840
- type: "content_block_delta",
841
- index: currentContentBlockIndex,
842
- delta: { type: "text_delta", text: choice.delta.content }
843
- })}
844
36
 
845
- `);
846
- }
847
- if (choice.delta?.tool_calls) {
848
- for (const toolCall of choice.delta.tool_calls) {
849
- const toolCallIndex = toolCall.index ?? 0;
850
- if (!toolCallIndexToContentBlockIndex.has(toolCallIndex)) {
851
- if (currentContentBlockIndex >= 0) {
852
- safeEnqueue(`event: content_block_stop
853
- data: ${JSON.stringify({
854
- type: "content_block_stop",
855
- index: currentContentBlockIndex
856
- })}
857
37
 
858
- `);
859
- hasTextContentStarted = false;
860
- }
861
- const newBlockIndex = assignContentBlockIndex();
862
- toolCallIndexToContentBlockIndex.set(toolCallIndex, newBlockIndex);
863
- safeEnqueue(`event: content_block_start
864
- data: ${JSON.stringify({
865
- type: "content_block_start",
866
- index: newBlockIndex,
867
- content_block: {
868
- type: "tool_use",
869
- id: toolCall.id || `call_${Date.now()}_${toolCallIndex}`,
870
- name: toolCall.function?.name || `tool_${toolCallIndex}`,
871
- input: {}
872
- }
873
- })}
874
38
 
875
- `);
876
- currentContentBlockIndex = newBlockIndex;
877
- }
878
- if (toolCall.function?.arguments) {
879
- const blockIndex = toolCallIndexToContentBlockIndex.get(toolCallIndex);
880
- if (blockIndex !== void 0) {
881
- safeEnqueue(`event: content_block_delta
882
- data: ${JSON.stringify({
883
- type: "content_block_delta",
884
- index: blockIndex,
885
- delta: { type: "input_json_delta", partial_json: toolCall.function.arguments }
886
- })}
887
-
888
- `);
889
- }
890
- }
891
- }
892
- }
893
- if (choice.finish_reason) {
894
- const stopReasonMapping = {
895
- stop: "end_turn",
896
- length: "max_tokens",
897
- tool_calls: "tool_use",
898
- content_filter: "stop_sequence"
899
- };
900
- stopReasonDelta = {
901
- type: "message_delta",
902
- delta: {
903
- stop_reason: stopReasonMapping[choice.finish_reason] || "end_turn",
904
- stop_sequence: null
905
- },
906
- usage: {
907
- input_tokens: (chunk.usage?.prompt_tokens || 0) - (chunk.usage?.prompt_tokens_details?.cached_tokens || 0),
908
- output_tokens: chunk.usage?.completion_tokens || 0,
909
- cache_read_input_tokens: chunk.usage?.prompt_tokens_details?.cached_tokens || 0
910
- }
911
- };
912
- }
913
- } catch (e) {
914
- logger?.error("Error parsing stream chunk:", e);
915
- }
916
- }
917
- }
918
- } catch (e) {
919
- if (!isClosed) {
920
- controller.error(e);
921
- }
922
- } finally {
923
- safeClose();
924
- reader.releaseLock();
925
- }
926
- }
927
- });
928
- }
929
-
930
- // src/transformer/transformers/AnthropicTransformer.ts
931
- var AnthropicTransformer = class {
932
- static TransformerName = "anthropic";
933
- name = "anthropic";
934
- logger;
935
- endPoint = "/v1/messages";
936
- useBearer;
937
- constructor(options) {
938
- this.useBearer = options?.UseBearer ?? false;
939
- }
940
- /**
941
- * Handle authentication - Anthropic uses x-api-key header
942
- */
943
- async auth(request, provider, _context) {
944
- const headers = {};
945
- if (this.useBearer) {
946
- headers["authorization"] = `Bearer ${provider.apiKey}`;
947
- headers["x-api-key"] = void 0;
948
- } else {
949
- headers["x-api-key"] = provider.apiKey;
950
- headers["authorization"] = void 0;
951
- }
952
- return {
953
- body: request,
954
- config: { headers }
955
- };
956
- }
957
- /**
958
- * Transform Anthropic request to unified format.
959
- */
960
- async transformRequestOut(request, _context) {
961
- return transformAnthropicRequestToUnified(request);
962
- }
963
- /**
964
- * Transform OpenAI/unified response back to Anthropic format
965
- * (auto-detects stream vs JSON via Content-Type).
966
- */
967
- async transformResponseIn(response, context) {
968
- const contentType = response.headers.get("Content-Type") ?? "";
969
- if (contentType.includes("text/event-stream")) {
970
- if (!response.body) {
971
- throw new Error("Stream response body is null");
972
- }
973
- const convertedStream = convertOpenAIStreamToAnthropic(response.body, context, this.logger);
974
- return new Response(convertedStream, {
975
- headers: {
976
- "Content-Type": "text/event-stream",
977
- "Cache-Control": "no-cache",
978
- Connection: "keep-alive"
979
- }
980
- });
981
- } else {
982
- const data = await response.json();
983
- const anthropicResponse = convertOpenAIResponseToAnthropic(data);
984
- return new Response(JSON.stringify(anthropicResponse), {
985
- headers: { "Content-Type": "application/json" }
986
- });
987
- }
988
- }
989
- /**
990
- * Transform unified request to Anthropic Messages API format.
991
- * This is the reverse of transformRequestOut — converts OpenAI/unified format
992
- * to Anthropic's expected request body structure.
993
- */
994
- async transformRequestIn(request, _provider, _context) {
995
- return buildAnthropicRequestBody(request);
996
- }
997
- /**
998
- * Transform Anthropic response to OpenAI/unified format
999
- * (auto-detects stream vs JSON via Content-Type).
1000
- */
1001
- async transformResponseOut(response, _context) {
1002
- const contentType = response.headers.get("Content-Type") ?? "";
1003
- if (contentType.includes("text/event-stream")) {
1004
- if (!response.body) {
1005
- throw new Error("Stream response body is null");
1006
- }
1007
- const convertedStream = convertAnthropicStreamToOpenAI(response.body, this.logger);
1008
- return new Response(convertedStream, {
1009
- headers: {
1010
- "Content-Type": "text/event-stream",
1011
- "Cache-Control": "no-cache",
1012
- Connection: "keep-alive"
1013
- }
1014
- });
1015
- } else {
1016
- const data = await response.json();
1017
- const openaiResponse = convertAnthropicResponseToOpenAI(data);
1018
- return new Response(JSON.stringify(openaiResponse), {
1019
- headers: { "Content-Type": "application/json" }
1020
- });
1021
- }
1022
- }
1023
- };
1024
-
1025
- // src/transformer/transformers/DeepseekTransformer.ts
1026
- var DeepseekTransformer = class {
1027
- static TransformerName = "deepseek";
1028
- name = "deepseek";
1029
- logger;
1030
- /**
1031
- * Transform request: limit max_tokens to 8192 for legacy models only
1032
- * V4 models support up to 384K output tokens
1033
- */
1034
- async transformRequestIn(request, _provider, _context) {
1035
- const isV4 = request.model?.startsWith("deepseek-v4");
1036
- if (!isV4 && request.max_tokens && request.max_tokens > 8192) {
1037
- this.logger?.debug("DeepSeek: Limiting max_tokens from %d to 8192", request.max_tokens);
1038
- request.max_tokens = 8192;
1039
- }
1040
- return request;
1041
- }
1042
- /**
1043
- * Transform response: convert reasoning_content to thinking blocks
1044
- */
1045
- async transformResponseOut(response, _context) {
1046
- const contentType = response.headers.get("Content-Type") ?? "";
1047
- if (contentType.includes("application/json")) {
1048
- return this.handleJsonResponse(response);
1049
- } else if (contentType.includes("stream") || contentType.includes("text/event-stream")) {
1050
- return this.handleStreamResponse(response);
1051
- }
1052
- return response;
1053
- }
1054
- /**
1055
- * Handle JSON (non-streaming) response
1056
- */
1057
- async handleJsonResponse(response) {
1058
- const jsonResponse = await response.json();
1059
- if (jsonResponse.choices?.[0]?.message?.reasoning_content) {
1060
- jsonResponse.choices[0].message.thinking = {
1061
- content: jsonResponse.choices[0].message.reasoning_content
1062
- };
1063
- delete jsonResponse.choices[0].message.reasoning_content;
1064
- }
1065
- return new Response(JSON.stringify(jsonResponse), {
1066
- status: response.status,
1067
- statusText: response.statusText,
1068
- headers: response.headers
1069
- });
1070
- }
1071
- /**
1072
- * Handle streaming response - convert reasoning_content to thinking blocks
1073
- */
1074
- async handleStreamResponse(response) {
1075
- if (!response.body) {
1076
- return response;
1077
- }
1078
- const decoder = new TextDecoder();
1079
- const encoder = new TextEncoder();
1080
- let reasoningContent = "";
1081
- let isReasoningComplete = false;
1082
- let buffer = "";
1083
- const stream = new ReadableStream({
1084
- start: async (controller) => {
1085
- const reader = response.body.getReader();
1086
- const processLine = (line) => {
1087
- if (line.startsWith("data: ") && line.trim() !== "data: [DONE]") {
1088
- try {
1089
- const data = JSON.parse(line.slice(6));
1090
- if (data.choices?.[0]?.delta?.reasoning_content) {
1091
- reasoningContent += data.choices[0].delta.reasoning_content;
1092
- const thinkingChunk = {
1093
- ...data,
1094
- choices: [
1095
- {
1096
- ...data.choices[0],
1097
- delta: {
1098
- ...data.choices[0].delta,
1099
- thinking: {
1100
- content: data.choices[0].delta.reasoning_content
1101
- }
1102
- }
1103
- }
1104
- ]
1105
- };
1106
- delete thinkingChunk.choices[0].delta.reasoning_content;
1107
- const thinkingLine = `data: ${JSON.stringify(thinkingChunk)}
1108
-
1109
- `;
1110
- controller.enqueue(encoder.encode(thinkingLine));
1111
- return;
1112
- }
1113
- if (data.choices?.[0]?.delta?.content && reasoningContent && !isReasoningComplete) {
1114
- isReasoningComplete = true;
1115
- const signature = Date.now().toString();
1116
- const thinkingChunk = {
1117
- ...data,
1118
- choices: [
1119
- {
1120
- ...data.choices[0],
1121
- delta: {
1122
- ...data.choices[0].delta,
1123
- content: null,
1124
- thinking: {
1125
- signature
1126
- }
1127
- }
1128
- }
1129
- ]
1130
- };
1131
- const thinkingLine = `data: ${JSON.stringify(thinkingChunk)}
1132
-
1133
- `;
1134
- controller.enqueue(encoder.encode(thinkingLine));
1135
- }
1136
- if (data.choices?.[0]?.delta?.reasoning_content) {
1137
- delete data.choices[0].delta.reasoning_content;
1138
- }
1139
- if (data.choices?.[0]?.delta && Object.keys(data.choices[0].delta).length > 0) {
1140
- if (isReasoningComplete) {
1141
- data.choices[0].index++;
1142
- }
1143
- const modifiedLine = `data: ${JSON.stringify(data)}
1144
-
1145
- `;
1146
- controller.enqueue(encoder.encode(modifiedLine));
1147
- }
1148
- } catch (_e) {
1149
- controller.enqueue(encoder.encode(line + "\n"));
1150
- }
1151
- } else {
1152
- controller.enqueue(encoder.encode(line + "\n"));
1153
- }
1154
- };
1155
- try {
1156
- while (true) {
1157
- const { done, value } = await reader.read();
1158
- if (done) {
1159
- if (buffer.trim()) {
1160
- const lines2 = buffer.split("\n");
1161
- for (const line of lines2) {
1162
- if (line.trim()) {
1163
- controller.enqueue(encoder.encode(line + "\n"));
1164
- }
1165
- }
1166
- }
1167
- break;
1168
- }
1169
- const chunk = decoder.decode(value, { stream: true });
1170
- buffer += chunk;
1171
- const lines = buffer.split("\n");
1172
- buffer = lines.pop() || "";
1173
- for (const line of lines) {
1174
- if (!line.trim()) continue;
1175
- try {
1176
- processLine(line);
1177
- } catch (error) {
1178
- this.logger?.error("Error processing DeepSeek stream line:", error);
1179
- controller.enqueue(encoder.encode(line + "\n"));
1180
- }
1181
- }
1182
- }
1183
- } catch (error) {
1184
- this.logger?.error("DeepSeek stream error:", error);
1185
- controller.error(error);
1186
- } finally {
1187
- try {
1188
- reader.releaseLock();
1189
- } catch (e) {
1190
- this.logger?.error("Error releasing reader lock:", e);
1191
- }
1192
- controller.close();
1193
- }
1194
- }
1195
- });
1196
- return new Response(stream, {
1197
- status: response.status,
1198
- statusText: response.statusText,
1199
- headers: new Headers({
1200
- "Content-Type": "text/event-stream",
1201
- "Cache-Control": "no-cache",
1202
- Connection: "keep-alive"
1203
- })
1204
- });
1205
- }
1206
- };
1207
-
1208
- // src/transformer/transformers/utils/gemini.response-in.ts
1209
- var FINISH_REASON_TO_GEMINI = {
1210
- stop: "STOP",
1211
- length: "MAX_TOKENS",
1212
- tool_calls: "STOP",
1213
- content_filter: "SAFETY",
1214
- // Already-lowercased Gemini reasons (pass-through from another transformer)
1215
- max_tokens: "MAX_TOKENS",
1216
- safety: "SAFETY"
1217
- };
1218
- function toGeminiFinishReason(openaiReason) {
1219
- if (!openaiReason) return null;
1220
- return FINISH_REASON_TO_GEMINI[openaiReason] || openaiReason.toUpperCase();
1221
- }
1222
- function convertOpenAIResponseToGemini(openaiData) {
1223
- const choice = openaiData.choices?.[0];
1224
- const message = choice?.message ?? {};
1225
- const usage = openaiData.usage;
1226
- const usagePromptDetails = usage?.prompt_tokens_details;
1227
- const usageOutputDetails = usage?.output_tokens_details;
1228
- const parts = [];
1229
- const thinking = message.thinking;
1230
- if (thinking?.content) {
1231
- parts.push({ text: thinking.content, thought: true });
1232
- }
1233
- if (thinking?.signature) {
1234
- parts.push({ thoughtSignature: thinking.signature });
1235
- }
1236
- if (message.content) {
1237
- parts.push({ text: message.content });
1238
- }
1239
- const toolCalls = message.tool_calls;
1240
- if (toolCalls?.length) {
1241
- for (const tc of toolCalls) {
1242
- const func = tc.function;
1243
- let args = {};
1244
- try {
1245
- const raw = func.arguments;
1246
- args = typeof raw === "string" ? JSON.parse(raw) : raw;
1247
- } catch {
1248
- args = {};
1249
- }
1250
- parts.push({
1251
- functionCall: {
1252
- id: tc.id,
1253
- name: func.name,
1254
- args
1255
- }
1256
- });
1257
- }
1258
- }
1259
- if (parts.length === 0) {
1260
- parts.push({ text: "" });
1261
- }
1262
- return {
1263
- responseId: openaiData.id || "",
1264
- modelVersion: openaiData.model || "",
1265
- candidates: [{
1266
- content: { parts },
1267
- finishReason: toGeminiFinishReason(choice?.finish_reason)
1268
- }],
1269
- usageMetadata: usage ? {
1270
- promptTokenCount: usage.prompt_tokens || 0,
1271
- candidatesTokenCount: usage.completion_tokens || 0,
1272
- totalTokenCount: usage.total_tokens || 0,
1273
- cachedContentTokenCount: usagePromptDetails?.cached_tokens || 0,
1274
- thoughtsTokenCount: usageOutputDetails?.reasoning_tokens || 0
1275
- } : void 0
1276
- };
1277
- }
1278
- function convertOpenAIStreamToGemini(openaiStream, logger) {
1279
- const decoder = new TextDecoder();
1280
- const encoder = new TextEncoder();
1281
- const pendingToolCalls = /* @__PURE__ */ new Map();
1282
- let model = "";
1283
- let responseId = "";
1284
- return new ReadableStream({
1285
- start: async (controller) => {
1286
- const reader = openaiStream.getReader();
1287
- let buffer = "";
1288
- let isClosed = false;
1289
- const emit = (data) => {
1290
- if (isClosed) return;
1291
- try {
1292
- controller.enqueue(encoder.encode(`data: ${JSON.stringify(data)}
1293
-
1294
- `));
1295
- } catch {
1296
- isClosed = true;
1297
- }
1298
- };
1299
- const flushToolCalls = () => {
1300
- if (pendingToolCalls.size === 0) return;
1301
- const parts = [];
1302
- for (const tc of pendingToolCalls.values()) {
1303
- let args = {};
1304
- try {
1305
- args = JSON.parse(tc.args || "{}");
1306
- } catch {
1307
- }
1308
- parts.push({
1309
- functionCall: { id: tc.id, name: tc.name, args }
1310
- });
1311
- }
1312
- pendingToolCalls.clear();
1313
- emit({
1314
- responseId,
1315
- modelVersion: model,
1316
- candidates: [{ content: { parts }, finishReason: null }]
1317
- });
1318
- };
1319
- try {
1320
- while (true) {
1321
- const { done, value } = await reader.read();
1322
- if (done) break;
1323
- buffer += decoder.decode(value, { stream: true });
1324
- const lines = buffer.split("\n");
1325
- buffer = lines.pop() || "";
1326
- for (const line of lines) {
1327
- if (isClosed) break;
1328
- if (!line.startsWith("data:")) continue;
1329
- const data = line.slice(5).trim();
1330
- if (!data || data === "[DONE]") continue;
1331
- try {
1332
- const chunk = JSON.parse(data);
1333
- if (!responseId && chunk.id) responseId = chunk.id;
1334
- if (!model && chunk.model) model = chunk.model;
1335
- const choice = chunk.choices?.[0];
1336
- if (!choice) continue;
1337
- const delta = choice.delta ?? {};
1338
- if (delta.thinking) {
1339
- const parts = [];
1340
- if (delta.thinking.content) {
1341
- parts.push({ text: delta.thinking.content, thought: true });
1342
- }
1343
- if (delta.thinking.signature) {
1344
- parts.push({ thoughtSignature: delta.thinking.signature });
1345
- }
1346
- if (parts.length > 0) {
1347
- emit({
1348
- responseId,
1349
- modelVersion: model,
1350
- candidates: [{ content: { parts }, finishReason: null }]
1351
- });
1352
- }
1353
- }
1354
- if (delta.content) {
1355
- emit({
1356
- responseId,
1357
- modelVersion: model,
1358
- candidates: [{
1359
- content: { parts: [{ text: delta.content }] },
1360
- finishReason: null
1361
- }]
1362
- });
1363
- }
1364
- if (delta.tool_calls) {
1365
- for (const tc of delta.tool_calls) {
1366
- const idx = tc.index ?? 0;
1367
- const existing = pendingToolCalls.get(idx);
1368
- const func = tc.function;
1369
- if (existing) {
1370
- if (func?.arguments) {
1371
- existing.args += func.arguments;
1372
- }
1373
- } else {
1374
- pendingToolCalls.set(idx, {
1375
- id: tc.id || `tool_${Date.now()}_${idx}`,
1376
- name: func?.name || "",
1377
- args: func?.arguments || ""
1378
- });
1379
- }
1380
- }
1381
- }
1382
- if (choice.finish_reason) {
1383
- flushToolCalls();
1384
- const geminiUsage = chunk.usage ? {
1385
- promptTokenCount: chunk.usage.prompt_tokens || 0,
1386
- candidatesTokenCount: chunk.usage.completion_tokens || 0,
1387
- totalTokenCount: chunk.usage.total_tokens || 0,
1388
- cachedContentTokenCount: chunk.usage.prompt_tokens_details?.cached_tokens || 0,
1389
- thoughtsTokenCount: chunk.usage.output_tokens_details?.reasoning_tokens || 0
1390
- } : void 0;
1391
- emit({
1392
- responseId,
1393
- modelVersion: model,
1394
- candidates: [{
1395
- content: { parts: [{ text: "" }] },
1396
- finishReason: toGeminiFinishReason(choice.finish_reason) || "STOP"
1397
- }],
1398
- usageMetadata: geminiUsage
1399
- });
1400
- }
1401
- } catch (e) {
1402
- logger?.error(`Error parsing OpenAI stream chunk for Gemini conversion: ${e}`);
1403
- }
1404
- }
1405
- }
1406
- flushToolCalls();
1407
- } catch (e) {
1408
- if (!isClosed) controller.error(e);
1409
- } finally {
1410
- if (!isClosed) {
1411
- try {
1412
- controller.close();
1413
- } catch {
1414
- }
1415
- }
1416
- reader.releaseLock();
1417
- }
1418
- }
1419
- });
1420
- }
1421
- async function transformResponseIn(response, logger) {
1422
- const contentType = response.headers.get("Content-Type") ?? "";
1423
- if (contentType.includes("text/event-stream")) {
1424
- if (!response.body) {
1425
- throw new Error("Stream response body is null");
1426
- }
1427
- const geminiStream = convertOpenAIStreamToGemini(response.body, logger);
1428
- return new Response(geminiStream, {
1429
- headers: {
1430
- "Content-Type": "text/event-stream",
1431
- "Cache-Control": "no-cache",
1432
- Connection: "keep-alive"
1433
- }
1434
- });
1435
- }
1436
- const data = await response.json();
1437
- const geminiResponse = convertOpenAIResponseToGemini(data);
1438
- return new Response(JSON.stringify(geminiResponse), {
1439
- status: response.status,
1440
- statusText: response.statusText,
1441
- headers: { "Content-Type": "application/json" }
1442
- });
1443
- }
1444
-
1445
- // src/transformer/transformers/utils/gemini.stream.ts
1446
- async function transformResponseOut(response, providerName, logger) {
1447
- const contentType = response.headers.get("Content-Type") ?? "";
1448
- if (contentType.includes("application/json")) {
1449
- return handleJsonResponse(response, providerName, logger);
1450
- } else if (contentType.includes("stream") || contentType.includes("text/event-stream")) {
1451
- return handleStreamResponse(response, providerName, logger);
1452
- }
1453
- return response;
1454
- }
1455
- async function handleJsonResponse(response, providerName, logger) {
1456
- const jsonResponse = await response.json();
1457
- logger?.debug(`${providerName} JSON response received`);
1458
- const parts = jsonResponse.candidates?.[0]?.content?.parts || [];
1459
- let thinkingContent = "";
1460
- let thinkingSignature = "";
1461
- const nonThinkingParts = [];
1462
- for (const part of parts) {
1463
- if (part.text && part.thought === true) {
1464
- thinkingContent += part.text;
1465
- } else {
1466
- nonThinkingParts.push(part);
1467
- }
1468
- }
1469
- thinkingSignature = parts.find((part) => part.thoughtSignature)?.thoughtSignature ?? "";
1470
- const toolCalls = nonThinkingParts.filter((part) => part.functionCall).map((part) => ({
1471
- id: part.functionCall?.id || `tool_${Math.random().toString(36).substring(2, 15)}`,
1472
- type: "function",
1473
- function: {
1474
- name: part.functionCall?.name ?? "",
1475
- arguments: JSON.stringify(part.functionCall?.args || {})
1476
- }
1477
- }));
1478
- const textContent = nonThinkingParts.filter((part) => part.text).map((part) => part.text).join("\n");
1479
- const openAIResponse = {
1480
- id: jsonResponse.responseId ?? "",
1481
- choices: [
1482
- {
1483
- finish_reason: (jsonResponse.candidates?.[0]?.finishReason ?? "").toLowerCase() || null,
1484
- index: 0,
1485
- message: {
1486
- content: textContent,
1487
- role: "assistant",
1488
- tool_calls: toolCalls.length > 0 ? toolCalls : void 0,
1489
- ...thinkingSignature && {
1490
- thinking: {
1491
- content: thinkingContent || "(no content)",
1492
- signature: thinkingSignature
1493
- }
1494
- }
1495
- }
1496
- }
1497
- ],
1498
- created: Math.floor(Date.now() / 1e3),
1499
- model: jsonResponse.modelVersion ?? "",
1500
- object: "chat.completion",
1501
- usage: {
1502
- completion_tokens: jsonResponse.usageMetadata?.candidatesTokenCount || 0,
1503
- prompt_tokens: jsonResponse.usageMetadata?.promptTokenCount || 0,
1504
- prompt_tokens_details: {
1505
- cached_tokens: jsonResponse.usageMetadata?.cachedContentTokenCount || 0
1506
- },
1507
- total_tokens: jsonResponse.usageMetadata?.totalTokenCount || 0,
1508
- output_tokens_details: {
1509
- reasoning_tokens: jsonResponse.usageMetadata?.thoughtsTokenCount || 0
1510
- }
1511
- }
1512
- };
1513
- return new Response(JSON.stringify(openAIResponse), {
1514
- status: response.status,
1515
- statusText: response.statusText,
1516
- headers: response.headers
1517
- });
1518
- }
1519
- function handleStreamResponse(response, providerName, logger) {
1520
- if (!response.body) {
1521
- return response;
1522
- }
1523
- const decoder = new TextDecoder();
1524
- const encoder = new TextEncoder();
1525
- let signatureSent = false;
1526
- let contentSent = false;
1527
- let hasThinkingContent = false;
1528
- let pendingContent = "";
1529
- let contentIndex = 0;
1530
- let toolCallIndex = -1;
1531
- const stream = new ReadableStream({
1532
- async start(controller) {
1533
- const reader = response.body.getReader();
1534
- let buffer = "";
1535
- const processLine = async (line) => {
1536
- if (!line.startsWith("data: ")) return;
1537
- const chunkStr = line.slice(6).trim();
1538
- if (!chunkStr) return;
1539
- logger?.debug(`${providerName} chunk: ${chunkStr.substring(0, 100)}...`);
1540
- try {
1541
- const chunk = JSON.parse(chunkStr);
1542
- if (!chunk.candidates?.[0]) {
1543
- logger?.debug("Invalid chunk structure");
1544
- return;
1545
- }
1546
- const candidate = chunk.candidates[0];
1547
- const parts = candidate.content?.parts || [];
1548
- parts.filter((part) => part.text && part.thought === true).forEach((part) => {
1549
- hasThinkingContent = true;
1550
- const thinkingChunk = createChunk({
1551
- responseId: chunk.responseId,
1552
- modelVersion: chunk.modelVersion,
1553
- contentIndex,
1554
- delta: {
1555
- role: "assistant",
1556
- content: null,
1557
- thinking: { content: part.text }
1558
- }
1559
- });
1560
- controller.enqueue(encoder.encode(`data: ${JSON.stringify(thinkingChunk)}
1561
-
1562
- `));
1563
- });
1564
- const signature = parts.find((part) => part.thoughtSignature)?.thoughtSignature;
1565
- if (signature && !signatureSent) {
1566
- if (!hasThinkingContent) {
1567
- const thinkingChunk = createChunk({
1568
- responseId: chunk.responseId,
1569
- modelVersion: chunk.modelVersion,
1570
- contentIndex,
1571
- delta: {
1572
- role: "assistant",
1573
- content: null,
1574
- thinking: { content: "" }
1575
- }
1576
- });
1577
- controller.enqueue(encoder.encode(`data: ${JSON.stringify(thinkingChunk)}
1578
-
1579
- `));
1580
- }
1581
- const signatureChunk = createChunk({
1582
- responseId: chunk.responseId,
1583
- modelVersion: chunk.modelVersion,
1584
- contentIndex,
1585
- delta: {
1586
- role: "assistant",
1587
- content: null,
1588
- thinking: { signature }
1589
- }
1590
- });
1591
- controller.enqueue(encoder.encode(`data: ${JSON.stringify(signatureChunk)}
1592
-
1593
- `));
1594
- signatureSent = true;
1595
- contentIndex++;
1596
- if (pendingContent) {
1597
- const pendingChunk = createChunk({
1598
- responseId: chunk.responseId,
1599
- modelVersion: chunk.modelVersion,
1600
- contentIndex,
1601
- delta: { role: "assistant", content: pendingContent }
1602
- });
1603
- controller.enqueue(encoder.encode(`data: ${JSON.stringify(pendingChunk)}
1604
-
1605
- `));
1606
- pendingContent = "";
1607
- contentSent = true;
1608
- }
1609
- }
1610
- const toolCalls = parts.filter((part) => part.functionCall).map((part) => ({
1611
- id: part.functionCall?.id || `ccr_tool_${Math.random().toString(36).substring(2, 15)}`,
1612
- type: "function",
1613
- function: {
1614
- name: part.functionCall?.name ?? "",
1615
- arguments: JSON.stringify(part.functionCall?.args || {})
1616
- }
1617
- }));
1618
- const textContent = parts.filter((part) => part.text && part.thought !== true).map((part) => part.text).join("\n");
1619
- if (!textContent && signatureSent && !contentSent) {
1620
- contentSent = true;
1621
- }
1622
- if (hasThinkingContent && textContent && !signatureSent) {
1623
- if (chunk.modelVersion?.includes("3")) {
1624
- pendingContent += textContent;
1625
- return;
1626
- } else {
1627
- const signatureChunk = createChunk({
1628
- responseId: chunk.responseId,
1629
- modelVersion: chunk.modelVersion,
1630
- contentIndex,
1631
- delta: {
1632
- role: "assistant",
1633
- content: null,
1634
- thinking: { signature: `ccr_${Date.now()}` }
1635
- }
1636
- });
1637
- controller.enqueue(encoder.encode(`data: ${JSON.stringify(signatureChunk)}
1638
-
1639
- `));
1640
- signatureSent = true;
1641
- }
1642
- }
1643
- if (textContent) {
1644
- if (!pendingContent) contentIndex++;
1645
- const contentChunk = createChunk({
1646
- responseId: chunk.responseId,
1647
- modelVersion: chunk.modelVersion,
1648
- contentIndex,
1649
- delta: { role: "assistant", content: textContent },
1650
- finishReason: candidate.finishReason,
1651
- usageMetadata: chunk.usageMetadata,
1652
- groundingMetadata: candidate.groundingMetadata
1653
- });
1654
- controller.enqueue(encoder.encode(`data: ${JSON.stringify(contentChunk)}
1655
-
1656
- `));
1657
- contentSent = true;
1658
- }
1659
- if (toolCalls.length > 0) {
1660
- for (const tool of toolCalls) {
1661
- contentIndex++;
1662
- toolCallIndex++;
1663
- const toolChunk = createChunk({
1664
- responseId: chunk.responseId,
1665
- modelVersion: chunk.modelVersion,
1666
- contentIndex,
1667
- delta: {
1668
- role: "assistant",
1669
- tool_calls: [{ ...tool, index: toolCallIndex }]
1670
- },
1671
- finishReason: candidate.finishReason,
1672
- usageMetadata: chunk.usageMetadata,
1673
- groundingMetadata: candidate.groundingMetadata
1674
- });
1675
- controller.enqueue(encoder.encode(`data: ${JSON.stringify(toolChunk)}
1676
-
1677
- `));
1678
- }
1679
- contentSent = true;
1680
- }
1681
- } catch (_error) {
1682
- logger?.error(`Error parsing ${providerName} stream chunk: ${chunkStr}`);
1683
- }
1684
- };
1685
- try {
1686
- while (true) {
1687
- const { done, value } = await reader.read();
1688
- if (done) {
1689
- if (buffer) await processLine(buffer);
1690
- break;
1691
- }
1692
- buffer += decoder.decode(value, { stream: true });
1693
- const lines = buffer.split("\n");
1694
- buffer = lines.pop() || "";
1695
- for (const line of lines) {
1696
- await processLine(line);
1697
- }
1698
- }
1699
- } catch (error) {
1700
- controller.error(error);
1701
- } finally {
1702
- controller.close();
1703
- }
1704
- }
1705
- });
1706
- return new Response(stream, {
1707
- status: response.status,
1708
- statusText: response.statusText,
1709
- headers: response.headers
1710
- });
1711
- }
1712
- function createChunk(options) {
1713
- const {
1714
- responseId,
1715
- modelVersion,
1716
- contentIndex,
1717
- delta,
1718
- finishReason,
1719
- usageMetadata,
1720
- groundingMetadata
1721
- } = options;
1722
- const chunk = {
1723
- choices: [
1724
- {
1725
- delta,
1726
- finish_reason: finishReason?.toLowerCase() || null,
1727
- index: contentIndex,
1728
- logprobs: null
1729
- }
1730
- ],
1731
- created: Math.floor(Date.now() / 1e3),
1732
- id: responseId || "",
1733
- model: modelVersion || "",
1734
- object: "chat.completion.chunk",
1735
- system_fingerprint: "fp_a49d71b8a1"
1736
- };
1737
- if (usageMetadata) {
1738
- chunk.usage = {
1739
- completion_tokens: usageMetadata.candidatesTokenCount || 0,
1740
- prompt_tokens: usageMetadata.promptTokenCount || 0,
1741
- prompt_tokens_details: {
1742
- cached_tokens: usageMetadata.cachedContentTokenCount || 0
1743
- },
1744
- total_tokens: usageMetadata.totalTokenCount || 0,
1745
- output_tokens_details: {
1746
- reasoning_tokens: usageMetadata.thoughtsTokenCount || 0
1747
- }
1748
- };
1749
- }
1750
- if (groundingMetadata?.groundingChunks?.length) {
1751
- const annotations = groundingMetadata.groundingChunks.map((groundingChunk, index) => {
1752
- const support = groundingMetadata.groundingSupports?.find(
1753
- (s) => s.groundingChunkIndices?.includes(index)
1754
- );
1755
- return {
1756
- type: "url_citation",
1757
- url_citation: {
1758
- url: groundingChunk.web?.uri || "",
1759
- title: groundingChunk.web?.title || "",
1760
- content: support?.segment?.text || "",
1761
- start_index: support?.segment?.startIndex || 0,
1762
- end_index: support?.segment?.endIndex || 0
1763
- }
1764
- };
1765
- });
1766
- chunk.choices[0].delta.annotations = annotations;
1767
- }
1768
- return chunk;
1769
- }
1770
-
1771
- // src/transformer/transformers/utils/gemini.schema.ts
1772
- var GeminiType = {
1773
- TYPE_UNSPECIFIED: "TYPE_UNSPECIFIED",
1774
- STRING: "STRING",
1775
- NUMBER: "NUMBER",
1776
- INTEGER: "INTEGER",
1777
- BOOLEAN: "BOOLEAN",
1778
- ARRAY: "ARRAY",
1779
- OBJECT: "OBJECT",
1780
- NULL: "NULL"
1781
- };
1782
- function flattenTypeArrayToAnyOf(typeList, resultingSchema) {
1783
- if (typeList.includes("null")) {
1784
- resultingSchema.nullable = true;
1785
- }
1786
- const listWithoutNull = typeList.filter((type) => type !== "null");
1787
- if (listWithoutNull.length === 1) {
1788
- const upperCaseType = listWithoutNull[0].toUpperCase();
1789
- resultingSchema.type = Object.values(GeminiType).includes(upperCaseType) ? upperCaseType : GeminiType.TYPE_UNSPECIFIED;
1790
- } else {
1791
- resultingSchema.anyOf = listWithoutNull.map((typeName) => {
1792
- const upperCaseType = typeName.toUpperCase();
1793
- return {
1794
- type: Object.values(GeminiType).includes(upperCaseType) ? upperCaseType : GeminiType.TYPE_UNSPECIFIED
1795
- };
1796
- });
1797
- }
1798
- }
1799
- function processJsonSchema(jsonSchema) {
1800
- const genAISchema = {};
1801
- const schemaFieldNames = ["items"];
1802
- const listSchemaFieldNames = ["anyOf"];
1803
- const dictSchemaFieldNames = ["properties"];
1804
- let workingSchema = jsonSchema;
1805
- if (workingSchema.type && workingSchema.anyOf) {
1806
- throw new Error("type and anyOf cannot be both populated.");
1807
- }
1808
- const incomingAnyOf = workingSchema.anyOf;
1809
- if (incomingAnyOf && Array.isArray(incomingAnyOf) && incomingAnyOf.length === 2) {
1810
- if (incomingAnyOf[0]?.type === "null") {
1811
- genAISchema.nullable = true;
1812
- workingSchema = incomingAnyOf[1];
1813
- } else if (incomingAnyOf[1]?.type === "null") {
1814
- genAISchema.nullable = true;
1815
- workingSchema = incomingAnyOf[0];
1816
- }
1817
- }
1818
- if (workingSchema.type && Array.isArray(workingSchema.type)) {
1819
- flattenTypeArrayToAnyOf(workingSchema.type, genAISchema);
1820
- }
1821
- for (const [fieldName, fieldValue] of Object.entries(workingSchema)) {
1822
- if (fieldValue == null) {
1823
- continue;
1824
- }
1825
- if (fieldName === "type") {
1826
- if (fieldValue === "null") {
1827
- throw new Error("type: null cannot be the only possible type for the field.");
1828
- }
1829
- if (Array.isArray(fieldValue)) {
1830
- continue;
1831
- }
1832
- const upperCaseValue = fieldValue.toUpperCase();
1833
- genAISchema.type = Object.values(GeminiType).includes(upperCaseValue) ? upperCaseValue : GeminiType.TYPE_UNSPECIFIED;
1834
- } else if (schemaFieldNames.includes(fieldName)) {
1835
- genAISchema[fieldName] = processJsonSchema(fieldValue);
1836
- } else if (listSchemaFieldNames.includes(fieldName)) {
1837
- const listValue = [];
1838
- for (const item of fieldValue) {
1839
- if (item.type === "null") {
1840
- genAISchema.nullable = true;
1841
- continue;
1842
- }
1843
- listValue.push(processJsonSchema(item));
1844
- }
1845
- genAISchema[fieldName] = listValue;
1846
- } else if (dictSchemaFieldNames.includes(fieldName)) {
1847
- const dictValue = {};
1848
- for (const [key, value] of Object.entries(fieldValue)) {
1849
- dictValue[key] = processJsonSchema(value);
1850
- }
1851
- genAISchema[fieldName] = dictValue;
1852
- } else {
1853
- if (fieldName === "additionalProperties") {
1854
- continue;
1855
- }
1856
- genAISchema[fieldName] = fieldValue;
1857
- }
1858
- }
1859
- return genAISchema;
1860
- }
1861
- function transformTool(tool) {
1862
- const functionDeclarations = tool.functionDeclarations;
1863
- if (functionDeclarations) {
1864
- for (const functionDeclaration of functionDeclarations) {
1865
- if (functionDeclaration.parameters) {
1866
- const params = functionDeclaration.parameters;
1867
- if (!Object.keys(params).includes("$schema")) {
1868
- functionDeclaration.parameters = processJsonSchema(params);
1869
- } else {
1870
- if (!functionDeclaration.parametersJsonSchema) {
1871
- functionDeclaration.parametersJsonSchema = functionDeclaration.parameters;
1872
- delete functionDeclaration.parameters;
1873
- }
1874
- }
1875
- }
1876
- if (functionDeclaration.response) {
1877
- const response = functionDeclaration.response;
1878
- if (!Object.keys(response).includes("$schema")) {
1879
- functionDeclaration.response = processJsonSchema(response);
1880
- } else {
1881
- if (!functionDeclaration.responseJsonSchema) {
1882
- functionDeclaration.responseJsonSchema = functionDeclaration.response;
1883
- delete functionDeclaration.response;
1884
- }
1885
- }
1886
- }
1887
- }
1888
- }
1889
- return tool;
1890
- }
1891
-
1892
- // src/transformer/transformers/utils/gemini.util.ts
1893
- function buildRequestBody(request) {
1894
- const tools = [];
1895
- const functionDeclarations = request.tools?.filter((tool) => tool.function.name !== "web_search")?.map((tool) => ({
1896
- name: tool.function.name,
1897
- description: tool.function.description,
1898
- parametersJsonSchema: tool.function.parameters
1899
- }));
1900
- if (functionDeclarations?.length) {
1901
- tools.push(
1902
- transformTool({
1903
- functionDeclarations
1904
- })
1905
- );
1906
- }
1907
- const webSearch = request.tools?.find((tool) => tool.function.name === "web_search");
1908
- if (webSearch) {
1909
- tools.push({ googleSearch: {} });
1910
- }
1911
- const contents = [];
1912
- const toolResponses = request.messages.filter((item) => item.role === "tool");
1913
- request.messages.filter((item) => item.role !== "tool").forEach((message) => {
1914
- let role;
1915
- if (message.role === "assistant") {
1916
- role = "model";
1917
- } else if (["user", "system"].includes(message.role)) {
1918
- role = "user";
1919
- } else {
1920
- role = "user";
1921
- }
1922
- const parts = [];
1923
- if (typeof message.content === "string") {
1924
- const part = { text: message.content };
1925
- if (message.thinking?.signature) {
1926
- part.thoughtSignature = message.thinking.signature;
1927
- }
1928
- parts.push(part);
1929
- } else if (Array.isArray(message.content)) {
1930
- for (const content of message.content) {
1931
- if (content.type === "text") {
1932
- parts.push({ text: content.text || "" });
1933
- } else if (content.type === "image_url") {
1934
- const imageUrl = content.image_url?.url ?? "";
1935
- if (imageUrl.startsWith("http")) {
1936
- parts.push({
1937
- file_data: {
1938
- mime_type: content.media_type,
1939
- file_uri: imageUrl
1940
- }
1941
- });
1942
- } else {
1943
- const data = imageUrl.split(",").pop() || imageUrl;
1944
- parts.push({
1945
- inlineData: {
1946
- mime_type: content.media_type || "image/png",
1947
- data
1948
- }
1949
- });
1950
- }
1951
- }
1952
- }
1953
- } else if (message.content && typeof message.content === "object") {
1954
- const contentObj = message.content;
1955
- if (contentObj.text) {
1956
- parts.push({ text: contentObj.text });
1957
- } else {
1958
- parts.push({ text: JSON.stringify(message.content) });
1959
- }
1960
- }
1961
- if (Array.isArray(message.tool_calls)) {
1962
- for (let index = 0; index < message.tool_calls.length; index++) {
1963
- const toolCall = message.tool_calls[index];
1964
- const functionCallPart = {
1965
- functionCall: {
1966
- id: toolCall.id || `tool_${Math.random().toString(36).substring(2, 15)}`,
1967
- name: toolCall.function.name,
1968
- args: JSON.parse(toolCall.function.arguments || "{}")
1969
- }
1970
- };
1971
- if (index === 0 && message.thinking?.signature) {
1972
- functionCallPart.thoughtSignature = message.thinking.signature;
1973
- }
1974
- parts.push(functionCallPart);
1975
- }
1976
- }
1977
- if (parts.length === 0) {
1978
- parts.push({ text: "" });
1979
- }
1980
- contents.push({ role, parts });
1981
- if (role === "model" && message.tool_calls) {
1982
- const functionResponses = message.tool_calls.map(
1983
- (tool) => {
1984
- const response = toolResponses.find((item) => item.tool_call_id === tool.id);
1985
- return {
1986
- functionResponse: {
1987
- name: tool.function?.name ?? "",
1988
- response: { result: response?.content }
1989
- }
1990
- };
1991
- }
1992
- );
1993
- contents.push({
1994
- role: "user",
1995
- parts: functionResponses
1996
- });
1997
- }
1998
- });
1999
- const generationConfig = {};
2000
- if (request.reasoning?.effort && request.reasoning.effort !== "none") {
2001
- generationConfig.thinkingConfig = {
2002
- includeThoughts: true
2003
- };
2004
- if (request.model.includes("gemini-3")) {
2005
- generationConfig.thinkingConfig.thinkingLevel = request.reasoning.effort;
2006
- } else {
2007
- const thinkingBudgets = request.model.includes("pro") ? [128, 32768] : [0, 24576];
2008
- const maxTokens = request.reasoning.max_tokens;
2009
- if (typeof maxTokens !== "undefined") {
2010
- let thinkingBudget;
2011
- if (maxTokens >= thinkingBudgets[0] && maxTokens <= thinkingBudgets[1]) {
2012
- thinkingBudget = maxTokens;
2013
- } else if (maxTokens < thinkingBudgets[0]) {
2014
- thinkingBudget = thinkingBudgets[0];
2015
- } else {
2016
- thinkingBudget = thinkingBudgets[1];
2017
- }
2018
- generationConfig.thinkingConfig.thinkingBudget = thinkingBudget;
2019
- }
2020
- }
2021
- }
2022
- const body = {
2023
- contents,
2024
- tools: tools.length > 0 ? tools : void 0,
2025
- generationConfig: Object.keys(generationConfig).length > 0 ? generationConfig : void 0
2026
- };
2027
- if (request.tool_choice) {
2028
- const toolConfig = {
2029
- functionCallingConfig: {}
2030
- };
2031
- if (request.tool_choice === "auto") {
2032
- toolConfig.functionCallingConfig.mode = "auto";
2033
- } else if (request.tool_choice === "none") {
2034
- toolConfig.functionCallingConfig.mode = "none";
2035
- } else if (request.tool_choice === "required") {
2036
- toolConfig.functionCallingConfig.mode = "any";
2037
- } else if (typeof request.tool_choice === "object" && request.tool_choice.function?.name) {
2038
- toolConfig.functionCallingConfig.mode = "any";
2039
- toolConfig.functionCallingConfig.allowedFunctionNames = [
2040
- request.tool_choice.function.name
2041
- ];
2042
- }
2043
- body.toolConfig = toolConfig;
2044
- }
2045
- return body;
2046
- }
2047
- function transformRequestOut(request) {
2048
- const contents = request.contents;
2049
- const tools = request.tools;
2050
- const model = request.model;
2051
- const maxTokens = request.max_tokens;
2052
- const temperature = request.temperature;
2053
- const stream = request.stream;
2054
- const toolChoice = request.tool_choice;
2055
- const unifiedRequest = {
2056
- messages: [],
2057
- model,
2058
- max_tokens: maxTokens,
2059
- temperature,
2060
- stream,
2061
- tool_choice: toolChoice
2062
- };
2063
- if (Array.isArray(contents)) {
2064
- for (const content of contents) {
2065
- if (typeof content === "string") {
2066
- unifiedRequest.messages.push({
2067
- role: "user",
2068
- content
2069
- });
2070
- } else if ("text" in content && typeof content.text === "string") {
2071
- unifiedRequest.messages.push({
2072
- role: "user",
2073
- content: content.text || null
2074
- });
2075
- } else if ("role" in content && content.role === "user") {
2076
- const geminiContent = content;
2077
- unifiedRequest.messages.push({
2078
- role: "user",
2079
- content: geminiContent.parts?.map((part) => ({
2080
- type: "text",
2081
- text: part.text || ""
2082
- })) || []
2083
- });
2084
- } else if (content.role === "model") {
2085
- unifiedRequest.messages.push({
2086
- role: "assistant",
2087
- content: content.parts?.map((part) => ({
2088
- type: "text",
2089
- text: part.text || ""
2090
- })) || []
2091
- });
2092
- }
2093
- }
2094
- }
2095
- if (Array.isArray(tools)) {
2096
- unifiedRequest.tools = [];
2097
- for (const tool of tools) {
2098
- if (Array.isArray(tool.functionDeclarations)) {
2099
- for (const funcDecl of tool.functionDeclarations) {
2100
- unifiedRequest.tools.push({
2101
- type: "function",
2102
- function: {
2103
- name: funcDecl.name,
2104
- description: funcDecl.description ?? "",
2105
- parameters: funcDecl.parameters ?? {}
2106
- }
2107
- });
2108
- }
2109
- }
2110
- }
2111
- }
2112
- return unifiedRequest;
2113
- }
2114
-
2115
- // src/transformer/transformers/GeminiCodeAssistTransformer.ts
2116
- var DEFAULT_CODE_ASSIST_ENDPOINT = "https://cloudcode-pa.googleapis.com";
2117
- var DEFAULT_CODE_ASSIST_API_VERSION = "v1internal";
2118
- function resolveCodeAssistEndpoint() {
2119
- return (process.env.CODE_ASSIST_ENDPOINT || DEFAULT_CODE_ASSIST_ENDPOINT).replace(/\/+$/, "");
2120
- }
2121
- function resolveCodeAssistApiVersion() {
2122
- return process.env.CODE_ASSIST_API_VERSION || DEFAULT_CODE_ASSIST_API_VERSION;
2123
- }
2124
- function buildCodeAssistUrl(stream) {
2125
- const base = resolveCodeAssistEndpoint();
2126
- const version = resolveCodeAssistApiVersion();
2127
- const method = stream ? "streamGenerateContent?alt=sse" : "generateContent";
2128
- return `${base}/${version}:${method}`;
2129
- }
2130
- function generateUserPromptId() {
2131
- const c = globalThis.crypto;
2132
- if (c?.randomUUID) return c.randomUUID();
2133
- return `omnicross-${Date.now()}-${Math.random().toString(36).slice(2, 10)}`;
2134
- }
2135
- function peelResponseEnvelope(parsed) {
2136
- if (parsed && typeof parsed === "object" && "response" in parsed) {
2137
- return parsed.response;
2138
- }
2139
- return parsed;
2140
- }
2141
- async function unwrapCodeAssistResponse(response) {
2142
- const contentType = response.headers.get("Content-Type") ?? "";
2143
- if (contentType.includes("stream") || contentType.includes("text/event-stream")) {
2144
- const sourceBody = response.body;
2145
- if (!sourceBody) return response;
2146
- const decoder = new TextDecoder();
2147
- const encoder = new TextEncoder();
2148
- const peeled = new ReadableStream({
2149
- async start(controller) {
2150
- const reader = sourceBody.getReader();
2151
- let buffer = "";
2152
- const processLine = (line) => {
2153
- if (!line.startsWith("data:")) {
2154
- if (line.length > 0) controller.enqueue(encoder.encode(`${line}
2155
- `));
2156
- return;
2157
- }
2158
- const payload = line.slice(line.indexOf(":") + 1).trim();
2159
- if (!payload || payload === "[DONE]") {
2160
- controller.enqueue(encoder.encode(`${line}
2161
- `));
2162
- return;
2163
- }
2164
- try {
2165
- const parsed = JSON.parse(payload);
2166
- const inner2 = peelResponseEnvelope(parsed);
2167
- controller.enqueue(encoder.encode(`data: ${JSON.stringify(inner2)}
2168
- `));
2169
- } catch {
2170
- controller.enqueue(encoder.encode(`${line}
2171
- `));
2172
- }
2173
- };
2174
- try {
2175
- while (true) {
2176
- const { done, value } = await reader.read();
2177
- if (done) {
2178
- if (buffer) processLine(buffer);
2179
- break;
2180
- }
2181
- buffer += decoder.decode(value, { stream: true });
2182
- const lines = buffer.split("\n");
2183
- buffer = lines.pop() || "";
2184
- for (const line of lines) processLine(line);
2185
- }
2186
- } catch (err) {
2187
- controller.error(err);
2188
- } finally {
2189
- controller.close();
2190
- }
2191
- }
2192
- });
2193
- return new Response(peeled, {
2194
- status: response.status,
2195
- statusText: response.statusText,
2196
- headers: response.headers
2197
- });
2198
- }
2199
- const raw = await response.json().catch(() => null);
2200
- const inner = peelResponseEnvelope(raw);
2201
- return new Response(JSON.stringify(inner), {
2202
- status: response.status,
2203
- statusText: response.statusText,
2204
- headers: response.headers
2205
- });
2206
- }
2207
- var GeminiCodeAssistTransformer = class {
2208
- static TransformerName = "gemini-code-assist";
2209
- name = "gemini-code-assist";
2210
- logger;
2211
- /** Code Assist has no fixed `/models/:modelAndAction` endpoint pattern — the
2212
- * URL is built per-request in `transformRequestIn`. Left undefined so the
2213
- * TransformerService does NOT treat this as an endpoint (reverse) transformer. */
2214
- endPoint = void 0;
2215
- /**
2216
- * unified → Code Assist envelope.
2217
- *
2218
- * Builds the inner public-Gemini body via the shared `buildRequestBody`, then
2219
- * wraps it as `{ model, project, user_prompt_id, request: <inner> }` and sets
2220
- * the Code Assist URL + Bearer-only headers.
2221
- *
2222
- * The resolved Code Assist `project` is threaded in via `provider.geminiProject`
2223
- * (stashed by the subscription dispatch seam — see SubscriptionDispatcher /
2224
- * openaiResponsesIngress). `undefined` is the valid fresh free-tier value.
2225
- */
2226
- async transformRequestIn(request, provider, _context) {
2227
- const inner = buildRequestBody(request);
2228
- const envelope = {
2229
- model: request.model,
2230
- project: provider.geminiProject,
2231
- user_prompt_id: generateUserPromptId(),
2232
- request: inner
2233
- };
2234
- const url = buildCodeAssistUrl(Boolean(request.stream));
2235
- const headers = {
2236
- "x-goog-api-key": void 0,
2237
- "X-Goog-Api-Key": void 0
2238
- };
2239
- return {
2240
- body: envelope,
2241
- config: { url, headers }
2242
- };
2243
- }
2244
- /**
2245
- * Code Assist request → unified (endpoint-decode parity with GeminiTransformer).
2246
- * Peels the top-level `request` envelope first, then delegates to the shared
2247
- * gemini request decoder. Not used on the subscription dispatch path (the
2248
- * endpoint transformer there is Anthropic/OpenAI-Response), but provided for
2249
- * completeness so this transformer is a drop-in for the gemini one.
2250
- */
2251
- async transformRequestOut(request, _context) {
2252
- const r = request;
2253
- const inner = r && typeof r === "object" && "request" in r ? r.request : r;
2254
- if (inner && typeof inner === "object" && !("model" in inner) && "model" in r) {
2255
- inner.model = r.model;
2256
- }
2257
- return transformRequestOut(inner);
2258
- }
2259
- /**
2260
- * Code Assist response → OpenAI-compatible. PEEL the `.response` envelope from
2261
- * the body / each SSE chunk, then DELEGATE to the existing gemini parser.
2262
- */
2263
- async transformResponseOut(response, _context) {
2264
- const unwrapped = await unwrapCodeAssistResponse(response);
2265
- return transformResponseOut(unwrapped, this.name, this.logger);
2266
- }
2267
- /**
2268
- * OpenAI-compatible response → Code Assist (endpoint-encode parity). Re-wraps
2269
- * the standard gemini response under the top-level `response` key after the
2270
- * shared gemini encoder produces a public-Gemini body. Symmetric with
2271
- * `transformResponseOut`'s peel.
2272
- */
2273
- async transformResponseIn(response, _context) {
2274
- const geminiResponse = await transformResponseIn(response, this.logger);
2275
- const contentType = geminiResponse.headers.get("Content-Type") ?? "";
2276
- if (contentType.includes("text/event-stream")) {
2277
- return geminiResponse;
2278
- }
2279
- const data = await geminiResponse.json().catch(() => null);
2280
- return new Response(JSON.stringify({ response: data }), {
2281
- status: geminiResponse.status,
2282
- statusText: geminiResponse.statusText,
2283
- headers: { "Content-Type": "application/json" }
2284
- });
2285
- }
2286
- };
2287
-
2288
- // src/transformer/transformers/GeminiTransformer.ts
2289
- var GeminiTransformer = class {
2290
- static TransformerName = "gemini";
2291
- name = "gemini";
2292
- logger;
2293
- /**
2294
- * API endpoint pattern for Gemini
2295
- * :modelAndAction will be replaced with actual model and action
2296
- */
2297
- endPoint = "/v1beta/models/:modelAndAction";
2298
- /** Use Bearer token instead of x-goog-api-key (for relay providers) */
2299
- useBearer;
2300
- constructor(options) {
2301
- this.useBearer = options?.UseBearer ?? false;
2302
- }
2303
- /**
2304
- * Handle authentication
2305
- * - Official Gemini: x-goog-api-key header
2306
- * - Relay providers: Authorization: Bearer header
2307
- */
2308
- async auth(request, provider, _context) {
2309
- const headers = {};
2310
- if (this.useBearer) {
2311
- headers["authorization"] = `Bearer ${provider.apiKey}`;
2312
- headers["x-goog-api-key"] = void 0;
2313
- } else {
2314
- headers["x-goog-api-key"] = provider.apiKey;
2315
- headers["authorization"] = void 0;
2316
- }
2317
- return {
2318
- body: request,
2319
- config: { headers }
2320
- };
2321
- }
2322
- /**
2323
- * Transform request from unified format to Gemini format
2324
- * Also builds the correct URL for the Gemini API
2325
- */
2326
- async transformRequestIn(request, provider, _context) {
2327
- const body = buildRequestBody(request);
2328
- const action = request.stream ? "streamGenerateContent?alt=sse" : "generateContent";
2329
- const url = new URL(`./${request.model}:${action}`, provider.baseUrl);
2330
- const headers = {};
2331
- if (this.useBearer) {
2332
- headers["authorization"] = `Bearer ${provider.apiKey}`;
2333
- headers["x-goog-api-key"] = void 0;
2334
- } else {
2335
- headers["x-goog-api-key"] = provider.apiKey;
2336
- headers["Authorization"] = void 0;
2337
- }
2338
- return {
2339
- body,
2340
- config: { url, headers }
2341
- };
2342
- }
2343
- /**
2344
- * Transform incoming request to unified format
2345
- * (For requests coming into the Gemini endpoint)
2346
- */
2347
- async transformRequestOut(request, _context) {
2348
- return transformRequestOut(request);
2349
- }
2350
- /**
2351
- * Transform Gemini response to OpenAI-compatible format
2352
- */
2353
- async transformResponseOut(response, _context) {
2354
- return transformResponseOut(response, this.name, this.logger);
2355
- }
2356
- /**
2357
- * Transform OpenAI-compatible response back to Gemini format
2358
- * (For endpoint mode — returning Gemini-format responses to the client)
2359
- */
2360
- async transformResponseIn(response, _context) {
2361
- return transformResponseIn(response, this.logger);
2362
- }
2363
- };
2364
-
2365
- // src/transformer/transformers/OpenAIResponseTransformer.ts
2366
- var OpenAIResponseTransformer = class {
2367
- static TransformerName = "openai-response";
2368
- name = "openai-response";
2369
- endPoint = "/v1/responses";
2370
- logger;
2371
- /**
2372
- * Handle authentication - Bearer token
2373
- */
2374
- async auth(request, provider, _context) {
2375
- return {
2376
- body: request,
2377
- config: {
2378
- headers: {
2379
- Authorization: `Bearer ${provider.apiKey}`,
2380
- "Content-Type": "application/json"
2381
- }
2382
- }
2383
- };
2384
- }
2385
- /**
2386
- * Transform unified request → Response API format
2387
- */
2388
- async transformRequestIn(request, provider, _context) {
2389
- const input = [];
2390
- for (const msg of request.messages) {
2391
- if (msg.role === "system") {
2392
- input.push({
2393
- role: "developer",
2394
- content: typeof msg.content === "string" ? msg.content : flattenContent(msg.content)
2395
- });
2396
- } else if (msg.role === "tool") {
2397
- input.push({
2398
- type: "function_call_output",
2399
- call_id: msg.tool_call_id,
2400
- output: typeof msg.content === "string" ? msg.content : ""
2401
- });
2402
- } else {
2403
- const entry = {
2404
- role: msg.role,
2405
- content: typeof msg.content === "string" ? msg.content : flattenContent(msg.content)
2406
- };
2407
- if (msg.role === "assistant" && msg.tool_calls?.length) {
2408
- input.push(entry);
2409
- for (const tc of msg.tool_calls) {
2410
- input.push({
2411
- type: "function_call",
2412
- id: tc.id,
2413
- call_id: tc.id,
2414
- name: tc.function.name,
2415
- arguments: tc.function.arguments
2416
- });
2417
- }
2418
- continue;
2419
- }
2420
- input.push(entry);
2421
- }
2422
- }
2423
- const body = {
2424
- model: request.model,
2425
- input,
2426
- stream: request.stream ?? false,
2427
- ...request.max_tokens ? { max_output_tokens: request.max_tokens } : {},
2428
- ...request.temperature !== void 0 ? { temperature: request.temperature } : {}
2429
- };
2430
- if (request.reasoning?.effort && request.reasoning.effort !== "none") {
2431
- body.reasoning = { effort: request.reasoning.effort, summary: "auto" };
2432
- }
2433
- if (request.tools?.length) {
2434
- body.tools = request.tools.map((tool) => ({
2435
- type: "function",
2436
- name: tool.function.name,
2437
- description: tool.function.description,
2438
- parameters: tool.function.parameters
2439
- }));
2440
- }
2441
- if (request.tool_choice) {
2442
- if (typeof request.tool_choice === "string") {
2443
- body.tool_choice = request.tool_choice;
2444
- } else if (typeof request.tool_choice === "object" && "function" in request.tool_choice) {
2445
- body.tool_choice = { type: "function", name: request.tool_choice.function.name };
2446
- }
2447
- }
2448
- const url = new URL("/v1/responses", provider.baseUrl);
2449
- return { body, config: { url } };
2450
- }
2451
- /**
2452
- * Transform Response API request → unified format
2453
- */
2454
- async transformRequestOut(request, _context) {
2455
- const req = request;
2456
- const messages = [];
2457
- if (req.input) {
2458
- for (const item of req.input) {
2459
- const entry = item;
2460
- if (entry.type === "function_call_output") {
2461
- messages.push({
2462
- role: "tool",
2463
- content: entry.output || "",
2464
- tool_call_id: entry.call_id || void 0
2465
- });
2466
- continue;
2467
- }
2468
- if (entry.type === "function_call") {
2469
- const toolCall = {
2470
- id: (entry.call_id ?? entry.id) || "",
2471
- type: "function",
2472
- function: {
2473
- name: entry.name || "",
2474
- arguments: typeof entry.arguments === "string" ? entry.arguments : ""
2475
- }
2476
- };
2477
- const last = messages[messages.length - 1];
2478
- if (last && last.role === "assistant") {
2479
- (last.tool_calls ??= []).push(toolCall);
2480
- } else {
2481
- messages.push({ role: "assistant", content: null, tool_calls: [toolCall] });
2482
- }
2483
- continue;
2484
- }
2485
- const role = entry.role;
2486
- if (role === "developer") {
2487
- messages.push({
2488
- role: "system",
2489
- content: typeof entry.content === "string" ? entry.content : JSON.stringify(entry.content)
2490
- });
2491
- } else if (role === "user" || role === "assistant") {
2492
- messages.push({
2493
- role,
2494
- content: typeof entry.content === "string" ? entry.content : JSON.stringify(entry.content)
2495
- });
2496
- }
2497
- }
2498
- }
2499
- const result = {
2500
- messages,
2501
- model: req.model,
2502
- max_tokens: req.max_output_tokens,
2503
- temperature: req.temperature,
2504
- stream: req.stream
2505
- };
2506
- if (req.reasoning?.effort) {
2507
- result.reasoning = {
2508
- effort: req.reasoning.effort,
2509
- enabled: true
2510
- };
2511
- }
2512
- if (req.tools?.length) {
2513
- result.tools = req.tools.filter((t) => t.type === "function").map((t) => ({
2514
- type: "function",
2515
- function: {
2516
- name: t.name || "",
2517
- description: t.description || "",
2518
- parameters: t.parameters || {}
2519
- }
2520
- }));
2521
- }
2522
- return result;
2523
- }
2524
- /**
2525
- * Transform Response API response → unified (OpenAI CC) format
2526
- */
2527
- async transformResponseOut(response, _context) {
2528
- const contentType = response.headers.get("Content-Type") ?? "";
2529
- if (contentType.includes("text/event-stream")) {
2530
- if (!response.body) {
2531
- throw new Error("Stream response body is null");
2532
- }
2533
- return new Response(convertResponseApiStreamToOpenAI(response.body), {
2534
- headers: {
2535
- "Content-Type": "text/event-stream",
2536
- "Cache-Control": "no-cache",
2537
- Connection: "keep-alive"
2538
- }
2539
- });
2540
- }
2541
- const data = await response.json();
2542
- return new Response(JSON.stringify(convertResponseApiJsonToOpenAI(data)), {
2543
- headers: { "Content-Type": "application/json" }
2544
- });
2545
- }
2546
- /**
2547
- * Transform OpenAI CC response → Response API format
2548
- */
2549
- async transformResponseIn(response, _context) {
2550
- const contentType = response.headers.get("Content-Type") ?? "";
2551
- if (contentType.includes("text/event-stream")) {
2552
- if (!response.body) {
2553
- throw new Error("Stream response body is null");
2554
- }
2555
- return new Response(convertOpenAIStreamToResponseApi(response.body), {
2556
- headers: {
2557
- "Content-Type": "text/event-stream",
2558
- "Cache-Control": "no-cache",
2559
- Connection: "keep-alive"
2560
- }
2561
- });
2562
- }
2563
- const data = await response.json();
2564
- return new Response(JSON.stringify(convertOpenAIJsonToResponseApi(data)), {
2565
- headers: { "Content-Type": "application/json" }
2566
- });
2567
- }
2568
- };
2569
- function flattenContent(content) {
2570
- if (typeof content === "string") return content;
2571
- if (!content) return "";
2572
- if (Array.isArray(content)) {
2573
- return content.filter((c) => c.type === "text").map((c) => c.text || "").join("\n");
2574
- }
2575
- return "";
2576
- }
2577
- function convertResponseApiJsonToOpenAI(data) {
2578
- let textContent = "";
2579
- const toolCalls = [];
2580
- const output = data.output;
2581
- if (output) {
2582
- for (const item of output) {
2583
- if (item.type === "message") {
2584
- const content = item.content;
2585
- if (content) {
2586
- for (const part of content) {
2587
- if (part.type === "output_text" && typeof part.text === "string") {
2588
- textContent += part.text;
2589
- }
2590
- }
2591
- }
2592
- } else if (item.type === "function_call") {
2593
- toolCalls.push({
2594
- id: item.call_id || item.id || `call_${Date.now()}`,
2595
- type: "function",
2596
- function: {
2597
- name: item.name,
2598
- arguments: typeof item.arguments === "string" ? item.arguments : JSON.stringify(item.arguments || {})
2599
- }
2600
- });
2601
- }
2602
- }
2603
- }
2604
- const usage = data.usage;
2605
- const message = {
2606
- role: "assistant",
2607
- content: textContent || null
2608
- };
2609
- if (toolCalls.length > 0) {
2610
- message.tool_calls = toolCalls;
2611
- }
2612
- return {
2613
- id: data.id || `chatcmpl-${Date.now()}`,
2614
- object: "chat.completion",
2615
- created: Math.floor(Date.now() / 1e3),
2616
- model: data.model || "unknown",
2617
- choices: [
2618
- {
2619
- index: 0,
2620
- message,
2621
- finish_reason: toolCalls.length > 0 ? "tool_calls" : "stop"
2622
- }
2623
- ],
2624
- usage: usage ? {
2625
- prompt_tokens: usage.input_tokens || 0,
2626
- completion_tokens: usage.output_tokens || 0,
2627
- total_tokens: (usage.input_tokens || 0) + (usage.output_tokens || 0)
2628
- } : void 0
2629
- };
2630
- }
2631
- function convertOpenAIJsonToResponseApi(data) {
2632
- const choices = data.choices;
2633
- const message = choices?.[0]?.message;
2634
- const output = [];
2635
- if (message) {
2636
- const contentParts = [];
2637
- if (message.content) {
2638
- contentParts.push({ type: "output_text", text: message.content });
2639
- }
2640
- if (contentParts.length > 0) {
2641
- output.push({ type: "message", role: "assistant", content: contentParts });
2642
- }
2643
- const toolCalls = message.tool_calls;
2644
- if (toolCalls?.length) {
2645
- for (const tc of toolCalls) {
2646
- const func = tc.function;
2647
- output.push({
2648
- type: "function_call",
2649
- id: tc.id,
2650
- call_id: tc.id,
2651
- name: func?.name,
2652
- arguments: func?.arguments
2653
- });
2654
- }
2655
- }
2656
- }
2657
- const usage = data.usage;
2658
- return {
2659
- id: data.id || `resp_${Date.now()}`,
2660
- object: "response",
2661
- status: "completed",
2662
- model: data.model || "unknown",
2663
- output,
2664
- usage: usage ? {
2665
- input_tokens: usage.prompt_tokens || 0,
2666
- output_tokens: usage.completion_tokens || 0,
2667
- total_tokens: usage.total_tokens || (usage.prompt_tokens || 0) + (usage.completion_tokens || 0)
2668
- } : void 0
2669
- };
2670
- }
2671
- function convertResponseApiStreamToOpenAI(responseApiStream) {
2672
- const decoder = new TextDecoder();
2673
- const encoder = new TextEncoder();
2674
- return new ReadableStream({
2675
- start: async (controller) => {
2676
- const reader = responseApiStream.getReader();
2677
- let buffer = "";
2678
- let isClosed = false;
2679
- const messageId = `chatcmpl-${Date.now()}`;
2680
- let model = "unknown";
2681
- let hasEmittedRole = false;
2682
- const safeEnqueue = (str) => {
2683
- if (!isClosed) {
2684
- try {
2685
- controller.enqueue(encoder.encode(str));
2686
- } catch {
2687
- isClosed = true;
2688
- }
2689
- }
2690
- };
2691
- const emitChunk = (choices, usage) => {
2692
- const chunk = {
2693
- id: messageId,
2694
- object: "chat.completion.chunk",
2695
- created: Math.floor(Date.now() / 1e3),
2696
- model,
2697
- choices
2698
- };
2699
- if (usage) chunk.usage = usage;
2700
- safeEnqueue(`data: ${JSON.stringify(chunk)}
2701
-
2702
- `);
2703
- };
2704
- try {
2705
- while (true) {
2706
- const { done, value } = await reader.read();
2707
- if (done) break;
2708
- buffer += decoder.decode(value, { stream: true });
2709
- const lines = buffer.split("\n");
2710
- buffer = lines.pop() || "";
2711
- for (const line of lines) {
2712
- if (isClosed) break;
2713
- if (!line.startsWith("data:")) continue;
2714
- const data = line.slice(5).trim();
2715
- if (data === "[DONE]") continue;
2716
- try {
2717
- const event = JSON.parse(data);
2718
- model = event.model || event.response?.model || model;
2719
- switch (event.type) {
2720
- case "response.output_text.delta":
2721
- if (event.delta) {
2722
- if (!hasEmittedRole) {
2723
- emitChunk([{ index: 0, delta: { role: "assistant", content: "" }, finish_reason: null }]);
2724
- hasEmittedRole = true;
2725
- }
2726
- emitChunk([{ index: 0, delta: { content: event.delta }, finish_reason: null }]);
2727
- }
2728
- break;
2729
- case "response.reasoning_summary_text.delta":
2730
- if (event.delta) {
2731
- emitChunk([{
2732
- index: 0,
2733
- delta: { thinking: { content: event.delta } },
2734
- finish_reason: null
2735
- }]);
2736
- }
2737
- break;
2738
- case "response.completed": {
2739
- const resp = event.response;
2740
- const respUsage = resp?.usage;
2741
- const usage = respUsage ? {
2742
- prompt_tokens: respUsage.input_tokens || 0,
2743
- completion_tokens: respUsage.output_tokens || 0,
2744
- total_tokens: (respUsage.input_tokens || 0) + (respUsage.output_tokens || 0)
2745
- } : void 0;
2746
- emitChunk([{ index: 0, delta: {}, finish_reason: "stop" }], usage);
2747
- safeEnqueue("data: [DONE]\n\n");
2748
- break;
2749
- }
2750
- case "error":
2751
- emitChunk([{
2752
- index: 0,
2753
- delta: { content: `[Error: ${event.error?.message || "Unknown error"}]` },
2754
- finish_reason: "stop"
2755
- }]);
2756
- break;
2757
- default:
2758
- break;
2759
- }
2760
- } catch {
2761
- }
2762
- }
2763
- }
2764
- } catch (e) {
2765
- if (!isClosed) controller.error(e);
2766
- } finally {
2767
- if (!isClosed) {
2768
- try {
2769
- controller.close();
2770
- } catch {
2771
- }
2772
- }
2773
- reader.releaseLock();
2774
- }
2775
- }
2776
- });
2777
- }
2778
- function convertOpenAIStreamToResponseApi(openaiStream) {
2779
- const decoder = new TextDecoder();
2780
- const encoder = new TextEncoder();
2781
- return new ReadableStream({
2782
- start: async (controller) => {
2783
- const reader = openaiStream.getReader();
2784
- let buffer = "";
2785
- let isClosed = false;
2786
- let accumulatedContent = "";
2787
- let model = "unknown";
2788
- const responseId = `resp_${Date.now()}`;
2789
- const safeEnqueue = (str) => {
2790
- if (!isClosed) {
2791
- try {
2792
- controller.enqueue(encoder.encode(str));
2793
- } catch {
2794
- isClosed = true;
2795
- }
2796
- }
2797
- };
2798
- const emitEvent = (event) => {
2799
- safeEnqueue(`data: ${JSON.stringify(event)}
2800
-
2801
- `);
2802
- };
2803
- emitEvent({
2804
- type: "response.created",
2805
- response: { id: responseId, status: "in_progress" }
2806
- });
2807
- try {
2808
- while (true) {
2809
- const { done, value } = await reader.read();
2810
- if (done) break;
2811
- buffer += decoder.decode(value, { stream: true });
2812
- const lines = buffer.split("\n");
2813
- buffer = lines.pop() || "";
2814
- for (const line of lines) {
2815
- if (isClosed) break;
2816
- if (!line.startsWith("data:")) continue;
2817
- const data = line.slice(5).trim();
2818
- if (data === "[DONE]") continue;
2819
- try {
2820
- const chunk = JSON.parse(data);
2821
- const choice = chunk.choices?.[0];
2822
- model = chunk.model || model;
2823
- if (!choice) continue;
2824
- if (choice.delta?.content) {
2825
- accumulatedContent += choice.delta.content;
2826
- emitEvent({ type: "response.output_text.delta", delta: choice.delta.content });
2827
- }
2828
- if (choice.delta?.thinking?.content) {
2829
- emitEvent({
2830
- type: "response.reasoning_summary_text.delta",
2831
- delta: choice.delta.thinking.content
2832
- });
2833
- }
2834
- if (choice.finish_reason) {
2835
- emitEvent({ type: "response.output_text.done", text: accumulatedContent });
2836
- emitEvent({
2837
- type: "response.completed",
2838
- response: {
2839
- id: responseId,
2840
- status: "completed",
2841
- model,
2842
- output: [
2843
- {
2844
- type: "message",
2845
- role: "assistant",
2846
- content: [{ type: "output_text", text: accumulatedContent }]
2847
- }
2848
- ],
2849
- usage: chunk.usage ? {
2850
- input_tokens: chunk.usage.prompt_tokens || 0,
2851
- output_tokens: chunk.usage.completion_tokens || 0,
2852
- total_tokens: chunk.usage.total_tokens || 0
2853
- } : void 0
2854
- }
2855
- });
2856
- }
2857
- } catch {
2858
- }
2859
- }
2860
- }
2861
- } catch (e) {
2862
- if (!isClosed) controller.error(e);
2863
- } finally {
2864
- if (!isClosed) {
2865
- try {
2866
- controller.close();
2867
- } catch {
2868
- }
2869
- }
2870
- reader.releaseLock();
2871
- }
2872
- }
2873
- });
2874
- }
2875
-
2876
- // src/transformer/transformers/OpenCodeGoTransformer.ts
2877
- var OpenCodeGoTransformer = class {
2878
- static TransformerName = "opencodego";
2879
- name = "opencodego";
2880
- endPoint = "/v1/chat/completions";
2881
- logger;
2882
- async auth(request, _provider, _context) {
2883
- return { body: request, config: { headers: {} } };
2884
- }
2885
- /**
2886
- * Unified → OpenAI Chat Completions.
2887
- * Unified IS chat completions shape; this is mostly stripping `meta` and
2888
- * normalizing string-content single-block messages.
2889
- */
2890
- async transformRequestIn(request, _provider, _context) {
2891
- const messages = request.messages.map((m) => {
2892
- const content = m.content;
2893
- if (Array.isArray(content) && content.length === 1 && content[0]?.type === "text") {
2894
- return { ...m, content: content[0].text };
2895
- }
2896
- return m;
2897
- });
2898
- const out = {
2899
- model: request.model,
2900
- messages,
2901
- stream: request.stream
2902
- };
2903
- if (request.temperature !== void 0) out.temperature = request.temperature;
2904
- if (request.max_tokens !== void 0) out.max_tokens = request.max_tokens;
2905
- if (request.tools && request.tools.length > 0) out.tools = request.tools;
2906
- if (request.tool_choice !== void 0) out.tool_choice = request.tool_choice;
2907
- if (request.reasoning?.effort && request.reasoning.effort !== "none") {
2908
- out.reasoning_effort = request.reasoning.effort;
2909
- }
2910
- return out;
2911
- }
2912
- /**
2913
- * OpenAI Chat Completions response → Unified.
2914
- * The upstream's response shape already matches Unified — pass through.
2915
- * The endpoint AnthropicTransformer re-encodes to Anthropic for the SDK.
2916
- */
2917
- async transformResponseOut(response, _context) {
2918
- return response;
2919
- }
2920
- };
2921
-
2922
- // src/transformer/transformers/ReasoningTransformer.ts
2923
- var import_thinking_config = require("@omnicross/contracts/thinking-config");
2924
- var ReasoningTransformer = class {
2925
- static TransformerName = "reasoning";
2926
- name = "reasoning";
2927
- logger;
2928
- enabled;
2929
- constructor(options) {
2930
- this.enabled = options?.enable !== false;
2931
- }
2932
- /**
2933
- * Transform request: convert reasoning config to thinking parameters
2934
- * Uses model-specific budget calculation based on effort level
2935
- */
2936
- async transformRequestIn(request, provider, _context) {
2937
- const extendedRequest = request;
2938
- const modelId = request.model;
2939
- if (!this.enabled) {
2940
- extendedRequest.thinking = {
2941
- type: "disabled",
2942
- budget_tokens: -1
2943
- };
2944
- extendedRequest.enable_thinking = false;
2945
- return extendedRequest;
2946
- }
2947
- if (request.reasoning) {
2948
- const effortLevel = request.reasoning.effort || "none";
2949
- const userMaxTokens = request.reasoning.max_tokens || request.max_tokens;
2950
- const calculatedBudget = (0, import_thinking_config.calculateThinkingBudget)(modelId, effortLevel, userMaxTokens);
2951
- const providerName = provider.name?.toLowerCase() || "";
2952
- if (providerName === "anthropic" || providerName.includes("claude")) {
2953
- const thinkingConfig = (0, import_thinking_config.buildAnthropicThinking)(modelId, effortLevel, userMaxTokens);
2954
- if (thinkingConfig) {
2955
- extendedRequest.thinking = thinkingConfig;
2956
- } else {
2957
- extendedRequest.thinking = {
2958
- type: "disabled"
2959
- };
2960
- }
2961
- } else if (providerName === "openai" || modelId.match(/^o[134]/i)) {
2962
- const reasoningEffort = (0, import_thinking_config.getOpenAIReasoningEffort)(effortLevel);
2963
- if (reasoningEffort) {
2964
- extendedRequest.reasoning_effort = reasoningEffort;
2965
- }
2966
- extendedRequest.thinking = {
2967
- type: effortLevel === "none" ? "disabled" : "enabled",
2968
- budget_tokens: calculatedBudget
2969
- };
2970
- } else if (providerName === "deepseek" && modelId?.startsWith("deepseek-v4")) {
2971
- extendedRequest.thinking = {
2972
- type: effortLevel === "none" ? "disabled" : "enabled",
2973
- budget_tokens: calculatedBudget
2974
- };
2975
- if (effortLevel !== "none") {
2976
- extendedRequest.reasoning_effort = effortLevel === "high" ? "max" : "high";
2977
- }
2978
- } else if (providerName === "deepseek" || providerName === "qwen" || providerName === "alibaba") {
2979
- const qwenConfig = (0, import_thinking_config.buildQwenThinkingConfig)(effortLevel, userMaxTokens);
2980
- extendedRequest.enable_thinking = qwenConfig.enable_thinking;
2981
- if (qwenConfig.thinking_budget) {
2982
- extendedRequest.thinking_budget = qwenConfig.thinking_budget;
2983
- }
2984
- extendedRequest.thinking = {
2985
- type: qwenConfig.enable_thinking ? "enabled" : "disabled",
2986
- budget_tokens: calculatedBudget
2987
- };
2988
- } else {
2989
- extendedRequest.thinking = {
2990
- type: effortLevel === "none" ? "disabled" : "enabled",
2991
- budget_tokens: calculatedBudget
2992
- };
2993
- extendedRequest.enable_thinking = effortLevel !== "none";
2994
- }
2995
- this.logger?.debug(`[ReasoningTransformer] Model: ${modelId}, Effort: ${effortLevel}, Budget: ${calculatedBudget}`);
2996
- }
2997
- return extendedRequest;
2998
- }
2999
- /**
3000
- * Transform response: convert reasoning_content to thinking blocks
3001
- */
3002
- async transformResponseOut(response, _context) {
3003
- if (!this.enabled) return response;
3004
- const contentType = response.headers.get("Content-Type") ?? "";
3005
- if (contentType.includes("application/json")) {
3006
- return this.handleJsonResponse(response);
3007
- } else if (contentType.includes("stream") || contentType.includes("text/event-stream")) {
3008
- return this.handleStreamResponse(response);
3009
- }
3010
- return response;
3011
- }
3012
- /**
3013
- * Handle JSON (non-streaming) response
3014
- */
3015
- async handleJsonResponse(response) {
3016
- const jsonResponse = await response.json();
3017
- if (jsonResponse.choices?.[0]?.message?.reasoning_content) {
3018
- jsonResponse.thinking = {
3019
- content: jsonResponse.choices[0].message.reasoning_content
3020
- };
3021
- delete jsonResponse.choices[0].message.reasoning_content;
3022
- }
3023
- return new Response(JSON.stringify(jsonResponse), {
3024
- status: response.status,
3025
- statusText: response.statusText,
3026
- headers: response.headers
3027
- });
3028
- }
3029
- /**
3030
- * Handle streaming response - convert reasoning_content to thinking blocks
3031
- */
3032
- handleStreamResponse(response) {
3033
- if (!response.body) {
3034
- return response;
3035
- }
3036
- const decoder = new TextDecoder();
3037
- const encoder = new TextEncoder();
3038
- let reasoningContent = "";
3039
- let isReasoningComplete = false;
3040
- let buffer = "";
3041
- const stream = new ReadableStream({
3042
- start: async (controller) => {
3043
- const reader = response.body.getReader();
3044
- const processLine = (line) => {
3045
- this.logger?.debug("Processing reasoning line:", line);
3046
- if (line.startsWith("data: ") && line.trim() !== "data: [DONE]") {
3047
- try {
3048
- const data = JSON.parse(line.slice(6));
3049
- if (data.choices?.[0]?.delta?.reasoning_content) {
3050
- reasoningContent += data.choices[0].delta.reasoning_content;
3051
- const thinkingChunk = {
3052
- ...data,
3053
- choices: [
3054
- {
3055
- ...data.choices[0],
3056
- delta: {
3057
- ...data.choices[0].delta,
3058
- thinking: {
3059
- content: data.choices[0].delta.reasoning_content
3060
- }
3061
- }
3062
- }
3063
- ]
3064
- };
3065
- delete thinkingChunk.choices[0].delta.reasoning_content;
3066
- const thinkingLine = `data: ${JSON.stringify(thinkingChunk)}
3067
-
3068
- `;
3069
- controller.enqueue(encoder.encode(thinkingLine));
3070
- return;
3071
- }
3072
- if ((data.choices?.[0]?.delta?.content || data.choices?.[0]?.delta?.tool_calls) && reasoningContent && !isReasoningComplete) {
3073
- isReasoningComplete = true;
3074
- const signature = Date.now().toString();
3075
- const thinkingChunk = {
3076
- ...data,
3077
- choices: [
3078
- {
3079
- ...data.choices[0],
3080
- delta: {
3081
- ...data.choices[0].delta,
3082
- content: null,
3083
- thinking: {
3084
- signature
3085
- }
3086
- }
3087
- }
3088
- ]
3089
- };
3090
- delete thinkingChunk.choices[0].delta.reasoning_content;
3091
- const thinkingLine = `data: ${JSON.stringify(thinkingChunk)}
3092
-
3093
- `;
3094
- controller.enqueue(encoder.encode(thinkingLine));
3095
- }
3096
- if (data.choices?.[0]?.delta?.reasoning_content) {
3097
- delete data.choices[0].delta.reasoning_content;
3098
- }
3099
- if (data.choices?.[0]?.delta && Object.keys(data.choices[0].delta).length > 0) {
3100
- if (isReasoningComplete) {
3101
- data.choices[0].index++;
3102
- }
3103
- const modifiedLine = `data: ${JSON.stringify(data)}
3104
-
3105
- `;
3106
- controller.enqueue(encoder.encode(modifiedLine));
3107
- }
3108
- } catch (_e) {
3109
- controller.enqueue(encoder.encode(line + "\n"));
3110
- }
3111
- } else {
3112
- controller.enqueue(encoder.encode(line + "\n"));
3113
- }
3114
- };
3115
- try {
3116
- while (true) {
3117
- const { done, value } = await reader.read();
3118
- if (done) {
3119
- if (buffer.trim()) {
3120
- const lines2 = buffer.split("\n");
3121
- for (const line of lines2) {
3122
- if (line.trim()) {
3123
- controller.enqueue(encoder.encode(line + "\n"));
3124
- }
3125
- }
3126
- }
3127
- break;
3128
- }
3129
- const chunk = decoder.decode(value, { stream: true });
3130
- buffer += chunk;
3131
- const lines = buffer.split("\n");
3132
- buffer = lines.pop() || "";
3133
- for (const line of lines) {
3134
- if (!line.trim()) continue;
3135
- try {
3136
- processLine(line);
3137
- } catch (error) {
3138
- this.logger?.error("Error processing reasoning stream line:", error);
3139
- controller.enqueue(encoder.encode(line + "\n"));
3140
- }
3141
- }
3142
- }
3143
- } catch (error) {
3144
- this.logger?.error("Reasoning stream error:", error);
3145
- controller.error(error);
3146
- } finally {
3147
- try {
3148
- reader.releaseLock();
3149
- } catch (e) {
3150
- this.logger?.error("Error releasing reader lock:", e);
3151
- }
3152
- controller.close();
3153
- }
3154
- }
3155
- });
3156
- return new Response(stream, {
3157
- status: response.status,
3158
- statusText: response.statusText,
3159
- headers: new Headers({
3160
- "Content-Type": "text/event-stream",
3161
- "Cache-Control": "no-cache",
3162
- Connection: "keep-alive"
3163
- })
3164
- });
3165
- }
3166
- };
3167
-
3168
- // src/transformer/transformers/index.ts
3169
- var BuiltinTransformers = {
3170
- DeepseekTransformer,
3171
- ReasoningTransformer,
3172
- GeminiTransformer,
3173
- GeminiCodeAssistTransformer,
3174
- AnthropicTransformer,
3175
- OpenAIResponseTransformer,
3176
- OpenCodeGoTransformer
3177
- };
3178
- function getBuiltinTransformers() {
3179
- return BuiltinTransformers;
3180
- }
3181
- var BUILTIN_TRANSFORMER_NAMES = [
3182
- "deepseek",
3183
- "reasoning",
3184
- "gemini",
3185
- "gemini-code-assist",
3186
- "anthropic",
3187
- "openai-response",
3188
- "opencodego"
3189
- ];
3190
- async function registerBuiltinTransformers(service) {
3191
- await service.initialize(getBuiltinTransformers());
3192
- }
3193
- // Annotate the CommonJS export names for ESM import in node:
3194
- 0 && (module.exports = {
3195
- AnthropicTransformer,
3196
- BUILTIN_TRANSFORMER_NAMES,
3197
- BuiltinTransformers,
3198
- DeepseekTransformer,
3199
- GeminiCodeAssistTransformer,
3200
- GeminiTransformer,
3201
- OpenAIResponseTransformer,
3202
- OpenCodeGoTransformer,
3203
- ReasoningTransformer,
3204
- getBuiltinTransformers,
3205
- registerBuiltinTransformers
3206
- });
39
+ exports.AnthropicTransformer = _chunk4VAVYUZScjs.AnthropicTransformer; exports.BUILTIN_TRANSFORMER_NAMES = _chunkFFALUUZZcjs.BUILTIN_TRANSFORMER_NAMES; exports.BuiltinTransformers = _chunkFFALUUZZcjs.BuiltinTransformers; exports.DeepseekTransformer = _chunkFFALUUZZcjs.DeepseekTransformer; exports.GeminiCodeAssistTransformer = _chunkRSJ3TWJQcjs.GeminiCodeAssistTransformer; exports.GeminiTransformer = _chunk7YN22L2Hcjs.GeminiTransformer; exports.OpenAIResponseTransformer = _chunk2DCNB7DFcjs.OpenAIResponseTransformer; exports.OpenCodeGoTransformer = _chunkC72S6TTVcjs.OpenCodeGoTransformer; exports.ReasoningTransformer = _chunkDWKQZ2SKcjs.ReasoningTransformer; exports.getBuiltinTransformers = _chunkFFALUUZZcjs.getBuiltinTransformers; exports.registerBuiltinTransformers = _chunkFFALUUZZcjs.registerBuiltinTransformers;