mcp-use 0.2.0 → 1.0.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 (97) 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 +5 -46
  23. package/dist/src/browser.d.ts.map +1 -1
  24. package/dist/src/browser.js +9 -75
  25. package/dist/src/oauth-helper.d.ts +2 -12
  26. package/dist/src/oauth-helper.d.ts.map +1 -1
  27. package/dist/src/react/index.cjs +986 -0
  28. package/dist/src/react/index.d.ts +9 -0
  29. package/dist/src/react/index.d.ts.map +1 -0
  30. package/dist/src/react/index.js +11 -0
  31. package/dist/src/react/types.d.ts +139 -0
  32. package/dist/src/react/types.d.ts.map +1 -0
  33. package/dist/src/react/useMcp.d.ts +3 -0
  34. package/dist/src/react/useMcp.d.ts.map +1 -0
  35. package/dist/src/server/index.cjs +566 -0
  36. package/dist/src/server/index.d.ts +3 -0
  37. package/dist/src/server/index.d.ts.map +1 -0
  38. package/dist/src/server/index.js +9 -0
  39. package/dist/src/server/logging.d.ts +16 -0
  40. package/dist/src/server/logging.d.ts.map +1 -0
  41. package/dist/src/server/mcp-server.d.ts +282 -0
  42. package/dist/src/server/mcp-server.d.ts.map +1 -0
  43. package/dist/src/server/types.d.ts +47 -0
  44. package/dist/src/server/types.d.ts.map +1 -0
  45. package/dist/src/utils/assert.d.ts +8 -0
  46. package/dist/src/utils/assert.d.ts.map +1 -0
  47. package/dist/tsconfig.tsbuildinfo +1 -0
  48. package/package.json +67 -40
  49. package/dist/src/adapters/base.js +0 -124
  50. package/dist/src/adapters/index.js +0 -2
  51. package/dist/src/adapters/langchain_adapter.js +0 -49
  52. package/dist/src/agents/base.js +0 -9
  53. package/dist/src/agents/index.js +0 -3
  54. package/dist/src/agents/mcp_agent.js +0 -1002
  55. package/dist/src/agents/prompts/system_prompt_builder.js +0 -40
  56. package/dist/src/agents/prompts/templates.js +0 -39
  57. package/dist/src/agents/remote.js +0 -264
  58. package/dist/src/agents/utils/ai_sdk.js +0 -62
  59. package/dist/src/agents/utils/index.js +0 -1
  60. package/dist/src/client/base.js +0 -119
  61. package/dist/src/client.js +0 -50
  62. package/dist/src/config.js +0 -34
  63. package/dist/src/connectors/base.js +0 -143
  64. package/dist/src/connectors/http.js +0 -150
  65. package/dist/src/connectors/index.js +0 -4
  66. package/dist/src/connectors/stdio.js +0 -68
  67. package/dist/src/connectors/websocket.js +0 -157
  68. package/dist/src/logging.js +0 -232
  69. package/dist/src/managers/index.js +0 -2
  70. package/dist/src/managers/server_manager.js +0 -106
  71. package/dist/src/managers/tools/acquire_active_mcp_server.js +0 -17
  72. package/dist/src/managers/tools/add_server_from_config.js +0 -40
  73. package/dist/src/managers/tools/base.js +0 -17
  74. package/dist/src/managers/tools/connect_mcp_server.js +0 -46
  75. package/dist/src/managers/tools/index.js +0 -5
  76. package/dist/src/managers/tools/list_mcp_servers.js +0 -33
  77. package/dist/src/managers/tools/release_mcp_server_connection.js +0 -19
  78. package/dist/src/oauth-helper.js +0 -427
  79. package/dist/src/observability/index.js +0 -12
  80. package/dist/src/observability/langfuse.js +0 -211
  81. package/dist/src/observability/manager.js +0 -199
  82. package/dist/src/observability/types.js +0 -4
  83. package/dist/src/session.js +0 -23
  84. package/dist/src/task_managers/base.js +0 -127
  85. package/dist/src/task_managers/index.js +0 -5
  86. package/dist/src/task_managers/sse.js +0 -43
  87. package/dist/src/task_managers/stdio.js +0 -51
  88. package/dist/src/task_managers/streamable_http.js +0 -50
  89. package/dist/src/task_managers/websocket.js +0 -67
  90. package/dist/src/telemetry/events.js +0 -44
  91. package/dist/src/telemetry/index.js +0 -8
  92. package/dist/src/telemetry/telemetry.js +0 -324
  93. package/dist/src/telemetry/utils.js +0 -39
  94. package/dist/tests/ai_sdk_compatibility.test.js +0 -214
  95. package/dist/tests/stream_events.test.js +0 -307
  96. package/dist/tests/stream_events_simple.test.js +0 -179
  97. package/dist/vitest.config.js +0 -21
