@librechat/agents 3.6.16 → 3.7.1
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/agents/AgentContext.cjs +11 -2
- package/dist/cjs/agents/AgentContext.cjs.map +1 -1
- package/dist/cjs/graphs/Graph.cjs +12 -9
- 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/invoke.cjs +56 -9
- package/dist/cjs/llm/invoke.cjs.map +1 -1
- package/dist/cjs/llm/mistral/index.cjs +9 -0
- package/dist/cjs/llm/mistral/index.cjs.map +1 -1
- package/dist/cjs/llm/openai/index.cjs +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 +19 -11
- package/dist/cjs/messages/content.cjs +8 -5
- package/dist/cjs/messages/content.cjs.map +1 -1
- package/dist/cjs/messages/core.cjs +9 -4
- package/dist/cjs/messages/core.cjs.map +1 -1
- package/dist/cjs/messages/format.cjs +15 -5
- package/dist/cjs/messages/format.cjs.map +1 -1
- package/dist/cjs/messages/index.cjs +2 -1
- package/dist/cjs/messages/projectionInvariant.cjs +74 -0
- package/dist/cjs/messages/projectionInvariant.cjs.map +1 -0
- package/dist/cjs/messages/provenance.cjs +30 -8
- package/dist/cjs/messages/provenance.cjs.map +1 -1
- package/dist/cjs/messages/prune.cjs +42 -8
- package/dist/cjs/messages/prune.cjs.map +1 -1
- package/dist/cjs/messages/recency.cjs +202 -7
- package/dist/cjs/messages/recency.cjs.map +1 -1
- package/dist/cjs/messages/toolResultTypes.cjs +1 -0
- package/dist/cjs/run.cjs +7 -2
- package/dist/cjs/run.cjs.map +1 -1
- package/dist/cjs/session/AgentSession.cjs +4 -23
- package/dist/cjs/session/AgentSession.cjs.map +1 -1
- package/dist/cjs/session/deriveMessages.cjs +25 -0
- package/dist/cjs/session/deriveMessages.cjs.map +1 -0
- package/dist/cjs/session/index.cjs +1 -0
- package/dist/cjs/summarization/node.cjs +13 -6
- package/dist/cjs/summarization/node.cjs.map +1 -1
- package/dist/cjs/tools/Calculator.cjs +7 -4
- package/dist/cjs/tools/Calculator.cjs.map +1 -1
- package/dist/cjs/tools/CodeExecutor.cjs +1 -1
- package/dist/cjs/tools/subagent/InMemorySubagentTaskStore.cjs +65 -8
- package/dist/cjs/tools/subagent/InMemorySubagentTaskStore.cjs.map +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/agents/AgentContext.mjs +11 -2
- package/dist/esm/agents/AgentContext.mjs.map +1 -1
- package/dist/esm/graphs/Graph.mjs +12 -9
- 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/invoke.mjs +56 -9
- package/dist/esm/llm/invoke.mjs.map +1 -1
- package/dist/esm/llm/mistral/index.mjs +3 -1
- package/dist/esm/llm/mistral/index.mjs.map +1 -1
- package/dist/esm/llm/openai/index.mjs +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 +10 -11
- package/dist/esm/messages/content.mjs +8 -6
- package/dist/esm/messages/content.mjs.map +1 -1
- package/dist/esm/messages/core.mjs +9 -5
- package/dist/esm/messages/core.mjs.map +1 -1
- package/dist/esm/messages/format.mjs +16 -6
- package/dist/esm/messages/format.mjs.map +1 -1
- package/dist/esm/messages/index.mjs +2 -1
- package/dist/esm/messages/projectionInvariant.mjs +72 -0
- package/dist/esm/messages/projectionInvariant.mjs.map +1 -0
- package/dist/esm/messages/provenance.mjs +30 -9
- package/dist/esm/messages/provenance.mjs.map +1 -1
- package/dist/esm/messages/prune.mjs +42 -9
- package/dist/esm/messages/prune.mjs.map +1 -1
- package/dist/esm/messages/recency.mjs +201 -8
- package/dist/esm/messages/recency.mjs.map +1 -1
- package/dist/esm/messages/toolResultTypes.mjs +1 -1
- package/dist/esm/run.mjs +8 -3
- package/dist/esm/run.mjs.map +1 -1
- package/dist/esm/session/AgentSession.mjs +4 -23
- package/dist/esm/session/AgentSession.mjs.map +1 -1
- package/dist/esm/session/deriveMessages.mjs +25 -0
- package/dist/esm/session/deriveMessages.mjs.map +1 -0
- package/dist/esm/session/index.mjs +1 -0
- package/dist/esm/summarization/node.mjs +14 -7
- package/dist/esm/summarization/node.mjs.map +1 -1
- package/dist/esm/tools/Calculator.mjs +7 -2
- package/dist/esm/tools/Calculator.mjs.map +1 -1
- package/dist/esm/tools/CodeExecutor.mjs +1 -1
- package/dist/esm/tools/subagent/InMemorySubagentTaskStore.mjs +65 -8
- package/dist/esm/tools/subagent/InMemorySubagentTaskStore.mjs.map +1 -1
- package/dist/esm/utils/llm.mjs +15 -1
- package/dist/esm/utils/llm.mjs.map +1 -1
- package/dist/types/agents/AgentContext.d.ts +6 -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/content.d.ts +4 -1
- package/dist/types/messages/core.d.ts +2 -0
- package/dist/types/messages/format.d.ts +6 -0
- package/dist/types/messages/index.d.ts +1 -0
- package/dist/types/messages/projectionInvariant.d.ts +25 -0
- package/dist/types/messages/provenance.d.ts +10 -0
- package/dist/types/messages/prune.d.ts +5 -4
- package/dist/types/messages/recency.d.ts +30 -18
- package/dist/types/session/deriveMessages.d.ts +11 -0
- package/dist/types/session/index.d.ts +2 -0
- package/dist/types/tools/subagent/InMemorySubagentTaskStore.d.ts +13 -1
- package/dist/types/types/graph.d.ts +1 -1
- package/dist/types/types/subagentTasks.d.ts +22 -0
- package/dist/types/types/summarize.d.ts +15 -13
- package/dist/types/utils/llm.d.ts +10 -0
- package/package.json +60 -1
- package/src/agents/AgentContext.ts +19 -5
- package/src/graphs/Graph.ts +11 -9
- 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/invoke.ts +102 -23
- 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/content.ts +20 -10
- package/src/messages/core.ts +16 -11
- package/src/messages/format.ts +29 -5
- package/src/messages/index.ts +1 -0
- package/src/messages/projectionInvariant.ts +134 -0
- package/src/messages/provenance.ts +60 -18
- package/src/messages/prune.ts +86 -11
- package/src/messages/recency.ts +429 -27
- package/src/run.ts +14 -6
- package/src/session/AgentSession.ts +4 -30
- package/src/session/deriveMessages.ts +37 -0
- package/src/session/index.ts +2 -0
- package/src/summarization/node.ts +37 -15
- package/src/tools/Calculator.ts +9 -2
- package/src/tools/subagent/InMemorySubagentTaskStore.ts +139 -6
- package/src/types/graph.ts +1 -0
- package/src/types/subagentTasks.ts +28 -0
- package/src/types/summarize.ts +15 -13
- package/src/utils/llm.ts +39 -0
|
@@ -5,6 +5,22 @@ import type { InjectedMessage } from './tools';
|
|
|
5
5
|
export type SubagentTaskStatus = 'running' | 'completed' | 'error' | 'cancelled';
|
|
6
6
|
/** Where a pending parent message may enter the child run. */
|
|
7
7
|
export type SubagentTaskBoundary = 'preempt' | 'tool' | 'turn';
|
|
8
|
+
/**
|
|
9
|
+
* Lifecycle of one parent-to-child message after the task store accepts it.
|
|
10
|
+
* Hosts may render a transient `submitted` state before this authoritative
|
|
11
|
+
* receipt exists; that transport state is intentionally not persisted here.
|
|
12
|
+
*/
|
|
13
|
+
export type SubagentTaskControlReceiptStatus = 'accepted' | 'applied' | 'rejected' | 'failed';
|
|
14
|
+
/** Bounded authoritative receipt for one steer, queue, or interrupt command. */
|
|
15
|
+
export interface SubagentTaskControlReceipt {
|
|
16
|
+
controlId: string;
|
|
17
|
+
action: 'steer' | 'queue' | 'interrupt';
|
|
18
|
+
status: SubagentTaskControlReceiptStatus;
|
|
19
|
+
createdAt: number;
|
|
20
|
+
updatedAt: number;
|
|
21
|
+
boundary?: SubagentTaskBoundary;
|
|
22
|
+
reason?: 'withdrawn' | 'task_completed' | 'task_cancelled' | 'task_failed';
|
|
23
|
+
}
|
|
8
24
|
/** Parent-to-child control operations accepted while a task is running. */
|
|
9
25
|
export type SubagentTaskControlCommand = {
|
|
10
26
|
action: 'steer' | 'queue' | 'interrupt';
|
|
@@ -39,6 +55,12 @@ export interface SubagentTaskSnapshot {
|
|
|
39
55
|
resultAvailable: boolean;
|
|
40
56
|
resultClaimed: boolean;
|
|
41
57
|
pendingControls: number;
|
|
58
|
+
/**
|
|
59
|
+
* Bounded receipts emitted by stores that support authoritative control
|
|
60
|
+
* tracking. Optional so legacy and custom stores remain compatible during
|
|
61
|
+
* rolling upgrades.
|
|
62
|
+
*/
|
|
63
|
+
controlReceipts?: SubagentTaskControlReceipt[];
|
|
42
64
|
progress?: SubagentTaskProgress;
|
|
43
65
|
error?: string;
|
|
44
66
|
}
|
|
@@ -5,25 +5,27 @@ export type SummarizationTrigger = {
|
|
|
5
5
|
value: number;
|
|
6
6
|
};
|
|
7
7
|
/**
|
|
8
|
-
* Controls how
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
8
|
+
* Controls how much recent context is preserved verbatim during compaction.
|
|
9
|
+
* User-turn boundaries are preferred. Under context pressure, older closed
|
|
10
|
+
* tool units inside an otherwise indivisible turn may be summarized while a
|
|
11
|
+
* token-priced recent tail is retained. A lone user payload stays intact.
|
|
12
12
|
*/
|
|
13
13
|
export type RetainRecentConfig = {
|
|
14
14
|
/**
|
|
15
|
-
* Maximum number of recent user-led turns to keep in the tail.
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
15
|
+
* Maximum number of recent user-led turns to keep in the tail. A turn begins
|
|
16
|
+
* at a user-authored HumanMessage and includes every following AIMessage and
|
|
17
|
+
* tool result up to the next user-authored HumanMessage. Provider-native
|
|
18
|
+
* HumanMessages containing only tool results remain in the current turn.
|
|
19
|
+
* Set to `0` to disable the recency window (legacy behavior: summarize
|
|
20
|
+
* everything). Defaults to `2`.
|
|
21
21
|
*/
|
|
22
22
|
turns?: number;
|
|
23
23
|
/**
|
|
24
|
-
* Optional
|
|
25
|
-
*
|
|
26
|
-
*
|
|
24
|
+
* Optional retained-recent token budget. Older turns are added whole only
|
|
25
|
+
* while cumulative tokens stay below the cap. If a tool-heavy history has
|
|
26
|
+
* no compactable turn-level head, this is also the minimum recent tail kept
|
|
27
|
+
* behind a pairing-balanced intra-turn cut. When omitted, that fallback
|
|
28
|
+
* retains 16% of the configured context window.
|
|
27
29
|
*/
|
|
28
30
|
tokens?: number;
|
|
29
31
|
};
|
|
@@ -1,4 +1,14 @@
|
|
|
1
1
|
import type { ProviderName } from '@/types';
|
|
2
|
+
/** Walks the constructor chain for LangChain's `lc_name` serialization ids.
|
|
3
|
+
* Constructor identity is unusable across lazily loaded module formats — the
|
|
4
|
+
* CJS and ESM builds carry distinct classes — so guards match on the ids the
|
|
5
|
+
* relevant classes declare instead of on `instanceof`. */
|
|
6
|
+
export declare function constructorChainHasLcName(model: unknown, names: ReadonlySet<string>): boolean;
|
|
7
|
+
/** Matches exactly the instances that were `instanceof` this package's
|
|
8
|
+
* `ChatOpenAI`/`AzureChatOpenAI`: only those classes declare the
|
|
9
|
+
* `LibreChatOpenAI`/`LibreChatAzureOpenAI` ids, their subclasses keep them in
|
|
10
|
+
* the chain, and upstream `@langchain/openai` classes never carry them. */
|
|
11
|
+
export declare function isLibreChatOpenAIModel(model: unknown): model is import('@/llm/openai').ChatOpenAI | import('@/llm/openai').AzureChatOpenAI;
|
|
2
12
|
export declare function isOpenAILike(provider?: ProviderName): boolean;
|
|
3
13
|
export declare function isGoogleLike(provider?: ProviderName): boolean;
|
|
4
14
|
/** Returns true for native Anthropic or Bedrock running a Claude model. */
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@librechat/agents",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.7.1",
|
|
4
4
|
"reova": {
|
|
5
5
|
"enabled": true,
|
|
6
6
|
"endpoint": "https://telemetry.reo.dev/data"
|
|
@@ -78,6 +78,41 @@
|
|
|
78
78
|
"types": "./dist/types/langchain/utils/env.d.ts",
|
|
79
79
|
"import": "./dist/esm/langchain/utils/env.mjs",
|
|
80
80
|
"require": "./dist/cjs/langchain/utils/env.cjs"
|
|
81
|
+
},
|
|
82
|
+
"./llm/openai": {
|
|
83
|
+
"types": "./dist/types/llm/openai/index.d.ts",
|
|
84
|
+
"import": "./dist/esm/llm/openai/index.mjs",
|
|
85
|
+
"require": "./dist/cjs/llm/openai/index.cjs"
|
|
86
|
+
},
|
|
87
|
+
"./llm/mistral": {
|
|
88
|
+
"types": "./dist/types/llm/mistral/index.d.ts",
|
|
89
|
+
"import": "./dist/esm/llm/mistral/index.mjs",
|
|
90
|
+
"require": "./dist/cjs/llm/mistral/index.cjs"
|
|
91
|
+
},
|
|
92
|
+
"./llm/anthropic": {
|
|
93
|
+
"types": "./dist/types/llm/anthropic/index.d.ts",
|
|
94
|
+
"import": "./dist/esm/llm/anthropic/index.mjs",
|
|
95
|
+
"require": "./dist/cjs/llm/anthropic/index.cjs"
|
|
96
|
+
},
|
|
97
|
+
"./llm/google": {
|
|
98
|
+
"types": "./dist/types/llm/google/index.d.ts",
|
|
99
|
+
"import": "./dist/esm/llm/google/index.mjs",
|
|
100
|
+
"require": "./dist/cjs/llm/google/index.cjs"
|
|
101
|
+
},
|
|
102
|
+
"./llm/bedrock": {
|
|
103
|
+
"types": "./dist/types/llm/bedrock/index.d.ts",
|
|
104
|
+
"import": "./dist/esm/llm/bedrock/index.mjs",
|
|
105
|
+
"require": "./dist/cjs/llm/bedrock/index.cjs"
|
|
106
|
+
},
|
|
107
|
+
"./llm/vertexai": {
|
|
108
|
+
"types": "./dist/types/llm/vertexai/index.d.ts",
|
|
109
|
+
"import": "./dist/esm/llm/vertexai/index.mjs",
|
|
110
|
+
"require": "./dist/cjs/llm/vertexai/index.cjs"
|
|
111
|
+
},
|
|
112
|
+
"./llm/openrouter": {
|
|
113
|
+
"types": "./dist/types/llm/openrouter/index.d.ts",
|
|
114
|
+
"import": "./dist/esm/llm/openrouter/index.mjs",
|
|
115
|
+
"require": "./dist/cjs/llm/openrouter/index.cjs"
|
|
81
116
|
}
|
|
82
117
|
},
|
|
83
118
|
"typesVersions": {
|
|
@@ -96,6 +131,27 @@
|
|
|
96
131
|
],
|
|
97
132
|
"responses": [
|
|
98
133
|
"dist/types/responses/index.d.ts"
|
|
134
|
+
],
|
|
135
|
+
"llm/openai": [
|
|
136
|
+
"./dist/types/llm/openai/index.d.ts"
|
|
137
|
+
],
|
|
138
|
+
"llm/mistral": [
|
|
139
|
+
"./dist/types/llm/mistral/index.d.ts"
|
|
140
|
+
],
|
|
141
|
+
"llm/anthropic": [
|
|
142
|
+
"./dist/types/llm/anthropic/index.d.ts"
|
|
143
|
+
],
|
|
144
|
+
"llm/google": [
|
|
145
|
+
"./dist/types/llm/google/index.d.ts"
|
|
146
|
+
],
|
|
147
|
+
"llm/bedrock": [
|
|
148
|
+
"./dist/types/llm/bedrock/index.d.ts"
|
|
149
|
+
],
|
|
150
|
+
"llm/vertexai": [
|
|
151
|
+
"./dist/types/llm/vertexai/index.d.ts"
|
|
152
|
+
],
|
|
153
|
+
"llm/openrouter": [
|
|
154
|
+
"./dist/types/llm/openrouter/index.d.ts"
|
|
99
155
|
]
|
|
100
156
|
}
|
|
101
157
|
},
|
|
@@ -162,6 +218,9 @@
|
|
|
162
218
|
"tool_search": "node -r dotenv/config --loader ./tsconfig-paths-bootstrap.mjs --experimental-specifier-resolution=node ./src/scripts/tool_search.ts",
|
|
163
219
|
"bench:cache": "node --loader ./tsconfig-paths-bootstrap.mjs --experimental-specifier-resolution=node ./src/scripts/bench-prompt-cache.ts",
|
|
164
220
|
"bench:context-pressure": "node --loader ./tsconfig-paths-bootstrap.mjs --experimental-specifier-resolution=node ./src/scripts/bench-context-pressure-cache.ts",
|
|
221
|
+
"bench:compaction-range": "node --loader ./tsconfig-paths-bootstrap.mjs --experimental-specifier-resolution=node ./src/scripts/bench-compaction-range.ts",
|
|
222
|
+
"bench:provider-derivation": "node --loader ./tsconfig-paths-bootstrap.mjs --experimental-specifier-resolution=node ./src/scripts/bench-provider-derivation.ts",
|
|
223
|
+
"bench:provider-projection": "node --loader ./tsconfig-paths-bootstrap.mjs --experimental-specifier-resolution=node ./src/scripts/bench-provider-request-projection.ts",
|
|
165
224
|
"bench:execution-world": "node --loader ./tsconfig-paths-bootstrap.mjs --experimental-specifier-resolution=node ./src/scripts/bench-execution-world.ts",
|
|
166
225
|
"probe:overflow": "node -r dotenv/config --loader ./tsconfig-paths-bootstrap.mjs --experimental-specifier-resolution=node ./src/scripts/context-overflow-probe.ts",
|
|
167
226
|
"subagent": "node -r dotenv/config --loader ./tsconfig-paths-bootstrap.mjs --experimental-specifier-resolution=node ./src/scripts/multi-agent-subagent.ts",
|
|
@@ -357,6 +357,8 @@ export class AgentContext {
|
|
|
357
357
|
* - `'none'`: no summary present
|
|
358
358
|
*/
|
|
359
359
|
private _summaryLocation: 'system_prompt' | 'user_message' | 'none' = 'none';
|
|
360
|
+
/** Whether a mid-run summary must appear before every retained message. */
|
|
361
|
+
private summaryPrecedesMessages: boolean = false;
|
|
360
362
|
/**
|
|
361
363
|
* Durable summary that survives reset() calls. Set from initialSummary
|
|
362
364
|
* during fromConfig() and updated by setSummary() so that the latest
|
|
@@ -365,6 +367,7 @@ export class AgentContext {
|
|
|
365
367
|
*/
|
|
366
368
|
private _durableSummaryText?: string;
|
|
367
369
|
private _durableSummaryTokenCount: number = 0;
|
|
370
|
+
private durableSummaryPrecedesMessages: boolean = false;
|
|
368
371
|
/** Number of summarization cycles that have occurred for this agent context */
|
|
369
372
|
private _summaryVersion: number = 0;
|
|
370
373
|
/**
|
|
@@ -989,10 +992,10 @@ export class AgentContext {
|
|
|
989
992
|
return messages;
|
|
990
993
|
}
|
|
991
994
|
|
|
992
|
-
const tailIndex =
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
995
|
+
const tailIndex =
|
|
996
|
+
this._summaryLocation === 'user_message' && this.summaryPrecedesMessages
|
|
997
|
+
? 0
|
|
998
|
+
: this.getPromptCacheDynamicTailIndex(messages, promptCacheProvider);
|
|
996
999
|
const stablePrefix = messages.slice(0, tailIndex);
|
|
997
1000
|
const trailingMessages = messages.slice(tailIndex);
|
|
998
1001
|
const cacheablePrefix = this.addStablePromptCacheMarkers(
|
|
@@ -1204,6 +1207,7 @@ export class AgentContext {
|
|
|
1204
1207
|
|
|
1205
1208
|
this.summaryText = this._durableSummaryText;
|
|
1206
1209
|
this.summaryTokenCount = this._durableSummaryTokenCount;
|
|
1210
|
+
this.summaryPrecedesMessages = this.durableSummaryPrecedesMessages;
|
|
1207
1211
|
this._lastSummarizationMsgCount = 0;
|
|
1208
1212
|
this.lastCallUsage = undefined;
|
|
1209
1213
|
this.totalTokensFresh = false;
|
|
@@ -1461,12 +1465,18 @@ export class AgentContext {
|
|
|
1461
1465
|
}
|
|
1462
1466
|
}
|
|
1463
1467
|
|
|
1464
|
-
setSummary(
|
|
1468
|
+
setSummary(
|
|
1469
|
+
text: string,
|
|
1470
|
+
tokenCount: number,
|
|
1471
|
+
options?: { precedesMessages?: boolean }
|
|
1472
|
+
): void {
|
|
1465
1473
|
this.summaryText = text;
|
|
1466
1474
|
this.summaryTokenCount = tokenCount;
|
|
1467
1475
|
this._summaryLocation = 'user_message';
|
|
1476
|
+
this.summaryPrecedesMessages = options?.precedesMessages === true;
|
|
1468
1477
|
this._durableSummaryText = text;
|
|
1469
1478
|
this._durableSummaryTokenCount = tokenCount;
|
|
1479
|
+
this.durableSummaryPrecedesMessages = this.summaryPrecedesMessages;
|
|
1470
1480
|
this._summaryVersion += 1;
|
|
1471
1481
|
this.systemRunnableStale = true;
|
|
1472
1482
|
this.pruneMessages = undefined;
|
|
@@ -1477,8 +1487,10 @@ export class AgentContext {
|
|
|
1477
1487
|
this.summaryText = text;
|
|
1478
1488
|
this.summaryTokenCount = tokenCount;
|
|
1479
1489
|
this._summaryLocation = 'system_prompt';
|
|
1490
|
+
this.summaryPrecedesMessages = false;
|
|
1480
1491
|
this._durableSummaryText = text;
|
|
1481
1492
|
this._durableSummaryTokenCount = tokenCount;
|
|
1493
|
+
this.durableSummaryPrecedesMessages = false;
|
|
1482
1494
|
this._summaryVersion += 1;
|
|
1483
1495
|
this.systemRunnableStale = true;
|
|
1484
1496
|
}
|
|
@@ -1683,6 +1695,8 @@ export class AgentContext {
|
|
|
1683
1695
|
this.summaryTokenCount = 0;
|
|
1684
1696
|
this._durableSummaryText = undefined;
|
|
1685
1697
|
this._durableSummaryTokenCount = 0;
|
|
1698
|
+
this.summaryPrecedesMessages = false;
|
|
1699
|
+
this.durableSummaryPrecedesMessages = false;
|
|
1686
1700
|
this._summaryLocation = 'none';
|
|
1687
1701
|
this.systemRunnableStale = true;
|
|
1688
1702
|
}
|
package/src/graphs/Graph.ts
CHANGED
|
@@ -53,9 +53,8 @@ import {
|
|
|
53
53
|
cloneMessage,
|
|
54
54
|
CALIBRATION_RATIO_MAX,
|
|
55
55
|
createPruneMessages,
|
|
56
|
-
|
|
56
|
+
projectToolMessagesForProvider,
|
|
57
57
|
calculateMaxToolCallInputChars,
|
|
58
|
-
projectToolStreamContentForProvider,
|
|
59
58
|
syncBudgetDerivedFields,
|
|
60
59
|
addTailCacheControl,
|
|
61
60
|
resolvePromptCacheTtl,
|
|
@@ -69,6 +68,7 @@ import {
|
|
|
69
68
|
makeIsDeferred,
|
|
70
69
|
partitionAndMarkAnthropicToolCache,
|
|
71
70
|
DEFAULT_RETAIN_RECENT_TURNS,
|
|
71
|
+
resolveIntraTurnRetainTokens,
|
|
72
72
|
splitAtRecencyBoundary,
|
|
73
73
|
convertInjectedMessages,
|
|
74
74
|
coalesceAdjacentUserTurns,
|
|
@@ -3178,15 +3178,10 @@ export class StandardGraph extends Graph<t.BaseGraphState, t.GraphNode> {
|
|
|
3178
3178
|
const maxProviderToolResultChars =
|
|
3179
3179
|
agentContext.maxToolResultChars ??
|
|
3180
3180
|
calculateMaxToolResultChars(agentContext.maxContextTokens);
|
|
3181
|
-
const beforeToolStreamProjection = finalMessages;
|
|
3182
|
-
finalMessages = trackProviderMessageOrigins(
|
|
3183
|
-
beforeToolStreamProjection,
|
|
3184
|
-
projectToolStreamContentForProvider(beforeToolStreamProjection)
|
|
3185
|
-
);
|
|
3186
3181
|
const beforeToolInputProjection = finalMessages;
|
|
3187
3182
|
finalMessages = trackProviderMessageOrigins(
|
|
3188
3183
|
beforeToolInputProjection,
|
|
3189
|
-
|
|
3184
|
+
projectToolMessagesForProvider(
|
|
3190
3185
|
beforeToolInputProjection,
|
|
3191
3186
|
calculateMaxToolCallInputChars(agentContext.maxContextTokens)
|
|
3192
3187
|
)
|
|
@@ -3942,6 +3937,9 @@ export class StandardGraph extends Graph<t.BaseGraphState, t.GraphNode> {
|
|
|
3942
3937
|
*/
|
|
3943
3938
|
const estimatedPromptTokens = getEstimatedPromptTokens(contextUsage);
|
|
3944
3939
|
|
|
3940
|
+
const recencyTokenCounter =
|
|
3941
|
+
agentContext.contextPressureTokenCounts?.count ??
|
|
3942
|
+
agentContext.tokenCounter;
|
|
3945
3943
|
const canSummarizeOverflow =
|
|
3946
3944
|
agentContext.summarizationEnabled === true &&
|
|
3947
3945
|
splitAtRecencyBoundary(messages, {
|
|
@@ -3949,7 +3947,11 @@ export class StandardGraph extends Graph<t.BaseGraphState, t.GraphNode> {
|
|
|
3949
3947
|
agentContext.summarizationConfig?.retainRecent?.turns ??
|
|
3950
3948
|
DEFAULT_RETAIN_RECENT_TURNS,
|
|
3951
3949
|
tokens: agentContext.summarizationConfig?.retainRecent?.tokens,
|
|
3952
|
-
tokenCounter:
|
|
3950
|
+
tokenCounter: recencyTokenCounter,
|
|
3951
|
+
intraTurnTokens: resolveIntraTurnRetainTokens({
|
|
3952
|
+
tokens: agentContext.summarizationConfig?.retainRecent?.tokens,
|
|
3953
|
+
maxContextTokens: agentContext.maxContextTokens,
|
|
3954
|
+
}),
|
|
3953
3955
|
}).head.length > 0;
|
|
3954
3956
|
|
|
3955
3957
|
const getLocalProviderOverflowMeasurement = (
|
package/src/index.ts
CHANGED
|
@@ -70,8 +70,9 @@ export type { Interrupt } from '@langchain/langgraph';
|
|
|
70
70
|
|
|
71
71
|
/* LLM */
|
|
72
72
|
export { markTokenCounterCacheCompatible } from './llm/tokenCounterCacheCompatibility';
|
|
73
|
-
|
|
74
|
-
|
|
73
|
+
/** Provider chat-model classes moved off the root barrel: importing any of them here
|
|
74
|
+
* forced every host to pay that provider SDK's module init at boot. They remain
|
|
75
|
+
* available from their own entries, e.g. `@librechat/agents/llm/openai`. */
|
|
75
76
|
export type {
|
|
76
77
|
OpenRouterReasoning,
|
|
77
78
|
OpenRouterReasoningEffort,
|
|
@@ -83,7 +84,6 @@ export type {
|
|
|
83
84
|
ProviderFamily,
|
|
84
85
|
ProviderRegistrationOptions,
|
|
85
86
|
} from './provider-registration';
|
|
86
|
-
export { CustomChatMistralAI } from './llm/mistral';
|
|
87
87
|
export {
|
|
88
88
|
smoothStream,
|
|
89
89
|
resolveStreamDelay,
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { createRequire } from 'node:module';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Synchronous on-demand module loading: provider SDKs and other heavy dependencies
|
|
5
|
+
* load with their first request instead of at import time. This is the only module
|
|
6
|
+
* that touches `import.meta`; jest maps it to `test/stubs/lazyRequire.ts` so suites
|
|
7
|
+
* resolve source modules through their own resolver (the same precedent as the
|
|
8
|
+
* `@langchain/mistralai` stub).
|
|
9
|
+
*
|
|
10
|
+
* Internal modules load as format-matched siblings — `.cjs` neighbors from the CJS
|
|
11
|
+
* build and `.mjs` neighbors from the ESM build (Node's `require(esm)`, safe on the
|
|
12
|
+
* declared `>=24` engine) — so a lazily resolved provider shares one LangChain class
|
|
13
|
+
* graph with the code that requested it. Under a source-mode runner such as `tsx`,
|
|
14
|
+
* the seam resolves the TypeScript source directly through the active loader.
|
|
15
|
+
*/
|
|
16
|
+
const moduleUrl = import.meta.url;
|
|
17
|
+
const requireModule = createRequire(moduleUrl);
|
|
18
|
+
|
|
19
|
+
function detectBuildExtension(url: string): '.cjs' | '.mjs' | null {
|
|
20
|
+
if (url.endsWith('.mjs')) {
|
|
21
|
+
return '.mjs';
|
|
22
|
+
}
|
|
23
|
+
if (url.endsWith('.cjs')) {
|
|
24
|
+
return '.cjs';
|
|
25
|
+
}
|
|
26
|
+
return null;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const buildExtension = detectBuildExtension(moduleUrl);
|
|
30
|
+
|
|
31
|
+
/** False when the package runs from TypeScript source, where dist siblings do
|
|
32
|
+
* not exist and lazily loadable modules must be registered up front. */
|
|
33
|
+
export function isBuiltRuntime(): boolean {
|
|
34
|
+
return buildExtension != null;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/** Source-mode commands run the TypeScript through an ESM loader that a synchronous
|
|
38
|
+
* CJS `require` can neither reach nor share module identity with, so lazily loadable
|
|
39
|
+
* modules are provided up front instead: `@/llm/providers.eager` imports them through
|
|
40
|
+
* the active loader and registers them here. */
|
|
41
|
+
const sourceModeModules = new Map<string, unknown>();
|
|
42
|
+
|
|
43
|
+
export function registerSourceModeModules(modules: Record<string, unknown>): void {
|
|
44
|
+
for (const [relativePath, moduleExports] of Object.entries(modules)) {
|
|
45
|
+
sourceModeModules.set(relativePath, moduleExports);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/** Loads a module of this package by its src-relative path, e.g. `llm/openai/index`. */
|
|
50
|
+
export function requireInternalModule<T>(relativePath: string): T {
|
|
51
|
+
if (buildExtension != null) {
|
|
52
|
+
return requireModule(`./${relativePath}${buildExtension}`) as T;
|
|
53
|
+
}
|
|
54
|
+
const provided = sourceModeModules.get(relativePath);
|
|
55
|
+
if (provided == null) {
|
|
56
|
+
throw new Error(
|
|
57
|
+
`Lazily loaded module "${relativePath}" is unavailable when running from source; ` +
|
|
58
|
+
'import \'@/llm/providers.eager\' at the entrypoint before any model is used.'
|
|
59
|
+
);
|
|
60
|
+
}
|
|
61
|
+
return provided as T;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/** Loads a third-party package on first use; identity-sensitive callers must not use this. */
|
|
65
|
+
export function requireLazyModule<T>(specifier: string): T {
|
|
66
|
+
return requireModule(specifier) as T;
|
|
67
|
+
}
|
|
@@ -4,7 +4,11 @@ import type { OpenAIClient } from '@langchain/openai';
|
|
|
4
4
|
import type { DocumentType } from '@smithy/types';
|
|
5
5
|
import type { GraphTools } from '@/types';
|
|
6
6
|
import { buildBedrockCachePoint, type PromptCacheTtl } from '@/messages/cache';
|
|
7
|
-
import {
|
|
7
|
+
import { requireInternalModule } from '@/lazyRequire';
|
|
8
|
+
|
|
9
|
+
/** Loads with the first Bedrock request rather than alongside every graph. */
|
|
10
|
+
const convertToOpenAITool: typeof import('@/llm/openai')._convertToOpenAITool = (...args) =>
|
|
11
|
+
requireInternalModule<typeof import('@/llm/openai')>('llm/openai/index')._convertToOpenAITool(...args);
|
|
8
12
|
|
|
9
13
|
const BEDROCK_TOOL_CACHE_MARKER = '__lc_bedrock_cache_point_after';
|
|
10
14
|
const BEDROCK_TOOL_CACHE_DISABLED_MARKER = '__lc_bedrock_skip_tool_cache';
|
|
@@ -77,7 +81,7 @@ function toBedrockTool(tool: unknown): BedrockToolWithCacheMarker {
|
|
|
77
81
|
}
|
|
78
82
|
|
|
79
83
|
return openAIToBedrockTool(
|
|
80
|
-
|
|
84
|
+
convertToOpenAITool(tool as BindToolsInput) as OpenAIFunctionTool
|
|
81
85
|
) as BedrockToolWithCacheMarker;
|
|
82
86
|
}
|
|
83
87
|
|
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;
|
package/src/llm/invoke.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { concat } from '@langchain/core/utils/stream';
|
|
2
2
|
import { AIMessageChunk } from '@langchain/core/messages';
|
|
3
|
+
import { BaseCallbackHandler } from '@langchain/core/callbacks/base';
|
|
3
4
|
import { getCallbackManagerForConfig } from '@langchain/core/runnables';
|
|
4
5
|
import {
|
|
5
6
|
CallbackManager,
|
|
@@ -40,7 +41,12 @@ import { assertNotTruncatedToolCall } from '@/llm/truncation';
|
|
|
40
41
|
import { safeDispatchCustomEvent } from '@/utils/events';
|
|
41
42
|
import { getContextOverflowInfo } from '@/utils/errors';
|
|
42
43
|
import { appendCallbacks } from '@/utils/callbacks';
|
|
43
|
-
import {
|
|
44
|
+
import {
|
|
45
|
+
inspectProviderMessageProjection,
|
|
46
|
+
ProviderMessageProjectionInvariantError,
|
|
47
|
+
resolveProviderMessageProjectionInvariantMode,
|
|
48
|
+
modifyDeltaProperties,
|
|
49
|
+
} from '@/messages';
|
|
44
50
|
import { canSealPreempt } from '@/llm/preempt';
|
|
45
51
|
import { initializeModel } from '@/llm/init';
|
|
46
52
|
|
|
@@ -106,6 +112,79 @@ export type OnChunk = (
|
|
|
106
112
|
/** Unique per-model-attempt sequence; see the stamp in `attemptInvoke`. */
|
|
107
113
|
let streamLimitAttemptSeq = 0;
|
|
108
114
|
|
|
115
|
+
function createModelStartHandler({
|
|
116
|
+
config,
|
|
117
|
+
mode,
|
|
118
|
+
provider,
|
|
119
|
+
captureRunId,
|
|
120
|
+
}: {
|
|
121
|
+
config: RunnableConfig;
|
|
122
|
+
mode: ReturnType<typeof resolveProviderMessageProjectionInvariantMode>;
|
|
123
|
+
provider: t.ProviderName;
|
|
124
|
+
captureRunId?: (runId: string) => void;
|
|
125
|
+
}): BaseCallbackHandler {
|
|
126
|
+
let inspected = false;
|
|
127
|
+
const handler = BaseCallbackHandler.fromMethods({
|
|
128
|
+
handleChatModelStart: async (
|
|
129
|
+
_llm: Serialized,
|
|
130
|
+
messageBatches: BaseMessage[][],
|
|
131
|
+
runId: string
|
|
132
|
+
): Promise<void> => {
|
|
133
|
+
captureRunId?.(runId);
|
|
134
|
+
if (mode === 'off' || inspected) {
|
|
135
|
+
return;
|
|
136
|
+
}
|
|
137
|
+
inspected = true;
|
|
138
|
+
const report = inspectProviderMessageProjection(messageBatches[0] ?? []);
|
|
139
|
+
if (report.valid) {
|
|
140
|
+
return;
|
|
141
|
+
}
|
|
142
|
+
if (mode === 'assert') {
|
|
143
|
+
throw new ProviderMessageProjectionInvariantError(report);
|
|
144
|
+
}
|
|
145
|
+
try {
|
|
146
|
+
const callbackManager = await getCallbackManagerForConfig(config);
|
|
147
|
+
await callbackManager?.handleCustomEvent?.(
|
|
148
|
+
GraphEvents.ON_AGENT_LOG,
|
|
149
|
+
{
|
|
150
|
+
level: 'warn',
|
|
151
|
+
scope: 'projection',
|
|
152
|
+
message: 'Provider message projection has provenance gaps',
|
|
153
|
+
data: { provider, report },
|
|
154
|
+
runId,
|
|
155
|
+
} satisfies t.AgentLogEvent,
|
|
156
|
+
runId
|
|
157
|
+
);
|
|
158
|
+
} catch {
|
|
159
|
+
return;
|
|
160
|
+
}
|
|
161
|
+
},
|
|
162
|
+
});
|
|
163
|
+
handler.name = 'provider-message-projection-invariant';
|
|
164
|
+
handler.raiseError = mode === 'assert';
|
|
165
|
+
handler.awaitHandlers = true;
|
|
166
|
+
return handler;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
function withModelStartHandler({
|
|
170
|
+
config,
|
|
171
|
+
mode,
|
|
172
|
+
provider,
|
|
173
|
+
captureRunId,
|
|
174
|
+
}: {
|
|
175
|
+
config: RunnableConfig;
|
|
176
|
+
mode: ReturnType<typeof resolveProviderMessageProjectionInvariantMode>;
|
|
177
|
+
provider: t.ProviderName;
|
|
178
|
+
captureRunId?: (runId: string) => void;
|
|
179
|
+
}): RunnableConfig {
|
|
180
|
+
return {
|
|
181
|
+
...config,
|
|
182
|
+
callbacks: appendCallbacks(config.callbacks, [
|
|
183
|
+
createModelStartHandler({ config, mode, provider, captureRunId }),
|
|
184
|
+
]),
|
|
185
|
+
};
|
|
186
|
+
}
|
|
187
|
+
|
|
109
188
|
function getManualToolStreamNormalizationProvider(
|
|
110
189
|
provider: t.ProviderName
|
|
111
190
|
): t.ProviderName {
|
|
@@ -632,6 +711,24 @@ async function attemptInvokeBody(
|
|
|
632
711
|
config: RunnableConfig
|
|
633
712
|
): Promise<Partial<t.BaseGraphState>> {
|
|
634
713
|
const { model, messages: messagesForProvider, provider } = request;
|
|
714
|
+
const projectionInvariantMode =
|
|
715
|
+
resolveProviderMessageProjectionInvariantMode();
|
|
716
|
+
let sealedRunId: string | undefined;
|
|
717
|
+
let invocationConfig = config;
|
|
718
|
+
const captureModelRunId =
|
|
719
|
+
model.stream != null && context?.preemption != null;
|
|
720
|
+
if (projectionInvariantMode !== 'off' || captureModelRunId) {
|
|
721
|
+
invocationConfig = withModelStartHandler({
|
|
722
|
+
config,
|
|
723
|
+
mode: projectionInvariantMode,
|
|
724
|
+
provider,
|
|
725
|
+
captureRunId: captureModelRunId
|
|
726
|
+
? (runId: string): void => {
|
|
727
|
+
sealedRunId ??= runId;
|
|
728
|
+
}
|
|
729
|
+
: undefined,
|
|
730
|
+
});
|
|
731
|
+
}
|
|
635
732
|
|
|
636
733
|
/**
|
|
637
734
|
* Stamp the provider that is ACTUALLY serving this invocation onto the
|
|
@@ -647,28 +744,10 @@ async function attemptInvokeBody(
|
|
|
647
744
|
* Observed, not dictated. `handleChatModelStart` fires with the chat
|
|
648
745
|
* model's real run id before the first chunk, which is the only way to
|
|
649
746
|
* name the run a seal has to close — pinning `config.runId` does not
|
|
650
|
-
* survive the bound runnable.
|
|
651
|
-
*
|
|
747
|
+
* survive the bound runnable. The same handler owns the opt-in projection
|
|
748
|
+
* invariant so enabled diagnostics do not stack a second model callback.
|
|
652
749
|
*/
|
|
653
|
-
|
|
654
|
-
const streamConfig =
|
|
655
|
-
context?.preemption == null
|
|
656
|
-
? config
|
|
657
|
-
: {
|
|
658
|
-
...config,
|
|
659
|
-
callbacks: appendCallbacks(config.callbacks, [
|
|
660
|
-
{
|
|
661
|
-
handleChatModelStart: (
|
|
662
|
-
_llm: Serialized,
|
|
663
|
-
_messages: BaseMessage[][],
|
|
664
|
-
runId: string
|
|
665
|
-
): void => {
|
|
666
|
-
sealedRunId ??= runId;
|
|
667
|
-
},
|
|
668
|
-
},
|
|
669
|
-
]),
|
|
670
|
-
};
|
|
671
|
-
const stream = await model.stream(messagesForProvider, streamConfig);
|
|
750
|
+
const stream = await model.stream(messagesForProvider, invocationConfig);
|
|
672
751
|
let finalChunk: AIMessageChunk | undefined;
|
|
673
752
|
let preempted = false;
|
|
674
753
|
const registeredStreamHandler =
|
|
@@ -855,7 +934,7 @@ async function attemptInvokeBody(
|
|
|
855
934
|
return { messages: [finalChunk as AIMessageChunk] };
|
|
856
935
|
}
|
|
857
936
|
|
|
858
|
-
const finalMessage = await model.invoke(messagesForProvider,
|
|
937
|
+
const finalMessage = await model.invoke(messagesForProvider, invocationConfig);
|
|
859
938
|
if ((finalMessage.tool_calls?.length ?? 0) > 0) {
|
|
860
939
|
finalMessage.tool_calls = finalMessage.tool_calls?.filter(
|
|
861
940
|
(tool_call: ToolCall) => !!tool_call.name
|