@librechat/agents 3.3.4 → 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/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 +456 -7
- package/dist/cjs/graphs/Graph.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/bedrock/utils/message_inputs.cjs +1 -3
- package/dist/cjs/llm/bedrock/utils/message_inputs.cjs.map +1 -1
- package/dist/cjs/llm/invoke.cjs +268 -3
- package/dist/cjs/llm/invoke.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 +17 -3
- package/dist/cjs/messages/alternation.cjs +92 -0
- package/dist/cjs/messages/alternation.cjs.map +1 -0
- package/dist/cjs/messages/format.cjs +72 -0
- 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 +3 -0
- package/dist/cjs/messages/injected.cjs +60 -0
- package/dist/cjs/messages/injected.cjs.map +1 -0
- 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 +28 -7
- package/dist/cjs/stream.cjs.map +1 -1
- package/dist/cjs/tools/ToolNode.cjs +3 -23
- 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/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 +455 -6
- package/dist/esm/graphs/Graph.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/bedrock/utils/message_inputs.mjs +1 -3
- package/dist/esm/llm/bedrock/utils/message_inputs.mjs.map +1 -1
- package/dist/esm/llm/invoke.mjs +270 -6
- package/dist/esm/llm/invoke.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 +8 -5
- package/dist/esm/messages/alternation.mjs +91 -0
- package/dist/esm/messages/alternation.mjs.map +1 -0
- package/dist/esm/messages/format.mjs +72 -0
- 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 +3 -0
- package/dist/esm/messages/injected.mjs +60 -0
- package/dist/esm/messages/injected.mjs.map +1 -0
- 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 +27 -8
- package/dist/esm/stream.mjs.map +1 -1
- package/dist/esm/tools/ToolNode.mjs +3 -23
- 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/types/common/constants.d.ts +18 -0
- package/dist/types/graphs/Graph.d.ts +138 -1
- 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 +7 -0
- package/dist/types/llm/preempt.d.ts +40 -0
- package/dist/types/messages/alternation.d.ts +23 -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/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 +0 -25
- package/package.json +1 -1
- 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 +568 -3
- package/src/graphs/__tests__/Graph.contextOverflow.test.ts +18 -7
- 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/bedrock/utils/message_inputs.test.ts +82 -0
- package/src/llm/bedrock/utils/message_inputs.ts +14 -11
- package/src/llm/bedrock/utils/toolResultCachePoint.test.ts +15 -0
- package/src/llm/invoke.alternation.test.ts +87 -0
- package/src/llm/invoke.handoffCue.test.ts +112 -0
- package/src/llm/invoke.ts +417 -8
- package/src/llm/preempt.test.ts +323 -0
- package/src/llm/preempt.ts +178 -0
- package/src/messages/alternation.test.ts +212 -0
- package/src/messages/alternation.ts +112 -0
- package/src/messages/format.ts +91 -0
- package/src/messages/formatAgentMessages.steer.test.ts +267 -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/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/stream.dispatch.test.ts +63 -0
- package/src/stream.ts +36 -8
- package/src/tools/ToolNode.ts +3 -31
- 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/types/graph.ts +12 -1
- package/src/types/run.ts +67 -0
- package/src/types/stream.ts +0 -41
- 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
|
@@ -182,6 +182,19 @@ function formatToolCallOutput(output) {
|
|
|
182
182
|
return require_toolContent.compactToolContent(output, require_truncation.HARD_MAX_TOOL_RESULT_CHARS).content;
|
|
183
183
|
}
|
|
184
184
|
/**
|
|
185
|
+
* Content for the synthetic assistant turn that separates a trailing steer
|
|
186
|
+
* from the next user turn. Non-empty by necessity — see the push site.
|
|
187
|
+
*/
|
|
188
|
+
const STEER_ANCHOR_PLACEHOLDER = "_";
|
|
189
|
+
/**
|
|
190
|
+
* True when an assistant message replayed as a steer and nothing followed it,
|
|
191
|
+
* so the emitted run ends on the steer's `HumanMessage`.
|
|
192
|
+
*/
|
|
193
|
+
function endsWithSteerMessage(formatted) {
|
|
194
|
+
if (formatted.length === 0) return false;
|
|
195
|
+
return formatted[formatted.length - 1].additional_kwargs.source === "steer";
|
|
196
|
+
}
|
|
197
|
+
/**
|
|
185
198
|
* Helper function to format an assistant message
|
|
186
199
|
* @param message The message to format
|
|
187
200
|
* @param options Optional formatting options
|
|
@@ -617,6 +630,27 @@ function extractSkillName(args) {
|
|
|
617
630
|
*/
|
|
618
631
|
const formatAgentMessages = (payload, indexTokenCountMap, tools, skills, options) => {
|
|
619
632
|
const messages = [];
|
|
633
|
+
/**
|
|
634
|
+
* A steer ended the previous payload entry, so the next message emitted —
|
|
635
|
+
* whichever entry finally produces one — must be separated from it by an
|
|
636
|
+
* assistant turn. Held rather than emitted so an entry that produces
|
|
637
|
+
* nothing cannot leave the anchor stranded as the final turn.
|
|
638
|
+
*/
|
|
639
|
+
let pendingSteerAnchor = false;
|
|
640
|
+
/**
|
|
641
|
+
* Emits the deferred anchor ahead of `next` — the message about to be
|
|
642
|
+
* pushed. When that message is itself an assistant turn, it already IS the
|
|
643
|
+
* separation the anchor exists to synthesize, so the intent is simply
|
|
644
|
+
* discharged: emitting the placeholder anyway would put two assistant turns
|
|
645
|
+
* back to back, which strict-alternation providers can reject and nothing downstream
|
|
646
|
+
* repairs (`coalesceAdjacentUserTurns` merges user turns only).
|
|
647
|
+
*/
|
|
648
|
+
const flushSteerAnchor = (next) => {
|
|
649
|
+
if (!pendingSteerAnchor) return;
|
|
650
|
+
pendingSteerAnchor = false;
|
|
651
|
+
if (next.role === "assistant") return;
|
|
652
|
+
messages.push(withMessageRole(new _langchain_core_messages.AIMessage({ content: STEER_ANCHOR_PLACEHOLDER }), "assistant"));
|
|
653
|
+
};
|
|
620
654
|
const updatedIndexTokenCountMap = {};
|
|
621
655
|
let boundaryTokenAdjustment;
|
|
622
656
|
const indexMapping = {};
|
|
@@ -652,6 +686,7 @@ const formatAgentMessages = (payload, indexTokenCountMap, tools, skills, options
|
|
|
652
686
|
langChain: true
|
|
653
687
|
});
|
|
654
688
|
if (sourceMessageId != null && sourceMessageId !== "") formattedMessage.id = sourceMessageId;
|
|
689
|
+
flushSteerAnchor(formattedMessage);
|
|
655
690
|
messages.push(formattedMessage);
|
|
656
691
|
indexMapping[i] = [messages.length - 1];
|
|
657
692
|
continue;
|
|
@@ -755,7 +790,44 @@ const formatAgentMessages = (payload, indexTokenCountMap, tools, skills, options
|
|
|
755
790
|
provider: options?.provider
|
|
756
791
|
});
|
|
757
792
|
if (sourceMessageId != null && sourceMessageId !== "") for (const formattedMessage of formattedMessages) formattedMessage.id = sourceMessageId;
|
|
793
|
+
/**
|
|
794
|
+
* A steer that ends an assistant message leaves the replay on a
|
|
795
|
+
* `HumanMessage`. The next payload message is itself a user turn, so the
|
|
796
|
+
* sequence would reach the provider as two adjacent user turns — rejected
|
|
797
|
+
* by strict-alternation providers. Anchor it with a placeholder assistant
|
|
798
|
+
* turn.
|
|
799
|
+
*
|
|
800
|
+
* The placeholder must be NON-EMPTY. A string-content assistant message
|
|
801
|
+
* with no tool calls passes through `_convertMessagesToAnthropicPayload`
|
|
802
|
+
* verbatim — the empty-text repair there only covers array content and
|
|
803
|
+
* tool-call turns — so an empty anchor would reach Anthropic as
|
|
804
|
+
* `{role: 'assistant', content: ''}` and trade one invalid sequence for
|
|
805
|
+
* another. Same single-underscore convention the Anthropic converter
|
|
806
|
+
* already uses when it has to synthesize a non-empty block.
|
|
807
|
+
*
|
|
808
|
+
* Deferred rather than decided by lookahead. `i < payload.length - 1` only
|
|
809
|
+
* proves a later ENTRY exists, not that it EMITS: entries with empty
|
|
810
|
+
* content, and entries dropped by `applySummaryBoundary`, are skipped
|
|
811
|
+
* silently. A trailing steer followed only by those would get the anchor
|
|
812
|
+
* as the FINAL turn — an assistant prefill with no request after it, which
|
|
813
|
+
* the model may simply never answer. So the intent is recorded and flushed
|
|
814
|
+
* only when a message actually follows.
|
|
815
|
+
*
|
|
816
|
+
* Pushed AFTER the id stamping above, deliberately. `messagesStateReducer`
|
|
817
|
+
* treats a repeated id as replace-in-place, so an anchor carrying the
|
|
818
|
+
* shared `sourceMessageId` would overwrite the steer it exists to protect.
|
|
819
|
+
* Left unstamped, it reaches the reducer with a null id and is assigned a
|
|
820
|
+
* fresh one. `endsWithSteerMessage` reads only `additional_kwargs.source`,
|
|
821
|
+
* so the deferral cannot change which messages get anchored.
|
|
822
|
+
*/
|
|
823
|
+
/**
|
|
824
|
+
* Guarded on emission: an assistant entry whose blocks all filtered away
|
|
825
|
+
* emits nothing, and flushing for it would strand the anchor as the final
|
|
826
|
+
* turn — the pending flag stays set for whichever entry emits next.
|
|
827
|
+
*/
|
|
828
|
+
if (formattedMessages.length > 0) flushSteerAnchor(formattedMessages[0]);
|
|
758
829
|
messages.push(...formattedMessages);
|
|
830
|
+
if (endsWithSteerMessage(formattedMessages)) pendingSteerAnchor = true;
|
|
759
831
|
const endMessageIndex = messages.length;
|
|
760
832
|
if (pendingSkillNames?.size != null && pendingSkillNames.size > 0) {
|
|
761
833
|
const skipSkillBodyNames = options?.skipSkillBodyNames;
|