@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
@@ -53,6 +53,116 @@ 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 attachLibreChatDeltaFields(chunk, delta) {
99
+ if (!messages.AIMessageChunk.isInstance(chunk)) {
100
+ return chunk;
101
+ }
102
+ const libreChatDelta = delta;
103
+ if (libreChatDelta.reasoning != null &&
104
+ chunk.additional_kwargs.reasoning_content == null) {
105
+ chunk.additional_kwargs.reasoning_content = libreChatDelta.reasoning;
106
+ }
107
+ if (libreChatDelta.reasoning_details != null) {
108
+ chunk.additional_kwargs.reasoning_details =
109
+ libreChatDelta.reasoning_details;
110
+ }
111
+ if (libreChatDelta.provider_specific_fields != null) {
112
+ chunk.additional_kwargs.provider_specific_fields =
113
+ libreChatDelta.provider_specific_fields;
114
+ }
115
+ return chunk;
116
+ }
117
+ function attachLibreChatMessageFields(message, rawMessage) {
118
+ if (!messages.isAIMessage(message)) {
119
+ return message;
120
+ }
121
+ if (rawMessage.reasoning != null &&
122
+ message.additional_kwargs.reasoning_content == null) {
123
+ message.additional_kwargs.reasoning_content = rawMessage.reasoning;
124
+ }
125
+ if (rawMessage.reasoning_details != null) {
126
+ message.additional_kwargs.reasoning_details = rawMessage.reasoning_details;
127
+ }
128
+ if (rawMessage.provider_specific_fields != null) {
129
+ message.additional_kwargs.provider_specific_fields =
130
+ rawMessage.provider_specific_fields;
131
+ }
132
+ return message;
133
+ }
134
+ function getCustomOpenAIClientOptions(owner, options) {
135
+ if (!owner.client) {
136
+ const openAIEndpointConfig = {
137
+ baseURL: owner.clientConfig.baseURL,
138
+ };
139
+ const endpoint = openai.getEndpoint(openAIEndpointConfig);
140
+ const params = {
141
+ ...owner.clientConfig,
142
+ baseURL: endpoint,
143
+ timeout: owner.timeout,
144
+ maxRetries: 0,
145
+ };
146
+ if (params.baseURL == null) {
147
+ delete params.baseURL;
148
+ }
149
+ params.defaultHeaders = openai.getHeadersWithUserAgent(params.defaultHeaders);
150
+ owner.client = new CustomOpenAIClient(params);
151
+ }
152
+ const requestOptions = {
153
+ ...owner.clientConfig,
154
+ ...options,
155
+ };
156
+ return requestOptions;
157
+ }
158
+ async function* delayStreamChunks(chunks, delay) {
159
+ for await (const chunk of chunks) {
160
+ yield chunk;
161
+ if (delay != null) {
162
+ await run.sleep(delay);
163
+ }
164
+ }
165
+ }
56
166
  function createAbortHandler(controller) {
57
167
  return function () {
58
168
  controller.abort();
@@ -112,89 +222,162 @@ class CustomAzureOpenAIClient extends openai$1.AzureOpenAI {
112
222
  }));
113
223
  }
114
224
  }
