@librechat/agents 2.3.0 → 2.3.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.
|
@@ -204,24 +204,48 @@ function getMessagesWithinTokenLimit({ messages: _messages, maxContextTokens, in
|
|
|
204
204
|
}
|
|
205
205
|
}
|
|
206
206
|
}
|
|
207
|
-
// If the latest message is an assistant message, ensure an assistant message appears
|
|
208
|
-
//
|
|
207
|
+
// If the latest message is an assistant message, ensure an assistant message with thinking appears at the end
|
|
208
|
+
// of the context (which will become the beginning after reversal)
|
|
209
|
+
// but maintain system message precedence after reversal
|
|
209
210
|
if (latestMessageIsAssistant && context.length > 0) {
|
|
210
|
-
// Find
|
|
211
|
-
const
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
211
|
+
// Find assistant messages with thinking blocks
|
|
212
|
+
const assistantIndices = [];
|
|
213
|
+
for (let i = 0; i < context.length; i++) {
|
|
214
|
+
const msg = context[i];
|
|
215
|
+
if (msg.getType() === 'ai') {
|
|
216
|
+
const hasThinking = Array.isArray(msg.content) &&
|
|
217
|
+
msg.content.some(item => item && typeof item === 'object' && item.type === 'thinking');
|
|
218
|
+
if (hasThinking) {
|
|
219
|
+
assistantIndices.push(i);
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
// If we found assistant messages with thinking blocks
|
|
224
|
+
if (assistantIndices.length > 0) {
|
|
225
|
+
// Get the first assistant message with thinking
|
|
226
|
+
const assistantWithThinkingIndex = assistantIndices[0];
|
|
227
|
+
const assistantWithThinking = context[assistantWithThinkingIndex];
|
|
228
|
+
// Remove it from its current position
|
|
229
|
+
context.splice(assistantWithThinkingIndex, 1);
|
|
230
|
+
// Check if there's a system message in the context
|
|
231
|
+
const systemIndex = context.findIndex(msg => msg.getType() === 'system');
|
|
232
|
+
const hasSystem = systemIndex !== -1;
|
|
233
|
+
if (hasSystem) {
|
|
234
|
+
// We want the system message to be first after reversal
|
|
235
|
+
// This means we need to put it at the end position before reversal
|
|
236
|
+
// And the assistant message should be second after reversal
|
|
237
|
+
// This means we need to put it at the end - 1 position before reversal
|
|
238
|
+
// First, ensure the system message is at the end (will be first after reversal)
|
|
239
|
+
const systemMsg = context[systemIndex];
|
|
240
|
+
context.splice(systemIndex, 1);
|
|
241
|
+
context.push(systemMsg);
|
|
242
|
+
// Then, put the assistant message right before the system message (will be second after reversal)
|
|
243
|
+
context.splice(context.length - 1, 0, assistantWithThinking);
|
|
221
244
|
}
|
|
222
245
|
else {
|
|
223
|
-
//
|
|
224
|
-
|
|
246
|
+
// No system message, so we want assistant to be first after reversal
|
|
247
|
+
// This means we need to put it at the end position before reversal
|
|
248
|
+
context.push(assistantWithThinking);
|
|
225
249
|
}
|
|
226
250
|
}
|
|
227
251
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"prune.cjs","sources":["../../../src/messages/prune.ts"],"sourcesContent":["import { AIMessage } from '@langchain/core/messages';\nimport type { BaseMessage, UsageMetadata } from '@langchain/core/messages';\nimport type { TokenCounter } from '@/types/run';\nexport type PruneMessagesFactoryParams = {\n maxTokens: number;\n startIndex: number;\n tokenCounter: TokenCounter;\n indexTokenCountMap: Record<string, number>;\n thinkingEnabled?: boolean;\n};\nexport type PruneMessagesParams = {\n messages: BaseMessage[];\n usageMetadata?: Partial<UsageMetadata>;\n startOnMessageType?: ReturnType<BaseMessage['getType']>;\n}\n\n/**\n * Calculates the total tokens from a single usage object\n * \n * @param usage The usage metadata object containing token information\n * @returns An object containing the total input and output tokens\n */\nfunction calculateTotalTokens(usage: Partial<UsageMetadata>): UsageMetadata {\n const baseInputTokens = Number(usage.input_tokens) || 0;\n const cacheCreation = Number(usage.input_token_details?.cache_creation) || 0;\n const cacheRead = Number(usage.input_token_details?.cache_read) || 0;\n \n const totalInputTokens = baseInputTokens + cacheCreation + cacheRead;\n const totalOutputTokens = Number(usage.output_tokens) || 0;\n\n return {\n input_tokens: totalInputTokens,\n output_tokens: totalOutputTokens,\n total_tokens: totalInputTokens + totalOutputTokens\n };\n}\n\n/**\n * Processes an array of messages and returns a context of messages that fit within a specified token limit.\n * It iterates over the messages from newest to oldest, adding them to the context until the token limit is reached.\n * \n * @param options Configuration options for processing messages\n * @returns Object containing the message context, remaining tokens, messages not included, and summary index\n */\nfunction getMessagesWithinTokenLimit({\n messages: _messages,\n maxContextTokens,\n indexTokenCountMap,\n startOnMessageType,\n thinkingEnabled,\n tokenCounter,\n}: {\n messages: BaseMessage[];\n maxContextTokens: number;\n indexTokenCountMap: Record<string, number>;\n startOnMessageType?: string;\n thinkingEnabled?: boolean;\n tokenCounter?: TokenCounter;\n}): {\n context: BaseMessage[];\n remainingContextTokens: number;\n messagesToRefine: BaseMessage[];\n summaryIndex: number;\n} {\n // Every reply is primed with <|start|>assistant<|message|>, so we\n // start with 3 tokens for the label after all messages have been counted.\n let summaryIndex = -1;\n let currentTokenCount = 3;\n const instructions = _messages?.[0]?.getType() === 'system' ? _messages[0] : undefined;\n const instructionsTokenCount = instructions != null ? indexTokenCountMap[0] : 0;\n let remainingContextTokens = maxContextTokens - instructionsTokenCount;\n const messages = [..._messages];\n let context: BaseMessage[] = [];\n\n if (currentTokenCount < remainingContextTokens) {\n let currentIndex = messages.length;\n while (messages.length > 0 && currentTokenCount < remainingContextTokens && currentIndex > 1) {\n currentIndex--;\n if (messages.length === 1 && instructions) {\n break;\n }\n const poppedMessage = messages.pop();\n if (!poppedMessage) continue;\n \n const tokenCount = indexTokenCountMap[currentIndex] || 0;\n\n if ((currentTokenCount + tokenCount) <= remainingContextTokens) {\n context.push(poppedMessage);\n currentTokenCount += tokenCount;\n } else {\n messages.push(poppedMessage);\n break;\n }\n }\n \n // Handle startOnMessageType requirement\n if (startOnMessageType && context.length > 0) {\n const requiredTypeIndex = context.findIndex(msg => msg.getType() === startOnMessageType);\n \n if (requiredTypeIndex > 0) {\n context = context.slice(requiredTypeIndex);\n }\n }\n \n // Add system message if it exists\n if (instructions && _messages.length > 0) {\n context.push(_messages[0] as BaseMessage);\n messages.shift();\n }\n \n // Handle thinking mode requirement for Anthropic\n if (thinkingEnabled && context.length > 0 && tokenCounter) {\n // Check if the latest message is an assistant message\n const latestMessageIsAssistant = _messages.length > 0 && _messages[_messages.length - 1].getType() === 'ai';\n \n // Process only if we have an assistant message in the context\n const firstAssistantIndex = context.findIndex(msg => msg.getType() === 'ai');\n \n if (firstAssistantIndex >= 0) {\n const firstAssistantMsg = context[firstAssistantIndex];\n \n // Check if the first assistant message already has a thinking block\n const hasThinkingBlock = Array.isArray(firstAssistantMsg.content) && \n firstAssistantMsg.content.some(item => \n item && typeof item === 'object' && item.type === 'thinking');\n \n // Only proceed if we need to add thinking blocks\n if (!hasThinkingBlock) {\n // Collect thinking blocks from pruned assistant messages, starting from the most recent\n const thinkingBlocks: any[] = [];\n \n // Look through pruned messages for thinking blocks, starting from the end (most recent)\n for (let i = messages.length - 1; i >= 0; i--) {\n const msg = messages[i];\n if (msg.getType() === 'ai' && Array.isArray(msg.content)) {\n for (const item of msg.content) {\n if (item && typeof item === 'object' && item.type === 'thinking') {\n thinkingBlocks.push(item);\n // We only need one thinking block\n break;\n }\n }\n if (thinkingBlocks.length > 0) break; // Stop after finding one thinking block\n }\n }\n \n // If we found thinking blocks, add them to the first assistant message\n if (thinkingBlocks.length > 0) {\n // Calculate token count of original message\n const originalTokenCount = tokenCounter(firstAssistantMsg);\n \n // Create a new content array with thinking blocks at the beginning\n let newContent: any[];\n \n if (Array.isArray(firstAssistantMsg.content)) {\n // Keep the original content (excluding any existing thinking blocks)\n const originalContent = firstAssistantMsg.content.filter(item => \n !(item && typeof item === 'object' && item.type === 'thinking'));\n \n newContent = [...thinkingBlocks, ...originalContent];\n } else if (typeof firstAssistantMsg.content === 'string') {\n newContent = [\n ...thinkingBlocks,\n { type: 'text', text: firstAssistantMsg.content }\n ];\n } else {\n newContent = thinkingBlocks;\n }\n \n // Create a new message with the updated content\n const newMessage = new AIMessage({\n content: newContent,\n additional_kwargs: firstAssistantMsg.additional_kwargs,\n response_metadata: firstAssistantMsg.response_metadata,\n });\n \n // Calculate token count of new message\n const newTokenCount = tokenCounter(newMessage);\n \n // Adjust current token count\n currentTokenCount += (newTokenCount - originalTokenCount);\n \n // Replace the first assistant message\n context[firstAssistantIndex] = newMessage;\n \n // If we've exceeded the token limit, we need to prune more messages\n if (currentTokenCount > remainingContextTokens) {\n // Build a map of tool call IDs to track AI <--> tool message correspondences\n const toolCallIdMap = new Map<string, number>();\n \n // Identify tool call IDs in the context\n for (let i = 0; i < context.length; i++) {\n const msg = context[i];\n \n // Check for tool calls in AI messages\n if (msg.getType() === 'ai' && Array.isArray(msg.content)) {\n for (const item of msg.content) {\n if (item && typeof item === 'object' && item.type === 'tool_use' && item.id) {\n toolCallIdMap.set(item.id, i);\n }\n }\n }\n \n // Check for tool messages\n if (msg.getType() === 'tool' && 'tool_call_id' in msg && typeof msg.tool_call_id === 'string') {\n toolCallIdMap.set(msg.tool_call_id, i);\n }\n }\n \n // Track which messages to remove\n const indicesToRemove = new Set<number>();\n \n // Start removing messages from the end, but preserve AI <--> tool message correspondences\n let i = context.length - 1;\n while (i > firstAssistantIndex && currentTokenCount > remainingContextTokens) {\n const msgToRemove = context[i];\n \n // Check if this is a tool message or has tool calls\n let canRemove = true;\n \n if (msgToRemove.getType() === 'tool' && 'tool_call_id' in msgToRemove && typeof msgToRemove.tool_call_id === 'string') {\n // If this is a tool message, check if we need to keep its corresponding AI message\n const aiIndex = toolCallIdMap.get(msgToRemove.tool_call_id);\n if (aiIndex !== undefined && aiIndex !== i && !indicesToRemove.has(aiIndex)) {\n // We need to remove both the tool message and its corresponding AI message\n indicesToRemove.add(i);\n indicesToRemove.add(aiIndex);\n currentTokenCount -= (tokenCounter(msgToRemove) + tokenCounter(context[aiIndex]));\n canRemove = false;\n }\n } else if (msgToRemove.getType() === 'ai' && Array.isArray(msgToRemove.content)) {\n // If this is an AI message with tool calls, check if we need to keep its corresponding tool messages\n for (const item of msgToRemove.content) {\n if (item && typeof item === 'object' && item.type === 'tool_use' && item.id) {\n const toolIndex = toolCallIdMap.get(item.id as string);\n if (toolIndex !== undefined && toolIndex !== i && !indicesToRemove.has(toolIndex)) {\n // We need to remove both the AI message and its corresponding tool message\n indicesToRemove.add(i);\n indicesToRemove.add(toolIndex);\n currentTokenCount -= (tokenCounter(msgToRemove) + tokenCounter(context[toolIndex]));\n canRemove = false;\n break;\n }\n }\n }\n }\n \n // If we can remove this message individually\n if (canRemove && !indicesToRemove.has(i)) {\n indicesToRemove.add(i);\n currentTokenCount -= tokenCounter(msgToRemove);\n }\n \n i--;\n }\n \n // Remove messages in reverse order to avoid index shifting\n const sortedIndices = Array.from(indicesToRemove).sort((a, b) => b - a);\n for (const index of sortedIndices) {\n context.splice(index, 1);\n }\n \n // Update remainingContextTokens to reflect the new token count\n remainingContextTokens = maxContextTokens - currentTokenCount;\n }\n }\n }\n }\n \n // If the latest message is an assistant message, ensure an assistant message appears early in the context\n // but maintain system message precedence\n if (latestMessageIsAssistant && context.length > 0) {\n // Find the first assistant message in the context\n const assistantIndex = context.findIndex(msg => msg.getType() === 'ai');\n if (assistantIndex > 0) {\n // Check if there's a system message at the beginning\n const hasSystemFirst = context[0].getType() === 'system';\n \n // Move the assistant message to the appropriate position\n const assistantMsg = context[assistantIndex];\n context.splice(assistantIndex, 1);\n \n if (hasSystemFirst) {\n // Insert after the system message\n context.splice(1, 0, assistantMsg);\n } else {\n // Insert at the beginning if no system message\n context.unshift(assistantMsg);\n }\n }\n }\n }\n }\n\n const prunedMemory = messages;\n summaryIndex = prunedMemory.length - 1;\n remainingContextTokens -= currentTokenCount;\n\n return {\n summaryIndex,\n remainingContextTokens,\n context: context.reverse(),\n messagesToRefine: prunedMemory,\n };\n}\n\nfunction checkValidNumber(value: unknown): value is number {\n return typeof value === 'number' && !isNaN(value) && value > 0;\n}\n\nexport function createPruneMessages(factoryParams: PruneMessagesFactoryParams) {\n const indexTokenCountMap = { ...factoryParams.indexTokenCountMap };\n let lastTurnStartIndex = factoryParams.startIndex;\n let totalTokens = (Object.values(indexTokenCountMap)).reduce((a, b) => a + b, 0);\n \n return function pruneMessages(params: PruneMessagesParams): {\n context: BaseMessage[];\n indexTokenCountMap: Record<string, number>;\n } {\n let currentUsage: UsageMetadata | undefined;\n if (params.usageMetadata && (\n checkValidNumber(params.usageMetadata.input_tokens)\n || (\n checkValidNumber(params.usageMetadata.input_token_details)\n && (\n checkValidNumber(params.usageMetadata.input_token_details.cache_creation)\n || checkValidNumber(params.usageMetadata.input_token_details.cache_read)\n )\n )\n ) && checkValidNumber(params.usageMetadata.output_tokens)) {\n currentUsage = calculateTotalTokens(params.usageMetadata);\n totalTokens = currentUsage.total_tokens;\n }\n\n for (let i = lastTurnStartIndex; i < params.messages.length; i++) {\n const message = params.messages[i];\n if (i === lastTurnStartIndex && indexTokenCountMap[i] === undefined && currentUsage) {\n indexTokenCountMap[i] = currentUsage.output_tokens;\n } else if (indexTokenCountMap[i] === undefined) {\n indexTokenCountMap[i] = factoryParams.tokenCounter(message);\n totalTokens += indexTokenCountMap[i];\n }\n }\n\n // If `currentUsage` is defined, we need to distribute the current total tokensto our `indexTokenCountMap`,\n // for all message index keys before `lastTurnStartIndex`, as it has the most accurate count for those messages.\n // We must distribute it in a weighted manner, so that the total token count is equal to `currentUsage.total_tokens`,\n // relative the manually counted tokens in `indexTokenCountMap`.\n if (currentUsage) {\n const totalIndexTokens = Object.values(indexTokenCountMap).reduce((a, b) => a + b, 0);\n const ratio = currentUsage.total_tokens / totalIndexTokens;\n for (const key in indexTokenCountMap) {\n indexTokenCountMap[key] = Math.round(indexTokenCountMap[key] * ratio);\n }\n }\n\n lastTurnStartIndex = params.messages.length;\n if (totalTokens <= factoryParams.maxTokens) {\n return { context: params.messages, indexTokenCountMap };\n }\n\n // Pass the tokenCounter to getMessagesWithinTokenLimit for token recalculation\n const { context } = getMessagesWithinTokenLimit({\n maxContextTokens: factoryParams.maxTokens,\n messages: params.messages,\n indexTokenCountMap,\n startOnMessageType: params.startOnMessageType,\n thinkingEnabled: factoryParams.thinkingEnabled,\n tokenCounter: factoryParams.tokenCounter,\n });\n\n return { context, indexTokenCountMap };\n }\n}\n"],"names":["messages","AIMessage"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"prune.cjs","sources":["../../../src/messages/prune.ts"],"sourcesContent":["import { AIMessage } from '@langchain/core/messages';\nimport type { BaseMessage, UsageMetadata } from '@langchain/core/messages';\nimport type { TokenCounter } from '@/types/run';\nexport type PruneMessagesFactoryParams = {\n maxTokens: number;\n startIndex: number;\n tokenCounter: TokenCounter;\n indexTokenCountMap: Record<string, number>;\n thinkingEnabled?: boolean;\n};\nexport type PruneMessagesParams = {\n messages: BaseMessage[];\n usageMetadata?: Partial<UsageMetadata>;\n startOnMessageType?: ReturnType<BaseMessage['getType']>;\n}\n\n/**\n * Calculates the total tokens from a single usage object\n * \n * @param usage The usage metadata object containing token information\n * @returns An object containing the total input and output tokens\n */\nfunction calculateTotalTokens(usage: Partial<UsageMetadata>): UsageMetadata {\n const baseInputTokens = Number(usage.input_tokens) || 0;\n const cacheCreation = Number(usage.input_token_details?.cache_creation) || 0;\n const cacheRead = Number(usage.input_token_details?.cache_read) || 0;\n \n const totalInputTokens = baseInputTokens + cacheCreation + cacheRead;\n const totalOutputTokens = Number(usage.output_tokens) || 0;\n\n return {\n input_tokens: totalInputTokens,\n output_tokens: totalOutputTokens,\n total_tokens: totalInputTokens + totalOutputTokens\n };\n}\n\n/**\n * Processes an array of messages and returns a context of messages that fit within a specified token limit.\n * It iterates over the messages from newest to oldest, adding them to the context until the token limit is reached.\n * \n * @param options Configuration options for processing messages\n * @returns Object containing the message context, remaining tokens, messages not included, and summary index\n */\nfunction getMessagesWithinTokenLimit({\n messages: _messages,\n maxContextTokens,\n indexTokenCountMap,\n startOnMessageType,\n thinkingEnabled,\n tokenCounter,\n}: {\n messages: BaseMessage[];\n maxContextTokens: number;\n indexTokenCountMap: Record<string, number>;\n startOnMessageType?: string;\n thinkingEnabled?: boolean;\n tokenCounter?: TokenCounter;\n}): {\n context: BaseMessage[];\n remainingContextTokens: number;\n messagesToRefine: BaseMessage[];\n summaryIndex: number;\n} {\n // Every reply is primed with <|start|>assistant<|message|>, so we\n // start with 3 tokens for the label after all messages have been counted.\n let summaryIndex = -1;\n let currentTokenCount = 3;\n const instructions = _messages?.[0]?.getType() === 'system' ? _messages[0] : undefined;\n const instructionsTokenCount = instructions != null ? indexTokenCountMap[0] : 0;\n let remainingContextTokens = maxContextTokens - instructionsTokenCount;\n const messages = [..._messages];\n let context: BaseMessage[] = [];\n\n if (currentTokenCount < remainingContextTokens) {\n let currentIndex = messages.length;\n while (messages.length > 0 && currentTokenCount < remainingContextTokens && currentIndex > 1) {\n currentIndex--;\n if (messages.length === 1 && instructions) {\n break;\n }\n const poppedMessage = messages.pop();\n if (!poppedMessage) continue;\n \n const tokenCount = indexTokenCountMap[currentIndex] || 0;\n\n if ((currentTokenCount + tokenCount) <= remainingContextTokens) {\n context.push(poppedMessage);\n currentTokenCount += tokenCount;\n } else {\n messages.push(poppedMessage);\n break;\n }\n }\n \n // Handle startOnMessageType requirement\n if (startOnMessageType && context.length > 0) {\n const requiredTypeIndex = context.findIndex(msg => msg.getType() === startOnMessageType);\n \n if (requiredTypeIndex > 0) {\n context = context.slice(requiredTypeIndex);\n }\n }\n \n // Add system message if it exists\n if (instructions && _messages.length > 0) {\n context.push(_messages[0] as BaseMessage);\n messages.shift();\n }\n \n // Handle thinking mode requirement for Anthropic\n if (thinkingEnabled && context.length > 0 && tokenCounter) {\n // Check if the latest message is an assistant message\n const latestMessageIsAssistant = _messages.length > 0 && _messages[_messages.length - 1].getType() === 'ai';\n \n // Process only if we have an assistant message in the context\n const firstAssistantIndex = context.findIndex(msg => msg.getType() === 'ai');\n \n if (firstAssistantIndex >= 0) {\n const firstAssistantMsg = context[firstAssistantIndex];\n \n // Check if the first assistant message already has a thinking block\n const hasThinkingBlock = Array.isArray(firstAssistantMsg.content) && \n firstAssistantMsg.content.some(item => \n item && typeof item === 'object' && item.type === 'thinking');\n \n // Only proceed if we need to add thinking blocks\n if (!hasThinkingBlock) {\n // Collect thinking blocks from pruned assistant messages, starting from the most recent\n const thinkingBlocks: any[] = [];\n \n // Look through pruned messages for thinking blocks, starting from the end (most recent)\n for (let i = messages.length - 1; i >= 0; i--) {\n const msg = messages[i];\n if (msg.getType() === 'ai' && Array.isArray(msg.content)) {\n for (const item of msg.content) {\n if (item && typeof item === 'object' && item.type === 'thinking') {\n thinkingBlocks.push(item);\n // We only need one thinking block\n break;\n }\n }\n if (thinkingBlocks.length > 0) break; // Stop after finding one thinking block\n }\n }\n \n // If we found thinking blocks, add them to the first assistant message\n if (thinkingBlocks.length > 0) {\n // Calculate token count of original message\n const originalTokenCount = tokenCounter(firstAssistantMsg);\n \n // Create a new content array with thinking blocks at the beginning\n let newContent: any[];\n \n if (Array.isArray(firstAssistantMsg.content)) {\n // Keep the original content (excluding any existing thinking blocks)\n const originalContent = firstAssistantMsg.content.filter(item => \n !(item && typeof item === 'object' && item.type === 'thinking'));\n \n newContent = [...thinkingBlocks, ...originalContent];\n } else if (typeof firstAssistantMsg.content === 'string') {\n newContent = [\n ...thinkingBlocks,\n { type: 'text', text: firstAssistantMsg.content }\n ];\n } else {\n newContent = thinkingBlocks;\n }\n \n // Create a new message with the updated content\n const newMessage = new AIMessage({\n content: newContent,\n additional_kwargs: firstAssistantMsg.additional_kwargs,\n response_metadata: firstAssistantMsg.response_metadata,\n });\n \n // Calculate token count of new message\n const newTokenCount = tokenCounter(newMessage);\n \n // Adjust current token count\n currentTokenCount += (newTokenCount - originalTokenCount);\n \n // Replace the first assistant message\n context[firstAssistantIndex] = newMessage;\n \n // If we've exceeded the token limit, we need to prune more messages\n if (currentTokenCount > remainingContextTokens) {\n // Build a map of tool call IDs to track AI <--> tool message correspondences\n const toolCallIdMap = new Map<string, number>();\n \n // Identify tool call IDs in the context\n for (let i = 0; i < context.length; i++) {\n const msg = context[i];\n \n // Check for tool calls in AI messages\n if (msg.getType() === 'ai' && Array.isArray(msg.content)) {\n for (const item of msg.content) {\n if (item && typeof item === 'object' && item.type === 'tool_use' && item.id) {\n toolCallIdMap.set(item.id, i);\n }\n }\n }\n \n // Check for tool messages\n if (msg.getType() === 'tool' && 'tool_call_id' in msg && typeof msg.tool_call_id === 'string') {\n toolCallIdMap.set(msg.tool_call_id, i);\n }\n }\n \n // Track which messages to remove\n const indicesToRemove = new Set<number>();\n \n // Start removing messages from the end, but preserve AI <--> tool message correspondences\n let i = context.length - 1;\n while (i > firstAssistantIndex && currentTokenCount > remainingContextTokens) {\n const msgToRemove = context[i];\n \n // Check if this is a tool message or has tool calls\n let canRemove = true;\n \n if (msgToRemove.getType() === 'tool' && 'tool_call_id' in msgToRemove && typeof msgToRemove.tool_call_id === 'string') {\n // If this is a tool message, check if we need to keep its corresponding AI message\n const aiIndex = toolCallIdMap.get(msgToRemove.tool_call_id);\n if (aiIndex !== undefined && aiIndex !== i && !indicesToRemove.has(aiIndex)) {\n // We need to remove both the tool message and its corresponding AI message\n indicesToRemove.add(i);\n indicesToRemove.add(aiIndex);\n currentTokenCount -= (tokenCounter(msgToRemove) + tokenCounter(context[aiIndex]));\n canRemove = false;\n }\n } else if (msgToRemove.getType() === 'ai' && Array.isArray(msgToRemove.content)) {\n // If this is an AI message with tool calls, check if we need to keep its corresponding tool messages\n for (const item of msgToRemove.content) {\n if (item && typeof item === 'object' && item.type === 'tool_use' && item.id) {\n const toolIndex = toolCallIdMap.get(item.id as string);\n if (toolIndex !== undefined && toolIndex !== i && !indicesToRemove.has(toolIndex)) {\n // We need to remove both the AI message and its corresponding tool message\n indicesToRemove.add(i);\n indicesToRemove.add(toolIndex);\n currentTokenCount -= (tokenCounter(msgToRemove) + tokenCounter(context[toolIndex]));\n canRemove = false;\n break;\n }\n }\n }\n }\n \n // If we can remove this message individually\n if (canRemove && !indicesToRemove.has(i)) {\n indicesToRemove.add(i);\n currentTokenCount -= tokenCounter(msgToRemove);\n }\n \n i--;\n }\n \n // Remove messages in reverse order to avoid index shifting\n const sortedIndices = Array.from(indicesToRemove).sort((a, b) => b - a);\n for (const index of sortedIndices) {\n context.splice(index, 1);\n }\n \n // Update remainingContextTokens to reflect the new token count\n remainingContextTokens = maxContextTokens - currentTokenCount;\n }\n }\n }\n }\n \n // If the latest message is an assistant message, ensure an assistant message with thinking appears at the end\n // of the context (which will become the beginning after reversal)\n // but maintain system message precedence after reversal\n if (latestMessageIsAssistant && context.length > 0) {\n // Find assistant messages with thinking blocks\n const assistantIndices: number[] = [];\n for (let i = 0; i < context.length; i++) {\n const msg = context[i];\n if (msg.getType() === 'ai') {\n const hasThinking = Array.isArray(msg.content) && \n msg.content.some(item => item && typeof item === 'object' && item.type === 'thinking');\n \n if (hasThinking) {\n assistantIndices.push(i);\n }\n }\n }\n \n // If we found assistant messages with thinking blocks\n if (assistantIndices.length > 0) {\n // Get the first assistant message with thinking\n const assistantWithThinkingIndex = assistantIndices[0];\n const assistantWithThinking = context[assistantWithThinkingIndex];\n \n // Remove it from its current position\n context.splice(assistantWithThinkingIndex, 1);\n \n // Check if there's a system message in the context\n const systemIndex = context.findIndex(msg => msg.getType() === 'system');\n const hasSystem = systemIndex !== -1;\n \n if (hasSystem) {\n // We want the system message to be first after reversal\n // This means we need to put it at the end position before reversal\n // And the assistant message should be second after reversal\n // This means we need to put it at the end - 1 position before reversal\n \n // First, ensure the system message is at the end (will be first after reversal)\n const systemMsg = context[systemIndex];\n context.splice(systemIndex, 1);\n context.push(systemMsg);\n \n // Then, put the assistant message right before the system message (will be second after reversal)\n context.splice(context.length - 1, 0, assistantWithThinking);\n } else {\n // No system message, so we want assistant to be first after reversal\n // This means we need to put it at the end position before reversal\n context.push(assistantWithThinking);\n }\n }\n }\n }\n }\n\n const prunedMemory = messages;\n summaryIndex = prunedMemory.length - 1;\n remainingContextTokens -= currentTokenCount;\n\n return {\n summaryIndex,\n remainingContextTokens,\n context: context.reverse(),\n messagesToRefine: prunedMemory,\n };\n}\n\nfunction checkValidNumber(value: unknown): value is number {\n return typeof value === 'number' && !isNaN(value) && value > 0;\n}\n\nexport function createPruneMessages(factoryParams: PruneMessagesFactoryParams) {\n const indexTokenCountMap = { ...factoryParams.indexTokenCountMap };\n let lastTurnStartIndex = factoryParams.startIndex;\n let totalTokens = (Object.values(indexTokenCountMap)).reduce((a, b) => a + b, 0);\n \n return function pruneMessages(params: PruneMessagesParams): {\n context: BaseMessage[];\n indexTokenCountMap: Record<string, number>;\n } {\n let currentUsage: UsageMetadata | undefined;\n if (params.usageMetadata && (\n checkValidNumber(params.usageMetadata.input_tokens)\n || (\n checkValidNumber(params.usageMetadata.input_token_details)\n && (\n checkValidNumber(params.usageMetadata.input_token_details.cache_creation)\n || checkValidNumber(params.usageMetadata.input_token_details.cache_read)\n )\n )\n ) && checkValidNumber(params.usageMetadata.output_tokens)) {\n currentUsage = calculateTotalTokens(params.usageMetadata);\n totalTokens = currentUsage.total_tokens;\n }\n\n for (let i = lastTurnStartIndex; i < params.messages.length; i++) {\n const message = params.messages[i];\n if (i === lastTurnStartIndex && indexTokenCountMap[i] === undefined && currentUsage) {\n indexTokenCountMap[i] = currentUsage.output_tokens;\n } else if (indexTokenCountMap[i] === undefined) {\n indexTokenCountMap[i] = factoryParams.tokenCounter(message);\n totalTokens += indexTokenCountMap[i];\n }\n }\n\n // If `currentUsage` is defined, we need to distribute the current total tokensto our `indexTokenCountMap`,\n // for all message index keys before `lastTurnStartIndex`, as it has the most accurate count for those messages.\n // We must distribute it in a weighted manner, so that the total token count is equal to `currentUsage.total_tokens`,\n // relative the manually counted tokens in `indexTokenCountMap`.\n if (currentUsage) {\n const totalIndexTokens = Object.values(indexTokenCountMap).reduce((a, b) => a + b, 0);\n const ratio = currentUsage.total_tokens / totalIndexTokens;\n for (const key in indexTokenCountMap) {\n indexTokenCountMap[key] = Math.round(indexTokenCountMap[key] * ratio);\n }\n }\n\n lastTurnStartIndex = params.messages.length;\n if (totalTokens <= factoryParams.maxTokens) {\n return { context: params.messages, indexTokenCountMap };\n }\n\n // Pass the tokenCounter to getMessagesWithinTokenLimit for token recalculation\n const { context } = getMessagesWithinTokenLimit({\n maxContextTokens: factoryParams.maxTokens,\n messages: params.messages,\n indexTokenCountMap,\n startOnMessageType: params.startOnMessageType,\n thinkingEnabled: factoryParams.thinkingEnabled,\n tokenCounter: factoryParams.tokenCounter,\n });\n\n return { context, indexTokenCountMap };\n }\n}\n"],"names":["messages","AIMessage"],"mappings":"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"}
|
|
@@ -202,24 +202,48 @@ function getMessagesWithinTokenLimit({ messages: _messages, maxContextTokens, in
|
|
|
202
202
|
}
|
|
203
203
|
}
|
|
204
204
|
}
|
|
205
|
-
// If the latest message is an assistant message, ensure an assistant message appears
|
|
206
|
-
//
|
|
205
|
+
// If the latest message is an assistant message, ensure an assistant message with thinking appears at the end
|
|
206
|
+
// of the context (which will become the beginning after reversal)
|
|
207
|
+
// but maintain system message precedence after reversal
|
|
207
208
|
if (latestMessageIsAssistant && context.length > 0) {
|
|
208
|
-
// Find
|
|
209
|
-
const
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
209
|
+
// Find assistant messages with thinking blocks
|
|
210
|
+
const assistantIndices = [];
|
|
211
|
+
for (let i = 0; i < context.length; i++) {
|
|
212
|
+
const msg = context[i];
|
|
213
|
+
if (msg.getType() === 'ai') {
|
|
214
|
+
const hasThinking = Array.isArray(msg.content) &&
|
|
215
|
+
msg.content.some(item => item && typeof item === 'object' && item.type === 'thinking');
|
|
216
|
+
if (hasThinking) {
|
|
217
|
+
assistantIndices.push(i);
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
// If we found assistant messages with thinking blocks
|
|
222
|
+
if (assistantIndices.length > 0) {
|
|
223
|
+
// Get the first assistant message with thinking
|
|
224
|
+
const assistantWithThinkingIndex = assistantIndices[0];
|
|
225
|
+
const assistantWithThinking = context[assistantWithThinkingIndex];
|
|
226
|
+
// Remove it from its current position
|
|
227
|
+
context.splice(assistantWithThinkingIndex, 1);
|
|
228
|
+
// Check if there's a system message in the context
|
|
229
|
+
const systemIndex = context.findIndex(msg => msg.getType() === 'system');
|
|
230
|
+
const hasSystem = systemIndex !== -1;
|
|
231
|
+
if (hasSystem) {
|
|
232
|
+
// We want the system message to be first after reversal
|
|
233
|
+
// This means we need to put it at the end position before reversal
|
|
234
|
+
// And the assistant message should be second after reversal
|
|
235
|
+
// This means we need to put it at the end - 1 position before reversal
|
|
236
|
+
// First, ensure the system message is at the end (will be first after reversal)
|
|
237
|
+
const systemMsg = context[systemIndex];
|
|
238
|
+
context.splice(systemIndex, 1);
|
|
239
|
+
context.push(systemMsg);
|
|
240
|
+
// Then, put the assistant message right before the system message (will be second after reversal)
|
|
241
|
+
context.splice(context.length - 1, 0, assistantWithThinking);
|
|
219
242
|
}
|
|
220
243
|
else {
|
|
221
|
-
//
|
|
222
|
-
|
|
244
|
+
// No system message, so we want assistant to be first after reversal
|
|
245
|
+
// This means we need to put it at the end position before reversal
|
|
246
|
+
context.push(assistantWithThinking);
|
|
223
247
|
}
|
|
224
248
|
}
|
|
225
249
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"prune.mjs","sources":["../../../src/messages/prune.ts"],"sourcesContent":["import { AIMessage } from '@langchain/core/messages';\nimport type { BaseMessage, UsageMetadata } from '@langchain/core/messages';\nimport type { TokenCounter } from '@/types/run';\nexport type PruneMessagesFactoryParams = {\n maxTokens: number;\n startIndex: number;\n tokenCounter: TokenCounter;\n indexTokenCountMap: Record<string, number>;\n thinkingEnabled?: boolean;\n};\nexport type PruneMessagesParams = {\n messages: BaseMessage[];\n usageMetadata?: Partial<UsageMetadata>;\n startOnMessageType?: ReturnType<BaseMessage['getType']>;\n}\n\n/**\n * Calculates the total tokens from a single usage object\n * \n * @param usage The usage metadata object containing token information\n * @returns An object containing the total input and output tokens\n */\nfunction calculateTotalTokens(usage: Partial<UsageMetadata>): UsageMetadata {\n const baseInputTokens = Number(usage.input_tokens) || 0;\n const cacheCreation = Number(usage.input_token_details?.cache_creation) || 0;\n const cacheRead = Number(usage.input_token_details?.cache_read) || 0;\n \n const totalInputTokens = baseInputTokens + cacheCreation + cacheRead;\n const totalOutputTokens = Number(usage.output_tokens) || 0;\n\n return {\n input_tokens: totalInputTokens,\n output_tokens: totalOutputTokens,\n total_tokens: totalInputTokens + totalOutputTokens\n };\n}\n\n/**\n * Processes an array of messages and returns a context of messages that fit within a specified token limit.\n * It iterates over the messages from newest to oldest, adding them to the context until the token limit is reached.\n * \n * @param options Configuration options for processing messages\n * @returns Object containing the message context, remaining tokens, messages not included, and summary index\n */\nfunction getMessagesWithinTokenLimit({\n messages: _messages,\n maxContextTokens,\n indexTokenCountMap,\n startOnMessageType,\n thinkingEnabled,\n tokenCounter,\n}: {\n messages: BaseMessage[];\n maxContextTokens: number;\n indexTokenCountMap: Record<string, number>;\n startOnMessageType?: string;\n thinkingEnabled?: boolean;\n tokenCounter?: TokenCounter;\n}): {\n context: BaseMessage[];\n remainingContextTokens: number;\n messagesToRefine: BaseMessage[];\n summaryIndex: number;\n} {\n // Every reply is primed with <|start|>assistant<|message|>, so we\n // start with 3 tokens for the label after all messages have been counted.\n let summaryIndex = -1;\n let currentTokenCount = 3;\n const instructions = _messages?.[0]?.getType() === 'system' ? _messages[0] : undefined;\n const instructionsTokenCount = instructions != null ? indexTokenCountMap[0] : 0;\n let remainingContextTokens = maxContextTokens - instructionsTokenCount;\n const messages = [..._messages];\n let context: BaseMessage[] = [];\n\n if (currentTokenCount < remainingContextTokens) {\n let currentIndex = messages.length;\n while (messages.length > 0 && currentTokenCount < remainingContextTokens && currentIndex > 1) {\n currentIndex--;\n if (messages.length === 1 && instructions) {\n break;\n }\n const poppedMessage = messages.pop();\n if (!poppedMessage) continue;\n \n const tokenCount = indexTokenCountMap[currentIndex] || 0;\n\n if ((currentTokenCount + tokenCount) <= remainingContextTokens) {\n context.push(poppedMessage);\n currentTokenCount += tokenCount;\n } else {\n messages.push(poppedMessage);\n break;\n }\n }\n \n // Handle startOnMessageType requirement\n if (startOnMessageType && context.length > 0) {\n const requiredTypeIndex = context.findIndex(msg => msg.getType() === startOnMessageType);\n \n if (requiredTypeIndex > 0) {\n context = context.slice(requiredTypeIndex);\n }\n }\n \n // Add system message if it exists\n if (instructions && _messages.length > 0) {\n context.push(_messages[0] as BaseMessage);\n messages.shift();\n }\n \n // Handle thinking mode requirement for Anthropic\n if (thinkingEnabled && context.length > 0 && tokenCounter) {\n // Check if the latest message is an assistant message\n const latestMessageIsAssistant = _messages.length > 0 && _messages[_messages.length - 1].getType() === 'ai';\n \n // Process only if we have an assistant message in the context\n const firstAssistantIndex = context.findIndex(msg => msg.getType() === 'ai');\n \n if (firstAssistantIndex >= 0) {\n const firstAssistantMsg = context[firstAssistantIndex];\n \n // Check if the first assistant message already has a thinking block\n const hasThinkingBlock = Array.isArray(firstAssistantMsg.content) && \n firstAssistantMsg.content.some(item => \n item && typeof item === 'object' && item.type === 'thinking');\n \n // Only proceed if we need to add thinking blocks\n if (!hasThinkingBlock) {\n // Collect thinking blocks from pruned assistant messages, starting from the most recent\n const thinkingBlocks: any[] = [];\n \n // Look through pruned messages for thinking blocks, starting from the end (most recent)\n for (let i = messages.length - 1; i >= 0; i--) {\n const msg = messages[i];\n if (msg.getType() === 'ai' && Array.isArray(msg.content)) {\n for (const item of msg.content) {\n if (item && typeof item === 'object' && item.type === 'thinking') {\n thinkingBlocks.push(item);\n // We only need one thinking block\n break;\n }\n }\n if (thinkingBlocks.length > 0) break; // Stop after finding one thinking block\n }\n }\n \n // If we found thinking blocks, add them to the first assistant message\n if (thinkingBlocks.length > 0) {\n // Calculate token count of original message\n const originalTokenCount = tokenCounter(firstAssistantMsg);\n \n // Create a new content array with thinking blocks at the beginning\n let newContent: any[];\n \n if (Array.isArray(firstAssistantMsg.content)) {\n // Keep the original content (excluding any existing thinking blocks)\n const originalContent = firstAssistantMsg.content.filter(item => \n !(item && typeof item === 'object' && item.type === 'thinking'));\n \n newContent = [...thinkingBlocks, ...originalContent];\n } else if (typeof firstAssistantMsg.content === 'string') {\n newContent = [\n ...thinkingBlocks,\n { type: 'text', text: firstAssistantMsg.content }\n ];\n } else {\n newContent = thinkingBlocks;\n }\n \n // Create a new message with the updated content\n const newMessage = new AIMessage({\n content: newContent,\n additional_kwargs: firstAssistantMsg.additional_kwargs,\n response_metadata: firstAssistantMsg.response_metadata,\n });\n \n // Calculate token count of new message\n const newTokenCount = tokenCounter(newMessage);\n \n // Adjust current token count\n currentTokenCount += (newTokenCount - originalTokenCount);\n \n // Replace the first assistant message\n context[firstAssistantIndex] = newMessage;\n \n // If we've exceeded the token limit, we need to prune more messages\n if (currentTokenCount > remainingContextTokens) {\n // Build a map of tool call IDs to track AI <--> tool message correspondences\n const toolCallIdMap = new Map<string, number>();\n \n // Identify tool call IDs in the context\n for (let i = 0; i < context.length; i++) {\n const msg = context[i];\n \n // Check for tool calls in AI messages\n if (msg.getType() === 'ai' && Array.isArray(msg.content)) {\n for (const item of msg.content) {\n if (item && typeof item === 'object' && item.type === 'tool_use' && item.id) {\n toolCallIdMap.set(item.id, i);\n }\n }\n }\n \n // Check for tool messages\n if (msg.getType() === 'tool' && 'tool_call_id' in msg && typeof msg.tool_call_id === 'string') {\n toolCallIdMap.set(msg.tool_call_id, i);\n }\n }\n \n // Track which messages to remove\n const indicesToRemove = new Set<number>();\n \n // Start removing messages from the end, but preserve AI <--> tool message correspondences\n let i = context.length - 1;\n while (i > firstAssistantIndex && currentTokenCount > remainingContextTokens) {\n const msgToRemove = context[i];\n \n // Check if this is a tool message or has tool calls\n let canRemove = true;\n \n if (msgToRemove.getType() === 'tool' && 'tool_call_id' in msgToRemove && typeof msgToRemove.tool_call_id === 'string') {\n // If this is a tool message, check if we need to keep its corresponding AI message\n const aiIndex = toolCallIdMap.get(msgToRemove.tool_call_id);\n if (aiIndex !== undefined && aiIndex !== i && !indicesToRemove.has(aiIndex)) {\n // We need to remove both the tool message and its corresponding AI message\n indicesToRemove.add(i);\n indicesToRemove.add(aiIndex);\n currentTokenCount -= (tokenCounter(msgToRemove) + tokenCounter(context[aiIndex]));\n canRemove = false;\n }\n } else if (msgToRemove.getType() === 'ai' && Array.isArray(msgToRemove.content)) {\n // If this is an AI message with tool calls, check if we need to keep its corresponding tool messages\n for (const item of msgToRemove.content) {\n if (item && typeof item === 'object' && item.type === 'tool_use' && item.id) {\n const toolIndex = toolCallIdMap.get(item.id as string);\n if (toolIndex !== undefined && toolIndex !== i && !indicesToRemove.has(toolIndex)) {\n // We need to remove both the AI message and its corresponding tool message\n indicesToRemove.add(i);\n indicesToRemove.add(toolIndex);\n currentTokenCount -= (tokenCounter(msgToRemove) + tokenCounter(context[toolIndex]));\n canRemove = false;\n break;\n }\n }\n }\n }\n \n // If we can remove this message individually\n if (canRemove && !indicesToRemove.has(i)) {\n indicesToRemove.add(i);\n currentTokenCount -= tokenCounter(msgToRemove);\n }\n \n i--;\n }\n \n // Remove messages in reverse order to avoid index shifting\n const sortedIndices = Array.from(indicesToRemove).sort((a, b) => b - a);\n for (const index of sortedIndices) {\n context.splice(index, 1);\n }\n \n // Update remainingContextTokens to reflect the new token count\n remainingContextTokens = maxContextTokens - currentTokenCount;\n }\n }\n }\n }\n \n // If the latest message is an assistant message, ensure an assistant message appears early in the context\n // but maintain system message precedence\n if (latestMessageIsAssistant && context.length > 0) {\n // Find the first assistant message in the context\n const assistantIndex = context.findIndex(msg => msg.getType() === 'ai');\n if (assistantIndex > 0) {\n // Check if there's a system message at the beginning\n const hasSystemFirst = context[0].getType() === 'system';\n \n // Move the assistant message to the appropriate position\n const assistantMsg = context[assistantIndex];\n context.splice(assistantIndex, 1);\n \n if (hasSystemFirst) {\n // Insert after the system message\n context.splice(1, 0, assistantMsg);\n } else {\n // Insert at the beginning if no system message\n context.unshift(assistantMsg);\n }\n }\n }\n }\n }\n\n const prunedMemory = messages;\n summaryIndex = prunedMemory.length - 1;\n remainingContextTokens -= currentTokenCount;\n\n return {\n summaryIndex,\n remainingContextTokens,\n context: context.reverse(),\n messagesToRefine: prunedMemory,\n };\n}\n\nfunction checkValidNumber(value: unknown): value is number {\n return typeof value === 'number' && !isNaN(value) && value > 0;\n}\n\nexport function createPruneMessages(factoryParams: PruneMessagesFactoryParams) {\n const indexTokenCountMap = { ...factoryParams.indexTokenCountMap };\n let lastTurnStartIndex = factoryParams.startIndex;\n let totalTokens = (Object.values(indexTokenCountMap)).reduce((a, b) => a + b, 0);\n \n return function pruneMessages(params: PruneMessagesParams): {\n context: BaseMessage[];\n indexTokenCountMap: Record<string, number>;\n } {\n let currentUsage: UsageMetadata | undefined;\n if (params.usageMetadata && (\n checkValidNumber(params.usageMetadata.input_tokens)\n || (\n checkValidNumber(params.usageMetadata.input_token_details)\n && (\n checkValidNumber(params.usageMetadata.input_token_details.cache_creation)\n || checkValidNumber(params.usageMetadata.input_token_details.cache_read)\n )\n )\n ) && checkValidNumber(params.usageMetadata.output_tokens)) {\n currentUsage = calculateTotalTokens(params.usageMetadata);\n totalTokens = currentUsage.total_tokens;\n }\n\n for (let i = lastTurnStartIndex; i < params.messages.length; i++) {\n const message = params.messages[i];\n if (i === lastTurnStartIndex && indexTokenCountMap[i] === undefined && currentUsage) {\n indexTokenCountMap[i] = currentUsage.output_tokens;\n } else if (indexTokenCountMap[i] === undefined) {\n indexTokenCountMap[i] = factoryParams.tokenCounter(message);\n totalTokens += indexTokenCountMap[i];\n }\n }\n\n // If `currentUsage` is defined, we need to distribute the current total tokensto our `indexTokenCountMap`,\n // for all message index keys before `lastTurnStartIndex`, as it has the most accurate count for those messages.\n // We must distribute it in a weighted manner, so that the total token count is equal to `currentUsage.total_tokens`,\n // relative the manually counted tokens in `indexTokenCountMap`.\n if (currentUsage) {\n const totalIndexTokens = Object.values(indexTokenCountMap).reduce((a, b) => a + b, 0);\n const ratio = currentUsage.total_tokens / totalIndexTokens;\n for (const key in indexTokenCountMap) {\n indexTokenCountMap[key] = Math.round(indexTokenCountMap[key] * ratio);\n }\n }\n\n lastTurnStartIndex = params.messages.length;\n if (totalTokens <= factoryParams.maxTokens) {\n return { context: params.messages, indexTokenCountMap };\n }\n\n // Pass the tokenCounter to getMessagesWithinTokenLimit for token recalculation\n const { context } = getMessagesWithinTokenLimit({\n maxContextTokens: factoryParams.maxTokens,\n messages: params.messages,\n indexTokenCountMap,\n startOnMessageType: params.startOnMessageType,\n thinkingEnabled: factoryParams.thinkingEnabled,\n tokenCounter: factoryParams.tokenCounter,\n });\n\n return { context, indexTokenCountMap };\n }\n}\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"prune.mjs","sources":["../../../src/messages/prune.ts"],"sourcesContent":["import { AIMessage } from '@langchain/core/messages';\nimport type { BaseMessage, UsageMetadata } from '@langchain/core/messages';\nimport type { TokenCounter } from '@/types/run';\nexport type PruneMessagesFactoryParams = {\n maxTokens: number;\n startIndex: number;\n tokenCounter: TokenCounter;\n indexTokenCountMap: Record<string, number>;\n thinkingEnabled?: boolean;\n};\nexport type PruneMessagesParams = {\n messages: BaseMessage[];\n usageMetadata?: Partial<UsageMetadata>;\n startOnMessageType?: ReturnType<BaseMessage['getType']>;\n}\n\n/**\n * Calculates the total tokens from a single usage object\n * \n * @param usage The usage metadata object containing token information\n * @returns An object containing the total input and output tokens\n */\nfunction calculateTotalTokens(usage: Partial<UsageMetadata>): UsageMetadata {\n const baseInputTokens = Number(usage.input_tokens) || 0;\n const cacheCreation = Number(usage.input_token_details?.cache_creation) || 0;\n const cacheRead = Number(usage.input_token_details?.cache_read) || 0;\n \n const totalInputTokens = baseInputTokens + cacheCreation + cacheRead;\n const totalOutputTokens = Number(usage.output_tokens) || 0;\n\n return {\n input_tokens: totalInputTokens,\n output_tokens: totalOutputTokens,\n total_tokens: totalInputTokens + totalOutputTokens\n };\n}\n\n/**\n * Processes an array of messages and returns a context of messages that fit within a specified token limit.\n * It iterates over the messages from newest to oldest, adding them to the context until the token limit is reached.\n * \n * @param options Configuration options for processing messages\n * @returns Object containing the message context, remaining tokens, messages not included, and summary index\n */\nfunction getMessagesWithinTokenLimit({\n messages: _messages,\n maxContextTokens,\n indexTokenCountMap,\n startOnMessageType,\n thinkingEnabled,\n tokenCounter,\n}: {\n messages: BaseMessage[];\n maxContextTokens: number;\n indexTokenCountMap: Record<string, number>;\n startOnMessageType?: string;\n thinkingEnabled?: boolean;\n tokenCounter?: TokenCounter;\n}): {\n context: BaseMessage[];\n remainingContextTokens: number;\n messagesToRefine: BaseMessage[];\n summaryIndex: number;\n} {\n // Every reply is primed with <|start|>assistant<|message|>, so we\n // start with 3 tokens for the label after all messages have been counted.\n let summaryIndex = -1;\n let currentTokenCount = 3;\n const instructions = _messages?.[0]?.getType() === 'system' ? _messages[0] : undefined;\n const instructionsTokenCount = instructions != null ? indexTokenCountMap[0] : 0;\n let remainingContextTokens = maxContextTokens - instructionsTokenCount;\n const messages = [..._messages];\n let context: BaseMessage[] = [];\n\n if (currentTokenCount < remainingContextTokens) {\n let currentIndex = messages.length;\n while (messages.length > 0 && currentTokenCount < remainingContextTokens && currentIndex > 1) {\n currentIndex--;\n if (messages.length === 1 && instructions) {\n break;\n }\n const poppedMessage = messages.pop();\n if (!poppedMessage) continue;\n \n const tokenCount = indexTokenCountMap[currentIndex] || 0;\n\n if ((currentTokenCount + tokenCount) <= remainingContextTokens) {\n context.push(poppedMessage);\n currentTokenCount += tokenCount;\n } else {\n messages.push(poppedMessage);\n break;\n }\n }\n \n // Handle startOnMessageType requirement\n if (startOnMessageType && context.length > 0) {\n const requiredTypeIndex = context.findIndex(msg => msg.getType() === startOnMessageType);\n \n if (requiredTypeIndex > 0) {\n context = context.slice(requiredTypeIndex);\n }\n }\n \n // Add system message if it exists\n if (instructions && _messages.length > 0) {\n context.push(_messages[0] as BaseMessage);\n messages.shift();\n }\n \n // Handle thinking mode requirement for Anthropic\n if (thinkingEnabled && context.length > 0 && tokenCounter) {\n // Check if the latest message is an assistant message\n const latestMessageIsAssistant = _messages.length > 0 && _messages[_messages.length - 1].getType() === 'ai';\n \n // Process only if we have an assistant message in the context\n const firstAssistantIndex = context.findIndex(msg => msg.getType() === 'ai');\n \n if (firstAssistantIndex >= 0) {\n const firstAssistantMsg = context[firstAssistantIndex];\n \n // Check if the first assistant message already has a thinking block\n const hasThinkingBlock = Array.isArray(firstAssistantMsg.content) && \n firstAssistantMsg.content.some(item => \n item && typeof item === 'object' && item.type === 'thinking');\n \n // Only proceed if we need to add thinking blocks\n if (!hasThinkingBlock) {\n // Collect thinking blocks from pruned assistant messages, starting from the most recent\n const thinkingBlocks: any[] = [];\n \n // Look through pruned messages for thinking blocks, starting from the end (most recent)\n for (let i = messages.length - 1; i >= 0; i--) {\n const msg = messages[i];\n if (msg.getType() === 'ai' && Array.isArray(msg.content)) {\n for (const item of msg.content) {\n if (item && typeof item === 'object' && item.type === 'thinking') {\n thinkingBlocks.push(item);\n // We only need one thinking block\n break;\n }\n }\n if (thinkingBlocks.length > 0) break; // Stop after finding one thinking block\n }\n }\n \n // If we found thinking blocks, add them to the first assistant message\n if (thinkingBlocks.length > 0) {\n // Calculate token count of original message\n const originalTokenCount = tokenCounter(firstAssistantMsg);\n \n // Create a new content array with thinking blocks at the beginning\n let newContent: any[];\n \n if (Array.isArray(firstAssistantMsg.content)) {\n // Keep the original content (excluding any existing thinking blocks)\n const originalContent = firstAssistantMsg.content.filter(item => \n !(item && typeof item === 'object' && item.type === 'thinking'));\n \n newContent = [...thinkingBlocks, ...originalContent];\n } else if (typeof firstAssistantMsg.content === 'string') {\n newContent = [\n ...thinkingBlocks,\n { type: 'text', text: firstAssistantMsg.content }\n ];\n } else {\n newContent = thinkingBlocks;\n }\n \n // Create a new message with the updated content\n const newMessage = new AIMessage({\n content: newContent,\n additional_kwargs: firstAssistantMsg.additional_kwargs,\n response_metadata: firstAssistantMsg.response_metadata,\n });\n \n // Calculate token count of new message\n const newTokenCount = tokenCounter(newMessage);\n \n // Adjust current token count\n currentTokenCount += (newTokenCount - originalTokenCount);\n \n // Replace the first assistant message\n context[firstAssistantIndex] = newMessage;\n \n // If we've exceeded the token limit, we need to prune more messages\n if (currentTokenCount > remainingContextTokens) {\n // Build a map of tool call IDs to track AI <--> tool message correspondences\n const toolCallIdMap = new Map<string, number>();\n \n // Identify tool call IDs in the context\n for (let i = 0; i < context.length; i++) {\n const msg = context[i];\n \n // Check for tool calls in AI messages\n if (msg.getType() === 'ai' && Array.isArray(msg.content)) {\n for (const item of msg.content) {\n if (item && typeof item === 'object' && item.type === 'tool_use' && item.id) {\n toolCallIdMap.set(item.id, i);\n }\n }\n }\n \n // Check for tool messages\n if (msg.getType() === 'tool' && 'tool_call_id' in msg && typeof msg.tool_call_id === 'string') {\n toolCallIdMap.set(msg.tool_call_id, i);\n }\n }\n \n // Track which messages to remove\n const indicesToRemove = new Set<number>();\n \n // Start removing messages from the end, but preserve AI <--> tool message correspondences\n let i = context.length - 1;\n while (i > firstAssistantIndex && currentTokenCount > remainingContextTokens) {\n const msgToRemove = context[i];\n \n // Check if this is a tool message or has tool calls\n let canRemove = true;\n \n if (msgToRemove.getType() === 'tool' && 'tool_call_id' in msgToRemove && typeof msgToRemove.tool_call_id === 'string') {\n // If this is a tool message, check if we need to keep its corresponding AI message\n const aiIndex = toolCallIdMap.get(msgToRemove.tool_call_id);\n if (aiIndex !== undefined && aiIndex !== i && !indicesToRemove.has(aiIndex)) {\n // We need to remove both the tool message and its corresponding AI message\n indicesToRemove.add(i);\n indicesToRemove.add(aiIndex);\n currentTokenCount -= (tokenCounter(msgToRemove) + tokenCounter(context[aiIndex]));\n canRemove = false;\n }\n } else if (msgToRemove.getType() === 'ai' && Array.isArray(msgToRemove.content)) {\n // If this is an AI message with tool calls, check if we need to keep its corresponding tool messages\n for (const item of msgToRemove.content) {\n if (item && typeof item === 'object' && item.type === 'tool_use' && item.id) {\n const toolIndex = toolCallIdMap.get(item.id as string);\n if (toolIndex !== undefined && toolIndex !== i && !indicesToRemove.has(toolIndex)) {\n // We need to remove both the AI message and its corresponding tool message\n indicesToRemove.add(i);\n indicesToRemove.add(toolIndex);\n currentTokenCount -= (tokenCounter(msgToRemove) + tokenCounter(context[toolIndex]));\n canRemove = false;\n break;\n }\n }\n }\n }\n \n // If we can remove this message individually\n if (canRemove && !indicesToRemove.has(i)) {\n indicesToRemove.add(i);\n currentTokenCount -= tokenCounter(msgToRemove);\n }\n \n i--;\n }\n \n // Remove messages in reverse order to avoid index shifting\n const sortedIndices = Array.from(indicesToRemove).sort((a, b) => b - a);\n for (const index of sortedIndices) {\n context.splice(index, 1);\n }\n \n // Update remainingContextTokens to reflect the new token count\n remainingContextTokens = maxContextTokens - currentTokenCount;\n }\n }\n }\n }\n \n // If the latest message is an assistant message, ensure an assistant message with thinking appears at the end\n // of the context (which will become the beginning after reversal)\n // but maintain system message precedence after reversal\n if (latestMessageIsAssistant && context.length > 0) {\n // Find assistant messages with thinking blocks\n const assistantIndices: number[] = [];\n for (let i = 0; i < context.length; i++) {\n const msg = context[i];\n if (msg.getType() === 'ai') {\n const hasThinking = Array.isArray(msg.content) && \n msg.content.some(item => item && typeof item === 'object' && item.type === 'thinking');\n \n if (hasThinking) {\n assistantIndices.push(i);\n }\n }\n }\n \n // If we found assistant messages with thinking blocks\n if (assistantIndices.length > 0) {\n // Get the first assistant message with thinking\n const assistantWithThinkingIndex = assistantIndices[0];\n const assistantWithThinking = context[assistantWithThinkingIndex];\n \n // Remove it from its current position\n context.splice(assistantWithThinkingIndex, 1);\n \n // Check if there's a system message in the context\n const systemIndex = context.findIndex(msg => msg.getType() === 'system');\n const hasSystem = systemIndex !== -1;\n \n if (hasSystem) {\n // We want the system message to be first after reversal\n // This means we need to put it at the end position before reversal\n // And the assistant message should be second after reversal\n // This means we need to put it at the end - 1 position before reversal\n \n // First, ensure the system message is at the end (will be first after reversal)\n const systemMsg = context[systemIndex];\n context.splice(systemIndex, 1);\n context.push(systemMsg);\n \n // Then, put the assistant message right before the system message (will be second after reversal)\n context.splice(context.length - 1, 0, assistantWithThinking);\n } else {\n // No system message, so we want assistant to be first after reversal\n // This means we need to put it at the end position before reversal\n context.push(assistantWithThinking);\n }\n }\n }\n }\n }\n\n const prunedMemory = messages;\n summaryIndex = prunedMemory.length - 1;\n remainingContextTokens -= currentTokenCount;\n\n return {\n summaryIndex,\n remainingContextTokens,\n context: context.reverse(),\n messagesToRefine: prunedMemory,\n };\n}\n\nfunction checkValidNumber(value: unknown): value is number {\n return typeof value === 'number' && !isNaN(value) && value > 0;\n}\n\nexport function createPruneMessages(factoryParams: PruneMessagesFactoryParams) {\n const indexTokenCountMap = { ...factoryParams.indexTokenCountMap };\n let lastTurnStartIndex = factoryParams.startIndex;\n let totalTokens = (Object.values(indexTokenCountMap)).reduce((a, b) => a + b, 0);\n \n return function pruneMessages(params: PruneMessagesParams): {\n context: BaseMessage[];\n indexTokenCountMap: Record<string, number>;\n } {\n let currentUsage: UsageMetadata | undefined;\n if (params.usageMetadata && (\n checkValidNumber(params.usageMetadata.input_tokens)\n || (\n checkValidNumber(params.usageMetadata.input_token_details)\n && (\n checkValidNumber(params.usageMetadata.input_token_details.cache_creation)\n || checkValidNumber(params.usageMetadata.input_token_details.cache_read)\n )\n )\n ) && checkValidNumber(params.usageMetadata.output_tokens)) {\n currentUsage = calculateTotalTokens(params.usageMetadata);\n totalTokens = currentUsage.total_tokens;\n }\n\n for (let i = lastTurnStartIndex; i < params.messages.length; i++) {\n const message = params.messages[i];\n if (i === lastTurnStartIndex && indexTokenCountMap[i] === undefined && currentUsage) {\n indexTokenCountMap[i] = currentUsage.output_tokens;\n } else if (indexTokenCountMap[i] === undefined) {\n indexTokenCountMap[i] = factoryParams.tokenCounter(message);\n totalTokens += indexTokenCountMap[i];\n }\n }\n\n // If `currentUsage` is defined, we need to distribute the current total tokensto our `indexTokenCountMap`,\n // for all message index keys before `lastTurnStartIndex`, as it has the most accurate count for those messages.\n // We must distribute it in a weighted manner, so that the total token count is equal to `currentUsage.total_tokens`,\n // relative the manually counted tokens in `indexTokenCountMap`.\n if (currentUsage) {\n const totalIndexTokens = Object.values(indexTokenCountMap).reduce((a, b) => a + b, 0);\n const ratio = currentUsage.total_tokens / totalIndexTokens;\n for (const key in indexTokenCountMap) {\n indexTokenCountMap[key] = Math.round(indexTokenCountMap[key] * ratio);\n }\n }\n\n lastTurnStartIndex = params.messages.length;\n if (totalTokens <= factoryParams.maxTokens) {\n return { context: params.messages, indexTokenCountMap };\n }\n\n // Pass the tokenCounter to getMessagesWithinTokenLimit for token recalculation\n const { context } = getMessagesWithinTokenLimit({\n maxContextTokens: factoryParams.maxTokens,\n messages: params.messages,\n indexTokenCountMap,\n startOnMessageType: params.startOnMessageType,\n thinkingEnabled: factoryParams.thinkingEnabled,\n tokenCounter: factoryParams.tokenCounter,\n });\n\n return { context, indexTokenCountMap };\n }\n}\n"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
package/src/messages/prune.ts
CHANGED
|
@@ -267,25 +267,54 @@ function getMessagesWithinTokenLimit({
|
|
|
267
267
|
}
|
|
268
268
|
}
|
|
269
269
|
|
|
270
|
-
// If the latest message is an assistant message, ensure an assistant message appears
|
|
271
|
-
//
|
|
270
|
+
// If the latest message is an assistant message, ensure an assistant message with thinking appears at the end
|
|
271
|
+
// of the context (which will become the beginning after reversal)
|
|
272
|
+
// but maintain system message precedence after reversal
|
|
272
273
|
if (latestMessageIsAssistant && context.length > 0) {
|
|
273
|
-
// Find
|
|
274
|
-
const
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
274
|
+
// Find assistant messages with thinking blocks
|
|
275
|
+
const assistantIndices: number[] = [];
|
|
276
|
+
for (let i = 0; i < context.length; i++) {
|
|
277
|
+
const msg = context[i];
|
|
278
|
+
if (msg.getType() === 'ai') {
|
|
279
|
+
const hasThinking = Array.isArray(msg.content) &&
|
|
280
|
+
msg.content.some(item => item && typeof item === 'object' && item.type === 'thinking');
|
|
281
|
+
|
|
282
|
+
if (hasThinking) {
|
|
283
|
+
assistantIndices.push(i);
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
// If we found assistant messages with thinking blocks
|
|
289
|
+
if (assistantIndices.length > 0) {
|
|
290
|
+
// Get the first assistant message with thinking
|
|
291
|
+
const assistantWithThinkingIndex = assistantIndices[0];
|
|
292
|
+
const assistantWithThinking = context[assistantWithThinkingIndex];
|
|
293
|
+
|
|
294
|
+
// Remove it from its current position
|
|
295
|
+
context.splice(assistantWithThinkingIndex, 1);
|
|
278
296
|
|
|
279
|
-
//
|
|
280
|
-
const
|
|
281
|
-
|
|
297
|
+
// Check if there's a system message in the context
|
|
298
|
+
const systemIndex = context.findIndex(msg => msg.getType() === 'system');
|
|
299
|
+
const hasSystem = systemIndex !== -1;
|
|
282
300
|
|
|
283
|
-
if (
|
|
284
|
-
//
|
|
285
|
-
|
|
301
|
+
if (hasSystem) {
|
|
302
|
+
// We want the system message to be first after reversal
|
|
303
|
+
// This means we need to put it at the end position before reversal
|
|
304
|
+
// And the assistant message should be second after reversal
|
|
305
|
+
// This means we need to put it at the end - 1 position before reversal
|
|
306
|
+
|
|
307
|
+
// First, ensure the system message is at the end (will be first after reversal)
|
|
308
|
+
const systemMsg = context[systemIndex];
|
|
309
|
+
context.splice(systemIndex, 1);
|
|
310
|
+
context.push(systemMsg);
|
|
311
|
+
|
|
312
|
+
// Then, put the assistant message right before the system message (will be second after reversal)
|
|
313
|
+
context.splice(context.length - 1, 0, assistantWithThinking);
|
|
286
314
|
} else {
|
|
287
|
-
//
|
|
288
|
-
|
|
315
|
+
// No system message, so we want assistant to be first after reversal
|
|
316
|
+
// This means we need to put it at the end position before reversal
|
|
317
|
+
context.push(assistantWithThinking);
|
|
289
318
|
}
|
|
290
319
|
}
|
|
291
320
|
}
|
|
@@ -498,11 +498,11 @@ describe('Prune Messages with Thinking Mode Tests', () => {
|
|
|
498
498
|
}
|
|
499
499
|
});
|
|
500
500
|
|
|
501
|
-
it('should ensure an assistant message appears
|
|
501
|
+
it('should ensure an assistant message with thinking appears at the beginning of the context when the latest message is an assistant message', () => {
|
|
502
502
|
// Create a token counter
|
|
503
503
|
const tokenCounter = createTestTokenCounter();
|
|
504
504
|
|
|
505
|
-
// Create messages with the latest message being an assistant message
|
|
505
|
+
// Create messages with the latest message being an assistant message with thinking
|
|
506
506
|
const assistantMessageWithThinking = new AIMessage({
|
|
507
507
|
content: [
|
|
508
508
|
{
|
|
@@ -516,12 +516,41 @@ describe('Prune Messages with Thinking Mode Tests', () => {
|
|
|
516
516
|
],
|
|
517
517
|
});
|
|
518
518
|
|
|
519
|
+
// Create an assistant message with tool use
|
|
520
|
+
const assistantMessageWithToolUse = new AIMessage({
|
|
521
|
+
content: [
|
|
522
|
+
{
|
|
523
|
+
type: "text",
|
|
524
|
+
text: "Let me check that file:",
|
|
525
|
+
},
|
|
526
|
+
{
|
|
527
|
+
type: "tool_use",
|
|
528
|
+
id: "tool123",
|
|
529
|
+
name: "text_editor_mcp_textEditor",
|
|
530
|
+
input: "{\"command\": \"view\", \"path\": \"/path/to/file.txt\"}",
|
|
531
|
+
},
|
|
532
|
+
],
|
|
533
|
+
});
|
|
534
|
+
|
|
535
|
+
// Create a tool response message
|
|
536
|
+
const toolResponseMessage = new ToolMessage({
|
|
537
|
+
content: [
|
|
538
|
+
{
|
|
539
|
+
type: "text",
|
|
540
|
+
text: "{\"success\":true,\"message\":\"File content\"}",
|
|
541
|
+
},
|
|
542
|
+
],
|
|
543
|
+
tool_call_id: "tool123",
|
|
544
|
+
name: "text_editor_mcp_textEditor",
|
|
545
|
+
});
|
|
546
|
+
|
|
519
547
|
// Test case without system message
|
|
520
548
|
const messagesWithoutSystem = [
|
|
521
549
|
new HumanMessage("Hello"),
|
|
522
|
-
|
|
550
|
+
assistantMessageWithToolUse,
|
|
551
|
+
toolResponseMessage,
|
|
523
552
|
new HumanMessage("Next message"),
|
|
524
|
-
assistantMessageWithThinking, // Latest message is an assistant message
|
|
553
|
+
assistantMessageWithThinking, // Latest message is an assistant message with thinking
|
|
525
554
|
];
|
|
526
555
|
|
|
527
556
|
// Calculate token counts for each message
|
|
@@ -532,7 +561,7 @@ describe('Prune Messages with Thinking Mode Tests', () => {
|
|
|
532
561
|
|
|
533
562
|
// Create pruneMessages function with thinking mode enabled
|
|
534
563
|
const pruneMessagesWithoutSystem = createPruneMessages({
|
|
535
|
-
maxTokens:
|
|
564
|
+
maxTokens: 100, // Set a token limit to force some pruning
|
|
536
565
|
startIndex: 0,
|
|
537
566
|
tokenCounter,
|
|
538
567
|
indexTokenCountMap: { ...indexTokenCountMapWithoutSystem },
|
|
@@ -542,17 +571,25 @@ describe('Prune Messages with Thinking Mode Tests', () => {
|
|
|
542
571
|
// Prune messages
|
|
543
572
|
const resultWithoutSystem = pruneMessagesWithoutSystem({ messages: messagesWithoutSystem });
|
|
544
573
|
|
|
545
|
-
// Verify that the first message in the pruned context is an assistant message when no system message
|
|
574
|
+
// Verify that the first message in the pruned context is an assistant message with thinking when no system message
|
|
546
575
|
expect(resultWithoutSystem.context.length).toBeGreaterThan(0);
|
|
547
576
|
expect(resultWithoutSystem.context[0].getType()).toBe('ai');
|
|
548
577
|
|
|
578
|
+
// Verify that the first message has a thinking block
|
|
579
|
+
const firstMsgContent = resultWithoutSystem.context[0].content as any[];
|
|
580
|
+
expect(Array.isArray(firstMsgContent)).toBe(true);
|
|
581
|
+
const hasThinkingBlock = firstMsgContent.some(item =>
|
|
582
|
+
item && typeof item === 'object' && item.type === 'thinking');
|
|
583
|
+
expect(hasThinkingBlock).toBe(true);
|
|
584
|
+
|
|
549
585
|
// Test case with system message
|
|
550
586
|
const messagesWithSystem = [
|
|
551
587
|
new SystemMessage("System instruction"),
|
|
552
588
|
new HumanMessage("Hello"),
|
|
553
|
-
|
|
589
|
+
assistantMessageWithToolUse,
|
|
590
|
+
toolResponseMessage,
|
|
554
591
|
new HumanMessage("Next message"),
|
|
555
|
-
assistantMessageWithThinking, // Latest message is an assistant message
|
|
592
|
+
assistantMessageWithThinking, // Latest message is an assistant message with thinking
|
|
556
593
|
];
|
|
557
594
|
|
|
558
595
|
// Calculate token counts for each message
|
|
@@ -563,7 +600,7 @@ describe('Prune Messages with Thinking Mode Tests', () => {
|
|
|
563
600
|
|
|
564
601
|
// Create pruneMessages function with thinking mode enabled
|
|
565
602
|
const pruneMessagesWithSystem = createPruneMessages({
|
|
566
|
-
maxTokens:
|
|
603
|
+
maxTokens: 120, // Set a token limit to force some pruning but keep system message
|
|
567
604
|
startIndex: 0,
|
|
568
605
|
tokenCounter,
|
|
569
606
|
indexTokenCountMap: { ...indexTokenCountMapWithSystem },
|
|
@@ -573,10 +610,17 @@ describe('Prune Messages with Thinking Mode Tests', () => {
|
|
|
573
610
|
// Prune messages
|
|
574
611
|
const resultWithSystem = pruneMessagesWithSystem({ messages: messagesWithSystem });
|
|
575
612
|
|
|
576
|
-
// Verify that the system message remains first, followed by an assistant message
|
|
613
|
+
// Verify that the system message remains first, followed by an assistant message with thinking
|
|
577
614
|
expect(resultWithSystem.context.length).toBeGreaterThan(1);
|
|
578
615
|
expect(resultWithSystem.context[0].getType()).toBe('system');
|
|
579
616
|
expect(resultWithSystem.context[1].getType()).toBe('ai');
|
|
617
|
+
|
|
618
|
+
// Verify that the second message has a thinking block
|
|
619
|
+
const secondMsgContent = resultWithSystem.context[1].content as any[];
|
|
620
|
+
expect(Array.isArray(secondMsgContent)).toBe(true);
|
|
621
|
+
const hasThinkingBlockInSecond = secondMsgContent.some(item =>
|
|
622
|
+
item && typeof item === 'object' && item.type === 'thinking');
|
|
623
|
+
expect(hasThinkingBlockInSecond).toBe(true);
|
|
580
624
|
});
|
|
581
625
|
|
|
582
626
|
it('should look for thinking blocks starting from the most recent messages', () => {
|