illuma-agents 1.0.4 → 1.0.6

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.
Files changed (46) hide show
  1. package/dist/cjs/graphs/Graph.cjs +80 -1
  2. package/dist/cjs/graphs/Graph.cjs.map +1 -1
  3. package/dist/cjs/llm/anthropic/utils/message_outputs.cjs.map +1 -1
  4. package/dist/cjs/main.cjs +4 -0
  5. package/dist/cjs/main.cjs.map +1 -1
  6. package/dist/cjs/messages/cache.cjs +87 -14
  7. package/dist/cjs/messages/cache.cjs.map +1 -1
  8. package/dist/cjs/messages/format.cjs +242 -6
  9. package/dist/cjs/messages/format.cjs.map +1 -1
  10. package/dist/cjs/stream.cjs +3 -2
  11. package/dist/cjs/stream.cjs.map +1 -1
  12. package/dist/cjs/tools/handlers.cjs +5 -5
  13. package/dist/cjs/tools/handlers.cjs.map +1 -1
  14. package/dist/esm/graphs/Graph.mjs +80 -1
  15. package/dist/esm/graphs/Graph.mjs.map +1 -1
  16. package/dist/esm/llm/anthropic/utils/message_outputs.mjs.map +1 -1
  17. package/dist/esm/main.mjs +2 -2
  18. package/dist/esm/messages/cache.mjs +86 -15
  19. package/dist/esm/messages/cache.mjs.map +1 -1
  20. package/dist/esm/messages/format.mjs +242 -8
  21. package/dist/esm/messages/format.mjs.map +1 -1
  22. package/dist/esm/stream.mjs +3 -2
  23. package/dist/esm/stream.mjs.map +1 -1
  24. package/dist/esm/tools/handlers.mjs +5 -5
  25. package/dist/esm/tools/handlers.mjs.map +1 -1
  26. package/dist/types/graphs/Graph.d.ts +19 -2
  27. package/dist/types/messages/cache.d.ts +16 -0
  28. package/dist/types/messages/format.d.ts +25 -1
  29. package/dist/types/tools/handlers.d.ts +2 -1
  30. package/dist/types/types/stream.d.ts +1 -0
  31. package/package.json +4 -1
  32. package/src/graphs/Graph.ts +99 -2
  33. package/src/llm/anthropic/utils/message_outputs.ts +289 -289
  34. package/src/messages/cache.test.ts +499 -3
  35. package/src/messages/cache.ts +115 -25
  36. package/src/messages/ensureThinkingBlock.test.ts +393 -0
  37. package/src/messages/format.ts +312 -6
  38. package/src/messages/labelContentByAgent.test.ts +887 -0
  39. package/src/scripts/test-multi-agent-list-handoff.ts +169 -13
  40. package/src/scripts/test-parallel-agent-labeling.ts +325 -0
  41. package/src/scripts/test-thinking-handoff-bedrock.ts +153 -0
  42. package/src/scripts/test-thinking-handoff.ts +147 -0
  43. package/src/specs/thinking-handoff.test.ts +620 -0
  44. package/src/stream.ts +19 -10
  45. package/src/tools/handlers.ts +36 -18
  46. package/src/types/stream.ts +1 -0
@@ -4,6 +4,9 @@ var _enum = require('../common/enum.cjs');
4
4
 
5
5
  /**
6
6
  * Anthropic API: Adds cache control to the appropriate user messages in the payload.
7
+ * Strips ALL existing cache control (both Anthropic and Bedrock formats) from all messages,
8
+ * then adds fresh cache control to the last 2 user messages in a single backward pass.
9
+ * This ensures we don't accumulate stale cache points across multiple turns.
7
10
  * @param messages - The array of message objects.
8
11
  * @returns - The updated array of message objects with cache control added.
9
12
  */
@@ -13,12 +16,20 @@ function addCacheControl(messages) {
13
16
  }
14
17
  const updatedMessages = [...messages];
15
18
  let userMessagesModified = 0;
