@illuma-ai/agents 1.1.21 → 1.1.22

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 (241) hide show
  1. package/dist/cjs/graphs/Graph.cjs +12 -1
  2. package/dist/cjs/graphs/Graph.cjs.map +1 -1
  3. package/dist/cjs/graphs/MultiAgentGraph.cjs +85 -1
  4. package/dist/cjs/graphs/MultiAgentGraph.cjs.map +1 -1
  5. package/dist/cjs/run.cjs +20 -9
  6. package/dist/cjs/run.cjs.map +1 -1
  7. package/dist/esm/graphs/Graph.mjs +12 -1
  8. package/dist/esm/graphs/Graph.mjs.map +1 -1
  9. package/dist/esm/graphs/MultiAgentGraph.mjs +85 -1
  10. package/dist/esm/graphs/MultiAgentGraph.mjs.map +1 -1
  11. package/dist/esm/run.mjs +20 -9
  12. package/dist/esm/run.mjs.map +1 -1
  13. package/dist/types/graphs/MultiAgentGraph.d.ts +17 -0
  14. package/package.json +1 -1
  15. package/src/graphs/Graph.ts +12 -1
  16. package/src/graphs/MultiAgentGraph.ts +105 -1
  17. package/src/graphs/__tests__/multi-agent-delegate.test.ts +191 -0
  18. package/src/run.ts +20 -11
  19. package/src/scripts/test-bedrock-handoff-autonomous.ts +231 -0
  20. package/src/agents/AgentContext.js +0 -782
  21. package/src/agents/AgentContext.test.js +0 -421
  22. package/src/agents/__tests__/AgentContext.test.js +0 -678
  23. package/src/agents/__tests__/resolveStructuredOutputMode.test.js +0 -117
  24. package/src/common/enum.js +0 -192
  25. package/src/common/index.js +0 -3
  26. package/src/events.js +0 -166
  27. package/src/graphs/Graph.js +0 -1857
  28. package/src/graphs/MultiAgentGraph.js +0 -1092
  29. package/src/graphs/__tests__/structured-output.integration.test.js +0 -624
  30. package/src/graphs/__tests__/structured-output.test.js +0 -144
  31. package/src/graphs/contextManagement.e2e.test.js +0 -718
  32. package/src/graphs/contextManagement.test.js +0 -485
  33. package/src/graphs/handoffValidation.test.js +0 -276
  34. package/src/graphs/index.js +0 -3
  35. package/src/index.js +0 -28
  36. package/src/instrumentation.js +0 -21
  37. package/src/llm/anthropic/index.js +0 -319
  38. package/src/llm/anthropic/types.js +0 -46
  39. package/src/llm/anthropic/utils/message_inputs.js +0 -627
  40. package/src/llm/anthropic/utils/message_outputs.js +0 -290
  41. package/src/llm/anthropic/utils/output_parsers.js +0 -89
  42. package/src/llm/anthropic/utils/tools.js +0 -25
  43. package/src/llm/bedrock/__tests__/bedrock-caching.test.js +0 -392
  44. package/src/llm/bedrock/index.js +0 -303
  45. package/src/llm/bedrock/types.js +0 -2
  46. package/src/llm/bedrock/utils/index.js +0 -6
  47. package/src/llm/bedrock/utils/message_inputs.js +0 -463
  48. package/src/llm/bedrock/utils/message_outputs.js +0 -269
  49. package/src/llm/fake.js +0 -92
  50. package/src/llm/google/index.js +0 -215
  51. package/src/llm/google/types.js +0 -12
  52. package/src/llm/google/utils/common.js +0 -670
  53. package/src/llm/google/utils/tools.js +0 -111
  54. package/src/llm/google/utils/zod_to_genai_parameters.js +0 -47
  55. package/src/llm/openai/index.js +0 -1033
  56. package/src/llm/openai/types.js +0 -2
  57. package/src/llm/openai/utils/index.js +0 -756
  58. package/src/llm/openai/utils/isReasoningModel.test.js +0 -79
  59. package/src/llm/openrouter/index.js +0 -261
  60. package/src/llm/openrouter/reasoning.test.js +0 -181
  61. package/src/llm/providers.js +0 -36
  62. package/src/llm/text.js +0 -65
  63. package/src/llm/vertexai/index.js +0 -402
  64. package/src/messages/__tests__/tools.test.js +0 -392
  65. package/src/messages/cache.js +0 -404
  66. package/src/messages/cache.test.js +0 -1167
  67. package/src/messages/content.js +0 -48
  68. package/src/messages/content.test.js +0 -314
  69. package/src/messages/core.js +0 -359
  70. package/src/messages/ensureThinkingBlock.test.js +0 -997
  71. package/src/messages/format.js +0 -973
  72. package/src/messages/formatAgentMessages.test.js +0 -2278
  73. package/src/messages/formatAgentMessages.tools.test.js +0 -362
  74. package/src/messages/formatMessage.test.js +0 -608
  75. package/src/messages/ids.js +0 -18
  76. package/src/messages/index.js +0 -9
  77. package/src/messages/labelContentByAgent.test.js +0 -725
  78. package/src/messages/prune.js +0 -438
  79. package/src/messages/reducer.js +0 -60
  80. package/src/messages/shiftIndexTokenCountMap.test.js +0 -63
  81. package/src/messages/summarize.js +0 -146
  82. package/src/messages/summarize.test.js +0 -332
  83. package/src/messages/tools.js +0 -90
  84. package/src/mockStream.js +0 -81
  85. package/src/prompts/collab.js +0 -7
  86. package/src/prompts/index.js +0 -3
  87. package/src/prompts/taskmanager.js +0 -58
  88. package/src/run.js +0 -427
  89. package/src/schemas/index.js +0 -3
  90. package/src/schemas/schema-preparation.test.js +0 -370
  91. package/src/schemas/validate.js +0 -314
  92. package/src/schemas/validate.test.js +0 -264
  93. package/src/scripts/abort.js +0 -127
  94. package/src/scripts/ant_web_search.js +0 -130
  95. package/src/scripts/ant_web_search_edge_case.js +0 -133
  96. package/src/scripts/ant_web_search_error_edge_case.js +0 -119
  97. package/src/scripts/args.js +0 -41
  98. package/src/scripts/bedrock-cache-debug.js +0 -186
  99. package/src/scripts/bedrock-content-aggregation-test.js +0 -195
  100. package/src/scripts/bedrock-merge-test.js +0 -80
  101. package/src/scripts/bedrock-parallel-tools-test.js +0 -150
  102. package/src/scripts/caching.js +0 -106
  103. package/src/scripts/cli.js +0 -152
  104. package/src/scripts/cli2.js +0 -119
  105. package/src/scripts/cli3.js +0 -163
  106. package/src/scripts/cli4.js +0 -165
  107. package/src/scripts/cli5.js +0 -165
  108. package/src/scripts/code_exec.js +0 -171
  109. package/src/scripts/code_exec_files.js +0 -180
  110. package/src/scripts/code_exec_multi_session.js +0 -185
  111. package/src/scripts/code_exec_ptc.js +0 -265
  112. package/src/scripts/code_exec_session.js +0 -217
  113. package/src/scripts/code_exec_simple.js +0 -120
  114. package/src/scripts/content.js +0 -111
  115. package/src/scripts/empty_input.js +0 -125
  116. package/src/scripts/handoff-test.js +0 -96
  117. package/src/scripts/image.js +0 -138
  118. package/src/scripts/memory.js +0 -83
  119. package/src/scripts/multi-agent-chain.js +0 -271
  120. package/src/scripts/multi-agent-conditional.js +0 -185
  121. package/src/scripts/multi-agent-document-review-chain.js +0 -171
  122. package/src/scripts/multi-agent-hybrid-flow.js +0 -264
  123. package/src/scripts/multi-agent-parallel-start.js +0 -214
  124. package/src/scripts/multi-agent-parallel.js +0 -346
  125. package/src/scripts/multi-agent-sequence.js +0 -184
  126. package/src/scripts/multi-agent-supervisor.js +0 -324
  127. package/src/scripts/multi-agent-test.js +0 -147
  128. package/src/scripts/parallel-asymmetric-tools-test.js +0 -202
  129. package/src/scripts/parallel-full-metadata-test.js +0 -176
  130. package/src/scripts/parallel-tools-test.js +0 -256
  131. package/src/scripts/programmatic_exec.js +0 -277
  132. package/src/scripts/programmatic_exec_agent.js +0 -168
  133. package/src/scripts/search.js +0 -118
  134. package/src/scripts/sequential-full-metadata-test.js +0 -143
  135. package/src/scripts/simple.js +0 -174
  136. package/src/scripts/single-agent-metadata-test.js +0 -152
  137. package/src/scripts/stream.js +0 -113
  138. package/src/scripts/test-custom-prompt-key.js +0 -132
  139. package/src/scripts/test-handoff-input.js +0 -143
  140. package/src/scripts/test-handoff-preamble.js +0 -227
  141. package/src/scripts/test-handoff-steering.js +0 -353
  142. package/src/scripts/test-multi-agent-list-handoff.js +0 -318
  143. package/src/scripts/test-parallel-agent-labeling.js +0 -253
  144. package/src/scripts/test-parallel-handoffs.js +0 -229
  145. package/src/scripts/test-thinking-handoff-bedrock.js +0 -132
  146. package/src/scripts/test-thinking-handoff.js +0 -132
  147. package/src/scripts/test-thinking-to-thinking-handoff-bedrock.js +0 -140
  148. package/src/scripts/test-tool-before-handoff-role-order.js +0 -223
  149. package/src/scripts/test-tools-before-handoff.js +0 -187
  150. package/src/scripts/test_code_api.js +0 -263
  151. package/src/scripts/thinking-bedrock.js +0 -128
  152. package/src/scripts/thinking-vertexai.js +0 -130
  153. package/src/scripts/thinking.js +0 -134
  154. package/src/scripts/tool_search.js +0 -114
  155. package/src/scripts/tools.js +0 -125
  156. package/src/specs/agent-handoffs-bedrock.integration.test.js +0 -280
  157. package/src/specs/agent-handoffs.test.js +0 -924
  158. package/src/specs/anthropic.simple.test.js +0 -287
  159. package/src/specs/azure.simple.test.js +0 -381
  160. package/src/specs/cache.simple.test.js +0 -282
  161. package/src/specs/custom-event-await.test.js +0 -148
  162. package/src/specs/deepseek.simple.test.js +0 -189
  163. package/src/specs/emergency-prune.test.js +0 -308
  164. package/src/specs/moonshot.simple.test.js +0 -237
  165. package/src/specs/observability.integration.test.js +0 -1337
  166. package/src/specs/openai.simple.test.js +0 -233
  167. package/src/specs/openrouter.simple.test.js +0 -202
  168. package/src/specs/prune.test.js +0 -733
  169. package/src/specs/reasoning.test.js +0 -144
  170. package/src/specs/spec.utils.js +0 -4
  171. package/src/specs/thinking-handoff.test.js +0 -486
  172. package/src/specs/thinking-prune.test.js +0 -600
  173. package/src/specs/token-distribution-edge-case.test.js +0 -246
  174. package/src/specs/token-memoization.test.js +0 -32
  175. package/src/specs/tokens.test.js +0 -49
  176. package/src/specs/tool-error.test.js +0 -139
  177. package/src/splitStream.js +0 -204
  178. package/src/splitStream.test.js +0 -504
  179. package/src/stream.js +0 -650
  180. package/src/stream.test.js +0 -225
  181. package/src/test/mockTools.js +0 -340
  182. package/src/tools/BrowserTools.js +0 -245
  183. package/src/tools/Calculator.js +0 -38
  184. package/src/tools/Calculator.test.js +0 -225
  185. package/src/tools/CodeExecutor.js +0 -233
  186. package/src/tools/ProgrammaticToolCalling.js +0 -602
  187. package/src/tools/StreamingToolCallBuffer.js +0 -179
  188. package/src/tools/ToolNode.js +0 -930
  189. package/src/tools/ToolSearch.js +0 -904
  190. package/src/tools/__tests__/BrowserTools.test.js +0 -306
  191. package/src/tools/__tests__/ProgrammaticToolCalling.integration.test.js +0 -276
  192. package/src/tools/__tests__/ProgrammaticToolCalling.test.js +0 -807
  193. package/src/tools/__tests__/StreamingToolCallBuffer.test.js +0 -175
  194. package/src/tools/__tests__/ToolApproval.test.js +0 -675
  195. package/src/tools/__tests__/ToolNode.recovery.test.js +0 -200
  196. package/src/tools/__tests__/ToolNode.session.test.js +0 -319
  197. package/src/tools/__tests__/ToolSearch.integration.test.js +0 -125
  198. package/src/tools/__tests__/ToolSearch.test.js +0 -812
  199. package/src/tools/__tests__/handlers.test.js +0 -799
  200. package/src/tools/__tests__/truncation-recovery.integration.test.js +0 -362
  201. package/src/tools/handlers.js +0 -306
  202. package/src/tools/schema.js +0 -25
  203. package/src/tools/search/anthropic.js +0 -34
  204. package/src/tools/search/content.js +0 -116
  205. package/src/tools/search/content.test.js +0 -133
  206. package/src/tools/search/firecrawl.js +0 -173
  207. package/src/tools/search/format.js +0 -198
  208. package/src/tools/search/highlights.js +0 -241
  209. package/src/tools/search/index.js +0 -3
  210. package/src/tools/search/jina-reranker.test.js +0 -106
  211. package/src/tools/search/rerankers.js +0 -165
  212. package/src/tools/search/schema.js +0 -102
  213. package/src/tools/search/search.js +0 -561
  214. package/src/tools/search/serper-scraper.js +0 -126
  215. package/src/tools/search/test.js +0 -129
  216. package/src/tools/search/tool.js +0 -453
  217. package/src/tools/search/types.js +0 -2
  218. package/src/tools/search/utils.js +0 -59
  219. package/src/types/graph.js +0 -24
  220. package/src/types/graph.test.js +0 -192
  221. package/src/types/index.js +0 -7
  222. package/src/types/llm.js +0 -2
  223. package/src/types/messages.js +0 -2
  224. package/src/types/run.js +0 -2
  225. package/src/types/stream.js +0 -2
  226. package/src/types/tools.js +0 -2
  227. package/src/utils/contextAnalytics.js +0 -79
  228. package/src/utils/contextAnalytics.test.js +0 -166
  229. package/src/utils/events.js +0 -26
  230. package/src/utils/graph.js +0 -11
  231. package/src/utils/handlers.js +0 -65
  232. package/src/utils/index.js +0 -10
  233. package/src/utils/llm.js +0 -21
  234. package/src/utils/llmConfig.js +0 -205
  235. package/src/utils/logging.js +0 -37
  236. package/src/utils/misc.js +0 -51
  237. package/src/utils/run.js +0 -69
  238. package/src/utils/schema.js +0 -21
  239. package/src/utils/title.js +0 -119
  240. package/src/utils/tokens.js +0 -92
  241. package/src/utils/toonFormat.js +0 -379
