@librechat/agents 3.3.2 → 3.3.4

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 (162) hide show
  1. package/dist/cjs/agents/AgentContext.cjs +2 -1
  2. package/dist/cjs/agents/AgentContext.cjs.map +1 -1
  3. package/dist/cjs/graphs/Graph.cjs +342 -109
  4. package/dist/cjs/graphs/Graph.cjs.map +1 -1
  5. package/dist/cjs/graphs/MultiAgentGraph.cjs +3 -1
  6. package/dist/cjs/graphs/MultiAgentGraph.cjs.map +1 -1
  7. package/dist/cjs/langfuse.cjs +6 -0
  8. package/dist/cjs/langfuse.cjs.map +1 -1
  9. package/dist/cjs/llm/anthropic/utils/message_inputs.cjs +79 -6
  10. package/dist/cjs/llm/anthropic/utils/message_inputs.cjs.map +1 -1
  11. package/dist/cjs/llm/bedrock/utils/message_inputs.cjs +37 -10
  12. package/dist/cjs/llm/bedrock/utils/message_inputs.cjs.map +1 -1
  13. package/dist/cjs/llm/google/utils/common.cjs +19 -7
  14. package/dist/cjs/llm/google/utils/common.cjs.map +1 -1
  15. package/dist/cjs/llm/invoke.cjs +64 -3
  16. package/dist/cjs/llm/invoke.cjs.map +1 -1
  17. package/dist/cjs/llm/openai/index.cjs +41 -5
  18. package/dist/cjs/llm/openai/index.cjs.map +1 -1
  19. package/dist/cjs/llm/openai/utils/index.cjs +25 -4
  20. package/dist/cjs/llm/openai/utils/index.cjs.map +1 -1
  21. package/dist/cjs/llm/openrouter/index.cjs +4 -1
  22. package/dist/cjs/llm/openrouter/index.cjs.map +1 -1
  23. package/dist/cjs/main.cjs +19 -2
  24. package/dist/cjs/messages/cache.cjs +54 -33
  25. package/dist/cjs/messages/cache.cjs.map +1 -1
  26. package/dist/cjs/messages/contextPruning.cjs +17 -43
  27. package/dist/cjs/messages/contextPruning.cjs.map +1 -1
  28. package/dist/cjs/messages/core.cjs +315 -23
  29. package/dist/cjs/messages/core.cjs.map +1 -1
  30. package/dist/cjs/messages/format.cjs +218 -60
  31. package/dist/cjs/messages/format.cjs.map +1 -1
  32. package/dist/cjs/messages/index.cjs +1 -1
  33. package/dist/cjs/messages/prune.cjs +503 -127
  34. package/dist/cjs/messages/prune.cjs.map +1 -1
  35. package/dist/cjs/stream.cjs +7 -3
  36. package/dist/cjs/stream.cjs.map +1 -1
  37. package/dist/cjs/summarization/node.cjs +28 -14
  38. package/dist/cjs/summarization/node.cjs.map +1 -1
  39. package/dist/cjs/tools/ToolNode.cjs +54 -41
  40. package/dist/cjs/tools/ToolNode.cjs.map +1 -1
  41. package/dist/cjs/tools/toolOutputReferences.cjs +6 -0
  42. package/dist/cjs/tools/toolOutputReferences.cjs.map +1 -1
  43. package/dist/cjs/utils/index.cjs +1 -1
  44. package/dist/cjs/utils/llm.cjs +1 -1
  45. package/dist/cjs/utils/llm.cjs.map +1 -1
  46. package/dist/cjs/utils/tokens.cjs +307 -20
  47. package/dist/cjs/utils/tokens.cjs.map +1 -1
  48. package/dist/cjs/utils/toolContent.cjs +1514 -0
  49. package/dist/cjs/utils/toolContent.cjs.map +1 -0
  50. package/dist/esm/agents/AgentContext.mjs +2 -1
  51. package/dist/esm/agents/AgentContext.mjs.map +1 -1
  52. package/dist/esm/graphs/Graph.mjs +349 -116
  53. package/dist/esm/graphs/Graph.mjs.map +1 -1
  54. package/dist/esm/graphs/MultiAgentGraph.mjs +3 -1
  55. package/dist/esm/graphs/MultiAgentGraph.mjs.map +1 -1
  56. package/dist/esm/langfuse.mjs +6 -0
  57. package/dist/esm/langfuse.mjs.map +1 -1
  58. package/dist/esm/llm/anthropic/utils/message_inputs.mjs +79 -6
  59. package/dist/esm/llm/anthropic/utils/message_inputs.mjs.map +1 -1
  60. package/dist/esm/llm/bedrock/utils/message_inputs.mjs +37 -10
  61. package/dist/esm/llm/bedrock/utils/message_inputs.mjs.map +1 -1
  62. package/dist/esm/llm/google/utils/common.mjs +19 -7
  63. package/dist/esm/llm/google/utils/common.mjs.map +1 -1
  64. package/dist/esm/llm/invoke.mjs +65 -5
  65. package/dist/esm/llm/invoke.mjs.map +1 -1
  66. package/dist/esm/llm/openai/index.mjs +41 -5
  67. package/dist/esm/llm/openai/index.mjs.map +1 -1
  68. package/dist/esm/llm/openai/utils/index.mjs +25 -4
  69. package/dist/esm/llm/openai/utils/index.mjs.map +1 -1
  70. package/dist/esm/llm/openrouter/index.mjs +4 -1
  71. package/dist/esm/llm/openrouter/index.mjs.map +1 -1
  72. package/dist/esm/main.mjs +7 -7
  73. package/dist/esm/messages/cache.mjs +55 -34
  74. package/dist/esm/messages/cache.mjs.map +1 -1
  75. package/dist/esm/messages/contextPruning.mjs +17 -43
  76. package/dist/esm/messages/contextPruning.mjs.map +1 -1
  77. package/dist/esm/messages/core.mjs +305 -24
  78. package/dist/esm/messages/core.mjs.map +1 -1
  79. package/dist/esm/messages/format.mjs +218 -61
  80. package/dist/esm/messages/format.mjs.map +1 -1
  81. package/dist/esm/messages/index.mjs +1 -1
  82. package/dist/esm/messages/prune.mjs +500 -128
  83. package/dist/esm/messages/prune.mjs.map +1 -1
  84. package/dist/esm/stream.mjs +7 -3
  85. package/dist/esm/stream.mjs.map +1 -1
  86. package/dist/esm/summarization/node.mjs +28 -14
  87. package/dist/esm/summarization/node.mjs.map +1 -1
  88. package/dist/esm/tools/ToolNode.mjs +54 -41
  89. package/dist/esm/tools/ToolNode.mjs.map +1 -1
  90. package/dist/esm/tools/toolOutputReferences.mjs +6 -0
  91. package/dist/esm/tools/toolOutputReferences.mjs.map +1 -1
  92. package/dist/esm/utils/index.mjs +1 -1
  93. package/dist/esm/utils/llm.mjs +1 -1
  94. package/dist/esm/utils/llm.mjs.map +1 -1
  95. package/dist/esm/utils/tokens.mjs +307 -21
  96. package/dist/esm/utils/tokens.mjs.map +1 -1
  97. package/dist/esm/utils/toolContent.mjs +1503 -0
  98. package/dist/esm/utils/toolContent.mjs.map +1 -0
  99. package/dist/types/graphs/Graph.d.ts +1 -1
  100. package/dist/types/llm/invoke.d.ts +27 -1
  101. package/dist/types/llm/openai/index.d.ts +4 -0
  102. package/dist/types/llm/openai/utils/index.d.ts +2 -0
  103. package/dist/types/llm/openrouter/index.d.ts +5 -0
  104. package/dist/types/messages/contextPruning.d.ts +2 -1
  105. package/dist/types/messages/core.d.ts +36 -0
  106. package/dist/types/messages/format.d.ts +6 -0
  107. package/dist/types/messages/prune.d.ts +16 -12
  108. package/dist/types/types/stream.d.ts +1 -1
  109. package/dist/types/utils/tokens.d.ts +7 -0
  110. package/dist/types/utils/toolContent.d.ts +107 -0
  111. package/package.json +13 -9
  112. package/src/__tests__/stream.eagerEventExecution.test.ts +74 -0
  113. package/src/agents/AgentContext.ts +1 -0
  114. package/src/graphs/Graph.ts +698 -200
  115. package/src/graphs/MultiAgentGraph.ts +6 -1
  116. package/src/graphs/__tests__/Graph.contextOverflow.test.ts +1128 -4
  117. package/src/langfuse.ts +15 -0
  118. package/src/llm/anthropic/utils/message_inputs.ts +158 -12
  119. package/src/llm/anthropic/utils/tool-id-normalization.test.ts +109 -0
  120. package/src/llm/bedrock/utils/message_inputs.test.ts +49 -1
  121. package/src/llm/bedrock/utils/message_inputs.ts +86 -13
  122. package/src/llm/google/utils/common.test.ts +75 -9
  123. package/src/llm/google/utils/common.ts +34 -3
  124. package/src/llm/invoke.test.ts +488 -0
  125. package/src/llm/invoke.ts +196 -2
  126. package/src/llm/openai/index.ts +106 -6
  127. package/src/llm/openai/utils/index.ts +109 -53
  128. package/src/llm/openai/utils/messages.test.ts +330 -1
  129. package/src/llm/openrouter/index.ts +12 -2
  130. package/src/llm/openrouter/reasoning.test.ts +314 -0
  131. package/src/messages/__tests__/observationMasking.test.ts +93 -2
  132. package/src/messages/cache.tail.test.ts +193 -0
  133. package/src/messages/cache.test.ts +113 -0
  134. package/src/messages/cache.ts +92 -60
  135. package/src/messages/contextPruning.test.ts +184 -0
  136. package/src/messages/contextPruning.ts +49 -42
  137. package/src/messages/core.ts +653 -40
  138. package/src/messages/ensureThinkingBlock.test.ts +49 -1
  139. package/src/messages/foldToollessToolBlocks.test.ts +163 -5
  140. package/src/messages/format.ts +363 -91
  141. package/src/messages/formatAgentMessages.test.ts +604 -14
  142. package/src/messages/formatAgentMessages.tools.test.ts +103 -0
  143. package/src/messages/prune.ts +996 -183
  144. package/src/specs/langfuse-callbacks.test.ts +203 -1
  145. package/src/specs/prune.test.ts +1083 -6
  146. package/src/specs/summarization-unit.test.ts +105 -0
  147. package/src/specs/tokens.test.ts +609 -32
  148. package/src/stream.ts +23 -15
  149. package/src/summarization/__tests__/node.test.ts +77 -0
  150. package/src/summarization/node.ts +46 -18
  151. package/src/tools/ToolNode.ts +147 -68
  152. package/src/tools/__tests__/ToolNode.onResultCompletion.test.ts +148 -1
  153. package/src/tools/__tests__/ToolNode.outputReferences.test.ts +112 -3
  154. package/src/tools/__tests__/annotateMessagesForLLM.test.ts +32 -0
  155. package/src/tools/__tests__/directToolHooks.test.ts +255 -7
  156. package/src/tools/toolOutputReferences.ts +6 -0
  157. package/src/types/stream.ts +1 -1
  158. package/src/utils/llm.test.ts +18 -0
  159. package/src/utils/llm.ts +4 -1
  160. package/src/utils/tokens.ts +586 -31
  161. package/src/utils/toolContent.test.ts +1432 -0
  162. package/src/utils/toolContent.ts +2707 -0
