@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
|
@@ -7,8 +7,18 @@ import type {
|
|
|
7
7
|
BaseMessageFields,
|
|
8
8
|
} from '@langchain/core/messages';
|
|
9
9
|
import type { RunnableConfig, Runnable } from '@langchain/core/runnables';
|
|
10
|
-
import type * as t from '@/types';
|
|
11
10
|
import type { ExactTokenCountCache } from '@/llm/contextPressureMeter';
|
|
11
|
+
import type * as t from '@/types';
|
|
12
|
+
import {
|
|
13
|
+
type CallerCapabilityProjection,
|
|
14
|
+
allowsToolCaller,
|
|
15
|
+
applyCallerCapabilityDefinitionOverrides,
|
|
16
|
+
createCallerCapabilityProjectionSnapshot,
|
|
17
|
+
isToolDefinitionActive,
|
|
18
|
+
isProgrammaticControlTool,
|
|
19
|
+
mergeCallerCapabilityDefinitions,
|
|
20
|
+
resolveCallerCapabilityProjection,
|
|
21
|
+
} from '@/tools/CallerCapabilities';
|
|
12
22
|
import {
|
|
13
23
|
addTailCacheControl,
|
|
14
24
|
addCacheControlToStablePrefixMessages,
|
|
@@ -19,6 +29,12 @@ import {
|
|
|
19
29
|
cloneMessage,
|
|
20
30
|
type PromptCacheTtl,
|
|
21
31
|
} from '@/messages/cache';
|
|
32
|
+
import {
|
|
33
|
+
isProgrammaticRunnerAutoBound,
|
|
34
|
+
isProgrammaticRunnerResolvedDirectly,
|
|
35
|
+
resolveLocalImplementationNames,
|
|
36
|
+
resolveLocalToolRegistry,
|
|
37
|
+
} from '@/tools/local/resolveLocalExecutionTools';
|
|
22
38
|
import {
|
|
23
39
|
DEFAULT_RESERVE_RATIO,
|
|
24
40
|
ORIGINAL_CONTENT_MAX_CHARS,
|
|
@@ -33,27 +49,11 @@ import {
|
|
|
33
49
|
Constants,
|
|
34
50
|
Providers,
|
|
35
51
|
} from '@/common';
|
|
36
|
-
import {
|
|
37
|
-
|
|
38
|
-
isProgrammaticRunnerResolvedDirectly,
|
|
39
|
-
resolveLocalImplementationNames,
|
|
40
|
-
resolveLocalToolRegistry,
|
|
41
|
-
} from '@/tools/local/resolveLocalExecutionTools';
|
|
42
|
-
import {
|
|
43
|
-
type CallerCapabilityProjection,
|
|
44
|
-
allowsToolCaller,
|
|
45
|
-
applyCallerCapabilityDefinitionOverrides,
|
|
46
|
-
createCallerCapabilityProjectionSnapshot,
|
|
47
|
-
isToolDefinitionActive,
|
|
48
|
-
isProgrammaticControlTool,
|
|
49
|
-
mergeCallerCapabilityDefinitions,
|
|
50
|
-
resolveCallerCapabilityProjection,
|
|
51
|
-
} from '@/tools/CallerCapabilities';
|
|
52
|
+
import { isTokenCounterCacheCompatible } from '@/llm/tokenCounterCacheCompatibility';
|
|
53
|
+
import { createExactTokenCountCache } from '@/llm/contextPressureMeter';
|
|
52
54
|
import { createSchemaOnlyTools } from '@/tools/schema';
|
|
53
55
|
import { apportionTokenCounts } from '@/utils/tokens';
|
|
54
56
|
import { isThinkingEnabled } from '@/llm/request';
|
|
55
|
-
import { createExactTokenCountCache } from '@/llm/contextPressureMeter';
|
|
56
|
-
import { isTokenCounterCacheCompatible } from '@/llm/tokenCounterCacheCompatibility';
|
|
57
57
|
import { toJsonSchema } from '@/utils/schema';
|
|
58
58
|
|
|
59
59
|
type AgentSystemTextBlock = {
|
|
@@ -201,7 +201,7 @@ export class AgentContext {
|
|
|
201
201
|
/** Human-readable name for this agent (used in handoff context). Falls back to agentId if not provided. */
|
|
202
202
|
name?: string;
|
|
203
203
|
/** Provider for this specific agent */
|
|
204
|
-
provider:
|
|
204
|
+
provider: t.ProviderName;
|
|
205
205
|
/** Client options for this agent */
|
|
206
206
|
clientOptions?: t.ClientOptions;
|
|
207
207
|
/** Per-agent Langfuse tracing configuration. */
|
|
@@ -433,7 +433,7 @@ export class AgentContext {
|
|
|
433
433
|
agentId: string;
|
|
434
434
|
codeSessionKey?: string;
|
|
435
435
|
name?: string;
|
|
436
|
-
provider:
|
|
436
|
+
provider: t.ProviderName;
|
|
437
437
|
clientOptions?: t.ClientOptions;
|
|
438
438
|
langfuse?: t.LangfuseConfig;
|
|
439
439
|
maxContextTokens?: number;
|
|
@@ -570,7 +570,9 @@ export class AgentContext {
|
|
|
570
570
|
directOnlyToolNames.length > 0
|
|
571
571
|
? `\nCall these tools directly; never list them in the \`tool_manifest\` or reference them inside ${programmaticRunnerNames}: ${directOnlyToolNames
|
|
572
572
|
.map((name) => `\`${name}\``)
|
|
573
|
-
.join(
|
|
573
|
+
.join(
|
|
574
|
+
', '
|
|
575
|
+
)}. Every ${programmaticRunnerNames} call must include a \`tool_manifest\` containing the exact registered names used by its code; the manifest is validated before execution starts.`
|
|
574
576
|
: '';
|
|
575
577
|
const boundary =
|
|
576
578
|
'\n\n' +
|
|
@@ -658,9 +660,8 @@ export class AgentContext {
|
|
|
658
660
|
this.toolExecution,
|
|
659
661
|
this.toolDefinitions?.some((toolDef) => toolDef.name === name) === true
|
|
660
662
|
) ||
|
|
661
|
-
this.graphTools?.some(
|
|
662
|
-
|
|
663
|
-
) === true
|
|
663
|
+
this.graphTools?.some((tool) => 'name' in tool && tool.name === name) ===
|
|
664
|
+
true
|
|
664
665
|
);
|
|
665
666
|
}
|
|
666
667
|
|
|
@@ -1618,7 +1619,7 @@ export class AgentContext {
|
|
|
1618
1619
|
|
|
1619
1620
|
/** Applies token calibration only when the observation came from this provider. */
|
|
1620
1621
|
applyObservedOverflowCalibration(
|
|
1621
|
-
provider:
|
|
1622
|
+
provider: t.ProviderName | undefined,
|
|
1622
1623
|
observedCalibrationRatio: number | undefined
|
|
1623
1624
|
): void {
|
|
1624
1625
|
if (
|
package/src/graphs/Graph.ts
CHANGED
|
@@ -72,7 +72,6 @@ import {
|
|
|
72
72
|
splitAtRecencyBoundary,
|
|
73
73
|
convertInjectedMessages,
|
|
74
74
|
coalesceAdjacentUserTurns,
|
|
75
|
-
strictAlternationProviders,
|
|
76
75
|
appendPredecessorHandoffCue,
|
|
77
76
|
stampSyntheticProviderMessage,
|
|
78
77
|
} from '@/messages';
|
|
@@ -98,14 +97,6 @@ import {
|
|
|
98
97
|
joinKeys,
|
|
99
98
|
sleep,
|
|
100
99
|
} from '@/utils';
|
|
101
|
-
import {
|
|
102
|
-
attemptInvoke,
|
|
103
|
-
tryFallbackProviders,
|
|
104
|
-
getFallbackErrorContext,
|
|
105
|
-
getFallbackOverflowCandidates,
|
|
106
|
-
} from '@/llm/invoke';
|
|
107
|
-
import { prepareProviderRequest } from '@/llm/prepareProviderRequest';
|
|
108
|
-
import { createContextPressureMeter } from '@/llm/contextPressureMeter';
|
|
109
100
|
import {
|
|
110
101
|
resolveStreamLimits,
|
|
111
102
|
StreamLimitExceededError,
|
|
@@ -130,6 +121,12 @@ import {
|
|
|
130
121
|
planContextOverflowRecovery,
|
|
131
122
|
translateRecoveryBudget,
|
|
132
123
|
} from '@/llm/contextOverflowRecovery';
|
|
124
|
+
import {
|
|
125
|
+
attemptInvoke,
|
|
126
|
+
tryFallbackProviders,
|
|
127
|
+
getFallbackErrorContext,
|
|
128
|
+
getFallbackOverflowCandidates,
|
|
129
|
+
} from '@/llm/invoke';
|
|
133
130
|
import {
|
|
134
131
|
hasToolOutputTracingConfig,
|
|
135
132
|
resolveLangfuseConfig,
|
|
@@ -159,8 +156,11 @@ import { createLocalCodingToolBundle } from '@/tools/local/LocalCodingTools';
|
|
|
159
156
|
import { SUBAGENT_REPLAY_CONTROLLER } from '@/tools/subagent/SubagentReplay';
|
|
160
157
|
import { applyGraphRuntimeConfig } from '@/graphs/applyGraphRuntimeConfig';
|
|
161
158
|
import { partitionAndMarkBedrockToolCache } from '@/llm/bedrock/toolCache';
|
|
159
|
+
import { createContextPressureMeter } from '@/llm/contextPressureMeter';
|
|
162
160
|
import { safeDispatchCustomEvent, emitAgentLog } from '@/utils/events';
|
|
161
|
+
import { prepareProviderRequest } from '@/llm/prepareProviderRequest';
|
|
163
162
|
import { createCloudflareCodingToolBundle } from '@/tools/cloudflare';
|
|
163
|
+
import { providerRequiresStrictAlternation } from '@/llm/providers';
|
|
164
164
|
import { buildSubagentToolParams } from '@/tools/SubagentTool';
|
|
165
165
|
import { initializeLangfuseTracing } from '@/instrumentation';
|
|
166
166
|
import { shouldTriggerSummarization } from '@/summarization';
|
|
@@ -324,7 +324,7 @@ function isGoogleServerSideToolMessageContentPart(
|
|
|
324
324
|
}
|
|
325
325
|
|
|
326
326
|
function hasGoogleServerSideToolDeltaContent(
|
|
327
|
-
provider:
|
|
327
|
+
provider: t.ProviderName | undefined,
|
|
328
328
|
content: t.MessageDelta['content']
|
|
329
329
|
): content is t.MessageContentComplex[] {
|
|
330
330
|
return (
|
|
@@ -337,7 +337,7 @@ function hasGoogleServerSideToolDeltaContent(
|
|
|
337
337
|
}
|
|
338
338
|
|
|
339
339
|
function getMessageDeltaContent(
|
|
340
|
-
provider:
|
|
340
|
+
provider: t.ProviderName | undefined,
|
|
341
341
|
content: MessageContent | undefined
|
|
342
342
|
): t.MessageDelta['content'] | undefined {
|
|
343
343
|
if (content == null) {
|
|
@@ -550,7 +550,7 @@ async function dispatchTextMessageContent({
|
|
|
550
550
|
}: {
|
|
551
551
|
graph: Graph<t.BaseGraphState>;
|
|
552
552
|
stepKey: string;
|
|
553
|
-
provider?:
|
|
553
|
+
provider?: t.ProviderName;
|
|
554
554
|
content: t.MessageDelta['content'];
|
|
555
555
|
metadata: Record<string, unknown>;
|
|
556
556
|
}): Promise<boolean> {
|
|
@@ -3237,7 +3237,7 @@ export class StandardGraph extends Graph<t.BaseGraphState, t.GraphNode> {
|
|
|
3237
3237
|
info,
|
|
3238
3238
|
}: {
|
|
3239
3239
|
projection: ReturnType<typeof measureProviderPayload>;
|
|
3240
|
-
provider?:
|
|
3240
|
+
provider?: t.ProviderName;
|
|
3241
3241
|
info: string;
|
|
3242
3242
|
}): ContextOverflowError => {
|
|
3243
3243
|
const error = new ContextOverflowError(
|
|
@@ -3508,7 +3508,7 @@ export class StandardGraph extends Graph<t.BaseGraphState, t.GraphNode> {
|
|
|
3508
3508
|
* drop messages, so coalescing has to see its output, and it is the
|
|
3509
3509
|
* last shaping step before the cache breakpoint is chosen.
|
|
3510
3510
|
*/
|
|
3511
|
-
if (
|
|
3511
|
+
if (providerRequiresStrictAlternation(agentContext.provider)) {
|
|
3512
3512
|
/**
|
|
3513
3513
|
* Wrapped like every other provider transform: the merged message is
|
|
3514
3514
|
* a NEW object, and without re-attachment the final pre-invoke
|
package/src/index.ts
CHANGED
|
@@ -78,6 +78,11 @@ export type {
|
|
|
78
78
|
ChatOpenRouterCallOptions,
|
|
79
79
|
} from './llm/openrouter';
|
|
80
80
|
export { getChatModelClass } from './llm/providers';
|
|
81
|
+
export { registerProvider } from './provider-registration';
|
|
82
|
+
export type {
|
|
83
|
+
ProviderFamily,
|
|
84
|
+
ProviderRegistrationOptions,
|
|
85
|
+
} from './provider-registration';
|
|
81
86
|
export { CustomChatMistralAI } from './llm/mistral';
|
|
82
87
|
export {
|
|
83
88
|
smoothStream,
|
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
* provider-space budget.
|
|
19
19
|
*/
|
|
20
20
|
import type { ContextOverflowInfo } from '@/utils/errors';
|
|
21
|
-
import type {
|
|
21
|
+
import type { ProviderName } from '@/types';
|
|
22
22
|
import { getContextOverflowInfo } from '@/utils/errors';
|
|
23
23
|
|
|
24
24
|
/** Fraction of the previous budget used when the provider named no ceiling. */
|
|
@@ -66,7 +66,7 @@ export interface OverflowRecoveryPlan {
|
|
|
66
66
|
|
|
67
67
|
export interface OverflowRecoveryParams {
|
|
68
68
|
error: unknown;
|
|
69
|
-
provider:
|
|
69
|
+
provider: ProviderName;
|
|
70
70
|
/** Budget in force when the rejected prompt was built. */
|
|
71
71
|
maxContextTokens?: number;
|
|
72
72
|
/** Our own estimate of the prompt we actually sent. */
|
package/src/llm/init.ts
CHANGED
|
@@ -6,29 +6,46 @@ import { getChatModelClass } from '@/llm/providers';
|
|
|
6
6
|
import { isOpenAILike } from '@/utils';
|
|
7
7
|
import { Providers } from '@/common';
|
|
8
8
|
|
|
9
|
+
type InitializeModelParams<P extends t.ProviderName> = {
|
|
10
|
+
provider: P;
|
|
11
|
+
tools?: t.GraphTools;
|
|
12
|
+
} & (
|
|
13
|
+
| {
|
|
14
|
+
override: t.ChatModelInstance;
|
|
15
|
+
clientOptions?: t.ProviderOptionsFor<P>;
|
|
16
|
+
}
|
|
17
|
+
| ([P] extends [keyof t.ProviderOptionsMap]
|
|
18
|
+
? {
|
|
19
|
+
override?: t.ChatModelInstance;
|
|
20
|
+
clientOptions?: t.ProviderOptionsFor<P>;
|
|
21
|
+
}
|
|
22
|
+
: object extends t.ProviderOptionsFor<P>
|
|
23
|
+
? {
|
|
24
|
+
override?: t.ChatModelInstance;
|
|
25
|
+
clientOptions?: t.ProviderOptionsFor<P>;
|
|
26
|
+
}
|
|
27
|
+
: {
|
|
28
|
+
override?: undefined;
|
|
29
|
+
clientOptions: t.ProviderOptionsFor<P>;
|
|
30
|
+
})
|
|
31
|
+
);
|
|
32
|
+
|
|
9
33
|
/**
|
|
10
|
-
* Creates a chat model instance for a given
|
|
11
|
-
* field assignments, and optionally binds
|
|
12
|
-
*
|
|
13
|
-
* This is the single entry point for model creation across the codebase — used
|
|
14
|
-
* by both the agent graph (main LLM) and the summarization node (compaction LLM).
|
|
15
|
-
* An optional `override` model can be passed to skip construction entirely
|
|
16
|
-
* (useful for cached/reused model instances or test fakes).
|
|
34
|
+
* Creates a chat model instance for a given built-in or host-registered
|
|
35
|
+
* provider, applies provider-specific field assignments, and optionally binds
|
|
36
|
+
* tools.
|
|
17
37
|
*/
|
|
18
|
-
export function initializeModel({
|
|
38
|
+
export function initializeModel<P extends t.ProviderName>({
|
|
19
39
|
provider,
|
|
20
40
|
clientOptions,
|
|
21
41
|
tools,
|
|
22
42
|
override,
|
|
23
|
-
}: {
|
|
24
|
-
provider: Providers;
|
|
25
|
-
clientOptions?: t.ClientOptions;
|
|
26
|
-
tools?: t.GraphTools;
|
|
27
|
-
override?: t.ChatModelInstance;
|
|
28
|
-
}): Runnable {
|
|
43
|
+
}: InitializeModelParams<P>): Runnable {
|
|
29
44
|
const model =
|
|
30
45
|
override ??
|
|
31
|
-
new (getChatModelClass(provider))(
|
|
46
|
+
new (getChatModelClass(provider))(
|
|
47
|
+
(clientOptions ?? {}) as t.ProviderOptionsFor<P>
|
|
48
|
+
);
|
|
32
49
|
|
|
33
50
|
if (
|
|
34
51
|
isOpenAILike(provider) &&
|
|
@@ -56,8 +73,14 @@ export function initializeModel({
|
|
|
56
73
|
}
|
|
57
74
|
|
|
58
75
|
if (!tools || tools.length === 0) {
|
|
59
|
-
return model
|
|
76
|
+
return model;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
if (!('bindTools' in model) || typeof model.bindTools !== 'function') {
|
|
80
|
+
throw new TypeError(
|
|
81
|
+
`LLM provider does not support tool binding: ${provider}`
|
|
82
|
+
);
|
|
60
83
|
}
|
|
61
84
|
|
|
62
|
-
return
|
|
85
|
+
return model.bindTools(tools);
|
|
63
86
|
}
|
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;
|
|
@@ -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 !==
|