16
- for (let i = updatedMessages.length - 1; i >= 0 && userMessagesModified < 2; i--) {
19
+ for (let i = updatedMessages.length - 1; i >= 0; i--) {
17
20
  const message = updatedMessages[i];
18
- if ('getType' in message && message.getType() !== 'human') {
19
- continue;
21
+ const isUserMessage = ('getType' in message && message.getType() === 'human') ||
22
+ ('role' in message && message.role === 'user');
23
+ if (Array.isArray(message.content)) {
24
+ message.content = message.content.filter((block) => !isCachePoint(block));
25
+ for (let j = 0; j < message.content.length; j++) {
26
+ const block = message.content[j];
27
+ if ('cache_control' in block) {
28
+ delete block.cache_control;
29
+ }
30
+ }
20
31
  }
21
- else if ('role' in message && message.role !== 'user') {
32
+ if (userMessagesModified >= 2 || !isUserMessage) {
22
33
  continue;
23
34
  }
24
35
  if (typeof message.content === 'string') {
@@ -46,10 +57,60 @@ function addCacheControl(messages) {
46
57
  }
47
58
  return updatedMessages;
48
59
  }
60
+ /**
61
+ * Checks if a content block is a cache point
62
+ */
63
+ function isCachePoint(block) {
64
+ return 'cachePoint' in block && !('type' in block);
65
+ }
66
+ /**
67
+ * Removes all Anthropic cache_control fields from messages
68
+ * Used when switching from Anthropic to Bedrock provider
69
+ */
70
+ function stripAnthropicCacheControl(messages) {
71
+ if (!Array.isArray(messages)) {
72
+ return messages;
73
+ }
74
+ const updatedMessages = [...messages];
75
+ for (let i = 0; i < updatedMessages.length; i++) {
76
+ const message = updatedMessages[i];
77
+ const content = message.content;
78
+ if (Array.isArray(content)) {
79
+ for (let j = 0; j < content.length; j++) {
80
+ const block = content[j];
81
+ if ('cache_control' in block) {
82
+ delete block.cache_control;
83
+ }
84
+ }
85
+ }
86
+ }
87
+ return updatedMessages;
88
+ }
89
+ /**
90
+ * Removes all Bedrock cachePoint blocks from messages
91
+ * Used when switching from Bedrock to Anthropic provider
92
+ */
93
+ function stripBedrockCacheControl(messages) {
94
+ if (!Array.isArray(messages)) {
95
+ return messages;
96
+ }
97
+ const updatedMessages = [...messages];
98
+ for (let i = 0; i < updatedMessages.length; i++) {
99
+ const message = updatedMessages[i];
100
+ const content = message.content;
101
+ if (Array.isArray(content)) {
102
+ message.content = content.filter((block) => !isCachePoint(block));
103
+ }
104
+ }
105
+ return updatedMessages;
106
+ }
49
107
  /**
50
108
  * Adds Bedrock Converse API cache points to the last two messages.
51
109
  * Inserts `{ cachePoint: { type: 'default' } }` as a separate content block
52
110
  * immediately after the last text block in each targeted message.
111
+ * Strips ALL existing cache control (both Bedrock and Anthropic formats) from all messages,
112
+ * then adds fresh cache points to the last 2 messages in a single backward pass.
113
+ * This ensures we don't accumulate stale cache points across multiple turns.
53
114
  * @param messages - The array of message objects.
54
115
  * @returns - The updated array of message objects with cache points added.
55
116
  */
@@ -59,14 +120,24 @@ function addBedrockCacheControl(messages) {
59
120
  }
60
121
  const updatedMessages = messages.slice();
61
122
  let messagesModified = 0;
62
- for (let i = updatedMessages.length - 1; i >= 0 && messagesModified < 2; i--) {
123
+ for (let i = updatedMessages.length - 1; i >= 0; i--) {
63
124
  const message = updatedMessages[i];
64
- if ('getType' in message &&
125
+ const isToolMessage = 'getType' in message &&
65
126
  typeof message.getType === 'function' &&
66
- message.getType() === 'tool') {
127
+ message.getType() === 'tool';
128
+ const content = message.content;
129
+ if (Array.isArray(content)) {
130
+ message.content = content.filter((block) => !isCachePoint(block));
131
+ for (let j = 0; j < message.content.length; j++) {
132
+ const block = message.content[j];
133
+ if ('cache_control' in block) {
134
+ delete block.cache_control;
135
+ }
136
+ }
137
+ }
138
+ if (messagesModified >= 2 || isToolMessage) {
67
139
  continue;
68
140
  }
69
- const content = message.content;
70
141
  if (typeof content === 'string' && content === '') {
71
142
  continue;
72
143
  }
@@ -78,9 +149,9 @@ function addBedrockCacheControl(messages) {
78
149
  messagesModified++;
79
150
  continue;
80
151
  }
81
- if (Array.isArray(content)) {
152
+ if (Array.isArray(message.content)) {
82
153
  let hasCacheableContent = false;
83
- for (const block of content) {
154
+ for (const block of message.content) {
84
155
  if (block.type === _enum.ContentTypes.TEXT) {
85
156
  if (typeof block.text === 'string' && block.text !== '') {
86
157
  hasCacheableContent = true;
@@ -92,15 +163,15 @@ function addBedrockCacheControl(messages) {
92
163
  continue;
93
164
  }
94
165
  let inserted = false;
95
- for (let j = content.length - 1; j >= 0; j--) {
96
- const block = content[j];
166
+ for (let j = message.content.length - 1; j >= 0; j--) {
167
+ const block = message.content[j];
97
168
  const type = block.type;
98
169
  if (type === _enum.ContentTypes.TEXT || type === 'text') {
99
170
  const text = block.text;
100
171
  if (text === '' || text === undefined) {
101
172
  continue;
102
173
  }
103
- content.splice(j + 1, 0, {
174
+ message.content.splice(j + 1, 0, {
104
175
  cachePoint: { type: 'default' },
105
176
  });
106
177
  inserted = true;
@@ -108,7 +179,7 @@ function addBedrockCacheControl(messages) {
108
179
  }
109
180
  }
110
181
  if (!inserted) {
111
- content.push({
182
+ message.content.push({
112
183
  cachePoint: { type: 'default' },
113
184
  });
114
185
  }
@@ -120,4 +191,6 @@ function addBedrockCacheControl(messages) {
120
191
 
121
192
  exports.addBedrockCacheControl = addBedrockCacheControl;
122
193
  exports.addCacheControl = addCacheControl;
194
+ exports.stripAnthropicCacheControl = stripAnthropicCacheControl;
195
+ exports.stripBedrockCacheControl = stripBedrockCacheControl;
123
196
  //# sourceMappingURL=cache.cjs.map
@@ -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 * Anthropic API: Adds cache control to the appropriate user messages in the payload.\n * @param messages - The array of message objects.\n * @returns - The updated 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 = [...messages];\n let userMessagesModified = 0;\n\n for (\n let i = updatedMessages.length - 1;\n i >= 0 && userMessagesModified < 2;\n i--\n ) {\n const message = updatedMessages[i];\n if ('getType' in message && message.getType() !== 'human') {\n continue;\n } else if ('role' in message && message.role !== 'user') {\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 * 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 * @param messages - The array of message objects.\n * @returns - The updated 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.slice();\n let messagesModified = 0;\n\n for (\n let i = updatedMessages.length - 1;\n i >= 0 && messagesModified < 2;\n i--\n ) {\n const message = updatedMessages[i];\n\n if (\n 'getType' in message &&\n typeof message.getType === 'function' &&\n message.getType() === 'tool'\n ) {\n continue;\n }\n\n const content = message.content;\n\n if (typeof content === 'string' && content === '') {\n continue;\n }\n\n if (typeof content === 'string') {\n message.content = [\n { type: ContentTypes.TEXT, text: content },\n { cachePoint: { type: 'default' } },\n ] as MessageContentComplex[];\n messagesModified++;\n continue;\n }\n\n if (Array.isArray(content)) {\n let hasCacheableContent = false;\n for (const block of 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 continue;\n }\n\n let inserted = false;\n for (let j = content.length - 1; j >= 0; j--) {\n const block = 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 content.splice(j + 1, 0, {\n cachePoint: { type: 'default' },\n } as MessageContentComplex);\n inserted = true;\n break;\n }\n }\n if (!inserted) {\n content.push({\n cachePoint: { type: 'default' },\n } as MessageContentComplex);\n }\n messagesModified++;\n }\n }\n\n return updatedMessages;\n}\n"],"names":["ContentTypes"],"mappings":"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"}
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 * 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 * @param messages - The array of message objects.\n * @returns - The updated 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 = [...messages];\n let userMessagesModified = 0;\n\n for (let i = updatedMessages.length - 1; i >= 0; i--) {\n const message = updatedMessages[i];\n const isUserMessage =\n ('getType' in message && message.getType() === 'human') ||\n ('role' in message && message.role === 'user');\n\n if (Array.isArray(message.content)) {\n message.content = message.content.filter(\n (block) => !isCachePoint(block as MessageContentComplex)\n ) as typeof message.content;\n\n for (let j = 0; j < message.content.length; j++) {\n const block = message.content[j] as Record<string, unknown>;\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 * Removes all Anthropic cache_control fields from messages\n * Used when switching from Anthropic to Bedrock provider\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 = [...messages];\n\n for (let i = 0; i < updatedMessages.length; i++) {\n const message = updatedMessages[i];\n const content = message.content;\n\n if (Array.isArray(content)) {\n for (let j = 0; j < content.length; j++) {\n const block = content[j] as Record<string, unknown>;\n if ('cache_control' in block) {\n delete block.cache_control;\n }\n }\n }\n }\n\n return updatedMessages;\n}\n\n/**\n * Removes all Bedrock cachePoint blocks from messages\n * Used when switching from Bedrock to Anthropic provider\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 = [...messages];\n\n for (let i = 0; i < updatedMessages.length; i++) {\n const message = updatedMessages[i];\n const content = message.content;\n\n if (Array.isArray(content)) {\n message.content = content.filter(\n (block) => !isCachePoint(block as MessageContentComplex)\n ) as typeof content;\n }\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 * @param messages - The array of message objects.\n * @returns - The updated 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.slice();\n let messagesModified = 0;\n\n for (let i = updatedMessages.length - 1; i >= 0; i--) {\n const message = updatedMessages[i];\n const isToolMessage =\n 'getType' in message &&\n typeof message.getType === 'function' &&\n message.getType() === 'tool';\n\n const content = message.content;\n\n if (Array.isArray(content)) {\n message.content = content.filter(\n (block) => !isCachePoint(block)\n ) as typeof content;\n\n for (let j = 0; j < message.content.length; j++) {\n const block = message.content[j] as Record<string, unknown>;\n if ('cache_control' in block) {\n delete block.cache_control;\n }\n }\n }\n\n if (messagesModified >= 2 || isToolMessage) {\n continue;\n }\n\n if (typeof content === 'string' && content === '') {\n continue;\n }\n\n if (typeof content === 'string') {\n message.content = [\n { type: ContentTypes.TEXT, text: content },\n { cachePoint: { type: 'default' } },\n ] as MessageContentComplex[];\n messagesModified++;\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 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\n return updatedMessages;\n}\n"],"names":["ContentTypes"],"mappings":"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"}
@@ -182,19 +182,20 @@ function formatAssistantMessage(message) {
182
182
  }
183
183
  // Create a new AIMessage with this text and prepare for tool calls
184
184
  lastAIMessage = new messages.AIMessage({
185
- content: part.text || '',
185
+ content: part.text != null ? part.text : '',
186
186
  });
187
187
  formattedMessages.push(lastAIMessage);
188
188
  }
189
189
  else if (part.type === _enum.ContentTypes.TOOL_CALL) {
190
190
  // Skip malformed tool call entries without tool_call property
191
- if (!part.tool_call) {
191
+ if (part.tool_call == null) {
192
192
  continue;
193
193
  }
194
194
  // Note: `tool_calls` list is defined when constructed by `AIMessage` class, and outputs should be excluded from it
195
195
  const { output, args: _args, ..._tool_call } = part.tool_call;
196
196
  // Skip invalid tool calls that have no name AND no output
197
- if (!_tool_call.name && (output == null || output === '')) {
197
+ if (_tool_call.name == null ||
198
+ (_tool_call.name === '' && (output == null || output === ''))) {
198
199
  continue;
199
200
  }
200
201
  if (!lastAIMessage) {
@@ -223,7 +224,7 @@ function formatAssistantMessage(message) {
223
224
  formattedMessages.push(new messages.ToolMessage({
224
225
  tool_call_id: tool_call.id ?? '',
225
226
  name: tool_call.name,
226
- content: output || '',
227
+ content: output != null ? output : '',
227
228
  }));
228
229
  }
229
230
  else if (part.type === _enum.ContentTypes.THINK) {
@@ -257,6 +258,177 @@ function formatAssistantMessage(message) {
257
258
  }
258
259
  return formattedMessages;
259
260
  }
261
+ /**
262
+ * Labels all agent content for parallel patterns (fan-out/fan-in)
263
+ * Groups consecutive content by agent and wraps with clear labels
264
+ */
265
+ function labelAllAgentContent(contentParts, agentIdMap, agentNames) {
266
+ const result = [];
267
+ let currentAgentId;
268
+ let agentContentBuffer = [];
269
+ const flushAgentBuffer = () => {
270
+ if (agentContentBuffer.length === 0) {
271
+ return;
272
+ }
273
+ if (currentAgentId != null && currentAgentId !== '') {
274
+ const agentName = (agentNames?.[currentAgentId] ?? '') || currentAgentId;
275
+ const formattedParts = [];
276
+ formattedParts.push(`--- ${agentName} ---`);
277
+ for (const part of agentContentBuffer) {
278
+ if (part.type === _enum.ContentTypes.THINK) {
279
+ const thinkContent = part.think || '';
280
+ if (thinkContent) {
281
+ formattedParts.push(`${agentName}: ${JSON.stringify({
282
+ type: 'think',
283
+ think: thinkContent,
284
+ })}`);
285
+ }
286
+ }
287
+ else if (part.type === _enum.ContentTypes.TEXT) {
288
+ const textContent = part.text ?? '';
289
+ if (textContent) {
290
+ formattedParts.push(`${agentName}: ${textContent}`);
291
+ }
292
+ }
293
+ else if (part.type === _enum.ContentTypes.TOOL_CALL) {
294
+ formattedParts.push(`${agentName}: ${JSON.stringify({
295
+ type: 'tool_call',
296
+ tool_call: part.tool_call,
297
+ })}`);
298
+ }
299
+ }
300
+ formattedParts.push(`--- End of ${agentName} ---`);
301
+ // Create a single text content part with all agent content
302
+ result.push({
303
+ type: _enum.ContentTypes.TEXT,
304
+ text: formattedParts.join('\n\n'),
305
+ });
306
+ }
307
+ else {
308
+ // No agent ID, pass through as-is
309
+ result.push(...agentContentBuffer);
310
+ }
311
+ agentContentBuffer = [];
312
+ };
313
+ for (let i = 0; i < contentParts.length; i++) {
314
+ const part = contentParts[i];
315
+ const agentId = agentIdMap[i];
316
+ // If agent changed, flush previous buffer
317
+ if (agentId !== currentAgentId && currentAgentId !== undefined) {
318
+ flushAgentBuffer();
319
+ }
320
+ currentAgentId = agentId;
321
+ agentContentBuffer.push(part);
322
+ }
323
+ // Flush any remaining content
324
+ flushAgentBuffer();
325
+ return result;
326
+ }
327
+ /**
328
+ * Groups content parts by agent and formats them with agent labels
329
+ * This preprocesses multi-agent content to prevent identity confusion
330
+ *
331
+ * @param contentParts - The content parts from a run
332
+ * @param agentIdMap - Map of content part index to agent ID
333
+ * @param agentNames - Optional map of agent ID to display name
334
+ * @param options - Configuration options
335
+ * @param options.labelNonTransferContent - If true, labels all agent transitions (for parallel patterns)
336
+ * @returns Modified content parts with agent labels where appropriate
337
+ */
338
+ const labelContentByAgent = (contentParts, agentIdMap, agentNames, options) => {
339
+ if (!agentIdMap || Object.keys(agentIdMap).length === 0) {
340
+ return contentParts;
341
+ }
342
+ // If labelNonTransferContent is true, use a different strategy for parallel patterns
343
+ if (options?.labelNonTransferContent === true) {
344
+ return labelAllAgentContent(contentParts, agentIdMap, agentNames);
345
+ }
346
+ const result = [];
347
+ let currentAgentId;
348
+ let agentContentBuffer = [];
349
+ let transferToolCallIndex;
350
+ let transferToolCallId;
351
+ const flushAgentBuffer = () => {
352
+ if (agentContentBuffer.length === 0) {
353
+ return;
354
+ }
355
+ // If this is content from a transferred agent, format it specially
356
+ if (currentAgentId != null &&
357
+ currentAgentId !== '' &&
358
+ transferToolCallIndex !== undefined) {
359
+ const agentName = (agentNames?.[currentAgentId] ?? '') || currentAgentId;
360
+ const formattedParts = [];
361
+ formattedParts.push(`--- Transfer to ${agentName} ---`);
362
+ for (const part of agentContentBuffer) {
363
+ if (part.type === _enum.ContentTypes.THINK) {
364
+ formattedParts.push(`${agentName}: ${JSON.stringify({
365
+ type: 'think',
366
+ think: part.think,
367
+ })}`);
368
+ }
369
+ else if ('text' in part && part.type === _enum.ContentTypes.TEXT) {
370
+ const textContent = part.text ?? '';
371
+ if (textContent) {
372
+ formattedParts.push(`${agentName}: ${JSON.stringify({
373
+ type: 'text',
374
+ text: textContent,
375
+ })}`);
376
+ }
377
+ }
378
+ else if (part.type === _enum.ContentTypes.TOOL_CALL) {
379
+ formattedParts.push(`${agentName}: ${JSON.stringify({
380
+ type: 'tool_call',
381
+ tool_call: part.tool_call,
382
+ })}`);
383
+ }
384
+ }
385
+ formattedParts.push(`--- End of ${agentName} response ---`);
386
+ // Find the tool call that triggered this transfer and update its output
387
+ if (transferToolCallIndex < result.length) {
388
+ const transferToolCall = result[transferToolCallIndex];
389
+ if (transferToolCall.type === _enum.ContentTypes.TOOL_CALL &&
390
+ transferToolCall.tool_call?.id === transferToolCallId) {
391
+ transferToolCall.tool_call.output = formattedParts.join('\n\n');
392
+ }
393
+ }
394
+ }
395
+ else {
396
+ // Not from a transfer, add as-is
397
+ result.push(...agentContentBuffer);
398
+ }
399
+ agentContentBuffer = [];
400
+ transferToolCallIndex = undefined;
401
+ transferToolCallId = undefined;
402
+ };
403
+ for (let i = 0; i < contentParts.length; i++) {
404
+ const part = contentParts[i];
405
+ const agentId = agentIdMap[i];
406
+ // Check if this is a transfer tool call
407
+ const isTransferTool = (part.type === _enum.ContentTypes.TOOL_CALL &&
408
+ part.tool_call?.name?.startsWith('lc_transfer_to_')) ??
409
+ false;
410
+ // If agent changed, flush previous buffer
411
+ if (agentId !== currentAgentId && currentAgentId !== undefined) {
412
+ flushAgentBuffer();
413
+ }
414
+ currentAgentId = agentId;
415
+ if (isTransferTool) {
416
+ // Flush any existing buffer first
417
+ flushAgentBuffer();
418
+ // Add the transfer tool call to result
419
+ result.push(part);
420
+ // Mark that the next agent's content should be captured
421
+ transferToolCallIndex = result.length - 1;
422
+ transferToolCallId = part.tool_call?.id;
423
+ currentAgentId = undefined; // Reset to capture the next agent
424
+ }
425
+ else {
426
+ agentContentBuffer.push(part);
427
+ }
428
+ }
429
+ flushAgentBuffer();
430
+ return result;
431
+ };
260
432
  /**
261
433
  * Formats an array of messages for LangChain, handling tool calls and creating ToolMessage instances.
262
434
  *
@@ -307,7 +479,7 @@ const formatAgentMessages = (payload, indexTokenCountMap, tools) => {
307
479
  break;
308
480
  }
309
481
  // Protect against malformed tool call entries
310
- if (!part.tool_call ||
482
+ if (part.tool_call == null ||
311
483
  part.tool_call.name == null ||
312
484
  part.tool_call.name === '') {
313
485
  hasInvalidTool = true;
@@ -334,7 +506,7 @@ const formatAgentMessages = (payload, indexTokenCountMap, tools) => {
334
506
  // Check if this is a continuation of the tool sequence
335
507
  let isToolResponse = false;
336
508
  const content = payload[j].content;
337
- if (content && Array.isArray(content)) {
509
+ if (content != null && Array.isArray(content)) {
338
510
  for (const part of content) {
339
511
  if (part.type === _enum.ContentTypes.TOOL_CALL) {
340
512
  isToolResponse = true;
@@ -433,11 +605,75 @@ function shiftIndexTokenCountMap(indexTokenCountMap, instructionsTokenCount) {
433
605
  }
434
606
  return shiftedMap;
435
607
  }
608
+ /**
609
+ * Ensures compatibility when switching from a non-thinking agent to a thinking-enabled agent.
610
+ * Converts AI messages with tool calls (that lack thinking blocks) into buffer strings,
611
+ * avoiding the thinking block signature requirement.
612
+ *
613
+ * @param messages - Array of messages to process
614
+ * @param provider - The provider being used (unused but kept for future compatibility)
615
+ * @returns The messages array with tool sequences converted to buffer strings if necessary
616
+ */
617
+ function ensureThinkingBlockInMessages(messages$1, _provider) {
618
+ const result = [];
619
+ let i = 0;
620
+ while (i < messages$1.length) {
621
+ const msg = messages$1[i];
622
+ const isAI = msg instanceof messages.AIMessage || msg instanceof messages.AIMessageChunk;
623
+ if (!isAI) {
624
+ result.push(msg);
625
+ i++;
626
+ continue;
627
+ }
628
+ const aiMsg = msg;
629
+ const hasToolCalls = aiMsg.tool_calls && aiMsg.tool_calls.length > 0;
630
+ const contentIsArray = Array.isArray(aiMsg.content);
631
+ // Check if the message has tool calls or tool_use content
632
+ let hasToolUse = hasToolCalls ?? false;
633
+ let firstContentType;
634
+ if (contentIsArray && aiMsg.content.length > 0) {
635
+ const content = aiMsg.content;
636
+ firstContentType = content[0]?.type;
637
+ hasToolUse =
638
+ hasToolUse ||
639
+ content.some((c) => typeof c === 'object' && c.type === 'tool_use');
640
+ }
641
+ // If message has tool use but no thinking block, convert to buffer string
642
+ if (hasToolUse &&
643
+ firstContentType !== _enum.ContentTypes.THINKING &&
644
+ firstContentType !== 'redacted_thinking') {
645
+ // Collect the AI message and any following tool messages
646
+ const toolSequence = [msg];
647
+ let j = i + 1;
648
+ // Look ahead for tool messages that belong to this AI message
649
+ while (j < messages$1.length && messages$1[j] instanceof messages.ToolMessage) {
650
+ toolSequence.push(messages$1[j]);
651
+ j++;
652
+ }
653
+ // Convert the sequence to a buffer string and wrap in a HumanMessage
654
+ // This avoids the thinking block requirement which only applies to AI messages
655
+ const bufferString = messages.getBufferString(toolSequence);
656
+ result.push(new messages.HumanMessage({
657
+ content: `[Previous agent context]\n${bufferString}`,
658
+ }));
659
+ // Skip the messages we've processed
660
+ i = j;
661
+ }
662
+ else {
663
+ // Keep the message as is
664
+ result.push(msg);
665
+ i++;
666
+ }
667
+ }
668
+ return result;
669
+ }
436
670
 
671
+ exports.ensureThinkingBlockInMessages = ensureThinkingBlockInMessages;
437
672
  exports.formatAgentMessages = formatAgentMessages;
438
673
  exports.formatFromLangChain = formatFromLangChain;
439
674
  exports.formatLangChainMessages = formatLangChainMessages;
440
675
  exports.formatMediaMessage = formatMediaMessage;
441
676
  exports.formatMessage = formatMessage;
677
+ exports.labelContentByAgent = labelContentByAgent;
442
678
  exports.shiftIndexTokenCountMap = shiftIndexTokenCountMap;
443
679
  //# sourceMappingURL=format.cjs.map