115
- /** @ts-expect-error We are intentionally overriding `getReasoningParams` */
116
- class ChatOpenAI extends openai.ChatOpenAI {
117
- _lc_stream_delay;
225
+ class LibreChatOpenAICompletions extends openai.ChatOpenAICompletions {
226
+ includeReasoningContent;
227
+ includeReasoningDetails;
228
+ convertReasoningDetailsToContent;
118
229
  constructor(fields) {
119
230
  super(fields);
120
- this._lc_stream_delay = fields?._lc_stream_delay;
121
- }
122
- get exposedClient() {
123
- return this.client;
231
+ this.includeReasoningContent = fields?.includeReasoningContent;
232
+ this.includeReasoningDetails = fields?.includeReasoningDetails;
233
+ this.convertReasoningDetailsToContent =
234
+ fields?.convertReasoningDetailsToContent;
124
235
  }
125
- static lc_name() {
126
- return 'LibreChatOpenAI';
236
+ _getReasoningParams(options) {
237
+ return getReasoningParams(this.reasoning, options);
127
238
  }
128
239
  _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;
240
+ return getCustomOpenAIClientOptions(this, options);
150
241
  }
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,
242
+ _convertCompletionsDeltaToBaseMessageChunk(delta, rawResponse, defaultRole) {
243
+ return attachLibreChatDeltaFields(super._convertCompletionsDeltaToBaseMessageChunk(delta, rawResponse, defaultRole), delta);
244
+ }
245
+ _convertCompletionsMessageToBaseMessage(message, rawResponse) {
246
+ return attachLibreChatMessageFields(super._convertCompletionsMessageToBaseMessage(message, rawResponse), message);
247
+ }
248
+ async _generate(messages$1, options, runManager) {
249
+ if (this.includeReasoningContent !== true &&
250
+ this.includeReasoningDetails !== true) {
251
+ return super._generate(messages$1, options, runManager);
252
+ }
253
+ options.signal?.throwIfAborted();
254
+ const usageMetadata = {};
255
+ const params = this.invocationParams(options);
256
+ const messagesMapped = index._convertMessagesToOpenAIParams(messages$1, this.model, {
257
+ includeReasoningContent: this.includeReasoningContent,
258
+ includeReasoningDetails: this.includeReasoningDetails,
259
+ convertReasoningDetailsToContent: this.convertReasoningDetailsToContent,
260
+ });
261
+ if (params.stream === true) {
262
+ const stream = this._streamResponseChunks(messages$1, options, runManager);
263
+ const finalChunks = new Map();
264
+ for await (const chunk of stream) {
265
+ chunk.message.response_metadata = {
266
+ ...chunk.generationInfo,
267
+ ...chunk.message.response_metadata,
268
+ };
269
+ const index = typeof chunk.generationInfo?.completion === 'number'
270
+ ? chunk.generationInfo.completion
271
+ : 0;
272
+ const existingChunk = finalChunks.get(index);
273
+ if (existingChunk == null) {
274
+ finalChunks.set(index, chunk);
275
+ }
276
+ else {
277
+ finalChunks.set(index, existingChunk.concat(chunk));
278
+ }
279
+ }
280
+ const generations = Array.from(finalChunks.entries())
281
+ .sort(([aKey], [bKey]) => aKey - bKey)
282
+ .map(([, value]) => value);
283
+ const { functions, function_call } = this.invocationParams(options);
284
+ const promptTokenUsage = await this._getEstimatedTokenCountFromPrompt(messages$1, functions, function_call);
285
+ const completionTokenUsage = await this._getNumTokensFromGenerations(generations);
286
+ usageMetadata.input_tokens = promptTokenUsage;
287
+ usageMetadata.output_tokens = completionTokenUsage;
288
+ usageMetadata.total_tokens = promptTokenUsage + completionTokenUsage;
289
+ return {
290
+ generations,
291
+ llmOutput: {
292
+ estimatedTokenUsage: {
293
+ promptTokens: usageMetadata.input_tokens,
294
+ completionTokens: usageMetadata.output_tokens,
295
+ totalTokens: usageMetadata.total_tokens,
296
+ },
297
+ },
162
298
  };
163
299
  }
164
- if (options?.reasoning !== undefined) {
165
- reasoning = {
166
- ...reasoning,
167
- ...options.reasoning,
300
+ const data = await this.completionWithRetry({
301
+ ...params,
302
+ stream: false,
303
+ messages: messagesMapped,
304
+ }, {
305
+ signal: options.signal,
306
+ ...options.options,
307
+ });
308
+ const { completion_tokens: completionTokens, prompt_tokens: promptTokens, total_tokens: totalTokens, prompt_tokens_details: promptTokensDetails, completion_tokens_details: completionTokensDetails, } = data.usage ?? {};
309
+ if (completionTokens != null) {
310
+ usageMetadata.output_tokens =
311
+ (usageMetadata.output_tokens ?? 0) + completionTokens;
312
+ }
313
+ if (promptTokens != null) {
314
+ usageMetadata.input_tokens =
315
+ (usageMetadata.input_tokens ?? 0) + promptTokens;
316
+ }
317
+ if (totalTokens != null) {
318
+ usageMetadata.total_tokens =
319
+ (usageMetadata.total_tokens ?? 0) + totalTokens;
320
+ }
321
+ if (promptTokensDetails?.audio_tokens != null ||
322
+ promptTokensDetails?.cached_tokens != null) {
323
+ usageMetadata.input_token_details = {
324
+ ...(promptTokensDetails.audio_tokens != null && {
325
+ audio: promptTokensDetails.audio_tokens,
326
+ }),
327
+ ...(promptTokensDetails.cached_tokens != null && {
328
+ cache_read: promptTokensDetails.cached_tokens,
329
+ }),
168
330
  };
169
331
  }
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);
332
+ if (completionTokensDetails?.audio_tokens != null ||
333
+ completionTokensDetails?.reasoning_tokens != null) {
334
+ usageMetadata.output_token_details = {
335
+ ...(completionTokensDetails.audio_tokens != null && {
336
+ audio: completionTokensDetails.audio_tokens,
337
+ }),
338
+ ...(completionTokensDetails.reasoning_tokens != null && {
339
+ reasoning: completionTokensDetails.reasoning_tokens,
340
+ }),
341
+ };
178
342
  }
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);
343
+ const generations = [];
344
+ for (const part of data.choices) {
345
+ const generation = {
346
+ text: part.message.content ?? '',
347
+ message: this._convertCompletionsMessageToBaseMessage(part.message, data),
348
+ };
349
+ generation.generationInfo = {
350
+ finish_reason: part.finish_reason,
351
+ ...(part.logprobs ? { logprobs: part.logprobs } : {}),
352
+ };
353
+ if (messages.isAIMessage(generation.message)) {
354
+ generation.message.usage_metadata = usageMetadata;
191
355
  }
192
- await runManager?.handleLLMNewToken(chunk.text || '', undefined, undefined, undefined, undefined, { chunk });
356
+ generation.message = new messages.AIMessage(Object.fromEntries(Object.entries(generation.message).filter(([key]) => !key.startsWith('lc_'))));
357
+ generations.push(generation);
193
358
  }
194
- return;
359
+ return {
360
+ generations,
361
+ llmOutput: {
362
+ tokenUsage: {
363
+ promptTokens: usageMetadata.input_tokens,
364
+ completionTokens: usageMetadata.output_tokens,
365
+ totalTokens: usageMetadata.total_tokens,
366
+ },
367
+ },
368
+ };
195
369
  }
196
- async *_streamResponseChunks2(messages$1, options, runManager) {
197
- const messagesMapped = index._convertMessagesToOpenAIParams(messages$1, this.model);
370
+ async *_streamResponseChunks(messages$1, options, runManager) {
371
+ if (this.includeReasoningContent !== true &&
372
+ this.includeReasoningDetails !== true) {
373
+ yield* super._streamResponseChunks(messages$1, options, runManager);
374
+ return;
375
+ }
376
+ const messagesMapped = index._convertMessagesToOpenAIParams(messages$1, this.model, {
377
+ includeReasoningContent: this.includeReasoningContent,
378
+ includeReasoningDetails: this.includeReasoningDetails,
379
+ convertReasoningDetailsToContent: this.convertReasoningDetailsToContent,
380
+ });
198
381
  const params = {
199
382
  ...this.invocationParams(options, {
200
383
  streaming: true,
@@ -206,49 +389,40 @@ class ChatOpenAI extends openai.ChatOpenAI {
206
389
  const streamIterable = await this.completionWithRetry(params, options);
207
390
  let usage;
208
391
  for await (const data of streamIterable) {
209
- const choice = data.choices[0];
210
- if (data.usage) {
392
+ if (options.signal?.aborted === true) {
393
+ return;
394
+ }
395
+ const choices = data.choices;
396
+ const choice = choices?.[0];
397
+ if (data.usage != null) {
211
398
  usage = data.usage;
212
399
  }
213
- if (!choice) {
400
+ if (choice == null) {
214
401
  continue;
215
402
  }
216
403
  const { delta } = choice;
217
- if (!delta) {
404
+ if (delta == null) {
218
405
  continue;
219
406
  }
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
- }
407
+ const chunk = this._convertCompletionsDeltaToBaseMessageChunk(delta, data, defaultRole);
231
408
  defaultRole = delta.role ?? defaultRole;
232
409
  const newTokenIndices = {
233
410
  prompt: options.promptIndex ?? 0,
234
- completion: choice.index ?? 0,
411
+ completion: choice.index,
235
412
  };
236
413
  if (typeof chunk.content !== 'string') {
237
414
  // eslint-disable-next-line no-console
238
415
  console.log('[WARNING]: Received non-string content from OpenAI. This is currently not supported.');
239
416
  continue;
240
417
  }
241
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
242
418
  const generationInfo = { ...newTokenIndices };
243
419
  if (choice.finish_reason != null) {
244
420
  generationInfo.finish_reason = choice.finish_reason;
245
- // Only include system fingerprint in the last chunk for now
246
- // to avoid concatenation issues
247
421
  generationInfo.system_fingerprint = data.system_fingerprint;
248
422
  generationInfo.model_name = data.model;
249
423
  generationInfo.service_tier = data.service_tier;
250
424
  }
251
- if (this.logprobs == true) {
425
+ if (this.logprobs === true) {
252
426
  generationInfo.logprobs = choice.logprobs;
253
427
  }
254
428
  const generationChunk = new outputs.ChatGenerationChunk({
@@ -257,10 +431,7 @@ class ChatOpenAI extends openai.ChatOpenAI {
257
431
  generationInfo,
258
432
  });
259
433
  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 });
434
+ await runManager?.handleLLMNewToken(generationChunk.text, newTokenIndices, undefined, undefined, undefined, { chunk: generationChunk });
264
435
  }
265
436
  if (usage) {
266
437
  const inputTokenDetails = {
@@ -282,9 +453,7 @@ class ChatOpenAI extends openai.ChatOpenAI {
282
453
  const generationChunk = new outputs.ChatGenerationChunk({
283
454
  message: new messages.AIMessageChunk({
284
455
  content: '',
285
- response_metadata: {
286
- usage: { ...usage },
287
- },
456
+ response_metadata: { usage: { ...usage } },
288
457
  usage_metadata: {
289
458
  input_tokens: usage.prompt_tokens,
290
459
  output_tokens: usage.completion_tokens,
@@ -300,54 +469,84 @@ class ChatOpenAI extends openai.ChatOpenAI {
300
469
  text: '',
301
470
  });
302
471
  yield generationChunk;
303
- if (this._lc_stream_delay != null) {
304
- await run.sleep(this._lc_stream_delay);
305
- }
472
+ await runManager?.handleLLMNewToken(generationChunk.text, {
473
+ prompt: 0,
474
+ completion: 0,
475
+ }, undefined, undefined, undefined, { chunk: generationChunk });
306
476
  }
307
477
  if (options.signal?.aborted === true) {
308
478
  throw new Error('AbortError');
309
479
  }
310
480
  }
311
481
  }
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;
482
+ class LibreChatOpenAIResponses extends openai.ChatOpenAIResponses {
483
+ _getReasoningParams(options) {
484
+ return getReasoningParams(this.reasoning, options);
318
485
  }
319
- get exposedClient() {
320
- return this.client;
486
+ _getClientOptions(options) {
487
+ return getCustomOpenAIClientOptions(this, options);
321
488
  }
322
- static lc_name() {
323
- return 'LibreChatAzureOpenAI';
489
+ }
490
+ class LibreChatAzureOpenAICompletions extends openai.AzureChatOpenAICompletions {
491
+ _getReasoningParams(options) {
492
+ return getGatedReasoningParams(this.model, this.reasoning, options);
324
493
  }
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,
494
+ _getClientOptions(options) {
495
+ if (!this.client) {
496
+ const openAIEndpointConfig = {
497
+ azureOpenAIApiDeploymentName: this.azureOpenAIApiDeploymentName,
498
+ azureOpenAIApiInstanceName: this.azureOpenAIApiInstanceName,
499
+ azureOpenAIApiKey: this.azureOpenAIApiKey,
500
+ azureOpenAIBasePath: this.azureOpenAIBasePath,
501
+ azureADTokenProvider: this.azureADTokenProvider,
502
+ baseURL: this.clientConfig.baseURL,
503
+ };
504
+ const endpoint = openai.getEndpoint(openAIEndpointConfig);
505
+ const params = {
506
+ ...this.clientConfig,
507
+ baseURL: endpoint,
508
+ timeout: this.timeout,
509
+ maxRetries: 0,
510
+ };
511
+ if (!this.azureADTokenProvider) {
512
+ params.apiKey = openAIEndpointConfig.azureOpenAIApiKey;
513
+ }
514
+ if (params.baseURL == null) {
515
+ delete params.baseURL;
516
+ }
517
+ const defaultHeaders = normalizeHeaders(params.defaultHeaders);
518
+ params.defaultHeaders = {
519
+ ...params.defaultHeaders,
520
+ 'User-Agent': defaultHeaders['User-Agent'] != null
521
+ ? `${defaultHeaders['User-Agent']}: librechat-azure-openai-v2`
522
+ : 'librechat-azure-openai-v2',
339
523
  };
524
+ this.client = new CustomAzureOpenAIClient({
525
+ apiVersion: this.azureOpenAIApiVersion,
526
+ azureADTokenProvider: this.azureADTokenProvider,
527
+ ...params,
528
+ });
340
529
  }
341
- if (options?.reasoning !== undefined) {
342
- reasoning = {
343
- ...reasoning,
344
- ...options.reasoning,
530
+ const requestOptions = {
531
+ ...this.clientConfig,
532
+ ...options,
533
+ };
534
+ if (this.azureOpenAIApiKey != null) {
535
+ requestOptions.headers = {
536
+ 'api-key': this.azureOpenAIApiKey,
537
+ ...requestOptions.headers,
538
+ };
539
+ requestOptions.query = {
540
+ 'api-version': this.azureOpenAIApiVersion,
541
+ ...requestOptions.query,
345
542
  };
346
543
  }
347
- return reasoning;
544
+ return requestOptions;
348
545
  }
546
+ }
547
+ class LibreChatAzureOpenAIResponses extends openai.AzureChatOpenAIResponses {
349
548
  _getReasoningParams(options) {
350
- return this.getReasoningParams(options);
549
+ return getGatedReasoningParams(this.model, this.reasoning, options);
351
550
  }
352
551
  _getClientOptions(options) {
353
552
  if (!this.client) {
@@ -401,116 +600,26 @@ class AzureChatOpenAI extends openai.AzureChatOpenAI {
401
600
  }
402
601
  return requestOptions;
403
602
  }
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;
424
- }
425
603
  }
426
- class ChatDeepSeek extends deepseek.ChatDeepSeek {
604
+ function withLibreChatOpenAIFields(fields) {
605
+ const nextFields = fields ?? {};
606
+ return {
607
+ ...nextFields,
608
+ completions: nextFields.completions ?? new LibreChatOpenAICompletions(nextFields),
609
+ responses: nextFields.responses ?? new LibreChatOpenAIResponses(nextFields),
610
+ };
611
+ }
612
+ class ChatOpenAI extends openai.ChatOpenAI {
613
+ _lc_stream_delay;
614
+ constructor(fields) {
615
+ super(withLibreChatOpenAIFields(fields));
616
+ this._lc_stream_delay = fields?._lc_stream_delay;
617
+ }
427
618
  get exposedClient() {
428
- return this.client;
619
+ return getExposedOpenAIClient(this.completions, this.responses, this._useResponsesApi(undefined));
429
620
  }
430
621
  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
- });
622
+ return 'LibreChatOpenAI';
514
623
  }
515
624
  _getClientOptions(options) {
516
625
  if (!this.client) {
@@ -535,300 +644,148 @@ class ChatDeepSeek extends deepseek.ChatDeepSeek {
535
644
  };
536
645
  return requestOptions;
537
646
  }
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,
647
+ /**
648
+ * Returns backwards compatible reasoning parameters from constructor params and call options
649
+ * @internal
650
+ */
651
+ getReasoningParams(options) {
652
+ return getReasoningParams(this.reasoning, options);
653
+ }
654
+ _getReasoningParams(options) {
655
+ return this.getReasoningParams(options);
656
+ }
657
+ async *_streamResponseChunks(messages, options, runManager) {
658
+ yield* delayStreamChunks(super._streamResponseChunks(messages, options, runManager), this._lc_stream_delay);
659
+ }
660
+ }
661
+ class AzureChatOpenAI extends openai.AzureChatOpenAI {
662
+ _lc_stream_delay;
663
+ constructor(fields) {
664
+ super(fields);
665
+ this.completions = new LibreChatAzureOpenAICompletions(fields);
666
+ this.responses = new LibreChatAzureOpenAIResponses(fields);
667
+ this._lc_stream_delay = fields?._lc_stream_delay;
668
+ }
669
+ get exposedClient() {
670
+ return getExposedOpenAIClient(this.completions, this.responses, this._useResponsesApi(undefined));
671
+ }
672
+ static lc_name() {
673
+ return 'LibreChatAzureOpenAI';
674
+ }
675
+ /**
676
+ * Returns backwards compatible reasoning parameters from constructor params and call options
677
+ * @internal
678
+ */
679
+ getReasoningParams(options) {
680
+ return getGatedReasoningParams(this.model, this.reasoning, options);
681
+ }
682
+ _getReasoningParams(options) {
683
+ return this.getReasoningParams(options);
684
+ }
685
+ _getClientOptions(options) {
686
+ if (!this.client) {
687
+ const openAIEndpointConfig = {
688
+ azureOpenAIApiDeploymentName: this.azureOpenAIApiDeploymentName,
689
+ azureOpenAIApiInstanceName: this.azureOpenAIApiInstanceName,
690
+ azureOpenAIApiKey: this.azureOpenAIApiKey,
691
+ azureOpenAIBasePath: this.azureOpenAIBasePath,
692
+ azureADTokenProvider: this.azureADTokenProvider,
693
+ baseURL: this.clientConfig.baseURL,
572
694
  };
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;
577
- }
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;
695
+ const endpoint = openai.getEndpoint(openAIEndpointConfig);
696
+ const params = {
697
+ ...this.clientConfig,
698
+ baseURL: endpoint,
699
+ timeout: this.timeout,
700
+ maxRetries: 0,
701
+ };
702
+ if (!this.azureADTokenProvider) {
703
+ params.apiKey = openAIEndpointConfig.azureOpenAIApiKey;
585
704
  }
586
- if (this.logprobs == true) {
587
- generationInfo.logprobs = choice.logprobs;
705
+ if (params.baseURL == null) {
706
+ delete params.baseURL;
588
707
  }
589
- const generationChunk = new outputs.ChatGenerationChunk({
590
- message: chunk,
591
- text: chunk.content,
592
- generationInfo,
708
+ const defaultHeaders = normalizeHeaders(params.defaultHeaders);
709
+ params.defaultHeaders = {
710
+ ...params.defaultHeaders,
711
+ 'User-Agent': defaultHeaders['User-Agent'] != null
712
+ ? `${defaultHeaders['User-Agent']}: librechat-azure-openai-v2`
713
+ : 'librechat-azure-openai-v2',
714
+ };
715
+ this.client = new CustomAzureOpenAIClient({
716
+ apiVersion: this.azureOpenAIApiVersion,
717
+ azureADTokenProvider: this.azureADTokenProvider,
718
+ ...params,
593
719
  });
594
- yield generationChunk;
595
- await runManager?.handleLLMNewToken(generationChunk.text || '', newTokenIndices, undefined, undefined, undefined, { chunk: generationChunk });
596
720
  }
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
- }),
721
+ const requestOptions = {
722
+ ...this.clientConfig,
723
+ ...options,
724
+ };
725
+ if (this.azureOpenAIApiKey != null) {
726
+ requestOptions.headers = {
727
+ 'api-key': this.azureOpenAIApiKey,
728
+ ...requestOptions.headers,
605
729
  };
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
- }),
730
+ requestOptions.query = {
731
+ 'api-version': this.azureOpenAIApiVersion,
732
+ ...requestOptions.query,
613
733
  };
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
734
  }
735
+ return requestOptions;
736
+ }
737
+ async *_streamResponseChunks(messages, options, runManager) {
738
+ yield* delayStreamChunks(super._streamResponseChunks(messages, options, runManager), this._lc_stream_delay);
639
739
  }
640
740
  }
641
- class ChatMoonshot extends ChatOpenAI {
642
- static lc_name() {
643
- return 'LibreChatMoonshot';
741
+ class ChatDeepSeek extends deepseek.ChatDeepSeek {
742
+ _lc_stream_delay;
743
+ constructor(fields) {
744
+ super(fields);
745
+ this._lc_stream_delay = fields?._lc_stream_delay;
644
746
  }
645
- _convertMessages(messages) {
646
- return index._convertMessagesToOpenAIParams(messages, this.model, {
647
- includeReasoningContent: true,
648
- });
747
+ get exposedClient() {
748
+ return this.client;
649
749
  }
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),
750
+ static lc_name() {
751
+ return 'LibreChatDeepSeek';
752
+ }
753
+ _getClientOptions(options) {
754
+ if (!this.client) {
755
+ const openAIEndpointConfig = {
756
+ baseURL: this.clientConfig.baseURL,
671
757
  };
672
- generation.generationInfo = {
673
- ...(part.finish_reason ? { finish_reason: part.finish_reason } : {}),
674
- ...(part.logprobs ? { logprobs: part.logprobs } : {}),
758
+ const endpoint = openai.getEndpoint(openAIEndpointConfig);
759
+ const params = {
760
+ ...this.clientConfig,
761
+ baseURL: endpoint,
762
+ timeout: this.timeout,
763
+ maxRetries: 0,
675
764
  };
676
- generations.push(generation);
765
+ if (params.baseURL == null) {
766
+ delete params.baseURL;
767
+ }
768
+ this.client = new CustomOpenAIClient(params);
677
769
  }
678
- return {
679
- generations,
680
- llmOutput: {
681
- tokenUsage: {
682
- completionTokens: completion_tokens,
683
- promptTokens: prompt_tokens,
684
- totalTokens: total_tokens,
685
- },
686
- },
770
+ const requestOptions = {
771
+ ...this.clientConfig,
772
+ ...options,
687
773
  };
774
+ return requestOptions;
688
775
  }
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
- });
776
+ async *_streamResponseChunks(messages, options, runManager) {
777
+ yield* delayStreamChunks(super._streamResponseChunks(messages, options, runManager), this._lc_stream_delay);
724
778
  }
725
- async *_streamResponseChunks(messages$1, options, runManager) {
726
- const messagesMapped = index._convertMessagesToOpenAIParams(messages$1, this.model, {
779
+ }
780
+ class ChatMoonshot extends ChatOpenAI {
781
+ constructor(fields) {
782
+ super({
783
+ ...fields,
727
784
  includeReasoningContent: true,
728
785
  });
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
- }
786
+ }
787
+ static lc_name() {
788
+ return 'LibreChatMoonshot';
832
789
  }
833
790
  }
834
791
  class ChatXAI extends xai.ChatXAI {
@@ -876,144 +833,8 @@ class ChatXAI extends xai.ChatXAI {
876
833
  };
877
834
  return requestOptions;
878
835
  }
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
- }
836
+ async *_streamResponseChunks(messages, options, runManager) {
837
+ yield* delayStreamChunks(super._streamResponseChunks(messages, options, runManager), this._lc_stream_delay);
1017
838
  }
1018
839
  }
1019
840