@librechat/agents 3.0.772 → 3.0.774

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.
@@ -1,10 +1,10 @@
1
1
  'use strict';
2
2
 
3
+ var messages = require('@langchain/core/messages');
3
4
  var _enum = require('../common/enum.cjs');
4
5
 
5
6
  /**
6
7
  * Deep clones a message's content to prevent mutation of the original.
7
- * Handles both string and array content types.
8
8
  */
9
9
  function deepCloneContent(content) {
10
10
  if (typeof content === 'string') {
@@ -16,37 +16,63 @@ function deepCloneContent(content) {
16
16
  return content;
17
17
  }
18
18
  /**
19
- * Creates a shallow clone of a message with deep-cloned content.
20
- * This ensures modifications to content don't affect the original message.
19
+ * Simple shallow clone with deep-cloned content.
20
+ * Used for stripping cache control where we don't need proper LangChain instances.
21
21
  */
22
- function cloneMessageWithContent(message) {
23
- if (message.content === undefined) {
24
- return { ...message };
25
- }
26
- const clonedContent = deepCloneContent(message.content);
27
- const cloned = {
22
+ function shallowCloneMessage(message) {
23
+ return {
28
24
  ...message,
29
- content: clonedContent,
25
+ content: deepCloneContent(message.content ?? ''),
30
26
  };
31
- /**
32
- * LangChain messages store internal state in lc_kwargs.
33
- * Clone it but don't sync content yet - that happens after all modifications.
34
- */
35
- const lcKwargs = message.lc_kwargs;
36
- if (lcKwargs != null && typeof lcKwargs === 'object') {
37
- cloned.lc_kwargs = { ...lcKwargs };
38
- }
39
- return cloned;
40
27
  }
41
28
  /**
42
- * Syncs lc_kwargs.content with the message's content property.
43
- * Call this after all modifications to ensure LangChain serialization works correctly.
29
+ * Creates a new LangChain message instance with the given content.
30
+ * Required when adding cache points to ensure proper serialization.
44
31
  */
45
- function syncLcKwargsContent(message) {
46
- const lcKwargs = message.lc_kwargs;
47
- if (lcKwargs != null && typeof lcKwargs === 'object') {
48
- lcKwargs.content = message.content;
32
+ function createNewMessage(message, content) {
33
+ if ('getType' in message && typeof message.getType === 'function') {
34
+ const baseMsg = message;
35
+ const msgType = baseMsg.getType();
36
+ const baseFields = {
37
+ content,
38
+ name: baseMsg.name,
39
+ additional_kwargs: { ...baseMsg.additional_kwargs },
40
+ response_metadata: { ...baseMsg.response_metadata },
41
+ id: baseMsg.id,
42
+ };
43
+ switch (msgType) {
44
+ case 'human':
45
+ return new messages.HumanMessage(baseFields);
46
+ case 'ai': {
47
+ const aiMsg = baseMsg;
48
+ return new messages.AIMessage({
49
+ ...baseFields,
50
+ tool_calls: aiMsg.tool_calls ? [...aiMsg.tool_calls] : [],
51
+ invalid_tool_calls: aiMsg.invalid_tool_calls
52
+ ? [...aiMsg.invalid_tool_calls]
53
+ : [],
54
+ usage_metadata: aiMsg.usage_metadata,
55
+ });
56
+ }
57
+ case 'system':
58
+ return new messages.SystemMessage(baseFields);
59
+ case 'tool': {
60
+ const toolMsg = baseMsg;
61
+ return new messages.ToolMessage({
62
+ ...baseFields,
63
+ tool_call_id: toolMsg.tool_call_id,
64
+ status: toolMsg.status,
65
+ artifact: toolMsg.artifact,
66
+ });
67
+ }
68
+ }
49
69
  }
70
+ const cloned = { ...message, content };
71
+ const lcKwargs = cloned.lc_kwargs;
72
+ if (lcKwargs != null) {
73
+ cloned.lc_kwargs = { ...lcKwargs, content };
74
+ }
75
+ return cloned;
50
76
  }
51
77
  /**
52
78
  * Checks if a message's content needs cache control stripping.
@@ -90,7 +116,7 @@ function addCacheControl(messages) {
90
116
  if (!needsStripping && !needsCacheAdd) {
91
117
  continue;
92
118
  }
93
- const message = cloneMessageWithContent(originalMessage);
119
+ const message = shallowCloneMessage(originalMessage);
94
120
  updatedMessages[i] = message;
95
121
  if (hasArrayContent) {
96
122
  message.content = message.content.filter((block) => !isCachePoint(block));
@@ -102,7 +128,6 @@ function addCacheControl(messages) {
102
128
  }
103
129
  }
104
130
  if (userMessagesModified >= 2 || !isUserMessage) {
105
- syncLcKwargsContent(message);
106
131
  continue;
107
132
  }
108
133
  if (typeof message.content === 'string') {
@@ -127,7 +152,6 @@ function addCacheControl(messages) {
127
152
  }
128
153
  }
129
154
  }
130
- syncLcKwargsContent(message);
131
155
  }
132
156
  return updatedMessages;
133
157
  }
@@ -163,7 +187,7 @@ function stripAnthropicCacheControl(messages) {
163
187
  if (!Array.isArray(content) || !hasAnthropicCacheControl(content)) {
164
188
  continue;
165
189
  }
166
- const message = cloneMessageWithContent(originalMessage);
190
+ const message = shallowCloneMessage(originalMessage);
167
191
  updatedMessages[i] = message;
168
192
  for (let j = 0; j < message.content.length; j++) {
169
193
  const block = message.content[j];
@@ -200,7 +224,7 @@ function stripBedrockCacheControl(messages) {
200
224
  if (!Array.isArray(content) || !hasBedrockCachePoint(content)) {
201
225
  continue;
202
226
  }
203
- const message = cloneMessageWithContent(originalMessage);
227
+ const message = shallowCloneMessage(originalMessage);
204
228
  updatedMessages[i] = message;
205
229
  message.content = message.content.filter((block) => !isCachePoint(block));
206
230
  }
@@ -240,68 +264,67 @@ function addBedrockCacheControl(messages) {
240
264
  if (!needsStripping && !needsCacheAdd) {
241
265
  continue;
242
266
  }
243
- const message = cloneMessageWithContent(originalMessage);
244
- updatedMessages[i] = message;
267
+ let workingContent;
245
268
  if (hasArrayContent) {
246
- message.content = message.content.filter((block) => !isCachePoint(block));
247
- for (let j = 0; j < message.content.length; j++) {
248
- const block = message.content[j];
269
+ workingContent = deepCloneContent(content).filter((block) => !isCachePoint(block));
270
+ for (let j = 0; j < workingContent.length; j++) {
271
+ const block = workingContent[j];
249
272
  if ('cache_control' in block) {
250
273
  delete block.cache_control;
251
274
  }
252
275
  }
253
276
  }
277
+ else if (typeof content === 'string') {
278
+ workingContent = [{ type: _enum.ContentTypes.TEXT, text: content }];
279
+ }
280
+ else {
281
+ workingContent = [];
282
+ }
254
283
  if (messagesModified >= 2 || isToolMessage || isEmptyString) {
255
- syncLcKwargsContent(message);
284
+ updatedMessages[i] = shallowCloneMessage(originalMessage);
285
+ updatedMessages[i].content = workingContent;
256
286
  continue;
257
287
  }
258
- if (typeof message.content === 'string') {
259
- message.content = [
260
- { type: _enum.ContentTypes.TEXT, text: message.content },
261
- { cachePoint: { type: 'default' } },
262
- ];
263
- messagesModified++;
264
- syncLcKwargsContent(message);
288
+ if (workingContent.length === 0) {
265
289
  continue;
266
290
  }
267
- if (Array.isArray(message.content)) {
268
- let hasCacheableContent = false;
269
- for (const block of message.content) {
270
- if (block.type === _enum.ContentTypes.TEXT) {
271
- if (typeof block.text === 'string' && block.text !== '') {
272
- hasCacheableContent = true;
273
- break;
274
- }
275
- }
276
- }
277
- if (!hasCacheableContent) {
278
- syncLcKwargsContent(message);
279
- continue;
280
- }
281
- let inserted = false;
282
- for (let j = message.content.length - 1; j >= 0; j--) {
283
- const block = message.content[j];
284
- const type = block.type;
285
- if (type === _enum.ContentTypes.TEXT || type === 'text') {
286
- const text = block.text;
287
- if (text === '' || text === undefined) {
288
- continue;
289
- }
290
- message.content.splice(j + 1, 0, {
291
- cachePoint: { type: 'default' },
292
- });
293
- inserted = true;
291
+ let hasCacheableContent = false;
292
+ for (const block of workingContent) {
293
+ if (block.type === _enum.ContentTypes.TEXT) {
294
+ if (typeof block.text === 'string' && block.text !== '') {
295
+ hasCacheableContent = true;
294
296
  break;
295
297
  }
296
298
  }
297
- if (!inserted) {
298
- message.content.push({
299
+ }
300
+ if (!hasCacheableContent) {
301
+ updatedMessages[i] = shallowCloneMessage(originalMessage);
302
+ updatedMessages[i].content = workingContent;
303
+ continue;
304
+ }
305
+ let inserted = false;
306
+ for (let j = workingContent.length - 1; j >= 0; j--) {
307
+ const block = workingContent[j];
308
+ const type = block.type;
309
+ if (type === _enum.ContentTypes.TEXT || type === 'text') {
310
+ const text = block.text;
311
+ if (text === '' || text === undefined) {
312
+ continue;
313
+ }
314
+ workingContent.splice(j + 1, 0, {
299
315
  cachePoint: { type: 'default' },
300
316
  });
317
+ inserted = true;
318
+ break;
301
319
  }
302
- messagesModified++;
303
320
  }
304
- syncLcKwargsContent(message);
321
+ if (!inserted) {
322
+ workingContent.push({
323
+ cachePoint: { type: 'default' },
324
+ });
325
+ }
326
+ updatedMessages[i] = createNewMessage(originalMessage, workingContent);
327
+ messagesModified++;
305
328
  }
306
329
  return updatedMessages;
307
330
  }
@@ -1 +1 @@
1
- {"version":3,"file":"cache.cjs","sources":["../../../src/messages/cache.ts"],"sourcesContent":["import { BaseMessage, MessageContentComplex } from '@langchain/core/messages';\nimport type { AnthropicMessage } from '@/types/messages';\nimport type Anthropic from '@anthropic-ai/sdk';\nimport { ContentTypes } from '@/common/enum';\n\ntype MessageWithContent = {\n content?: string | MessageContentComplex[];\n};\n\n/**\n * Deep clones a message's content to prevent mutation of the original.\n * Handles both string and array content types.\n */\nfunction deepCloneContent<T extends string | MessageContentComplex[]>(\n content: T\n): T {\n if (typeof content === 'string') {\n return content;\n }\n if (Array.isArray(content)) {\n return content.map((block) => ({ ...block })) as T;\n }\n return content;\n}\n\n/**\n * Creates a shallow clone of a message with deep-cloned content.\n * This ensures modifications to content don't affect the original message.\n */\nfunction cloneMessageWithContent<T extends MessageWithContent>(message: T): T {\n if (message.content === undefined) {\n return { ...message };\n }\n\n const clonedContent = deepCloneContent(message.content);\n const cloned = {\n ...message,\n content: clonedContent,\n };\n\n /**\n * LangChain messages store internal state in lc_kwargs.\n * Clone it but don't sync content yet - that happens after all modifications.\n */\n const lcKwargs = (message as Record<string, unknown>).lc_kwargs;\n if (lcKwargs != null && typeof lcKwargs === 'object') {\n (cloned as Record<string, unknown>).lc_kwargs = { ...lcKwargs };\n }\n\n return cloned;\n}\n\n/**\n * Syncs lc_kwargs.content with the message's content property.\n * Call this after all modifications to ensure LangChain serialization works correctly.\n */\nfunction syncLcKwargsContent<T extends MessageWithContent>(message: T): void {\n const lcKwargs = (message as Record<string, unknown>).lc_kwargs;\n if (lcKwargs != null && typeof lcKwargs === 'object') {\n (lcKwargs as Record<string, unknown>).content = message.content;\n }\n}\n\n/**\n * Checks if a message's content needs cache control stripping.\n * Returns true if content has cachePoint blocks or cache_control fields.\n */\nfunction needsCacheStripping(content: MessageContentComplex[]): boolean {\n for (let i = 0; i < content.length; i++) {\n const block = content[i];\n if (isCachePoint(block)) return true;\n if ('cache_control' in block) return true;\n }\n return false;\n}\n\n/**\n * Anthropic API: Adds cache control to the appropriate user messages in the payload.\n * Strips ALL existing cache control (both Anthropic and Bedrock formats) from all messages,\n * then adds fresh cache control to the last 2 user messages in a single backward pass.\n * This ensures we don't accumulate stale cache points across multiple turns.\n * Returns a new array - only clones messages that require modification.\n * @param messages - The array of message objects.\n * @returns - A new array of message objects with cache control added.\n */\nexport function addCacheControl<T extends AnthropicMessage | BaseMessage>(\n messages: T[]\n): T[] {\n if (!Array.isArray(messages) || messages.length < 2) {\n return messages;\n }\n\n const updatedMessages: T[] = [...messages];\n let userMessagesModified = 0;\n\n for (let i = updatedMessages.length - 1; i >= 0; i--) {\n const originalMessage = updatedMessages[i];\n const isUserMessage =\n ('getType' in originalMessage && originalMessage.getType() === 'human') ||\n ('role' in originalMessage && originalMessage.role === 'user');\n\n const hasArrayContent = Array.isArray(originalMessage.content);\n const needsStripping =\n hasArrayContent &&\n needsCacheStripping(originalMessage.content as MessageContentComplex[]);\n const needsCacheAdd =\n userMessagesModified < 2 &&\n isUserMessage &&\n (typeof originalMessage.content === 'string' || hasArrayContent);\n\n if (!needsStripping && !needsCacheAdd) {\n continue;\n }\n\n const message = cloneMessageWithContent(\n originalMessage as MessageWithContent\n ) as T;\n updatedMessages[i] = message;\n\n if (hasArrayContent) {\n message.content = (message.content as MessageContentComplex[]).filter(\n (block) => !isCachePoint(block as MessageContentComplex)\n ) as typeof message.content;\n\n for (\n let j = 0;\n j < (message.content as MessageContentComplex[]).length;\n j++\n ) {\n const block = (message.content as MessageContentComplex[])[j] as Record<\n string,\n unknown\n >;\n if ('cache_control' in block) {\n delete block.cache_control;\n }\n }\n }\n\n if (userMessagesModified >= 2 || !isUserMessage) {\n syncLcKwargsContent(message);\n continue;\n }\n\n if (typeof message.content === 'string') {\n message.content = [\n {\n type: 'text',\n text: message.content,\n cache_control: { type: 'ephemeral' },\n },\n ];\n userMessagesModified++;\n } else if (Array.isArray(message.content)) {\n for (let j = message.content.length - 1; j >= 0; j--) {\n const contentPart = message.content[j];\n if ('type' in contentPart && contentPart.type === 'text') {\n (contentPart as Anthropic.TextBlockParam).cache_control = {\n type: 'ephemeral',\n };\n userMessagesModified++;\n break;\n }\n }\n }\n\n syncLcKwargsContent(message);\n }\n\n return updatedMessages;\n}\n\n/**\n * Checks if a content block is a cache point\n */\nfunction isCachePoint(block: MessageContentComplex): boolean {\n return 'cachePoint' in block && !('type' in block);\n}\n\n/**\n * Checks if a message's content has Anthropic cache_control fields.\n */\nfunction hasAnthropicCacheControl(content: MessageContentComplex[]): boolean {\n for (let i = 0; i < content.length; i++) {\n if ('cache_control' in content[i]) return true;\n }\n return false;\n}\n\n/**\n * Removes all Anthropic cache_control fields from messages\n * Used when switching from Anthropic to Bedrock provider\n * Returns a new array - only clones messages that require modification.\n */\nexport function stripAnthropicCacheControl<T extends MessageWithContent>(\n messages: T[]\n): T[] {\n if (!Array.isArray(messages)) {\n return messages;\n }\n\n const updatedMessages: T[] = [...messages];\n\n for (let i = 0; i < updatedMessages.length; i++) {\n const originalMessage = updatedMessages[i];\n const content = originalMessage.content;\n\n if (!Array.isArray(content) || !hasAnthropicCacheControl(content)) {\n continue;\n }\n\n const message = cloneMessageWithContent(originalMessage);\n updatedMessages[i] = message;\n\n for (\n let j = 0;\n j < (message.content as MessageContentComplex[]).length;\n j++\n ) {\n const block = (message.content as MessageContentComplex[])[j] as Record<\n string,\n unknown\n >;\n if ('cache_control' in block) {\n delete block.cache_control;\n }\n }\n }\n\n return updatedMessages;\n}\n\n/**\n * Checks if a message's content has Bedrock cachePoint blocks.\n */\nfunction hasBedrockCachePoint(content: MessageContentComplex[]): boolean {\n for (let i = 0; i < content.length; i++) {\n if (isCachePoint(content[i])) return true;\n }\n return false;\n}\n\n/**\n * Removes all Bedrock cachePoint blocks from messages\n * Used when switching from Bedrock to Anthropic provider\n * Returns a new array - only clones messages that require modification.\n */\nexport function stripBedrockCacheControl<T extends MessageWithContent>(\n messages: T[]\n): T[] {\n if (!Array.isArray(messages)) {\n return messages;\n }\n\n const updatedMessages: T[] = [...messages];\n\n for (let i = 0; i < updatedMessages.length; i++) {\n const originalMessage = updatedMessages[i];\n const content = originalMessage.content;\n\n if (!Array.isArray(content) || !hasBedrockCachePoint(content)) {\n continue;\n }\n\n const message = cloneMessageWithContent(originalMessage);\n updatedMessages[i] = message;\n\n message.content = (message.content as MessageContentComplex[]).filter(\n (block) => !isCachePoint(block as MessageContentComplex)\n ) as typeof content;\n }\n\n return updatedMessages;\n}\n\n/**\n * Adds Bedrock Converse API cache points to the last two messages.\n * Inserts `{ cachePoint: { type: 'default' } }` as a separate content block\n * immediately after the last text block in each targeted message.\n * Strips ALL existing cache control (both Bedrock and Anthropic formats) from all messages,\n * then adds fresh cache points to the last 2 messages in a single backward pass.\n * This ensures we don't accumulate stale cache points across multiple turns.\n * Returns a new array - only clones messages that require modification.\n * @param messages - The array of message objects.\n * @returns - A new array of message objects with cache points added.\n */\nexport function addBedrockCacheControl<\n T extends Partial<BaseMessage> & MessageWithContent,\n>(messages: T[]): T[] {\n if (!Array.isArray(messages) || messages.length < 2) {\n return messages;\n }\n\n const updatedMessages: T[] = [...messages];\n let messagesModified = 0;\n\n for (let i = updatedMessages.length - 1; i >= 0; i--) {\n const originalMessage = updatedMessages[i];\n const isToolMessage =\n 'getType' in originalMessage &&\n typeof originalMessage.getType === 'function' &&\n originalMessage.getType() === 'tool';\n\n const content = originalMessage.content;\n const hasArrayContent = Array.isArray(content);\n const needsStripping =\n hasArrayContent &&\n needsCacheStripping(content as MessageContentComplex[]);\n const isEmptyString = typeof content === 'string' && content === '';\n const needsCacheAdd =\n messagesModified < 2 &&\n !isToolMessage &&\n !isEmptyString &&\n (typeof content === 'string' || hasArrayContent);\n\n if (!needsStripping && !needsCacheAdd) {\n continue;\n }\n\n const message = cloneMessageWithContent(originalMessage);\n updatedMessages[i] = message;\n\n if (hasArrayContent) {\n message.content = (message.content as MessageContentComplex[]).filter(\n (block) => !isCachePoint(block)\n ) as typeof content;\n\n for (\n let j = 0;\n j < (message.content as MessageContentComplex[]).length;\n j++\n ) {\n const block = (message.content as MessageContentComplex[])[j] as Record<\n string,\n unknown\n >;\n if ('cache_control' in block) {\n delete block.cache_control;\n }\n }\n }\n\n if (messagesModified >= 2 || isToolMessage || isEmptyString) {\n syncLcKwargsContent(message);\n continue;\n }\n\n if (typeof message.content === 'string') {\n message.content = [\n { type: ContentTypes.TEXT, text: message.content },\n { cachePoint: { type: 'default' } },\n ] as MessageContentComplex[];\n messagesModified++;\n syncLcKwargsContent(message);\n continue;\n }\n\n if (Array.isArray(message.content)) {\n let hasCacheableContent = false;\n for (const block of message.content) {\n if (block.type === ContentTypes.TEXT) {\n if (typeof block.text === 'string' && block.text !== '') {\n hasCacheableContent = true;\n break;\n }\n }\n }\n\n if (!hasCacheableContent) {\n syncLcKwargsContent(message);\n continue;\n }\n\n let inserted = false;\n for (let j = message.content.length - 1; j >= 0; j--) {\n const block = message.content[j] as MessageContentComplex;\n const type = (block as { type?: string }).type;\n if (type === ContentTypes.TEXT || type === 'text') {\n const text = (block as { text?: string }).text;\n if (text === '' || text === undefined) {\n continue;\n }\n message.content.splice(j + 1, 0, {\n cachePoint: { type: 'default' },\n } as MessageContentComplex);\n inserted = true;\n break;\n }\n }\n if (!inserted) {\n message.content.push({\n cachePoint: { type: 'default' },\n } as MessageContentComplex);\n }\n messagesModified++;\n }\n\n syncLcKwargsContent(message);\n }\n\n return updatedMessages;\n}\n"],"names":["ContentTypes"],"mappings":";;;;AASA;;;AAGG;AACH,SAAS,gBAAgB,CACvB,OAAU,EAAA;AAEV,IAAA,IAAI,OAAO,OAAO,KAAK,QAAQ,EAAE;AAC/B,QAAA,OAAO,OAAO;;AAEhB,IAAA,IAAI,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE;AAC1B,QAAA,OAAO,OAAO,CAAC,GAAG,CAAC,CAAC,KAAK,MAAM,EAAE,GAAG,KAAK,EAAE,CAAC,CAAM;;AAEpD,IAAA,OAAO,OAAO;AAChB;AAEA;;;AAGG;AACH,SAAS,uBAAuB,CAA+B,OAAU,EAAA;AACvE,IAAA,IAAI,OAAO,CAAC,OAAO,KAAK,SAAS,EAAE;AACjC,QAAA,OAAO,EAAE,GAAG,OAAO,EAAE;;IAGvB,MAAM,aAAa,GAAG,gBAAgB,CAAC,OAAO,CAAC,OAAO,CAAC;AACvD,IAAA,MAAM,MAAM,GAAG;AACb,QAAA,GAAG,OAAO;AACV,QAAA,OAAO,EAAE,aAAa;KACvB;AAED;;;AAGG;AACH,IAAA,MAAM,QAAQ,GAAI,OAAmC,CAAC,SAAS;IAC/D,IAAI,QAAQ,IAAI,IAAI,IAAI,OAAO,QAAQ,KAAK,QAAQ,EAAE;AACnD,QAAA,MAAkC,CAAC,SAAS,GAAG,EAAE,GAAG,QAAQ,EAAE;;AAGjE,IAAA,OAAO,MAAM;AACf;AAEA;;;AAGG;AACH,SAAS,mBAAmB,CAA+B,OAAU,EAAA;AACnE,IAAA,MAAM,QAAQ,GAAI,OAAmC,CAAC,SAAS;IAC/D,IAAI,QAAQ,IAAI,IAAI,IAAI,OAAO,QAAQ,KAAK,QAAQ,EAAE;AACnD,QAAA,QAAoC,CAAC,OAAO,GAAG,OAAO,CAAC,OAAO;;AAEnE;AAEA;;;AAGG;AACH,SAAS,mBAAmB,CAAC,OAAgC,EAAA;AAC3D,IAAA,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE;AACvC,QAAA,MAAM,KAAK,GAAG,OAAO,CAAC,CAAC,CAAC;QACxB,IAAI,YAAY,CAAC,KAAK,CAAC;AAAE,YAAA,OAAO,IAAI;QACpC,IAAI,eAAe,IAAI,KAAK;AAAE,YAAA,OAAO,IAAI;;AAE3C,IAAA,OAAO,KAAK;AACd;AAEA;;;;;;;;AAQG;AACG,SAAU,eAAe,CAC7B,QAAa,EAAA;AAEb,IAAA,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,IAAI,QAAQ,CAAC,MAAM,GAAG,CAAC,EAAE;AACnD,QAAA,OAAO,QAAQ;;AAGjB,IAAA,MAAM,eAAe,GAAQ,CAAC,GAAG,QAAQ,CAAC;IAC1C,IAAI,oBAAoB,GAAG,CAAC;AAE5B,IAAA,KAAK,IAAI,CAAC,GAAG,eAAe,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,EAAE;AACpD,QAAA,MAAM,eAAe,GAAG,eAAe,CAAC,CAAC,CAAC;AAC1C,QAAA,MAAM,aAAa,GACjB,CAAC,SAAS,IAAI,eAAe,IAAI,eAAe,CAAC,OAAO,EAAE,KAAK,OAAO;aACrE,MAAM,IAAI,eAAe,IAAI,eAAe,CAAC,IAAI,KAAK,MAAM,CAAC;QAEhE,MAAM,eAAe,GAAG,KAAK,CAAC,OAAO,CAAC,eAAe,CAAC,OAAO,CAAC;QAC9D,MAAM,cAAc,GAClB,eAAe;AACf,YAAA,mBAAmB,CAAC,eAAe,CAAC,OAAkC,CAAC;AACzE,QAAA,MAAM,aAAa,GACjB,oBAAoB,GAAG,CAAC;YACxB,aAAa;aACZ,OAAO,eAAe,CAAC,OAAO,KAAK,QAAQ,IAAI,eAAe,CAAC;AAElE,QAAA,IAAI,CAAC,cAAc,IAAI,CAAC,aAAa,EAAE;YACrC;;AAGF,QAAA,MAAM,OAAO,GAAG,uBAAuB,CACrC,eAAqC,CACjC;AACN,QAAA,eAAe,CAAC,CAAC,CAAC,GAAG,OAAO;QAE5B,IAAI,eAAe,EAAE;YACnB,OAAO,CAAC,OAAO,GAAI,OAAO,CAAC,OAAmC,CAAC,MAAM,CACnE,CAAC,KAAK,KAAK,CAAC,YAAY,CAAC,KAA8B,CAAC,CAC/B;AAE3B,YAAA,KACE,IAAI,CAAC,GAAG,CAAC,EACT,CAAC,GAAI,OAAO,CAAC,OAAmC,CAAC,MAAM,EACvD,CAAC,EAAE,EACH;gBACA,MAAM,KAAK,GAAI,OAAO,CAAC,OAAmC,CAAC,CAAC,CAG3D;AACD,gBAAA,IAAI,eAAe,IAAI,KAAK,EAAE;oBAC5B,OAAO,KAAK,CAAC,aAAa;;;;AAKhC,QAAA,IAAI,oBAAoB,IAAI,CAAC,IAAI,CAAC,aAAa,EAAE;YAC/C,mBAAmB,CAAC,OAAO,CAAC;YAC5B;;AAGF,QAAA,IAAI,OAAO,OAAO,CAAC,OAAO,KAAK,QAAQ,EAAE;YACvC,OAAO,CAAC,OAAO,GAAG;AAChB,gBAAA;AACE,oBAAA,IAAI,EAAE,MAAM;oBACZ,IAAI,EAAE,OAAO,CAAC,OAAO;AACrB,oBAAA,aAAa,EAAE,EAAE,IAAI,EAAE,WAAW,EAAE;AACrC,iBAAA;aACF;AACD,YAAA,oBAAoB,EAAE;;aACjB,IAAI,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE;AACzC,YAAA,KAAK,IAAI,CAAC,GAAG,OAAO,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,EAAE;gBACpD,MAAM,WAAW,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC;gBACtC,IAAI,MAAM,IAAI,WAAW,IAAI,WAAW,CAAC,IAAI,KAAK,MAAM,EAAE;oBACvD,WAAwC,CAAC,aAAa,GAAG;AACxD,wBAAA,IAAI,EAAE,WAAW;qBAClB;AACD,oBAAA,oBAAoB,EAAE;oBACtB;;;;QAKN,mBAAmB,CAAC,OAAO,CAAC;;AAG9B,IAAA,OAAO,eAAe;AACxB;AAEA;;AAEG;AACH,SAAS,YAAY,CAAC,KAA4B,EAAA;IAChD,OAAO,YAAY,IAAI,KAAK,IAAI,EAAE,MAAM,IAAI,KAAK,CAAC;AACpD;AAEA;;AAEG;AACH,SAAS,wBAAwB,CAAC,OAAgC,EAAA;AAChE,IAAA,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE;AACvC,QAAA,IAAI,eAAe,IAAI,OAAO,CAAC,CAAC,CAAC;AAAE,YAAA,OAAO,IAAI;;AAEhD,IAAA,OAAO,KAAK;AACd;AAEA;;;;AAIG;AACG,SAAU,0BAA0B,CACxC,QAAa,EAAA;IAEb,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE;AAC5B,QAAA,OAAO,QAAQ;;AAGjB,IAAA,MAAM,eAAe,GAAQ,CAAC,GAAG,QAAQ,CAAC;AAE1C,IAAA,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,eAAe,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE;AAC/C,QAAA,MAAM,eAAe,GAAG,eAAe,CAAC,CAAC,CAAC;AAC1C,QAAA,MAAM,OAAO,GAAG,eAAe,CAAC,OAAO;AAEvC,QAAA,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC,wBAAwB,CAAC,OAAO,CAAC,EAAE;YACjE;;AAGF,QAAA,MAAM,OAAO,GAAG,uBAAuB,CAAC,eAAe,CAAC;AACxD,QAAA,eAAe,CAAC,CAAC,CAAC,GAAG,OAAO;AAE5B,QAAA,KACE,IAAI,CAAC,GAAG,CAAC,EACT,CAAC,GAAI,OAAO,CAAC,OAAmC,CAAC,MAAM,EACvD,CAAC,EAAE,EACH;YACA,MAAM,KAAK,GAAI,OAAO,CAAC,OAAmC,CAAC,CAAC,CAG3D;AACD,YAAA,IAAI,eAAe,IAAI,KAAK,EAAE;gBAC5B,OAAO,KAAK,CAAC,aAAa;;;;AAKhC,IAAA,OAAO,eAAe;AACxB;AAEA;;AAEG;AACH,SAAS,oBAAoB,CAAC,OAAgC,EAAA;AAC5D,IAAA,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE;AACvC,QAAA,IAAI,YAAY,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;AAAE,YAAA,OAAO,IAAI;;AAE3C,IAAA,OAAO,KAAK;AACd;AAEA;;;;AAIG;AACG,SAAU,wBAAwB,CACtC,QAAa,EAAA;IAEb,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE;AAC5B,QAAA,OAAO,QAAQ;;AAGjB,IAAA,MAAM,eAAe,GAAQ,CAAC,GAAG,QAAQ,CAAC;AAE1C,IAAA,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,eAAe,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE;AAC/C,QAAA,MAAM,eAAe,GAAG,eAAe,CAAC,CAAC,CAAC;AAC1C,QAAA,MAAM,OAAO,GAAG,eAAe,CAAC,OAAO;AAEvC,QAAA,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC,oBAAoB,CAAC,OAAO,CAAC,EAAE;YAC7D;;AAGF,QAAA,MAAM,OAAO,GAAG,uBAAuB,CAAC,eAAe,CAAC;AACxD,QAAA,eAAe,CAAC,CAAC,CAAC,GAAG,OAAO;QAE5B,OAAO,CAAC,OAAO,GAAI,OAAO,CAAC,OAAmC,CAAC,MAAM,CACnE,CAAC,KAAK,KAAK,CAAC,YAAY,CAAC,KAA8B,CAAC,CACvC;;AAGrB,IAAA,OAAO,eAAe;AACxB;AAEA;;;;;;;;;;AAUG;AACG,SAAU,sBAAsB,CAEpC,QAAa,EAAA;AACb,IAAA,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,IAAI,QAAQ,CAAC,MAAM,GAAG,CAAC,EAAE;AACnD,QAAA,OAAO,QAAQ;;AAGjB,IAAA,MAAM,eAAe,GAAQ,CAAC,GAAG,QAAQ,CAAC;IAC1C,IAAI,gBAAgB,GAAG,CAAC;AAExB,IAAA,KAAK,IAAI,CAAC,GAAG,eAAe,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,EAAE;AACpD,QAAA,MAAM,eAAe,GAAG,eAAe,CAAC,CAAC,CAAC;AAC1C,QAAA,MAAM,aAAa,GACjB,SAAS,IAAI,eAAe;AAC5B,YAAA,OAAO,eAAe,CAAC,OAAO,KAAK,UAAU;AAC7C,YAAA,eAAe,CAAC,OAAO,EAAE,KAAK,MAAM;AAEtC,QAAA,MAAM,OAAO,GAAG,eAAe,CAAC,OAAO;QACvC,MAAM,eAAe,GAAG,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC;QAC9C,MAAM,cAAc,GAClB,eAAe;YACf,mBAAmB,CAAC,OAAkC,CAAC;QACzD,MAAM,aAAa,GAAG,OAAO,OAAO,KAAK,QAAQ,IAAI,OAAO,KAAK,EAAE;AACnE,QAAA,MAAM,aAAa,GACjB,gBAAgB,GAAG,CAAC;AACpB,YAAA,CAAC,aAAa;AACd,YAAA,CAAC,aAAa;AACd,aAAC,OAAO,OAAO,KAAK,QAAQ,IAAI,eAAe,CAAC;AAElD,QAAA,IAAI,CAAC,cAAc,IAAI,CAAC,aAAa,EAAE;YACrC;;AAGF,QAAA,MAAM,OAAO,GAAG,uBAAuB,CAAC,eAAe,CAAC;AACxD,QAAA,eAAe,CAAC,CAAC,CAAC,GAAG,OAAO;QAE5B,IAAI,eAAe,EAAE;YACnB,OAAO,CAAC,OAAO,GAAI,OAAO,CAAC,OAAmC,CAAC,MAAM,CACnE,CAAC,KAAK,KAAK,CAAC,YAAY,CAAC,KAAK,CAAC,CACd;AAEnB,YAAA,KACE,IAAI,CAAC,GAAG,CAAC,EACT,CAAC,GAAI,OAAO,CAAC,OAAmC,CAAC,MAAM,EACvD,CAAC,EAAE,EACH;gBACA,MAAM,KAAK,GAAI,OAAO,CAAC,OAAmC,CAAC,CAAC,CAG3D;AACD,gBAAA,IAAI,eAAe,IAAI,KAAK,EAAE;oBAC5B,OAAO,KAAK,CAAC,aAAa;;;;QAKhC,IAAI,gBAAgB,IAAI,CAAC,IAAI,aAAa,IAAI,aAAa,EAAE;YAC3D,mBAAmB,CAAC,OAAO,CAAC;YAC5B;;AAGF,QAAA,IAAI,OAAO,OAAO,CAAC,OAAO,KAAK,QAAQ,EAAE;YACvC,OAAO,CAAC,OAAO,GAAG;gBAChB,EAAE,IAAI,EAAEA,kBAAY,CAAC,IAAI,EAAE,IAAI,EAAE,OAAO,CAAC,OAAO,EAAE;AAClD,gBAAA,EAAE,UAAU,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,EAAE;aACT;AAC5B,YAAA,gBAAgB,EAAE;YAClB,mBAAmB,CAAC,OAAO,CAAC;YAC5B;;QAGF,IAAI,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE;YAClC,IAAI,mBAAmB,GAAG,KAAK;AAC/B,YAAA,KAAK,MAAM,KAAK,IAAI,OAAO,CAAC,OAAO,EAAE;gBACnC,IAAI,KAAK,CAAC,IAAI,KAAKA,kBAAY,CAAC,IAAI,EAAE;AACpC,oBAAA,IAAI,OAAO,KAAK,CAAC,IAAI,KAAK,QAAQ,IAAI,KAAK,CAAC,IAAI,KAAK,EAAE,EAAE;wBACvD,mBAAmB,GAAG,IAAI;wBAC1B;;;;YAKN,IAAI,CAAC,mBAAmB,EAAE;gBACxB,mBAAmB,CAAC,OAAO,CAAC;gBAC5B;;YAGF,IAAI,QAAQ,GAAG,KAAK;AACpB,YAAA,KAAK,IAAI,CAAC,GAAG,OAAO,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,EAAE;gBACpD,MAAM,KAAK,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC,CAA0B;AACzD,gBAAA,MAAM,IAAI,GAAI,KAA2B,CAAC,IAAI;gBAC9C,IAAI,IAAI,KAAKA,kBAAY,CAAC,IAAI,IAAI,IAAI,KAAK,MAAM,EAAE;AACjD,oBAAA,MAAM,IAAI,GAAI,KAA2B,CAAC,IAAI;oBAC9C,IAAI,IAAI,KAAK,EAAE,IAAI,IAAI,KAAK,SAAS,EAAE;wBACrC;;oBAEF,OAAO,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE;AAC/B,wBAAA,UAAU,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE;AACP,qBAAA,CAAC;oBAC3B,QAAQ,GAAG,IAAI;oBACf;;;YAGJ,IAAI,CAAC,QAAQ,EAAE;AACb,gBAAA,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC;AACnB,oBAAA,UAAU,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE;AACP,iBAAA,CAAC;;AAE7B,YAAA,gBAAgB,EAAE;;QAGpB,mBAAmB,CAAC,OAAO,CAAC;;AAG9B,IAAA,OAAO,eAAe;AACxB;;;;;;;"}
1
+ {"version":3,"file":"cache.cjs","sources":["../../../src/messages/cache.ts"],"sourcesContent":["import {\n BaseMessage,\n MessageContentComplex,\n AIMessage,\n HumanMessage,\n SystemMessage,\n ToolMessage,\n} from '@langchain/core/messages';\nimport type { AnthropicMessage } from '@/types/messages';\nimport type Anthropic from '@anthropic-ai/sdk';\nimport { ContentTypes } from '@/common/enum';\n\ntype MessageWithContent = {\n content?: string | MessageContentComplex[];\n};\n\n/**\n * Deep clones a message's content to prevent mutation of the original.\n */\nfunction deepCloneContent<T extends string | MessageContentComplex[]>(\n content: T\n): T {\n if (typeof content === 'string') {\n return content;\n }\n if (Array.isArray(content)) {\n return content.map((block) => ({ ...block })) as T;\n }\n return content;\n}\n\n/**\n * Simple shallow clone with deep-cloned content.\n * Used for stripping cache control where we don't need proper LangChain instances.\n */\nfunction shallowCloneMessage<T extends MessageWithContent>(message: T): T {\n return {\n ...message,\n content: deepCloneContent(message.content ?? ''),\n } as T;\n}\n\n/**\n * Creates a new LangChain message instance with the given content.\n * Required when adding cache points to ensure proper serialization.\n */\nfunction createNewMessage<T extends MessageWithContent>(\n message: T,\n content: MessageContentComplex[]\n): T {\n if ('getType' in message && typeof message.getType === 'function') {\n const baseMsg = message as unknown as BaseMessage;\n const msgType = baseMsg.getType();\n\n const baseFields = {\n content,\n name: baseMsg.name,\n additional_kwargs: { ...baseMsg.additional_kwargs },\n response_metadata: { ...baseMsg.response_metadata },\n id: baseMsg.id,\n };\n\n switch (msgType) {\n case 'human':\n return new HumanMessage(baseFields) as unknown as T;\n case 'ai': {\n const aiMsg = baseMsg as AIMessage;\n return new AIMessage({\n ...baseFields,\n tool_calls: aiMsg.tool_calls ? [...aiMsg.tool_calls] : [],\n invalid_tool_calls: aiMsg.invalid_tool_calls\n ? [...aiMsg.invalid_tool_calls]\n : [],\n usage_metadata: aiMsg.usage_metadata,\n }) as unknown as T;\n }\n case 'system':\n return new SystemMessage(baseFields) as unknown as T;\n case 'tool': {\n const toolMsg = baseMsg as ToolMessage;\n return new ToolMessage({\n ...baseFields,\n tool_call_id: toolMsg.tool_call_id,\n status: toolMsg.status,\n artifact: toolMsg.artifact,\n }) as unknown as T;\n }\n default:\n break;\n }\n }\n\n const cloned = { ...message, content } as T;\n const lcKwargs = (cloned as Record<string, unknown>).lc_kwargs as\n | Record<string, unknown>\n | undefined;\n if (lcKwargs != null) {\n (cloned as Record<string, unknown>).lc_kwargs = { ...lcKwargs, content };\n }\n return cloned;\n}\n\n/**\n * Checks if a message's content needs cache control stripping.\n * Returns true if content has cachePoint blocks or cache_control fields.\n */\nfunction needsCacheStripping(content: MessageContentComplex[]): boolean {\n for (let i = 0; i < content.length; i++) {\n const block = content[i];\n if (isCachePoint(block)) return true;\n if ('cache_control' in block) return true;\n }\n return false;\n}\n\n/**\n * Anthropic API: Adds cache control to the appropriate user messages in the payload.\n * Strips ALL existing cache control (both Anthropic and Bedrock formats) from all messages,\n * then adds fresh cache control to the last 2 user messages in a single backward pass.\n * This ensures we don't accumulate stale cache points across multiple turns.\n * Returns a new array - only clones messages that require modification.\n * @param messages - The array of message objects.\n * @returns - A new array of message objects with cache control added.\n */\nexport function addCacheControl<T extends AnthropicMessage | BaseMessage>(\n messages: T[]\n): T[] {\n if (!Array.isArray(messages) || messages.length < 2) {\n return messages;\n }\n\n const updatedMessages: T[] = [...messages];\n let userMessagesModified = 0;\n\n for (let i = updatedMessages.length - 1; i >= 0; i--) {\n const originalMessage = updatedMessages[i];\n const isUserMessage =\n ('getType' in originalMessage && originalMessage.getType() === 'human') ||\n ('role' in originalMessage && originalMessage.role === 'user');\n\n const hasArrayContent = Array.isArray(originalMessage.content);\n const needsStripping =\n hasArrayContent &&\n needsCacheStripping(originalMessage.content as MessageContentComplex[]);\n const needsCacheAdd =\n userMessagesModified < 2 &&\n isUserMessage &&\n (typeof originalMessage.content === 'string' || hasArrayContent);\n\n if (!needsStripping && !needsCacheAdd) {\n continue;\n }\n\n const message = shallowCloneMessage(\n originalMessage as MessageWithContent\n ) as T;\n updatedMessages[i] = message;\n\n if (hasArrayContent) {\n message.content = (message.content as MessageContentComplex[]).filter(\n (block) => !isCachePoint(block as MessageContentComplex)\n ) as typeof message.content;\n\n for (\n let j = 0;\n j < (message.content as MessageContentComplex[]).length;\n j++\n ) {\n const block = (message.content as MessageContentComplex[])[j] as Record<\n string,\n unknown\n >;\n if ('cache_control' in block) {\n delete block.cache_control;\n }\n }\n }\n\n if (userMessagesModified >= 2 || !isUserMessage) {\n continue;\n }\n\n if (typeof message.content === 'string') {\n message.content = [\n {\n type: 'text',\n text: message.content,\n cache_control: { type: 'ephemeral' },\n },\n ];\n userMessagesModified++;\n } else if (Array.isArray(message.content)) {\n for (let j = message.content.length - 1; j >= 0; j--) {\n const contentPart = message.content[j];\n if ('type' in contentPart && contentPart.type === 'text') {\n (contentPart as Anthropic.TextBlockParam).cache_control = {\n type: 'ephemeral',\n };\n userMessagesModified++;\n break;\n }\n }\n }\n }\n\n return updatedMessages;\n}\n\n/**\n * Checks if a content block is a cache point\n */\nfunction isCachePoint(block: MessageContentComplex): boolean {\n return 'cachePoint' in block && !('type' in block);\n}\n\n/**\n * Checks if a message's content has Anthropic cache_control fields.\n */\nfunction hasAnthropicCacheControl(content: MessageContentComplex[]): boolean {\n for (let i = 0; i < content.length; i++) {\n if ('cache_control' in content[i]) return true;\n }\n return false;\n}\n\n/**\n * Removes all Anthropic cache_control fields from messages\n * Used when switching from Anthropic to Bedrock provider\n * Returns a new array - only clones messages that require modification.\n */\nexport function stripAnthropicCacheControl<T extends MessageWithContent>(\n messages: T[]\n): T[] {\n if (!Array.isArray(messages)) {\n return messages;\n }\n\n const updatedMessages: T[] = [...messages];\n\n for (let i = 0; i < updatedMessages.length; i++) {\n const originalMessage = updatedMessages[i];\n const content = originalMessage.content;\n\n if (!Array.isArray(content) || !hasAnthropicCacheControl(content)) {\n continue;\n }\n\n const message = shallowCloneMessage(originalMessage);\n updatedMessages[i] = message;\n\n for (\n let j = 0;\n j < (message.content as MessageContentComplex[]).length;\n j++\n ) {\n const block = (message.content as MessageContentComplex[])[j] as Record<\n string,\n unknown\n >;\n if ('cache_control' in block) {\n delete block.cache_control;\n }\n }\n }\n\n return updatedMessages;\n}\n\n/**\n * Checks if a message's content has Bedrock cachePoint blocks.\n */\nfunction hasBedrockCachePoint(content: MessageContentComplex[]): boolean {\n for (let i = 0; i < content.length; i++) {\n if (isCachePoint(content[i])) return true;\n }\n return false;\n}\n\n/**\n * Removes all Bedrock cachePoint blocks from messages\n * Used when switching from Bedrock to Anthropic provider\n * Returns a new array - only clones messages that require modification.\n */\nexport function stripBedrockCacheControl<T extends MessageWithContent>(\n messages: T[]\n): T[] {\n if (!Array.isArray(messages)) {\n return messages;\n }\n\n const updatedMessages: T[] = [...messages];\n\n for (let i = 0; i < updatedMessages.length; i++) {\n const originalMessage = updatedMessages[i];\n const content = originalMessage.content;\n\n if (!Array.isArray(content) || !hasBedrockCachePoint(content)) {\n continue;\n }\n\n const message = shallowCloneMessage(originalMessage);\n updatedMessages[i] = message;\n\n message.content = (message.content as MessageContentComplex[]).filter(\n (block) => !isCachePoint(block as MessageContentComplex)\n ) as typeof content;\n }\n\n return updatedMessages;\n}\n\n/**\n * Adds Bedrock Converse API cache points to the last two messages.\n * Inserts `{ cachePoint: { type: 'default' } }` as a separate content block\n * immediately after the last text block in each targeted message.\n * Strips ALL existing cache control (both Bedrock and Anthropic formats) from all messages,\n * then adds fresh cache points to the last 2 messages in a single backward pass.\n * This ensures we don't accumulate stale cache points across multiple turns.\n * Returns a new array - only clones messages that require modification.\n * @param messages - The array of message objects.\n * @returns - A new array of message objects with cache points added.\n */\nexport function addBedrockCacheControl<\n T extends Partial<BaseMessage> & MessageWithContent,\n>(messages: T[]): T[] {\n if (!Array.isArray(messages) || messages.length < 2) {\n return messages;\n }\n\n const updatedMessages: T[] = [...messages];\n let messagesModified = 0;\n\n for (let i = updatedMessages.length - 1; i >= 0; i--) {\n const originalMessage = updatedMessages[i];\n const isToolMessage =\n 'getType' in originalMessage &&\n typeof originalMessage.getType === 'function' &&\n originalMessage.getType() === 'tool';\n\n const content = originalMessage.content;\n const hasArrayContent = Array.isArray(content);\n const needsStripping =\n hasArrayContent &&\n needsCacheStripping(content as MessageContentComplex[]);\n const isEmptyString = typeof content === 'string' && content === '';\n const needsCacheAdd =\n messagesModified < 2 &&\n !isToolMessage &&\n !isEmptyString &&\n (typeof content === 'string' || hasArrayContent);\n\n if (!needsStripping && !needsCacheAdd) {\n continue;\n }\n\n let workingContent: MessageContentComplex[];\n\n if (hasArrayContent) {\n workingContent = deepCloneContent(\n content as MessageContentComplex[]\n ).filter((block) => !isCachePoint(block));\n\n for (let j = 0; j < workingContent.length; j++) {\n const block = workingContent[j] as Record<string, unknown>;\n if ('cache_control' in block) {\n delete block.cache_control;\n }\n }\n } else if (typeof content === 'string') {\n workingContent = [{ type: ContentTypes.TEXT, text: content }];\n } else {\n workingContent = [];\n }\n\n if (messagesModified >= 2 || isToolMessage || isEmptyString) {\n updatedMessages[i] = shallowCloneMessage(originalMessage);\n (updatedMessages[i] as MessageWithContent).content = workingContent;\n continue;\n }\n\n if (workingContent.length === 0) {\n continue;\n }\n\n let hasCacheableContent = false;\n for (const block of workingContent) {\n if (block.type === ContentTypes.TEXT) {\n if (typeof block.text === 'string' && block.text !== '') {\n hasCacheableContent = true;\n break;\n }\n }\n }\n\n if (!hasCacheableContent) {\n updatedMessages[i] = shallowCloneMessage(originalMessage);\n (updatedMessages[i] as MessageWithContent).content = workingContent;\n continue;\n }\n\n let inserted = false;\n for (let j = workingContent.length - 1; j >= 0; j--) {\n const block = workingContent[j] as MessageContentComplex;\n const type = (block as { type?: string }).type;\n if (type === ContentTypes.TEXT || type === 'text') {\n const text = (block as { text?: string }).text;\n if (text === '' || text === undefined) {\n continue;\n }\n workingContent.splice(j + 1, 0, {\n cachePoint: { type: 'default' },\n } as MessageContentComplex);\n inserted = true;\n break;\n }\n }\n if (!inserted) {\n workingContent.push({\n cachePoint: { type: 'default' },\n } as MessageContentComplex);\n }\n\n updatedMessages[i] = createNewMessage(originalMessage, workingContent);\n messagesModified++;\n }\n\n return updatedMessages;\n}\n"],"names":["HumanMessage","AIMessage","SystemMessage","ToolMessage","ContentTypes"],"mappings":"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"}
@@ -1,8 +1,8 @@
1
+ import { ToolMessage, SystemMessage, AIMessage, HumanMessage } from '@langchain/core/messages';
1
2
  import { ContentTypes } from '../common/enum.mjs';
2
3
 
3
4
  /**
4
5
  * Deep clones a message's content to prevent mutation of the original.
5
- * Handles both string and array content types.
6
6
  */
7
7
  function deepCloneContent(content) {
8
8
  if (typeof content === 'string') {
@@ -14,37 +14,63 @@ function deepCloneContent(content) {
14
14
  return content;
15
15
  }
16
16
  /**
17
- * Creates a shallow clone of a message with deep-cloned content.
18
- * This ensures modifications to content don't affect the original message.
17
+ * Simple shallow clone with deep-cloned content.
18
+ * Used for stripping cache control where we don't need proper LangChain instances.
19
19
  */
20
- function cloneMessageWithContent(message) {
21
- if (message.content === undefined) {
22
- return { ...message };
23
- }
24
- const clonedContent = deepCloneContent(message.content);
25
- const cloned = {
20
+ function shallowCloneMessage(message) {
21
+ return {
26
22
  ...message,
27
- content: clonedContent,
23
+ content: deepCloneContent(message.content ?? ''),
28
24
  };
29
- /**
30
- * LangChain messages store internal state in lc_kwargs.
31
- * Clone it but don't sync content yet - that happens after all modifications.
32
- */
33
- const lcKwargs = message.lc_kwargs;
34
- if (lcKwargs != null && typeof lcKwargs === 'object') {
35
- cloned.lc_kwargs = { ...lcKwargs };
36
- }
37
- return cloned;
38
25
  }
39
26
  /**
40
- * Syncs lc_kwargs.content with the message's content property.
41
- * Call this after all modifications to ensure LangChain serialization works correctly.
27
+ * Creates a new LangChain message instance with the given content.
28
+ * Required when adding cache points to ensure proper serialization.
42
29
  */
43
- function syncLcKwargsContent(message) {
44
- const lcKwargs = message.lc_kwargs;
45
- if (lcKwargs != null && typeof lcKwargs === 'object') {
46
- lcKwargs.content = message.content;
30
+ function createNewMessage(message, content) {
31
+ if ('getType' in message && typeof message.getType === 'function') {
32
+ const baseMsg = message;
33
+ const msgType = baseMsg.getType();
34
+ const baseFields = {
35
+ content,
36
+ name: baseMsg.name,
37
+ additional_kwargs: { ...baseMsg.additional_kwargs },
38
+ response_metadata: { ...baseMsg.response_metadata },
39
+ id: baseMsg.id,
40
+ };
41
+ switch (msgType) {
42
+ case 'human':
43
+ return new HumanMessage(baseFields);
44
+ case 'ai': {
45
+ const aiMsg = baseMsg;
46
+ return new AIMessage({
47
+ ...baseFields,
48
+ tool_calls: aiMsg.tool_calls ? [...aiMsg.tool_calls] : [],
49
+ invalid_tool_calls: aiMsg.invalid_tool_calls
50
+ ? [...aiMsg.invalid_tool_calls]
51
+ : [],
52
+ usage_metadata: aiMsg.usage_metadata,
53
+ });
54
+ }
55
+ case 'system':
56
+ return new SystemMessage(baseFields);
57
+ case 'tool': {
58
+ const toolMsg = baseMsg;
59
+ return new ToolMessage({
60
+ ...baseFields,
61
+ tool_call_id: toolMsg.tool_call_id,
62
+ status: toolMsg.status,
63
+ artifact: toolMsg.artifact,
64
+ });
65
+ }
66
+ }
47
67
  }
68
+ const cloned = { ...message, content };
69
+ const lcKwargs = cloned.lc_kwargs;
70
+ if (lcKwargs != null) {
71
+ cloned.lc_kwargs = { ...lcKwargs, content };
72
+ }
73
+ return cloned;
48
74
  }
49
75
  /**
50
76
  * Checks if a message's content needs cache control stripping.
@@ -88,7 +114,7 @@ function addCacheControl(messages) {
88
114
  if (!needsStripping && !needsCacheAdd) {
89
115
  continue;
90
116
  }
91
- const message = cloneMessageWithContent(originalMessage);
117
+ const message = shallowCloneMessage(originalMessage);
92
118
  updatedMessages[i] = message;
93
119
  if (hasArrayContent) {
94
120
  message.content = message.content.filter((block) => !isCachePoint(block));
@@ -100,7 +126,6 @@ function addCacheControl(messages) {
100
126
  }
101
127
  }
102
128
  if (userMessagesModified >= 2 || !isUserMessage) {
103
- syncLcKwargsContent(message);
104
129
  continue;
105
130
  }
106
131
  if (typeof message.content === 'string') {
@@ -125,7 +150,6 @@ function addCacheControl(messages) {
125
150
  }
126
151
  }
127
152
  }
128
- syncLcKwargsContent(message);
129
153
  }
130
154
  return updatedMessages;
131
155
  }
@@ -161,7 +185,7 @@ function stripAnthropicCacheControl(messages) {
161
185
  if (!Array.isArray(content) || !hasAnthropicCacheControl(content)) {
162
186
  continue;
163
187
  }
164
- const message = cloneMessageWithContent(originalMessage);
188
+ const message = shallowCloneMessage(originalMessage);
165
189
  updatedMessages[i] = message;
166
190
  for (let j = 0; j < message.content.length; j++) {
167
191
  const block = message.content[j];
@@ -198,7 +222,7 @@ function stripBedrockCacheControl(messages) {
198
222
  if (!Array.isArray(content) || !hasBedrockCachePoint(content)) {
199
223
  continue;
200
224
  }
201
- const message = cloneMessageWithContent(originalMessage);
225
+ const message = shallowCloneMessage(originalMessage);
202
226
  updatedMessages[i] = message;
203
227
  message.content = message.content.filter((block) => !isCachePoint(block));
204
228
  }
@@ -238,68 +262,67 @@ function addBedrockCacheControl(messages) {
238
262
  if (!needsStripping && !needsCacheAdd) {
239
263
  continue;
240
264
  }
241
- const message = cloneMessageWithContent(originalMessage);
242
- updatedMessages[i] = message;
265
+ let workingContent;
243
266
  if (hasArrayContent) {
244
- message.content = message.content.filter((block) => !isCachePoint(block));
245
- for (let j = 0; j < message.content.length; j++) {
246
- const block = message.content[j];
267
+ workingContent = deepCloneContent(content).filter((block) => !isCachePoint(block));
268
+ for (let j = 0; j < workingContent.length; j++) {
269
+ const block = workingContent[j];
247
270
  if ('cache_control' in block) {
248
271
  delete block.cache_control;
249
272
  }
250
273
  }
251
274
  }
275
+ else if (typeof content === 'string') {
276
+ workingContent = [{ type: ContentTypes.TEXT, text: content }];
277
+ }
278
+ else {
279
+ workingContent = [];
280
+ }
252
281
  if (messagesModified >= 2 || isToolMessage || isEmptyString) {
253
- syncLcKwargsContent(message);
282
+ updatedMessages[i] = shallowCloneMessage(originalMessage);
283
+ updatedMessages[i].content = workingContent;
254
284
  continue;
255
285
  }
256
- if (typeof message.content === 'string') {
257
- message.content = [
258
- { type: ContentTypes.TEXT, text: message.content },
259
- { cachePoint: { type: 'default' } },
260
- ];
261
- messagesModified++;
262
- syncLcKwargsContent(message);
286
+ if (workingContent.length === 0) {
263
287
  continue;
264
288
  }
265
- if (Array.isArray(message.content)) {
266
- let hasCacheableContent = false;
267
- for (const block of message.content) {
268
- if (block.type === ContentTypes.TEXT) {
269
- if (typeof block.text === 'string' && block.text !== '') {
270
- hasCacheableContent = true;
271
- break;
272
- }
273
- }
274
- }
275
- if (!hasCacheableContent) {
276
- syncLcKwargsContent(message);
277
- continue;
278
- }
279
- let inserted = false;
280
- for (let j = message.content.length - 1; j >= 0; j--) {
281
- const block = message.content[j];
282
- const type = block.type;
283
- if (type === ContentTypes.TEXT || type === 'text') {
284
- const text = block.text;
285
- if (text === '' || text === undefined) {
286
- continue;
287
- }
288
- message.content.splice(j + 1, 0, {
289
- cachePoint: { type: 'default' },
290
- });
291
- inserted = true;
289
+ let hasCacheableContent = false;
290
+ for (const block of workingContent) {
291
+ if (block.type === ContentTypes.TEXT) {
292
+ if (typeof block.text === 'string' && block.text !== '') {
293
+ hasCacheableContent = true;
292
294
  break;
293
295
  }
294
296
  }
295
- if (!inserted) {
296
- message.content.push({
297
+ }
298
+ if (!hasCacheableContent) {
299
+ updatedMessages[i] = shallowCloneMessage(originalMessage);
300
+ updatedMessages[i].content = workingContent;
301
+ continue;
302
+ }
303
+ let inserted = false;
304
+ for (let j = workingContent.length - 1; j >= 0; j--) {
305
+ const block = workingContent[j];
306
+ const type = block.type;
307
+ if (type === ContentTypes.TEXT || type === 'text') {
308
+ const text = block.text;
309
+ if (text === '' || text === undefined) {
310
+ continue;
311
+ }
312
+ workingContent.splice(j + 1, 0, {
297
313
  cachePoint: { type: 'default' },
298
314
  });
315
+ inserted = true;
316
+ break;
299
317
  }
300
- messagesModified++;
301
318
  }
302
- syncLcKwargsContent(message);
319
+ if (!inserted) {
320
+ workingContent.push({
321
+ cachePoint: { type: 'default' },
322
+ });
323
+ }
324
+ updatedMessages[i] = createNewMessage(originalMessage, workingContent);
325
+ messagesModified++;
303
326
  }
304
327
  return updatedMessages;
305
328
  }
@@ -1 +1 @@
1
- {"version":3,"file":"cache.mjs","sources":["../../../src/messages/cache.ts"],"sourcesContent":["import { BaseMessage, MessageContentComplex } from '@langchain/core/messages';\nimport type { AnthropicMessage } from '@/types/messages';\nimport type Anthropic from '@anthropic-ai/sdk';\nimport { ContentTypes } from '@/common/enum';\n\ntype MessageWithContent = {\n content?: string | MessageContentComplex[];\n};\n\n/**\n * Deep clones a message's content to prevent mutation of the original.\n * Handles both string and array content types.\n */\nfunction deepCloneContent<T extends string | MessageContentComplex[]>(\n content: T\n): T {\n if (typeof content === 'string') {\n return content;\n }\n if (Array.isArray(content)) {\n return content.map((block) => ({ ...block })) as T;\n }\n return content;\n}\n\n/**\n * Creates a shallow clone of a message with deep-cloned content.\n * This ensures modifications to content don't affect the original message.\n */\nfunction cloneMessageWithContent<T extends MessageWithContent>(message: T): T {\n if (message.content === undefined) {\n return { ...message };\n }\n\n const clonedContent = deepCloneContent(message.content);\n const cloned = {\n ...message,\n content: clonedContent,\n };\n\n /**\n * LangChain messages store internal state in lc_kwargs.\n * Clone it but don't sync content yet - that happens after all modifications.\n */\n const lcKwargs = (message as Record<string, unknown>).lc_kwargs;\n if (lcKwargs != null && typeof lcKwargs === 'object') {\n (cloned as Record<string, unknown>).lc_kwargs = { ...lcKwargs };\n }\n\n return cloned;\n}\n\n/**\n * Syncs lc_kwargs.content with the message's content property.\n * Call this after all modifications to ensure LangChain serialization works correctly.\n */\nfunction syncLcKwargsContent<T extends MessageWithContent>(message: T): void {\n const lcKwargs = (message as Record<string, unknown>).lc_kwargs;\n if (lcKwargs != null && typeof lcKwargs === 'object') {\n (lcKwargs as Record<string, unknown>).content = message.content;\n }\n}\n\n/**\n * Checks if a message's content needs cache control stripping.\n * Returns true if content has cachePoint blocks or cache_control fields.\n */\nfunction needsCacheStripping(content: MessageContentComplex[]): boolean {\n for (let i = 0; i < content.length; i++) {\n const block = content[i];\n if (isCachePoint(block)) return true;\n if ('cache_control' in block) return true;\n }\n return false;\n}\n\n/**\n * Anthropic API: Adds cache control to the appropriate user messages in the payload.\n * Strips ALL existing cache control (both Anthropic and Bedrock formats) from all messages,\n * then adds fresh cache control to the last 2 user messages in a single backward pass.\n * This ensures we don't accumulate stale cache points across multiple turns.\n * Returns a new array - only clones messages that require modification.\n * @param messages - The array of message objects.\n * @returns - A new array of message objects with cache control added.\n */\nexport function addCacheControl<T extends AnthropicMessage | BaseMessage>(\n messages: T[]\n): T[] {\n if (!Array.isArray(messages) || messages.length < 2) {\n return messages;\n }\n\n const updatedMessages: T[] = [...messages];\n let userMessagesModified = 0;\n\n for (let i = updatedMessages.length - 1; i >= 0; i--) {\n const originalMessage = updatedMessages[i];\n const isUserMessage =\n ('getType' in originalMessage && originalMessage.getType() === 'human') ||\n ('role' in originalMessage && originalMessage.role === 'user');\n\n const hasArrayContent = Array.isArray(originalMessage.content);\n const needsStripping =\n hasArrayContent &&\n needsCacheStripping(originalMessage.content as MessageContentComplex[]);\n const needsCacheAdd =\n userMessagesModified < 2 &&\n isUserMessage &&\n (typeof originalMessage.content === 'string' || hasArrayContent);\n\n if (!needsStripping && !needsCacheAdd) {\n continue;\n }\n\n const message = cloneMessageWithContent(\n originalMessage as MessageWithContent\n ) as T;\n updatedMessages[i] = message;\n\n if (hasArrayContent) {\n message.content = (message.content as MessageContentComplex[]).filter(\n (block) => !isCachePoint(block as MessageContentComplex)\n ) as typeof message.content;\n\n for (\n let j = 0;\n j < (message.content as MessageContentComplex[]).length;\n j++\n ) {\n const block = (message.content as MessageContentComplex[])[j] as Record<\n string,\n unknown\n >;\n if ('cache_control' in block) {\n delete block.cache_control;\n }\n }\n }\n\n if (userMessagesModified >= 2 || !isUserMessage) {\n syncLcKwargsContent(message);\n continue;\n }\n\n if (typeof message.content === 'string') {\n message.content = [\n {\n type: 'text',\n text: message.content,\n cache_control: { type: 'ephemeral' },\n },\n ];\n userMessagesModified++;\n } else if (Array.isArray(message.content)) {\n for (let j = message.content.length - 1; j >= 0; j--) {\n const contentPart = message.content[j];\n if ('type' in contentPart && contentPart.type === 'text') {\n (contentPart as Anthropic.TextBlockParam).cache_control = {\n type: 'ephemeral',\n };\n userMessagesModified++;\n break;\n }\n }\n }\n\n syncLcKwargsContent(message);\n }\n\n return updatedMessages;\n}\n\n/**\n * Checks if a content block is a cache point\n */\nfunction isCachePoint(block: MessageContentComplex): boolean {\n return 'cachePoint' in block && !('type' in block);\n}\n\n/**\n * Checks if a message's content has Anthropic cache_control fields.\n */\nfunction hasAnthropicCacheControl(content: MessageContentComplex[]): boolean {\n for (let i = 0; i < content.length; i++) {\n if ('cache_control' in content[i]) return true;\n }\n return false;\n}\n\n/**\n * Removes all Anthropic cache_control fields from messages\n * Used when switching from Anthropic to Bedrock provider\n * Returns a new array - only clones messages that require modification.\n */\nexport function stripAnthropicCacheControl<T extends MessageWithContent>(\n messages: T[]\n): T[] {\n if (!Array.isArray(messages)) {\n return messages;\n }\n\n const updatedMessages: T[] = [...messages];\n\n for (let i = 0; i < updatedMessages.length; i++) {\n const originalMessage = updatedMessages[i];\n const content = originalMessage.content;\n\n if (!Array.isArray(content) || !hasAnthropicCacheControl(content)) {\n continue;\n }\n\n const message = cloneMessageWithContent(originalMessage);\n updatedMessages[i] = message;\n\n for (\n let j = 0;\n j < (message.content as MessageContentComplex[]).length;\n j++\n ) {\n const block = (message.content as MessageContentComplex[])[j] as Record<\n string,\n unknown\n >;\n if ('cache_control' in block) {\n delete block.cache_control;\n }\n }\n }\n\n return updatedMessages;\n}\n\n/**\n * Checks if a message's content has Bedrock cachePoint blocks.\n */\nfunction hasBedrockCachePoint(content: MessageContentComplex[]): boolean {\n for (let i = 0; i < content.length; i++) {\n if (isCachePoint(content[i])) return true;\n }\n return false;\n}\n\n/**\n * Removes all Bedrock cachePoint blocks from messages\n * Used when switching from Bedrock to Anthropic provider\n * Returns a new array - only clones messages that require modification.\n */\nexport function stripBedrockCacheControl<T extends MessageWithContent>(\n messages: T[]\n): T[] {\n if (!Array.isArray(messages)) {\n return messages;\n }\n\n const updatedMessages: T[] = [...messages];\n\n for (let i = 0; i < updatedMessages.length; i++) {\n const originalMessage = updatedMessages[i];\n const content = originalMessage.content;\n\n if (!Array.isArray(content) || !hasBedrockCachePoint(content)) {\n continue;\n }\n\n const message = cloneMessageWithContent(originalMessage);\n updatedMessages[i] = message;\n\n message.content = (message.content as MessageContentComplex[]).filter(\n (block) => !isCachePoint(block as MessageContentComplex)\n ) as typeof content;\n }\n\n return updatedMessages;\n}\n\n/**\n * Adds Bedrock Converse API cache points to the last two messages.\n * Inserts `{ cachePoint: { type: 'default' } }` as a separate content block\n * immediately after the last text block in each targeted message.\n * Strips ALL existing cache control (both Bedrock and Anthropic formats) from all messages,\n * then adds fresh cache points to the last 2 messages in a single backward pass.\n * This ensures we don't accumulate stale cache points across multiple turns.\n * Returns a new array - only clones messages that require modification.\n * @param messages - The array of message objects.\n * @returns - A new array of message objects with cache points added.\n */\nexport function addBedrockCacheControl<\n T extends Partial<BaseMessage> & MessageWithContent,\n>(messages: T[]): T[] {\n if (!Array.isArray(messages) || messages.length < 2) {\n return messages;\n }\n\n const updatedMessages: T[] = [...messages];\n let messagesModified = 0;\n\n for (let i = updatedMessages.length - 1; i >= 0; i--) {\n const originalMessage = updatedMessages[i];\n const isToolMessage =\n 'getType' in originalMessage &&\n typeof originalMessage.getType === 'function' &&\n originalMessage.getType() === 'tool';\n\n const content = originalMessage.content;\n const hasArrayContent = Array.isArray(content);\n const needsStripping =\n hasArrayContent &&\n needsCacheStripping(content as MessageContentComplex[]);\n const isEmptyString = typeof content === 'string' && content === '';\n const needsCacheAdd =\n messagesModified < 2 &&\n !isToolMessage &&\n !isEmptyString &&\n (typeof content === 'string' || hasArrayContent);\n\n if (!needsStripping && !needsCacheAdd) {\n continue;\n }\n\n const message = cloneMessageWithContent(originalMessage);\n updatedMessages[i] = message;\n\n if (hasArrayContent) {\n message.content = (message.content as MessageContentComplex[]).filter(\n (block) => !isCachePoint(block)\n ) as typeof content;\n\n for (\n let j = 0;\n j < (message.content as MessageContentComplex[]).length;\n j++\n ) {\n const block = (message.content as MessageContentComplex[])[j] as Record<\n string,\n unknown\n >;\n if ('cache_control' in block) {\n delete block.cache_control;\n }\n }\n }\n\n if (messagesModified >= 2 || isToolMessage || isEmptyString) {\n syncLcKwargsContent(message);\n continue;\n }\n\n if (typeof message.content === 'string') {\n message.content = [\n { type: ContentTypes.TEXT, text: message.content },\n { cachePoint: { type: 'default' } },\n ] as MessageContentComplex[];\n messagesModified++;\n syncLcKwargsContent(message);\n continue;\n }\n\n if (Array.isArray(message.content)) {\n let hasCacheableContent = false;\n for (const block of message.content) {\n if (block.type === ContentTypes.TEXT) {\n if (typeof block.text === 'string' && block.text !== '') {\n hasCacheableContent = true;\n break;\n }\n }\n }\n\n if (!hasCacheableContent) {\n syncLcKwargsContent(message);\n continue;\n }\n\n let inserted = false;\n for (let j = message.content.length - 1; j >= 0; j--) {\n const block = message.content[j] as MessageContentComplex;\n const type = (block as { type?: string }).type;\n if (type === ContentTypes.TEXT || type === 'text') {\n const text = (block as { text?: string }).text;\n if (text === '' || text === undefined) {\n continue;\n }\n message.content.splice(j + 1, 0, {\n cachePoint: { type: 'default' },\n } as MessageContentComplex);\n inserted = true;\n break;\n }\n }\n if (!inserted) {\n message.content.push({\n cachePoint: { type: 'default' },\n } as MessageContentComplex);\n }\n messagesModified++;\n }\n\n syncLcKwargsContent(message);\n }\n\n return updatedMessages;\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"cache.mjs","sources":["../../../src/messages/cache.ts"],"sourcesContent":["import {\n BaseMessage,\n MessageContentComplex,\n AIMessage,\n HumanMessage,\n SystemMessage,\n ToolMessage,\n} from '@langchain/core/messages';\nimport type { AnthropicMessage } from '@/types/messages';\nimport type Anthropic from '@anthropic-ai/sdk';\nimport { ContentTypes } from '@/common/enum';\n\ntype MessageWithContent = {\n content?: string | MessageContentComplex[];\n};\n\n/**\n * Deep clones a message's content to prevent mutation of the original.\n */\nfunction deepCloneContent<T extends string | MessageContentComplex[]>(\n content: T\n): T {\n if (typeof content === 'string') {\n return content;\n }\n if (Array.isArray(content)) {\n return content.map((block) => ({ ...block })) as T;\n }\n return content;\n}\n\n/**\n * Simple shallow clone with deep-cloned content.\n * Used for stripping cache control where we don't need proper LangChain instances.\n */\nfunction shallowCloneMessage<T extends MessageWithContent>(message: T): T {\n return {\n ...message,\n content: deepCloneContent(message.content ?? ''),\n } as T;\n}\n\n/**\n * Creates a new LangChain message instance with the given content.\n * Required when adding cache points to ensure proper serialization.\n */\nfunction createNewMessage<T extends MessageWithContent>(\n message: T,\n content: MessageContentComplex[]\n): T {\n if ('getType' in message && typeof message.getType === 'function') {\n const baseMsg = message as unknown as BaseMessage;\n const msgType = baseMsg.getType();\n\n const baseFields = {\n content,\n name: baseMsg.name,\n additional_kwargs: { ...baseMsg.additional_kwargs },\n response_metadata: { ...baseMsg.response_metadata },\n id: baseMsg.id,\n };\n\n switch (msgType) {\n case 'human':\n return new HumanMessage(baseFields) as unknown as T;\n case 'ai': {\n const aiMsg = baseMsg as AIMessage;\n return new AIMessage({\n ...baseFields,\n tool_calls: aiMsg.tool_calls ? [...aiMsg.tool_calls] : [],\n invalid_tool_calls: aiMsg.invalid_tool_calls\n ? [...aiMsg.invalid_tool_calls]\n : [],\n usage_metadata: aiMsg.usage_metadata,\n }) as unknown as T;\n }\n case 'system':\n return new SystemMessage(baseFields) as unknown as T;\n case 'tool': {\n const toolMsg = baseMsg as ToolMessage;\n return new ToolMessage({\n ...baseFields,\n tool_call_id: toolMsg.tool_call_id,\n status: toolMsg.status,\n artifact: toolMsg.artifact,\n }) as unknown as T;\n }\n default:\n break;\n }\n }\n\n const cloned = { ...message, content } as T;\n const lcKwargs = (cloned as Record<string, unknown>).lc_kwargs as\n | Record<string, unknown>\n | undefined;\n if (lcKwargs != null) {\n (cloned as Record<string, unknown>).lc_kwargs = { ...lcKwargs, content };\n }\n return cloned;\n}\n\n/**\n * Checks if a message's content needs cache control stripping.\n * Returns true if content has cachePoint blocks or cache_control fields.\n */\nfunction needsCacheStripping(content: MessageContentComplex[]): boolean {\n for (let i = 0; i < content.length; i++) {\n const block = content[i];\n if (isCachePoint(block)) return true;\n if ('cache_control' in block) return true;\n }\n return false;\n}\n\n/**\n * Anthropic API: Adds cache control to the appropriate user messages in the payload.\n * Strips ALL existing cache control (both Anthropic and Bedrock formats) from all messages,\n * then adds fresh cache control to the last 2 user messages in a single backward pass.\n * This ensures we don't accumulate stale cache points across multiple turns.\n * Returns a new array - only clones messages that require modification.\n * @param messages - The array of message objects.\n * @returns - A new array of message objects with cache control added.\n */\nexport function addCacheControl<T extends AnthropicMessage | BaseMessage>(\n messages: T[]\n): T[] {\n if (!Array.isArray(messages) || messages.length < 2) {\n return messages;\n }\n\n const updatedMessages: T[] = [...messages];\n let userMessagesModified = 0;\n\n for (let i = updatedMessages.length - 1; i >= 0; i--) {\n const originalMessage = updatedMessages[i];\n const isUserMessage =\n ('getType' in originalMessage && originalMessage.getType() === 'human') ||\n ('role' in originalMessage && originalMessage.role === 'user');\n\n const hasArrayContent = Array.isArray(originalMessage.content);\n const needsStripping =\n hasArrayContent &&\n needsCacheStripping(originalMessage.content as MessageContentComplex[]);\n const needsCacheAdd =\n userMessagesModified < 2 &&\n isUserMessage &&\n (typeof originalMessage.content === 'string' || hasArrayContent);\n\n if (!needsStripping && !needsCacheAdd) {\n continue;\n }\n\n const message = shallowCloneMessage(\n originalMessage as MessageWithContent\n ) as T;\n updatedMessages[i] = message;\n\n if (hasArrayContent) {\n message.content = (message.content as MessageContentComplex[]).filter(\n (block) => !isCachePoint(block as MessageContentComplex)\n ) as typeof message.content;\n\n for (\n let j = 0;\n j < (message.content as MessageContentComplex[]).length;\n j++\n ) {\n const block = (message.content as MessageContentComplex[])[j] as Record<\n string,\n unknown\n >;\n if ('cache_control' in block) {\n delete block.cache_control;\n }\n }\n }\n\n if (userMessagesModified >= 2 || !isUserMessage) {\n continue;\n }\n\n if (typeof message.content === 'string') {\n message.content = [\n {\n type: 'text',\n text: message.content,\n cache_control: { type: 'ephemeral' },\n },\n ];\n userMessagesModified++;\n } else if (Array.isArray(message.content)) {\n for (let j = message.content.length - 1; j >= 0; j--) {\n const contentPart = message.content[j];\n if ('type' in contentPart && contentPart.type === 'text') {\n (contentPart as Anthropic.TextBlockParam).cache_control = {\n type: 'ephemeral',\n };\n userMessagesModified++;\n break;\n }\n }\n }\n }\n\n return updatedMessages;\n}\n\n/**\n * Checks if a content block is a cache point\n */\nfunction isCachePoint(block: MessageContentComplex): boolean {\n return 'cachePoint' in block && !('type' in block);\n}\n\n/**\n * Checks if a message's content has Anthropic cache_control fields.\n */\nfunction hasAnthropicCacheControl(content: MessageContentComplex[]): boolean {\n for (let i = 0; i < content.length; i++) {\n if ('cache_control' in content[i]) return true;\n }\n return false;\n}\n\n/**\n * Removes all Anthropic cache_control fields from messages\n * Used when switching from Anthropic to Bedrock provider\n * Returns a new array - only clones messages that require modification.\n */\nexport function stripAnthropicCacheControl<T extends MessageWithContent>(\n messages: T[]\n): T[] {\n if (!Array.isArray(messages)) {\n return messages;\n }\n\n const updatedMessages: T[] = [...messages];\n\n for (let i = 0; i < updatedMessages.length; i++) {\n const originalMessage = updatedMessages[i];\n const content = originalMessage.content;\n\n if (!Array.isArray(content) || !hasAnthropicCacheControl(content)) {\n continue;\n }\n\n const message = shallowCloneMessage(originalMessage);\n updatedMessages[i] = message;\n\n for (\n let j = 0;\n j < (message.content as MessageContentComplex[]).length;\n j++\n ) {\n const block = (message.content as MessageContentComplex[])[j] as Record<\n string,\n unknown\n >;\n if ('cache_control' in block) {\n delete block.cache_control;\n }\n }\n }\n\n return updatedMessages;\n}\n\n/**\n * Checks if a message's content has Bedrock cachePoint blocks.\n */\nfunction hasBedrockCachePoint(content: MessageContentComplex[]): boolean {\n for (let i = 0; i < content.length; i++) {\n if (isCachePoint(content[i])) return true;\n }\n return false;\n}\n\n/**\n * Removes all Bedrock cachePoint blocks from messages\n * Used when switching from Bedrock to Anthropic provider\n * Returns a new array - only clones messages that require modification.\n */\nexport function stripBedrockCacheControl<T extends MessageWithContent>(\n messages: T[]\n): T[] {\n if (!Array.isArray(messages)) {\n return messages;\n }\n\n const updatedMessages: T[] = [...messages];\n\n for (let i = 0; i < updatedMessages.length; i++) {\n const originalMessage = updatedMessages[i];\n const content = originalMessage.content;\n\n if (!Array.isArray(content) || !hasBedrockCachePoint(content)) {\n continue;\n }\n\n const message = shallowCloneMessage(originalMessage);\n updatedMessages[i] = message;\n\n message.content = (message.content as MessageContentComplex[]).filter(\n (block) => !isCachePoint(block as MessageContentComplex)\n ) as typeof content;\n }\n\n return updatedMessages;\n}\n\n/**\n * Adds Bedrock Converse API cache points to the last two messages.\n * Inserts `{ cachePoint: { type: 'default' } }` as a separate content block\n * immediately after the last text block in each targeted message.\n * Strips ALL existing cache control (both Bedrock and Anthropic formats) from all messages,\n * then adds fresh cache points to the last 2 messages in a single backward pass.\n * This ensures we don't accumulate stale cache points across multiple turns.\n * Returns a new array - only clones messages that require modification.\n * @param messages - The array of message objects.\n * @returns - A new array of message objects with cache points added.\n */\nexport function addBedrockCacheControl<\n T extends Partial<BaseMessage> & MessageWithContent,\n>(messages: T[]): T[] {\n if (!Array.isArray(messages) || messages.length < 2) {\n return messages;\n }\n\n const updatedMessages: T[] = [...messages];\n let messagesModified = 0;\n\n for (let i = updatedMessages.length - 1; i >= 0; i--) {\n const originalMessage = updatedMessages[i];\n const isToolMessage =\n 'getType' in originalMessage &&\n typeof originalMessage.getType === 'function' &&\n originalMessage.getType() === 'tool';\n\n const content = originalMessage.content;\n const hasArrayContent = Array.isArray(content);\n const needsStripping =\n hasArrayContent &&\n needsCacheStripping(content as MessageContentComplex[]);\n const isEmptyString = typeof content === 'string' && content === '';\n const needsCacheAdd =\n messagesModified < 2 &&\n !isToolMessage &&\n !isEmptyString &&\n (typeof content === 'string' || hasArrayContent);\n\n if (!needsStripping && !needsCacheAdd) {\n continue;\n }\n\n let workingContent: MessageContentComplex[];\n\n if (hasArrayContent) {\n workingContent = deepCloneContent(\n content as MessageContentComplex[]\n ).filter((block) => !isCachePoint(block));\n\n for (let j = 0; j < workingContent.length; j++) {\n const block = workingContent[j] as Record<string, unknown>;\n if ('cache_control' in block) {\n delete block.cache_control;\n }\n }\n } else if (typeof content === 'string') {\n workingContent = [{ type: ContentTypes.TEXT, text: content }];\n } else {\n workingContent = [];\n }\n\n if (messagesModified >= 2 || isToolMessage || isEmptyString) {\n updatedMessages[i] = shallowCloneMessage(originalMessage);\n (updatedMessages[i] as MessageWithContent).content = workingContent;\n continue;\n }\n\n if (workingContent.length === 0) {\n continue;\n }\n\n let hasCacheableContent = false;\n for (const block of workingContent) {\n if (block.type === ContentTypes.TEXT) {\n if (typeof block.text === 'string' && block.text !== '') {\n hasCacheableContent = true;\n break;\n }\n }\n }\n\n if (!hasCacheableContent) {\n updatedMessages[i] = shallowCloneMessage(originalMessage);\n (updatedMessages[i] as MessageWithContent).content = workingContent;\n continue;\n }\n\n let inserted = false;\n for (let j = workingContent.length - 1; j >= 0; j--) {\n const block = workingContent[j] as MessageContentComplex;\n const type = (block as { type?: string }).type;\n if (type === ContentTypes.TEXT || type === 'text') {\n const text = (block as { text?: string }).text;\n if (text === '' || text === undefined) {\n continue;\n }\n workingContent.splice(j + 1, 0, {\n cachePoint: { type: 'default' },\n } as MessageContentComplex);\n inserted = true;\n break;\n }\n }\n if (!inserted) {\n workingContent.push({\n cachePoint: { type: 'default' },\n } as MessageContentComplex);\n }\n\n updatedMessages[i] = createNewMessage(originalMessage, workingContent);\n messagesModified++;\n }\n\n return updatedMessages;\n}\n"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@librechat/agents",
3
- "version": "3.0.772",
3
+ "version": "3.0.774",
4
4
  "main": "./dist/cjs/main.cjs",
5
5
  "module": "./dist/esm/main.mjs",
6
6
  "types": "./dist/types/index.d.ts",
@@ -1,4 +1,11 @@
1
- import { BaseMessage, MessageContentComplex } from '@langchain/core/messages';
1
+ import {
2
+ BaseMessage,
3
+ MessageContentComplex,
4
+ AIMessage,
5
+ HumanMessage,
6
+ SystemMessage,
7
+ ToolMessage,
8
+ } from '@langchain/core/messages';
2
9
  import type { AnthropicMessage } from '@/types/messages';
3
10
  import type Anthropic from '@anthropic-ai/sdk';
4
11
  import { ContentTypes } from '@/common/enum';
@@ -9,7 +16,6 @@ type MessageWithContent = {
9
16
 
10
17
  /**
11
18
  * Deep clones a message's content to prevent mutation of the original.
12
- * Handles both string and array content types.
13
19
  */
14
20
  function deepCloneContent<T extends string | MessageContentComplex[]>(
15
21
  content: T
@@ -24,41 +30,74 @@ function deepCloneContent<T extends string | MessageContentComplex[]>(
24
30
  }
25
31
 
26
32
  /**
27
- * Creates a shallow clone of a message with deep-cloned content.
28
- * This ensures modifications to content don't affect the original message.
33
+ * Simple shallow clone with deep-cloned content.
34
+ * Used for stripping cache control where we don't need proper LangChain instances.
29
35
  */
30
- function cloneMessageWithContent<T extends MessageWithContent>(message: T): T {
31
- if (message.content === undefined) {
32
- return { ...message };
33
- }
34
-
35
- const clonedContent = deepCloneContent(message.content);
36
- const cloned = {
36
+ function shallowCloneMessage<T extends MessageWithContent>(message: T): T {
37
+ return {
37
38
  ...message,
38
- content: clonedContent,
39
- };
40
-
41
- /**
42
- * LangChain messages store internal state in lc_kwargs.
43
- * Clone it but don't sync content yet - that happens after all modifications.
44
- */
45
- const lcKwargs = (message as Record<string, unknown>).lc_kwargs;
46
- if (lcKwargs != null && typeof lcKwargs === 'object') {
47
- (cloned as Record<string, unknown>).lc_kwargs = { ...lcKwargs };
48
- }
49
-
50
- return cloned;
39
+ content: deepCloneContent(message.content ?? ''),
40
+ } as T;
51
41
  }
52
42
 
53
43
  /**
54
- * Syncs lc_kwargs.content with the message's content property.
55
- * Call this after all modifications to ensure LangChain serialization works correctly.
44
+ * Creates a new LangChain message instance with the given content.
45
+ * Required when adding cache points to ensure proper serialization.
56
46
  */
57
- function syncLcKwargsContent<T extends MessageWithContent>(message: T): void {
58
- const lcKwargs = (message as Record<string, unknown>).lc_kwargs;
59
- if (lcKwargs != null && typeof lcKwargs === 'object') {
60
- (lcKwargs as Record<string, unknown>).content = message.content;
47
+ function createNewMessage<T extends MessageWithContent>(
48
+ message: T,
49
+ content: MessageContentComplex[]
50
+ ): T {
51
+ if ('getType' in message && typeof message.getType === 'function') {
52
+ const baseMsg = message as unknown as BaseMessage;
53
+ const msgType = baseMsg.getType();
54
+
55
+ const baseFields = {
56
+ content,
57
+ name: baseMsg.name,
58
+ additional_kwargs: { ...baseMsg.additional_kwargs },
59
+ response_metadata: { ...baseMsg.response_metadata },
60
+ id: baseMsg.id,
61
+ };
62
+
63
+ switch (msgType) {
64
+ case 'human':
65
+ return new HumanMessage(baseFields) as unknown as T;
66
+ case 'ai': {
67
+ const aiMsg = baseMsg as AIMessage;
68
+ return new AIMessage({
69
+ ...baseFields,
70
+ tool_calls: aiMsg.tool_calls ? [...aiMsg.tool_calls] : [],
71
+ invalid_tool_calls: aiMsg.invalid_tool_calls
72
+ ? [...aiMsg.invalid_tool_calls]
73
+ : [],
74
+ usage_metadata: aiMsg.usage_metadata,
75
+ }) as unknown as T;
76
+ }
77
+ case 'system':
78
+ return new SystemMessage(baseFields) as unknown as T;
79
+ case 'tool': {
80
+ const toolMsg = baseMsg as ToolMessage;
81
+ return new ToolMessage({
82
+ ...baseFields,
83
+ tool_call_id: toolMsg.tool_call_id,
84
+ status: toolMsg.status,
85
+ artifact: toolMsg.artifact,
86
+ }) as unknown as T;
87
+ }
88
+ default:
89
+ break;
90
+ }
61
91
  }
92
+
93
+ const cloned = { ...message, content } as T;
94
+ const lcKwargs = (cloned as Record<string, unknown>).lc_kwargs as
95
+ | Record<string, unknown>
96
+ | undefined;
97
+ if (lcKwargs != null) {
98
+ (cloned as Record<string, unknown>).lc_kwargs = { ...lcKwargs, content };
99
+ }
100
+ return cloned;
62
101
  }
63
102
 
64
103
  /**
@@ -112,7 +151,7 @@ export function addCacheControl<T extends AnthropicMessage | BaseMessage>(
112
151
  continue;
113
152
  }
114
153
 
115
- const message = cloneMessageWithContent(
154
+ const message = shallowCloneMessage(
116
155
  originalMessage as MessageWithContent
117
156
  ) as T;
118
157
  updatedMessages[i] = message;
@@ -138,7 +177,6 @@ export function addCacheControl<T extends AnthropicMessage | BaseMessage>(
138
177
  }
139
178
 
140
179
  if (userMessagesModified >= 2 || !isUserMessage) {
141
- syncLcKwargsContent(message);
142
180
  continue;
143
181
  }
144
182
 
@@ -163,8 +201,6 @@ export function addCacheControl<T extends AnthropicMessage | BaseMessage>(
163
201
  }
164
202
  }
165
203
  }
166
-
167
- syncLcKwargsContent(message);
168
204
  }
169
205
 
170
206
  return updatedMessages;
@@ -209,7 +245,7 @@ export function stripAnthropicCacheControl<T extends MessageWithContent>(
209
245
  continue;
210
246
  }
211
247
 
212
- const message = cloneMessageWithContent(originalMessage);
248
+ const message = shallowCloneMessage(originalMessage);
213
249
  updatedMessages[i] = message;
214
250
 
215
251
  for (
@@ -262,7 +298,7 @@ export function stripBedrockCacheControl<T extends MessageWithContent>(
262
298
  continue;
263
299
  }
264
300
 
265
- const message = cloneMessageWithContent(originalMessage);
301
+ const message = shallowCloneMessage(originalMessage);
266
302
  updatedMessages[i] = message;
267
303
 
268
304
  message.content = (message.content as MessageContentComplex[]).filter(
@@ -317,85 +353,75 @@ export function addBedrockCacheControl<
317
353
  continue;
318
354
  }
319
355
 
320
- const message = cloneMessageWithContent(originalMessage);
321
- updatedMessages[i] = message;
356
+ let workingContent: MessageContentComplex[];
322
357
 
323
358
  if (hasArrayContent) {
324
- message.content = (message.content as MessageContentComplex[]).filter(
325
- (block) => !isCachePoint(block)
326
- ) as typeof content;
359
+ workingContent = deepCloneContent(
360
+ content as MessageContentComplex[]
361
+ ).filter((block) => !isCachePoint(block));
327
362
 
328
- for (
329
- let j = 0;
330
- j < (message.content as MessageContentComplex[]).length;
331
- j++
332
- ) {
333
- const block = (message.content as MessageContentComplex[])[j] as Record<
334
- string,
335
- unknown
336
- >;
363
+ for (let j = 0; j < workingContent.length; j++) {
364
+ const block = workingContent[j] as Record<string, unknown>;
337
365
  if ('cache_control' in block) {
338
366
  delete block.cache_control;
339
367
  }
340
368
  }
369
+ } else if (typeof content === 'string') {
370
+ workingContent = [{ type: ContentTypes.TEXT, text: content }];
371
+ } else {
372
+ workingContent = [];
341
373
  }
342
374
 
343
375
  if (messagesModified >= 2 || isToolMessage || isEmptyString) {
344
- syncLcKwargsContent(message);
376
+ updatedMessages[i] = shallowCloneMessage(originalMessage);
377
+ (updatedMessages[i] as MessageWithContent).content = workingContent;
345
378
  continue;
346
379
  }
347
380
 
348
- if (typeof message.content === 'string') {
349
- message.content = [
350
- { type: ContentTypes.TEXT, text: message.content },
351
- { cachePoint: { type: 'default' } },
352
- ] as MessageContentComplex[];
353
- messagesModified++;
354
- syncLcKwargsContent(message);
381
+ if (workingContent.length === 0) {
355
382
  continue;
356
383
  }
357
384
 
358
- if (Array.isArray(message.content)) {
359
- let hasCacheableContent = false;
360
- for (const block of message.content) {
361
- if (block.type === ContentTypes.TEXT) {
362
- if (typeof block.text === 'string' && block.text !== '') {
363
- hasCacheableContent = true;
364
- break;
365
- }
385
+ let hasCacheableContent = false;
386
+ for (const block of workingContent) {
387
+ if (block.type === ContentTypes.TEXT) {
388
+ if (typeof block.text === 'string' && block.text !== '') {
389
+ hasCacheableContent = true;
390
+ break;
366
391
  }
367
392
  }
393
+ }
368
394
 
369
- if (!hasCacheableContent) {
370
- syncLcKwargsContent(message);
371
- continue;
372
- }
395
+ if (!hasCacheableContent) {
396
+ updatedMessages[i] = shallowCloneMessage(originalMessage);
397
+ (updatedMessages[i] as MessageWithContent).content = workingContent;
398
+ continue;
399
+ }
373
400
 
374
- let inserted = false;
375
- for (let j = message.content.length - 1; j >= 0; j--) {
376
- const block = message.content[j] as MessageContentComplex;
377
- const type = (block as { type?: string }).type;
378
- if (type === ContentTypes.TEXT || type === 'text') {
379
- const text = (block as { text?: string }).text;
380
- if (text === '' || text === undefined) {
381
- continue;
382
- }
383
- message.content.splice(j + 1, 0, {
384
- cachePoint: { type: 'default' },
385
- } as MessageContentComplex);
386
- inserted = true;
387
- break;
401
+ let inserted = false;
402
+ for (let j = workingContent.length - 1; j >= 0; j--) {
403
+ const block = workingContent[j] as MessageContentComplex;
404
+ const type = (block as { type?: string }).type;
405
+ if (type === ContentTypes.TEXT || type === 'text') {
406
+ const text = (block as { text?: string }).text;
407
+ if (text === '' || text === undefined) {
408
+ continue;
388
409
  }
389
- }
390
- if (!inserted) {
391
- message.content.push({
410
+ workingContent.splice(j + 1, 0, {
392
411
  cachePoint: { type: 'default' },
393
412
  } as MessageContentComplex);
413
+ inserted = true;
414
+ break;
394
415
  }
395
- messagesModified++;
416
+ }
417
+ if (!inserted) {
418
+ workingContent.push({
419
+ cachePoint: { type: 'default' },
420
+ } as MessageContentComplex);
396
421
  }
397
422
 
398
- syncLcKwargsContent(message);
423
+ updatedMessages[i] = createNewMessage(originalMessage, workingContent);
424
+ messagesModified++;
399
425
  }
400
426
 
401
427
  return updatedMessages;