@librechat/agents 3.3.3 → 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.
- package/dist/cjs/agents/AgentContext.cjs +2 -1
- package/dist/cjs/agents/AgentContext.cjs.map +1 -1
- package/dist/cjs/graphs/Graph.cjs +342 -109
- package/dist/cjs/graphs/Graph.cjs.map +1 -1
- package/dist/cjs/graphs/MultiAgentGraph.cjs +3 -1
- package/dist/cjs/graphs/MultiAgentGraph.cjs.map +1 -1
- package/dist/cjs/llm/anthropic/utils/message_inputs.cjs +79 -6
- package/dist/cjs/llm/anthropic/utils/message_inputs.cjs.map +1 -1
- package/dist/cjs/llm/bedrock/utils/message_inputs.cjs +37 -10
- package/dist/cjs/llm/bedrock/utils/message_inputs.cjs.map +1 -1
- package/dist/cjs/llm/google/utils/common.cjs +19 -7
- package/dist/cjs/llm/google/utils/common.cjs.map +1 -1
- package/dist/cjs/llm/invoke.cjs +64 -3
- package/dist/cjs/llm/invoke.cjs.map +1 -1
- package/dist/cjs/llm/openai/index.cjs +41 -5
- package/dist/cjs/llm/openai/index.cjs.map +1 -1
- package/dist/cjs/llm/openai/utils/index.cjs +25 -4
- package/dist/cjs/llm/openai/utils/index.cjs.map +1 -1
- package/dist/cjs/llm/openrouter/index.cjs +4 -1
- package/dist/cjs/llm/openrouter/index.cjs.map +1 -1
- package/dist/cjs/main.cjs +19 -2
- package/dist/cjs/messages/cache.cjs +54 -33
- package/dist/cjs/messages/cache.cjs.map +1 -1
- package/dist/cjs/messages/contextPruning.cjs +17 -43
- package/dist/cjs/messages/contextPruning.cjs.map +1 -1
- package/dist/cjs/messages/core.cjs +315 -23
- package/dist/cjs/messages/core.cjs.map +1 -1
- package/dist/cjs/messages/format.cjs +218 -60
- package/dist/cjs/messages/format.cjs.map +1 -1
- package/dist/cjs/messages/index.cjs +1 -1
- package/dist/cjs/messages/prune.cjs +503 -127
- package/dist/cjs/messages/prune.cjs.map +1 -1
- package/dist/cjs/stream.cjs +7 -3
- package/dist/cjs/stream.cjs.map +1 -1
- package/dist/cjs/summarization/node.cjs +28 -14
- package/dist/cjs/summarization/node.cjs.map +1 -1
- package/dist/cjs/tools/ToolNode.cjs +54 -41
- package/dist/cjs/tools/ToolNode.cjs.map +1 -1
- package/dist/cjs/tools/toolOutputReferences.cjs +6 -0
- package/dist/cjs/tools/toolOutputReferences.cjs.map +1 -1
- package/dist/cjs/utils/index.cjs +1 -1
- package/dist/cjs/utils/llm.cjs +1 -1
- package/dist/cjs/utils/llm.cjs.map +1 -1
- package/dist/cjs/utils/tokens.cjs +307 -20
- package/dist/cjs/utils/tokens.cjs.map +1 -1
- package/dist/cjs/utils/toolContent.cjs +1514 -0
- package/dist/cjs/utils/toolContent.cjs.map +1 -0
- package/dist/esm/agents/AgentContext.mjs +2 -1
- package/dist/esm/agents/AgentContext.mjs.map +1 -1
- package/dist/esm/graphs/Graph.mjs +349 -116
- package/dist/esm/graphs/Graph.mjs.map +1 -1
- package/dist/esm/graphs/MultiAgentGraph.mjs +3 -1
- package/dist/esm/graphs/MultiAgentGraph.mjs.map +1 -1
- package/dist/esm/llm/anthropic/utils/message_inputs.mjs +79 -6
- package/dist/esm/llm/anthropic/utils/message_inputs.mjs.map +1 -1
- package/dist/esm/llm/bedrock/utils/message_inputs.mjs +37 -10
- package/dist/esm/llm/bedrock/utils/message_inputs.mjs.map +1 -1
- package/dist/esm/llm/google/utils/common.mjs +19 -7
- package/dist/esm/llm/google/utils/common.mjs.map +1 -1
- package/dist/esm/llm/invoke.mjs +65 -5
- package/dist/esm/llm/invoke.mjs.map +1 -1
- package/dist/esm/llm/openai/index.mjs +41 -5
- package/dist/esm/llm/openai/index.mjs.map +1 -1
- package/dist/esm/llm/openai/utils/index.mjs +25 -4
- package/dist/esm/llm/openai/utils/index.mjs.map +1 -1
- package/dist/esm/llm/openrouter/index.mjs +4 -1
- package/dist/esm/llm/openrouter/index.mjs.map +1 -1
- package/dist/esm/main.mjs +7 -7
- package/dist/esm/messages/cache.mjs +55 -34
- package/dist/esm/messages/cache.mjs.map +1 -1
- package/dist/esm/messages/contextPruning.mjs +17 -43
- package/dist/esm/messages/contextPruning.mjs.map +1 -1
- package/dist/esm/messages/core.mjs +305 -24
- package/dist/esm/messages/core.mjs.map +1 -1
- package/dist/esm/messages/format.mjs +218 -61
- package/dist/esm/messages/format.mjs.map +1 -1
- package/dist/esm/messages/index.mjs +1 -1
- package/dist/esm/messages/prune.mjs +500 -128
- package/dist/esm/messages/prune.mjs.map +1 -1
- package/dist/esm/stream.mjs +7 -3
- package/dist/esm/stream.mjs.map +1 -1
- package/dist/esm/summarization/node.mjs +28 -14
- package/dist/esm/summarization/node.mjs.map +1 -1
- package/dist/esm/tools/ToolNode.mjs +54 -41
- package/dist/esm/tools/ToolNode.mjs.map +1 -1
- package/dist/esm/tools/toolOutputReferences.mjs +6 -0
- package/dist/esm/tools/toolOutputReferences.mjs.map +1 -1
- package/dist/esm/utils/index.mjs +1 -1
- package/dist/esm/utils/llm.mjs +1 -1
- package/dist/esm/utils/llm.mjs.map +1 -1
- package/dist/esm/utils/tokens.mjs +307 -21
- package/dist/esm/utils/tokens.mjs.map +1 -1
- package/dist/esm/utils/toolContent.mjs +1503 -0
- package/dist/esm/utils/toolContent.mjs.map +1 -0
- package/dist/types/graphs/Graph.d.ts +1 -1
- package/dist/types/llm/invoke.d.ts +27 -1
- package/dist/types/llm/openai/index.d.ts +4 -0
- package/dist/types/llm/openai/utils/index.d.ts +2 -0
- package/dist/types/llm/openrouter/index.d.ts +5 -0
- package/dist/types/messages/contextPruning.d.ts +2 -1
- package/dist/types/messages/core.d.ts +36 -0
- package/dist/types/messages/format.d.ts +6 -0
- package/dist/types/messages/prune.d.ts +16 -12
- package/dist/types/types/stream.d.ts +1 -1
- package/dist/types/utils/tokens.d.ts +7 -0
- package/dist/types/utils/toolContent.d.ts +107 -0
- package/package.json +1 -1
- package/src/__tests__/stream.eagerEventExecution.test.ts +74 -0
- package/src/agents/AgentContext.ts +1 -0
- package/src/graphs/Graph.ts +698 -200
- package/src/graphs/MultiAgentGraph.ts +6 -1
- package/src/graphs/__tests__/Graph.contextOverflow.test.ts +1128 -4
- package/src/llm/anthropic/utils/message_inputs.ts +158 -12
- package/src/llm/anthropic/utils/tool-id-normalization.test.ts +109 -0
- package/src/llm/bedrock/utils/message_inputs.test.ts +49 -1
- package/src/llm/bedrock/utils/message_inputs.ts +86 -13
- package/src/llm/google/utils/common.test.ts +75 -9
- package/src/llm/google/utils/common.ts +34 -3
- package/src/llm/invoke.test.ts +488 -0
- package/src/llm/invoke.ts +196 -2
- package/src/llm/openai/index.ts +106 -6
- package/src/llm/openai/utils/index.ts +109 -53
- package/src/llm/openai/utils/messages.test.ts +330 -1
- package/src/llm/openrouter/index.ts +12 -2
- package/src/llm/openrouter/reasoning.test.ts +314 -0
- package/src/messages/__tests__/observationMasking.test.ts +93 -2
- package/src/messages/cache.tail.test.ts +193 -0
- package/src/messages/cache.test.ts +113 -0
- package/src/messages/cache.ts +92 -60
- package/src/messages/contextPruning.test.ts +184 -0
- package/src/messages/contextPruning.ts +49 -42
- package/src/messages/core.ts +653 -40
- package/src/messages/ensureThinkingBlock.test.ts +49 -1
- package/src/messages/foldToollessToolBlocks.test.ts +163 -5
- package/src/messages/format.ts +363 -91
- package/src/messages/formatAgentMessages.test.ts +604 -14
- package/src/messages/formatAgentMessages.tools.test.ts +103 -0
- package/src/messages/prune.ts +996 -183
- package/src/specs/prune.test.ts +1083 -6
- package/src/specs/summarization-unit.test.ts +105 -0
- package/src/specs/tokens.test.ts +609 -32
- package/src/stream.ts +23 -15
- package/src/summarization/__tests__/node.test.ts +77 -0
- package/src/summarization/node.ts +46 -18
- package/src/tools/ToolNode.ts +147 -68
- package/src/tools/__tests__/ToolNode.onResultCompletion.test.ts +148 -1
- package/src/tools/__tests__/ToolNode.outputReferences.test.ts +112 -3
- package/src/tools/__tests__/annotateMessagesForLLM.test.ts +32 -0
- package/src/tools/__tests__/directToolHooks.test.ts +255 -7
- package/src/tools/toolOutputReferences.ts +6 -0
- package/src/types/stream.ts +1 -1
- package/src/utils/llm.test.ts +18 -0
- package/src/utils/llm.ts +4 -1
- package/src/utils/tokens.ts +586 -31
- package/src/utils/toolContent.test.ts +1432 -0
- 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(
|
|
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,
|
package/src/llm/openai/index.ts
CHANGED
|
@@ -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
|
|
1548
|
-
|
|
1549
|
-
|
|
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(
|
|
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 {
|