@librechat/agents 3.1.75 → 3.1.77-dev.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (272) hide show
  1. package/dist/cjs/graphs/Graph.cjs +22 -3
  2. package/dist/cjs/graphs/Graph.cjs.map +1 -1
  3. package/dist/cjs/hitl/askUserQuestion.cjs +67 -0
  4. package/dist/cjs/hitl/askUserQuestion.cjs.map +1 -0
  5. package/dist/cjs/hooks/HookRegistry.cjs +54 -0
  6. package/dist/cjs/hooks/HookRegistry.cjs.map +1 -1
  7. package/dist/cjs/hooks/createToolPolicyHook.cjs +115 -0
  8. package/dist/cjs/hooks/createToolPolicyHook.cjs.map +1 -0
  9. package/dist/cjs/hooks/executeHooks.cjs +40 -1
  10. package/dist/cjs/hooks/executeHooks.cjs.map +1 -1
  11. package/dist/cjs/hooks/types.cjs +1 -0
  12. package/dist/cjs/hooks/types.cjs.map +1 -1
  13. package/dist/cjs/langchain/google-common.cjs +3 -0
  14. package/dist/cjs/langchain/google-common.cjs.map +1 -0
  15. package/dist/cjs/langchain/index.cjs +86 -0
  16. package/dist/cjs/langchain/index.cjs.map +1 -0
  17. package/dist/cjs/langchain/language_models/chat_models.cjs +3 -0
  18. package/dist/cjs/langchain/language_models/chat_models.cjs.map +1 -0
  19. package/dist/cjs/langchain/messages/tool.cjs +3 -0
  20. package/dist/cjs/langchain/messages/tool.cjs.map +1 -0
  21. package/dist/cjs/langchain/messages.cjs +51 -0
  22. package/dist/cjs/langchain/messages.cjs.map +1 -0
  23. package/dist/cjs/langchain/openai.cjs +3 -0
  24. package/dist/cjs/langchain/openai.cjs.map +1 -0
  25. package/dist/cjs/langchain/prompts.cjs +11 -0
  26. package/dist/cjs/langchain/prompts.cjs.map +1 -0
  27. package/dist/cjs/langchain/runnables.cjs +19 -0
  28. package/dist/cjs/langchain/runnables.cjs.map +1 -0
  29. package/dist/cjs/langchain/tools.cjs +23 -0
  30. package/dist/cjs/langchain/tools.cjs.map +1 -0
  31. package/dist/cjs/langchain/utils/env.cjs +11 -0
  32. package/dist/cjs/langchain/utils/env.cjs.map +1 -0
  33. package/dist/cjs/llm/anthropic/index.cjs +145 -52
  34. package/dist/cjs/llm/anthropic/index.cjs.map +1 -1
  35. package/dist/cjs/llm/anthropic/types.cjs.map +1 -1
  36. package/dist/cjs/llm/anthropic/utils/message_inputs.cjs +21 -14
  37. package/dist/cjs/llm/anthropic/utils/message_inputs.cjs.map +1 -1
  38. package/dist/cjs/llm/anthropic/utils/message_outputs.cjs +84 -70
  39. package/dist/cjs/llm/anthropic/utils/message_outputs.cjs.map +1 -1
  40. package/dist/cjs/llm/bedrock/index.cjs +1 -1
  41. package/dist/cjs/llm/bedrock/index.cjs.map +1 -1
  42. package/dist/cjs/llm/bedrock/utils/message_inputs.cjs +213 -3
  43. package/dist/cjs/llm/bedrock/utils/message_inputs.cjs.map +1 -1
  44. package/dist/cjs/llm/bedrock/utils/message_outputs.cjs +2 -1
  45. package/dist/cjs/llm/bedrock/utils/message_outputs.cjs.map +1 -1
  46. package/dist/cjs/llm/google/utils/common.cjs +5 -4
  47. package/dist/cjs/llm/google/utils/common.cjs.map +1 -1
  48. package/dist/cjs/llm/openai/index.cjs +519 -655
  49. package/dist/cjs/llm/openai/index.cjs.map +1 -1
  50. package/dist/cjs/llm/openai/utils/index.cjs +20 -458
  51. package/dist/cjs/llm/openai/utils/index.cjs.map +1 -1
  52. package/dist/cjs/llm/openrouter/index.cjs +57 -175
  53. package/dist/cjs/llm/openrouter/index.cjs.map +1 -1
  54. package/dist/cjs/llm/vertexai/index.cjs +5 -3
  55. package/dist/cjs/llm/vertexai/index.cjs.map +1 -1
  56. package/dist/cjs/main.cjs +112 -3
  57. package/dist/cjs/main.cjs.map +1 -1
  58. package/dist/cjs/messages/cache.cjs +2 -1
  59. package/dist/cjs/messages/cache.cjs.map +1 -1
  60. package/dist/cjs/messages/core.cjs +7 -6
  61. package/dist/cjs/messages/core.cjs.map +1 -1
  62. package/dist/cjs/messages/format.cjs +73 -15
  63. package/dist/cjs/messages/format.cjs.map +1 -1
  64. package/dist/cjs/messages/langchain.cjs +26 -0
  65. package/dist/cjs/messages/langchain.cjs.map +1 -0
  66. package/dist/cjs/messages/prune.cjs +7 -6
  67. package/dist/cjs/messages/prune.cjs.map +1 -1
  68. package/dist/cjs/run.cjs +400 -42
  69. package/dist/cjs/run.cjs.map +1 -1
  70. package/dist/cjs/tools/ToolNode.cjs +556 -56
  71. package/dist/cjs/tools/ToolNode.cjs.map +1 -1
  72. package/dist/cjs/tools/search/search.cjs +55 -66
  73. package/dist/cjs/tools/search/search.cjs.map +1 -1
  74. package/dist/cjs/tools/search/tavily-scraper.cjs +189 -0
  75. package/dist/cjs/tools/search/tavily-scraper.cjs.map +1 -0
  76. package/dist/cjs/tools/search/tavily-search.cjs +372 -0
  77. package/dist/cjs/tools/search/tavily-search.cjs.map +1 -0
  78. package/dist/cjs/tools/search/tool.cjs +26 -4
  79. package/dist/cjs/tools/search/tool.cjs.map +1 -1
  80. package/dist/cjs/tools/search/utils.cjs +10 -3
  81. package/dist/cjs/tools/search/utils.cjs.map +1 -1
  82. package/dist/esm/graphs/Graph.mjs +22 -3
  83. package/dist/esm/graphs/Graph.mjs.map +1 -1
  84. package/dist/esm/hitl/askUserQuestion.mjs +65 -0
  85. package/dist/esm/hitl/askUserQuestion.mjs.map +1 -0
  86. package/dist/esm/hooks/HookRegistry.mjs +54 -0
  87. package/dist/esm/hooks/HookRegistry.mjs.map +1 -1
  88. package/dist/esm/hooks/createToolPolicyHook.mjs +113 -0
  89. package/dist/esm/hooks/createToolPolicyHook.mjs.map +1 -0
  90. package/dist/esm/hooks/executeHooks.mjs +40 -1
  91. package/dist/esm/hooks/executeHooks.mjs.map +1 -1
  92. package/dist/esm/hooks/types.mjs +1 -0
  93. package/dist/esm/hooks/types.mjs.map +1 -1
  94. package/dist/esm/langchain/google-common.mjs +2 -0
  95. package/dist/esm/langchain/google-common.mjs.map +1 -0
  96. package/dist/esm/langchain/index.mjs +5 -0
  97. package/dist/esm/langchain/index.mjs.map +1 -0
  98. package/dist/esm/langchain/language_models/chat_models.mjs +2 -0
  99. package/dist/esm/langchain/language_models/chat_models.mjs.map +1 -0
  100. package/dist/esm/langchain/messages/tool.mjs +2 -0
  101. package/dist/esm/langchain/messages/tool.mjs.map +1 -0
  102. package/dist/esm/langchain/messages.mjs +2 -0
  103. package/dist/esm/langchain/messages.mjs.map +1 -0
  104. package/dist/esm/langchain/openai.mjs +2 -0
  105. package/dist/esm/langchain/openai.mjs.map +1 -0
  106. package/dist/esm/langchain/prompts.mjs +2 -0
  107. package/dist/esm/langchain/prompts.mjs.map +1 -0
  108. package/dist/esm/langchain/runnables.mjs +2 -0
  109. package/dist/esm/langchain/runnables.mjs.map +1 -0
  110. package/dist/esm/langchain/tools.mjs +2 -0
  111. package/dist/esm/langchain/tools.mjs.map +1 -0
  112. package/dist/esm/langchain/utils/env.mjs +2 -0
  113. package/dist/esm/langchain/utils/env.mjs.map +1 -0
  114. package/dist/esm/llm/anthropic/index.mjs +146 -54
  115. package/dist/esm/llm/anthropic/index.mjs.map +1 -1
  116. package/dist/esm/llm/anthropic/types.mjs.map +1 -1
  117. package/dist/esm/llm/anthropic/utils/message_inputs.mjs +21 -14
  118. package/dist/esm/llm/anthropic/utils/message_inputs.mjs.map +1 -1
  119. package/dist/esm/llm/anthropic/utils/message_outputs.mjs +84 -71
  120. package/dist/esm/llm/anthropic/utils/message_outputs.mjs.map +1 -1
  121. package/dist/esm/llm/bedrock/index.mjs +1 -1
  122. package/dist/esm/llm/bedrock/index.mjs.map +1 -1
  123. package/dist/esm/llm/bedrock/utils/message_inputs.mjs +214 -4
  124. package/dist/esm/llm/bedrock/utils/message_inputs.mjs.map +1 -1
  125. package/dist/esm/llm/bedrock/utils/message_outputs.mjs +2 -1
  126. package/dist/esm/llm/bedrock/utils/message_outputs.mjs.map +1 -1
  127. package/dist/esm/llm/google/utils/common.mjs +5 -4
  128. package/dist/esm/llm/google/utils/common.mjs.map +1 -1
  129. package/dist/esm/llm/openai/index.mjs +520 -656
  130. package/dist/esm/llm/openai/index.mjs.map +1 -1
  131. package/dist/esm/llm/openai/utils/index.mjs +23 -459
  132. package/dist/esm/llm/openai/utils/index.mjs.map +1 -1
  133. package/dist/esm/llm/openrouter/index.mjs +57 -175
  134. package/dist/esm/llm/openrouter/index.mjs.map +1 -1
  135. package/dist/esm/llm/vertexai/index.mjs +5 -3
  136. package/dist/esm/llm/vertexai/index.mjs.map +1 -1
  137. package/dist/esm/main.mjs +7 -0
  138. package/dist/esm/main.mjs.map +1 -1
  139. package/dist/esm/messages/cache.mjs +2 -1
  140. package/dist/esm/messages/cache.mjs.map +1 -1
  141. package/dist/esm/messages/core.mjs +7 -6
  142. package/dist/esm/messages/core.mjs.map +1 -1
  143. package/dist/esm/messages/format.mjs +73 -15
  144. package/dist/esm/messages/format.mjs.map +1 -1
  145. package/dist/esm/messages/langchain.mjs +23 -0
  146. package/dist/esm/messages/langchain.mjs.map +1 -0
  147. package/dist/esm/messages/prune.mjs +7 -6
  148. package/dist/esm/messages/prune.mjs.map +1 -1
  149. package/dist/esm/run.mjs +400 -42
  150. package/dist/esm/run.mjs.map +1 -1
  151. package/dist/esm/tools/ToolNode.mjs +557 -57
  152. package/dist/esm/tools/ToolNode.mjs.map +1 -1
  153. package/dist/esm/tools/search/search.mjs +55 -66
  154. package/dist/esm/tools/search/search.mjs.map +1 -1
  155. package/dist/esm/tools/search/tavily-scraper.mjs +186 -0
  156. package/dist/esm/tools/search/tavily-scraper.mjs.map +1 -0
  157. package/dist/esm/tools/search/tavily-search.mjs +370 -0
  158. package/dist/esm/tools/search/tavily-search.mjs.map +1 -0
  159. package/dist/esm/tools/search/tool.mjs +26 -4
  160. package/dist/esm/tools/search/tool.mjs.map +1 -1
  161. package/dist/esm/tools/search/utils.mjs +10 -3
  162. package/dist/esm/tools/search/utils.mjs.map +1 -1
  163. package/dist/types/graphs/Graph.d.ts +7 -0
  164. package/dist/types/hitl/askUserQuestion.d.ts +55 -0
  165. package/dist/types/hitl/index.d.ts +6 -0
  166. package/dist/types/hooks/HookRegistry.d.ts +58 -0
  167. package/dist/types/hooks/createToolPolicyHook.d.ts +87 -0
  168. package/dist/types/hooks/index.d.ts +4 -1
  169. package/dist/types/hooks/types.d.ts +109 -3
  170. package/dist/types/index.d.ts +10 -0
  171. package/dist/types/langchain/google-common.d.ts +1 -0
  172. package/dist/types/langchain/index.d.ts +8 -0
  173. package/dist/types/langchain/language_models/chat_models.d.ts +1 -0
  174. package/dist/types/langchain/messages/tool.d.ts +1 -0
  175. package/dist/types/langchain/messages.d.ts +2 -0
  176. package/dist/types/langchain/openai.d.ts +1 -0
  177. package/dist/types/langchain/prompts.d.ts +1 -0
  178. package/dist/types/langchain/runnables.d.ts +2 -0
  179. package/dist/types/langchain/tools.d.ts +2 -0
  180. package/dist/types/langchain/utils/env.d.ts +1 -0
  181. package/dist/types/llm/anthropic/index.d.ts +22 -9
  182. package/dist/types/llm/anthropic/types.d.ts +5 -1
  183. package/dist/types/llm/anthropic/utils/message_outputs.d.ts +13 -6
  184. package/dist/types/llm/anthropic/utils/output_parsers.d.ts +1 -1
  185. package/dist/types/llm/openai/index.d.ts +21 -24
  186. package/dist/types/llm/openrouter/index.d.ts +11 -9
  187. package/dist/types/llm/vertexai/index.d.ts +1 -0
  188. package/dist/types/messages/cache.d.ts +4 -1
  189. package/dist/types/messages/format.d.ts +4 -1
  190. package/dist/types/messages/langchain.d.ts +27 -0
  191. package/dist/types/run.d.ts +117 -1
  192. package/dist/types/tools/ToolNode.d.ts +26 -1
  193. package/dist/types/tools/search/tavily-scraper.d.ts +19 -0
  194. package/dist/types/tools/search/tavily-search.d.ts +4 -0
  195. package/dist/types/tools/search/types.d.ts +99 -5
  196. package/dist/types/tools/search/utils.d.ts +2 -2
  197. package/dist/types/types/graph.d.ts +23 -37
  198. package/dist/types/types/hitl.d.ts +272 -0
  199. package/dist/types/types/index.d.ts +1 -0
  200. package/dist/types/types/llm.d.ts +3 -3
  201. package/dist/types/types/run.d.ts +33 -0
  202. package/dist/types/types/stream.d.ts +1 -1
  203. package/dist/types/types/tools.d.ts +19 -0
  204. package/package.json +80 -17
  205. package/src/graphs/Graph.ts +33 -4
  206. package/src/graphs/__tests__/composition.smoke.test.ts +188 -0
  207. package/src/hitl/askUserQuestion.ts +72 -0
  208. package/src/hitl/index.ts +7 -0
  209. package/src/hooks/HookRegistry.ts +71 -0
  210. package/src/hooks/__tests__/createToolPolicyHook.test.ts +259 -0
  211. package/src/hooks/createToolPolicyHook.ts +184 -0
  212. package/src/hooks/executeHooks.ts +50 -1
  213. package/src/hooks/index.ts +6 -0
  214. package/src/hooks/types.ts +112 -0
  215. package/src/index.ts +22 -0
  216. package/src/langchain/google-common.ts +1 -0
  217. package/src/langchain/index.ts +8 -0
  218. package/src/langchain/language_models/chat_models.ts +1 -0
  219. package/src/langchain/messages/tool.ts +5 -0
  220. package/src/langchain/messages.ts +21 -0
  221. package/src/langchain/openai.ts +1 -0
  222. package/src/langchain/prompts.ts +1 -0
  223. package/src/langchain/runnables.ts +7 -0
  224. package/src/langchain/tools.ts +8 -0
  225. package/src/langchain/utils/env.ts +1 -0
  226. package/src/llm/anthropic/index.ts +252 -84
  227. package/src/llm/anthropic/llm.spec.ts +751 -102
  228. package/src/llm/anthropic/types.ts +9 -1
  229. package/src/llm/anthropic/utils/message_inputs.ts +37 -19
  230. package/src/llm/anthropic/utils/message_outputs.ts +119 -101
  231. package/src/llm/bedrock/index.ts +2 -2
  232. package/src/llm/bedrock/llm.spec.ts +341 -0
  233. package/src/llm/bedrock/utils/message_inputs.ts +303 -4
  234. package/src/llm/bedrock/utils/message_outputs.ts +2 -1
  235. package/src/llm/custom-chat-models.smoke.test.ts +836 -0
  236. package/src/llm/google/llm.spec.ts +339 -57
  237. package/src/llm/google/utils/common.ts +53 -48
  238. package/src/llm/openai/contentBlocks.test.ts +346 -0
  239. package/src/llm/openai/index.ts +856 -833
  240. package/src/llm/openai/utils/index.ts +107 -78
  241. package/src/llm/openai/utils/messages.test.ts +159 -0
  242. package/src/llm/openrouter/index.ts +124 -247
  243. package/src/llm/openrouter/reasoning.test.ts +8 -1
  244. package/src/llm/vertexai/index.ts +11 -5
  245. package/src/llm/vertexai/llm.spec.ts +28 -1
  246. package/src/messages/cache.test.ts +4 -3
  247. package/src/messages/cache.ts +3 -2
  248. package/src/messages/core.ts +16 -9
  249. package/src/messages/format.ts +96 -16
  250. package/src/messages/formatAgentMessages.test.ts +166 -1
  251. package/src/messages/langchain.ts +39 -0
  252. package/src/messages/prune.ts +12 -8
  253. package/src/run.ts +456 -47
  254. package/src/scripts/caching.ts +2 -3
  255. package/src/specs/summarization.test.ts +51 -58
  256. package/src/tools/ToolNode.ts +706 -63
  257. package/src/tools/__tests__/hitl.test.ts +3593 -0
  258. package/src/tools/search/search.ts +83 -73
  259. package/src/tools/search/tavily-scraper.ts +235 -0
  260. package/src/tools/search/tavily-search.ts +424 -0
  261. package/src/tools/search/tavily.test.ts +965 -0
  262. package/src/tools/search/tool.ts +36 -26
  263. package/src/tools/search/types.ts +133 -8
  264. package/src/tools/search/utils.ts +13 -5
  265. package/src/types/graph.ts +32 -87
  266. package/src/types/hitl.ts +303 -0
  267. package/src/types/index.ts +1 -0
  268. package/src/types/llm.ts +3 -3
  269. package/src/types/run.ts +33 -0
  270. package/src/types/stream.ts +1 -1
  271. package/src/types/tools.ts +19 -0
  272. package/src/utils/llmConfig.ts +1 -6
