@librechat/agents 3.3.3 → 3.3.4
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/graphs/Graph.cjs +342 -109
- 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/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 +37 -10
- 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 +64 -3
- 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/main.cjs +19 -2
- 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 +218 -60
- package/dist/cjs/messages/format.cjs.map +1 -1
- package/dist/cjs/messages/index.cjs +1 -1
- package/dist/cjs/messages/prune.cjs +503 -127
- package/dist/cjs/messages/prune.cjs.map +1 -1
- package/dist/cjs/stream.cjs +7 -3
- 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 +54 -41
- package/dist/cjs/tools/ToolNode.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/graphs/Graph.mjs +349 -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/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 +37 -10
- 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 +65 -5
- 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/main.mjs +7 -7
- 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 +218 -61
- package/dist/esm/messages/format.mjs.map +1 -1
- package/dist/esm/messages/index.mjs +1 -1
- package/dist/esm/messages/prune.mjs +500 -128
- package/dist/esm/messages/prune.mjs.map +1 -1
- package/dist/esm/stream.mjs +7 -3
- 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 +54 -41
- package/dist/esm/tools/ToolNode.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/graphs/Graph.d.ts +1 -1
- package/dist/types/llm/invoke.d.ts +27 -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/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/prune.d.ts +16 -12
- package/dist/types/types/stream.d.ts +1 -1
- 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/graphs/Graph.ts +698 -200
- package/src/graphs/MultiAgentGraph.ts +6 -1
- package/src/graphs/__tests__/Graph.contextOverflow.test.ts +1128 -4
- 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 +49 -1
- package/src/llm/bedrock/utils/message_inputs.ts +86 -13
- package/src/llm/google/utils/common.test.ts +75 -9
- package/src/llm/google/utils/common.ts +34 -3
- package/src/llm/invoke.test.ts +488 -0
- package/src/llm/invoke.ts +196 -2
- 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/messages/__tests__/observationMasking.test.ts +93 -2
- 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 +363 -91
- package/src/messages/formatAgentMessages.test.ts +604 -14
- package/src/messages/formatAgentMessages.tools.test.ts +103 -0
- package/src/messages/prune.ts +996 -183
- 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.ts +23 -15
- package/src/summarization/__tests__/node.test.ts +77 -0
- package/src/summarization/node.ts +46 -18
- package/src/tools/ToolNode.ts +147 -68
- 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/toolOutputReferences.ts +6 -0
- package/src/types/stream.ts +1 -1
- 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
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import "../common/enum.mjs";
|
|
2
2
|
import "../common/index.mjs";
|
|
3
|
+
import { HARD_MAX_TOOL_RESULT_CHARS } from "../utils/truncation.mjs";
|
|
4
|
+
import { compactToolContent, getToolContentCharLength, isAtomicToolContentBlock, serializeStructuredValueBounded } from "../utils/toolContent.mjs";
|
|
3
5
|
import { toLangChainContent, toLangChainMessageFields } from "./langchain.mjs";
|
|
4
6
|
import { normalizeAnthropicToolCallId } from "../llm/anthropic/utils/message_inputs.mjs";
|
|
5
7
|
import { emitAgentLog } from "../utils/events.mjs";
|
|
@@ -175,6 +177,10 @@ function hasToolCallOutput(part) {
|
|
|
175
177
|
const output = part.tool_call?.output;
|
|
176
178
|
return output != null && output !== "";
|
|
177
179
|
}
|
|
180
|
+
function formatToolCallOutput(output) {
|
|
181
|
+
if (output == null) return "";
|
|
182
|
+
return compactToolContent(output, HARD_MAX_TOOL_RESULT_CHARS).content;
|
|
183
|
+
}
|
|
178
184
|
/**
|
|
179
185
|
* Helper function to format an assistant message
|
|
180
186
|
* @param message The message to format
|
|
@@ -312,7 +318,7 @@ function formatAssistantMessage(message, options) {
|
|
|
312
318
|
formattedMessages.push(withMessageRole(new ToolMessage({
|
|
313
319
|
tool_call_id: tool_call.id ?? "",
|
|
314
320
|
name: tool_call.name,
|
|
315
|
-
content: output
|
|
321
|
+
content: formatToolCallOutput(output)
|
|
316
322
|
}), "tool"));
|
|
317
323
|
} else if (part.type === "think" || part.type === "thinking" || part.type === "reasoning" || part.type === "reasoning_content" || part.type === "redacted_thinking") {
|
|
318
324
|
hasReasoning = true;
|
|
@@ -583,7 +589,10 @@ function contentPartCharLength(part) {
|
|
|
583
589
|
if (typeof record.thinking === "string") len += record.thinking.length;
|
|
584
590
|
const { input } = record;
|
|
585
591
|
if (typeof input === "string") len += input.length;
|
|
586
|
-
else if (input != null && typeof input === "object")
|
|
592
|
+
else if (input != null && typeof input === "object") {
|
|
593
|
+
const measured = serializeStructuredValueBounded(input, 0).originalChars;
|
|
594
|
+
len += measured === Number.MAX_SAFE_INTEGER ? HARD_MAX_TOOL_RESULT_CHARS : Math.min(measured, HARD_MAX_TOOL_RESULT_CHARS);
|
|
595
|
+
}
|
|
587
596
|
return len;
|
|
588
597
|
}
|
|
589
598
|
/** Extracts the skillName from a skill tool_call's args (string or object). */
|
|
@@ -821,7 +830,10 @@ const formatAgentMessages = (payload, indexTokenCountMap, tools, skills, options
|
|
|
821
830
|
if (typeof tc.name === "string") len += tc.name.length;
|
|
822
831
|
const { args } = tc;
|
|
823
832
|
if (typeof args === "string") len += args.length;
|
|
824
|
-
else if (args != null)
|
|
833
|
+
else if (args != null) {
|
|
834
|
+
const measured = serializeStructuredValueBounded(args, 0).originalChars;
|
|
835
|
+
len += measured === Number.MAX_SAFE_INTEGER ? HARD_MAX_TOOL_RESULT_CHARS : Math.min(measured, HARD_MAX_TOOL_RESULT_CHARS);
|
|
836
|
+
}
|
|
825
837
|
}
|
|
826
838
|
lengths[k] = len;
|
|
827
839
|
totalLength += len;
|
|
@@ -867,10 +879,99 @@ function shiftIndexTokenCountMap(indexTokenCountMap, instructionsTokenCount) {
|
|
|
867
879
|
}
|
|
868
880
|
return shiftedMap;
|
|
869
881
|
}
|
|
870
|
-
/** Block types that contain binary image data and must be preserved structurally. */
|
|
871
|
-
const IMAGE_BLOCK_TYPES = new Set(["image_url", "image"]);
|
|
872
882
|
/** Checks whether a BaseMessage is a tool-role message. */
|
|
873
883
|
const isToolMessage$1 = (m) => m instanceof ToolMessage || "role" in m && m.role === "tool";
|
|
884
|
+
const PORTABLE_FOLDED_MEDIA_TYPES = new Set(["image", "image_url"]);
|
|
885
|
+
const MAX_FOLDED_BLOCK_CHARS = 8e3;
|
|
886
|
+
const MAX_FOLDED_CONTEXT_CHARS = HARD_MAX_TOOL_RESULT_CHARS;
|
|
887
|
+
const MAX_FOLDED_CONTEXT_WORK = 1e5;
|
|
888
|
+
const FOLDED_CONTEXT_TRUNCATION_NOTICE = "… [additional folded context omitted]";
|
|
889
|
+
const syntheticProviderContextMessages = /* @__PURE__ */ new WeakSet();
|
|
890
|
+
function createFoldContextBudget() {
|
|
891
|
+
return {
|
|
892
|
+
remainingChars: MAX_FOLDED_CONTEXT_CHARS,
|
|
893
|
+
remainingWork: MAX_FOLDED_CONTEXT_WORK,
|
|
894
|
+
truncated: false
|
|
895
|
+
};
|
|
896
|
+
}
|
|
897
|
+
function readFoldedDataProperty(value, key) {
|
|
898
|
+
if (value == null || typeof value !== "object") return;
|
|
899
|
+
try {
|
|
900
|
+
const descriptor = Object.getOwnPropertyDescriptor(value, key);
|
|
901
|
+
return descriptor != null && "value" in descriptor ? descriptor.value : void 0;
|
|
902
|
+
} catch {
|
|
903
|
+
return;
|
|
904
|
+
}
|
|
905
|
+
}
|
|
906
|
+
/**
|
|
907
|
+
* Adds one logical line without first concatenating caller-controlled strings.
|
|
908
|
+
* The shared budget covers every synthetic message emitted by one transform,
|
|
909
|
+
* so many individually bounded blocks cannot build an unbounded aggregate.
|
|
910
|
+
*/
|
|
911
|
+
function appendFoldedLine(textChunks, budget, pieces) {
|
|
912
|
+
if (budget.remainingChars <= 0) {
|
|
913
|
+
budget.truncated = true;
|
|
914
|
+
return false;
|
|
915
|
+
}
|
|
916
|
+
const separatorChars = textChunks.length > 0 ? 1 : 0;
|
|
917
|
+
const available = budget.remainingChars - separatorChars;
|
|
918
|
+
if (available <= 0) {
|
|
919
|
+
budget.remainingChars = 0;
|
|
920
|
+
budget.truncated = true;
|
|
921
|
+
return false;
|
|
922
|
+
}
|
|
923
|
+
let totalChars = 0;
|
|
924
|
+
for (const piece of pieces) totalChars = Math.min(Number.MAX_SAFE_INTEGER, totalChars + piece.length);
|
|
925
|
+
if (totalChars <= available) {
|
|
926
|
+
const line = pieces.join("");
|
|
927
|
+
textChunks.push(line);
|
|
928
|
+
budget.remainingChars -= separatorChars + line.length;
|
|
929
|
+
return true;
|
|
930
|
+
}
|
|
931
|
+
const notice = FOLDED_CONTEXT_TRUNCATION_NOTICE.slice(0, available);
|
|
932
|
+
let remainingHeadChars = Math.max(0, available - notice.length);
|
|
933
|
+
const boundedPieces = [];
|
|
934
|
+
for (const piece of pieces) {
|
|
935
|
+
if (remainingHeadChars <= 0) break;
|
|
936
|
+
const retained = piece.slice(0, remainingHeadChars);
|
|
937
|
+
boundedPieces.push(retained);
|
|
938
|
+
remainingHeadChars -= retained.length;
|
|
939
|
+
}
|
|
940
|
+
boundedPieces.push(notice);
|
|
941
|
+
textChunks.push(boundedPieces.join(""));
|
|
942
|
+
budget.remainingChars = 0;
|
|
943
|
+
budget.truncated = true;
|
|
944
|
+
return false;
|
|
945
|
+
}
|
|
946
|
+
function consumeFoldedWork(textChunks, budget) {
|
|
947
|
+
if (budget.remainingChars <= 0) return false;
|
|
948
|
+
if (budget.remainingWork-- > 0) return true;
|
|
949
|
+
appendFoldedLine(textChunks, budget, [FOLDED_CONTEXT_TRUNCATION_NOTICE]);
|
|
950
|
+
budget.remainingChars = 0;
|
|
951
|
+
budget.truncated = true;
|
|
952
|
+
return false;
|
|
953
|
+
}
|
|
954
|
+
function serializeFoldedValue(value) {
|
|
955
|
+
const compacted = compactToolContent(value, MAX_FOLDED_BLOCK_CHARS).content;
|
|
956
|
+
return typeof compacted === "string" ? compacted : serializeStructuredValueBounded(compacted, MAX_FOLDED_BLOCK_CHARS).content;
|
|
957
|
+
}
|
|
958
|
+
function markSyntheticProviderContext(message) {
|
|
959
|
+
syntheticProviderContextMessages.add(message);
|
|
960
|
+
return message;
|
|
961
|
+
}
|
|
962
|
+
function appendSyntheticProviderContextMessage(result, parts) {
|
|
963
|
+
if (parts.length === 0) return false;
|
|
964
|
+
result.push(markSyntheticProviderContext(withMessageRole(new HumanMessage({ content: toLangChainContent(parts) }), "user")));
|
|
965
|
+
return true;
|
|
966
|
+
}
|
|
967
|
+
/**
|
|
968
|
+
* Identifies provider-context placeholders created by this module without
|
|
969
|
+
* trusting user-controlled content prefixes or leaking marker metadata onto
|
|
970
|
+
* the provider wire.
|
|
971
|
+
*/
|
|
972
|
+
function isSyntheticProviderContextMessage(message) {
|
|
973
|
+
return syntheticProviderContextMessages.has(message);
|
|
974
|
+
}
|
|
874
975
|
/** Flushes accumulated text chunks into `parts` as a single text block. */
|
|
875
976
|
function flushTextChunks(textChunks, parts) {
|
|
876
977
|
if (textChunks.length === 0) return;
|
|
@@ -882,88 +983,139 @@ function flushTextChunks(textChunks, parts) {
|
|
|
882
983
|
}
|
|
883
984
|
/**
|
|
884
985
|
* Appends a single message's content to the running `textChunks` / `parts`
|
|
885
|
-
* accumulators.
|
|
886
|
-
* binary data
|
|
887
|
-
*
|
|
888
|
-
*
|
|
986
|
+
* accumulators. Portable image blocks are shallow-copied into `parts` so
|
|
987
|
+
* binary data never becomes text tokens. Provider-specific media/resource
|
|
988
|
+
* blocks are retained as bounded text so a folded cross-provider history
|
|
989
|
+
* cannot contain an unsupported native block or JSON-expand without limit.
|
|
889
990
|
*
|
|
890
991
|
* When `content` is an array containing tool_use blocks, `tool_calls` is NOT
|
|
891
992
|
* additionally serialized (avoiding double output). `tool_calls` is used as
|
|
892
993
|
* a fallback when `content` is a plain string or an array with no tool_use.
|
|
893
994
|
*/
|
|
894
|
-
function appendMessageContent(msg, role, textChunks, parts) {
|
|
995
|
+
function appendMessageContent(msg, role, textChunks, parts, budget) {
|
|
895
996
|
const { content } = msg;
|
|
896
997
|
if (typeof content === "string") {
|
|
897
|
-
if (content) textChunks
|
|
898
|
-
appendToolCalls(msg, role, textChunks);
|
|
998
|
+
if (content && consumeFoldedWork(textChunks, budget)) appendFoldedLine(textChunks, budget, [`${role}: `, content]);
|
|
999
|
+
appendToolCalls(msg, role, textChunks, budget);
|
|
899
1000
|
return;
|
|
900
1001
|
}
|
|
901
1002
|
if (!Array.isArray(content)) {
|
|
902
|
-
appendToolCalls(msg, role, textChunks);
|
|
1003
|
+
appendToolCalls(msg, role, textChunks, budget);
|
|
903
1004
|
return;
|
|
904
1005
|
}
|
|
905
1006
|
let hasToolUseBlock = false;
|
|
906
1007
|
for (const block of content) {
|
|
907
|
-
if (
|
|
908
|
-
|
|
909
|
-
|
|
1008
|
+
if (!consumeFoldedWork(textChunks, budget)) {
|
|
1009
|
+
hasToolUseBlock = true;
|
|
1010
|
+
break;
|
|
1011
|
+
}
|
|
1012
|
+
const blockTypeValue = readFoldedDataProperty(block, "type");
|
|
1013
|
+
const blockType = typeof blockTypeValue === "string" ? blockTypeValue : void 0;
|
|
1014
|
+
if (blockType !== "tool_use" && blockType !== "tool_call" && blockType !== "tool_result" && isAtomicToolContentBlock(block)) {
|
|
1015
|
+
if (PORTABLE_FOLDED_MEDIA_TYPES.has(blockType ?? "")) {
|
|
1016
|
+
const blockChars = getToolContentCharLength([block]);
|
|
1017
|
+
if (blockChars > budget.remainingChars) {
|
|
1018
|
+
appendFoldedLine(textChunks, budget, [`${role}: [${blockType ?? "media"} omitted: folded context limit]`]);
|
|
1019
|
+
continue;
|
|
1020
|
+
}
|
|
1021
|
+
flushTextChunks(textChunks, parts);
|
|
1022
|
+
parts.push({ ...block });
|
|
1023
|
+
budget.remainingChars -= blockChars;
|
|
1024
|
+
} else appendFoldedLine(textChunks, budget, [`${role}: [${blockType ?? "media"}] `, serializeFoldedValue(block)]);
|
|
910
1025
|
continue;
|
|
911
1026
|
}
|
|
912
|
-
if (
|
|
1027
|
+
if (blockType === "tool_use") {
|
|
913
1028
|
hasToolUseBlock = true;
|
|
914
|
-
|
|
1029
|
+
const name = readFoldedDataProperty(block, "name");
|
|
1030
|
+
const input = readFoldedDataProperty(block, "input");
|
|
1031
|
+
appendFoldedLine(textChunks, budget, [`${role}: [tool_use] ${typeof name === "string" ? name : ""} `, serializeFoldedValue(input ?? {})]);
|
|
915
1032
|
continue;
|
|
916
1033
|
}
|
|
917
|
-
if (
|
|
1034
|
+
if (blockType === "tool_call") {
|
|
918
1035
|
hasToolUseBlock = true;
|
|
919
|
-
const nested = block
|
|
920
|
-
const
|
|
921
|
-
const
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
1036
|
+
const nested = readFoldedDataProperty(block, "tool_call");
|
|
1037
|
+
const nestedName = readFoldedDataProperty(nested, "name");
|
|
1038
|
+
const topLevelName = readFoldedDataProperty(block, "name");
|
|
1039
|
+
let name = "";
|
|
1040
|
+
if (typeof nestedName === "string") name = nestedName;
|
|
1041
|
+
else if (typeof topLevelName === "string") name = topLevelName;
|
|
1042
|
+
const nestedArgs = readFoldedDataProperty(nested, "args");
|
|
1043
|
+
const topLevelArgs = readFoldedDataProperty(block, "args");
|
|
1044
|
+
const rawArgs = nestedArgs ?? topLevelArgs ?? {};
|
|
1045
|
+
const argsText = typeof rawArgs === "string" ? rawArgs : serializeFoldedValue(rawArgs);
|
|
1046
|
+
appendFoldedLine(textChunks, budget, [`${role}: [tool_use] ${name}${argsText ? " " : ""}`, argsText]);
|
|
1047
|
+
const output = readFoldedDataProperty(nested, "output");
|
|
1048
|
+
if (output != null && output !== "") appendFoldedLine(textChunks, budget, ["Tool: ", typeof output === "string" ? output : serializeFoldedValue(output)]);
|
|
926
1049
|
continue;
|
|
927
1050
|
}
|
|
928
|
-
if (
|
|
1051
|
+
if (blockType === "tool_result") {
|
|
929
1052
|
hasToolUseBlock = true;
|
|
930
|
-
const inner = block
|
|
1053
|
+
const inner = readFoldedDataProperty(block, "content");
|
|
931
1054
|
if (typeof inner === "string") {
|
|
932
|
-
if (inner) textChunks
|
|
933
|
-
} else if (Array.isArray(inner)) for (const innerBlock of inner)
|
|
934
|
-
if (
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
1055
|
+
if (inner) appendFoldedLine(textChunks, budget, [`${role}: [tool_result] `, inner]);
|
|
1056
|
+
} else if (Array.isArray(inner)) for (const innerBlock of inner) {
|
|
1057
|
+
if (!consumeFoldedWork(textChunks, budget)) break;
|
|
1058
|
+
if (typeof innerBlock === "string") {
|
|
1059
|
+
if (innerBlock) appendFoldedLine(textChunks, budget, [`${role}: [tool_result] `, innerBlock]);
|
|
1060
|
+
} else {
|
|
1061
|
+
const innerTypeValue = readFoldedDataProperty(innerBlock, "type");
|
|
1062
|
+
const innerType = typeof innerTypeValue === "string" ? innerTypeValue : void 0;
|
|
1063
|
+
if (isAtomicToolContentBlock(innerBlock) && PORTABLE_FOLDED_MEDIA_TYPES.has(innerType ?? "")) {
|
|
1064
|
+
const blockChars = getToolContentCharLength([innerBlock]);
|
|
1065
|
+
if (blockChars <= budget.remainingChars) {
|
|
1066
|
+
flushTextChunks(textChunks, parts);
|
|
1067
|
+
parts.push({ ...innerBlock });
|
|
1068
|
+
budget.remainingChars -= blockChars;
|
|
1069
|
+
} else appendFoldedLine(textChunks, budget, [`${role}: [${innerType ?? "media"} omitted: folded context limit]`]);
|
|
1070
|
+
} else {
|
|
1071
|
+
const textValue = readFoldedDataProperty(innerBlock, "text");
|
|
1072
|
+
const inputValue = readFoldedDataProperty(innerBlock, "input");
|
|
1073
|
+
const innerText = textValue ?? inputValue;
|
|
1074
|
+
appendFoldedLine(textChunks, budget, [`${role}: [tool_result] `, typeof innerText === "string" && innerText ? innerText : serializeFoldedValue(innerBlock)]);
|
|
1075
|
+
}
|
|
1076
|
+
}
|
|
941
1077
|
}
|
|
942
|
-
else if (inner != null) textChunks
|
|
1078
|
+
else if (inner != null) appendFoldedLine(textChunks, budget, [`${role}: [tool_result] `, serializeFoldedValue(inner)]);
|
|
943
1079
|
continue;
|
|
944
1080
|
}
|
|
945
|
-
const text = block
|
|
1081
|
+
const text = readFoldedDataProperty(block, "text") ?? readFoldedDataProperty(block, "input");
|
|
946
1082
|
if (typeof text === "string" && text) {
|
|
947
|
-
textChunks
|
|
1083
|
+
appendFoldedLine(textChunks, budget, [`${role}: `, text]);
|
|
948
1084
|
continue;
|
|
949
1085
|
}
|
|
950
|
-
if (
|
|
1086
|
+
if (blockType != null && blockType !== "") appendFoldedLine(textChunks, budget, [`${role}: [${blockType}] `, serializeFoldedValue(block)]);
|
|
951
1087
|
}
|
|
952
|
-
if (!hasToolUseBlock) appendToolCalls(msg, role, textChunks);
|
|
1088
|
+
if (!hasToolUseBlock) appendToolCalls(msg, role, textChunks, budget);
|
|
953
1089
|
}
|
|
954
|
-
function appendToolCalls(msg, role, textChunks) {
|
|
1090
|
+
function appendToolCalls(msg, role, textChunks, budget) {
|
|
955
1091
|
if (role !== "AI") return;
|
|
956
1092
|
const aiMsg = msg;
|
|
957
1093
|
if (aiMsg.tool_calls && aiMsg.tool_calls.length > 0) {
|
|
958
|
-
for (const tc of aiMsg.tool_calls)
|
|
1094
|
+
for (const tc of aiMsg.tool_calls) {
|
|
1095
|
+
if (!consumeFoldedWork(textChunks, budget)) break;
|
|
1096
|
+
const name = readFoldedDataProperty(tc, "name");
|
|
1097
|
+
const args = readFoldedDataProperty(tc, "args");
|
|
1098
|
+
appendFoldedLine(textChunks, budget, [
|
|
1099
|
+
`AI: [tool_call] ${typeof name === "string" ? name : ""}(`,
|
|
1100
|
+
serializeFoldedValue(args),
|
|
1101
|
+
")"
|
|
1102
|
+
]);
|
|
1103
|
+
}
|
|
959
1104
|
return;
|
|
960
1105
|
}
|
|
961
1106
|
const rawToolCalls = aiMsg.additional_kwargs.tool_calls;
|
|
962
1107
|
if (!Array.isArray(rawToolCalls)) return;
|
|
963
1108
|
for (const tc of rawToolCalls) {
|
|
964
|
-
|
|
1109
|
+
if (!consumeFoldedWork(textChunks, budget)) break;
|
|
1110
|
+
const fn = readFoldedDataProperty(tc, "function");
|
|
965
1111
|
if (fn == null) continue;
|
|
966
|
-
|
|
1112
|
+
const name = readFoldedDataProperty(fn, "name");
|
|
1113
|
+
const args = readFoldedDataProperty(fn, "arguments");
|
|
1114
|
+
appendFoldedLine(textChunks, budget, [
|
|
1115
|
+
`AI: [tool_call] ${typeof name === "string" ? name : ""}(`,
|
|
1116
|
+
typeof args === "string" ? args : "",
|
|
1117
|
+
")"
|
|
1118
|
+
]);
|
|
967
1119
|
}
|
|
968
1120
|
}
|
|
969
1121
|
/**
|
|
@@ -1004,6 +1156,7 @@ function ensureThinkingBlockInMessages(messages, _provider, config, runStartInde
|
|
|
1004
1156
|
}
|
|
1005
1157
|
if (lastHumanIndex === messages.length - 1) return messages;
|
|
1006
1158
|
const result = lastHumanIndex >= 0 ? messages.slice(0, lastHumanIndex + 1) : [];
|
|
1159
|
+
const foldBudget = createFoldContextBudget();
|
|
1007
1160
|
let i = lastHumanIndex + 1;
|
|
1008
1161
|
while (i < messages.length) {
|
|
1009
1162
|
const msg = messages[i];
|
|
@@ -1019,8 +1172,9 @@ function ensureThinkingBlockInMessages(messages, _provider, config, runStartInde
|
|
|
1019
1172
|
let hasThinkingBlock = false;
|
|
1020
1173
|
if (contentIsArray && aiMsg.content.length > 0) for (const c of aiMsg.content) {
|
|
1021
1174
|
if (typeof c !== "object") continue;
|
|
1022
|
-
|
|
1023
|
-
|
|
1175
|
+
const type = readFoldedDataProperty(c, "type");
|
|
1176
|
+
if (type === "tool_use") hasToolUse = true;
|
|
1177
|
+
else if (type === "thinking" || type === "reasoning_content" || type === "reasoning" || type === "redacted_thinking") hasThinkingBlock = true;
|
|
1024
1178
|
if (hasToolUse && hasThinkingBlock) break;
|
|
1025
1179
|
}
|
|
1026
1180
|
if (!hasThinkingBlock && aiMsg.additional_kwargs.reasoning_content != null) hasThinkingBlock = true;
|
|
@@ -1036,16 +1190,16 @@ function ensureThinkingBlockInMessages(messages, _provider, config, runStartInde
|
|
|
1036
1190
|
continue;
|
|
1037
1191
|
}
|
|
1038
1192
|
const parts = [];
|
|
1039
|
-
const textChunks = [
|
|
1040
|
-
|
|
1193
|
+
const textChunks = [];
|
|
1194
|
+
appendFoldedLine(textChunks, foldBudget, ["[Previous agent context]"]);
|
|
1195
|
+
appendMessageContent(msg, "AI", textChunks, parts, foldBudget);
|
|
1041
1196
|
let j = i + 1;
|
|
1042
1197
|
while (j < messages.length && isToolMessage$1(messages[j])) {
|
|
1043
|
-
appendMessageContent(messages[j], "Tool", textChunks, parts);
|
|
1198
|
+
appendMessageContent(messages[j], "Tool", textChunks, parts, foldBudget);
|
|
1044
1199
|
j++;
|
|
1045
1200
|
}
|
|
1046
1201
|
flushTextChunks(textChunks, parts);
|
|
1047
|
-
emitAgentLog(config, "warn", "format", `ensureThinkingBlockInMessages: injecting [Previous agent context] HumanMessage (${parts.length} msgs at index ${i}, no thinking block in chain)`);
|
|
1048
|
-
result.push(withMessageRole(new HumanMessage({ content: toLangChainContent(parts) }), "user"));
|
|
1202
|
+
if (appendSyntheticProviderContextMessage(result, parts)) emitAgentLog(config, "warn", "format", `ensureThinkingBlockInMessages: injecting [Previous agent context] HumanMessage (${parts.length} msgs at index ${i}, no thinking block in chain)`);
|
|
1049
1203
|
i = j;
|
|
1050
1204
|
} else {
|
|
1051
1205
|
result.push(msg);
|
|
@@ -1069,8 +1223,9 @@ function messageHasToolContent(msg) {
|
|
|
1069
1223
|
if (aiMsg.tool_calls != null && aiMsg.tool_calls.length > 0) return true;
|
|
1070
1224
|
const rawToolCalls = aiMsg.additional_kwargs.tool_calls;
|
|
1071
1225
|
if (Array.isArray(rawToolCalls) && rawToolCalls.length > 0) return true;
|
|
1072
|
-
if (Array.isArray(msg.content)) {
|
|
1073
|
-
|
|
1226
|
+
if (Array.isArray(msg.content)) for (const block of msg.content) {
|
|
1227
|
+
const type = readFoldedDataProperty(block, "type");
|
|
1228
|
+
if (typeof block === "object" && (type === "tool_use" || type === "tool_call" || type === "tool_result")) return true;
|
|
1074
1229
|
}
|
|
1075
1230
|
return false;
|
|
1076
1231
|
}
|
|
@@ -1081,7 +1236,7 @@ function messageHasToolContent(msg) {
|
|
|
1081
1236
|
* and labelled as tool output. */
|
|
1082
1237
|
function isToolResultMessage(msg) {
|
|
1083
1238
|
if (isToolMessage$1(msg)) return true;
|
|
1084
|
-
if (Array.isArray(msg.content)) return msg.content.some((block) => typeof block === "object" && block
|
|
1239
|
+
if (Array.isArray(msg.content)) return msg.content.some((block) => typeof block === "object" && readFoldedDataProperty(block, "type") === "tool_result");
|
|
1085
1240
|
return false;
|
|
1086
1241
|
}
|
|
1087
1242
|
/**
|
|
@@ -1108,6 +1263,7 @@ function isToolResultMessage(msg) {
|
|
|
1108
1263
|
function foldToolBlocksForToollessAgent(messages, config) {
|
|
1109
1264
|
let result = null;
|
|
1110
1265
|
let foldedCount = 0;
|
|
1266
|
+
const foldBudget = createFoldContextBudget();
|
|
1111
1267
|
let i = 0;
|
|
1112
1268
|
while (i < messages.length) {
|
|
1113
1269
|
const msg = messages[i];
|
|
@@ -1119,17 +1275,18 @@ function foldToolBlocksForToollessAgent(messages, config) {
|
|
|
1119
1275
|
/** First fold — copy the untouched prefix once, then append from here. */
|
|
1120
1276
|
if (result === null) result = messages.slice(0, i);
|
|
1121
1277
|
const parts = [];
|
|
1122
|
-
const textChunks = [
|
|
1123
|
-
|
|
1278
|
+
const textChunks = [];
|
|
1279
|
+
appendFoldedLine(textChunks, foldBudget, ["[Previous tool interaction]"]);
|
|
1280
|
+
appendMessageContent(msg, isToolResultMessage(msg) ? "Tool" : "AI", textChunks, parts, foldBudget);
|
|
1124
1281
|
foldedCount++;
|
|
1125
1282
|
let j = i + 1;
|
|
1126
1283
|
while (j < messages.length && isToolResultMessage(messages[j])) {
|
|
1127
|
-
appendMessageContent(messages[j], "Tool", textChunks, parts);
|
|
1284
|
+
appendMessageContent(messages[j], "Tool", textChunks, parts, foldBudget);
|
|
1128
1285
|
foldedCount++;
|
|
1129
1286
|
j++;
|
|
1130
1287
|
}
|
|
1131
1288
|
flushTextChunks(textChunks, parts);
|
|
1132
|
-
result
|
|
1289
|
+
appendSyntheticProviderContextMessage(result, parts);
|
|
1133
1290
|
i = j;
|
|
1134
1291
|
}
|
|
1135
1292
|
if (result === null) return messages;
|
|
@@ -1162,6 +1319,6 @@ function chainHasThinkingBlock(messages, currentIndex) {
|
|
|
1162
1319
|
return false;
|
|
1163
1320
|
}
|
|
1164
1321
|
//#endregion
|
|
1165
|
-
export { ensureThinkingBlockInMessages, foldToolBlocksForToollessAgent, formatAgentMessages, formatFromLangChain, formatLangChainMessages, formatMediaMessage, formatMessage, labelContentByAgent, shiftIndexTokenCountMap, withMessageRole };
|
|
1322
|
+
export { ensureThinkingBlockInMessages, foldToolBlocksForToollessAgent, formatAgentMessages, formatFromLangChain, formatLangChainMessages, formatMediaMessage, formatMessage, isSyntheticProviderContextMessage, labelContentByAgent, shiftIndexTokenCountMap, withMessageRole };
|
|
1166
1323
|
|
|
1167
1324
|
//# sourceMappingURL=format.mjs.map
|