package/src/llm/invoke.ts CHANGED
@@ -6,6 +6,20 @@ import type { BaseMessage } from '@langchain/core/messages';
6
6
  import type { ToolOutputReferenceRegistry } from '@/tools/toolOutputReferences';
7
7
  import type { ContextOverflowContext } from '@/utils/errors';
8
8
  import type * as t from '@/types';
9
+ import {
10
+ projectCacheControlledToolOutputsToText,
11
+ projectComputerCallOutputsToText,
12
+ projectOpenAIChatToolMessageContent,
13
+ projectOpenAIResponsesToolMessageContent,
14
+ projectOpenRouterToolMessageContent,
15
+ projectSingleTextToolOutputsToText,
16
+ projectStructuredToolOutputsToText,
17
+ projectToolStreamContentForProvider,
18
+ } from '@/messages/core';
19
+ import {
20
+ stripAnthropicCacheControl,
21
+ stripBedrockCacheControl,
22
+ } from '@/messages/cache';
9
23
  import { annotateMessagesForLLM } from '@/tools/toolOutputReferences';
10
24
  import { assertNotTruncatedToolCall } from '@/llm/truncation';
11
25
  import { Constants, GraphEvents, Providers } from '@/common';
@@ -14,6 +28,7 @@ import { getContextOverflowInfo } from '@/utils/errors';
14
28
  import { modifyDeltaProperties } from '@/messages';
