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