@librechat/agents 3.6.15 → 3.7.0
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/README.md +41 -0
- package/dist/cjs/_virtual/_rolldown/runtime.cjs +10 -0
- package/dist/cjs/agents/AgentContext.cjs +1 -1
- package/dist/cjs/agents/AgentContext.cjs.map +1 -1
- package/dist/cjs/graphs/Graph.cjs +13 -13
- package/dist/cjs/graphs/Graph.cjs.map +1 -1
- package/dist/cjs/lazyRequire.cjs +33 -0
- package/dist/cjs/lazyRequire.cjs.map +1 -0
- package/dist/cjs/llm/anthropic/index.cjs +13 -0
- package/dist/cjs/llm/anthropic/index.cjs.map +1 -1
- package/dist/cjs/llm/bedrock/index.cjs +10 -1
- package/dist/cjs/llm/bedrock/index.cjs.map +1 -1
- package/dist/cjs/llm/bedrock/toolCache.cjs +3 -2
- package/dist/cjs/llm/bedrock/toolCache.cjs.map +1 -1
- package/dist/cjs/llm/google/index.cjs +10 -1
- package/dist/cjs/llm/google/index.cjs.map +1 -1
- package/dist/cjs/llm/init.cjs +7 -4
- package/dist/cjs/llm/init.cjs.map +1 -1
- package/dist/cjs/llm/invoke.cjs +9 -2
- package/dist/cjs/llm/invoke.cjs.map +1 -1
- package/dist/cjs/llm/mistral/index.cjs +9 -0
- package/dist/cjs/llm/mistral/index.cjs.map +1 -1
- package/dist/cjs/llm/openai/index.cjs +41 -1
- package/dist/cjs/llm/openai/index.cjs.map +1 -1
- package/dist/cjs/llm/openrouter/index.cjs +12 -3
- package/dist/cjs/llm/openrouter/index.cjs.map +1 -1
- package/dist/cjs/llm/openrouter/toolCache.cjs +3 -2
- package/dist/cjs/llm/openrouter/toolCache.cjs.map +1 -1
- package/dist/cjs/llm/prepareProviderRequest.cjs +6 -3
- package/dist/cjs/llm/prepareProviderRequest.cjs.map +1 -1
- package/dist/cjs/llm/providerRegistry.cjs +81 -0
- package/dist/cjs/llm/providerRegistry.cjs.map +1 -0
- package/dist/cjs/llm/providers.cjs +37 -28
- package/dist/cjs/llm/providers.cjs.map +1 -1
- package/dist/cjs/llm/providers.eager.cjs +21 -0
- package/dist/cjs/llm/providers.eager.cjs.map +1 -0
- package/dist/cjs/llm/request.cjs +6 -4
- package/dist/cjs/llm/request.cjs.map +1 -1
- package/dist/cjs/llm/truncation.cjs +2 -1
- package/dist/cjs/llm/truncation.cjs.map +1 -1
- package/dist/cjs/llm/vertexai/index.cjs +17 -0
- package/dist/cjs/llm/vertexai/index.cjs.map +1 -1
- package/dist/cjs/main.cjs +19 -18
- package/dist/cjs/messages/core.cjs +9 -4
- package/dist/cjs/messages/core.cjs.map +1 -1
- package/dist/cjs/messages/format.cjs.map +1 -1
- package/dist/cjs/messages/prune.cjs +50 -12
- package/dist/cjs/messages/prune.cjs.map +1 -1
- package/dist/cjs/provider-registration.cjs +4 -0
- package/dist/cjs/run.cjs +9 -4
- package/dist/cjs/run.cjs.map +1 -1
- package/dist/cjs/stream.cjs +1 -1
- package/dist/cjs/stream.cjs.map +1 -1
- package/dist/cjs/summarization/node.cjs +2 -2
- package/dist/cjs/summarization/node.cjs.map +1 -1
- package/dist/cjs/tools/Calculator.cjs +7 -4
- package/dist/cjs/tools/Calculator.cjs.map +1 -1
- package/dist/cjs/tools/CodeExecutor.cjs +1 -1
- package/dist/cjs/utils/llm.cjs +22 -4
- package/dist/cjs/utils/llm.cjs.map +1 -1
- package/dist/esm/_virtual/_rolldown/runtime.mjs +14 -0
- package/dist/esm/agents/AgentContext.mjs +1 -1
- package/dist/esm/agents/AgentContext.mjs.map +1 -1
- package/dist/esm/graphs/Graph.mjs +13 -13
- package/dist/esm/graphs/Graph.mjs.map +1 -1
- package/dist/esm/lazyRequire.mjs +30 -0
- package/dist/esm/lazyRequire.mjs.map +1 -0
- package/dist/esm/llm/anthropic/index.mjs +6 -1
- package/dist/esm/llm/anthropic/index.mjs.map +1 -1
- package/dist/esm/llm/bedrock/index.mjs +4 -2
- package/dist/esm/llm/bedrock/index.mjs.map +1 -1
- package/dist/esm/llm/bedrock/toolCache.mjs +3 -2
- package/dist/esm/llm/bedrock/toolCache.mjs.map +1 -1
- package/dist/esm/llm/google/index.mjs +4 -2
- package/dist/esm/llm/google/index.mjs.map +1 -1
- package/dist/esm/llm/init.mjs +8 -5
- package/dist/esm/llm/init.mjs.map +1 -1
- package/dist/esm/llm/invoke.mjs +9 -2
- package/dist/esm/llm/invoke.mjs.map +1 -1
- package/dist/esm/llm/mistral/index.mjs +3 -1
- package/dist/esm/llm/mistral/index.mjs.map +1 -1
- package/dist/esm/llm/openai/index.mjs +31 -9
- package/dist/esm/llm/openai/index.mjs.map +1 -1
- package/dist/esm/llm/openrouter/index.mjs +3 -1
- package/dist/esm/llm/openrouter/index.mjs.map +1 -1
- package/dist/esm/llm/openrouter/toolCache.mjs +3 -2
- package/dist/esm/llm/openrouter/toolCache.mjs.map +1 -1
- package/dist/esm/llm/prepareProviderRequest.mjs +7 -4
- package/dist/esm/llm/prepareProviderRequest.mjs.map +1 -1
- package/dist/esm/llm/providerRegistry.mjs +76 -0
- package/dist/esm/llm/providerRegistry.mjs.map +1 -0
- package/dist/esm/llm/providers.eager.mjs +22 -0
- package/dist/esm/llm/providers.eager.mjs.map +1 -0
- package/dist/esm/llm/providers.mjs +38 -28
- package/dist/esm/llm/providers.mjs.map +1 -1
- package/dist/esm/llm/request.mjs +6 -4
- package/dist/esm/llm/request.mjs.map +1 -1
- package/dist/esm/llm/truncation.mjs +2 -1
- package/dist/esm/llm/truncation.mjs.map +1 -1
- package/dist/esm/llm/vertexai/index.mjs +8 -1
- package/dist/esm/llm/vertexai/index.mjs.map +1 -1
- package/dist/esm/main.mjs +12 -13
- package/dist/esm/messages/core.mjs +9 -5
- package/dist/esm/messages/core.mjs.map +1 -1
- package/dist/esm/messages/format.mjs.map +1 -1
- package/dist/esm/messages/prune.mjs +50 -13
- package/dist/esm/messages/prune.mjs.map +1 -1
- package/dist/esm/provider-registration.mjs +3 -0
- package/dist/esm/run.mjs +10 -5
- package/dist/esm/run.mjs.map +1 -1
- package/dist/esm/stream.mjs +1 -1
- package/dist/esm/stream.mjs.map +1 -1
- package/dist/esm/summarization/node.mjs +2 -2
- package/dist/esm/summarization/node.mjs.map +1 -1
- package/dist/esm/tools/Calculator.mjs +7 -2
- package/dist/esm/tools/Calculator.mjs.map +1 -1
- package/dist/esm/tools/CodeExecutor.mjs +1 -1
- package/dist/esm/utils/llm.mjs +21 -5
- package/dist/esm/utils/llm.mjs.map +1 -1
- package/dist/types/agents/AgentContext.d.ts +5 -5
- package/dist/types/index.d.ts +5 -3
- package/dist/types/lazyRequire.d.ts +8 -0
- package/dist/types/llm/contextOverflowRecovery.d.ts +2 -2
- package/dist/types/llm/init.d.ts +21 -14
- package/dist/types/llm/invoke.d.ts +5 -6
- package/dist/types/llm/prepareProviderRequest.d.ts +5 -6
- package/dist/types/llm/providerRegistry.d.ts +22 -0
- package/dist/types/llm/providers.d.ts +4 -5
- package/dist/types/llm/providers.eager.d.ts +1 -0
- package/dist/types/llm/request.d.ts +2 -3
- package/dist/types/llm/truncation.d.ts +2 -2
- package/dist/types/messages/core.d.ts +3 -2
- package/dist/types/messages/format.d.ts +3 -3
- package/dist/types/messages/prune.d.ts +8 -6
- package/dist/types/provider-registration.d.ts +15 -0
- package/dist/types/stream.d.ts +1 -2
- package/dist/types/summarization/node.d.ts +1 -2
- package/dist/types/types/activityLabel.d.ts +3 -4
- package/dist/types/types/graph.d.ts +4 -5
- package/dist/types/types/llm.d.ts +54 -13
- package/dist/types/types/reasoningLabel.d.ts +2 -3
- package/dist/types/types/run.d.ts +3 -3
- package/dist/types/types/summarize.d.ts +2 -2
- package/dist/types/utils/errors.d.ts +3 -3
- package/dist/types/utils/llm.d.ts +14 -4
- package/dist/types/utils/llmConfig.d.ts +2 -2
- package/package.json +66 -1
- package/src/agents/AgentContext.ts +27 -26
- package/src/graphs/Graph.ts +16 -22
- package/src/index.ts +8 -3
- package/src/lazyRequire.ts +67 -0
- package/src/llm/bedrock/toolCache.ts +6 -2
- package/src/llm/contextOverflowRecovery.ts +2 -2
- package/src/llm/init.ts +55 -25
- package/src/llm/invoke.ts +36 -21
- package/src/llm/openrouter/toolCache.ts +8 -2
- package/src/llm/prepareProviderRequest.ts +19 -18
- package/src/llm/providerRegistry.ts +174 -0
- package/src/llm/providers.eager.ts +24 -0
- package/src/llm/providers.ts +99 -42
- package/src/llm/request.ts +10 -6
- package/src/llm/truncation.ts +9 -3
- package/src/messages/core.ts +18 -13
- package/src/messages/format.ts +14 -16
- package/src/messages/prune.ts +108 -28
- package/src/provider-registration.ts +29 -0
- package/src/run.ts +15 -7
- package/src/session/AgentSession.ts +1 -1
- package/src/stream.ts +7 -8
- package/src/summarization/node.ts +7 -7
- package/src/tools/Calculator.ts +9 -2
- package/src/types/activityLabel.ts +3 -4
- package/src/types/graph.ts +5 -5
- package/src/types/llm.ts +95 -13
- package/src/types/reasoningLabel.ts +2 -3
- package/src/types/run.ts +3 -3
- package/src/types/summarize.ts +2 -2
- package/src/utils/errors.ts +3 -3
- package/src/utils/llm.ts +61 -15
- package/src/utils/llmConfig.ts +4 -4
package/src/llm/invoke.ts
CHANGED
|
@@ -13,14 +13,9 @@ import type { ToolCall } from '@langchain/core/messages/tool';
|
|
|
13
13
|
import type { BaseMessage } from '@langchain/core/messages';
|
|
14
14
|
import type { ToolOutputReferenceRegistry } from '@/tools/toolOutputReferences';
|
|
15
15
|
import type { PreparedProviderRequest } from '@/llm/prepareProviderRequest';
|
|
16
|
-
import type { StreamLimitState } from '@/llm/streamLimits';
|
|
17
16
|
import type { ContextOverflowContext } from '@/utils/errors';
|
|
17
|
+
import type { StreamLimitState } from '@/llm/streamLimits';
|
|
18
18
|
import type * as t from '@/types';
|
|
19
|
-
import {
|
|
20
|
-
modifyDeltaProperties,
|
|
21
|
-
} from '@/messages';
|
|
22
|
-
import { ChatModelStreamHandler, dispatchesChatModelStream } from '@/stream';
|
|
23
|
-
import { Constants, ContentTypes, GraphEvents, Providers } from '@/common';
|
|
24
19
|
import {
|
|
25
20
|
enforceStreamLimitsForWireChunk,
|
|
26
21
|
registerActiveStreamLimitGeneration,
|
|
@@ -35,11 +30,17 @@ import {
|
|
|
35
30
|
assertPreparedProviderRequestFor,
|
|
36
31
|
prepareProviderRequest,
|
|
37
32
|
} from '@/llm/prepareProviderRequest';
|
|
33
|
+
import {
|
|
34
|
+
getProviderFamily,
|
|
35
|
+
providerUsesManualToolStream,
|
|
36
|
+
} from '@/llm/providers';
|
|
37
|
+
import { ChatModelStreamHandler, dispatchesChatModelStream } from '@/stream';
|
|
38
|
+
import { Constants, ContentTypes, GraphEvents, Providers } from '@/common';
|
|
38
39
|
import { assertNotTruncatedToolCall } from '@/llm/truncation';
|
|
39
|
-
import { manualToolStreamProviders } from '@/llm/providers';
|
|
40
40
|
import { safeDispatchCustomEvent } from '@/utils/events';
|
|
41
41
|
import { getContextOverflowInfo } from '@/utils/errors';
|
|
42
42
|
import { appendCallbacks } from '@/utils/callbacks';
|
|
43
|
+
import { modifyDeltaProperties } from '@/messages';
|
|
43
44
|
import { canSealPreempt } from '@/llm/preempt';
|
|
44
45
|
import { initializeModel } from '@/llm/init';
|
|
45
46
|
|
|
@@ -105,6 +106,19 @@ export type OnChunk = (
|
|
|
105
106
|
/** Unique per-model-attempt sequence; see the stamp in `attemptInvoke`. */
|
|
106
107
|
let streamLimitAttemptSeq = 0;
|
|
107
108
|
|
|
109
|
+
function getManualToolStreamNormalizationProvider(
|
|
110
|
+
provider: t.ProviderName
|
|
111
|
+
): t.ProviderName {
|
|
112
|
+
const family = getProviderFamily(provider);
|
|
113
|
+
if (family === 'anthropic') {
|
|
114
|
+
return Providers.ANTHROPIC;
|
|
115
|
+
}
|
|
116
|
+
if (family === 'bedrock') {
|
|
117
|
+
return Providers.BEDROCK;
|
|
118
|
+
}
|
|
119
|
+
return provider;
|
|
120
|
+
}
|
|
121
|
+
|
|
108
122
|
/**
|
|
109
123
|
* The registered handler that owns content-part dispatch, if any.
|
|
110
124
|
*
|
|
@@ -136,7 +150,7 @@ function removeOpenRouterFinalReasoningReplayContent({
|
|
|
136
150
|
}: {
|
|
137
151
|
current?: AIMessageChunk;
|
|
138
152
|
next: AIMessageChunk;
|
|
139
|
-
provider:
|
|
153
|
+
provider: t.ProviderName;
|
|
140
154
|
}): AIMessageChunk {
|
|
141
155
|
const content = getOpenRouterFinalReasoningContent({
|
|
142
156
|
current,
|
|
@@ -161,7 +175,7 @@ function getOpenRouterFinalReasoningContent({
|
|
|
161
175
|
}: {
|
|
162
176
|
current?: AIMessageChunk;
|
|
163
177
|
next: AIMessageChunk;
|
|
164
|
-
provider:
|
|
178
|
+
provider: t.ProviderName;
|
|
165
179
|
}): string | undefined {
|
|
166
180
|
if (
|
|
167
181
|
provider !== Providers.OPENROUTER ||
|
|
@@ -197,7 +211,7 @@ function getStreamHandlingChunk({
|
|
|
197
211
|
}: {
|
|
198
212
|
current?: AIMessageChunk;
|
|
199
213
|
next: AIMessageChunk;
|
|
200
|
-
provider:
|
|
214
|
+
provider: t.ProviderName;
|
|
201
215
|
}): AIMessageChunk | undefined {
|
|
202
216
|
const content = getOpenRouterFinalReasoningContent({
|
|
203
217
|
current,
|
|
@@ -473,7 +487,7 @@ function appendStreamChunk({
|
|
|
473
487
|
}: {
|
|
474
488
|
current?: AIMessageChunk;
|
|
475
489
|
next: AIMessageChunk;
|
|
476
|
-
provider:
|
|
490
|
+
provider: t.ProviderName;
|
|
477
491
|
}): AIMessageChunk {
|
|
478
492
|
if (current == null) {
|
|
479
493
|
return next;
|
|
@@ -514,11 +528,11 @@ type AttemptInvokeParams = AttemptInvokeCommonParams &
|
|
|
514
528
|
request?: never;
|
|
515
529
|
model: t.ChatModel;
|
|
516
530
|
messages: BaseMessage[];
|
|
517
|
-
provider:
|
|
531
|
+
provider: t.ProviderName;
|
|
518
532
|
}
|
|
519
533
|
);
|
|
520
534
|
|
|
521
|
-
function resolveAttemptProvider(params: AttemptInvokeParams):
|
|
535
|
+
function resolveAttemptProvider(params: AttemptInvokeParams): t.ProviderName {
|
|
522
536
|
if (params.request != null) {
|
|
523
537
|
return params.request.provider;
|
|
524
538
|
}
|
|
@@ -586,9 +600,7 @@ export async function attemptInvoke(
|
|
|
586
600
|
: undefined;
|
|
587
601
|
const generationKey =
|
|
588
602
|
leaseTarget != null
|
|
589
|
-
? resolveGenerationKey(
|
|
590
|
-
stampedConfig.metadata as Record<string, unknown>
|
|
591
|
-
)
|
|
603
|
+
? resolveGenerationKey(stampedConfig.metadata as Record<string, unknown>)
|
|
592
604
|
: undefined;
|
|
593
605
|
if (leaseTarget != null && generationKey != null) {
|
|
594
606
|
registerActiveStreamLimitGeneration(leaseTarget, generationKey);
|
|
@@ -809,8 +821,11 @@ async function attemptInvokeBody(
|
|
|
809
821
|
}
|
|
810
822
|
}
|
|
811
823
|
|
|
812
|
-
if (
|
|
813
|
-
finalChunk = modifyDeltaProperties(
|
|
824
|
+
if (providerUsesManualToolStream(provider)) {
|
|
825
|
+
finalChunk = modifyDeltaProperties(
|
|
826
|
+
getManualToolStreamNormalizationProvider(provider),
|
|
827
|
+
finalChunk
|
|
828
|
+
);
|
|
814
829
|
}
|
|
815
830
|
|
|
816
831
|
if (preempted && finalChunk != null) {
|
|
@@ -857,7 +872,7 @@ async function attemptInvokeBody(
|
|
|
857
872
|
* differ, which is the whole reason a fallback exists.
|
|
858
873
|
*/
|
|
859
874
|
export interface FallbackErrorContext {
|
|
860
|
-
provider:
|
|
875
|
+
provider: t.ProviderName;
|
|
861
876
|
clientOptions?: t.ClientOptions;
|
|
862
877
|
maxContextTokens?: number;
|
|
863
878
|
}
|
|
@@ -968,7 +983,7 @@ export async function tryFallbackProviders({
|
|
|
968
983
|
prepareProviderRequest?: (input: {
|
|
969
984
|
model: t.ChatModel;
|
|
970
985
|
messages: BaseMessage[];
|
|
971
|
-
provider:
|
|
986
|
+
provider: t.ProviderName;
|
|
972
987
|
clientOptions?: t.ClientOptions;
|
|
973
988
|
maxContextTokens?: number;
|
|
974
989
|
config?: RunnableConfig;
|
|
@@ -977,7 +992,7 @@ export async function tryFallbackProviders({
|
|
|
977
992
|
prepareProviderMessages?: (input: {
|
|
978
993
|
model: t.ChatModel;
|
|
979
994
|
messages: BaseMessage[];
|
|
980
|
-
provider:
|
|
995
|
+
provider: t.ProviderName;
|
|
981
996
|
clientOptions?: t.ClientOptions;
|
|
982
997
|
maxContextTokens?: number;
|
|
983
998
|
config?: RunnableConfig;
|
|
@@ -5,7 +5,13 @@ import {
|
|
|
5
5
|
buildAnthropicCacheControl,
|
|
6
6
|
type PromptCacheTtl,
|
|
7
7
|
} from '@/messages/cache';
|
|
8
|
-
import {
|
|
8
|
+
import { requireInternalModule } from '@/lazyRequire';
|
|
9
|
+
|
|
10
|
+
/** Loads with the first OpenRouter request rather than alongside every graph. */
|
|
11
|
+
const convertToOpenAITool = (
|
|
12
|
+
tool: BindToolsInput
|
|
13
|
+
): OpenAIClient.ChatCompletionTool =>
|
|
14
|
+
requireInternalModule<typeof import('@/llm/openai')>('llm/openai/index')._convertToOpenAITool(tool);
|
|
9
15
|
|
|
10
16
|
type OpenRouterCacheControl = { type: 'ephemeral'; ttl?: '1h' };
|
|
11
17
|
|
|
@@ -38,7 +44,7 @@ function hasDeferredMarker(tool: unknown): boolean {
|
|
|
38
44
|
}
|
|
39
45
|
|
|
40
46
|
function toOpenRouterTool(tool: unknown): OpenRouterToolWithCacheControl {
|
|
41
|
-
const converted =
|
|
47
|
+
const converted = convertToOpenAITool(
|
|
42
48
|
tool as BindToolsInput
|
|
43
49
|
) as OpenRouterToolWithCacheControl;
|
|
44
50
|
|
|
@@ -14,7 +14,6 @@ import {
|
|
|
14
14
|
} from '@/messages/core';
|
|
15
15
|
import {
|
|
16
16
|
coalesceAdjacentUserTurns,
|
|
17
|
-
strictAlternationProviders,
|
|
18
17
|
appendPredecessorHandoffCue,
|
|
19
18
|
removePredecessorHandoffCue,
|
|
20
19
|
} from '@/messages';
|
|
@@ -23,8 +22,10 @@ import {
|
|
|
23
22
|
stripBedrockCacheControl,
|
|
24
23
|
} from '@/messages/cache';
|
|
25
24
|
import { annotateMessagesForLLM } from '@/tools/toolOutputReferences';
|
|
26
|
-
import {
|
|
25
|
+
import { providerRequiresStrictAlternation } from '@/llm/providers';
|
|
27
26
|
import { isAnthropicLike, isOpenAILike } from '@/utils/llm';
|
|
27
|
+
import { getProviderFamily } from '@/llm/providerRegistry';
|
|
28
|
+
import { Providers } from '@/common';
|
|
28
29
|
|
|
29
30
|
const preparedProviderRequestBrand = Symbol('PreparedProviderRequest');
|
|
30
31
|
|
|
@@ -43,7 +44,7 @@ export interface ProviderPayloadMeasurement {
|
|
|
43
44
|
export interface PreparedProviderRequest {
|
|
44
45
|
readonly model: t.ChatModel;
|
|
45
46
|
readonly modelId?: string;
|
|
46
|
-
readonly provider:
|
|
47
|
+
readonly provider: t.ProviderName;
|
|
47
48
|
readonly projectionMode: ProviderMessageProjectionMode;
|
|
48
49
|
readonly messages: BaseMessage[];
|
|
49
50
|
readonly measurement?: ProviderPayloadMeasurement;
|
|
@@ -63,7 +64,7 @@ export interface ProviderRequestContext {
|
|
|
63
64
|
export interface PrepareProviderRequestParams {
|
|
64
65
|
model: t.ChatModel;
|
|
65
66
|
messages: BaseMessage[];
|
|
66
|
-
provider:
|
|
67
|
+
provider: t.ProviderName;
|
|
67
68
|
context?: ProviderRequestContext;
|
|
68
69
|
config?: RunnableConfig;
|
|
69
70
|
maxToolResultChars?: number;
|
|
@@ -72,7 +73,7 @@ export interface PrepareProviderRequestParams {
|
|
|
72
73
|
|
|
73
74
|
export function usesNativeOpenAIResponses(
|
|
74
75
|
model: t.ChatModel,
|
|
75
|
-
provider:
|
|
76
|
+
provider: t.ProviderName,
|
|
76
77
|
callOptions?: unknown
|
|
77
78
|
): boolean {
|
|
78
79
|
if (!isOpenAILike(provider)) {
|
|
@@ -142,7 +143,7 @@ export function usesNativeOpenAIResponses(
|
|
|
142
143
|
|
|
143
144
|
function resolveProviderMessageProjectionMode(
|
|
144
145
|
model: t.ChatModel,
|
|
145
|
-
provider:
|
|
146
|
+
provider: t.ProviderName,
|
|
146
147
|
callOptions?: unknown
|
|
147
148
|
): ProviderMessageProjectionMode {
|
|
148
149
|
return usesNativeOpenAIResponses(model, provider, callOptions)
|
|
@@ -153,18 +154,16 @@ function resolveProviderMessageProjectionMode(
|
|
|
153
154
|
interface ProjectMessagesForProviderParams {
|
|
154
155
|
model: t.ChatModel;
|
|
155
156
|
messages: BaseMessage[];
|
|
156
|
-
provider:
|
|
157
|
+
provider: t.ProviderName;
|
|
157
158
|
maxToolResultChars?: number;
|
|
158
159
|
callOptions?: unknown;
|
|
159
160
|
}
|
|
160
161
|
|
|
161
|
-
function projectMessagesForProviderMode(
|
|
162
|
-
messages,
|
|
163
|
-
|
|
164
|
-
maxToolResultChars,
|
|
165
|
-
}: ProjectMessagesForProviderParams,
|
|
166
|
-
projectionMode: ProviderMessageProjectionMode
|
|
162
|
+
function projectMessagesForProviderMode(
|
|
163
|
+
{ messages, provider, maxToolResultChars }: ProjectMessagesForProviderParams,
|
|
164
|
+
projectionMode: ProviderMessageProjectionMode
|
|
167
165
|
): BaseMessage[] {
|
|
166
|
+
const providerFamily = getProviderFamily(provider);
|
|
168
167
|
const nativeOpenAIResponses = projectionMode === 'openai-responses';
|
|
169
168
|
const providerInputMessages = projectToolStreamContentForProvider(
|
|
170
169
|
messages,
|
|
@@ -197,7 +196,7 @@ projectionMode: ProviderMessageProjectionMode
|
|
|
197
196
|
)
|
|
198
197
|
);
|
|
199
198
|
}
|
|
200
|
-
if (provider === Providers.ANTHROPIC) {
|
|
199
|
+
if (provider === Providers.ANTHROPIC || providerFamily === 'anthropic') {
|
|
201
200
|
return projectComputerCallOutputsToText(
|
|
202
201
|
projectSingleTextToolOutputsToText(
|
|
203
202
|
stripBedrockCacheControl(providerInputMessages),
|
|
@@ -205,7 +204,7 @@ projectionMode: ProviderMessageProjectionMode
|
|
|
205
204
|
)
|
|
206
205
|
);
|
|
207
206
|
}
|
|
208
|
-
if (provider === Providers.BEDROCK) {
|
|
207
|
+
if (provider === Providers.BEDROCK || providerFamily === 'bedrock') {
|
|
209
208
|
return stripAnthropicCacheControl(
|
|
210
209
|
projectComputerCallOutputsToText(
|
|
211
210
|
projectCacheControlledToolOutputsToText(
|
|
@@ -310,7 +309,7 @@ export function prepareProviderRequest({
|
|
|
310
309
|
: (message): boolean => isRunProduced.call(context, message)
|
|
311
310
|
)
|
|
312
311
|
: removePredecessorHandoffCue(annotated);
|
|
313
|
-
const preparedMessages =
|
|
312
|
+
const preparedMessages = providerRequiresStrictAlternation(provider)
|
|
314
313
|
? coalesceAdjacentUserTurns(cued)
|
|
315
314
|
: cued;
|
|
316
315
|
|
|
@@ -332,7 +331,7 @@ export function prepareProviderRequest({
|
|
|
332
331
|
export function assertPreparedProviderRequestFor(
|
|
333
332
|
request: PreparedProviderRequest,
|
|
334
333
|
model: t.ChatModel,
|
|
335
|
-
provider:
|
|
334
|
+
provider: t.ProviderName,
|
|
336
335
|
config?: RunnableConfig
|
|
337
336
|
): void {
|
|
338
337
|
if (
|
|
@@ -344,7 +343,9 @@ export function assertPreparedProviderRequestFor(
|
|
|
344
343
|
throw new Error('Prepared provider request does not match serving model');
|
|
345
344
|
}
|
|
346
345
|
if (request.provider !== provider) {
|
|
347
|
-
throw new Error(
|
|
346
|
+
throw new Error(
|
|
347
|
+
'Prepared provider request does not match serving provider'
|
|
348
|
+
);
|
|
348
349
|
}
|
|
349
350
|
if (
|
|
350
351
|
request.projectionMode !==
|
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
import type { BaseChatModel } from '@langchain/core/language_models/chat_models';
|
|
2
|
+
import type {
|
|
3
|
+
ProviderFamily,
|
|
4
|
+
ProviderRegistrationOptions,
|
|
5
|
+
} from '../provider-registration';
|
|
6
|
+
import type { ProviderModelConstructor, ProviderName } from '@/types';
|
|
7
|
+
|
|
8
|
+
type ProviderModelClass = new (config: never) => BaseChatModel;
|
|
9
|
+
|
|
10
|
+
interface StoredProviderRegistration {
|
|
11
|
+
model?: ProviderModelClass;
|
|
12
|
+
/** Built-ins defer their provider SDK import until the first model request;
|
|
13
|
+
* the resolved class is validated once and memoized into `model`. */
|
|
14
|
+
loadModel?: () => ProviderModelClass;
|
|
15
|
+
family: ProviderFamily;
|
|
16
|
+
manualToolStream: boolean;
|
|
17
|
+
strictAlternation: boolean;
|
|
18
|
+
owner: symbol;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
interface ProviderRegistryGlobal {
|
|
22
|
+
[key: symbol]: Map<ProviderName, StoredProviderRegistration> | undefined;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
const PROVIDER_REGISTRY_KEY = Symbol.for(
|
|
26
|
+
'@librechat/agents:providerRegistry:v1'
|
|
27
|
+
);
|
|
28
|
+
const providerRegistryGlobal = globalThis as ProviderRegistryGlobal;
|
|
29
|
+
const registeredProviders =
|
|
30
|
+
providerRegistryGlobal[PROVIDER_REGISTRY_KEY] ??
|
|
31
|
+
new Map<ProviderName, StoredProviderRegistration>();
|
|
32
|
+
providerRegistryGlobal[PROVIDER_REGISTRY_KEY] = registeredProviders;
|
|
33
|
+
const builtInProviders = new Map<ProviderName, StoredProviderRegistration>();
|
|
34
|
+
|
|
35
|
+
function normalizeProvider(provider: ProviderName): ProviderName {
|
|
36
|
+
if (typeof provider !== 'string' || provider.trim() === '') {
|
|
37
|
+
throw new TypeError('LLM provider name must be a non-empty string');
|
|
38
|
+
}
|
|
39
|
+
if (provider !== provider.trim()) {
|
|
40
|
+
throw new TypeError(
|
|
41
|
+
'LLM provider name must not have surrounding whitespace'
|
|
42
|
+
);
|
|
43
|
+
}
|
|
44
|
+
return provider;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function isConstructible<T extends abstract new (...args: never[]) => object>(
|
|
48
|
+
value: T
|
|
49
|
+
): boolean {
|
|
50
|
+
try {
|
|
51
|
+
Reflect.construct(String, [], value);
|
|
52
|
+
return true;
|
|
53
|
+
} catch {
|
|
54
|
+
return false;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
function createRegistration<
|
|
59
|
+
TOptions extends object,
|
|
60
|
+
TModel extends BaseChatModel,
|
|
61
|
+
>(
|
|
62
|
+
provider: ProviderName,
|
|
63
|
+
options: ProviderRegistrationOptions<TOptions, TModel>
|
|
64
|
+
): StoredProviderRegistration {
|
|
65
|
+
if (typeof options.model !== 'function' || !isConstructible(options.model)) {
|
|
66
|
+
throw new TypeError(`LLM provider constructor is invalid: ${provider}`);
|
|
67
|
+
}
|
|
68
|
+
return {
|
|
69
|
+
model: options.model,
|
|
70
|
+
family: options.family ?? 'generic',
|
|
71
|
+
manualToolStream: options.manualToolStream ?? false,
|
|
72
|
+
strictAlternation: options.strictAlternation ?? false,
|
|
73
|
+
owner: Symbol(provider),
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
function getRegistration(
|
|
78
|
+
provider: ProviderName
|
|
79
|
+
): StoredProviderRegistration | undefined {
|
|
80
|
+
return builtInProviders.get(provider) ?? registeredProviders.get(provider);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/** Registers one host provider until the returned disposer is called. */
|
|
84
|
+
export function registerProvider<
|
|
85
|
+
TOptions extends object,
|
|
86
|
+
TModel extends BaseChatModel,
|
|
87
|
+
>(options: ProviderRegistrationOptions<TOptions, TModel>): () => void {
|
|
88
|
+
const provider = normalizeProvider(options.provider);
|
|
89
|
+
if (getRegistration(provider) != null) {
|
|
90
|
+
throw new Error(`LLM provider already registered: ${provider}`);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
const registration = createRegistration(provider, options);
|
|
94
|
+
registeredProviders.set(provider, registration);
|
|
95
|
+
|
|
96
|
+
return (): void => {
|
|
97
|
+
if (registeredProviders.get(provider)?.owner === registration.owner) {
|
|
98
|
+
registeredProviders.delete(provider);
|
|
99
|
+
}
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/** Initializes one built-in for the current package module graph. */
|
|
104
|
+
export function registerBuiltInProvider<
|
|
105
|
+
TOptions extends object,
|
|
106
|
+
TModel extends BaseChatModel,
|
|
107
|
+
>(options: ProviderRegistrationOptions<TOptions, TModel>): void {
|
|
108
|
+
const provider = normalizeProvider(options.provider);
|
|
109
|
+
if (builtInProviders.has(provider)) {
|
|
110
|
+
throw new Error(`LLM provider already registered: ${provider}`);
|
|
111
|
+
}
|
|
112
|
+
builtInProviders.set(provider, createRegistration(provider, options));
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
interface BuiltInProviderLoaderOptions {
|
|
116
|
+
provider: ProviderName;
|
|
117
|
+
loadModel: () => ProviderModelClass;
|
|
118
|
+
family?: ProviderFamily;
|
|
119
|
+
manualToolStream?: boolean;
|
|
120
|
+
strictAlternation?: boolean;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/** Registers a built-in whose provider SDK loads on first use, not at import time. */
|
|
124
|
+
export function registerBuiltInProviderLoader(
|
|
125
|
+
options: BuiltInProviderLoaderOptions
|
|
126
|
+
): void {
|
|
127
|
+
const provider = normalizeProvider(options.provider);
|
|
128
|
+
if (builtInProviders.has(provider)) {
|
|
129
|
+
throw new Error(`LLM provider already registered: ${provider}`);
|
|
130
|
+
}
|
|
131
|
+
builtInProviders.set(provider, {
|
|
132
|
+
loadModel: options.loadModel,
|
|
133
|
+
family: options.family ?? 'generic',
|
|
134
|
+
manualToolStream: options.manualToolStream ?? false,
|
|
135
|
+
strictAlternation: options.strictAlternation ?? false,
|
|
136
|
+
owner: Symbol(provider),
|
|
137
|
+
});
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
export function getRegisteredChatModelClass<P extends ProviderName>(
|
|
141
|
+
provider: P
|
|
142
|
+
): ProviderModelConstructor<P> {
|
|
143
|
+
const registration = getRegistration(provider);
|
|
144
|
+
if (!registration) {
|
|
145
|
+
throw new Error(`Unsupported LLM provider: ${provider}`);
|
|
146
|
+
}
|
|
147
|
+
if (registration.model == null && registration.loadModel != null) {
|
|
148
|
+
const loaded = registration.loadModel();
|
|
149
|
+
if (typeof loaded !== 'function' || !isConstructible(loaded)) {
|
|
150
|
+
throw new TypeError(`LLM provider constructor is invalid: ${provider}`);
|
|
151
|
+
}
|
|
152
|
+
registration.model = loaded;
|
|
153
|
+
}
|
|
154
|
+
if (registration.model == null) {
|
|
155
|
+
throw new Error(`Unsupported LLM provider: ${provider}`);
|
|
156
|
+
}
|
|
157
|
+
return registration.model as ProviderModelConstructor<P>;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
export function getProviderFamily(
|
|
161
|
+
provider: ProviderName
|
|
162
|
+
): ProviderFamily | undefined {
|
|
163
|
+
return getRegistration(provider)?.family;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
export function providerUsesManualToolStream(provider: ProviderName): boolean {
|
|
167
|
+
return getRegistration(provider)?.manualToolStream ?? false;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
export function providerRequiresStrictAlternation(
|
|
171
|
+
provider: ProviderName
|
|
172
|
+
): boolean {
|
|
173
|
+
return getRegistration(provider)?.strictAlternation ?? false;
|
|
174
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import * as openai from '@/llm/openai';
|
|
2
|
+
import * as google from '@/llm/google';
|
|
3
|
+
import * as bedrock from '@/llm/bedrock';
|
|
4
|
+
import * as mistral from '@/llm/mistral';
|
|
5
|
+
import * as vertexai from '@/llm/vertexai';
|
|
6
|
+
import * as anthropic from '@/llm/anthropic';
|
|
7
|
+
import * as openrouter from '@/llm/openrouter';
|
|
8
|
+
import { registerSourceModeModules } from '@/lazyRequire';
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Source-mode counterpart of the lazy provider loading the built package uses: commands
|
|
12
|
+
* that run the TypeScript directly import this module first, so every lazily loadable
|
|
13
|
+
* provider module is loaded through the active ESM loader — one module graph, one set of
|
|
14
|
+
* class identities — and registered with the lazy-require seam.
|
|
15
|
+
*/
|
|
16
|
+
registerSourceModeModules({
|
|
17
|
+
'llm/openai/index': openai,
|
|
18
|
+
'llm/google/index': google,
|
|
19
|
+
'llm/bedrock/index': bedrock,
|
|
20
|
+
'llm/mistral/index': mistral,
|
|
21
|
+
'llm/vertexai/index': vertexai,
|
|
22
|
+
'llm/anthropic/index': anthropic,
|
|
23
|
+
'llm/openrouter/index': openrouter,
|
|
24
|
+
});
|
package/src/llm/providers.ts
CHANGED
|
@@ -1,52 +1,109 @@
|
|
|
1
|
-
|
|
2
|
-
import {
|
|
3
|
-
import type {
|
|
4
|
-
|
|
5
|
-
ProviderOptionsMap,
|
|
6
|
-
ChatModelMap,
|
|
7
|
-
} from '@/types';
|
|
1
|
+
import type { ProviderModelConstructor, ProviderName } from '@/types';
|
|
2
|
+
import { requireInternalModule } from '@/lazyRequire';
|
|
3
|
+
import type { ProviderFamily } from '../provider-registration';
|
|
4
|
+
import type { BaseChatModel } from '@langchain/core/language_models/chat_models';
|
|
8
5
|
import {
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
ChatOpenAI,
|
|
13
|
-
ChatXAI,
|
|
14
|
-
} from '@/llm/openai';
|
|
15
|
-
import { CustomChatGoogleGenerativeAI } from '@/llm/google';
|
|
16
|
-
import { CustomChatBedrockConverse } from '@/llm/bedrock';
|
|
17
|
-
import { CustomAnthropic } from '@/llm/anthropic';
|
|
18
|
-
import { ChatOpenRouter } from '@/llm/openrouter';
|
|
19
|
-
import { ChatVertexAI } from '@/llm/vertexai';
|
|
6
|
+
getRegisteredChatModelClass,
|
|
7
|
+
registerBuiltInProviderLoader,
|
|
8
|
+
} from '@/llm/providerRegistry';
|
|
20
9
|
import { Providers } from '@/common';
|
|
21
10
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
[Providers.MOONSHOT]: ChatMoonshot,
|
|
11
|
+
/**
|
|
12
|
+
* Built-in provider SDKs load on first model request, not at import time: eagerly
|
|
13
|
+
* importing every provider cost hundreds of milliseconds of boot in hosts that
|
|
14
|
+
* configure one or two of them. `createRequire` keeps resolution synchronous and
|
|
15
|
+
* correct from both the CJS and ESM builds.
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
type ProviderModelClass = new (config: never) => BaseChatModel;
|
|
19
|
+
|
|
20
|
+
type BuiltInProviderTraits = {
|
|
21
|
+
family: ProviderFamily;
|
|
22
|
+
manualToolStream?: boolean;
|
|
23
|
+
strictAlternation?: boolean;
|
|
36
24
|
};
|
|
37
25
|
|
|
38
|
-
|
|
26
|
+
function initializeBuiltInProvider(
|
|
27
|
+
provider: Providers,
|
|
28
|
+
loadModel: () => ProviderModelClass,
|
|
29
|
+
traits: BuiltInProviderTraits
|
|
30
|
+
): void {
|
|
31
|
+
registerBuiltInProviderLoader({
|
|
32
|
+
provider,
|
|
33
|
+
loadModel,
|
|
34
|
+
...traits,
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
const fromOpenAI =
|
|
39
|
+
(name: string) => (): ProviderModelClass =>
|
|
40
|
+
(requireInternalModule<Record<string, ProviderModelClass>>('llm/openai/index'))[
|
|
41
|
+
name
|
|
42
|
+
];
|
|
43
|
+
|
|
44
|
+
initializeBuiltInProvider(Providers.XAI, fromOpenAI('ChatXAI'), { family: 'openai' });
|
|
45
|
+
initializeBuiltInProvider(Providers.OPENAI, fromOpenAI('ChatOpenAI'), { family: 'openai' });
|
|
46
|
+
initializeBuiltInProvider(Providers.AZURE, fromOpenAI('AzureChatOpenAI'), {
|
|
47
|
+
family: 'openai',
|
|
48
|
+
});
|
|
49
|
+
initializeBuiltInProvider(
|
|
50
|
+
Providers.VERTEXAI,
|
|
51
|
+
() => (requireInternalModule<typeof import('@/llm/vertexai')>('llm/vertexai/index')).ChatVertexAI,
|
|
52
|
+
{ family: 'google' }
|
|
53
|
+
);
|
|
54
|
+
initializeBuiltInProvider(Providers.DEEPSEEK, fromOpenAI('ChatDeepSeek'), {
|
|
55
|
+
family: 'openai',
|
|
56
|
+
});
|
|
57
|
+
const loadMistral = (): ProviderModelClass =>
|
|
58
|
+
(requireInternalModule<typeof import('@/llm/mistral')>('llm/mistral/index')).CustomChatMistralAI;
|
|
59
|
+
initializeBuiltInProvider(Providers.MISTRALAI, loadMistral, {
|
|
60
|
+
family: 'mistral',
|
|
61
|
+
strictAlternation: true,
|
|
62
|
+
});
|
|
63
|
+
initializeBuiltInProvider(Providers.MISTRAL, loadMistral, {
|
|
64
|
+
family: 'mistral',
|
|
65
|
+
strictAlternation: true,
|
|
66
|
+
});
|
|
67
|
+
initializeBuiltInProvider(
|
|
39
68
|
Providers.ANTHROPIC,
|
|
69
|
+
() => (requireInternalModule<typeof import('@/llm/anthropic')>('llm/anthropic/index')).CustomAnthropic,
|
|
70
|
+
{ family: 'anthropic', manualToolStream: true }
|
|
71
|
+
);
|
|
72
|
+
initializeBuiltInProvider(
|
|
73
|
+
Providers.OPENROUTER,
|
|
74
|
+
() =>
|
|
75
|
+
(requireInternalModule<typeof import('@/llm/openrouter')>('llm/openrouter/index')).ChatOpenRouter,
|
|
76
|
+
{ family: 'openai' }
|
|
77
|
+
);
|
|
78
|
+
initializeBuiltInProvider(
|
|
40
79
|
Providers.BEDROCK,
|
|
41
|
-
|
|
80
|
+
() =>
|
|
81
|
+
(requireInternalModule<typeof import('@/llm/bedrock')>('llm/bedrock/index'))
|
|
82
|
+
.CustomChatBedrockConverse,
|
|
83
|
+
{ family: 'bedrock', manualToolStream: true, strictAlternation: true }
|
|
84
|
+
);
|
|
85
|
+
initializeBuiltInProvider(
|
|
86
|
+
Providers.GOOGLE,
|
|
87
|
+
() =>
|
|
88
|
+
(requireInternalModule<typeof import('@/llm/google')>('llm/google/index'))
|
|
89
|
+
.CustomChatGoogleGenerativeAI,
|
|
90
|
+
{ family: 'google' }
|
|
91
|
+
);
|
|
92
|
+
initializeBuiltInProvider(Providers.MOONSHOT, fromOpenAI('ChatMoonshot'), {
|
|
93
|
+
family: 'generic',
|
|
94
|
+
});
|
|
42
95
|
|
|
43
|
-
export const getChatModelClass = <P extends
|
|
96
|
+
export const getChatModelClass = <P extends ProviderName>(
|
|
44
97
|
provider: P
|
|
45
|
-
):
|
|
46
|
-
const ChatModelClass = llmProviders[provider];
|
|
47
|
-
if (!ChatModelClass) {
|
|
48
|
-
throw new Error(`Unsupported LLM provider: ${provider}`);
|
|
49
|
-
}
|
|
98
|
+
): ProviderModelConstructor<P> => getRegisteredChatModelClass(provider);
|
|
50
99
|
|
|
51
|
-
|
|
52
|
-
|
|
100
|
+
export {
|
|
101
|
+
getProviderFamily,
|
|
102
|
+
providerRequiresStrictAlternation,
|
|
103
|
+
providerUsesManualToolStream,
|
|
104
|
+
registerProvider,
|
|
105
|
+
} from '@/llm/providerRegistry';
|
|
106
|
+
export type {
|
|
107
|
+
ProviderFamily,
|
|
108
|
+
ProviderRegistrationOptions,
|
|
109
|
+
} from '../provider-registration';
|