15
29
  import { ChatModelStreamHandler } from '@/stream';
16
30
  import { initializeModel } from '@/llm/init';
31
+ import { isOpenAILike } from '@/utils/llm';
17
32
 
18
33
  /**
19
34
  * Context passed to `attemptInvoke`. Matches the subset of Graph that
@@ -54,6 +69,152 @@ export type InvokeContext = NonNullable<
54
69
  */
55
70
  export type OnChunk = (chunk: AIMessageChunk) => void | Promise<void>;
56
71
 
72
+ export function usesNativeOpenAIResponses(
73
+ model: t.ChatModel,
74
+ provider: Providers,
75
+ callOptions?: unknown
76
+ ): boolean {
77
+ if (!isOpenAILike(provider)) {
78
+ return false;
79
+ }
80
+ let candidate: unknown = model;
81
+ let effectiveCallOptions = callOptions;
82
+ const seen = new Set<object>();
83
+ for (let depth = 0; depth < 20; depth++) {
84
+ if (candidate == null || typeof candidate !== 'object') {
85
+ return false;
86
+ }
87
+ if (seen.has(candidate)) {
88
+ return false;
89
+ }
90
+ seen.add(candidate);
91
+ const runnable = candidate as {
92
+ _useResponsesApi?: (options?: unknown) => boolean;
93
+ bound?: unknown;
94
+ defaultOptions?: unknown;
95
+ last?: unknown;
96
+ constructor?: { name?: unknown };
97
+ };
98
+ try {
99
+ if (
100
+ runnable.defaultOptions != null &&
101
+ typeof runnable.defaultOptions === 'object' &&
102
+ !Array.isArray(runnable.defaultOptions) &&
103
+ effectiveCallOptions != null &&
104
+ typeof effectiveCallOptions === 'object' &&
105
+ !Array.isArray(effectiveCallOptions)
106
+ ) {
107
+ effectiveCallOptions = {
108
+ ...(runnable.defaultOptions as Record<string, unknown>),
109
+ ...(effectiveCallOptions as Record<string, unknown>),
110
+ };
111
+ } else if (effectiveCallOptions == null) {
112
+ effectiveCallOptions = runnable.defaultOptions;
113
+ }
114
+ if (
115
+ runnable._useResponsesApi?.(effectiveCallOptions) === true ||
116
+ runnable._useResponsesApi?.(undefined) === true
117
+ ) {
118
+ return true;
119
+ }
120
+ } catch {
121
+ // Continue through RunnableSequence/RunnableBinding wrappers.
122
+ }
123
+ if (
124
+ typeof runnable.constructor?.name === 'string' &&
125
+ runnable.constructor.name.includes('Responses')
126
+ ) {
127
+ return true;
128
+ }
129
+ if (runnable.last != null && typeof runnable.last === 'object') {
130
+ candidate = runnable.last;
131
+ continue;
132
+ }
133
+ if (runnable.bound != null && typeof runnable.bound === 'object') {
134
+ candidate = runnable.bound;
135
+ continue;
136
+ }
137
+ return false;
138
+ }
139
+ return false;
140
+ }
141
+
142
+ /**
143
+ * Produces the exact provider-facing message representation before a model
144
+ * adapter serializes it. This is shared by invocation and Graph's final budget
145
+ * guard so structured tool output cannot grow after the payload was measured.
146
+ */
147
+ export function projectMessagesForProvider({
148
+ model,
149
+ messages,
150
+ provider,
151
+ maxToolResultChars,
152
+ callOptions,
153
+ }: {
154
+ model: t.ChatModel;
155
+ messages: BaseMessage[];
156
+ provider: Providers;
157
+ maxToolResultChars?: number;
158
+ callOptions?: unknown;
159
+ }): BaseMessage[] {
160
+ const providerInputMessages = projectToolStreamContentForProvider(messages);
161
+ if (usesNativeOpenAIResponses(model, provider, callOptions)) {
162
+ return projectOpenAIResponsesToolMessageContent(
163
+ stripAnthropicCacheControl(
164
+ stripBedrockCacheControl(providerInputMessages)
165
+ ),
166
+ maxToolResultChars
167
+ );
168
+ }
169
+ if (provider === Providers.OPENROUTER) {
170
+ return projectComputerCallOutputsToText(
171
+ projectOpenRouterToolMessageContent(
172
+ stripBedrockCacheControl(providerInputMessages),
173
+ maxToolResultChars
174
+ )
175
+ );
176
+ }
177
+ if (isOpenAILike(provider)) {
178
+ return projectComputerCallOutputsToText(
179
+ projectOpenAIChatToolMessageContent(
180
+ stripAnthropicCacheControl(
181
+ stripBedrockCacheControl(providerInputMessages)
182
+ ),
183
+ maxToolResultChars
184
+ )
185
+ );
186
+ }
187
+ if (provider === Providers.ANTHROPIC) {
188
+ return projectComputerCallOutputsToText(
189
+ projectSingleTextToolOutputsToText(
190
+ stripBedrockCacheControl(providerInputMessages),
191
+ maxToolResultChars
192
+ )
193
+ );
194
+ }
195
+ if (provider === Providers.BEDROCK) {
196
+ return stripAnthropicCacheControl(
197
+ projectComputerCallOutputsToText(
198
+ projectCacheControlledToolOutputsToText(
199
+ providerInputMessages,
200
+ maxToolResultChars
201
+ )
202
+ )
203
+ );
204
+ }
205
+ return projectComputerCallOutputsToText(
206
+ projectStructuredToolOutputsToText(
207
+ projectSingleTextToolOutputsToText(
208
+ stripAnthropicCacheControl(
209
+ stripBedrockCacheControl(providerInputMessages)
210
+ ),
211
+ maxToolResultChars
212
+ ),
213
+ maxToolResultChars
214
+ )
215
+ );
216
+ }
217
+
57
218
  function getRegisteredDefaultChatStreamHandler(
58
219
  context?: InvokeContext
59
220
  ): ChatModelStreamHandler | undefined {
@@ -207,9 +368,19 @@ export async function attemptInvoke(
207
368
  * untouched so the graph state never sees `[ref: …]` / `_ref`
208
369
  * payload.
209
370
  */
371
+ const invocationMessages = projectMessagesForProvider({
372
+ model,
373
+ messages,
374
+ provider,
375
+ callOptions: config,
376
+ });
210
377
  const registry = context?.getOrCreateToolOutputRegistry();
211
378
  const runId = config?.configurable?.run_id as string | undefined;
212
- const messagesForProvider = annotateMessagesForLLM(messages, registry, runId);
379
+ const messagesForProvider = annotateMessagesForLLM(
380
+ invocationMessages,
381
+ registry,
382
+ runId
383
+ );
213
384
 
214
385
  /**
215
386
  * Stamp the provider that is ACTUALLY serving this invocation onto the
@@ -404,6 +575,7 @@ export async function tryFallbackProviders({
404
575
  context,
405
576
  onChunk,
406
577
  overflowContext,
578
+ prepareProviderMessages,
407
579
  }: {
408
580
  fallbacks: t.FallbackConfig[];
409
581
  tools?: t.GraphTools;
@@ -419,6 +591,19 @@ export async function tryFallbackProviders({
419
591
  * be dropped in favour of whichever failure came last.
420
592
  */
421
593
  overflowContext?: ContextOverflowContext;
594
+ /**
595
+ * Optional final payload guard used by Graph. It receives the initialized,
596
+ * tool-bound fallback model so Responses-vs-Chat projection is exact before
597
+ * the fallback request is measured and sent.
598
+ */
599
+ prepareProviderMessages?: (input: {
600
+ model: t.ChatModel;
601
+ messages: BaseMessage[];
602
+ provider: Providers;
603
+ clientOptions?: t.ClientOptions;
604
+ maxContextTokens?: number;
605
+ config?: RunnableConfig;
606
+ }) => BaseMessage[] | Promise<BaseMessage[]>;
422
607
  }): Promise<Partial<t.BaseGraphState> | undefined> {
423
608
  const isOverflow = (
424
609
  error: unknown,
@@ -460,10 +645,19 @@ export async function tryFallbackProviders({
460
645
  [Constants.INVOKED_MODEL]: fbModelName,
461
646
  },
462
647
  };
648
+ const fallbackMessages =
649
+ (await prepareProviderMessages?.({
650
+ model: fbModel as t.ChatModel,
651
+ messages,
652
+ provider: fb.provider,
653
+ clientOptions: fb.clientOptions,
654
+ maxContextTokens: fb.maxContextTokens,
655
+ config: fbConfig,
656
+ })) ?? messages;
463
657
  const result = await attemptInvoke(
464
658
  {
465
659
  model: fbModel as t.ChatModel,
466
- messages,
660
+ messages: fallbackMessages,
467
661
  provider: fb.provider,
468
662
  context,
469
663
  onChunk,
@@ -29,16 +29,28 @@ import type {
29
29
  BaseMessageChunk,
30
30
  UsageMetadata,
31
31
  } from '@langchain/core/messages';
32
+ import type { ChatModelStreamEvent } from '@langchain/core/language_models/event';
32
33
  import type { BindToolsInput } from '@langchain/core/language_models/chat_models';
33
34
  import type { ChatGeneration, ChatResult } from '@langchain/core/outputs';
34
35
  import type { ChatXAIInput } from '@langchain/xai';
35
36
  import type * as t from '@langchain/openai';
36
37
  import type { SeenScalarMetadata } from './streamMetadata';
37
38
  import type { HeaderValue, HeadersLike } from './types';
39
+ import type { PromptCacheTtl } from '@/messages/cache';
40
+ import {
41
+ buildAnthropicCacheControl,
42
+ resolvePromptCacheTtl,
43
+ stripAnthropicCacheControl,
44
+ stripBedrockCacheControl,
45
+ } from '@/messages/cache';
38
46
  import {
39
47
  STREAMED_TOOL_CALL_ADAPTER_METADATA_KEY,
40
48
  OPENAI_CHAT_SEQUENTIAL_STREAMED_TOOL_CALL_ADAPTER,
41
49
  } from '@/tools/streamedToolCallSeals';
50
+ import {
51
+ projectOpenAIResponsesToolMessageContent,
52
+ projectToolStreamContentForProvider,
53
+ } from '@/messages/core';
42
54
  import { isReasoningModel, _convertMessagesToOpenAIParams } from './utils';
43
55
  import { dropRepeatedScalarMetadata } from './streamMetadata';
44
56
 
@@ -102,6 +114,9 @@ type LibreChatOpenAIFields = t.ChatOpenAIFields & {
102
114
  includeReasoningContent?: boolean;
103
115
  includeReasoningDetails?: boolean;
104
116
  convertReasoningDetailsToContent?: boolean;
117
+ preserveToolCacheControl?: boolean;
118
+ responsesPromptCache?: boolean;
119
+ responsesPromptCacheTtl?: PromptCacheTtl;
105
120
  promptCacheExplicit?: boolean;
106
121
  safety_identifier?: string;
107
122
  };
@@ -168,6 +183,40 @@ type OpenAIManagedRequestParams = {
168
183
  };
169
184
  safety_identifier?: string;
170
185
  };
186
+
187
+ function stripResponsesToolCacheControl<T>(tools: T): T {
188
+ if (!Array.isArray(tools)) {
189
+ return tools;
190
+ }
191
+
192
+ return tools.map((tool) => {
193
+ if (tool == null || typeof tool !== 'object') {
194
+ return tool;
195
+ }
196
+ const clone = { ...(tool as Record<string, unknown>) };
197
+ delete clone.cache_control;
198
+ if (
199
+ clone.extras != null &&
200
+ typeof clone.extras === 'object' &&
201
+ !Array.isArray(clone.extras)
202
+ ) {
203
+ clone.extras = { ...(clone.extras as Record<string, unknown>) };
204
+ delete (clone.extras as Record<string, unknown>).cache_control;
205
+ }
206
+ return clone;
207
+ }) as T;
208
+ }
209
+
210
+ function projectOpenAIResponsesProviderMessages(
211
+ messages: BaseMessage[]
212
+ ): BaseMessage[] {
213
+ return projectOpenAIResponsesToolMessageContent(
214
+ stripAnthropicCacheControl(
215
+ stripBedrockCacheControl(projectToolStreamContentForProvider(messages))
216
+ )
217
+ );
218
+ }
219
+
171
220
  type ResponsesRequest =
172
221
  | OpenAIClient.Responses.ResponseCreateParamsStreaming
173
222
  | OpenAIClient.Responses.ResponseCreateParamsNonStreaming;
@@ -1116,6 +1165,7 @@ class LibreChatOpenAICompletions extends OriginalChatOpenAICompletions {
1116
1165
  private includeReasoningContent?: boolean;
1117
1166
  private includeReasoningDetails?: boolean;
1118
1167
  private convertReasoningDetailsToContent?: boolean;
1168
+ private preserveToolCacheControl?: boolean;
1119
1169
  private promptCacheExplicit?: boolean;
1120
1170
  private safetyIdentifier?: string;
1121
1171
 
@@ -1125,6 +1175,7 @@ class LibreChatOpenAICompletions extends OriginalChatOpenAICompletions {
1125
1175
  this.includeReasoningDetails = fields?.includeReasoningDetails;
1126
1176
  this.convertReasoningDetailsToContent =
1127
1177
  fields?.convertReasoningDetailsToContent;
1178
+ this.preserveToolCacheControl = fields?.preserveToolCacheControl;
1128
1179
  this.promptCacheExplicit = fields?.promptCacheExplicit;
1129
1180
  this.safetyIdentifier = fields?.safety_identifier;
1130
1181
  }
@@ -1225,6 +1276,7 @@ class LibreChatOpenAICompletions extends OriginalChatOpenAICompletions {
1225
1276
  includeReasoningContent: this.includeReasoningContent,
1226
1277
  includeReasoningDetails: this.includeReasoningDetails,
1227
1278
  convertReasoningDetailsToContent: this.convertReasoningDetailsToContent,
1279
+ preserveToolCacheControl: this.preserveToolCacheControl,
1228
1280
  }
1229
1281
  );
1230
1282
 
@@ -1393,6 +1445,7 @@ class LibreChatOpenAICompletions extends OriginalChatOpenAICompletions {
1393
1445
  includeReasoningContent: this.includeReasoningContent,
1394
1446
  includeReasoningDetails: this.includeReasoningDetails,
1395
1447
  convertReasoningDetailsToContent: this.convertReasoningDetailsToContent,
1448
+ preserveToolCacheControl: this.preserveToolCacheControl,
1396
1449
  });
1397
1450
 
1398
1451
  const params = {
@@ -1533,21 +1586,52 @@ class LibreChatOpenAICompletions extends OriginalChatOpenAICompletions {
1533
1586
 
1534
1587
  class LibreChatOpenAIResponses extends OriginalChatOpenAIResponses {
1535
1588
  private promptCacheExplicit?: boolean;
1589
+ private responsesPromptCache?: boolean;
1590
+ private responsesPromptCacheTtl?: PromptCacheTtl;
1536
1591
  private safetyIdentifier?: string;
1537
1592
 
1538
1593
  constructor(fields?: LibreChatOpenAIFields) {
1539
1594
  super(fields);
1540
1595
  this.promptCacheExplicit = fields?.promptCacheExplicit;
1596
+ this.responsesPromptCache = fields?.responsesPromptCache;
1597
+ this.responsesPromptCacheTtl = fields?.responsesPromptCacheTtl;
1541
1598
  this.safetyIdentifier = fields?.safety_identifier;
1542
1599
  }
1543
1600
 
1544
1601
  invocationParams(
1545
1602
  options?: this['ParsedCallOptions']
1546
1603
  ): ReturnType<OriginalChatOpenAIResponses['invocationParams']> {
1547
- const params = applyManagedRequestParams(super.invocationParams(options), {
1548
- promptCacheExplicit: this.promptCacheExplicit,
1549
- safetyIdentifier: this.safetyIdentifier,
1550
- });
1604
+ const cacheOptions = options as
1605
+ | {
1606
+ promptCache?: boolean;
1607
+ promptCacheTtl?: PromptCacheTtl;
1608
+ }
1609
+ | undefined;
1610
+ const promptCache = cacheOptions?.promptCache ?? this.responsesPromptCache;
1611
+ const cacheControl =
1612
+ promptCache === true
1613
+ ? buildAnthropicCacheControl(
1614
+ resolvePromptCacheTtl(
1615
+ cacheOptions?.promptCacheTtl ?? this.responsesPromptCacheTtl
1616
+ )
1617
+ )
1618
+ : undefined;
1619
+ const baseParams = applyManagedRequestParams(
1620
+ super.invocationParams(options),
1621
+ {
1622
+ promptCacheExplicit: this.promptCacheExplicit,
1623
+ safetyIdentifier: this.safetyIdentifier,
1624
+ }
1625
+ );
1626
+ const params = {
1627
+ ...baseParams,
1628
+ ...(baseParams.tools != null && {
1629
+ tools: stripResponsesToolCacheControl(baseParams.tools),
1630
+ }),
1631
+ ...(cacheControl != null && {
1632
+ cache_control: cacheControl,
1633
+ }),
1634
+ };
1551
1635
  if (shouldIncludeEncryptedReasoning(this.model, params)) {
1552
1636
  params.include = [
1553
1637
  ...new Set([
@@ -1592,7 +1676,11 @@ class LibreChatOpenAIResponses extends OriginalChatOpenAIResponses {
1592
1676
  options: this['ParsedCallOptions'],
1593
1677
  runManager?: CallbackManagerForLLMRun
1594
1678
  ): Promise<ChatResult> {
1595
- const result = await super._generate(messages, options, runManager);
1679
+ const result = await super._generate(
1680
+ projectOpenAIResponsesProviderMessages(messages),
1681
+ options,
1682
+ runManager
1683
+ );
1596
1684
  for (const generation of result.generations) {
1597
1685
  attachCacheWriteUsage(generation.message);
1598
1686
  }
@@ -1605,7 +1693,7 @@ class LibreChatOpenAIResponses extends OriginalChatOpenAIResponses {
1605
1693
  runManager?: CallbackManagerForLLMRun
1606
1694
  ): AsyncGenerator<ChatGenerationChunk> {
1607
1695
  for await (const chunk of super._streamResponseChunks(
1608
- messages,
1696
+ projectOpenAIResponsesProviderMessages(messages),
1609
1697
  options,
1610
1698
  runManager
1611
1699
  )) {
@@ -1614,6 +1702,18 @@ class LibreChatOpenAIResponses extends OriginalChatOpenAIResponses {
1614
1702
  }
1615
1703
  }
1616
1704
 
1705
+ async *_streamChatModelEvents(
1706
+ messages: BaseMessage[],
1707
+ options: this['ParsedCallOptions'],
1708
+ runManager?: CallbackManagerForLLMRun
1709
+ ): AsyncGenerator<ChatModelStreamEvent> {
1710
+ yield* super._streamChatModelEvents(
1711
+ projectOpenAIResponsesProviderMessages(messages),
1712
+ options,
1713
+ runManager
1714
+ );
1715
+ }
1716
+
1617
1717
  protected _getReasoningParams(
1618
1718
  options?: this['ParsedCallOptions']
1619
1719
  ): OpenAIClient.Reasoning | undefined {