@@ -1,324 +0,0 @@
1
- import * as fs from 'node:fs';
2
- import * as os from 'node:os';
3
- import * as path from 'node:path';
4
- import { PostHog } from 'posthog-node';
5
- import { v4 as uuidv4 } from 'uuid';
6
- import { logger } from '../logging.js';
7
- import { MCPAgentExecutionEvent } from './events.js';
8
- import { getPackageVersion } from './utils.js';
9
- // Environment detection function
10
- function isNodeJSEnvironment() {
11
- try {
12
- // Check for Cloudflare Workers specifically
13
- if (typeof navigator !== 'undefined' && navigator.userAgent?.includes('Cloudflare-Workers')) {
14
- return false;
15
- }
16
- // Check for other edge runtime indicators
17
- if (typeof globalThis.EdgeRuntime !== 'undefined' || typeof globalThis.Deno !== 'undefined') {
18
- return false;
19
- }
20
- // Check for Node.js specific globals that are not available in edge environments
21
- const hasNodeGlobals = (typeof process !== 'undefined'
22
- && typeof process.platform !== 'undefined'
23
- && typeof __dirname !== 'undefined');
24
- // Check for Node.js modules
25
- const hasNodeModules = (typeof fs !== 'undefined'
26
- && typeof os !== 'undefined'
27
- && typeof fs.existsSync === 'function');
28
- return hasNodeGlobals && hasNodeModules;
29
- }
30
- catch {
31
- return false;
32
- }
33
- }
34
- // Simple Scarf event logger implementation
35
- class ScarfEventLogger {
36
- endpoint;
37
- timeout;
38
- constructor(endpoint, timeout = 3000) {
39
- this.endpoint = endpoint;
40
- this.timeout = timeout;
41
- }
42
- async logEvent(properties) {
43
- try {
44
- const controller = new AbortController();
45
- const timeoutId = setTimeout(() => controller.abort(), this.timeout);
46
- const response = await fetch(this.endpoint, {
47
- method: 'POST',
48
- headers: {
49
- 'Content-Type': 'application/json',
50
- },
51
- body: JSON.stringify(properties),
52
- signal: controller.signal,
53
- });
54
- clearTimeout(timeoutId);
55
- if (!response.ok) {
56
- throw new Error(`HTTP error! status: ${response.status}`);
57
- }
58
- }
59
- catch (error) {
60
- // Silently fail - telemetry should not break the application
61
- logger.debug(`Failed to send Scarf event: ${error}`);
62
- }
63
- }
64
- }
65
- function getCacheHome() {
66
- // Return a safe fallback for non-Node.js environments
67
- if (!isNodeJSEnvironment()) {
68
- return '/tmp/mcp_use_cache';
69
- }
70
- // XDG_CACHE_HOME for Linux and manually set envs
71
- const envVar = process.env.XDG_CACHE_HOME;
72
- if (envVar && path.isAbsolute(envVar)) {
73
- return envVar;
74
- }
75
- const platform = process.platform;
76
- const homeDir = os.homedir();
77
- if (platform === 'win32') {
78
- const appdata = process.env.LOCALAPPDATA || process.env.APPDATA;
79
- if (appdata) {
80
- return appdata;
81
- }
82
- return path.join(homeDir, 'AppData', 'Local');
83
- }
84
- else if (platform === 'darwin') {
85
- // macOS
86
- return path.join(homeDir, 'Library', 'Caches');
87
- }
88
- else {
89
- // Linux or other Unix
90
- return path.join(homeDir, '.cache');
91
- }
92
- }
93
- export class Telemetry {
94
- static instance = null;
95
- USER_ID_PATH = path.join(getCacheHome(), 'mcp_use_3', 'telemetry_user_id');
96
- VERSION_DOWNLOAD_PATH = path.join(getCacheHome(), 'mcp_use', 'download_version');
97
- PROJECT_API_KEY = 'phc_lyTtbYwvkdSbrcMQNPiKiiRWrrM1seyKIMjycSvItEI';
98
- HOST = 'https://eu.i.posthog.com';
99
- SCARF_GATEWAY_URL = 'https://mcpuse.gateway.scarf.sh/events-ts';
100
- UNKNOWN_USER_ID = 'UNKNOWN_USER_ID';
101
- _currUserId = null;
102
- _posthogClient = null;
103
- _scarfClient = null;
104
- _source = 'typescript';
105
- constructor() {
106
- // Check if we're in a Node.js environment first
107
- const isNodeJS = isNodeJSEnvironment();
108
- // Safely access environment variables
109
- const telemetryDisabled = (typeof process !== 'undefined' && process.env?.MCP_USE_ANONYMIZED_TELEMETRY?.toLowerCase() === 'false') || false;
110
- // Check for source from environment variable, default to 'typescript'
111
- this._source = (typeof process !== 'undefined' && process.env?.MCP_USE_TELEMETRY_SOURCE) || 'typescript';
112
- if (telemetryDisabled) {
113
- this._posthogClient = null;
114
- this._scarfClient = null;
115
- logger.debug('Telemetry disabled via environment variable');
116
- }
117
- else if (!isNodeJS) {
118
- this._posthogClient = null;
119
- this._scarfClient = null;
120
- logger.debug('Telemetry disabled - non-Node.js environment detected (e.g., Cloudflare Workers)');
121
- }
122
- else {
123
- logger.info('Anonymized telemetry enabled. Set MCP_USE_ANONYMIZED_TELEMETRY=false to disable.');
124
- // Initialize PostHog
125
- try {
126
- this._posthogClient = new PostHog(this.PROJECT_API_KEY, {
127
- host: this.HOST,
128
- disableGeoip: false,
129
- });
130
- }
131
- catch (e) {
132
- logger.warn(`Failed to initialize PostHog telemetry: ${e}`);
133
- this._posthogClient = null;
134
- }
135
- // Initialize Scarf
136
- try {
137
- this._scarfClient = new ScarfEventLogger(this.SCARF_GATEWAY_URL, 3000);
138
- }
139
- catch (e) {
140
- logger.warn(`Failed to initialize Scarf telemetry: ${e}`);
141
- this._scarfClient = null;
142
- }
143
- }
144
- }
145
- static getInstance() {
146
- if (!Telemetry.instance) {
147
- Telemetry.instance = new Telemetry();
148
- }
149
- return Telemetry.instance;
150
- }
151
- /**
152
- * Set the source identifier for telemetry events.
153
- * This allows tracking usage from different applications.
154
- * @param source - The source identifier (e.g., "my-app", "cli", "vs-code-extension")
155
- */
156
- setSource(source) {
157
- this._source = source;
158
- logger.debug(`Telemetry source set to: ${source}`);
159
- }
160
- /**
161
- * Get the current source identifier.
162
- */
163
- getSource() {
164
- return this._source;
165
- }
166
- get userId() {
167
- if (this._currUserId) {
168
- return this._currUserId;
169
- }
170
- // If we're not in a Node.js environment, just return a static user ID
171
- if (!isNodeJSEnvironment()) {
172
- this._currUserId = this.UNKNOWN_USER_ID;
173
- return this._currUserId;
174
- }
175
- try {
176
- const isFirstTime = !fs.existsSync(this.USER_ID_PATH);
177
- if (isFirstTime) {
178
- logger.debug(`Creating user ID path: ${this.USER_ID_PATH}`);
179
- fs.mkdirSync(path.dirname(this.USER_ID_PATH), { recursive: true });
180
- const newUserId = uuidv4();
181
- fs.writeFileSync(this.USER_ID_PATH, newUserId);
182
- this._currUserId = newUserId;
183
- logger.debug(`User ID path created: ${this.USER_ID_PATH}`);
184
- }
185
- else {
186
- this._currUserId = fs.readFileSync(this.USER_ID_PATH, 'utf-8').trim();
187
- }
188
- // Always check for version-based download tracking
189
- // Note: We can't await here since this is a getter, so we fire and forget
190
- this.trackPackageDownload({
191
- triggered_by: 'user_id_property',
192
- }).catch(e => logger.debug(`Failed to track package download: ${e}`));
193
- }
194
- catch (e) {
195
- logger.debug(`Failed to get/create user ID: ${e}`);
196
- this._currUserId = this.UNKNOWN_USER_ID;
197
- }
198
- return this._currUserId;
199
- }
200
- async capture(event) {
201
- if (!this._posthogClient && !this._scarfClient) {
202
- return;
203
- }
204
- // Send to PostHog
205
- if (this._posthogClient) {
206
- try {
207
- // Add package version, language flag, and source to all events
208
- const properties = { ...event.properties };
209
- properties.mcp_use_version = getPackageVersion();
210
- properties.language = 'typescript';
211
- properties.source = this._source;
212
- this._posthogClient.capture({
213
- distinctId: this.userId,
214
- event: event.name,
215
- properties,
216
- });
217
- }
218
- catch (e) {
219
- logger.debug(`Failed to track PostHog event ${event.name}: ${e}`);
220
- }
221
- }
222
- // Send to Scarf (when implemented)
223
- if (this._scarfClient) {
224
- try {
225
- // Add package version, user_id, language flag, and source to all events
226
- const properties = {};
227
- properties.mcp_use_version = getPackageVersion();
228
- properties.user_id = this.userId;
229
- properties.event = event.name;
230
- properties.language = 'typescript';
231
- properties.source = this._source;
232
- await this._scarfClient.logEvent(properties);
233
- }
234
- catch (e) {
235
- logger.debug(`Failed to track Scarf event ${event.name}: ${e}`);
236
- }
237
- }
238
- }
239
- async trackPackageDownload(properties) {
240
- if (!this._scarfClient) {
241
- return;
242
- }
243
- // Skip tracking in non-Node.js environments
244
- if (!isNodeJSEnvironment()) {
245
- return;
246
- }
247
- try {
248
- const currentVersion = getPackageVersion();
249
- let shouldTrack = false;
250
- let firstDownload = false;
251
- // Check if version file exists
252
- if (!fs.existsSync(this.VERSION_DOWNLOAD_PATH)) {
253
- // First download
254
- shouldTrack = true;
255
- firstDownload = true;
256
- // Create directory and save version
257
- fs.mkdirSync(path.dirname(this.VERSION_DOWNLOAD_PATH), { recursive: true });
258
- fs.writeFileSync(this.VERSION_DOWNLOAD_PATH, currentVersion);
259
- }
260
- else {
261
- // Read saved version
262
- const savedVersion = fs.readFileSync(this.VERSION_DOWNLOAD_PATH, 'utf-8').trim();
263
- // Compare versions (simple string comparison for now)
264
- if (currentVersion > savedVersion) {
265
- shouldTrack = true;
266
- firstDownload = false;
267
- // Update saved version
268
- fs.writeFileSync(this.VERSION_DOWNLOAD_PATH, currentVersion);
269
- }
270
- }
271
- if (shouldTrack) {
272
- logger.debug(`Tracking package download event with properties: ${JSON.stringify(properties)}`);
273
- // Add package version, user_id, language flag, and source to event
274
- const eventProperties = { ...(properties || {}) };
275
- eventProperties.mcp_use_version = currentVersion;
276
- eventProperties.user_id = this.userId;
277
- eventProperties.event = 'package_download';
278
- eventProperties.first_download = firstDownload;
279
- eventProperties.language = 'typescript';
280
- eventProperties.source = this._source;
281
- await this._scarfClient.logEvent(eventProperties);
282
- }
283
- }
284
- catch (e) {
285
- logger.debug(`Failed to track Scarf package_download event: ${e}`);
286
- }
287
- }
288
- async trackAgentExecution(data) {
289
- const event = new MCPAgentExecutionEvent(data);
290
- await this.capture(event);
291
- }
292
- flush() {
293
- // Flush PostHog
294
- if (this._posthogClient) {
295
- try {
296
- this._posthogClient.flush();
297
- logger.debug('PostHog client telemetry queue flushed');
298
- }
299
- catch (e) {
300
- logger.debug(`Failed to flush PostHog client: ${e}`);
301
- }
302
- }
303
- // Scarf events are sent immediately, no flush needed
304
- if (this._scarfClient) {
305
- logger.debug('Scarf telemetry events sent immediately (no flush needed)');
306
- }
307
- }
308
- shutdown() {
309
- // Shutdown PostHog
310
- if (this._posthogClient) {
311
- try {
312
- this._posthogClient.shutdown();
313
- logger.debug('PostHog client shutdown successfully');
314
- }
315
- catch (e) {
316
- logger.debug(`Error shutting down PostHog client: ${e}`);
317
- }
318
- }
319
- // Scarf doesn't require explicit shutdown
320
- if (this._scarfClient) {
321
- logger.debug('Scarf telemetry client shutdown (no action needed)');
322
- }
323
- }
324
- }
@@ -1,39 +0,0 @@
1
- import * as fs from 'node:fs';
2
- import * as path from 'node:path';
3
- export function getPackageVersion() {
4
- try {
5
- // Check if we're in a Node.js environment with file system access
6
- if (typeof __dirname === 'undefined' || typeof fs === 'undefined') {
7
- return 'unknown';
8
- }
9
- const packagePath = path.join(__dirname, '../../package.json');
10
- const packageJson = JSON.parse(fs.readFileSync(packagePath, 'utf-8'));
11
- return packageJson.version || 'unknown';
12
- }
13
- catch {
14
- return 'unknown';
15
- }
16
- }
17
- export function getModelProvider(llm) {
18
- // Use LangChain's standard _llm_type property for identification
19
- return llm._llm_type || llm.constructor.name.toLowerCase();
20
- }
21
- export function getModelName(llm) {
22
- // First try _identifying_params which may contain model info
23
- if ('_identifyingParams' in llm) {
24
- const identifyingParams = llm._identifyingParams;
25
- if (typeof identifyingParams === 'object' && identifyingParams !== null) {
26
- // Common keys that contain model names
27
- for (const key of ['model', 'modelName', 'model_name', 'modelId', 'model_id', 'deploymentName', 'deployment_name']) {
28
- if (key in identifyingParams) {
29
- return String(identifyingParams[key]);
30
- }
31
- }
32
- }
33
- }
34
- // Fallback to direct model attributes
35
- return llm.model || llm.modelName || llm.constructor.name;
36
- }
37
- export function extractModelInfo(llm) {
38
- return [getModelProvider(llm), getModelName(llm)];
39
- }
@@ -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 };