@@ -53,6 +53,153 @@ function normalizeHeaders(headers) {
53
53
  });
54
54
  return Object.fromEntries(output.entries());
55
55
  }
56
+ function getExposedOpenAIClient(completions, responses, preferResponses) {
57
+ const responsesClient = responses.client;
58
+ if (responsesClient?.abortHandler != null) {
59
+ return responsesClient;
60
+ }
61
+ const completionsClient = completions.client;
62
+ if (completionsClient?.abortHandler != null) {
63
+ return completionsClient;
64
+ }
65
+ const delegate = preferResponses ? responses : completions;
66
+ delegate._getClientOptions(undefined);
67
+ return delegate.client;
68
+ }
69
+ function getReasoningParams(baseReasoning, options) {
70
+ let reasoning;
71
+ if (baseReasoning !== undefined) {
72
+ reasoning = {
73
+ ...reasoning,
74
+ ...baseReasoning,
75
+ };
76
+ }
77
+ if (options?.reasoning !== undefined) {
78
+ reasoning = {
79
+ ...reasoning,
80
+ ...options.reasoning,
81
+ };
82
+ }
83
+ if (options?.reasoningEffort !== undefined &&
84
+ reasoning?.effort === undefined) {
85
+ reasoning = {
86
+ ...reasoning,
87
+ effort: options.reasoningEffort,
88
+ };
89
+ }
90
+ return reasoning;
91
+ }
92
+ function getGatedReasoningParams(model, baseReasoning, options) {
93
+ if (!index.isReasoningModel(model)) {
94
+ return;
95
+ }
96
+ return getReasoningParams(baseReasoning, options);
97
+ }
98
+ function isObject(value) {
99
+ return typeof value === 'object' && value !== null;
100
+ }
101
+ function isOpenAIChatCompletionChunk(value) {
102
+ if (!isObject(value)) {
103
+ return false;
104
+ }
105
+ // Intentionally loose: downstream handlers already tolerate empty choices.
106
+ const { choices } = value;
107
+ return Array.isArray(choices);
108
+ }
109
+ function getOpenAIChatCompletionChunk(value) {
110
+ if (isOpenAIChatCompletionChunk(value)) {
111
+ return value;
112
+ }
113
+ const { data } = value;
114
+ if (isOpenAIChatCompletionChunk(data)) {
115
+ return data;
116
+ }
117
+ return undefined;
118
+ }
119
+ async function* filterOpenAIChatCompletionStream(stream) {
120
+ for await (const item of stream) {
121
+ const chunk = getOpenAIChatCompletionChunk(item);
122
+ if (chunk == null) {
123
+ continue;
124
+ }
125
+ yield chunk;
126
+ }
127
+ }
128
+ async function completionWithFilteredOpenAIStream(request, requestOptions, completionWithRetry) {
129
+ if (request.stream !== true) {
130
+ return (await completionWithRetry(request, requestOptions));
131
+ }
132
+ const stream = await completionWithRetry(request, requestOptions);
133
+ return filterOpenAIChatCompletionStream(stream);
134
+ }
135
+ function attachLibreChatDeltaFields(chunk, delta) {
136
+ if (!messages.AIMessageChunk.isInstance(chunk)) {
137
+ return chunk;
138
+ }
139
+ const libreChatDelta = delta;
140
+ if (libreChatDelta.reasoning != null &&
141
+ chunk.additional_kwargs.reasoning_content == null) {
142
+ chunk.additional_kwargs.reasoning_content = libreChatDelta.reasoning;
143
+ }
144
+ if (libreChatDelta.reasoning_details != null) {
145
+ chunk.additional_kwargs.reasoning_details =
146
+ libreChatDelta.reasoning_details;
147
+ }
148
+ if (libreChatDelta.provider_specific_fields != null) {
149
+ chunk.additional_kwargs.provider_specific_fields =
150
+ libreChatDelta.provider_specific_fields;
151
+ }
152
+ return chunk;
153
+ }
154
+ function attachLibreChatMessageFields(message, rawMessage) {
155
+ if (!messages.isAIMessage(message)) {
156
+ return message;
157
+ }
158
+ if (rawMessage.reasoning != null &&
159
+ message.additional_kwargs.reasoning_content == null) {
160
+ message.additional_kwargs.reasoning_content = rawMessage.reasoning;
161
+ }
162
+ if (rawMessage.reasoning_details != null) {
163
+ message.additional_kwargs.reasoning_details = rawMessage.reasoning_details;
164
+ }
165
+ if (rawMessage.provider_specific_fields != null) {
166
+ message.additional_kwargs.provider_specific_fields =
167
+ rawMessage.provider_specific_fields;
168
+ }
169
+ return message;
170
+ }
171
+ function getCustomOpenAIClientOptions(owner, options) {
172
+ if (!owner.client) {
173
+ const openAIEndpointConfig = {
174
+ baseURL: owner.clientConfig.baseURL,
175
+ };
176
+ const endpoint = openai.getEndpoint(openAIEndpointConfig);
177
+ const params = {
178
+ ...owner.clientConfig,
179
+ baseURL: endpoint,
180
+ timeout: owner.timeout,
181
+ maxRetries: 0,
182
+ };
183
+ if (params.baseURL == null) {
184
+ delete params.baseURL;
185
+ }
186
+ params.defaultHeaders = openai.getHeadersWithUserAgent(params.defaultHeaders);
187
+ owner.client = new CustomOpenAIClient(params);
188
+ }
189
+ const requestOptions = {
190
+ ...owner.clientConfig,
191
+ ...options,
192
+ };
193
+ return requestOptions;
194
+ }
195
+ async function* delayStreamChunks(chunks, delay) {
196
+ for await (const chunk of chunks) {
197
+ yield chunk;
198
+ if (delay != null) {
199
+ await run.sleep(delay);
200
+ }
201
+ }
202
+ }
56
203
  function createAbortHandler(controller) {
57
204
  return function () {
58
205
  controller.abort();
@@ -112,89 +259,165 @@ class CustomAzureOpenAIClient extends openai$1.AzureOpenAI {
112
259
  }));
