@librechat/agents 3.6.16 → 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/dist/cjs/_virtual/_rolldown/runtime.cjs +10 -0
- package/dist/cjs/graphs/Graph.cjs +5 -7
- 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 +6 -4
- package/dist/cjs/llm/init.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 +42 -2
- 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/providerRegistry.cjs +15 -3
- package/dist/cjs/llm/providerRegistry.cjs.map +1 -1
- package/dist/cjs/llm/providers.cjs +18 -22
- 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/vertexai/index.cjs +17 -0
- package/dist/cjs/llm/vertexai/index.cjs.map +1 -1
- package/dist/cjs/main.cjs +8 -10
- package/dist/cjs/messages/core.cjs +9 -4
- package/dist/cjs/messages/core.cjs.map +1 -1
- package/dist/cjs/messages/prune.cjs +42 -8
- package/dist/cjs/messages/prune.cjs.map +1 -1
- package/dist/cjs/run.cjs +7 -2
- package/dist/cjs/run.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 +16 -0
- package/dist/cjs/utils/llm.cjs.map +1 -1
- package/dist/esm/_virtual/_rolldown/runtime.mjs +14 -0
- package/dist/esm/graphs/Graph.mjs +4 -6
- 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 +7 -5
- package/dist/esm/llm/init.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 +32 -10
- 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/providerRegistry.mjs +15 -3
- package/dist/esm/llm/providerRegistry.mjs.map +1 -1
- 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 +19 -23
- package/dist/esm/llm/providers.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 +5 -8
- package/dist/esm/messages/core.mjs +9 -5
- package/dist/esm/messages/core.mjs.map +1 -1
- package/dist/esm/messages/prune.mjs +42 -9
- package/dist/esm/messages/prune.mjs.map +1 -1
- package/dist/esm/run.mjs +8 -3
- package/dist/esm/run.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 +15 -1
- package/dist/esm/utils/llm.mjs.map +1 -1
- package/dist/types/index.d.ts +3 -3
- package/dist/types/lazyRequire.d.ts +8 -0
- package/dist/types/llm/providerRegistry.d.ts +11 -0
- package/dist/types/llm/providers.eager.d.ts +1 -0
- package/dist/types/messages/core.d.ts +2 -0
- package/dist/types/messages/prune.d.ts +5 -4
- package/dist/types/utils/llm.d.ts +10 -0
- package/package.json +58 -1
- package/src/graphs/Graph.ts +2 -8
- package/src/index.ts +3 -3
- package/src/lazyRequire.ts +67 -0
- package/src/llm/bedrock/toolCache.ts +6 -2
- package/src/llm/init.ts +15 -8
- package/src/llm/openrouter/toolCache.ts +8 -2
- package/src/llm/providerRegistry.ts +41 -1
- package/src/llm/providers.eager.ts +24 -0
- package/src/llm/providers.ts +63 -49
- package/src/messages/core.ts +16 -11
- package/src/messages/prune.ts +86 -11
- package/src/run.ts +14 -6
- package/src/tools/Calculator.ts +9 -2
- package/src/utils/llm.ts +39 -0
package/src/llm/init.ts
CHANGED
|
@@ -1,9 +1,7 @@
|
|
|
1
|
-
import { ChatVertexAI } from '@langchain/google-vertexai';
|
|
2
1
|
import type { Runnable } from '@langchain/core/runnables';
|
|
3
2
|
import type * as t from '@/types';
|
|
4
|
-
import { ChatOpenAI, AzureChatOpenAI } from '@/llm/openai';
|
|
5
3
|
import { getChatModelClass } from '@/llm/providers';
|
|
6
|
-
import { isOpenAILike } from '@/utils';
|
|
4
|
+
import { isOpenAILike, isLibreChatOpenAIModel, constructorChainHasLcName } from '@/utils';
|
|
7
5
|
import { Providers } from '@/common';
|
|
8
6
|
|
|
9
7
|
type InitializeModelParams<P extends t.ProviderName> = {
|
|
@@ -30,6 +28,18 @@ type InitializeModelParams<P extends t.ProviderName> = {
|
|
|
30
28
|
})
|
|
31
29
|
);
|
|
32
30
|
|
|
31
|
+
const VERTEX_LC_NAMES: ReadonlySet<string> = new Set(['ChatVertexAI']);
|
|
32
|
+
|
|
33
|
+
/** Structural stand-in for `instanceof ChatVertexAI`: matches both builds of
|
|
34
|
+
* `@langchain/google-vertexai`, while this package's own vertex class reports
|
|
35
|
+
* `LibreChatVertexAI` and keeps failing this guard exactly as it did under
|
|
36
|
+
* `instanceof`. */
|
|
37
|
+
function isLangchainVertexModel(
|
|
38
|
+
model: unknown
|
|
39
|
+
): model is import('@langchain/google-vertexai').ChatVertexAI {
|
|
40
|
+
return constructorChainHasLcName(model, VERTEX_LC_NAMES);
|
|
41
|
+
}
|
|
42
|
+
|
|
33
43
|
/**
|
|
34
44
|
* Creates a chat model instance for a given built-in or host-registered
|
|
35
45
|
* provider, applies provider-specific field assignments, and optionally binds
|
|
@@ -47,10 +57,7 @@ export function initializeModel<P extends t.ProviderName>({
|
|
|
47
57
|
(clientOptions ?? {}) as t.ProviderOptionsFor<P>
|
|
48
58
|
);
|
|
49
59
|
|
|
50
|
-
if (
|
|
51
|
-
isOpenAILike(provider) &&
|
|
52
|
-
(model instanceof ChatOpenAI || model instanceof AzureChatOpenAI)
|
|
53
|
-
) {
|
|
60
|
+
if (isOpenAILike(provider) && isLibreChatOpenAIModel(model)) {
|
|
54
61
|
const opts = clientOptions as t.OpenAIClientOptions | undefined;
|
|
55
62
|
if (opts) {
|
|
56
63
|
model.temperature = opts.temperature as number;
|
|
@@ -59,7 +66,7 @@ export function initializeModel<P extends t.ProviderName>({
|
|
|
59
66
|
model.presencePenalty = opts.presencePenalty as number;
|
|
60
67
|
model.n = opts.n as number;
|
|
61
68
|
}
|
|
62
|
-
} else if (provider === Providers.VERTEXAI && model
|
|
69
|
+
} else if (provider === Providers.VERTEXAI && isLangchainVertexModel(model)) {
|
|
63
70
|
const opts = clientOptions as t.VertexAIClientOptions | undefined;
|
|
64
71
|
if (opts) {
|
|
65
72
|
model.temperature = opts.temperature as number;
|
|
@@ -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
|
|
|
@@ -5,8 +5,13 @@ import type {
|
|
|
5
5
|
} from '../provider-registration';
|
|
6
6
|
import type { ProviderModelConstructor, ProviderName } from '@/types';
|
|
7
7
|
|
|
8
|
+
type ProviderModelClass = new (config: never) => BaseChatModel;
|
|
9
|
+
|
|
8
10
|
interface StoredProviderRegistration {
|
|
9
|
-
model
|
|
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;
|
|
10
15
|
family: ProviderFamily;
|
|
11
16
|
manualToolStream: boolean;
|
|
12
17
|
strictAlternation: boolean;
|
|
@@ -107,6 +112,31 @@ export function registerBuiltInProvider<
|
|
|
107
112
|
builtInProviders.set(provider, createRegistration(provider, options));
|
|
108
113
|
}
|
|
109
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
|
+
|
|
110
140
|
export function getRegisteredChatModelClass<P extends ProviderName>(
|
|
111
141
|
provider: P
|
|
112
142
|
): ProviderModelConstructor<P> {
|
|
@@ -114,6 +144,16 @@ export function getRegisteredChatModelClass<P extends ProviderName>(
|
|
|
114
144
|
if (!registration) {
|
|
115
145
|
throw new Error(`Unsupported LLM provider: ${provider}`);
|
|
116
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
|
+
}
|
|
117
157
|
return registration.model as ProviderModelConstructor<P>;
|
|
118
158
|
}
|
|
119
159
|
|
|
@@ -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,81 +1,95 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
|
|
3
|
-
ProviderModelConstructor,
|
|
4
|
-
ProviderName,
|
|
5
|
-
} from '@/types';
|
|
1
|
+
import type { ProviderModelConstructor, ProviderName } from '@/types';
|
|
2
|
+
import { requireInternalModule } from '@/lazyRequire';
|
|
6
3
|
import type { ProviderFamily } from '../provider-registration';
|
|
7
|
-
import {
|
|
8
|
-
AzureChatOpenAI,
|
|
9
|
-
ChatDeepSeek,
|
|
10
|
-
ChatMoonshot,
|
|
11
|
-
ChatOpenAI,
|
|
12
|
-
ChatXAI,
|
|
13
|
-
} from '@/llm/openai';
|
|
4
|
+
import type { BaseChatModel } from '@langchain/core/language_models/chat_models';
|
|
14
5
|
import {
|
|
15
6
|
getRegisteredChatModelClass,
|
|
16
|
-
|
|
7
|
+
registerBuiltInProviderLoader,
|
|
17
8
|
} from '@/llm/providerRegistry';
|
|
18
|
-
import { CustomChatGoogleGenerativeAI } from '@/llm/google';
|
|
19
|
-
import { CustomChatBedrockConverse } from '@/llm/bedrock';
|
|
20
|
-
import { CustomChatMistralAI } from '@/llm/mistral';
|
|
21
|
-
import { CustomAnthropic } from '@/llm/anthropic';
|
|
22
|
-
import { ChatOpenRouter } from '@/llm/openrouter';
|
|
23
|
-
import { ChatVertexAI } from '@/llm/vertexai';
|
|
24
9
|
import { Providers } from '@/common';
|
|
25
10
|
|
|
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
|
+
|
|
26
20
|
type BuiltInProviderTraits = {
|
|
27
21
|
family: ProviderFamily;
|
|
28
22
|
manualToolStream?: boolean;
|
|
29
23
|
strictAlternation?: boolean;
|
|
30
24
|
};
|
|
31
25
|
|
|
32
|
-
function initializeBuiltInProvider
|
|
33
|
-
provider:
|
|
34
|
-
|
|
26
|
+
function initializeBuiltInProvider(
|
|
27
|
+
provider: Providers,
|
|
28
|
+
loadModel: () => ProviderModelClass,
|
|
35
29
|
traits: BuiltInProviderTraits
|
|
36
30
|
): void {
|
|
37
|
-
|
|
31
|
+
registerBuiltInProviderLoader({
|
|
38
32
|
provider,
|
|
39
|
-
|
|
33
|
+
loadModel,
|
|
40
34
|
...traits,
|
|
41
35
|
});
|
|
42
36
|
}
|
|
43
37
|
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
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
47
|
family: 'openai',
|
|
48
48
|
});
|
|
49
|
-
initializeBuiltInProvider(
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
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'), {
|
|
53
55
|
family: 'openai',
|
|
54
56
|
});
|
|
55
|
-
|
|
57
|
+
const loadMistral = (): ProviderModelClass =>
|
|
58
|
+
(requireInternalModule<typeof import('@/llm/mistral')>('llm/mistral/index')).CustomChatMistralAI;
|
|
59
|
+
initializeBuiltInProvider(Providers.MISTRALAI, loadMistral, {
|
|
56
60
|
family: 'mistral',
|
|
57
61
|
strictAlternation: true,
|
|
58
62
|
});
|
|
59
|
-
initializeBuiltInProvider(Providers.MISTRAL,
|
|
63
|
+
initializeBuiltInProvider(Providers.MISTRAL, loadMistral, {
|
|
60
64
|
family: 'mistral',
|
|
61
65
|
strictAlternation: true,
|
|
62
66
|
});
|
|
63
|
-
initializeBuiltInProvider(
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
67
|
+
initializeBuiltInProvider(
|
|
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(
|
|
79
|
+
Providers.BEDROCK,
|
|
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'), {
|
|
79
93
|
family: 'generic',
|
|
80
94
|
});
|
|
81
95
|
|
package/src/messages/core.ts
CHANGED
|
@@ -980,6 +980,19 @@ function isCompleteToolStreamContentBlock(block: unknown): boolean {
|
|
|
980
980
|
}
|
|
981
981
|
}
|
|
982
982
|
|
|
983
|
+
/** Drops incomplete streamed text blocks before provider-facing tool shaping. */
|
|
984
|
+
export function dropIncompleteToolStreamContent(
|
|
985
|
+
content: AIMessage['content']
|
|
986
|
+
): AIMessage['content'] {
|
|
987
|
+
if (!Array.isArray(content)) {
|
|
988
|
+
return content;
|
|
989
|
+
}
|
|
990
|
+
const completeContent = content.filter(isCompleteToolStreamContentBlock);
|
|
991
|
+
return completeContent.length === content.length
|
|
992
|
+
? content
|
|
993
|
+
: toLangChainContent(completeContent);
|
|
994
|
+
}
|
|
995
|
+
|
|
983
996
|
function projectPreemptedResponsesV1Content(
|
|
984
997
|
content: AIMessage['content'],
|
|
985
998
|
reasoning: unknown,
|
|
@@ -2026,20 +2039,12 @@ export function projectToolStreamContentForProvider(
|
|
|
2026
2039
|
}
|
|
2027
2040
|
continue;
|
|
2028
2041
|
}
|
|
2029
|
-
|
|
2030
|
-
|
|
2031
|
-
}
|
|
2032
|
-
const content = assistantMessage.content.filter(
|
|
2033
|
-
isCompleteToolStreamContentBlock
|
|
2034
|
-
);
|
|
2035
|
-
if (content.length === assistantMessage.content.length) {
|
|
2042
|
+
const content = dropIncompleteToolStreamContent(assistantMessage.content);
|
|
2043
|
+
if (content === assistantMessage.content) {
|
|
2036
2044
|
continue;
|
|
2037
2045
|
}
|
|
2038
2046
|
projected ??= [...messages];
|
|
2039
|
-
projected[i] = cloneAIMessageWithContent(
|
|
2040
|
-
assistantMessage,
|
|
2041
|
-
toLangChainContent(content)
|
|
2042
|
-
);
|
|
2047
|
+
projected[i] = cloneAIMessageWithContent(assistantMessage, content);
|
|
2043
2048
|
}
|
|
2044
2049
|
return projected ?? messages;
|
|
2045
2050
|
}
|
package/src/messages/prune.ts
CHANGED
|
@@ -31,6 +31,7 @@ import { resolveContextPruningSettings } from './contextPruningSettings';
|
|
|
31
31
|
import { hasUnsafeStructuredSerialization } from '@/utils/tokens';
|
|
32
32
|
import { ContentTypes, Providers, Constants } from '@/common';
|
|
33
33
|
import { getProviderFamily } from '@/llm/providerRegistry';
|
|
34
|
+
import { dropIncompleteToolStreamContent } from './core';
|
|
34
35
|
import { applyContextPruning } from './contextPruning';
|
|
35
36
|
import { toLangChainContent } from './langchain';
|
|
36
37
|
|
|
@@ -1412,6 +1413,47 @@ function cloneWithProjectedProperties<T extends object>(
|
|
|
1412
1413
|
) as T;
|
|
1413
1414
|
}
|
|
1414
1415
|
|
|
1416
|
+
function cloneAIMessageWithProjectedStreamContent(
|
|
1417
|
+
message: AIMessage | AIMessageChunk,
|
|
1418
|
+
changes: Readonly<Record<string, unknown>>,
|
|
1419
|
+
streamContent: AIMessage['content']
|
|
1420
|
+
): AIMessage | AIMessageChunk {
|
|
1421
|
+
const descriptors = Object.getOwnPropertyDescriptors(message) as Record<
|
|
1422
|
+
string,
|
|
1423
|
+
PropertyDescriptor | undefined
|
|
1424
|
+
>;
|
|
1425
|
+
for (const [key, projectedValue] of Object.entries(changes)) {
|
|
1426
|
+
const descriptor = descriptors[key];
|
|
1427
|
+
descriptors[key] = {
|
|
1428
|
+
configurable: descriptor?.configurable ?? true,
|
|
1429
|
+
enumerable: descriptor?.enumerable ?? true,
|
|
1430
|
+
value: projectedValue,
|
|
1431
|
+
writable: descriptor?.writable ?? true,
|
|
1432
|
+
};
|
|
1433
|
+
}
|
|
1434
|
+
const lcKwargs = descriptors.lc_kwargs;
|
|
1435
|
+
if (
|
|
1436
|
+
lcKwargs != null &&
|
|
1437
|
+
'value' in lcKwargs &&
|
|
1438
|
+
typeof lcKwargs.value === 'object' &&
|
|
1439
|
+
lcKwargs.value != null
|
|
1440
|
+
) {
|
|
1441
|
+
descriptors.lc_kwargs = {
|
|
1442
|
+
...lcKwargs,
|
|
1443
|
+
value: {
|
|
1444
|
+
...(lcKwargs.value as Record<string, unknown>),
|
|
1445
|
+
...(message.response_metadata.output_version === 'v1'
|
|
1446
|
+
? { content: undefined, contentBlocks: streamContent }
|
|
1447
|
+
: { content: streamContent }),
|
|
1448
|
+
},
|
|
1449
|
+
};
|
|
1450
|
+
}
|
|
1451
|
+
return Object.create(
|
|
1452
|
+
Object.getPrototypeOf(message),
|
|
1453
|
+
descriptors as PropertyDescriptorMap
|
|
1454
|
+
) as AIMessage | AIMessageChunk;
|
|
1455
|
+
}
|
|
1456
|
+
|
|
1415
1457
|
function createBoundedTruncationValue(
|
|
1416
1458
|
preview: string,
|
|
1417
1459
|
originalChars: number,
|
|
@@ -1875,9 +1917,10 @@ export function calculateMaxToolCallInputChars(
|
|
|
1875
1917
|
* Returns the original array when no message changes and otherwise clones only
|
|
1876
1918
|
* the array and AI messages whose inline input or `tool_calls` args changed.
|
|
1877
1919
|
*/
|
|
1878
|
-
|
|
1920
|
+
function projectToolCallInputsInternal(
|
|
1879
1921
|
messages: BaseMessage[],
|
|
1880
|
-
maxInputChars: number
|
|
1922
|
+
maxInputChars: number,
|
|
1923
|
+
dropIncompleteStreamContent: boolean
|
|
1881
1924
|
): BaseMessage[] {
|
|
1882
1925
|
const normalizedMaxInputChars = normalizeToolInputLimit(maxInputChars);
|
|
1883
1926
|
let projectedMessages: BaseMessage[] | undefined;
|
|
@@ -1889,16 +1932,21 @@ export function projectToolCallInputs(
|
|
|
1889
1932
|
}
|
|
1890
1933
|
|
|
1891
1934
|
const aiMessage = message as AIMessage | AIMessageChunk;
|
|
1892
|
-
|
|
1893
|
-
|
|
1894
|
-
|
|
1895
|
-
|
|
1935
|
+
const streamContent = dropIncompleteStreamContent
|
|
1936
|
+
? dropIncompleteToolStreamContent(aiMessage.content)
|
|
1937
|
+
: aiMessage.content;
|
|
1938
|
+
let projectedContent = streamContent;
|
|
1939
|
+
let contentChanged = streamContent !== aiMessage.content;
|
|
1940
|
+
if (Array.isArray(streamContent)) {
|
|
1941
|
+
const originalContent = streamContent as MessageContentComplex[];
|
|
1896
1942
|
const mappedContent = originalContent.map((block) =>
|
|
1897
1943
|
projectInlineToolInput(block, normalizedMaxInputChars)
|
|
1898
1944
|
);
|
|
1899
|
-
contentChanged =
|
|
1900
|
-
|
|
1901
|
-
|
|
1945
|
+
contentChanged =
|
|
1946
|
+
contentChanged ||
|
|
1947
|
+
mappedContent.some(
|
|
1948
|
+
(block, blockIndex) => block !== originalContent[blockIndex]
|
|
1949
|
+
);
|
|
1902
1950
|
projectedContent = toLangChainContent(mappedContent);
|
|
1903
1951
|
}
|
|
1904
1952
|
|
|
@@ -2020,18 +2068,45 @@ export function projectToolCallInputs(
|
|
|
2020
2068
|
continue;
|
|
2021
2069
|
}
|
|
2022
2070
|
|
|
2023
|
-
const
|
|
2071
|
+
const changes = {
|
|
2024
2072
|
content: projectedContent,
|
|
2025
2073
|
tool_calls: projectedToolCalls.length > 0 ? projectedToolCalls : [],
|
|
2026
2074
|
additional_kwargs: projectedAdditionalKwargs,
|
|
2027
2075
|
response_metadata: projectedResponseMetadata,
|
|
2028
|
-
}
|
|
2076
|
+
};
|
|
2077
|
+
const projectedMessage =
|
|
2078
|
+
streamContent === aiMessage.content
|
|
2079
|
+
? cloneWithProjectedProperties(aiMessage, changes)
|
|
2080
|
+
: cloneAIMessageWithProjectedStreamContent(
|
|
2081
|
+
aiMessage,
|
|
2082
|
+
changes,
|
|
2083
|
+
streamContent
|
|
2084
|
+
);
|
|
2029
2085
|
projectedMessages ??= [...messages];
|
|
2030
2086
|
projectedMessages[i] = projectedMessage;
|
|
2031
2087
|
}
|
|
2032
2088
|
return projectedMessages ?? messages;
|
|
2033
2089
|
}
|
|
2034
2090
|
|
|
2091
|
+
/** Projects all historical tool-call input representations to bounded values. */
|
|
2092
|
+
export function projectToolCallInputs(
|
|
2093
|
+
messages: BaseMessage[],
|
|
2094
|
+
maxInputChars: number
|
|
2095
|
+
): BaseMessage[] {
|
|
2096
|
+
return projectToolCallInputsInternal(messages, maxInputChars, false);
|
|
2097
|
+
}
|
|
2098
|
+
|
|
2099
|
+
/**
|
|
2100
|
+
* Derives provider-safe tool history in one pass by dropping incomplete stream
|
|
2101
|
+
* content and bounding every provider-consumed tool-call input representation.
|
|
2102
|
+
*/
|
|
2103
|
+
export function projectToolMessagesForProvider(
|
|
2104
|
+
messages: BaseMessage[],
|
|
2105
|
+
maxInputChars: number
|
|
2106
|
+
): BaseMessage[] {
|
|
2107
|
+
return projectToolCallInputsInternal(messages, maxInputChars, true);
|
|
2108
|
+
}
|
|
2109
|
+
|
|
2035
2110
|
export function preFlightTruncateToolCallInputs(params: {
|
|
2036
2111
|
messages: BaseMessage[];
|
|
2037
2112
|
maxContextTokens: number;
|
package/src/run.ts
CHANGED
|
@@ -2,7 +2,6 @@
|
|
|
2
2
|
import { nanoid } from 'nanoid';
|
|
3
3
|
import { PromptTemplate } from '@langchain/core/prompts';
|
|
4
4
|
import { RunnableLambda } from '@langchain/core/runnables';
|
|
5
|
-
import { AzureChatOpenAI, ChatOpenAI } from '@langchain/openai';
|
|
6
5
|
import { BaseCallbackHandler } from '@langchain/core/callbacks/base';
|
|
7
6
|
import {
|
|
8
7
|
Command,
|
|
@@ -36,6 +35,7 @@ import {
|
|
|
36
35
|
ACTIVITY_PHASE_LABEL_RUN_NAME,
|
|
37
36
|
DEFAULT_RECURSION_LIMIT,
|
|
38
37
|
} from '@/common';
|
|
38
|
+
import { isBuiltRuntime } from '@/lazyRequire';
|
|
39
39
|
import {
|
|
40
40
|
requireValidSubagentResumeManifest,
|
|
41
41
|
stripSubagentResumeManifest,
|
|
@@ -101,9 +101,19 @@ import { createGraph } from '@/graphs/createGraph';
|
|
|
101
101
|
import { resolveMaxSeals } from '@/llm/preempt';
|
|
102
102
|
import { initializeModel } from '@/llm/init';
|
|
103
103
|
import { HandlerRegistry } from '@/events';
|
|
104
|
-
import { isOpenAILike } from '@/utils/llm';
|
|
104
|
+
import { isOpenAILike, isLibreChatOpenAIModel } from '@/utils/llm';
|
|
105
105
|
import { executeHooks } from '@/hooks';
|
|
106
106
|
|
|
107
|
+
/** Source-mode runs have no dist siblings for the lazy-loading seam, so every
|
|
108
|
+
* lazily loadable module is imported through the active loader before the
|
|
109
|
+
* first model resolves. The built package never enters this branch. */
|
|
110
|
+
async function ensureSourceModeProviders(): Promise<void> {
|
|
111
|
+
if (isBuiltRuntime()) {
|
|
112
|
+
return;
|
|
113
|
+
}
|
|
114
|
+
await import('@/llm/providers.eager');
|
|
115
|
+
}
|
|
116
|
+
|
|
107
117
|
export const defaultOmitOptions = new Set([
|
|
108
118
|
'stream',
|
|
109
119
|
'thinking',
|
|
@@ -717,6 +727,7 @@ export class Run<_T extends t.BaseGraphState> {
|
|
|
717
727
|
static async create<T extends t.BaseGraphState>(
|
|
718
728
|
config: t.RunConfig
|
|
719
729
|
): Promise<Run<T>> {
|
|
730
|
+
await ensureSourceModeProviders();
|
|
720
731
|
/** Create tokenCounter if indexTokenCountMap is provided but tokenCounter is not */
|
|
721
732
|
if (config.indexTokenCountMap && !config.tokenCounter) {
|
|
722
733
|
const gc = config.graphConfig;
|
|
@@ -1974,10 +1985,7 @@ export class Run<_T extends t.BaseGraphState> {
|
|
|
1974
1985
|
clientOptions,
|
|
1975
1986
|
}) as t.ChatModelInstance;
|
|
1976
1987
|
|
|
1977
|
-
if (
|
|
1978
|
-
isOpenAILike(provider) &&
|
|
1979
|
-
(model instanceof ChatOpenAI || model instanceof AzureChatOpenAI)
|
|
1980
|
-
) {
|
|
1988
|
+
if (isOpenAILike(provider) && isLibreChatOpenAIModel(model)) {
|
|
1981
1989
|
model.temperature = (clientOptions as t.OpenAIClientOptions | undefined)
|
|
1982
1990
|
?.temperature as number;
|
|
1983
1991
|
model.topP = (clientOptions as t.OpenAIClientOptions | undefined)
|
package/src/tools/Calculator.ts
CHANGED
|
@@ -1,5 +1,12 @@
|
|
|
1
|
-
import * as math from 'mathjs';
|
|
2
1
|
import { Tool } from '@langchain/core/tools';
|
|
2
|
+
import { requireLazyModule } from '@/lazyRequire';
|
|
3
|
+
|
|
4
|
+
/** mathjs costs ~150ms of module init; a calculator that is never invoked never pays it. */
|
|
5
|
+
let math: typeof import('mathjs') | undefined;
|
|
6
|
+
const evaluateExpression = (input: string): string => {
|
|
7
|
+
math ??= requireLazyModule<typeof import('mathjs')>('mathjs');
|
|
8
|
+
return math.evaluate(input).toString();
|
|
9
|
+
};
|
|
3
10
|
|
|
4
11
|
export const CalculatorToolName = 'calculator';
|
|
5
12
|
|
|
@@ -36,7 +43,7 @@ export class Calculator extends Tool {
|
|
|
36
43
|
|
|
37
44
|
async _call(input: string): Promise<string> {
|
|
38
45
|
try {
|
|
39
|
-
return
|
|
46
|
+
return evaluateExpression(input);
|
|
40
47
|
} catch {
|
|
41
48
|
return 'I don\'t know how to do that.';
|
|
42
49
|
}
|
package/src/utils/llm.ts
CHANGED
|
@@ -3,6 +3,45 @@ import type { ProviderName } from '@/types';
|
|
|
3
3
|
import { getProviderFamily } from '@/llm/providerRegistry';
|
|
4
4
|
import { Providers } from '@/common';
|
|
5
5
|
|
|
6
|
+
const OPENAI_FAMILY_LC_NAMES: ReadonlySet<string> = new Set([
|
|
7
|
+
'LibreChatOpenAI',
|
|
8
|
+
'LibreChatAzureOpenAI',
|
|
9
|
+
]);
|
|
10
|
+
|
|
11
|
+
/** Walks the constructor chain for LangChain's `lc_name` serialization ids.
|
|
12
|
+
* Constructor identity is unusable across lazily loaded module formats — the
|
|
13
|
+
* CJS and ESM builds carry distinct classes — so guards match on the ids the
|
|
14
|
+
* relevant classes declare instead of on `instanceof`. */
|
|
15
|
+
export function constructorChainHasLcName(
|
|
16
|
+
model: unknown,
|
|
17
|
+
names: ReadonlySet<string>
|
|
18
|
+
): boolean {
|
|
19
|
+
if (typeof model !== 'object' || model == null) {
|
|
20
|
+
return false;
|
|
21
|
+
}
|
|
22
|
+
let ctor: unknown = model.constructor;
|
|
23
|
+
while (typeof ctor === 'function') {
|
|
24
|
+
const lcName = (ctor as { lc_name?: () => string }).lc_name?.();
|
|
25
|
+
if (lcName != null && names.has(lcName)) {
|
|
26
|
+
return true;
|
|
27
|
+
}
|
|
28
|
+
ctor = Object.getPrototypeOf(ctor);
|
|
29
|
+
}
|
|
30
|
+
return false;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/** Matches exactly the instances that were `instanceof` this package's
|
|
34
|
+
* `ChatOpenAI`/`AzureChatOpenAI`: only those classes declare the
|
|
35
|
+
* `LibreChatOpenAI`/`LibreChatAzureOpenAI` ids, their subclasses keep them in
|
|
36
|
+
* the chain, and upstream `@langchain/openai` classes never carry them. */
|
|
37
|
+
export function isLibreChatOpenAIModel(
|
|
38
|
+
model: unknown
|
|
39
|
+
): model is
|
|
40
|
+
| import('@/llm/openai').ChatOpenAI
|
|
41
|
+
| import('@/llm/openai').AzureChatOpenAI {
|
|
42
|
+
return constructorChainHasLcName(model, OPENAI_FAMILY_LC_NAMES);
|
|
43
|
+
}
|
|
44
|
+
|
|
6
45
|
export function isOpenAILike(provider?: ProviderName): boolean {
|
|
7
46
|
if (provider == null) {
|
|
8
47
|
return false;
|