mcp-use 0.1.20 → 0.3.0

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 (140) hide show
  1. package/dist/chunk-2HFIPY7C.js +429 -0
  2. package/dist/chunk-4DEFXVWT.js +680 -0
  3. package/dist/chunk-JXLQRAW2.js +532 -0
  4. package/dist/chunk-SHUYVCID.js +6 -0
  5. package/dist/chunk-YUSC6R6V.js +299 -0
  6. package/dist/index.cjs +5762 -0
  7. package/dist/index.d.ts +7 -0
  8. package/dist/index.d.ts.map +1 -1
  9. package/dist/index.js +3767 -22
  10. package/dist/langfuse-YA2S23SM.js +13 -0
  11. package/dist/src/agents/remote.d.ts.map +1 -1
  12. package/dist/src/agents/utils/ai_sdk.d.ts.map +1 -1
  13. package/dist/src/auth/browser-provider.d.ts +52 -0
  14. package/dist/src/auth/browser-provider.d.ts.map +1 -0
  15. package/dist/src/auth/callback.d.ts +6 -0
  16. package/dist/src/auth/callback.d.ts.map +1 -0
  17. package/dist/src/auth/index.d.ts +7 -0
  18. package/dist/src/auth/index.d.ts.map +1 -0
  19. package/dist/src/auth/types.d.ts +18 -0
  20. package/dist/src/auth/types.d.ts.map +1 -0
  21. package/dist/src/browser.cjs +323 -0
  22. package/dist/src/browser.d.ts +8 -0
  23. package/dist/src/browser.d.ts.map +1 -0
  24. package/dist/src/browser.js +9 -0
  25. package/dist/src/client/base.d.ts +32 -0
  26. package/dist/src/client/base.d.ts.map +1 -0
  27. package/dist/src/client.d.ts +19 -16
  28. package/dist/src/client.d.ts.map +1 -1
  29. package/dist/src/logging.d.ts +1 -1
  30. package/dist/src/logging.d.ts.map +1 -1
  31. package/dist/src/oauth-helper.d.ts +125 -0
  32. package/dist/src/oauth-helper.d.ts.map +1 -0
  33. package/dist/src/react/index.cjs +986 -0
  34. package/dist/src/react/index.d.ts +9 -0
  35. package/dist/src/react/index.d.ts.map +1 -0
  36. package/dist/src/react/index.js +11 -0
  37. package/dist/src/react/types.d.ts +139 -0
  38. package/dist/src/react/types.d.ts.map +1 -0
  39. package/dist/src/react/useMcp.d.ts +3 -0
  40. package/dist/src/react/useMcp.d.ts.map +1 -0
  41. package/dist/src/server/index.cjs +566 -0
  42. package/dist/src/server/index.d.ts +3 -0
  43. package/dist/src/server/index.d.ts.map +1 -0
  44. package/dist/src/server/index.js +9 -0
  45. package/dist/src/server/logging.d.ts +16 -0
  46. package/dist/src/server/logging.d.ts.map +1 -0
  47. package/dist/src/server/mcp-server.d.ts +282 -0
  48. package/dist/src/server/mcp-server.d.ts.map +1 -0
  49. package/dist/src/server/types.d.ts +47 -0
  50. package/dist/src/server/types.d.ts.map +1 -0
  51. package/dist/src/utils/assert.d.ts +8 -0
  52. package/dist/src/utils/assert.d.ts.map +1 -0
  53. package/dist/tsconfig.tsbuildinfo +1 -0
  54. package/package.json +72 -40
  55. package/dist/examples/add_server_tool.d.ts +0 -8
  56. package/dist/examples/add_server_tool.d.ts.map +0 -1
  57. package/dist/examples/add_server_tool.js +0 -79
  58. package/dist/examples/ai_sdk_example.d.ts +0 -23
  59. package/dist/examples/ai_sdk_example.d.ts.map +0 -1
  60. package/dist/examples/ai_sdk_example.js +0 -213
  61. package/dist/examples/airbnb_use.d.ts +0 -10
  62. package/dist/examples/airbnb_use.d.ts.map +0 -1
  63. package/dist/examples/airbnb_use.js +0 -43
  64. package/dist/examples/blender_use.d.ts +0 -15
  65. package/dist/examples/blender_use.d.ts.map +0 -1
  66. package/dist/examples/blender_use.js +0 -39
  67. package/dist/examples/browser_use.d.ts +0 -10
  68. package/dist/examples/browser_use.d.ts.map +0 -1
  69. package/dist/examples/browser_use.js +0 -46
  70. package/dist/examples/chat_example.d.ts +0 -10
  71. package/dist/examples/chat_example.d.ts.map +0 -1
  72. package/dist/examples/chat_example.js +0 -86
  73. package/dist/examples/filesystem_use.d.ts +0 -11
  74. package/dist/examples/filesystem_use.d.ts.map +0 -1
  75. package/dist/examples/filesystem_use.js +0 -43
  76. package/dist/examples/http_example.d.ts +0 -18
  77. package/dist/examples/http_example.d.ts.map +0 -1
  78. package/dist/examples/http_example.js +0 -37
  79. package/dist/examples/mcp_everything.d.ts +0 -6
  80. package/dist/examples/mcp_everything.d.ts.map +0 -1
  81. package/dist/examples/mcp_everything.js +0 -25
  82. package/dist/examples/multi_server_example.d.ts +0 -10
  83. package/dist/examples/multi_server_example.d.ts.map +0 -1
  84. package/dist/examples/multi_server_example.js +0 -51
  85. package/dist/examples/observability.d.ts +0 -6
  86. package/dist/examples/observability.d.ts.map +0 -1
  87. package/dist/examples/observability.js +0 -50
  88. package/dist/examples/stream_example.d.ts +0 -12
  89. package/dist/examples/stream_example.d.ts.map +0 -1
  90. package/dist/examples/stream_example.js +0 -198
  91. package/dist/examples/structured_output.d.ts +0 -9
  92. package/dist/examples/structured_output.d.ts.map +0 -1
  93. package/dist/examples/structured_output.js +0 -95
  94. package/dist/src/adapters/base.js +0 -124
  95. package/dist/src/adapters/index.js +0 -2
  96. package/dist/src/adapters/langchain_adapter.js +0 -49
  97. package/dist/src/agents/base.js +0 -9
  98. package/dist/src/agents/index.js +0 -3
  99. package/dist/src/agents/mcp_agent.js +0 -1002
  100. package/dist/src/agents/prompts/system_prompt_builder.js +0 -40
  101. package/dist/src/agents/prompts/templates.js +0 -39
  102. package/dist/src/agents/remote.js +0 -264
  103. package/dist/src/agents/utils/ai_sdk.js +0 -62
  104. package/dist/src/agents/utils/index.js +0 -1
  105. package/dist/src/client.js +0 -133
  106. package/dist/src/config.js +0 -34
  107. package/dist/src/connectors/base.js +0 -143
  108. package/dist/src/connectors/http.js +0 -150
  109. package/dist/src/connectors/index.js +0 -4
  110. package/dist/src/connectors/stdio.js +0 -68
  111. package/dist/src/connectors/websocket.js +0 -157
  112. package/dist/src/logging.js +0 -217
  113. package/dist/src/managers/index.js +0 -2
  114. package/dist/src/managers/server_manager.js +0 -106
  115. package/dist/src/managers/tools/acquire_active_mcp_server.js +0 -17
  116. package/dist/src/managers/tools/add_server_from_config.js +0 -40
  117. package/dist/src/managers/tools/base.js +0 -17
  118. package/dist/src/managers/tools/connect_mcp_server.js +0 -46
  119. package/dist/src/managers/tools/index.js +0 -5
  120. package/dist/src/managers/tools/list_mcp_servers.js +0 -33
  121. package/dist/src/managers/tools/release_mcp_server_connection.js +0 -19
  122. package/dist/src/observability/index.js +0 -12
  123. package/dist/src/observability/langfuse.js +0 -211
  124. package/dist/src/observability/manager.js +0 -199
  125. package/dist/src/observability/types.js +0 -4
  126. package/dist/src/session.js +0 -23
  127. package/dist/src/task_managers/base.js +0 -127
  128. package/dist/src/task_managers/index.js +0 -5
  129. package/dist/src/task_managers/sse.js +0 -43
  130. package/dist/src/task_managers/stdio.js +0 -51
  131. package/dist/src/task_managers/streamable_http.js +0 -50
  132. package/dist/src/task_managers/websocket.js +0 -67
  133. package/dist/src/telemetry/events.js +0 -44
  134. package/dist/src/telemetry/index.js +0 -8
  135. package/dist/src/telemetry/telemetry.js +0 -324
  136. package/dist/src/telemetry/utils.js +0 -39
  137. package/dist/tests/ai_sdk_compatibility.test.js +0 -214
  138. package/dist/tests/stream_events.test.js +0 -307
  139. package/dist/tests/stream_events_simple.test.js +0 -179
  140. package/dist/vitest.config.js +0 -21
