@librechat/agents 2.4.69 → 2.4.71

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.
@@ -9,7 +9,6 @@ import {
9
9
  HumanMessage,
10
10
  type AIMessage,
11
11
  type ToolMessage,
12
- type MessageContent,
13
12
  isAIMessage,
14
13
  type StandardContentBlockConverter,
15
14
  type StandardTextBlock,
@@ -123,7 +122,7 @@ function _ensureMessageContents(
123
122
  type: 'tool_result',
124
123
  // rare case: message.content could be undefined
125
124
  ...(message.content != null
126
- ? { content: _formatContent(message.content) }
125
+ ? { content: _formatContent(message) }
127
126
  : {}),
128
127
  tool_use_id: (message as ToolMessage).tool_call_id,
129
128
  },
@@ -348,7 +347,7 @@ const standardContentBlockConverter: StandardContentBlockConverter<{
348
347
  },
349
348
  };
350
349
 
351
- function _formatContent(content: MessageContent) {
350
+ function _formatContent(message: BaseMessage) {
352
351
  const toolTypes = [
353
352
  'tool_use',
354
353
  'tool_result',
@@ -358,6 +357,7 @@ function _formatContent(content: MessageContent) {
358
357
  'web_search_result',
359
358
  ];
360
359
  const textTypes = ['text', 'text_delta'];
360
+ const { content } = message;
361
361
 
362
362
  if (typeof content === 'string') {
363
363
  return content;
@@ -465,6 +465,27 @@ function _formatContent(content: MessageContent) {
465
465
  ...(cacheControl ? { cache_control: cacheControl } : {}),
466
466
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
467
467
  } as any;
468
+ } else if (
469
+ 'functionCall' in contentPart &&
470
+ contentPart.functionCall &&
471
+ typeof contentPart.functionCall === 'object' &&
472
+ isAIMessage(message)
473
+ ) {
474
+ const correspondingToolCall = message.tool_calls?.find(
475
+ (toolCall) => toolCall.name === contentPart.functionCall.name
476
+ );
477
+ if (!correspondingToolCall) {
478
+ throw new Error(
479
+ `Could not find tool call for function call ${contentPart.functionCall.name}`
480
+ );
481
+ }
482
+ // Google GenAI models include a `functionCall` object inside content. We should ignore it as Anthropic will not support it.
483
+ return {
484
+ id: correspondingToolCall.id,
485
+ type: 'tool_use',
486
+ name: correspondingToolCall.name,
487
+ input: contentPart.functionCall.args,
488
+ };
468
489
  } else {
469
490
  throw new Error('Unsupported message content format');
470
491
  }
@@ -540,13 +561,13 @@ export function _convertMessagesToAnthropicPayload(
540
561
  }
541
562
  return {
542
563
  role,
543
- content: _formatContent(message.content),
564
+ content: _formatContent(message),
544
565
  };
545
566
  }
546
567
  } else {
547
568
  return {
548
569
  role,
549
- content: _formatContent(message.content),
570
+ content: _formatContent(message),
550
571
  };
551
572
  }
552
573
  });
@@ -24,6 +24,7 @@ import type { BaseMessage, UsageMetadata } from '@langchain/core/messages';
24
24
  import type { ChatXAIInput } from '@langchain/xai';
25
25
  import type * as t from '@langchain/openai';
26
26
  import {
27
+ isReasoningModel,
27
28
  _convertMessagesToOpenAIParams,
28
29
  _convertMessagesToOpenAIResponsesParams,
29
30
  _convertOpenAIResponsesDeltaToBaseMessageChunk,
@@ -224,6 +225,35 @@ export class ChatOpenAI extends OriginalChatOpenAI<t.ChatOpenAICallOptions> {
224
225
  return requestOptions;
225
226
  }
226
227
 
228
+ /**
229
+ * Returns backwards compatible reasoning parameters from constructor params and call options
230
+ * @internal
231
+ */
232
+ protected _getReasoningParams(
233
+ options?: this['ParsedCallOptions']
234
+ ): OpenAIClient.Reasoning | undefined {
235
+ if (!isReasoningModel(this.model)) {
236
+ return;
237
+ }
238
+
239
+ // apply options in reverse order of importance -- newer options supersede older options
240
+ let reasoning: OpenAIClient.Reasoning | undefined;
241
+ if (this.reasoning !== undefined) {
242
+ reasoning = {
243
+ ...reasoning,
244
+ ...this.reasoning,
245
+ };
246
+ }
247
+ if (options?.reasoning !== undefined) {
248
+ reasoning = {
249
+ ...reasoning,
250
+ ...options.reasoning,
251
+ };
252
+ }
253
+
254
+ return reasoning;
255
+ }
256
+
227
257
  async *_streamResponseChunks(
228
258
  messages: BaseMessage[],
229
259
  options: this['ParsedCallOptions'],
@@ -395,6 +425,34 @@ export class AzureChatOpenAI extends OriginalAzureChatOpenAI {
395
425
  public get exposedClient(): CustomOpenAIClient {
396
426
  return this.client;
397
427
  }
428
+ /**
429
+ * Returns backwards compatible reasoning parameters from constructor params and call options
430
+ * @internal
431
+ */
432
+ protected _getReasoningParams(
433
+ options?: this['ParsedCallOptions']
434
+ ): OpenAIClient.Reasoning | undefined {
435
+ if (!isReasoningModel(this.model)) {
436
+ return;
437
+ }
438
+
439
+ // apply options in reverse order of importance -- newer options supersede older options
440
+ let reasoning: OpenAIClient.Reasoning | undefined;
441
+ if (this.reasoning !== undefined) {
442
+ reasoning = {
443
+ ...reasoning,
444
+ ...this.reasoning,
445
+ };
446
+ }
447
+ if (options?.reasoning !== undefined) {
448
+ reasoning = {
449
+ ...reasoning,
450
+ ...options.reasoning,
451
+ };
452
+ }
453
+
454
+ return reasoning;
455
+ }
398
456
  protected _getClientOptions(
399
457
  options: OpenAICoreRequestOptions | undefined
400
458
  ): OpenAICoreRequestOptions {
@@ -648,7 +648,11 @@ export function _convertMessagesToOpenAIResponsesParams(
648
648
  }
649
649
 
650
650
  export function isReasoningModel(model?: string) {
651
- return model != null && model && /^o\d/.test(model);
651
+ return (
652
+ model != null &&
653
+ model !== '' &&
654
+ (/^o\d/.test(model) || /^gpt-[5-9]/.test(model))
655
+ );
652
656
  }
653
657
 
654
658
  function _convertOpenAIResponsesMessageToBaseMessage(