@librechat/agents 3.6.15 → 3.6.16
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/agents/AgentContext.cjs +1 -1
- package/dist/cjs/agents/AgentContext.cjs.map +1 -1
- package/dist/cjs/graphs/Graph.cjs +9 -7
- package/dist/cjs/graphs/Graph.cjs.map +1 -1
- package/dist/cjs/llm/init.cjs +1 -0
- 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/openai/index.cjs +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 +69 -0
- package/dist/cjs/llm/providerRegistry.cjs.map +1 -0
- package/dist/cjs/llm/providers.cjs +38 -25
- package/dist/cjs/llm/providers.cjs.map +1 -1
- 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/main.cjs +18 -15
- package/dist/cjs/messages/format.cjs.map +1 -1
- package/dist/cjs/messages/prune.cjs +8 -4
- package/dist/cjs/messages/prune.cjs.map +1 -1
- package/dist/cjs/provider-registration.cjs +4 -0
- package/dist/cjs/run.cjs +2 -2
- 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/utils/llm.cjs +6 -4
- package/dist/cjs/utils/llm.cjs.map +1 -1
- package/dist/esm/agents/AgentContext.mjs +1 -1
- package/dist/esm/agents/AgentContext.mjs.map +1 -1
- package/dist/esm/graphs/Graph.mjs +10 -8
- package/dist/esm/graphs/Graph.mjs.map +1 -1
- package/dist/esm/llm/init.mjs +1 -0
- 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/openai/index.mjs +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 +64 -0
- package/dist/esm/llm/providerRegistry.mjs.map +1 -0
- package/dist/esm/llm/providers.mjs +36 -22
- 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/main.mjs +12 -10
- package/dist/esm/messages/format.mjs.map +1 -1
- package/dist/esm/messages/prune.mjs +8 -4
- package/dist/esm/messages/prune.mjs.map +1 -1
- package/dist/esm/provider-registration.mjs +3 -0
- package/dist/esm/run.mjs +2 -2
- 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/utils/llm.mjs +6 -4
- package/dist/esm/utils/llm.mjs.map +1 -1
- package/dist/types/agents/AgentContext.d.ts +5 -5
- package/dist/types/index.d.ts +2 -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 +11 -0
- package/dist/types/llm/providers.d.ts +4 -5
- 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 +1 -2
- package/dist/types/messages/format.d.ts +3 -3
- package/dist/types/messages/prune.d.ts +3 -2
- 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 +4 -4
- package/dist/types/utils/llmConfig.d.ts +2 -2
- package/package.json +9 -1
- package/src/agents/AgentContext.ts +27 -26
- package/src/graphs/Graph.ts +14 -14
- package/src/index.ts +5 -0
- package/src/llm/contextOverflowRecovery.ts +2 -2
- package/src/llm/init.ts +40 -17
- package/src/llm/invoke.ts +36 -21
- package/src/llm/prepareProviderRequest.ts +19 -18
- package/src/llm/providerRegistry.ts +134 -0
- package/src/llm/providers.ts +73 -30
- package/src/llm/request.ts +10 -6
- package/src/llm/truncation.ts +9 -3
- package/src/messages/core.ts +2 -2
- package/src/messages/format.ts +14 -16
- package/src/messages/prune.ts +22 -17
- package/src/provider-registration.ts +29 -0
- package/src/run.ts +1 -1
- package/src/session/AgentSession.ts +1 -1
- package/src/stream.ts +7 -8
- package/src/summarization/node.ts +7 -7
- 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 +22 -15
- package/src/utils/llmConfig.ts +4 -4
|
@@ -0,0 +1,134 @@
|
|
|
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
|
+
interface StoredProviderRegistration {
|
|
9
|
+
model: new (config: never) => BaseChatModel;
|
|
10
|
+
family: ProviderFamily;
|
|
11
|
+
manualToolStream: boolean;
|
|
12
|
+
strictAlternation: boolean;
|
|
13
|
+
owner: symbol;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
interface ProviderRegistryGlobal {
|
|
17
|
+
[key: symbol]: Map<ProviderName, StoredProviderRegistration> | undefined;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
const PROVIDER_REGISTRY_KEY = Symbol.for(
|
|
21
|
+
'@librechat/agents:providerRegistry:v1'
|
|
22
|
+
);
|
|
23
|
+
const providerRegistryGlobal = globalThis as ProviderRegistryGlobal;
|
|
24
|
+
const registeredProviders =
|
|
25
|
+
providerRegistryGlobal[PROVIDER_REGISTRY_KEY] ??
|
|
26
|
+
new Map<ProviderName, StoredProviderRegistration>();
|
|
27
|
+
providerRegistryGlobal[PROVIDER_REGISTRY_KEY] = registeredProviders;
|
|
28
|
+
const builtInProviders = new Map<ProviderName, StoredProviderRegistration>();
|
|
29
|
+
|
|
30
|
+
function normalizeProvider(provider: ProviderName): ProviderName {
|
|
31
|
+
if (typeof provider !== 'string' || provider.trim() === '') {
|
|
32
|
+
throw new TypeError('LLM provider name must be a non-empty string');
|
|
33
|
+
}
|
|
34
|
+
if (provider !== provider.trim()) {
|
|
35
|
+
throw new TypeError(
|
|
36
|
+
'LLM provider name must not have surrounding whitespace'
|
|
37
|
+
);
|
|
38
|
+
}
|
|
39
|
+
return provider;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function isConstructible<T extends abstract new (...args: never[]) => object>(
|
|
43
|
+
value: T
|
|
44
|
+
): boolean {
|
|
45
|
+
try {
|
|
46
|
+
Reflect.construct(String, [], value);
|
|
47
|
+
return true;
|
|
48
|
+
} catch {
|
|
49
|
+
return false;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
function createRegistration<
|
|
54
|
+
TOptions extends object,
|
|
55
|
+
TModel extends BaseChatModel,
|
|
56
|
+
>(
|
|
57
|
+
provider: ProviderName,
|
|
58
|
+
options: ProviderRegistrationOptions<TOptions, TModel>
|
|
59
|
+
): StoredProviderRegistration {
|
|
60
|
+
if (typeof options.model !== 'function' || !isConstructible(options.model)) {
|
|
61
|
+
throw new TypeError(`LLM provider constructor is invalid: ${provider}`);
|
|
62
|
+
}
|
|
63
|
+
return {
|
|
64
|
+
model: options.model,
|
|
65
|
+
family: options.family ?? 'generic',
|
|
66
|
+
manualToolStream: options.manualToolStream ?? false,
|
|
67
|
+
strictAlternation: options.strictAlternation ?? false,
|
|
68
|
+
owner: Symbol(provider),
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
function getRegistration(
|
|
73
|
+
provider: ProviderName
|
|
74
|
+
): StoredProviderRegistration | undefined {
|
|
75
|
+
return builtInProviders.get(provider) ?? registeredProviders.get(provider);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/** Registers one host provider until the returned disposer is called. */
|
|
79
|
+
export function registerProvider<
|
|
80
|
+
TOptions extends object,
|
|
81
|
+
TModel extends BaseChatModel,
|
|
82
|
+
>(options: ProviderRegistrationOptions<TOptions, TModel>): () => void {
|
|
83
|
+
const provider = normalizeProvider(options.provider);
|
|
84
|
+
if (getRegistration(provider) != null) {
|
|
85
|
+
throw new Error(`LLM provider already registered: ${provider}`);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
const registration = createRegistration(provider, options);
|
|
89
|
+
registeredProviders.set(provider, registration);
|
|
90
|
+
|
|
91
|
+
return (): void => {
|
|
92
|
+
if (registeredProviders.get(provider)?.owner === registration.owner) {
|
|
93
|
+
registeredProviders.delete(provider);
|
|
94
|
+
}
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/** Initializes one built-in for the current package module graph. */
|
|
99
|
+
export function registerBuiltInProvider<
|
|
100
|
+
TOptions extends object,
|
|
101
|
+
TModel extends BaseChatModel,
|
|
102
|
+
>(options: ProviderRegistrationOptions<TOptions, TModel>): void {
|
|
103
|
+
const provider = normalizeProvider(options.provider);
|
|
104
|
+
if (builtInProviders.has(provider)) {
|
|
105
|
+
throw new Error(`LLM provider already registered: ${provider}`);
|
|
106
|
+
}
|
|
107
|
+
builtInProviders.set(provider, createRegistration(provider, options));
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
export function getRegisteredChatModelClass<P extends ProviderName>(
|
|
111
|
+
provider: P
|
|
112
|
+
): ProviderModelConstructor<P> {
|
|
113
|
+
const registration = getRegistration(provider);
|
|
114
|
+
if (!registration) {
|
|
115
|
+
throw new Error(`Unsupported LLM provider: ${provider}`);
|
|
116
|
+
}
|
|
117
|
+
return registration.model as ProviderModelConstructor<P>;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
export function getProviderFamily(
|
|
121
|
+
provider: ProviderName
|
|
122
|
+
): ProviderFamily | undefined {
|
|
123
|
+
return getRegistration(provider)?.family;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
export function providerUsesManualToolStream(provider: ProviderName): boolean {
|
|
127
|
+
return getRegistration(provider)?.manualToolStream ?? false;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
export function providerRequiresStrictAlternation(
|
|
131
|
+
provider: ProviderName
|
|
132
|
+
): boolean {
|
|
133
|
+
return getRegistration(provider)?.strictAlternation ?? false;
|
|
134
|
+
}
|
package/src/llm/providers.ts
CHANGED
|
@@ -1,10 +1,9 @@
|
|
|
1
|
-
// src/llm/providers.ts
|
|
2
|
-
import { CustomChatMistralAI } from '@/llm/mistral';
|
|
3
1
|
import type {
|
|
4
2
|
ChatModelConstructorMap,
|
|
5
|
-
|
|
6
|
-
|
|
3
|
+
ProviderModelConstructor,
|
|
4
|
+
ProviderName,
|
|
7
5
|
} from '@/types';
|
|
6
|
+
import type { ProviderFamily } from '../provider-registration';
|
|
8
7
|
import {
|
|
9
8
|
AzureChatOpenAI,
|
|
10
9
|
ChatDeepSeek,
|
|
@@ -12,41 +11,85 @@ import {
|
|
|
12
11
|
ChatOpenAI,
|
|
13
12
|
ChatXAI,
|
|
14
13
|
} from '@/llm/openai';
|
|
14
|
+
import {
|
|
15
|
+
getRegisteredChatModelClass,
|
|
16
|
+
registerBuiltInProvider,
|
|
17
|
+
} from '@/llm/providerRegistry';
|
|
15
18
|
import { CustomChatGoogleGenerativeAI } from '@/llm/google';
|
|
16
19
|
import { CustomChatBedrockConverse } from '@/llm/bedrock';
|
|
20
|
+
import { CustomChatMistralAI } from '@/llm/mistral';
|
|
17
21
|
import { CustomAnthropic } from '@/llm/anthropic';
|
|
18
22
|
import { ChatOpenRouter } from '@/llm/openrouter';
|
|
19
23
|
import { ChatVertexAI } from '@/llm/vertexai';
|
|
20
24
|
import { Providers } from '@/common';
|
|
21
25
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
[Providers.VERTEXAI]: ChatVertexAI,
|
|
27
|
-
[Providers.DEEPSEEK]: ChatDeepSeek,
|
|
28
|
-
[Providers.MISTRALAI]: CustomChatMistralAI,
|
|
29
|
-
[Providers.MISTRAL]: CustomChatMistralAI,
|
|
30
|
-
[Providers.ANTHROPIC]: CustomAnthropic,
|
|
31
|
-
[Providers.OPENROUTER]: ChatOpenRouter,
|
|
32
|
-
[Providers.BEDROCK]: CustomChatBedrockConverse,
|
|
33
|
-
// [Providers.ANTHROPIC]: ChatAnthropic,
|
|
34
|
-
[Providers.GOOGLE]: CustomChatGoogleGenerativeAI,
|
|
35
|
-
[Providers.MOONSHOT]: ChatMoonshot,
|
|
26
|
+
type BuiltInProviderTraits = {
|
|
27
|
+
family: ProviderFamily;
|
|
28
|
+
manualToolStream?: boolean;
|
|
29
|
+
strictAlternation?: boolean;
|
|
36
30
|
};
|
|
37
31
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
32
|
+
function initializeBuiltInProvider<P extends Providers>(
|
|
33
|
+
provider: P,
|
|
34
|
+
model: ChatModelConstructorMap[P],
|
|
35
|
+
traits: BuiltInProviderTraits
|
|
36
|
+
): void {
|
|
37
|
+
registerBuiltInProvider({
|
|
38
|
+
provider,
|
|
39
|
+
model,
|
|
40
|
+
...traits,
|
|
41
|
+
});
|
|
42
|
+
}
|
|
42
43
|
|
|
43
|
-
|
|
44
|
+
initializeBuiltInProvider(Providers.XAI, ChatXAI, { family: 'openai' });
|
|
45
|
+
initializeBuiltInProvider(Providers.OPENAI, ChatOpenAI, { family: 'openai' });
|
|
46
|
+
initializeBuiltInProvider(Providers.AZURE, AzureChatOpenAI, {
|
|
47
|
+
family: 'openai',
|
|
48
|
+
});
|
|
49
|
+
initializeBuiltInProvider(Providers.VERTEXAI, ChatVertexAI, {
|
|
50
|
+
family: 'google',
|
|
51
|
+
});
|
|
52
|
+
initializeBuiltInProvider(Providers.DEEPSEEK, ChatDeepSeek, {
|
|
53
|
+
family: 'openai',
|
|
54
|
+
});
|
|
55
|
+
initializeBuiltInProvider(Providers.MISTRALAI, CustomChatMistralAI, {
|
|
56
|
+
family: 'mistral',
|
|
57
|
+
strictAlternation: true,
|
|
58
|
+
});
|
|
59
|
+
initializeBuiltInProvider(Providers.MISTRAL, CustomChatMistralAI, {
|
|
60
|
+
family: 'mistral',
|
|
61
|
+
strictAlternation: true,
|
|
62
|
+
});
|
|
63
|
+
initializeBuiltInProvider(Providers.ANTHROPIC, CustomAnthropic, {
|
|
64
|
+
family: 'anthropic',
|
|
65
|
+
manualToolStream: true,
|
|
66
|
+
});
|
|
67
|
+
initializeBuiltInProvider(Providers.OPENROUTER, ChatOpenRouter, {
|
|
68
|
+
family: 'openai',
|
|
69
|
+
});
|
|
70
|
+
initializeBuiltInProvider(Providers.BEDROCK, CustomChatBedrockConverse, {
|
|
71
|
+
family: 'bedrock',
|
|
72
|
+
manualToolStream: true,
|
|
73
|
+
strictAlternation: true,
|
|
74
|
+
});
|
|
75
|
+
initializeBuiltInProvider(Providers.GOOGLE, CustomChatGoogleGenerativeAI, {
|
|
76
|
+
family: 'google',
|
|
77
|
+
});
|
|
78
|
+
initializeBuiltInProvider(Providers.MOONSHOT, ChatMoonshot, {
|
|
79
|
+
family: 'generic',
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
export const getChatModelClass = <P extends ProviderName>(
|
|
44
83
|
provider: P
|
|
45
|
-
):
|
|
46
|
-
const ChatModelClass = llmProviders[provider];
|
|
47
|
-
if (!ChatModelClass) {
|
|
48
|
-
throw new Error(`Unsupported LLM provider: ${provider}`);
|
|
49
|
-
}
|
|
84
|
+
): ProviderModelConstructor<P> => getRegisteredChatModelClass(provider);
|
|
50
85
|
|
|
51
|
-
|
|
52
|
-
|
|
86
|
+
export {
|
|
87
|
+
getProviderFamily,
|
|
88
|
+
providerRequiresStrictAlternation,
|
|
89
|
+
providerUsesManualToolStream,
|
|
90
|
+
registerProvider,
|
|
91
|
+
} from '@/llm/providerRegistry';
|
|
92
|
+
export type {
|
|
93
|
+
ProviderFamily,
|
|
94
|
+
ProviderRegistrationOptions,
|
|
95
|
+
} from '../provider-registration';
|
package/src/llm/request.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type * as t from '@/types';
|
|
2
|
+
import { getProviderFamily } from '@/llm/providerRegistry';
|
|
2
3
|
import { Providers } from '@/common';
|
|
3
4
|
|
|
4
5
|
/**
|
|
@@ -7,20 +8,21 @@ import { Providers } from '@/common';
|
|
|
7
8
|
* and OpenAI-compat (modelKwargs.thinking).
|
|
8
9
|
*/
|
|
9
10
|
export function isThinkingEnabled(
|
|
10
|
-
provider:
|
|
11
|
+
provider: t.ProviderName,
|
|
11
12
|
clientOptions?: t.ClientOptions
|
|
12
13
|
): boolean {
|
|
13
14
|
if (!clientOptions) return false;
|
|
15
|
+
const family = getProviderFamily(provider);
|
|
14
16
|
|
|
15
17
|
if (
|
|
16
|
-
provider === Providers.ANTHROPIC &&
|
|
18
|
+
(provider === Providers.ANTHROPIC || family === 'anthropic') &&
|
|
17
19
|
(clientOptions as t.AnthropicClientOptions).thinking != null
|
|
18
20
|
) {
|
|
19
21
|
return true;
|
|
20
22
|
}
|
|
21
23
|
|
|
22
24
|
if (
|
|
23
|
-
provider === Providers.BEDROCK &&
|
|
25
|
+
(provider === Providers.BEDROCK || family === 'bedrock') &&
|
|
24
26
|
(clientOptions as t.BedrockAnthropicInput).additionalModelRequestFields?.[
|
|
25
27
|
'thinking'
|
|
26
28
|
] != null
|
|
@@ -29,7 +31,7 @@ export function isThinkingEnabled(
|
|
|
29
31
|
}
|
|
30
32
|
|
|
31
33
|
if (
|
|
32
|
-
provider === Providers.OPENAI &&
|
|
34
|
+
(provider === Providers.OPENAI || family === 'openai') &&
|
|
33
35
|
(
|
|
34
36
|
(clientOptions as t.OpenAIClientOptions).modelKwargs
|
|
35
37
|
?.thinking as t.AnthropicClientOptions['thinking']
|
|
@@ -47,9 +49,11 @@ export function isThinkingEnabled(
|
|
|
47
49
|
* use `maxTokens`.
|
|
48
50
|
*/
|
|
49
51
|
export function getMaxOutputTokensKey(
|
|
50
|
-
provider:
|
|
52
|
+
provider: t.ProviderName
|
|
51
53
|
): 'maxOutputTokens' | 'maxTokens' {
|
|
52
|
-
return provider === Providers.GOOGLE ||
|
|
54
|
+
return provider === Providers.GOOGLE ||
|
|
55
|
+
provider === Providers.VERTEXAI ||
|
|
56
|
+
getProviderFamily(provider) === 'google'
|
|
53
57
|
? 'maxOutputTokens'
|
|
54
58
|
: 'maxTokens';
|
|
55
59
|
}
|
package/src/llm/truncation.ts
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import type { AIMessageChunk, BaseMessage } from '@langchain/core/messages';
|
|
2
|
+
import type { ProviderName } from '@/types';
|
|
3
|
+
import { getProviderFamily } from '@/llm/providerRegistry';
|
|
2
4
|
import { Providers } from '@/common';
|
|
3
5
|
|
|
4
6
|
/**
|
|
@@ -7,7 +9,7 @@ import { Providers } from '@/common';
|
|
|
7
9
|
* `functionCall` whole and seal it on arrival, so a `MAX_TOKENS` finish does
|
|
8
10
|
* NOT imply the arguments were cut off — the truncation guard must skip them.
|
|
9
11
|
*/
|
|
10
|
-
const ATOMIC_TOOL_CALL_ARG_PROVIDERS = new Set<
|
|
12
|
+
const ATOMIC_TOOL_CALL_ARG_PROVIDERS = new Set<ProviderName>([
|
|
11
13
|
Providers.GOOGLE,
|
|
12
14
|
Providers.VERTEXAI,
|
|
13
15
|
]);
|
|
@@ -162,12 +164,16 @@ function collectToolCallNames(message: AIMessageChunk | BaseMessage): string[] {
|
|
|
162
164
|
*/
|
|
163
165
|
export function assertNotTruncatedToolCall(
|
|
164
166
|
message: AIMessageChunk | BaseMessage | undefined | null,
|
|
165
|
-
provider?:
|
|
167
|
+
provider?: ProviderName
|
|
166
168
|
): void {
|
|
167
169
|
if (message == null) {
|
|
168
170
|
return;
|
|
169
171
|
}
|
|
170
|
-
if (
|
|
172
|
+
if (
|
|
173
|
+
provider != null &&
|
|
174
|
+
(ATOMIC_TOOL_CALL_ARG_PROVIDERS.has(provider) ||
|
|
175
|
+
getProviderFamily(provider) === 'google')
|
|
176
|
+
) {
|
|
171
177
|
return;
|
|
172
178
|
}
|
|
173
179
|
const stopReason = getTruncationStopReason(message);
|
package/src/messages/core.ts
CHANGED
|
@@ -90,7 +90,7 @@ const modifyContent = ({
|
|
|
90
90
|
messageType,
|
|
91
91
|
content,
|
|
92
92
|
}: {
|
|
93
|
-
provider:
|
|
93
|
+
provider: t.ProviderName;
|
|
94
94
|
messageType: string;
|
|
95
95
|
content: t.ExtendedMessageContent[];
|
|
96
96
|
}): (t.ExtendedMessageContent | null)[] => {
|
|
@@ -243,7 +243,7 @@ function hasReasoningContent(content: BaseMessage['content']): boolean {
|
|
|
243
243
|
}
|
|
244
244
|
|
|
245
245
|
export function modifyDeltaProperties(
|
|
246
|
-
provider:
|
|
246
|
+
provider: t.ProviderName,
|
|
247
247
|
obj?: AIMessageChunk
|
|
248
248
|
): AIMessageChunk | undefined {
|
|
249
249
|
if (!obj || typeof obj !== 'object') return obj;
|
package/src/messages/format.ts
CHANGED
|
@@ -27,6 +27,7 @@ import type {
|
|
|
27
27
|
ToolCallPart,
|
|
28
28
|
TPayload,
|
|
29
29
|
TMessage,
|
|
30
|
+
ProviderName,
|
|
30
31
|
} from '@/types';
|
|
31
32
|
import type {
|
|
32
33
|
ProviderMessageAttribution,
|
|
@@ -366,7 +367,7 @@ export const formatFromLangChain = (
|
|
|
366
367
|
interface FormatAssistantMessageOptions {
|
|
367
368
|
preserveUnpairedServerToolUses?: boolean;
|
|
368
369
|
preserveReasoningContent?: boolean;
|
|
369
|
-
provider?:
|
|
370
|
+
provider?: ProviderName;
|
|
370
371
|
sourceMessageId?: string;
|
|
371
372
|
sourceContentPartOffset?: number;
|
|
372
373
|
sourceContentPartIndices?: readonly SourceContentPartIndices[];
|
|
@@ -376,7 +377,7 @@ interface FormatAssistantMessageOptions {
|
|
|
376
377
|
type SourceContentPartIndices = number | readonly number[];
|
|
377
378
|
|
|
378
379
|
interface FormatAgentMessagesOptions {
|
|
379
|
-
provider?:
|
|
380
|
+
provider?: ProviderName;
|
|
380
381
|
/** Reconstruct hidden `reasoning_content` from `THINK` parts onto prior
|
|
381
382
|
* tool-call messages. Explicit opt-in for OpenAI-compatible endpoints that
|
|
382
383
|
* replay reasoning across turns; defaults to on for DeepSeek thinking-mode. */
|
|
@@ -478,10 +479,7 @@ function collectTrustedToolResultSourceContentPartIndices(
|
|
|
478
479
|
let trusted: Set<number> | undefined;
|
|
479
480
|
let previousPart: MessageContentComplex | null | undefined;
|
|
480
481
|
for (let index = 0; index < content.length; index++) {
|
|
481
|
-
const part = content[index] as
|
|
482
|
-
| MessageContentComplex
|
|
483
|
-
| null
|
|
484
|
-
| undefined;
|
|
482
|
+
const part = content[index] as MessageContentComplex | null | undefined;
|
|
485
483
|
if (part == null) {
|
|
486
484
|
previousPart = part;
|
|
487
485
|
continue;
|
|
@@ -509,13 +507,18 @@ function sourceContentPartIndicesAreTrustedToolResult(
|
|
|
509
507
|
trustedToolSourceContentPartIndices: ReadonlySet<number> | undefined
|
|
510
508
|
): boolean {
|
|
511
509
|
if (typeof sourceContentPartIndices === 'number') {
|
|
512
|
-
return
|
|
510
|
+
return (
|
|
511
|
+
trustedToolSourceContentPartIndices?.has(sourceContentPartIndices) ===
|
|
512
|
+
true
|
|
513
|
+
);
|
|
513
514
|
}
|
|
514
515
|
if (sourceContentPartIndices.length === 0) {
|
|
515
516
|
return false;
|
|
516
517
|
}
|
|
517
518
|
for (const sourceContentPartIndex of sourceContentPartIndices) {
|
|
518
|
-
if (
|
|
519
|
+
if (
|
|
520
|
+
trustedToolSourceContentPartIndices?.has(sourceContentPartIndex) !== true
|
|
521
|
+
) {
|
|
519
522
|
return false;
|
|
520
523
|
}
|
|
521
524
|
}
|
|
@@ -1377,10 +1380,7 @@ function stampSourceMessageIdentity(
|
|
|
1377
1380
|
},
|
|
1378
1381
|
];
|
|
1379
1382
|
}
|
|
1380
|
-
setProviderMessageProvenance(
|
|
1381
|
-
message,
|
|
1382
|
-
partsToStamp
|
|
1383
|
-
);
|
|
1383
|
+
setProviderMessageProvenance(message, partsToStamp);
|
|
1384
1384
|
if (sourceMessageId == null || derivedIndex !== 0) {
|
|
1385
1385
|
return;
|
|
1386
1386
|
}
|
|
@@ -2759,9 +2759,7 @@ function getSyntheticProviderContextProvenanceParts(
|
|
|
2759
2759
|
): ProviderMessageProvenancePart[] | null {
|
|
2760
2760
|
/** Fold labels are generated context, while retained source bytes keep their
|
|
2761
2761
|
* original attribution so downstream policy can still route them exactly. */
|
|
2762
|
-
const parts: ProviderMessageProvenancePart[] = [
|
|
2763
|
-
{ attribution: 'synthetic' },
|
|
2764
|
-
];
|
|
2762
|
+
const parts: ProviderMessageProvenancePart[] = [{ attribution: 'synthetic' }];
|
|
2765
2763
|
for (const source of sourceMessages) {
|
|
2766
2764
|
const {
|
|
2767
2765
|
message: sourceMessage,
|
|
@@ -3311,7 +3309,7 @@ function appendToolCalls(
|
|
|
3311
3309
|
*/
|
|
3312
3310
|
export function ensureThinkingBlockInMessages(
|
|
3313
3311
|
messages: BaseMessage[],
|
|
3314
|
-
_provider:
|
|
3312
|
+
_provider: ProviderName,
|
|
3315
3313
|
config?: RunnableConfig,
|
|
3316
3314
|
runStartIndex?: number
|
|
3317
3315
|
): BaseMessage[] {
|
package/src/messages/prune.ts
CHANGED
|
@@ -13,6 +13,7 @@ import type {
|
|
|
13
13
|
} from '@/types/stream';
|
|
14
14
|
import type { ContextPruningConfig } from '@/types/graph';
|
|
15
15
|
import type { TokenCounter } from '@/types/run';
|
|
16
|
+
import type { ProviderName } from '@/types';
|
|
16
17
|
import {
|
|
17
18
|
cloneToolMessageWithContent,
|
|
18
19
|
compactToolContent,
|
|
@@ -29,6 +30,7 @@ import {
|
|
|
29
30
|
import { resolveContextPruningSettings } from './contextPruningSettings';
|
|
30
31
|
import { hasUnsafeStructuredSerialization } from '@/utils/tokens';
|
|
31
32
|
import { ContentTypes, Providers, Constants } from '@/common';
|
|
33
|
+
import { getProviderFamily } from '@/llm/providerRegistry';
|
|
32
34
|
import { applyContextPruning } from './contextPruning';
|
|
33
35
|
import { toLangChainContent } from './langchain';
|
|
34
36
|
|
|
@@ -130,7 +132,7 @@ export function clampCalibrationRatio(ratio: number): number {
|
|
|
130
132
|
}
|
|
131
133
|
|
|
132
134
|
export type PruneMessagesFactoryParams = {
|
|
133
|
-
provider?:
|
|
135
|
+
provider?: ProviderName;
|
|
134
136
|
maxTokens: number;
|
|
135
137
|
/** Per-tool-result character cap applied while reconciling cached counts. */
|
|
136
138
|
maxToolResultChars?: number;
|
|
@@ -2065,6 +2067,15 @@ type ThinkingBlocks = {
|
|
|
2065
2067
|
};
|
|
2066
2068
|
|
|
2067
2069
|
export function createPruneMessages(factoryParams: PruneMessagesFactoryParams) {
|
|
2070
|
+
const providerFamily =
|
|
2071
|
+
factoryParams.provider == null
|
|
2072
|
+
? undefined
|
|
2073
|
+
: getProviderFamily(factoryParams.provider);
|
|
2074
|
+
const usesBedrockThinking =
|
|
2075
|
+
factoryParams.provider === Providers.BEDROCK ||
|
|
2076
|
+
providerFamily === 'bedrock';
|
|
2077
|
+
const usesOpenAIThinking =
|
|
2078
|
+
factoryParams.provider === Providers.OPENAI || providerFamily === 'openai';
|
|
2068
2079
|
const indexTokenCountMap = { ...factoryParams.indexTokenCountMap };
|
|
2069
2080
|
let lastTurnStartIndex = factoryParams.startIndex;
|
|
2070
2081
|
let lastCutOffIndex = 0;
|
|
@@ -2152,10 +2163,7 @@ export function createPruneMessages(factoryParams: PruneMessagesFactoryParams) {
|
|
|
2152
2163
|
};
|
|
2153
2164
|
}
|
|
2154
2165
|
|
|
2155
|
-
if (
|
|
2156
|
-
factoryParams.provider === Providers.OPENAI &&
|
|
2157
|
-
factoryParams.thinkingEnabled === true
|
|
2158
|
-
) {
|
|
2166
|
+
if (usesOpenAIThinking && factoryParams.thinkingEnabled === true) {
|
|
2159
2167
|
for (let i = lastTurnStartIndex; i < params.messages.length; i++) {
|
|
2160
2168
|
const m = params.messages[i];
|
|
2161
2169
|
if (
|
|
@@ -2729,10 +2737,9 @@ export function createPruneMessages(factoryParams: PruneMessagesFactoryParams) {
|
|
|
2729
2737
|
thinkingEnabled: factoryParams.thinkingEnabled,
|
|
2730
2738
|
tokenCounter: factoryParams.tokenCounter,
|
|
2731
2739
|
instructionTokens: rawSpaceInstructionTokens,
|
|
2732
|
-
reasoningType:
|
|
2733
|
-
|
|
2734
|
-
|
|
2735
|
-
: ContentTypes.THINKING,
|
|
2740
|
+
reasoningType: usesBedrockThinking
|
|
2741
|
+
? ContentTypes.REASONING_CONTENT
|
|
2742
|
+
: ContentTypes.THINKING,
|
|
2736
2743
|
thinkingStartIndex:
|
|
2737
2744
|
factoryParams.thinkingEnabled === true
|
|
2738
2745
|
? runThinkingStartIndex
|
|
@@ -2826,10 +2833,9 @@ export function createPruneMessages(factoryParams: PruneMessagesFactoryParams) {
|
|
|
2826
2833
|
thinkingEnabled: factoryParams.thinkingEnabled,
|
|
2827
2834
|
tokenCounter: factoryParams.tokenCounter,
|
|
2828
2835
|
instructionTokens: currentInstructionTokens,
|
|
2829
|
-
reasoningType:
|
|
2830
|
-
|
|
2831
|
-
|
|
2832
|
-
: ContentTypes.THINKING,
|
|
2836
|
+
reasoningType: usesBedrockThinking
|
|
2837
|
+
? ContentTypes.REASONING_CONTENT
|
|
2838
|
+
: ContentTypes.THINKING,
|
|
2833
2839
|
thinkingStartIndex:
|
|
2834
2840
|
factoryParams.thinkingEnabled === true
|
|
2835
2841
|
? runThinkingStartIndex
|
|
@@ -2963,10 +2969,9 @@ export function createPruneMessages(factoryParams: PruneMessagesFactoryParams) {
|
|
|
2963
2969
|
thinkingEnabled: factoryParams.thinkingEnabled,
|
|
2964
2970
|
tokenCounter: factoryParams.tokenCounter,
|
|
2965
2971
|
instructionTokens: currentInstructionTokens,
|
|
2966
|
-
reasoningType:
|
|
2967
|
-
|
|
2968
|
-
|
|
2969
|
-
: ContentTypes.THINKING,
|
|
2972
|
+
reasoningType: usesBedrockThinking
|
|
2973
|
+
? ContentTypes.REASONING_CONTENT
|
|
2974
|
+
: ContentTypes.THINKING,
|
|
2970
2975
|
thinkingStartIndex:
|
|
2971
2976
|
factoryParams.thinkingEnabled === true
|
|
2972
2977
|
? runThinkingStartIndex
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import type { BaseChatModel } from '@langchain/core/language_models/chat_models';
|
|
2
|
+
|
|
3
|
+
declare const CUSTOM_PROVIDER_OPTIONS_TYPE: unique symbol;
|
|
4
|
+
|
|
5
|
+
/** Declaration-merge this map to type host-registered provider options. */
|
|
6
|
+
export interface CustomProviderOptionsMap {
|
|
7
|
+
readonly [CUSTOM_PROVIDER_OPTIONS_TYPE]?: never;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export type ProviderFamily =
|
|
11
|
+
| 'openai'
|
|
12
|
+
| 'anthropic'
|
|
13
|
+
| 'bedrock'
|
|
14
|
+
| 'google'
|
|
15
|
+
| 'mistral'
|
|
16
|
+
| 'generic';
|
|
17
|
+
|
|
18
|
+
export interface ProviderRegistrationOptions<
|
|
19
|
+
TOptions extends object,
|
|
20
|
+
TModel extends BaseChatModel,
|
|
21
|
+
> {
|
|
22
|
+
provider: string;
|
|
23
|
+
model: new (config: TOptions) => TModel;
|
|
24
|
+
family?: ProviderFamily;
|
|
25
|
+
manualToolStream?: boolean;
|
|
26
|
+
strictAlternation?: boolean;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export { registerProvider } from './llm/providers';
|
package/src/run.ts
CHANGED
package/src/stream.ts
CHANGED
|
@@ -820,12 +820,11 @@ function startEagerToolExecutions(args: {
|
|
|
820
820
|
toolCalls: entries.map((entry) => entry.request),
|
|
821
821
|
userId: graph.config?.configurable?.user_id as string | undefined,
|
|
822
822
|
agentId: agentContext?.agentId,
|
|
823
|
-
callerCapabilityProjection:
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
)?.getCallerCapabilityProjectionSnapshot?.(),
|
|
823
|
+
callerCapabilityProjection: (
|
|
824
|
+
agentContext as
|
|
825
|
+
| Partial<Pick<AgentContext, 'getCallerCapabilityProjectionSnapshot'>>
|
|
826
|
+
| undefined
|
|
827
|
+
)?.getCallerCapabilityProjectionSnapshot?.(),
|
|
829
828
|
configurable: graph.config?.configurable as
|
|
830
829
|
| Record<string, unknown>
|
|
831
830
|
| undefined,
|
|
@@ -1327,7 +1326,7 @@ export function getChunkContent({
|
|
|
1327
1326
|
reasoningKey,
|
|
1328
1327
|
}: {
|
|
1329
1328
|
chunk?: Partial<AIMessageChunk>;
|
|
1330
|
-
provider?:
|
|
1329
|
+
provider?: t.ProviderName;
|
|
1331
1330
|
reasoningKey: 'reasoning_content' | 'reasoning';
|
|
1332
1331
|
}): string | t.MessageContentComplex[] | undefined {
|
|
1333
1332
|
if (
|
|
@@ -1851,7 +1850,7 @@ export class ChatModelStreamHandler implements t.EventHandler {
|
|
|
1851
1850
|
|
|
1852
1851
|
if (Array.isArray(content) && content.every(isTextContentPart)) {
|
|
1853
1852
|
const contentGroups = splitAssistantTextContentByPhase(content);
|
|
1854
|
-
const currentStepId = graph.stepKeyIds
|
|
1853
|
+
const currentStepId = graph.stepKeyIds.get(stepKey)?.at(-1);
|
|
1855
1854
|
const currentStep =
|
|
1856
1855
|
currentStepId == null ? undefined : graph.getRunStep(currentStepId);
|
|
1857
1856
|
const currentPhase =
|