@@ -1,132 +0,0 @@
1
- #!/usr/bin/env bun
2
- import { config } from 'dotenv';
3
- config();
4
- import { HumanMessage } from '@langchain/core/messages';
5
- import { ToolEndHandler, ModelEndHandler } from '@/events';
6
- import { ChatModelStreamHandler } from '@/stream';
7
- import { Providers, GraphEvents } from '@/common';
8
- import { Run } from '@/run';
9
- const conversationHistory = [];
10
- /**
11
- * Test edge case: switching from OpenAI supervisor (no thinking) to Anthropic specialist (with thinking enabled)
12
- * This should not throw an error about missing thinking blocks
13
- */
14
- async function testThinkingHandoff() {
15
- console.log('Testing OpenAI → Anthropic (with thinking) handoff...\n');
16
- // Create custom handlers
17
- const customHandlers = {
18
- [GraphEvents.TOOL_END]: new ToolEndHandler(),
19
- [GraphEvents.CHAT_MODEL_END]: new ModelEndHandler(),
20
- [GraphEvents.CHAT_MODEL_STREAM]: new ChatModelStreamHandler(),
21
- [GraphEvents.TOOL_START]: {
22
- handle: (_event, data) => {
23
- const toolData = data;
24
- if (toolData?.name) {
25
- console.log(`\nšŸ”§ Tool called: ${toolData.name}`);
26
- }
27
- },
28
- },
29
- [GraphEvents.ON_RUN_STEP]: {
30
- handle: (_event, data) => {
31
- const runStep = data;
32
- console.log(`\nšŸ“ ON_RUN_STEP: agentId=${runStep.agentId}, groupId=${runStep.groupId}`);
33
- },
34
- },
35
- };
36
- // Create the graph configuration
37
- function createGraphConfig() {
38
- console.log('Creating graph with OpenAI supervisor and Anthropic specialist with thinking enabled.\n');
39
- const agents = [
40
- {
41
- agentId: 'supervisor',
42
- provider: Providers.OPENAI,
43
- clientOptions: {
44
- modelName: 'gpt-4o-mini',
45
- apiKey: process.env.OPENAI_API_KEY,
46
- },
47
- instructions: `You are a task supervisor. When the user asks about code review, use transfer_to_code_reviewer to hand off to the specialist.`,
48
- maxContextTokens: 8000,
49
- },
50
- {
51
- agentId: 'code_reviewer',
52
- provider: Providers.ANTHROPIC,
53
- clientOptions: {
54
- modelName: 'claude-3-7-sonnet-20250219',
55
- apiKey: process.env.ANTHROPIC_API_KEY,
56
- thinking: {
57
- type: 'enabled',
58
- budget_tokens: 2000,
59
- },
60
- },
61
- instructions: `You are a code review specialist. Think carefully about the code quality, best practices, and potential issues. Provide thoughtful feedback.`,
62
- maxContextTokens: 8000,
63
- },
64
- ];
65
- const edges = [
66
- {
67
- from: 'supervisor',
68
- to: ['code_reviewer'],
69
- description: 'Transfer to code review specialist',
70
- edgeType: 'transfer',
71
- },
72
- ];
73
- return {
74
- runId: `thinking-handoff-test-${Date.now()}`,
75
- graphConfig: {
76
- type: 'multi-agent',
77
- agents,
78
- edges,
79
- },
80
- customHandlers,
81
- returnContent: true,
82
- skipCleanup: true,
83
- };
84
- }
85
- try {
86
- // Test query that should trigger a handoff
87
- const query = 'Can you review this function and tell me if there are any issues?\n\nfunction add(a, b) { return a + b; }';
88
- console.log(`${'='.repeat(60)}`);
89
- console.log(`USER QUERY: "${query}"`);
90
- console.log('='.repeat(60));
91
- // Initialize conversation
92
- conversationHistory.push(new HumanMessage(query));
93
- // Create and run the graph
94
- const runConfig = createGraphConfig();
95
- const run = await Run.create(runConfig);
96
- const config = {
97
- configurable: {
98
- thread_id: 'thinking-handoff-test-1',
99
- },
100
- streamMode: 'values',
101
- version: 'v2',
102
- };
103
- console.log('\nProcessing request...\n');
104
- // Process with streaming
105
- const inputs = {
106
- messages: conversationHistory,
107
- };
108
- await run.processStream(inputs, config);
109
- const finalMessages = run.getRunMessages();
110
- if (finalMessages) {
111
- conversationHistory.push(...finalMessages);
112
- }
113
- // Success!
114
- console.log(`\n${'='.repeat(60)}`);
115
- console.log('āœ… TEST PASSED');
116
- console.log('='.repeat(60));
117
- console.log('\nSuccessfully handed off from OpenAI (no thinking) to');
118
- console.log('Anthropic with thinking enabled without errors!');
119
- console.log('\nThe ensureThinkingBlockInMessages() function correctly');
120
- console.log('added a placeholder thinking block to the last assistant');
121
- console.log('message before calling the Anthropic API.');
122
- }
123
- catch (error) {
124
- console.error('\nāŒ TEST FAILED');
125
- console.error('='.repeat(60));
126
- console.error('Error:', error);
127
- process.exit(1);
128
- }
129
- }
130
- // Run the test
131
- testThinkingHandoff();
132
- //# sourceMappingURL=test-thinking-handoff.js.map
@@ -1,140 +0,0 @@
1
- #!/usr/bin/env bun
2
- import { config } from 'dotenv';
3
- config();
4
- import { HumanMessage } from '@langchain/core/messages';
5
- import { Run } from '@/run';
6
- import { ChatModelStreamHandler } from '@/stream';
7
- import { Providers, GraphEvents } from '@/common';
8
- import { ToolEndHandler, ModelEndHandler } from '@/events';
9
- const conversationHistory = [];
10
- /**
11
- * Test edge case: switching from Bedrock supervisor (with thinking) to Bedrock specialist (with thinking)
12
- * Both agents use extended thinking, validating that thinking blocks are properly
13
- * handled across the handoff boundary when both sides produce them.
14
- */
15
- async function testThinkingToThinkingHandoffBedrock() {
16
- console.log('Testing Bedrock (with thinking) → Bedrock (with thinking) handoff...\n');
17
- const customHandlers = {
18
- [GraphEvents.TOOL_END]: new ToolEndHandler(),
19
- [GraphEvents.CHAT_MODEL_END]: new ModelEndHandler(),
20
- [GraphEvents.CHAT_MODEL_STREAM]: new ChatModelStreamHandler(),
21
- [GraphEvents.TOOL_START]: {
22
- handle: (_event, data) => {
23
- const toolData = data;
24
- if (toolData?.name) {
25
- console.log(`\nšŸ”§ Tool called: ${toolData.name}`);
26
- }
27
- },
28
- },
29
- [GraphEvents.ON_RUN_STEP]: {
30
- handle: (_event, data) => {
31
- const runStep = data;
32
- console.log(`\nšŸ“ ON_RUN_STEP: agentId=${runStep.agentId}, groupId=${runStep.groupId}`);
33
- },
34
- },
35
- };
36
- function createGraphConfig() {
37
- console.log('Creating graph with Bedrock supervisor (thinking) and Bedrock specialist (thinking).\n');
38
- const agents = [
39
- {
40
- agentId: 'supervisor',
41
- provider: Providers.BEDROCK,
42
- clientOptions: {
43
- region: process.env.BEDROCK_AWS_REGION || 'us-east-1',
44
- model: 'us.anthropic.claude-sonnet-4-5-20250929-v1:0',
45
- credentials: {
46
- accessKeyId: process.env.BEDROCK_AWS_ACCESS_KEY_ID,
47
- secretAccessKey: process.env.BEDROCK_AWS_SECRET_ACCESS_KEY,
48
- },
49
- additionalModelRequestFields: {
50
- thinking: {
51
- type: 'enabled',
52
- budget_tokens: 2000,
53
- },
54
- },
55
- },
56
- instructions: `You are a task supervisor. When the user asks about code review, use transfer_to_code_reviewer to hand off to the specialist.`,
57
- maxContextTokens: 8000,
58
- },
59
- {
60
- agentId: 'code_reviewer',
61
- provider: Providers.BEDROCK,
62
- clientOptions: {
63
- region: process.env.BEDROCK_AWS_REGION || 'us-east-1',
64
- model: 'us.anthropic.claude-sonnet-4-5-20250929-v1:0',
65
- credentials: {
66
- accessKeyId: process.env.BEDROCK_AWS_ACCESS_KEY_ID,
67
- secretAccessKey: process.env.BEDROCK_AWS_SECRET_ACCESS_KEY,
68
- },
69
- additionalModelRequestFields: {
70
- thinking: {
71
- type: 'enabled',
72
- budget_tokens: 2000,
73
- },
74
- },
75
- },
76
- instructions: `You are a code review specialist using Bedrock with extended thinking. Think carefully about the code quality, best practices, and potential issues. Provide thoughtful feedback.`,
77
- maxContextTokens: 8000,
78
- },
79
- ];
80
- const edges = [
81
- {
82
- from: 'supervisor',
83
- to: ['code_reviewer'],
84
- description: 'Transfer to code review specialist',
85
- edgeType: 'transfer',
86
- },
87
- ];
88
- return {
89
- runId: `thinking-to-thinking-bedrock-test-${Date.now()}`,
90
- graphConfig: {
91
- type: 'multi-agent',
92
- agents,
93
- edges,
94
- },
95
- customHandlers,
96
- returnContent: true,
97
- skipCleanup: true,
98
- };
99
- }
100
- try {
101
- const query = 'Can you review this function and tell me if there are any issues?\n\nfunction add(a, b) { return a + b; }';
102
- console.log(`${'='.repeat(60)}`);
103
- console.log(`USER QUERY: "${query}"`);
104
- console.log('='.repeat(60));
105
- conversationHistory.push(new HumanMessage(query));
106
- const runConfig = createGraphConfig();
107
- const run = await Run.create(runConfig);
108
- const streamConfig = {
109
- configurable: {
110
- thread_id: 'thinking-to-thinking-bedrock-test-1',
111
- },
112
- streamMode: 'values',
113
- version: 'v2',
114
- };
115
- console.log('\nProcessing request...\n');
116
- const inputs = {
117
- messages: conversationHistory,
118
- };
119
- await run.processStream(inputs, streamConfig);
120
- const finalMessages = run.getRunMessages();
121
- if (finalMessages) {
122
- conversationHistory.push(...finalMessages);
123
- }
124
- console.log(`\n${'='.repeat(60)}`);
125
- console.log('āœ… TEST PASSED');
126
- console.log('='.repeat(60));
127
- console.log('\nSuccessfully handed off from Bedrock (with thinking) to');
128
- console.log('Bedrock (with thinking) without errors!');
129
- console.log('\nThinking blocks were properly managed across the handoff');
130
- console.log('boundary when both agents produce them.');
131
- }
132
- catch (error) {
133
- console.error('\nāŒ TEST FAILED');
134
- console.error('='.repeat(60));
135
- console.error('Error:', error);
136
- process.exit(1);
137
- }
138
- }
139
- testThinkingToThinkingHandoffBedrock();
140
- //# sourceMappingURL=test-thinking-to-thinking-handoff-bedrock.js.map
@@ -1,223 +0,0 @@
1
- import { config } from 'dotenv';
2
- config();
3
- import { z } from 'zod';
4
- import { tool } from '@langchain/core/tools';
5
- import { HumanMessage } from '@langchain/core/messages';
6
- import { ChatModelStreamHandler, createContentAggregator } from '@/stream';
7
- import { ToolEndHandler, ModelEndHandler } from '@/events';
8
- import { GraphEvents, Providers } from '@/common';
9
- import { Run } from '@/run';
10
- const conversationHistory = [];
11
- /**
12
- * Test: Tool call followed by handoff (role order validation)
13
- *
14
- * Reproduces the bug from issue #54:
15
- * When a router agent runs a non-handoff tool (e.g. list_upload_sessions)
16
- * and then hands off to another agent in the same turn, the receiving agent
17
- * gets a message sequence of `... tool → user` which many chat APIs reject
18
- * with: "400 Unexpected role 'user' after role 'tool'"
19
- *
20
- * The fix ensures handoff instructions are injected into the last ToolMessage
21
- * (instead of appending a new HumanMessage) when the filtered messages end
22
- * with a ToolMessage.
23
- */
24
- async function testToolBeforeHandoffRoleOrder() {
25
- console.log('='.repeat(60));
26
- console.log('Test: Tool Call Before Handoff (Role Order Validation)');
27
- console.log('='.repeat(60));
28
- console.log('\nThis test verifies that:');
29
- console.log('1. Router calls a regular tool AND then hands off');
30
- console.log('2. The receiving agent does NOT get tool → user role sequence');
31
- console.log('3. No 400 API error occurs after the handoff\n');
32
- const { contentParts, aggregateContent } = createContentAggregator();
33
- let currentAgent = '';
34
- let toolCallCount = 0;
35
- let handoffOccurred = false;
36
- const customHandlers = {
37
- [GraphEvents.TOOL_END]: new ToolEndHandler(async () => {
38
- toolCallCount++;
39
- console.log(`\n Tool completed (total: ${toolCallCount})`);
40
- }),
41
- [GraphEvents.CHAT_MODEL_END]: new ModelEndHandler(),
42
- [GraphEvents.CHAT_MODEL_STREAM]: new ChatModelStreamHandler(),
43
- [GraphEvents.ON_RUN_STEP]: {
44
- handle: (event, data) => {
45
- const runStep = data;
46
- if (runStep.agentId) {
47
- currentAgent = runStep.agentId;
48
- console.log(`\n[Agent: ${currentAgent}] Processing...`);
49
- }
50
- aggregateContent({ event, data: runStep });
51
- },
52
- },
53
- [GraphEvents.ON_RUN_STEP_COMPLETED]: {
54
- handle: (event, data) => {
55
- aggregateContent({
56
- event,
57
- data: data,
58
- });
59
- },
60
- },
61
- [GraphEvents.ON_MESSAGE_DELTA]: {
62
- handle: (event, data) => {
63
- aggregateContent({ event, data: data });
64
- },
65
- },
66
- [GraphEvents.TOOL_START]: {
67
- handle: (_event, data, _metadata) => {
68
- const toolData = data;
69
- if (toolData?.name?.includes('transfer_to_')) {
70
- handoffOccurred = true;
71
- const specialist = toolData.name.replace('lc_transfer_to_', '');
72
- console.log(`\n Handoff initiated to: ${specialist}`);
73
- }
74
- },
75
- },
76
- };
77
- /**
78
- * Create a simple tool for the router agent.
79
- * This simulates the list_upload_sessions scenario from issue #54:
80
- * the router calls a regular tool and THEN hands off in the same turn.
81
- */
82
- const listSessions = tool(async () => {
83
- return JSON.stringify({
84
- sessions: [
85
- { id: 'sess_1', name: 'Q4 Report', status: 'ready' },
86
- { id: 'sess_2', name: 'Budget Analysis', status: 'pending' },
87
- ],
88
- });
89
- }, {
90
- name: 'list_upload_sessions',
91
- description: 'List available upload sessions for data analysis',
92
- schema: z.object({}),
93
- });
94
- const agents = [
95
- {
96
- agentId: 'router',
97
- provider: Providers.OPENAI,
98
- clientOptions: {
99
- modelName: 'gpt-4.1-mini',
100
- apiKey: process.env.OPENAI_API_KEY,
101
- },
102
- tools: [listSessions],
103
- instructions: `You are a Router agent with access to upload sessions and a data analysis specialist.
104
-
105
- Your workflow for data-related requests:
106
- 1. FIRST: Call list_upload_sessions to check available data
107
- 2. THEN: Transfer to the data_analyst with your findings
108
-
109
- CRITICAL: You MUST call list_upload_sessions first, then immediately transfer to data_analyst.
110
- Do NOT write a long response. Just call the tool and hand off.`,
111
- maxContextTokens: 8000,
112
- },
113
- {
114
- agentId: 'data_analyst',
115
- provider: Providers.OPENAI,
116
- clientOptions: {
117
- modelName: 'gpt-4.1-mini',
118
- apiKey: process.env.OPENAI_API_KEY,
119
- },
120
- instructions: `You are a Data Analyst specialist. When you receive a request:
121
- 1. Review any data or context provided
122
- 2. Provide a concise analysis or recommendation
123
- 3. Keep your response brief and focused`,
124
- maxContextTokens: 8000,
125
- },
126
- ];
127
- const edges = [
128
- {
129
- from: 'router',
130
- to: 'data_analyst',
131
- description: 'Transfer to data analyst after checking sessions',
132
- edgeType: 'transfer',
133
- prompt: 'Provide specific instructions for the data analyst about what to analyze',
134
- promptKey: 'instructions',
135
- },
136
- ];
137
- const runConfig = {
138
- runId: `tool-before-handoff-role-order-${Date.now()}`,
139
- graphConfig: {
140
- type: 'multi-agent',
141
- agents,
142
- edges,
143
- },
144
- customHandlers,
145
- returnContent: true,
146
- skipCleanup: true,
147
- };
148
- const run = await Run.create(runConfig);
149
- const streamConfig = {
150
- configurable: {
151
- thread_id: 'tool-before-handoff-role-order-1',
152
- },
153
- streamMode: 'values',
154
- version: 'v2',
155
- };
156
- try {
157
- const query = 'I want to visualize my CSV data. Can you check what upload sessions are available and have the analyst help me?';
158
- console.log('\n' + '-'.repeat(60));
159
- console.log(`USER QUERY: "${query}"`);
160
- console.log('-'.repeat(60));
161
- console.log('\nExpected behavior:');
162
- console.log('1. Router calls list_upload_sessions tool');
163
- console.log('2. Router hands off to data_analyst');
164
- console.log('3. data_analyst responds WITHOUT 400 error\n');
165
- conversationHistory.push(new HumanMessage(query));
166
- const inputs = { messages: conversationHistory };
167
- await run.processStream(inputs, streamConfig);
168
- const finalMessages = run.getRunMessages();
169
- if (finalMessages) {
170
- conversationHistory.push(...finalMessages);
171
- }
172
- /** Results */
173
- console.log(`\n${'='.repeat(60)}`);
174
- console.log('TEST RESULTS:');
175
- console.log('='.repeat(60));
176
- console.log(`Tool calls made: ${toolCallCount}`);
177
- console.log(`Handoff occurred: ${handoffOccurred ? 'Yes' : 'No'}`);
178
- console.log(`Test status: ${toolCallCount > 0 && handoffOccurred ? 'PASSED' : 'FAILED'}`);
179
- if (toolCallCount === 0) {
180
- console.log('\nNote: Router did not call any tools before handoff.');
181
- console.log('The bug only occurs when a non-handoff tool is called in the same turn as the handoff.');
182
- console.log('Try running again - the model may need stronger prompting.');
183
- }
184
- console.log('='.repeat(60));
185
- /** Show conversation history */
186
- console.log('\nConversation History:');
187
- console.log('-'.repeat(60));
188
- conversationHistory.forEach((msg, idx) => {
189
- const role = msg.getType();
190
- const content = typeof msg.content === 'string'
191
- ? msg.content.substring(0, 150) +
192
- (msg.content.length > 150 ? '...' : '')
193
- : '[complex content]';
194
- console.log(` [${idx}] ${role}: ${content}`);
195
- });
196
- }
197
- catch (error) {
198
- const errorMsg = error instanceof Error ? error.message : String(error);
199
- console.error('\nTest FAILED with error:', errorMsg);
200
- if (errorMsg.includes('Unexpected role') || errorMsg.includes('400')) {
201
- console.error('\n>>> This is the exact bug from issue #54! <<<<');
202
- console.error('>>> The tool→user role sequence caused a 400 API error. <<<');
203
- }
204
- console.log('\nConversation history at failure:');
205
- console.dir(conversationHistory, { depth: null });
206
- }
207
- }
208
- process.on('unhandledRejection', (reason, promise) => {
209
- console.error('Unhandled Rejection at:', promise, 'reason:', reason);
210
- console.log('\nConversation history at failure:');
211
- console.dir(conversationHistory, { depth: null });
212
- process.exit(1);
213
- });
214
- process.on('uncaughtException', (err) => {
215
- console.error('Uncaught Exception:', err);
216
- });
217
- testToolBeforeHandoffRoleOrder().catch((err) => {
218
- console.error('Test failed:', err);
219
- console.log('\nConversation history at failure:');
220
- console.dir(conversationHistory, { depth: null });
221
- process.exit(1);
222
- });
223
- //# sourceMappingURL=test-tool-before-handoff-role-order.js.map
@@ -1,187 +0,0 @@
1
- import { config } from 'dotenv';
2
- config();
3
- import { HumanMessage } from '@langchain/core/messages';
4
- import { Run } from '@/run';
5
- import { Providers, GraphEvents } from '@/common';
6
- import { ChatModelStreamHandler, createContentAggregator } from '@/stream';
7
- import { ToolEndHandler, ModelEndHandler } from '@/events';
8
- const conversationHistory = [];
9
- /**
10
- * Test edge case: Agent performs 2 web searches before handing off
11
- *
12
- * This tests how the system behaves when an agent with handoff capabilities
13
- * uses tools before transferring control to another agent.
14
- */
15
- async function testToolsBeforeHandoff() {
16
- console.log('Testing Tools Before Handoff Edge Case...\n');
17
- // Set up content aggregator
18
- const { contentParts, aggregateContent } = createContentAggregator();
19
- // Track tool calls and handoffs
20
- let toolCallCount = 0;
21
- let handoffOccurred = false;
22
- // Create custom handlers
23
- const customHandlers = {
24
- [GraphEvents.TOOL_END]: new ToolEndHandler(async () => {
25
- console.log('\nāœ… Tool completed');
26
- }),
27
- [GraphEvents.CHAT_MODEL_END]: new ModelEndHandler(),
28
- [GraphEvents.CHAT_MODEL_STREAM]: new ChatModelStreamHandler(),
29
- [GraphEvents.ON_RUN_STEP]: {
30
- handle: (event, data) => {
31
- const runStepData = data;
32
- if (runStepData?.name) {
33
- console.log(`\n[${runStepData.name}] Processing...`);
34
- }
35
- aggregateContent({ event, data: data });
36
- },
37
- },
38
- [GraphEvents.ON_RUN_STEP_COMPLETED]: {
39
- handle: (event, data) => {
40
- aggregateContent({
41
- event,
42
- data: data,
43
- });
44
- },
45
- },
46
- [GraphEvents.ON_MESSAGE_DELTA]: {
47
- handle: (event, data) => {
48
- // console.log('====== ON_MESSAGE_DELTA ======');
49
- console.dir(data, { depth: null });
50
- aggregateContent({ event, data: data });
51
- },
52
- },
53
- [GraphEvents.TOOL_START]: {
54
- handle: (_event, data, metadata) => {
55
- const toolData = data;
56
- console.log(`\nšŸ”§ Tool started:`);
57
- console.dir({ toolData, metadata }, { depth: null });
58
- if (toolData?.output?.name?.includes('transfer_to_')) {
59
- handoffOccurred = true;
60
- const specialist = toolData.name.replace('transfer_to_', '');
61
- console.log(`\nšŸ”€ Handoff initiated to: ${specialist}`);
62
- }
63
- },
64
- },
65
- };
66
- // Create the graph with research agent and report writer
67
- function createGraphWithToolsAndHandoff() {
68
- const agents = [
69
- {
70
- agentId: 'research_coordinator',
71
- provider: Providers.OPENAI,
72
- clientOptions: {
73
- modelName: 'gpt-4.1-mini',
74
- apiKey: process.env.OPENAI_API_KEY,
75
- },
76
- tools: [],
77
- instructions: `You are a Research Coordinator with access to a report writer specialist.
78
-
79
- Your workflow MUST follow these steps IN ORDER:
80
- 1. FIRST: Write an initial response acknowledging the request
81
- - Explain what you understand about the topic
82
- - Provide any general knowledge you have
83
- 2. FINALLY: Transfer to the report writer
84
- - Provide the report writer with a summary of the information
85
-
86
- CRITICAL: You MUST write your initial response before transferring to the report writer.`,
87
- maxContextTokens: 8000,
88
- },
89
- {
90
- agentId: 'report_writer',
91
- provider: Providers.OPENAI,
92
- clientOptions: {
93
- modelName: 'gpt-5-mini',
94
- apiKey: process.env.OPENAI_API_KEY,
95
- },
96
- instructions: `You are a Report Writer specialist. Your role is to:
97
- 1. Receive research findings from the Research Coordinator
98
- 2. Create a well-structured, comprehensive report
99
- 3. Include all key findings from the research
100
- 4. Format the report with clear sections and bullet points
101
- 5. Add a brief executive summary at the beginning
102
-
103
- Focus on clarity, completeness, and professional presentation.`,
104
- maxContextTokens: 8000,
105
- },
106
- ];
107
- // Create edge from research coordinator to report writer
108
- const edges = [
109
- {
110
- from: 'research_coordinator',
111
- to: 'report_writer',
112
- description: 'Transfer to report writer after completing research',
113
- edgeType: 'transfer',
114
- },
115
- ];
116
- return {
117
- runId: `tools-before-handoff-${Date.now()}`,
118
- graphConfig: {
119
- type: 'multi-agent',
120
- agents,
121
- edges,
122
- },
123
- customHandlers,
124
- returnContent: true,
125
- skipCleanup: true,
126
- };
127
- }
128
- try {
129
- // Single test query that requires handoff to report writer
130
- const query = `Tell me about quantum computing developments,
131
- including major breakthroughs and commercial applications.
132
- I need a comprehensive report.`;
133
- console.log('='.repeat(60));
134
- console.log(`USER QUERY: "${query}"`);
135
- console.log('='.repeat(60));
136
- // Create the graph
137
- const runConfig = createGraphWithToolsAndHandoff();
138
- const run = await Run.create(runConfig);
139
- console.log('\nExpected behavior:');
140
- console.log('1. Research Coordinator writes initial response');
141
- console.log('2. Research Coordinator hands off to Report Writer');
142
- console.log('3. Report Writer creates final report\n');
143
- // Process with streaming
144
- conversationHistory.push(new HumanMessage(query));
145
- const inputs = {
146
- messages: conversationHistory,
147
- };
148
- const config = {
149
- configurable: {
150
- thread_id: 'tools-handoff-test-1',
151
- },
152
- streamMode: 'values',
153
- version: 'v2',
154
- };
155
- const finalContentParts = await run.processStream(inputs, config);
156
- const finalMessages = run.getRunMessages();
157
- if (finalMessages) {
158
- conversationHistory.push(...finalMessages);
159
- }
160
- // Show results summary
161
- console.log(`\n${'─'.repeat(60)}`);
162
- console.log('EDGE CASE TEST RESULTS:');
163
- console.log('─'.repeat(60));
164
- console.log(`Tool calls before handoff: ${toolCallCount}`);
165
- console.log(`Expected tool calls: 0 (no web search available)`);
166
- console.log(`Handoff occurred: ${handoffOccurred ? 'Yes āœ…' : 'No āŒ'}`);
167
- console.log(`Test status: ${handoffOccurred ? 'PASSED āœ…' : 'FAILED āŒ'}`);
168
- console.log('─'.repeat(60));
169
- // Display conversation history
170
- console.log('\nConversation History:');
171
- console.log('─'.repeat(60));
172
- conversationHistory.forEach((msg, idx) => {
173
- const role = msg.constructor.name.replace('Message', '');
174
- console.log(`\n[${idx}] ${role}:`);
175
- if (typeof msg.content === 'string') {
176
- console.log(msg.content.substring(0, 200) +
177
- (msg.content.length > 200 ? '...' : ''));
178
- }
179
- });
180
- }
181
- catch (error) {
182
- console.error('Error in tools-before-handoff test:', error);
183
- }
184
- }
185
- // Run the test
186
- testToolsBeforeHandoff();
187
- //# sourceMappingURL=test-tools-before-handoff.js.map