@librechat/agents 3.3.3 → 3.3.5
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/agents/AgentContext.cjs +2 -1
- package/dist/cjs/agents/AgentContext.cjs.map +1 -1
- package/dist/cjs/common/constants.cjs +21 -0
- package/dist/cjs/common/constants.cjs.map +1 -1
- package/dist/cjs/events.cjs +10 -1
- package/dist/cjs/events.cjs.map +1 -1
- package/dist/cjs/graphs/Graph.cjs +793 -111
- package/dist/cjs/graphs/Graph.cjs.map +1 -1
- package/dist/cjs/graphs/MultiAgentGraph.cjs +3 -1
- package/dist/cjs/graphs/MultiAgentGraph.cjs.map +1 -1
- package/dist/cjs/hooks/HookRegistry.cjs +25 -0
- package/dist/cjs/hooks/HookRegistry.cjs.map +1 -1
- package/dist/cjs/hooks/index.cjs +12 -0
- package/dist/cjs/hooks/index.cjs.map +1 -1
- package/dist/cjs/hooks/types.cjs +1 -0
- package/dist/cjs/hooks/types.cjs.map +1 -1
- package/dist/cjs/langfuse.cjs +8 -0
- package/dist/cjs/langfuse.cjs.map +1 -1
- package/dist/cjs/llm/anthropic/utils/message_inputs.cjs +79 -6
- package/dist/cjs/llm/anthropic/utils/message_inputs.cjs.map +1 -1
- package/dist/cjs/llm/bedrock/utils/message_inputs.cjs +38 -13
- package/dist/cjs/llm/bedrock/utils/message_inputs.cjs.map +1 -1
- package/dist/cjs/llm/google/utils/common.cjs +19 -7
- package/dist/cjs/llm/google/utils/common.cjs.map +1 -1
- package/dist/cjs/llm/invoke.cjs +331 -5
- package/dist/cjs/llm/invoke.cjs.map +1 -1
- package/dist/cjs/llm/openai/index.cjs +41 -5
- package/dist/cjs/llm/openai/index.cjs.map +1 -1
- package/dist/cjs/llm/openai/utils/index.cjs +25 -4
- package/dist/cjs/llm/openai/utils/index.cjs.map +1 -1
- package/dist/cjs/llm/openrouter/index.cjs +4 -1
- package/dist/cjs/llm/openrouter/index.cjs.map +1 -1
- package/dist/cjs/llm/preempt.cjs +132 -0
- package/dist/cjs/llm/preempt.cjs.map +1 -0
- package/dist/cjs/main.cjs +36 -5
- package/dist/cjs/messages/alternation.cjs +92 -0
- package/dist/cjs/messages/alternation.cjs.map +1 -0
- package/dist/cjs/messages/cache.cjs +54 -33
- package/dist/cjs/messages/cache.cjs.map +1 -1
- package/dist/cjs/messages/contextPruning.cjs +17 -43
- package/dist/cjs/messages/contextPruning.cjs.map +1 -1
- package/dist/cjs/messages/core.cjs +315 -23
- package/dist/cjs/messages/core.cjs.map +1 -1
- package/dist/cjs/messages/format.cjs +290 -60
- package/dist/cjs/messages/format.cjs.map +1 -1
- package/dist/cjs/messages/handoffCue.cjs +63 -0
- package/dist/cjs/messages/handoffCue.cjs.map +1 -0
- package/dist/cjs/messages/index.cjs +4 -1
- package/dist/cjs/messages/injected.cjs +60 -0
- package/dist/cjs/messages/injected.cjs.map +1 -0
- package/dist/cjs/messages/prune.cjs +503 -127
- package/dist/cjs/messages/prune.cjs.map +1 -1
- package/dist/cjs/run.cjs +80 -7
- package/dist/cjs/run.cjs.map +1 -1
- package/dist/cjs/session/handlers.cjs +18 -9
- package/dist/cjs/session/handlers.cjs.map +1 -1
- package/dist/cjs/stream.cjs +35 -10
- package/dist/cjs/stream.cjs.map +1 -1
- package/dist/cjs/summarization/node.cjs +28 -14
- package/dist/cjs/summarization/node.cjs.map +1 -1
- package/dist/cjs/tools/ToolNode.cjs +56 -63
- package/dist/cjs/tools/ToolNode.cjs.map +1 -1
- package/dist/cjs/tools/search/keenable-scraper.cjs +90 -0
- package/dist/cjs/tools/search/keenable-scraper.cjs.map +1 -0
- package/dist/cjs/tools/search/tool.cjs +9 -1
- package/dist/cjs/tools/search/tool.cjs.map +1 -1
- package/dist/cjs/tools/toolOutputReferences.cjs +6 -0
- package/dist/cjs/tools/toolOutputReferences.cjs.map +1 -1
- package/dist/cjs/utils/index.cjs +1 -1
- package/dist/cjs/utils/llm.cjs +1 -1
- package/dist/cjs/utils/llm.cjs.map +1 -1
- package/dist/cjs/utils/tokens.cjs +307 -20
- package/dist/cjs/utils/tokens.cjs.map +1 -1
- package/dist/cjs/utils/toolContent.cjs +1514 -0
- package/dist/cjs/utils/toolContent.cjs.map +1 -0
- package/dist/esm/agents/AgentContext.mjs +2 -1
- package/dist/esm/agents/AgentContext.mjs.map +1 -1
- package/dist/esm/common/constants.mjs +19 -1
- package/dist/esm/common/constants.mjs.map +1 -1
- package/dist/esm/events.mjs +10 -1
- package/dist/esm/events.mjs.map +1 -1
- package/dist/esm/graphs/Graph.mjs +798 -116
- package/dist/esm/graphs/Graph.mjs.map +1 -1
- package/dist/esm/graphs/MultiAgentGraph.mjs +3 -1
- package/dist/esm/graphs/MultiAgentGraph.mjs.map +1 -1
- package/dist/esm/hooks/HookRegistry.mjs +25 -0
- package/dist/esm/hooks/HookRegistry.mjs.map +1 -1
- package/dist/esm/hooks/index.mjs +12 -1
- package/dist/esm/hooks/index.mjs.map +1 -1
- package/dist/esm/hooks/types.mjs +1 -0
- package/dist/esm/hooks/types.mjs.map +1 -1
- package/dist/esm/langfuse.mjs +9 -1
- package/dist/esm/langfuse.mjs.map +1 -1
- package/dist/esm/llm/anthropic/utils/message_inputs.mjs +79 -6
- package/dist/esm/llm/anthropic/utils/message_inputs.mjs.map +1 -1
- package/dist/esm/llm/bedrock/utils/message_inputs.mjs +38 -13
- package/dist/esm/llm/bedrock/utils/message_inputs.mjs.map +1 -1
- package/dist/esm/llm/google/utils/common.mjs +19 -7
- package/dist/esm/llm/google/utils/common.mjs.map +1 -1
- package/dist/esm/llm/invoke.mjs +332 -8
- package/dist/esm/llm/invoke.mjs.map +1 -1
- package/dist/esm/llm/openai/index.mjs +41 -5
- package/dist/esm/llm/openai/index.mjs.map +1 -1
- package/dist/esm/llm/openai/utils/index.mjs +25 -4
- package/dist/esm/llm/openai/utils/index.mjs.map +1 -1
- package/dist/esm/llm/openrouter/index.mjs +4 -1
- package/dist/esm/llm/openrouter/index.mjs.map +1 -1
- package/dist/esm/llm/preempt.mjs +131 -0
- package/dist/esm/llm/preempt.mjs.map +1 -0
- package/dist/esm/main.mjs +14 -11
- package/dist/esm/messages/alternation.mjs +91 -0
- package/dist/esm/messages/alternation.mjs.map +1 -0
- package/dist/esm/messages/cache.mjs +55 -34
- package/dist/esm/messages/cache.mjs.map +1 -1
- package/dist/esm/messages/contextPruning.mjs +17 -43
- package/dist/esm/messages/contextPruning.mjs.map +1 -1
- package/dist/esm/messages/core.mjs +305 -24
- package/dist/esm/messages/core.mjs.map +1 -1
- package/dist/esm/messages/format.mjs +290 -61
- package/dist/esm/messages/format.mjs.map +1 -1
- package/dist/esm/messages/handoffCue.mjs +61 -0
- package/dist/esm/messages/handoffCue.mjs.map +1 -0
- package/dist/esm/messages/index.mjs +4 -1
- package/dist/esm/messages/injected.mjs +60 -0
- package/dist/esm/messages/injected.mjs.map +1 -0
- package/dist/esm/messages/prune.mjs +500 -128
- package/dist/esm/messages/prune.mjs.map +1 -1
- package/dist/esm/run.mjs +80 -7
- package/dist/esm/run.mjs.map +1 -1
- package/dist/esm/session/handlers.mjs +19 -10
- package/dist/esm/session/handlers.mjs.map +1 -1
- package/dist/esm/stream.mjs +34 -11
- package/dist/esm/stream.mjs.map +1 -1
- package/dist/esm/summarization/node.mjs +28 -14
- package/dist/esm/summarization/node.mjs.map +1 -1
- package/dist/esm/tools/ToolNode.mjs +56 -63
- package/dist/esm/tools/ToolNode.mjs.map +1 -1
- package/dist/esm/tools/search/keenable-scraper.mjs +88 -0
- package/dist/esm/tools/search/keenable-scraper.mjs.map +1 -0
- package/dist/esm/tools/search/tool.mjs +9 -1
- package/dist/esm/tools/search/tool.mjs.map +1 -1
- package/dist/esm/tools/toolOutputReferences.mjs +6 -0
- package/dist/esm/tools/toolOutputReferences.mjs.map +1 -1
- package/dist/esm/utils/index.mjs +1 -1
- package/dist/esm/utils/llm.mjs +1 -1
- package/dist/esm/utils/llm.mjs.map +1 -1
- package/dist/esm/utils/tokens.mjs +307 -21
- package/dist/esm/utils/tokens.mjs.map +1 -1
- package/dist/esm/utils/toolContent.mjs +1503 -0
- package/dist/esm/utils/toolContent.mjs.map +1 -0
- package/dist/types/common/constants.d.ts +18 -0
- package/dist/types/graphs/Graph.d.ts +139 -2
- package/dist/types/hooks/HookRegistry.d.ts +15 -0
- package/dist/types/hooks/index.d.ts +12 -1
- package/dist/types/hooks/types.d.ts +45 -6
- package/dist/types/index.d.ts +1 -1
- package/dist/types/llm/invoke.d.ts +34 -1
- package/dist/types/llm/openai/index.d.ts +4 -0
- package/dist/types/llm/openai/utils/index.d.ts +2 -0
- package/dist/types/llm/openrouter/index.d.ts +5 -0
- package/dist/types/llm/preempt.d.ts +40 -0
- package/dist/types/messages/alternation.d.ts +23 -0
- package/dist/types/messages/contextPruning.d.ts +2 -1
- package/dist/types/messages/core.d.ts +36 -0
- package/dist/types/messages/format.d.ts +6 -0
- package/dist/types/messages/handoffCue.d.ts +40 -0
- package/dist/types/messages/index.d.ts +3 -0
- package/dist/types/messages/injected.d.ts +3 -0
- package/dist/types/messages/prune.d.ts +16 -12
- package/dist/types/run.d.ts +7 -0
- package/dist/types/stream.d.ts +14 -0
- package/dist/types/tools/ToolNode.d.ts +0 -7
- package/dist/types/tools/search/keenable-scraper.d.ts +15 -0
- package/dist/types/tools/search/types.d.ts +31 -2
- package/dist/types/types/graph.d.ts +8 -1
- package/dist/types/types/run.d.ts +65 -0
- package/dist/types/types/stream.d.ts +1 -26
- package/dist/types/utils/tokens.d.ts +7 -0
- package/dist/types/utils/toolContent.d.ts +107 -0
- package/package.json +1 -1
- package/src/__tests__/stream.eagerEventExecution.test.ts +74 -0
- package/src/agents/AgentContext.ts +1 -0
- package/src/{splitStream.test.ts → aggregator.test.ts} +59 -666
- package/src/common/constants.ts +21 -0
- package/src/events.ts +15 -1
- package/src/graphs/Graph.ts +1261 -198
- package/src/graphs/MultiAgentGraph.ts +6 -1
- package/src/graphs/__tests__/Graph.contextOverflow.test.ts +1139 -4
- package/src/graphs/__tests__/Graph.preemptSignal.test.ts +126 -0
- package/src/hooks/HookRegistry.ts +40 -0
- package/src/hooks/__tests__/preemptBoundary.test.ts +152 -0
- package/src/hooks/index.ts +16 -2
- package/src/hooks/types.ts +47 -3
- package/src/index.ts +1 -1
- package/src/langfuse.ts +26 -1
- package/src/llm/anthropic/utils/message_inputs.ts +158 -12
- package/src/llm/anthropic/utils/tool-id-normalization.test.ts +109 -0
- package/src/llm/bedrock/utils/message_inputs.test.ts +131 -1
- package/src/llm/bedrock/utils/message_inputs.ts +100 -24
- package/src/llm/bedrock/utils/toolResultCachePoint.test.ts +15 -0
- package/src/llm/google/utils/common.test.ts +75 -9
- package/src/llm/google/utils/common.ts +34 -3
- package/src/llm/invoke.alternation.test.ts +87 -0
- package/src/llm/invoke.handoffCue.test.ts +112 -0
- package/src/llm/invoke.test.ts +488 -0
- package/src/llm/invoke.ts +611 -8
- package/src/llm/openai/index.ts +106 -6
- package/src/llm/openai/utils/index.ts +109 -53
- package/src/llm/openai/utils/messages.test.ts +330 -1
- package/src/llm/openrouter/index.ts +12 -2
- package/src/llm/openrouter/reasoning.test.ts +314 -0
- package/src/llm/preempt.test.ts +323 -0
- package/src/llm/preempt.ts +178 -0
- package/src/messages/__tests__/observationMasking.test.ts +93 -2
- package/src/messages/alternation.test.ts +212 -0
- package/src/messages/alternation.ts +112 -0
- package/src/messages/cache.tail.test.ts +193 -0
- package/src/messages/cache.test.ts +113 -0
- package/src/messages/cache.ts +92 -60
- package/src/messages/contextPruning.test.ts +184 -0
- package/src/messages/contextPruning.ts +49 -42
- package/src/messages/core.ts +653 -40
- package/src/messages/ensureThinkingBlock.test.ts +49 -1
- package/src/messages/foldToollessToolBlocks.test.ts +163 -5
- package/src/messages/format.ts +454 -91
- package/src/messages/formatAgentMessages.steer.test.ts +267 -0
- package/src/messages/formatAgentMessages.test.ts +604 -14
- package/src/messages/formatAgentMessages.tools.test.ts +103 -0
- package/src/messages/handoffCue.test.ts +96 -0
- package/src/messages/handoffCue.ts +78 -0
- package/src/messages/index.ts +3 -0
- package/src/messages/injected.test.ts +90 -0
- package/src/messages/injected.ts +74 -0
- package/src/messages/prune.ts +996 -183
- package/src/run.ts +91 -6
- package/src/scripts/preempt-probe.ts +330 -0
- package/src/scripts/preempt-scenarios.ts +388 -0
- package/src/session/handlers.ts +32 -12
- package/src/specs/handoffCue.test.ts +165 -0
- package/src/specs/langfuse-callbacks.test.ts +352 -2
- package/src/specs/preemptSeal.test.ts +309 -0
- package/src/specs/prune.test.ts +1083 -6
- package/src/specs/summarization-unit.test.ts +105 -0
- package/src/specs/tokens.test.ts +609 -32
- package/src/stream.dispatch.test.ts +63 -0
- package/src/stream.ts +59 -23
- package/src/summarization/__tests__/node.test.ts +77 -0
- package/src/summarization/node.ts +46 -18
- package/src/tools/ToolNode.ts +150 -99
- package/src/tools/__tests__/ToolNode.onResultCompletion.test.ts +148 -1
- package/src/tools/__tests__/ToolNode.outputReferences.test.ts +112 -3
- package/src/tools/__tests__/annotateMessagesForLLM.test.ts +32 -0
- package/src/tools/__tests__/directToolHooks.test.ts +255 -7
- package/src/tools/search/keenable-scraper.test.ts +153 -0
- package/src/tools/search/keenable-scraper.ts +137 -0
- package/src/tools/search/tool.ts +13 -2
- package/src/tools/search/types.ts +50 -3
- package/src/tools/toolOutputReferences.ts +6 -0
- package/src/types/graph.ts +12 -1
- package/src/types/run.ts +67 -0
- package/src/types/stream.ts +1 -42
- package/src/utils/llm.test.ts +18 -0
- package/src/utils/llm.ts +4 -1
- package/src/utils/tokens.ts +586 -31
- package/src/utils/toolContent.test.ts +1432 -0
- package/src/utils/toolContent.ts +2707 -0
- package/dist/cjs/splitStream.cjs +0 -151
- package/dist/cjs/splitStream.cjs.map +0 -1
- package/dist/esm/splitStream.mjs +0 -150
- package/dist/esm/splitStream.mjs.map +0 -1
- package/dist/types/mockStream.d.ts +0 -32
- package/dist/types/splitStream.d.ts +0 -37
- package/src/mockStream.ts +0 -99
- package/src/splitStream.ts +0 -234
|
@@ -101,6 +101,63 @@ export type StandardGraphConfig = Omit<MultiAgentGraphConfig, 'edges' | 'type'>
|
|
|
101
101
|
type?: 'standard';
|
|
102
102
|
signal?: AbortSignal;
|
|
103
103
|
};
|
|
104
|
+
/**
|
|
105
|
+
* Cooperative mid-generation preemption. Lets a host seal the live model
|
|
106
|
+
* stream at the next provider-safe token boundary — the run is never
|
|
107
|
+
* aborted, the partial assistant turn is kept, and the graph self-loops
|
|
108
|
+
* into a fresh model call once the `PreemptBoundary` hook has injected
|
|
109
|
+
* whatever the host queued.
|
|
110
|
+
*
|
|
111
|
+
* Preconditions the host MUST satisfy:
|
|
112
|
+
* - `shouldPreempt` is polled once per streamed chunk on the top-level
|
|
113
|
+
* graph. It must be synchronous, allocation-free and O(1) — never I/O.
|
|
114
|
+
* It must also be LEVEL-TRIGGERED (non-consuming): the SDK never clears
|
|
115
|
+
* the host's request, and a true result is only honored once the
|
|
116
|
+
* accumulated chunk is provider-safe, so the predicate may be polled
|
|
117
|
+
* many times before a seal. A one-shot read that clears its own pending
|
|
118
|
+
* flag would silently lose the request on an unsafe chunk (leading
|
|
119
|
+
* whitespace/reasoning, an in-flight tool call) — keep returning true
|
|
120
|
+
* until the `PreemptBoundary` drain hands over the queued injection,
|
|
121
|
+
* then disarm there.
|
|
122
|
+
* - Sealing is only honored on the SDK's own dispatch loop. A run whose
|
|
123
|
+
* registered `CHAT_MODEL_STREAM` handler IS the SDK dispatcher — or wraps
|
|
124
|
+
* it, which `composeEventHandlers` and `createRunHandlers` both do —
|
|
125
|
+
* consumes chunks through a decoupled `streamEvents` reader that can lag
|
|
126
|
+
* the accumulated chunk, so those runs never seal.
|
|
127
|
+
*
|
|
128
|
+
* Detection is by capability, not identity: the dispatcher carries
|
|
129
|
+
* `SDK_STREAM_DISPATCH` and the SDK's wrappers propagate it. A handler
|
|
130
|
+
* that merely OBSERVES the raw chunk echo — LibreChat's no-op
|
|
131
|
+
* `OpenAIChatModelStreamHandler`, say — is unbranded and does NOT disable
|
|
132
|
+
* sealing, because it assigns no content-part indices and so cannot be
|
|
133
|
+
* inverted. A host that renders from the raw feed and wants the opt-out
|
|
134
|
+
* should brand its handler with `SDK_STREAM_DISPATCH`.
|
|
135
|
+
* - `RunConfig.tokenCounter` should be set. A sealed turn ends before most
|
|
136
|
+
* providers send their usage chunk, so the synthetic `CHAT_MODEL_END`
|
|
137
|
+
* falls back to the counter to report `output_tokens`. Without one that
|
|
138
|
+
* fallback silently no-ops and the sealed turn's usage is lost — verified
|
|
139
|
+
* live: OpenAI, Azure OpenAI and DeepSeek report no usage for the sealed
|
|
140
|
+
* segment without a counter, while Anthropic streams usage incrementally
|
|
141
|
+
* and reports it either way.
|
|
142
|
+
*/
|
|
143
|
+
export interface StreamPreemption {
|
|
144
|
+
/**
|
|
145
|
+
* Polled once per streamed chunk. Synchronous, allocation-free, O(1), and
|
|
146
|
+
* level-triggered — keep returning true until the `PreemptBoundary` drain
|
|
147
|
+
* consumes the request; a self-clearing read loses it on an unsafe chunk.
|
|
148
|
+
*/
|
|
149
|
+
shouldPreempt: () => boolean;
|
|
150
|
+
/**
|
|
151
|
+
* Max cooperative seals per run. Each seal costs one extra superstep, so
|
|
152
|
+
* this also bounds the recursion-limit headroom the run reserves.
|
|
153
|
+
*/
|
|
154
|
+
maxSeals?: number;
|
|
155
|
+
}
|
|
156
|
+
/** Seals honored and boundaries that had nothing to inject, per run. */
|
|
157
|
+
export type PreemptStats = {
|
|
158
|
+
seals: number;
|
|
159
|
+
emptyBoundaries: number;
|
|
160
|
+
};
|
|
104
161
|
export type RunConfig = {
|
|
105
162
|
runId: string;
|
|
106
163
|
graphConfig: LegacyGraphConfig | StandardGraphConfig | MultiAgentGraphConfig;
|
|
@@ -132,6 +189,14 @@ export type RunConfig = {
|
|
|
132
189
|
* block to prevent leaks.
|
|
133
190
|
*/
|
|
134
191
|
hooks?: HookRegistry;
|
|
192
|
+
/**
|
|
193
|
+
* Opt-in cooperative preemption for this run. Requires a `hooks` registry
|
|
194
|
+
* with a `PreemptBoundary` matcher — the seal only stops the stream, the
|
|
195
|
+
* hook is what supplies the messages to resume with. Omit to keep the
|
|
196
|
+
* pre-preemption behavior, where a mid-run injection can only land at a
|
|
197
|
+
* tool boundary.
|
|
198
|
+
*/
|
|
199
|
+
preemption?: StreamPreemption;
|
|
135
200
|
returnContent?: boolean;
|
|
136
201
|
tokenCounter?: TokenCounter;
|
|
137
202
|
indexTokenCountMap?: Record<string, number>;
|
|
@@ -2,7 +2,6 @@ import type { MessageContentImageUrl, MessageContentText, ToolMessage, BaseMessa
|
|
|
2
2
|
import type { ToolCall, ToolCallChunk } from '@langchain/core/messages/tool';
|
|
3
3
|
import type { LLMResult, Generation } from '@langchain/core/outputs';
|
|
4
4
|
import type { Command } from '@langchain/langgraph';
|
|
5
|
-
import type OpenAITypes from 'openai';
|
|
6
5
|
import type { AnthropicContentBlock } from '@/llm/anthropic/types';
|
|
7
6
|
import type { SummarizeCompleteEvent } from '@/types/summarize';
|
|
8
7
|
import type { ToolEndEvent } from '@/types/tools';
|
|
@@ -265,7 +264,7 @@ export type ToolCallPart = {
|
|
|
265
264
|
/** If provided, an identifier associated with the tool call */
|
|
266
265
|
id?: string;
|
|
267
266
|
/** If provided, the output of the tool call */
|
|
268
|
-
output?:
|
|
267
|
+
output?: ToolResultContent['content'];
|
|
269
268
|
/** Auth URL */
|
|
270
269
|
auth?: string;
|
|
271
270
|
/** Expiration time */
|
|
@@ -297,30 +296,6 @@ export interface TMessage {
|
|
|
297
296
|
[key: string]: unknown;
|
|
298
297
|
}
|
|
299
298
|
export type TPayload = Array<Partial<TMessage>>;
|
|
300
|
-
export type CustomChunkDelta = null | undefined | (Partial<OpenAITypes.Chat.Completions.ChatCompletionChunk.Choice.Delta> & {
|
|
301
|
-
reasoning?: string | null;
|
|
302
|
-
reasoning_content?: string | null;
|
|
303
|
-
});
|
|
304
|
-
export type CustomChunkChoice = Partial<Omit<OpenAITypes.Chat.Completions.ChatCompletionChunk.Choice, 'delta'> & {
|
|
305
|
-
delta?: CustomChunkDelta;
|
|
306
|
-
}>;
|
|
307
|
-
export type CustomChunk = Partial<OpenAITypes.ChatCompletionChunk> & {
|
|
308
|
-
choices?: Partial<Array<CustomChunkChoice>>;
|
|
309
|
-
};
|
|
310
|
-
export type SplitStreamHandlers = Partial<{
|
|
311
|
-
[GraphEvents.ON_RUN_STEP]: ({ event, data, }: {
|
|
312
|
-
event: GraphEvents;
|
|
313
|
-
data: RunStep;
|
|
314
|
-
}) => void;
|
|
315
|
-
[GraphEvents.ON_MESSAGE_DELTA]: ({ event, data, }: {
|
|
316
|
-
event: GraphEvents;
|
|
317
|
-
data: MessageDeltaEvent;
|
|
318
|
-
}) => void;
|
|
319
|
-
[GraphEvents.ON_REASONING_DELTA]: ({ event, data, }: {
|
|
320
|
-
event: GraphEvents;
|
|
321
|
-
data: ReasoningDeltaEvent;
|
|
322
|
-
}) => void;
|
|
323
|
-
}>;
|
|
324
299
|
export type SummarizeDeltaData = {
|
|
325
300
|
id: string;
|
|
326
301
|
delta: {
|
|
@@ -44,6 +44,13 @@ export declare function estimateDocumentBlockTokens(block: Record<string, unknow
|
|
|
44
44
|
*/
|
|
45
45
|
export declare function estimateTimedMediaBlockTokens(block: Record<string, unknown>): number;
|
|
46
46
|
export declare function encodingForModel(model: string): EncodingName;
|
|
47
|
+
/**
|
|
48
|
+
* Detects values whose native JSON representation can differ after local
|
|
49
|
+
* measurement. Accessor properties and `toJSON` hooks are deliberately not
|
|
50
|
+
* invoked; values too large to inspect within bounded work are treated as
|
|
51
|
+
* unsafe so the caller can normalize or reject them conservatively.
|
|
52
|
+
*/
|
|
53
|
+
export declare function hasUnsafeStructuredSerialization(value: unknown): boolean;
|
|
47
54
|
export declare function getTokenCountForMessage(message: BaseMessage, getTokenCount: (text: string) => number, encoding?: EncodingName): number;
|
|
48
55
|
/**
|
|
49
56
|
* Largest-remainder apportionment: scales each count by `multiplier` and
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import { ToolMessage, type BaseMessage } from '@langchain/core/messages';
|
|
2
|
+
type ToolContent = BaseMessage['content'];
|
|
3
|
+
/**
|
|
4
|
+
* Serializes values that providers render as JSON without throwing on values
|
|
5
|
+
* such as bigint or circular diagnostic metadata.
|
|
6
|
+
*/
|
|
7
|
+
export declare function serializeStructuredValue(value: unknown): string;
|
|
8
|
+
type StructuredWorkState = {
|
|
9
|
+
remaining: number;
|
|
10
|
+
characterRemaining: number;
|
|
11
|
+
exceeded: boolean;
|
|
12
|
+
failurePlaceholder?: string;
|
|
13
|
+
propertyCache: WeakMap<object, Map<string, unknown>>;
|
|
14
|
+
propertyCacheEntries: number;
|
|
15
|
+
};
|
|
16
|
+
export type BoundedStructuredSerialization = {
|
|
17
|
+
/** Provider-facing head/tail preview, bounded by `maxChars`. */
|
|
18
|
+
content: string;
|
|
19
|
+
/** Exact serialized prefix up to the defensive traversal-work ceiling. */
|
|
20
|
+
prefix: string;
|
|
21
|
+
/** Exact length, or `Number.MAX_SAFE_INTEGER` when traversal was capped. */
|
|
22
|
+
originalChars: number;
|
|
23
|
+
truncated: boolean;
|
|
24
|
+
};
|
|
25
|
+
/**
|
|
26
|
+
* Serializes structured output while retaining at most the requested provider
|
|
27
|
+
* preview and registry prefix. The traversal never calls `toJSON` and never
|
|
28
|
+
* materializes the complete serialized string when it exceeds those limits.
|
|
29
|
+
*
|
|
30
|
+
* `prefixChars` is useful for the tool-output registry: it receives the exact
|
|
31
|
+
* serialized prefix up to `registry.perOutputLimit`, while `content` retains
|
|
32
|
+
* the provider-facing head/tail truncation behavior at `maxChars`. Property
|
|
33
|
+
* accessors are represented by a fixed placeholder instead of being invoked.
|
|
34
|
+
*/
|
|
35
|
+
export declare function serializeStructuredValueBounded(value: unknown, maxChars: number, prefixChars?: number, work?: StructuredWorkState): BoundedStructuredSerialization;
|
|
36
|
+
export declare function isAtomicToolContentBlock(value: unknown): boolean;
|
|
37
|
+
/**
|
|
38
|
+
* Produces the text representation providers use for structured tool results.
|
|
39
|
+
* Text-only block arrays stay readable; opaque blocks use canonical JSON.
|
|
40
|
+
*/
|
|
41
|
+
export declare function serializeToolContent(content: unknown): string;
|
|
42
|
+
export declare function getToolContentCharLength(content: unknown): number;
|
|
43
|
+
/**
|
|
44
|
+
* Produces provider-facing tool-result text without ever exceeding `maxChars`.
|
|
45
|
+
*/
|
|
46
|
+
export declare function serializeToolContentBounded(content: unknown, maxChars: number): string;
|
|
47
|
+
export type CompactToolContentResult = {
|
|
48
|
+
content: ToolContent;
|
|
49
|
+
changed: boolean;
|
|
50
|
+
originalChars: number;
|
|
51
|
+
};
|
|
52
|
+
export type CacheControlledTextToolContent = [
|
|
53
|
+
{
|
|
54
|
+
type: 'text';
|
|
55
|
+
text: string;
|
|
56
|
+
cache_control: {
|
|
57
|
+
type: 'ephemeral';
|
|
58
|
+
ttl?: '1h';
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
];
|
|
62
|
+
/** Reads one safe text block and returns its bounded text payload. */
|
|
63
|
+
export declare function getBoundedSingleTextToolContent(content: unknown, maxChars: number): string | undefined;
|
|
64
|
+
/**
|
|
65
|
+
* Canonicalizes the single cache-decorated text block produced by tail prompt
|
|
66
|
+
* caching without invoking accessors or custom serialization hooks.
|
|
67
|
+
*/
|
|
68
|
+
export declare function getBoundedCacheControlledTextToolContent(content: unknown, maxChars: number): CacheControlledTextToolContent | undefined;
|
|
69
|
+
export type ComputerCallOutputScreenshot = {
|
|
70
|
+
type: 'input_image';
|
|
71
|
+
image_url: string;
|
|
72
|
+
detail?: InputImageDetail;
|
|
73
|
+
} | {
|
|
74
|
+
type: 'input_image';
|
|
75
|
+
file_id: string;
|
|
76
|
+
detail?: InputImageDetail;
|
|
77
|
+
} | {
|
|
78
|
+
type: 'computer_screenshot';
|
|
79
|
+
image_url: string;
|
|
80
|
+
} | {
|
|
81
|
+
type: 'computer_screenshot';
|
|
82
|
+
file_id: string;
|
|
83
|
+
};
|
|
84
|
+
type InputImageDetail = 'low' | 'high' | 'auto' | 'original';
|
|
85
|
+
/**
|
|
86
|
+
* Selects the exact screenshot shape accepted by LangChain's Responses
|
|
87
|
+
* converter without invoking accessors or user-defined serialization hooks.
|
|
88
|
+
*/
|
|
89
|
+
export declare function getComputerCallOutputScreenshot(content: unknown): ComputerCallOutputScreenshot | undefined;
|
|
90
|
+
/** Returns the provider image URL when a screenshot is URL-backed. */
|
|
91
|
+
export declare function getComputerCallOutputImageUrl(content: unknown): string | undefined;
|
|
92
|
+
/** Returns whether content can be sent as a native computer screenshot. */
|
|
93
|
+
export declare function isComputerCallOutputContent(content: unknown): content is ToolContent;
|
|
94
|
+
/** Returns whether a ToolMessage carries the native computer-output marker. */
|
|
95
|
+
export declare function hasComputerCallOutputMarker(message: BaseMessage): boolean;
|
|
96
|
+
/** Native Responses computer screenshots are indivisible provider payloads. */
|
|
97
|
+
export declare function isComputerCallOutputMessage(message: BaseMessage): boolean;
|
|
98
|
+
/**
|
|
99
|
+
* Bounds structured tool output without slicing binary/media payloads.
|
|
100
|
+
* Purely textual/structured arrays become a universally valid string tool
|
|
101
|
+
* result. For mixed-media arrays, compactable blocks become one text preview
|
|
102
|
+
* while atomic blocks remain intact.
|
|
103
|
+
*/
|
|
104
|
+
export declare function compactToolContent(content: unknown, maxChars: number): CompactToolContentResult;
|
|
105
|
+
/** Clones a ToolMessage while retaining fields omitted by ad-hoc clones. */
|
|
106
|
+
export declare function cloneToolMessageWithContent(message: ToolMessage, content: ToolContent, artifact?: unknown): ToolMessage;
|
|
107
|
+
export {};
|
package/package.json
CHANGED
|
@@ -2498,6 +2498,80 @@ describe('ChatModelStreamHandler eager event tool execution', () => {
|
|
|
2498
2498
|
).toBe(true);
|
|
2499
2499
|
});
|
|
2500
2500
|
|
|
2501
|
+
it('serializes bigint output before eager completion dispatch', async () => {
|
|
2502
|
+
const graph = createGraph();
|
|
2503
|
+
const completedEvents: Array<{ result: t.ToolEndEvent }> = [];
|
|
2504
|
+
jest
|
|
2505
|
+
.spyOn(events, 'safeDispatchCustomEvent')
|
|
2506
|
+
.mockImplementation(async (event, data): Promise<void> => {
|
|
2507
|
+
if (event === GraphEvents.ON_RUN_STEP_COMPLETED) {
|
|
2508
|
+
completedEvents.push(data as { result: t.ToolEndEvent });
|
|
2509
|
+
return;
|
|
2510
|
+
}
|
|
2511
|
+
if (event !== GraphEvents.ON_TOOL_EXECUTE) {
|
|
2512
|
+
return;
|
|
2513
|
+
}
|
|
2514
|
+
const batch = data as t.ToolExecuteBatchRequest;
|
|
2515
|
+
batch.resolve([
|
|
2516
|
+
{
|
|
2517
|
+
toolCallId: 'call_weather',
|
|
2518
|
+
status: 'success',
|
|
2519
|
+
content: [{ rowsRead: BigInt(42) }],
|
|
2520
|
+
},
|
|
2521
|
+
]);
|
|
2522
|
+
});
|
|
2523
|
+
|
|
2524
|
+
const handler = new ChatModelStreamHandler();
|
|
2525
|
+
const metadata = { langgraph_node: 'agent' };
|
|
2526
|
+
await handler.handle(
|
|
2527
|
+
GraphEvents.CHAT_MODEL_STREAM,
|
|
2528
|
+
{
|
|
2529
|
+
chunk: {
|
|
2530
|
+
content: '',
|
|
2531
|
+
tool_call_chunks: [
|
|
2532
|
+
{
|
|
2533
|
+
id: 'call_weather',
|
|
2534
|
+
name: 'weather',
|
|
2535
|
+
args: '{"city":"NYC"}',
|
|
2536
|
+
index: 0,
|
|
2537
|
+
},
|
|
2538
|
+
],
|
|
2539
|
+
} as unknown as t.StreamChunk,
|
|
2540
|
+
},
|
|
2541
|
+
metadata,
|
|
2542
|
+
graph
|
|
2543
|
+
);
|
|
2544
|
+
await handler.handle(
|
|
2545
|
+
GraphEvents.CHAT_MODEL_STREAM,
|
|
2546
|
+
{
|
|
2547
|
+
chunk: {
|
|
2548
|
+
content: '',
|
|
2549
|
+
tool_call_chunks: [
|
|
2550
|
+
{
|
|
2551
|
+
id: 'call_stock',
|
|
2552
|
+
name: 'stock',
|
|
2553
|
+
args: '{"ticker":"C',
|
|
2554
|
+
index: 1,
|
|
2555
|
+
},
|
|
2556
|
+
],
|
|
2557
|
+
} as unknown as t.StreamChunk,
|
|
2558
|
+
},
|
|
2559
|
+
metadata,
|
|
2560
|
+
graph
|
|
2561
|
+
);
|
|
2562
|
+
|
|
2563
|
+
await graph.eagerEventToolExecutions.get('call_weather')?.promise;
|
|
2564
|
+
|
|
2565
|
+
expect(completedEvents).toHaveLength(1);
|
|
2566
|
+
expect(
|
|
2567
|
+
(
|
|
2568
|
+
completedEvents[0].result as {
|
|
2569
|
+
tool_call?: { output?: string };
|
|
2570
|
+
}
|
|
2571
|
+
).tool_call?.output
|
|
2572
|
+
).toBe('[{"rowsRead":"42"}]');
|
|
2573
|
+
});
|
|
2574
|
+
|
|
2501
2575
|
it('does not emit a stale eager completion after the active execution is invalidated', async () => {
|
|
2502
2576
|
const graph = createGraph({
|
|
2503
2577
|
getAgentContext: jest.fn(
|
|
@@ -1638,6 +1638,7 @@ export class AgentContext {
|
|
|
1638
1638
|
provider: this.provider,
|
|
1639
1639
|
tokenCounter,
|
|
1640
1640
|
maxTokens: this.maxContextTokens,
|
|
1641
|
+
maxToolResultChars: this.maxToolResultChars,
|
|
1641
1642
|
thinkingEnabled: isThinkingEnabled(this.provider, this.clientOptions),
|
|
1642
1643
|
indexTokenCountMap,
|
|
1643
1644
|
contextPruningConfig: this.contextPruningConfig,
|