@@ -1,214 +0,0 @@
1
- /**
2
- * Tests for AI SDK compatibility with MCPAgent streamEvents()
3
- *
4
- * These tests verify that streamEvents() can be used with the AI SDK's
5
- * LangChainAdapter for creating data stream responses compatible with
6
- * Vercel AI SDK hooks like useCompletion and useChat.
7
- */
8
- import { LangChainAdapter } from 'ai';
9
- import { describe, expect, it } from 'vitest';
10
- // Mock an async generator that simulates our streamEvents output
11
- async function* mockStreamEvents() {
12
- // Simulate typical events from streamEvents
13
- yield {
14
- event: 'on_chain_start',
15
- name: 'AgentExecutor',
16
- data: { input: { input: 'test query' } },
17
- };
18
- yield {
19
- event: 'on_chat_model_stream',
20
- name: 'ChatAnthropic',
21
- data: { chunk: { content: 'Hello' } },
22
- };
23
- yield {
24
- event: 'on_chat_model_stream',
25
- name: 'ChatAnthropic',
26
- data: { chunk: { content: ' world' } },
27
- };
28
- yield {
29
- event: 'on_chat_model_stream',
30
- name: 'ChatAnthropic',
31
- data: { chunk: { content: '!' } },
32
- };
33
- yield {
34
- event: 'on_tool_start',
35
- name: 'test_tool',
36
- data: { input: { query: 'test' } },
37
- };
38
- yield {
39
- event: 'on_tool_end',
40
- name: 'test_tool',
41
- data: { output: 'Tool executed successfully' },
42
- };
43
- yield {
44
- event: 'on_chain_end',
45
- name: 'AgentExecutor',
46
- data: { output: 'Hello world!' },
47
- };
48
- }
49
- // Function to convert streamEvents to a format compatible with AI SDK
50
- async function* streamEventsToAISDK(streamEvents) {
51
- for await (const event of streamEvents) {
52
- // Only yield the actual content tokens from chat model streams
53
- if (event.event === 'on_chat_model_stream' && event.data?.chunk?.content) {
54
- yield event.data.chunk.content;
55
- }
56
- }
57
- }
58
- // Alternative adapter that yields complete content at the end
59
- async function* streamEventsToCompleteContent(streamEvents) {
60
- let fullContent = '';
61
- for await (const event of streamEvents) {
62
- if (event.event === 'on_chat_model_stream' && event.data?.chunk?.content) {
63
- fullContent += event.data.chunk.content;
64
- }
65
- // For tool events, we could add additional formatting
66
- else if (event.event === 'on_tool_start') {
67
- // Could add tool start indicators if needed
68
- }
69
- else if (event.event === 'on_tool_end') {
70
- // Could add tool completion indicators if needed
71
- }
72
- }
73
- // Yield the complete content at the end
74
- if (fullContent) {
75
- yield fullContent;
76
- }
77
- }
78
- describe('aI SDK Compatibility', () => {
79
- it('should convert streamEvents to AI SDK compatible stream', async () => {
80
- const mockEvents = mockStreamEvents();
81
- const aiSDKStream = streamEventsToAISDK(mockEvents);
82
- const tokens = [];
83
- for await (const token of aiSDKStream) {
84
- tokens.push(token);
85
- }
86
- expect(tokens).toEqual(['Hello', ' world', '!']);
87
- });
88
- it('should work with LangChainAdapter.toDataStreamResponse', async () => {
89
- const mockEvents = mockStreamEvents();
90
- const aiSDKStream = streamEventsToAISDK(mockEvents);
91
- // Convert async generator to ReadableStream for AI SDK compatibility
92
- const readableStream = new ReadableStream({
93
- async start(controller) {
94
- try {
95
- for await (const token of aiSDKStream) {
96
- controller.enqueue(token);
97
- }
98
- controller.close();
99
- }
100
- catch (error) {
101
- controller.error(error);
102
- }
103
- },
104
- });
105
- // Test that we can create a data stream response
106
- const response = LangChainAdapter.toDataStreamResponse(readableStream);
107
- expect(response).toBeInstanceOf(Response);
108
- expect(response.headers.get('Content-Type')).toBe('text/plain; charset=utf-8');
109
- });
110
- it('should convert streamEvents to complete content stream', async () => {
111
- const mockEvents = mockStreamEvents();
112
- const contentStream = streamEventsToCompleteContent(mockEvents);
113
- const content = [];
114
- for await (const chunk of contentStream) {
115
- content.push(chunk);
116
- }
117
- expect(content).toEqual(['Hello world!']);
118
- });
119
- it('should handle empty streams gracefully', async () => {
120
- async function* emptyStreamEvents() {
121
- // Empty generator
122
- }
123
- const emptyEvents = emptyStreamEvents();
124
- const aiSDKStream = streamEventsToAISDK(emptyEvents);
125
- const tokens = [];
126
- for await (const token of aiSDKStream) {
127
- tokens.push(token);
128
- }
129
- expect(tokens).toEqual([]);
130
- });
131
- it('should filter non-content events correctly', async () => {
132
- async function* mixedEvents() {
133
- yield {
134
- event: 'on_chain_start',
135
- name: 'Test',
136
- data: { input: 'test' },
137
- };
138
- yield {
139
- event: 'on_chat_model_stream',
140
- name: 'ChatModel',
141
- data: { chunk: { content: 'Content' } },
142
- };
143
- yield {
144
- event: 'on_tool_start',
145
- name: 'Tool',
146
- data: { input: 'test' },
147
- };
148
- yield {
149
- event: 'on_chat_model_stream',
150
- name: 'ChatModel',
151
- data: { chunk: { content: ' token' } },
152
- };
153
- yield {
154
- event: 'on_chain_end',
155
- name: 'Test',
156
- data: { output: 'result' },
157
- };
158
- }
159
- const events = mixedEvents();
160
- const aiSDKStream = streamEventsToAISDK(events);
161
- const tokens = [];
162
- for await (const token of aiSDKStream) {
163
- tokens.push(token);
164
- }
165
- expect(tokens).toEqual(['Content', ' token']);
166
- });
167
- it('should create readable stream from streamEvents', async () => {
168
- const mockEvents = mockStreamEvents();
169
- // Create a ReadableStream from our async generator
170
- const readableStream = new ReadableStream({
171
- async start(controller) {
172
- try {
173
- for await (const event of streamEventsToAISDK(mockEvents)) {
174
- controller.enqueue(new TextEncoder().encode(event));
175
- }
176
- controller.close();
177
- }
178
- catch (error) {
179
- controller.error(error);
180
- }
181
- },
182
- });
183
- expect(readableStream).toBeInstanceOf(ReadableStream);
184
- // Test that we can read from the stream
185
- const reader = readableStream.getReader();
186
- const decoder = new TextDecoder();
187
- const chunks = [];
188
- while (true) {
189
- const { done, value } = await reader.read();
190
- if (done)
191
- break;
192
- chunks.push(decoder.decode(value));
193
- }
194
- expect(chunks).toEqual(['Hello', ' world', '!']);
195
- });
196
- });
197
- // Convert async generator to ReadableStream for AI SDK compatibility
198
- function createReadableStreamFromGenerator(generator) {
199
- return new ReadableStream({
200
- async start(controller) {
201
- try {
202
- for await (const chunk of generator) {
203
- controller.enqueue(chunk);
204
- }
205
- controller.close();
206
- }
207
- catch (error) {
208
- controller.error(error);
209
- }
210
- },
211
- });
212
- }
213
- // Export the adapter functions for use in examples
214
- export { createReadableStreamFromGenerator, streamEventsToAISDK, streamEventsToCompleteContent };
@@ -1,307 +0,0 @@
1
- /* eslint-disable no-unreachable-loop, unused-imports/no-unused-vars */
2
- import { HumanMessage } from '@langchain/core/messages';
3
- import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
4
- import { MCPAgent, MCPClient } from '../index.js';
5
- // Mock the MCP client for testing
6
- vi.mock('../src/client.js', () => ({
7
- MCPClient: vi.fn().mockImplementation(() => ({
8
- getAllActiveSessions: vi.fn().mockResolvedValue({}),
9
- createAllSessions: vi.fn().mockResolvedValue({}),
10
- closeAllSessions: vi.fn().mockResolvedValue(undefined),
11
- })),
12
- }));
13
- // Mock the LangChain adapter
14
- vi.mock('../src/adapters/langchain_adapter.js', () => ({
15
- LangChainAdapter: vi.fn().mockImplementation(() => ({
16
- createToolsFromConnectors: vi.fn().mockResolvedValue([
17
- {
18
- name: 'test_tool',
19
- description: 'A test tool',
20
- schema: {},
21
- func: vi.fn().mockResolvedValue('Test tool result'),
22
- },
23
- ]),
24
- })),
25
- }));
26
- describe('mCPAgent streamEvents()', () => {
27
- let agent;
28
- let mockClient;
29
- let mockLLM;
30
- beforeEach(() => {
31
- // Create mock LLM that supports streamEvents
32
- mockLLM = {
33
- invoke: vi.fn().mockResolvedValue({ content: 'Test response' }),
34
- _modelType: 'chat_anthropic',
35
- _llmType: 'anthropic',
36
- };
37
- // Create mock client
38
- mockClient = new MCPClient({});
39
- // Create agent with mocked dependencies
40
- agent = new MCPAgent({
41
- llm: mockLLM,
42
- client: mockClient,
43
- maxSteps: 3,
44
- memoryEnabled: true,
45
- verbose: false,
46
- });
47
- // Mock the agent executor's streamEvents method
48
- const mockStreamEvents = vi.fn().mockImplementation(async function* () {
49
- // Simulate typical event sequence
50
- yield {
51
- event: 'on_chain_start',
52
- name: 'AgentExecutor',
53
- data: { input: { input: 'test query' } },
54
- };
55
- yield {
56
- event: 'on_chat_model_stream',
57
- name: 'ChatAnthropic',
58
- data: { chunk: { content: 'Hello' } },
59
- };
60
- yield {
61
- event: 'on_chat_model_stream',
62
- name: 'ChatAnthropic',
63
- data: { chunk: { content: ' world' } },
64
- };
65
- yield {
66
- event: 'on_tool_start',
67
- name: 'test_tool',
68
- data: { input: { query: 'test' } },
69
- };
70
- yield {
71
- event: 'on_tool_end',
72
- name: 'test_tool',
73
- data: { output: 'Tool result' },
74
- };
75
- yield {
76
- event: 'on_chain_end',
77
- name: 'AgentExecutor',
78
- data: { output: [{ text: 'Hello world' }] },
79
- };
80
- });
81
- // Mock initialize method
82
- vi.spyOn(agent, 'initialize').mockResolvedValue(undefined);
83
- // Mock agentExecutor after initialization
84
- Object.defineProperty(agent, 'agentExecutor', {
85
- get: () => ({
86
- streamEvents: mockStreamEvents,
87
- maxIterations: 3,
88
- }),
89
- configurable: true,
90
- });
91
- // Mock tools
92
- Object.defineProperty(agent, 'tools', {
93
- get: () => [{ name: 'test_tool' }],
94
- configurable: true,
95
- });
96
- // Mock telemetry using bracket notation to access private property
97
- vi.spyOn(agent.telemetry, 'trackAgentExecution').mockResolvedValue(undefined);
98
- });
99
- afterEach(() => {
100
- vi.clearAllMocks();
101
- });
102
- it('should yield StreamEvent objects', async () => {
103
- const events = [];
104
- for await (const event of agent.streamEvents('test query')) {
105
- events.push(event);
106
- }
107
- expect(events).toHaveLength(6);
108
- // Check event structure
109
- events.forEach((event) => {
110
- expect(event).toHaveProperty('event');
111
- expect(event).toHaveProperty('name');
112
- expect(event).toHaveProperty('data');
113
- });
114
- });
115
- it('should handle token streaming correctly', async () => {
116
- const tokens = [];
117
- for await (const event of agent.streamEvents('test query')) {
118
- if (event.event === 'on_chat_model_stream' && event.data?.chunk?.content) {
119
- tokens.push(event.data.chunk.content);
120
- }
121
- }
122
- expect(tokens).toEqual(['Hello', ' world']);
123
- });
124
- it('should track tool execution events', async () => {
125
- const toolEvents = [];
126
- for await (const event of agent.streamEvents('test query')) {
127
- if (event.event.includes('tool')) {
128
- toolEvents.push(event);
129
- }
130
- }
131
- expect(toolEvents).toHaveLength(2);
132
- expect(toolEvents[0].event).toBe('on_tool_start');
133
- expect(toolEvents[0].name).toBe('test_tool');
134
- expect(toolEvents[1].event).toBe('on_tool_end');
135
- expect(toolEvents[1].name).toBe('test_tool');
136
- });
137
- it('should initialize agent if not already initialized', async () => {
138
- const initializeSpy = vi.spyOn(agent, 'initialize');
139
- // Set initialized to false
140
- Object.defineProperty(agent, 'initialized', {
141
- get: () => false,
142
- configurable: true,
143
- });
144
- const events = [];
145
- for await (const event of agent.streamEvents('test query')) {
146
- events.push(event);
147
- break; // Just get first event
148
- }
149
- expect(initializeSpy).toHaveBeenCalled();
150
- });
151
- it('should handle memory correctly when enabled', async () => {
152
- const addToHistorySpy = vi.spyOn(agent, 'addToHistory');
153
- // Consume all events
154
- const events = [];
155
- for await (const event of agent.streamEvents('test query')) {
156
- events.push(event);
157
- }
158
- // Should add user message and AI response to history
159
- expect(addToHistorySpy).toHaveBeenCalledTimes(2);
160
- });
161
- it('should track telemetry', async () => {
162
- const telemetrySpy = vi.spyOn(agent.telemetry, 'trackAgentExecution');
163
- // Consume all events
164
- for await (const event of agent.streamEvents('test query')) {
165
- // Just consume events
166
- }
167
- expect(telemetrySpy).toHaveBeenCalledWith(expect.objectContaining({
168
- executionMethod: 'streamEvents',
169
- query: 'test query',
170
- success: true,
171
- }));
172
- });
173
- it('should handle errors gracefully', async () => {
174
- // Mock agent executor to throw error
175
- Object.defineProperty(agent, 'agentExecutor', {
176
- get: () => ({
177
- streamEvents: vi.fn().mockImplementation(async function* () {
178
- throw new Error('Test error');
179
- }),
180
- maxIterations: 3,
181
- }),
182
- configurable: true,
183
- });
184
- await expect(async () => {
185
- for await (const event of agent.streamEvents('test query')) {
186
- // Should not reach here
187
- }
188
- }).rejects.toThrow('Test error');
189
- });
190
- it('should respect maxSteps parameter', async () => {
191
- const mockAgentExecutor = {
192
- streamEvents: vi.fn().mockImplementation(async function* () {
193
- yield { event: 'test', name: 'test', data: {} };
194
- }),
195
- maxIterations: 3,
196
- };
197
- Object.defineProperty(agent, 'agentExecutor', {
198
- get: () => mockAgentExecutor,
199
- configurable: true,
200
- });
201
- for await (const event of agent.streamEvents('test query', 5)) {
202
- break;
203
- }
204
- expect(mockAgentExecutor.maxIterations).toBe(5);
205
- });
206
- it('should handle external history', async () => {
207
- const externalHistory = [
208
- new HumanMessage('Previous message'),
209
- ];
210
- // Mock the agent executor to capture inputs
211
- let capturedInputs;
212
- const mockStreamEvents = vi.fn().mockImplementation(async function* (inputs) {
213
- capturedInputs = inputs;
214
- yield { event: 'test', name: 'test', data: {} };
215
- });
216
- Object.defineProperty(agent, 'agentExecutor', {
217
- get: () => ({
218
- streamEvents: mockStreamEvents,
219
- maxIterations: 3,
220
- }),
221
- configurable: true,
222
- });
223
- // Mock initialize method
224
- vi.spyOn(agent, 'initialize').mockResolvedValue(undefined);
225
- for await (const event of agent.streamEvents('test query', undefined, true, externalHistory)) {
226
- break;
227
- }
228
- expect(capturedInputs.chat_history).toEqual(externalHistory);
229
- });
230
- it('should clean up resources on completion', async () => {
231
- const closeSpy = vi.spyOn(agent, 'close').mockResolvedValue(undefined);
232
- // Test with manageConnector=true and no client
233
- Object.defineProperty(agent, 'client', {
234
- get: () => undefined,
235
- configurable: true,
236
- });
237
- // Consume all events
238
- for await (const event of agent.streamEvents('test query', undefined, true)) {
239
- // Just consume events
240
- }
241
- // Note: cleanup only happens if initialized in this call and no client
242
- // This is hard to test with our current mocking setup, but the logic is there
243
- });
244
- });
245
- describe('mCPAgent streamEvents() edge cases', () => {
246
- it('should handle empty event stream', async () => {
247
- const mockLLM = {
248
- invoke: vi.fn().mockResolvedValue({ content: 'Test response' }),
249
- _modelType: 'chat_anthropic',
250
- };
251
- const mockClient = new MCPClient({});
252
- const agent = new MCPAgent({
253
- llm: mockLLM,
254
- client: mockClient,
255
- maxSteps: 3,
256
- });
257
- // Mock empty event stream
258
- Object.defineProperty(agent, 'agentExecutor', {
259
- get: () => ({
260
- streamEvents: vi.fn().mockImplementation(async function* () {
261
- // Empty generator
262
- }),
263
- maxIterations: 3,
264
- }),
265
- configurable: true,
266
- });
267
- vi.spyOn(agent, 'initialize').mockResolvedValue(undefined);
268
- vi.spyOn(agent.telemetry, 'trackAgentExecution').mockResolvedValue(undefined);
269
- const events = [];
270
- for await (const event of agent.streamEvents('test query')) {
271
- events.push(event);
272
- }
273
- expect(events).toHaveLength(0);
274
- });
275
- it('should handle malformed events gracefully', async () => {
276
- const mockLLM = {
277
- invoke: vi.fn().mockResolvedValue({ content: 'Test response' }),
278
- _modelType: 'chat_anthropic',
279
- };
280
- const mockClient = new MCPClient({});
281
- const agent = new MCPAgent({
282
- llm: mockLLM,
283
- client: mockClient,
284
- maxSteps: 3,
285
- });
286
- // Mock malformed event stream
287
- Object.defineProperty(agent, 'agentExecutor', {
288
- get: () => ({
289
- streamEvents: vi.fn().mockImplementation(async function* () {
290
- yield { event: 'malformed' }; // Missing required fields
291
- yield null; // Invalid event
292
- yield { event: 'on_chat_model_stream', data: { chunk: { content: 'test' } } };
293
- yield { event: 'on_chain_end', data: { output: [{ text: 'test response' }] } };
294
- }),
295
- maxIterations: 3,
296
- }),
297
- configurable: true,
298
- });
299
- vi.spyOn(agent, 'initialize').mockResolvedValue(undefined);
300
- vi.spyOn(agent.telemetry, 'trackAgentExecution').mockResolvedValue(undefined);
301
- const events = [];
302
- for await (const event of agent.streamEvents('test query')) {
303
- events.push(event);
304
- }
305
- expect(events).toHaveLength(3); // Should still yield all events, even malformed ones
306
- });
307
- });
@@ -1,179 +0,0 @@
1
- /**
2
- * Simple tests for MCPAgent streamEvents() method
3
- *
4
- * These tests verify the basic functionality of streamEvents() using minimal mocking
5
- */
6
- import { describe, expect, it } from 'vitest';
7
- describe('test MCPAgent streamEvents() - Core Functionality', () => {
8
- it('should be a generator function that yields StreamEvent objects', async () => {
9
- // Mock a simple agent-like object with streamEvents method
10
- const mockAgent = {
11
- async *streamEvents(query) {
12
- // Simulate typical event sequence
13
- yield {
14
- event: 'on_chain_start',
15
- name: 'AgentExecutor',
16
- data: { input: { input: query } },
17
- };
18
- yield {
19
- event: 'on_chat_model_stream',
20
- name: 'ChatAnthropic',
21
- data: { chunk: { content: 'Hello' } },
22
- };
23
- yield {
24
- event: 'on_chat_model_stream',
25
- name: 'ChatAnthropic',
26
- data: { chunk: { content: ' world!' } },
27
- };
28
- yield {
29
- event: 'on_tool_start',
30
- name: 'test_tool',
31
- data: { input: { query: 'test' } },
32
- };
33
- yield {
34
- event: 'on_tool_end',
35
- name: 'test_tool',
36
- data: { output: 'Tool result' },
37
- };
38
- yield {
39
- event: 'on_chain_end',
40
- name: 'AgentExecutor',
41
- data: { output: 'Hello world!' },
42
- };
43
- },
44
- };
45
- const events = [];
46
- const tokens = [];
47
- const toolEvents = [];
48
- // Collect all events
49
- for await (const event of mockAgent.streamEvents('test query')) {
50
- events.push(event);
51
- // Collect tokens
52
- if (event.event === 'on_chat_model_stream' && event.data?.chunk?.content) {
53
- tokens.push(event.data.chunk.content);
54
- }
55
- // Collect tool events
56
- if (event.event.includes('tool')) {
57
- toolEvents.push(event);
58
- }
59
- }
60
- // Verify we got the expected number of events
61
- expect(events).toHaveLength(6);
62
- // Verify event structure
63
- events.forEach((event) => {
64
- expect(event).toHaveProperty('event');
65
- expect(event).toHaveProperty('name');
66
- expect(event).toHaveProperty('data');
67
- });
68
- // Verify token streaming works
69
- expect(tokens).toEqual(['Hello', ' world!']);
70
- // Verify tool events
71
- expect(toolEvents).toHaveLength(2);
72
- expect(toolEvents[0].event).toBe('on_tool_start');
73
- expect(toolEvents[1].event).toBe('on_tool_end');
74
- // Verify event types are correct
75
- expect(events[0].event).toBe('on_chain_start');
76
- expect(events[1].event).toBe('on_chat_model_stream');
77
- expect(events[2].event).toBe('on_chat_model_stream');
78
- expect(events[3].event).toBe('on_tool_start');
79
- expect(events[4].event).toBe('on_tool_end');
80
- expect(events[5].event).toBe('on_chain_end');
81
- });
82
- it('should handle different event types correctly', async () => {
83
- const mockAgent = {
84
- async *streamEvents() {
85
- // Test different event types
86
- const eventTypes = [
87
- 'on_chain_start',
88
- 'on_llm_start',
89
- 'on_llm_stream',
90
- 'on_llm_end',
91
- 'on_tool_start',
92
- 'on_tool_stream',
93
- 'on_tool_end',
94
- 'on_retriever_start',
95
- 'on_retriever_end',
96
- 'on_parser_start',
97
- 'on_parser_end',
98
- 'on_chain_end',
99
- ];
100
- for (const eventType of eventTypes) {
101
- yield {
102
- event: eventType,
103
- name: 'TestComponent',
104
- data: { test: true },
105
- run_id: 'test-run-id',
106
- metadata: {},
107
- };
108
- }
109
- },
110
- };
111
- const events = [];
112
- for await (const event of mockAgent.streamEvents()) {
113
- events.push(event);
114
- }
115
- expect(events).toHaveLength(12);
116
- // Verify we got all the different event types
117
- const receivedEventTypes = events.map(e => e.event);
118
- expect(receivedEventTypes).toContain('on_chain_start');
119
- expect(receivedEventTypes).toContain('on_llm_stream');
120
- expect(receivedEventTypes).toContain('on_tool_start');
121
- expect(receivedEventTypes).toContain('on_tool_end');
122
- expect(receivedEventTypes).toContain('on_chain_end');
123
- });
124
- it('should work with empty event streams', async () => {
125
- const mockAgent = {
126
- async *streamEvents() {
127
- // Empty generator
128
- },
129
- };
130
- const events = [];
131
- for await (const event of mockAgent.streamEvents()) {
132
- events.push(event);
133
- }
134
- expect(events).toHaveLength(0);
135
- });
136
- it('should handle streaming token reconstruction', async () => {
137
- const mockAgent = {
138
- async *streamEvents() {
139
- const tokens = ['The', ' quick', ' brown', ' fox', ' jumps', ' over', ' the', ' lazy', ' dog.'];
140
- for (const token of tokens) {
141
- yield {
142
- event: 'on_chat_model_stream',
143
- name: 'ChatModel',
144
- data: { chunk: { content: token } },
145
- };
146
- }
147
- },
148
- };
149
- let reconstructedText = '';
150
- const tokenCount = { count: 0 };
151
- for await (const event of mockAgent.streamEvents()) {
152
- if (event.event === 'on_chat_model_stream' && event.data?.chunk?.content) {
153
- reconstructedText += event.data.chunk.content;
154
- tokenCount.count++;
155
- }
156
- }
157
- expect(reconstructedText).toBe('The quick brown fox jumps over the lazy dog.');
158
- expect(tokenCount.count).toBe(9);
159
- });
160
- });
161
- describe('streamEvent type verification', () => {
162
- it('should have correct StreamEvent interface', () => {
163
- const sampleEvent = {
164
- event: 'on_chat_model_stream',
165
- name: 'TestModel',
166
- data: {
167
- chunk: { content: 'test' },
168
- input: { query: 'test' },
169
- output: 'result',
170
- },
171
- run_id: 'test-run-id',
172
- metadata: {},
173
- };
174
- expect(sampleEvent.event).toBe('on_chat_model_stream');
175
- expect(sampleEvent.name).toBe('TestModel');
176
- expect(sampleEvent.data).toBeDefined();
177
- expect(sampleEvent.data.chunk?.content).toBe('test');
178
- });
179
- });