113
260
  }
114
261
  }
115
- /** @ts-expect-error We are intentionally overriding `getReasoningParams` */
116
- class ChatOpenAI extends openai.ChatOpenAI {
117
- _lc_stream_delay;
262
+ class LibreChatOpenAICompletions extends openai.ChatOpenAICompletions {
263
+ includeReasoningContent;
264
+ includeReasoningDetails;
265
+ convertReasoningDetailsToContent;
118
266
  constructor(fields) {
119
267
  super(fields);
120
- this._lc_stream_delay = fields?._lc_stream_delay;
121
- }
122
- get exposedClient() {
123
- return this.client;
268
+ this.includeReasoningContent = fields?.includeReasoningContent;
269
+ this.includeReasoningDetails = fields?.includeReasoningDetails;
270
+ this.convertReasoningDetailsToContent =
271
+ fields?.convertReasoningDetailsToContent;
124
272
  }
125
- static lc_name() {
126
- return 'LibreChatOpenAI';
273
+ _getReasoningParams(options) {
274
+ return getReasoningParams(this.reasoning, options);
127
275
  }
128
276
  _getClientOptions(options) {
129
- if (!this.client) {
130
- const openAIEndpointConfig = {
131
- baseURL: this.clientConfig.baseURL,
132
- };
133
- const endpoint = openai.getEndpoint(openAIEndpointConfig);
134
- const params = {
135
- ...this.clientConfig,
136
- baseURL: endpoint,
137
- timeout: this.timeout,
138
- maxRetries: 0,
139
- };
140
- if (params.baseURL == null) {
141
- delete params.baseURL;
142
- }
143
- this.client = new CustomOpenAIClient(params);
144
- }
145
- const requestOptions = {
146
- ...this.clientConfig,
147
- ...options,
148
- };
149
- return requestOptions;
277
+ return getCustomOpenAIClientOptions(this, options);
150
278
  }
151
- /**
152
- * Returns backwards compatible reasoning parameters from constructor params and call options
153
- * @internal
154
- */
155
- getReasoningParams(options) {
156
- // apply options in reverse order of importance -- newer options supersede older options
157
- let reasoning;
158
- if (this.reasoning !== undefined) {
159
- reasoning = {
160
- ...reasoning,
161
- ...this.reasoning,
279
+ async completionWithRetry(request, requestOptions) {
280
+ return completionWithFilteredOpenAIStream(request, requestOptions, super.completionWithRetry.bind(this));
281
+ }
282
+ _convertCompletionsDeltaToBaseMessageChunk(delta, rawResponse, defaultRole) {
283
+ return attachLibreChatDeltaFields(super._convertCompletionsDeltaToBaseMessageChunk(delta, rawResponse, defaultRole), delta);
284
+ }
285
+ _convertCompletionsMessageToBaseMessage(message, rawResponse) {
286
+ return attachLibreChatMessageFields(super._convertCompletionsMessageToBaseMessage(message, rawResponse), message);
287
+ }
288
+ async _generate(messages$1, options, runManager) {
289
+ if (this.includeReasoningContent !== true &&
290
+ this.includeReasoningDetails !== true) {
291
+ return super._generate(messages$1, options, runManager);
292
+ }
293
+ options.signal?.throwIfAborted();
294
+ const usageMetadata = {};
295
+ const params = this.invocationParams(options);
296
+ const messagesMapped = index._convertMessagesToOpenAIParams(messages$1, this.model, {
297
+ includeReasoningContent: this.includeReasoningContent,
298
+ includeReasoningDetails: this.includeReasoningDetails,
299
+ convertReasoningDetailsToContent: this.convertReasoningDetailsToContent,
300
+ });
301
+ if (params.stream === true) {
302
+ const stream = this._streamResponseChunks(messages$1, options, runManager);
303
+ const finalChunks = new Map();
304
+ for await (const chunk of stream) {
305
+ chunk.message.response_metadata = {
306
+ ...chunk.generationInfo,
307
+ ...chunk.message.response_metadata,
308
+ };
309
+ const index = typeof chunk.generationInfo?.completion === 'number'
310
+ ? chunk.generationInfo.completion
311
+ : 0;
312
+ const existingChunk = finalChunks.get(index);
313
+ if (existingChunk == null) {
314
+ finalChunks.set(index, chunk);
315
+ }
316
+ else {
317
+ finalChunks.set(index, existingChunk.concat(chunk));
318
+ }
319
+ }
320
+ const generations = Array.from(finalChunks.entries())
321
+ .sort(([aKey], [bKey]) => aKey - bKey)
322
+ .map(([, value]) => value);
323
+ const { functions, function_call } = this.invocationParams(options);
324
+ const promptTokenUsage = await this._getEstimatedTokenCountFromPrompt(messages$1, functions, function_call);
325
+ const completionTokenUsage = await this._getNumTokensFromGenerations(generations);
326
+ usageMetadata.input_tokens = promptTokenUsage;
327
+ usageMetadata.output_tokens = completionTokenUsage;
328
+ usageMetadata.total_tokens = promptTokenUsage + completionTokenUsage;
329
+ return {
330
+ generations,
331
+ llmOutput: {
332
+ estimatedTokenUsage: {
333
+ promptTokens: usageMetadata.input_tokens,
334
+ completionTokens: usageMetadata.output_tokens,
335
+ totalTokens: usageMetadata.total_tokens,
336
+ },
337
+ },
162
338
  };
163
339
  }
164
- if (options?.reasoning !== undefined) {
165
- reasoning = {
166
- ...reasoning,
167
- ...options.reasoning,
340
+ const data = await this.completionWithRetry({
341
+ ...params,
342
+ stream: false,
343
+ messages: messagesMapped,
344
+ }, {
345
+ signal: options.signal,
346
+ ...options.options,
347
+ });
348
+ const { completion_tokens: completionTokens, prompt_tokens: promptTokens, total_tokens: totalTokens, prompt_tokens_details: promptTokensDetails, completion_tokens_details: completionTokensDetails, } = data.usage ?? {};
349
+ if (completionTokens != null) {
350
+ usageMetadata.output_tokens =
351
+ (usageMetadata.output_tokens ?? 0) + completionTokens;
352
+ }
353
+ if (promptTokens != null) {
354
+ usageMetadata.input_tokens =
355
+ (usageMetadata.input_tokens ?? 0) + promptTokens;
356
+ }
357
+ if (totalTokens != null) {
358
+ usageMetadata.total_tokens =
359
+ (usageMetadata.total_tokens ?? 0) + totalTokens;
360
+ }
361
+ if (promptTokensDetails?.audio_tokens != null ||
362
+ promptTokensDetails?.cached_tokens != null) {
363
+ usageMetadata.input_token_details = {
364
+ ...(promptTokensDetails.audio_tokens != null && {
365
+ audio: promptTokensDetails.audio_tokens,
366
+ }),
367
+ ...(promptTokensDetails.cached_tokens != null && {
368
+ cache_read: promptTokensDetails.cached_tokens,
369
+ }),
168
370
  };
169
371
  }
170
- return reasoning;
171
- }
172
- _getReasoningParams(options) {
173
- return this.getReasoningParams(options);
174
- }
175
- async *_streamResponseChunks(messages, options, runManager) {
176
- if (!this._useResponseApi(options)) {
177
- return yield* this._streamResponseChunks2(messages, options, runManager);
372
+ if (completionTokensDetails?.audio_tokens != null ||
373
+ completionTokensDetails?.reasoning_tokens != null) {
374
+ usageMetadata.output_token_details = {
375
+ ...(completionTokensDetails.audio_tokens != null && {
376
+ audio: completionTokensDetails.audio_tokens,
377
+ }),
378
+ ...(completionTokensDetails.reasoning_tokens != null && {
379
+ reasoning: completionTokensDetails.reasoning_tokens,
380
+ }),
381
+ };
178
382
  }
179
- const streamIterable = await this.responseApiWithRetry({
180
- ...this.invocationParams(options, { streaming: true }),
181
- input: index._convertMessagesToOpenAIResponsesParams(messages, this.model, this.zdrEnabled),
182
- stream: true,
183
- }, options);
184
- for await (const data of streamIterable) {
185
- const chunk = index._convertOpenAIResponsesDeltaToBaseMessageChunk(data);
186
- if (chunk == null)
187
- continue;
188
- yield chunk;
189
- if (this._lc_stream_delay != null) {
190
- await run.sleep(this._lc_stream_delay);
383
+ const generations = [];
384
+ for (const part of data.choices) {
385
+ const generation = {
386
+ text: part.message.content ?? '',
387
+ message: this._convertCompletionsMessageToBaseMessage(part.message, data),
388
+ };
389
+ generation.generationInfo = {
390
+ finish_reason: part.finish_reason,
391
+ ...(part.logprobs ? { logprobs: part.logprobs } : {}),
392
+ };
393
+ if (messages.isAIMessage(generation.message)) {
394
+ generation.message.usage_metadata = usageMetadata;
191
395
  }
192
- await runManager?.handleLLMNewToken(chunk.text || '', undefined, undefined, undefined, undefined, { chunk });
396
+ generation.message = new messages.AIMessage(Object.fromEntries(Object.entries(generation.message).filter(([key]) => !key.startsWith('lc_'))));
397
+ generations.push(generation);
193
398
  }
194
- return;
399
+ return {
400
+ generations,
401
+ llmOutput: {
402
+ tokenUsage: {
403
+ promptTokens: usageMetadata.input_tokens,
404
+ completionTokens: usageMetadata.output_tokens,
405
+ totalTokens: usageMetadata.total_tokens,
406
+ },
407
+ },
408
+ };
195
409
  }
196
- async *_streamResponseChunks2(messages$1, options, runManager) {
197
- const messagesMapped = index._convertMessagesToOpenAIParams(messages$1, this.model);
410
+ async *_streamResponseChunks(messages$1, options, runManager) {
411
+ if (this.includeReasoningContent !== true &&
412
+ this.includeReasoningDetails !== true) {
413
+ yield* super._streamResponseChunks(messages$1, options, runManager);
414
+ return;
415
+ }
416
+ const messagesMapped = index._convertMessagesToOpenAIParams(messages$1, this.model, {
417
+ includeReasoningContent: this.includeReasoningContent,
418
+ includeReasoningDetails: this.includeReasoningDetails,
419
+ convertReasoningDetailsToContent: this.convertReasoningDetailsToContent,
420
+ });
198
421
  const params = {
199
422
  ...this.invocationParams(options, {
200
423
  streaming: true,
@@ -206,49 +429,40 @@ class ChatOpenAI extends openai.ChatOpenAI {
206
429
  const streamIterable = await this.completionWithRetry(params, options);
207
430
  let usage;
208
431
  for await (const data of streamIterable) {
209
- const choice = data.choices[0];
210
- if (data.usage) {
432
+ if (options.signal?.aborted === true) {
433
+ return;
434
+ }
435
+ const choices = data.choices;
436
+ const choice = choices?.[0];
437
+ if (data.usage != null) {
211
438
  usage = data.usage;
212
439
  }
213
- if (!choice) {
440
+ if (choice == null) {
214
441
  continue;
215
442
  }
216
443
  const { delta } = choice;
217
- if (!delta) {
444
+ if (delta == null) {
218
445
  continue;
219
446
  }
220
- const chunk = this._convertOpenAIDeltaToBaseMessageChunk(delta, data, defaultRole);
221
- if ('reasoning_content' in delta) {
222
- chunk.additional_kwargs.reasoning_content = delta.reasoning_content;
223
- }
224
- else if ('reasoning' in delta) {
225
- chunk.additional_kwargs.reasoning_content = delta.reasoning;
226
- }
227
- if ('provider_specific_fields' in delta) {
228
- chunk.additional_kwargs.provider_specific_fields =
229
- delta.provider_specific_fields;
230
- }
447
+ const chunk = this._convertCompletionsDeltaToBaseMessageChunk(delta, data, defaultRole);
231
448
  defaultRole = delta.role ?? defaultRole;
232
449
  const newTokenIndices = {
233
450
  prompt: options.promptIndex ?? 0,
234
- completion: choice.index ?? 0,
451
+ completion: choice.index,
235
452
  };
236
453
  if (typeof chunk.content !== 'string') {
237
454
  // eslint-disable-next-line no-console
238
455
  console.log('[WARNING]: Received non-string content from OpenAI. This is currently not supported.');
239
456
  continue;
240
457
  }
241
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
242
458
  const generationInfo = { ...newTokenIndices };
243
459
  if (choice.finish_reason != null) {
244
460
  generationInfo.finish_reason = choice.finish_reason;
245
- // Only include system fingerprint in the last chunk for now
246
- // to avoid concatenation issues
247
461
  generationInfo.system_fingerprint = data.system_fingerprint;
248
462
  generationInfo.model_name = data.model;
249
463
  generationInfo.service_tier = data.service_tier;
250
464
  }
251
- if (this.logprobs == true) {
465
+ if (this.logprobs === true) {
252
466
  generationInfo.logprobs = choice.logprobs;
253
467
  }
254
468
  const generationChunk = new outputs.ChatGenerationChunk({
@@ -257,10 +471,7 @@ class ChatOpenAI extends openai.ChatOpenAI {
257
471
  generationInfo,
258
472
  });
259
473
  yield generationChunk;
260
- if (this._lc_stream_delay != null) {
261
- await run.sleep(this._lc_stream_delay);
262
- }
263
- await runManager?.handleLLMNewToken(generationChunk.text || '', newTokenIndices, undefined, undefined, undefined, { chunk: generationChunk });
474
+ await runManager?.handleLLMNewToken(generationChunk.text, newTokenIndices, undefined, undefined, undefined, { chunk: generationChunk });
264
475
  }
265
476
  if (usage) {
266
477
  const inputTokenDetails = {
@@ -282,9 +493,7 @@ class ChatOpenAI extends openai.ChatOpenAI {
282
493
  const generationChunk = new outputs.ChatGenerationChunk({
283
494
  message: new messages.AIMessageChunk({
284
495
  content: '',
285
- response_metadata: {
286
- usage: { ...usage },
287
- },
496
+ response_metadata: { usage: { ...usage } },
288
497
  usage_metadata: {
289
498
  input_tokens: usage.prompt_tokens,
290
499
  output_tokens: usage.completion_tokens,
@@ -300,54 +509,27 @@ class ChatOpenAI extends openai.ChatOpenAI {
300
509
  text: '',
301
510
  });
302
511
  yield generationChunk;
303
- if (this._lc_stream_delay != null) {
304
- await run.sleep(this._lc_stream_delay);
305
- }
512
+ await runManager?.handleLLMNewToken(generationChunk.text, {
513
+ prompt: 0,
514
+ completion: 0,
515
+ }, undefined, undefined, undefined, { chunk: generationChunk });
306
516
  }
307
517
  if (options.signal?.aborted === true) {
308
518
  throw new Error('AbortError');
309
519
  }
310
520
  }
311
521
  }
312
- /** @ts-expect-error We are intentionally overriding `getReasoningParams` */
313
- class AzureChatOpenAI extends openai.AzureChatOpenAI {
314
- _lc_stream_delay;
315
- constructor(fields) {
316
- super(fields);
317
- this._lc_stream_delay = fields?._lc_stream_delay;
318
- }
319
- get exposedClient() {
320
- return this.client;
321
- }
322
- static lc_name() {
323
- return 'LibreChatAzureOpenAI';
522
+ class LibreChatOpenAIResponses extends openai.ChatOpenAIResponses {
523
+ _getReasoningParams(options) {
524
+ return getReasoningParams(this.reasoning, options);
324
525
  }
325
- /**
326
- * Returns backwards compatible reasoning parameters from constructor params and call options
327
- * @internal
328
- */
329
- getReasoningParams(options) {
330
- if (!index.isReasoningModel(this.model)) {
331
- return;
332
- }
333
- // apply options in reverse order of importance -- newer options supersede older options
334
- let reasoning;
335
- if (this.reasoning !== undefined) {
336
- reasoning = {
337
- ...reasoning,
338
- ...this.reasoning,
339
- };
340
- }
341
- if (options?.reasoning !== undefined) {
342
- reasoning = {
343
- ...reasoning,
344
- ...options.reasoning,
345
- };
346
- }
347
- return reasoning;
526
+ _getClientOptions(options) {
527
+ return getCustomOpenAIClientOptions(this, options);
348
528
  }
529
+ }
530
+ class LibreChatAzureOpenAICompletions extends openai.AzureChatOpenAICompletions {
349
531
  _getReasoningParams(options) {
350
- return this.getReasoningParams(options);
532
+ return getGatedReasoningParams(this.model, this.reasoning, options);
351
533
  }
352
534
  _getClientOptions(options) {
353
535
  if (!this.client) {
@@ -401,120 +583,22 @@ class AzureChatOpenAI extends openai.AzureChatOpenAI {
401
583
  }
402
584
  return requestOptions;
403
585
  }
404
- async *_streamResponseChunks(messages, options, runManager) {
405
- if (!this._useResponseApi(options)) {
406
- return yield* super._streamResponseChunks(messages, options, runManager);
407
- }
408
- const streamIterable = await this.responseApiWithRetry({
409
- ...this.invocationParams(options, { streaming: true }),
410
- input: index._convertMessagesToOpenAIResponsesParams(messages, this.model, this.zdrEnabled),
411
- stream: true,
412
- }, options);
413
- for await (const data of streamIterable) {
414
- const chunk = index._convertOpenAIResponsesDeltaToBaseMessageChunk(data);
415
- if (chunk == null)
416
- continue;
417
- yield chunk;
418
- if (this._lc_stream_delay != null) {
419
- await run.sleep(this._lc_stream_delay);
420
- }
421
- await runManager?.handleLLMNewToken(chunk.text || '', undefined, undefined, undefined, undefined, { chunk });
422
- }
423
- return;
586
+ async completionWithRetry(request, requestOptions) {
587
+ return completionWithFilteredOpenAIStream(request, requestOptions, super.completionWithRetry.bind(this));
424
588
  }
425
589
  }
426
- class ChatDeepSeek extends deepseek.ChatDeepSeek {
427
- get exposedClient() {
428
- return this.client;
429
- }
430
- static lc_name() {
431
- return 'LibreChatDeepSeek';
432
- }
433
- _convertMessages(messages) {
434
- return index._convertMessagesToOpenAIParams(messages, this.model, {
435
- includeReasoningContent: true,
436
- });
437
- }
438
- async _generate(messages, options, runManager) {
439
- const params = this.invocationParams(options);
440
- if (params.stream === true) {
441
- return super._generate(messages, options ?? {}, runManager);
442
- }
443
- const messagesMapped = this._convertMessages(messages);
444
- const data = await this.completionWithRetry({
445
- ...params,
446
- stream: false,
447
- messages: messagesMapped,
448
- }, {
449
- signal: options?.signal,
450
- ...options?.options,
451
- });
452
- const { completion_tokens, prompt_tokens, total_tokens } = data.usage ?? {};
453
- const generations = [];
454
- for (const part of data.choices ?? []) {
455
- const text = part.message.content ?? '';
456
- const generation = {
457
- text: typeof text === 'string' ? text : '',
458
- message: this._convertResponseToMessage(part, data),
459
- };
460
- generation.generationInfo = {
461
- ...(part.finish_reason != null
462
- ? { finish_reason: part.finish_reason }
463
- : {}),
464
- ...(part.logprobs ? { logprobs: part.logprobs } : {}),
465
- };
466
- generations.push(generation);
467
- }
468
- return {
469
- generations,
470
- llmOutput: {
471
- tokenUsage: {
472
- completionTokens: completion_tokens,
473
- promptTokens: prompt_tokens,
474
- totalTokens: total_tokens,
475
- },
476
- },
477
- };
478
- }
479
- _convertResponseToMessage(choice, data) {
480
- const { message } = choice;
481
- const rawToolCalls = message.tool_calls;
482
- const toolCalls = rawToolCalls?.map((tc) => ({
483
- id: tc.id,
484
- name: tc.function.name,
485
- args: JSON.parse(tc.function.arguments || '{}'),
486
- type: 'tool_call',
487
- }));
488
- const additional_kwargs = {};
489
- if (rawToolCalls) {
490
- additional_kwargs.tool_calls = rawToolCalls;
491
- }
492
- if ('reasoning_content' in message &&
493
- message.reasoning_content != null &&
494
- message.reasoning_content !== '') {
495
- additional_kwargs.reasoning_content = message.reasoning_content;
496
- }
497
- return new messages.AIMessage({
498
- content: message.content ?? '',
499
- tool_calls: toolCalls,
500
- additional_kwargs,
501
- usage_metadata: data.usage
502
- ? {
503
- input_tokens: data.usage.prompt_tokens,
504
- output_tokens: data.usage.completion_tokens,
505
- total_tokens: data.usage.total_tokens,
506
- }
507
- : undefined,
508
- response_metadata: {
509
- model_name: data.model,
510
- system_fingerprint: data.system_fingerprint,
511
- finish_reason: choice.finish_reason,
512
- },
513
- });
590
+ class LibreChatAzureOpenAIResponses extends openai.AzureChatOpenAIResponses {
591
+ _getReasoningParams(options) {
592
+ return getGatedReasoningParams(this.model, this.reasoning, options);
514
593
  }
515
594
  _getClientOptions(options) {
516
595
  if (!this.client) {
517
596
  const openAIEndpointConfig = {
597
+ azureOpenAIApiDeploymentName: this.azureOpenAIApiDeploymentName,
598
+ azureOpenAIApiInstanceName: this.azureOpenAIApiInstanceName,
599
+ azureOpenAIApiKey: this.azureOpenAIApiKey,
600
+ azureOpenAIBasePath: this.azureOpenAIBasePath,
601
+ azureADTokenProvider: this.azureADTokenProvider,
518
602
  baseURL: this.clientConfig.baseURL,
519
603
  };
520
604
  const endpoint = openai.getEndpoint(openAIEndpointConfig);
@@ -524,311 +608,227 @@ class ChatDeepSeek extends deepseek.ChatDeepSeek {
524
608
  timeout: this.timeout,
525
609
  maxRetries: 0,
526
610
  };
611
+ if (!this.azureADTokenProvider) {
612
+ params.apiKey = openAIEndpointConfig.azureOpenAIApiKey;
613
+ }
527
614
  if (params.baseURL == null) {
528
615
  delete params.baseURL;
529
616
  }
530
- this.client = new CustomOpenAIClient(params);
617
+ const defaultHeaders = normalizeHeaders(params.defaultHeaders);
618
+ params.defaultHeaders = {
619
+ ...params.defaultHeaders,
620
+ 'User-Agent': defaultHeaders['User-Agent'] != null
621
+ ? `${defaultHeaders['User-Agent']}: librechat-azure-openai-v2`
622
+ : 'librechat-azure-openai-v2',
623
+ };
624
+ this.client = new CustomAzureOpenAIClient({
625
+ apiVersion: this.azureOpenAIApiVersion,
626
+ azureADTokenProvider: this.azureADTokenProvider,
627
+ ...params,
628
+ });
531
629
  }
532
630
  const requestOptions = {
533
631
  ...this.clientConfig,
534
632
  ...options,
535
633
  };
634
+ if (this.azureOpenAIApiKey != null) {
635
+ requestOptions.headers = {
636
+ 'api-key': this.azureOpenAIApiKey,
637
+ ...requestOptions.headers,
638
+ };
639
+ requestOptions.query = {
640
+ 'api-version': this.azureOpenAIApiVersion,
641
+ ...requestOptions.query,
642
+ };
643
+ }
536
644
  return requestOptions;
537
645
  }
538
- async *_streamResponseChunks(messages$1, options, runManager) {
539
- const messagesMapped = index._convertMessagesToOpenAIParams(messages$1, this.model, {
540
- includeReasoningContent: true,
541
- });
542
- const params = {
543
- ...this.invocationParams(options, {
544
- streaming: true,
545
- }),
546
- messages: messagesMapped,
547
- stream: true,
548
- };
549
- let defaultRole;
550
- const streamIterable = await this.completionWithRetry(params, options);
551
- let usage;
552
- for await (const data of streamIterable) {
553
- const choice = data.choices[0];
554
- if (data.usage) {
555
- usage = data.usage;
556
- }
557
- if (!choice) {
558
- continue;
559
- }
560
- const { delta } = choice;
561
- if (!delta) {
562
- continue;
563
- }
564
- const chunk = this._convertOpenAIDeltaToBaseMessageChunk(delta, data, defaultRole);
565
- if ('reasoning_content' in delta) {
566
- chunk.additional_kwargs.reasoning_content = delta.reasoning_content;
567
- }
568
- defaultRole = delta.role ?? defaultRole;
569
- const newTokenIndices = {
570
- prompt: options.promptIndex ?? 0,
571
- completion: choice.index ?? 0,
646
+ }
647
+ function withLibreChatOpenAIFields(fields) {
648
+ const nextFields = fields ?? {};
649
+ return {
650
+ ...nextFields,
651
+ completions: nextFields.completions ?? new LibreChatOpenAICompletions(nextFields),
652
+ responses: nextFields.responses ?? new LibreChatOpenAIResponses(nextFields),
653
+ };
654
+ }
655
+ class ChatOpenAI extends openai.ChatOpenAI {
656
+ _lc_stream_delay;
657
+ constructor(fields) {
658
+ super(withLibreChatOpenAIFields(fields));
659
+ this._lc_stream_delay = fields?._lc_stream_delay;
660
+ }
661
+ get exposedClient() {
662
+ return getExposedOpenAIClient(this.completions, this.responses, this._useResponsesApi(undefined));
663
+ }
664
+ static lc_name() {
665
+ return 'LibreChatOpenAI';
666
+ }
667
+ _getClientOptions(options) {
668
+ if (!this.client) {
669
+ const openAIEndpointConfig = {
670
+ baseURL: this.clientConfig.baseURL,
572
671
  };
573
- if (typeof chunk.content !== 'string') {
574
- // eslint-disable-next-line no-console
575
- console.log('[WARNING]: Received non-string content from OpenAI. This is currently not supported.');
576
- continue;
672
+ const endpoint = openai.getEndpoint(openAIEndpointConfig);
673
+ const params = {
674
+ ...this.clientConfig,
675
+ baseURL: endpoint,
676
+ timeout: this.timeout,
677
+ maxRetries: 0,
678
+ };
679
+ if (params.baseURL == null) {
680
+ delete params.baseURL;
577
681
  }
578
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
579
- const generationInfo = { ...newTokenIndices };
580
- if (choice.finish_reason != null) {
581
- generationInfo.finish_reason = choice.finish_reason;
582
- generationInfo.system_fingerprint = data.system_fingerprint;
583
- generationInfo.model_name = data.model;
584
- generationInfo.service_tier = data.service_tier;
682
+ this.client = new CustomOpenAIClient(params);
683
+ }
684
+ const requestOptions = {
685
+ ...this.clientConfig,
686
+ ...options,
687
+ };
688
+ return requestOptions;
689
+ }
690
+ /**
691
+ * Returns backwards compatible reasoning parameters from constructor params and call options
692
+ * @internal
693
+ */
694
+ getReasoningParams(options) {
695
+ return getReasoningParams(this.reasoning, options);
696
+ }
697
+ _getReasoningParams(options) {
698
+ return this.getReasoningParams(options);
699
+ }
700
+ async *_streamResponseChunks(messages, options, runManager) {
701
+ yield* delayStreamChunks(super._streamResponseChunks(messages, options, runManager), this._lc_stream_delay);
702
+ }
703
+ }
704
+ class AzureChatOpenAI extends openai.AzureChatOpenAI {
705
+ _lc_stream_delay;
706
+ constructor(fields) {
707
+ super(fields);
708
+ this.completions = new LibreChatAzureOpenAICompletions(fields);
709
+ this.responses = new LibreChatAzureOpenAIResponses(fields);
710
+ this._lc_stream_delay = fields?._lc_stream_delay;
711
+ }
712
+ get exposedClient() {
713
+ return getExposedOpenAIClient(this.completions, this.responses, this._useResponsesApi(undefined));
714
+ }
715
+ static lc_name() {
716
+ return 'LibreChatAzureOpenAI';
717
+ }
718
+ /**
719
+ * Returns backwards compatible reasoning parameters from constructor params and call options
720
+ * @internal
721
+ */
722
+ getReasoningParams(options) {
723
+ return getGatedReasoningParams(this.model, this.reasoning, options);
724
+ }
725
+ _getReasoningParams(options) {
726
+ return this.getReasoningParams(options);
727
+ }
728
+ _getClientOptions(options) {
729
+ if (!this.client) {
730
+ const openAIEndpointConfig = {
731
+ azureOpenAIApiDeploymentName: this.azureOpenAIApiDeploymentName,
732
+ azureOpenAIApiInstanceName: this.azureOpenAIApiInstanceName,
733
+ azureOpenAIApiKey: this.azureOpenAIApiKey,
734
+ azureOpenAIBasePath: this.azureOpenAIBasePath,
735
+ azureADTokenProvider: this.azureADTokenProvider,
736
+ baseURL: this.clientConfig.baseURL,
737
+ };
738
+ const endpoint = openai.getEndpoint(openAIEndpointConfig);
739
+ const params = {
740
+ ...this.clientConfig,
741
+ baseURL: endpoint,
742
+ timeout: this.timeout,
743
+ maxRetries: 0,
744
+ };
745
+ if (!this.azureADTokenProvider) {
746
+ params.apiKey = openAIEndpointConfig.azureOpenAIApiKey;
585
747
  }
586
- if (this.logprobs == true) {
587
- generationInfo.logprobs = choice.logprobs;
748
+ if (params.baseURL == null) {
749
+ delete params.baseURL;
588
750
  }
589
- const generationChunk = new outputs.ChatGenerationChunk({
590
- message: chunk,
591
- text: chunk.content,
592
- generationInfo,
751
+ const defaultHeaders = normalizeHeaders(params.defaultHeaders);
752
+ params.defaultHeaders = {
753
+ ...params.defaultHeaders,
754
+ 'User-Agent': defaultHeaders['User-Agent'] != null
755
+ ? `${defaultHeaders['User-Agent']}: librechat-azure-openai-v2`
756
+ : 'librechat-azure-openai-v2',
757
+ };
758
+ this.client = new CustomAzureOpenAIClient({
759
+ apiVersion: this.azureOpenAIApiVersion,
760
+ azureADTokenProvider: this.azureADTokenProvider,
761
+ ...params,
593
762
  });
594
- yield generationChunk;
595
- await runManager?.handleLLMNewToken(generationChunk.text || '', newTokenIndices, undefined, undefined, undefined, { chunk: generationChunk });
596
763
  }
597
- if (usage) {
598
- const inputTokenDetails = {
599
- ...(usage.prompt_tokens_details?.audio_tokens != null && {
600
- audio: usage.prompt_tokens_details.audio_tokens,
601
- }),
602
- ...(usage.prompt_tokens_details?.cached_tokens != null && {
603
- cache_read: usage.prompt_tokens_details.cached_tokens,
604
- }),
764
+ const requestOptions = {
765
+ ...this.clientConfig,
766
+ ...options,
767
+ };
768
+ if (this.azureOpenAIApiKey != null) {
769
+ requestOptions.headers = {
770
+ 'api-key': this.azureOpenAIApiKey,
771
+ ...requestOptions.headers,
605
772
  };
606
- const outputTokenDetails = {
607
- ...(usage.completion_tokens_details?.audio_tokens != null && {
608
- audio: usage.completion_tokens_details.audio_tokens,
609
- }),
610
- ...(usage.completion_tokens_details?.reasoning_tokens != null && {
611
- reasoning: usage.completion_tokens_details.reasoning_tokens,
612
- }),
773
+ requestOptions.query = {
774
+ 'api-version': this.azureOpenAIApiVersion,
775
+ ...requestOptions.query,
613
776
  };
614
- const generationChunk = new outputs.ChatGenerationChunk({
615
- message: new messages.AIMessageChunk({
616
- content: '',
617
- response_metadata: {
618
- usage: { ...usage },
619
- },
620
- usage_metadata: {
621
- input_tokens: usage.prompt_tokens,
622
- output_tokens: usage.completion_tokens,
623
- total_tokens: usage.total_tokens,
624
- ...(Object.keys(inputTokenDetails).length > 0 && {
625
- input_token_details: inputTokenDetails,
626
- }),
627
- ...(Object.keys(outputTokenDetails).length > 0 && {
628
- output_token_details: outputTokenDetails,
629
- }),
630
- },
631
- }),
632
- text: '',
633
- });
634
- yield generationChunk;
635
- }
636
- if (options.signal?.aborted === true) {
637
- throw new Error('AbortError');
638
777
  }
778
+ return requestOptions;
779
+ }
780
+ async *_streamResponseChunks(messages, options, runManager) {
781
+ yield* delayStreamChunks(super._streamResponseChunks(messages, options, runManager), this._lc_stream_delay);
639
782
  }
640
783
  }
641
- class ChatMoonshot extends ChatOpenAI {
642
- static lc_name() {
643
- return 'LibreChatMoonshot';
784
+ class ChatDeepSeek extends deepseek.ChatDeepSeek {
785
+ _lc_stream_delay;
786
+ constructor(fields) {
787
+ super(fields);
788
+ this._lc_stream_delay = fields?._lc_stream_delay;
644
789
  }
645
- _convertMessages(messages) {
646
- return index._convertMessagesToOpenAIParams(messages, this.model, {
647
- includeReasoningContent: true,
648
- });
790
+ get exposedClient() {
791
+ return this.client;
649
792
  }
650
- async _generate(messages, options, runManager) {
651
- const params = this.invocationParams(options);
652
- if (params.stream === true) {
653
- return super._generate(messages, options, runManager);
654
- }
655
- const messagesMapped = this._convertMessages(messages);
656
- const data = await this.completionWithRetry({
657
- ...params,
658
- stream: false,
659
- messages: messagesMapped,
660
- }, {
661
- signal: options.signal,
662
- ...options.options,
663
- });
664
- const { completion_tokens, prompt_tokens, total_tokens } = data.usage ?? {};
665
- const generations = [];
666
- for (const part of data.choices ?? []) {
667
- const text = part.message.content ?? '';
668
- const generation = {
669
- text: typeof text === 'string' ? text : '',
670
- message: this._convertResponseToMessage(part, data),
793
+ static lc_name() {
794
+ return 'LibreChatDeepSeek';
795
+ }
796
+ _getClientOptions(options) {
797
+ if (!this.client) {
798
+ const openAIEndpointConfig = {
799
+ baseURL: this.clientConfig.baseURL,
671
800
  };
672
- generation.generationInfo = {
673
- ...(part.finish_reason ? { finish_reason: part.finish_reason } : {}),
674
- ...(part.logprobs ? { logprobs: part.logprobs } : {}),
801
+ const endpoint = openai.getEndpoint(openAIEndpointConfig);
802
+ const params = {
803
+ ...this.clientConfig,
804
+ baseURL: endpoint,
805
+ timeout: this.timeout,
806
+ maxRetries: 0,
675
807
  };
676
- generations.push(generation);
808
+ if (params.baseURL == null) {
809
+ delete params.baseURL;
810
+ }
811
+ this.client = new CustomOpenAIClient(params);
677
812
  }
678
- return {
679
- generations,
680
- llmOutput: {
681
- tokenUsage: {
682
- completionTokens: completion_tokens,
683
- promptTokens: prompt_tokens,
684
- totalTokens: total_tokens,
685
- },
686
- },
813
+ const requestOptions = {
814
+ ...this.clientConfig,
815
+ ...options,
687
816
  };
817
+ return requestOptions;
688
818
  }
689
- _convertResponseToMessage(choice, data) {
690
- const { message } = choice;
691
- const rawToolCalls = message.tool_calls;
692
- const toolCalls = rawToolCalls?.map((tc) => ({
693
- id: tc.id,
694
- name: tc.function.name,
695
- args: JSON.parse(tc.function.arguments || '{}'),
696
- type: 'tool_call',
697
- }));
698
- const additional_kwargs = {};
699
- if (rawToolCalls) {
700
- additional_kwargs.tool_calls = rawToolCalls;
701
- }
702
- if ('reasoning_content' in message &&
703
- message.reasoning_content != null &&
704
- message.reasoning_content !== '') {
705
- additional_kwargs.reasoning_content = message.reasoning_content;
706
- }
707
- return new messages.AIMessage({
708
- content: message.content ?? '',
709
- tool_calls: toolCalls,
710
- additional_kwargs,
711
- usage_metadata: data.usage
712
- ? {
713
- input_tokens: data.usage.prompt_tokens,
714
- output_tokens: data.usage.completion_tokens,
715
- total_tokens: data.usage.total_tokens,
716
- }
717
- : undefined,
718
- response_metadata: {
719
- model_name: data.model,
720
- system_fingerprint: data.system_fingerprint,
721
- finish_reason: choice.finish_reason,
722
- },
723
- });
819
+ async *_streamResponseChunks(messages, options, runManager) {
820
+ yield* delayStreamChunks(super._streamResponseChunks(messages, options, runManager), this._lc_stream_delay);
724
821
  }
725
- async *_streamResponseChunks(messages$1, options, runManager) {
726
- const messagesMapped = index._convertMessagesToOpenAIParams(messages$1, this.model, {
822
+ }
823
+ class ChatMoonshot extends ChatOpenAI {
824
+ constructor(fields) {
825
+ super({
826
+ ...fields,
727
827
  includeReasoningContent: true,
728
828
  });
729
- const params = {
730
- ...this.invocationParams(options, {
731
- streaming: true,
732
- }),
733
- messages: messagesMapped,
734
- stream: true,
735
- };
736
- let defaultRole;
737
- const streamIterable = await this.completionWithRetry(params, options);
738
- let usage;
739
- for await (const data of streamIterable) {
740
- const choice = data.choices[0];
741
- if (data.usage) {
742
- usage = data.usage;
743
- }
744
- if (!choice) {
745
- continue;
746
- }
747
- const { delta } = choice;
748
- if (!delta) {
749
- continue;
750
- }
751
- const chunk = this._convertOpenAIDeltaToBaseMessageChunk(delta, data, defaultRole);
752
- if ('reasoning_content' in delta) {
753
- chunk.additional_kwargs.reasoning_content = delta.reasoning_content;
754
- }
755
- defaultRole = delta.role ?? defaultRole;
756
- const newTokenIndices = {
757
- prompt: options.promptIndex ?? 0,
758
- completion: choice.index ?? 0,
759
- };
760
- if (typeof chunk.content !== 'string') {
761
- // eslint-disable-next-line no-console
762
- console.log('[WARNING]: Received non-string content from OpenAI. This is currently not supported.');
763
- continue;
764
- }
765
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
766
- const generationInfo = { ...newTokenIndices };
767
- if (choice.finish_reason != null) {
768
- generationInfo.finish_reason = choice.finish_reason;
769
- generationInfo.system_fingerprint = data.system_fingerprint;
770
- generationInfo.model_name = data.model;
771
- generationInfo.service_tier = data.service_tier;
772
- }
773
- if (this.logprobs == true) {
774
- generationInfo.logprobs = choice.logprobs;
775
- }
776
- const generationChunk = new outputs.ChatGenerationChunk({
777
- message: chunk,
778
- text: chunk.content,
779
- generationInfo,
780
- });
781
- yield generationChunk;
782
- if (this._lc_stream_delay != null) {
783
- await run.sleep(this._lc_stream_delay);
784
- }
785
- await runManager?.handleLLMNewToken(generationChunk.text || '', newTokenIndices, undefined, undefined, undefined, { chunk: generationChunk });
786
- }
787
- if (usage) {
788
- const inputTokenDetails = {
789
- ...(usage.prompt_tokens_details?.audio_tokens != null && {
790
- audio: usage.prompt_tokens_details.audio_tokens,
791
- }),
792
- ...(usage.prompt_tokens_details?.cached_tokens != null && {
793
- cache_read: usage.prompt_tokens_details.cached_tokens,
794
- }),
795
- };
796
- const outputTokenDetails = {
797
- ...(usage.completion_tokens_details?.audio_tokens != null && {
798
- audio: usage.completion_tokens_details.audio_tokens,
799
- }),
800
- ...(usage.completion_tokens_details?.reasoning_tokens != null && {
801
- reasoning: usage.completion_tokens_details.reasoning_tokens,
802
- }),
803
- };
804
- const generationChunk = new outputs.ChatGenerationChunk({
805
- message: new messages.AIMessageChunk({
806
- content: '',
807
- response_metadata: {
808
- usage: { ...usage },
809
- },
810
- usage_metadata: {
811
- input_tokens: usage.prompt_tokens,
812
- output_tokens: usage.completion_tokens,
813
- total_tokens: usage.total_tokens,
814
- ...(Object.keys(inputTokenDetails).length > 0 && {
815
- input_token_details: inputTokenDetails,
816
- }),
817
- ...(Object.keys(outputTokenDetails).length > 0 && {
818
- output_token_details: outputTokenDetails,
819
- }),
820
- },
821
- }),
822
- text: '',
823
- });
824
- yield generationChunk;
825
- if (this._lc_stream_delay != null) {
826
- await run.sleep(this._lc_stream_delay);
827
- }
828
- }
829
- if (options.signal?.aborted === true) {
830
- throw new Error('AbortError');
831
- }
829
+ }
830
+ static lc_name() {
831
+ return 'LibreChatMoonshot';
832
832
  }
833
833
  }
834
834
  class ChatXAI extends xai.ChatXAI {
@@ -876,144 +876,8 @@ class ChatXAI extends xai.ChatXAI {
876
876
  };
877
877
  return requestOptions;
878
878
  }
879
- async *_streamResponseChunks(messages$1, options, runManager) {
880
- const messagesMapped = index._convertMessagesToOpenAIParams(messages$1, this.model);
881
- const params = {
882
- ...this.invocationParams(options, {
883
- streaming: true,
884
- }),
885
- messages: messagesMapped,
886
- stream: true,
887
- };
888
- let defaultRole;
889
- const streamIterable = await this.completionWithRetry(params, options);
890
- let usage;
891
- for await (const data of streamIterable) {
892
- const choice = data.choices[0];
893
- if (data.usage) {
894
- usage = data.usage;
895
- }
896
- if (!choice) {
897
- continue;
898
- }
899
- const { delta } = choice;
900
- if (!delta) {
901
- continue;
902
- }
903
- const chunk = this._convertOpenAIDeltaToBaseMessageChunk(delta, data, defaultRole);
904
- if (chunk.usage_metadata != null) {
905
- chunk.usage_metadata = {
906
- input_tokens: chunk.usage_metadata.input_tokens ?? 0,
907
- output_tokens: chunk.usage_metadata.output_tokens ?? 0,
908
- total_tokens: chunk.usage_metadata.total_tokens ?? 0,
909
- };
910
- }
911
- if ('reasoning_content' in delta) {
912
- chunk.additional_kwargs.reasoning_content = delta.reasoning_content;
913
- }
914
- defaultRole = delta.role ?? defaultRole;
915
- const newTokenIndices = {
916
- prompt: options.promptIndex ?? 0,
917
- completion: choice.index ?? 0,
918
- };
919
- if (typeof chunk.content !== 'string') {
920
- // eslint-disable-next-line no-console
921
- console.log('[WARNING]: Received non-string content from OpenAI. This is currently not supported.');
922
- continue;
923
- }
924
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
925
- const generationInfo = { ...newTokenIndices };
926
- if (choice.finish_reason != null) {
927
- generationInfo.finish_reason = choice.finish_reason;
928
- // Only include system fingerprint in the last chunk for now
929
- // to avoid concatenation issues
930
- generationInfo.system_fingerprint = data.system_fingerprint;
931
- generationInfo.model_name = data.model;
932
- generationInfo.service_tier = data.service_tier;
933
- }
934
- if (this.logprobs == true) {
935
- generationInfo.logprobs = choice.logprobs;
936
- }
937
- const generationChunk = new outputs.ChatGenerationChunk({
938
- message: chunk,
939
- text: chunk.content,
940
- generationInfo,
941
- });
942
- yield generationChunk;
943
- if (this._lc_stream_delay != null) {
944
- await run.sleep(this._lc_stream_delay);
945
- }
946
- await runManager?.handleLLMNewToken(generationChunk.text || '', newTokenIndices, undefined, undefined, undefined, { chunk: generationChunk });
947
- }
948
- if (usage) {
949
- // Type assertion for xAI-specific usage structure
950
- const xaiUsage = usage;
951
- const inputTokenDetails = {
952
- // Standard OpenAI fields
953
- ...(usage.prompt_tokens_details?.audio_tokens != null && {
954
- audio: usage.prompt_tokens_details.audio_tokens,
955
- }),
956
- ...(usage.prompt_tokens_details?.cached_tokens != null && {
957
- cache_read: usage.prompt_tokens_details.cached_tokens,
958
- }),
959
- // Add xAI-specific prompt token details if they exist
960
- ...(xaiUsage.prompt_tokens_details?.text_tokens != null && {
961
- text: xaiUsage.prompt_tokens_details.text_tokens,
962
- }),
963
- ...(xaiUsage.prompt_tokens_details?.image_tokens != null && {
964
- image: xaiUsage.prompt_tokens_details.image_tokens,
965
- }),
966
- };
967
- const outputTokenDetails = {
968
- // Standard OpenAI fields
969
- ...(usage.completion_tokens_details?.audio_tokens != null && {
970
- audio: usage.completion_tokens_details.audio_tokens,
971
- }),
972
- ...(usage.completion_tokens_details?.reasoning_tokens != null && {
973
- reasoning: usage.completion_tokens_details.reasoning_tokens,
974
- }),
975
- // Add xAI-specific completion token details if they exist
976
- ...(xaiUsage.completion_tokens_details?.accepted_prediction_tokens !=
977
- null && {
978
- accepted_prediction: xaiUsage.completion_tokens_details.accepted_prediction_tokens,
979
- }),
980
- ...(xaiUsage.completion_tokens_details?.rejected_prediction_tokens !=
981
- null && {
982
- rejected_prediction: xaiUsage.completion_tokens_details.rejected_prediction_tokens,
983
- }),
984
- };
985
- const generationChunk = new outputs.ChatGenerationChunk({
986
- message: new messages.AIMessageChunk({
987
- content: '',
988
- response_metadata: {
989
- usage: { ...usage },
990
- // Include xAI-specific metadata if it exists
991
- ...(xaiUsage.num_sources_used != null && {
992
- num_sources_used: xaiUsage.num_sources_used,
993
- }),
994
- },
995
- usage_metadata: {
996
- input_tokens: usage.prompt_tokens,
997
- output_tokens: usage.completion_tokens,
998
- total_tokens: usage.total_tokens,
999
- ...(Object.keys(inputTokenDetails).length > 0 && {
1000
- input_token_details: inputTokenDetails,
1001
- }),
1002
- ...(Object.keys(outputTokenDetails).length > 0 && {
1003
- output_token_details: outputTokenDetails,
1004
- }),
1005
- },
1006
- }),
1007
- text: '',
1008
- });
1009
- yield generationChunk;
1010
- if (this._lc_stream_delay != null) {
1011
- await run.sleep(this._lc_stream_delay);
1012
- }
1013
- }
1014
- if (options.signal?.aborted === true) {
1015
- throw new Error('AbortError');
1016
- }
879
+ async *_streamResponseChunks(messages, options, runManager) {
880
+ yield* delayStreamChunks(super._streamResponseChunks(messages, options, runManager), this._lc_stream_delay);
1017
881
  }
1018
882
  }
1019
883